1 /******************************************************************************* 2 * Copyright (c) 2000, 2017 IBM Corporation and others. 3 * 4 * This program and the accompanying materials 5 * are made available under the terms of the Eclipse Public License 2.0 6 * which accompanies this distribution, and is available at 7 * https://www.eclipse.org/legal/epl-2.0/ 8 * 9 * SPDX-License-Identifier: EPL-2.0 10 * 11 * Contributors: 12 * IBM Corporation - initial API and implementation 13 *******************************************************************************/ 14 package org.eclipse.team.internal.ui; 15 16 import java.io.ByteArrayOutputStream; 17 import java.io.IOException; 18 import java.io.InputStream; 19 import java.lang.reflect.InvocationTargetException; 20 import java.util.ArrayList; 21 import java.util.Collections; 22 import java.util.Comparator; 23 import java.util.HashSet; 24 import java.util.Iterator; 25 import java.util.List; 26 import java.util.MissingResourceException; 27 import java.util.ResourceBundle; 28 import java.util.Set; 29 30 import org.eclipse.compare.CompareConfiguration; 31 import org.eclipse.compare.CompareEditorInput; 32 import org.eclipse.compare.structuremergeviewer.IDiffContainer; 33 import org.eclipse.compare.structuremergeviewer.IDiffElement; 34 import org.eclipse.core.resources.IFile; 35 import org.eclipse.core.resources.IResource; 36 import org.eclipse.core.resources.IStorage; 37 import org.eclipse.core.resources.mapping.ModelProvider; 38 import org.eclipse.core.resources.mapping.ResourceMapping; 39 import org.eclipse.core.resources.mapping.ResourceMappingContext; 40 import org.eclipse.core.resources.mapping.ResourceTraversal; 41 import org.eclipse.core.runtime.Adapters; 42 import org.eclipse.core.runtime.CoreException; 43 import org.eclipse.core.runtime.IAdaptable; 44 import org.eclipse.core.runtime.IProgressMonitor; 45 import org.eclipse.core.runtime.IStatus; 46 import org.eclipse.core.runtime.NullProgressMonitor; 47 import org.eclipse.core.runtime.Platform; 48 import org.eclipse.core.runtime.Status; 49 import org.eclipse.core.runtime.content.IContentType; 50 import org.eclipse.core.runtime.jobs.Job; 51 import org.eclipse.jface.action.IAction; 52 import org.eclipse.jface.dialogs.ErrorDialog; 53 import org.eclipse.jface.dialogs.MessageDialog; 54 import org.eclipse.jface.operation.IRunnableWithProgress; 55 import org.eclipse.jface.preference.IPreferenceStore; 56 import org.eclipse.jface.resource.ImageDescriptor; 57 import org.eclipse.jface.util.OpenStrategy; 58 import org.eclipse.jface.viewers.IStructuredSelection; 59 import org.eclipse.jface.viewers.StructuredViewer; 60 import org.eclipse.osgi.util.NLS; 61 import org.eclipse.swt.custom.BusyIndicator; 62 import org.eclipse.swt.widgets.Control; 63 import org.eclipse.swt.widgets.Display; 64 import org.eclipse.swt.widgets.Shell; 65 import org.eclipse.team.core.RepositoryProvider; 66 import org.eclipse.team.core.TeamException; 67 import org.eclipse.team.core.diff.IDiff; 68 import org.eclipse.team.core.diff.IThreeWayDiff; 69 import org.eclipse.team.core.history.IFileHistoryProvider; 70 import org.eclipse.team.core.history.IFileRevision; 71 import org.eclipse.team.core.mapping.IResourceDiff; 72 import org.eclipse.team.core.mapping.ISynchronizationScope; 73 import org.eclipse.team.core.synchronize.FastSyncInfoFilter; 74 import org.eclipse.team.core.synchronize.SyncInfo; 75 import org.eclipse.team.core.variants.IResourceVariant; 76 import org.eclipse.team.internal.core.mapping.CompoundResourceTraversal; 77 import org.eclipse.team.internal.ui.history.FileRevisionEditorInput; 78 import org.eclipse.team.internal.ui.synchronize.SyncInfoModelElement; 79 import org.eclipse.team.ui.TeamImages; 80 import org.eclipse.team.ui.TeamUI; 81 import org.eclipse.team.ui.mapping.ISynchronizationCompareAdapter; 82 import org.eclipse.team.ui.synchronize.ISynchronizeManager; 83 import org.eclipse.team.ui.synchronize.ISynchronizeModelElement; 84 import org.eclipse.team.ui.synchronize.ISynchronizePageConfiguration; 85 import org.eclipse.team.ui.synchronize.ISynchronizeParticipant; 86 import org.eclipse.team.ui.synchronize.SaveableCompareEditorInput; 87 import org.eclipse.ui.IContributorResourceAdapter; 88 import org.eclipse.ui.IEditorDescriptor; 89 import org.eclipse.ui.IEditorPart; 90 import org.eclipse.ui.IEditorReference; 91 import org.eclipse.ui.IEditorRegistry; 92 import org.eclipse.ui.IReusableEditor; 93 import org.eclipse.ui.IWorkbench; 94 import org.eclipse.ui.IWorkbenchPage; 95 import org.eclipse.ui.IWorkbenchSite; 96 import org.eclipse.ui.IWorkbenchWindow; 97 import org.eclipse.ui.PartInitException; 98 import org.eclipse.ui.PlatformUI; 99 import org.eclipse.ui.ide.IContributorResourceAdapter2; 100 import org.eclipse.ui.ide.IDE; 101 import org.eclipse.ui.internal.ErrorEditorPart; 102 import org.eclipse.ui.internal.registry.EditorDescriptor; 103 import org.eclipse.ui.progress.IWorkbenchSiteProgressService; 104 import org.eclipse.ui.texteditor.AbstractDecoratedTextEditor; 105 import org.osgi.framework.Bundle; 106 107 public class Utils { 108 109 /** 110 * Constant used to indicate that tests are being run. This field 111 * should be the same as the corresponding field on 112 * org.eclipse.compare.internal.Utilities 113 */ 114 public static boolean RUNNING_TESTS = false; 115 116 /** 117 * Constant used while testing the indicate that changes should be flushed 118 * when the compare input changes and a viewer is dirty. This field 119 * should be the same as the corresponding field on 120 * org.eclipse.compare.internal.Utilities 121 */ 122 public static boolean TESTING_FLUSH_ON_COMPARE_INPUT_CHANGE = false; 123 124 /** 125 * The SortOperation takes a collection of objects and returns a sorted 126 * collection of these objects. Concrete instances of this class provide 127 * the criteria for the sorting of the objects based on the type of the 128 * objects. 129 */ 130 static public abstract class Sorter { 131 132 /** 133 * Returns true is elementTwo is 'greater than' elementOne This is the 134 * 'ordering' method of the sort operation. Each subclass overrides this 135 * method with the particular implementation of the 'greater than' 136 * concept for the objects being sorted. 137 * @param elementOne element 1 138 * @param elementTwo element 2 139 * @return whether element 2 is greater that element 1 140 */ compare(Object elementOne, Object elementTwo)141 public abstract boolean compare(Object elementOne, Object elementTwo); 142 143 /** 144 * Sort the objects in sorted collection and return that collection. 145 */ quickSort(Object[] sortedCollection, int left, int right)146 private Object[] quickSort(Object[] sortedCollection, int left, int right) { 147 int originalLeft = left; 148 int originalRight = right; 149 Object mid = sortedCollection[(left + right) >>> 1]; 150 do { 151 while (compare(sortedCollection[left], mid)) 152 left++; 153 while (compare(mid, sortedCollection[right])) 154 right--; 155 if (left <= right) { 156 Object tmp = sortedCollection[left]; 157 sortedCollection[left] = sortedCollection[right]; 158 sortedCollection[right] = tmp; 159 left++; 160 right--; 161 } 162 } while (left <= right); 163 if (originalLeft < right) 164 sortedCollection = quickSort(sortedCollection, originalLeft, right); 165 if (left < originalRight) 166 sortedCollection = quickSort(sortedCollection, left, originalRight); 167 return sortedCollection; 168 } 169 170 /** 171 * Return a new sorted collection from this unsorted collection. Sort 172 * using quick sort. 173 * @param unSortedCollection the original collection 174 * @return the sorted collection 175 */ sort(Object[] unSortedCollection)176 public Object[] sort(Object[] unSortedCollection) { 177 int size = unSortedCollection.length; 178 Object[] sortedCollection = new Object[size]; 179 //copy the array so can return a new sorted collection 180 System.arraycopy(unSortedCollection, 0, sortedCollection, 0, size); 181 if (size > 1) 182 quickSort(sortedCollection, 0, size - 1); 183 return sortedCollection; 184 } 185 } 186 187 public static final Comparator<IResource> resourceComparator = new Comparator<IResource>() { 188 @Override 189 public boolean equals(Object obj) { 190 return false; 191 } 192 @Override 193 public int compare(IResource o1, IResource o2) { 194 return o1.getFullPath().toString().compareTo(o2.getFullPath().toString()); 195 } 196 }; 197 198 /** 199 * Shows the given errors to the user. 200 * @param shell 201 * the shell to open the error dialog in 202 * @param exception 203 * the exception containing the error 204 * @param title 205 * the title of the error dialog 206 * @param message 207 * the message for the error dialog 208 */ handleError(Shell shell, Exception exception, String title, String message)209 public static void handleError(Shell shell, Exception exception, String title, String message) { 210 IStatus status = null; 211 boolean log = false; 212 boolean dialog = false; 213 Throwable t = exception; 214 if (exception instanceof TeamException) { 215 status = ((TeamException) exception).getStatus(); 216 log = false; 217 dialog = true; 218 } else if (exception instanceof InvocationTargetException) { 219 t = ((InvocationTargetException) exception).getTargetException(); 220 if (t instanceof TeamException) { 221 status = ((TeamException) t).getStatus(); 222 log = false; 223 dialog = true; 224 } else if (t instanceof CoreException) { 225 status = ((CoreException) t).getStatus(); 226 log = true; 227 dialog = true; 228 } else if (t instanceof InterruptedException) { 229 return; 230 } else { 231 status = new Status(IStatus.ERROR, TeamUIPlugin.ID, 1, TeamUIMessages.TeamAction_internal, t); 232 log = true; 233 dialog = true; 234 } 235 } 236 if (status == null) 237 return; 238 if (!status.isOK()) { 239 IStatus toShow = status; 240 if (status.isMultiStatus()) { 241 IStatus[] children = status.getChildren(); 242 if (children.length == 1) { 243 toShow = children[0]; 244 } 245 } 246 if (title == null) { 247 title = status.getMessage(); 248 } 249 if (message == null) { 250 message = status.getMessage(); 251 } 252 if (dialog && shell != null) { 253 ErrorDialog.openError(shell, title, message, toShow); 254 } 255 if (log || shell == null) { 256 TeamUIPlugin.log(toShow.getSeverity(), message, t); 257 } 258 } 259 } 260 runWithProgress(Shell parent, boolean cancelable, final IRunnableWithProgress runnable)261 public static void runWithProgress(Shell parent, boolean cancelable, final IRunnableWithProgress runnable) throws InvocationTargetException, InterruptedException { 262 boolean createdShell = false; 263 try { 264 if (parent == null || parent.isDisposed()) { 265 Display display = Display.getCurrent(); 266 if (display == null) { 267 // cannot provide progress (not in UI thread) 268 runnable.run(new NullProgressMonitor()); 269 return; 270 } 271 // get the active shell or a suitable top-level shell 272 parent = display.getActiveShell(); 273 if (parent == null) { 274 parent = new Shell(display); 275 createdShell = true; 276 } 277 } 278 // pop up progress dialog after a short delay 279 final Exception[] holder = new Exception[1]; 280 BusyIndicator.showWhile(parent.getDisplay(), () -> { 281 try { 282 runnable.run(new NullProgressMonitor()); 283 } catch (InvocationTargetException e1) { 284 holder[0] = e1; 285 } catch (InterruptedException e2) { 286 holder[0] = e2; 287 } 288 }); 289 if (holder[0] != null) { 290 if (holder[0] instanceof InvocationTargetException) { 291 throw (InvocationTargetException) holder[0]; 292 } else { 293 throw (InterruptedException) holder[0]; 294 } 295 } 296 //new TimeoutProgressMonitorDialog(parent, TIMEOUT).run(true 297 // /*fork*/, cancelable, runnable); 298 } finally { 299 if (createdShell) 300 parent.dispose(); 301 } 302 } 303 getShell(IWorkbenchSite site)304 public static Shell getShell(IWorkbenchSite site) { 305 return getShell(site, false); 306 } 307 getShell(IWorkbenchSite site, boolean syncIfNecessary)308 public static Shell getShell(IWorkbenchSite site, boolean syncIfNecessary) { 309 if(site != null) { 310 Shell shell = site.getShell(); 311 if (!shell.isDisposed()) 312 return shell; 313 } 314 IWorkbench workbench = PlatformUI.getWorkbench(); 315 if (workbench != null) { 316 IWorkbenchWindow window = workbench.getActiveWorkbenchWindow(); 317 if (window != null) { 318 return window.getShell(); 319 } 320 } 321 // Fallback to using the display 322 Display display = Display.getCurrent(); 323 if (display == null) { 324 display = Display.getDefault(); 325 if (display.isDisposed()) return null; 326 if (syncIfNecessary) { 327 final Shell[] result = new Shell[] { null }; 328 Runnable r = () -> result[0] = new Shell(Display.getDefault()); 329 display.syncExec(r); 330 return result[0]; 331 } 332 } 333 if (display.isDisposed()) return null; 334 return new Shell(display); 335 } 336 /* 337 * This method is only for use by the Target Management feature (see bug 338 * 16509). @param t 339 */ handle(final Throwable exception)340 public static void handle(final Throwable exception) { 341 TeamUIPlugin.getStandardDisplay().asyncExec(() -> { 342 IStatus error = null; 343 Throwable t = exception; 344 if (t instanceof InvocationTargetException) { 345 t = ((InvocationTargetException) t).getTargetException(); 346 } 347 if (t instanceof CoreException) { 348 error = ((CoreException) t).getStatus(); 349 } else if (t instanceof TeamException) { 350 error = ((TeamException) t).getStatus(); 351 } else { 352 error = new Status(IStatus.ERROR, TeamUIPlugin.ID, 1, TeamUIMessages.simpleInternal, t); 353 } 354 Shell shell = new Shell(Display.getDefault()); 355 if (error.getSeverity() == IStatus.INFO) { 356 MessageDialog.openInformation(shell, TeamUIMessages.information, error.getMessage()); 357 } else { 358 ErrorDialog.openError(shell, TeamUIMessages.exception, null, error); 359 } 360 shell.dispose(); 361 // Let's log non-team exceptions 362 if (!(t instanceof TeamException)) { 363 TeamUIPlugin.log(error.getSeverity(), error.getMessage(), t); 364 } 365 }); 366 } 367 findShell()368 public static Shell findShell() { 369 Display display = TeamUIPlugin.getStandardDisplay(); 370 Shell activeShell = display.getActiveShell(); 371 if (activeShell != null) 372 return activeShell; 373 // worst case, just create our own. 374 return new Shell(display); 375 } 376 initAction(IAction a, String prefix)377 public static void initAction(IAction a, String prefix) { 378 Utils.initAction(a, prefix, Policy.getActionBundle()); 379 } 380 initAction(IAction a, String prefix, ResourceBundle bundle)381 public static void initAction(IAction a, String prefix, ResourceBundle bundle) { 382 Utils.initAction(a, prefix, bundle, null); 383 } 384 updateLabels(SyncInfo sync, CompareConfiguration config, IProgressMonitor monitor)385 public static void updateLabels(SyncInfo sync, CompareConfiguration config, IProgressMonitor monitor) { 386 final IResourceVariant remote = sync.getRemote(); 387 final IResourceVariant base = sync.getBase(); 388 String baseAuthor = null; 389 String remoteAuthor = null; 390 String localAuthor = null; 391 String localContentId = sync.getLocalContentIdentifier(); 392 String remoteContentId= remote != null ? remote.getContentIdentifier() : null; 393 String baseContentId= base != null ? base.getContentIdentifier() : null; 394 if (isShowAuthor()) { 395 baseAuthor = getAuthor(base, monitor); 396 if (baseContentId != null && baseContentId.equals(remoteContentId)) 397 remoteAuthor= baseAuthor; 398 else 399 remoteAuthor= getAuthor(remote, monitor); 400 401 if (localContentId != null) { 402 if (localContentId.equals(baseContentId)) 403 localAuthor= baseAuthor; 404 else if (localContentId.equals(remoteAuthor)) 405 localAuthor= remoteAuthor; 406 else 407 localAuthor= sync.getLocalAuthor(monitor); 408 } 409 } 410 if (localContentId != null) { 411 if (localAuthor != null) { 412 config.setLeftLabel(NLS.bind(TeamUIMessages.SyncInfoCompareInput_localLabelAuthorExists, new String[] { localContentId, localAuthor })); 413 } else { 414 config.setLeftLabel(NLS.bind(TeamUIMessages.SyncInfoCompareInput_localLabelExists, new String[] { localContentId })); 415 } 416 } else { 417 config.setLeftLabel(TeamUIMessages.SyncInfoCompareInput_localLabel); 418 } 419 if (remote != null) { 420 if (remoteAuthor != null) { 421 config.setRightLabel(NLS.bind(TeamUIMessages.SyncInfoCompareInput_remoteLabelAuthorExists, new String[] { remoteContentId, remoteAuthor })); 422 } else { 423 config.setRightLabel(NLS.bind(TeamUIMessages.SyncInfoCompareInput_remoteLabelExists, new String[] { remoteContentId })); 424 } 425 } else { 426 config.setRightLabel(TeamUIMessages.SyncInfoCompareInput_remoteLabel); 427 } 428 if (base != null) { 429 if (baseAuthor != null) { 430 config.setAncestorLabel(NLS.bind(TeamUIMessages.SyncInfoCompareInput_baseLabelAuthorExists, new String[] { baseContentId, baseAuthor })); 431 } else { 432 config.setAncestorLabel(NLS.bind(TeamUIMessages.SyncInfoCompareInput_baseLabelExists, new String[] { baseContentId })); 433 } 434 } else { 435 config.setAncestorLabel(TeamUIMessages.SyncInfoCompareInput_baseLabel); 436 } 437 } 438 439 /** 440 * DO NOT REMOVE, used in a product. 441 * 442 * @deprecated As of 3.5, replaced by 443 * {@link #updateLabels(SyncInfo, CompareConfiguration, IProgressMonitor)} 444 */ 445 @SuppressWarnings("javadoc") 446 @Deprecated updateLabels(SyncInfo sync, CompareConfiguration config)447 public static void updateLabels(SyncInfo sync, CompareConfiguration config) { 448 updateLabels(sync, config, null); 449 } 450 isShowAuthor()451 public static boolean isShowAuthor() { 452 IPreferenceStore store = TeamUIPlugin.getPlugin().getPreferenceStore(); 453 return store.getBoolean(IPreferenceIds.SHOW_AUTHOR_IN_COMPARE_EDITOR); 454 } 455 getAuthor(IResourceVariant variant, IProgressMonitor monitor)456 private static String getAuthor(IResourceVariant variant, 457 IProgressMonitor monitor) { 458 String author = null; 459 if (variant instanceof IAdaptable) { 460 IAdaptable adaptable = (IAdaptable) variant; 461 IFileRevision revision = adaptable.getAdapter(IFileRevision.class); 462 if (revision == null) 463 return null; 464 try { 465 IFileRevision complete = revision.withAllProperties(monitor); 466 if (complete != null) { 467 author = complete.getAuthor(); 468 } 469 } catch (CoreException e) { 470 TeamUIPlugin.log(e); 471 } 472 } 473 return author; 474 } 475 getLocalContentId(IDiff diff)476 public static String getLocalContentId(IDiff diff) { 477 if (diff instanceof IThreeWayDiff) { 478 IThreeWayDiff twd = (IThreeWayDiff) diff; 479 diff = twd.getLocalChange(); 480 if (diff == null) 481 diff = twd.getRemoteChange(); 482 } 483 if (diff instanceof IResourceDiff) { 484 IResourceDiff rd = (IResourceDiff) diff; 485 IResource resource = rd.getResource(); 486 IFileHistoryProvider provider = getHistoryProvider(resource); 487 if (provider != null) { 488 IFileRevision revision = provider.getWorkspaceFileRevision(resource); 489 if (revision != null) 490 return revision.getContentIdentifier(); 491 } 492 } 493 return null; 494 } 495 getHistoryProvider(IResource resource)496 public static IFileHistoryProvider getHistoryProvider(IResource resource) { 497 RepositoryProvider rp = RepositoryProvider.getProvider(resource.getProject()); 498 if (rp != null) 499 return rp.getFileHistoryProvider(); 500 return null; 501 } 502 getBase(IDiff diff)503 public static IFileRevision getBase(IDiff diff) { 504 if (diff instanceof IThreeWayDiff) { 505 IThreeWayDiff twd = (IThreeWayDiff) diff; 506 IDiff remoteChange = twd.getRemoteChange(); 507 if (remoteChange instanceof IResourceDiff) { 508 IResourceDiff rd = (IResourceDiff) remoteChange; 509 return rd.getBeforeState(); 510 } 511 IDiff localChange = twd.getLocalChange(); 512 if (localChange instanceof IResourceDiff) { 513 IResourceDiff ld = (IResourceDiff) localChange; 514 return ld.getBeforeState(); 515 } 516 } 517 return null; 518 } 519 getRemote(IDiff diff)520 public static IFileRevision getRemote(IDiff diff) { 521 if (diff instanceof IResourceDiff) { 522 IResourceDiff rd = (IResourceDiff) diff; 523 return rd.getAfterState(); 524 } 525 if (diff instanceof IThreeWayDiff) { 526 IThreeWayDiff twd = (IThreeWayDiff) diff; 527 IDiff remoteChange = twd.getRemoteChange(); 528 if (remoteChange instanceof IResourceDiff) { 529 IResourceDiff rd = (IResourceDiff) remoteChange; 530 return rd.getAfterState(); 531 } 532 IDiff localChange = twd.getLocalChange(); 533 if (localChange instanceof IResourceDiff) { 534 IResourceDiff ld = (IResourceDiff) localChange; 535 return ld.getBeforeState(); 536 } 537 } 538 return null; 539 } 540 541 /** 542 * Initialize the given Action from a ResourceBundle. 543 * @param a the action 544 * @param prefix the bundle key prefix 545 * @param bundle the bundle 546 * @param bindings additional input to the action label 547 */ initAction(IAction a, String prefix, ResourceBundle bundle, String[] bindings)548 public static void initAction(IAction a, String prefix, ResourceBundle bundle, String[] bindings) { 549 String labelKey = "label"; //$NON-NLS-1$ 550 String tooltipKey = "tooltip"; //$NON-NLS-1$ 551 String imageKey = "image"; //$NON-NLS-1$ 552 String descriptionKey = "description"; //$NON-NLS-1$ 553 if (prefix != null && prefix.length() > 0) { 554 labelKey = prefix + labelKey; 555 tooltipKey = prefix + tooltipKey; 556 imageKey = prefix + imageKey; 557 descriptionKey = prefix + descriptionKey; 558 } 559 String s = null; 560 if(bindings != null) { 561 s = NLS.bind(getString(labelKey, bundle), bindings); 562 } else { 563 s = getString(labelKey, bundle); 564 } 565 if (s != null) 566 a.setText(s); 567 s = getString(tooltipKey, bundle); 568 if (s != null) 569 a.setToolTipText(s); 570 s = getString(descriptionKey, bundle); 571 if (s != null) 572 a.setDescription(s); 573 String relPath = getString(imageKey, bundle); 574 if (relPath != null && !relPath.equals(imageKey) && relPath.trim().length() > 0) { 575 String dPath; 576 String ePath; 577 if (relPath.contains("/")) { //$NON-NLS-1$ 578 String path = relPath.substring(1); 579 dPath = 'd' + path; 580 ePath = 'e' + path; 581 } else { 582 dPath = "dlcl16/" + relPath; //$NON-NLS-1$ 583 ePath = "elcl16/" + relPath; //$NON-NLS-1$ 584 } 585 ImageDescriptor id = TeamImages.getImageDescriptor(dPath); 586 if (id != null) 587 a.setDisabledImageDescriptor(id); 588 id = TeamUIPlugin.getImageDescriptor(ePath); 589 if (id != null) 590 a.setImageDescriptor(id); 591 } 592 } 593 getString(String key, ResourceBundle b)594 public static String getString(String key, ResourceBundle b) { 595 try { 596 return b.getString(key); 597 } catch (MissingResourceException e) { 598 return key; 599 } catch (NullPointerException e) { 600 return "!" + key + "!"; //$NON-NLS-1$ //$NON-NLS-2$ 601 } 602 } 603 modeToString(int mode)604 public static String modeToString(int mode) { 605 switch (mode) { 606 case ISynchronizePageConfiguration.INCOMING_MODE : 607 return TeamUIMessages.Utils_22; 608 case ISynchronizePageConfiguration.OUTGOING_MODE : 609 return TeamUIMessages.Utils_23; 610 case ISynchronizePageConfiguration.BOTH_MODE : 611 return TeamUIMessages.Utils_24; 612 case ISynchronizePageConfiguration.CONFLICTING_MODE : 613 return TeamUIMessages.Utils_25; 614 default: 615 return TeamUIMessages.Utils_26; 616 } 617 } 618 619 /** 620 * Returns the list of resources contained in the given elements. 621 * @param elements 622 * @return the list of resources contained in the given elements. 623 */ getResources(Object[] elements, List<Object> nonResources, boolean isContributed, boolean includeMappingResources)624 private static IResource[] getResources(Object[] elements, List<Object> nonResources, 625 boolean isContributed, boolean includeMappingResources) { 626 List<IResource> resources = new ArrayList<>(); 627 for (Object element : elements) { 628 boolean isResource = false; 629 if (element instanceof IResource) { 630 resources.add((IResource) element); 631 isResource = true; 632 } else if (element instanceof ISynchronizeModelElement){ 633 IResource resource = ((ISynchronizeModelElement) element).getResource(); 634 if (resource != null) { 635 resources.add(resource); 636 isResource = true; 637 } 638 } else if (element instanceof ResourceMapping) { 639 if (includeMappingResources) { 640 isResource = true; 641 getResources((ResourceMapping)element, resources); 642 } 643 } else if (element != null) { 644 Object adapted; 645 if (isContributed) { 646 adapted = getResource(element); 647 } else { 648 adapted = Adapters.adapt(element, IResource.class); 649 } 650 if (adapted instanceof IResource) { 651 IResource resource = (IResource) adapted; 652 isResource = true; 653 if (resource.getType() != IResource.ROOT) { 654 resources.add(resource); 655 } 656 } else { 657 if (isContributed) { 658 adapted = getResourceMapping(element); 659 } else { 660 adapted = Adapters.adapt(element, ResourceMapping.class); 661 } 662 if (adapted instanceof ResourceMapping && includeMappingResources) { 663 isResource = true; 664 getResources((ResourceMapping) adapted, resources); 665 } 666 } 667 } 668 if (!isResource) { 669 if (nonResources != null) 670 nonResources.add(element); 671 } 672 } 673 return resources.toArray(new IResource[resources.size()]); 674 } 675 getResources(ResourceMapping element, List<IResource> resources)676 private static void getResources(ResourceMapping element, List<IResource> resources) { 677 try { 678 ResourceTraversal[] traversals = element.getTraversals(ResourceMappingContext.LOCAL_CONTEXT, null); 679 for (ResourceTraversal traversal : traversals) { 680 IResource[] resourceArray = traversal.getResources(); 681 Collections.addAll(resources, resourceArray); 682 } 683 } catch (CoreException e) { 684 TeamUIPlugin.log(new Status(IStatus.ERROR, TeamUIPlugin.ID, 0, "Error traversing resource mapping", e)); //$NON-NLS-1$ 685 } 686 } 687 getNonResources(Object[] elements)688 public static Object[] getNonResources(Object[] elements) { 689 List<Object> nonResources = new ArrayList<>(); 690 getResources(elements, nonResources, false, false); 691 return nonResources.toArray(); 692 } 693 getResources(Object[] element)694 public static IResource[] getResources(Object[] element) { 695 return getResources(element, null, false /* isContributed */, false /* includeMappingResources */); 696 } 697 getContributedResources(Object[] elements)698 public static IResource[] getContributedResources(Object[] elements) { 699 return getResources(elements, null, true /* isContributed */, true /* isIncudeMappings */); 700 } 701 702 /** 703 * Return whether any sync nodes in the given selection or their 704 * descendants match the given filter. 705 * @param selection a selection 706 * @param filter a sync info filter 707 * @return whether any sync nodes in the given selection or their 708 * descendants match the given filter 709 */ hasMatchingDescendant(IStructuredSelection selection, FastSyncInfoFilter filter)710 public static boolean hasMatchingDescendant(IStructuredSelection selection, FastSyncInfoFilter filter) { 711 for (Iterator iter = selection.iterator(); iter.hasNext();) { 712 Object o = iter.next(); 713 if (o instanceof ISynchronizeModelElement) { 714 if (hasMatchingDescendant((ISynchronizeModelElement)o, filter)) { 715 return true; 716 } 717 } 718 } 719 return false; 720 } 721 hasMatchingDescendant(ISynchronizeModelElement element, FastSyncInfoFilter filter)722 private static boolean hasMatchingDescendant(ISynchronizeModelElement element, FastSyncInfoFilter filter) { 723 if (element.getKind() != SyncInfo.IN_SYNC && element instanceof SyncInfoModelElement) { 724 SyncInfo info = ((SyncInfoModelElement) element).getSyncInfo(); 725 if (info != null && filter.select(info)) { 726 return true; 727 } 728 } 729 IDiffElement[] children = element.getChildren(); 730 for (IDiffElement child : children) { 731 if (child instanceof ISynchronizeModelElement) { 732 if (hasMatchingDescendant((ISynchronizeModelElement)child, filter)) { 733 return true; 734 } 735 } 736 } 737 return false; 738 } 739 740 /** 741 * This method returns all out-of-sync SyncInfos that are in the current 742 * selection. 743 * @param selected the selected objects 744 * 745 * @return the list of selected sync infos 746 */ getDiffNodes(Object[] selected)747 public static IDiffElement[] getDiffNodes(Object[] selected) { 748 Set<IDiffElement> result = new HashSet<>(); 749 for (Object object : selected) { 750 if(object instanceof IDiffElement) { 751 collectAllNodes((IDiffElement)object, result); 752 } 753 } 754 return result.toArray(new IDiffElement[result.size()]); 755 } 756 collectAllNodes(IDiffElement element, Set<IDiffElement> nodes)757 private static void collectAllNodes(IDiffElement element, Set<IDiffElement> nodes) { 758 if (element.getKind() != SyncInfo.IN_SYNC) { 759 nodes.add(element); 760 } 761 if(element instanceof IDiffContainer) { 762 IDiffElement[] children = ((IDiffContainer)element).getChildren(); 763 for (IDiffElement c : children) { 764 collectAllNodes(c, nodes); 765 } 766 } 767 } 768 schedule(Job job, IWorkbenchSite site)769 public static void schedule(Job job, IWorkbenchSite site) { 770 if (site != null) { 771 IWorkbenchSiteProgressService siteProgress = site.getAdapter(IWorkbenchSiteProgressService.class); 772 if (siteProgress != null) { 773 siteProgress.schedule(job, 0, true /* use half-busy cursor */); 774 return; 775 } 776 } 777 job.schedule(); 778 } 779 readBytes(InputStream in)780 public static byte[] readBytes(InputStream in) { 781 ByteArrayOutputStream bos= new ByteArrayOutputStream(); 782 try { 783 while (true) { 784 int c= in.read(); 785 if (c == -1) 786 break; 787 bos.write(c); 788 } 789 790 } catch (IOException ex) { 791 return null; 792 793 } finally { 794 if (in != null) { 795 try { 796 in.close(); 797 } catch (IOException x) { 798 // silently ignored 799 } 800 } 801 try { 802 bos.close(); 803 } catch (IOException x) { 804 // silently ignored 805 } 806 } 807 return bos.toByteArray(); 808 } 809 equalObject(Object o1, Object o2)810 public static boolean equalObject(Object o1, Object o2) { 811 if (o1 == null && o2 == null) return true; 812 if (o1 == null || o2 == null) return false; 813 return o1.equals(o2); 814 } 815 getKey(String id, String secondaryId)816 public static String getKey(String id, String secondaryId) { 817 return secondaryId == null ? id : id + '/' + secondaryId; 818 } 819 convertSelection(IResource[] resources)820 public static String convertSelection(IResource[] resources) { 821 StringBuilder buffer = new StringBuilder(); 822 for (int i = 0; i < resources.length; i++) { 823 IResource resource = resources[i]; 824 if(i > 0) buffer.append(", "); //$NON-NLS-1$ 825 buffer.append(resource.getFullPath()); 826 } 827 return buffer.toString(); 828 } 829 830 /** 831 * Shorten the given text <code>t</code> so that its length 832 * doesn't exceed the given width. This implementation 833 * replaces characters in the center of the original string with an 834 * ellipsis ("..."). 835 * @param maxWidth the maximum length for the text 836 * @param textValue the text to be shortened 837 * @return the shortened text 838 */ shortenText(int maxWidth, String textValue)839 public static String shortenText(int maxWidth, String textValue) { 840 int length = textValue.length(); 841 if (length < maxWidth) 842 return textValue; 843 String ellipsis = "..."; //$NON-NLS-1$ 844 int subStrLen = (maxWidth - ellipsis.length()) / 2; 845 int addtl = (maxWidth - ellipsis.length()) % 2; 846 847 StringBuilder sb = new StringBuilder(maxWidth); 848 sb.append(textValue.substring(0, subStrLen)); 849 sb.append(ellipsis); 850 sb.append(textValue.substring(length - subStrLen - addtl)); 851 return sb.toString(); 852 } 853 getTypeName(ISynchronizeParticipant participant)854 public static String getTypeName(ISynchronizeParticipant participant) { 855 ISynchronizeManager manager = TeamUI.getSynchronizeManager(); 856 return manager.getParticipantDescriptor(participant.getId()).getName(); 857 } 858 859 /** 860 * The viewer will only be updated if the viewer is not null, the control is not disposed, and 861 * this code is being run from the UI thread. 862 * @param viewer the viewer to be updated 863 * @return whether it is safe to update the viewer 864 */ canUpdateViewer(StructuredViewer viewer)865 public static boolean canUpdateViewer(StructuredViewer viewer) { 866 if(viewer == null || viewer.getControl().isDisposed()) return false; 867 Display display = viewer.getControl().getDisplay(); 868 if (display == null) return false; 869 if (display.getThread() != Thread.currentThread ()) return false; 870 return true; 871 } 872 asyncExec(final Runnable r, StructuredViewer v)873 public static void asyncExec(final Runnable r, StructuredViewer v) { 874 if(v == null) return; 875 final Control ctrl = v.getControl(); 876 if (ctrl != null && !ctrl.isDisposed()) { 877 ctrl.getDisplay().asyncExec(() -> { 878 if (!ctrl.isDisposed()) { 879 BusyIndicator.showWhile(ctrl.getDisplay(), r); 880 } 881 }); 882 } 883 } 884 syncExec(final Runnable r, StructuredViewer v)885 public static void syncExec(final Runnable r, StructuredViewer v) { 886 if(v == null) return; 887 final Control ctrl = v.getControl(); 888 syncExec(r, ctrl); 889 } 890 syncExec(final Runnable r, final Control ctrl)891 public static void syncExec(final Runnable r, final Control ctrl) { 892 if (ctrl != null && !ctrl.isDisposed()) { 893 ctrl.getDisplay().syncExec(() -> { 894 if (!ctrl.isDisposed()) { 895 BusyIndicator.showWhile(ctrl.getDisplay(), r); 896 } 897 }); 898 } 899 } 900 asyncExec(final Runnable r, final Control ctrl)901 public static void asyncExec(final Runnable r, final Control ctrl) { 902 if (ctrl != null && !ctrl.isDisposed()) { 903 ctrl.getDisplay().asyncExec(() -> { 904 if (!ctrl.isDisposed()) { 905 BusyIndicator.showWhile(ctrl.getDisplay(), r); 906 } 907 }); 908 } 909 } 910 getSyncInfo(ISynchronizeModelElement node)911 public static SyncInfo getSyncInfo(ISynchronizeModelElement node) { 912 if (node instanceof IAdaptable) { 913 return ((IAdaptable) node).getAdapter(SyncInfo.class); 914 } 915 return null; 916 } 917 getCompareAdapter(Object element)918 public static ISynchronizationCompareAdapter getCompareAdapter(Object element) { 919 ModelProvider provider = getModelProvider(element); 920 if (provider != null) { 921 Object o = provider.getAdapter(ISynchronizationCompareAdapter.class); 922 if (o instanceof ISynchronizationCompareAdapter) { 923 return (ISynchronizationCompareAdapter) o; 924 } 925 } 926 return null; 927 } 928 getModelProvider(Object o)929 public static ModelProvider getModelProvider(Object o) { 930 if (o instanceof ModelProvider) { 931 return (ModelProvider) o; 932 } 933 ResourceMapping mapping = getResourceMapping(o); 934 if (mapping != null) 935 return mapping.getModelProvider(); 936 return null; 937 } 938 getResource(Object o)939 public static IResource getResource(Object o) { 940 IResource resource = null; 941 if (o instanceof IResource) { 942 resource = (IResource) o; 943 } else if (o instanceof IAdaptable) { 944 IAdaptable adaptable = (IAdaptable) o; 945 resource = adaptable.getAdapter(IResource.class); 946 if (resource == null) { 947 IContributorResourceAdapter adapter = adaptable.getAdapter(IContributorResourceAdapter.class); 948 if (adapter != null) 949 resource = adapter.getAdaptedResource(adaptable); 950 } 951 } 952 return resource; 953 } 954 955 getResourceMapping(Object o)956 public static ResourceMapping getResourceMapping(Object o) { 957 if (o instanceof ResourceMapping) { 958 return (ResourceMapping) o; 959 } 960 if (o instanceof IAdaptable) { 961 IAdaptable adaptable = (IAdaptable) o; 962 Object adapted = adaptable.getAdapter(ResourceMapping.class); 963 if (adapted instanceof ResourceMapping) { 964 return(ResourceMapping) adapted; 965 } 966 adapted = adaptable.getAdapter(IContributorResourceAdapter.class); 967 if (adapted instanceof IContributorResourceAdapter2) { 968 IContributorResourceAdapter2 cra = (IContributorResourceAdapter2) adapted; 969 return cra.getAdaptedResourceMapping(adaptable); 970 } 971 } else { 972 Object adapted = Platform.getAdapterManager().getAdapter(o, ResourceMapping.class); 973 if (adapted instanceof ResourceMapping) { 974 return(ResourceMapping) adapted; 975 } 976 } 977 return null; 978 } 979 getResourceMappings(Object[] objects)980 public static ResourceMapping[] getResourceMappings(Object[] objects) { 981 List<ResourceMapping> result = new ArrayList<>(); 982 for (Object object : objects) { 983 ResourceMapping mapping = getResourceMapping(object); 984 if (mapping != null) 985 result.add(mapping); 986 } 987 return result.toArray(new ResourceMapping[result.size()]); 988 } 989 getLabel(ResourceMapping mapping)990 public static String getLabel(ResourceMapping mapping) { 991 ModelProvider provider = mapping.getModelProvider(); 992 ISynchronizationCompareAdapter adapter = getCompareAdapter(provider); 993 if (adapter == null) 994 return ""; //$NON-NLS-1$ 995 String pathString = adapter.getPathString(mapping); 996 if (pathString == null || pathString.length() == 0) 997 return adapter.getName(mapping); 998 return pathString; 999 } 1000 getLabel(ModelProvider provider)1001 public static String getLabel(ModelProvider provider) { 1002 ResourceMapping mapping = Utils.getResourceMapping(provider); 1003 if (mapping != null) { 1004 String base = Utils.getLabel(mapping); 1005 if (base != null && base.length() > 0) 1006 return base; 1007 } 1008 return provider.getDescriptor().getLabel(); 1009 } 1010 getScopeDescription(ISynchronizationScope scope)1011 public static String getScopeDescription(ISynchronizationScope scope) { 1012 ResourceMapping[] mappings = scope.getInputMappings(); 1013 if (mappings.length == 1) { 1014 String label = getLabel(mappings[0]); 1015 if (label == null) 1016 return TeamUIMessages.Utils_19; 1017 else 1018 return label; 1019 } 1020 String desc = convertSelection(mappings); 1021 if (desc.length() > 0) 1022 return shortenText(30, desc); 1023 return NLS.bind(TeamUIMessages.Utils_18, Integer.valueOf(mappings.length)); 1024 } 1025 convertSelection(ResourceMapping[] mappings)1026 public static String convertSelection(ResourceMapping[] mappings) { 1027 StringBuilder buffer = new StringBuilder(); 1028 boolean hadOne = false; 1029 for (ResourceMapping resourceMapping : mappings) { 1030 String label = getLabel(resourceMapping); 1031 if (label != null) { 1032 if(hadOne) buffer.append(", "); //$NON-NLS-1$ 1033 hadOne = true; 1034 buffer.append(label); 1035 } 1036 } 1037 return buffer.toString(); 1038 } 1039 getTraversals(Object[] elements)1040 public static ResourceTraversal[] getTraversals(Object[] elements) throws CoreException { 1041 CompoundResourceTraversal traversal = new CompoundResourceTraversal(); 1042 for (Object object : elements) { 1043 ResourceMapping mapping = getResourceMapping(object); 1044 if (mapping != null) { 1045 traversal.addTraversals(mapping.getTraversals(ResourceMappingContext.LOCAL_CONTEXT, null)); 1046 } 1047 } 1048 return traversal.asTraversals(); 1049 } 1050 1051 /** 1052 * Return whether the editor associated with a descriptor is a text editor 1053 * (i.e. an instance of AbstractDecoratedTextEditor). 1054 * See bug 99568 for a request to move the createEditor method to IEditorDescriptor. 1055 * @param descriptor 1056 * @return whether the editor associated with a descriptor is a text editor 1057 * @throws CoreException 1058 */ isTextEditor(IEditorDescriptor descriptor)1059 public static boolean isTextEditor(IEditorDescriptor descriptor) throws CoreException { 1060 if (!(descriptor instanceof EditorDescriptor)) 1061 return false; 1062 1063 EditorDescriptor desc = (EditorDescriptor) descriptor; 1064 String className = desc.getClassName(); 1065 String contributor = desc.getPluginId(); 1066 1067 if (className == null || contributor == null) 1068 return false; 1069 1070 try { 1071 Bundle bundle= Platform.getBundle(contributor); 1072 if (bundle != null) { 1073 Class clazz= bundle.loadClass(className); 1074 return AbstractDecoratedTextEditor.class.isAssignableFrom(clazz); 1075 } 1076 } catch (ClassNotFoundException e) { 1077 // fallback and create editor 1078 } 1079 1080 IEditorPart editor= desc.createEditor(); 1081 editor.dispose(); 1082 return editor instanceof AbstractDecoratedTextEditor; 1083 } 1084 openEditor(IWorkbenchPage page, IFileRevision revision, IProgressMonitor monitor)1085 public static IEditorPart openEditor(IWorkbenchPage page, IFileRevision revision, IProgressMonitor monitor) throws CoreException { 1086 IStorage file = revision.getStorage(monitor); 1087 if (file instanceof IFile) { 1088 //if this is the current workspace file, open it 1089 return IDE.openEditor(page, (IFile)file, OpenStrategy.activateOnOpen()); 1090 } else { 1091 FileRevisionEditorInput fileRevEditorInput = FileRevisionEditorInput.createEditorInputFor(revision, monitor); 1092 IEditorPart part = openEditor(page, fileRevEditorInput); 1093 return part; 1094 } 1095 } 1096 openEditor(IWorkbenchPage page, FileRevisionEditorInput editorInput)1097 public static IEditorPart openEditor(IWorkbenchPage page, 1098 FileRevisionEditorInput editorInput) throws PartInitException { 1099 String id = getEditorId(editorInput); 1100 return openEditor(page, editorInput, id); 1101 } 1102 openEditor(IWorkbenchPage page, FileRevisionEditorInput editorInput, String editorId)1103 public static IEditorPart openEditor(IWorkbenchPage page, 1104 FileRevisionEditorInput editorInput, String editorId) 1105 throws PartInitException { 1106 try { 1107 IEditorPart part = page.openEditor(editorInput, editorId, 1108 OpenStrategy.activateOnOpen()); 1109 // See bug 90582 for the reasons behind this discouraged access 1110 if (part instanceof ErrorEditorPart) { 1111 page.closeEditor(part, false); 1112 part = null; 1113 } 1114 if (part == null) { 1115 throw new PartInitException(NLS.bind(TeamUIMessages.Utils_17, 1116 editorId)); 1117 } 1118 return part; 1119 } catch (PartInitException e) { 1120 if (editorId.equals("org.eclipse.ui.DefaultTextEditor")) { //$NON-NLS-1$ 1121 throw e; 1122 } else { 1123 return page.openEditor(editorInput, 1124 "org.eclipse.ui.DefaultTextEditor"); //$NON-NLS-1$ 1125 } 1126 } 1127 } 1128 getEditors(IFileRevision revision)1129 public static IEditorDescriptor[] getEditors(IFileRevision revision) { 1130 String name= revision.getName(); 1131 IEditorRegistry registry = PlatformUI.getWorkbench() 1132 .getEditorRegistry(); 1133 // so far only the revision name is used to find editors 1134 IEditorDescriptor[] editorDescs= registry.getEditors(name/* , getContentType(revision) */); 1135 return IDE.overrideEditorAssociations(name, null, editorDescs); 1136 } 1137 getDefaultEditor(IFileRevision revision)1138 public static IEditorDescriptor getDefaultEditor(IFileRevision revision) { 1139 String name= revision.getName(); 1140 // so far only the revision name is used to find the default editor 1141 try { 1142 return IDE.getEditorDescriptor(name); 1143 } catch (PartInitException e) { 1144 // Fallback to old way of getting the editor 1145 IEditorRegistry registry= PlatformUI.getWorkbench().getEditorRegistry(); 1146 return registry.getDefaultEditor(name); 1147 } 1148 } 1149 getEditorId(FileRevisionEditorInput editorInput)1150 private static String getEditorId(FileRevisionEditorInput editorInput) { 1151 String id= getEditorId(editorInput, getContentType(editorInput)); 1152 return id; 1153 } 1154 getContentType(FileRevisionEditorInput editorInput)1155 private static IContentType getContentType(FileRevisionEditorInput editorInput) { 1156 IContentType type = null; 1157 try { 1158 InputStream contents = editorInput.getStorage().getContents(); 1159 try { 1160 type = getContentType(editorInput.getFileRevision().getName(), contents); 1161 } finally { 1162 try { 1163 contents.close(); 1164 } catch (IOException e) { 1165 // ignore 1166 } 1167 } 1168 } catch (CoreException e) { 1169 TeamUIPlugin.log(IStatus.ERROR, NLS.bind("An error occurred reading the contents of file {0}", new String[] { editorInput.getName() }), e); //$NON-NLS-1$ 1170 } 1171 return type; 1172 } 1173 getContentType(String fileName, InputStream contents)1174 private static IContentType getContentType(String fileName, InputStream contents) { 1175 IContentType type = null; 1176 if (contents != null) { 1177 try { 1178 type = Platform.getContentTypeManager().findContentTypeFor(contents, fileName); 1179 } catch (IOException e) { 1180 TeamUIPlugin.log(IStatus.ERROR, NLS.bind("An error occurred reading the contents of file {0}", fileName), e); //$NON-NLS-1$ 1181 } 1182 } 1183 if (type == null) { 1184 type = Platform.getContentTypeManager().findContentTypeFor(fileName); 1185 } 1186 return type; 1187 } 1188 getEditorId(FileRevisionEditorInput editorInput, IContentType type)1189 private static String getEditorId(FileRevisionEditorInput editorInput, IContentType type) { 1190 String fileName= editorInput.getFileRevision().getName(); 1191 IEditorRegistry registry = PlatformUI.getWorkbench().getEditorRegistry(); 1192 IEditorDescriptor descriptor = registry.getDefaultEditor(fileName, type); 1193 IDE.overrideDefaultEditorAssociation(editorInput, type, descriptor); 1194 String id; 1195 if (descriptor == null || descriptor.isOpenExternal()) { 1196 id = "org.eclipse.ui.DefaultTextEditor"; //$NON-NLS-1$ 1197 } else { 1198 id = descriptor.getId(); 1199 } 1200 return id; 1201 } 1202 1203 /** 1204 * Returns an editor that can be re-used. An open compare editor that has 1205 * un-saved changes cannot be re-used. 1206 * 1207 * @param input 1208 * the input being opened 1209 * @param page 1210 * @param editorInputClasses 1211 * @return an EditorPart or <code>null</code> if none can be found 1212 */ findReusableCompareEditor( CompareEditorInput input, IWorkbenchPage page, Class[] editorInputClasses)1213 public static IEditorPart findReusableCompareEditor( 1214 CompareEditorInput input, IWorkbenchPage page, 1215 Class[] editorInputClasses) { 1216 IEditorReference[] editorRefs = page.getEditorReferences(); 1217 // first loop looking for an editor with the same input 1218 for (IEditorReference editorRef : editorRefs) { 1219 IEditorPart part = editorRef.getEditor(false); 1220 if (part != null && part instanceof IReusableEditor) { 1221 for (Class editorInputClasse : editorInputClasses) { 1222 // check if the editor input type 1223 // complies with the types given by the caller 1224 if (editorInputClasse.isInstance(part.getEditorInput()) && part.getEditorInput().equals(input)) { 1225 return part; 1226 } 1227 } 1228 } 1229 } 1230 // if none found and "Reuse open compare editors" preference is on use 1231 // a non-dirty editor 1232 if (TeamUIPlugin.getPlugin().getPreferenceStore() 1233 .getBoolean(IPreferenceIds.REUSE_OPEN_COMPARE_EDITOR)) { 1234 for (IEditorReference editorRef : editorRefs) { 1235 IEditorPart part = editorRef.getEditor(false); 1236 if (part != null 1237 && (part.getEditorInput() instanceof SaveableCompareEditorInput) 1238 && part instanceof IReusableEditor && !part.isDirty()) { 1239 return part; 1240 } 1241 } 1242 } 1243 1244 // no re-usable editor found 1245 return null; 1246 } 1247 1248 } 1249