blob: a9b59a959d82d1f76e5818bbd12344320374a6e8 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2017 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.actions;
import java.lang.reflect.InvocationTargetException;
import java.text.Collator;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import org.eclipse.compare.structuremergeviewer.IDiffElement;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.action.IMenuManager;
import org.eclipse.jface.action.LegacyActionTools;
import org.eclipse.jface.action.MenuManager;
import org.eclipse.jface.action.Separator;
import org.eclipse.jface.dialogs.IDialogSettings;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.ViewerSorter;
import org.eclipse.osgi.util.NLS;
import org.eclipse.swt.widgets.Control;
import org.eclipse.team.core.diff.IDiff;
import org.eclipse.team.core.subscribers.Subscriber;
import org.eclipse.team.core.synchronize.FastSyncInfoFilter;
import org.eclipse.team.core.synchronize.FastSyncInfoFilter.SyncInfoDirectionFilter;
import org.eclipse.team.core.synchronize.SyncInfo;
import org.eclipse.team.internal.core.subscribers.ActiveChangeSet;
import org.eclipse.team.internal.core.subscribers.ActiveChangeSetManager;
import org.eclipse.team.internal.core.subscribers.ChangeSet;
import org.eclipse.team.internal.ui.TeamUIMessages;
import org.eclipse.team.internal.ui.TeamUIPlugin;
import org.eclipse.team.internal.ui.synchronize.ChangeSetCapability;
import org.eclipse.team.internal.ui.synchronize.ChangeSetModelProvider;
import org.eclipse.team.internal.ui.synchronize.ChangeSetModelSorter;
import org.eclipse.team.ui.synchronize.ISynchronizePageConfiguration;
import org.eclipse.team.ui.synchronize.SubscriberParticipant;
import org.eclipse.team.ui.synchronize.SynchronizeModelAction;
import org.eclipse.team.ui.synchronize.SynchronizeModelOperation;
import org.eclipse.team.ui.synchronize.SynchronizePageActionGroup;
import org.eclipse.ui.actions.BaseSelectionListenerAction;
/**
* This action group contributes actions that support the management
* of Change sets to a synchronize page.
*
* @since 3.1
*/
public class ChangeSetActionGroup extends SynchronizePageActionGroup {
/**
* Menu group that can be added to the context menu
*/
public final static String CHANGE_SET_GROUP = "change_set_group"; //$NON-NLS-1$
// Constants for persisting sorting options
private static final String P_LAST_COMMENTSORT = TeamUIPlugin.ID + ".P_LAST_COMMENT_SORT"; //$NON-NLS-1$
public static final FastSyncInfoFilter OUTGOING_RESOURCE_FILTER = new SyncInfoDirectionFilter(
new int[] { SyncInfo.OUTGOING, SyncInfo.CONFLICTING });
private class CreateChangeSetAction extends SynchronizeModelAction {
public CreateChangeSetAction(ISynchronizePageConfiguration configuration) {
super(TeamUIMessages.ChangeLogModelProvider_0, configuration);
}
@Override
protected boolean needsToSaveDirtyEditors() {
return false;
}
@Override
protected FastSyncInfoFilter getSyncInfoFilter() {
return OUTGOING_RESOURCE_FILTER;
}
@Override
protected SynchronizeModelOperation getSubscriberOperation(ISynchronizePageConfiguration configuration, IDiffElement[] elements) {
return new SynchronizeModelOperation(configuration, elements) {
@Override
public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException {
syncExec(() -> {
ActiveChangeSet set = createChangeSet(getDiffs(getSyncInfoSet().getResources()));
if (set != null) {
getActiveChangeSetManager().add(set);
}
});
}
};
}
}
private abstract class ChangeSetAction extends BaseSelectionListenerAction {
public ChangeSetAction(String title, ISynchronizePageConfiguration configuration) {
super(title);
}
@Override
protected boolean updateSelection(IStructuredSelection selection) {
return getSelectedSet() != null;
}
protected ActiveChangeSet getSelectedSet() {
IStructuredSelection selection = getStructuredSelection();
if (selection.size() == 1) {
Object first = selection.getFirstElement();
if (first instanceof IAdaptable) {
Object adapter = ((IAdaptable)first).getAdapter(ChangeSet.class);
if (adapter instanceof ActiveChangeSet) {
return (ActiveChangeSet)adapter;
}
}
}
return null;
}
}
private class EditChangeSetAction extends ChangeSetAction {
public EditChangeSetAction(ISynchronizePageConfiguration configuration) {
super(TeamUIMessages.ChangeLogModelProvider_6, configuration);
}
@Override
public void run() {
ActiveChangeSet set = getSelectedSet();
if (set == null) return;
editChangeSet(set);
}
}
private class RemoveChangeSetAction extends ChangeSetAction {
public RemoveChangeSetAction(ISynchronizePageConfiguration configuration) {
super(TeamUIMessages.ChangeLogModelProvider_7, configuration);
}
@Override
public void run() {
ActiveChangeSet set = getSelectedSet();
if (set == null) return;
if (MessageDialog.openConfirm(getConfiguration().getSite().getShell(), TeamUIMessages.ChangeSetActionGroup_0, NLS.bind(TeamUIMessages.ChangeSetActionGroup_1, new String[] { LegacyActionTools.escapeMnemonics(set.getTitle()) }))) { //
getActiveChangeSetManager().remove(set);
}
}
}
private class MakeDefaultChangeSetAction extends ChangeSetAction {
public MakeDefaultChangeSetAction(
ISynchronizePageConfiguration configuration) {
super(TeamUIMessages.ChangeLogModelProvider_9, configuration);
}
@Override
protected boolean updateSelection(IStructuredSelection selection) {
if (getSelectedSet() != null) {
setText(TeamUIMessages.ChangeLogModelProvider_9);
setChecked(getSelectedSet().equals(
getActiveChangeSetManager().getDefaultSet()));
} else {
setText(TeamUIMessages.ChangeLogModelProvider_10);
setChecked(false);
}
return true;
}
@Override
public void run() {
getActiveChangeSetManager().makeDefault(
isChecked() ? getSelectedSet() : null);
if (getSelectedSet() == null) {
setChecked(false); // keep unchecked
}
}
}
private class AddToChangeSetAction extends SynchronizeModelAction {
private final ActiveChangeSet set;
public AddToChangeSetAction(ISynchronizePageConfiguration configuration, ActiveChangeSet set, ISelection selection) {
super(set == null ? TeamUIMessages.ChangeSetActionGroup_2 : LegacyActionTools.escapeMnemonics(set.getTitle()), configuration);
this.set = set;
selectionChanged(selection);
}
@Override
protected FastSyncInfoFilter getSyncInfoFilter() {
return OUTGOING_RESOURCE_FILTER;
}
@Override
protected boolean needsToSaveDirtyEditors() {
return false;
}
@Override
protected SynchronizeModelOperation getSubscriberOperation(ISynchronizePageConfiguration configuration, IDiffElement[] elements) {
return new SynchronizeModelOperation(configuration, elements) {
@Override
public void run(IProgressMonitor monitor)
throws InvocationTargetException, InterruptedException {
IResource[] resources = getSyncInfoSet().getResources();
if (set != null) {
IDiff[] diffArray = getDiffs(resources);
set.add(diffArray);
} else {
ChangeSet[] sets = getActiveChangeSetManager().getSets();
for (int i = 0; i < sets.length; i++) {
ActiveChangeSet activeSet = (ActiveChangeSet)sets[i];
activeSet.remove(resources);
}
}
}
};
}
}
/* *****************************************************************************
* Action that allows changing the model providers sort order.
*/
private class ToggleSortOrderAction extends Action {
private int criteria;
protected ToggleSortOrderAction(String name, int criteria) {
super(name, IAction.AS_RADIO_BUTTON);
this.criteria = criteria;
update();
}
@Override
public void run() {
if (isChecked() && sortCriteria != criteria) {
sortCriteria = criteria;
String key = getSettingsKey();
IDialogSettings pageSettings = getConfiguration().getSite().getPageSettings();
if(pageSettings != null) {
pageSettings.put(key, criteria);
}
update();
provider.setViewerSorter(getViewerSorter());
}
}
public void update() {
setChecked(criteria == sortCriteria);
}
protected String getSettingsKey() {
return P_LAST_COMMENTSORT;
}
}
/*
* The model provider for this action group
*/
private ChangeSetModelProvider provider;
/*
* The actions created by this group
*/
private MenuManager sortByComment;
private CreateChangeSetAction createChangeSet;
private MenuManager addToChangeSet;
private EditChangeSetAction editChangeSet;
private RemoveChangeSetAction removeChangeSet;
private MakeDefaultChangeSetAction makeDefault;
private SynchronizePageActionGroup subActions;
/*
* The currently chosen sort criteria
*/
private int sortCriteria = ChangeSetModelSorter.DATE;
public static int getSortCriteria(ISynchronizePageConfiguration configuration) {
int sortCriteria = ChangeSetModelSorter.DATE;
try {
IDialogSettings pageSettings = configuration.getSite().getPageSettings();
if(pageSettings != null) {
sortCriteria = pageSettings.getInt(P_LAST_COMMENTSORT);
}
} catch(NumberFormatException e) {
// ignore and use the defaults.
}
switch (sortCriteria) {
case ChangeSetModelSorter.COMMENT:
case ChangeSetModelSorter.DATE:
case ChangeSetModelSorter.USER:
break;
default:
sortCriteria = ChangeSetModelSorter.DATE;
break;
}
return sortCriteria;
}
public ChangeSetActionGroup(ChangeSetModelProvider provider) {
this.provider = provider;
}
@Override
public void initialize(ISynchronizePageConfiguration configuration) {
super.initialize(configuration);
if (getChangeSetCapability().supportsCheckedInChangeSets()) {
sortCriteria = getSortCriteria(configuration);
sortByComment = new MenuManager(TeamUIMessages.ChangeLogModelProvider_0a);
sortByComment.add(new ToggleSortOrderAction(TeamUIMessages.ChangeLogModelProvider_1a, ChangeSetModelSorter.COMMENT));
sortByComment.add(new ToggleSortOrderAction(TeamUIMessages.ChangeLogModelProvider_2a, ChangeSetModelSorter.DATE));
sortByComment.add(new ToggleSortOrderAction(TeamUIMessages.ChangeLogModelProvider_3a, ChangeSetModelSorter.USER));
}
if (getChangeSetCapability().supportsActiveChangeSets()) {
addToChangeSet = new MenuManager(TeamUIMessages.ChangeLogModelProvider_12);
addToChangeSet.setRemoveAllWhenShown(true);
addToChangeSet.addMenuListener(manager -> addChangeSets(manager));
createChangeSet = new CreateChangeSetAction(configuration);
addToChangeSet.add(createChangeSet);
addToChangeSet.add(new Separator());
editChangeSet = new EditChangeSetAction(configuration);
makeDefault = new MakeDefaultChangeSetAction(configuration);
removeChangeSet = new RemoveChangeSetAction(configuration);
}
subActions = getChangeSetCapability().getActionGroup();
if (subActions != null) {
subActions.initialize(configuration);
}
}
@Override
public void fillContextMenu(IMenuManager menu) {
if (getChangeSetCapability().enableCheckedInChangeSetsFor(getConfiguration())) {
appendToGroup(menu, ISynchronizePageConfiguration.SORT_GROUP, sortByComment);
}
if (getChangeSetCapability().enableActiveChangeSetsFor(getConfiguration())) {
appendToGroup(
menu,
CHANGE_SET_GROUP,
addToChangeSet);
appendToGroup(
menu,
CHANGE_SET_GROUP,
editChangeSet);
appendToGroup(
menu,
CHANGE_SET_GROUP,
removeChangeSet);
appendToGroup(
menu,
CHANGE_SET_GROUP,
makeDefault);
}
if (subActions != null) {
subActions.fillContextMenu(menu);
}
}
protected void addChangeSets(IMenuManager manager) {
ChangeSet[] sets = getActiveChangeSetManager().getSets();
Arrays.sort(sets, new Comparator<ChangeSet>() {
private Collator collator = Collator.getInstance();
@Override
public int compare(ChangeSet o1, ChangeSet o2) {
return collator.compare(o1.getName(), o2.getName());
}
});
ISelection selection = getContext().getSelection();
createChangeSet.selectionChanged(selection);
addToChangeSet.add(createChangeSet);
addToChangeSet.add(new Separator());
for (int i = 0; i < sets.length; i++) {
ActiveChangeSet set = (ActiveChangeSet)sets[i];
AddToChangeSetAction action = new AddToChangeSetAction(getConfiguration(), set, selection);
manager.add(action);
}
addToChangeSet.add(new Separator());
// Action that removes change set resources
addToChangeSet.add(new AddToChangeSetAction(getConfiguration(), null, selection));
}
/**
* Return the change set manager for the current page.
* @return the change set manager for the current page
*/
protected ActiveChangeSetManager getActiveChangeSetManager() {
return getChangeSetCapability().getActiveChangeSetManager();
}
@Override
public void dispose() {
if (addToChangeSet != null) {
addToChangeSet.dispose();
addToChangeSet.removeAll();
}
if (sortByComment != null) {
sortByComment.dispose();
sortByComment.removeAll();
}
if (subActions != null) {
subActions.dispose();
}
super.dispose();
}
@Override
public void updateActionBars() {
if (editChangeSet != null)
editChangeSet.selectionChanged((IStructuredSelection)getContext().getSelection());
if (removeChangeSet != null)
removeChangeSet.selectionChanged((IStructuredSelection)getContext().getSelection());
if (makeDefault != null)
makeDefault.selectionChanged((IStructuredSelection)getContext().getSelection());
super.updateActionBars();
}
private void syncExec(final Runnable runnable) {
final Control ctrl = getConfiguration().getPage().getViewer().getControl();
if (ctrl != null && !ctrl.isDisposed()) {
ctrl.getDisplay().syncExec(() -> {
if (!ctrl.isDisposed()) {
runnable.run();
}
});
}
}
/**
* Return a viewer sorter that utilizes the sort criteria
* selected by the user.
* @return a sorter
*/
public ViewerSorter getViewerSorter() {
return new ChangeSetModelSorter(provider, sortCriteria);
}
private ActiveChangeSet createChangeSet(IDiff[] diffs) {
return getChangeSetCapability().createChangeSet(getConfiguration(), diffs);
}
private void editChangeSet(ActiveChangeSet set) {
getChangeSetCapability().editChangeSet(getConfiguration(), set);
}
private ChangeSetCapability getChangeSetCapability() {
return provider.getChangeSetCapability();
}
private IDiff[] getDiffs(IResource[] resources) {
List<IDiff> diffs = new ArrayList<>();
Subscriber s = ((SubscriberParticipant)getConfiguration().getParticipant()).getSubscriber();
for (int i = 0; i < resources.length; i++) {
IResource resource = resources[i];
try {
IDiff diff = s.getDiff(resource);
if (diff != null)
diffs.add(diff);
} catch (CoreException e) {
TeamUIPlugin.log(e);
}
}
IDiff[] diffArray = diffs.toArray(new IDiff[diffs.size()]);
return diffArray;
}
}