Skip to main content
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--examples/org.eclipse.team.examples.filesystem/.project11
-rw-r--r--examples/org.eclipse.team.examples.filesystem/plugin.xml229
-rw-r--r--examples/org.eclipse.team.examples.filesystem/src/org/eclipse/team/examples/pessimistic/IPessimisticFilesystemConstants.java64
-rw-r--r--examples/org.eclipse.team.examples.filesystem/src/org/eclipse/team/examples/pessimistic/IResourceStateListener.java22
-rw-r--r--examples/org.eclipse.team.examples.filesystem/src/org/eclipse/team/examples/pessimistic/PessimisticFilesystemProvider.java652
-rw-r--r--examples/org.eclipse.team.examples.filesystem/src/org/eclipse/team/examples/pessimistic/PessimisticFilesystemProviderPlugin.java152
-rw-r--r--examples/org.eclipse.team.examples.filesystem/src/org/eclipse/team/examples/pessimistic/PessimisticModificationValidator.java326
-rw-r--r--examples/org.eclipse.team.examples.filesystem/src/org/eclipse/team/examples/pessimistic/ResourceChangeListener.java294
-rw-r--r--examples/org.eclipse.team.examples.filesystem/src/org/eclipse/team/examples/pessimistic/ResourceSetContentProvider.java72
-rw-r--r--examples/org.eclipse.team.examples.filesystem/src/org/eclipse/team/examples/pessimistic/ui/AddToControlAction.java83
-rw-r--r--examples/org.eclipse.team.examples.filesystem/src/org/eclipse/team/examples/pessimistic/ui/BlankPage.java38
-rw-r--r--examples/org.eclipse.team.examples.filesystem/src/org/eclipse/team/examples/pessimistic/ui/CheckInAction.java45
-rw-r--r--examples/org.eclipse.team.examples.filesystem/src/org/eclipse/team/examples/pessimistic/ui/CheckOutAction.java43
-rw-r--r--examples/org.eclipse.team.examples.filesystem/src/org/eclipse/team/examples/pessimistic/ui/ConfigurationWizard.java54
-rw-r--r--examples/org.eclipse.team.examples.filesystem/src/org/eclipse/team/examples/pessimistic/ui/DisconnectAction.java90
-rw-r--r--examples/org.eclipse.team.examples.filesystem/src/org/eclipse/team/examples/pessimistic/ui/PessimisticDecorator.java130
-rw-r--r--examples/org.eclipse.team.examples.filesystem/src/org/eclipse/team/examples/pessimistic/ui/PessimisticPreferencesPage.java358
-rw-r--r--examples/org.eclipse.team.examples.filesystem/src/org/eclipse/team/examples/pessimistic/ui/PessimisticProviderAction.java231
-rw-r--r--examples/org.eclipse.team.examples.filesystem/src/org/eclipse/team/examples/pessimistic/ui/RemoveFromControlAction.java81
-rw-r--r--examples/org.eclipse.team.examples.filesystem/src/org/eclipse/team/examples/pessimistic/ui/SourceManagementAction.java71
-rw-r--r--examples/org.eclipse.team.examples.filesystem/src/org/eclipse/team/examples/pessimistic/ui/UncheckOutAction.java25
21 files changed, 3042 insertions, 29 deletions
diff --git a/examples/org.eclipse.team.examples.filesystem/.project b/examples/org.eclipse.team.examples.filesystem/.project
index eee25274a..06b5b570f 100644
--- a/examples/org.eclipse.team.examples.filesystem/.project
+++ b/examples/org.eclipse.team.examples.filesystem/.project
@@ -22,8 +22,19 @@
<arguments>
</arguments>
</buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.ManifestBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.SchemaBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.jdt.core.javanature</nature>
+ <nature>org.eclipse.pde.PluginNature</nature>
</natures>
</projectDescription>
diff --git a/examples/org.eclipse.team.examples.filesystem/plugin.xml b/examples/org.eclipse.team.examples.filesystem/plugin.xml
index ce1bb0e2d..42fa51190 100644
--- a/examples/org.eclipse.team.examples.filesystem/plugin.xml
+++ b/examples/org.eclipse.team.examples.filesystem/plugin.xml
@@ -1,5 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<?eclipse version="3.0"?>
+<!-- =================================================================================== -->
+<!-- Team Examples Plug-in Manifest -->
+<!-- =================================================================================== -->
<plugin
id="org.eclipse.team.examples.filesystem"
name="%pluginName"
@@ -7,35 +10,56 @@
provider-name="%providerName"
class="org.eclipse.team.examples.filesystem.FileSystemPlugin">
- <runtime>
- <library name="teamfilesystem.jar">
- <export name="*"/>
- <packages prefixes="org.eclipse.team.examples.filesystem"/>
- </library>
- </runtime>
- <requires>
- <import plugin="org.eclipse.core.runtime.compatibility"/>
- <import plugin="org.eclipse.ui.ide" optional="true"/>
- <import plugin="org.eclipse.ui.views" optional="true"/>
- <import plugin="org.eclipse.jface.text" optional="true"/>
- <import plugin="org.eclipse.ui.workbench.texteditor" optional="true"/>
- <import plugin="org.eclipse.ui.editors" optional="true"/>
- <import plugin="org.eclipse.core.resources"/>
- <import plugin="org.eclipse.team.core"/>
- <import plugin="org.eclipse.team.ui"/>
- <import plugin="org.eclipse.ui"/>
- </requires>
+<!-- =================================================================================== -->
+<!-- Libraries -->
+<!-- =================================================================================== -->
+<runtime>
+ <library name="teamfilesystem.jar">
+ <export name="*"/>
+ <packages prefixes="org.eclipse.team.examples.filesystem"/>
+ </library>
+</runtime>
+
+<!-- =================================================================================== -->
+<!-- Imports -->
+<!-- =================================================================================== -->
+
+<requires>
+ <import plugin="org.eclipse.core.runtime.compatibility"/>
+ <import plugin="org.eclipse.ui.ide" optional="true"/>
+ <import plugin="org.eclipse.ui.views" optional="true"/>
+ <import plugin="org.eclipse.jface.text" optional="true"/>
+ <import plugin="org.eclipse.ui.workbench.texteditor" optional="true"/>
+ <import plugin="org.eclipse.ui.editors" optional="true"/>
+ <import plugin="org.eclipse.core.resources"/>
+ <import plugin="org.eclipse.team.core"/>
+ <import plugin="org.eclipse.team.ui"/>
+ <import plugin="org.eclipse.ui"/>
+</requires>
+
+<!-- =================================================================================== -->
+<!-- Repository Providers -->
+<!-- =================================================================================== -->
+
+<extension point="org.eclipse.team.core.repository">
+ <repository
+ class="org.eclipse.team.examples.filesystem.FileSystemProvider"
+ id="org.eclipse.team.examples.filesystem.FileSystemProvider">
+ </repository>
+</extension>
+
+<extension point="org.eclipse.team.core.repository">
+ <repository
+ class="org.eclipse.team.examples.pessimistic.PessimisticFilesystemProvider"
+ id="org.eclipse.team.examples.pessimistic.pessimisticnature">
+ </repository>
+</extension>
+
+<!-- =================================================================================== -->
+<!-- Menus for File System Example -->
+<!-- =================================================================================== -->
-<!-- *************** Repository Provider **************** -->
- <extension
- point="org.eclipse.team.core.repository">
- <repository
- class="org.eclipse.team.examples.filesystem.FileSystemProvider"
- id="org.eclipse.team.examples.filesystem.FileSystemProvider">
- </repository>
- </extension>
-<!-- *************** POPUP MENUS **************** -->
<extension
point="org.eclipse.ui.popupMenus">
<objectContribution
@@ -85,7 +109,11 @@
</action>
</objectContribution>
</extension>
-<!-- *************** CONFIGURATION WIZARD **************** -->
+
+<!-- =================================================================================== -->
+<!-- Sharing Wizards -->
+<!-- =================================================================================== -->
+
<extension
point="org.eclipse.team.ui.configurationWizards">
<wizard
@@ -99,7 +127,21 @@
</description>
</wizard>
</extension>
-<!-- *************** PROPERTY PAGES **************** -->
+
+ <extension
+ point="org.eclipse.team.ui.configurationWizards">
+ <wizard
+ name="Pessimistic Simple Provider (non-versioning)"
+ icon="icons/full/wizards/fsicon_wiz.gif"
+ class="org.eclipse.team.examples.pessimistic.ui.ConfigurationWizard"
+ id="org.eclipse.team.examples.pessimistic.ui.ConfigurationWizard">
+ </wizard>
+ </extension>
+
+<!-- =================================================================================== -->
+<!-- Property Pages -->
+<!-- =================================================================================== -->
+
<extension
point="org.eclipse.ui.propertyPages">
<page
@@ -115,4 +157,133 @@
</page>
</extension>
+<!-- =================================================================================== -->
+<!-- Preference Pages -->
+<!-- =================================================================================== -->
+
+ <extension
+ point="org.eclipse.ui.preferencePages">
+ <page
+ name="Pessimistic Filesystem Provider"
+ category="org.eclipse.team.ui.TeamPreferences"
+ class="org.eclipse.team.examples.pessimistic.ui.PessimisticPreferencesPage"
+ id="org.eclipse.team.examples.pessimistic.PessimisticPreferences">
+ </page>
+ </extension>
+
+<!-- =================================================================================== -->
+<!-- Decorators -->
+<!-- =================================================================================== -->
+
+ <extension
+ point="org.eclipse.ui.decorators">
+ <decorator
+ objectClass="org.eclipse.core.resources.IResource"
+ adaptable="true"
+ label="Pessimistic Filesystem Provider Decorator"
+ state="true"
+ class="org.eclipse.team.examples.pessimistic.ui.PessimisticDecorator"
+ id="org.eclipse.team.pessimistic.ui.decorator">
+ <description>
+ Provides simple checked-in, checked-out decorations on files.
+ </description>
+ </decorator>
+ </extension>
+
+<!-- =================================================================================== -->
+<!-- Menus for Pessimistic Provider -->
+<!-- =================================================================================== -->
+
+ <extension
+ point="org.eclipse.ui.popupMenus">
+ <objectContribution
+ objectClass="org.eclipse.core.resources.IResource"
+ adaptable="true"
+ id="org.eclipse.team.cvs.ui.filesystem.ResourceContributions">
+ <filter
+ name="projectPersistentProperty"
+ value="org.eclipse.team.core.repository=org.eclipse.team.examples.pessimistic.pessimisticnature">
+ </filter>
+ <action
+ label="Checkout"
+ tooltip="Check resources out of the repository"
+ class="org.eclipse.team.examples.pessimistic.ui.CheckOutAction"
+ menubarPath="team.main/group1"
+ id="org.eclipse.team.examples.pessimistic.checkout">
+ </action>
+ <action
+ label="Checkin"
+ tooltip="Check resources into the repository"
+ class="org.eclipse.team.examples.pessimistic.ui.CheckInAction"
+ menubarPath="team.main/group1"
+ id="org.eclipse.team.examples.pessimistic.checkin">
+ </action>
+ <action
+ label="Uncheckout"
+ tooltip="Revert checked out status of resources"
+ class="org.eclipse.team.examples.pessimistic.ui.UncheckOutAction"
+ menubarPath="team.main/group1"
+ id="org.eclipse.team.examples.pessimistic.uncheckout">
+ </action>
+ </objectContribution>
+ <objectContribution
+ objectClass="org.eclipse.core.resources.IFile"
+ adaptable="true"
+ id="org.eclipse.team.cvs.ui.filesystem.ResourceContributions">
+ <filter
+ name="projectPersistentProperty"
+ value="org.eclipse.team.core.repository=org.eclipse.team.examples.pessimistic.pessimisticnature">
+ </filter>
+ <action
+ label="Add to control"
+ class="org.eclipse.team.examples.pessimistic.ui.AddToControlAction"
+ menubarPath="team.main/group2"
+ id="org.eclipse.team.examples.pessimistic.addToControl">
+ </action>
+ <action
+ label="Remove from control"
+ class="org.eclipse.team.examples.pessimistic.ui.RemoveFromControlAction"
+ menubarPath="team.main/group2"
+ id="org.eclipse.team.examples.pessimistic.removeFromControl">
+ </action>
+ </objectContribution>
+ <objectContribution
+ objectClass="org.eclipse.core.resources.IFolder"
+ adaptable="true"
+ id="org.eclipse.team.cvs.ui.filesystem.ResourceContributions">
+ <filter
+ name="projectPersistentProperty"
+ value="org.eclipse.team.core.repository=org.eclipse.team.examples.pessimistic.pessimisticnature">
+ </filter>
+ <action
+ label="Add to control"
+ class="org.eclipse.team.examples.pessimistic.ui.AddToControlAction"
+ menubarPath="team.main/group2"
+ id="org.eclipse.team.examples.pessimistic.addToControl">
+ </action>
+ <action
+ label="Remove from control"
+ class="org.eclipse.team.examples.pessimistic.ui.RemoveFromControlAction"
+ menubarPath="team.main/group2"
+ id="org.eclipse.team.examples.pessimistic.removeFromControl">
+ </action>
+ </objectContribution>
+ <objectContribution
+ objectClass="org.eclipse.core.resources.IProject"
+ adaptable="true"
+ id="org.eclipse.team.cvs.ui.filesystem.ResourceContributions">
+ <filter
+ name="projectPersistentProperty"
+ value="org.eclipse.team.core.repository=org.eclipse.team.examples.pessimistic.pessimisticnature">
+ </filter>
+ <action
+ label="Stop sharing"
+ tooltip="Stop sharing the project using the pessimistic file provider"
+ class="org.eclipse.team.examples.pessimistic.ui.DisconnectAction"
+ menubarPath="team.main/projectGroup"
+ id="org.eclipse.team.examples.pessimistic.disconnect">
+ </action>
+ </objectContribution>
+ </extension>
+
</plugin>
diff --git a/examples/org.eclipse.team.examples.filesystem/src/org/eclipse/team/examples/pessimistic/IPessimisticFilesystemConstants.java b/examples/org.eclipse.team.examples.filesystem/src/org/eclipse/team/examples/pessimistic/IPessimisticFilesystemConstants.java
new file mode 100644
index 000000000..7f8748631
--- /dev/null
+++ b/examples/org.eclipse.team.examples.filesystem/src/org/eclipse/team/examples/pessimistic/IPessimisticFilesystemConstants.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2002 IBM Corp. All rights reserved.
+ * This file is made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ */
+package org.eclipse.team.examples.pessimistic;
+
+/**
+ * Preference constants for the <code>PessimisticFilesystemProvider</code>.
+ */
+public interface IPessimisticFilesystemConstants {
+ /**
+ * Preference name's prefix
+ */
+ String PREFIX = "org.eclipse.team.examples.pessimistic.";
+
+ /**
+ * Preference name for when checked in files are saved.
+ */
+ String PREF_CHECKED_IN_FILES_SAVED = PREFIX + "WhenCheckedInFilesAreSaved";
+ /**
+ * Preference name for when checked in files are edited with a UI context.
+ */
+ String PREF_CHECKED_IN_FILES_EDITED = PREFIX + "WhenCheckedInFilesAreEdited";
+ /**
+ * Preference name for when checked in files are edited without a UI context.
+ */
+ String PREF_CHECKED_IN_FILES_EDITED_NOPROMPT = PREFIX + "WhenCheckedInFilesAreEditedNoPrompt";
+ /**
+ * Preference name for the option to always fail validate edit.
+ */
+ String PREF_FAIL_VALIDATE_EDIT= PREFIX + "FailValidateEdit";
+ /**
+ * Preference name for the option to touch files during validate edit calls
+ */
+ String PREF_TOUCH_DURING_VALIDATE_EDIT= PREFIX + "ChangeFileContents";
+ /**
+ * Preference name for the option to add files to the repository provider.
+ */
+ String PREF_ADD_TO_CONTROL= PREFIX + "AddToControl";
+
+ /**
+ * Preference option indicating that the user should be prompted.
+ */
+ int OPTION_PROMPT = 1;
+ /**
+ * Preference option indicating that the action should happen automatically.
+ */
+ int OPTION_AUTOMATIC = 2;
+ /**
+ * Preference option indicating that the action should not occur.
+ */
+ int OPTION_DO_NOTHING = 4;
+
+ /**
+ * Status flag indicating that resources are ready to be edited.
+ */
+ int STATUS_OK_TO_EDIT = 1;
+ /**
+ * Status flag indicating that resources need to be reloaded.
+ */
+ int STATUS_PROMPT_FOR_RELOAD = 2;
+}
diff --git a/examples/org.eclipse.team.examples.filesystem/src/org/eclipse/team/examples/pessimistic/IResourceStateListener.java b/examples/org.eclipse.team.examples.filesystem/src/org/eclipse/team/examples/pessimistic/IResourceStateListener.java
new file mode 100644
index 000000000..d8dc6be75
--- /dev/null
+++ b/examples/org.eclipse.team.examples.filesystem/src/org/eclipse/team/examples/pessimistic/IResourceStateListener.java
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2002 IBM Corp. All rights reserved.
+ * This file is made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ */
+package org.eclipse.team.examples.pessimistic;
+
+import org.eclipse.core.resources.IResource;
+
+/**
+ * An <code>IResourceStateListener</code> recieves callbacks
+ * when the repository state of resources change, i.e. a file gets checked
+ * in, a folder gets checked out, a project is no longer shared, etc.
+ */
+public interface IResourceStateListener {
+ /**
+ * Notifies this listener that the state of the resources has changed.
+ * @param resources An array of resources with changed states or an empty array.
+ */
+ void stateChanged(IResource[] resources);
+}
diff --git a/examples/org.eclipse.team.examples.filesystem/src/org/eclipse/team/examples/pessimistic/PessimisticFilesystemProvider.java b/examples/org.eclipse.team.examples.filesystem/src/org/eclipse/team/examples/pessimistic/PessimisticFilesystemProvider.java
new file mode 100644
index 000000000..374535ad5
--- /dev/null
+++ b/examples/org.eclipse.team.examples.filesystem/src/org/eclipse/team/examples/pessimistic/PessimisticFilesystemProvider.java
@@ -0,0 +1,652 @@
+/*
+ * Copyright (c) 2002 IBM Corp. All rights reserved.
+ * This file is made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ */
+package org.eclipse.team.examples.pessimistic;
+
+import java.io.*;
+import java.util.*;
+
+import org.eclipse.core.resources.*;
+import org.eclipse.core.runtime.*;
+import org.eclipse.jface.preference.IPreferenceStore;
+import org.eclipse.team.core.RepositoryProvider;
+
+/**
+ * The <code>PessimisticFilesystemProvider</code> is a repository provider.
+ *
+ * The provider manages a file named ".pessimistic" in each container it
+ * controls. This is where it stores metadata on which files it controls
+ * in that container. This file is considered to be controlled by the
+ * provider and may be deleted.
+ *
+ * The provider provides very simple checkin/checkout facilities by marking
+ * files read-only to check them in and read-write to check them out. It
+ * also supports ignoring derived files.
+ */
+public class PessimisticFilesystemProvider extends RepositoryProvider {
+ /**
+ * The name of the file used to store metadata on which
+ * files are controlled by this provider.
+ */
+ private static final String CONTROL_FILE_NAME= ".pessimistic";
+ /**
+ * The file modification validator for this provider.
+ */
+ private IFileModificationValidator validator;
+ /**
+ * The cache of resources that are currently controlled.
+ * The cache is a map of parent resource -> set of controlled children.
+ */
+ private Map fControlledResources;
+
+ /**
+ * Creates a new provider, required for team repository extension.
+ */
+ public PessimisticFilesystemProvider() {
+ validator = new PessimisticModificationValidator(this);
+ fControlledResources= new HashMap(1);
+ }
+
+ /**
+ * Adds the resources to the control of this provider.
+ */
+ public void addToControl(final IResource[] resources, IProgressMonitor monitor) {
+ if (PessimisticFilesystemProviderPlugin.getInstance().isDebugging()) {
+ System.out.println("Add to control:");
+ if (resources != null) {
+ for (int i= 0; i < resources.length; i++) {
+ System.out.println("\t" + resources[i]);
+ }
+ } else {
+ System.out.println("null resources");
+ }
+ }
+ if (resources == null || resources.length == 0) {
+ return;
+ }
+ final Set toAdd= new HashSet(resources.length);
+ IWorkspaceRunnable runnable= new IWorkspaceRunnable() {
+ public void run(IProgressMonitor monitor) throws CoreException {
+ for (int i = 0; i < resources.length; i++) {
+ IResource resource= resources[i];
+ if (!isControlled(resource)) {
+ toAdd.add(resource);
+ }
+ }
+ Map byParent= sortByParent(toAdd);
+
+ monitor.beginTask("Adding to control", 1000);
+ for (Iterator i= byParent.keySet().iterator(); i.hasNext();) {
+ IContainer parent= (IContainer) i.next();
+ Set controlledResources= (Set)fControlledResources.get(parent);
+ if (controlledResources == null) {
+ controlledResources= new HashSet(1);
+ fControlledResources.put(parent, controlledResources);
+ }
+ controlledResources.addAll((Set)byParent.get(parent));
+ writeControlFile(parent, monitor);
+ }
+ monitor.done();
+ }
+ };
+ run(runnable, monitor);
+ fireStateChanged(toAdd, false);
+ }
+
+ /**
+ * Removes the resources from the control of this provider.
+ */
+ public void removeFromControl(final IResource[] resources, IProgressMonitor monitor) {
+ if (PessimisticFilesystemProviderPlugin.getInstance().isDebugging()) {
+ System.out.println("Remove from control:");
+ if (resources != null) {
+ for (int i= 0; i < resources.length; i++) {
+ System.out.println("\t" + resources[i]);
+ }
+ } else {
+ System.out.println("null resources");
+ }
+ }
+ if (resources == null || resources.length == 0) {
+ return;
+ }
+ final Set toRemove= new HashSet(resources.length);
+ IWorkspaceRunnable runnable= new IWorkspaceRunnable() {
+ public void run(IProgressMonitor monitor) throws CoreException {
+ for (int i = 0; i < resources.length; i++) {
+ IResource resource= resources[i];
+ if (isControlled(resource)) {
+ toRemove.add(resource);
+ }
+ }
+ Map byParent= sortByParent(toRemove);
+
+ Set keys= byParent.keySet();
+ monitor.beginTask("Removing from control", 1000);
+ for (Iterator i= byParent.keySet().iterator(); i.hasNext();) {
+ IContainer parent= (IContainer) i.next();
+ Set controlledResources= (Set)fControlledResources.get(parent);
+ if (controlledResources == null) {
+ deleteControlFile(parent, monitor);
+ } else {
+ Set toRemove= (Set)byParent.get(parent);
+ controlledResources.removeAll(toRemove);
+ if (controlledResources.isEmpty()) {
+ fControlledResources.remove(parent);
+ deleteControlFile(parent, monitor);
+ } else {
+ writeControlFile(parent, monitor);
+ }
+ for (Iterator j= controlledResources.iterator(); j.hasNext();) {
+ IResource resource= (IResource) j.next();
+ if (!resource.exists()) {
+ j.remove();
+ }
+ }
+ }
+ }
+ monitor.done();
+ }
+ };
+ run(runnable, monitor);
+ fireStateChanged(toRemove, false);
+ }
+
+ /*
+ * Returns a map of IContainer -> Set of IResource.
+ */
+ private Map sortByParent(Set resources) {
+ Map byParent= new HashMap(1);
+ for (Iterator i = resources.iterator(); i.hasNext();) {
+ IResource resource= (IResource) i.next();
+ IContainer parent= resource.getParent();
+ Set set= (Set)byParent.get(parent);
+ if (set == null) {
+ set= new HashSet(1);
+ byParent.put(parent, set);
+ }
+ set.add(resource);
+ }
+ return byParent;
+ }
+
+ /*
+ * Deletes the control file for the given container.
+ */
+ private void deleteControlFile(final IContainer container, IProgressMonitor monitor) {
+ IWorkspaceRunnable runnable= new IWorkspaceRunnable() {
+ public void run(IProgressMonitor monitor) throws CoreException {
+ IFile controlFile= getControlFile(container, monitor);
+ monitor.beginTask("Deleting control file " + controlFile, 1);
+ if (controlFile.exists()) {
+ controlFile.delete(true, false, monitor);
+ }
+ monitor.done();
+ }
+ };
+ run(runnable, monitor);
+ }
+
+ /*
+ * Answers the control file for the given container. If the control
+ * file exists, but is a directory, it will be deleted!
+ */
+ private IFile getControlFile(IContainer container, IProgressMonitor monitor) throws CoreException {
+ IResource child= container.findMember(CONTROL_FILE_NAME);
+ if (child != null) {
+ if (child.getType() == IResource.FILE) {
+ return (IFile)child;
+ } else {
+ child.delete(true, monitor);
+ }
+ }
+ IFile controlFile= container.getFile(new Path(CONTROL_FILE_NAME));
+ monitor.beginTask("Creating control file " + controlFile, 2);
+ controlFile.create(new ByteArrayInputStream(new byte[0]), true, monitor);
+ controlFile.setDerived(true);
+ monitor.done();
+ return controlFile;
+ }
+
+ /*
+ * Reads the contents of a control file, answering the set of
+ * resources that was specified in the file.
+ */
+ private Set readControlFile(IFile controlFile) {
+ Set controlledResources= new HashSet(1);
+ if (controlFile.exists()) {
+ InputStream in= null;
+ try {
+ try {
+ in= ((IFile)controlFile).getContents(true);
+ } catch (CoreException e) {
+ PessimisticFilesystemProviderPlugin.getInstance().logError(e, "Could not open stream on control file: " + controlFile);
+ }
+ DataInputStream dIn= new DataInputStream(in);
+ int count= 0;
+ try {
+ count= dIn.readInt();
+ } catch (IOException e) {
+ // could be empty
+ }
+ if (count > 0) {
+ try {
+ for(int i= 0; i < count; i++) {
+ String name= dIn.readUTF();
+ IResource resource= getProject().findMember(new Path(name));
+ if (resource != null) {
+ controlledResources.add(resource);
+ }
+ }
+ } catch (IOException e) {
+ // corrupt control file
+ try {
+ controlFile.delete(true, null);
+ } catch (CoreException ce) {
+ PessimisticFilesystemProviderPlugin.getInstance().logError(ce, "Could not delete corrupt control file: " + controlFile);
+ }
+ }
+ }
+ } finally {
+ if (in != null) {
+ try {
+ in.close();
+ } catch (IOException e) {
+ PessimisticFilesystemProviderPlugin.getInstance().logError(e, "Problems closing input stream on control file: " + controlFile);
+ }
+ }
+ }
+ }
+ return controlledResources;
+ }
+
+ /*
+ * Writes the currently controled resources to the control file for the container.
+ */
+ private void writeControlFile(IContainer container, IProgressMonitor monitor) throws CoreException {
+ IFile controlFile= getControlFile(container, monitor);
+ Set controlledResources= (Set)fControlledResources.get(container);
+ InputStream contents= generateControlFileContents(controlledResources);
+ monitor.beginTask("Writing control file " + controlFile, 1000);
+ if (contents == null) {
+ controlFile.delete(true, false, monitor);
+ } else {
+ controlFile.setContents(contents, true, false, monitor);
+ }
+ monitor.done();
+ }
+
+ /*
+ * Generates an InputStream on a byte array which specifies
+ * the resources given in controlledResources.
+ */
+ private InputStream generateControlFileContents(Set controlledResources) {
+ if (controlledResources == null || controlledResources.isEmpty()) {
+ return null;
+ }
+ ByteArrayOutputStream byteOut= new ByteArrayOutputStream();
+ DataOutputStream out= new DataOutputStream(byteOut);
+ try {
+ out.writeInt(controlledResources.size());
+ for (Iterator i= controlledResources.iterator(); i.hasNext();) {
+ IResource resource= (IResource) i.next();
+ out.writeUTF(resource.getProjectRelativePath().toString());
+ }
+ out.flush();
+ } catch (IOException e) {
+ PessimisticFilesystemProviderPlugin.getInstance().logError(e, "Unexpected problems during content generation");
+ }
+ return new ByteArrayInputStream(byteOut.toByteArray());
+ }
+
+ /*
+ * @see IProjectNature#setProject(IProject)
+ */
+ public void setProject(IProject project) {
+ if (PessimisticFilesystemProviderPlugin.getInstance().isDebugging()) {
+ System.out.println("Set project to " + project);
+ }
+ super.setProject(project);
+ configureProject();
+ }
+
+ /*
+ * @see IRepositoryProvider#getID()
+ */
+ public String getID() {
+ return PessimisticFilesystemProviderPlugin.NATURE_ID;
+ }
+
+ /*
+ * @see IRepositoryProvider#getFileModificationValidator()
+ */
+ public IFileModificationValidator getFileModificationValidator() {
+ return validator;
+ }
+
+ /*
+ * @see IRepositoryProvider#deconfigure()
+ */
+ public void deconfigure() {
+ if (PessimisticFilesystemProviderPlugin.getInstance().isDebugging()) {
+ System.out.println("Deconfigure " + getProject());
+ }
+
+ fControlledResources.clear();
+ fireStateChanged(getSubtreeMembers(getProject()), true);
+ }
+
+ /*
+ * @see IRepositoryProvider#configure()
+ */
+ public void configureProject() {
+ if (PessimisticFilesystemProviderPlugin.getInstance().isDebugging()) {
+ System.out.println("Configure " + getProject());
+ }
+
+ readControlFiles();
+ fireStateChanged(getSubtreeMembers(getProject()), true);
+ }
+
+ /*
+ * Reads the control files located in the project
+ */
+ private void readControlFiles() {
+ IProject project= getProject();
+ Set set= new HashSet(1);
+ set.add(project);
+ fControlledResources.put(project.getParent(), set);
+ try {
+ getProject().accept(new IResourceVisitor() {
+ public boolean visit(IResource resource) throws CoreException {
+ if (resource.getType() == IResource.FILE) {
+ if (CONTROL_FILE_NAME.equals(resource.getName())) {
+ Set controlledResources= readControlFile((IFile)resource);
+ fControlledResources.put(resource.getParent(), controlledResources);
+ }
+ return false;
+ }
+ return true;
+ }
+ });
+ } catch (CoreException e) {
+ PessimisticFilesystemProviderPlugin.getInstance().logError(e, "Problems traversing resource tree");
+ }
+ }
+
+ /**
+ * Checks the resources in by marking them read-only.
+ */
+ public void checkin(final IResource[] resources, IProgressMonitor monitor) {
+ if (PessimisticFilesystemProviderPlugin.getInstance().isDebugging()) {
+ System.out.println("Check in:");
+ if (resources != null) {
+ for (int i= 0; i < resources.length; i++) {
+ System.out.println("\t" + resources[i]);
+ }
+ } else {
+ System.out.println("null resources");
+ }
+ }
+ if (resources == null || resources.length == 0) {
+ return;
+ }
+ final Set modified= new HashSet(1);
+ IWorkspaceRunnable runnable= new IWorkspaceRunnable() {
+ public void run(IProgressMonitor monitor) throws CoreException {
+ monitor.beginTask("Checking in resources", 1000);
+ for(int i= 0; i < resources.length; i++) {
+ IResource resource= resources[i];
+ if (isControlled(resource)) {
+ if (resource.exists()) {
+ resource.setReadOnly(true);
+ modified.add(resource);
+ }
+ }
+ }
+ monitor.done();
+ }
+ };
+ run(runnable, monitor);
+ fireStateChanged(modified, false);
+ }
+
+ /**
+ * Unchecks the resources out. In this provider this operation is
+ * equivalent to checkin.
+ *
+ * @see PessimisticFilesystemProvider#checkin(IResource[], IProgressMonitor)
+ */
+ public void uncheckout(final IResource[] resources, IProgressMonitor monitor) {
+ if (PessimisticFilesystemProviderPlugin.getInstance().isDebugging()) {
+ System.out.println("Uncheckout:");
+ if (resources != null) {
+ for (int i= 0; i < resources.length; i++) {
+ System.out.println("\t" + resources[i]);
+ }
+ } else {
+ System.out.println("null resources");
+ }
+ }
+ if (resources == null || resources.length == 0) {
+ return;
+ }
+ final Set modified= new HashSet(1);
+ IWorkspaceRunnable runnable= new IWorkspaceRunnable() {
+ public void run(IProgressMonitor monitor) throws CoreException {
+ monitor.beginTask("Unchecking in resources", 1000);
+ for(int i= 0; i < resources.length; i++) {
+ IResource resource= resources[i];
+ if (isControlled(resource)) {
+ if (resource.exists()) {
+ resource.setReadOnly(true);
+ modified.add(resource);
+ }
+ }
+ }
+ monitor.done();
+ }
+ };
+ run(runnable, monitor);
+ fireStateChanged(modified, false);
+ }
+
+ /**
+ * Checks the resources out by marking the resources read-write.
+ */
+ public void checkout(final IResource[] resources, IProgressMonitor monitor) {
+ if (PessimisticFilesystemProviderPlugin.getInstance().isDebugging()) {
+ System.out.println("Check out:");
+ if (resources != null) {
+ for (int i= 0; i < resources.length; i++) {
+ System.out.println("\t" + resources[i]);
+ }
+ } else {
+ System.out.println("null resources");
+ }
+ }
+ if (resources == null || resources.length == 0) {
+ return;
+ }
+ final Set modified= new HashSet(1);
+ IWorkspaceRunnable runnable= new IWorkspaceRunnable() {
+ public void run(IProgressMonitor monitor) throws CoreException {
+ monitor.beginTask("Checking out resources", 1000);
+ for(int i= 0; i < resources.length; i++) {
+ IResource resource= resources[i];
+ if (isControlled(resource)) {
+ if(resource.exists()) {
+ resource.setReadOnly(false);
+ modified.add(resource);
+ }
+ }
+ }
+ monitor.done();
+ }
+ };
+ run(runnable, monitor);
+ fireStateChanged(modified, false);
+ }
+
+ /**
+ * Answers <code>true</code> if and only if the resource is
+ * not <code>null</code>, controlled, not ignored, and checked out.
+ * Otherwise this method answers <code>false</code>.
+ */
+ public boolean isCheckedout(IResource resource) {
+ if (PessimisticFilesystemProviderPlugin.getInstance().isDebugging()) {
+ System.out.println("Is checked out: " + resource);
+ }
+ if (resource == null) {
+ return false;
+ }
+ if (!isControlled(resource)) {
+ return false;
+ }
+ if (isIgnored(resource)) {
+ return false;
+ }
+ return !resource.isReadOnly();
+ }
+
+ /**
+ * Answers <code>true</code> if the resource is not <code>null</code>,
+ * and is controlled, <code>false</code> otherwise.
+ */
+ public boolean isControlled(IResource resource) {
+ if (PessimisticFilesystemProviderPlugin.getInstance().isDebugging()) {
+ System.out.println("Is controlled: " + resource);
+ }
+ if (resource == null) {
+ return false;
+ }
+ IProject project= getProject();
+ if (!project.equals(resource.getProject())) {
+ return false;
+ }
+ Set controlled= (Set)fControlledResources.get(resource.getParent());
+ if (controlled == null) {
+ return false;
+ }
+ return controlled.contains(resource);
+ }
+
+ /**
+ * Answers <code>true</code> if the resource is ignored.
+ * Resources are ignored if they are derived.
+ * Will return <code>false</code> when a resource is derived, but
+ * has explicitly been added to the control of this provider.
+ */
+ public boolean isIgnored (IResource resource) {
+ if (PessimisticFilesystemProviderPlugin.getInstance().isDebugging()) {
+ System.out.println("Is ignored: " + resource);
+ }
+ if (resource.isDerived()) {
+ if (isControlled(resource)) {
+ return false;
+ }
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Answers <code>true</code> if the preference to change the content
+ * of the file has been set to <code>true</code>, <code>false</code>
+ * otherwise.
+ */
+ public boolean hasContentChanged(IResource resource) {
+ if (PessimisticFilesystemProviderPlugin.getInstance().isDebugging()) {
+ System.out.println("Has content change: " + resource);
+ }
+
+ IPreferenceStore preferences= PessimisticFilesystemProviderPlugin.getInstance().getPreferenceStore();
+ boolean change= preferences.getBoolean(IPessimisticFilesystemConstants.PREF_TOUCH_DURING_VALIDATE_EDIT);
+ if (change) {
+ try {
+ resource.touch(null);
+ } catch (CoreException e) {
+ PessimisticFilesystemProviderPlugin.getInstance().logError(e, "Problems touching resource: " + resource);
+ }
+ }
+ return change;
+ }
+
+
+ /*
+ * Notifies listeners that the state of the resources has changed.
+ *
+ * @param resources A collection of resources whose state has changed.
+ * @param queueAfterWorkspaceOperation If <code>true</code>, indicates that the
+ * notification should occur after the current workspace runnable
+ * has completed.
+ */
+ private void fireStateChanged(final Collection resources, boolean queueAfterWorkspaceOperation) {
+ if (resources == null || resources.isEmpty()) {
+ return;
+ }
+
+ if (queueAfterWorkspaceOperation) {
+ Thread t= new Thread(new Runnable() {
+ public void run() {
+ try {
+ ResourcesPlugin.getWorkspace().run(
+ new IWorkspaceRunnable() {
+ public void run(IProgressMonitor monitor) throws CoreException {
+ }
+ },
+ null);
+ } catch (CoreException e) {
+ PessimisticFilesystemProviderPlugin.getInstance().logError(e, "Problem during empty runnable");
+ }
+ fireStateChanged(resources, false);
+ }
+ });
+ t.start();
+ } else {
+ PessimisticFilesystemProviderPlugin.getInstance().fireResourcesChanged(
+ (IResource[])resources.toArray(new IResource[resources.size()]));
+ }
+ }
+
+ /*
+ * Answers a collection of all of the resources contained below
+ * the given resource and the resource itself.
+ */
+ private Collection getSubtreeMembers(IResource resource) {
+ final Set resources= new HashSet(1);
+ IResourceVisitor visitor= new IResourceVisitor() {
+ public boolean visit(IResource resource) throws CoreException {
+ switch (resource.getType()) {
+ case IResource.PROJECT:
+ case IResource.FOLDER:
+ case IResource.FILE:
+ resources.add(resource);
+ return true;
+ }
+ return true;
+ }
+ };
+ try {
+ resource.accept(visitor);
+ } catch (CoreException e) {
+ PessimisticFilesystemProviderPlugin.getInstance().logError(e, "Problem during resource visiting");
+ }
+ return resources;
+ }
+
+ /*
+ * Runs a workspace operation reporting errors to the PessimisticFilesystemProviderPlugin.
+ */
+ private void run(IWorkspaceRunnable runnable, IProgressMonitor monitor) {
+ try {
+ ResourcesPlugin.getWorkspace().run(runnable, monitor);
+ } catch (CoreException e) {
+ PessimisticFilesystemProviderPlugin.getInstance().logError(e, "Problems during workspace operation.");
+ }
+ }
+}
+
diff --git a/examples/org.eclipse.team.examples.filesystem/src/org/eclipse/team/examples/pessimistic/PessimisticFilesystemProviderPlugin.java b/examples/org.eclipse.team.examples.filesystem/src/org/eclipse/team/examples/pessimistic/PessimisticFilesystemProviderPlugin.java
new file mode 100644
index 000000000..df787013f
--- /dev/null
+++ b/examples/org.eclipse.team.examples.filesystem/src/org/eclipse/team/examples/pessimistic/PessimisticFilesystemProviderPlugin.java
@@ -0,0 +1,152 @@
+/*
+ * Copyright (c) 2002 IBM Corp. All rights reserved.
+ * This file is made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ */
+package org.eclipse.team.examples.pessimistic;
+
+import java.util.*;
+
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.runtime.*;
+import org.eclipse.jface.preference.IPreferenceStore;
+import org.eclipse.ui.plugin.AbstractUIPlugin;
+
+/**
+ * The plugin for the <code>PessimisticFilesystemProvider</code>.
+ */
+public class PessimisticFilesystemProviderPlugin extends AbstractUIPlugin {
+ /*
+ * Singleton instance.
+ */
+ private static PessimisticFilesystemProviderPlugin instance;
+ /*
+ * The resource change listener which notifies the provider of
+ * added and deleted files.
+ */
+ private ResourceChangeListener fListener;
+ /*
+ * The provider listeners
+ */
+ private List fListeners;
+
+ /**
+ * The plugin identifier
+ */
+ public static final String PLUGIN_ID = "org.eclipse.team.examples.pessimistic";
+ /**
+ * The nature identifier.
+ */
+ public static final String NATURE_ID = PLUGIN_ID + ".pessimisticnature";
+
+ /**
+ * Contstructor required by plugin lifecycle.
+ */
+ public PessimisticFilesystemProviderPlugin(IPluginDescriptor pluginDescriptor) {
+ super(pluginDescriptor);
+ instance = this;
+ fListeners= new ArrayList(1);
+ //setDebugging(true);
+ }
+
+ /**
+ * Answers the singleton instance of this plugin.
+ */
+ public static PessimisticFilesystemProviderPlugin getInstance() {
+ return instance;
+ }
+
+ /**
+ * Initializes the default preferences for this plugin.
+ */
+ protected void initializeDefaultPreferences(IPreferenceStore store) {
+ store.setDefault(
+ IPessimisticFilesystemConstants.PREF_CHECKED_IN_FILES_EDITED,
+ IPessimisticFilesystemConstants.OPTION_PROMPT);
+ store.setDefault(
+ IPessimisticFilesystemConstants.PREF_CHECKED_IN_FILES_EDITED_NOPROMPT,
+ IPessimisticFilesystemConstants.OPTION_AUTOMATIC);
+ store.setDefault(
+ IPessimisticFilesystemConstants.PREF_CHECKED_IN_FILES_SAVED,
+ IPessimisticFilesystemConstants.OPTION_DO_NOTHING);
+ store.setDefault(
+ IPessimisticFilesystemConstants.PREF_ADD_TO_CONTROL,
+ IPessimisticFilesystemConstants.OPTION_PROMPT);
+ store.setDefault(IPessimisticFilesystemConstants.PREF_FAIL_VALIDATE_EDIT, false);
+ store.setDefault(IPessimisticFilesystemConstants.PREF_TOUCH_DURING_VALIDATE_EDIT, true);
+ }
+
+ /**
+ * Convenience method for logging errors.
+ */
+ public void logError(Throwable exception, String message) {
+ String pluginId= getDescriptor().getUniqueIdentifier();
+ Status status= new Status(Status.ERROR, pluginId, Status.OK, message, exception);
+ getLog().log(status);
+ if (isDebugging()) {
+ System.out.println(message);
+ exception.printStackTrace();
+ }
+ }
+
+ /**
+ * Starts the resource listener.
+ *
+ * @see Plugin#startup()
+ */
+ public void startup() throws CoreException {
+ fListener= new ResourceChangeListener();
+ fListener.startup();
+ super.startup();
+ }
+
+ /**
+ * Stops the resource listener.
+ *
+ * @see Plugin#startup()
+ */
+ public void shutdown() throws CoreException {
+ fListener.shutdown();
+ fListener= null;
+ super.shutdown();
+ }
+
+ /**
+ * Notifies the registered <code>IResourceStateListener</code> objects
+ * that the repository state for the resources has changed.
+ *
+ * @param resources Collection of resources that have changed.
+ */
+ public void fireResourcesChanged(IResource[] resources) {
+ if (resources == null || resources.length == 0 || fListeners.isEmpty())
+ return;
+ for (Iterator i= fListeners.iterator(); i.hasNext();) {
+ IResourceStateListener listener= (IResourceStateListener) i.next();
+ listener.stateChanged(resources);
+ }
+ }
+
+ /**
+ * Adds the listener to the list of listeners that are notified when
+ * the repository state of resources change.
+ *
+ * @param listener
+ */
+ public void addProviderListener(IResourceStateListener listener) {
+ if (fListeners.contains(listener))
+ return;
+ fListeners.add(listener);
+ }
+
+
+ /**
+ * Removes the listener from the list of listeners that are notified when
+ * the repository state of resources change.
+ *
+ * @param listener
+ */
+ public void removeProviderListener(IResourceStateListener listener) {
+ fListeners.remove(listener);
+ }
+} \ No newline at end of file
diff --git a/examples/org.eclipse.team.examples.filesystem/src/org/eclipse/team/examples/pessimistic/PessimisticModificationValidator.java b/examples/org.eclipse.team.examples.filesystem/src/org/eclipse/team/examples/pessimistic/PessimisticModificationValidator.java
new file mode 100644
index 000000000..1177f6282
--- /dev/null
+++ b/examples/org.eclipse.team.examples.filesystem/src/org/eclipse/team/examples/pessimistic/PessimisticModificationValidator.java
@@ -0,0 +1,326 @@
+/*
+ * Copyright (c) 2002 IBM Corp. All rights reserved.
+ * This file is made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ */
+package org.eclipse.team.examples.pessimistic;
+
+import java.util.*;
+
+import org.eclipse.core.resources.*;
+import org.eclipse.core.runtime.*;
+import org.eclipse.jface.preference.IPreferenceStore;
+import org.eclipse.jface.viewers.ILabelProvider;
+import org.eclipse.jface.viewers.ITreeContentProvider;
+import org.eclipse.jface.window.Window;
+import org.eclipse.swt.widgets.*;
+import org.eclipse.ui.dialogs.CheckedTreeSelectionDialog;
+import org.eclipse.ui.model.WorkbenchLabelProvider;
+import org.eclipse.ui.views.navigator.ResourceSorter;
+
+/**
+ * The <code>PessimisticModificationValidator</code> is an
+ * implementation of the <code>IFileModificationValidator</code> for the
+ * <code>PessimisticFilesystemProvider</code>.
+ *
+ * @see PessimiticFilesystemProvider
+ * @see IFileModificationValidator
+ */
+public class PessimisticModificationValidator
+ implements IFileModificationValidator {
+ /*
+ * The provider for this validator
+ */
+ private PessimisticFilesystemProvider fProvider;
+
+ public PessimisticModificationValidator(PessimisticFilesystemProvider provider) {
+ fProvider= provider;
+ }
+
+ /**
+ * @see IFileModificationValidator#validateEdit(IFile[], Object)
+ */
+ public IStatus validateEdit(IFile[] files, Object context) {
+ if (files.length == 0) {
+ return new Status( IStatus.OK, getUid(), IStatus.OK, "OK", null);
+ }
+
+ Set checkOut = new HashSet();
+ int reloadCount = 0;
+ int checkoutFailCount = 0;
+
+ Map validateEditStatusMap= new HashMap(files.length);
+
+ for ( int i = 0 ; i < files.length; i++ ) {
+ IFile file= files[i];
+
+ if (fProvider.isControlled(file) ) {
+ if (fProvider.isCheckedout(file)) {
+ setValidateEditStatus(validateEditStatusMap, file,
+ IPessimisticFilesystemConstants.STATUS_OK_TO_EDIT );
+ } else {
+ checkOut.add(file);
+ }
+ } else {
+ setValidateEditStatus(validateEditStatusMap, file,
+ IPessimisticFilesystemConstants.STATUS_OK_TO_EDIT);
+ }
+ }
+
+ if (!checkOut.isEmpty()) {
+ if (context != null) {
+ boolean shouldFail= shouldFailValidateEdit();
+ checkout(checkOut, IPessimisticFilesystemConstants.PREF_CHECKED_IN_FILES_EDITED, shouldFail, context);
+ if (shouldFail) {
+ return new Status( IStatus.ERROR, getUid(), IStatus.ERROR, "Fail Validate Edit Preference true", null);
+ }
+ } else {
+ if (isAutomaticCheckout()) {
+ if (shouldFailValidateEdit()) {
+ return new Status( IStatus.ERROR, getUid(), IStatus.ERROR, "Fail Validate Edit Preference true", null);
+ }
+
+ checkout(checkOut);
+ }
+ }
+
+ for (Iterator i= checkOut.iterator(); i.hasNext(); ) {
+ IFile file = (IFile) i.next();
+
+ if ( fProvider.isCheckedout(file) ) {
+ if ( !fProvider.hasContentChanged(file) ) {
+ setValidateEditStatus(validateEditStatusMap, file,
+ IPessimisticFilesystemConstants.STATUS_OK_TO_EDIT );
+ } else {
+ reloadCount++;
+ setValidateEditStatus(validateEditStatusMap, file,
+ IPessimisticFilesystemConstants.STATUS_PROMPT_FOR_RELOAD );
+ }
+ } else {
+ checkoutFailCount++;
+ }
+ }
+ }
+
+ if (reloadCount + checkoutFailCount == 0) {
+ return new Status( IStatus.OK, getUid(), IStatus.OK, "OK", null);
+ }
+
+ if (checkoutFailCount == files.length) {
+ return new Status( IStatus.ERROR, getUid(), IStatus.ERROR, "NOTOK", null);
+ }
+
+ IStatus children[] = new Status[ files.length ];
+
+ int mask = IPessimisticFilesystemConstants.STATUS_OK_TO_EDIT |
+ IPessimisticFilesystemConstants.STATUS_PROMPT_FOR_RELOAD;
+
+ for (int i = 0; i < files.length; i++) {
+ int result = getValidateEditStatus(validateEditStatusMap, files[i]);
+ if ((result & mask) != 0) {
+ children[i] = new Status( IStatus.OK, getUid(), IStatus.OK, "OK", null);
+ } else {
+ children[i] = new Status( IStatus.ERROR, getUid(), IStatus.ERROR, "NOTOK", null);
+ }
+ }
+ return new MultiStatus( getUid(), IStatus.OK, children, "MULTISTATUS", null);
+ }
+
+ /**
+ * @see IFileModificationValidator#validateSave(IFile)
+ */
+ public IStatus validateSave(IFile file) {
+ int checkedInFilesSaved = getPreferences().getInt(IPessimisticFilesystemConstants.PREF_CHECKED_IN_FILES_SAVED);
+ if (checkedInFilesSaved == IPessimisticFilesystemConstants.OPTION_DO_NOTHING) {
+ return new Status( IStatus.OK, getUid(), IStatus.OK, "", null);
+ }
+
+
+ IStatus status = new Status( IStatus.OK, getUid(), IStatus.OK,
+ "File is writable", null);
+
+ if (!fProvider.isControlled(file)) {
+ return status;
+ }
+
+ if (fProvider.isIgnored(file)) {
+ return status;
+ }
+
+ if (fProvider.isCheckedout(file)) {
+ return status;
+ }
+ Set files= new HashSet(1);
+ files.add(file);
+
+ checkout(files, IPessimisticFilesystemConstants.PREF_CHECKED_IN_FILES_SAVED, false, null);
+
+ if (fProvider.isCheckedout(file)) {
+ return status;
+ }
+ return new Status(
+ IStatus.ERROR,
+ getUid(),
+ IStatus.ERROR,
+ file.getProjectRelativePath() + " could not be checked out",
+ null);
+ }
+
+ /*
+ * Convenience method to get the plugin id
+ */
+ private String getUid() {
+ return PessimisticFilesystemProviderPlugin.PLUGIN_ID;
+ }
+
+ /*
+ * Convenience method to answer if the fail validate edit preference
+ * has been set.
+ */
+ private boolean shouldFailValidateEdit() {
+ return getPreferences().getBoolean(IPessimisticFilesystemConstants.PREF_FAIL_VALIDATE_EDIT);
+ }
+
+ /*
+ * Convenience method to answer if the check out preference is set to automatic.
+ */
+ private boolean isAutomaticCheckout() {
+ return getPreferences().getInt(IPessimisticFilesystemConstants.PREF_CHECKED_IN_FILES_EDITED_NOPROMPT) == IPessimisticFilesystemConstants.OPTION_AUTOMATIC;
+ }
+
+ /*
+ * Optionally prompts the user to select which resources should be
+ * checked out, and then checks the selected resources.
+ */
+ private void promptAndCheckout(Set resources, boolean beQuiet, boolean shouldFail, Object context) {
+ if (resources.isEmpty()) {
+ return;
+ }
+
+ Set temp= new HashSet(resources.size());
+ for(Iterator i= resources.iterator(); i.hasNext(); ) {
+ IFile resource= (IFile)i.next();
+ if (fProvider.isControlled(resource) && !fProvider.isCheckedout(resource))
+ temp.add(resource);
+ }
+ resources= temp;
+
+ if (!beQuiet && !resources.isEmpty()) {
+ final Shell shell= getShell(context);
+ if (shell != null && !shell.isDisposed()) {
+ Display display = shell.getDisplay();
+ final Set[] result = {resources};
+ display.syncExec(new Runnable() {
+ public void run() {
+ ILabelProvider labelProvider= new WorkbenchLabelProvider();
+ Object[] resourceArray= result[0].toArray();
+ ITreeContentProvider contentProvider= new ResourceSetContentProvider(result[0]);
+ CheckedTreeSelectionDialog dialog= new CheckedTreeSelectionDialog(shell, labelProvider, contentProvider);
+ dialog.setMessage("Select resources to be checked out.");
+ dialog.setTitle("Check out resources");
+ dialog.setContainerMode(true);
+ dialog.setBlockOnOpen(true);
+ dialog.setSorter(new ResourceSorter(ResourceSorter.NAME));
+ dialog.setExpandedElements(resourceArray);
+ dialog.setInitialSelections(resourceArray);
+ dialog.setInput(ResourcesPlugin.getWorkspace().getRoot());
+ int status= dialog.open();
+ result[0]= null;
+ if (status == Window.OK) {
+ Object[] results= dialog.getResult();
+ result[0] = new HashSet(results.length);
+ for (int i= 0; i < results.length; i++) {
+ result[0].add(results[i]);
+ }
+ }
+ }
+ });
+ resources= result[0];
+ } else {
+ resources= null;
+ PessimisticFilesystemProviderPlugin.getInstance().logError(new RuntimeException(), "Context is invalid: " + context);
+ }
+ }
+
+ if (resources != null && !resources.isEmpty() && !shouldFail) {
+ checkout(resources);
+ }
+ }
+
+ /*
+ * Checks out the files contained in the resources set
+ */
+ private void checkout(Set resources) {
+ if (resources.isEmpty())
+ return;
+ IFile[] checkOut= new IFile[resources.size()];
+ resources.toArray(checkOut);
+ fProvider.checkout(checkOut, null);
+ }
+
+ /*
+ * Convenience method to get the plugin preferences.
+ */
+ private IPreferenceStore getPreferences() {
+ return PessimisticFilesystemProviderPlugin.getInstance().getPreferenceStore();
+ }
+
+ /*
+ * Checks out the files if necessary and if the preferences allow.
+ */
+ private void checkout(Set resources, String itemId, boolean shouldFail, Object context) {
+ if (resources.isEmpty()) {
+ return;
+ }
+
+ int preference= getPreferences().getInt(itemId);
+
+ if (preference == IPessimisticFilesystemConstants.OPTION_DO_NOTHING)
+ return;
+
+ boolean beQuiet= false;
+ if (preference == IPessimisticFilesystemConstants.OPTION_AUTOMATIC) {
+ beQuiet= true;
+ }
+ promptAndCheckout(resources, beQuiet, shouldFail, context);
+ }
+
+ /*
+ * Convenience method to set the validate edit status for the given resource.
+ */
+ private static void setValidateEditStatus(Map map, IFile resource, int status) {
+ map.put(resource, new Integer(status));
+ }
+
+ /*
+ * Convenience method to get the validate edit status for the given resource.
+ */
+ private static int getValidateEditStatus(Map map, IFile resource) {
+ Integer i= (Integer)map.get(resource);
+ if (i == null)
+ return 0;
+ return i.intValue();
+ }
+
+ /*
+ * Convenience method to get a shell from an object.
+ */
+ private Shell getShell(Object context) {
+ if (context instanceof Shell) {
+ return (Shell)context;
+ }
+
+ if (context instanceof Control) {
+ Control control= (Control)context;
+ return control.getShell();
+ }
+
+ if (context instanceof Widget) {
+ Widget widget= (Widget)context;
+ return widget.getDisplay().getActiveShell();
+ }
+
+ return null;
+ }
+}
diff --git a/examples/org.eclipse.team.examples.filesystem/src/org/eclipse/team/examples/pessimistic/ResourceChangeListener.java b/examples/org.eclipse.team.examples.filesystem/src/org/eclipse/team/examples/pessimistic/ResourceChangeListener.java
new file mode 100644
index 000000000..2a206beaa
--- /dev/null
+++ b/examples/org.eclipse.team.examples.filesystem/src/org/eclipse/team/examples/pessimistic/ResourceChangeListener.java
@@ -0,0 +1,294 @@
+/*
+ * Copyright (c) 2002 IBM Corp. All rights reserved.
+ * This file is made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ */
+package org.eclipse.team.examples.pessimistic;
+
+import java.util.*;
+
+import org.eclipse.core.resources.*;
+import org.eclipse.core.runtime.*;
+import org.eclipse.jface.window.Window;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.team.core.RepositoryProvider;
+import org.eclipse.ui.*;
+import org.eclipse.ui.dialogs.CheckedTreeSelectionDialog;
+import org.eclipse.ui.model.WorkbenchLabelProvider;
+import org.eclipse.ui.views.navigator.ResourceSorter;
+
+/**
+ * The <code>ResourceChangeListener</code> listens for resource changes
+ * and (optionally) prompts the user to add the new resources to the
+ * control of the repository provider.
+ */
+public class ResourceChangeListener implements IResourceDeltaVisitor, IResourceChangeListener {
+ /*
+ * Set of added resources
+ */
+ private Set fAdded;
+ /*
+ * Set of removed resources
+ */
+ private Set fRemoved;
+
+ public ResourceChangeListener() {
+ fAdded= new HashSet(1);
+ fRemoved= new HashSet(1);
+ }
+
+ /**
+ * Looks for the following changes:
+ * <ul>
+ * <li>Resources that are controlled and are removed</li>
+ * <li>Resources that are added under a managed project</li>
+ * </ul>
+ * @see org.eclipse.core.resources.IResourceDeltaVisitor#visit(IResourceDelta)
+ */
+ public boolean visit(IResourceDelta delta) throws CoreException {
+ IResource resource= delta.getResource();
+ if (resource != null) {
+ IProject project= resource.getProject();
+ if (project != null) {
+ PessimisticFilesystemProvider provider= (PessimisticFilesystemProvider)RepositoryProvider.getProvider(project, PessimisticFilesystemProviderPlugin.NATURE_ID);
+ if (provider == null)
+ return false;
+ if (provider.isControlled(resource)) {
+ switch (delta.getKind()) {
+ case IResourceDelta.CHANGED:
+ case IResourceDelta.ADDED:
+ return true;
+ case IResourceDelta.REMOVED:
+ fRemoved.add(resource);
+ return false;
+ }
+ } else {
+ switch (delta.getKind()) {
+ case IResourceDelta.CHANGED:
+ case IResourceDelta.REMOVED:
+ return true;
+ case IResourceDelta.ADDED:
+ // don't prompt for ignored resources
+ if (!provider.isIgnored(resource)) {
+ fAdded.add(resource);
+ }
+ return true;
+ }
+ }
+ } else {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /*
+ * Convenience method to return a resource array from a collection
+ */
+ private IResource[] toResourceArray(Collection collection) {
+ if (collection.isEmpty()) {
+ return new IResource[0];
+ }
+ IResource[] resources= new IResource[collection.size()];
+ collection.toArray(resources);
+ return resources;
+ }
+
+ /**
+ * @see IResourceChangeListener#resourceChanged(IResourceChangeEvent)
+ */
+ public void resourceChanged (IResourceChangeEvent event) {
+ try {
+ event.getDelta().accept(this);
+ } catch (CoreException e) {
+ e.printStackTrace();
+ PessimisticFilesystemProviderPlugin.getInstance().logError(e, "Exceptions during resource callback");
+ }
+
+ if (!fRemoved.isEmpty() || !fAdded.isEmpty()) {
+ final IWorkspaceRunnable workspaceRunnable= new IWorkspaceRunnable() {
+ public void run(final IProgressMonitor monitor) throws CoreException {
+ if (!fRemoved.isEmpty()) {
+ remove(monitor);
+ }
+
+ if (!fAdded.isEmpty()) {
+ add(monitor);
+ }
+ }
+ };
+ // must fork since we are in resource callback.
+ Runnable run= new Runnable() {
+ public void run() {
+ try {
+ IWorkspace workspace= ResourcesPlugin.getWorkspace();
+ if (workspace != null) {
+ workspace.run(workspaceRunnable, null);
+ }
+ } catch (CoreException e) {
+ PessimisticFilesystemProviderPlugin.getInstance().logError(e, "Problems encountered during attempt to add/remove control.");
+ }
+ }
+ };
+ new Thread(run).start();
+ }
+ }
+
+ /*
+ * Convenience method to get the preference for what to do
+ * when new resource have been detected.
+ */
+ private int getAddToControlPreference() {
+ Preferences preferences= PessimisticFilesystemProviderPlugin.getInstance().getPluginPreferences();
+ return preferences.getInt(IPessimisticFilesystemConstants.PREF_ADD_TO_CONTROL);
+ }
+
+ /*
+ * Adds the resources to the control of the provider.
+ * If the add to control preference is:
+ * do nothing - does not add
+ * automatic - adds all resources
+ * prompt - brings up a prompt which requests that the user
+ * select which resources to add
+ */
+ private void add(final IProgressMonitor monitor) {
+ switch (getAddToControlPreference()) {
+ case IPessimisticFilesystemConstants.OPTION_DO_NOTHING:
+ break;
+ case IPessimisticFilesystemConstants.OPTION_AUTOMATIC:
+ addToControl(fAdded, monitor);
+ break;
+ case IPessimisticFilesystemConstants.OPTION_PROMPT:
+ final Shell shell= getShell();
+ if (shell != null && !shell.isDisposed()) {
+ final Set resources= new HashSet(fAdded);
+ Runnable run= new Runnable() {
+ public void run() {
+ CheckedTreeSelectionDialog dialog= new CheckedTreeSelectionDialog(shell, new WorkbenchLabelProvider(), new ResourceSetContentProvider(resources));
+ dialog.setMessage("Select the resources to be added to the control of the repository.");
+ dialog.setTitle("Add resources to control");
+ dialog.setContainerMode(true);
+ dialog.setBlockOnOpen(true);
+ dialog.setSorter(new ResourceSorter(ResourceSorter.NAME));
+ Object[] resourceArray= resources.toArray();
+ dialog.setExpandedElements(resourceArray);
+ dialog.setInitialSelections(resourceArray);
+ dialog.setInput(ResourcesPlugin.getWorkspace().getRoot());
+ int status= dialog.open();
+
+ if (status == Window.OK) {
+ Object[] results= dialog.getResult();
+ if (results != null) {
+ Set resources= new HashSet(results.length);
+ for (int i= 0; i < results.length; i++) {
+ resources.add(results[i]);
+ }
+ addToControl(resources, monitor);
+ }
+ }
+ }
+ };
+
+ Display display= shell.getDisplay();
+ display.asyncExec(run);
+ } else {
+ PessimisticFilesystemProviderPlugin.getInstance().logError(null, "Could not aquire a shell");
+ }
+ break;
+ }
+ fAdded.clear();
+ }
+
+ /*
+ * Adds the resources to the control of the provider.
+ */
+ private void addToControl(Collection resources, final IProgressMonitor monitor) {
+ Map byProject= sortByProject(resources);
+ for (Iterator i= byProject.keySet().iterator(); i.hasNext();) {
+ IProject project= (IProject) i.next();
+ PessimisticFilesystemProvider provider= (PessimisticFilesystemProvider)RepositoryProvider.getProvider(project, PessimisticFilesystemProviderPlugin.NATURE_ID);
+ if (provider != null) {
+ provider.addToControl(toResourceArray((Collection)byProject.get(project)), monitor);
+ }
+
+ }
+ }
+
+ /*
+ * Removes the resources from the control of the provider.
+ */
+ private void remove(IProgressMonitor monitor) {
+ Map byProject= sortByProject(fRemoved);
+ for (Iterator i= byProject.keySet().iterator(); i.hasNext();) {
+ IProject project= (IProject) i.next();
+ PessimisticFilesystemProvider provider= (PessimisticFilesystemProvider)RepositoryProvider.getProvider(project, PessimisticFilesystemProviderPlugin.NATURE_ID);
+ if (provider != null) {
+ provider.removeFromControl(toResourceArray((Collection)byProject.get(project)), monitor);
+ }
+ }
+ fRemoved.clear();
+ }
+
+ /*
+ * Convenience method to sort the resources by project
+ */
+ private Map sortByProject(Collection resources) {
+ Map byProject= new HashMap();
+ for (Iterator i= resources.iterator(); i.hasNext();) {
+ IResource resource= (IResource) i.next();
+ IProject project= resource.getProject();
+ Set set= (Set)byProject.get(project);
+ if (set == null) {
+ set= new HashSet(1);
+ byProject.put(project, set);
+ }
+ set.add(resource);
+ }
+ return byProject;
+ }
+
+ /*
+ * Convenience method which answers a shell with which to prompt.
+ */
+ private Shell getShell() {
+ IWorkbench workbench= PlatformUI.getWorkbench();
+ if (workbench != null) {
+ IWorkbenchWindow window= workbench.getActiveWorkbenchWindow();
+ if (window == null) {
+ IWorkbenchWindow[] windows= workbench.getWorkbenchWindows();
+ if (windows != null && windows.length > 0) {
+ window= windows[0];
+ }
+ }
+ if (window != null) {
+ Shell shell= window.getShell();
+ if (shell == null)
+ return null;
+ if (shell.isDisposed())
+ return null;
+ return shell;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Starts listening for changes.
+ */
+ public void startup() {
+ ResourcesPlugin.getWorkspace().addResourceChangeListener(this, IResourceChangeEvent.POST_CHANGE);
+ if (PessimisticFilesystemProviderPlugin.getInstance().isDebugging())
+ System.out.println ("Resource callback registered");
+ }
+
+ /**
+ * Stops listening for changes.
+ */
+ public void shutdown() {
+ ResourcesPlugin.getWorkspace().removeResourceChangeListener(this);
+ if (PessimisticFilesystemProviderPlugin.getInstance().isDebugging())
+ System.out.println ("Resource callback unregistered");
+ }
+}
diff --git a/examples/org.eclipse.team.examples.filesystem/src/org/eclipse/team/examples/pessimistic/ResourceSetContentProvider.java b/examples/org.eclipse.team.examples.filesystem/src/org/eclipse/team/examples/pessimistic/ResourceSetContentProvider.java
new file mode 100644
index 000000000..0d3248b7c
--- /dev/null
+++ b/examples/org.eclipse.team.examples.filesystem/src/org/eclipse/team/examples/pessimistic/ResourceSetContentProvider.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2002 IBM Corp. All rights reserved.
+ * This file is made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ */
+package org.eclipse.team.examples.pessimistic;
+
+import java.util.*;
+
+import org.eclipse.core.resources.IResource;
+import org.eclipse.jface.viewers.ITreeContentProvider;
+import org.eclipse.jface.viewers.Viewer;
+
+public class ResourceSetContentProvider implements ITreeContentProvider {
+ private static final Object[] EMPTY_ARRAY= new Object[0];
+ private Map fResourceTree;
+ private IResource[] fRoots;
+
+ public ResourceSetContentProvider(Set resources) {
+ fResourceTree= new HashMap(1);
+ Set roots= new HashSet(resources);
+ for(Iterator i= resources.iterator(); i.hasNext(); ) {
+ IResource resource= (IResource)i.next();
+ if(resource.getType() == IResource.ROOT) {
+ continue; // root cannot be displayed
+ }
+ IResource parent= resource.getParent();
+ if (roots.contains(parent)) {
+ roots.remove(resource);
+ Set set= (Set)fResourceTree.get(parent);
+ if (set == null) {
+ set= new HashSet(1);
+ fResourceTree.put(parent, set);
+ }
+ set.add(resource);
+ }
+ }
+ fRoots= (IResource[])roots.toArray(new IResource[roots.size()]);
+ }
+
+ public Object[] getChildren(Object parentElement) {
+ Set set= (Set) fResourceTree.get(parentElement);
+ if (set != null) {
+ return set.toArray();
+ }
+ return EMPTY_ARRAY;
+ }
+
+ public Object getParent(Object element) {
+ if (element instanceof IResource) {
+ return ((IResource)element).getParent();
+ }
+ return null;
+ }
+
+ public boolean hasChildren(Object element) {
+ return fResourceTree.get(element) != null;
+ }
+
+ public Object[] getElements(Object inputElement) {
+ return fRoots;
+ }
+
+ public void dispose() {
+ fResourceTree= null;
+ }
+
+ public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
+ }
+
+}
diff --git a/examples/org.eclipse.team.examples.filesystem/src/org/eclipse/team/examples/pessimistic/ui/AddToControlAction.java b/examples/org.eclipse.team.examples.filesystem/src/org/eclipse/team/examples/pessimistic/ui/AddToControlAction.java
new file mode 100644
index 000000000..d7178d0f8
--- /dev/null
+++ b/examples/org.eclipse.team.examples.filesystem/src/org/eclipse/team/examples/pessimistic/ui/AddToControlAction.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2002 IBM Corp. All rights reserved.
+ * This file is made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ */
+package org.eclipse.team.examples.pessimistic.ui;
+
+import java.lang.reflect.InvocationTargetException;
+import java.util.*;
+
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.jface.action.IAction;
+import org.eclipse.jface.operation.IRunnableWithProgress;
+import org.eclipse.team.examples.pessimistic.PessimisticFilesystemProvider;
+
+/**
+ * Adds the selected resources and their parent resources to
+ * the control of the provider.
+ */
+public class AddToControlAction extends PessimisticProviderAction {
+
+ /**
+ * Collects the selected resources, sorts them by project
+ * and adds them to their respective repository providers.
+ *
+ * @see IActionDelegate#run(IAction)
+ */
+ public void run(IAction action) {
+ IResource[] resources= getSelectedResources();
+ if (resources == null || resources.length == 0)
+ return;
+ Set resourceSet= new HashSet(resources.length);
+ for(int i= 0; i < resources.length; i++) {
+ IResource resource= resources[i];
+ while (resource.getType() != IResource.PROJECT && !isControlled(resource)) {
+ resourceSet.add(resource);
+ resource= resource.getParent();
+ }
+ }
+ if (!resourceSet.isEmpty()) {
+ final Map byProject= sortByProject(resourceSet);
+ IRunnableWithProgress runnable= new IRunnableWithProgress() {
+ public void run(IProgressMonitor monitor)
+ throws InvocationTargetException, InterruptedException {
+ for (Iterator i= byProject.keySet().iterator(); i.hasNext();) {
+ IProject project= (IProject) i.next();
+ PessimisticFilesystemProvider provider= getProvider(project);
+ if (provider != null) {
+ Set set= (Set)byProject.get(project);
+ IResource[] resources= new IResource[set.size()];
+ set.toArray(resources);
+ provider.addToControl(resources, monitor);
+ }
+ }
+ }
+ };
+ runWithProgressDialog(runnable);
+ }
+ }
+
+ /**
+ * Answers <code>true</code> if the selected resource is not
+ * a project (or the workspace root) and is not controlled.
+ *
+ * @see PessimisticProviderAction#shouldEnableFor(IResource)
+ */
+ protected boolean shouldEnableFor(IResource resource) {
+ if (resource == null) {
+ return false;
+ }
+ if ((resource.getType() & (IResource.ROOT | IResource.PROJECT)) != 0) {
+ return false;
+ }
+ PessimisticFilesystemProvider provider= getProvider(resource);
+ if (provider == null)
+ return false;
+ return !provider.isControlled(resource);
+ }
+
+}
diff --git a/examples/org.eclipse.team.examples.filesystem/src/org/eclipse/team/examples/pessimistic/ui/BlankPage.java b/examples/org.eclipse.team.examples.filesystem/src/org/eclipse/team/examples/pessimistic/ui/BlankPage.java
new file mode 100644
index 000000000..e7be75fc7
--- /dev/null
+++ b/examples/org.eclipse.team.examples.filesystem/src/org/eclipse/team/examples/pessimistic/ui/BlankPage.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2002 IBM Corp. All rights reserved.
+ * This file is made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ */
+package org.eclipse.team.examples.pessimistic.ui;
+
+import org.eclipse.jface.wizard.WizardPage;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Composite;
+
+/**
+ * A wizard page that is empty to workaround a bug.
+ */
+public class BlankPage extends WizardPage {
+
+ /**
+ * Creates a blank page telling the user what is about to happen.
+ */
+ public BlankPage() {
+ super("AddPessimisticFilesystemSupport");
+ setTitle("Pessimistic filesystem provider");
+ setDescription("Add pessimistic filesystem provider support to this project");
+ setPageComplete(true);
+ }
+
+ /**
+ * Creates an empty control.
+ */
+ public void createControl(Composite parent) {
+ Composite client = new Composite(parent, SWT.NULL);
+ GridLayout layout = new GridLayout();
+ client.setLayout(layout);
+ setControl(client);
+ }
+} \ No newline at end of file
diff --git a/examples/org.eclipse.team.examples.filesystem/src/org/eclipse/team/examples/pessimistic/ui/CheckInAction.java b/examples/org.eclipse.team.examples.filesystem/src/org/eclipse/team/examples/pessimistic/ui/CheckInAction.java
new file mode 100644
index 000000000..fa4dd3759
--- /dev/null
+++ b/examples/org.eclipse.team.examples.filesystem/src/org/eclipse/team/examples/pessimistic/ui/CheckInAction.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2002 IBM Corp. All rights reserved.
+ * This file is made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ */
+package org.eclipse.team.examples.pessimistic.ui;
+
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.team.examples.pessimistic.PessimisticFilesystemProvider;
+
+/**
+ * Performs a check in on the selected resources. If a folder is
+ * selected all of its children are recursively checked in.
+ */
+public class CheckInAction extends SourceManagementAction {
+
+ /**
+ * Answers <code>true</code> if and only if the resource is
+ * not null, controlled, not ignored, and is checked out.
+ *
+ * @see PessimisticProviderAction#shouldEnableFor(IResource)
+ */
+ protected boolean shouldEnableFor(IResource resource) {
+ if (resource == null)
+ return false;
+ PessimisticFilesystemProvider provider= getProvider(resource);
+ if (provider == null)
+ return false;
+ if (!provider.isControlled(resource))
+ return false;
+ if (provider.isIgnored(resource))
+ return false;
+ return provider.isCheckedout(resource);
+ }
+
+ /*
+ * @see SourceControlAction#manageResources(PessimisticFilesystemProvider, IResource[], IProgressMonitor)
+ */
+ protected void manageResources(PessimisticFilesystemProvider provider, IResource[] resources, IProgressMonitor monitor) {
+ provider.checkin(resources, monitor);
+ }
+
+}
diff --git a/examples/org.eclipse.team.examples.filesystem/src/org/eclipse/team/examples/pessimistic/ui/CheckOutAction.java b/examples/org.eclipse.team.examples.filesystem/src/org/eclipse/team/examples/pessimistic/ui/CheckOutAction.java
new file mode 100644
index 000000000..37e54dc45
--- /dev/null
+++ b/examples/org.eclipse.team.examples.filesystem/src/org/eclipse/team/examples/pessimistic/ui/CheckOutAction.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2002 IBM Corp. All rights reserved.
+ * This file is made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ */
+package org.eclipse.team.examples.pessimistic.ui;
+
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.team.examples.pessimistic.PessimisticFilesystemProvider;
+
+/**
+ * Performs a check out on the selected resources. If a folder is
+ * selected all of its children are recursively checked out.
+ */
+public class CheckOutAction extends SourceManagementAction {
+ /**
+ * Answers <code>true</code> if and only if the <code>resource</code>
+ * is not <code>null</code>, controlled, not ignored and not checked out.
+ *
+ * @see PessimisticProviderAction#shouldEnableFor(IResource)
+ */
+ protected boolean shouldEnableFor(IResource resource) {
+ if (resource == null)
+ return false;
+ PessimisticFilesystemProvider provider= getProvider(resource);
+ if (provider == null)
+ return false;
+ if (!provider.isControlled(resource))
+ return false;
+ if (provider.isIgnored(resource))
+ return false;
+ return !provider.isCheckedout(resource);
+ }
+
+ /*
+ * @see SourceControlAction#manageResources(PessimisticFilesystemProvider, IResource[], IProgressMonitor)
+ */
+ protected void manageResources(PessimisticFilesystemProvider provider, IResource[] resources, IProgressMonitor monitor) {
+ provider.checkout(resources, monitor);
+ }
+}
diff --git a/examples/org.eclipse.team.examples.filesystem/src/org/eclipse/team/examples/pessimistic/ui/ConfigurationWizard.java b/examples/org.eclipse.team.examples.filesystem/src/org/eclipse/team/examples/pessimistic/ui/ConfigurationWizard.java
new file mode 100644
index 000000000..4f9525da8
--- /dev/null
+++ b/examples/org.eclipse.team.examples.filesystem/src/org/eclipse/team/examples/pessimistic/ui/ConfigurationWizard.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2002 IBM Corp. All rights reserved.
+ * This file is made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ */
+package org.eclipse.team.examples.pessimistic.ui;
+
+import org.eclipse.core.resources.IProject;
+import org.eclipse.jface.wizard.Wizard;
+import org.eclipse.team.core.RepositoryProvider;
+import org.eclipse.team.core.TeamException;
+import org.eclipse.team.examples.pessimistic.PessimisticFilesystemProviderPlugin;
+import org.eclipse.team.ui.IConfigurationWizard;
+import org.eclipse.ui.IWorkbench;
+
+/**
+ * A wizard which adds the <code>PessimisticFilesystemProvider</code> nature
+ * to a given project.
+ */
+public class ConfigurationWizard extends Wizard implements IConfigurationWizard {
+ /*
+ * The project in question.
+ */
+ private IProject project;
+
+ /*
+ * @see Wizard#addPages()
+ */
+ public void addPages() {
+ // workaround the wizard problem
+ addPage(new BlankPage());
+ }
+
+ /*
+ * @see Wizard#performFinish()
+ */
+ public boolean performFinish() {
+ try {
+ RepositoryProvider.map(project, PessimisticFilesystemProviderPlugin.NATURE_ID);
+ } catch (TeamException e) {
+ PessimisticFilesystemProviderPlugin.getInstance().logError(e, "Could not set sharing on " + project);
+ return false;
+ }
+ return true;
+ }
+
+ /*
+ * @see IConfigurationWizard#init(IWorkbench, IProject)
+ */
+ public void init(IWorkbench workbench, IProject project) {
+ this.project = project;
+ }
+}
diff --git a/examples/org.eclipse.team.examples.filesystem/src/org/eclipse/team/examples/pessimistic/ui/DisconnectAction.java b/examples/org.eclipse.team.examples.filesystem/src/org/eclipse/team/examples/pessimistic/ui/DisconnectAction.java
new file mode 100644
index 000000000..74757fd3f
--- /dev/null
+++ b/examples/org.eclipse.team.examples.filesystem/src/org/eclipse/team/examples/pessimistic/ui/DisconnectAction.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 2002 IBM Corp. All rights reserved.
+ * This file is made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ */
+package org.eclipse.team.examples.pessimistic.ui;
+
+import java.lang.reflect.InvocationTargetException;
+import java.util.*;
+
+import org.eclipse.core.resources.*;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.jface.action.IAction;
+import org.eclipse.jface.operation.IRunnableWithProgress;
+import org.eclipse.team.core.RepositoryProvider;
+import org.eclipse.team.core.TeamException;
+import org.eclipse.team.examples.pessimistic.PessimisticFilesystemProvider;
+import org.eclipse.team.examples.pessimistic.PessimisticFilesystemProviderPlugin;
+
+public class DisconnectAction extends PessimisticProviderAction {
+ /**
+ * Collects the selected resources, extracts the projects selected
+ * and disconnects the projects from their respective providers.
+ *
+ * @see IActionDelegate#run(IAction)
+ */
+ public void run(IAction action) {
+ if (PessimisticFilesystemProviderPlugin.getInstance().isDebugging())
+ System.out.println("Disconnect");
+
+ IResource[] resources= getSelectedResources();
+ if (resources == null || resources.length == 0)
+ return;
+ final Set projects= new HashSet(resources.length);
+ for(int i= 0; i < resources.length; i++) {
+ IResource resource= resources[i];
+ if (resource.getType() == IResource.PROJECT) {
+ projects.add(resource.getProject());
+ }
+ }
+ if (!projects.isEmpty()) {
+ IRunnableWithProgress runnable= new IRunnableWithProgress() {
+ public void run(IProgressMonitor monitor)
+ throws InvocationTargetException, InterruptedException {
+ IWorkspaceRunnable runnable= new IWorkspaceRunnable() {
+ public void run(IProgressMonitor monitor)
+ throws CoreException {
+ for (Iterator i= projects.iterator(); i.hasNext();) {
+ IProject project= (IProject) i.next();
+ PessimisticFilesystemProvider provider= getProvider(project);
+ if (provider != null) {
+ try {
+ RepositoryProvider.unmap(project);
+ } catch (TeamException e) {
+ PessimisticFilesystemProviderPlugin.getInstance().logError(e, "Could not unmap " + project);
+ }
+ }
+ }
+ }
+ };
+ try {
+ ResourcesPlugin.getWorkspace().run(runnable, monitor);
+ } catch (CoreException e) {
+ PessimisticFilesystemProviderPlugin.getInstance().logError(e, "Problem during unmap runnable");
+ }
+
+ }
+ };
+ runWithProgressDialog(runnable);
+ }
+ }
+
+ /**
+ * Answers <code>true</code> if and only if the resource is a
+ * project and is controlled by the pessimistic filesystem provider.
+ *
+ * @see PessimisticProviderAction#shouldEnableFor(IResource)
+ */
+ protected boolean shouldEnableFor(IResource resource) {
+ if (resource.getType() == IResource.PROJECT) {
+ PessimisticFilesystemProvider provider= getProvider(resource);
+ if (provider == null)
+ return false;
+ return true;
+ }
+ return false;
+ }
+}
diff --git a/examples/org.eclipse.team.examples.filesystem/src/org/eclipse/team/examples/pessimistic/ui/PessimisticDecorator.java b/examples/org.eclipse.team.examples.filesystem/src/org/eclipse/team/examples/pessimistic/ui/PessimisticDecorator.java
new file mode 100644
index 000000000..8e4e64843
--- /dev/null
+++ b/examples/org.eclipse.team.examples.filesystem/src/org/eclipse/team/examples/pessimistic/ui/PessimisticDecorator.java
@@ -0,0 +1,130 @@
+/*
+ * Copyright (c) 2002 IBM Corp. All rights reserved.
+ * This file is made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ */
+package org.eclipse.team.examples.pessimistic.ui;
+
+import java.util.HashSet;
+import java.util.Set;
+
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.runtime.IAdaptable;
+import org.eclipse.jface.viewers.*;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.team.core.RepositoryProvider;
+import org.eclipse.team.examples.pessimistic.*;
+
+/**
+ * The <code>PessimisticDecorator</code> is a label provider
+ * that decorates resources controlled by a <code>PessimisticFilesystemProvider</code>.
+ */
+public class PessimisticDecorator extends LabelProvider implements ILabelDecorator, IResourceStateListener {
+
+ private Set fDecoratedProjects;
+
+ /**
+ * Constructor needed for extension
+ */
+ public PessimisticDecorator() {
+ fDecoratedProjects= new HashSet(1);
+ PessimisticFilesystemProviderPlugin.getInstance().addProviderListener(this);
+ }
+
+ /*
+ * @see org.eclipse.jface.viewers.ILabelDecorator#decorateText(String, Object)
+ */
+ public String decorateText(String text, Object element) {
+ IResource resource= getResource(element);
+ if (resource == null)
+ return text;
+ PessimisticFilesystemProvider provider= getProvider(resource);
+ if (provider == null) {
+ return text;
+ }
+ if (provider.isControlled(resource)) {
+ if (provider.isCheckedout(resource)) {
+ return ">" + text;
+ } else {
+ return text;
+ }
+ } else {
+ if (provider.isIgnored(resource)) {
+ return "[ignored] " + text;
+ } else {
+ return "(not controlled) " + text;
+ }
+ }
+ }
+
+ /*
+ * @see org.eclipse.jface.viewers.ILabelDecorator#decorateImage(Image, Object)
+ */
+ public Image decorateImage(Image image, Object element) {
+ return image;
+ }
+
+ /*
+ * Convenience method to get the provider of a resource
+ */
+ private PessimisticFilesystemProvider getProvider(IResource resource) {
+ IProject project= resource.getProject();
+ if (project != null) {
+ return (PessimisticFilesystemProvider) RepositoryProvider.getProvider(project, PessimisticFilesystemProviderPlugin.NATURE_ID);
+ }
+ return null;
+ }
+
+ /*
+ * Convenience method to get a resource from an object
+ */
+ private IResource getResource(Object object) {
+ if (object instanceof IResource) {
+ return (IResource) object;
+ }
+ if (object instanceof IAdaptable) {
+ return (IResource) ((IAdaptable) object).getAdapter(IResource.class);
+ }
+ return null;
+ }
+
+ /*
+ * Fires label events
+ */
+ private void postLabelEvents(final LabelProviderChangedEvent[] events) {
+ if (events != null && events.length > 0) {
+ Display.getDefault().asyncExec(new Runnable() {
+ public void run() {
+ for (int i= 0; i < events.length; i++) {
+ fireLabelProviderChanged(events[i]);
+ }
+ }
+ });
+ }
+ }
+
+ /*
+ * @see org.eclipse.jface.viewers.IBaseLabelProvider#dispose()
+ */
+ public void dispose() {
+ PessimisticFilesystemProviderPlugin.getInstance().removeProviderListener(this);
+ super.dispose();
+ }
+
+ /*
+ * @see org.eclipse.team.examples.pessimistic.IResourceStateListener#resourcesChanged(IResource[])
+ */
+ public void stateChanged(IResource[] resources) {
+ if (resources.length > 0) {
+ LabelProviderChangedEvent[] events= new LabelProviderChangedEvent[resources.length];
+ for (int i= 0; i < resources.length; i++) {
+ events[i]= new LabelProviderChangedEvent(this, resources[i]);
+ }
+ postLabelEvents(events);
+ }
+ }
+
+} \ No newline at end of file
diff --git a/examples/org.eclipse.team.examples.filesystem/src/org/eclipse/team/examples/pessimistic/ui/PessimisticPreferencesPage.java b/examples/org.eclipse.team.examples.filesystem/src/org/eclipse/team/examples/pessimistic/ui/PessimisticPreferencesPage.java
new file mode 100644
index 000000000..81213bb8b
--- /dev/null
+++ b/examples/org.eclipse.team.examples.filesystem/src/org/eclipse/team/examples/pessimistic/ui/PessimisticPreferencesPage.java
@@ -0,0 +1,358 @@
+/*
+ * Copyright (c) 2002 IBM Corp. All rights reserved.
+ * This file is made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ */
+package org.eclipse.team.examples.pessimistic.ui;
+
+import org.eclipse.jface.preference.IPreferenceStore;
+import org.eclipse.jface.preference.PreferencePage;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.*;
+import org.eclipse.team.examples.pessimistic.IPessimisticFilesystemConstants;
+import org.eclipse.team.examples.pessimistic.PessimisticFilesystemProviderPlugin;
+import org.eclipse.ui.IWorkbench;
+import org.eclipse.ui.IWorkbenchPreferencePage;
+
+/**
+ * A preference page for the <code>PessimisticFilesystemProviderPlugin</code>.
+ */
+public class PessimisticPreferencesPage
+ extends PreferencePage
+ implements IWorkbenchPreferencePage {
+
+ /*
+ * Widget for the files are edited preference
+ */
+ private Combo filesAreEditedCombo;
+ /*
+ * Widget for the files are edited without a context preference
+ */
+ private Combo filesAreEditedNoPromptCombo;
+ /*
+ * Widget for the files are saved preference
+ */
+ private Combo filesAreSavedCombo;
+ /*
+ * Widget for the files are edited preference
+ */
+ private Combo addToControlCombo;
+ /*
+ * Widget for the change file contents preference
+ */
+ private Button changeFileContents;
+ /*
+ * Widget for the fail validate edit preference
+ */
+ private Button failValidateEdit;
+
+ /*
+ * Option strings for the files are edited preference.
+ */
+ private static final String[] EDIT_OPTION_STRINGS=
+ new String[] {
+ "Prompt to checkout",
+ "Checkout",
+ "Do nothing", };
+ /*
+ * Option values for the files are edited preference.
+ */
+ private static final int[] EDIT_OPTION_KEYS=
+ new int[] {
+ IPessimisticFilesystemConstants.OPTION_PROMPT,
+ IPessimisticFilesystemConstants.OPTION_AUTOMATIC,
+ IPessimisticFilesystemConstants.OPTION_DO_NOTHING, };
+
+ /*
+ * Option strings for the files are edited without a context preference.
+ */
+ private static final String[] EDIT_NO_PROMPT_OPTION_STRINGS=
+ new String[] {
+ "Checkout",
+ "Do nothing", };
+ /*
+ * Option values for the files are edited without a context preference.
+ */
+ private static final int[] EDIT_NO_PROMPT_OPTION_KEYS=
+ new int[] {
+ IPessimisticFilesystemConstants.OPTION_AUTOMATIC,
+ IPessimisticFilesystemConstants.OPTION_DO_NOTHING, };
+
+ /*
+ * Option strings for the files are saved preference.
+ */
+ private static final String[] SAVE_OPTION_STRINGS=
+ new String[] {
+ "Checkout",
+ "Do nothing", };
+ /*
+ * Option values for the files are saved preference.
+ */
+ private static final int[] SAVE_OPTION_KEYS=
+ new int[] {
+ IPessimisticFilesystemConstants.OPTION_AUTOMATIC,
+ IPessimisticFilesystemConstants.OPTION_DO_NOTHING, };
+
+ /*
+ * Option strings for the add to control preference.
+ */
+ private static final String[] ADD_TO_CONTROL_OPTION_STRINGS=
+ new String[] {
+ "Prompt to add to control",
+ "Add to control",
+ "Do nothing", };
+ /*
+ * Option values for the add to control preference.
+ */
+ private static final int[] ADD_TO_CONTROL_OPTION_KEYS=
+ new int[] {
+ IPessimisticFilesystemConstants.OPTION_PROMPT,
+ IPessimisticFilesystemConstants.OPTION_AUTOMATIC,
+ IPessimisticFilesystemConstants.OPTION_DO_NOTHING, };
+
+
+ /*
+ * @see org.eclipse.jface.preference.PreferencePage#doGetPreferenceStore()
+ */
+ protected IPreferenceStore doGetPreferenceStore() {
+ return PessimisticFilesystemProviderPlugin.getInstance().getPreferenceStore();
+ }
+
+
+ /*
+ * Sets the layout to be a grid layout with the given number of columns.
+ */
+ protected void setDefaultLayout(Composite group, int columns) {
+ GridLayout layout = new GridLayout();
+ group.setLayout(layout);
+
+ GridData data =
+ new GridData(
+ GridData.VERTICAL_ALIGN_FILL
+ | GridData.HORIZONTAL_ALIGN_FILL
+ | GridData.GRAB_HORIZONTAL);
+
+ layout.numColumns = columns;
+ group.setLayoutData(data);
+ }
+
+ /*
+ * @see org.eclipse.jface.preference.PreferencePage#createContents(Composite)
+ */
+ protected Control createContents(Composite parent) {
+ Composite composite = new Composite(parent, SWT.NULL);
+ setDefaultLayout(composite, 1);
+
+ Composite options = new Composite(composite, SWT.NULL);
+ setDefaultLayout(options, 2);
+
+ Label label = new Label(options, SWT.NONE);
+ label.setText("File handling:");
+ GridData gridData = new GridData();
+ gridData.horizontalSpan = 2;
+ gridData.horizontalAlignment = GridData.FILL;
+ label.setLayoutData(gridData);
+
+ label = new Label(options, SWT.NONE);
+ label.setText("When checked in files are edited:");
+ gridData = new GridData();
+ gridData.horizontalSpan = 1;
+ gridData.horizontalAlignment = GridData.FILL;
+ label.setLayoutData(gridData);
+
+ filesAreEditedCombo= new Combo(options, SWT.BORDER | SWT.READ_ONLY);
+ gridData = new GridData();
+ gridData.horizontalSpan= 1;
+ gridData.horizontalAlignment = GridData.FILL;
+ filesAreEditedCombo.setLayoutData(gridData);
+ filesAreEditedCombo.setItems(EDIT_OPTION_STRINGS);
+
+ label = new Label(options, SWT.NONE);
+ label.setText("When checked in files are edited programmatically:");
+ gridData = new GridData();
+ gridData.horizontalSpan = 1;
+ gridData.horizontalAlignment = GridData.FILL;
+ label.setLayoutData(gridData);
+
+ filesAreEditedNoPromptCombo= new Combo(options, SWT.BORDER | SWT.READ_ONLY);
+ gridData = new GridData();
+ gridData.horizontalSpan= 1;
+ gridData.horizontalAlignment = GridData.FILL;
+ filesAreEditedNoPromptCombo.setLayoutData(gridData);
+ filesAreEditedNoPromptCombo.setItems(EDIT_NO_PROMPT_OPTION_STRINGS);
+
+ label = new Label(options, SWT.NONE);
+ label.setText("When checked in files are saved:");
+ gridData = new GridData();
+ gridData.horizontalSpan = 1;
+ gridData.horizontalAlignment = GridData.FILL;
+ label.setLayoutData(gridData);
+
+ filesAreSavedCombo= new Combo(options, SWT.BORDER | SWT.READ_ONLY);
+ gridData = new GridData();
+ gridData.horizontalSpan = 1;
+ gridData.horizontalAlignment = GridData.FILL;
+ filesAreSavedCombo.setLayoutData(gridData);
+ filesAreSavedCombo.setItems(SAVE_OPTION_STRINGS);
+
+ label = new Label(options, SWT.NONE);
+ label.setText("When files are created:");
+ gridData = new GridData();
+ gridData.horizontalSpan = 1;
+ gridData.horizontalAlignment = GridData.FILL;
+ label.setLayoutData(gridData);
+
+ addToControlCombo= new Combo(options, SWT.BORDER | SWT.READ_ONLY);
+ gridData = new GridData();
+ gridData.horizontalSpan = 1;
+ gridData.horizontalAlignment = GridData.FILL;
+ addToControlCombo.setLayoutData(gridData);
+ addToControlCombo.setItems(ADD_TO_CONTROL_OPTION_STRINGS);
+
+ options = new Composite(composite, SWT.NULL);
+ setDefaultLayout(options, 1);
+
+ label = new Label(options, SWT.NONE);
+ label.setText("Error cases:");
+ gridData = new GridData();
+ gridData.horizontalSpan = 1;
+ gridData.horizontalAlignment = GridData.FILL;
+ label.setLayoutData(gridData);
+
+ failValidateEdit= new Button(options, SWT.CHECK | SWT.LEFT);
+ failValidateEdit.setText("Fail validate edit");
+ gridData = new GridData();
+ failValidateEdit.setLayoutData(gridData);
+
+ changeFileContents= new Button(options, SWT.CHECK | SWT.LEFT);
+ changeFileContents.setText("Touch files during validate edit");
+ gridData = new GridData();
+ changeFileContents.setLayoutData(gridData);
+
+ updatePreferencePage();
+
+ return composite;
+ }
+
+ /*
+ * @see org.eclipse.ui.IWorkbenchPreferencePage#init(IWorkbench)
+ */
+ public void init(IWorkbench workbench) {
+ }
+
+ /*
+ * @see org.eclipse.jface.preference.PreferencePage#performDefaults()
+ */
+ protected void performDefaults() {
+ IPreferenceStore store = getPreferenceStore();
+
+ filesAreEditedCombo.select(
+ getEditOptionIndex(store.getDefaultInt(IPessimisticFilesystemConstants.PREF_CHECKED_IN_FILES_EDITED)));
+ filesAreEditedNoPromptCombo.select(
+ getEditNoPromptOptionIndex(store.getDefaultInt(IPessimisticFilesystemConstants.PREF_CHECKED_IN_FILES_EDITED_NOPROMPT)));
+ filesAreSavedCombo.select(
+ getSaveOptionIndex(store.getDefaultInt(IPessimisticFilesystemConstants.PREF_CHECKED_IN_FILES_SAVED)));
+ addToControlCombo.select(
+ getAddToControlOptionIndex(store.getDefaultInt(IPessimisticFilesystemConstants.PREF_ADD_TO_CONTROL)));
+ failValidateEdit.setSelection(
+ store.getDefaultBoolean(IPessimisticFilesystemConstants.PREF_FAIL_VALIDATE_EDIT));
+ changeFileContents.setSelection(
+ store.getDefaultBoolean(IPessimisticFilesystemConstants.PREF_TOUCH_DURING_VALIDATE_EDIT));
+ super.performDefaults();
+ }
+
+ /*
+ * @see org.eclipse.jface.preference.IPreferencePage#performOk()
+ */
+ public boolean performOk() {
+ IPreferenceStore store = getPreferenceStore();
+
+ store.setValue(
+ IPessimisticFilesystemConstants.PREF_CHECKED_IN_FILES_EDITED,
+ EDIT_OPTION_KEYS[filesAreEditedCombo.getSelectionIndex()]);
+ store.setValue(
+ IPessimisticFilesystemConstants.PREF_CHECKED_IN_FILES_EDITED_NOPROMPT,
+ SAVE_OPTION_KEYS[filesAreEditedNoPromptCombo.getSelectionIndex()]);
+ store.setValue(
+ IPessimisticFilesystemConstants.PREF_CHECKED_IN_FILES_SAVED,
+ SAVE_OPTION_KEYS[filesAreSavedCombo.getSelectionIndex()]);
+ store.setValue(
+ IPessimisticFilesystemConstants.PREF_ADD_TO_CONTROL,
+ ADD_TO_CONTROL_OPTION_KEYS[addToControlCombo.getSelectionIndex()]);
+ store.setValue(
+ IPessimisticFilesystemConstants.PREF_FAIL_VALIDATE_EDIT,
+ failValidateEdit.getSelection());
+ store.setValue(
+ IPessimisticFilesystemConstants.PREF_TOUCH_DURING_VALIDATE_EDIT,
+ changeFileContents.getSelection());
+ return true;
+ }
+
+ /*
+ * Sets the widgets to have the state stored in the preferences.
+ */
+ protected void updatePreferencePage() {
+ IPreferenceStore store = getPreferenceStore();
+
+ filesAreEditedCombo.select(
+ getEditOptionIndex(store.getInt(IPessimisticFilesystemConstants.PREF_CHECKED_IN_FILES_EDITED)));
+ filesAreEditedNoPromptCombo.select(
+ getEditNoPromptOptionIndex(store.getInt(IPessimisticFilesystemConstants.PREF_CHECKED_IN_FILES_EDITED_NOPROMPT)));
+ filesAreSavedCombo.select(
+ getSaveOptionIndex(store.getInt(IPessimisticFilesystemConstants.PREF_CHECKED_IN_FILES_SAVED)));
+ addToControlCombo.select(
+ getAddToControlOptionIndex(store.getInt(IPessimisticFilesystemConstants.PREF_ADD_TO_CONTROL)));
+ failValidateEdit.setSelection(
+ store.getBoolean(IPessimisticFilesystemConstants.PREF_FAIL_VALIDATE_EDIT));
+ changeFileContents.setSelection(
+ store.getBoolean(IPessimisticFilesystemConstants.PREF_TOUCH_DURING_VALIDATE_EDIT));
+ }
+
+ /*
+ * Answers the index of the given key.
+ */
+ protected int getEditOptionIndex(int key) {
+ for(int i= 0; i < EDIT_OPTION_KEYS.length; i++) {
+ if (EDIT_OPTION_KEYS[i] == key)
+ return i;
+ }
+ return -1;
+ }
+
+ /*
+ * Answers the index of the given key.
+ */
+ protected int getSaveOptionIndex(int key) {
+ for(int i= 0; i < SAVE_OPTION_KEYS.length; i++) {
+ if (SAVE_OPTION_KEYS[i] == key)
+ return i;
+ }
+ return -1;
+ }
+
+ /*
+ * Answers the index of the given key.
+ */
+ protected int getEditNoPromptOptionIndex(int key) {
+ for(int i= 0; i < SAVE_OPTION_KEYS.length; i++) {
+ if (SAVE_OPTION_KEYS[i] == key)
+ return i;
+ }
+ return -1;
+ }
+
+ /*
+ * Answers the index of the given key.
+ */
+ protected int getAddToControlOptionIndex(int key) {
+ for(int i= 0; i < ADD_TO_CONTROL_OPTION_KEYS.length; i++) {
+ if (ADD_TO_CONTROL_OPTION_KEYS[i] == key)
+ return i;
+ }
+ return -1;
+ }
+
+} \ No newline at end of file
diff --git a/examples/org.eclipse.team.examples.filesystem/src/org/eclipse/team/examples/pessimistic/ui/PessimisticProviderAction.java b/examples/org.eclipse.team.examples.filesystem/src/org/eclipse/team/examples/pessimistic/ui/PessimisticProviderAction.java
new file mode 100644
index 000000000..ec035b7ea
--- /dev/null
+++ b/examples/org.eclipse.team.examples.filesystem/src/org/eclipse/team/examples/pessimistic/ui/PessimisticProviderAction.java
@@ -0,0 +1,231 @@
+/*
+ * Copyright (c) 2002 IBM Corp. All rights reserved.
+ * This file is made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ */
+package org.eclipse.team.examples.pessimistic.ui;
+
+import java.lang.reflect.InvocationTargetException;
+import java.util.*;
+
+import org.eclipse.core.resources.*;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IAdaptable;
+import org.eclipse.jface.action.IAction;
+import org.eclipse.jface.dialogs.ProgressMonitorDialog;
+import org.eclipse.jface.operation.IRunnableWithProgress;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.team.core.RepositoryProvider;
+import org.eclipse.team.examples.pessimistic.PessimisticFilesystemProvider;
+import org.eclipse.team.examples.pessimistic.PessimisticFilesystemProviderPlugin;
+import org.eclipse.ui.IObjectActionDelegate;
+import org.eclipse.ui.IWorkbenchPart;
+
+
+/**
+ * Abstract base action implementation for all pessimistic provider actions.
+ * Provides convenience methods an abstractions.
+ */
+public abstract class PessimisticProviderAction
+ implements IObjectActionDelegate {
+
+ /*
+ * The current selection.
+ */
+ protected ISelection fSelection;
+ /*
+ * The current shell.
+ */
+ protected Shell fShell;
+
+ /*
+ * @see org.eclipse.ui.IActionDelegate#selectionChanged(IAction, ISelection)
+ */
+ public void selectionChanged(IAction action, ISelection selection) {
+ fSelection = selection;
+
+ boolean enabled= action.isEnabled();
+ if (enabled != checkEnablement()) {
+ action.setEnabled(!enabled);
+ }
+ }
+
+ /*
+ * @see org.eclipse.ui.IObjectActionDelegate#setActivePart(IAction, IWorkbenchPart)
+ */
+ public void setActivePart(IAction action, IWorkbenchPart part) {
+ fShell= part.getSite().getShell();
+ }
+
+ /**
+ * Answers <code>true</code> if this action should be enabled
+ * for the given <code>resource</code>.
+ */
+ protected abstract boolean shouldEnableFor(IResource resource);
+
+ /*
+ * Checks to see if this action should be enabled.
+ */
+ protected boolean checkEnablement() {
+ IResource[] resources= getSelectedResources();
+ if (resources == null || resources.length == 0) {
+ return false;
+ } else {
+ boolean enabled= false;
+ for(int i= 0; !enabled && i < resources.length; i++) {
+ if (shouldEnableFor(resources[i])) {
+ enabled= true;
+ }
+ }
+ return enabled;
+ }
+ }
+
+ /**
+ * Convenience method to get an array of resources from the selection.
+ */
+ protected IResource[] getSelectedResources() {
+ ArrayList resources = null;
+ if (!fSelection.isEmpty()) {
+ resources = new ArrayList();
+ Iterator elements = ((IStructuredSelection) fSelection).iterator();
+ while (elements.hasNext()) {
+ Object next = elements.next();
+ if (next instanceof IResource) {
+ resources.add(next);
+ continue;
+ }
+ if (next instanceof IAdaptable) {
+ IAdaptable a = (IAdaptable) next;
+ Object adapter = a.getAdapter(IResource.class);
+ if (adapter instanceof IResource) {
+ resources.add(adapter);
+ continue;
+ }
+ }
+ }
+ }
+ if (resources != null && !resources.isEmpty()) {
+ IResource[] result = new IResource[resources.size()];
+ resources.toArray(result);
+ return result;
+ }
+ return new IResource[0];
+ }
+
+ /**
+ * Convenience method which answers <code>true</code> if the
+ * resource is controlled by a <code>PessimisticFilesystemProvider</code>.
+ */
+ protected boolean isControlled(IResource resource) {
+ PessimisticFilesystemProvider provider= getProvider(resource);
+ if (provider == null)
+ return false;
+ return provider.isControlled(resource);
+ }
+
+ /**
+ * Convenience method which answers <code>true</code> if and only if the
+ * resource is controlled by a <code>PessimisticFilesystemProvider</code>
+ * and is checked out.
+ */
+ protected boolean isCheckedOut(IResource resource) {
+ PessimisticFilesystemProvider provider= getProvider(resource);
+ if (provider == null)
+ return false;
+ return provider.isCheckedout(resource);
+ }
+
+ /**
+ * Convenience method which answers <code>true</code> if and only if the
+ * resource is controlled by a <code>PessimisticFilesystemProvider</code>
+ * and the resource is ignored.
+ */
+ protected boolean isIgnored(IResource resource) {
+ PessimisticFilesystemProvider provider= getProvider(resource);
+ if (provider == null)
+ return false;
+ return provider.isIgnored(resource);
+ }
+
+ /**
+ * Convenience method which answers the <code>PessimisticFilesystemProvider</code>
+ * for the given <code>resource</code> or <code>null</code> if the
+ * <code>resource</code> is not associated with a <code>PessimisticFilesystemProvider</code>.
+ */
+ protected PessimisticFilesystemProvider getProvider(IResource resource) {
+ if (resource == null) {
+ return null;
+ }
+ IProject project= resource.getProject();
+ if (project == null) {
+ return null;
+ }
+ return (PessimisticFilesystemProvider)RepositoryProvider.getProvider(project, PessimisticFilesystemProviderPlugin.NATURE_ID);
+ }
+
+ /**
+ * Convenience method which walks a resource tree and collects the
+ * resources that this action would enable for.
+ */
+ protected void recursivelyAdd(IResource resource, Set resources) {
+ if (isControlled(resource) && !isIgnored(resource)) {
+ if (shouldEnableFor(resource)) {
+ resources.add(resource);
+ }
+
+ if (resource instanceof IContainer) {
+ IContainer container = (IContainer) resource;
+ IResource[] members= null;
+ try {
+ members = container.members();
+ } catch (CoreException e) {
+ PessimisticFilesystemProviderPlugin.getInstance().logError(e, "Exception traversing members");
+ }
+ if (members != null) {
+ for (int i = 0; i < members.length; i++) {
+ recursivelyAdd(members[i], resources);
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Convenience method which sorts the given <code>resources</code>
+ * into a map of IProject -> Set of IResource objects.
+ */
+ protected Map sortByProject(Set resources) {
+ Map byProject= new HashMap();
+ if (resources != null) {
+ for (Iterator i= resources.iterator(); i.hasNext();) {
+ IResource resource= (IResource) i.next();
+ IProject project= resource.getProject();
+ Set set= (Set)byProject.get(project);
+ if (set == null) {
+ set= new HashSet(1);
+ byProject.put(project, set);
+ }
+ set.add(resource);
+ }
+ }
+ return byProject;
+ }
+
+ /**
+ * Convenience method for displaying runnable progress
+ * with a <code>ProgressMonitorDialog</code>.
+ */
+ protected void runWithProgressDialog(IRunnableWithProgress runnable) {
+ try {
+ new ProgressMonitorDialog(fShell).run(true, false, runnable);
+ } catch (InvocationTargetException e) {
+ PessimisticFilesystemProviderPlugin.getInstance().logError(e, "Problems running action " + this);
+ } catch (InterruptedException e) {
+ PessimisticFilesystemProviderPlugin.getInstance().logError(e, "Problems running action " + this);
+ }
+ }
+}
diff --git a/examples/org.eclipse.team.examples.filesystem/src/org/eclipse/team/examples/pessimistic/ui/RemoveFromControlAction.java b/examples/org.eclipse.team.examples.filesystem/src/org/eclipse/team/examples/pessimistic/ui/RemoveFromControlAction.java
new file mode 100644
index 000000000..9a03edb10
--- /dev/null
+++ b/examples/org.eclipse.team.examples.filesystem/src/org/eclipse/team/examples/pessimistic/ui/RemoveFromControlAction.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2002 IBM Corp. All rights reserved.
+ * This file is made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ */
+package org.eclipse.team.examples.pessimistic.ui;
+
+import java.lang.reflect.InvocationTargetException;
+import java.util.*;
+
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.jface.action.IAction;
+import org.eclipse.jface.operation.IRunnableWithProgress;
+import org.eclipse.team.examples.pessimistic.PessimisticFilesystemProvider;
+
+/**
+ * Removes the selected resources and their children resources from
+ * the control of the provider.
+ */
+public class RemoveFromControlAction extends PessimisticProviderAction {
+
+ /**
+ * Collects the selected resources into sets by project,
+ * then removes the resources from the provider associated
+ * with their containing project.
+ *
+ * @see org.eclipse.ui.IActionDelegate#run(IAction)
+ */
+ public void run(IAction action) {
+ IResource[] resources= getSelectedResources();
+ if (resources == null || resources.length == 0)
+ return;
+ Set resourceSet= new HashSet(resources.length);
+ for(int i= 0; i < resources.length; i++) {
+ IResource resource= resources[i];
+ recursivelyAdd(resource, resourceSet);
+ }
+ if (!resourceSet.isEmpty()) {
+ final Map byProject= sortByProject(resourceSet);
+ IRunnableWithProgress runnable= new IRunnableWithProgress() {
+ public void run(IProgressMonitor monitor)
+ throws InvocationTargetException, InterruptedException {
+ for (Iterator i= byProject.keySet().iterator(); i.hasNext();) {
+ IProject project= (IProject) i.next();
+ PessimisticFilesystemProvider provider= getProvider(project);
+ if (provider != null) {
+ Set set= (Set)byProject.get(project);
+ IResource[] resources= new IResource[set.size()];
+ set.toArray(resources);
+ provider.removeFromControl(resources, monitor);
+ }
+ }
+ }
+ };
+ runWithProgressDialog(runnable);
+ }
+ }
+
+ /**
+ * Answers <code>true</code> if and only if the resource is not <code>null</code>,
+ * not a project or the workspace root, and is controlled by the provider.
+ *
+ * @see org.eclipse.team.examples.pessimistic.ui.PessimisticProviderAction#shouldEnableFor(IResource)
+ */
+ protected boolean shouldEnableFor(IResource resource) {
+ if (resource == null) {
+ return false;
+ }
+ if ((resource.getType() & (IResource.ROOT | IResource.PROJECT)) != 0) {
+ return false;
+ }
+ PessimisticFilesystemProvider provider= getProvider(resource);
+ if (provider == null)
+ return false;
+ return provider.isControlled(resource);
+ }
+
+}
diff --git a/examples/org.eclipse.team.examples.filesystem/src/org/eclipse/team/examples/pessimistic/ui/SourceManagementAction.java b/examples/org.eclipse.team.examples.filesystem/src/org/eclipse/team/examples/pessimistic/ui/SourceManagementAction.java
new file mode 100644
index 000000000..a5df14347
--- /dev/null
+++ b/examples/org.eclipse.team.examples.filesystem/src/org/eclipse/team/examples/pessimistic/ui/SourceManagementAction.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2002 IBM Corp. All rights reserved.
+ * This file is made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ */
+package org.eclipse.team.examples.pessimistic.ui;
+
+import java.lang.reflect.InvocationTargetException;
+import java.util.*;
+
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.jface.action.IAction;
+import org.eclipse.jface.operation.IRunnableWithProgress;
+import org.eclipse.team.examples.pessimistic.PessimisticFilesystemProvider;
+
+/**
+ * An abstract action used to centralize the implementation of
+ * source management actions.
+ */
+public abstract class SourceManagementAction extends PessimisticProviderAction {
+
+ /**
+ * Collects the selected resources by project, then iterates
+ * over the projects finding the associated provider. If a
+ * provider is found it requests that this action manage the resources
+ * using the found provider.
+ *
+ * @see org.eclipse.ui.IActionDelegate#run(IAction)
+ */
+ public void run(IAction action) {
+ IResource[] resources= getSelectedResources();
+ if (resources == null || resources.length == 0)
+ return;
+ Set resourceSet= new HashSet(resources.length);
+ for(int i= 0; i < resources.length; i++) {
+ IResource resource= resources[i];
+ recursivelyAdd(resource, resourceSet);
+ }
+ if (!resourceSet.isEmpty()) {
+ final Map byProject= sortByProject(resourceSet);
+ IRunnableWithProgress runnable= new IRunnableWithProgress() {
+ public void run(IProgressMonitor monitor)
+ throws InvocationTargetException, InterruptedException {
+ for (Iterator i= byProject.keySet().iterator(); i.hasNext();) {
+ IProject project= (IProject) i.next();
+ PessimisticFilesystemProvider provider= getProvider(project);
+ if (provider != null) {
+ Set set= (Set)byProject.get(project);
+ IResource[] resources= new IResource[set.size()];
+ set.toArray(resources);
+ manageResources(provider, resources, monitor);
+ }
+ }
+ }
+ };
+ runWithProgressDialog(runnable);
+ }
+ }
+
+ /**
+ * Manages the <code>resources</code> using the given <code>provider</code>.
+ *
+ * @param provider The provider associated with the resources.
+ * @param resources The resources to be managed.
+ * @param monitor A progress monitor to give feedback.
+ */
+ protected abstract void manageResources(PessimisticFilesystemProvider provider, IResource[] resources, IProgressMonitor monitor);
+}
diff --git a/examples/org.eclipse.team.examples.filesystem/src/org/eclipse/team/examples/pessimistic/ui/UncheckOutAction.java b/examples/org.eclipse.team.examples.filesystem/src/org/eclipse/team/examples/pessimistic/ui/UncheckOutAction.java
new file mode 100644
index 000000000..69a768213
--- /dev/null
+++ b/examples/org.eclipse.team.examples.filesystem/src/org/eclipse/team/examples/pessimistic/ui/UncheckOutAction.java
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2002 IBM Corp. All rights reserved.
+ * This file is made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ */
+package org.eclipse.team.examples.pessimistic.ui;
+
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.team.examples.pessimistic.PessimisticFilesystemProvider;
+
+/**
+ * Performs an uncheck out on the selected resources. If a folder is
+ * selected all of its children are recursively unchecked out.
+ */
+public class UncheckOutAction extends CheckInAction {
+ /**
+ * @see org.eclipse.team.examples.pessimistic.ui.SourceManagementAction#manageResources(PessimisticFilesystemProvider, IResource[], IProgressMonitor)
+ */
+ protected void manageResources(PessimisticFilesystemProvider provider, IResource[] resources, IProgressMonitor monitor) {
+ provider.uncheckout(resources, monitor);
+ }
+
+}

Back to the top