| /******************************************************************************* |
| * Copyright (c) 2006, 2015 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.ltk.ui.refactoring.model; |
| |
| import java.util.Arrays; |
| import java.util.HashSet; |
| import java.util.Iterator; |
| import java.util.Set; |
| |
| import org.eclipse.team.core.mapping.ISynchronizationContext; |
| import org.eclipse.team.core.mapping.ISynchronizationScope; |
| import org.eclipse.team.ui.mapping.MergeActionHandler; |
| import org.eclipse.team.ui.mapping.SynchronizationActionProvider; |
| import org.eclipse.team.ui.synchronize.ISynchronizePageConfiguration; |
| |
| import org.eclipse.core.commands.AbstractHandler; |
| import org.eclipse.core.commands.ExecutionEvent; |
| import org.eclipse.core.commands.ExecutionException; |
| import org.eclipse.core.commands.IHandler; |
| |
| import org.eclipse.core.runtime.Assert; |
| |
| import org.eclipse.core.resources.IResource; |
| import org.eclipse.core.resources.mapping.ResourceMapping; |
| |
| import org.eclipse.jface.action.IMenuManager; |
| import org.eclipse.jface.viewers.ISelection; |
| import org.eclipse.jface.viewers.IStructuredSelection; |
| |
| import org.eclipse.ltk.core.refactoring.RefactoringDescriptor; |
| import org.eclipse.ltk.core.refactoring.RefactoringDescriptorProxy; |
| import org.eclipse.ltk.core.refactoring.history.RefactoringHistory; |
| import org.eclipse.ltk.core.refactoring.model.AbstractRefactoringDescriptorResourceMapping; |
| import org.eclipse.ltk.core.refactoring.model.AbstractRefactoringHistoryResourceMapping; |
| import org.eclipse.ltk.internal.core.refactoring.history.RefactoringDescriptorProxyAdapter; |
| import org.eclipse.ltk.internal.ui.refactoring.actions.AcceptRefactoringsAction; |
| import org.eclipse.ltk.internal.ui.refactoring.actions.RejectRefactoringsAction; |
| |
| /** |
| * Refactoring-aware synchronization action provider which contributes an action |
| * to accept pending refactorings during team synchronization. |
| * <p> |
| * This action provider contributes an action for refactoring history objects. |
| * Additionally, existing command handlers for the <code>Merge</code>, |
| * <code>Mark As Merged</code> and <code>Overwrite</code> actions are |
| * wrapped and automatically disabled for refactoring history objects. |
| * </p> |
| * <p> |
| * Note: this class is intended to be extended by clients who need refactoring |
| * support in a team synchronization viewer. It needs to be be registered with |
| * the <code>org.eclipse.ui.navigator.navigatorContent</code> or |
| * <code>org.eclipse.ui.navigator.viewer</code> extension points in order to |
| * participate in the team synchronization viewers. |
| * </p> |
| * |
| * @see org.eclipse.team.ui.mapping.SynchronizationActionProvider |
| * |
| * @since 3.2 |
| */ |
| public class RefactoringSynchronizationActionProvider extends SynchronizationActionProvider { |
| |
| /** Delegate for refactoring action handlers */ |
| private final class RefactoringHandlerDelegate extends AbstractHandler { |
| |
| /** The delegate handler */ |
| private final IHandler fDelegateHandler; |
| |
| /** |
| * Creates a new synchronization handler delegate. |
| * |
| * @param handler |
| * the delegate handler |
| */ |
| public RefactoringHandlerDelegate(final IHandler handler) { |
| Assert.isNotNull(handler); |
| fDelegateHandler= handler; |
| } |
| |
| @Override |
| public void dispose() { |
| fDelegateHandler.dispose(); |
| super.dispose(); |
| } |
| |
| @Override |
| public Object execute(final ExecutionEvent event) throws ExecutionException { |
| return fDelegateHandler.execute(event); |
| } |
| |
| @Override |
| public boolean isEnabled() { |
| return !hasRefactorings(getSynchronizationContext(), getSynchronizePageConfiguration()) && fDelegateHandler.isEnabled(); |
| } |
| } |
| |
| /** |
| * Gets the refactoring represented by the specified proxy. |
| * |
| * @param scope |
| * the synchronization scope |
| * @param proxy |
| * the refactoring descriptor proxy |
| * @param set |
| * the set of refactoring descriptor proxies |
| */ |
| private static void getRefactoring(final ISynchronizationScope scope, final RefactoringDescriptorProxy proxy, final Set<RefactoringDescriptorProxy> set) { |
| final ResourceMapping mapping= proxy.getAdapter(ResourceMapping.class); |
| if (mapping instanceof AbstractRefactoringDescriptorResourceMapping) { |
| final AbstractRefactoringDescriptorResourceMapping extended= (AbstractRefactoringDescriptorResourceMapping) mapping; |
| final IResource resource= extended.getResource(); |
| if (resource != null && scope.contains(resource)) |
| set.add(proxy); |
| } |
| } |
| |
| /** |
| * Returns the currently selected refactorings. |
| * |
| * @param context |
| * the synchronization context |
| * @param configuration |
| * the synchronize page configuration |
| * @return the selected refactorings, or the empty array |
| */ |
| private static RefactoringDescriptorProxy[] getRefactorings(final ISynchronizationContext context, final ISynchronizePageConfiguration configuration) { |
| Assert.isNotNull(context); |
| Assert.isNotNull(configuration); |
| final Set<RefactoringDescriptorProxy> set= new HashSet<>(); |
| final ISelection selection= configuration.getSite().getSelectionProvider().getSelection(); |
| if (selection instanceof IStructuredSelection) { |
| final IStructuredSelection structured= (IStructuredSelection) selection; |
| if (!structured.isEmpty()) { |
| final ISynchronizationScope scope= context.getScope(); |
| for (Object element : structured.toArray()) { |
| if (element instanceof RefactoringHistory) { |
| getRefactorings(scope, (RefactoringHistory) element, set); |
| } else if (element instanceof RefactoringDescriptorProxy) { |
| getRefactoring(scope, (RefactoringDescriptorProxy) element, set); |
| } else if (element instanceof RefactoringDescriptor) { |
| getRefactoring(scope, new RefactoringDescriptorProxyAdapter((RefactoringDescriptor) element), set); |
| } |
| } |
| } |
| } |
| return set.toArray(new RefactoringDescriptorProxy[set.size()]); |
| } |
| |
| /** |
| * Gets the refactorings represented by the specified history. |
| * |
| * @param scope |
| * the synchronization scope |
| * @param history |
| * the refactoring history |
| * @param set |
| * the set of refactoring descriptor proxies |
| */ |
| private static void getRefactorings(final ISynchronizationScope scope, final RefactoringHistory history, final Set<RefactoringDescriptorProxy> set) { |
| final ResourceMapping mapping= history.getAdapter(ResourceMapping.class); |
| if (mapping instanceof AbstractRefactoringHistoryResourceMapping) { |
| final AbstractRefactoringHistoryResourceMapping extended= (AbstractRefactoringHistoryResourceMapping) mapping; |
| final IResource resource= extended.getResource(); |
| if (resource != null && scope.contains(resource)) |
| set.addAll(Arrays.asList(history.getDescriptors())); |
| } |
| } |
| |
| /** |
| * Is the specified refactoring in the scope? |
| * |
| * @param scope |
| * the synchronization scope |
| * @param proxy |
| * the refactoring descriptor proxy |
| * @return <code>true</code> if the refactoring is in the scope, |
| * <code>false</code> otherwise |
| */ |
| private static boolean hasRefactoring(final ISynchronizationScope scope, final RefactoringDescriptorProxy proxy) { |
| final ResourceMapping mapping= proxy.getAdapter(ResourceMapping.class); |
| if (mapping instanceof AbstractRefactoringDescriptorResourceMapping) { |
| final AbstractRefactoringDescriptorResourceMapping extended= (AbstractRefactoringDescriptorResourceMapping) mapping; |
| final IResource resource= extended.getResource(); |
| if (resource != null) |
| return scope.contains(resource); |
| } |
| return false; |
| } |
| |
| /** |
| * Returns whether any refactorings from the given synchronization context |
| * are selected. |
| * |
| * @param context |
| * the synchronization context |
| * @param configuration |
| * the synchronize page configuration |
| * @return <code>true</code> if any refactorings are selected, |
| * <code>false</code> otherwise |
| */ |
| private static boolean hasRefactorings(final ISynchronizationContext context, final ISynchronizePageConfiguration configuration) { |
| Assert.isNotNull(context); |
| Assert.isNotNull(configuration); |
| final ISelection selection= configuration.getSite().getSelectionProvider().getSelection(); |
| if (selection instanceof IStructuredSelection) { |
| final IStructuredSelection structured= (IStructuredSelection) selection; |
| if (!structured.isEmpty()) { |
| final ISynchronizationScope scope= context.getScope(); |
| for (Object element : structured.toArray()) { |
| if (element instanceof RefactoringHistory) { |
| return hasRefactorings(scope, (RefactoringHistory) element); |
| } else if (element instanceof RefactoringDescriptorProxy) { |
| return hasRefactoring(scope, (RefactoringDescriptorProxy) element); |
| } else if (element instanceof RefactoringDescriptor) { |
| return hasRefactoring(scope, new RefactoringDescriptorProxyAdapter((RefactoringDescriptor) element)); |
| } |
| } |
| } |
| } |
| return false; |
| } |
| |
| /** |
| * Does the specified refactoring history contain any refactorings in the |
| * scope? |
| * |
| * @param scope |
| * the synchronization scope |
| * @param history |
| * the refactoring history |
| * @return <code>true</code> if any refactorings are in the scope, |
| * <code>false</code> otherwise |
| */ |
| private static boolean hasRefactorings(final ISynchronizationScope scope, final RefactoringHistory history) { |
| final ResourceMapping mapping= history.getAdapter(ResourceMapping.class); |
| if (mapping instanceof AbstractRefactoringHistoryResourceMapping) { |
| final AbstractRefactoringHistoryResourceMapping extended= (AbstractRefactoringHistoryResourceMapping) mapping; |
| final IResource resource= extended.getResource(); |
| if (resource != null) |
| return scope.contains(resource); |
| } |
| return false; |
| } |
| |
| @Override |
| public void fillContextMenu(final IMenuManager menu) { |
| super.fillContextMenu(menu); |
| if (isRefactoringElementSelected()) { |
| final ISynchronizationContext context= getSynchronizationContext(); |
| final RefactoringDescriptorProxy[] proxies= getRefactorings(context, getSynchronizePageConfiguration()); |
| final AcceptRefactoringsAction accept= new AcceptRefactoringsAction(context, getExtensionSite().getViewSite().getShell()); |
| accept.setRefactoringDescriptors(proxies); |
| menu.add(accept); |
| final RejectRefactoringsAction reject= new RejectRefactoringsAction(context); |
| reject.setRefactoringDescriptors(proxies); |
| menu.add(reject); |
| } |
| } |
| |
| @Override |
| protected void initialize() { |
| super.initialize(); |
| final ISynchronizePageConfiguration configuration= getSynchronizePageConfiguration(); |
| registerHandler(MERGE_ACTION_ID, new RefactoringHandlerDelegate(MergeActionHandler.getDefaultHandler(MERGE_ACTION_ID, configuration))); |
| registerHandler(OVERWRITE_ACTION_ID, new RefactoringHandlerDelegate(MergeActionHandler.getDefaultHandler(OVERWRITE_ACTION_ID, configuration))); |
| registerHandler(MARK_AS_MERGE_ACTION_ID, new RefactoringHandlerDelegate(MergeActionHandler.getDefaultHandler(MARK_AS_MERGE_ACTION_ID, configuration))); |
| } |
| |
| @Override |
| protected void initializeOpenActions() { |
| if (!hasRefactorings(getSynchronizationContext(), getSynchronizePageConfiguration())) |
| super.initializeOpenActions(); |
| } |
| |
| private boolean isRefactoringElementSelected() { |
| final ISelection selection= getContext().getSelection(); |
| if (selection instanceof IStructuredSelection) { |
| final IStructuredSelection extended= (IStructuredSelection) selection; |
| for (final Iterator<?> iterator= extended.iterator(); iterator.hasNext();) { |
| final Object element= iterator.next(); |
| if (element instanceof RefactoringDescriptorProxy || element instanceof RefactoringDescriptor || element instanceof RefactoringHistory) { |
| return true; |
| } |
| } |
| } |
| return false; |
| } |
| } |