1 15 package org.eclipse.compare.contentmergeviewer; 16 17 import java.io.UnsupportedEncodingException ; 18 import java.lang.reflect.InvocationTargetException ; 19 import java.util.*; 20 import java.util.List ; 21 22 import org.eclipse.compare.*; 23 import org.eclipse.compare.internal.*; 24 import org.eclipse.compare.patch.IHunk; 25 import org.eclipse.compare.rangedifferencer.*; 26 import org.eclipse.compare.structuremergeviewer.*; 27 import org.eclipse.core.resources.ResourcesPlugin; 28 import org.eclipse.core.runtime.*; 29 import org.eclipse.core.runtime.Assert; 30 import org.eclipse.jface.action.*; 31 import org.eclipse.jface.dialogs.ErrorDialog; 32 import org.eclipse.jface.dialogs.MessageDialog; 33 import org.eclipse.jface.operation.IRunnableWithProgress; 34 import org.eclipse.jface.preference.IPreferenceStore; 35 import org.eclipse.jface.resource.ColorRegistry; 36 import org.eclipse.jface.resource.JFaceResources; 37 import org.eclipse.jface.text.*; 38 import org.eclipse.jface.text.Region; 39 import org.eclipse.jface.text.source.SourceViewerConfiguration; 40 import org.eclipse.jface.util.IPropertyChangeListener; 41 import org.eclipse.jface.util.PropertyChangeEvent; 42 import org.eclipse.jface.viewers.*; 43 import org.eclipse.jface.window.Window; 44 import org.eclipse.osgi.util.NLS; 45 import org.eclipse.swt.SWT; 46 import org.eclipse.swt.accessibility.AccessibleAdapter; 47 import org.eclipse.swt.accessibility.AccessibleEvent; 48 import org.eclipse.swt.custom.StyleRange; 49 import org.eclipse.swt.custom.StyledText; 50 import org.eclipse.swt.events.*; 51 import org.eclipse.swt.graphics.*; 52 import org.eclipse.swt.widgets.*; 53 import org.eclipse.ui.*; 54 import org.eclipse.ui.actions.ActionFactory; 55 import org.eclipse.ui.progress.IProgressService; 56 import org.eclipse.ui.texteditor.*; 57 58 import com.ibm.icu.text.MessageFormat; 59 60 106 public class TextMergeViewer extends ContentMergeViewer implements IAdaptable { 107 108 private static final String COPY_LEFT_TO_RIGHT_INDICATOR = ">"; private static final String COPY_RIGHT_TO_LEFT_INDICATOR = "<"; private static final char ANCESTOR_CONTRIBUTOR = MergeViewerContentProvider.ANCESTOR_CONTRIBUTOR; 111 private static final char RIGHT_CONTRIBUTOR = MergeViewerContentProvider.RIGHT_CONTRIBUTOR; 112 private static final char LEFT_CONTRIBUTOR = MergeViewerContentProvider.LEFT_CONTRIBUTOR; 113 114 private static final String DIFF_RANGE_CATEGORY = CompareUIPlugin.PLUGIN_ID + ".DIFF_RANGE_CATEGORY"; 116 static final boolean DEBUG= false; 117 118 private static final boolean FIX_47640= true; 119 120 private static final String [] GLOBAL_ACTIONS= { 121 ActionFactory.UNDO.getId(), 122 ActionFactory.REDO.getId(), 123 ActionFactory.CUT.getId(), 124 ActionFactory.COPY.getId(), 125 ActionFactory.PASTE.getId(), 126 ActionFactory.DELETE.getId(), 127 ActionFactory.SELECT_ALL.getId(), 128 ActionFactory.SAVE.getId(), 129 ActionFactory.FIND.getId() 130 }; 131 private static final String [] TEXT_ACTIONS= { 132 MergeSourceViewer.UNDO_ID, 133 MergeSourceViewer.REDO_ID, 134 MergeSourceViewer.CUT_ID, 135 MergeSourceViewer.COPY_ID, 136 MergeSourceViewer.PASTE_ID, 137 MergeSourceViewer.DELETE_ID, 138 MergeSourceViewer.SELECT_ALL_ID, 139 MergeSourceViewer.SAVE_ID, 140 MergeSourceViewer.FIND_ID 141 }; 142 143 private static final String BUNDLE_NAME= "org.eclipse.compare.contentmergeviewer.TextMergeViewerResources"; 145 private static final String INCOMING_COLOR= "INCOMING_COLOR"; private static final String OUTGOING_COLOR= "OUTGOING_COLOR"; private static final String CONFLICTING_COLOR= "CONFLICTING_COLOR"; private static final String RESOLVED_COLOR= "RESOLVED_COLOR"; 151 153 private static final int MARGIN_WIDTH= 6; 154 155 private static final int CENTER_WIDTH= 34; 156 157 private static final int BIRDS_EYE_VIEW_WIDTH= 12; 158 159 private static final int BIRDS_EYE_VIEW_INSET= 2; 160 161 private static final int RESOLVE_SIZE= 5; 162 163 private static final boolean APPEND_CONFLICT= true; 164 165 166 private static final int LW= 1; 167 168 private static final boolean USE_MERGING_TOKEN_DIFF= false; 169 170 private boolean fLeftIsLocal; 172 private boolean fShowCurrentOnly= false; 173 private boolean fShowCurrentOnly2= false; 174 private int fMarginWidth= MARGIN_WIDTH; 175 private int fTopInset; 176 177 private RGB fBackground; 179 private RGB fForeground; 180 private boolean fPollSystemForeground= true; 181 private boolean fPollSystemBackground= true; 182 183 private RGB SELECTED_INCOMING; 184 private RGB INCOMING; 185 private RGB INCOMING_FILL; 186 private RGB INCOMING_TEXT_FILL; 187 188 private RGB SELECTED_CONFLICT; 189 private RGB CONFLICT; 190 private RGB CONFLICT_FILL; 191 private RGB CONFLICT_TEXT_FILL; 192 193 private RGB SELECTED_OUTGOING; 194 private RGB OUTGOING; 195 private RGB OUTGOING_FILL; 196 private RGB OUTGOING_TEXT_FILL; 197 198 private RGB RESOLVED; 199 200 private IPreferenceStore fPreferenceStore; 201 private IPropertyChangeListener fPreferenceChangeListener; 202 203 204 private ArrayList fAllDiffs; 205 206 private ArrayList fChangeDiffs; 207 208 private Diff fCurrentDiff; 209 210 private HashMap fNewAncestorRanges= new HashMap(); 211 private HashMap fNewLeftRanges= new HashMap(); 212 private HashMap fNewRightRanges= new HashMap(); 213 214 private MergeSourceViewer fAncestor; 215 private MergeSourceViewer fLeft; 216 private MergeSourceViewer fRight; 217 218 private int fLeftLineCount; 219 private int fRightLineCount; 220 221 private boolean fInScrolling; 222 223 private int fPts[]= new int[8]; 225 private int fInheritedDirection; private int fTextDirection; 228 private ActionContributionItem fIgnoreAncestorItem; 229 private boolean fHighlightRanges; 230 231 private boolean fShowPseudoConflicts= false; 232 233 private boolean fUseSplines= true; 234 private boolean fUseSingleLine= true; 235 private boolean fUseResolveUI= true; 236 private boolean fHighlightTokenChanges = false; 237 238 private String fSymbolicFontName; 239 240 private ActionContributionItem fNextDiff; private ActionContributionItem fPreviousDiff; private ActionContributionItem fCopyDiffLeftToRightItem; 243 private ActionContributionItem fCopyDiffRightToLeftItem; 244 245 private CompareHandlerService fHandlerService; 246 247 private boolean fSynchronizedScrolling= true; 248 private boolean fShowMoreInfo= false; 249 250 private MergeSourceViewer fFocusPart; 251 252 private boolean fSubDoc= true; 253 private IPositionUpdater fPositionUpdater; 254 private boolean fIsMotif; 255 private boolean fIsCarbon; 256 257 private boolean fHasErrors; 258 259 260 private BufferedCanvas fAncestorCanvas; 262 private BufferedCanvas fLeftCanvas; 263 private BufferedCanvas fRightCanvas; 264 private Canvas fScrollCanvas; 265 private ScrollBar fVScrollBar; 266 private Canvas fBirdsEyeCanvas; 267 private Canvas fSummaryHeader; 268 private HeaderPainter fHeaderPainter; 269 270 private Map fColors; 272 private Cursor fBirdsEyeCursor; 273 274 private double[] fBasicCenterCurve; 276 277 private Button fCenterButton; 278 private Diff fButtonDiff; 279 280 private ContributorInfo fLeftContributor; 281 private ContributorInfo fRightContributor; 282 private ContributorInfo fAncestorContributor; 283 private boolean isRefreshing; 284 private int fSynchronziedScrollPosition; 285 private ActionContributionItem fNextChange; 286 private ActionContributionItem fPreviousChange; 287 private ShowWhitespaceAction showWhitespaceAction; 288 private InternalOutlineViewerCreator fOutlineViewerCreator; 289 private TextEditorPropertyAction toggleLineNumbersAction; 290 private IFindReplaceTarget fFindReplaceTarget; 291 private ChangePropertyAction fIgnoreWhitespace; 292 293 private final class InternalOutlineViewerCreator extends OutlineViewerCreator implements ISelectionChangedListener { 294 public Viewer findStructureViewer(Viewer oldViewer, 295 ICompareInput input, Composite parent, 296 CompareConfiguration configuration) { 297 if (input != getInput()) 298 return null; 299 final Viewer v = CompareUI.findStructureViewer(oldViewer, input, parent, configuration); 300 if (v != null) { 301 v.getControl().addDisposeListener(new DisposeListener() { 302 public void widgetDisposed(DisposeEvent e) { 303 v.removeSelectionChangedListener(InternalOutlineViewerCreator.this); 304 } 305 }); 306 v.addSelectionChangedListener(this); 307 } 308 309 return v; 310 } 311 312 public boolean hasViewerFor(Object input) { 313 return true; 314 } 315 316 public void selectionChanged(SelectionChangedEvent event) { 317 ISelection s = event.getSelection(); 318 if (s instanceof IStructuredSelection) { 319 IStructuredSelection ss = (IStructuredSelection) s; 320 Object element = ss.getFirstElement(); 321 Diff diff = findDiff(element); 322 if (diff != null) 323 setCurrentDiff(diff, true); 324 } 325 } 326 327 private Diff findDiff(Object element) { 328 if (element instanceof ICompareInput) { 329 ICompareInput ci = (ICompareInput) element; 330 Position p = getPosition(ci.getLeft()); 331 if (p != null) 332 return findDiff(p, true); 333 p = getPosition(ci.getRight()); 334 if (p != null) 335 return findDiff(p, false); 336 } 337 return null; 338 } 339 340 private Diff findDiff(Position p, boolean left) { 341 for (Iterator iterator = fAllDiffs.iterator(); iterator.hasNext();) { 342 Diff diff = (Diff) iterator.next(); 343 Position diffPos; 344 if (left) { 345 diffPos = diff.fLeftPos; 346 } else { 347 diffPos = diff.fRightPos; 348 } 349 if (diffPos.offset + diffPos.length >= p.offset && diff.fDirection != RangeDifference.NOCHANGE) 351 return diff; 352 if (diffPos.offset >= p.offset) 354 return diff; 355 } 356 return null; 357 } 358 359 private Position getPosition(ITypedElement left) { 360 if (left instanceof DocumentRangeNode) { 361 DocumentRangeNode drn = (DocumentRangeNode) left; 362 return drn.getRange(); 363 } 364 return null; 365 } 366 367 public Object getInput() { 368 return TextMergeViewer.this.getInput(); 369 } 370 } 371 372 class ContributorInfo implements IElementStateListener, VerifyListener, IDocumentListener { 373 private final TextMergeViewer fViewer; 374 private final Object fElement; 375 private char fLeg; 376 private String fEncoding; 377 private IDocumentProvider fDocumentProvider; 378 private IEditorInput fDocumentKey; 379 private ISelection fSelection; 380 private int fTopIndex = -1; 381 private boolean fNeedsValidation = false; 382 private MergeSourceViewer fSourceViewer; 383 384 public ContributorInfo(TextMergeViewer viewer, Object element, char leg) { 385 fViewer = viewer; 386 fElement = element; 387 fLeg = leg; 388 if (fElement instanceof IEncodedStreamContentAccessor) { 389 try { 390 fEncoding = ((IEncodedStreamContentAccessor)fElement).getCharset(); 391 } catch (CoreException e) { 392 } 394 } 395 } 396 397 public String getEncoding() { 398 if (fEncoding == null) 399 return ResourcesPlugin.getEncoding(); 400 return fEncoding; 401 } 402 403 public void setEncodingIfAbsent(ContributorInfo otherContributor) { 404 if (fEncoding == null) 405 fEncoding = otherContributor.fEncoding; 406 } 407 408 public IDocument getDocument() { 409 if (fDocumentProvider != null) { 410 IDocument document = fDocumentProvider.getDocument(getDocumentKey()); 411 if (document != null) 412 return document; 413 } 414 if (fElement instanceof IDocument) 415 return (IDocument) fElement; 416 if (fElement instanceof IDocumentRange) 417 return ((IDocumentRange) fElement).getDocument(); 418 if (fElement instanceof IStreamContentAccessor) 419 return DocumentManager.get(fElement); 420 return null; 421 } 422 423 public void setDocument(MergeSourceViewer viewer, boolean isEditable) { 424 Assert.isTrue(fSourceViewer == null); 426 fSourceViewer = viewer; 427 try { 428 internalSetDocument(viewer); 429 } catch (RuntimeException e) { 430 clearCachedDocument(); 432 throw e; 433 } 434 viewer.setEditable(isEditable); 435 if (isEditable) { 437 fNeedsValidation = true; 438 viewer.getTextWidget().addVerifyListener(this); 439 } 440 } 441 442 445 private boolean internalSetDocument(MergeSourceViewer tp) { 446 447 if (tp == null) 448 return false; 449 450 IDocument newDocument = null; 451 Position range= null; 452 453 if (fElement instanceof IDocumentRange) { 454 newDocument= ((IDocumentRange)fElement).getDocument(); 455 range= ((IDocumentRange)fElement).getRange(); 456 connectToSharedDocument(); 457 458 } else if (fElement instanceof IDocument) { 459 newDocument= (IDocument) fElement; 460 461 } else if (fElement instanceof IStreamContentAccessor) { 462 newDocument= DocumentManager.get(fElement); 463 if (newDocument == null) { 464 newDocument = createDocument(); 465 DocumentManager.put(fElement, newDocument); 466 setupDocument(newDocument); 467 } else if (fDocumentProvider == null) { 468 connectToSharedDocument(); 470 } 471 } else if (fElement == null) { 473 ITypedElement parent= this.fViewer.getParent(fLeg); 475 if (parent instanceof IDocumentRange) { 476 newDocument= ((IDocumentRange)parent).getDocument(); 477 newDocument.addPositionCategory(DIFF_RANGE_CATEGORY); 478 Object input= this.fViewer.getInput(); 479 range= this.fViewer.getNewRange(fLeg, input); 480 if (range == null) { 481 int pos= 0; 482 if (input instanceof ICompareInput) 483 pos= this.fViewer.findInsertionPosition(fLeg, (ICompareInput)input); 484 range= new Position(pos, 0); 485 try { 486 newDocument.addPosition(DIFF_RANGE_CATEGORY, range); 487 } catch (BadPositionCategoryException ex) { 488 if (TextMergeViewer.DEBUG) System.out.println("BadPositionCategoryException: " + ex); } catch (BadLocationException ex) { 491 if (TextMergeViewer.DEBUG) System.out.println("BadLocationException: " + ex); } 494 this.fViewer.addNewRange(fLeg, input, range); 495 } 496 } else if (parent instanceof IDocument) { 497 newDocument= ((IDocumentRange)fElement).getDocument(); 498 } 499 } 500 501 boolean enabled= true; 502 if (newDocument == null) { 503 newDocument= new Document(""); enabled= false; 505 } 506 507 IDocument oldDoc= tp.getDocument(); 509 if (newDocument != oldDoc) { 510 updateViewerDocument(tp, newDocument, range); 511 } else { updateViewerDocumentRange(tp, range); 513 } 514 newDocument.addDocumentListener(this); 515 516 tp.setEnabled(enabled); 517 518 return enabled; 519 } 520 521 524 private void updateViewerDocumentRange(MergeSourceViewer tp, Position range) { 525 tp.setRegion(range); 526 if (this.fViewer.fSubDoc) { 527 if (range != null) { 528 IRegion r= this.fViewer.normalizeDocumentRegion(tp.getDocument(), TextMergeViewer.toRegion(range)); 529 tp.setVisibleRegion(r.getOffset(), r.getLength()); 530 } else 531 tp.resetVisibleRegion(); 532 } else 533 tp.resetVisibleRegion(); 534 } 535 536 539 private void updateViewerDocument(MergeSourceViewer tp, IDocument document, Position range) { 540 unsetDocument(tp); 541 if (document == null) 542 return; 543 544 document.addPositionCategory(DIFF_RANGE_CATEGORY); 546 if (this.fViewer.fPositionUpdater == null) 547 this.fViewer.fPositionUpdater= this.fViewer.new ChildPositionUpdater(DIFF_RANGE_CATEGORY); 548 else 549 document.removePositionUpdater(this.fViewer.fPositionUpdater); 550 document.addPositionUpdater(this.fViewer.fPositionUpdater); 551 552 tp.setRegion(range); 554 if (this.fViewer.fSubDoc) { 555 if (range != null) { 556 IRegion r= this.fViewer.normalizeDocumentRegion(document, TextMergeViewer.toRegion(range)); 557 tp.setDocument(document, r.getOffset(), r.getLength()); 558 } else 559 tp.setDocument(document); 560 } else 561 tp.setDocument(document); 562 563 tp.rememberDocument(document); 564 } 565 566 private void unsetDocument(MergeSourceViewer tp) { 567 IDocument oldDoc= internalGetDocument(tp); 568 if (oldDoc != null) { 569 tp.rememberDocument(null); 570 try { 571 oldDoc.removePositionCategory(DIFF_RANGE_CATEGORY); 572 } catch (BadPositionCategoryException ex) { 573 } 575 if (fPositionUpdater != null) 576 oldDoc.removePositionUpdater(fPositionUpdater); 577 oldDoc.removeDocumentListener(this); 578 } 579 } 580 581 private IDocument createDocument() { 582 IDocument newDoc = connectToSharedDocument(); 585 586 if (newDoc == null) { 587 IStreamContentAccessor sca= (IStreamContentAccessor) fElement; 588 String s= null; 589 590 try { 591 String encoding = getEncoding(); 592 s = Utilities.readString(sca, encoding); 593 } catch (CoreException ex) { 594 this.fViewer.setError(fLeg, ex.getMessage()); 595 } 596 597 newDoc= new Document(s != null ? s : ""); } 599 return newDoc; 600 } 601 602 608 private IDocument connectToSharedDocument() { 609 IEditorInput key = getDocumentKey(); 610 if (key != null) { 611 if (fDocumentProvider != null) { 612 return fDocumentProvider.getDocument(key); 614 } 615 IDocumentProvider documentProvider = getDocumentProvider(); 616 if (documentProvider != null) { 617 try { 618 connect(documentProvider, key); 619 setCachedDocumentProvider(key, 620 documentProvider); 621 IDocument newDoc = documentProvider.getDocument(key); 622 this.fViewer.updateDirtyState(key, documentProvider, fLeg); 623 return newDoc; 624 } catch (CoreException e) { 625 CompareUIPlugin.log(e); 627 } 628 } 629 } 630 return null; 631 } 632 633 private void connect(IDocumentProvider documentProvider, IEditorInput input) throws CoreException { 634 final ISharedDocumentAdapter sda = (ISharedDocumentAdapter) Utilities.getAdapter(fElement, ISharedDocumentAdapter.class); 635 if (sda != null) { 636 sda.connect(documentProvider, input); 637 } else { 638 documentProvider.connect(input); 639 } 640 } 641 642 private void disconnect(IDocumentProvider provider, IEditorInput input) { 643 final ISharedDocumentAdapter sda = (ISharedDocumentAdapter) Utilities.getAdapter(fElement, ISharedDocumentAdapter.class); 644 if (sda != null) { 645 sda.disconnect(provider, input); 646 } else { 647 provider.disconnect(input); 648 } 649 } 650 651 private void setCachedDocumentProvider(IEditorInput key, 652 IDocumentProvider documentProvider) { 653 fDocumentKey = key; 654 fDocumentProvider = documentProvider; 655 documentProvider.addElementStateListener(this); 656 } 657 658 public void disconnect() { 659 IDocumentProvider provider = null; 660 IEditorInput input = getDocumentKey(); 661 synchronized(this) { 662 if (fDocumentProvider != null) { 663 provider = fDocumentProvider; 664 fDocumentProvider = null; 665 fDocumentKey = null; 666 } 667 } 668 if (provider != null) { 669 disconnect(provider, input); 670 provider.removeElementStateListener(this); 671 } 672 if (fSourceViewer != null && !fSourceViewer.getTextWidget().isDisposed()) { 674 if (fNeedsValidation) { 675 fSourceViewer.getTextWidget().removeVerifyListener(this); 676 fNeedsValidation = false; 677 } 678 IDocument oldDoc= internalGetDocument(fSourceViewer); 679 if (oldDoc != null) { 680 oldDoc.removeDocumentListener(this); 681 } 682 } 683 clearCachedDocument(); 684 } 685 686 private void clearCachedDocument() { 687 IDocument doc = DocumentManager.get(fElement); 689 if (doc != null) 690 DocumentManager.remove(doc); 691 } 692 693 private IDocument internalGetDocument(MergeSourceViewer tp) { 694 IDocument oldDoc= tp.getDocument(); 695 if (oldDoc == null) { 696 oldDoc= tp.getRememberedDocument(); 697 } 698 return oldDoc; 699 } 700 701 711 private IEditorInput getDocumentKey() { 712 if (fDocumentKey != null) 713 return fDocumentKey; 714 if (isUsingDefaultContentProvider() && fElement != null && canHaveSharedDocument()) { 715 ISharedDocumentAdapter sda = (ISharedDocumentAdapter)Utilities.getAdapter(fElement, ISharedDocumentAdapter.class, true); 716 if (sda != null) { 717 return sda.getDocumentKey(fElement); 718 } 719 } 720 return null; 721 } 722 723 private IDocumentProvider getDocumentProvider() { 724 if (fDocumentProvider != null) 725 return fDocumentProvider; 726 if (isUsingDefaultContentProvider()) { 729 IEditorInput input = getDocumentKey(); 730 if (input != null) 731 return SharedDocumentAdapter.getDocumentProvider(input); 732 } 733 return null; 734 } 735 736 private boolean isUsingDefaultContentProvider() { 737 return fViewer.isUsingDefaultContentProvider(); 738 } 739 740 private boolean canHaveSharedDocument() { 741 return fViewer.canHaveSharedDocument(); 742 } 743 744 boolean hasSharedDocument(Object object) { 745 return (fElement == object && 746 fDocumentProvider != null 747 && fDocumentProvider.getDocument(getDocumentKey()) != null); 748 } 749 750 public boolean flush() throws CoreException { 751 if (fDocumentProvider != null) { 752 IEditorInput input = getDocumentKey(); 753 IDocument document = fDocumentProvider.getDocument(input); 754 if (document != null) { 755 final ISharedDocumentAdapter sda = (ISharedDocumentAdapter) Utilities.getAdapter(fElement, ISharedDocumentAdapter.class); 756 if (sda != null) { 757 sda.flushDocument(fDocumentProvider, input, document, false); 758 return true; 759 } 760 try { 761 fDocumentProvider.aboutToChange(input); 762 fDocumentProvider.saveDocument(new NullProgressMonitor(), input, document, false); 763 return true; 764 } finally { 765 fDocumentProvider.changed(input); 766 } 767 } 768 } 769 return false; 770 } 771 772 public void elementMoved(Object originalElement, Object movedElement) { 773 IEditorInput input = getDocumentKey(); 774 if (input != null && input.equals(originalElement)) { 775 resetDocument(); 777 } 778 } 779 public void elementDirtyStateChanged(Object element, boolean isDirty) { 780 if (!checkState()) 781 return; 782 IEditorInput input = getDocumentKey(); 783 if (input != null && input.equals(element)) { 784 this.fViewer.updateDirtyState(input, getDocumentProvider(), fLeg); 785 } 786 } 787 788 public void elementDeleted(Object element) { 789 IEditorInput input = getDocumentKey(); 790 if (input != null && input.equals(element)) { 791 resetDocument(); 793 } 794 } 795 private void resetDocument() { 796 clearCachedDocument(); 799 if (checkState()) 803 fViewer.refresh(); 804 } 805 806 private boolean checkState() { 807 if (fViewer == null) 808 return false; 809 Control control = fViewer.getControl(); 810 if (control == null) 811 return false; 812 return !control.isDisposed(); 813 } 814 815 public void elementContentReplaced(Object element) { 816 if (!checkState()) 817 return; 818 IEditorInput input = getDocumentKey(); 819 if (input != null && input.equals(element)) { 820 this.fViewer.updateDirtyState(input, getDocumentProvider(), fLeg); 821 } 822 } 823 public void elementContentAboutToBeReplaced(Object element) { 824 } 826 827 public Object getElement() { 828 return fElement; 829 } 830 831 public void cacheSelection(MergeSourceViewer viewer) { 832 if (viewer == null) { 833 this.fSelection = null; 834 this.fTopIndex = -1; 835 } else { 836 this.fSelection = viewer.getSelection(); 837 this.fTopIndex = viewer.getTopIndex(); 838 } 839 } 840 841 public void updateSelection(MergeSourceViewer viewer, boolean includeScroll) { 842 if (fSelection != null) 843 viewer.setSelection(fSelection); 844 if (includeScroll && fTopIndex != -1) { 845 viewer.setTopIndex(fTopIndex); 846 } 847 } 848 849 public void transferContributorStateFrom( 850 ContributorInfo oldContributor) { 851 if (oldContributor != null) { 852 fSelection = oldContributor.fSelection; 853 fTopIndex = oldContributor.fTopIndex; 854 } 855 856 } 857 858 public boolean validateChange() { 859 if (fElement == null) 860 return true; 861 if (fDocumentProvider instanceof IDocumentProviderExtension) { 862 IDocumentProviderExtension ext = (IDocumentProviderExtension)fDocumentProvider; 863 if (ext.isReadOnly(fDocumentKey)) { 864 try { 865 ext.validateState(fDocumentKey, getControl().getShell()); 866 ext.updateStateCache(fDocumentKey); 867 } catch (CoreException e) { 868 ErrorDialog.openError(getControl().getShell(), CompareMessages.TextMergeViewer_12, CompareMessages.TextMergeViewer_13, e.getStatus()); 869 return false; 870 } 871 } 872 return !ext.isReadOnly(fDocumentKey); 873 } 874 IEditableContentExtension ext = (IEditableContentExtension)Utilities.getAdapter(fElement, IEditableContentExtension.class); 875 if (ext != null) { 876 if (ext.isReadOnly()) { 877 IStatus status = ext.validateEdit(getControl().getShell()); 878 if (!status.isOK()) { 879 if (status.getSeverity() == IStatus.ERROR) { 880 ErrorDialog.openError(getControl().getShell(), CompareMessages.TextMergeViewer_14, CompareMessages.TextMergeViewer_15, status); 881 return false; 882 } 883 if (status.getSeverity() == IStatus.CANCEL) 884 return false; 885 } 886 } 887 } 888 return true; 889 } 890 891 894 public void verifyText(VerifyEvent e) { 895 if (!validateChange()) { 896 e.doit= false; 897 } 898 } 899 900 903 public void documentAboutToBeChanged(DocumentEvent e) { 904 } 906 907 910 public void documentChanged(DocumentEvent e) { 911 boolean dirty = true; 912 if (fDocumentProvider != null && fDocumentKey != null) { 913 dirty = fDocumentProvider.canSaveDocument(fDocumentKey); 914 } 915 TextMergeViewer.this.documentChanged(e, dirty); 916 if (fNeedsValidation && fSourceViewer != null && !fSourceViewer.getTextWidget().isDisposed()) { 918 fSourceViewer.getTextWidget().removeVerifyListener(this); 919 fNeedsValidation = false; 920 } 921 } 922 } 923 924 class HeaderPainter implements PaintListener { 925 926 private static final int INSET= BIRDS_EYE_VIEW_INSET; 927 928 private RGB fIndicatorColor; 929 private Color fSeparatorColor; 930 931 public HeaderPainter() { 932 fSeparatorColor= fSummaryHeader.getDisplay().getSystemColor(SWT.COLOR_WIDGET_NORMAL_SHADOW); 933 } 934 935 938 public boolean setColor(RGB color) { 939 RGB oldColor= fIndicatorColor; 940 fIndicatorColor= color; 941 if (color == null) 942 return oldColor != null; 943 if (oldColor != null) 944 return !color.equals(oldColor); 945 return true; 946 } 947 948 private void drawBevelRect(GC gc, int x, int y, int w, int h, Color topLeft, Color bottomRight) { 949 gc.setForeground(topLeft); 950 gc.drawLine(x, y, x + w -1, y); 951 gc.drawLine(x, y, x, y + h -1); 952 953 gc.setForeground(bottomRight); 954 gc.drawLine(x + w, y, x + w, y + h); 955 gc.drawLine(x, y + h, x + w, y + h); 956 } 957 958 public void paintControl(PaintEvent e) { 959 960 Point s= fSummaryHeader.getSize(); 961 962 if (fIndicatorColor != null) { 963 Display d= fSummaryHeader.getDisplay(); 964 e.gc.setBackground(getColor(d, fIndicatorColor)); 965 int min= Math.min(s.x, s.y)-2*INSET; 966 Rectangle r= new Rectangle((s.x-min)/2, (s.y-min)/2, min, min); 967 e.gc.fillRectangle(r); 968 if (d != null) 969 drawBevelRect(e.gc, r.x, r.y, r.width -1, r.height -1, d.getSystemColor(SWT.COLOR_WIDGET_NORMAL_SHADOW), d.getSystemColor(SWT.COLOR_WIDGET_HIGHLIGHT_SHADOW)); 970 971 e.gc.setForeground(fSeparatorColor); 972 e.gc.setLineWidth(0 ); 973 e.gc.drawLine(0+1, s.y-1, s.x-1-1, s.y-1); 974 } 975 } 976 } 977 978 982 class ChildPositionUpdater extends DefaultPositionUpdater { 983 984 987 protected ChildPositionUpdater(String category) { 988 super(category); 989 } 990 991 995 protected boolean notDeleted() { 996 return true; 997 } 998 999 1005 protected void adaptToInsert() { 1006 1007 if (fPosition == fLeft.getRegion() || fPosition == fRight.getRegion()) { 1008 int myStart= fPosition.offset; 1009 int myEnd= fPosition.offset + fPosition.length; 1010 myEnd= Math.max(myStart, myEnd); 1011 1012 int yoursStart= fOffset; 1013 int yoursEnd= fOffset + fReplaceLength -1; 1014 yoursEnd= Math.max(yoursStart, yoursEnd); 1015 1016 if (myEnd < yoursStart) 1017 return; 1018 1019 if (myStart <= yoursStart) 1020 fPosition.length += fReplaceLength; 1021 else 1022 fPosition.offset += fReplaceLength; 1023 } else { 1024 super.adaptToInsert(); 1025 } 1026 } 1027 } 1028 1029 1033 class Diff { 1034 1035 Position fAncestorPos; 1036 1037 Position fLeftPos; 1038 1039 Position fRightPos; 1040 1041 Diff fParent; 1042 1043 boolean fResolved; 1044 int fDirection; 1045 boolean fIsToken= false; 1046 1047 ArrayList fDiffs; 1048 boolean fIsWhitespace= false; 1049 1050 1053 Diff(Diff parent, int dir, IDocument ancestorDoc, Position aRange, int ancestorStart, int ancestorEnd, 1054 IDocument leftDoc, Position lRange, int leftStart, int leftEnd, 1055 IDocument rightDoc, Position rRange, int rightStart, int rightEnd) { 1056 fParent= parent != null ? parent : this; 1057 fDirection= dir; 1058 1059 fLeftPos= createPosition(leftDoc, lRange, leftStart, leftEnd); 1060 fRightPos= createPosition(rightDoc, rRange, rightStart, rightEnd); 1061 if (ancestorDoc != null) 1062 fAncestorPos= createPosition(ancestorDoc, aRange, ancestorStart, ancestorEnd); 1063 } 1064 1065 Position getPosition(char type) { 1066 switch (type) { 1067 case ANCESTOR_CONTRIBUTOR: 1068 return fAncestorPos; 1069 case LEFT_CONTRIBUTOR: 1070 return fLeftPos; 1071 case RIGHT_CONTRIBUTOR: 1072 return fRightPos; 1073 } 1074 return null; 1075 } 1076 1077 boolean isInRange(char type, int pos) { 1078 Position p= getPosition(type); 1079 return (pos >= p.offset) && (pos < (p.offset+p.length)); 1080 } 1081 1082 String changeType() { 1083 boolean leftEmpty= fLeftPos.length == 0; 1084 boolean rightEmpty= fRightPos.length == 0; 1085 1086 if (fDirection == RangeDifference.LEFT) { 1087 if (!leftEmpty && rightEmpty) 1088 return CompareMessages.TextMergeViewer_changeType_addition; 1089 if (leftEmpty && !rightEmpty) 1090 return CompareMessages.TextMergeViewer_changeType_deletion; 1091 } else { 1092 if (leftEmpty && !rightEmpty) 1093 return CompareMessages.TextMergeViewer_changeType_addition; 1094 if (!leftEmpty && rightEmpty) 1095 return CompareMessages.TextMergeViewer_changeType_deletion; 1096 } 1097 return CompareMessages.TextMergeViewer_changeType_change; 1098 } 1099 1100 Image getImage() { 1101 int code= Differencer.CHANGE; 1102 switch (fDirection) { 1103 case RangeDifference.RIGHT: 1104 code+= Differencer.LEFT; 1105 break; 1106 case RangeDifference.LEFT: 1107 code+= Differencer.RIGHT; 1108 break; 1109 case RangeDifference.ANCESTOR: 1110 case RangeDifference.CONFLICT: 1111 code+= Differencer.CONFLICTING; 1112 break; 1113 } 1114 if (code != 0) 1115 return getCompareConfiguration().getImage(code); 1116 return null; 1117 } 1118 1119 Position createPosition(IDocument doc, Position range, int start, int end) { 1120 try { 1121 int l= end-start; 1122 if (range != null) { 1123 int dl= range.length; 1124 if (l > dl) 1125 l= dl; 1126 } else { 1127 int dl= doc.getLength(); 1128 if (start+l > dl) 1129 l= dl-start; 1130 } 1131 1132 Position p= null; 1133 try { 1134 p= new Position(start, l); 1135 } catch (RuntimeException ex) { 1136 p= new Position(0, 0); 1137 } 1138 1139 try { 1140 doc.addPosition(DIFF_RANGE_CATEGORY, p); 1141 } catch (BadPositionCategoryException ex) { 1142 } 1144 return p; 1145 } catch (BadLocationException ee) { 1146 } 1148 return null; 1149 } 1150 1151 void add(Diff d) { 1152 if (fDiffs == null) 1153 fDiffs= new ArrayList(); 1154 fDiffs.add(d); 1155 } 1156 1157 boolean isDeleted() { 1158 if (fAncestorPos != null && fAncestorPos.isDeleted()) 1159 return true; 1160 return fLeftPos.isDeleted() || fRightPos.isDeleted(); 1161 } 1162 1163 void setResolved(boolean r) { 1164 fResolved= r; 1165 if (r) 1166 fDiffs= null; 1167 } 1168 1169 boolean isResolved() { 1170 if (!fResolved && fDiffs != null) { 1171 Iterator e= fDiffs.iterator(); 1172 while (e.hasNext()) { 1173 Diff d= (Diff) e.next(); 1174 if (!d.isResolved()) 1175 return false; 1176 } 1177 return true; 1178 } 1179 return fResolved; 1180 } 1181 1182 1196 private boolean isIncomingOrConflicting() { 1197 switch (fDirection) { 1198 case RangeDifference.RIGHT: 1199 if (fLeftIsLocal) 1200 return true; 1201 break; 1202 case RangeDifference.LEFT: 1203 if (!fLeftIsLocal) 1204 return true; 1205 break; 1206 case RangeDifference.CONFLICT: 1207 return true; 1208 } 1209 return false; 1210 } 1211 1212 1218 private boolean isUnresolvedIncomingOrConflicting() { 1219 if (fResolved) 1220 return false; 1221 return isIncomingOrConflicting(); 1222 } 1223 1224 Position getPosition(MergeSourceViewer w) { 1225 if (w == fLeft) 1226 return fLeftPos; 1227 if (w == fRight) 1228 return fRightPos; 1229 if (w == fAncestor) 1230 return fAncestorPos; 1231 return null; 1232 } 1233 1234 1237 boolean overlaps(MergeSourceViewer w, int start, int end) { 1238 Position h= getPosition(w); 1239 if (h != null) { 1240 int ds= h.getOffset(); 1241 int de= ds + h.getLength(); 1242 if ((start < de) && (end >= ds)) 1243 return true; 1244 } 1245 return false; 1246 } 1247 1248 int getMaxDiffHeight() { 1249 Point region= new Point(0, 0); 1250 int h= fLeft.getLineRange(fLeftPos, region).y; 1251 if (isThreeWay()) 1252 h= Math.max(h, fAncestor.getLineRange(fAncestorPos, region).y); 1253 return Math.max(h, fRight.getLineRange(fRightPos, region).y); 1254 } 1255 1256 int getAncestorHeight() { 1257 Point region= new Point(0, 0); 1258 return fAncestor.getLineRange(fAncestorPos, region).y; 1259 } 1260 1261 int getLeftHeight() { 1262 Point region= new Point(0, 0); 1263 return fLeft.getLineRange(fLeftPos, region).y; 1264 } 1265 1266 int getRightHeight() { 1267 Point region= new Point(0, 0); 1268 return fRight.getLineRange(fRightPos, region).y; 1269 } 1270 1271 public Diff[] getChangeDiffs(MergeSourceViewer viewer, IRegion region) { 1272 if (fDiffs != null && intersectsRegion(viewer, region)) { 1273 List result = new ArrayList(); 1274 for (Iterator iterator = fDiffs.iterator(); iterator.hasNext();) { 1275 Diff diff = (Diff) iterator.next(); 1276 if (diff.intersectsRegion(viewer, region)) { 1277 result.add(diff); 1278 } 1279 } 1280 return (Diff[]) result.toArray(new Diff[result.size()]); 1281 } 1282 return new Diff[0]; 1283 } 1284 1285 private boolean intersectsRegion(MergeSourceViewer viewer, 1286 IRegion region) { 1287 Position p = getPosition(viewer); 1288 if (p != null) 1289 return p.overlapsWith(region.getOffset(), region.getLength()); 1290 return false; 1291 } 1292 1293 public StyleRange getStyleRange(MergeSourceViewer viewer, IRegion region) { 1294 Color cTextFill = getColor(null, getTextFillColor()); 1296 if (cTextFill == null) 1297 return null; 1298 Position p = getPosition(viewer); 1299 int start = p.getOffset(); 1300 int length = p.getLength(); 1301 if (start < region.getOffset()) { 1303 length = length - (region.getOffset() - start); 1304 start = region.getOffset(); 1305 } 1306 int regionEnd = region.getOffset() + region.getLength(); 1308 if (start + length > regionEnd) { 1309 length = regionEnd - start; 1310 } 1311 if (length < 0) 1312 return null; 1313 1314 return new StyleRange(start, length, null, cTextFill); 1315 } 1316 1317 private RGB getTextFillColor() { 1318 if (isThreeWay() && !isIgnoreAncestor()) { 1319 switch (fDirection) { 1320 case RangeDifference.RIGHT: 1321 if (fLeftIsLocal) 1322 return INCOMING_TEXT_FILL; 1323 return OUTGOING_TEXT_FILL; 1324 case RangeDifference.ANCESTOR: 1325 return CONFLICT_TEXT_FILL; 1326 case RangeDifference.LEFT: 1327 if (fLeftIsLocal) 1328 return OUTGOING_TEXT_FILL; 1329 return INCOMING_TEXT_FILL; 1330 case RangeDifference.CONFLICT: 1331 return CONFLICT_TEXT_FILL; 1332 } 1333 return null; 1334 } 1335 return OUTGOING_TEXT_FILL; 1336 } 1337 1338 public boolean hasChildren() { 1339 return fDiffs != null && !fDiffs.isEmpty(); 1340 } 1341 } 1342 1343 private class ChangeHighlighter implements ITextPresentationListener { 1344 1345 private final MergeSourceViewer viewer; 1346 1347 public ChangeHighlighter(MergeSourceViewer viewer) { 1348 this.viewer = viewer; 1349 } 1350 1351 1354 public void applyTextPresentation(TextPresentation textPresentation) { 1355 if (!fHighlightTokenChanges) 1356 return; 1357 IRegion region= textPresentation.getExtent(); 1358 Diff[] changeDiffs = getChangeDiffs(region); 1359 for (int i = 0; i < changeDiffs.length; i++) { 1360 Diff diff = changeDiffs[i]; 1361 StyleRange range = getStyleRange(diff, region); 1362 if (range != null) 1363 textPresentation.mergeStyleRange(range); 1364 } 1365 } 1366 1367 private StyleRange getStyleRange(Diff diff, IRegion region) { 1368 return diff.getStyleRange(viewer, region); 1369 } 1370 1371 private Diff[] getChangeDiffs(IRegion region) { 1372 if (fChangeDiffs == null) 1373 return new Diff[0]; 1374 List intersectingDiffs = new ArrayList(); 1375 for (Iterator iterator = fChangeDiffs.iterator(); iterator.hasNext();) { 1376 Diff diff = (Diff) iterator.next(); 1377 Diff[] changeDiffs = diff.getChangeDiffs(viewer, region); 1378 for (int i = 0; i < changeDiffs.length; i++) { 1379 Diff changeDiff = changeDiffs[i]; 1380 intersectingDiffs.add(changeDiff); 1381 } 1382 } 1383 return (Diff[]) intersectingDiffs.toArray(new Diff[intersectingDiffs.size()]); 1384 } 1385 1386 } 1387 1388 private class FindReplaceTarget implements IFindReplaceTarget { 1389 1390 public boolean canPerformFind() { 1391 return fFocusPart != null; 1392 } 1393 1394 public int findAndSelect(int widgetOffset, String findString, 1395 boolean searchForward, boolean caseSensitive, boolean wholeWord) { 1396 return fFocusPart.getFindReplaceTarget().findAndSelect(widgetOffset, findString, searchForward, caseSensitive, wholeWord); 1397 } 1398 1399 public Point getSelection() { 1400 return fFocusPart.getFindReplaceTarget().getSelection(); 1401 } 1402 1403 public String getSelectionText() { 1404 return fFocusPart.getFindReplaceTarget().getSelectionText(); 1405 } 1406 1407 public boolean isEditable() { 1408 return fFocusPart.getFindReplaceTarget().isEditable(); 1409 } 1410 1411 public void replaceSelection(String text) { 1412 fFocusPart.getFindReplaceTarget().replaceSelection(text); 1413 } 1414 1415 } 1416 1417 1419 1425 public TextMergeViewer(Composite parent, CompareConfiguration configuration) { 1426 this(parent, SWT.NULL, configuration); 1427 } 1428 1429 1436 public TextMergeViewer(Composite parent, int style, CompareConfiguration configuration) { 1437 super(style, ResourceBundle.getBundle(BUNDLE_NAME), configuration); 1438 1439 int inheritedStyle= parent.getStyle(); 1440 if ((inheritedStyle & SWT.LEFT_TO_RIGHT) != 0) 1441 fInheritedDirection= SWT.LEFT_TO_RIGHT; 1442 else if ((inheritedStyle & SWT.RIGHT_TO_LEFT) != 0) 1443 fInheritedDirection= SWT.RIGHT_TO_LEFT; 1444 else 1445 fInheritedDirection= SWT.NONE; 1446 1447 if ((style & SWT.LEFT_TO_RIGHT) != 0) 1448 fTextDirection= SWT.LEFT_TO_RIGHT; 1449 else if ((style & SWT.RIGHT_TO_LEFT) != 0) 1450 fTextDirection= SWT.RIGHT_TO_LEFT; 1451 else 1452 fTextDirection= SWT.NONE; 1453 1454 fSymbolicFontName= getClass().getName(); 1455 1456 String platform= SWT.getPlatform(); 1457 fIsMotif= "motif".equals(platform); fIsCarbon= "carbon".equals(platform); 1460 if (fIsMotif) 1461 fMarginWidth= 0; 1462 1463 Display display= parent.getDisplay(); 1464 1465 fPreferenceChangeListener= new IPropertyChangeListener() { 1466 public void propertyChange(PropertyChangeEvent event) { 1467 TextMergeViewer.this.handlePropertyChangeEvent(event); 1468 } 1469 }; 1470 1471 fPreferenceStore= getCompareConfiguration().getPreferenceStore(); 1472 if (fPreferenceStore != null) { 1473 fPreferenceStore.addPropertyChangeListener(fPreferenceChangeListener); 1474 1475 checkForColorUpdate(display); 1476 1477 fLeftIsLocal= Utilities.getBoolean(getCompareConfiguration(), "LEFT_IS_LOCAL", false); fSynchronizedScrolling= fPreferenceStore.getBoolean(ComparePreferencePage.SYNCHRONIZE_SCROLLING); 1479 fShowMoreInfo= fPreferenceStore.getBoolean(ComparePreferencePage.SHOW_MORE_INFO); 1480 fShowPseudoConflicts= fPreferenceStore.getBoolean(ComparePreferencePage.SHOW_PSEUDO_CONFLICTS); 1481 fUseSingleLine= fPreferenceStore.getBoolean(ComparePreferencePage.USE_SINGLE_LINE); 1483 fHighlightTokenChanges= fPreferenceStore.getBoolean(ComparePreferencePage.HIGHLIGHT_TOKEN_CHANGES); 1484 } 1486 1487 buildControl(parent); 1488 1489 INavigatable nav= new INavigatable() { 1490 public boolean selectChange(int flag) { 1491 if (flag == INavigatable.FIRST_CHANGE || flag == INavigatable.LAST_CHANGE) { 1492 selectFirstDiff(flag == INavigatable.FIRST_CHANGE); 1493 return false; 1494 } 1495 return navigate(flag == INavigatable.NEXT_CHANGE, false, false); 1496 } 1497 public Object getInput() { 1498 return TextMergeViewer.this.getInput(); 1499 } 1500 public boolean openSelectedChange() { 1501 return false; 1502 } 1503 public boolean hasChange(int flag) { 1504 return getNextVisibleDiff(flag == INavigatable.NEXT_CHANGE, false) != null; 1505 } 1506 }; 1507 fComposite.setData(INavigatable.NAVIGATOR_PROPERTY, nav); 1508 1509 fBirdsEyeCursor= new Cursor(parent.getDisplay(), SWT.CURSOR_HAND); 1510 1511 JFaceResources.getFontRegistry().addListener(fPreferenceChangeListener); 1512 JFaceResources.getColorRegistry().addListener(fPreferenceChangeListener); 1513 updateFont(); 1514 } 1515 1516 private void updateFont() { 1517 Font f= JFaceResources.getFont(fSymbolicFontName); 1518 if (f != null) { 1519 if (fAncestor != null) 1520 fAncestor.setFont(f); 1521 if (fLeft != null) 1522 fLeft.setFont(f); 1523 if (fRight != null) 1524 fRight.setFont(f); 1525 } 1526 } 1527 1528 private void checkForColorUpdate(Display display) { 1529 if (fPollSystemForeground) { 1530 RGB fg= display.getSystemColor(SWT.COLOR_LIST_FOREGROUND).getRGB(); 1531 if (fForeground == null || !fg.equals(fForeground)) { 1532 fForeground= fg; 1533 updateColors(display); 1534 } 1535 } 1536 if (fPollSystemBackground) { 1537 RGB bg= display.getSystemColor(SWT.COLOR_LIST_BACKGROUND).getRGB(); 1538 if (fBackground == null || !bg.equals(fBackground)) { 1539 fBackground= bg; 1540 updateColors(display); 1541 } 1542 } 1543 } 1544 1545 1551 public void setBackgroundColor(RGB background) { 1552 fPollSystemBackground= (background == null); 1553 fBackground= background; 1554 updateColors(null); 1555 } 1556 1557 private RGB getBackground(Display display) { 1558 if (fBackground != null) 1559 return fBackground; 1560 if (display == null) 1561 display= fComposite.getDisplay(); 1562 return display.getSystemColor(SWT.COLOR_LIST_BACKGROUND).getRGB(); 1563 } 1564 1565 1571 public void setForegroundColor(RGB foreground) { 1572 fPollSystemForeground= (foreground == null); 1573 fForeground= foreground; 1574 updateColors(null); 1575 } 1576 1577 private void updateColors(Display display) { 1578 1579 if (display == null) 1580 display= fComposite.getDisplay(); 1581 1582 Color color= null; 1583 if (fBackground != null) 1584 color= getColor(display, fBackground); 1585 1586 if (fAncestor != null) 1587 fAncestor.setBackgroundColor(color); 1588 if (fLeft != null) 1589 fLeft.setBackgroundColor(color); 1590 if (fRight != null) 1591 fRight.setBackgroundColor(color); 1592 1593 ColorRegistry registry= JFaceResources.getColorRegistry(); 1594 1595 RGB bg= getBackground(display); 1596 SELECTED_INCOMING= registry.getRGB(INCOMING_COLOR); 1597 if (SELECTED_INCOMING == null) 1598 SELECTED_INCOMING= new RGB(0, 0, 255); INCOMING= interpolate(SELECTED_INCOMING, bg, 0.6); 1600 INCOMING_FILL= interpolate(SELECTED_INCOMING, bg, 0.97); 1601 INCOMING_TEXT_FILL= interpolate(SELECTED_INCOMING, bg, 0.85); 1602 1603 SELECTED_OUTGOING= registry.getRGB(OUTGOING_COLOR); 1604 if (SELECTED_OUTGOING == null) 1605 SELECTED_OUTGOING= new RGB(0, 0, 0); OUTGOING= interpolate(SELECTED_OUTGOING, bg, 0.6); 1607 OUTGOING_FILL= interpolate(SELECTED_OUTGOING, bg, 0.97); 1608 OUTGOING_TEXT_FILL= interpolate(SELECTED_OUTGOING, bg, 0.85); 1609 1610 SELECTED_CONFLICT= registry.getRGB(CONFLICTING_COLOR); 1611 if (SELECTED_CONFLICT == null) 1612 SELECTED_CONFLICT= new RGB(255, 0, 0); CONFLICT= interpolate(SELECTED_CONFLICT, bg, 0.6); 1614 CONFLICT_FILL= interpolate(SELECTED_CONFLICT, bg, 0.97); 1615 CONFLICT_TEXT_FILL= interpolate(SELECTED_CONFLICT, bg, 0.85); 1616 1617 RESOLVED= registry.getRGB(RESOLVED_COLOR); 1618 if (RESOLVED == null) 1619 RESOLVED= new RGB(0, 255, 0); 1621 updatePresentation(display); 1622 } 1623 1624 private void updatePresentation(Display display) { 1625 if (display == null) 1626 display= fComposite.getDisplay(); 1627 refreshBirdsEyeView(); 1628 invalidateLines(); 1629 updateAllDiffBackgrounds(display); 1630 invalidateTextPresentation(); 1631 } 1632 1633 1637 public void invalidateTextPresentation() { 1638 if (fAncestor != null) 1639 fAncestor.invalidateTextPresentation(); 1640 if (fLeft != null) 1641 fLeft.invalidateTextPresentation(); 1642 if (fRight != null) 1643 fRight.invalidateTextPresentation(); 1644 } 1645 1646 1657 protected void configureTextViewer(TextViewer textViewer) { 1658 if(textViewer instanceof MergeSourceViewer){ 1661 SourceViewerConfiguration configuration= new SourceViewerConfiguration(); 1662 ((MergeSourceViewer)textViewer).configure(configuration); 1663 } 1664 } 1665 1666 1675 protected ITokenComparator createTokenComparator(String line) { 1676 return new TokenComparator(line); 1677 } 1678 1679 1690 protected void setupDocument(IDocument document) { 1691 String partitioning = getDocumentPartitioning(); 1692 if (partitioning == null || !(document instanceof IDocumentExtension3)) { 1693 if (document.getDocumentPartitioner() == null) { 1694 IDocumentPartitioner partitioner= getDocumentPartitioner(); 1695 if (partitioner != null) { 1696 document.setDocumentPartitioner(partitioner); 1697 partitioner.connect(document); 1698 } 1699 } 1700 } else { 1701 IDocumentExtension3 ex3 = (IDocumentExtension3) document; 1702 if (ex3.getDocumentPartitioner(partitioning) == null) { 1703 IDocumentPartitioner partitioner= getDocumentPartitioner(); 1704 if (partitioner != null) { 1705 ex3.setDocumentPartitioner(partitioning, partitioner); 1706 partitioner.connect(document); 1707 } 1708 } 1709 } 1710 } 1711 1712 1726 protected IDocumentPartitioner getDocumentPartitioner() { 1727 return null; 1728 } 1729 1730 1743 protected String getDocumentPartitioning() { 1744 return null; 1745 } 1746 1747 1753 protected void handleDispose(DisposeEvent event) { 1754 1755 if (fHandlerService != null) 1756 fHandlerService.dispose(); 1757 1758 Object input= getInput(); 1759 removeFromDocumentManager(ANCESTOR_CONTRIBUTOR, input); 1760 removeFromDocumentManager(LEFT_CONTRIBUTOR, input); 1761 removeFromDocumentManager(RIGHT_CONTRIBUTOR, input); 1762 1763 if (DEBUG) 1764 DocumentManager.dump(); 1765 1766 if (fPreferenceChangeListener != null) { 1767 JFaceResources.getFontRegistry().removeListener(fPreferenceChangeListener); 1768 JFaceResources.getColorRegistry().removeListener(fPreferenceChangeListener); 1769 if (fPreferenceStore != null) 1770 fPreferenceStore.removePropertyChangeListener(fPreferenceChangeListener); 1771 fPreferenceChangeListener= null; 1772 } 1773 1774 fLeftCanvas= null; 1775 fRightCanvas= null; 1776 fVScrollBar= null; 1777 fBirdsEyeCanvas= null; 1778 fSummaryHeader= null; 1779 1780 fAncestorContributor.unsetDocument(fAncestor); 1781 fLeftContributor.unsetDocument(fLeft); 1782 fRightContributor.unsetDocument(fRight); 1783 1784 disconnect(fLeftContributor); 1785 disconnect(fRightContributor); 1786 disconnect(fAncestorContributor); 1787 1788 if (fColors != null) { 1789 Iterator i= fColors.values().iterator(); 1790 while (i.hasNext()) { 1791 Color color= (Color) i.next(); 1792 if (!color.isDisposed()) 1793 color.dispose(); 1794 } 1795 fColors= null; 1796 } 1797 1798 if (fBirdsEyeCursor != null) { 1799 fBirdsEyeCursor.dispose(); 1800 fBirdsEyeCursor= null; 1801 } 1802 1803 if (showWhitespaceAction != null) 1804 showWhitespaceAction.dispose(); 1805 1806 if (toggleLineNumbersAction != null) 1807 toggleLineNumbersAction.dispose(); 1808 1809 if (fIgnoreWhitespace != null) 1810 fIgnoreWhitespace.dispose(); 1811 1812 super.handleDispose(event); 1813 } 1814 1815 private void disconnect(ContributorInfo legInfo) { 1816 if (legInfo != null) 1817 legInfo.disconnect(); 1818 } 1819 1820 1824 1828 protected void createControls(Composite composite) { 1829 1830 PlatformUI.getWorkbench().getHelpSystem().setHelp(composite, ICompareContextIds.TEXT_MERGE_VIEW); 1831 1832 if (fMarginWidth > 0) { 1834 fAncestorCanvas= new BufferedCanvas(composite, SWT.NONE) { 1835 public void doPaint(GC gc) { 1836 paintSides(gc, fAncestor, fAncestorCanvas, false); 1837 } 1838 }; 1839 fAncestorCanvas.addMouseListener( 1840 new MouseAdapter() { 1841 public void mouseDown(MouseEvent e) { 1842 setCurrentDiff2(handleMouseInSides(fAncestorCanvas, fAncestor, e.y), false); 1843 } 1844 } 1845 ); 1846 } 1847 1848 fAncestor= createPart(composite); 1849 fAncestor.setEditable(false); 1850 fAncestor.getTextWidget().getAccessible().addAccessibleListener(new AccessibleAdapter() { 1851 public void getName(AccessibleEvent e) { 1852 e.result = NLS.bind(CompareMessages.TextMergeViewer_accessible_ancestor, getCompareConfiguration().getAncestorLabel(getInput())); 1853 } 1854 }); 1855 fAncestor.addTextPresentationListener(new ChangeHighlighter(fAncestor)); 1856 1857 fSummaryHeader= new Canvas(composite, SWT.NONE); 1858 fHeaderPainter= new HeaderPainter(); 1859 fSummaryHeader.addPaintListener(fHeaderPainter); 1860 updateResolveStatus(); 1861 1862 if (fMarginWidth > 0) { 1864 fLeftCanvas= new BufferedCanvas(composite, SWT.NONE) { 1865 public void doPaint(GC gc) { 1866 paintSides(gc, fLeft, fLeftCanvas, false); 1867 } 1868 }; 1869 fLeftCanvas.addMouseListener( 1870 new MouseAdapter() { 1871 public void mouseDown(MouseEvent e) { 1872 setCurrentDiff2(handleMouseInSides(fLeftCanvas, fLeft, e.y), false); 1873 } 1874 } 1875 ); 1876 } 1877 1878 fLeft= createPart(composite); 1879 fLeft.getTextWidget().getVerticalBar().setVisible(!fSynchronizedScrolling); 1880 fLeft.addAction(MergeSourceViewer.SAVE_ID, fLeftSaveAction); 1881 fLeft.getTextWidget().getAccessible().addAccessibleListener(new AccessibleAdapter() { 1882 public void getName(AccessibleEvent e) { 1883 e.result = NLS.bind(CompareMessages.TextMergeViewer_accessible_left, getCompareConfiguration().getLeftLabel(getInput())); 1884 } 1885 }); 1886 fLeft.addTextPresentationListener(new ChangeHighlighter(fLeft)); 1887 1888 fRight= createPart(composite); 1889 fRight.getTextWidget().getVerticalBar().setVisible(!fSynchronizedScrolling); 1890 fRight.addAction(MergeSourceViewer.SAVE_ID, fRightSaveAction); 1891 fRight.getTextWidget().getAccessible().addAccessibleListener(new AccessibleAdapter() { 1892 public void getName(AccessibleEvent e) { 1893 e.result = NLS.bind(CompareMessages.TextMergeViewer_accessible_right, getCompareConfiguration().getRightLabel(getInput())); 1894 } 1895 }); 1896 fRight.addTextPresentationListener(new ChangeHighlighter(fRight)); 1897 1898 hsynchViewport(fAncestor, fLeft, fRight); 1899 hsynchViewport(fLeft, fAncestor, fRight); 1900 hsynchViewport(fRight, fAncestor, fLeft); 1901 1902 if (fMarginWidth > 0) { 1903 fRightCanvas= new BufferedCanvas(composite, SWT.NONE) { 1904 public void doPaint(GC gc) { 1905 paintSides(gc, fRight, fRightCanvas, fSynchronizedScrolling); 1906 } 1907 }; 1908 fRightCanvas.addMouseListener( 1909 new MouseAdapter() { 1910 public void mouseDown(MouseEvent e) { 1911 setCurrentDiff2(handleMouseInSides(fRightCanvas, fRight, e.y), false); 1912 } 1913 } 1914 ); 1915 } 1916 1917 fScrollCanvas= new Canvas(composite, SWT.V_SCROLL); 1918 Rectangle trim= fLeft.getTextWidget().computeTrim(0, 0, 0, 0); 1919 fTopInset= trim.y; 1920 1921 fVScrollBar= fScrollCanvas.getVerticalBar(); 1922 fVScrollBar.setIncrement(1); 1923 fVScrollBar.setVisible(true); 1924 fVScrollBar.addListener(SWT.Selection, 1925 new Listener() { 1926 public void handleEvent(Event e) { 1927 int vpos= ((ScrollBar)e.widget).getSelection(); 1928 synchronizedScrollVertical(vpos); 1929 } 1930 } 1931 ); 1932 1933 fBirdsEyeCanvas= new BufferedCanvas(composite, SWT.NONE) { 1934 public void doPaint(GC gc) { 1935 paintBirdsEyeView(this, gc); 1936 } 1937 }; 1938 fBirdsEyeCanvas.addMouseListener( 1939 new MouseAdapter() { 1940 public void mouseDown(MouseEvent e) { 1941 setCurrentDiff2(handlemouseInBirdsEyeView(fBirdsEyeCanvas, e.y), true); 1942 } 1943 } 1944 ); 1945 fBirdsEyeCanvas.addMouseMoveListener( 1946 new MouseMoveListener() { 1947 1948 private Cursor fLastCursor; 1949 1950 public void mouseMove(MouseEvent e) { 1951 Cursor cursor= null; 1952 Diff diff= handlemouseInBirdsEyeView(fBirdsEyeCanvas, e.y); 1953 if (diff != null && diff.fDirection != RangeDifference.NOCHANGE) 1954 cursor= fBirdsEyeCursor; 1955 if (fLastCursor != cursor) { 1956 fBirdsEyeCanvas.setCursor(cursor); 1957 fLastCursor= cursor; 1958 } 1959 } 1960 } 1961 ); 1962 } 1963 1964 private void hsynchViewport(final TextViewer tv1, final TextViewer tv2, final TextViewer tv3) { 1965 final StyledText st1= tv1.getTextWidget(); 1966 final StyledText st2= tv2.getTextWidget(); 1967 final StyledText st3= tv3.getTextWidget(); 1968 final ScrollBar sb1= st1.getHorizontalBar(); 1969 sb1.addSelectionListener(new SelectionAdapter() { 1970 public void widgetSelected(SelectionEvent e) { 1971 if (fSynchronizedScrolling) { 1972 int max= sb1.getMaximum()-sb1.getThumb(); 1973 double v= 0.0; 1974 if (max > 0) 1975 v= (float)sb1.getSelection() / (float)max; 1976 if (st2.isVisible()) { 1977 ScrollBar sb2= st2.getHorizontalBar(); 1978 st2.setHorizontalPixel((int)((sb2.getMaximum()-sb2.getThumb()) * v)); 1979 } 1980 if (st3.isVisible()) { 1981 ScrollBar sb3= st3.getHorizontalBar(); 1982 st3.setHorizontalPixel((int)((sb3.getMaximum()-sb3.getThumb()) * v)); 1983 } 1984 workaround65205(); 1985 } 1986 } 1987 }); 1988 } 1989 1990 1995 private void workaround65205() { 1996 if (fIsCarbon && fComposite != null && !fComposite.isDisposed()) 1997 fComposite.getDisplay().update(); 1998 } 1999 2000 private void setCurrentDiff2(Diff diff, boolean reveal) { 2001 if (diff != null && diff.fDirection != RangeDifference.NOCHANGE) { 2002 setCurrentDiff(diff, reveal); 2004 } 2005 } 2006 2007 private Diff handleMouseInSides(Canvas canvas, MergeSourceViewer tp, int my) { 2008 2009 int lineHeight= tp.getTextWidget().getLineHeight(); 2010 int visibleHeight= tp.getViewportHeight(); 2011 2012 if (! fHighlightRanges) 2013 return null; 2014 2015 if (fChangeDiffs != null) { 2016 int shift= tp.getVerticalScrollOffset() + (2-LW); 2017 2018 Point region= new Point(0, 0); 2019 Iterator e= fChangeDiffs.iterator(); 2020 while (e.hasNext()) { 2021 Diff diff= (Diff) e.next(); 2022 if (diff.isDeleted()) 2023 continue; 2024 2025 if (fShowCurrentOnly2 && !isCurrentDiff(diff)) 2026 continue; 2027 2028 tp.getLineRange(diff.getPosition(tp), region); 2029 int y= (region.x * lineHeight) + shift; 2030 int h= region.y * lineHeight; 2031 2032 if (y+h < 0) 2033 continue; 2034 if (y >= visibleHeight) 2035 break; 2036 2037 if (my >= y && my < y+h) 2038 return diff; 2039 } 2040 } 2041 return null; 2042 } 2043 2044 private Diff getDiffUnderMouse(Canvas canvas, int mx, int my, Rectangle r) { 2045 2046 if (! fSynchronizedScrolling) 2047 return null; 2048 2049 int lineHeight= fLeft.getTextWidget().getLineHeight(); 2050 int visibleHeight= fRight.getViewportHeight(); 2051 2052 Point size= canvas.getSize(); 2053 int w= size.x; 2054 2055 if (! fHighlightRanges) 2056 return null; 2057 2058 if (fChangeDiffs != null) { 2059 int lshift= fLeft.getVerticalScrollOffset(); 2060 int rshift= fRight.getVerticalScrollOffset(); 2061 2062 Point region= new Point(0, 0); 2063 2064 Iterator e= fChangeDiffs.iterator(); 2065 while (e.hasNext()) { 2066 Diff diff= (Diff) e.next(); 2067 if (diff.isDeleted()) 2068 continue; 2069 2070 if (fShowCurrentOnly2 && !isCurrentDiff(diff)) 2071 continue; 2072 2073 fLeft.getLineRange(diff.fLeftPos, region); 2074 int ly= (region.x * lineHeight) + lshift; 2075 int lh= region.y * lineHeight; 2076 2077 fRight.getLineRange(diff.fRightPos, region); 2078 int ry= (region.x * lineHeight) + rshift; 2079 int rh= region.y * lineHeight; 2080 2081 if (Math.max(ly+lh, ry+rh) < 0) 2082 continue; 2083 if (Math.min(ly, ry) >= visibleHeight) 2084 break; 2085 2086 int cx= (w-RESOLVE_SIZE)/2; 2087 int cy= ((ly+lh/2) + (ry+rh/2) - RESOLVE_SIZE)/2; 2088 if (my >= cy && my < cy+RESOLVE_SIZE && mx >= cx && mx < cx+RESOLVE_SIZE) { 2089 if (r != null) { 2090 int SIZE= fIsCarbon ? 30 : 20; 2091 r.x= cx+(RESOLVE_SIZE-SIZE)/2; 2092 r.y= cy+(RESOLVE_SIZE-SIZE)/2; 2093 r.width= SIZE; 2094 r.height= SIZE; 2095 } 2096 return diff; 2097 } 2098 } 2099 } 2100 return null; 2101 } 2102 2103 private Diff handlemouseInBirdsEyeView(Canvas canvas, int my) { 2104 int yy, hh; 2105 2106 Point size= canvas.getSize(); 2107 2108 int virtualHeight= fSynchronizedScrolling ? getVirtualHeight() : getRightHeight(); 2109 if (virtualHeight < getViewportHeight()) 2110 return null; 2111 2112 int y= 0; 2113 if (fAllDiffs != null) { 2114 Iterator e= fAllDiffs.iterator(); 2115 for (int i= 0; e.hasNext(); i++) { 2116 Diff diff= (Diff) e.next(); 2117 int h= fSynchronizedScrolling ? diff.getMaxDiffHeight() 2118 : diff.getRightHeight(); 2119 if (useChange(diff.fDirection) && !diff.fIsWhitespace) { 2120 2121 yy= (y*size.y)/virtualHeight; 2122 hh= (h*size.y)/virtualHeight; 2123 if (hh < 3) 2124 hh= 3; 2125 2126 if (my >= yy && my < yy+hh) 2127 return diff; 2128 } 2129 y+= h; 2130 } 2131 } 2132 return null; 2133 } 2134 2135 private void paintBirdsEyeView(Canvas canvas, GC gc) { 2136 2137 Color c; 2138 Rectangle r= new Rectangle(0, 0, 0, 0); 2139 int yy, hh; 2140 2141 Point size= canvas.getSize(); 2142 2143 int virtualHeight= fSynchronizedScrolling ? getVirtualHeight() : getRightHeight(); 2144 if (virtualHeight < getViewportHeight()) 2145 return; 2146 2147 Display display= canvas.getDisplay(); 2148 int y= 0; 2149 if (fAllDiffs != null) { 2150 Iterator e= fAllDiffs.iterator(); 2151 for (int i= 0; e.hasNext(); i++) { 2152 Diff diff= (Diff) e.next(); 2153 int h= fSynchronizedScrolling ? diff.getMaxDiffHeight() 2154 : diff.getRightHeight(); 2155 2156 if (useChange(diff.fDirection) && !diff.fIsWhitespace) { 2157 2158 yy= (y*size.y)/virtualHeight; 2159 hh= (h*size.y)/virtualHeight; 2160 if (hh < 3) 2161 hh= 3; 2162 2163 c= getColor(display, getFillColor(diff)); 2164 if (c != null) { 2165 gc.setBackground(c); 2166 gc.fillRectangle(BIRDS_EYE_VIEW_INSET, yy, size.x-(2*BIRDS_EYE_VIEW_INSET),hh); 2167 } 2168 c= getColor(display, getStrokeColor(diff)); 2169 if (c != null) { 2170 gc.setForeground(c); 2171 r.x= BIRDS_EYE_VIEW_INSET; 2172 r.y= yy; 2173 r.width= size.x-(2*BIRDS_EYE_VIEW_INSET)-1; 2174 r.height= hh; 2175 if (diff == fCurrentDiff || 2176 (fCurrentDiff != null && diff == fCurrentDiff.fParent)) { 2177 gc.setLineWidth(2); 2178 r.x++; 2179 r.y++; 2180 r.width--; 2181 r.height--; 2182 } else { 2183 gc.setLineWidth(0 ); 2184 } 2185 gc.drawRectangle(r); 2186 } 2187 } 2188 2189 y+= h; 2190 } 2191 } 2192 } 2193 2194 private void refreshBirdsEyeView() { 2195 if (fBirdsEyeCanvas != null) 2196 fBirdsEyeCanvas.redraw(); 2197 } 2198 2199 2205 protected boolean handleSetFocus() { 2206 if (fFocusPart == null) { 2207 if (fLeft != null && fLeft.getEnabled()) { 2208 fFocusPart= fLeft; 2209 } else if (fRight != null && fRight.getEnabled()) { 2210 fFocusPart= fRight; 2211 } else if (fAncestor != null && fAncestor.getEnabled()) { 2212 fFocusPart= fAncestor; 2213 } 2214 } 2215 if (fFocusPart != null) { 2216 StyledText st= fFocusPart.getTextWidget(); 2217 if (st != null) 2218 return st.setFocus(); 2219 } 2220 return false; } 2222 2223 2224 class HoverResizer extends Resizer { 2225 Canvas fCanvas; 2226 public HoverResizer(Canvas c, int dir) { 2227 super(c, dir); 2228 fCanvas= c; 2229 } 2230 public void mouseMove(MouseEvent e) { 2231 if (!fIsDown && fUseSingleLine && showResolveUI() && handleMouseMoveOverCenter(fCanvas, e.x, e.y)) 2232 return; 2233 super.mouseMove(e); 2234 } 2235 } 2236 2237 2240 protected final Control createCenterControl(Composite parent) { 2241 if (fSynchronizedScrolling) { 2242 final Canvas canvas= new BufferedCanvas(parent, SWT.NONE) { 2243 public void doPaint(GC gc) { 2244 paintCenter(this, gc); 2245 } 2246 }; 2247 if (fUseResolveUI) { 2248 2249 new HoverResizer(canvas, HORIZONTAL); 2250 2251 fCenterButton= new Button(canvas, fIsCarbon ? SWT.FLAT : SWT.PUSH); 2252 if (fNormalCursor == null) fNormalCursor= new Cursor(canvas.getDisplay(), SWT.CURSOR_ARROW); 2253 fCenterButton.setCursor(fNormalCursor); 2254 fCenterButton.setText(COPY_RIGHT_TO_LEFT_INDICATOR); 2255 fCenterButton.pack(); 2256 fCenterButton.setVisible(false); 2257 fCenterButton.addSelectionListener( 2258 new SelectionAdapter() { 2259 public void widgetSelected(SelectionEvent e) { 2260 fCenterButton.setVisible(false); 2261 if (fButtonDiff != null) { 2262 setCurrentDiff(fButtonDiff, false); 2263 copy(fCurrentDiff, 2264 fCenterButton.getText().equals(COPY_LEFT_TO_RIGHT_INDICATOR), 2265 fCurrentDiff.fDirection != RangeDifference.CONFLICT); 2266 } 2267 } 2268 } 2269 ); 2270 } else { 2271 new Resizer(canvas, HORIZONTAL); 2272 } 2273 2274 return canvas; 2275 } 2276 return super.createCenterControl(parent); 2277 } 2278 2279 private boolean handleMouseMoveOverCenter(Canvas canvas, int x, int y) { 2280 Rectangle r= new Rectangle(0, 0, 0, 0); 2281 Diff diff= getDiffUnderMouse(canvas, x, y, r); 2282 if (diff != null && !diff.isUnresolvedIncomingOrConflicting()) 2283 diff= null; 2284 if (diff != fButtonDiff) { 2285 if (diff != null) { 2286 if (fLeft.isEditable()) { 2287 fButtonDiff= diff; 2288 fCenterButton.setText(COPY_RIGHT_TO_LEFT_INDICATOR); 2289 String tt= fCopyDiffRightToLeftItem.getAction().getToolTipText(); 2290 fCenterButton.setToolTipText(tt); 2291 fCenterButton.setBounds(r); 2292 fCenterButton.setVisible(true); 2293 } else if (fRight.isEditable()) { 2294 fButtonDiff= diff; 2295 fCenterButton.setText(COPY_LEFT_TO_RIGHT_INDICATOR); 2296 String tt= fCopyDiffLeftToRightItem.getAction().getToolTipText(); 2297 fCenterButton.setToolTipText(tt); 2298 fCenterButton.setBounds(r); 2299 fCenterButton.setVisible(true); 2300 } else 2301 fButtonDiff= null; 2302 } else { 2303 fCenterButton.setVisible(false); 2304 fButtonDiff= null; 2305 } 2306 } 2307 return fButtonDiff != null; 2308 } 2309 2310 2313 protected final int getCenterWidth() { 2314 if (fSynchronizedScrolling) 2315 return CENTER_WIDTH; 2316 return super.getCenterWidth(); 2317 } 2318 2319 private int getDirection() { 2320 switch (fTextDirection) { 2321 case SWT.LEFT_TO_RIGHT: 2322 case SWT.RIGHT_TO_LEFT: 2323 if (fInheritedDirection == fTextDirection) 2324 return SWT.NONE; 2325 return fTextDirection; 2326 } 2327 return fInheritedDirection; 2328 } 2329 2330 2333 private MergeSourceViewer createPart(Composite parent) { 2334 2335 final MergeSourceViewer part= new MergeSourceViewer(parent, getDirection(), getResourceBundle(), getCompareConfiguration().getContainer()); 2336 final StyledText te= part.getTextWidget(); 2337 2338 if (!fConfirmSave) 2339 part.hideSaveAction(); 2340 2341 te.addPaintListener( 2342 new PaintListener() { 2343 public void paintControl(PaintEvent e) { 2344 paint(e, part); 2345 } 2346 } 2347 ); 2348 te.addKeyListener( 2349 new KeyAdapter() { 2350 public void keyPressed(KeyEvent e) { 2351 handleSelectionChanged(part); 2352 } 2353 } 2354 ); 2355 te.addMouseListener( 2356 new MouseAdapter() { 2357 public void mouseDown(MouseEvent e) { 2358 handleSelectionChanged(part); 2360 } 2361 } 2362 ); 2363 2364 te.addFocusListener( 2365 new FocusAdapter() { 2366 public void focusGained(FocusEvent fe) { 2367 fFocusPart= part; 2368 connectGlobalActions(fFocusPart); 2369 } 2370 public void focusLost(FocusEvent fe) { 2371 connectGlobalActions(null); 2372 } 2373 } 2374 ); 2375 2376 part.addViewportListener( 2377 new IViewportListener() { 2378 public void viewportChanged(int verticalPosition) { 2379 syncViewport(part); 2380 } 2381 } 2382 ); 2383 2384 Font font= JFaceResources.getFont(fSymbolicFontName); 2385 if (font != null) 2386 te.setFont(font); 2387 2388 if (fBackground != null) te.setBackground(getColor(parent.getDisplay(), fBackground)); 2390 2391 contributeFindAction(part); 2393 2394 configureTextViewer(part); 2395 2396 return part; 2397 } 2398 2399 private void contributeFindAction(MergeSourceViewer viewer) { 2400 IAction action; 2401 IWorkbenchPart wp = getCompareConfiguration().getContainer().getWorkbenchPart(); 2402 if (wp != null) 2403 action = new FindReplaceAction(getResourceBundle(), "Editor.FindReplace.", wp); else 2405 action = new FindReplaceAction(getResourceBundle(), "Editor.FindReplace.", viewer.getControl().getShell(), getFindReplaceTarget()); action.setActionDefinitionId(IWorkbenchActionDefinitionIds.FIND_REPLACE); 2407 viewer.addAction(MergeSourceViewer.FIND_ID, action); 2408 } 2409 2410 private void connectGlobalActions(final MergeSourceViewer part) { 2411 if (fHandlerService != null) { 2412 if (part != null) 2413 part.updateActions(); 2414 fHandlerService.updatePaneActionHandlers(new Runnable () { 2415 public void run() { 2416 for (int i= 0; i < GLOBAL_ACTIONS.length; i++) { 2417 IAction action= null; 2418 if (part != null) { 2419 action= part.getAction(TEXT_ACTIONS[i]); 2420 if (action == null && TEXT_ACTIONS[i].equals(MergeSourceViewer.SAVE_ID)) { 2421 if (part == fLeft) 2422 action= fLeftSaveAction; 2423 else 2424 action= fRightSaveAction; 2425 } 2426 } 2427 fHandlerService.setGlobalActionHandler(GLOBAL_ACTIONS[i], action); 2428 } 2429 } 2430 }); 2431 } 2432 } 2433 2434 private IDocument getElementDocument(char type, Object element) { 2435 if (element instanceof IDocument) { 2436 return (IDocument) element; 2437 } 2438 ITypedElement te= Utilities.getLeg(type, element); 2439 IDocument document = null; 2441 switch (type) { 2442 case ANCESTOR_CONTRIBUTOR: 2443 document = getDocument(te, fAncestorContributor); 2444 break; 2445 case LEFT_CONTRIBUTOR: 2446 document = getDocument(te, fLeftContributor); 2447 break; 2448 case RIGHT_CONTRIBUTOR: 2449 document = getDocument(te, fRightContributor); 2450 break; 2451 } 2452 if (document != null) 2453 return document; 2454 return Utilities.getDocument(type, element, isUsingDefaultContentProvider(), canHaveSharedDocument()); 2456 } 2457 2458 private boolean isUsingDefaultContentProvider() { 2459 return getContentProvider() instanceof MergeViewerContentProvider; 2460 } 2461 2462 private boolean canHaveSharedDocument() { 2463 return getDocumentPartitioning() != null 2464 || getDocumentPartitioner() == null; 2465 } 2466 2467 private IDocument getDocument(ITypedElement te, ContributorInfo info) { 2468 if (info != null && info.getElement() == te) 2469 return info.getDocument(); 2470 return null; 2471 } 2472 2473 IDocument getDocument(char type, Object input) { 2474 IDocument doc= getElementDocument(type, input); 2475 if (doc != null) 2476 return doc; 2477 2478 if (input instanceof IDiffElement) { 2479 IDiffContainer parent= ((IDiffElement)input).getParent(); 2480 return getElementDocument(type, parent); 2481 } 2482 return null; 2483 } 2484 2485 2488 boolean sameDoc(char type, Object newInput, Object oldInput) { 2489 IDocument newDoc= getDocument(type, newInput); 2490 IDocument oldDoc= getDocument(type, oldInput); 2491 return newDoc == oldDoc; 2492 } 2493 2494 2501 protected boolean doSave(Object newInput, Object oldInput) { 2502 if (oldInput != null && newInput != null) { 2504 if (sameDoc(ANCESTOR_CONTRIBUTOR, newInput, oldInput) && 2506 sameDoc(LEFT_CONTRIBUTOR, newInput, oldInput) && 2507 sameDoc(RIGHT_CONTRIBUTOR, newInput, oldInput)) { 2508 if (DEBUG) System.out.println("----- Same docs !!!!"); return false; 2510 } 2511 } 2512 2513 if (DEBUG) System.out.println("***** New docs !!!!"); 2515 removeFromDocumentManager(ANCESTOR_CONTRIBUTOR, oldInput); 2516 removeFromDocumentManager(LEFT_CONTRIBUTOR, oldInput); 2517 removeFromDocumentManager(RIGHT_CONTRIBUTOR, oldInput); 2518 2519 if (DEBUG) 2520 DocumentManager.dump(); 2521 2522 return super.doSave(newInput, oldInput); 2523 } 2524 2525 private void removeFromDocumentManager(char leg, Object oldInput) { 2526 IDocument document= getDocument(leg, oldInput); 2527 if (document != null) 2528 DocumentManager.remove(document); 2529 } 2530 2531 private ITypedElement getParent(char type) { 2532 Object input= getInput(); 2533 if (input instanceof IDiffElement) { 2534 IDiffContainer parent= ((IDiffElement)input).getParent(); 2535 return Utilities.getLeg(type, parent); 2536 } 2537 return null; 2538 } 2539 2540 2544 protected void updateContent(Object ancestor, Object left, Object right) { 2545 2546 boolean emptyInput= (ancestor == null && left == null && right == null); 2547 2548 Object input= getInput(); 2549 2550 Position leftRange= null; 2551 Position rightRange= null; 2552 2553 if (FIX_47640 && !emptyInput && (left == null || right == null)) { 2555 if (input instanceof IDiffElement) { 2556 IDiffContainer parent= ((IDiffElement)input).getParent(); 2557 if (parent instanceof ICompareInput) { 2558 ICompareInput ci= (ICompareInput) parent; 2559 2560 if (ci.getAncestor() instanceof IDocumentRange 2561 || ci.getLeft() instanceof IDocumentRange 2562 || ci.getRight() instanceof IDocumentRange) { 2563 2564 if (left instanceof IDocumentRange) 2565 leftRange= ((IDocumentRange)left).getRange(); 2566 if (right instanceof IDocumentRange) 2567 rightRange= ((IDocumentRange)right).getRange(); 2568 2569 ancestor= ci.getAncestor(); 2570 left= ci.getLeft(); 2571 right= ci.getRight(); 2572 } 2573 } 2574 } 2575 } 2576 2577 int n= 0; 2578 if (left != null) 2579 n++; 2580 if (right != null) 2581 n++; 2582 fHighlightRanges= n > 1; 2583 2584 resetDiffs(); 2585 fHasErrors= false; 2587 CompareConfiguration cc= getCompareConfiguration(); 2588 IMergeViewerContentProvider cp= getMergeContentProvider(); 2589 2590 if (cp instanceof MergeViewerContentProvider) { 2591 MergeViewerContentProvider mcp= (MergeViewerContentProvider) cp; 2592 mcp.setAncestorError(null); 2593 mcp.setLeftError(null); 2594 mcp.setRightError(null); 2595 } 2596 2597 ContributorInfo oldLeftContributor = fLeftContributor; 2600 ContributorInfo oldRightContributor = fRightContributor; 2601 ContributorInfo oldAncestorContributor = fAncestorContributor; 2602 2603 fLeftContributor = createLegInfoFor(left, LEFT_CONTRIBUTOR); 2605 fRightContributor = createLegInfoFor(right, RIGHT_CONTRIBUTOR); 2606 fAncestorContributor = createLegInfoFor(ancestor, ANCESTOR_CONTRIBUTOR); 2607 2608 fLeftContributor.transferContributorStateFrom(oldLeftContributor); 2609 fRightContributor.transferContributorStateFrom(oldRightContributor); 2610 fAncestorContributor.transferContributorStateFrom(oldAncestorContributor); 2611 2612 disconnect(oldLeftContributor); 2614 disconnect(oldRightContributor); 2615 disconnect(oldAncestorContributor); 2616 2617 fLeftContributor.setEncodingIfAbsent(fRightContributor); 2620 fRightContributor.setEncodingIfAbsent(fLeftContributor); 2621 fAncestorContributor.setEncodingIfAbsent(fLeftContributor); 2622 2623 fLeftContributor.setDocument(fLeft, cc.isLeftEditable() && cp.isLeftEditable(input)); 2625 fLeftLineCount= fLeft.getLineCount(); 2626 2627 fRightContributor.setDocument(fRight, cc.isRightEditable() && cp.isRightEditable(input)); 2628 fRightLineCount= fRight.getLineCount(); 2629 2630 fAncestorContributor.setDocument(fAncestor, false); 2631 2632 if (isPatchHunk()){ 2634 setSyncScrolling(false); 2635 } else { 2636 setSyncScrolling(fPreferenceStore.getBoolean(ComparePreferencePage.SYNCHRONIZE_SCROLLING)); 2637 } 2638 2639 update(false); 2640 2641 if (!fHasErrors && !emptyInput && !fComposite.isDisposed()) { 2642 if (isRefreshing()) { 2643 fLeftContributor.updateSelection(fLeft, !fSynchronizedScrolling); 2644 fRightContributor.updateSelection(fRight, !fSynchronizedScrolling); 2645 fAncestorContributor.updateSelection(fAncestor, !fSynchronizedScrolling); 2646 if (fSynchronizedScrolling && fSynchronziedScrollPosition != -1) { 2647 synchronizedScrollVertical(fSynchronziedScrollPosition); 2648 } 2649 } else { 2650 if (isPatchHunk()) { 2651 if (right != null && Utilities.getAdapter(right, IHunk.class) != null) 2652 fLeft.setTopIndex(getHunkStart()); 2653 else 2654 fRight.setTopIndex(getHunkStart()); 2655 } else { 2656 Diff selectDiff= null; 2657 if (FIX_47640) { 2658 if (leftRange != null) 2659 selectDiff= findDiff(LEFT_CONTRIBUTOR, leftRange); 2660 else if (rightRange != null) 2661 selectDiff= findDiff(RIGHT_CONTRIBUTOR, rightRange); 2662 } 2663 if (selectDiff != null) 2664 setCurrentDiff(selectDiff, true); 2665 else 2666 selectFirstDiff(true); 2667 } 2668 } 2669 } 2670 2671 } 2672 2673 private boolean isRefreshing() { 2674 return isRefreshing; 2675 } 2676 2677 private ContributorInfo createLegInfoFor(Object element, char leg) { 2678 return new ContributorInfo(this, element, leg); 2679 } 2680 2681 private Diff findDiff(char c, Position range) { 2682 2683 MergeSourceViewer v; 2684 int start= range.getOffset(); 2685 int end= start + range.getLength(); 2686 if (c == LEFT_CONTRIBUTOR) 2687 v= fLeft; 2688 else if (c == RIGHT_CONTRIBUTOR) 2689 v= fRight; 2690 else 2691 return null; 2692 2693 if (fChangeDiffs != null) { 2694 Iterator iter= fChangeDiffs.iterator(); 2695 while (iter.hasNext()) { 2696 Diff diff= (Diff) iter.next(); 2697 if (diff.isDeleted() || diff.fDirection == RangeDifference.NOCHANGE) 2698 continue; 2699 if (diff.overlaps(v, start, end)) 2700 return diff; 2701 } 2702 } 2703 return null; 2704 } 2705 2706 private void updateDiffBackground(Diff diff) { 2707 2708 if (! fHighlightRanges) 2709 return; 2710 2711 if (diff == null || diff.fIsToken) 2712 return; 2713 2714 if (fShowCurrentOnly && !isCurrentDiff(diff)) 2715 return; 2716 2717 Color c= getColor(null, getFillColor(diff)); 2718 if (c == null) 2719 return; 2720 2721 if (isThreeWay()) 2722 fAncestor.setLineBackground(diff.fAncestorPos, c); 2723 fLeft.setLineBackground(diff.fLeftPos, c); 2724 fRight.setLineBackground(diff.fRightPos, c); 2725 } 2726 2727 private void updateAllDiffBackgrounds(Display display) { 2728 if (fChangeDiffs != null) { 2729 boolean threeWay= isThreeWay(); 2730 Iterator iter= fChangeDiffs.iterator(); 2731 while (iter.hasNext()) { 2732 Diff diff= (Diff) iter.next(); 2733 Color c= getColor(display, getFillColor(diff)); 2734 if (threeWay) 2735 fAncestor.setLineBackground(diff.fAncestorPos, c); 2736 fLeft.setLineBackground(diff.fLeftPos, c); 2737 fRight.setLineBackground(diff.fRightPos, c); 2738 } 2739 } 2740 } 2741 2742 boolean isCurrentDiff(Diff diff) { 2743 if (diff == null) 2744 return false; 2745 if (diff == fCurrentDiff) 2746 return true; 2747 if (fCurrentDiff != null && fCurrentDiff.fParent == diff) 2748 return true; 2749 return false; 2750 } 2751 2752 2757 private void documentChanged(DocumentEvent e, boolean dirty) { 2758 2759 IDocument doc= e.getDocument(); 2760 2761 if (doc == fLeft.getDocument()) { 2762 setLeftDirty(dirty); 2763 } else if (doc == fRight.getDocument()) { 2764 setRightDirty(dirty); 2765 } 2766 2767 updateLines(doc); 2768 } 2769 2770 2782 protected int findInsertionPosition(char type, ICompareInput input) { 2783 2784 ITypedElement other= null; 2785 char otherType= 0; 2786 2787 switch (type) { 2788 case ANCESTOR_CONTRIBUTOR: 2789 other= input.getLeft(); 2790 otherType= LEFT_CONTRIBUTOR; 2791 if (other == null) { 2792 other= input.getRight(); 2793 otherType= RIGHT_CONTRIBUTOR; 2794 } 2795 break; 2796 case LEFT_CONTRIBUTOR: 2797 other= input.getRight(); 2798 otherType= RIGHT_CONTRIBUTOR; 2799 if (other == null) { 2800 other= input.getAncestor(); 2801 otherType= ANCESTOR_CONTRIBUTOR; 2802 } 2803 break; 2804 case RIGHT_CONTRIBUTOR: 2805 other= input.getLeft(); 2806 otherType= LEFT_CONTRIBUTOR; 2807 if (other == null) { 2808 other= input.getAncestor(); 2809 otherType= ANCESTOR_CONTRIBUTOR; 2810 } 2811 break; 2812 } 2813 2814 if (other instanceof IDocumentRange) { 2815 IDocumentRange dr= (IDocumentRange) other; 2816 Position p= dr.getRange(); 2817 Diff diff= findDiff(otherType, p.offset); 2818 if (diff != null) { 2819 switch (type) { 2820 case ANCESTOR_CONTRIBUTOR: 2821 if (diff.fAncestorPos != null) 2822 return diff.fAncestorPos.offset; 2823 break; 2824 case LEFT_CONTRIBUTOR: 2825 if (diff.fLeftPos != null) 2826 return diff.fLeftPos.offset; 2827 break; 2828 case RIGHT_CONTRIBUTOR: 2829 if (diff.fRightPos != null) 2830 return diff.fRightPos.offset; 2831 break; 2832 } 2833 } 2834 } 2835 return 0; 2836 } 2837 2838 private void setError(char type, String message) { 2839 IMergeViewerContentProvider cp= getMergeContentProvider(); 2840 if (cp instanceof MergeViewerContentProvider) { 2841 MergeViewerContentProvider mcp= (MergeViewerContentProvider) cp; 2842 switch (type) { 2843 case ANCESTOR_CONTRIBUTOR: 2844 mcp.setAncestorError(message); 2845 break; 2846 case LEFT_CONTRIBUTOR: 2847 mcp.setLeftError(message); 2848 break; 2849 case RIGHT_CONTRIBUTOR: 2850 mcp.setRightError(message); 2851 break; 2852 } 2853 } 2854 fHasErrors= true; 2855 } 2856 2857 private void updateDirtyState(IEditorInput key, 2858 IDocumentProvider documentProvider, char type) { 2859 boolean dirty = documentProvider.canSaveDocument(key); 2860 if (type == LEFT_CONTRIBUTOR) 2861 setLeftDirty(dirty); 2862 else if (type == RIGHT_CONTRIBUTOR) 2863 setRightDirty(dirty); 2864 } 2865 2866 private Position getNewRange(char type, Object input) { 2867 switch (type) { 2868 case ANCESTOR_CONTRIBUTOR: 2869 return (Position) fNewAncestorRanges.get(input); 2870 case LEFT_CONTRIBUTOR: 2871 return (Position) fNewLeftRanges.get(input); 2872 case RIGHT_CONTRIBUTOR: 2873 return (Position) fNewRightRanges.get(input); 2874 } 2875 return null; 2876 } 2877 2878 private void addNewRange(char type, Object input, Position range) { 2879 switch (type) { 2880 case ANCESTOR_CONTRIBUTOR: 2881 fNewAncestorRanges.put(input, range); 2882 break; 2883 case LEFT_CONTRIBUTOR: 2884 fNewLeftRanges.put(input, range); 2885 break; 2886 case RIGHT_CONTRIBUTOR: 2887 fNewRightRanges.put(input, range); 2888 break; 2889 } 2890 } 2891 2892 2898 protected byte[] getContents(boolean left) { 2899 MergeSourceViewer v= left ? fLeft : fRight; 2900 if (v != null) { 2901 IDocument d= v.getDocument(); 2902 if (d != null) { 2903 String contents= d.get(); 2904 if (contents != null) { 2905 byte[] bytes; 2906 try { 2907 bytes= contents.getBytes(left ? fLeftContributor.getEncoding() : fRightContributor.getEncoding()); 2908 } catch(UnsupportedEncodingException ex) { 2909 bytes= contents.getBytes(); 2911 } 2912 return bytes; 2913 } 2914 } 2915 } 2916 return null; 2917 } 2918 2919 private IRegion normalizeDocumentRegion(IDocument doc, IRegion region) { 2920 2921 if (region == null || doc == null) 2922 return region; 2923 2924 int maxLength= doc.getLength(); 2925 2926 int start= region.getOffset(); 2927 if (start < 0) 2928 start= 0; 2929 else if (start > maxLength) 2930 start= maxLength; 2931 2932 int length= region.getLength(); 2933 if (length < 0) 2934 length= 0; 2935 else if (start + length > maxLength) 2936 length= maxLength - start; 2937 2938 return new Region(start, length); 2939 } 2940 2941 2944 protected final void handleResizeAncestor(int x, int y, int width, int height) { 2945 if (width > 0) { 2946 Rectangle trim= fLeft.getTextWidget().computeTrim(0, 0, 0, 0); 2947 int scrollbarHeight= trim.height; 2948 if (Utilities.okToUse(fAncestorCanvas)) 2949 fAncestorCanvas.setVisible(true); 2950 if (fAncestor.isControlOkToUse()) 2951 fAncestor.getTextWidget().setVisible(true); 2952 2953 if (fAncestorCanvas != null) { 2954 fAncestorCanvas.setBounds(x, y, fMarginWidth, height-scrollbarHeight); 2955 x+= fMarginWidth; 2956 width-= fMarginWidth; 2957 } 2958 fAncestor.setBounds(x, y, width, height); 2959 } else { 2960 if (Utilities.okToUse(fAncestorCanvas)) 2961 fAncestorCanvas.setVisible(false); 2962 if (fAncestor.isControlOkToUse()) { 2963 StyledText t= fAncestor.getTextWidget(); 2964 t.setVisible(false); 2965 fAncestor.setBounds(0, 0, 0, 0); 2966 if (fFocusPart == fAncestor) { 2967 fFocusPart= fLeft; 2968 fFocusPart.getTextWidget().setFocus(); 2969 } 2970 } 2971 } 2972 } 2973 2974 2977 protected final void handleResizeLeftRight(int x, int y, int width1, int centerWidth, int width2, int height) { 2978 2979 if (fBirdsEyeCanvas != null) 2980 width2-= BIRDS_EYE_VIEW_WIDTH; 2981 2982 Rectangle trim= fLeft.getTextWidget().computeTrim(0, 0, 0, 0); 2983 int scrollbarHeight= trim.height + trim.x; 2984 2985 Composite composite= (Composite) getControl(); 2986 2987 int leftTextWidth= width1; 2988 if (fLeftCanvas != null) { 2989 fLeftCanvas.setBounds(x, y, fMarginWidth, height-scrollbarHeight); 2990 x+= fMarginWidth; 2991 leftTextWidth-= fMarginWidth; 2992 } 2993 2994 fLeft.setBounds(x, y, leftTextWidth, height); 2995 x+= leftTextWidth; 2996 2997 if (fCenter == null || fCenter.isDisposed()) 2998 fCenter= createCenterControl(composite); 2999 fCenter.setBounds(x, y, centerWidth, height-scrollbarHeight); 3000 x+= centerWidth; 3001 3002 if (!fSynchronizedScrolling) { if (fRightCanvas != null) { 3004 fRightCanvas.setBounds(x, y, fMarginWidth, height-scrollbarHeight); 3005 fRightCanvas.redraw(); 3006 x+= fMarginWidth; 3007 } 3008 } 3010 3011 int scrollbarWidth= 0; 3012 if (fSynchronizedScrolling && fScrollCanvas != null) { 3013 trim= fLeft.getTextWidget().computeTrim(0, 0, 0, 0); 3014 scrollbarWidth= trim.width + 2*trim.x+1; 3016 } 3017 int rightTextWidth= width2-scrollbarWidth; 3018 if (fRightCanvas != null) 3019 rightTextWidth-= fMarginWidth; 3020 fRight.setBounds(x, y, rightTextWidth, height); 3021 x+= rightTextWidth; 3022 3023 if (fSynchronizedScrolling) { 3024 if (fRightCanvas != null) { fRightCanvas.setBounds(x, y, fMarginWidth, height-scrollbarHeight); 3026 x+= fMarginWidth; 3027 } 3028 if (fScrollCanvas != null) 3029 fScrollCanvas.setBounds(x, y, scrollbarWidth, height-scrollbarHeight); 3030 } 3031 3032 if (fBirdsEyeCanvas != null) { 3033 int verticalScrollbarButtonHeight= scrollbarWidth; 3034 int horizontalScrollbarButtonHeight= scrollbarHeight; 3035 if (fIsCarbon) { 3036 verticalScrollbarButtonHeight+= 2; 3037 horizontalScrollbarButtonHeight= 18; 3038 } 3039 if (fSummaryHeader != null) 3040 fSummaryHeader.setBounds(x+scrollbarWidth, y, BIRDS_EYE_VIEW_WIDTH, verticalScrollbarButtonHeight); 3041 y+= verticalScrollbarButtonHeight; 3042 fBirdsEyeCanvas.setBounds(x+scrollbarWidth, y, BIRDS_EYE_VIEW_WIDTH, height-(2*verticalScrollbarButtonHeight+horizontalScrollbarButtonHeight)); 3043 } 3044 3045 updateVScrollBar(); 3047 refreshBirdsEyeView(); 3048 } 3049 3050 3053 private void handleSelectionChanged(MergeSourceViewer tw) { 3054 Point p= tw.getSelectedRange(); 3055 Diff d= findDiff(tw, p.x, p.x+p.y); 3056 updateStatus(d); 3057 setCurrentDiff(d, false); } 3059 3060 private static IRegion toRegion(Position position) { 3061 if (position != null) 3062 return new Region(position.getOffset(), position.getLength()); 3063 return null; 3064 } 3065 3066 3068 private static int maxWork(IRangeComparator a, IRangeComparator l, IRangeComparator r) { 3069 int ln= l.getRangeCount(); 3070 int rn= r.getRangeCount(); 3071 if (a != null) { 3072 int an= a.getRangeCount(); 3073 return (2 * Math.max(an, ln)) + (2 * Math.max(an, rn)); 3074 } 3075 return 2 * Math.max(ln, rn); 3076 } 3077 3078 3082 private void doDiff() { 3083 3084 ArrayList newAllDiffs = new ArrayList(); 3085 fChangeDiffs= new ArrayList(); 3086 fCurrentDiff= null; 3087 3088 IDocument aDoc= null; 3089 IDocument lDoc= fLeft.getDocument(); 3090 IDocument rDoc= fRight.getDocument(); 3091 if (lDoc == null || rDoc == null) 3092 return; 3093 3094 Position aRegion= null; 3095 Position lRegion= fLeft.getRegion(); 3096 Position rRegion= fRight.getRegion(); 3097 3098 boolean threeWay= isThreeWay(); 3099 3100 if (threeWay && !isIgnoreAncestor()) { 3101 aDoc= fAncestor.getDocument(); 3102 aRegion= fAncestor.getRegion(); 3103 } 3104 3105 resetPositions(lDoc); 3106 resetPositions(rDoc); 3107 resetPositions(aDoc); 3108 3109 fAncestor.resetLineBackground(); 3110 fLeft.resetLineBackground(); 3111 fRight.resetLineBackground(); 3112 3113 boolean ignoreWhiteSpace= Utilities.getBoolean(getCompareConfiguration(), CompareConfiguration.IGNORE_WHITESPACE, false); 3114 3115 DocLineComparator sright= new DocLineComparator(rDoc, toRegion(rRegion), ignoreWhiteSpace); 3116 DocLineComparator sleft= new DocLineComparator(lDoc, toRegion(lRegion), ignoreWhiteSpace); 3117 DocLineComparator sancestor= null; 3118 boolean isRight = true; 3119 if (aDoc != null) { 3120 sancestor= new DocLineComparator(aDoc, toRegion(aRegion), ignoreWhiteSpace); 3121 if (isPatchHunk()) { 3122 ITypedElement right = ((ICompareInput)getInput()).getRight(); 3123 isRight = right != null && Utilities.getAdapter(right, IHunk.class) != null; 3124 if (isRight) { 3125 sleft= new DocLineComparator(aDoc, toRegion(aRegion), ignoreWhiteSpace); 3126 } else { 3127 sright= new DocLineComparator(aDoc, toRegion(aRegion), ignoreWhiteSpace); 3128 } 3129 } 3130 } 3131 3132 if (!fSubDoc && rRegion != null && lRegion != null) { 3133 3135 int astart= 0; 3136 int as= 0; 3137 if (aRegion != null) { 3138 astart= aRegion.getOffset(); 3139 as= Math.max(0, astart-1); 3140 } 3141 int ys= Math.max(0, lRegion.getOffset()-1); 3142 int ms= Math.max(0, rRegion.getOffset()-1); 3143 3144 if (as > 0 || ys > 0 || ms > 0) { 3145 Diff diff= new Diff(null, RangeDifference.NOCHANGE, 3146 aDoc, aRegion, 0, astart, 3147 lDoc, lRegion, 0, lRegion.getOffset(), 3148 rDoc, rRegion, 0, rRegion.getOffset()); 3149 newAllDiffs.add(diff); 3150 } 3151 } 3152 3153 final ResourceBundle bundle= getResourceBundle(); 3154 3155 final Object [] result= new Object [1]; 3156 final DocLineComparator sa= sancestor, sl= sleft, sr= sright; 3157 IRunnableWithProgress runnable= new IRunnableWithProgress() { 3158 public void run(IProgressMonitor monitor) throws InterruptedException , InvocationTargetException { 3159 String progressTitle= Utilities.getString(bundle, "compareProgressTask.title"); monitor.beginTask(progressTitle, maxWork(sa, sl, sr)); 3161 try { 3162 result[0]= RangeDifferencer.findRanges(monitor, sa, sl, sr); 3163 } catch (OutOfMemoryError ex) { 3164 System.gc(); 3165 throw new InvocationTargetException (ex); 3166 } 3167 if (monitor.isCanceled()) { throw new InterruptedException (); 3169 } 3170 monitor.done(); 3171 } 3172 }; 3173 3174 RangeDifference[] e= null; 3175 try { 3176 getCompareConfiguration().getContainer().run(true, true, runnable); 3177 e= (RangeDifference[]) result[0]; 3178 } catch (InvocationTargetException ex) { 3179 String title= Utilities.getString(bundle, "tooComplexError.title"); String format= Utilities.getString(bundle, "tooComplexError.format"); String msg= MessageFormat.format(format, new Object [] { Integer.toString(PlatformUI.getWorkbench().getProgressService().getLongOperationTime()/1000) } ); 3182 MessageDialog.openError(fComposite.getShell(), title, msg); 3183 e= null; 3184 } catch (InterruptedException ex) { 3185 } 3187 3188 if (e == null) { 3189 Diff diff= new Diff(null, RangeDifference.NOCHANGE, 3191 aDoc, aRegion, 0, aDoc != null ? aDoc.getLength() : 0, 3192 lDoc, lRegion, 0, lDoc.getLength(), 3193 rDoc, rRegion, 0, rDoc.getLength()); 3194 3195 newAllDiffs.add(diff); 3196 } else { 3197 for (int i= 0; i < e.length; i++) { 3198 String a= null, s= null, d= null; 3199 RangeDifference es= e[i]; 3200 3201 int kind= es.kind(); 3202 3203 int ancestorStart= 0; 3204 int ancestorEnd= 0; 3205 if (sancestor != null) { 3206 ancestorStart= sancestor.getTokenStart(es.ancestorStart()); 3207 ancestorEnd= getTokenEnd2(sancestor, es.ancestorStart(), es.ancestorLength()); 3208 } 3209 3210 int leftStart= sleft.getTokenStart(es.leftStart()); 3211 int leftEnd= getTokenEnd2(sleft, es.leftStart(), es.leftLength()); 3212 3213 int rightStart= sright.getTokenStart(es.rightStart()); 3214 int rightEnd= getTokenEnd2(sright, es.rightStart(), es.rightLength()); 3215 3216 if (isPatchHunk()) { 3217 if (isRight) 3218 leftStart = leftEnd = getHunkStart(); 3219 else 3220 rightStart = rightEnd = getHunkStart(); 3221 } 3222 3223 Diff diff= new Diff(null, kind, 3224 aDoc, aRegion, ancestorStart, ancestorEnd, 3225 lDoc, lRegion, leftStart, leftEnd, 3226 rDoc, rRegion, rightStart, rightEnd); 3227 3228 newAllDiffs.add(diff); 3230 if (ignoreWhiteSpace && !isPatchHunk()) { 3231 if (sancestor != null) 3232 a= extract2(aDoc, sancestor, es.ancestorStart(), es.ancestorLength()); 3233 s= extract2(lDoc, sleft, es.leftStart(), es.leftLength()); 3234 d= extract2(rDoc, sright, es.rightStart(), es.rightLength()); 3235 3236 if ((a == null || a.trim().length() == 0) && s.trim().length() == 0 && d.trim().length() == 0) { 3237 diff.fIsWhitespace= true; 3238 continue; 3239 } 3240 } 3241 3242 if (useChange(kind)) { 3243 fChangeDiffs.add(diff); updateDiffBackground(diff); 3245 3246 if (!isPatchHunk()) { 3248 if (s == null) 3249 s= extract2(lDoc, sleft, es.leftStart(), es.leftLength()); 3250 if (d == null) 3251 d= extract2(rDoc, sright, es.rightStart(), es.rightLength()); 3252 3253 if (s.length() > 0 && d.length() > 0) { 3254 if (a == null && sancestor != null) 3255 a= extract2(aDoc, sancestor, es.ancestorStart(), es.ancestorLength()); 3256 if (USE_MERGING_TOKEN_DIFF) 3257 mergingTokenDiff(diff, aDoc, a, rDoc, d, lDoc, s); 3258 else 3259 simpleTokenDiff(diff, aDoc, a, rDoc, d, lDoc, s); 3260 } 3261 } 3262 } 3263 } 3264 } 3265 3266 if (!fSubDoc && rRegion != null && lRegion != null) { 3267 3269 int aEnd= 0; 3270 int aLen= 0; 3271 if (aRegion != null && aDoc != null) { 3272 aEnd= aRegion.getOffset()+aRegion.getLength(); 3273 aLen= aDoc.getLength(); 3274 } 3275 Diff diff= new Diff(null, RangeDifference.NOCHANGE, 3276 aDoc, aRegion, aEnd, aLen, 3277 lDoc, lRegion, lRegion.getOffset()+lRegion.getLength(), lDoc.getLength(), 3278 rDoc, rRegion, rRegion.getOffset()+rRegion.getLength(), rDoc.getLength()); 3279 newAllDiffs.add(diff); 3280 } 3281 fAllDiffs = newAllDiffs; 3282 invalidateTextPresentation(); 3283 } 3284 3285 private void resetPositions(IDocument doc) { 3286 if (doc == null) 3287 return; 3288 try { 3289 doc.removePositionCategory(DIFF_RANGE_CATEGORY); 3290 } catch (BadPositionCategoryException e) { 3291 } 3293 doc.addPositionCategory(DIFF_RANGE_CATEGORY); 3294 } 3295 3296 private Diff findDiff(char type, int pos) { 3297 3298 IDocument aDoc= null; 3299 IDocument lDoc= fLeft.getDocument(); 3300 IDocument rDoc= fRight.getDocument(); 3301 if (lDoc == null || rDoc == null) 3302 return null; 3303 3304 Position aRegion= null; 3305 Position lRegion= null; 3306 Position rRegion= null; 3307 3308 boolean threeWay= isThreeWay(); 3309 3310 if (threeWay && !isIgnoreAncestor()) 3311 aDoc= fAncestor.getDocument(); 3312 3313 boolean ignoreWhiteSpace= Utilities.getBoolean(getCompareConfiguration(), CompareConfiguration.IGNORE_WHITESPACE, false); 3314 3315 DocLineComparator sright= new DocLineComparator(rDoc, toRegion(rRegion), ignoreWhiteSpace); 3316 DocLineComparator sleft= new DocLineComparator(lDoc, toRegion(lRegion), ignoreWhiteSpace); 3317 DocLineComparator sancestor= null; 3318 if (aDoc != null) 3319 sancestor= new DocLineComparator(aDoc, toRegion(aRegion), ignoreWhiteSpace); 3320 3321 final ResourceBundle bundle= getResourceBundle(); 3322 3323 final Object [] result= new Object [1]; 3324 final DocLineComparator sa= sancestor, sl= sleft, sr= sright; 3325 IRunnableWithProgress runnable= new IRunnableWithProgress() { 3326 public void run(IProgressMonitor monitor) throws InterruptedException , InvocationTargetException { 3327 String progressTitle= Utilities.getString(bundle, "compareProgressTask.title"); monitor.beginTask(progressTitle, maxWork(sa, sl, sr)); 3329 try { 3330 result[0]= RangeDifferencer.findRanges(monitor, sa, sl, sr); 3331 } catch (OutOfMemoryError ex) { 3332 System.gc(); 3333 throw new InvocationTargetException (ex); 3334 } 3335 if (monitor.isCanceled()) { throw new InterruptedException (); 3337 } 3338 monitor.done(); 3339 } 3340 }; 3341 IProgressService progressService= PlatformUI.getWorkbench().getProgressService(); 3342 3343 RangeDifference[] e= null; 3344 try { 3345 progressService.run(true, true, runnable); 3346 e= (RangeDifference[]) result[0]; 3347 } catch (InvocationTargetException ex) { 3348 String title= Utilities.getString(bundle, "tooComplexError.title"); String format= Utilities.getString(bundle, "tooComplexError.format"); String msg= MessageFormat.format(format, new Object [] { Integer.toString(progressService.getLongOperationTime()/1000) } ); 3351 MessageDialog.openError(fComposite.getShell(), title, msg); 3352 e= null; 3353 } catch (InterruptedException ex) { 3354 } 3356 3357 if (e != null) { 3358 for (int i= 0; i < e.length; i++) { 3359 RangeDifference es= e[i]; 3360 3361 int kind= es.kind(); 3362 3363 int ancestorStart= 0; 3364 int ancestorEnd= 0; 3365 if (sancestor != null) { 3366 ancestorStart= sancestor.getTokenStart(es.ancestorStart()); 3367 ancestorEnd= getTokenEnd2(sancestor, es.ancestorStart(), es.ancestorLength()); 3368 } 3369 3370 int leftStart= sleft.getTokenStart(es.leftStart()); 3371 int leftEnd= getTokenEnd2(sleft, es.leftStart(), es.leftLength()); 3372 3373 int rightStart= sright.getTokenStart(es.rightStart()); 3374 int rightEnd= getTokenEnd2(sright, es.rightStart(), es.rightLength()); 3375 3376 Diff diff= new Diff(null, kind, 3377 aDoc, aRegion, ancestorStart, ancestorEnd, 3378 lDoc, lRegion, leftStart, leftEnd, 3379 rDoc, rRegion, rightStart, rightEnd); 3380 3381 if (diff.isInRange(type, pos)) 3382 return diff; 3383 } 3384 } 3385 3386 return null; 3387 } 3388 3389 3392 private boolean useChange(int kind) { 3393 if (kind == RangeDifference.NOCHANGE) 3394 return false; 3395 if (kind == RangeDifference.ANCESTOR) 3396 return fShowPseudoConflicts; 3397 return true; 3398 } 3399 3400 private int getTokenEnd(ITokenComparator tc, int start, int count) { 3401 if (count <= 0) 3402 return tc.getTokenStart(start); 3403 int index= start + count - 1; 3404 return tc.getTokenStart(index) + tc.getTokenLength(index); 3405 } 3406 3407 private static int getTokenEnd2(ITokenComparator tc, int start, int length) { 3408 return tc.getTokenStart(start + length); 3409 } 3410 3411 3420 private String extract2(IDocument doc, ITokenComparator tc, int start, int length) { 3421 int count= tc.getRangeCount(); 3422 if (length > 0 && count > 0) { 3423 3424 3433 int startPos= tc.getTokenStart(start); 3434 int endPos; 3435 3436 if (length == 1) { 3437 endPos= startPos + tc.getTokenLength(start); 3438 } else { 3439 endPos= tc.getTokenStart(start + length); 3440 } 3441 3442 try { 3443 return doc.get(startPos, endPos - startPos); 3444 } catch (BadLocationException e) { 3445 } 3447 3448 } 3449 return ""; } 3451 3452 3455 private void simpleTokenDiff(final Diff baseDiff, 3456 IDocument ancestorDoc, String a, 3457 IDocument rightDoc, String d, 3458 IDocument leftDoc, String s) { 3459 3460 int ancestorStart= 0; 3461 ITokenComparator sa= null; 3462 if (ancestorDoc != null) { 3463 ancestorStart= baseDiff.fAncestorPos.getOffset(); 3464 sa= createTokenComparator(a); 3465 } 3466 3467 int rightStart= baseDiff.fRightPos.getOffset(); 3468 ITokenComparator sm= createTokenComparator(d); 3469 3470 int leftStart= baseDiff.fLeftPos.getOffset(); 3471 ITokenComparator sy= createTokenComparator(s); 3472 3473 RangeDifference[] e= RangeDifferencer.findRanges(sa, sy, sm); 3474 for (int i= 0; i < e.length; i++) { 3475 RangeDifference es= e[i]; 3476 int kind= es.kind(); 3477 if (kind != RangeDifference.NOCHANGE) { 3478 3479 int ancestorStart2= ancestorStart; 3480 int ancestorEnd2= ancestorStart; 3481 if (ancestorDoc != null) { 3482 ancestorStart2 += sa.getTokenStart(es.ancestorStart()); 3483 ancestorEnd2 += getTokenEnd(sa, es.ancestorStart(), es.ancestorLength()); 3484 } 3485 3486 int leftStart2= leftStart + sy.getTokenStart(es.leftStart()); 3487 int leftEnd2= leftStart + getTokenEnd(sy, es.leftStart(), es.leftLength()); 3488 3489 int rightStart2= rightStart + sm.getTokenStart(es.rightStart()); 3490 int rightEnd2= rightStart + getTokenEnd(sm, es.rightStart(), es.rightLength()); 3491 3492 Diff diff= new Diff(baseDiff, kind, 3493 ancestorDoc, null, ancestorStart2, ancestorEnd2, 3494 leftDoc, null, leftStart2, leftEnd2, 3495 rightDoc, null, rightStart2, rightEnd2); 3496 3497 int leftS= baseDiff.fLeftPos.offset; 3499 int leftE= baseDiff.fLeftPos.offset+baseDiff.fLeftPos.length; 3500 int rightS= baseDiff.fRightPos.offset; 3501 int rightE= baseDiff.fRightPos.offset+baseDiff.fRightPos.length; 3502 if (leftS != leftStart2 || leftE != leftEnd2 || 3503 rightS != rightStart2 || rightE != rightEnd2) { 3504 diff.fIsToken= true; 3505 baseDiff.add(diff); 3507 } 3508 } 3509 } 3510 } 3511 3512 3516 private void mergingTokenDiff(Diff baseDiff, 3517 IDocument ancestorDoc, String a, 3518 IDocument rightDoc, String d, 3519 IDocument leftDoc, String s) { 3520 ITokenComparator sa= null; 3521 int ancestorStart= 0; 3522 if (ancestorDoc != null) { 3523 sa= createTokenComparator(a); 3524 ancestorStart= baseDiff.fAncestorPos.getOffset(); 3525 } 3526 3527 int rightStart= baseDiff.fRightPos.getOffset(); 3528 ITokenComparator sm= createTokenComparator(d); 3529 3530 int leftStart= baseDiff.fLeftPos.getOffset(); 3531 ITokenComparator sy= createTokenComparator(s); 3532 3533 RangeDifference[] r= RangeDifferencer.findRanges(sa, sy, sm); 3534 for (int i= 0; i < r.length; i++) { 3535 RangeDifference es= r[i]; 3536 int start= i; 3538 int leftLine= -1; 3539 int rightLine= -1; 3540 try { 3541 leftLine= leftDoc.getLineOfOffset(leftStart+sy.getTokenStart(es.leftStart())); 3542 rightLine= rightDoc.getLineOfOffset(rightStart+sm.getTokenStart(es.rightStart())); 3543 } catch (BadLocationException e) { 3544 } 3546 i++; 3547 for (; i < r.length; i++) { 3548 es= r[i]; 3549 try { 3550 if (leftLine != leftDoc.getLineOfOffset(leftStart+sy.getTokenStart(es.leftStart()))) 3551 break; 3552 if (rightLine != rightDoc.getLineOfOffset(rightStart+sm.getTokenStart(es.rightStart()))) 3553 break; 3554 } catch (BadLocationException e) { 3555 } 3557 } 3558 int end= i; 3559 3560 RangeDifference first= null; 3562 for (int ii= start; ii < end; ii++) { 3563 es= r[ii]; 3564 if (useChange(es.kind())) { 3565 first= es; 3566 break; 3567 } 3568 } 3569 3570 RangeDifference last= null; 3572 for (int ii= end-1; ii >= start; ii--) { 3573 es= r[ii]; 3574 if (useChange(es.kind())) { 3575 last= es; 3576 break; 3577 } 3578 } 3579 3580 if (first != null && last != null) { 3581 3582 int ancestorStart2= 0; 3583 int ancestorEnd2= 0; 3584 if (ancestorDoc != null) { 3585 ancestorStart2= ancestorStart+sa.getTokenStart(first.ancestorStart()); 3586 ancestorEnd2= ancestorStart+getTokenEnd(sa, last.ancestorStart(), last.ancestorLength()); 3587 } 3588 3589 int leftStart2= leftStart+sy.getTokenStart(first.leftStart()); 3590 int leftEnd2= leftStart+getTokenEnd(sy, last.leftStart(), last.leftLength()); 3591 3592 int rightStart2= rightStart+sm.getTokenStart(first.rightStart()); 3593 int rightEnd2= rightStart+getTokenEnd(sm, last.rightStart(), last.rightLength()); 3594 Diff diff= new Diff(baseDiff, first.kind(), 3595 ancestorDoc, null, ancestorStart2, ancestorEnd2, 3596 leftDoc, null, leftStart2, leftEnd2, 3597 rightDoc, null, rightStart2, rightEnd2); 3598 diff.fIsToken= true; 3599 baseDiff.add(diff); 3600 } 3601 } 3602 } 3603 3604 3606 private void updateControls() { 3607 3608 boolean leftToRight= false; 3609 boolean rightToLeft= false; 3610 3611 updateStatus(fCurrentDiff); 3612 updateResolveStatus(); 3613 3614 if (fCurrentDiff != null) { 3615 IMergeViewerContentProvider cp= getMergeContentProvider(); 3616 if (cp != null) { 3617 if (!isPatchHunk()) { 3618 rightToLeft= cp.isLeftEditable(getInput()); 3619 leftToRight= cp.isRightEditable(getInput()); 3620 } 3621 } 3622 } 3623 3624 if (fDirectionLabel != null) { 3625 if (fHighlightRanges && fCurrentDiff != null && isThreeWay() && !isIgnoreAncestor()) { 3626 fDirectionLabel.setImage(fCurrentDiff.getImage()); 3627 } else { 3628 fDirectionLabel.setImage(null); 3629 } 3630 } 3631 3632 if (fCopyDiffLeftToRightItem != null) 3633 ((Action)fCopyDiffLeftToRightItem.getAction()).setEnabled(leftToRight); 3634 if (fCopyDiffRightToLeftItem != null) 3635 ((Action)fCopyDiffRightToLeftItem.getAction()).setEnabled(rightToLeft); 3636 3637 boolean enableNavigation= false; 3638 if (fCurrentDiff == null && fChangeDiffs != null && fChangeDiffs.size() > 0) 3639 enableNavigation= true; 3640 else if (fChangeDiffs != null && fChangeDiffs.size() > 1) 3641 enableNavigation= true; 3642 else if (fCurrentDiff != null && fCurrentDiff.fDiffs != null) 3643 enableNavigation= true; 3644 else if (fCurrentDiff != null && fCurrentDiff.fIsToken) 3645 enableNavigation= true; 3646 3647 if (fNextDiff != null) { 3648 IAction a= fNextDiff.getAction(); 3649 a.setEnabled(enableNavigation || hasNextElement(true)); 3650 } 3651 if (fPreviousDiff != null) { 3652 IAction a= fPreviousDiff.getAction(); 3653 a.setEnabled(enableNavigation || hasNextElement(false)); 3654 } 3655 if (fNextChange != null) { 3656 IAction a= fNextChange.getAction(); 3657 a.setEnabled(enableNavigation); 3658 } 3659 if (fPreviousChange != null) { 3660 IAction a= fPreviousChange.getAction(); 3661 a.setEnabled(enableNavigation); 3662 } 3663 } 3664 3665 private void updateResolveStatus() { 3666 3667 RGB rgb= null; 3668 3669 if (showResolveUI()) { 3670 int incomingOrConflicting= 0; 3672 int unresolvedIncoming= 0; 3673 int unresolvedConflicting= 0; 3674 3675 if (fChangeDiffs != null) { 3676 Iterator e= fChangeDiffs.iterator(); 3677 while (e.hasNext()) { 3678 Diff d= (Diff) e.next(); 3679 if (d.isIncomingOrConflicting() ) { 3680 incomingOrConflicting++; 3681 if (!d.fResolved) { 3682 if (d.fDirection == RangeDifference.CONFLICT) { 3683 unresolvedConflicting++; 3684 break; } 3686 unresolvedIncoming++; 3687 } 3688 } 3689 } 3690 } 3691 3692 if (incomingOrConflicting > 0) { 3693 if (unresolvedConflicting > 0) 3694 rgb= SELECTED_CONFLICT; 3695 else if (unresolvedIncoming > 0) 3696 rgb= SELECTED_INCOMING; 3697 else 3698 rgb= RESOLVED; 3699 } 3700 } 3701 3702 if (fHeaderPainter.setColor(rgb)) 3703 fSummaryHeader.redraw(); 3704 } 3705 3706 private void updateStatus(Diff diff) { 3707 3708 if (! fShowMoreInfo) 3709 return; 3710 3711 String diffDescription; 3712 3713 if (diff == null) { 3714 diffDescription= CompareMessages.TextMergeViewer_diffDescription_noDiff_format; 3715 } else { 3716 3717 if (diff.fIsToken) diff= diff.fParent; 3719 3720 String format= CompareMessages.TextMergeViewer_diffDescription_diff_format; 3721 diffDescription= MessageFormat.format(format, 3722 new String [] { 3723 getDiffType(diff), getDiffNumber(diff), getDiffRange(fLeft, diff.fLeftPos), getDiffRange(fRight, diff.fRightPos) } 3728 ); 3729 } 3730 3731 String format= CompareMessages.TextMergeViewer_statusLine_format; 3732 String s= MessageFormat.format(format, 3733 new String [] { 3734 getCursorPosition(fLeft), getCursorPosition(fRight), diffDescription } 3738 ); 3739 3740 getCompareConfiguration().getContainer().setStatusMessage(s); 3741 } 3742 3743 private void clearStatus() { 3744 getCompareConfiguration().getContainer().setStatusMessage(null); 3745 } 3746 3747 private String getDiffType(Diff diff) { 3748 String s= ""; switch(diff.fDirection) { 3750 case RangeDifference.LEFT: 3751 s= CompareMessages.TextMergeViewer_direction_outgoing; 3752 break; 3753 case RangeDifference.RIGHT: 3754 s= CompareMessages.TextMergeViewer_direction_incoming; 3755 break; 3756 case RangeDifference.CONFLICT: 3757 s= CompareMessages.TextMergeViewer_direction_conflicting; 3758 break; 3759 } 3760 String format= CompareMessages.TextMergeViewer_diffType_format; 3761 return MessageFormat.format(format, new String [] { s, diff.changeType() } ); 3762 } 3763 3764 private String getDiffNumber(Diff diff) { 3765 int diffNumber= 0; 3767 if (fChangeDiffs != null) { 3768 Iterator e= fChangeDiffs.iterator(); 3769 while (e.hasNext()) { 3770 Diff d= (Diff) e.next(); 3771 diffNumber++; 3772 if (d == diff) 3773 break; 3774 } 3775 } 3776 return Integer.toString(diffNumber); 3777 } 3778 3779 private String getDiffRange(MergeSourceViewer v, Position pos) { 3780 Point p= v.getLineRange(pos, new Point(0, 0)); 3781 int startLine= p.x+1; 3782 int endLine= p.x+p.y; 3783 3784 String format; 3785 if (endLine < startLine) 3786 format= CompareMessages.TextMergeViewer_beforeLine_format; 3787 else 3788 format= CompareMessages.TextMergeViewer_range_format; 3789 return MessageFormat.format(format, 3790 new String [] { Integer.toString(startLine), 3791 Integer.toString(endLine) } ); 3792 } 3793 3794 3799 private String getCursorPosition(MergeSourceViewer v) { 3800 if (v != null) { 3801 StyledText styledText= v.getTextWidget(); 3802 3803 IDocument document= v.getDocument(); 3804 if (document != null) { 3805 int offset= v.getVisibleRegion().getOffset(); 3806 int caret= offset + styledText.getCaretOffset(); 3807 3808 try { 3809 3810 int line=document.getLineOfOffset(caret); 3811 3812 int lineOffset= document.getLineOffset(line); 3813 int occurrences= 0; 3814 for (int i= lineOffset; i < caret; i++) 3815 if ('\t' == document.getChar(i)) 3816 ++ occurrences; 3817 3818 int tabWidth= styledText.getTabs(); 3819 int column= caret - lineOffset + (tabWidth -1) * occurrences; 3820 3821 String format= CompareMessages.TextMergeViewer_cursorPosition_format; 3822 return MessageFormat.format(format, 3823 new String [] { Integer.toString(line + 1), Integer.toString(column + 1) } ); 3824 3825 } catch (BadLocationException x) { 3826 } 3828 } 3829 } 3830 return ""; } 3832 3833 protected void updateHeader() { 3834 3835 super.updateHeader(); 3836 3837 updateControls(); 3838 } 3839 3840 3844 protected void createToolItems(ToolBarManager tbm) { 3845 3846 fHandlerService= CompareHandlerService.createFor(getCompareConfiguration().getContainer(), fLeft.getControl().getShell()); 3847 3848 final String ignoreAncestorActionKey= "action.IgnoreAncestor."; Action ignoreAncestorAction= new Action() { 3850 public void run() { 3851 if (!isIgnoreAncestor()) 3853 getCompareConfiguration().setProperty(ICompareUIConstants.PROP_ANCESTOR_VISIBLE, Boolean.FALSE); 3854 getCompareConfiguration().setProperty(ICompareUIConstants.PROP_IGNORE_ANCESTOR, Boolean.valueOf(!isIgnoreAncestor())); 3856 Utilities.initToggleAction(this, getResourceBundle(), ignoreAncestorActionKey, isIgnoreAncestor()); 3857 } 3858 }; 3859 ignoreAncestorAction.setChecked(isIgnoreAncestor()); 3860 Utilities.initAction(ignoreAncestorAction, getResourceBundle(), ignoreAncestorActionKey); 3861 Utilities.initToggleAction(ignoreAncestorAction, getResourceBundle(), ignoreAncestorActionKey, isIgnoreAncestor()); 3862 3863 fIgnoreAncestorItem= new ActionContributionItem(ignoreAncestorAction); 3864 fIgnoreAncestorItem.setVisible(false); 3865 tbm.appendToGroup("modes", fIgnoreAncestorItem); 3867 tbm.add(new Separator()); 3868 3869 Action a= new Action() { 3870 public void run() { 3871 if (navigate(true, false, false)) { 3872 endOfDocumentReached(true); 3873 } 3874 } 3875 }; 3876 Utilities.initAction(a, getResourceBundle(), "action.NextDiff."); fNextDiff= new ActionContributionItem(a); 3878 tbm.appendToGroup("navigation", fNextDiff); 3881 a= new Action() { 3882 public void run() { 3883 if (navigate(false, false, false)) { 3884 endOfDocumentReached(false); 3885 } 3886 } 3887 }; 3888 Utilities.initAction(a, getResourceBundle(), "action.PrevDiff."); fPreviousDiff= new ActionContributionItem(a); 3890 tbm.appendToGroup("navigation", fPreviousDiff); 3893 a= new Action() { 3894 public void run() { 3895 if (navigate(true, false, true)) { 3896 endOfDocumentReached(true); 3897 } 3898 } 3899 }; 3900 Utilities.initAction(a, getResourceBundle(), "action.NextChange."); fNextChange= new ActionContributionItem(a); 3902 tbm.appendToGroup("navigation", fNextChange); fHandlerService.registerAction(a, "org.eclipse.compare.selectNextChange"); 3905 a= new Action() { 3906 public void run() { 3907 if (navigate(false, false, true)) { 3908 endOfDocumentReached(false); 3909 } 3910 } 3911 }; 3912 Utilities.initAction(a, getResourceBundle(), "action.PrevChange."); fPreviousChange= new ActionContributionItem(a); 3914 tbm.appendToGroup("navigation", fPreviousChange); fHandlerService.registerAction(a, "org.eclipse.compare.selectPreviousChange"); 3917 CompareConfiguration cc= getCompareConfiguration(); 3918 3919 if (cc.isRightEditable()) { 3920 a= new Action() { 3921 public void run() { 3922 copyDiffLeftToRight(); 3923 } 3924 }; 3925 Utilities.initAction(a, getResourceBundle(), "action.CopyDiffLeftToRight."); fCopyDiffLeftToRightItem= new ActionContributionItem(a); 3927 fCopyDiffLeftToRightItem.setVisible(true); 3928 tbm.appendToGroup("merge", fCopyDiffLeftToRightItem); fHandlerService.registerAction(a, "org.eclipse.compare.copyLeftToRight"); } 3931 3932 if (cc.isLeftEditable()) { 3933 a= new Action() { 3934 public void run() { 3935 copyDiffRightToLeft(); 3936 } 3937 }; 3938 Utilities.initAction(a, getResourceBundle(), "action.CopyDiffRightToLeft."); fCopyDiffRightToLeftItem= new ActionContributionItem(a); 3940 fCopyDiffRightToLeftItem.setVisible(true); 3941 tbm.appendToGroup("merge", fCopyDiffRightToLeftItem); fHandlerService.registerAction(a, "org.eclipse.compare.copyRightToLeft"); } 3944 3945 fIgnoreWhitespace= ChangePropertyAction.createIgnoreWhiteSpaceAction(getResourceBundle(), getCompareConfiguration()); 3946 fIgnoreWhitespace.setActionDefinitionId(ICompareUIConstants.COMMAND_IGNORE_WHITESPACE); 3947 fLeft.addTextAction(fIgnoreWhitespace); 3948 fRight.addTextAction(fIgnoreWhitespace); 3949 fAncestor.addTextAction(fIgnoreWhitespace); 3950 fHandlerService.registerAction(fIgnoreWhitespace, fIgnoreWhitespace.getActionDefinitionId()); 3951 3952 showWhitespaceAction = new ShowWhitespaceAction(new MergeSourceViewer[] { 3953 fLeft, fRight, fAncestor 3954 }); 3955 fHandlerService.registerAction(showWhitespaceAction, ITextEditorActionDefinitionIds.SHOW_WHITESPACE_CHARACTERS); 3956 3957 toggleLineNumbersAction = new TextEditorPropertyAction(CompareMessages.TextMergeViewer_16, new MergeSourceViewer[] { 3958 fLeft, fRight, fAncestor 3959 }, AbstractDecoratedTextEditorPreferenceConstants.EDITOR_LINE_NUMBER_RULER); 3960 fHandlerService.registerAction(toggleLineNumbersAction, ITextEditorActionDefinitionIds.LINENUMBER_TOGGLE); 3961 } 3962 3963 3966 protected void handlePropertyChangeEvent(PropertyChangeEvent event) { 3967 3968 String key= event.getProperty(); 3969 3970 if (key.equals(CompareConfiguration.IGNORE_WHITESPACE) 3971 || key.equals(ComparePreferencePage.SHOW_PSEUDO_CONFLICTS)) { 3972 3973 fShowPseudoConflicts= fPreferenceStore.getBoolean(ComparePreferencePage.SHOW_PSEUDO_CONFLICTS); 3974 3975 update(true); 3976 selectFirstDiff(true); 3977 3978 3982 } else if (key.equals(ComparePreferencePage.USE_SINGLE_LINE)) { 3983 fUseSingleLine= fPreferenceStore.getBoolean(ComparePreferencePage.USE_SINGLE_LINE); 3984 fBasicCenterCurve= null; 3986 updateResolveStatus(); 3987 invalidateLines(); 3988 3989 } else if (key.equals(ComparePreferencePage.HIGHLIGHT_TOKEN_CHANGES)) { 3990 fHighlightTokenChanges= fPreferenceStore.getBoolean(ComparePreferencePage.HIGHLIGHT_TOKEN_CHANGES); 3991 updateResolveStatus(); 3992 updatePresentation(null); 3993 3994 3999 } else if (key.equals(fSymbolicFontName)) { 4000 updateFont(); 4001 invalidateLines(); 4002 4003 } else if (key.equals(INCOMING_COLOR) || key.equals(OUTGOING_COLOR) || key.equals(CONFLICTING_COLOR) || key.equals(RESOLVED_COLOR)) { 4004 updateColors(null); 4005 invalidateLines(); 4006 invalidateTextPresentation(); 4007 4008 } else if (key.equals(ComparePreferencePage.SYNCHRONIZE_SCROLLING)) { 4009 boolean b= fPreferenceStore.getBoolean(ComparePreferencePage.SYNCHRONIZE_SCROLLING); 4010 setSyncScrolling(b); 4011 4012 } else if (key.equals(ComparePreferencePage.SHOW_MORE_INFO)) { 4013 4014 boolean b= fPreferenceStore.getBoolean(ComparePreferencePage.SHOW_MORE_INFO); 4015 if (b != fShowMoreInfo) { 4016 fShowMoreInfo= b; 4017 if (fShowMoreInfo) 4018 updateStatus(fCurrentDiff); 4019 else 4020 clearStatus(); 4021 } 4022 4023 } else { 4024 super.handlePropertyChangeEvent(event); 4025 4026 if (key.equals(ICompareUIConstants.PROP_IGNORE_ANCESTOR)) { 4027 update(false); 4028 selectFirstDiff(true); 4029 } 4030 } 4031 } 4032 4033 private void selectFirstDiff(boolean first) { 4034 4035 if (fLeft == null || fRight == null) { 4036 return; 4037 } 4038 if (fLeft.getDocument() == null || fRight.getDocument() == null) { 4039 return; 4040 } 4041 4042 Diff firstDiff= null; 4043 if (first) 4044 firstDiff= findNext(fRight, fChangeDiffs, -1, -1, false); 4045 else 4046 firstDiff= findPrev(fRight, fChangeDiffs, 9999999, 9999999, false); 4047 setCurrentDiff(firstDiff, true); 4048 } 4049 4050 4051 4052 private void setSyncScrolling(boolean newMode) { 4053 if (fSynchronizedScrolling != newMode) { 4054 fSynchronizedScrolling= newMode; 4055 4056 scrollVertical(0, 0, 0, null); 4057 4058 Control center= getCenterControl(); 4060 if (center != null && !center.isDisposed()) 4061 center.dispose(); 4062 4063 fLeft.getTextWidget().getVerticalBar().setVisible(!fSynchronizedScrolling); 4064 fRight.getTextWidget().getVerticalBar().setVisible(!fSynchronizedScrolling); 4065 4066 fComposite.layout(true); 4067 } 4068 } 4069 4070 protected void updateToolItems() { 4071 if (!isPatchHunk()){ 4074 if (fIgnoreAncestorItem != null) 4075 fIgnoreAncestorItem.setVisible(isThreeWay()); 4076 4077 if (fCopyDiffLeftToRightItem != null) { 4078 IAction a= fCopyDiffLeftToRightItem.getAction(); 4079 if (a != null) 4080 a.setEnabled(a.isEnabled() && !fHasErrors); 4081 } 4082 if (fCopyDiffRightToLeftItem != null) { 4083 IAction a= fCopyDiffRightToLeftItem.getAction(); 4084 if (a != null) 4085 a.setEnabled(a.isEnabled() && !fHasErrors); 4086 } 4087 4088 super.updateToolItems(); 4089 } 4090 } 4091 4092 4094 private void updateLines(IDocument d) { 4095 4096 boolean left= false; 4097 boolean right= false; 4098 4099 if (d == fLeft.getDocument()) { 4103 int l= fLeft.getLineCount(); 4104 left= fLeftLineCount != l; 4105 fLeftLineCount= l; 4106 } else if (d == fRight.getDocument()) { 4107 int l= fRight.getLineCount(); 4108 right= fRightLineCount != l; 4109 fRightLineCount= l; 4110 } 4111 4112 if (left || right) { 4113 4114 if (left) { 4115 if (fLeftCanvas != null) 4116 fLeftCanvas.redraw(); 4117 } else { 4118 if (fRightCanvas != null) 4119 fRightCanvas.redraw(); 4120 } 4121 Control center= getCenterControl(); 4122 if (center != null) 4123 center.redraw(); 4124 4125 updateVScrollBar(); 4126 refreshBirdsEyeView(); 4127 } 4128 } 4129 4130 private void invalidateLines() { 4131 if (isThreeWay()) { 4132 if (Utilities.okToUse(fAncestorCanvas)) 4133 fAncestorCanvas.redraw(); 4134 if (fAncestor != null && fAncestor.isControlOkToUse()) 4135 fAncestor.getTextWidget().redraw(); 4136 } 4137 4138 if (Utilities.okToUse(fLeftCanvas)) 4139 fLeftCanvas.redraw(); 4140 4141 if (fLeft != null && fLeft.isControlOkToUse()) 4142 fLeft.getTextWidget().redraw(); 4143 4144 if (Utilities.okToUse(getCenterControl())) 4145 getCenterControl().redraw(); 4146 4147 if (fRight != null && fRight.isControlOkToUse()) 4148 fRight.getTextWidget().redraw(); 4149 4150 if (Utilities.okToUse(fRightCanvas)) 4151 fRightCanvas.redraw(); 4152 } 4153 4154 private boolean showResolveUI() { 4155 if (!fUseResolveUI || !isThreeWay() || isIgnoreAncestor()) 4156 return false; 4157 CompareConfiguration cc= getCompareConfiguration(); 4158 boolean l= cc.isLeftEditable(); 4160 boolean r= cc.isRightEditable(); 4161 return l || r; 4163 } 4164 4165 private void paintCenter(Canvas canvas, GC g) { 4166 4167 Display display= canvas.getDisplay(); 4168 4169 checkForColorUpdate(display); 4170 4171 if (! fSynchronizedScrolling) 4172 return; 4173 4174 int lineHeight= fLeft.getTextWidget().getLineHeight(); 4175 int visibleHeight= fRight.getViewportHeight(); 4176 4177 Point size= canvas.getSize(); 4178 int x= 0; 4179 int w= size.x; 4180 4181 g.setBackground(canvas.getBackground()); 4182 g.fillRectangle(x+1, 0, w-2, size.y); 4183 4184 if (!fIsMotif) { 4185 g.setBackground(display.getSystemColor(SWT.COLOR_WIDGET_NORMAL_SHADOW)); 4187 g.fillRectangle(0, 0, 1, size.y); 4188 g.fillRectangle(w-1, 0, 1, size.y); 4189 } 4190 4191 if (! fHighlightRanges) 4192 return; 4193 4194 boolean showResolveUI= showResolveUI(); 4195 4196 if (fChangeDiffs != null) { 4197 int lshift= fLeft.getVerticalScrollOffset(); 4198 int rshift= fRight.getVerticalScrollOffset(); 4199 4200 Point region= new Point(0, 0); 4201 4202 Iterator e= fChangeDiffs.iterator(); 4203 while (e.hasNext()) { 4204 Diff diff= (Diff) e.next(); 4205 if (diff.isDeleted()) 4206 continue; 4207 4208 if (fShowCurrentOnly2 && !isCurrentDiff(diff)) 4209 continue; 4210 4211 fLeft.getLineRange(diff.fLeftPos, region); 4212 int ly= (region.x * lineHeight) + lshift; 4213 int lh= region.y * lineHeight; 4214 4215 fRight.getLineRange(diff.fRightPos, region); 4216 int ry= (region.x * lineHeight) + rshift; 4217 int rh= region.y * lineHeight; 4218 4219 if (Math.max(ly+lh, ry+rh) < 0) 4220 continue; 4221 if (Math.min(ly, ry) >= visibleHeight) 4222 break; 4223 4224 fPts[0]= x; fPts[1]= ly; fPts[2]= w; fPts[3]= ry; 4225 fPts[6]= x; fPts[7]= ly+lh; fPts[4]= w; fPts[5]= ry+rh; 4226 4227 Color fillColor= getColor(display, getFillColor(diff)); 4228 Color strokeColor= getColor(display, getStrokeColor(diff)); 4229 4230 if (fUseSingleLine) { 4231 int w2= 3; 4232 4233 g.setBackground(fillColor); 4234 g.fillRectangle(0, ly, w2, lh); g.fillRectangle(w-w2, ry, w2, rh); 4237 g.setLineWidth(0 ); 4238 g.setForeground(strokeColor); 4239 g.drawRectangle(0-1, ly, w2, lh); g.drawRectangle(w-w2, ry, w2, rh); 4242 if (fUseSplines) { 4243 int[] points= getCenterCurvePoints(w2, ly+lh/2, w-w2, ry+rh/2); 4244 for (int i= 1; i < points.length; i++) 4245 g.drawLine(w2+i-1, points[i-1], w2+i, points[i]); 4246 } else { 4247 g.drawLine(w2, ly+lh/2, w-w2, ry+rh/2); 4248 } 4249 } else { 4250 if (fUseSplines) { 4252 g.setBackground(fillColor); 4253 4254 g.setLineWidth(0 ); 4255 g.setForeground(strokeColor); 4256 4257 int[] topPoints= getCenterCurvePoints(fPts[0], fPts[1], fPts[2], fPts[3]); 4258 int[] bottomPoints= getCenterCurvePoints(fPts[6], fPts[7], fPts[4], fPts[5]); 4259 g.setForeground(fillColor); 4260 g.drawLine(0, bottomPoints[0], 0, topPoints[0]); 4261 for (int i= 1; i < bottomPoints.length; i++) { 4262 g.setForeground(fillColor); 4263 g.drawLine(i, bottomPoints[i], i, topPoints[i]); 4264 g.setForeground(strokeColor); 4265 g.drawLine(i-1, topPoints[i-1], i, topPoints[i]); 4266 g.drawLine(i-1, bottomPoints[i-1], i, bottomPoints[i]); 4267 } 4268 } else { 4269 g.setBackground(fillColor); 4270 g.fillPolygon(fPts); 4271 4272 g.setLineWidth(0 ); 4273 g.setForeground(strokeColor); 4274 g.drawLine(fPts[0], fPts[1], fPts[2], fPts[3]); 4275 g.drawLine(fPts[6], fPts[7], fPts[4], fPts[5]); 4276 } 4277 } 4278 4279 if (fUseSingleLine && showResolveUI && diff.isUnresolvedIncomingOrConflicting()) { 4280 int cx= (w-RESOLVE_SIZE)/2; 4282 int cy= ((ly+lh/2) + (ry+rh/2) - RESOLVE_SIZE)/2; 4283 4284 g.setBackground(fillColor); 4285 g.fillRectangle(cx, cy, RESOLVE_SIZE, RESOLVE_SIZE); 4286 4287 g.setForeground(strokeColor); 4288 g.drawRectangle(cx, cy, RESOLVE_SIZE, RESOLVE_SIZE); 4289 } 4290 } 4291 } 4292 } 4293 4294 private int[] getCenterCurvePoints(int startx, int starty, int endx, int endy) { 4295 if (fBasicCenterCurve == null) 4296 buildBaseCenterCurve(endx-startx); 4297 double height= endy - starty; 4298 height= height/2; 4299 int width= endx-startx; 4300 int[] points= new int[width]; 4301 for (int i= 0; i < width; i++) { 4302 points[i]= (int) (-height * fBasicCenterCurve[i] + height + starty); 4303 } 4304 return points; 4305 } 4306 4307 private void buildBaseCenterCurve(int w) { 4308 double width= w; 4309 fBasicCenterCurve= new double[getCenterWidth()]; 4310 for (int i= 0; i < getCenterWidth(); i++) { 4311 double r= i / width; 4312 fBasicCenterCurve[i]= Math.cos(Math.PI * r); 4313 } 4314 } 4315 4316 private void paintSides(GC g, MergeSourceViewer tp, Canvas canvas, boolean right) { 4317 4318 Display display= canvas.getDisplay(); 4319 4320 int lineHeight= tp.getTextWidget().getLineHeight(); 4321 int visibleHeight= tp.getViewportHeight(); 4322 4323 Point size= canvas.getSize(); 4324 int x= 0; 4325 int w= fMarginWidth; 4326 int w2= w/2; 4327 4328 g.setBackground(canvas.getBackground()); 4329 g.fillRectangle(x, 0, w, size.y); 4330 4331 if (!fIsMotif) { 4332 g.setBackground(display.getSystemColor(SWT.COLOR_WIDGET_NORMAL_SHADOW)); 4334 if (right) 4335 g.fillRectangle(0, 0, 1, size.y); 4336 else 4337 g.fillRectangle(size.x-1, 0, 1, size.y); 4338 } 4339 4340 if (! fHighlightRanges) 4341 return; 4342 4343 if (fChangeDiffs != null) { 4344 int shift= tp.getVerticalScrollOffset() + (2-LW); 4345 4346 Point region= new Point(0, 0); 4347 Iterator e= fChangeDiffs.iterator(); 4348 while (e.hasNext()) { 4349 Diff diff= (Diff) e.next(); 4350 if (diff.isDeleted()) 4351 continue; 4352 4353 if (fShowCurrentOnly2 && !isCurrentDiff(diff)) 4354 continue; 4355 4356 tp.getLineRange(diff.getPosition(tp), region); 4357 int y= (region.x * lineHeight) + shift; 4358 int h= region.y * lineHeight; 4359 4360 if (y+h < 0) 4361 continue; 4362 if (y >= visibleHeight) 4363 break; 4364 4365 g.setBackground(getColor(display, getFillColor(diff))); 4366 if (right) 4367 g.fillRectangle(x, y, w2, h); 4368 else 4369 g.fillRectangle(x+w2, y, w2, h); 4370 4371 g.setLineWidth(0 ); 4372 g.setForeground(getColor(display, getStrokeColor(diff))); 4373 if (right) 4374 g.drawRectangle(x-1, y-1, w2, h); 4375 else 4376 g.drawRectangle(x+w2, y-1, w2, h); 4377 } 4378 } 4379 } 4380 4381 private void paint(PaintEvent event, MergeSourceViewer tp) { 4382 4383 if (! fHighlightRanges) 4384 return; 4385 if (fChangeDiffs == null) 4386 return; 4387 4388 Control canvas= (Control) event.widget; 4389 GC g= event.gc; 4390 4391 Display display= canvas.getDisplay(); 4392 4393 int lineHeight= tp.getTextWidget().getLineHeight(); 4394 int w= canvas.getSize().x; 4395 int shift= tp.getVerticalScrollOffset() + (2-LW); 4396 int maxh= event.y+event.height; 4398 shift+= fTopInset; 4400 4401 Point range= new Point(0, 0); 4402 4403 Iterator e= fChangeDiffs.iterator(); 4404 while (e.hasNext()) { 4405 Diff diff= (Diff) e.next(); 4406 if (diff.isDeleted()) 4407 continue; 4408 4409 if (fShowCurrentOnly && !isCurrentDiff(diff)) 4410 continue; 4411 4412 tp.getLineRange(diff.getPosition(tp), range); 4413 int y= (range.x * lineHeight) + shift; 4414 int h= range.y * lineHeight; 4415 4416 if (y+h < event.y) 4417 continue; 4418 if (y > maxh) 4419 break; 4420 4421 g.setBackground(getColor(display, getStrokeColor(diff))); 4422 g.fillRectangle(0, y-1, w, LW); 4423 g.fillRectangle(0, y+h-1, w, LW); 4424 } 4425 } 4426 4427 private RGB getFillColor(Diff diff) { 4428 boolean selected= fCurrentDiff != null && fCurrentDiff.fParent == diff; 4429 RGB selected_fill= getBackground(null); 4430 if (isThreeWay() && !isIgnoreAncestor()) { 4431 switch (diff.fDirection) { 4432 case RangeDifference.RIGHT: 4433 if (fLeftIsLocal) 4434 return selected ? selected_fill : INCOMING_FILL; 4435 return selected ? selected_fill : OUTGOING_FILL; 4436 case RangeDifference.ANCESTOR: 4437 return selected ? selected_fill : CONFLICT_FILL; 4438 case RangeDifference.LEFT: 4439 if (fLeftIsLocal) 4440 return selected ? selected_fill : OUTGOING_FILL; 4441 return selected ? selected_fill : INCOMING_FILL; 4442 case RangeDifference.CONFLICT: 4443 return selected ? selected_fill : CONFLICT_FILL; 4444 } 4445 return null; 4446 } 4447 return selected ? selected_fill : OUTGOING_FILL; 4448 } 4449 4450 private RGB getStrokeColor(Diff diff) { 4451 boolean selected= fCurrentDiff != null && fCurrentDiff.fParent == diff; 4452 4453 if (isThreeWay() && !isIgnoreAncestor()) { 4454 switch (diff.fDirection) { 4455 case RangeDifference.RIGHT: 4456 if (fLeftIsLocal) 4457 return selected ? SELECTED_INCOMING : INCOMING; 4458 return selected ? SELECTED_OUTGOING : OUTGOING; 4459 case RangeDifference.ANCESTOR: 4460 return selected ? SELECTED_CONFLICT : CONFLICT; 4461 case RangeDifference.LEFT: 4462 if (fLeftIsLocal) 4463 return selected ? SELECTED_OUTGOING : OUTGOING; 4464 return selected ? SELECTED_INCOMING : INCOMING; 4465 case RangeDifference.CONFLICT: 4466 return selected ? SELECTED_CONFLICT : CONFLICT; 4467 } 4468 return null; 4469 } 4470 return selected ? SELECTED_OUTGOING : OUTGOING; 4471 } 4472 4473 private Color getColor(Display display, RGB rgb) { 4474 if (rgb == null) 4475 return null; 4476 if (fColors == null) 4477 fColors= new HashMap(20); 4478 Color c= (Color) fColors.get(rgb); 4479 if (c == null) { 4480 c= new Color(display, rgb); 4481 fColors.put(rgb, c); 4482 } 4483 return c; 4484 } 4485 4486 static RGB interpolate(RGB fg, RGB bg, double scale) { 4487 if (fg != null && bg != null) 4488 return new RGB( 4489 (int)((1.0-scale) * fg.red + scale * bg.red), 4490 (int)((1.0-scale) * fg.green + scale * bg.green), 4491 (int)((1.0-scale) * fg.blue + scale * bg.blue) 4492 ); 4493 if (fg != null) 4494 return fg; 4495 if (bg != null) 4496 return bg; 4497 return new RGB(128, 128, 128); } 4499 4500 4502 private Diff getNextVisibleDiff(boolean down, boolean deep) { 4503 Diff diff= null; 4504 MergeSourceViewer part= getNavigationPart(); 4505 if (part == null) 4506 return null; 4507 Point s = part.getSelectedRange(); 4508 for (;;) { 4509 diff = null; 4510 diff = internalGetNextDiff(down, deep, part, s); 4511 if (diff != null && diff.fDirection == RangeDifference.ANCESTOR 4512 && !isAncestorVisible()) { 4513 Position position = diff.getPosition(part); 4514 s = new Point(position.getOffset(), position.getLength()); 4515 diff= null; 4516 continue; 4517 } 4518 break; 4519 } 4520 return diff; 4521 } 4522 4523 private Diff internalGetNextDiff(boolean down, boolean deep, MergeSourceViewer part, Point s) { 4524 if (fChangeDiffs != null) { 4525 if (down) 4526 return findNext(part, fChangeDiffs, s.x, s.x+s.y, deep); 4527 return findPrev(part, fChangeDiffs, s.x, s.x+s.y, deep); 4528 } 4529 return null; 4530 } 4531 4532 private MergeSourceViewer getNavigationPart() { 4533 MergeSourceViewer part= fFocusPart; 4534 if (part == null) 4535 part= fRight; 4536 return part; 4537 } 4538 4539 private Diff getWrappedDiff(Diff diff, boolean down) { 4540 if (fChangeDiffs != null && fChangeDiffs.size() > 0) { 4541 if (down) 4542 return (Diff) fChangeDiffs.get(0); 4543 return (Diff) fChangeDiffs.get(fChangeDiffs.size()-1); 4544 } 4545 return null; 4546 } 4547 4548 4551 private boolean navigate(boolean down, boolean wrap, boolean deep) { 4552 Diff diff= null; 4553 boolean wrapped = false; 4554 for (;;) { 4555 diff = getNextVisibleDiff(down, deep); 4556 if (diff == null && wrap) { 4557 if (wrapped) 4558 break; 4560 wrapped = true; 4561 diff = getWrappedDiff(diff, down); 4562 } 4563 if (diff != null) 4564 setCurrentDiff(diff, true, deep); 4565 if (diff != null && diff.fDirection == RangeDifference.ANCESTOR 4566 && !isAncestorVisible()) 4567 continue; 4568 break; 4569 } 4570 return diff == null; 4571 } 4572 4573 private void endOfDocumentReached(boolean down) { 4574 Control c= getControl(); 4575 if (Utilities.okToUse(c)) { 4576 handleEndOfDocumentReached(c.getShell(), down); 4577 } 4578 } 4579 4580 private void handleEndOfDocumentReached(Shell shell, boolean next) { 4581 boolean hasNextElement = hasNextElement(next); 4582 IPreferenceStore store = CompareUIPlugin.getDefault().getPreferenceStore(); 4583 String value = store.getString(ICompareUIConstants.PREF_NAVIGATION_END_ACTION); 4584 if (!value.equals(ICompareUIConstants.PREF_VALUE_PROMPT)) { 4585 if (hasNextElement || store.getString(ICompareUIConstants.PREF_NAVIGATION_END_ACTION).equals(ICompareUIConstants.PREF_VALUE_LOOP)) { 4587 performEndOfDocumentAction(shell, store, ICompareUIConstants.PREF_NAVIGATION_END_ACTION, next); 4588 return; 4589 } 4590 } 4591 shell.getDisplay().beep(); 4592 if (hasNextElement) { 4593 String loopMessage; 4594 String nextMessage; 4595 String message; 4596 String title; 4597 if (next) { 4598 title = CompareMessages.TextMergeViewer_0; 4599 message = CompareMessages.TextMergeViewer_1; 4600 loopMessage = CompareMessages.TextMergeViewer_2; 4601 nextMessage = CompareMessages.TextMergeViewer_3; 4602 } else { 4603 title = CompareMessages.TextMergeViewer_4; 4604 message = CompareMessages.TextMergeViewer_5; 4605 loopMessage = CompareMessages.TextMergeViewer_6; 4606 nextMessage = CompareMessages.TextMergeViewer_7; 4607 } 4608 String [] localLoopOption = new String [] { loopMessage, ICompareUIConstants.PREF_VALUE_LOOP }; 4609 String [] nextElementOption = new String [] { nextMessage, ICompareUIConstants.PREF_VALUE_NEXT}; 4610 NavigationEndDialog dialog = new NavigationEndDialog(shell, 4611 title, 4612 null, 4613 message, 4614 new String [][] { 4615 localLoopOption, 4616 nextElementOption, 4617 }); 4618 int result = dialog.open(); 4619 if (result == Window.OK) { 4620 performEndOfDocumentAction(shell, store, ICompareUIConstants.PREF_NAVIGATION_END_ACTION_LOCAL, next); 4621 if (dialog.getToggleState()) { 4622 store.putValue(ICompareUIConstants.PREF_NAVIGATION_END_ACTION, store.getString(ICompareUIConstants.PREF_NAVIGATION_END_ACTION_LOCAL)); 4623 } 4624 } 4625 } else { 4626 String message; 4627 String title; 4628 if (next) { 4629 title = CompareMessages.TextMergeViewer_8; 4630 message = CompareMessages.TextMergeViewer_9; 4631 } else { 4632 title = CompareMessages.TextMergeViewer_10; 4633 message = CompareMessages.TextMergeViewer_11; 4634 } 4635 if (MessageDialog.openQuestion(shell, title, message)) { 4636 selectFirstDiff(next); 4637 } 4638 } 4639 } 4640 4641 private void performEndOfDocumentAction(Shell shell, IPreferenceStore store, String key, boolean next) { 4642 String value = store.getString(key); 4643 if (value.equals(ICompareUIConstants.PREF_VALUE_NEXT)) { 4644 ICompareNavigator navigator = getCompareConfiguration().getContainer().getNavigator(); 4645 if (hasNextElement(next)) 4646 navigator.selectChange(next); 4647 else 4648 shell.getDisplay().beep(); 4649 } else { 4650 selectFirstDiff(next); 4651 } 4652 } 4653 4654 private boolean hasNextElement(boolean down) { 4655 ICompareNavigator navigator = getCompareConfiguration().getContainer().getNavigator(); 4656 if (navigator instanceof CompareNavigator) { 4657 CompareNavigator n = (CompareNavigator) navigator; 4658 return n.hasChange(down); 4659 } 4660 return false; 4661 } 4662 4663 4668 private Diff findDiff(MergeSourceViewer tp, int rangeStart, int rangeEnd) { 4669 if (fChangeDiffs != null) { 4670 Iterator e= fChangeDiffs.iterator(); 4671 while (e.hasNext()) { 4672 Diff diff= (Diff) e.next(); 4673 if (diff.overlaps(tp, rangeStart, rangeEnd)) 4674 return diff; 4675 } 4676 } 4677 return null; 4678 } 4679 4680 private static Diff findNext(MergeSourceViewer tp, List v, int start, int end, boolean deep) { 4681 for (int i= 0; i < v.size(); i++) { 4682 Diff diff= (Diff) v.get(i); 4683 Position p= diff.getPosition(tp); 4684 if (p != null) { 4685 int startOffset= p.getOffset(); 4686 if (end < startOffset) return diff; 4688 if (deep && diff.fDiffs != null) { 4689 Diff d= null; 4690 int endOffset= startOffset + p.getLength(); 4691 if (start == startOffset && (end == endOffset || end == endOffset-1)) { 4692 d= findNext(tp, diff.fDiffs, start-1, start-1, deep); 4693 } else if (end < endOffset) { 4694 d= findNext(tp, diff.fDiffs, start, end, deep); 4695 } 4696 if (d != null) 4697 return d; 4698 } 4699 } 4700 } 4701 return null; 4702 } 4703 4704 private static Diff findPrev(MergeSourceViewer tp, List v, int start, int end, boolean deep) { 4705 for (int i= v.size()-1; i >= 0; i--) { 4706 Diff diff= (Diff) v.get(i); 4707 Position p= diff.getPosition(tp); 4708 if (p != null) { 4709 int startOffset= p.getOffset(); 4710 int endOffset= startOffset + p.getLength(); 4711 if (start > endOffset) { 4712 if (deep && diff.fDiffs != null) { 4713 return findPrev(tp, diff.fDiffs, end, end, deep); 4715 } 4716 return diff; 4717 } 4718 if (deep && diff.fDiffs != null) { 4719 Diff d= null; 4720 if (start == startOffset && end == endOffset) { 4721 } else if (start >= startOffset) { 4724 if (isFirstDiff(tp, startOffset, diff.fDiffs)) { 4727 return diff; 4728 } 4729 d= findPrev(tp, diff.fDiffs, start, end, deep); 4730 } 4731 if (d != null) 4732 return d; 4733 } 4734 } 4735 } 4736 return null; 4737 } 4738 4739 private static boolean isFirstDiff(MergeSourceViewer tp, int startOffset, 4740 ArrayList diffs) { 4741 if (diffs.isEmpty()) 4742 return false; 4743 Diff diff = (Diff)diffs.get(0); 4744 Position p= diff.getPosition(tp); 4745 return (p.getOffset() >= startOffset); 4746 } 4747 4748 4753 private void setCurrentDiff(Diff d, boolean revealAndSelect) { 4754 setCurrentDiff(d, revealAndSelect, false); 4755 } 4756 4757 4762 private void setCurrentDiff(Diff d, boolean revealAndSelect, boolean deep) { 4763 4764 4767 if (fCenterButton != null && !fCenterButton.isDisposed()) 4768 fCenterButton.setVisible(false); 4769 4770 Diff oldDiff= fCurrentDiff; 4771 4772 if (d != null && revealAndSelect) { 4773 4774 if (d.fIsToken || !fHighlightTokenChanges || deep || !d.hasChildren()) { 4778 if (isThreeWay() && !isIgnoreAncestor()) 4779 fAncestor.setSelection(d.fAncestorPos); 4780 fLeft.setSelection(d.fLeftPos); 4781 fRight.setSelection(d.fRightPos); 4782 } else { 4783 if (isThreeWay() && !isIgnoreAncestor()) 4784 fAncestor.setSelection(new Position(d.fAncestorPos.offset, 0)); 4785 fLeft.setSelection(new Position(d.fLeftPos.offset, 0)); 4786 fRight.setSelection(new Position(d.fRightPos.offset, 0)); 4787 } 4788 4789 fCurrentDiff= d; 4791 revealDiff(d, d.fIsToken); 4792 } else { 4793 fCurrentDiff= d; 4794 } 4795 4796 Diff d1= oldDiff != null ? oldDiff.fParent : null; 4797 Diff d2= fCurrentDiff != null ? fCurrentDiff.fParent : null; 4798 if (d1 != d2) { 4799 updateDiffBackground(d1); 4800 updateDiffBackground(d2); 4801 } 4802 4803 updateControls(); 4804 invalidateLines(); 4805 refreshBirdsEyeView(); 4806 } 4807 4808 4811 private void revealDiff(Diff d, boolean smart) { 4812 4813 boolean ancestorIsVisible= false; 4814 boolean leftIsVisible= false; 4815 boolean rightIsVisible= false; 4816 4817 if (smart) { 4818 Point region= new Point(0, 0); 4819 int ls= fLeft.getLineRange(d.fLeftPos, region).x; 4821 int rs= fRight.getLineRange(d.fRightPos, region).x; 4822 4823 if (isThreeWay() && !isIgnoreAncestor()) { 4824 int as= fAncestor.getLineRange(d.fAncestorPos, region).x; 4825 if (as >= fAncestor.getTopIndex() && as <= fAncestor.getBottomIndex()) 4826 ancestorIsVisible= true; 4827 } 4828 4829 if (ls >= fLeft.getTopIndex() && ls <= fLeft.getBottomIndex()) 4830 leftIsVisible= true; 4831 4832 if (rs >= fRight.getTopIndex() && rs <= fRight.getBottomIndex()) 4833 rightIsVisible= true; 4834 } 4835 4836 if (!leftIsVisible || !rightIsVisible) { 4838 int avpos= 0, lvpos= 0, rvpos= 0; 4839 4840 MergeSourceViewer allButThis= null; 4841 if (leftIsVisible) { 4842 avpos= lvpos= rvpos= realToVirtualPosition(fLeft, fLeft.getTopIndex()); 4843 allButThis= fLeft; 4844 } else if (rightIsVisible) { 4845 avpos= lvpos= rvpos= realToVirtualPosition(fRight, fRight.getTopIndex()); 4846 allButThis= fRight; 4847 } else if (ancestorIsVisible) { 4848 avpos= lvpos= rvpos= realToVirtualPosition(fAncestor, fAncestor.getTopIndex()); 4849 allButThis= fAncestor; 4850 } else { 4851 if (fAllDiffs != null) { 4852 int vpos= 0; 4853 Iterator e= fAllDiffs.iterator(); 4854 for (int i= 0; e.hasNext(); i++) { 4855 Diff diff= (Diff) e.next(); 4856 if (diff == d) 4857 break; 4858 if (fSynchronizedScrolling) { 4859 vpos+= diff.getMaxDiffHeight(); 4860 } else { 4861 avpos+= diff.getAncestorHeight(); 4862 lvpos+= diff.getLeftHeight(); 4863 rvpos+= diff.getRightHeight(); 4864 } 4865 } 4866 if (fSynchronizedScrolling) 4867 avpos= lvpos= rvpos= vpos; 4868 } 4869 int delta= fRight.getViewportLines()/4; 4870 avpos-= delta; 4871 if (avpos < 0) 4872 avpos= 0; 4873 lvpos-= delta; 4874 if (lvpos < 0) 4875 lvpos= 0; 4876 rvpos-= delta; 4877 if (rvpos < 0) 4878 rvpos= 0; 4879 } 4880 4881 scrollVertical(avpos, lvpos, rvpos, allButThis); 4882 4883 if (fVScrollBar != null) 4884 fVScrollBar.setSelection(avpos); 4885 } 4886 4887 if (d.fIsToken) { 4889 reveal(fAncestor, d.fAncestorPos); 4891 reveal(fLeft, d.fLeftPos); 4892 reveal(fRight, d.fRightPos); 4893 } else { 4894 hscroll(fAncestor); 4896 hscroll(fLeft); 4897 hscroll(fRight); 4898 } 4899 } 4900 4901 private static void reveal(MergeSourceViewer v, Position p) { 4902 if (v != null && p != null) { 4903 StyledText st= v.getTextWidget(); 4904 if (st != null) { 4905 Rectangle r= st.getClientArea(); 4906 if (!r.isEmpty()) v.revealRange(p.offset, p.length); 4908 } 4909 } 4910 } 4911 4912 private static void hscroll(MergeSourceViewer v) { 4913 if (v != null) { 4914 StyledText st= v.getTextWidget(); 4915 if (st != null) 4916 st.setHorizontalIndex(0); 4917 } 4918 } 4919 4920 4922 void copyAllUnresolved(boolean leftToRight) { 4923 if (fChangeDiffs != null && isThreeWay() && !isIgnoreAncestor()) { 4924 IRewriteTarget target= leftToRight ? fRight.getRewriteTarget() : fLeft.getRewriteTarget(); 4925 boolean compoundChangeStarted= false; 4926 Iterator e= fChangeDiffs.iterator(); 4927 try { 4928 while (e.hasNext()) { 4929 Diff diff= (Diff) e.next(); 4930 switch (diff.fDirection) { 4931 case RangeDifference.LEFT: 4932 if (leftToRight) { 4933 if (!compoundChangeStarted) { 4934 target.beginCompoundChange(); 4935 compoundChangeStarted= true; 4936 } 4937 copy(diff, leftToRight); 4938 } 4939 break; 4940 case RangeDifference.RIGHT: 4941 if (!leftToRight) { 4942 if (!compoundChangeStarted) { 4943 target.beginCompoundChange(); 4944 compoundChangeStarted= true; 4945 } 4946 copy(diff, leftToRight); 4947 } 4948 break; 4949 default: 4950 continue; 4951 } 4952 } 4953 } finally { 4954 if (compoundChangeStarted) { 4955 target.endCompoundChange(); 4956 } 4957 } 4958 } 4959 } 4960 4961 4964 protected void copy(boolean leftToRight) { 4965 if (!validateChange(!leftToRight)) 4966 return; 4967 if (showResolveUI()) { 4968 copyAllUnresolved(leftToRight); 4969 invalidateLines(); 4970 return; 4971 } 4972 4973 if (leftToRight) { 4974 if (fLeft.getEnabled()) { 4975 String text= fLeft.getTextWidget().getText(); 4977 fRight.getTextWidget().setText(text); 4978 fRight.setEnabled(true); 4979 } else { 4980 fRight.getTextWidget().setText(""); fRight.setEnabled(false); 4983 } 4984 fRightLineCount= fRight.getLineCount(); 4985 setRightDirty(true); 4986 } else { 4987 if (fRight.getEnabled()) { 4988 String text= fRight.getTextWidget().getText(); 4990 fLeft.getTextWidget().setText(text); 4991 fLeft.setEnabled(true); 4992 } else { 4993 fLeft.getTextWidget().setText(""); fLeft.setEnabled(false); 4996 } 4997 fLeftLineCount= fLeft.getLineCount(); 4998 setLeftDirty(true); 4999 } 5000 update(false); 5001 selectFirstDiff(true); 5002 } 5003 5004 private void copyDiffLeftToRight() { 5005 copy(fCurrentDiff, true, false); 5006 } 5007 5008 private void copyDiffRightToLeft() { 5009 copy(fCurrentDiff, false, false); 5010 } 5011 5012 5015 private void copy(Diff diff, boolean leftToRight, boolean gotoNext) { 5016 if (copy(diff, leftToRight)) { 5017 if (gotoNext) { 5018 navigate(true, true, false ); 5019 } else { 5020 revealDiff(diff, true); 5021 updateControls(); 5022 } 5023 } 5024 } 5025 5026 5031 private boolean copy(Diff diff, boolean leftToRight) { 5032 5033 if (diff != null && !diff.isResolved()) { 5034 if (!validateChange(!leftToRight)) 5035 return false; 5036 Position fromPos= null; 5037 Position toPos= null; 5038 IDocument fromDoc= null; 5039 IDocument toDoc= null; 5040 5041 if (leftToRight) { 5042 fRight.setEnabled(true); 5043 fromPos= diff.fLeftPos; 5044 toPos= diff.fRightPos; 5045 fromDoc= fLeft.getDocument(); 5046 toDoc= fRight.getDocument(); 5047 } else { 5048 fLeft.setEnabled(true); 5049 fromPos= diff.fRightPos; 5050 toPos= diff.fLeftPos; 5051 fromDoc= fRight.getDocument(); 5052 toDoc= fLeft.getDocument(); 5053 } 5054 5055 if (fromDoc != null) { 5056 5057 int fromStart= fromPos.getOffset(); 5058 int fromLen= fromPos.getLength(); 5059 5060 int toStart= toPos.getOffset(); 5061 int toLen= toPos.getLength(); 5062 5063 try { 5064 String s= null; 5065 5066 switch (diff.fDirection) { 5067 case RangeDifference.RIGHT: 5068 case RangeDifference.LEFT: 5069 s= fromDoc.get(fromStart, fromLen); 5070 break; 5071 case RangeDifference.ANCESTOR: 5072 break; 5073 case RangeDifference.CONFLICT: 5074 if (APPEND_CONFLICT) { 5075 s= toDoc.get(toStart, toLen); 5076 s+= fromDoc.get(fromStart, fromLen); 5077 } else 5078 s= fromDoc.get(fromStart, fromLen); 5079 break; 5080 } 5081 if (s != null) { 5082 toDoc.replace(toStart, toLen, s); 5083 toPos.setOffset(toStart); 5084 toPos.setLength(s.length()); 5085 } 5086 5087 } catch (BadLocationException e) { 5088 } 5090 } 5091 5092 diff.setResolved(true); 5093 updateResolveStatus(); 5094 5095 return true; 5096 } 5097 return false; 5098 } 5099 5100 private boolean validateChange(boolean left) { 5101 ContributorInfo info; 5102 if (left) 5103 info = fLeftContributor; 5104 else 5105 info = fRightContributor; 5106 5107 return info.validateChange(); 5108 } 5109 5110 5112 5115 private int getVirtualHeight() { 5116 int h= 1; 5117 if (fAllDiffs != null) { 5118 Iterator e= fAllDiffs.iterator(); 5119 for (int i= 0; e.hasNext(); i++) { 5120 Diff diff= (Diff) e.next(); 5121 h+= diff.getMaxDiffHeight(); 5122 } 5123 } 5124 return h; 5125 } 5126 5127 5130 private int getRightHeight() { 5131 int h= 1; 5132 if (fAllDiffs != null) { 5133 Iterator e= fAllDiffs.iterator(); 5134 for (int i= 0; e.hasNext(); i++) { 5135 Diff diff= (Diff) e.next(); 5136 h+= diff.getRightHeight(); 5137 } 5138 } 5139 return h; 5140 } 5141 5142 5145 private int getViewportHeight() { 5146 StyledText te= fLeft.getTextWidget(); 5147 5148 int vh= te.getClientArea().height; 5149 if (vh == 0) { 5150 Rectangle trim= te.computeTrim(0, 0, 0, 0); 5151 int scrollbarHeight= trim.height; 5152 5153 int headerHeight= getHeaderHeight(); 5154 5155 Composite composite= (Composite) getControl(); 5156 Rectangle r= composite.getClientArea(); 5157 5158 vh= r.height-headerHeight-scrollbarHeight; 5159 } 5160 5161 return vh / te.getLineHeight(); 5162 } 5163 5164 5167 private int realToVirtualPosition(MergeSourceViewer w, int vpos) { 5168 5169 if (! fSynchronizedScrolling || fAllDiffs == null) 5170 return vpos; 5171 5172 int viewPos= 0; int virtualPos= 0; Point region= new Point(0, 0); 5175 5176 Iterator e= fAllDiffs.iterator(); 5177 while (e.hasNext()) { 5178 Diff diff= (Diff) e.next(); 5179 Position pos= diff.getPosition(w); 5180 w.getLineRange(pos, region); 5181 int realHeight= region.y; 5182 int virtualHeight= diff.getMaxDiffHeight(); 5183 if (vpos <= viewPos + realHeight) { vpos-= viewPos; if (realHeight <= 0) 5187 vpos= 0; 5188 else 5189 vpos= (vpos*virtualHeight)/realHeight; 5190 return virtualPos+vpos; 5191 } 5192 viewPos+= realHeight; 5193 virtualPos+= virtualHeight; 5194 } 5195 return virtualPos; 5196 } 5197 5198 private void scrollVertical(int avpos, int lvpos, int rvpos, MergeSourceViewer allBut) { 5199 5200 int s= 0; 5201 5202 if (fSynchronizedScrolling) { 5203 s= getVirtualHeight() - rvpos; 5204 int height= fRight.getViewportLines()/4; 5205 if (s < 0) 5206 s= 0; 5207 if (s > height) 5208 s= height; 5209 } 5210 5211 fInScrolling= true; 5212 5213 if (isThreeWay() && allBut != fAncestor) { 5214 if (fSynchronizedScrolling || allBut == null) { 5215 int y= virtualToRealPosition(fAncestor, avpos+s)-s; 5216 fAncestor.vscroll(y); 5217 } 5218 } 5219 5220 if (allBut != fLeft) { 5221 if (fSynchronizedScrolling || allBut == null) { 5222 int y= virtualToRealPosition(fLeft, lvpos+s)-s; 5223 fLeft.vscroll(y); 5224 } 5225 } 5226 5227 if (allBut != fRight) { 5228 if (fSynchronizedScrolling || allBut == null) { 5229 int y= virtualToRealPosition(fRight, rvpos+s)-s; 5230 fRight.vscroll(y); 5231 } 5232 } 5233 5234 fInScrolling= false; 5235 5236 if (isThreeWay() && fAncestorCanvas != null) 5237 fAncestorCanvas.repaint(); 5238 5239 if (fLeftCanvas != null) 5240 fLeftCanvas.repaint(); 5241 5242 Control center= getCenterControl(); 5243 if (center instanceof BufferedCanvas) 5244 ((BufferedCanvas)center).repaint(); 5245 5246 if (fRightCanvas != null) 5247 fRightCanvas.repaint(); 5248 } 5249 5250 5253 private void syncViewport(MergeSourceViewer w) { 5254 5255 if (fInScrolling) 5256 return; 5257 5258 int ix= w.getTopIndex(); 5259 int ix2= w.getDocumentRegionOffset(); 5260 5261 int viewPosition= realToVirtualPosition(w, ix-ix2); 5262 5263 scrollVertical(viewPosition, viewPosition, viewPosition, w); 5265 if (fVScrollBar != null) { 5266 int value= Math.max(0, Math.min(viewPosition, getVirtualHeight() - getViewportHeight())); 5267 fVScrollBar.setSelection(value); 5268 } 5270 } 5271 5272 5274 private void updateVScrollBar() { 5275 5276 if (Utilities.okToUse(fVScrollBar) && fSynchronizedScrolling) { 5277 int virtualHeight= getVirtualHeight(); 5278 int viewPortHeight= getViewportHeight(); 5279 int pageIncrement= viewPortHeight-1; 5280 int thumb= (viewPortHeight > virtualHeight) ? virtualHeight : viewPortHeight; 5281 5282 fVScrollBar.setPageIncrement(pageIncrement); 5283 fVScrollBar.setMaximum(virtualHeight); 5284 fVScrollBar.setThumb(thumb); 5285 } 5286 } 5287 5288 5291 private int virtualToRealPosition(MergeSourceViewer part, int v) { 5292 5293 if (! fSynchronizedScrolling || fAllDiffs == null) 5294 return v; 5295 5296 int virtualPos= 0; 5297 int viewPos= 0; 5298 Point region= new Point(0, 0); 5299 5300 Iterator e= fAllDiffs.iterator(); 5301 while (e.hasNext()) { 5302 Diff diff= (Diff) e.next(); 5303 Position pos= diff.getPosition(part); 5304 int viewHeight= part.getLineRange(pos, region).y; 5305 int virtualHeight= diff.getMaxDiffHeight(); 5306 if (v < (virtualPos + virtualHeight)) { 5307 v-= virtualPos; if (viewHeight <= 0) { 5309 v= 0; 5310 } else { 5311 v= (int) (v * ((double)viewHeight/virtualHeight)); 5312 } 5313 return viewPos+v; 5314 } 5315 virtualPos+= virtualHeight; 5316 viewPos+= viewHeight; 5317 } 5318 return viewPos; 5319 } 5320 5321 5324 protected void flushContent(Object oldInput, IProgressMonitor monitor) { 5325 5326 IMergeViewerContentProvider content= getMergeContentProvider(); 5328 Object leftContent = content.getLeftContent(oldInput); 5329 Object rightContent = content.getRightContent(oldInput); 5330 5331 if (leftContent != null && getCompareConfiguration().isLeftEditable() && isLeftDirty()) { 5332 if (fLeftContributor.hasSharedDocument(leftContent)) { 5333 if (flush(fLeftContributor)) 5334 setLeftDirty(false); 5335 } 5336 } 5337 5338 if (rightContent != null && getCompareConfiguration().isRightEditable() && isRightDirty()) { 5339 if (fRightContributor.hasSharedDocument(rightContent)) { 5340 if (flush(fRightContributor)) 5341 setRightDirty(false); 5342 } 5343 } 5344 5345 if (!(content instanceof MergeViewerContentProvider) || isLeftDirty() || isRightDirty()) { 5346 super.flushContent(oldInput, monitor); 5347 } 5348 } 5349 5350 private boolean flush(final ContributorInfo info) { 5351 try { 5352 return info.flush(); 5353 } catch (CoreException e) { 5354 handleException(e); 5355 } 5356 return false; 5357 } 5358 5359 private void handleException(Throwable throwable) { 5360 if (throwable instanceof InvocationTargetException ) { 5362 InvocationTargetException ite = (InvocationTargetException ) throwable; 5363 handleException(ite.getTargetException()); 5364 return; 5365 } 5366 CompareUIPlugin.log(throwable); 5367 } 5368 5369 5372 public Object getAdapter(Class adapter) { 5373 if (adapter == IMergeViewerTestAdapter.class) { 5374 return new IMergeViewerTestAdapter() { 5375 public IDocument getDocument(char leg) { 5376 switch (leg) { 5377 case LEFT_CONTRIBUTOR: 5378 return fLeft.getDocument(); 5379 case RIGHT_CONTRIBUTOR: 5380 return fRight.getDocument(); 5381 case ANCESTOR_CONTRIBUTOR: 5382 return fAncestor.getDocument(); 5383 } 5384 return null; 5385 } 5386 }; 5387 } 5388 if (adapter == OutlineViewerCreator.class) { 5389 if (fOutlineViewerCreator == null) 5390 fOutlineViewerCreator = new InternalOutlineViewerCreator(); 5391 return fOutlineViewerCreator; 5392 5393 } 5394 if (adapter == IFindReplaceTarget.class) 5395 return getFindReplaceTarget(); 5396 if (adapter == CompareHandlerService.class) 5397 return fHandlerService; 5398 return null; 5399 } 5400 5401 5404 protected void handleCompareInputChange() { 5405 try { 5406 beginRefresh(); 5407 super.handleCompareInputChange(); 5408 } finally { 5409 endRefresh(); 5410 } 5411 } 5412 5413 private void beginRefresh() { 5414 isRefreshing = true; 5415 fLeftContributor.cacheSelection(fLeft); 5416 fRightContributor.cacheSelection(fRight); 5417 fAncestorContributor.cacheSelection(fAncestor); 5418 if (fSynchronizedScrolling) { 5419 fSynchronziedScrollPosition = fVScrollBar.getSelection(); 5420 } 5421 5422 } 5423 5424 private void endRefresh() { 5425 isRefreshing = false; 5426 fLeftContributor.cacheSelection(null); 5427 fRightContributor.cacheSelection(null); 5428 fAncestorContributor.cacheSelection(null); 5429 fSynchronziedScrollPosition = -1; 5430 } 5431 5432 private void synchronizedScrollVertical(int vpos) { 5433 scrollVertical(vpos, vpos, vpos, null); 5434 workaround65205(); 5435 } 5436 5437 private boolean isIgnoreAncestor() { 5438 return Utilities.getBoolean(getCompareConfiguration(), ICompareUIConstants.PROP_IGNORE_ANCESTOR, false); 5439 } 5440 5441 void update(boolean includeControls) { 5442 if (getControl().isDisposed()) 5443 return; 5444 if (fHasErrors) { 5445 resetDiffs(); 5446 } else { 5447 doDiff(); 5448 } 5449 5450 if (includeControls) 5451 updateControls(); 5452 5453 updateVScrollBar(); 5454 updatePresentation(null); 5455 } 5456 5457 private void resetDiffs() { 5458 fCurrentDiff= null; 5460 fChangeDiffs= null; 5461 fAllDiffs= null; 5462 resetPositions(fLeft.getDocument()); 5463 resetPositions(fRight.getDocument()); 5464 resetPositions(fAncestor.getDocument()); 5465 } 5466 5467 private boolean isPatchHunk() { 5468 return Utilities.isHunk(getInput()); 5469 } 5470 5471 5475 private int getHunkStart() { 5476 Object input = getInput(); 5477 if (input != null && input instanceof DiffNode){ 5478 ITypedElement right = ((DiffNode) input).getRight(); 5479 if (right != null) { 5480 Object element = Utilities.getAdapter(right, IHunk.class); 5481 if (element instanceof IHunk) 5482 return ((IHunk)element).getStartPosition(); 5483 } 5484 ITypedElement left = ((DiffNode) input).getLeft(); 5485 if (left != null) { 5486 Object element = Utilities.getAdapter(left, IHunk.class); 5487 if (element instanceof IHunk) 5488 return ((IHunk)element).getStartPosition(); 5489 } 5490 } 5491 return 0; 5492 } 5493 5494 private IFindReplaceTarget getFindReplaceTarget() { 5495 if (fFindReplaceTarget == null) 5496 fFindReplaceTarget= new FindReplaceTarget(); 5497 return fFindReplaceTarget; 5498 } 5499} 5500 | Popular Tags |