blob: f63d31436c17bc49dcbac6407f1b7bf3348bfa9d [file] [log] [blame]
/*******************************************************************************
* 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;
}
}