| /******************************************************************************* |
| * Copyright (c) 2000, 2018 IBM Corporation and others. |
| * |
| * This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License 2.0 |
| * which accompanies this distribution, and is available at |
| * https://www.eclipse.org/legal/epl-2.0/ |
| * |
| * SPDX-License-Identifier: EPL-2.0 |
| * |
| * Contributors: |
| * IBM Corporation - initial API and implementation |
| *******************************************************************************/ |
| package org.eclipse.team.internal.ui.synchronize; |
| |
| import java.util.ArrayList; |
| import java.util.Arrays; |
| import java.util.HashMap; |
| import java.util.HashSet; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.ResourceBundle; |
| import java.util.Set; |
| |
| import org.eclipse.compare.CompareEditorInput; |
| import org.eclipse.compare.ITypedElement; |
| import org.eclipse.compare.ResourceNode; |
| import org.eclipse.compare.structuremergeviewer.ICompareInput; |
| import org.eclipse.core.resources.IFile; |
| import org.eclipse.core.resources.IResource; |
| import org.eclipse.core.runtime.Assert; |
| import org.eclipse.core.runtime.CoreException; |
| import org.eclipse.core.runtime.IAdaptable; |
| import org.eclipse.core.runtime.IProgressMonitor; |
| import org.eclipse.core.runtime.IStatus; |
| import org.eclipse.core.runtime.Status; |
| import org.eclipse.jface.action.IAction; |
| import org.eclipse.jface.action.IMenuManager; |
| import org.eclipse.jface.action.IToolBarManager; |
| import org.eclipse.jface.commands.ActionHandler; |
| import org.eclipse.jface.dialogs.DialogSettings; |
| import org.eclipse.jface.dialogs.ErrorDialog; |
| import org.eclipse.jface.dialogs.IDialogSettings; |
| import org.eclipse.jface.util.IPropertyChangeListener; |
| import org.eclipse.jface.util.PropertyChangeEvent; |
| import org.eclipse.jface.viewers.IBasicPropertyConstants; |
| import org.eclipse.jface.viewers.IElementComparer; |
| import org.eclipse.jface.viewers.ISelection; |
| import org.eclipse.jface.viewers.IStructuredSelection; |
| import org.eclipse.jface.viewers.StructuredSelection; |
| import org.eclipse.jface.viewers.StructuredViewer; |
| import org.eclipse.jface.viewers.TreeViewer; |
| import org.eclipse.osgi.util.NLS; |
| import org.eclipse.swt.widgets.Composite; |
| import org.eclipse.swt.widgets.Display; |
| import org.eclipse.team.core.TeamException; |
| import org.eclipse.team.core.history.IFileRevision; |
| import org.eclipse.team.core.variants.IResourceVariant; |
| import org.eclipse.team.internal.core.mapping.ResourceVariantFileRevision; |
| import org.eclipse.team.internal.ui.IHelpContextIds; |
| import org.eclipse.team.internal.ui.Policy; |
| import org.eclipse.team.internal.ui.TeamUIMessages; |
| import org.eclipse.team.internal.ui.TeamUIPlugin; |
| import org.eclipse.team.internal.ui.Utils; |
| import org.eclipse.team.internal.ui.history.FileRevisionEditorInput; |
| import org.eclipse.team.internal.ui.synchronize.actions.PasteAction; |
| import org.eclipse.team.internal.ui.synchronize.actions.PinParticipantAction; |
| import org.eclipse.team.internal.ui.synchronize.actions.RemoveSynchronizeParticipantAction; |
| import org.eclipse.team.internal.ui.synchronize.actions.SynchronizeAndRefreshAction; |
| import org.eclipse.team.internal.ui.synchronize.actions.SynchronizePageDropDownAction; |
| import org.eclipse.team.internal.ui.synchronize.actions.ToggleLinkingAction; |
| import org.eclipse.team.ui.TeamUI; |
| import org.eclipse.team.ui.synchronize.ISynchronizeManager; |
| import org.eclipse.team.ui.synchronize.ISynchronizePage; |
| import org.eclipse.team.ui.synchronize.ISynchronizePageConfiguration; |
| import org.eclipse.team.ui.synchronize.ISynchronizeParticipant; |
| import org.eclipse.team.ui.synchronize.ISynchronizeParticipantListener; |
| import org.eclipse.team.ui.synchronize.ISynchronizeParticipantReference; |
| import org.eclipse.team.ui.synchronize.ISynchronizeView; |
| import org.eclipse.team.ui.synchronize.ModelSynchronizeParticipant; |
| import org.eclipse.ui.IActionBars; |
| import org.eclipse.ui.IEditorInput; |
| import org.eclipse.ui.IEditorPart; |
| import org.eclipse.ui.IEditorReference; |
| import org.eclipse.ui.IPartListener2; |
| import org.eclipse.ui.ISaveablePart; |
| import org.eclipse.ui.ISaveablesLifecycleListener; |
| import org.eclipse.ui.ISaveablesSource; |
| import org.eclipse.ui.IStorageEditorInput; |
| import org.eclipse.ui.IViewSite; |
| import org.eclipse.ui.IWorkbenchCommandConstants; |
| import org.eclipse.ui.IWorkbenchPage; |
| import org.eclipse.ui.IWorkbenchPart; |
| import org.eclipse.ui.IWorkbenchPartReference; |
| import org.eclipse.ui.OpenAndLinkWithEditorHelper; |
| import org.eclipse.ui.PartInitException; |
| import org.eclipse.ui.PlatformUI; |
| import org.eclipse.ui.Saveable; |
| import org.eclipse.ui.SaveablesLifecycleEvent; |
| import org.eclipse.ui.actions.ActionFactory; |
| import org.eclipse.ui.handlers.IHandlerService; |
| import org.eclipse.ui.ide.IDE; |
| import org.eclipse.ui.part.EditorPart; |
| import org.eclipse.ui.part.FileEditorInput; |
| import org.eclipse.ui.part.IPage; |
| import org.eclipse.ui.part.IPageBookViewPage; |
| import org.eclipse.ui.part.IShowInTarget; |
| import org.eclipse.ui.part.MessagePage; |
| import org.eclipse.ui.part.Page; |
| import org.eclipse.ui.part.PageBook; |
| import org.eclipse.ui.part.PageBookView; |
| import org.eclipse.ui.part.ShowInContext; |
| import org.eclipse.ui.progress.IWorkbenchSiteProgressService; |
| import org.osgi.framework.FrameworkUtil; |
| |
| /** |
| * Implements a Synchronize View that contains multiple synchronize participants. |
| */ |
| public class SynchronizeView extends PageBookView implements ISynchronizeView, ISynchronizeParticipantListener, IPropertyChangeListener, ISaveablesSource, ISaveablePart, IShowInTarget { |
| |
| /** |
| * Suggested maximum length of participant names when shown in certain menus and dialog. |
| */ |
| public final static int MAX_NAME_LENGTH = 100; |
| |
| /** |
| * The participant being displayed, or <code>null</code> if none |
| */ |
| private ISynchronizeParticipant activeParticipantRef = null; |
| |
| /** |
| * Map of participants to dummy participant parts (used to close pages) |
| */ |
| private Map<ISynchronizeParticipant, IWorkbenchPart> fParticipantToPart; |
| |
| /** |
| * Map of parts to participants |
| */ |
| private Map<IWorkbenchPart, ISynchronizeParticipant> fPartToParticipant; |
| |
| /** |
| * Drop down action to switch between participants |
| */ |
| private SynchronizePageDropDownAction fPageDropDown; |
| |
| /** |
| * Action to remove the selected participant |
| */ |
| private PinParticipantAction fPinAction; |
| |
| /** |
| * Action to remove the currently shown participant |
| */ |
| private RemoveSynchronizeParticipantAction fRemoveCurrentAction; |
| |
| /** |
| * Action to remove all non-pinned participants |
| */ |
| private RemoveSynchronizeParticipantAction fRemoveAllAction; |
| |
| private ToggleLinkingAction fToggleLinkingAction; |
| |
| /** |
| * Refresh action. |
| * @since 3.7 |
| */ |
| private SynchronizeAndRefreshAction fRefreshAction; |
| |
| |
| /** |
| * Action to paste patch into the view, starting a new synchronization. |
| */ |
| private PasteAction fPastePatchAction; |
| private boolean fLinkingEnabled; |
| private OpenAndLinkWithEditorHelper fOpenAndLinkWithEditorHelper; |
| |
| |
| /** |
| * Preference key to save |
| */ |
| private static final String KEY_LAST_ACTIVE_PARTICIPANT_ID = "lastactiveparticipant_id"; //$NON-NLS-1$ |
| private static final String KEY_LAST_ACTIVE_PARTICIPANT_SECONDARY_ID = "lastactiveparticipant_sec_id"; //$NON-NLS-1$ |
| private static final String KEY_LINK_WITH_EDITOR = "linkWithEditor"; //$NON-NLS-1$ |
| private static final String KEY_SETTINGS_SECTION= "SynchronizeViewSettings"; //$NON-NLS-1$ |
| |
| |
| @Override |
| public void propertyChange(PropertyChangeEvent event) { |
| Object source = event.getSource(); |
| if (source instanceof ISynchronizeParticipant) { |
| if (event.getProperty().equals(IBasicPropertyConstants.P_TEXT)) { |
| if (source.equals(getParticipant())) { |
| updateTitle(); |
| } |
| } else if (event.getProperty().equals(ModelSynchronizeParticipant.PROP_DIRTY)) { |
| Display.getDefault().asyncExec(() -> firePropertyChange(PROP_DIRTY)); |
| } else if (event.getProperty().equals(ModelSynchronizeParticipant.PROP_ACTIVE_SAVEABLE)) { |
| Saveable oldSaveable = (Saveable)event.getOldValue(); |
| Saveable newSaveable = (Saveable)event.getNewValue(); |
| ISaveablesLifecycleListener listener = getSite().getPage().getWorkbenchWindow() |
| .getService(ISaveablesLifecycleListener.class); |
| if (listener != null && oldSaveable != null) |
| listener.handleLifecycleEvent(new SaveablesLifecycleEvent(this, SaveablesLifecycleEvent.POST_CLOSE, new Saveable[] { oldSaveable }, false)); |
| if (listener != null && newSaveable != null) |
| listener.handleLifecycleEvent(new SaveablesLifecycleEvent(this, SaveablesLifecycleEvent.POST_OPEN, new Saveable[] { newSaveable }, false)); |
| } else if (event.getProperty().equals(ISynchronizeParticipant.P_CONTENT)) { |
| final IWorkbenchSiteProgressService ps = getSite().getAdapter(IWorkbenchSiteProgressService.class); |
| if (ps != null) |
| Display.getDefault().asyncExec(() -> ps.warnOfContentChange()); |
| } |
| } |
| if (source instanceof ISynchronizePageConfiguration) { |
| ISynchronizePageConfiguration configuration = (ISynchronizePageConfiguration) source; |
| if (event.getProperty().equals(ISynchronizePageConfiguration.P_PAGE_DESCRIPTION)) { |
| if (configuration.getParticipant().equals(getParticipant())) { |
| updateTitle(); |
| } |
| } else if (event.getProperty().equals(ISynchronizePageConfiguration.P_MODE)) { |
| if (configuration.getParticipant().equals(getParticipant())) { |
| updateTitle(); |
| } |
| } |
| } |
| } |
| |
| @Override |
| public void partClosed(IWorkbenchPart part) { |
| super.partClosed(part); |
| } |
| |
| @Override |
| public ISynchronizeParticipant getParticipant() { |
| return activeParticipantRef; |
| } |
| |
| @Override |
| protected void showPageRec(PageRec pageRec) { |
| super.showPageRec(pageRec); |
| activeParticipantRef = fPartToParticipant.get(pageRec.part); |
| updateActionEnablements(); |
| updateTitle(); |
| } |
| |
| /* |
| * Updates the view title based on the active participant |
| */ |
| protected void updateTitle() { |
| ISynchronizeParticipant participant = getParticipant(); |
| if (participant == null) { |
| setContentDescription(""); //$NON-NLS-1$ |
| } else { |
| SynchronizeViewWorkbenchPart part = (SynchronizeViewWorkbenchPart)fParticipantToPart.get(participant); |
| ISynchronizePageConfiguration configuration = part.getConfiguration(); |
| String description = (String)configuration.getProperty(ISynchronizePageConfiguration.P_PAGE_DESCRIPTION); |
| if (description == null) |
| description = part.getParticipant().getName(); |
| // TODO: Get the description from the configuration |
| // TODO: listen to the configuration for description changes |
| setContentDescription(Utils.shortenText(MAX_NAME_LENGTH, description)); |
| setStatusLineMessage(description, configuration.getMode()); |
| } |
| } |
| |
| @Override |
| protected void doDestroyPage(IWorkbenchPart part, PageRec pageRecord) { |
| IPage page = pageRecord.page; |
| page.dispose(); |
| pageRecord.dispose(); |
| SynchronizeViewWorkbenchPart syncPart = (SynchronizeViewWorkbenchPart) part; |
| ISynchronizeParticipant participant = syncPart.getParticipant(); |
| clearCrossReferenceCache(part, participant); |
| } |
| |
| private void clearCrossReferenceCache(IWorkbenchPart part, ISynchronizeParticipant participant) { |
| participant.removePropertyChangeListener(this); |
| if (part == null) |
| return; |
| ISynchronizePageConfiguration configuration = ((SynchronizeViewWorkbenchPart)part).getConfiguration(); |
| if (configuration != null) |
| configuration.removePropertyChangeListener(this); |
| fPartToParticipant.remove(part); |
| fParticipantToPart.remove(participant); |
| } |
| |
| @Override |
| protected PageRec doCreatePage(IWorkbenchPart dummyPart) { |
| SynchronizeViewWorkbenchPart part = (SynchronizeViewWorkbenchPart)dummyPart; |
| ISynchronizeParticipant participant = part.getParticipant(); |
| participant.addPropertyChangeListener(this); |
| ISynchronizePageConfiguration configuration = participant.createPageConfiguration(); |
| part.setConfiguration(configuration); |
| configuration.addPropertyChangeListener(this); |
| IPageBookViewPage page = participant.createPage(configuration); |
| if(page != null) { |
| initPage(page); |
| initPage(configuration, page); |
| page.createControl(getPageBook()); |
| PageRec rec = new PageRec(dummyPart, page); |
| return rec; |
| } |
| return null; |
| } |
| |
| protected void initPage(ISynchronizePageConfiguration configuration, IPageBookViewPage page) { |
| // A page site does not provide everything the page may need |
| // Also provide the synchronize page site if the page is a synchronize view page |
| ((SynchronizePageConfiguration)configuration).setSite(new WorkbenchPartSynchronizePageSite(this, page.getSite(), getDialogSettings(configuration.getParticipant()))); |
| if (page instanceof ISynchronizePage) { |
| try { |
| ((ISynchronizePage)page).init(configuration.getSite()); |
| } catch (PartInitException e) { |
| TeamUIPlugin.log(IStatus.ERROR, e.getMessage(), e); |
| } |
| } |
| page.getSite().getActionBars().setGlobalActionHandler(ActionFactory.REFRESH.getId(), fRefreshAction); |
| page.getSite().getActionBars().updateActionBars(); |
| } |
| |
| @Override |
| protected boolean isImportant(IWorkbenchPart part) { |
| return part instanceof SynchronizeViewWorkbenchPart; |
| } |
| |
| @Override |
| public void dispose() { |
| super.dispose(); |
| TeamUI.getSynchronizeManager().removeSynchronizeParticipantListener(this); |
| // Pin action is hooked up to listeners, must call dispose to un-register. |
| fPinAction.dispose(); |
| fPastePatchAction.dispose(); |
| // Remember the last active participant |
| if(activeParticipantRef != null) { |
| rememberCurrentParticipant(); |
| } |
| fParticipantToPart = null; |
| fPartToParticipant = null; |
| // Remove 'Link with Editor' listener when closing the view |
| getSite().getPage().removePartListener(fLinkWithEditorListener); |
| } |
| |
| /** |
| * |
| */ |
| private void rememberCurrentParticipant() { |
| IDialogSettings section = getDialogSettings(); |
| section.put(KEY_LAST_ACTIVE_PARTICIPANT_ID, activeParticipantRef.getId()); |
| section.put(KEY_LAST_ACTIVE_PARTICIPANT_SECONDARY_ID, activeParticipantRef.getSecondaryId()); |
| } |
| |
| @Override |
| protected IPage createDefaultPage(PageBook book) { |
| Page page = new MessagePage(); |
| page.createControl(getPageBook()); |
| initPage(page); |
| return page; |
| } |
| |
| @Override |
| public void participantsAdded(final ISynchronizeParticipant[] participants) { |
| for (ISynchronizeParticipant participant : participants) { |
| if (isAvailable() && select(TeamUI.getSynchronizeManager().get(participant.getId(), participant.getSecondaryId()))) { |
| SynchronizeViewWorkbenchPart part = new SynchronizeViewWorkbenchPart(participant, getSite()); |
| fParticipantToPart.put(participant, part); |
| fPartToParticipant.put(part, participant); |
| } |
| } |
| Display.getDefault().asyncExec(() -> firePropertyChange(PROP_DIRTY)); |
| } |
| |
| @Override |
| public void participantsRemoved(final ISynchronizeParticipant[] participants) { |
| if (isAvailable()) { |
| Runnable r = () -> { |
| for (ISynchronizeParticipant participant : participants) { |
| if (isAvailable()) { |
| SynchronizeViewWorkbenchPart part = (SynchronizeViewWorkbenchPart)fParticipantToPart.get(participant); |
| if (part != null) { |
| partClosed(part); |
| clearCrossReferenceCache(part, participant); |
| } |
| // Remove any settings created for the participant |
| removeDialogSettings(participant); |
| if (getParticipant() == null) { |
| ISynchronizeParticipantReference[] available = TeamUI.getSynchronizeManager().getSynchronizeParticipants(); |
| if (available.length > 0) { |
| ISynchronizeParticipant p; |
| try { |
| p = available[available.length - 1].getParticipant(); |
| } catch (TeamException e) { |
| return; |
| } |
| display(p); |
| } else { |
| /* |
| * Remove 'Link with Editor' listener if |
| * there are no more participants available. |
| */ |
| getSite().getPage().removePartListener(fLinkWithEditorListener); |
| } |
| } |
| } |
| } |
| firePropertyChange(PROP_DIRTY); |
| }; |
| asyncExec(r); |
| } |
| } |
| |
| /** |
| * Constructs a synchronize view |
| */ |
| public SynchronizeView() { |
| super(); |
| fParticipantToPart = new HashMap<>(); |
| fPartToParticipant = new HashMap<>(); |
| updateTitle(); |
| } |
| |
| /** |
| * Create the default actions for the view. These will be shown regardless of the |
| * participant being displayed. |
| */ |
| protected void createActions() { |
| fPageDropDown= new SynchronizePageDropDownAction(this); |
| fRefreshAction= new SynchronizeAndRefreshAction(this); |
| fPinAction = new PinParticipantAction(); |
| fToggleLinkingAction = new ToggleLinkingAction(this); |
| fRemoveCurrentAction = new RemoveSynchronizeParticipantAction(this, false); |
| fRemoveAllAction = new RemoveSynchronizeParticipantAction(this, true); |
| fPastePatchAction = new PasteAction(this); |
| updateActionEnablements(); |
| } |
| |
| private void updateActionEnablements() { |
| if (fPinAction != null) { |
| fPinAction.setParticipant(activeParticipantRef); |
| } |
| if (fToggleLinkingAction != null) { |
| fToggleLinkingAction.setEnabled(getParticipant() != null); |
| } |
| if (fRemoveAllAction != null) { |
| fRemoveAllAction.setEnabled(getParticipant() != null); |
| } |
| if (fRemoveCurrentAction != null) { |
| fRemoveCurrentAction.setEnabled(getParticipant() != null); |
| } |
| if (fPastePatchAction != null) { |
| // The action is always enabled |
| fPastePatchAction.setEnabled(true); |
| } |
| } |
| |
| /** |
| * Add the actions to the toolbar |
| * |
| * @param bars the action bars |
| */ |
| protected void configureToolBar(IActionBars bars) { |
| IToolBarManager mgr = bars.getToolBarManager(); |
| mgr.add(fPageDropDown); |
| mgr.add(fPinAction); |
| IMenuManager menu = bars.getMenuManager(); |
| menu.add(fPinAction); |
| menu.add(fToggleLinkingAction); |
| menu.add(fRemoveCurrentAction); |
| menu.add(fRemoveAllAction); |
| |
| IHandlerService handlerService= this.getViewSite().getService(IHandlerService.class); |
| handlerService.activateHandler(IWorkbenchCommandConstants.NAVIGATE_TOGGLE_LINK_WITH_EDITOR, new ActionHandler(fToggleLinkingAction)); |
| handlerService.activateHandler(ActionFactory.PASTE.getCommandId(), new ActionHandler(fPastePatchAction)); |
| } |
| |
| @Override |
| public void display(ISynchronizeParticipant participant) { |
| SynchronizeViewWorkbenchPart part = (SynchronizeViewWorkbenchPart)fParticipantToPart.get(participant); |
| if (part != null) { |
| partActivated(part); |
| fPageDropDown.update(); |
| createOpenAndLinkWithEditorHelper(getViewer()); |
| rememberCurrentParticipant(); |
| PlatformUI.getWorkbench().getHelpSystem().setHelp(getPageBook().getParent(), participant.getHelpContextId()); |
| } |
| } |
| |
| private void createOpenAndLinkWithEditorHelper(StructuredViewer viewer) { |
| if (fOpenAndLinkWithEditorHelper != null) |
| fOpenAndLinkWithEditorHelper.dispose(); |
| fOpenAndLinkWithEditorHelper= new OpenAndLinkWithEditorHelper(viewer) { |
| @Override |
| protected void activate(ISelection selection) { |
| try { |
| final Object selectedElement = getSingleElement(selection); |
| if (isOpenInEditor(selectedElement) != null) |
| if (selectedElement instanceof IFile) |
| openInEditor((IFile) selectedElement, true); |
| } catch (PartInitException ex) { |
| // ignore if no editor input can be found |
| } |
| } |
| |
| @Override |
| protected void linkToEditor(ISelection selection) { |
| SynchronizeView.this.linkToEditor(selection); |
| } |
| |
| @Override |
| protected void open(ISelection selection, boolean activate) { |
| // TODO: implement, bug 291211 |
| } |
| }; |
| fOpenAndLinkWithEditorHelper.setLinkWithEditor(isLinkingEnabled()); |
| setLinkingEnabled(isLinkingEnabled()); |
| } |
| |
| @Override |
| protected IWorkbenchPart getBootstrapPart() { |
| return null; |
| } |
| |
| /** |
| * Registers the given runnable with the display |
| * associated with this view's control, if any. |
| * @param runnable a runnable |
| */ |
| public void asyncExec(Runnable runnable) { |
| if (isAvailable()) { |
| getPageBook().getDisplay().asyncExec(runnable); |
| } |
| } |
| |
| /** |
| * Creates this view's underlying viewer and actions. |
| * Hooks a pop-up menu to the underlying viewer's control, |
| * as well as a key listener. When the delete key is pressed, |
| * the <code>REMOVE_ACTION</code> is invoked. Hooks help to |
| * this view. Subclasses must implement the following methods |
| * which are called in the following order when a view is |
| * created:<ul> |
| * <li><code>createViewer(Composite)</code> - the context |
| * menu is hooked to the viewer's control.</li> |
| * <li><code>createActions()</code></li> |
| * <li><code>configureToolBar(IToolBarManager)</code></li> |
| * <li><code>getHelpContextId()</code></li> |
| * </ul> |
| * @see IWorkbenchPart#createPartControl(Composite) |
| */ |
| @Override |
| public void createPartControl(Composite parent) { |
| super.createPartControl(parent); |
| restoreLinkingEnabled(); |
| createActions(); |
| configureToolBar(getViewSite().getActionBars()); |
| updateForExistingParticipants(); |
| getViewSite().getActionBars().updateActionBars(); |
| updateTitle(); |
| |
| IWorkbenchSiteProgressService progress = getSite().getAdapter(IWorkbenchSiteProgressService.class); |
| if(progress != null) { |
| progress.showBusyForFamily(ISynchronizeManager.FAMILY_SYNCHRONIZE_OPERATION); |
| } |
| |
| PlatformUI.getWorkbench().getHelpSystem().setHelp(parent, IHelpContextIds.SYNC_VIEW); |
| } |
| |
| /** |
| * Initialize for existing participants |
| */ |
| private void updateForExistingParticipants() { |
| ISynchronizeManager manager = TeamUI.getSynchronizeManager(); |
| List participants = Arrays.asList(getParticipants()); |
| boolean errorOccurred = false; |
| for (Object participant : participants) { |
| try { |
| ISynchronizeParticipantReference ref = (ISynchronizeParticipantReference)participant; |
| participantsAdded(new ISynchronizeParticipant[] {ref.getParticipant()}); |
| } catch (TeamException e) { |
| errorOccurred = true; |
| continue; |
| } |
| |
| } |
| if (errorOccurred) { |
| participants = Arrays.asList(getParticipants()); |
| } |
| try { |
| // decide which participant to show on startup |
| if (participants.size() > 0) { |
| ISynchronizeParticipantReference participantToSelect = (ISynchronizeParticipantReference)participants.get(0); |
| IDialogSettings section = getDialogSettings(); |
| String selectedParticipantId = section.get(KEY_LAST_ACTIVE_PARTICIPANT_ID); |
| String selectedParticipantSecId = section.get(KEY_LAST_ACTIVE_PARTICIPANT_SECONDARY_ID); |
| if(selectedParticipantId != null) { |
| ISynchronizeParticipantReference selectedParticipant = manager.get(selectedParticipantId, selectedParticipantSecId); |
| if(selectedParticipant != null) { |
| participantToSelect = selectedParticipant; |
| } |
| } |
| display(participantToSelect.getParticipant()); |
| } |
| |
| // add as a listener to update when new participants are added |
| manager.addSynchronizeParticipantListener(this); |
| } catch (TeamException e) { |
| Utils.handle(e); |
| } |
| } |
| |
| private ISynchronizeParticipantReference[] getParticipants() { |
| ISynchronizeManager manager = TeamUI.getSynchronizeManager(); |
| // create pages |
| List<ISynchronizeParticipantReference> participants = new ArrayList<>(); |
| ISynchronizeParticipantReference[] refs = manager.getSynchronizeParticipants(); |
| for (ISynchronizeParticipantReference ref : refs) { |
| if(select(ref)) { |
| participants.add(ref); |
| } |
| } |
| return participants.toArray(new ISynchronizeParticipantReference[participants.size()]); |
| } |
| |
| private boolean isAvailable() { |
| return getPageBook() != null && !getPageBook().isDisposed(); |
| } |
| |
| /* |
| * Method used by test cases to access the page for a participant |
| */ |
| public IPage getPage(ISynchronizeParticipant participant) { |
| IWorkbenchPart part = fParticipantToPart.get(participant); |
| if (part == null) return null; |
| try { |
| return getPageRec(part).page; |
| } catch (NullPointerException e) { |
| // The PageRec class is not visible so we can't do a null check |
| // before accessing the page. |
| return null; |
| } |
| } |
| |
| protected boolean select(ISynchronizeParticipantReference ref) { |
| return true; |
| } |
| |
| /* |
| * Return the dialog settings for the view |
| */ |
| private IDialogSettings getDialogSettings() { |
| IDialogSettings workbenchSettings = PlatformUI.getDialogSettingsProvider(FrameworkUtil.getBundle(SynchronizeView.class)).getDialogSettings(); |
| IDialogSettings syncViewSettings = workbenchSettings.getSection(KEY_SETTINGS_SECTION); |
| if (syncViewSettings == null) { |
| syncViewSettings = workbenchSettings.addNewSection(KEY_SETTINGS_SECTION); |
| } |
| return syncViewSettings; |
| } |
| |
| private String getSettingsKey(ISynchronizeParticipant participant) { |
| String id = participant.getId(); |
| String secondaryId = participant.getSecondaryId(); |
| return secondaryId == null ? id : id + '.' + secondaryId; |
| } |
| |
| private IDialogSettings getDialogSettings(ISynchronizeParticipant participant) { |
| String key = getSettingsKey(participant); |
| IDialogSettings viewsSettings = getDialogSettings(); |
| IDialogSettings settings = viewsSettings.getSection(key); |
| if (settings == null) { |
| settings = viewsSettings.addNewSection(key); |
| } |
| return settings; |
| } |
| |
| private void removeDialogSettings(ISynchronizeParticipant participant) { |
| String key = getSettingsKey(participant); |
| IDialogSettings settings = getDialogSettings(); |
| if (settings.getSection(key) != null) { |
| // There isn't an explicit remove so just make sure |
| // That the old settings are forgotten |
| getDialogSettings().addSection(new DialogSettings(key)); |
| } |
| } |
| |
| @Override |
| public Saveable[] getSaveables() { |
| Set<Saveable> result = new HashSet<>(); |
| for (Object element : fPartToParticipant.keySet()) { |
| SynchronizeViewWorkbenchPart part = (SynchronizeViewWorkbenchPart) element; |
| Saveable saveable = getSaveable(part.getParticipant()); |
| if (saveable != null) { |
| result.add(saveable); |
| } |
| } |
| return result.toArray(new Saveable[result.size()]); |
| } |
| |
| private Saveable getSaveable(ISynchronizeParticipant participant) { |
| if (participant instanceof ModelSynchronizeParticipant) { |
| ModelSynchronizeParticipant msp = (ModelSynchronizeParticipant) participant; |
| return msp.getActiveSaveable(); |
| } |
| return null; |
| } |
| |
| @Override |
| public Saveable[] getActiveSaveables() { |
| ISynchronizeParticipant participant = getParticipant(); |
| Saveable s = getSaveable(participant); |
| if (s != null) |
| return new Saveable[] { s }; |
| return new Saveable[0]; |
| } |
| |
| @Override |
| public void doSave(IProgressMonitor monitor) { |
| Saveable[] saveables = getSaveables(); |
| if (saveables.length == 0) |
| return; |
| monitor.beginTask(null, 100* saveables.length); |
| for (Saveable saveable : saveables) { |
| try { |
| saveable.doSave(Policy.subMonitorFor(monitor, 100)); |
| } catch (CoreException e) { |
| ErrorDialog.openError(getSite().getShell(), null, e.getMessage(), e.getStatus()); |
| } |
| Policy.checkCanceled(monitor); |
| } |
| monitor.done(); |
| firePropertyChange(PROP_DIRTY); |
| } |
| |
| @Override |
| public void doSaveAs() { |
| // Not allowed |
| } |
| |
| @Override |
| public boolean isDirty() { |
| Saveable[] saveables = getSaveables(); |
| for (Saveable saveable : saveables) { |
| if (saveable.isDirty()) |
| return true; |
| } |
| return false; |
| } |
| |
| @Override |
| public boolean isSaveAsAllowed() { |
| return false; |
| } |
| |
| @Override |
| public boolean isSaveOnCloseNeeded() { |
| return true; |
| } |
| |
| private void setStatusLineMessage(String description, int mode) { |
| String syncMode = null; |
| ResourceBundle bundle = Policy.getActionBundle(); |
| switch (mode) { |
| case ISynchronizePageConfiguration.INCOMING_MODE: |
| syncMode = Utils.getString("action.directionFilterIncoming.tooltip", bundle); //$NON-NLS-1$ |
| break; |
| case ISynchronizePageConfiguration.OUTGOING_MODE: |
| syncMode = Utils.getString("action.directionFilterOutgoing.tooltip", bundle); //$NON-NLS-1$ |
| break; |
| case ISynchronizePageConfiguration.BOTH_MODE: |
| syncMode = Utils.getString("action.directionFilterBoth.tooltip", bundle); //$NON-NLS-1$ |
| break; |
| case ISynchronizePageConfiguration.CONFLICTING_MODE: |
| syncMode = Utils.getString("action.directionFilterConflicts.tooltip", bundle); //$NON-NLS-1$ |
| break; |
| } |
| |
| IViewSite viewSite = getViewSite(); |
| if (viewSite != null && syncMode != null) { |
| viewSite.getActionBars().getStatusLineManager().setMessage( |
| NLS.bind(TeamUIMessages.SynchronizeView_statusLine, |
| new String[] { description, syncMode })); |
| } |
| } |
| |
| // copy-pasted from org.eclipse.jdt.internal.ui.packageview.PackageExplorerPart and modified |
| |
| private IPartListener2 fLinkWithEditorListener= new IPartListener2() { |
| @Override |
| public void partVisible(IWorkbenchPartReference partRef) {} |
| @Override |
| public void partBroughtToTop(IWorkbenchPartReference partRef) {} |
| @Override |
| public void partClosed(IWorkbenchPartReference partRef) {} |
| @Override |
| public void partDeactivated(IWorkbenchPartReference partRef) {} |
| @Override |
| public void partHidden(IWorkbenchPartReference partRef) {} |
| @Override |
| public void partOpened(IWorkbenchPartReference partRef) {} |
| @Override |
| public void partInputChanged(IWorkbenchPartReference partRef) { |
| if (partRef instanceof IEditorReference) { |
| editorActivated(((IEditorReference) partRef).getEditor(true)); |
| } |
| } |
| |
| @Override |
| public void partActivated(IWorkbenchPartReference partRef) { |
| if (partRef instanceof IEditorReference) { |
| editorActivated(((IEditorReference) partRef).getEditor(true)); |
| } |
| } |
| |
| }; |
| |
| public boolean isLinkingEnabled() { |
| return fLinkingEnabled; |
| } |
| |
| private static IElementComparer COMPARER = new IElementComparer() { |
| |
| private Object getContributedResourceOrResourceVariant(Object o) { |
| IResource[] resources = Utils.getContributedResources(new Object[] {o}); |
| if (resources.length > 0) |
| return resources[0]; |
| if (o instanceof SyncInfoModelElement) { |
| SyncInfoModelElement sime = (SyncInfoModelElement) o; |
| return sime.getSyncInfo().getRemote(); |
| } |
| return null; |
| } |
| |
| @Override |
| public int hashCode(Object element) { |
| Object r = getContributedResourceOrResourceVariant(element); |
| if (r != null) |
| return r.hashCode(); |
| return element.hashCode(); |
| } |
| |
| @Override |
| public boolean equals(Object a, Object b) { |
| // no need to check for null, CustomeHashtable cannot contain null keys |
| if (a instanceof IResource || a instanceof IResourceVariant) { |
| b = getContributedResourceOrResourceVariant(b); |
| } else if (b instanceof IResource || b instanceof IResourceVariant) { |
| a = getContributedResourceOrResourceVariant(a); |
| return b.equals(a); // a may be null |
| } |
| return a.equals(b); |
| } |
| }; |
| |
| public void setLinkingEnabled(boolean enabled) { |
| fLinkingEnabled= enabled; |
| IDialogSettings dialogSettings = getDialogSettings(); |
| dialogSettings.put(KEY_LINK_WITH_EDITOR, fLinkingEnabled); |
| |
| IWorkbenchPage page= getSite().getPage(); |
| if (enabled) { |
| page.addPartListener(fLinkWithEditorListener); |
| |
| IEditorPart editor = page.getActiveEditor(); |
| if (editor != null) |
| editorActivated(editor); |
| } else { |
| page.removePartListener(fLinkWithEditorListener); |
| } |
| fOpenAndLinkWithEditorHelper.setLinkWithEditor(enabled); |
| |
| } |
| |
| private void restoreLinkingEnabled() { |
| fLinkingEnabled = getDialogSettings().getBoolean(KEY_LINK_WITH_EDITOR); |
| } |
| |
| /** |
| * Links to editor (if option enabled) |
| * @param selection the selection |
| */ |
| private void linkToEditor(ISelection selection) { |
| Object obj = getSingleElement(selection); |
| if (obj != null) { |
| IEditorPart part = isOpenInEditor(obj); |
| if (part != null) { |
| IWorkbenchPage page= getSite().getPage(); |
| page.bringToTop(part); |
| } |
| } |
| } |
| |
| /** |
| * An editor has been activated. Set the selection in the Sync View |
| * to be the editor's input, if linking is enabled. |
| * @param editor the activated editor |
| */ |
| private void editorActivated(IEditorPart editor) { |
| if (!isLinkingEnabled()) |
| return; |
| |
| IEditorInput editorInput= editor.getEditorInput(); |
| if (editorInput == null) |
| return; |
| Object input= getInputFromEditor(editorInput); |
| if (input == null) |
| return; |
| if (!inputIsSelected(editorInput)) |
| showInput(input); |
| else |
| getViewer().getTree().showSelection(); |
| } |
| |
| boolean showInput(Object input) { |
| Object element = input; |
| if (element != null) { |
| IElementComparer previousComparer = getViewer().getComparer(); |
| getViewer().setComparer(COMPARER); |
| try { |
| ISelection newSelection = new StructuredSelection(element); |
| if (getViewer().getSelection().equals(newSelection)) { |
| getViewer().reveal(element); |
| } else { |
| getViewer().setSelection(newSelection, true); |
| |
| while (element != null && getViewer().getSelection().isEmpty()) { |
| // Try to select parent in case element is filtered |
| element = getParent(element); |
| if (element != null) { |
| newSelection = new StructuredSelection(element); |
| getViewer().setSelection(newSelection, true); |
| } else { |
| // Failed to find parent to select |
| return false; |
| } |
| } |
| } |
| return true; |
| } finally { |
| getViewer().setComparer(previousComparer); |
| } |
| } |
| return false; |
| } |
| |
| /** |
| * Returns the element's parent. |
| * @param element the element |
| * |
| * @return the parent or <code>null</code> if there's no parent |
| */ |
| private Object getParent(Object element) { |
| if (element instanceof IResource) |
| return ((IResource)element).getParent(); |
| return null; |
| } |
| |
| private TreeViewer getViewer() { |
| IPage currentPage = getCurrentPage(); |
| if (currentPage instanceof ISynchronizePage) { |
| return (TreeViewer) ((ISynchronizePage)currentPage).getViewer(); |
| } |
| /* |
| * We should never get here. fLinkWithEditorListener is removed when no |
| * participants are available and the method should not be called |
| * afterwards. See participantsRemoved method for the listener's |
| * removal. |
| */ |
| Assert.isTrue(false); |
| return null; |
| } |
| |
| private boolean inputIsSelected(IEditorInput input) { |
| IStructuredSelection selection= getViewer().getStructuredSelection(); |
| if (selection.size() != 1) |
| return false; |
| IEditorInput selectionAsInput= getEditorInput(selection.getFirstElement()); |
| return input.equals(selectionAsInput); |
| } |
| |
| private static IEditorInput getEditorInput(Object input) { |
| IResource[] resources = Utils.getContributedResources(new Object[] { input }); |
| if (resources.length > 0) |
| input = resources[0]; |
| if (input instanceof IFile) |
| return new FileEditorInput((IFile) input); |
| return null; |
| } |
| |
| private Object getInputFromEditor(IEditorInput editorInput) { |
| Object input= editorInput.getAdapter(IFile.class); |
| if (input == null && editorInput instanceof FileRevisionEditorInput) { |
| IFileRevision fileRevision = ((FileRevisionEditorInput)editorInput).getFileRevision(); |
| if (fileRevision instanceof ResourceVariantFileRevision) |
| return ((ResourceVariantFileRevision) fileRevision).getVariant(); |
| } |
| if (input == null && editorInput instanceof IStorageEditorInput) { |
| try { |
| input= ((IStorageEditorInput) editorInput).getStorage(); |
| } catch (CoreException e) { |
| // ignore |
| } |
| } |
| return input; |
| } |
| |
| // copy-pasted from org.eclipse.jdt.internal.ui.javaeditor.EditorUtility and modified |
| |
| private static IEditorPart isOpenInEditor(Object inputElement) { |
| IEditorInput input = getEditorInput(inputElement); |
| if (input != null) { |
| IWorkbenchPage p = TeamUIPlugin.getActivePage(); |
| if (p != null) { |
| IEditorPart editor = p.findEditor(input); |
| if (editor == null) { |
| IEditorReference[] er = p.getEditorReferences(); |
| for (IEditorReference e : er) { |
| if (e.getId().equals("org.eclipse.compare.CompareEditor") && matches(e, input)) { //$NON-NLS-1$ |
| editor = e.getEditor(false); |
| } |
| } |
| } |
| return editor; |
| } |
| } |
| return null; |
| } |
| |
| private static boolean matches(IEditorReference editorRef, |
| IEditorInput input) { |
| if (input instanceof FileEditorInput) { |
| IFile file = ((FileEditorInput) input).getFile(); |
| |
| CompareEditorInput cei = (CompareEditorInput) ((EditorPart) editorRef |
| .getPart(false)).getEditorInput(); |
| Object compareResult = cei.getCompareResult(); |
| |
| if (compareResult instanceof IAdaptable) { |
| IResource r = ((IAdaptable) compareResult).getAdapter(IResource.class); |
| if (r != null) |
| return file.equals(r); |
| } |
| if (compareResult instanceof ICompareInput) { |
| ICompareInput compareInput = (ICompareInput) compareResult; |
| ITypedElement left = compareInput.getLeft(); |
| if (left instanceof ResourceNode) |
| if (file.equals(((ResourceNode) left).getResource())) |
| return true; |
| ITypedElement right = compareInput.getRight(); |
| if (right instanceof ResourceNode) |
| if (file.equals(((ResourceNode) right).getResource())) |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| private static IEditorPart openInEditor(IFile file, boolean activate) throws PartInitException { |
| if (file == null) |
| throwPartInitException(TeamUIMessages.SynchronizeView_fileMustNotBeNull); |
| |
| IWorkbenchPage p = TeamUIPlugin.getActivePage(); |
| if (p == null) |
| throwPartInitException(TeamUIMessages.SynchronizeView_noActiveWorkbenchPage); |
| |
| IEditorPart editorPart = IDE.openEditor(p, file, activate); |
| return editorPart; |
| } |
| |
| private static void throwPartInitException(String message) throws PartInitException { |
| IStatus status = new Status(IStatus.ERROR, TeamUIPlugin.ID, IStatus.OK, message, null); |
| throw new PartInitException(status); |
| } |
| |
| // copy-pasted from org.eclipse.jdt.internal.ui.util.SelectionUtil and modified |
| |
| /** |
| * Returns the selected element if the selection consists of a single |
| * element only. |
| * |
| * @param s the selection |
| * @return the selected first element or null |
| */ |
| private static Object getSingleElement(ISelection s) { |
| if (!(s instanceof IStructuredSelection)) |
| return null; |
| IStructuredSelection selection = (IStructuredSelection) s; |
| if (selection.size() != 1) |
| return null; |
| |
| return selection.getFirstElement(); |
| } |
| |
| @Override |
| public boolean show(ShowInContext context) { |
| Object selection = getSingleElement(context.getSelection()); |
| if (selection != null) { |
| // If can show the selection, do it. |
| // Otherwise, fall through and attempt to show the input |
| if (showInput(selection)) |
| return true; |
| } |
| Object input = context.getInput(); |
| if (input != null) { |
| if (input instanceof IEditorInput) { |
| return showInput(getInputFromEditor((IEditorInput) input)); |
| } |
| return showInput(input); |
| } |
| return false; |
| } |
| |
| public IAction getPastePatchAction() { |
| return fPastePatchAction; |
| } |
| } |