diff options
11 files changed, 830 insertions, 49 deletions
diff --git a/bundles/org.eclipse.team.cvs.ui/plugin.properties b/bundles/org.eclipse.team.cvs.ui/plugin.properties index c5da82b40..9b754a6dc 100644 --- a/bundles/org.eclipse.team.cvs.ui/plugin.properties +++ b/bundles/org.eclipse.team.cvs.ui/plugin.properties @@ -60,6 +60,9 @@ ReplaceWithTagAction.tooltip=Replace with Version on CVS Server TagAction.label=&Tag... TagAction.tooltip=Tag +SetKeywordSubstitutionAction.label=&Set Keyword Substitution... +SetKeywordSubstitutionAction.tooltip=Set Keyword Substitution for Files on CVS Server + DefineBranchAction.label=&Define Branch Tag... DefineBranchAction.tooltip=Define a Branch Tag that Exists on CVS Server diff --git a/bundles/org.eclipse.team.cvs.ui/plugin.xml b/bundles/org.eclipse.team.cvs.ui/plugin.xml index afbae06fb..98428ebce 100644 --- a/bundles/org.eclipse.team.cvs.ui/plugin.xml +++ b/bundles/org.eclipse.team.cvs.ui/plugin.xml @@ -58,6 +58,12 @@ objectClass="org.eclipse.core.resources.IResource" adaptable="true"> <filter name="projectNature" value="org.eclipse.team.cvs.core.cvsnature"/> <action + id="org.eclipse.team.ccvs.ui.setKeywordSubstitution" + label="%SetKeywordSubstitutionAction.label" + tooltip="%SetKeywordSubstitutionAction.tooltip" + menubarPath="team.main/group2" + class="org.eclipse.team.internal.ccvs.ui.actions.SetKeywordSubstitutionAction"/> + <action id="org.eclipse.team.ccvs.ui.tag" label="%TagAction.label" tooltip="%TagAction.tooltip" diff --git a/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/CVSDecorationRunnable.java b/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/CVSDecorationRunnable.java index 3ec5c60c7..07d842ee0 100644 --- a/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/CVSDecorationRunnable.java +++ b/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/CVSDecorationRunnable.java @@ -31,6 +31,7 @@ import org.eclipse.team.ccvs.core.ICVSResource; import org.eclipse.team.core.ITeamProvider; import org.eclipse.team.core.TeamPlugin; import org.eclipse.team.internal.ccvs.core.CVSException; +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.FolderSyncInfo; import org.eclipse.team.internal.ccvs.core.syncinfo.ResourceSyncInfo; @@ -172,13 +173,17 @@ public class CVSDecorationRunnable implements Runnable { } else { bindings.put(CVSDecoratorConfiguration.FILE_REVISION, fileInfo.getRevision()); } - bindings.put(CVSDecoratorConfiguration.FILE_KEYWORD, CVSDecorator.getFileTypeString(fileInfo.getName(), fileInfo.getKeywordMode())); + KSubstOption option = fileInfo.getKeywordMode() != null ? + KSubstOption.fromMode(fileInfo.getKeywordMode()) : + KSubstOption.fromPattern(fileInfo.getName()); + bindings.put(CVSDecoratorConfiguration.FILE_KEYWORD, option.getShortDisplayText()); if (tag != null && (tag.getType() != CVSTag.HEAD)) { bindings.put(CVSDecoratorConfiguration.RESOURCE_TAG, tag.getName()); } } else { // only show the type that cvs will use when comitting the file - bindings.put(CVSDecoratorConfiguration.FILE_KEYWORD, CVSDecorator.getFileTypeString(file.getName(), null)); + KSubstOption option = KSubstOption.fromPattern(file.getName()); + bindings.put(CVSDecoratorConfiguration.FILE_KEYWORD, option.getShortDisplayText()); } break; } diff --git a/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/CVSDecorator.java b/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/CVSDecorator.java index d44eb752f..33d9a66d7 100644 --- a/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/CVSDecorator.java +++ b/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/CVSDecorator.java @@ -9,12 +9,10 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; -import java.util.HashSet; import java.util.Hashtable; import java.util.Iterator; import java.util.List; import java.util.Map; -import java.util.Set; import org.eclipse.core.resources.IResource; import org.eclipse.core.resources.IResourceChangeEvent; @@ -34,7 +32,8 @@ import org.eclipse.team.core.IResourceStateChangeListener; import org.eclipse.team.core.ITeamProvider; import org.eclipse.team.core.TeamPlugin; import org.eclipse.team.internal.ccvs.core.CVSProvider; -import org.eclipse.team.internal.ccvs.core.resources.CVSWorkspaceRoot; +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.util.Assert; import org.eclipse.team.internal.ccvs.core.util.ResourceDeltaVisitor; @@ -353,28 +352,6 @@ public class CVSDecorator extends LabelProvider implements ILabelDecorator, IRes } } - public static String getFileTypeString(String name, String keyword) { - StringBuffer buffer = new StringBuffer(); - boolean isBinary = false; - if(keyword!=null) { - if (keyword.equals("-kb")) { //$NON-NLS-1$ - isBinary = true; - } - } else { - isBinary = !CVSProvider.isText(name); - } - - if(isBinary) { - buffer.append(Policy.bind("CVSFilePropertiesPage.binary")); - } else { - buffer.append(Policy.bind("CVSFilePropertiesPage.text")); - if(keyword!=null && !keyword.equals("-ko") && !"".equals(keyword)) { //$NON-NLS-1$ //$NON-NLS-2$ - buffer.append(" " + keyword); //$NON-NLS-1$ - } - } - return buffer.toString(); - } - /* * @see IBaseLabelProvider#dispose() */ diff --git a/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/CVSDecoratorPreferencesPage.java b/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/CVSDecoratorPreferencesPage.java index 4bfe11aea..51da566bf 100644 --- a/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/CVSDecoratorPreferencesPage.java +++ b/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/CVSDecoratorPreferencesPage.java @@ -32,6 +32,7 @@ import org.eclipse.swt.widgets.Listener; import org.eclipse.swt.widgets.Text; import org.eclipse.team.ccvs.core.ICVSRepositoryLocation; import org.eclipse.team.internal.ccvs.core.CVSException; +import org.eclipse.team.internal.ccvs.core.client.Command.KSubstOption; import org.eclipse.team.internal.ccvs.core.connection.CVSRepositoryLocation; import org.eclipse.ui.IWorkbench; import org.eclipse.ui.IWorkbenchPreferencePage; @@ -104,7 +105,8 @@ public class CVSDecoratorPreferencesPage extends PreferencePage implements IWork try { ICVSRepositoryLocation location = CVSRepositoryLocation.fromString(":pserver:username@host.acme.org:/home/cvsroot"); //$NON-NLS-1$ bindings.put(CVSDecoratorConfiguration.RESOURCE_TAG, "v2_0"); //$NON-NLS-1$ - bindings.put(CVSDecoratorConfiguration.FILE_KEYWORD, CVSDecorator.getFileTypeString("file.txt",null)); //$NON-NLS-1$ + bindings.put(CVSDecoratorConfiguration.FILE_KEYWORD, + KSubstOption.fromPattern("file.txt").getShortDisplayText()); //$NON-NLS-1$ bindings.put(CVSDecoratorConfiguration.FILE_REVISION, "1.34"); //$NON-NLS-1$ bindings.put(CVSDecoratorConfiguration.DIRTY_FLAG, dirtyFlag.getText()); bindings.put(CVSDecoratorConfiguration.ADDED_FLAG, addedFlag.getText()); diff --git a/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/CVSFilePropertiesPage.java b/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/CVSFilePropertiesPage.java index 300dc96d9..66018f2d6 100644 --- a/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/CVSFilePropertiesPage.java +++ b/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/CVSFilePropertiesPage.java @@ -16,6 +16,7 @@ import org.eclipse.swt.widgets.Label; import org.eclipse.team.ccvs.core.CVSTag; import org.eclipse.team.ccvs.core.ICVSFile; import org.eclipse.team.core.TeamException; +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.ui.dialogs.PropertyPage; @@ -62,16 +63,7 @@ public class CVSFilePropertiesPage extends PropertyPage { // Keyword Mode createLabel(composite, Policy.bind("CVSFilePropertiesPage.keywordMode")); - String keywordMode = syncInfo.getKeywordMode(); - if (keywordMode.equals("-kb")) { - createLabel(composite, Policy.bind("CVSFilePropertiesPage.binary")); - } else if (keywordMode.equals("-ko")) { - createLabel(composite, Policy.bind("CVSFilePropertiesPage.textNoKeyword")); - } else if (keywordMode.equals("")) { - createLabel(composite, Policy.bind("CVSFilePropertiesPage.text")); - } else { - createLabel(composite, keywordMode); - } + createLabel(composite, KSubstOption.fromMode(syncInfo.getKeywordMode()).getLongDisplayText()); // Tag createLabel(composite, Policy.bind("CVSFilePropertiesPage.tag")); 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 new file mode 100644 index 000000000..1fb82e987 --- /dev/null +++ b/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/actions/SetKeywordSubstitutionAction.java @@ -0,0 +1,70 @@ +package org.eclipse.team.internal.ccvs.ui.actions; + +/* + * (c) Copyright IBM Corp. 2000, 2001. + * All Rights Reserved. + */ + +import org.eclipse.core.resources.IResource; +import org.eclipse.jface.action.IAction; +import org.eclipse.jface.wizard.WizardDialog; +import org.eclipse.team.ccvs.core.CVSTeamProvider; +import org.eclipse.team.ccvs.core.ICVSResource; +import org.eclipse.team.core.ITeamManager; +import org.eclipse.team.core.ITeamProvider; +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.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; + + /* + * @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, "stuff", ""); + } + } + + /* + * @see TeamAction#isEnabled() + */ + protected boolean isEnabled() throws TeamException { + IResource[] resources = getSelectedResources(); + if (resources.length == 0) return false; + ITeamManager manager = TeamPlugin.getManager(); + for (int i = 0; i < resources.length; i++) { + IResource resource = resources[i]; + // resource must be local + if (! resource.isAccessible()) return false; + // provider must be CVS + ITeamProvider provider = manager.getProvider(resource.getProject()); + if (provider == null) return false; + if (! (provider instanceof CVSTeamProvider)) return false; + // resource must either be a project, or it must be managed + if (resource.getType() != IResource.PROJECT) { + ICVSResource cvsResource = CVSWorkspaceRoot.getCVSResourceFor(resource); + if (! cvsResource.isManaged()) return false; + } + } + return true; + } +} 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 e2050817b..2ee8fccce 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 @@ -91,9 +91,6 @@ CVSFilePropertiesPage.baseTimestamp=Base Timestamp: CVSFilePropertiesPage.dirty=Dirty: CVSFilePropertiesPage.modified=Modified: CVSFilePropertiesPage.keywordMode=Keyword Mode: -CVSFilePropertiesPage.binary=Binary -CVSFilePropertiesPage.textNoKeyword=Text with no keyword expansion -CVSFilePropertiesPage.text=Text CVSFilePropertiesPage.tag=Tag: CVSFilePropertiesPage.none=(none) CVSFilePropertiesPage.version={0} (Version) @@ -323,6 +320,54 @@ 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=\ + 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=\ + Binary files are stored in the repository without alteration.\n\ + CVS does not directly support conflict resolution for binary files. +SetKeywordSubstitution.SelectModePage.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=\ + 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. + 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/sync/CVSCatchupReleaseViewer.java b/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/sync/CVSCatchupReleaseViewer.java index b204b7b67..01be6ee7c 100644 --- a/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/sync/CVSCatchupReleaseViewer.java +++ b/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/sync/CVSCatchupReleaseViewer.java @@ -30,9 +30,9 @@ import org.eclipse.team.core.TeamException; import org.eclipse.team.core.sync.IRemoteResource; import org.eclipse.team.core.sync.IRemoteSyncElement; import org.eclipse.team.internal.ccvs.core.CVSException; +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.CVSDecorator; import org.eclipse.team.internal.ccvs.ui.CVSUIPlugin; import org.eclipse.team.internal.ccvs.ui.HistoryView; import org.eclipse.team.internal.ccvs.ui.ICVSUIConstants; @@ -172,13 +172,10 @@ public class CVSCatchupReleaseViewer extends CatchupReleaseViewer { try { ICVSFile cvsFile = CVSWorkspaceRoot.getCVSFileFor((IFile) resource); ResourceSyncInfo info = cvsFile.getSyncInfo(); - String kw; - if (info!=null) { - kw = CVSDecorator.getFileTypeString(resource.getName(), info.getKeywordMode()); - } else { - kw = CVSDecorator.getFileTypeString(resource.getName(), null); - } - postfix.append("(" + kw + ")"); + KSubstOption option = info != null && info.getKeywordMode() != null ? + KSubstOption.fromMode(info.getKeywordMode()) : + KSubstOption.fromPattern(resource.getName()); + postfix.append("(" + option.getShortDisplayText() + ")"); } catch(CVSException e) { ErrorDialog.openError(getControl().getShell(), null, null, e.getStatus()); } 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 new file mode 100644 index 000000000..f54e53c6f --- /dev/null +++ b/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/wizards/SetKeywordSubstitutionOperation.java @@ -0,0 +1,130 @@ +package org.eclipse.team.internal.ccvs.ui.wizards; + +/* + * (c) Copyright IBM Corp. 2000, 2001. + * 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.ITeamProvider; +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++) { + ITeamProvider provider = TeamPlugin.getManager().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 new file mode 100644 index 000000000..0a606664d --- /dev/null +++ b/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/wizards/SetKeywordSubstitutionWizard.java @@ -0,0 +1,554 @@ +package org.eclipse.team.internal.ccvs.ui.wizards; + +/* + * (c) Copyright IBM Corp. 2000, 2001. + * 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 |