| /******************************************************************************* |
| * 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); |
| } |
| } |
| } |
| |