diff options
author | Jean Michel-Lemieux | 2003-12-18 17:18:54 +0000 |
---|---|---|
committer | Jean Michel-Lemieux | 2003-12-18 17:18:54 +0000 |
commit | 6e9a80f4d397bf54448507f5bebed521de19ea32 (patch) | |
tree | 837a1f42bfb82152335a7f48a807f5fd53f325b1 | |
parent | 76c0f497bb971402f5204b45007d21876dd640bc (diff) | |
download | eclipse.platform.team-branch_20031218_pessimisticProvider.tar.gz eclipse.platform.team-branch_20031218_pessimisticProvider.tar.xz eclipse.platform.team-branch_20031218_pessimisticProvider.zip |
initial release of pessimistic providerbranch_20031218_pessimisticProvider
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); + } + +} |