Skip to main content
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichael Valenta2002-11-19 21:55:31 +0000
committerMichael Valenta2002-11-19 21:55:31 +0000
commit4652f36bfd9333df028190408aaaf1d7766dba3a (patch)
treeaddb2df7d16607d4f5a757b4813fb32c0a537e18
parent523ada77134b2a1a874ce0b36a7f5e3cdaa34269 (diff)
downloadeclipse.platform.team-4652f36bfd9333df028190408aaaf1d7766dba3a.tar.gz
eclipse.platform.team-4652f36bfd9333df028190408aaaf1d7766dba3a.tar.xz
eclipse.platform.team-4652f36bfd9333df028190408aaaf1d7766dba3a.zip
21577: [CVS Watch/Edit] Readonly/Edit/Unedit Support
-rw-r--r--bundles/org.eclipse.team.cvs.core/plugin.xml1
-rw-r--r--bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/CVSProviderPlugin.java63
-rw-r--r--bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/CVSTeamProvider.java84
-rw-r--r--bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/ICVSFile.java14
-rw-r--r--bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/ICVSFileModificationValidator.java30
-rw-r--r--bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/client/CheckedInHandler.java2
-rw-r--r--bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/client/Command.java26
-rw-r--r--bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/client/Session.java28
-rw-r--r--bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/client/listeners/LogListener.java2
-rw-r--r--bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/messages.properties2
-rw-r--r--bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/EclipseFile.java63
-rw-r--r--bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/EclipseFolder.java22
-rw-r--r--bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/EclipseSynchronizer.java118
-rw-r--r--bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/RemoteFile.java10
-rw-r--r--bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/syncinfo/BaserevInfo.java83
-rw-r--r--bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/util/MoveDeleteHook.java134
-rw-r--r--bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/util/SyncFileWriter.java121
-rw-r--r--bundles/org.eclipse.team.cvs.ui/plugin.xml12
-rw-r--r--bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/CVSUIPlugin.java59
-rw-r--r--bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/FileModificationValidator.java185
-rw-r--r--bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/WatchEditPreferencePage.java21
-rw-r--r--tests/org.eclipse.team.tests.cvs.core/src/org/eclipse/team/tests/ccvs/core/provider/ResourceDeltaTest.java4
22 files changed, 882 insertions, 202 deletions
diff --git a/bundles/org.eclipse.team.cvs.core/plugin.xml b/bundles/org.eclipse.team.cvs.core/plugin.xml
index 829d78d59..3024a3ca2 100644
--- a/bundles/org.eclipse.team.cvs.core/plugin.xml
+++ b/bundles/org.eclipse.team.cvs.core/plugin.xml
@@ -21,6 +21,7 @@
<!-- *************** Extension Points **************** -->
<extension-point name="Authenticator" id="authenticator"/>
<extension-point name="ConnectionMethods" id="connectionmethods"/>
+ <extension-point name="FileModificationValidator" id="filemodificationvalidator"/>
<!-- *************** Connection Methods **************** -->
<extension id="pserver" point="org.eclipse.team.cvs.core.connectionmethods">
diff --git a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/CVSProviderPlugin.java b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/CVSProviderPlugin.java
index eaf84431f..e94d678b4 100644
--- a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/CVSProviderPlugin.java
+++ b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/CVSProviderPlugin.java
@@ -29,7 +29,6 @@ import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IResourceChangeEvent;
import org.eclipse.core.resources.IResourceChangeListener;
-import org.eclipse.core.resources.IResourceDelta;
import org.eclipse.core.resources.IWorkspace;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
@@ -39,6 +38,7 @@ import org.eclipse.core.runtime.ISafeRunnable;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Platform;
import org.eclipse.core.runtime.Plugin;
+import org.eclipse.core.runtime.Preferences;
import org.eclipse.core.runtime.Status;
import org.eclipse.team.core.RepositoryProvider;
import org.eclipse.team.core.Team;
@@ -56,6 +56,9 @@ import org.eclipse.team.internal.ccvs.core.util.SyncFileChangeListener;
import org.eclipse.team.internal.ccvs.core.util.Util;
public class CVSProviderPlugin extends Plugin {
+
+ // preference names
+ public static final String READ_ONLY = "cvs.read.only"; //$NON-NLS-1$
// external command to run for ext connection method
public static final String DEFAULT_CVS_RSH = "ssh"; //$NON-NLS-1$
@@ -78,6 +81,7 @@ public class CVSProviderPlugin extends Plugin {
public static final String ID = "org.eclipse.team.cvs.core"; //$NON-NLS-1$
public static final String PT_AUTHENTICATOR = "authenticator"; //$NON-NLS-1$
public static final String PT_CONNECTIONMETHODS = "connectionmethods"; //$NON-NLS-1$
+ public static final String PT_FILE_MODIFICATION_VALIDATOR = "filemodificationvalidator"; //$NON-NLS-1$
// Directory to cache file contents
private static final String CACHE_DIRECTORY = ".cache"; //$NON-NLS-1$
@@ -97,7 +101,6 @@ public class CVSProviderPlugin extends Plugin {
private String cvsRshParameters = DEFAULT_CVS_RSH_PARAMETERS;
private String cvsServer = DEFAULT_CVS_SERVER;
private IConsoleListener consoleListener;
- private boolean watchEditEnabled = true;
private boolean determineVersionEnabled = true;
private static CVSProviderPlugin instance;
@@ -281,6 +284,7 @@ public class CVSProviderPlugin extends Plugin {
// save the state which includes the known repositories
saveState();
+ savePluginPreferences();
// remove listeners
IWorkspace workspace = ResourcesPlugin.getWorkspace();
@@ -291,49 +295,12 @@ public class CVSProviderPlugin extends Plugin {
deleteCacheDirectory();
}
- /*
- * Add a resource change listener to the workspace in order to respond to
- * resource deletions and moves and to ensure or project desription file is up to date.
+ /**
+ * @see org.eclipse.core.runtime.Plugin#initializeDefaultPluginPreferences()
*/
- private void initializeChangeListener() {
-
- // Build a change listener for changes to thr project meta-information
- IResourceChangeListener projectChangeListener = new IResourceChangeListener() {
- public void resourceChanged(IResourceChangeEvent event) {
- try {
- IResourceDelta root = event.getDelta();
- IResourceDelta[] projectDeltas = root.getAffectedChildren(IResourceDelta.CHANGED);
- for (int i = 0; i < projectDeltas.length; i++) {
- IResourceDelta delta = projectDeltas[i];
- IResource resource = delta.getResource();
- if (resource.getType() == IResource.PROJECT) {
- IProject project = (IProject)resource;
- // Get the team provider for the project and
- RepositoryProvider provider = RepositoryProvider.getProvider(project, getTypeId());
- if(provider==null) continue;
- /* Check if the project description changed. */
- if ((delta.getFlags() & IResourceDelta.DESCRIPTION) != 0) {
- /* The project description changed. Write the file. */
- ProjectDescriptionManager.writeProjectDescriptionIfNecessary((CVSTeamProvider)provider, project, Policy.monitorFor(null));
- }
-
- /* Check if the .vcm_meta file for the project is in the delta. */
- IResourceDelta[] children = delta.getAffectedChildren(IResourceDelta.REMOVED);
- for (int j = 0; j < children.length; j++) {
- IResourceDelta childDelta = children[j];
- IResource childResource = childDelta.getResource();
- if (ProjectDescriptionManager.isProjectDescription(childResource)) {
- ProjectDescriptionManager.writeProjectDescriptionIfNecessary((CVSTeamProvider)provider, project, Policy.monitorFor(null));
- }
- }
- }
- }
- } catch (CVSException ex) {
- Util.logError(Policy.bind("CVSProviderPlugin.cannotUpdateDescription"), ex); //$NON-NLS-1$
- }
- }
- };
- ResourcesPlugin.getWorkspace().addResourceChangeListener(projectChangeListener, IResourceChangeEvent.POST_AUTO_BUILD);
+ protected void initializeDefaultPluginPreferences(){
+ Preferences store = getPluginPreferences();
+ store.setDefault(READ_ONLY, false);
}
/**
@@ -424,14 +391,6 @@ public class CVSProviderPlugin extends Plugin {
promptOnFolderDelete = prompt;
}
- public boolean isWatchEditEnabled() {
- return watchEditEnabled;
- }
-
- public void setWatchEditEnabled(boolean enabled) {
- watchEditEnabled = enabled;
- }
-
private static List listeners = new ArrayList();
/*
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 25fb7764d..e4d59de2e 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
@@ -36,10 +36,13 @@ import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IResourceVisitor;
import org.eclipse.core.resources.team.IMoveDeleteHook;
import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.IExtension;
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.Platform;
import org.eclipse.core.runtime.QualifiedName;
import org.eclipse.core.runtime.Status;
import org.eclipse.team.core.RepositoryProvider;
@@ -100,6 +103,7 @@ import org.eclipse.team.internal.core.streams.LFtoCRLFInputStream;
* have them appear in Eclipse. This may be changed in the future.
*/
public class CVSTeamProvider extends RepositoryProvider {
+
private static final boolean IS_CRLF_PLATFORM = Arrays.equals(
System.getProperty("line.separator").getBytes(), new byte[] { '\r', '\n' }); //$NON-NLS-1$
@@ -110,11 +114,31 @@ public class CVSTeamProvider extends RepositoryProvider {
private String comment = ""; //$NON-NLS-1$
private static MoveDeleteHook moveDeleteHook= new MoveDeleteHook();
+ private static IFileModificationValidator fileModificationValidator;
// property used to indicate whether new directories should be discovered for the project
private final static QualifiedName FETCH_ABSENT_DIRECTORIES_PROP_KEY =
new QualifiedName("org.eclipse.team.cvs.core", "fetch_absent_directories"); //$NON-NLS-1$ //$NON-NLS-2$
-
+
+ private static IFileModificationValidator getPluggedInValidator() {
+ IExtension[] extensions = Platform.getPluginRegistry().getExtensionPoint(CVSProviderPlugin.ID, CVSProviderPlugin.PT_FILE_MODIFICATION_VALIDATOR).getExtensions();
+ if (extensions.length == 0)
+ return null;
+ IExtension extension = extensions[0];
+ IConfigurationElement[] configs = extension.getConfigurationElements();
+ if (configs.length == 0) {
+ CVSProviderPlugin.log(new Status(IStatus.ERROR, CVSProviderPlugin.ID, 0, Policy.bind("CVSAdapter.noConfigurationElement", new Object[] {extension.getUniqueIdentifier()}), null));//$NON-NLS-1$
+ return null;
+ }
+ try {
+ IConfigurationElement config = configs[0];
+ return (IFileModificationValidator) config.createExecutableExtension("run");//$NON-NLS-1$
+ } catch (CoreException ex) {
+ CVSProviderPlugin.log(new Status(IStatus.ERROR, CVSProviderPlugin.ID, 0, Policy.bind("CVSAdapter.unableToInstantiate", new Object[] {extension.getUniqueIdentifier()}), ex));//$NON-NLS-1$
+ return null;
+ }
+ }
+
/**
* No-arg Constructor for IProjectNature conformance
*/
@@ -1098,54 +1122,15 @@ public class CVSTeamProvider extends RepositoryProvider {
* @see org.eclipse.team.core.RepositoryProvider#getFileModificationValidator()
*/
public IFileModificationValidator getFileModificationValidator() {
- if (isWatchEditEnabled()) {
- return new IFileModificationValidator() {
- public IStatus validateEdit(IFile[] files, Object context) {
- try {
- // only do this for files that are read-only
- List readOnlys = new ArrayList();
- for (int i = 0; i < files.length; i++) {
- IFile iFile = files[i];
- if (iFile.isReadOnly())
- readOnlys.add(iFile);
- }
- if (readOnlys.isEmpty()) return OK;
-
- // XXX We should try to create a PM using the provided context
- edit((IFile[]) readOnlys.toArray(new IFile[readOnlys.size()]),
- false /* recurse */, true /* notify server */,
- ICVSFile.NO_NOTIFICATION, null);
- } catch (TeamException e) {
- return e.getStatus();
- }
- return OK;
- }
- public IStatus validateSave(IFile file) {
- // Ignore files that are not read-only
- if (!file.isReadOnly()) return OK;
- try {
- edit(new IResource[] {file},
- false /* recurse */, true /* notify server */,
- ICVSFile.NO_NOTIFICATION, null);
- } catch (TeamException e) {
- return e.getStatus();
- }
- return OK;
- }
- };
- } else {
- return super.getFileModificationValidator();
+ if (CVSTeamProvider.fileModificationValidator == null) {
+ CVSTeamProvider.fileModificationValidator = CVSTeamProvider.getPluggedInValidator();
+ if (CVSTeamProvider.fileModificationValidator == null) {
+ CVSTeamProvider.fileModificationValidator =super.getFileModificationValidator();
+ }
}
+ return CVSTeamProvider.fileModificationValidator;
}
-
- /**
- * Answer true if watch/edit support is enabled for this provider.
- * @return boolean
- */
- public boolean isWatchEditEnabled() {
- return CVSProviderPlugin.getPlugin().isWatchEditEnabled();
- }
-
+
/**
* Checkout (cvs edit) the provided resources so they can be modified locally and committed.
* This will make any read-only resources in the list writable and will notify the server
@@ -1176,7 +1161,7 @@ public class CVSTeamProvider extends RepositoryProvider {
notifyEditUnedit(resources, recurse, notifyServer, new ICVSResourceVisitor() {
public void visitFile(ICVSFile file) throws CVSException {
if (file.isReadOnly())
- file.edit(notification);
+ file.edit(notification, Policy.monitorFor(null));
}
public void visitFolder(ICVSFolder folder) throws CVSException {
// nothing needs to be done here as the recurse will handle the traversal
@@ -1210,7 +1195,7 @@ public class CVSTeamProvider extends RepositoryProvider {
notifyEditUnedit(resources, recurse, notifyServer, new ICVSResourceVisitor() {
public void visitFile(ICVSFile file) throws CVSException {
if (!file.isReadOnly())
- file.unedit();
+ file.unedit(Policy.monitorFor(null));
}
public void visitFolder(ICVSFolder folder) throws CVSException {
// nothing needs to be done here as the recurse will handle the traversal
@@ -1276,4 +1261,5 @@ public class CVSTeamProvider extends RepositoryProvider {
throw new CVSException(new CVSStatus(IStatus.ERROR, Policy.bind("CVSTeamProvider.errorSettingFetchProperty", project.getName()), e)); //$NON-NLS-1$
}
}
+
} \ No newline at end of file
diff --git a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/ICVSFile.java b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/ICVSFile.java
index 6d9800ddb..0348c5c4a 100644
--- a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/ICVSFile.java
+++ b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/ICVSFile.java
@@ -16,6 +16,7 @@ import java.util.Date;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.team.core.TeamException;
import org.eclipse.team.internal.ccvs.core.syncinfo.NotifyInfo;
+import org.eclipse.team.internal.ccvs.core.syncinfo.ResourceSyncInfo;
/**
* The CVS analog of a file. CVS files have access to synchronization information
@@ -124,7 +125,7 @@ public interface ICVSFile extends ICVSResource {
* @param notifications the set of operations for which the local user would like notification
* while the local file is being edited.
*/
- public void edit(int notifications) throws CVSException;
+ public void edit(int notifications, IProgressMonitor monitor) throws CVSException;
/**
* Undo a checkout of the file (analogous to "cvs unedit").
@@ -132,8 +133,15 @@ public interface ICVSFile extends ICVSResource {
* a notification message that will be sent to the server on the next connection
* If <code>isCheckedOut()</code> returns <code>false</code> then nothing is done.
*/
- public void unedit() throws CVSException;
-
+ public void unedit(IProgressMonitor monitor) throws CVSException;
+
+ /**
+ * Update the file's sync info to the given value and reset the read-only
+ * status of the file if a previous revision of the file was stored in the
+ * CVS/BASE directory.
+ */
+ public void committed(ResourceSyncInfo info) throws CVSException;
+
/**
* Answer any pending notification information associated with the receiver.
*
diff --git a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/ICVSFileModificationValidator.java b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/ICVSFileModificationValidator.java
new file mode 100644
index 000000000..59fb2be25
--- /dev/null
+++ b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/ICVSFileModificationValidator.java
@@ -0,0 +1,30 @@
+/*******************************************************************************
+ * Copyright (c) 2002 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Common Public License v0.5
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v05.html
+ *
+ * Contributors:
+ * IBM - Initial implementation
+ ******************************************************************************/
+package org.eclipse.team.internal.ccvs.core;
+
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.resources.IFileModificationValidator;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+
+/**
+ * @author Administrator
+ *
+ * To change this generated comment edit the template variable "typecomment":
+ * Window>Preferences>Java>Templates.
+ * To enable and disable the creation of type comments go to
+ * Window>Preferences>Java>Code Generation.
+ */
+public interface ICVSFileModificationValidator extends IFileModificationValidator {
+
+ public IStatus validateMoveDelete(IFile[] files, IProgressMonitor monitor);
+
+}
diff --git a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/client/CheckedInHandler.java b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/client/CheckedInHandler.java
index 8217bf20a..1b7845b20 100644
--- a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/client/CheckedInHandler.java
+++ b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/client/CheckedInHandler.java
@@ -57,7 +57,7 @@ class CheckedInHandler extends ResponseHandler {
newInfo = new ResourceSyncInfo(entryLine, fileInfo.getPermissions(), mFile.getTimeStamp());
}
- mFile.setSyncInfo(newInfo);
+ mFile.committed(newInfo);
}
}
diff --git a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/client/Command.java b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/client/Command.java
index 02256bc1c..1eddf23b0 100644
--- a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/client/Command.java
+++ b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/client/Command.java
@@ -509,6 +509,19 @@ public abstract class Command extends Request {
public void send(Session session) throws CVSException {
session.sendGlobalOption(option);
}
+ /**
+ * Add the given global option to the end of the provided list
+ *
+ * @param newOption
+ * @param options
+ * @return GlobalOption[]
+ */
+ protected GlobalOption[] addToEnd(GlobalOption[] options) {
+ GlobalOption[] globalOptions = new GlobalOption[options.length + 1];
+ System.arraycopy(options, 0, globalOptions, 0, options.length);
+ globalOptions[globalOptions.length - 1] = this;
+ return globalOptions;
+ }
}
/**
* Option subtype for global quietness options.
@@ -665,6 +678,8 @@ public abstract class Command extends Request {
/**
* Allows commands to filter the set of global options to be sent.
+ * This method invokes the method of the same name on the session
+ * itself in order to get any session wide or globally set options.
* Subclasses that override this method should call the superclass.
*
* @param session the session
@@ -672,16 +687,7 @@ public abstract class Command extends Request {
* @return the filtered global options
*/
protected GlobalOption[] filterGlobalOptions(Session session, GlobalOption[] globalOptions) {
- if (! DO_NOT_CHANGE.isElementOf(globalOptions)) {
- QuietOption quietOption = CVSProviderPlugin.getPlugin().getQuietness();
- if (quietOption != null) {
- GlobalOption[] oldOptions = globalOptions;
- globalOptions = new GlobalOption[oldOptions.length + 1];
- System.arraycopy(oldOptions, 0, globalOptions, 1, oldOptions.length);
- globalOptions[0] = quietOption;
- }
- }
- return globalOptions;
+ return session.filterGlobalOptions(globalOptions);
}
/**
diff --git a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/client/Session.java b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/client/Session.java
index 605ce45a3..a22d00bd7 100644
--- a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/client/Session.java
+++ b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/client/Session.java
@@ -48,6 +48,8 @@ import org.eclipse.team.internal.ccvs.core.ICVSResource;
import org.eclipse.team.internal.ccvs.core.ICVSResourceVisitor;
import org.eclipse.team.internal.ccvs.core.ICVSRunnable;
import org.eclipse.team.internal.ccvs.core.Policy;
+import org.eclipse.team.internal.ccvs.core.client.Command.GlobalOption;
+import org.eclipse.team.internal.ccvs.core.client.Command.QuietOption;
import org.eclipse.team.internal.ccvs.core.connection.CVSRepositoryLocation;
import org.eclipse.team.internal.ccvs.core.connection.Connection;
import org.eclipse.team.internal.ccvs.core.syncinfo.NotifyInfo;
@@ -1094,4 +1096,30 @@ public class Session {
public void setTextTransferOverride(Collection textTransferOverrideSet) {
this.textTransferOverrideSet = textTransferOverrideSet;
}
+
+ /**
+ * Filter the provided global options using parameters set on this session
+ * or globally. The session may add global options that correspond to user
+ * preferences or remove those that contradict requirements for this
+ * particular session.
+ *
+ * @param globalOptions the global options, read-only
+ * @return the filtered global options
+ */
+ protected GlobalOption[] filterGlobalOptions(GlobalOption[] globalOptions) {
+ if (! Command.DO_NOT_CHANGE.isElementOf(globalOptions)) {
+ // Get the user preference for verbosity
+ QuietOption quietOption = CVSProviderPlugin.getPlugin().getQuietness();
+ if (quietOption != null) {
+ globalOptions = quietOption.addToEnd(globalOptions);
+ }
+ // Get the user preference for read-only
+ if (CVSProviderPlugin.getPlugin().getPluginPreferences().getBoolean(CVSProviderPlugin.READ_ONLY)) {
+ if (!Command.MAKE_READ_ONLY.isElementOf(globalOptions)) {
+ globalOptions = Command.MAKE_READ_ONLY.addToEnd(globalOptions);
+ }
+ }
+ }
+ return globalOptions;
+ }
}
diff --git a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/client/listeners/LogListener.java b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/client/listeners/LogListener.java
index 06556b9e6..7cb07e209 100644
--- a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/client/listeners/LogListener.java
+++ b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/client/listeners/LogListener.java
@@ -36,7 +36,7 @@ public class LogListener implements ICommandOutputListener {
private String fileState; //
private StringBuffer comment; // comment
- private static final String NOTHING_KNOWN_ABOUT = "nothing known about ";
+ private static final String NOTHING_KNOWN_ABOUT = "nothing known about "; //$NON-NLS-1$
public LogListener(RemoteFile file, List entries) {
this.file = file;
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 8e99de7ee..0309da753 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
@@ -231,6 +231,8 @@ SyncFileUtil_Error_reloading_sync_information_58=Error reloading sync informatio
SyncFileUtil_Error_writing_to_.cvsignore_61=Error writing to .cvsignore
SyncFileUtil_Cannot_close_.cvsignore_62=Cannot close .cvsignore
SyncFileWriter.cvsFolderNotHidden=Folder ''{0}'' was not previously hidden but has now been marked as hidden. If it still appears in a view, close that view and reopen it.
+SyncFileWriter.baseNotAvailable=Could not restore the base contents of ''{0}'' from the local cache.
+BaseRevInfo.malformedEntryLine=Malformed entry line ''{0}'' for base revision information file.
FileModificationValidator.isReadOnly=File is Read Only.
diff --git a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/EclipseFile.java b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/EclipseFile.java
index 56685c03b..c3a15d487 100644
--- a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/EclipseFile.java
+++ b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/EclipseFile.java
@@ -31,6 +31,7 @@ import org.eclipse.team.internal.ccvs.core.ICVSRemoteResource;
import org.eclipse.team.internal.ccvs.core.ICVSResourceVisitor;
import org.eclipse.team.internal.ccvs.core.ILogEntry;
import org.eclipse.team.internal.ccvs.core.Policy;
+import org.eclipse.team.internal.ccvs.core.syncinfo.BaserevInfo;
import org.eclipse.team.internal.ccvs.core.syncinfo.NotifyInfo;
import org.eclipse.team.internal.ccvs.core.syncinfo.ResourceSyncInfo;
@@ -260,10 +261,34 @@ public class EclipseFile extends EclipseResource implements ICVSFile {
}
/**
+ * @see org.eclipse.team.internal.ccvs.core.ICVSFile#setNotifyInfo(NotifyInfo)
+ */
+ public void setBaserevInfo(BaserevInfo info) throws CVSException {
+ if (isManaged()) {
+ if (info == null) {
+ EclipseSynchronizer.getInstance().deleteBaserevInfo(resource);
+ EclipseSynchronizer.getInstance().deleteFileFromBaseDirectory(getIFile(), null);
+ } else
+ EclipseSynchronizer.getInstance().setBaserevInfo(resource, info);
+ }
+ }
+ /**
+ * @see org.eclipse.team.internal.ccvs.core.ICVSFile#getNotifyInfo()
+ */
+ public BaserevInfo getBaserevInfo() throws CVSException {
+ if (isManaged()) {
+ return EclipseSynchronizer.getInstance().getBaserevInfo(resource);
+ }
+ return null;
+ }
+
+ /**
* @see org.eclipse.team.internal.ccvs.core.ICVSFile#checkout(int)
*/
- public void edit(int notifications) throws CVSException {
+ public void edit(int notifications, IProgressMonitor monitor) throws CVSException {
if (!isReadOnly()) return;
+ ResourceSyncInfo info = getSyncInfo();
+ if (info == null || info.isAdded()) return;
// convert the notifications to internal form
char[] internalFormat;
@@ -286,10 +311,11 @@ public class EclipseFile extends EclipseResource implements ICVSFile {
}
// record the notification
- NotifyInfo info = new NotifyInfo(getName(), NotifyInfo.EDIT, new Date(), internalFormat);
- setNotifyInfo(info);
+ NotifyInfo notifyInfo = new NotifyInfo(getName(), NotifyInfo.EDIT, new Date(), internalFormat);
+ setNotifyInfo(notifyInfo);
- // XXX Copy original file to CVS/Base directory abd update CVS/Baserev file
+ EclipseSynchronizer.getInstance().copyFileToBaseDirectory(getIFile(), monitor);
+ setBaserevInfo(new BaserevInfo(getName(), info.getRevision()));
// allow editing
setReadOnly(false);
@@ -298,7 +324,7 @@ public class EclipseFile extends EclipseResource implements ICVSFile {
/**
* @see org.eclipse.team.internal.ccvs.core.ICVSFile#uncheckout()
*/
- public void unedit() throws CVSException {
+ public void unedit(IProgressMonitor monitor) throws CVSException {
if (isReadOnly()) return;
// record the notification
@@ -310,7 +336,8 @@ public class EclipseFile extends EclipseResource implements ICVSFile {
}
setNotifyInfo(info);
- // XXX Copy original file back from CVS/Base directory
+ EclipseSynchronizer.getInstance().restoreFileFromBaseDirectory(getIFile(), monitor);
+ setBaserevInfo(null);
// prevent editing
setReadOnly(true);
@@ -329,5 +356,29 @@ public class EclipseFile extends EclipseResource implements ICVSFile {
public NotifyInfo getPendingNotification() throws CVSException {
return getNotifyInfo();
}
+
+ /**
+ * @see org.eclipse.team.internal.ccvs.core.ICVSFile#committed(org.eclipse.team.internal.ccvs.core.syncinfo.ResourceSyncInfo)
+ */
+ public void committed(ResourceSyncInfo info) throws CVSException {
+ setSyncInfo(info);
+ clearCachedBase();
+ }
+
+ private void clearCachedBase() throws CVSException {
+ BaserevInfo base = getBaserevInfo();
+ if (base != null) {
+ setBaserevInfo(null);
+ setReadOnly(true);
+ }
+ }
+
+ /**
+ * @see org.eclipse.team.internal.ccvs.core.ICVSResource#unmanage(org.eclipse.core.runtime.IProgressMonitor)
+ */
+ public void unmanage(IProgressMonitor monitor) throws CVSException {
+ super.unmanage(monitor);
+ clearCachedBase();
+ }
} \ No newline at end of file
diff --git a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/EclipseFolder.java b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/EclipseFolder.java
index bf38c18fc..8843a53be 100644
--- a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/EclipseFolder.java
+++ b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/EclipseFolder.java
@@ -285,13 +285,13 @@ class EclipseFolder extends EclipseResource implements ICVSFolder {
final CVSException[] error = new CVSException[1];
// Remove the registered Move/Delete hook, assuming that the cvs runnable will keep sync info up-to-date
final MoveDeleteHook hook = CVSTeamProvider.getRegisteredMoveDeleteHook();
- boolean oldSetting = hook.isRecordOutgoingDeletions();
+ boolean oldSetting = hook.isWithinCVSOperation();
try {
ResourcesPlugin.getWorkspace().run(new IWorkspaceRunnable() {
public void run(IProgressMonitor monitor) throws CoreException {
try {
- hook.setRecordOutgoingDeletions(false);
- internalRun(job, monitor);
+ hook.setWithinCVSOperation(true);
+ EclipseSynchronizer.getInstance().run(job, monitor);
} catch(CVSException e) {
error[0] = e;
}
@@ -300,7 +300,7 @@ class EclipseFolder extends EclipseResource implements ICVSFolder {
} catch(CoreException e) {
throw CVSException.wrapException(e);
} finally {
- hook.setRecordOutgoingDeletions(oldSetting);
+ hook.setWithinCVSOperation(oldSetting);
}
if(error[0]!=null) {
throw error[0];
@@ -316,22 +316,10 @@ class EclipseFolder extends EclipseResource implements ICVSFolder {
*/
public void run(final ICVSRunnable job, int flags, IProgressMonitor monitor) throws CVSException {
if (flags == READ_ONLY)
- internalRun(job, monitor);
+ EclipseSynchronizer.getInstance().run(job, monitor);
else
run(job, monitor);
}
-
- private void internalRun(ICVSRunnable job, IProgressMonitor monitor) throws CVSException {
- monitor = Policy.monitorFor(monitor);
- monitor.beginTask(null, 100);
- try {
- EclipseSynchronizer.getInstance().beginOperation(Policy.subMonitorFor(monitor, 5));
- job.run(Policy.subMonitorFor(monitor, 60));
- } finally {
- EclipseSynchronizer.getInstance().endOperation(Policy.subMonitorFor(monitor, 35));
- monitor.done();
- }
- }
/**
* @see ICVSFolder#fetchChildren(IProgressMonitor)
diff --git a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/EclipseSynchronizer.java b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/EclipseSynchronizer.java
index ef515a265..6485c9133 100644
--- a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/EclipseSynchronizer.java
+++ b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/EclipseSynchronizer.java
@@ -31,7 +31,9 @@ import org.eclipse.core.runtime.Status;
import org.eclipse.team.internal.ccvs.core.CVSException;
import org.eclipse.team.internal.ccvs.core.CVSProviderPlugin;
import org.eclipse.team.internal.ccvs.core.CVSStatus;
+import org.eclipse.team.internal.ccvs.core.ICVSRunnable;
import org.eclipse.team.internal.ccvs.core.Policy;
+import org.eclipse.team.internal.ccvs.core.syncinfo.BaserevInfo;
import org.eclipse.team.internal.ccvs.core.syncinfo.FolderSyncInfo;
import org.eclipse.team.internal.ccvs.core.syncinfo.NotifyInfo;
import org.eclipse.team.internal.ccvs.core.syncinfo.ReentrantLock;
@@ -883,7 +885,7 @@ public class EclipseSynchronizer {
}
return null;
}
-
+
/**
* Method deleteNotifyInfo.
* @param resource
@@ -904,13 +906,107 @@ public class EclipseSynchronizer {
}
SyncFileWriter.writeAllNotifyInfo(resource.getParent(), newInfos);
}
+
+ /**
+ * Add the entry to the CVS/Baserev file. We are not initially concerned
+ * with efficiency since edit/unedit are typically issued on a small set of
+ * files.
+ *
+ * XXX If there was a previous notify entry for the resource, it is replaced. This is
+ * probably not the proper behavior (see EclipseFile).
+ *
+ * @param resource
+ * @param info
+ */
+ public void setBaserevInfo(IResource resource, BaserevInfo info) throws CVSException {
+ BaserevInfo[] infos = SyncFileWriter.readAllBaserevInfo(resource.getParent());
+ if (infos == null) {
+ infos = new BaserevInfo[] { info };
+ } else {
+ Map infoMap = new HashMap();
+ for (int i = 0; i < infos.length; i++) {
+ infoMap.put(infos[i].getName(), infos[i]);
+ }
+ infoMap.put(info.getName(), info);
+ BaserevInfo[] newInfos = new BaserevInfo[infoMap.size()];
+ int i = 0;
+ for (Iterator iter = infoMap.values().iterator(); iter.hasNext();) {
+ newInfos[i++] = (BaserevInfo) iter.next();
+ }
+ infos = newInfos;
+ }
+ SyncFileWriter.writeAllBaserevInfo(resource.getParent(), infos);
+ }
+
+ /**
+ * Method getBaserevInfo.
+ * @param resource
+ * @return BaserevInfo
+ */
+ public BaserevInfo getBaserevInfo(IResource resource) throws CVSException {
+ BaserevInfo[] infos = SyncFileWriter.readAllBaserevInfo(resource.getParent());
+ if (infos == null) return null;
+ for (int i = 0; i < infos.length; i++) {
+ BaserevInfo info = infos[i];
+ if (info.getName().equals(resource.getName())) {
+ return info;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Method deleteNotifyInfo.
+ * @param resource
+ */
+ public void deleteBaserevInfo(IResource resource) throws CVSException {
+ BaserevInfo[] infos = SyncFileWriter.readAllBaserevInfo(resource.getParent());
+ if (infos == null) return;
+ Map infoMap = new HashMap();
+ for (int i = 0; i < infos.length; i++) {
+ infoMap.put(infos[i].getName(), infos[i]);
+ }
+ infoMap.remove(resource.getName());
+ BaserevInfo[] newInfos = new BaserevInfo[infoMap.size()];
+ int i = 0;
+ for (Iterator iter = infoMap.values().iterator(); iter.hasNext();) {
+ newInfos[i++] = (BaserevInfo) iter.next();
+ }
+ SyncFileWriter.writeAllBaserevInfo(resource.getParent(), newInfos);
+ }
- public void copyFileToBaseDirectory(IFile file) throws CVSException {
+ public void copyFileToBaseDirectory(final IFile file, IProgressMonitor monitor) throws CVSException {
+ run(new ICVSRunnable() {
+ public void run(IProgressMonitor monitor) throws CVSException {
+ ResourceSyncInfo info = getResourceSync(file);
+ // The file must exist remotely and locally
+ if (info == null || info.isAdded() || info.isDeleted())
+ return;
+ SyncFileWriter.writeFileToBaseDirectory(file, monitor);
+ changedResources.add(file);
+ }
+ }, monitor);
+ }
+
+ public void restoreFileFromBaseDirectory(final IFile file, IProgressMonitor monitor) throws CVSException {
+ run(new ICVSRunnable() {
+ public void run(IProgressMonitor monitor) throws CVSException {
+ ResourceSyncInfo info = getResourceSync(file);
+ // The file must exist remotely
+ if (info == null || info.isAdded())
+ return;
+ SyncFileWriter.restoreFileFromBaseDirectory(file, monitor);
+ changedResources.add(file);
+ }
+ }, monitor);
+ }
+
+ public void deleteFileFromBaseDirectory(final IFile file, IProgressMonitor monitor) throws CVSException {
ResourceSyncInfo info = getResourceSync(file);
- // The file must exist remotely and must exist
- if (info == null || info.isAdded() || info.isDeleted())
+ // The file must exist remotely
+ if (info == null || info.isAdded())
return;
- SyncFileWriter.writeFileToBaseDirectory(file, info);
+ SyncFileWriter.deleteFileFromBaseDirectory(file, monitor);
}
/**
@@ -997,4 +1093,16 @@ public class EclipseSynchronizer {
}
return (IContainer[]) folders.toArray(new IContainer[folders.size()]);
}
+
+ public void run(ICVSRunnable job, IProgressMonitor monitor) throws CVSException {
+ monitor = Policy.monitorFor(monitor);
+ monitor.beginTask(null, 100);
+ try {
+ beginOperation(Policy.subMonitorFor(monitor, 5));
+ job.run(Policy.subMonitorFor(monitor, 60));
+ } finally {
+ endOperation(Policy.subMonitorFor(monitor, 35));
+ monitor.done();
+ }
+ }
} \ No newline at end of file
diff --git a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/RemoteFile.java b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/RemoteFile.java
index a664fd138..922fbe480 100644
--- a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/RemoteFile.java
+++ b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/RemoteFile.java
@@ -552,14 +552,14 @@ public class RemoteFile extends RemoteResource implements ICVSRemoteFile {
/**
* @see org.eclipse.team.internal.ccvs.core.ICVSFile#checkout(int)
*/
- public void edit(int notifications) throws CVSException {
+ public void edit(int notifications, IProgressMonitor monitor) throws CVSException {
// do nothing
}
/**
* @see org.eclipse.team.internal.ccvs.core.ICVSFile#uncheckout()
*/
- public void unedit() throws CVSException {
+ public void unedit(IProgressMonitor monitor) throws CVSException {
// do nothing
}
@@ -595,5 +595,11 @@ public class RemoteFile extends RemoteResource implements ICVSRemoteFile {
remoteFolder.setChildren(new ICVSRemoteResource[] { remoteFile });
return remoteFile;
}
+ /**
+ * @see org.eclipse.team.internal.ccvs.core.ICVSFile#committed(org.eclipse.team.internal.ccvs.core.syncinfo.ResourceSyncInfo)
+ */
+ public void committed(ResourceSyncInfo info) throws CVSException {
+ // do nothing
+ }
} \ No newline at end of file
diff --git a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/syncinfo/BaserevInfo.java b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/syncinfo/BaserevInfo.java
new file mode 100644
index 000000000..e9422ff9d
--- /dev/null
+++ b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/syncinfo/BaserevInfo.java
@@ -0,0 +1,83 @@
+/*******************************************************************************
+ * Copyright (c) 2002 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Common Public License v0.5
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v05.html
+ *
+ * Contributors:
+ * IBM - Initial implementation
+ ******************************************************************************/
+package org.eclipse.team.internal.ccvs.core.syncinfo;
+
+import org.eclipse.team.internal.ccvs.core.CVSException;
+import org.eclipse.team.internal.ccvs.core.Policy;
+import org.eclipse.team.internal.ccvs.core.util.EmptyTokenizer;
+
+/**
+ * This class represents the information in the CVS/Baserev file
+ */
+public class BaserevInfo {
+ private static final String BASEREV_PREFIX = "B"; //$NON-NLS-1$
+
+ private String name;
+ private String revision;
+
+ public BaserevInfo(String entryLine) throws CVSException {
+ setEntryLine(entryLine);
+ }
+
+ public BaserevInfo(String name, String revision) {
+ this.name = name;
+ this.revision = revision;
+ }
+ /**
+ * Return the entry line as it appears in the CVS/Baserev file
+ * @return String
+ */
+ public String getEntryLine() {
+ StringBuffer result = new StringBuffer();
+ result.append(BASEREV_PREFIX);
+ result.append(name);
+ result.append(ResourceSyncInfo.SEPARATOR);
+ result.append(revision);
+ return result.toString();
+ }
+ private void setEntryLine(String entryLine) throws CVSException {
+ if(entryLine.startsWith(BASEREV_PREFIX)) {
+ entryLine = entryLine.substring(1);
+ }
+ EmptyTokenizer tokenizer = new EmptyTokenizer(entryLine, ResourceSyncInfo.SEPARATOR);
+ if(tokenizer.countTokens() != 2) {
+ throw new CVSException(Policy.bind("BaseRevInfo.malformedEntryLine", entryLine)); //$NON-NLS-1$
+ }
+
+ name = tokenizer.nextToken();
+
+ if(name.length()==0) {
+ throw new CVSException(Policy.bind("BaseRevInfo.malformedEntryLine", entryLine)); //$NON-NLS-1$
+ }
+
+ revision = tokenizer.nextToken();
+
+ if(revision.length()==0) {
+ throw new CVSException(Policy.bind("BaseRevInfo.malformedEntryLine", entryLine)); //$NON-NLS-1$
+ }
+ }
+ /**
+ * Returns the name.
+ * @return String
+ */
+ public String getName() {
+ return name;
+ }
+
+ /**
+ * Returns the revision.
+ * @return String
+ */
+ public String getRevision() {
+ return revision;
+ }
+
+}
diff --git a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/util/MoveDeleteHook.java b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/util/MoveDeleteHook.java
index 7a76a31ad..0000158ad 100644
--- a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/util/MoveDeleteHook.java
+++ b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/util/MoveDeleteHook.java
@@ -10,20 +10,30 @@
******************************************************************************/
package org.eclipse.team.internal.ccvs.core.util;
+import java.util.ArrayList;
+import java.util.List;
+
import org.eclipse.core.resources.IFile;
+import org.eclipse.core.resources.IFileModificationValidator;
import org.eclipse.core.resources.IFolder;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IProjectDescription;
import org.eclipse.core.resources.IResource;
+import org.eclipse.core.resources.IResourceVisitor;
import org.eclipse.core.resources.team.IMoveDeleteHook;
import org.eclipse.core.resources.team.IResourceTree;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.team.core.RepositoryProvider;
import org.eclipse.team.internal.ccvs.core.CVSException;
import org.eclipse.team.internal.ccvs.core.CVSProviderPlugin;
+import org.eclipse.team.internal.ccvs.core.CVSTeamProvider;
import org.eclipse.team.internal.ccvs.core.ICVSFile;
+import org.eclipse.team.internal.ccvs.core.ICVSFileModificationValidator;
import org.eclipse.team.internal.ccvs.core.ICVSFolder;
import org.eclipse.team.internal.ccvs.core.ICVSRunnable;
+import org.eclipse.team.internal.ccvs.core.Policy;
import org.eclipse.team.internal.ccvs.core.resources.CVSWorkspaceRoot;
import org.eclipse.team.internal.ccvs.core.resources.EclipseSynchronizer;
import org.eclipse.team.internal.ccvs.core.syncinfo.MutableResourceSyncInfo;
@@ -35,7 +45,7 @@ import org.eclipse.team.internal.ccvs.core.syncinfo.ResourceSyncInfo;
*/
public class MoveDeleteHook implements IMoveDeleteHook {
- private boolean recordOutgoingDeletions = true;
+ private boolean withinCVSOperation = false;
/*
* Delete the file and return true if an outgoing deletion will result
@@ -53,7 +63,7 @@ public class MoveDeleteHook implements IMoveDeleteHook {
ICVSFile cvsFile = CVSWorkspaceRoot.getCVSFileFor(source);
try {
ResourceSyncInfo info = cvsFile.getSyncInfo();
- if (recordOutgoingDeletions && info != null && ! info.isAdded()) {
+ if (!withinCVSOperation && info != null && ! info.isAdded()) {
MutableResourceSyncInfo newInfo = info.cloneMutable();
newInfo.setDeleted(true);
cvsFile.setSyncInfo(newInfo);
@@ -125,12 +135,12 @@ public class MoveDeleteHook implements IMoveDeleteHook {
IFile file,
int updateFlags,
IProgressMonitor monitor) {
-
- // No special action is required here.
- // The AddDeleteMoveListener will update the sync info of the file
- return false;
+
+ // Return the opposite of the checkout request.
+ // If the file is deleted, the AddDeleteMoveListener will update the sync info of the file
+ return !checkOutFiles(tree, new IFile[] {file}, monitor);
}
-
+
/**
* @see IMoveDeleteHook#deleteFolder(IResourceTree, IFolder, int, IProgressMonitor)
*/
@@ -140,10 +150,12 @@ public class MoveDeleteHook implements IMoveDeleteHook {
final int updateFlags,
IProgressMonitor monitor) {
- final ICVSFolder cvsFolder = CVSWorkspaceRoot.getCVSFolderFor(folder);
+ monitor.beginTask(null, 100);
try {
+ if (!ensureCheckedOut(folder, tree, Policy.subMonitorFor(monitor, 30))) return true;
+ final ICVSFolder cvsFolder = CVSWorkspaceRoot.getCVSFolderFor(folder);
if (cvsFolder.isManaged()) {
- cvsFolder.run(new ICVSRunnable() {
+ EclipseSynchronizer.getInstance().run(new ICVSRunnable() {
public void run(IProgressMonitor monitor) throws CVSException {
try {
makeFolderOutgoingDeletion(tree, folder, null, updateFlags, monitor);
@@ -151,11 +163,13 @@ public class MoveDeleteHook implements IMoveDeleteHook {
tree.failed(e.getStatus());
}
}
- }, monitor);
+ }, Policy.subMonitorFor(monitor, 70));
return true;
}
} catch (CVSException e) {
tree.failed(e.getStatus());
+ } finally {
+ monitor.done();
}
return false;
}
@@ -175,6 +189,7 @@ public class MoveDeleteHook implements IMoveDeleteHook {
} catch (CVSException e) {
CVSProviderPlugin.log(e.getStatus());
}
+ // todo: Perform a "cvs release" if there are any edits on the project
return false;
}
@@ -182,15 +197,18 @@ public class MoveDeleteHook implements IMoveDeleteHook {
* @see IMoveDeleteHook#moveFile(IResourceTree, IFile, IFile, int, IProgressMonitor)
*/
public boolean moveFile(
- IResourceTree tree,
- IFile source,
- IFile destination,
- int updateFlags,
- IProgressMonitor monitor) {
-
- // No special action is required here.
- // The AddDeleteMoveListener will update the sync info of the source
- return false;
+ IResourceTree tree,
+ IFile source,
+ IFile destination,
+ int updateFlags,
+ IProgressMonitor monitor) {
+
+ // See comment in deleteFile
+ if (destination.exists())
+ // Ensure that we can write to the destination
+ return !checkOutFiles(tree, new IFile[] {source, destination}, monitor);
+ else
+ return !checkOutFiles(tree, new IFile[] {source}, monitor);
}
/**
@@ -203,10 +221,13 @@ public class MoveDeleteHook implements IMoveDeleteHook {
final int updateFlags,
IProgressMonitor monitor) {
- final ICVSFolder cvsFolder = CVSWorkspaceRoot.getCVSFolderFor(source);
+ monitor.beginTask(null, 100);
try {
+ if (!ensureCheckedOut(source, tree, Policy.subMonitorFor(monitor, 30))) return true;
+ if (!ensureCheckedOut(destination, tree, Policy.subMonitorFor(monitor, 10))) return true;
+ final ICVSFolder cvsFolder = CVSWorkspaceRoot.getCVSFolderFor(source);
if (cvsFolder.isManaged()) {
- cvsFolder.run(new ICVSRunnable() {
+ EclipseSynchronizer.getInstance().run(new ICVSRunnable() {
public void run(IProgressMonitor monitor) throws CVSException {
try {
makeFolderOutgoingDeletion(tree, source, destination, updateFlags, monitor);
@@ -214,11 +235,13 @@ public class MoveDeleteHook implements IMoveDeleteHook {
tree.failed(e.getStatus());
}
}
- }, monitor);
+ }, Policy.subMonitorFor(monitor, 60));
return true;
}
} catch (CVSException e) {
tree.failed(e.getStatus());
+ } finally {
+ monitor.done();
}
return false;
@@ -236,7 +259,8 @@ public class MoveDeleteHook implements IMoveDeleteHook {
// We need to move (or flush) any remembered folder deletions for the deleted project
// XXX We flush for now. This means that deleting a managed folder and then moving the
- // project will mean that the file deletions will be lost.
+ // project will mean that the file deletions will be lost. It also means that phantom
+ // folders are lost.
try {
EclipseSynchronizer.getInstance().prepareForDeletion(source);
} catch (CVSException e) {
@@ -249,16 +273,72 @@ public class MoveDeleteHook implements IMoveDeleteHook {
* Returns the recordOutgoingDeletions.
* @return boolean
*/
- public boolean isRecordOutgoingDeletions() {
- return recordOutgoingDeletions;
+ public boolean isWithinCVSOperation() {
+ return withinCVSOperation;
}
/**
* Sets the recordOutgoingDeletions.
* @param recordOutgoingDeletions The recordOutgoingDeletions to set
*/
- public void setRecordOutgoingDeletions(boolean recordOutgoingDeletions) {
- this.recordOutgoingDeletions = recordOutgoingDeletions;
+ public void setWithinCVSOperation(boolean withinCVSOperation) {
+ this.withinCVSOperation = withinCVSOperation;
+ }
+
+ /**
+ * Ensure that the given file is checked out (i.e. not read only). Return
+ * true if it is OK to procede and false otherwise.
+ *
+ * @param tree
+ * @param file
+ * @return boolean
+ */
+ private boolean checkOutFiles(IResourceTree tree, IFile[] files, IProgressMonitor monitor) {
+ // Ensure that the file is "checked out" (i.e. not read-only
+ IFileModificationValidator validator = getFileModificationValidator(files);
+ if (validator instanceof ICVSFileModificationValidator) {
+ IStatus status = ((ICVSFileModificationValidator)validator).validateMoveDelete(files, monitor);
+ if (status.isOK()) {
+ return true;
+ } else {
+ tree.failed(status);
+ return false;
+ }
+ }
+ return true;
}
+ private boolean ensureCheckedOut(IFolder folder, IResourceTree tree, IProgressMonitor monitor) {
+ if (!folder.exists()) return true;
+ try {
+ final List readOnlyFiles = new ArrayList();
+ // First, find any read-only files
+ folder.accept(new IResourceVisitor() {
+ public boolean visit(IResource resource) throws CoreException {
+ if (resource.getType() == IResource.FILE) {
+ IFile file = (IFile) resource;
+ if (file.isReadOnly()) {
+ readOnlyFiles.add(file);
+ }
+ }
+ return true;
+ }
+ });
+ if (readOnlyFiles.isEmpty()) return true;
+ // Next, ensure they are checked out
+ return checkOutFiles(tree, (IFile[]) readOnlyFiles.toArray(new IFile[readOnlyFiles.size()]), monitor);
+ } catch (CoreException e) {
+ tree.failed(e.getStatus());
+ return false;
+ }
+ }
+
+ private IFileModificationValidator getFileModificationValidator(IFile[] files) {
+ return getProvider(files).getFileModificationValidator();
+ }
+
+ private CVSTeamProvider getProvider(IFile[] files) {
+ CVSTeamProvider provider = (CVSTeamProvider)RepositoryProvider.getProvider(files[0].getProject(), CVSProviderPlugin.getTypeId());
+ return provider;
+ }
}
diff --git a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/util/SyncFileWriter.java b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/util/SyncFileWriter.java
index 658345fad..af0bbf738 100644
--- a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/util/SyncFileWriter.java
+++ b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/util/SyncFileWriter.java
@@ -34,6 +34,7 @@ import org.eclipse.team.internal.ccvs.core.CVSStatus;
import org.eclipse.team.internal.ccvs.core.CVSTag;
import org.eclipse.team.internal.ccvs.core.Policy;
import org.eclipse.team.internal.ccvs.core.resources.CVSEntryLineTag;
+import org.eclipse.team.internal.ccvs.core.syncinfo.BaserevInfo;
import org.eclipse.team.internal.ccvs.core.syncinfo.FolderSyncInfo;
import org.eclipse.team.internal.ccvs.core.syncinfo.NotifyInfo;
import org.eclipse.team.internal.ccvs.core.syncinfo.ResourceSyncInfo;
@@ -315,7 +316,64 @@ public class SyncFileWriter {
writeLines(cvsSubDir.getFile(NOTIFY), entries);
}
}
-
+
+ /**
+ * Reads the CVS/Baserev file from the specified folder and returns
+ * BaserevInfo instances for the data stored therein. If the folder does not
+ * have a CVS subdirectory then <code>null</code> is returned.
+ */
+ public static BaserevInfo[] readAllBaserevInfo(IContainer parent) throws CVSException {
+ IFolder cvsSubDir = getCVSSubdirectory(parent);
+ if (! cvsSubDir.exists()) return null;
+
+ // process Notify file contents
+ String[] entries = readLines(cvsSubDir.getFile(BASEREV));
+ if (entries == null) return null;
+ Map infos = new TreeMap();
+ for (int i = 0; i < entries.length; i++) {
+ String line = entries[i];
+ if(!"".equals(line)) { //$NON-NLS-1$
+ BaserevInfo info = new BaserevInfo(line);
+ infos.put(info.getName(), info);
+ }
+ }
+
+ return (BaserevInfo[])infos.values().toArray(new BaserevInfo[infos.size()]);
+ }
+
+ /**
+ * Writes the CVS/Baserev file to the specified folder using the data
+ * contained in the specified BaserevInfo instances. A CVS subdirectory must
+ * already exist (an exception is thrown if it doesn't).
+ */
+ public static void writeAllBaserevInfo(IContainer parent, BaserevInfo[] infos) throws CVSException {
+ // get the CVS directory
+ IFolder cvsSubDir = getCVSSubdirectory(parent);
+ // write lines will throw an exception if the CVS directory does not exist
+
+ if (infos.length == 0) {
+ // if there are no notify entries, delete the notify file
+ try {
+ IFile file = cvsSubDir.getFile(BASEREV);
+ if(file.exists()) {
+ file.delete(IResource.NONE, null);
+ }
+ } catch (CoreException e) {
+ throw CVSException.wrapException(e);
+ }
+ } else {
+ // format file contents
+ String[] entries = new String[infos.length];
+ for (int i = 0; i < infos.length; i++) {
+ BaserevInfo info = infos[i];
+ entries[i] = info.getEntryLine();
+ }
+
+ // write Notify entries
+ writeLines(cvsSubDir.getFile(BASEREV), entries);
+ }
+ }
+
/**
* Returns the CVS subdirectory for this folder.
*/
@@ -445,24 +503,73 @@ public class SyncFileWriter {
* @param file
* @param info
*/
- public static void writeFileToBaseDirectory(IFile file, ResourceSyncInfo info) throws CVSException {
+ public static void writeFileToBaseDirectory(IFile file, IProgressMonitor monitor) throws CVSException {
+ monitor = Policy.monitorFor(monitor);
+ monitor.beginTask(null, 100);
try {
IContainer cvsFolder = getCVSSubdirectory(file.getParent());
IFolder baseFolder = cvsFolder.getFolder(new Path(BASE_DIRNAME));
if (!baseFolder.exists()) {
- baseFolder.create(false /* force */, true /* local */, null);
+ baseFolder.create(false /* force */, true /* local */, Policy.subMonitorFor(monitor, 10));
}
IFile target = baseFolder.getFile(new Path(file.getName()));
if (target.exists()) {
// XXX Should ensure that we haven't already copied it
// XXX write the revision to the CVS/Baserev file
- target.setContents(file.getContents(), false /* force */, false /* history */, null);
- } else {
- // should use copy to ensure timestamp is the same
- target.create(file.getContents(), false /* force */, null);
+ target.delete(true, Policy.subMonitorFor(monitor, 10));
+ }
+ // Copy the file so the timestamp is maintained
+ file.copy(target.getFullPath(), true /* force */, Policy.subMonitorFor(monitor, 80));
+ } catch (CoreException e) {
+ throw CVSException.wrapException(e);
+ } finally {
+ monitor.done();
+ }
+ }
+ /**
+ * Method restoreFileFromBaseDirectory.
+ * @param file
+ * @param info
+ * @param monitor
+ */
+ public static void restoreFileFromBaseDirectory(IFile file, IProgressMonitor monitor) throws CVSException {
+ monitor = Policy.monitorFor(monitor);
+ monitor.beginTask(null, 100);
+ try {
+ IContainer cvsFolder = getCVSSubdirectory(file.getParent());
+ IFolder baseFolder = cvsFolder.getFolder(new Path(BASE_DIRNAME));
+ IFile source = baseFolder.getFile(new Path(file.getName()));
+ if (!source.exists()) {
+ throw new CVSException(Policy.bind("SyncFileWriter.baseNotAvailable", file.getFullPath().toString())); //$NON-NLS-1$
+ }
+ // Copy the file so the timestamp is maintained
+ source.move(file.getFullPath(), false /* force */, Policy.subMonitorFor(monitor, 100));
+ } catch (CoreException e) {
+ throw CVSException.wrapException(e);
+ } finally {
+ monitor.done();
+ }
+ }
+
+ /**
+ * Method deleteFileFromBaseDirectory.
+ * @param file
+ * @param monitor
+ */
+ public static void deleteFileFromBaseDirectory(IFile file, IProgressMonitor monitor) throws CVSException {
+ monitor = Policy.monitorFor(monitor);
+ monitor.beginTask(null, 100);
+ try {
+ IContainer cvsFolder = getCVSSubdirectory(file.getParent());
+ IFolder baseFolder = cvsFolder.getFolder(new Path(BASE_DIRNAME));
+ IFile source = baseFolder.getFile(new Path(file.getName()));
+ if (source.exists()) {
+ source.delete(false, false, Policy.subMonitorFor(monitor, 100));
}
} catch (CoreException e) {
throw CVSException.wrapException(e);
+ } finally {
+ monitor.done();
}
}
diff --git a/bundles/org.eclipse.team.cvs.ui/plugin.xml b/bundles/org.eclipse.team.cvs.ui/plugin.xml
index f3acdd757..efe4a5c3c 100644
--- a/bundles/org.eclipse.team.cvs.ui/plugin.xml
+++ b/bundles/org.eclipse.team.cvs.ui/plugin.xml
@@ -31,6 +31,15 @@
</run>
</authenticator>
</extension>
+<!-- *************** CVS File Modification Validator **************** -->
+ <extension
+ point="org.eclipse.team.cvs.core.filemodificationvalidator">
+ <validator>
+ <run
+ class="org.eclipse.team.internal.ccvs.ui.FileModificationValidator">
+ </run>
+ </validator>
+ </extension>
<!-- ******************* Wizards ****************** -->
<extension
point="org.eclipse.team.ui.configurationWizards">
@@ -572,7 +581,6 @@
id="org.eclipse.team.cvs.ui.ExtMethodPreferencePage">
</page>
</extension>
- <!--
<extension
point="org.eclipse.ui.preferencePages">
<page
@@ -582,7 +590,7 @@
id="org.eclipse.team.cvs.ui.WatchEditPreferencePage">
</page>
</extension>
- -->
+
<!-- **************** Decorator ******************* -->
<extension
point="org.eclipse.ui.decorators">
diff --git a/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/CVSUIPlugin.java b/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/CVSUIPlugin.java
index a68fc0e89..4e6415949 100644
--- a/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/CVSUIPlugin.java
+++ b/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/CVSUIPlugin.java
@@ -369,6 +369,43 @@ public class CVSUIPlugin extends AbstractUIPlugin implements IPropertyChangeList
// Log if the user requested it
if (log) CVSUIPlugin.log(status);
+ // Create a runnable that will display the error status
+ final String displayTitle = title;
+ final String displayMessage = message;
+ final IStatus displayStatus = status;
+ final IOpenableInShell openable = new IOpenableInShell() {
+ public void open(Shell shell) {
+ if (displayStatus.getSeverity() == IStatus.INFO && !displayStatus.isMultiStatus()) {
+ MessageDialog.openInformation(shell, Policy.bind("information"), displayStatus.getMessage()); //$NON-NLS-1$
+ } else {
+ ErrorDialog.openError(shell, displayTitle, displayMessage, displayStatus);
+ }
+ }
+ };
+ openDialog(providedShell, openable, flags);
+
+ // return the status we display
+ return status;
+ }
+
+ /**
+ * Interface that allows a shell to be passed to an open method. The
+ * provided shell can be used without sync-execing, etc.
+ */
+ public interface IOpenableInShell {
+ public void open(Shell shell);
+ }
+
+ /**
+ * Open the dialog code provided in the IOpenableInShell, ensuring that
+ * the provided whll is valid. This method will provide a shell to the
+ * IOpenableInShell if one is not provided to the method.
+ *
+ * @param providedShell
+ * @param openable
+ * @param flags
+ */
+ public static void openDialog(Shell providedShell, final IOpenableInShell openable, int flags) {
// If no shell was provided, try to get one from the active window
if (providedShell == null) {
IWorkbenchWindow window = CVSUIPlugin.getPlugin().getWorkbench().getActiveWorkbenchWindow();
@@ -378,13 +415,10 @@ public class CVSUIPlugin extends AbstractUIPlugin implements IPropertyChangeList
flags = flags | PERFORM_SYNC_EXEC;
}
}
-
+
// Create a runnable that will display the error status
final Shell shell = providedShell;
- final String displayTitle = title;
- final String displayMessage = message;
- final IStatus displayStatus = status;
- Runnable runnable = new Runnable() {
+ Runnable outerRunnable = new Runnable() {
public void run() {
Shell displayShell;
if (shell == null) {
@@ -393,17 +427,13 @@ public class CVSUIPlugin extends AbstractUIPlugin implements IPropertyChangeList
} else {
displayShell = shell;
}
- if (displayStatus.getSeverity() == IStatus.INFO && !displayStatus.isMultiStatus()) {
- MessageDialog.openInformation(displayShell, Policy.bind("information"), displayStatus.getMessage()); //$NON-NLS-1$
- } else {
- ErrorDialog.openError(displayShell, displayTitle, displayMessage, displayStatus);
- }
+ openable.open(displayShell);
if (shell == null) {
displayShell.dispose();
}
}
};
-
+
// Execute the above runnable as determined by the parameters
if (shell == null || (flags & PERFORM_SYNC_EXEC) > 0) {
Display display;
@@ -415,13 +445,10 @@ public class CVSUIPlugin extends AbstractUIPlugin implements IPropertyChangeList
} else {
display = shell.getDisplay();
}
- display.syncExec(runnable);
+ display.syncExec(outerRunnable);
} else {
- runnable.run();
+ outerRunnable.run();
}
-
- // return the status we display
- return status;
}
/**
diff --git a/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/FileModificationValidator.java b/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/FileModificationValidator.java
new file mode 100644
index 000000000..c0547370f
--- /dev/null
+++ b/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/FileModificationValidator.java
@@ -0,0 +1,185 @@
+/*******************************************************************************
+ * Copyright (c) 2002 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Common Public License v0.5
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v05.html
+ *
+ * Contributors:
+ * IBM - Initial implementation
+ ******************************************************************************/
+package org.eclipse.team.internal.ccvs.ui;
+
+import java.lang.reflect.InvocationTargetException;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.jface.dialogs.MessageDialog;
+import org.eclipse.jface.dialogs.ProgressMonitorDialog;
+import org.eclipse.jface.operation.IRunnableWithProgress;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.team.core.RepositoryProvider;
+import org.eclipse.team.core.TeamException;
+import org.eclipse.team.internal.ccvs.core.CVSException;
+import org.eclipse.team.internal.ccvs.core.CVSProviderPlugin;
+import org.eclipse.team.internal.ccvs.core.CVSTeamProvider;
+import org.eclipse.team.internal.ccvs.core.ICVSFile;
+import org.eclipse.team.internal.ccvs.core.ICVSFileModificationValidator;
+import org.eclipse.team.internal.ccvs.core.resources.CVSWorkspaceRoot;
+
+/**
+ * IFileModificationValidator that is pluged into the CVS Repository Provider
+ */
+public class FileModificationValidator implements ICVSFileModificationValidator {
+
+ public static final IStatus OK = new Status(IStatus.OK, CVSUIPlugin.ID, 0, Policy.bind("ok"), null); //$NON-NLS-1$
+ private static final int HIGHJACK = 1;
+
+ public FileModificationValidator() {
+ }
+
+ /**
+ * @see org.eclipse.core.resources.IFileModificationValidator#validateEdit(org.eclipse.core.resources.IFile, java.lang.Object)
+ */
+ public IStatus validateEdit(IFile[] files, Object context) {
+ IFile[] readOnlyFiles = getManagedReadOnlyFiles(files);
+ if (readOnlyFiles.length == 0) return OK;
+ return edit(readOnlyFiles, getShell(context));
+ }
+
+ /**
+ * @see org.eclipse.core.resources.IFileModificationValidator#validateSave(org.eclipse.core.resources.IFile)
+ */
+ public IStatus validateSave(IFile file) {
+ if (!needsCheckout(file)) return OK;
+ return edit(new IFile[] {file}, (Shell)null);
+ }
+
+ /**
+ * @see org.eclipse.team.internal.ccvs.core.ICVSFileModificationValidator#validateMoveDelete(org.eclipse.core.resources.IFile[], org.eclipse.core.runtime.IProgressMonitor)
+ */
+ public IStatus validateMoveDelete(IFile[] files, IProgressMonitor monitor) {
+ IFile[] readOnlyFiles = getManagedReadOnlyFiles(files);
+ if (readOnlyFiles.length == 0) return OK;
+ if (isPrompt()) {
+ IStatus status = promptToEditFiles(files, null);
+ if (!status.isOK() || status.getCode() == HIGHJACK) return status;
+ }
+ try {
+ edit(readOnlyFiles, monitor);
+ return OK;
+ } catch (CVSException e) {
+ return e.getStatus();
+ }
+ }
+
+ private IFile[] getManagedReadOnlyFiles(IFile[] files) {
+ List readOnlys = new ArrayList();
+ for (int i = 0; i < files.length; i++) {
+ IFile iFile = files[i];
+ if (needsCheckout(iFile)) {
+ readOnlys.add(iFile);
+ }
+ }
+ return (IFile[]) readOnlys.toArray(new IFile[readOnlys.size()]);
+ }
+
+ private boolean needsCheckout(IFile file) {
+ try {
+ if (file.isReadOnly()) {
+ ICVSFile cvsFile = CVSWorkspaceRoot.getCVSFileFor(file);
+ return cvsFile.isManaged();
+ }
+ } catch (CVSException e) {
+ // Log the exception and assume we don't need a checkout
+ CVSUIPlugin.log(e);
+ }
+ return false;
+ }
+
+ private CVSTeamProvider getProvider(IFile[] files) {
+ CVSTeamProvider provider = (CVSTeamProvider)RepositoryProvider.getProvider(files[0].getProject(), CVSProviderPlugin.getTypeId());
+ return provider;
+ }
+
+ private Shell getShell(Object context) {
+ if (context instanceof Shell)
+ return (Shell)context;
+ return null;
+ }
+
+ private IStatus getStatus(InvocationTargetException e) {
+ Throwable target = e.getTargetException();
+ if (target instanceof TeamException) {
+ return ((TeamException) target).getStatus();
+ } else if (target instanceof CoreException) {
+ return ((CoreException) target).getStatus();
+ }
+ return new Status(IStatus.ERROR, CVSUIPlugin.ID, 0, Policy.bind("internal"), target);
+ }
+
+ private IStatus edit(final IFile[] files, Shell shell) {
+ if (isPrompt()) {
+ IStatus status = promptToEditFiles(files, shell);
+ if (!status.isOK() || status.getCode() == HIGHJACK) return status;
+ }
+ // Create a runnable to edit the file
+ try {
+ run(shell, new IRunnableWithProgress() {
+ public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException {
+ try {
+ edit(files, monitor);
+ } catch (CVSException e) {
+ new InvocationTargetException(e);
+ }
+ }
+ });
+ return OK;
+ } catch (InvocationTargetException e) {
+ return getStatus(e);
+ }
+ }
+
+ private boolean isPrompt() {
+ return WatchEditPreferencePage.PROMPT.equals(CVSUIPlugin.getPlugin().getPreferenceStore().getString(ICVSUIConstants.PREF_PROMPT_ON_EDIT));
+ }
+
+ private IStatus promptToEditFiles(IFile[] files, Shell shell) {
+ final IStatus[] result = new IStatus[] { OK };
+ CVSUIPlugin.openDialog(shell, new CVSUIPlugin.IOpenableInShell() {
+ public void open(Shell shell) {
+ if (!MessageDialog.openQuestion(shell, "CVS Edit Files?", "There are read-only files being modified. Should a 'cvs edit' be performed?")) {
+ result[0] = new Status(IStatus.ERROR, CVSUIPlugin.ID, 0, "User vetoed file modfication", null);
+ }
+ //todo: need a custom DetailsDialog
+ }
+ }, 0);
+ return result[0];
+ }
+
+ private void run(Shell shell, final IRunnableWithProgress runnable) throws InvocationTargetException {
+ final InvocationTargetException[] exception = new InvocationTargetException[] { null };
+ CVSUIPlugin.openDialog(shell, new CVSUIPlugin.IOpenableInShell() {
+ public void open(Shell shell) {
+ try {
+ new ProgressMonitorDialog(shell).run(true /* fork */, true /* cancellable */, runnable);
+ } catch (InvocationTargetException e) {
+ exception[0] = e;
+ } catch (InterruptedException e) {
+ // do nothing
+ }
+ }
+ }, 0);
+ if (exception[0] != null)
+ throw exception[0];
+ }
+
+ private void edit(IFile[] files, IProgressMonitor monitor) throws CVSException {
+ getProvider(files).edit(files, false /* recurse */, true /* notify server */, ICVSFile.NO_NOTIFICATION, monitor);
+ }
+}
diff --git a/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/WatchEditPreferencePage.java b/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/WatchEditPreferencePage.java
index edd6be436..fc7af7fdf 100644
--- a/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/WatchEditPreferencePage.java
+++ b/bundles/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/WatchEditPreferencePage.java
@@ -10,9 +10,11 @@
******************************************************************************/
package org.eclipse.team.internal.ccvs.ui;
+import org.eclipse.core.runtime.Preferences;
import org.eclipse.jface.preference.BooleanFieldEditor;
import org.eclipse.jface.preference.IPreferenceStore;
import org.eclipse.jface.preference.RadioGroupFieldEditor;
+import org.eclipse.team.internal.ccvs.core.CVSProviderPlugin;
/**
* This page contains preferences related to the cvs watch/edit commands
@@ -23,9 +25,16 @@ public class WatchEditPreferencePage extends CVSFieldEditorPreferencePage {
public static final String PROMPT = "prompt"; //$NON-NLS-1$
public static void setDefaults() {
+ // Get the preference store from CVS core
+ Preferences corePrefs = CVSProviderPlugin.getPlugin().getPluginPreferences();
+ // Set the UI defaults
IPreferenceStore store = getCVSPreferenceStore();
- store.setDefault(ICVSUIConstants.PREF_CHECKOUT_READ_ONLY, false);
+ store.setDefault(ICVSUIConstants.PREF_CHECKOUT_READ_ONLY,
+ corePrefs.getDefaultBoolean(CVSProviderPlugin.READ_ONLY));
store.setDefault(ICVSUIConstants.PREF_PROMPT_ON_EDIT, PROMPT);
+ // Ensure that the preference values in UI match Core
+ store.setValue(ICVSUIConstants.PREF_CHECKOUT_READ_ONLY,
+ corePrefs.getBoolean(CVSProviderPlugin.READ_ONLY));
}
/**
@@ -63,8 +72,16 @@ public class WatchEditPreferencePage extends CVSFieldEditorPreferencePage {
*/
public boolean performOk() {
if (!super.performOk()) return false;
- // todo: push settings into core
+ pushPreferences();
return true;
}
+ private void pushPreferences() {
+ IPreferenceStore source = getCVSPreferenceStore();
+ Preferences target = CVSProviderPlugin.getPlugin().getPluginPreferences();
+ target.setValue(
+ CVSProviderPlugin.READ_ONLY,
+ source.getBoolean(ICVSUIConstants.PREF_CHECKOUT_READ_ONLY));
+ }
+
}
diff --git a/tests/org.eclipse.team.tests.cvs.core/src/org/eclipse/team/tests/ccvs/core/provider/ResourceDeltaTest.java b/tests/org.eclipse.team.tests.cvs.core/src/org/eclipse/team/tests/ccvs/core/provider/ResourceDeltaTest.java
index cbf6ac7e1..380ce598b 100644
--- a/tests/org.eclipse.team.tests.cvs.core/src/org/eclipse/team/tests/ccvs/core/provider/ResourceDeltaTest.java
+++ b/tests/org.eclipse.team.tests.cvs.core/src/org/eclipse/team/tests/ccvs/core/provider/ResourceDeltaTest.java
@@ -121,7 +121,8 @@ public class ResourceDeltaTest extends EclipseTest {
folder = project.getFolder(new Path("sub/moved"));
ICVSFolder cvsFolder = CVSWorkspaceRoot.getCVSFolderFor(folder);
assertNotManaged(cvsFolder);
- assertAdditionMarkerFor(folder, true);
+ assertAdditionMarkerFor(target, true);
+ assertAdditionMarkerFor(folder, false);
}
public void testDeletionHandling() throws TeamException, CoreException {
@@ -150,7 +151,6 @@ public class ResourceDeltaTest extends EclipseTest {
assertTrue("File " + file.getName() + " should not be marked as deleted", ! info.isDeleted());
assertTrue("File " + file.getName() + " should not be marked as addition", ! info.isAdded());
assertDeletionMarkerFor(project.getFile("deleted.txt"), false);
- assertAdditionMarkerFor(project.getFile("added.txt"), false);
}
public void testFolderAdditionHandling() throws TeamException, CoreException {

Back to the top