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.synchronize.actions; 15 16 import java.lang.reflect.InvocationTargetException; 17 import java.util.Iterator; 18 19 import org.eclipse.compare.CompareEditorInput; 20 import org.eclipse.compare.CompareUI; 21 import org.eclipse.compare.structuremergeviewer.ICompareInput; 22 import org.eclipse.core.resources.IResource; 23 import org.eclipse.core.runtime.Assert; 24 import org.eclipse.core.runtime.CoreException; 25 import org.eclipse.jface.action.Action; 26 import org.eclipse.jface.util.OpenStrategy; 27 import org.eclipse.jface.viewers.ISelection; 28 import org.eclipse.jface.viewers.IStructuredSelection; 29 import org.eclipse.team.core.synchronize.SyncInfo; 30 import org.eclipse.team.internal.ui.Utils; 31 import org.eclipse.team.internal.ui.mapping.ModelCompareEditorInput; 32 import org.eclipse.team.internal.ui.synchronize.SyncInfoModelElement; 33 import org.eclipse.team.internal.ui.synchronize.patch.ApplyPatchModelCompareEditorInput; 34 import org.eclipse.team.internal.ui.synchronize.patch.ApplyPatchSubscriberMergeContext; 35 import org.eclipse.team.ui.mapping.ISynchronizationCompareInput; 36 import org.eclipse.team.ui.mapping.ITeamContentProviderManager; 37 import org.eclipse.team.ui.synchronize.ISynchronizePageConfiguration; 38 import org.eclipse.team.ui.synchronize.ISynchronizePageSite; 39 import org.eclipse.team.ui.synchronize.ISynchronizeParticipant; 40 import org.eclipse.team.ui.synchronize.ModelSynchronizeParticipant; 41 import org.eclipse.team.ui.synchronize.SyncInfoCompareInput; 42 import org.eclipse.ui.IEditorInput; 43 import org.eclipse.ui.IEditorPart; 44 import org.eclipse.ui.IEditorReference; 45 import org.eclipse.ui.IReusableEditor; 46 import org.eclipse.ui.IWorkbenchPage; 47 import org.eclipse.ui.IWorkbenchPartSite; 48 import org.eclipse.ui.IWorkbenchWindow; 49 import org.eclipse.ui.PlatformUI; 50 51 /** 52 * Action to open a compare editor from a SyncInfo object. 53 * 54 * @see SyncInfoCompareInput 55 * @since 3.0 56 */ 57 public class OpenInCompareAction extends Action { 58 59 private final ISynchronizePageConfiguration configuration; 60 OpenInCompareAction(ISynchronizePageConfiguration configuration)61 public OpenInCompareAction(ISynchronizePageConfiguration configuration) { 62 this.configuration = configuration; 63 Utils.initAction(this, "action.openInCompareEditor."); //$NON-NLS-1$ 64 } 65 66 @Override run()67 public void run() { 68 ISelection selection = configuration.getSite().getSelectionProvider().getSelection(); 69 if(selection instanceof IStructuredSelection) { 70 if (!isOkToRun(selection)) 71 return; 72 73 boolean reuseEditorIfPossible = ((IStructuredSelection) selection).size()==1; 74 for (Iterator iterator = ((IStructuredSelection) selection).iterator(); iterator.hasNext();) { 75 Object obj = iterator.next(); 76 if (obj instanceof SyncInfoModelElement) { 77 SyncInfo info = ((SyncInfoModelElement) obj).getSyncInfo(); 78 if (info != null) { 79 // Use the open strategy to decide if the editor or the sync view should have focus 80 openCompareEditorOnSyncInfo(configuration, info, !OpenStrategy.activateOnOpen(), reuseEditorIfPossible); 81 } 82 } else if (obj != null){ 83 openCompareEditor(configuration, obj, !OpenStrategy.activateOnOpen(), reuseEditorIfPossible); 84 } 85 } 86 } 87 } 88 isOkToRun(ISelection selection)89 private boolean isOkToRun(ISelection selection) { 90 // do not open Compare Editor unless all elements have input 91 Object[] elements = ((IStructuredSelection) selection).toArray(); 92 ISynchronizeParticipant participant = configuration 93 .getParticipant(); 94 // model synchronize 95 if (participant instanceof ModelSynchronizeParticipant) { 96 ModelSynchronizeParticipant msp = (ModelSynchronizeParticipant) participant; 97 for (Object element : elements) { 98 // TODO: This is inefficient 99 if (!msp.hasCompareInputFor(element)) { 100 return false; 101 } 102 } 103 } else { 104 // all files 105 IResource resources[] = Utils.getResources(elements); 106 for (IResource resource : resources) { 107 if (resource.getType() != IResource.FILE) { 108 // Only supported if all the items are files. 109 return false; 110 } 111 } 112 } 113 return true; 114 } 115 openCompareEditor(ISynchronizePageConfiguration configuration, Object object, boolean keepFocus, boolean reuseEditorIfPossible)116 public static IEditorInput openCompareEditor(ISynchronizePageConfiguration configuration, Object object, boolean keepFocus, boolean reuseEditorIfPossible) { 117 Assert.isNotNull(object); 118 Assert.isNotNull(configuration); 119 ISynchronizeParticipant participant = configuration.getParticipant(); 120 ISynchronizePageSite site = configuration.getSite(); 121 if (object instanceof SyncInfoModelElement) { 122 SyncInfo info = ((SyncInfoModelElement) object).getSyncInfo(); 123 if (info != null) 124 return openCompareEditorOnSyncInfo(configuration, info, keepFocus, reuseEditorIfPossible); 125 } 126 if (participant instanceof ModelSynchronizeParticipant) { 127 ModelSynchronizeParticipant msp = (ModelSynchronizeParticipant) participant; 128 ICompareInput input = msp.asCompareInput(object); 129 IWorkbenchPage workbenchPage = getWorkbenchPage(site); 130 if (input != null && workbenchPage != null && isOkToOpen(site, participant, input)) { 131 if (isApplyPatchModelPresent(configuration)) 132 return openCompareEditor(workbenchPage, new ApplyPatchModelCompareEditorInput(msp, input, workbenchPage, configuration), keepFocus, site, reuseEditorIfPossible); 133 else 134 return openCompareEditor(workbenchPage, new ModelCompareEditorInput(msp, input, workbenchPage, configuration), keepFocus, site, reuseEditorIfPossible); 135 } 136 } 137 return null; 138 } 139 isApplyPatchModelPresent( ISynchronizePageConfiguration configuration)140 private static boolean isApplyPatchModelPresent( 141 ISynchronizePageConfiguration configuration) { 142 Object object = configuration.getProperty(ITeamContentProviderManager.P_SYNCHRONIZATION_CONTEXT); 143 return object instanceof ApplyPatchSubscriberMergeContext; 144 } 145 isOkToOpen(final ISynchronizePageSite site, final ISynchronizeParticipant participant, final ICompareInput input)146 private static boolean isOkToOpen(final ISynchronizePageSite site, final ISynchronizeParticipant participant, final ICompareInput input) { 147 if (participant instanceof ModelSynchronizeParticipant && input instanceof ISynchronizationCompareInput) { 148 final ModelSynchronizeParticipant msp = (ModelSynchronizeParticipant) participant; 149 final boolean[] result = new boolean[] { false }; 150 try { 151 PlatformUI.getWorkbench().getProgressService().run(true, true, monitor -> { 152 try { 153 result[0] = msp.checkForBufferChange(site.getShell(), (ISynchronizationCompareInput) input, 154 true, monitor); 155 } catch (CoreException e) { 156 throw new InvocationTargetException(e); 157 } 158 }); 159 } catch (InvocationTargetException e) { 160 Utils.handleError(site.getShell(), e, null, null); 161 } catch (InterruptedException e) { 162 return false; 163 } 164 return result[0]; 165 } 166 return true; 167 } 168 openCompareEditorOnSyncInfo(ISynchronizePageConfiguration configuration, SyncInfo info, boolean keepFocus, boolean reuseEditorIfPossible)169 public static CompareEditorInput openCompareEditorOnSyncInfo(ISynchronizePageConfiguration configuration, SyncInfo info, boolean keepFocus, boolean reuseEditorIfPossible) { 170 Assert.isNotNull(info); 171 Assert.isNotNull(configuration); 172 if(info.getLocal().getType() != IResource.FILE) return null; 173 SyncInfoCompareInput input = new SyncInfoCompareInput(configuration, info); 174 return openCompareEditor(getWorkbenchPage(configuration.getSite()), input, keepFocus, configuration.getSite(), reuseEditorIfPossible); 175 } 176 openCompareEditor(ISynchronizeParticipant participant, SyncInfo info, ISynchronizePageSite site)177 public static CompareEditorInput openCompareEditor(ISynchronizeParticipant participant, SyncInfo info, ISynchronizePageSite site) { 178 Assert.isNotNull(info); 179 Assert.isNotNull(participant); 180 if(info.getLocal().getType() != IResource.FILE) return null; 181 SyncInfoCompareInput input = new SyncInfoCompareInput(participant, info); 182 return openCompareEditor(getWorkbenchPage(site), input, false, site, false); 183 } 184 openCompareEditor( IWorkbenchPage page, CompareEditorInput input, boolean keepFocus, ISynchronizePageSite site, boolean reuseEditorIfPossible)185 private static CompareEditorInput openCompareEditor( 186 IWorkbenchPage page, 187 CompareEditorInput input, 188 boolean keepFocus, 189 ISynchronizePageSite site, 190 boolean reuseEditorIfPossible) { 191 if (page == null) 192 return null; 193 194 openCompareEditor(input, page, reuseEditorIfPossible); 195 if(site != null && keepFocus) { 196 site.setFocus(); 197 } 198 return input; 199 } 200 getWorkbenchPage(ISynchronizePageSite site)201 private static IWorkbenchPage getWorkbenchPage(ISynchronizePageSite site) { 202 IWorkbenchPage page = null; 203 if(site == null || site.getWorkbenchSite() == null) { 204 IWorkbenchWindow window= PlatformUI.getWorkbench().getActiveWorkbenchWindow(); 205 if (window != null) 206 page = window.getActivePage(); 207 } else { 208 page = site.getWorkbenchSite().getPage(); 209 } 210 return page; 211 } 212 openCompareEditor(CompareEditorInput input, IWorkbenchPage page)213 public static void openCompareEditor(CompareEditorInput input, IWorkbenchPage page) { 214 // try to reuse editors, if possible 215 openCompareEditor(input, page, true); 216 } 217 openCompareEditor(CompareEditorInput input, IWorkbenchPage page, boolean reuseEditorIfPossible)218 public static void openCompareEditor(CompareEditorInput input, IWorkbenchPage page, boolean reuseEditorIfPossible) { 219 if (page == null || input == null) 220 return; 221 IEditorPart editor = Utils.findReusableCompareEditor(input, page, 222 new Class[] { SyncInfoCompareInput.class, 223 ModelCompareEditorInput.class }); 224 // reuse editor only for single selection 225 if(editor != null && reuseEditorIfPossible) { 226 IEditorInput otherInput = editor.getEditorInput(); 227 if(otherInput.equals(input)) { 228 // simply provide focus to editor 229 page.activate(editor); 230 } else { 231 // if editor is currently not open on that input either re-use existing 232 CompareUI.reuseCompareEditor(input, (IReusableEditor)editor); 233 page.activate(editor); 234 } 235 } else { 236 CompareUI.openCompareEditorOnPage(input, page); 237 } 238 } 239 240 /** 241 * Returns an editor handle if a SyncInfoCompareInput compare editor is opened on 242 * the given IResource. 243 * 244 * @param site the view site in which to search for editors 245 * @param resource the resource to use to find the compare editor 246 * @return an editor handle if found and <code>null</code> otherwise 247 */ findOpenCompareEditor(IWorkbenchPartSite site, IResource resource)248 public static IEditorPart findOpenCompareEditor(IWorkbenchPartSite site, IResource resource) { 249 IWorkbenchPage page = site.getPage(); 250 IEditorReference[] editorRefs = page.getEditorReferences(); 251 for (IEditorReference editorRef : editorRefs) { 252 final IEditorPart part = editorRef.getEditor(false /* don't restore editor */); 253 if(part != null) { 254 IEditorInput input = part.getEditorInput(); 255 if(part != null && input instanceof SyncInfoCompareInput) { 256 SyncInfo inputInfo = ((SyncInfoCompareInput)input).getSyncInfo(); 257 if(inputInfo.getLocal().equals(resource)) { 258 return part; 259 } 260 } 261 } 262 } 263 return null; 264 } 265 266 /** 267 * Returns an editor handle if a compare editor is opened on 268 * the given object. 269 * @param site the view site in which to search for editors 270 * @param object the object to use to find the compare editor 271 * @param participant 272 * @return an editor handle if found and <code>null</code> otherwise 273 */ findOpenCompareEditor(IWorkbenchPartSite site, Object object, ISynchronizeParticipant participant)274 public static IEditorPart findOpenCompareEditor(IWorkbenchPartSite site, Object object, ISynchronizeParticipant participant) { 275 if (object instanceof SyncInfoModelElement) { 276 SyncInfoModelElement element = (SyncInfoModelElement) object; 277 SyncInfo info = element.getSyncInfo(); 278 return findOpenCompareEditor(site, info.getLocal()); 279 } 280 IWorkbenchPage page = site.getPage(); 281 IEditorReference[] editorRefs = page.getEditorReferences(); 282 for (IEditorReference editorRef : editorRefs) { 283 final IEditorPart part = editorRef.getEditor(false /* don't restore editor */); 284 if(part != null) { 285 IEditorInput input = part.getEditorInput(); 286 if(input instanceof ModelCompareEditorInput) { 287 if(((ModelCompareEditorInput)input).matches(object, participant)) { 288 return part; 289 } 290 } 291 } 292 } 293 return null; 294 } 295 } 296