blob: c2b942ac3bb89d1e8a05e2c70e64a4a4b4a109a3 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2006 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* 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.runtime.Assert;
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.resources.IResource;
import org.eclipse.core.resources.mapping.ResourceMapping;
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;
import org.eclipse.jface.action.IMenuManager;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.IStructuredSelection;
/**
* 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;
}
/**
* {@inheritDoc}
*/
public void dispose() {
fDelegateHandler.dispose();
super.dispose();
}
/**
* {@inheritDoc}
*/
public Object execute(final ExecutionEvent event) throws ExecutionException {
return fDelegateHandler.execute(event);
}
/**
* {@inheritDoc}
*/
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 set) {
final ResourceMapping mapping= (ResourceMapping) 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 set= new HashSet();
final ISelection selection= configuration.getSite().getSelectionProvider().getSelection();
if (selection instanceof IStructuredSelection) {
final IStructuredSelection structured= (IStructuredSelection) selection;
if (!structured.isEmpty()) {
final Object[] elements= structured.toArray();
final ISynchronizationScope scope= context.getScope();
for (int index= 0; index < elements.length; index++) {
if (elements[index] instanceof RefactoringHistory) {
getRefactorings(scope, (RefactoringHistory) elements[index], set);
} else if (elements[index] instanceof RefactoringDescriptorProxy) {
getRefactoring(scope, (RefactoringDescriptorProxy) elements[index], set);
} else if (elements[index] instanceof RefactoringDescriptor) {
getRefactoring(scope, new RefactoringDescriptorProxyAdapter(((RefactoringDescriptor) elements[index])), set);
}
}
}
}
return (RefactoringDescriptorProxy[]) 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 set) {
final ResourceMapping mapping= (ResourceMapping) 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= (ResourceMapping) 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 Object[] elements= structured.toArray();
final ISynchronizationScope scope= context.getScope();
for (int index= 0; index < elements.length; index++) {
if (elements[index] instanceof RefactoringHistory) {
return hasRefactorings(scope, (RefactoringHistory) elements[index]);
} else if (elements[index] instanceof RefactoringDescriptorProxy) {
return hasRefactoring(scope, (RefactoringDescriptorProxy) elements[index]);
} else if (elements[index] instanceof RefactoringDescriptor) {
return hasRefactoring(scope, new RefactoringDescriptorProxyAdapter((RefactoringDescriptor) elements[index]));
}
}
}
}
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= (ResourceMapping) 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;
}
/**
* {@inheritDoc}
*/
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);
}
}
/**
* {@inheritDoc}
*/
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)));
}
/**
* {@inheritDoc}
*/
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;
}
}