blob: 1e98440b5f174c254385d6743f050c72491ff507 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2009 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
* Brock Janiczak <brockj@tpg.com.au> - Bug 161536 Warn user when committing resources with problem markers
* Brock Janiczak <brockj@tpg.com.au> - Bug 177519 [Wizards] Adopt new IResource.findMaxProblemSeverity API
* Brock Janiczak <brockj@tpg.com.au> - Bug 166333 [Wizards] Show diff in CVS commit dialog
*
*******************************************************************************/
package org.eclipse.team.internal.ccvs.ui.wizards;
import java.lang.reflect.InvocationTargetException;
import java.util.*;
import org.eclipse.core.resources.*;
import org.eclipse.core.resources.mapping.ResourceMapping;
import org.eclipse.core.resources.mapping.ResourceTraversal;
import org.eclipse.core.runtime.*;
import org.eclipse.core.runtime.jobs.*;
import org.eclipse.jface.dialogs.*;
import org.eclipse.jface.preference.IPreferenceStore;
import org.eclipse.jface.wizard.IWizardPage;
import org.eclipse.jface.wizard.WizardDialog;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.team.core.IFileContentManager;
import org.eclipse.team.core.Team;
import org.eclipse.team.core.diff.*;
import org.eclipse.team.core.mapping.*;
import org.eclipse.team.core.synchronize.SyncInfoSet;
import org.eclipse.team.internal.ccvs.core.*;
import org.eclipse.team.internal.ccvs.core.client.Command;
import org.eclipse.team.internal.ccvs.core.resources.CVSWorkspaceRoot;
import org.eclipse.team.internal.ccvs.ui.*;
import org.eclipse.team.internal.ccvs.ui.actions.CommitAction;
import org.eclipse.team.internal.ccvs.ui.mappings.AbstractCommitAction;
import org.eclipse.team.internal.ccvs.ui.mappings.WorkspaceSubscriberContext;
import org.eclipse.team.internal.ccvs.ui.operations.*;
import org.eclipse.team.internal.core.subscribers.SubscriberDiffTreeEventHandler;
import org.eclipse.team.internal.ui.Policy;
import org.eclipse.team.internal.ui.Utils;
import org.eclipse.team.ui.synchronize.ModelSynchronizeParticipant;
import org.eclipse.ui.IWorkbenchPart;
import org.eclipse.ui.PlatformUI;
/**
* A wizard to commit the resources whose synchronization state is given in form
* of a set of <code>SyncInfo</code>.
*/
public class CommitWizard extends ResizableWizard {
public static final String COMMIT_WIZARD_DIALOG_SETTINGS = "CommitWizard"; //$NON-NLS-1$
/**
* An operation to add and commit resources to a CVS repository.
*/
public static class AddAndCommitOperation extends CVSOperation {
private final IResource[] fAllResources;
private final String fComment;
private Map fModesForExtensionsForOneTime;
private Map fModesForNamesForOneTime;
private IResource[] fNewResources;
private IJobChangeListener jobListener;
public AddAndCommitOperation(IWorkbenchPart part, IResource[] allResources, IResource[] newResources, String comment) {
super(part);
fAllResources = allResources;
fNewResources = newResources;
fModesForExtensionsForOneTime = Collections.EMPTY_MAP;
fModesForNamesForOneTime= Collections.EMPTY_MAP;
fComment = comment;
}
public void setModesForExtensionsForOneTime(Map modes) {
if (modes != null)
fModesForExtensionsForOneTime= modes;
}
public void setModesForNamesForOneTime(Map modes) {
if (modes != null)
fModesForNamesForOneTime= modes;
}
@Override
protected void execute(IProgressMonitor monitor) throws CVSException, InterruptedException {
try {
monitor.beginTask(null, (fNewResources.length + fAllResources.length) * 100);
if (fNewResources.length > 0) {
final AddOperation op= new AddOperation(getPart(), RepositoryProviderOperation.asResourceMappers(fNewResources));
op.addModesForExtensions(fModesForExtensionsForOneTime);
op.addModesForNames(fModesForNamesForOneTime);
op.run(Policy.subMonitorFor(monitor, fNewResources.length * 100));
}
if (fAllResources.length > 0) {
CommitOperation commitOperation = new CommitOperation(getPart(), RepositoryProviderOperation.asResourceMappers(fAllResources), new Command.LocalOption[0], fComment) {
@Override
public boolean consultModelsForMappings() {
// Do not consult models from the commit wizard
return false;
}
};
commitOperation.run(Policy.subMonitorFor(monitor, fAllResources.length * 100));
}
} catch (InvocationTargetException e) {
throw CVSException.wrapException(e);
} finally {
monitor.done();
}
}
@Override
protected String getJobName() {
return CVSUIMessages.CommitWizard_0;
}
@Override
protected String getTaskName() {
return CVSUIMessages.CommitWizard_1;
}
/*
* Set the job listener. It will only recieve scheduled and done
* events as these are what are used by a sync model operation
* to show busy state in the sync view.
*/
protected void setJobChangeListener(IJobChangeListener jobListener) {
this.jobListener = jobListener;
}
@Override
public void done(IJobChangeEvent event) {
super.done(event);
if (jobListener != null)
jobListener.done(event);
}
@Override
public void scheduled(IJobChangeEvent event) {
super.scheduled(event);
if (jobListener != null)
jobListener.scheduled(event);
}
}
private final IResource[] fResources;
private IResource[] fUnaddedDiffs;
private final ModelSynchronizeParticipant fParticipant;
private CommitWizardFileTypePage fFileTypePage;
private CommitWizardCommitPage fCommitPage;
private IJobChangeListener jobListener;
private IWorkbenchPart part;
public CommitWizard(SyncInfoSet infos) throws CVSException {
this(infos.getResources());
}
public CommitWizard(final IResource [] resources) throws CVSException {
super(COMMIT_WIZARD_DIALOG_SETTINGS, CVSUIPlugin.getPlugin().getDialogSettings());
setNeedsProgressMonitor(true);
setWindowTitle(CVSUIMessages.CommitWizard_2);
setDefaultPageImageDescriptor(CVSUIPlugin.getPlugin().getImageDescriptor(ICVSUIConstants.IMG_WIZBAN_NEW_LOCATION));
fResources= resources;
ResourceMapping[] mappings = Utils.getResourceMappings(resources);
fParticipant = createWorkspaceParticipant(mappings, getShell());
getAllOutOfSync();
fUnaddedDiffs = getUnaddedResources(getDiffTree().getAffectedResources());
}
private ModelSynchronizeParticipant createWorkspaceParticipant(ResourceMapping[] selectedMappings, Shell shell) {
ISynchronizationScopeManager manager = WorkspaceSubscriberContext.createWorkspaceScopeManager(selectedMappings, true, CommitAction.isIncludeChangeSets(shell, CVSUIMessages.SyncAction_1));
return new CommitWizardParticipant(WorkspaceSubscriberContext.createContext(manager, ISynchronizationContext.THREE_WAY), this);
}
public CommitWizard(SyncInfoSet infos, IJobChangeListener jobListener) throws CVSException {
this(infos);
this.jobListener = jobListener;
}
private void getAllOutOfSync() throws CVSException {
try {
ISynchronizationContext context = getParticipant().getContext();
SubscriberDiffTreeEventHandler handler = Adapters.adapt(context, SubscriberDiffTreeEventHandler.class);
handler.initializeIfNeeded();
Job.getJobManager().join(context, null);
} catch (InterruptedException e) {
throw new OperationCanceledException();
}
}
public boolean hasOutgoingChanges() {
IResourceDiffTree tree = getDiffTree();
return tree != null && tree.hasMatchingDiffs(ResourcesPlugin.getWorkspace().getRoot().getFullPath(), new FastDiffFilter() {
@Override
public boolean select(IDiff diff) {
return AbstractCommitAction.hasLocalChange(diff);
}
});
}
boolean hasConflicts() {
IResourceDiffTree tree = getDiffTree();
return tree != null && tree.hasMatchingDiffs(ResourcesPlugin.getWorkspace().getRoot().getFullPath(), new FastDiffFilter() {
@Override
public boolean select(IDiff diff) {
if (diff instanceof IThreeWayDiff) {
IThreeWayDiff twd = (IThreeWayDiff) diff;
return twd.getDirection() == IThreeWayDiff.CONFLICTING;
}
return false;
}
});
}
public int getHighestProblemSeverity() {
IResource[] resources = getDiffTree().getAffectedResources();
int mostSeriousSeverity = -1;
for (int i = 0; i < resources.length; i++) {
IResource resource = resources[i];
try {
int severity = resource.findMaxProblemSeverity(IMarker.PROBLEM, true, IResource.DEPTH_ZERO);
if (severity > mostSeriousSeverity) {
mostSeriousSeverity = severity;
}
} catch (CoreException e) {
}
}
return mostSeriousSeverity;
}
IResourceDiffTree getDiffTree() {
return fParticipant.getContext().getDiffTree();
}
public CommitWizardFileTypePage getFileTypePage() {
return fFileTypePage;
}
public CommitWizardCommitPage getCommitPage() {
return fCommitPage;
}
public ModelSynchronizeParticipant getParticipant() {
return fParticipant;
}
@Override
public boolean canFinish() {
final IWizardPage current= getContainer().getCurrentPage();
if (current == fFileTypePage && fCommitPage != null)
return false;
return super.canFinish();
}
@Override
public boolean performFinish() {
final String comment= fCommitPage.getComment(getShell());
if (comment == null)
return false;
IResource[] resources = AbstractCommitAction.getOutgoingChanges(getDiffTree(), fCommitPage.getTraversalsToCommit(), null);
if (resources.length == 0)
return true;
final IResource[] unadded;
try {
unadded = getUnaddedResources(resources);
} catch (CVSException e1) {
return false;
}
final IResource[] files = getFiles(resources);
final AddAndCommitOperation operation= new AddAndCommitOperation(getPart(), files, unadded, comment);
if (jobListener != null)
operation.setJobChangeListener(jobListener);
if (fFileTypePage != null) {
final Map extensionsToSave= new HashMap();
final Map extensionsNotToSave= new HashMap();
fFileTypePage.getModesForExtensions(extensionsToSave, extensionsNotToSave);
CommitWizardFileTypePage.saveExtensionMappings(extensionsToSave);
operation.setModesForExtensionsForOneTime(extensionsNotToSave);
final Map namesToSave= new HashMap();
final Map namesNotToSave= new HashMap();
fFileTypePage.getModesForNames(namesToSave, namesNotToSave);
CommitWizardFileTypePage.saveNameMappings(namesToSave);
operation.setModesForNamesForOneTime(namesNotToSave);
}
try {
operation.run();
} catch (InvocationTargetException e) {
return false;
} catch (InterruptedException e) {
return false;
}
fCommitPage.finish();
return super.performFinish();
}
@Override
public boolean performCancel() {
fCommitPage.finish();
return super.performCancel();
}
@Override
public void addPages() {
final Collection<String> names = new HashSet<>();
final Collection<String> extensions = new HashSet<>();
getUnknownNamesAndExtension(fUnaddedDiffs, names, extensions);
if (names.size() + extensions.size() > 0) {
fFileTypePage= new CommitWizardFileTypePage(extensions, names);
addPage(fFileTypePage);
}
fCommitPage= new CommitWizardCommitPage(fResources, this);
addPage(fCommitPage);
super.addPages();
}
@Override
public void dispose() {
fParticipant.dispose();
super.dispose();
}
public static void run(IWorkbenchPart part, Shell shell, IResource [] resources) throws CVSException {
try {
CommitWizard commitWizard = new CommitWizard(resources);
commitWizard.setPart(part);
run(shell, commitWizard);
} catch (OperationCanceledException e) {
// Ignore
}
}
private void setPart(IWorkbenchPart part) {
this.part = part;
}
public static void run(Shell shell, SyncInfoSet infos, IJobChangeListener jobListener) throws CVSException {
try {
run(shell, new CommitWizard(infos, jobListener));
} catch (OperationCanceledException e) {
// Ignore
}
}
public static void run(IWorkbenchPart part, Shell shell, final ResourceTraversal[] traversals) throws CVSException {
try {
final IResource [][] resources = new IResource[][] { null };
PlatformUI.getWorkbench().getProgressService().busyCursorWhile(monitor -> {
try {
resources[0] = getDeepResourcesToCommit(traversals, monitor);
} catch (CoreException e) {
throw new InvocationTargetException(e);
}
});
run(part, shell, resources[0]);
} catch (OperationCanceledException e) {
// Ignore
} catch (InvocationTargetException e) {
throw CVSException.wrapException(e);
} catch (InterruptedException e) {
// Ignore
}
}
private IWorkbenchPart getPart() {
if (part != null)
return part;
return PlatformUI.getWorkbench().getActiveWorkbenchWindow().getPartService().getActivePart();
}
private static void run(Shell shell, CommitWizard wizard) {
if (!wizard.hasOutgoingChanges()) {
MessageDialog.openInformation(shell, CVSUIMessages.CommitWizard_6, CVSUIMessages.CommitWizard_7); //
} else {
int highestProblemSeverity = wizard.getHighestProblemSeverity();
IPreferenceStore preferenceStore = CVSUIPlugin.getPlugin().getPreferenceStore();
switch (highestProblemSeverity) {
case IMarker.SEVERITY_WARNING:
String allowCommitsWithWarnings = preferenceStore.getString(ICVSUIConstants.PREF_ALLOW_COMMIT_WITH_WARNINGS);
if (MessageDialogWithToggle.PROMPT.equals(allowCommitsWithWarnings) || MessageDialogWithToggle.NEVER.equals(allowCommitsWithWarnings)) {
MessageDialogWithToggle warningDialog = MessageDialogWithToggle.openYesNoQuestion(shell, CVSUIMessages.CommitWizard_8, CVSUIMessages.CommitWizard_9, CVSUIMessages.CommitWizard_10, false, preferenceStore, ICVSUIConstants.PREF_ALLOW_COMMIT_WITH_WARNINGS);
if (IDialogConstants.YES_ID != warningDialog.getReturnCode()) {
return;
}
}
break;
case IMarker.SEVERITY_ERROR:
String allowCommitsWithErrors = preferenceStore.getString(ICVSUIConstants.PREF_ALLOW_COMMIT_WITH_ERRORS);
if (MessageDialogWithToggle.PROMPT.equals(allowCommitsWithErrors) || MessageDialogWithToggle.NEVER.equals(allowCommitsWithErrors)) {
MessageDialogWithToggle errorDialog = MessageDialogWithToggle.openYesNoQuestion(shell, CVSUIMessages.CommitWizard_11, CVSUIMessages.CommitWizard_12, CVSUIMessages.CommitWizard_13, false, preferenceStore, ICVSUIConstants.PREF_ALLOW_COMMIT_WITH_ERRORS);
if (IDialogConstants.YES_ID != errorDialog.getReturnCode()) {
return;
}
}
break;
}
open(shell, wizard);
}
}
protected static int open(Shell shell, ResizableWizard wizard) {
final WizardDialog dialog= new WizardDialog(shell, wizard);
dialog.setPageSize(wizard.loadSize());
return dialog.open();
}
private void getUnknownNamesAndExtension(IResource[] resources, Collection<String> names,
Collection<String> extensions) {
final IFileContentManager manager= Team.getFileContentManager();
for (int i = 0; i < resources.length; i++) {
IResource local = resources[i];
if (local instanceof IFile && manager.getType((IFile)local) == Team.UNKNOWN) {
final String extension= local.getFileExtension();
if (extension != null && !manager.isKnownExtension(extension)) {
extensions.add(extension);
}
final String name= local.getName();
if (extension == null && name != null && !manager.isKnownFilename(name))
names.add(name);
}
}
}
private IResource[] getUnaddedResources(IResource[] resources) throws CVSException {
List/* <IResource> */<IResource> unadded = new ArrayList<>();
for (int i = 0; i < resources.length; i++) {
if (!isAdded(resources[i])) {
unadded.add(resources[i]);
}
}
return unadded.toArray(new IResource[0]);
}
private IResource[] getFiles(IResource[] resources) {
final List<IResource> files = new ArrayList<>();
for (int i = 0; i < resources.length; i++) {
if (resources[i].getType() == IResource.FILE)
files.add(resources[i]);
}
return files.toArray(new IResource[0]);
}
private static boolean isAdded(IResource resource) throws CVSException {
final ICVSResource cvsResource = CVSWorkspaceRoot.getCVSResourceFor(resource);
if (cvsResource.isFolder()) {
return ((ICVSFolder)cvsResource).isCVSFolder();
}
return cvsResource.isManaged();
}
private static IResource[] getDeepResourcesToCommit(ResourceTraversal[] traversals, IProgressMonitor monitor) throws CoreException {
List<IResource> roots = new ArrayList<>();
for (int j = 0; j < traversals.length; j++) {
ResourceTraversal traversal = traversals[j];
IResource[] resources = traversal.getResources();
if (traversal.getDepth() == IResource.DEPTH_INFINITE) {
roots.addAll(Arrays.asList(resources));
} else if (traversal.getDepth() == IResource.DEPTH_ZERO) {
collectShallowFiles(resources, roots);
} else if (traversal.getDepth() == IResource.DEPTH_ONE) {
collectShallowFiles(resources, roots);
for (int k = 0; k < resources.length; k++) {
IResource resource = resources[k];
if (resource.getType() != IResource.FILE) {
collectShallowFiles(members(resource), roots);
}
}
}
}
return roots.toArray(new IResource[roots.size()]);
}
private static IResource[] members(IResource resource) throws CoreException {
return CVSProviderPlugin.getPlugin().getCVSWorkspaceSubscriber().members(resource);
}
private static void collectShallowFiles(IResource[] resources, List<IResource> roots) {
for (int k = 0; k < resources.length; k++) {
IResource resource = resources[k];
if (resource.getType() == IResource.FILE)
roots.add(resource);
}
}
}