diff options
14 files changed, 1151 insertions, 857 deletions
diff --git a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/CVSTeamProvider.java b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/CVSTeamProvider.java index 1cc6b3e1d..99c8f8b74 100644 --- a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/CVSTeamProvider.java +++ b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/CVSTeamProvider.java @@ -14,9 +14,11 @@ import java.io.PrintStream; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; +import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; +import java.util.Map; import java.util.Set; import java.util.SortedSet; import java.util.TreeSet; @@ -30,6 +32,7 @@ import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.NullProgressMonitor; import org.eclipse.core.runtime.Status; import org.eclipse.team.core.IFileTypeRegistry; import org.eclipse.team.core.RepositoryProvider; @@ -986,141 +989,124 @@ public class CVSTeamProvider extends RepositoryProvider { * and not obtain the new keyword sync info. * </p> * - * @param resources the resources to set keyword substitution mode - * @param depth the recursion depth - * @param toKSubst the desired keyword substitution mode + * @param changeSet a map from IFile to KSubstOption * @param monitor the progress monitor * @return a status code indicating success or failure of the operation * * @throws TeamException */ - public IStatus setKeywordSubstitution(final IResource[] resources, final int depth, - final KSubstOption toKSubst, IProgressMonitor monitor) throws TeamException { + public IStatus setKeywordSubstitution(final Map /* from IFile to KSubstOption */ changeSet, + IProgressMonitor monitor) throws TeamException { final IStatus[] result = new IStatus[] { ICommandOutputListener.OK }; workspaceRoot.getLocalRoot().run(new ICVSRunnable() { public void run(final IProgressMonitor monitor) throws CVSException { - final boolean toBinary = toKSubst.isBinary(); - final List /* of String */ filesToAdmin = new ArrayList(); + final Map /* from KSubstOption to List of String */ filesToAdmin = new HashMap(); final List /* of String */ filesToCommit = new ArrayList(); final Collection /* of ICVSFile */ filesToCommitAsText = new HashSet(); // need fast lookup - final IProgressMonitor progress = Policy.monitorFor(monitor); - progress.beginTask(Policy.bind("CVSTeamProvider.preparingToSetKSubst"), 100); //$NON-NLS-1$ - try { - /*** get all possibly affected files (ensure no duplicates) ***/ - final Set /* of IFile */ files = new HashSet(); - for (int i = 0; i < resources.length; i++) { - final IResource currentResource = resources[i]; - // throw an exception if the resource is not a child of the receiver - checkIsChild(currentResource); - try { - currentResource.accept(new IResourceVisitor() { - public boolean visit(IResource resource) throws CoreException { - if (resource.getType() == IResource.FILE) { - files.add(resource); - } - // always return true and let the depth determine if children are visited - return true; - } - }, depth, false); - } catch (CoreException e) { - throw new CVSException(new Status(IStatus.ERROR, CVSProviderPlugin.ID, - TeamException.UNABLE, Policy.bind("CVSTeamProvider.visitError", //$NON-NLS-1$ - new Object[] { currentResource.getFullPath() }), e)); - } + /*** determine the resources to be committed and/or admin'd ***/ + for (Iterator it = changeSet.entrySet().iterator(); it.hasNext();) { + Map.Entry entry = (Map.Entry) it.next(); + IFile file = (IFile) entry.getKey(); + KSubstOption toKSubst = (KSubstOption) entry.getValue(); + + // only set keyword substitution if resource is a managed file + checkIsChild(file); + ICVSFile mFile = CVSWorkspaceRoot.getCVSFileFor(file); + if (! mFile.isManaged()) continue; + + // only set keyword substitution if new differs from actual + ResourceSyncInfo info = mFile.getSyncInfo(); + KSubstOption fromKSubst = KSubstOption.fromMode(info.getKeywordMode()); + if (toKSubst.equals(fromKSubst)) continue; + + // change resource sync info immediately for an outgoing addition + if (info.isAdded()) { + ResourceSyncInfo newInfo = new ResourceSyncInfo( + info.getName(), info.getRevision(), info.getTimeStamp(), toKSubst.toMode(), + info.getTag(), info.getPermissions()); + mFile.setSyncInfo(newInfo); + continue; } - progress.worked(5); - - /*** determine the resources to be committed and those to be admin'd ***/ - for (Iterator it = files.iterator(); it.hasNext();) { - IFile file = (IFile) it.next(); - ICVSFile mFile = CVSWorkspaceRoot.getCVSFileFor(file); - // only set keyword substitution if resource is a managed file - if (mFile.isManaged()) { - ResourceSyncInfo info = mFile.getSyncInfo(); - String fromMode = info.getKeywordMode(); - KSubstOption fromKSubst = KSubstOption.fromMode(fromMode); - - // make sure we commit all added or changed resources - String remotePath = mFile.getRelativePath(workspaceRoot.getLocalRoot()); - - // check if mode must be changed - if (! toKSubst.equals(fromKSubst)) { - if (info.isAdded()) { - // change resource sync info for outgoing addition - ResourceSyncInfo newInfo = new ResourceSyncInfo( - info.getName(), info.getRevision(), info.getTimeStamp(), toKSubst.toMode(), - info.getTag(), info.getPermissions()); - mFile.setSyncInfo(newInfo); - } else if (info.isDeleted()) { - // ignore deletions - } else { - // file exists remotely - boolean fromBinary = fromKSubst.isBinary(); - if (fromBinary && ! toBinary) { - // converting from binary to text - cleanLineDelimiters(file, IS_CRLF_PLATFORM, progress); - // remember to commit the cleaned resource as text before admin - filesToCommitAsText.add(mFile); - } else { - // force a commit to bump the revision number - makeDirty(file); - } - // remember to commit and admin the resource - filesToCommit.add(remotePath); // FORCE creation of a new revision - filesToAdmin.add(remotePath); - } - } - } + + // nothing do to for deletions + if (info.isDeleted()) continue; + + // file exists remotely so we'll have to commit it + String remotePath = mFile.getRelativePath(workspaceRoot.getLocalRoot()); + if (fromKSubst.isBinary() && ! toKSubst.isBinary()) { + // converting from binary to text + cleanLineDelimiters(file, IS_CRLF_PLATFORM, new NullProgressMonitor()); // XXX need better progress monitoring + // remember to commit the cleaned resource as text before admin + filesToCommitAsText.add(mFile); + } + // force a commit to bump the revision number + makeDirty(file); + filesToCommit.add(remotePath); + // remember to admin the resource + List list = (List) filesToAdmin.get(toKSubst); + if (list == null) { + list = new ArrayList(); + filesToAdmin.put(toKSubst, list); } - progress.worked(5); + list.add(remotePath); + } - /*** commit then admin the resources ***/ - if (filesToAdmin.size() != 0 || filesToCommit.size() != 0) { - Session s = new Session(workspaceRoot.getRemoteLocation(), - workspaceRoot.getLocalRoot(), false); - IProgressMonitor sessionProgress = Policy.subMonitorFor(progress, 90); - sessionProgress.beginTask(Policy.bind("CVSTeamProvider.settingKSubst"), 5 + //$NON-NLS-1$ - filesToAdmin.size() + filesToCommit.size()); - try { - s.open(Policy.subMonitorFor(sessionProgress, 5)); - - // commit files that changed from binary to text - // NOTE: The files are committed as text with conversions even if the - // resource sync info still says "binary". - if (filesToCommit.size() != 0) { - s.setTextTransferOverride(filesToCommitAsText); - result[0] = Command.COMMIT.execute(s, Command.NO_GLOBAL_OPTIONS, - new LocalOption[] { Commit.DO_NOT_RECURSE, Commit.FORCE, - Commit.makeArgumentOption(Command.MESSAGE_OPTION, comment) }, - (String[]) filesToCommit.toArray(new String[filesToCommit.size()]), - null, Policy.subMonitorFor(sessionProgress, filesToCommit.size())); - s.setTextTransferOverride(null); - // if errors were encountered, abort - if (! result[0].isOK()) return; - } - - // admin files that changed keyword substitution mode - // NOTE: As confirmation of the completion of a command, the server replies - // with the RCS command output if a change took place. Rather than - // assume that the command succeeded, we listen for these lines - // and update the local ResourceSyncInfo for the particular files that - // were actually changed remotely. + /*** commit then admin the resources ***/ + // compute the total work to be performed + int totalWork = filesToCommit.size(); + for (Iterator it = filesToAdmin.values().iterator(); it.hasNext();) { + List list = (List) it.next(); + totalWork += list.size(); + } + if (totalWork != 0) { + Session s = new Session(workspaceRoot.getRemoteLocation(), + workspaceRoot.getLocalRoot(), false); + monitor.beginTask(Policy.bind("CVSTeamProvider.settingKSubst"), 5 + totalWork); + try { + s.open(Policy.subMonitorFor(monitor, 5)); + + // commit files that changed from binary to text + // NOTE: The files are committed as text with conversions even if the + // resource sync info still says "binary". + if (filesToCommit.size() != 0) { + s.setTextTransferOverride(filesToCommitAsText); + result[0] = Command.COMMIT.execute(s, Command.NO_GLOBAL_OPTIONS, + new LocalOption[] { Commit.DO_NOT_RECURSE, Commit.FORCE, + Commit.makeArgumentOption(Command.MESSAGE_OPTION, comment) }, + (String[]) filesToCommit.toArray(new String[filesToCommit.size()]), + null, Policy.subMonitorFor(monitor, filesToCommit.size())); + s.setTextTransferOverride(null); + // if errors were encountered, abort + if (! result[0].isOK()) return; + } + + // admin files that changed keyword substitution mode + // NOTE: As confirmation of the completion of a command, the server replies + // with the RCS command output if a change took place. Rather than + // assume that the command succeeded, we listen for these lines + // and update the local ResourceSyncInfo for the particular files that + // were actually changed remotely. + for (Iterator it = filesToAdmin.entrySet().iterator(); it.hasNext();) { + Map.Entry entry = (Map.Entry) it.next(); + KSubstOption toKSubst = (KSubstOption) entry.getKey(); + List list = (List) entry.getValue(); + // do it result[0] = Command.ADMIN.execute(s, Command.NO_GLOBAL_OPTIONS, new LocalOption[] { toKSubst }, - (String[]) filesToAdmin.toArray(new String[filesToAdmin.size()]), + (String[]) list.toArray(new String[list.size()]), new AdminKSubstListener(toKSubst.toMode()), - Policy.subMonitorFor(sessionProgress, filesToAdmin.size())); - } finally { - s.close(); - sessionProgress.done(); + Policy.subMonitorFor(monitor, list.size())); + // if errors were encountered, abort + if (! result[0].isOK()) return; } + } finally { + s.close(); + monitor.done(); } - } finally { - progress.done(); } } - }, monitor); + }, Policy.monitorFor(monitor)); return result[0]; } @@ -1174,9 +1160,6 @@ public class CVSTeamProvider extends RepositoryProvider { // write file back to disk with corrected delimiters if changes were made ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray()); file.setContents(bis, false /*force*/, true /*keepHistory*/, progress); - } else { - // otherwise make the file dirty - makeDirty(file); } } catch (CoreException e) { throw CVSException.wrapException(file, Policy.bind("CVSTeamProvider.cleanLineDelimitersException"), e); //$NON-NLS-1$ @@ -1185,6 +1168,9 @@ public class CVSTeamProvider extends RepositoryProvider { } } + /* + * Marks a file as dirty. + */ private static void makeDirty(IFile file) throws CVSException { ICVSFile mFile = CVSWorkspaceRoot.getCVSFileFor(file); mFile.setTimeStamp(null); diff --git a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/messages.properties b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/messages.properties index d5b23d352..49d21fde8 100644 --- a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/messages.properties +++ b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/messages.properties @@ -144,7 +144,7 @@ RemovedHandler.invalid=Invalid removed response received from CVS server for {0 KSubstOption.-kb.short=Binary KSubstOption.-kb.long=Binary (-kb) KSubstOption.-ko.short=Text -KSubstOption.-ko.long=Text (-ko) +KSubstOption.-ko.long=Text without keyword substitution (-ko) KSubstOption.-kkv.short=Text -kkv KSubstOption.-kkv.long=Text with keyword expansion (-kkv) KSubstOption.-kkvl.short=Text -kkvl diff --git a/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/actions/SetKeywordSubstitutionAction.java b/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/actions/SetKeywordSubstitutionAction.java index 6f189d74f..651e64f40 100644 --- a/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/actions/SetKeywordSubstitutionAction.java +++ b/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/actions/SetKeywordSubstitutionAction.java @@ -9,40 +9,32 @@ import org.eclipse.core.resources.IResource; import org.eclipse.jface.action.IAction; import org.eclipse.jface.wizard.WizardDialog; import org.eclipse.team.ccvs.core.CVSProviderPlugin; -import org.eclipse.team.ccvs.core.CVSTeamProvider; import org.eclipse.team.ccvs.core.ICVSResource; import org.eclipse.team.core.RepositoryProvider; import org.eclipse.team.core.RepositoryProviderType; import org.eclipse.team.core.TeamException; -import org.eclipse.team.core.TeamPlugin; import org.eclipse.team.internal.ccvs.core.client.Command; import org.eclipse.team.internal.ccvs.core.client.Command.KSubstOption; import org.eclipse.team.internal.ccvs.core.resources.CVSWorkspaceRoot; -import org.eclipse.team.internal.ccvs.ui.wizards.SetKeywordSubstitutionWizard; +import org.eclipse.team.internal.ccvs.ui.wizards.KSubstWizard; import org.eclipse.team.ui.actions.TeamAction; /** * TagAction tags the selected resources with a version tag specified by the user. */ public class SetKeywordSubstitutionAction extends TeamAction { - private KSubstOption previousOption = Command.KSUBST_TEXT; + private KSubstOption previousOption = null; // automatic /* * @see IActionDelegate#run(IAction) */ public void run(IAction action) { final IResource[] resources = getSelectedResources(); - SetKeywordSubstitutionWizard wizard = new SetKeywordSubstitutionWizard(resources, - IResource.DEPTH_INFINITE, previousOption); - try { - wizard.prepareToOpen(); - WizardDialog dialog = new WizardDialog(getShell(), wizard); - dialog.setMinimumPageSize(350, 250); - dialog.open(); - previousOption = wizard.getKSubstOption(); - } catch (TeamException e) { - handle(e, null, null); - } + KSubstWizard wizard = new KSubstWizard(resources, IResource.DEPTH_INFINITE, previousOption); + WizardDialog dialog = new WizardDialog(getShell(), wizard); + dialog.setMinimumPageSize(350, 250); + dialog.open(); + previousOption = wizard.getKSubstOption(); } /* diff --git a/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/messages.properties b/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/messages.properties index b01415330..44fa361fc 100644 --- a/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/messages.properties +++ b/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/messages.properties @@ -320,54 +320,65 @@ ResourcePropertiesPage.checkedIn=Checked In #ResourcePropertiesPage.none=none ResourcePropertiesPage.error=Error -SetKeywordSubstitution.title=Set Keyword Substitution - -SetKeywordSubstitution.working=Setting keyword substitution mode... -SetKeywordSubstitution.problemsMessage=Problems encountered setting keyword substitution -SetKeywordSubstitution.errorTitle=Errors Occurred -SetKeywordSubstitution.warningTitle=Warnings Occured - -SetKeywordSubstitution.SharedFilesPage.pageTitle=\ - Warning some of the selected files are already shared in the repository. -SetKeywordSubstitution.SharedFilesPage.pageDescription=\ - Do you want to exclude these files from this operation? -SetKeywordSubstitution.SharedFilesPage.contents=\ +KSubstWizard.title=Set Keyword Substitution +KSubstWizard.working=Setting keyword substitution mode... +KSubstWizard.problemsMessage=Problems encountered setting keyword substitution +KSubstWizard.errorTitle=Errors Occurred +KSubstWizard.warningTitle=Warnings Occured + +KSubstWizardSharedFilesPage.pageTitle=Set Keyword Substitution Mode +KSubstWizardSharedFilesPage.pageDescription=\ + Warning: Some of the affected files are already shared in the repository. +KSubstWizardSharedFilesPage.contents=\ Since the keyword substitution mode attribute is not version controlled, the \ change will be reflected immediately on all branches and in all revisions of \ any affected files that are already shared in the repository. You should inform \ all developers that they must delete and check out fresh copies of the affected \ files before committing new changes to the repository. You may also experience \ side-effects working with earlier revisions of these files. -SetKeywordSubstitution.SharedFilesPage.onlyAddedFilesButton=Don't change files that are already shared in the repository. -SetKeywordSubstitution.SharedFilesPage.committedFiles=Selected files that are already shared in the repository: - -SetKeywordSubstitution.OutgoingChangesPage.pageTitle=\ - Warning some of the selected files have outgoing changes. -SetKeywordSubstitution.OutgoingChangesPage.pageDescription=\ - Do you want to exclude these files from this operation? -SetKeywordSubstitution.OutgoingChangesPage.contents=\ - This operation may commit changes to files without providing a chance to resolve \ - conflicts first. -SetKeywordSubstitution.OutgoingChangesPage.onlyCleanFilesButton=Don't change files with outgoing changes. -SetKeywordSubstitution.OutgoingChangesPage.changedFiles=Selected files with outgoing changes. - -SetKeywordSubstitution.SelectModePage.pageTitle=Select and change keyword substitution mode -SetKeywordSubstitution.SelectModePage.pageDescription=\ - The keyword substitution mode specifies transformations to be performed \ - on files during CVS operations. -SetKeywordSubstitution.SelectModePage.contents=\ - If you are uncertain, choose 'Text' for plain text files, and 'Binary' for all others. -SetKeywordSubstitution.SelectModePage.binaryLabel=\ +KSubstWizardSharedFilesPage.includeSharedFiles=&Include files that are already shared in the repository. +KSubstWizardSharedFilesPage.sharedFilesViewer.title=&The following files were selected and are already shared in the repository: + +KSubstWizardDirtyFilesPage.pageTitle=Set Keyword Substitution Mode +KSubstWizardDirtyFilesPage.pageDescription=\ + Warning: Some of the affected files have outgoing changes. +KSubstWizardDirtyFilesPage.contents=\ + This operation may commit changes to files without first providing a chance to resolve \ + conflicts. +KSubstWizardDirtyFilesPage.includeDirtyFiles=&Include files that have outgoing changes. +KSubstWizardDirtyFilesPage.dirtyFilesViewer.title=&The following files were selected and have outgoing changes. + +KSubstWizardSelectionPage.pageTitle=Set Keyword Substitution Mode +KSubstWizardSelectionPage.pageDescription=\ + Choose the desired keyword substitution mode for all selected files. +KSubstWizardSelectionPage.automaticButton=&Automatic +KSubstWizardSelectionPage.automaticLabel=\ + Automatically chooses \'Text\' or \'Binary without keyword substitution\' \ + for each file according to the Team file extension preferences. +KSubstWizardSelectionPage.binaryButton=&Binary (-kb) +KSubstWizardSelectionPage.binaryLabel=\ Binary files are stored in the repository without alteration.\n\ CVS does not directly support conflict resolution for binary files. -SetKeywordSubstitution.SelectModePage.textLabel=\ +KSubstWizardSelectionPage.textButton=&Text without keyword substitution (-ko) +KSubstWizardSelectionPage.textLabel=\ Text files are stored in the repository in a neutral format but are retrieved in the platform's native text encoding.\n\ - CVS supports conflict resoltion and differencing of text files with single line granularity. -SetKeywordSubstitution.SelectModePage.textWithSubstitutions=Text with Keyword Substitution... -SetKeywordSubstitution.SelectModePage.textWithSubstitutionsLabel=\ + CVS supports conflict resolution and differencing of text files with single line granularity. +KSubstWizardSelectionPage.textWithSubstitutionsButton=Text with &keyword substitution +KSubstWizardSelectionPage.textWithSubstitutionsLabel=\ Text files may also contain keywords that are substituted with their value by the CVS server during file transfers.\n\ Please consult the CVS documentation for a description of the various supported keywords and modes. +KSubstWizardSummaryPage.pageTitle=Set Keyword Substitution Mode +KSubstWizardSummaryPage.pageDescription=\ + Summary of changes to be performed. +KSubstWizardSummaryPage.contents=\ + Click on \'Finish\' to change the following files to the indicated mode.\n\ + Not shown are files that you have elected not to change, or that already \ + have the requested mode. +KSubstWizardSummaryPage.summaryViewer.title=&The following files will have their keyword substitution changed to the indicated value. +KSubstWizardSummaryPage.summaryViewer.fileHeader=File Location +KSubstWizardSummaryPage.summaryViewer.ksubstHeader=Keyword Substitution Mode + SharingWizard.autoConnectTitle=Connect Project to Repository SharingWizard.couldNotImport=Could Not Import SharingWizard.couldNotImportLong=Your resources could not be imported into the repository because a module with that name already exists. diff --git a/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/wizards/CVSWizardPage.java b/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/wizards/CVSWizardPage.java index 7ee3f15fe..95a6d830e 100644 --- a/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/wizards/CVSWizardPage.java +++ b/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/wizards/CVSWizardPage.java @@ -5,8 +5,15 @@ package org.eclipse.team.internal.ccvs.ui.wizards; * All Rights Reserved. */ +import java.util.Collection; + +import org.eclipse.core.resources.IFile; import org.eclipse.jface.dialogs.IDialogConstants; import org.eclipse.jface.resource.ImageDescriptor; +import org.eclipse.jface.viewers.IStructuredContentProvider; +import org.eclipse.jface.viewers.LabelProvider; +import org.eclipse.jface.viewers.ListViewer; +import org.eclipse.jface.viewers.Viewer; import org.eclipse.jface.wizard.WizardPage; import org.eclipse.swt.SWT; import org.eclipse.swt.layout.GridData; @@ -14,17 +21,21 @@ import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.widgets.Button; import org.eclipse.swt.widgets.Combo; import org.eclipse.swt.widgets.Composite; -import org.eclipse.swt.widgets.Event; import org.eclipse.swt.widgets.Label; -import org.eclipse.swt.widgets.Listener; import org.eclipse.swt.widgets.Text; -import org.eclipse.team.internal.ccvs.ui.*; +import org.eclipse.ui.model.WorkbenchLabelProvider; +import org.eclipse.ui.model.WorkbenchViewerSorter; /** * Common superclass for CVS wizard pages. Provides convenience methods * for widget creation. */ public abstract class CVSWizardPage extends WizardPage { + protected static final int LABEL_WIDTH_HINT = 400; + protected static final int LABEL_INDENT_WIDTH = 32; + protected static final int LIST_HEIGHT_HINT = 100; + protected static final int SPACER_HEIGHT = 8; + /** * CVSWizardPage constructor comment. * @param pageName the name of the page @@ -100,11 +111,46 @@ public abstract class CVSWizardPage extends WizardPage { * @return the new label */ protected Label createLabel(Composite parent, String text) { + return createIndentedLabel(parent, text, 0); + } + /** + * Utility method that creates a label instance indented by the specified + * number of pixels and sets the default layout data. + * + * @param parent the parent for the new label + * @param text the text for the new label + * @param indent the indent in pixels, or 0 for none + * @return the new label + */ + protected Label createIndentedLabel(Composite parent, String text, int indent) { Label label = new Label(parent, SWT.LEFT); label.setText(text); GridData data = new GridData(); data.horizontalSpan = 1; data.horizontalAlignment = GridData.FILL; + data.horizontalIndent = indent; + label.setLayoutData(data); + return label; + } + /** + * Utility method that creates a label instance with word wrap and sets + * the default layout data. + * + * @param parent the parent for the new label + * @param text the text for the new label + * @param indent the indent in pixels, or 0 for none + * @param widthHint the nominal width of the label + * @return the new label + */ + protected Label createWrappingLabel(Composite parent, String text, int indent, int widthHint) { + Label label = new Label(parent, SWT.LEFT | SWT.WRAP); + label.setText(text); + GridData data = new GridData(); + data.horizontalSpan = 1; + data.horizontalAlignment = GridData.FILL; + data.horizontalIndent = indent; + data.grabExcessHorizontalSpace = true; + data.widthHint = widthHint; label.setLayoutData(data); return label; } @@ -139,4 +185,56 @@ public abstract class CVSWizardPage extends WizardPage { button.setLayoutData(data); return button; } + /** + * Utility method to create a full width separator preceeded by a blank space + * + * @param parent the parent of the separator + * @param verticalSpace the vertical whitespace to insert before the label + */ + protected void createSeparator(Composite parent, int verticalSpace) { + // space + Label label = new Label(parent, SWT.NONE); + GridData data = new GridData(); + data.heightHint = verticalSpace; + label.setLayoutData(data); + // separator + label = new Label(parent, SWT.SEPARATOR | SWT.HORIZONTAL); + data = new GridData(GridData.FILL_HORIZONTAL); + label.setLayoutData(data); + } + + /** + * Creates a ListViewer whose input is a Collection of IFiles. + * + * @param parent the parent of the viewer + * @param title the text for the title label + * @param heightHint the nominal height of the list + * @return the created list viewer + */ + public ListViewer createFileListViewer(Composite parent, String title, int heightHint) { + createLabel(parent, title); + ListViewer listViewer = new ListViewer(parent, SWT.READ_ONLY | SWT.V_SCROLL | SWT.H_SCROLL | SWT.BORDER); + listViewer.setContentProvider(new IStructuredContentProvider() { + public Object[] getElements(Object inputElement) { + Collection collection = (Collection) inputElement; + if (collection == null) return new IFile[0]; + return (IFile[]) collection.toArray(new IFile[collection.size()]); + } + public void dispose() { + } + public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { + } + }); + listViewer.setLabelProvider(new LabelProvider() { + public String getText(Object element) { + return ((IFile) element).getFullPath().toString(); + } + }); + listViewer.setSorter(new WorkbenchViewerSorter()); + + GridData data = new GridData(GridData.FILL_BOTH); + data.heightHint = heightHint; + listViewer.getList().setLayoutData(data); + return listViewer; + } } diff --git a/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/wizards/KSubstChangeSet.java b/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/wizards/KSubstChangeSet.java new file mode 100644 index 000000000..43fa185ec --- /dev/null +++ b/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/wizards/KSubstChangeSet.java @@ -0,0 +1,184 @@ +package org.eclipse.team.internal.ccvs.ui.wizards; + +/* + * (c) Copyright IBM Corp. 2000, 2002. + * All Rights Reserved. + */ + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.eclipse.core.resources.IFile; +import org.eclipse.core.resources.IResource; +import org.eclipse.core.resources.IResourceVisitor; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.team.ccvs.core.CVSProviderPlugin; +import org.eclipse.team.ccvs.core.ICVSFile; +import org.eclipse.team.core.TeamException; +import org.eclipse.team.internal.ccvs.core.CVSException; +import org.eclipse.team.internal.ccvs.core.Policy; +import org.eclipse.team.internal.ccvs.core.client.Command.KSubstOption; +import org.eclipse.team.internal.ccvs.core.resources.CVSWorkspaceRoot; +import org.eclipse.team.internal.ccvs.core.syncinfo.ResourceSyncInfo; + +/** + * Helper class to compute change sets for keyword substitution modes. + */ +class KSubstChangeSet { + public static final int ADDED_FILES = 1; + public static final int CHANGED_FILES = 2; + public static final int UNCHANGED_FILES = 4; + + private final IResource[] resources; + private final int depth; + private Set /* of IFile */ files = null; + private Map /* from IFile to KSubstOption */ addedFiles = new HashMap(); + private Map /* from IFile to KSubstOption */ changedFiles = new HashMap(); + private Map /* from IFile to KSubstOption */ unchangedFiles = new HashMap(); + private boolean computed = false; + private KSubstOption ksubst = null; + + /** + * Creates a new empty change set for the specified resources. + * + * @param resources the resources to consider + * @param depth the recursion depth + */ + public KSubstChangeSet(IResource[] resources, int depth) { + this.resources = resources; + this.depth = depth; + } + + /** + * Computes the lists of files that must have their keyword substitution + * mode changed, classified into three categories: added (but not yet committed), + * changed, unchanged. + * + * @param ksubst the desired keyword substitution mode, if null chooses for each file: + * <code>KSubstOption.fromPattern(fileName).isBinary() ? KSUBST_BINARY : KSUBST_TEXT</code> + */ + public void computeAffectedFiles(KSubstOption ksubst) throws TeamException { + // already computed this? + if (computed && this.ksubst == ksubst) return; + this.ksubst = ksubst; + this.computed = true; + // clear stored data + addedFiles.clear(); + changedFiles.clear(); + unchangedFiles.clear(); + if (files == null) files = getAllFiles(resources, depth); + // iterate over all files and determine the appropriate classifications + for (Iterator it = files.iterator(); it.hasNext();) { + IFile file = (IFile) it.next(); + ICVSFile cvsFile = CVSWorkspaceRoot.getCVSFileFor(file); + if (cvsFile.isManaged()) { + // check if the keyword substitution mode needs to be changed + ResourceSyncInfo info = cvsFile.getSyncInfo(); + KSubstOption fromKSubst = KSubstOption.fromMode(info.getKeywordMode()); + KSubstOption toKSubst = ksubst; + if (ksubst == null) { + toKSubst = KSubstOption.fromPattern(file.getName()); + } + if (! toKSubst.equals(fromKSubst)) { + // classify the change + if (info.isAdded()) { + addedFiles.put(file, toKSubst); + } else if (info.isDeleted()) { + // ignore deletions + } else if (cvsFile.isModified()) { + changedFiles.put(file, toKSubst); + } else { + unchangedFiles.put(file, toKSubst); + } + } + } + } + } + + /** + * Returns an unmodifiable map describing the changes to be performed. + * + * @return a Map from IFile to KSubstOption + */ + public Map getChangeSet(int type) { + Map map; + switch (type) { + case ADDED_FILES: + map = addedFiles; + break; + case CHANGED_FILES: + map = changedFiles; + break; + case UNCHANGED_FILES: + map = unchangedFiles; + break; + default: + map = new HashMap(); + if ((type & ADDED_FILES) != 0) map.putAll(addedFiles); + if ((type & CHANGED_FILES) != 0) map.putAll(changedFiles); + if ((type & UNCHANGED_FILES) != 0) map.putAll(unchangedFiles); + } + return Collections.unmodifiableMap(map); + } + + /** + * Returns an unmodifiable collection of all files that will be changed. + * + * @return a Collection of IFile + */ + public Collection getFileSet(int type) { + Collection collection; + switch (type) { + case ADDED_FILES: + collection = addedFiles.keySet(); + break; + case CHANGED_FILES: + collection = changedFiles.keySet(); + break; + case UNCHANGED_FILES: + collection = unchangedFiles.keySet(); + break; + default: + collection = new ArrayList(); + if ((type & ADDED_FILES) != 0) collection.addAll(addedFiles.keySet()); + if ((type & CHANGED_FILES) != 0) collection.addAll(changedFiles.keySet()); + if ((type & UNCHANGED_FILES) != 0) collection.addAll(unchangedFiles.keySet()); + } + return Collections.unmodifiableCollection(collection); + } + + /* + * Returns a set of all files encountered during the traversal. + */ + private static Set getAllFiles(IResource[] resources, int depth) throws TeamException { + final Set /* of IFile */ files = new HashSet(); + for (int i = 0; i < resources.length; i++) { + final IResource currentResource = resources[i]; + try { + currentResource.accept(new IResourceVisitor() { + public boolean visit(IResource resource) throws CoreException { + if (resource.getType() == IResource.FILE) { + files.add(resource); + } + // always return true and let the depth determine if children are visited + return true; + } + }, depth, false); + } catch (CoreException e) { + throw new CVSException(new Status(IStatus.ERROR, CVSProviderPlugin.ID, + TeamException.UNABLE, Policy.bind("CVSTeamProvider.visitError", //$NON-NLS-1$ + new Object[] { currentResource.getFullPath() }), e)); + } + } + return files; + } +} diff --git a/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/wizards/KSubstWizard.java b/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/wizards/KSubstWizard.java new file mode 100644 index 000000000..a6e8acf00 --- /dev/null +++ b/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/wizards/KSubstWizard.java @@ -0,0 +1,309 @@ +package org.eclipse.team.internal.ccvs.ui.wizards; + +/* + * (c) Copyright IBM Corp. 2000, 2002. + * All Rights Reserved. + */ + +import java.lang.reflect.InvocationTargetException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +import org.eclipse.core.resources.IFile; +import org.eclipse.core.resources.IResource; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.MultiStatus; +import org.eclipse.jface.dialogs.ErrorDialog; +import org.eclipse.jface.operation.IRunnableWithProgress; +import org.eclipse.jface.wizard.IWizardPage; +import org.eclipse.jface.wizard.Wizard; +import org.eclipse.swt.SWT; +import org.eclipse.swt.graphics.Cursor; +import org.eclipse.team.ccvs.core.CVSStatus; +import org.eclipse.team.ccvs.core.CVSTeamProvider; +import org.eclipse.team.core.RepositoryProvider; +import org.eclipse.team.core.RepositoryProviderType; +import org.eclipse.team.core.TeamException; +import org.eclipse.team.internal.ccvs.core.client.Command.KSubstOption; +import org.eclipse.team.internal.ccvs.ui.CVSUIPlugin; +import org.eclipse.team.internal.ccvs.ui.Policy; +import org.eclipse.ui.internal.IWorkbenchConstants; +import org.eclipse.ui.internal.IWorkbenchGraphicConstants; + +/** + * A wizard for changing the keyword substitution mode of files. + * + * 1. Ask the user select to select the desired keyword substitution mode. + * 2. Compute the set of possibly affected resources + * 3. If the affected resources include existing committed files, warn the user + * and provide an option to include them in the operation anyways. + * 4. If the affected resources include dirty files, warn the user and provide + * an option to include them in the operation anyways. + * 5. Perform the operation on Finish. + */ +public class KSubstWizard extends Wizard { + private KSubstOption defaultKSubst; + private KSubstChangeSet changeSet; + + private KSubstWizardSelectionPage mainPage; + private KSubstWizardSummaryPage summaryPage; + private KSubstWizardSharedFilesPage sharedFilesPage; + private KSubstWizardDirtyFilesPage dirtyFilesPage; + + /** + * Creates a wizard to set the keyword substitution mode for the specified resources. + * + * @param resources the resources to alter + * @param depth the recursion depth + * @param defaultOption the keyword substitution option to select by default + */ + public KSubstWizard(IResource[] resources, int depth, KSubstOption defaultOption) { + super(); + this.defaultKSubst = defaultOption; + this.changeSet = new KSubstChangeSet(resources, depth); + setWindowTitle(Policy.bind("KSubstWizard.title")); + } + + /** + * Returns the keyword substitution option that was selected at the time + * the Finish button was pressed. + */ + public KSubstOption getKSubstOption() { + return defaultKSubst; + } + + public void addPages() { + // add main page + String pageTitle = Policy.bind("KSubstWizardSelectionPage.pageTitle"); //$NON-NLS-1$ + String pageDescription = Policy.bind("KSubstWizardSelectionPage.pageDescription"); //$NON-NLS-1$ + mainPage = new KSubstWizardSelectionPage(pageTitle, defaultKSubst); + mainPage.setDescription(pageDescription); + mainPage.setTitle(pageTitle); + addPage(mainPage); + + // add summary page + pageTitle = Policy.bind("KSubstWizardSummaryPage.pageTitle"); //$NON-NLS-1$ + pageDescription = Policy.bind("KSubstWizardSummaryPage.pageDescription"); //$NON-NLS-1$ + summaryPage = new KSubstWizardSummaryPage(pageTitle); + summaryPage.setDescription(pageDescription); + summaryPage.setTitle(pageTitle); + addPage(summaryPage); + + // add shared files warning page + pageTitle = Policy.bind("KSubstWizardSharedFilesPage.pageTitle"); //$NON-NLS-1$ + pageDescription = Policy.bind("KSubstWizardSharedFilesPage.pageDescription"); //$NON-NLS-1$ + sharedFilesPage = new KSubstWizardSharedFilesPage(pageTitle, false); + sharedFilesPage.setDescription(pageDescription); + sharedFilesPage.setTitle(pageTitle); + addPage(sharedFilesPage); + + // add changed files warning page + pageTitle = Policy.bind("KSubstWizardDirtyFilesPage.pageTitle"); //$NON-NLS-1$ + pageDescription = Policy.bind("KSubstWizardDirtyFilesPage.pageDescription"); //$NON-NLS-1$ + dirtyFilesPage = new KSubstWizardDirtyFilesPage(pageTitle, false); + dirtyFilesPage.setDescription(pageDescription); + dirtyFilesPage.setTitle(pageTitle); + addPage(dirtyFilesPage); + } + + public IWizardPage getNextPage(IWizardPage page) { + if (page == mainPage) { + if (prepareSharedFilesPage()) return sharedFilesPage; + } else if (page == sharedFilesPage) { + if (sharedFilesPage.includeSharedFiles() && prepareDirtyFilesPage()) return dirtyFilesPage; + } else if (page == summaryPage) { + return null; + } + prepareSummaryPage(); + return summaryPage; + } + + public IWizardPage getPreviousPage(IWizardPage page) { + computeAffectedFiles(); + if (page == summaryPage) { + if (sharedFilesPage.includeSharedFiles() && prepareDirtyFilesPage()) return dirtyFilesPage; + if (prepareSharedFilesPage()) return sharedFilesPage; + return mainPage; + } else if (page == dirtyFilesPage) { + if (prepareSharedFilesPage()) return sharedFilesPage; + return mainPage; + } else if (page == sharedFilesPage) { + return mainPage; + } + return null; + } + + /* (Non-javadoc) + * Method declared on IWizard. + */ + public boolean needsProgressMonitor() { + return true; + } + + /* (Non-javadoc) + * Method declared on IWizard. + */ + public boolean needsPreviousAndNextButtons() { + return true; + } + + /* (Non-javadoc) + * Method declared on IWizard. + */ + public boolean performFinish() { + try { + defaultKSubst = mainPage.getKSubstOption(); + final List messages = new ArrayList(); + getContainer().run(false /*fork*/, true /*cancelable*/, new IRunnableWithProgress() { + public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException { + try { + monitor.beginTask("", 10000); + monitor.setTaskName(Policy.bind("KSubstWizard.working")); + computeAffectedFiles(); + Map table = getProviderMapping(changeSet.getChangeSet(KSubstChangeSet.ADDED_FILES | + (sharedFilesPage.includeSharedFiles() ? KSubstChangeSet.UNCHANGED_FILES | + (dirtyFilesPage.includeDirtyFiles() ? KSubstChangeSet.CHANGED_FILES : 0) : 0))); + int workPerProvider = 10000 / (table.size() + 1); + monitor.worked(workPerProvider); + for (Iterator it = table.entrySet().iterator(); it.hasNext();) { + Map.Entry entry = (Map.Entry) it.next(); + CVSTeamProvider provider = (CVSTeamProvider) entry.getKey(); + Map providerFiles = (Map) entry.getValue(); + + IStatus status = provider.setKeywordSubstitution(providerFiles, + Policy.subMonitorFor(monitor, workPerProvider)); + if (status.getCode() != CVSStatus.OK) { + messages.add(status); + } + } + } catch (TeamException e) { + throw new InvocationTargetException(e); + } finally { + monitor.done(); + } + } + }); + // Check for any status messages and display them + if ( ! messages.isEmpty()) { + boolean error = false; + MultiStatus combinedStatus = new MultiStatus(CVSUIPlugin.ID, 0, + Policy.bind("KSubstWizard.problemsMessage"), null); + for (int i = 0; i < messages.size(); i++) { + IStatus status = (IStatus)messages.get(i); + if (status.getSeverity() == IStatus.ERROR || status.getCode() == CVSStatus.SERVER_ERROR) { + error = true; + } + combinedStatus.merge(status); + } + String message = null; + IStatus statusToDisplay; + if (combinedStatus.getChildren().length == 1) { + message = combinedStatus.getMessage(); + statusToDisplay = combinedStatus.getChildren()[0]; + } else { + statusToDisplay = combinedStatus; + } + String title; + if (error) { + title = Policy.bind("KSubstWizard.errorTitle"); + } else { + title = Policy.bind("KSubstWizard.warningTitle"); + } + ErrorDialog.openError(getShell(), title, message, statusToDisplay); + } + return true; + } catch (InterruptedException e1) { + return true; + } catch (InvocationTargetException e2) { + if (e2.getTargetException() instanceof CoreException) { + CoreException e = (CoreException) e2.getTargetException(); + ErrorDialog.openError(getShell(), Policy.bind("KSubstWizard.problemsMessage"), null, e.getStatus()); //$NON-NLS-1$ + return false; + } else { + Throwable target = e2.getTargetException(); + if (target instanceof RuntimeException) { + throw (RuntimeException) target; + } + if (target instanceof Error) { + throw (Error) target; + } + } + return true; + } + } + + private boolean prepareDirtyFilesPage() { + Cursor busyCursor = new Cursor(getContainer().getShell().getDisplay(), SWT.CURSOR_WAIT); + try { + getContainer().getShell().setCursor(busyCursor); + computeAffectedFiles(); + Collection files = changeSet.getFileSet(KSubstChangeSet.CHANGED_FILES); + dirtyFilesPage.setDirtyFilesList(files); + return files.size() != 0; + } finally { + getContainer().getShell().setCursor(null); + busyCursor.dispose(); + } + } + + private boolean prepareSharedFilesPage() { + Cursor busyCursor = new Cursor(getContainer().getShell().getDisplay(), SWT.CURSOR_WAIT); + try { + getContainer().getShell().setCursor(busyCursor); + computeAffectedFiles(); + Collection files = changeSet.getFileSet(KSubstChangeSet.CHANGED_FILES | KSubstChangeSet.UNCHANGED_FILES); + sharedFilesPage.setSharedFilesList(files); + return files.size() != 0; + } finally { + getContainer().getShell().setCursor(null); + busyCursor.dispose(); + } + } + + private void prepareSummaryPage() { + Cursor busyCursor = new Cursor(getContainer().getShell().getDisplay(), SWT.CURSOR_WAIT); + try { + getContainer().getShell().setCursor(busyCursor); + computeAffectedFiles(); + Map affectedFiles = changeSet.getChangeSet(KSubstChangeSet.ADDED_FILES | + (sharedFilesPage.includeSharedFiles() ? KSubstChangeSet.UNCHANGED_FILES | + (dirtyFilesPage.includeDirtyFiles() ? KSubstChangeSet.CHANGED_FILES : 0) : 0)); + summaryPage.setChangeSet(affectedFiles); + } finally { + getContainer().getShell().setCursor(null); + busyCursor.dispose(); + } + } + + private void computeAffectedFiles() { + try { + changeSet.computeAffectedFiles(mainPage.getKSubstOption()); + } catch (TeamException e) { + ErrorDialog.openError(getShell(), Policy.bind("KSubstWizard.problemsMessage"), null, e.getStatus()); //$NON-NLS-1$ + } + } + + private Map getProviderMapping(Map affectedFiles) { + Map table = new HashMap(); + for (Iterator it = affectedFiles.entrySet().iterator(); it.hasNext();) { + Map.Entry entry = (Map.Entry) it.next(); + IFile file = (IFile) entry.getKey(); + KSubstOption toKSubst = (KSubstOption) entry.getValue(); + // classify file according to its provider + RepositoryProvider provider = RepositoryProviderType.getProvider(file.getProject()); + Map providerMap = (Map) table.get(provider); + if (providerMap == null) { + providerMap = new HashMap(); + table.put(provider, providerMap); + } + providerMap.put(file, toKSubst); + } + return table; + } +} diff --git a/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/wizards/KSubstWizardDirtyFilesPage.java b/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/wizards/KSubstWizardDirtyFilesPage.java new file mode 100644 index 000000000..95b6bc2bf --- /dev/null +++ b/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/wizards/KSubstWizardDirtyFilesPage.java @@ -0,0 +1,61 @@ +package org.eclipse.team.internal.ccvs.ui.wizards; + +/* + * (c) Copyright IBM Corp. 2000, 2002. + * All Rights Reserved. + */ + +import java.util.Collection; + +import org.eclipse.jface.viewers.ListViewer; +import org.eclipse.swt.SWT; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Event; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Listener; +import org.eclipse.team.internal.ccvs.ui.Policy; + +/** + * Page to warn user about uncommitted outgoing changes. + */ +public class KSubstWizardDirtyFilesPage extends CVSWizardPage { + private boolean includeDirtyFiles; + private Button includeDirtyFilesButton; + private ListViewer listViewer; + + public KSubstWizardDirtyFilesPage(String pageName, boolean includeDirtyFiles) { + super(pageName); + this.includeDirtyFiles = includeDirtyFiles; + } + + public void createControl(Composite parent) { + Composite top = new Composite(parent, SWT.NONE); + top.setLayout(new GridLayout()); + setControl(top); + createWrappingLabel(top, Policy.bind("KSubstWizardDirtyFilesPage.contents"), 0, LABEL_WIDTH_HINT); + + includeDirtyFilesButton = new Button(top, SWT.CHECK); + includeDirtyFilesButton.setText(Policy.bind("KSubstWizardDirtyFilesPage.includeDirtyFiles")); + includeDirtyFilesButton.setSelection(includeDirtyFiles); + includeDirtyFilesButton.addListener(SWT.Selection, new Listener() { + public void handleEvent(Event e) { + includeDirtyFiles = includeDirtyFilesButton.getSelection(); + } + }); + + createSeparator(top, SPACER_HEIGHT); + listViewer = createFileListViewer(top, + Policy.bind("KSubstWizardDirtyFilesPage.dirtyFilesViewer.title"), LIST_HEIGHT_HINT); + } + + public boolean includeDirtyFiles() { + return includeDirtyFiles; + } + + public void setDirtyFilesList(Collection files) { + listViewer.setInput(files); + } +} diff --git a/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/wizards/KSubstWizardSelectionPage.java b/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/wizards/KSubstWizardSelectionPage.java new file mode 100644 index 000000000..1a6d68f06 --- /dev/null +++ b/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/wizards/KSubstWizardSelectionPage.java @@ -0,0 +1,139 @@ +package org.eclipse.team.internal.ccvs.ui.wizards; + +/* + * (c) Copyright IBM Corp. 2000, 2002. + * All Rights Reserved. + */ + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Combo; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Event; +import org.eclipse.swt.widgets.Listener; +import org.eclipse.team.internal.ccvs.core.client.Command; +import org.eclipse.team.internal.ccvs.core.client.Command.KSubstOption; +import org.eclipse.team.internal.ccvs.ui.Policy; + +/** + * Page to select keyword substitution mode. + */ +public class KSubstWizardSelectionPage extends CVSWizardPage { + private KSubstOption ksubst; + private List ksubstOptions; + private Button automaticRadioButton; + private Button binaryRadioButton; + private Button textRadioButton; + private Button ksubstRadioButton; + private Combo ksubstOptionCombo; + + public KSubstWizardSelectionPage(String pageName, KSubstOption defaultKSubst) { + super(pageName); + this.ksubst = defaultKSubst; + + // sort the options by display text + KSubstOption[] options = KSubstOption.getAllKSubstOptions(); + this.ksubstOptions = new ArrayList(); + for (int i = 0; i < options.length; i++) { + KSubstOption option = options[i]; + if (! (Command.KSUBST_BINARY.equals(option) || + Command.KSUBST_TEXT.equals(option))) { + ksubstOptions.add(option); + } + } + Collections.sort(ksubstOptions, new Comparator() { + public int compare(Object a, Object b) { + String aKey = ((KSubstOption) a).getLongDisplayText(); + String bKey = ((KSubstOption) b).getLongDisplayText(); + return aKey.compareTo(bKey); + } + }); + } + + public void createControl(Composite parent) { + Composite top = new Composite(parent, SWT.NONE); + top.setLayout(new GridLayout()); + setControl(top); + + Listener selectionListener = new Listener() { + public void handleEvent(Event event) { + updateEnablements(); + } + }; + + // Automatic + automaticRadioButton = createRadioButton(top, Policy.bind("KSubstWizardSelectionPage.automaticButton"), 1); + automaticRadioButton.addListener(SWT.Selection, selectionListener); + automaticRadioButton.setSelection(ksubst == null); + createWrappingLabel(top, Policy.bind("KSubstWizardSelectionPage.automaticLabel"), LABEL_INDENT_WIDTH, LABEL_WIDTH_HINT); + + // Binary + binaryRadioButton = createRadioButton(top, Policy.bind("KSubstWizardSelectionPage.binaryButton"), 1); + binaryRadioButton.addListener(SWT.Selection, selectionListener); + binaryRadioButton.setSelection(Command.KSUBST_BINARY.equals(ksubst)); + createIndentedLabel(top, Policy.bind("KSubstWizardSelectionPage.binaryLabel"), LABEL_INDENT_WIDTH); + + // Text without keyword substitution + textRadioButton = createRadioButton(top, Policy.bind("KSubstWizardSelectionPage.textButton"), 1); + textRadioButton.addListener(SWT.Selection, selectionListener); + textRadioButton.setSelection(Command.KSUBST_TEXT.equals(ksubst)); + createIndentedLabel(top, Policy.bind("KSubstWizardSelectionPage.textLabel"), LABEL_INDENT_WIDTH); + + // Text with keyword substitution + ksubstRadioButton = createRadioButton(top, Policy.bind("KSubstWizardSelectionPage.textWithSubstitutionsButton"), 1); + ksubstRadioButton.addListener(SWT.Selection, selectionListener); + ksubstRadioButton.setSelection(false); + createIndentedLabel(top, Policy.bind("KSubstWizardSelectionPage.textWithSubstitutionsLabel"), LABEL_INDENT_WIDTH); + + ksubstOptionCombo = new Combo(top, SWT.READ_ONLY); + ksubstOptionCombo.addListener(SWT.Selection, selectionListener); + GridData data = new GridData(GridData.VERTICAL_ALIGN_FILL | GridData.HORIZONTAL_ALIGN_BEGINNING); + data.horizontalIndent = LABEL_INDENT_WIDTH; + ksubstOptionCombo.setLayoutData(data); + + // populate the combo box and select the default option + for (int i = 0; i < ksubstOptions.size(); ++i) { + KSubstOption option = (KSubstOption) ksubstOptions.get(i); + ksubstOptionCombo.add(option.getLongDisplayText()); + if (option.equals(ksubst)) { + ksubstOptionCombo.select(i); + ksubstRadioButton.setSelection(true); + } else if (option.equals(Command.KSUBST_TEXT_EXPAND)) { + // if no expansion mode selected, show KSUBST_TEXT_EXPAND + // since it is the server default + if (! ksubstRadioButton.getSelection()) ksubstOptionCombo.select(i); + } + } + updateEnablements(); + } + + /** + * Enable and disable controls based on the selected radio button. + */ + protected void updateEnablements() { + if (ksubstRadioButton.getSelection()) { + ksubstOptionCombo.setEnabled(true); + ksubst = (KSubstOption) ksubstOptions.get(ksubstOptionCombo.getSelectionIndex()); + } else { + ksubstOptionCombo.setEnabled(false); + if (automaticRadioButton.getSelection()) { + ksubst = null; + } else if (binaryRadioButton.getSelection()) { + ksubst = Command.KSUBST_BINARY; + } else if (textRadioButton.getSelection()) { + ksubst = Command.KSUBST_TEXT; + } + } + } + + public KSubstOption getKSubstOption() { + return ksubst; + } +} diff --git a/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/wizards/KSubstWizardSharedFilesPage.java b/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/wizards/KSubstWizardSharedFilesPage.java new file mode 100644 index 000000000..5604beca5 --- /dev/null +++ b/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/wizards/KSubstWizardSharedFilesPage.java @@ -0,0 +1,62 @@ +package org.eclipse.team.internal.ccvs.ui.wizards; + +/* + * (c) Copyright IBM Corp. 2000, 2002. + * All Rights Reserved. + */ + +import java.util.Collection; + +import org.eclipse.jface.viewers.ListViewer; +import org.eclipse.swt.SWT; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Event; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Listener; +import org.eclipse.team.internal.ccvs.ui.Policy; + +/** + * Page to warn user about the side-effects of changing keyword + * substitution on already committed files. + */ +public class KSubstWizardSharedFilesPage extends CVSWizardPage { + private boolean includeSharedFiles; + private Button includeSharedFilesButton; + private ListViewer listViewer; + + public KSubstWizardSharedFilesPage(String pageName, boolean includeSharedFiles) { + super(pageName); + this.includeSharedFiles = includeSharedFiles; + } + + public void createControl(Composite parent) { + Composite top = new Composite(parent, SWT.NONE); + top.setLayout(new GridLayout()); + setControl(top); + createWrappingLabel(top, Policy.bind("KSubstWizardSharedFilesPage.contents"), 0, LABEL_WIDTH_HINT); + + includeSharedFilesButton = new Button(top, SWT.CHECK); + includeSharedFilesButton.setText(Policy.bind("KSubstWizardSharedFilesPage.includeSharedFiles")); + includeSharedFilesButton.setSelection(includeSharedFiles); + includeSharedFilesButton.addListener(SWT.Selection, new Listener() { + public void handleEvent(Event e) { + includeSharedFiles = includeSharedFilesButton.getSelection(); + } + }); + + createSeparator(top, SPACER_HEIGHT); + listViewer = createFileListViewer(top, + Policy.bind("KSubstWizardSharedFilesPage.sharedFilesViewer.title"), LIST_HEIGHT_HINT); + } + + public boolean includeSharedFiles() { + return includeSharedFiles; + } + + public void setSharedFilesList(Collection files) { + listViewer.setInput(files); + } +} diff --git a/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/wizards/KSubstWizardSummaryPage.java b/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/wizards/KSubstWizardSummaryPage.java new file mode 100644 index 000000000..c5533fdb8 --- /dev/null +++ b/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/wizards/KSubstWizardSummaryPage.java @@ -0,0 +1,127 @@ +package org.eclipse.team.internal.ccvs.ui.wizards; + +/* + * (c) Copyright IBM Corp. 2000, 2002. + * All Rights Reserved. + */ + +import java.util.Map; + +import org.eclipse.core.resources.IFile; +import org.eclipse.jface.viewers.ColumnWeightData; +import org.eclipse.jface.viewers.ILabelProviderListener; +import org.eclipse.jface.viewers.IStructuredContentProvider; +import org.eclipse.jface.viewers.ITableLabelProvider; +import org.eclipse.jface.viewers.TableLayout; +import org.eclipse.jface.viewers.TableViewer; +import org.eclipse.jface.viewers.Viewer; +import org.eclipse.swt.SWT; +import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Table; +import org.eclipse.swt.widgets.TableColumn; +import org.eclipse.team.internal.ccvs.core.client.Command.KSubstOption; +import org.eclipse.team.internal.ccvs.ui.Policy; +import org.eclipse.ui.model.WorkbenchViewerSorter; + +public class KSubstWizardSummaryPage extends CVSWizardPage { + private TableViewer tableViewer; + + public KSubstWizardSummaryPage(String pageName) { + super(pageName); + } + + public void createControl(Composite parent) { + Composite top = new Composite(parent, SWT.NONE); + top.setLayout(new GridLayout()); + setControl(top); + createWrappingLabel(top, Policy.bind("KSubstWizardSummaryPage.contents"), 0, LABEL_WIDTH_HINT); + createSeparator(top, SPACER_HEIGHT); + tableViewer = createFileTableViewer(top, + Policy.bind("KSubstWizardSummaryPage.summaryViewer.title"), + Policy.bind("KSubstWizardSummaryPage.summaryViewer.fileHeader"), + Policy.bind("KSubstWizardSummaryPage.summaryViewer.ksubstHeader"), + LIST_HEIGHT_HINT); + } + + /** + * Creates a TableViewer whose input is a Map from IFile to KSubstOption. + * + * @param parent the parent of the viewer + * @param title the text for the title label + * @param heightHint the nominal height of the list + * @return the created list viewer + */ + public TableViewer createFileTableViewer(Composite parent, String title, + String fileHeader, String ksubstHeader, int heightHint) { + createLabel(parent, title); + // create a table + Table table = new Table(parent, SWT.V_SCROLL | SWT.H_SCROLL | SWT.BORDER | SWT.FULL_SELECTION); + GridData data = new GridData(GridData.FILL_BOTH); + data.heightHint = heightHint; + table.setLayoutData(data); + table.setLinesVisible(true); + table.setHeaderVisible(true); + // add the columns + TableColumn column = new TableColumn(table, SWT.LEFT, 0); + column.setText(fileHeader); + column = new TableColumn(table, SWT.LEFT, 1); + column.setText(ksubstHeader); + TableLayout tableLayout = new TableLayout(); + table.setLayout(tableLayout); + tableLayout.addColumnData(new ColumnWeightData(2, true)); + tableLayout.addColumnData(new ColumnWeightData(1, true)); + + // create a viewer for the table + TableViewer tableViewer = new TableViewer(table); + tableViewer.setContentProvider(new IStructuredContentProvider() { + public Object[] getElements(Object inputElement) { + Map changeSet = (Map) inputElement; + if (changeSet == null) return new Map.Entry[0]; + return changeSet.entrySet().toArray(); + } + public void dispose() { + } + public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { + } + }); + // show file name and keyword substitution mode + tableViewer.setLabelProvider(new ITableLabelProvider() { + public Image getColumnImage(Object element, int columnIndex) { + return null; + } + public String getColumnText(Object element, int columnIndex) { + Map.Entry entry = (Map.Entry) element; + if (columnIndex == 0) { + return ((IFile) entry.getKey()).getFullPath().toString(); + } else { + return ((KSubstOption) entry.getValue()).getLongDisplayText(); + } + } + public void addListener(ILabelProviderListener listener) { + } + public void dispose() { + } + public boolean isLabelProperty(Object element, String property) { + return false; + } + public void removeListener(ILabelProviderListener listener) { + } + }); + // sort by file name + tableViewer.setSorter(new WorkbenchViewerSorter() { + public int compare(Viewer viewer, Object e1, Object e2) { + return super.compare(viewer, ((Map.Entry) e1).getKey(), ((Map.Entry) e2).getKey()); + } + }); + return tableViewer; + } + + public void setChangeSet(Map changeSet) { + tableViewer.setInput(changeSet); + tableViewer.refresh(); + } +} diff --git a/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/wizards/SetKeywordSubstitutionOperation.java b/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/wizards/SetKeywordSubstitutionOperation.java deleted file mode 100644 index 734b52ed4..000000000 --- a/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/wizards/SetKeywordSubstitutionOperation.java +++ /dev/null @@ -1,129 +0,0 @@ -package org.eclipse.team.internal.ccvs.ui.wizards; - -/* - * (c) Copyright IBM Corp. 2000, 2002. - * All Rights Reserved. - */ - -import java.lang.reflect.InvocationTargetException; -import java.util.ArrayList; -import java.util.Hashtable; -import java.util.Iterator; -import java.util.List; -import java.util.Set; - -import org.eclipse.core.resources.IResource; -import org.eclipse.core.runtime.IProgressMonitor; -import org.eclipse.core.runtime.IStatus; -import org.eclipse.core.runtime.MultiStatus; -import org.eclipse.core.runtime.SubProgressMonitor; -import org.eclipse.jface.dialogs.ErrorDialog; -import org.eclipse.jface.operation.IRunnableWithProgress; -import org.eclipse.swt.widgets.Shell; -import org.eclipse.team.ccvs.core.CVSStatus; -import org.eclipse.team.ccvs.core.CVSTeamProvider; -import org.eclipse.team.core.RepositoryProvider; -import org.eclipse.team.core.RepositoryProviderType; -import org.eclipse.team.core.TeamException; -import org.eclipse.team.core.TeamPlugin; -import org.eclipse.team.internal.ccvs.core.client.Command.KSubstOption; -import org.eclipse.team.internal.ccvs.ui.CVSUIPlugin; -import org.eclipse.team.internal.ccvs.ui.Policy; - -/** - * An operation to change the keyword substitution and optionally commit - * resources in a CVS repository. - */ -public class SetKeywordSubstitutionOperation implements IRunnableWithProgress { - private IResource[] resources; - private int depth; - private Shell shell; - private KSubstOption ksubst; - - SetKeywordSubstitutionOperation(IResource[] resources, int depth, KSubstOption ksubst, Shell shell) { - this.resources = resources; - this.depth = depth; - this.shell = shell; - this.ksubst = ksubst; - } - - /** - * @see IRunnableWithProgress#run(IProgressMonitor) - */ - public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException { - List messages = new ArrayList(); - try { - Hashtable table = getProviderMapping(resources); - Set keySet = table.keySet(); - monitor.beginTask("", keySet.size() * 1000); - monitor.setTaskName(Policy.bind("SetKeywordSubstitution.working")); - Iterator iterator = keySet.iterator(); - - while (iterator.hasNext()) { - IProgressMonitor subMonitor = new SubProgressMonitor(monitor, 1000); - CVSTeamProvider provider = (CVSTeamProvider)iterator.next(); - List list = (List)table.get(provider); - IResource[] providerResources = (IResource[])list.toArray(new IResource[list.size()]); - IStatus status = provider.setKeywordSubstitution(providerResources, depth, - ksubst, subMonitor); - if (status.getCode() != CVSStatus.OK) { - messages.add(status); - } - } - } catch (TeamException e) { - throw new InvocationTargetException(e); - } finally { - monitor.done(); - } - - // Check for any status messages and display them - if (!messages.isEmpty()) { - boolean error = false; - MultiStatus combinedStatus = new MultiStatus(CVSUIPlugin.ID, 0, - Policy.bind("SetKeywordSubstitution.problemsMessage"), null); - for (int i = 0; i < messages.size(); i++) { - IStatus status = (IStatus)messages.get(i); - if (status.getSeverity() == IStatus.ERROR || status.getCode() == CVSStatus.SERVER_ERROR) { - error = true; - } - combinedStatus.merge(status); - } - String message = null; - IStatus statusToDisplay; - if (combinedStatus.getChildren().length == 1) { - message = combinedStatus.getMessage(); - statusToDisplay = combinedStatus.getChildren()[0]; - } else { - statusToDisplay = combinedStatus; - } - String title; - if (error) { - title = Policy.bind("SetKeywordSubstitution.errorTitle"); - } else { - title = Policy.bind("SetKeywordSubstitution.warningTitle"); - } - ErrorDialog.openError(shell, title, message, statusToDisplay); - } - } - - /** - * Convenience method that maps the given resources to their providers. - * The returned Hashtable has keys which are ITeamProviders, and values - * which are Lists of IResources that are shared with that provider. - * - * @return a hashtable mapping providers to their resources - */ - protected Hashtable getProviderMapping(IResource[] resources) { - Hashtable result = new Hashtable(); - for (int i = 0; i < resources.length; i++) { - RepositoryProvider provider = RepositoryProviderType.getProvider(resources[i].getProject()); - List list = (List)result.get(provider); - if (list == null) { - list = new ArrayList(); - result.put(provider, list); - } - list.add(resources[i]); - } - return result; - } -}
\ No newline at end of file diff --git a/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/wizards/SetKeywordSubstitutionWizard.java b/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/wizards/SetKeywordSubstitutionWizard.java deleted file mode 100644 index c2ef8fe2a..000000000 --- a/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/wizards/SetKeywordSubstitutionWizard.java +++ /dev/null @@ -1,554 +0,0 @@ -package org.eclipse.team.internal.ccvs.ui.wizards; - -/* - * (c) Copyright IBM Corp. 2000, 2002. - * All Rights Reserved. - */ - -import java.lang.reflect.InvocationTargetException; -import java.net.MalformedURLException; -import java.net.URL; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Comparator; -import java.util.HashSet; -import java.util.Iterator; -import java.util.List; -import java.util.Set; - -import org.eclipse.core.resources.IFile; -import org.eclipse.core.resources.IResource; -import org.eclipse.core.resources.IResourceVisitor; -import org.eclipse.core.runtime.CoreException; -import org.eclipse.jface.dialogs.ErrorDialog; -import org.eclipse.jface.operation.IRunnableWithProgress; -import org.eclipse.jface.resource.ImageDescriptor; -import org.eclipse.jface.viewers.IStructuredContentProvider; -import org.eclipse.jface.viewers.LabelProvider; -import org.eclipse.jface.viewers.ListViewer; -import org.eclipse.jface.viewers.Viewer; -import org.eclipse.jface.wizard.IWizardPage; -import org.eclipse.jface.wizard.Wizard; -import org.eclipse.jface.wizard.WizardPage; -import org.eclipse.swt.SWT; -import org.eclipse.swt.layout.FillLayout; -import org.eclipse.swt.layout.GridData; -import org.eclipse.swt.layout.GridLayout; -import org.eclipse.swt.widgets.Button; -import org.eclipse.swt.widgets.Combo; -import org.eclipse.swt.widgets.Composite; -import org.eclipse.swt.widgets.Display; -import org.eclipse.swt.widgets.Event; -import org.eclipse.swt.widgets.Group; -import org.eclipse.swt.widgets.Label; -import org.eclipse.swt.widgets.Listener; -import org.eclipse.team.ccvs.core.ICVSFile; -import org.eclipse.team.core.TeamException; -import org.eclipse.team.internal.ccvs.core.CVSException; -import org.eclipse.team.internal.ccvs.core.client.Command; -import org.eclipse.team.internal.ccvs.core.client.Command.KSubstOption; -import org.eclipse.team.internal.ccvs.core.resources.CVSWorkspaceRoot; -import org.eclipse.team.internal.ccvs.core.syncinfo.ResourceSyncInfo; -import org.eclipse.team.internal.ccvs.ui.CVSUIPlugin; -import org.eclipse.team.internal.ccvs.ui.Policy; -import org.eclipse.ui.model.WorkbenchViewerSorter; - -/** - * A wizard for changing the keyword substitution mode of files. - * - * 1. Compute the set of possibly affected resources - * 2. If the affected resources include existing committed files, warn the user - * and provide an option to exclude them from the operation. - * 3. If the affected resources include dirty files, warn the user and provide - * an option to commit them, or to exclude them from the operation. - * 4. Let the user select the desired keyword substitution mode. - * 5. Perform the operation on Finish. - */ -public class SetKeywordSubstitutionWizard extends Wizard { - private SharedFilesPage sharedFilesPage; - private OutgoingChangesPage outgoingChangesPage; - private SelectModePage mainPage; - - private KSubstOption defaultKSubst; - - private IResource[] resources; - private int depth; - private List /* of IFile */ addedFiles; - private List /* of IFile */ changedFiles; - private List /* of IFile */ unchangedFiles; - - private static final int LIST_HEIGHT_HINT = 100; - private static final int LABEL_WIDTH_HINT = 500; - private static final int LABEL_INDENT_WIDTH = 32; - private static final int VERTICAL_SPACE_HEIGHT = 10; - - /** - * Page to select keyword substitution mode. - */ - private static class SelectModePage extends WizardPage { - private KSubstOption ksubst; - private List ksubstOptions; - private Button binaryRadioButton; - private Button textRadioButton; - private Button ksubstRadioButton; - private Combo ksubstOptionCombo; - - public SelectModePage(String pageName, KSubstOption defaultKSubst) { - super(pageName); - this.ksubst = defaultKSubst; - - // sort the options by display text - KSubstOption[] options = KSubstOption.getAllKSubstOptions(); - this.ksubstOptions = new ArrayList(); - for (int i = 0; i < options.length; i++) { - KSubstOption option = options[i]; - if (! (Command.KSUBST_BINARY.equals(option) || - Command.KSUBST_TEXT.equals(option))) { - ksubstOptions.add(option); - } - } - Collections.sort(ksubstOptions, new Comparator() { - public int compare(Object a, Object b) { - String aKey = ((KSubstOption) a).getLongDisplayText(); - String bKey = ((KSubstOption) b).getLongDisplayText(); - return aKey.compareTo(bKey); - } - }); - } - - public void createControl(Composite parent) { - Composite top = createTopControl(parent); - setControl(top); - createWrappingLabel(top, Policy.bind("SetKeywordSubstitution.SelectModePage.contents")); - - Listener selectionListener = new Listener() { - public void handleEvent(Event event) { - updateEnablements(); - } - }; - - // Binary - binaryRadioButton = new Button(top, SWT.RADIO); - binaryRadioButton.setText(Command.KSUBST_BINARY.getLongDisplayText()); - binaryRadioButton.addListener(SWT.Selection, selectionListener); - binaryRadioButton.setSelection(Command.KSUBST_BINARY.equals(ksubst)); - createLabel(top, true, Policy.bind("SetKeywordSubstitution.SelectModePage.binaryLabel")); - - // Text - textRadioButton = new Button(top, SWT.RADIO); - textRadioButton.setText(Command.KSUBST_TEXT.getLongDisplayText()); - textRadioButton.addListener(SWT.Selection, selectionListener); - textRadioButton.setSelection(Command.KSUBST_TEXT.equals(ksubst)); - createLabel(top, true, Policy.bind("SetKeywordSubstitution.SelectModePage.textLabel")); - - // Text with keyword substitution - ksubstRadioButton = new Button(top, SWT.RADIO); - ksubstRadioButton.setText(Policy.bind("SetKeywordSubstitution.SelectModePage.textWithSubstitutions")); - ksubstRadioButton.addListener(SWT.Selection, selectionListener); - ksubstRadioButton.setSelection(false); - createLabel(top, true, Policy.bind("SetKeywordSubstitution.SelectModePage.textWithSubstitutionsLabel")); - - ksubstOptionCombo = new Combo(top, SWT.READ_ONLY); - ksubstOptionCombo.addListener(SWT.Selection, selectionListener); - GridData data = new GridData(GridData.VERTICAL_ALIGN_FILL | GridData.HORIZONTAL_ALIGN_BEGINNING); - data.horizontalIndent = LABEL_INDENT_WIDTH; - ksubstOptionCombo.setLayoutData(data); - - // populate the combo box and select the default option - for (int i = 0; i < ksubstOptions.size(); ++i) { - KSubstOption option = (KSubstOption) ksubstOptions.get(i); - ksubstOptionCombo.add(option.getLongDisplayText()); - if (option.equals(ksubst)) { - ksubstOptionCombo.select(i); - ksubstRadioButton.setSelection(true); - } else if (option.equals(Command.KSUBST_TEXT_EXPAND)) { - // if no expansion mode selected, show KSUBST_TEXT_EXPAND - // since it is the server default - if (! ksubstRadioButton.getSelection()) ksubstOptionCombo.select(i); - } - } - updateEnablements(); - } - - /** - * Enable and disable controls based on the selected radio button. - */ - protected void updateEnablements() { - if (binaryRadioButton.getSelection()) { - ksubstOptionCombo.setEnabled(false); - ksubst = Command.KSUBST_BINARY; - } - if (textRadioButton.getSelection()) { - ksubstOptionCombo.setEnabled(false); - ksubst = Command.KSUBST_TEXT; - } - if (ksubstRadioButton.getSelection()) { - ksubstOptionCombo.setEnabled(true); - ksubst = (KSubstOption) ksubstOptions.get(ksubstOptionCombo.getSelectionIndex()); - } - } - - public KSubstOption getKSubstOption() { - return ksubst; - } - } - - /** - * Page to warn user about possibly unintended changes to some files. - * Superclass of others. - */ - private static abstract class WarningPage extends WizardPage { - private String[] elements; - private ListViewer listViewer; - private String groupTitle; - - public WarningPage(String pageName, String[] elements, String groupTitle) { - super(pageName); - this.elements = elements; - this.groupTitle = groupTitle; - } - - public void createAffectedFilesViewer(Composite parent) { - Composite spacer = new Composite(parent, SWT.NONE); - GridData data = new GridData(); - data.heightHint = VERTICAL_SPACE_HEIGHT; - spacer.setLayoutData(data); - - Group group = new Group(parent, SWT.NONE); - data = new GridData(GridData.FILL_BOTH); - data.heightHint = LIST_HEIGHT_HINT; - group.setLayoutData(data); - group.setLayout(new FillLayout()); - group.setText(groupTitle); - - listViewer = new ListViewer(group, SWT.READ_ONLY | SWT.V_SCROLL | SWT.H_SCROLL); - listViewer.setContentProvider(new IStructuredContentProvider() { - public Object[] getElements(Object inputElement) { - return (Object[]) inputElement; - } - public void dispose() { - } - public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { - } - }); - listViewer.setLabelProvider(new LabelProvider()); - listViewer.setSorter(new WorkbenchViewerSorter()); - listViewer.setInput(elements); - } - } - - /** - * Page to warn user about the side-effects of changing keyword - * substitution on already committed files. - */ - private static class SharedFilesPage extends WarningPage { - private boolean onlyAddedFiles; - private Button onlyAddedFilesButton; - - public SharedFilesPage(String pageName, String[] sharedFiles, boolean onlyAddedFiles) { - super(pageName, sharedFiles, - Policy.bind("SetKeywordSubstitution.SharedFilesPage.committedFiles")); - this.onlyAddedFiles = onlyAddedFiles; - } - - public void createControl(Composite parent) { - Composite top = createTopControl(parent); - setControl(top); - createWrappingLabel(top, Policy.bind("SetKeywordSubstitution.SharedFilesPage.contents")); - - onlyAddedFilesButton = new Button(top, SWT.CHECK); - onlyAddedFilesButton.setText(Policy.bind("SetKeywordSubstitution.SharedFilesPage.onlyAddedFilesButton")); - onlyAddedFilesButton.setSelection(onlyAddedFiles); - onlyAddedFilesButton.addListener(SWT.Selection, new Listener() { - public void handleEvent(Event e) { - onlyAddedFiles = onlyAddedFilesButton.getSelection(); - } - }); - - createAffectedFilesViewer(top); - } - - public boolean getOnlyAddedFiles() { - return onlyAddedFiles; - } - } - - /** - * Page to warn user about uncommitted outgoing changes. - */ - private static class OutgoingChangesPage extends WarningPage { - private boolean onlyCleanFiles; - private Button onlyCleanFilesButton; - - public OutgoingChangesPage(String pageName, String[] changedFiles, boolean onlyCleanFiles) { - super(pageName, changedFiles, - Policy.bind("SetKeywordSubstitution.OutgoingChangesPage.changedFiles")); - this.onlyCleanFiles = onlyCleanFiles; - } - - public void createControl(Composite parent) { - Composite top = createTopControl(parent); - setControl(top); - createWrappingLabel(top, Policy.bind("SetKeywordSubstitution.OutgoingChangesPage.contents")); - - onlyCleanFilesButton = new Button(top, SWT.CHECK); - onlyCleanFilesButton.setText(Policy.bind("SetKeywordSubstitution.OutgoingChangesPage.onlyCleanFilesButton")); - onlyCleanFilesButton.setSelection(onlyCleanFiles); - onlyCleanFilesButton.addListener(SWT.Selection, new Listener() { - public void handleEvent(Event e) { - onlyCleanFiles = onlyCleanFilesButton.getSelection(); - } - }); - - createAffectedFilesViewer(top); - } - - public boolean getOnlyCleanFiles() { - return onlyCleanFiles; - } - } - - /** - * Creates a wizard to set the keyword substitution mode for the specified resources. - * - * @param resources the resources to alter - * @param depth the recursion depth - * @param defaultOption the keyword substitution option to select by default - */ - public SetKeywordSubstitutionWizard(IResource[] resources, int depth, KSubstOption defaultOption) { - super(); - this.resources = resources; - this.depth = depth; - this.defaultKSubst = defaultOption; - setWindowTitle(Policy.bind("SetKeywordSubstitution.title")); - initializeDefaultPageImageDescriptor(); - } - - /** - * Returns the keyword substitution option that was selected at the time - * the Finish button was pressed. - */ - public KSubstOption getKSubstOption() { - return defaultKSubst; - } - - public void addPages() { - // add non-additions warning page - if (changedFiles.size() != 0 || unchangedFiles.size() != 0) { - String pageTitle = Policy.bind("SetKeywordSubstitution.SharedFilesPage.pageTitle"); //$NON-NLS-1$ - String pageDescription = Policy.bind("SetKeywordSubstitution.SharedFilesPage.pageDescription"); //$NON-NLS-1$ - - String[] sharedFiles = new String[changedFiles.size() + unchangedFiles.size()]; - addNamesToArray(sharedFiles, 0, changedFiles); - addNamesToArray(sharedFiles, changedFiles.size(), unchangedFiles); - - sharedFilesPage = new SharedFilesPage(pageTitle, sharedFiles, true); - sharedFilesPage.setDescription(pageDescription); - sharedFilesPage.setTitle(pageTitle); - addPage(sharedFilesPage); - } - - // add uncommitted changes page - if (changedFiles.size() != 0) { - String pageTitle = Policy.bind("SetKeywordSubstitution.OutgoingChangesPage.pageTitle"); //$NON-NLS-1$ - String pageDescription = Policy.bind("SetKeywordSubstitution.OutgoingChangesPage.pageDescription"); //$NON-NLS-1$ - - String[] uncommittedFiles = new String[changedFiles.size()]; - addNamesToArray(uncommittedFiles, 0, changedFiles); - - outgoingChangesPage = new OutgoingChangesPage(pageTitle, uncommittedFiles, true); - outgoingChangesPage.setDescription(pageDescription); - outgoingChangesPage.setTitle(pageTitle); - addPage(outgoingChangesPage); - } - - // add main page - String pageTitle = Policy.bind("SetKeywordSubstitution.SelectModePage.pageTitle"); //$NON-NLS-1$ - String pageDescription = Policy.bind("SetKeywordSubstitution.SelectModePage.pageDescription"); //$NON-NLS-1$ - mainPage = new SelectModePage(pageTitle, defaultKSubst); - mainPage.setDescription(pageDescription); - mainPage.setTitle(pageTitle); - addPage(mainPage); - } - - public IWizardPage getNextPage(IWizardPage page) { - if (page == sharedFilesPage) { - if (! sharedFilesPage.getOnlyAddedFiles() && outgoingChangesPage != null) { - return outgoingChangesPage; - } - return mainPage; - } else if (page == outgoingChangesPage) { - return mainPage; - } - return null; - } - - public IWizardPage getPreviousPage(IWizardPage page) { - if (page == outgoingChangesPage) { - return sharedFilesPage; - } else if (page == mainPage) { - if (sharedFilesPage != null && sharedFilesPage.getOnlyAddedFiles()) { - // we must have skipped over the outgoing changes - return sharedFilesPage; - } else if (outgoingChangesPage != null) { - return outgoingChangesPage; - } - return sharedFilesPage; - } - return null; - } - - /* (Non-javadoc) - * Method declared on IWizard. - */ - public boolean needsProgressMonitor() { - return true; - } - - /* (Non-javadoc) - * Method declared on IWizard. - */ - public boolean needsPreviousAndNextButtons() { - return true; - } - - /* (Non-javadoc) - * Method declared on IWizard. - */ - public boolean performFinish() { - try { - KSubstOption ksubst = mainPage.getKSubstOption(); - defaultKSubst = ksubst; - List affectedResources = addedFiles; - if (sharedFilesPage != null && ! sharedFilesPage.getOnlyAddedFiles()) { - affectedResources.addAll(unchangedFiles); - if (outgoingChangesPage != null && ! outgoingChangesPage.getOnlyCleanFiles()) { - affectedResources.addAll(changedFiles); - } - } - IRunnableWithProgress operation = new SetKeywordSubstitutionOperation( - (IResource[]) affectedResources.toArray(new IResource[affectedResources.size()]), - IResource.DEPTH_ONE, ksubst, getShell()); - getContainer().run(false /*fork*/, true /*cancelable*/, operation); - return true; - } catch (InterruptedException e1) { - return true; - } catch (InvocationTargetException e2) { - if (e2.getTargetException() instanceof CoreException) { - CoreException e = (CoreException) e2.getTargetException(); - ErrorDialog.openError(getShell(), Policy.bind("SetKeywordSubstitution.problemsMessage"), null, e.getStatus()); //$NON-NLS-1$ - return false; - } else { - Throwable target = e2.getTargetException(); - if (target instanceof RuntimeException) { - throw (RuntimeException) target; - } - if (target instanceof Error) { - throw (Error) target; - } - } - return true; - } - } - - /** - * Declares the wizard banner image descriptor - */ - protected void initializeDefaultPageImageDescriptor() { - String iconPath; - if (Display.getCurrent().getIconDepth() > 4) { - iconPath = "icons/full/"; //$NON-NLS-1$ - } else { - iconPath = "icons/basic/"; //$NON-NLS-1$ - } - try { - URL installURL = CVSUIPlugin.getPlugin().getDescriptor().getInstallURL(); - URL url = new URL(installURL, iconPath + "wizban/setksubst_wizban.gif"); //$NON-NLS-1$ - ImageDescriptor desc = ImageDescriptor.createFromURL(url); - //setDefaultPageImageDescriptor(desc); - } catch (MalformedURLException e) { - // Should not happen. Ignore. - } - } - - private static void createLabel(Composite parent, boolean indent, String text) { - Label label = new Label(parent, SWT.LEFT); - label.setText(text); - GridData data = new GridData(GridData.VERTICAL_ALIGN_FILL | GridData.HORIZONTAL_ALIGN_FILL); - if (indent) data.horizontalIndent = LABEL_INDENT_WIDTH; - label.setLayoutData(data); - } - - private static void createWrappingLabel(Composite parent, String text) { - Label label = new Label(parent, SWT.LEFT | SWT.WRAP); - label.setText(text); - GridData data = new GridData(GridData.VERTICAL_ALIGN_FILL | GridData.FILL_HORIZONTAL); - data.widthHint = LABEL_WIDTH_HINT; - label.setLayoutData(data); - } - - private static Composite createTopControl(Composite parent) { - Composite composite = new Composite(parent, SWT.NULL); - GridLayout layout = new GridLayout(); - composite.setLayout(layout); - return composite; - } - - private void addNamesToArray(String[] array, int i, List /* of IFile */ files) { - for (Iterator it = files.iterator(); it.hasNext();) { - IFile file = (IFile) it.next(); - array[i++] = file.getFullPath().toString(); - } - } - - /** - * Populates the addedFiles, changedFiles, and unchangedFiles according to the - * selected resources. Ignores repeated occurrences of resources, unmanaged - * resources, and deleted resources. - */ - public void prepareToOpen() throws TeamException { - addedFiles = new ArrayList(); - changedFiles = new ArrayList(); - unchangedFiles = new ArrayList(); - final Set seen = new HashSet(); - final TeamException[] holder = new TeamException[1]; - try { - for (int i = 0; i < resources.length; i++) { - IResource resource = resources[i]; - resource.accept(new IResourceVisitor() { - public boolean visit(IResource resource) throws CoreException { - try { - if (! seen.contains(resource)) { - seen.add(resource); - if (resource.getType() == IResource.FILE && resource.exists()) { - IFile file = (IFile) resource; - ICVSFile cvsFile = CVSWorkspaceRoot.getCVSFileFor(file); - if (cvsFile.isManaged()) { - ResourceSyncInfo info = cvsFile.getSyncInfo(); - if (info.isAdded()) { - addedFiles.add(file); - } else if (info.isDeleted()) { - // ignore deletions - } else if (cvsFile.isModified()) { - changedFiles.add(file); - } else { - unchangedFiles.add(file); - } - } - } - } - return true; - } catch (TeamException e) { - holder[0] = e; - throw new CoreException(e.getStatus()); - } - } - }, depth, false); - } - } catch (CoreException e) { - throw CVSException.wrapException(e); - } finally { - if (holder[0] != null) throw holder[0]; - } - } -}
\ No newline at end of file diff --git a/tests/org.eclipse.team.tests.cvs.core/src/org/eclipse/team/tests/ccvs/core/provider/CVSProviderTest.java b/tests/org.eclipse.team.tests.cvs.core/src/org/eclipse/team/tests/ccvs/core/provider/CVSProviderTest.java index c4a4dc56c..b02f04b1e 100644 --- a/tests/org.eclipse.team.tests.cvs.core/src/org/eclipse/team/tests/ccvs/core/provider/CVSProviderTest.java +++ b/tests/org.eclipse.team.tests.cvs.core/src/org/eclipse/team/tests/ccvs/core/provider/CVSProviderTest.java @@ -7,6 +7,8 @@ import java.io.BufferedInputStream; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; +import java.util.HashMap; +import java.util.Map; import junit.framework.Test; import junit.framework.TestSuite; @@ -307,8 +309,14 @@ public class CVSProviderTest extends EclipseTest { assertHasKSubstOption(project, "added.xtxt", Command.KSUBST_TEXT_EXPAND); // change keyword substitution - IStatus status = getProvider(project).setKeywordSubstitution(new IResource[] { project }, - IResource.DEPTH_INFINITE, ksubst, null); + Map map = new HashMap(); + map.put(project.getFile("binary.xbin"), ksubst); + map.put(project.getFile("added.xbin"), ksubst); + map.put(project.getFile("text.xtxt"), ksubst); + map.put(project.getFile("folder1/a.xtxt"), ksubst); + map.put(project.getFile("added.xtxt"), ksubst); + + IStatus status = getProvider(project).setKeywordSubstitution(map, null); assertTrue("Status should be ok, was: " + status.toString(), status.isOK()); assertHasKSubstOption(project, "binary.xbin", ksubst); assertHasKSubstOption(project, "text.xtxt", ksubst); |