### Eclipse Workspace Patch 1.0 #P org.eclipse.jdt.ui Index: ui/org/eclipse/jdt/internal/ui/packageview/WorkingSetAwareContentProvider.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/packageview/WorkingSetAwareContentProvider.java,v retrieving revision 1.13 diff -u -r1.13 WorkingSetAwareContentProvider.java --- ui/org/eclipse/jdt/internal/ui/packageview/WorkingSetAwareContentProvider.java 14 Mar 2006 15:05:34 -0000 1.13 +++ ui/org/eclipse/jdt/internal/ui/packageview/WorkingSetAwareContentProvider.java 16 Mar 2006 15:43:29 -0000 @@ -220,6 +220,8 @@ toRefresh.add(newValue); } else if (IWorkingSetManager.CHANGE_WORKING_SET_NAME_CHANGE.equals(property)) { toRefresh.add(newValue); + } else if (WorkingSetModel.CHANGE_WORKING_SET_TEAM_DECORATION.equals(property)) { + toRefresh.add(newValue); } postRefresh(toRefresh, true); } Index: ui/org/eclipse/jdt/internal/ui/workingsets/WorkingSetModel.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/workingsets/WorkingSetModel.java,v retrieving revision 1.17 diff -u -r1.17 WorkingSetModel.java --- ui/org/eclipse/jdt/internal/ui/workingsets/WorkingSetModel.java 15 Mar 2006 10:34:47 -0000 1.17 +++ ui/org/eclipse/jdt/internal/ui/workingsets/WorkingSetModel.java 16 Mar 2006 15:43:29 -0000 @@ -19,10 +19,15 @@ import java.util.List; import java.util.Map; +import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IAdaptable; import org.eclipse.core.runtime.ListenerList; import org.eclipse.core.resources.IResource; +import org.eclipse.core.resources.IResourceChangeEvent; +import org.eclipse.core.resources.IResourceChangeListener; +import org.eclipse.core.resources.IResourceDelta; +import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.jface.util.IPropertyChangeListener; import org.eclipse.jface.util.PropertyChangeEvent; @@ -35,11 +40,19 @@ import org.eclipse.ui.IWorkingSetUpdater; import org.eclipse.ui.PlatformUI; +import org.eclipse.team.ui.mapping.ITeamStateChangeEvent; +import org.eclipse.team.ui.mapping.ITeamStateChangeListener; +import org.eclipse.team.ui.mapping.ITeamStateDescription; +import org.eclipse.team.ui.mapping.ITeamStateProvider; +import org.eclipse.team.ui.mapping.SynchronizationStateTester; + import org.eclipse.jdt.internal.corext.Assert; public class WorkingSetModel { public static final String CHANGE_WORKING_SET_MODEL_CONTENT= "workingSetModelChanged"; //$NON-NLS-1$ + + public static final String CHANGE_WORKING_SET_TEAM_DECORATION= "workingSetTamDecorationChanged"; //$NON-NLS-1$ public static final IElementComparer COMPARER= new WorkingSetComparar(); @@ -57,6 +70,11 @@ private ElementMapper fElementMapper= new ElementMapper(); private boolean fConfigured; + + private SynchronizationStateTester fSyncStateTester; + private ITeamStateChangeListener fTeamListener; + private IResourceChangeListener fResourceListener; + private Map fTeamState = new HashMap(); private static class WorkingSetComparar implements IElementComparer { public boolean equals(Object o1, Object o2) { @@ -248,9 +266,34 @@ }; PlatformUI.getWorkbench().getWorkingSetManager().addPropertyChangeListener(fWorkingSetManagerListener); fLocalWorkingSetManager.addPropertyChangeListener(fWorkingSetManagerListener); + fSyncStateTester = new SynchronizationStateTester() { + public void elementDecorated(Object element, ITeamStateDescription description) { + if (element instanceof IWorkingSet) { + IWorkingSet set = (IWorkingSet) element; + // Record the state that was decorated so we will avoid + // unnecessary label updates + fTeamState.put(set, description); + } + super.elementDecorated(element, description); + } + }; + fTeamListener = new ITeamStateChangeListener() { + public void teamStateChanged(ITeamStateChangeEvent event) { + handeTeamStateChange(event); + } + }; + fResourceListener = new IResourceChangeListener() { + public void resourceChanged(IResourceChangeEvent event) { + handleResourceChange(event.getDelta()); + } + }; + fSyncStateTester.getDecoratedStateProvider().addDecoratedStateChangeListener(fTeamListener); + ResourcesPlugin.getWorkspace().addResourceChangeListener(fResourceListener, IResourceChangeEvent.POST_CHANGE); } public void dispose() { + fSyncStateTester.getDecoratedStateProvider().removeDecoratedStateChangeListener(fTeamListener); + ResourcesPlugin.getWorkspace().removeResourceChangeListener(fResourceListener); if (fWorkingSetManagerListener != null) { PlatformUI.getWorkbench().getWorkingSetManager().removePropertyChangeListener(fWorkingSetManagerListener); fLocalWorkingSetManager.removePropertyChangeListener(fWorkingSetManagerListener); @@ -349,6 +392,7 @@ public void setActiveWorkingSets(IWorkingSet[] workingSets) { fActiveWorkingSets= new ArrayList(Arrays.asList(workingSets)); + fTeamState.clear(); fElementMapper.rebuild(getActiveWorkingSets()); fOthersWorkingSetUpdater.updateElements(); fireEvent(new PropertyChangeEvent(this, CHANGE_WORKING_SET_MODEL_CONTENT, null, null)); @@ -436,4 +480,88 @@ public boolean isActiveWorkingSet(IWorkingSet changedWorkingSet) { return fActiveWorkingSets.contains(changedWorkingSet); } -} \ No newline at end of file + + protected void handeTeamStateChange(ITeamStateChangeEvent event) { + for (Iterator iter = fActiveWorkingSets.iterator(); iter.hasNext();) { + IWorkingSet set = (IWorkingSet) iter.next(); + if (hasPotentialChanges(event, set) && hasRealChanges(set)) + fireEvent(new PropertyChangeEvent(WorkingSetModel.this, CHANGE_WORKING_SET_TEAM_DECORATION, null, null)); + } + } + + protected void handleResourceChange(IResourceDelta delta) { + for (Iterator iter = fActiveWorkingSets.iterator(); iter.hasNext();) { + IWorkingSet set = (IWorkingSet) iter.next(); + if (hasPotentialChanges(delta, set) && hasRealChanges(set)) { + fireEvent(new PropertyChangeEvent(WorkingSetModel.this, CHANGE_WORKING_SET_TEAM_DECORATION, null, null)); + } + } + } + + private boolean hasRealChanges(IWorkingSet set) { + try { + ITeamStateProvider decoratedStateProvider = fSyncStateTester.getDecoratedStateProvider(); + if (decoratedStateProvider.isDecorationEnabled(set)) { + ITeamStateDescription desc = decoratedStateProvider.getStateDescription(set, + ITeamStateProvider.USE_DECORATED_STATE_MASK, null /* use decorated properties */, null /* no progress */); + ITeamStateDescription oldDesc = (ITeamStateDescription)fTeamState.get(set); + if (oldDesc == desc) + return false; + boolean changed = (oldDesc == null && desc != null) + || (desc == null && oldDesc != null) + || (!desc.equals(oldDesc)); + if (desc == null) { + fTeamState.remove(set); + } else { + fTeamState.put(set, desc); + } + return changed; + } else { + if (fTeamState.containsKey(set)) { + fTeamState.remove(set); + return true; + } + } + } catch (CoreException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + return false; + } + + private boolean hasPotentialChanges(IResourceDelta delta, IWorkingSet set) { + IAdaptable[] elements = set.getElements(); + for (int i = 0; i < elements.length; i++) { + IAdaptable adaptable = elements[i]; + IResource resource = (IResource)adaptable.getAdapter(IResource.class); + if (resource != null) { + IResourceDelta memberDelta = delta.findMember(resource.getFullPath()); + if (isChangeOfInterest(memberDelta)) { + return true; + } + } + } + return false; + } + + private boolean isChangeOfInterest(IResourceDelta memberDelta) { + if (memberDelta != null + && (memberDelta.getKind() & (IResourceDelta.ADDED | IResourceDelta.REMOVED | IResourceDelta.CHANGED)) > 0) { + // TODO: Should exclude marker and sync deltas (and possibly others) + return true; + } + return false; + } + + private boolean hasPotentialChanges(ITeamStateChangeEvent event, IWorkingSet set) { + IAdaptable[] elements = set.getElements(); + for (int i = 0; i < elements.length; i++) { + IAdaptable adaptable = elements[i]; + IResource resource = (IResource)adaptable.getAdapter(IResource.class); + if (resource != null && event.hasChange(resource)) { + return true; + } + } + return false; + } +} #P org.eclipse.team.ui Index: plugin.xml =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.team.ui/plugin.xml,v retrieving revision 1.167 diff -u -r1.167 plugin.xml --- plugin.xml 23 Feb 2006 21:54:39 -0000 1.167 +++ plugin.xml 16 Mar 2006 15:43:29 -0000 @@ -335,6 +335,11 @@ + + + @@ -409,7 +414,7 @@ point="org.eclipse.team.ui.teamContentProviders"> * There are two different types of elements being decorated: those * that have a one-to-one mapping to a resource and those that do not. * Those that do should adapt to their corresponding resource. Doing * so will ensure that label updates occur when the state of that * resource changes (i.e. the team provider will generate label updates - * for those resources and the modle can translate them to appropriate + * for those resources and the model can translate them to appropriate * label updates of their model elements). *

* For those elements that do not have a one-to-one mapping to resources, * the model must do extra work. The purpose of this class is to allow * the model to decide when a label update for a logical model element is * required and to communicate the dirty state of their logical model - * elements to the team decorator. For logical model elements, the team decorator - * will only decorate based on the supervised state and the dirty state. - * This class provides methods for determining both of these so that - * logical models can track whether a label update is required for a - * model element. + * elements to the team decorator. *

* Model providers need to re-evaluate the state of a * model element whenever a change in the resources occurs by listening - * to both resource deltas and subscriber change events. + * to both resource deltas and change events from the decorated state provider + * ({@link #getDecoratedStateProvider()}. *

* Decoration enablement changes and decoration configuration changes * are handled by the {@link IDecoratorManager#update(String)} API. @@ -69,100 +59,72 @@ * @see Subscriber#addListener(org.eclipse.team.core.subscribers.ISubscriberChangeListener) */ public class SynchronizationStateTester { - + /** * Constant that is used as the property key on an {@link IDecorationContext}. * If a context passed to a team decorator has this property, the associated - * state tester will be used by the deocator to determine whether elements + * state tester will be used by the decorator to determine whether elements * have an outgoing change. */ public static final String PROP_TESTER = "org.eclipse.team.ui.syncStateTester"; //$NON-NLS-1$ - private Subscriber subscriber; - /** - * Create a tester that uses the workspace subscriber to - * obtain the synchronization state of resources. - * @see Team#getWorkspaceSubscriber() + * Create a synchronization state tester. */ public SynchronizationStateTester() { - this(Team.getWorkspaceSubscriber()); + super(); } /** - * Create a tester that obtains the synchroniation state - * from the given subscriber. - * @param subscriber the subscriber + * Return whether state decoration is enabled for the context + * to which this tester is associated. If true + * is returned, a team decorator will use the state methods provided + * on this class to calculate the synchronization state of model + * elements for the purpose of decoration. If false + * is returned, a team decorator will not decorate the elements with any + * synchronization related decorations. Subclasses will want to disable + * state decoration if state decoration is being provided another way + * (e.g. by a {@link SynchronizationLabelProvider}). By default, + * trueis returned. Subclasses may override. + * @return whether state decoration is enabled */ - public SynchronizationStateTester(Subscriber subscriber) { - this.subscriber = subscriber; + public boolean isStateDecorationEnabled() { + return true; } - + /** * Return whether decoration is enabled for the given - * model element. If decoration is not enabled, the model - * does not need to fire label change events when the team state - * of the element changes. + * model element in the context to which this tester is associated. + * By default, the enablement state from the provider returned + * from {@link #getDecoratedStateProvider()} is used but subclasses + * may override to disable decoration of particular elements. + *

+ * A team decorator should call this method before decorating a model element. + * If the method returns true, no team state decorations should be applied + * to the model element. Otherwise, the {@link #getState(Object, int, IProgressMonitor)} + * should be consulted in order to determine what state to decorate. * @param element the model element * @return whether decoration is enabled for the given * model element */ - public final boolean isDecorationEnabled(Object element) { - ResourceMapping mapping = Utils.getResourceMapping(element); - if (mapping != null) { - IProject[] projects = mapping.getProjects(); - return internalIsDecorationEnabled(projects); - } - return false; + public boolean isDecorationEnabled(Object element) { + return isStateDecorationEnabled() + && getDecoratedStateProvider().isDecorationEnabled(element); } /** * Return the mask that indicates what state the appropriate team decorator - * is capable of decorating. The state is determined by querying the - * org.eclipse.team.ui.teamDecorators extension point. - * - *

- * The state mask can consist of the following flags: - *

    - *
  • The diff kinds of {@link IDiff#ADD}, {@link IDiff#REMOVE} - * and {@link IDiff#CHANGE}. - *
  • The directions {@link IThreeWayDiff#INCOMING} and - * {@link IThreeWayDiff#OUTGOING}. - *
- * For convenience sake, if there are no kind flags but there is at least - * one direction flag then all kinds are assumed. + * is capable of decorating. The state mask is obtained from the provider + * returned from {@link #getDecoratedStateProvider()}. * * @param element * the model element to be decorated * @return the mask that indicates what state the appropriate team decorator * will decorate - * @see IDiff - * @see IThreeWayDiff + * @see TeamStateProvider#getDecoratedStateMask(Object) */ public final int getDecoratedStateMask(Object element) { - ResourceMapping mapping = Utils.getResourceMapping(element); - if (mapping != null) { - IProject[] projects = mapping.getProjects(); - return internalGetDecoratedStateMask(projects); - } - return 0; - } - - /** - * Return whether state decoration is enabled for the context - * to which this tester is associated. If true - * is returned, team decorators will use the state methods provided - * on this class to calculate the synchronization state of model - * elements for the purpose of decoration. If false - * is returned, team decorators will not decorate the elements with any - * synchronization related decorations. Subclasses will want to disable - * state decoration if state decoration is being provided another way - * (e.g. by a {@link SynchronizationLabelProvider}). By default, - * trueis returned. Subclasses may override. - * @return whether state decoration is enabled - */ - public boolean isStateDecorationEnabled() { - return true; + return getDecoratedStateProvider().getDecoratedStateMask(element); } /** @@ -171,7 +133,7 @@ * returned. By default, this method calls * {@link Subscriber#getState(ResourceMapping, int, IProgressMonitor)}. *

- * Team decorators will use this method to detemine how to decorate the + * A team decorator will use this method to determine how to decorate the * provided element. The {@link #getDecoratedStateMask(Object)} returns the * state that the corresponding team decorator is capable of decorating but * the decorator may be configured to decorate only a portion of that state. @@ -186,10 +148,11 @@ * decorated state of a model element changes. In this case the subclass * can override this method to record the stateMask and returned state. It can * use this recorded information to determine whether local changes or subscriber changes - * result in a change in the deocrated sstate of the model element. + * result in a change in the decorated state of the model element. *

  • The subclasses wishes to provide a more accurate change description for a model * element that represents only a portion of the file. In this case, the subclass can - * use the remote file contents available from the subscriber to determine whether + * use the remote file contents available from the provider to determine the proper + * state for the element. * * * @param element the model element @@ -198,122 +161,36 @@ * @param monitor a progress monitor * @return the synchronization state of the given element * @throws CoreException - * @see Subscriber#getState(ResourceMapping, int, IProgressMonitor) */ public int getState(Object element, int stateMask, IProgressMonitor monitor) throws CoreException { - ResourceMapping mapping = Utils.getResourceMapping(element); - if (mapping != null) { - try { - return subscriber.getState(mapping, stateMask, monitor); - } catch (CoreException e) { - IProject[] projects = mapping.getProjects(); - for (int i = 0; i < projects.length; i++) { - IProject project = projects[i]; - // Only through the exception if the project for the mapping is accessible - if (project.isAccessible()) { - throw e; - } - } - } - } - return 0; + ITeamStateDescription desc = getDecoratedStateProvider().getStateDescription(element, stateMask, new String[0], monitor); + if (desc != null) + return desc.getStateFlags(); + return IDiff.NO_CHANGE; } /** - * Return whether the given element is supervised. To determine this, the - * element is adapted to a resource mapping and, using the mapping's - * traversals, the subcriber is consulted to determine if the element is supervised. - * An element is supervised if all the resources covered by it's traversals are - * supervised. - * @see Subscriber#isSupervised(org.eclipse.core.resources.IResource) - * - * @param element the element being tested - * @return whether the given element is supervisied. - * @throws CoreException if an error occurres + * Return a decorated state provider that delegates to the appropriate team + * provider. + * @return a decorated state provider that delegates to the appropriate team + * provider */ - public final boolean isSupervised(Object element) throws CoreException { - ResourceMapping mapping = Utils.getResourceMapping(element); - if (mapping != null) { - ResourceTraversal[] traversals = mapping.getTraversals(ResourceMappingContext.LOCAL_CONTEXT, null); - for (int i = 0; i < traversals.length; i++) { - ResourceTraversal traversal = traversals[i]; - IResource[] resources = traversal.getResources(); - for (int j = 0; j < resources.length; j++) { - IResource resource = resources[j]; - if (subscriber.isSupervised(resource)) - return true; - } - } - } - return false; + public ITeamStateProvider getDecoratedStateProvider() { + return TeamUIPlugin.getPlugin().getDecoratedStateProvider(); } - + /** - * Return the subscriber associated with this tester. - * @return the subscriber associated with this tester. + * A callback to the tester made from the team decorator to notify the + * tester that the given element has been decorated with the given state. + * The purpose of the callback is to allow the owner of the tester to + * cache the decorated state in order to detect whether a future state + * change requires a label update for the element. + * @param element the element that was decorated + * @param description a description of the decorated state of the element */ - public Subscriber getSubscriber() { - return subscriber; + public void elementDecorated(Object element, ITeamStateDescription description) { + // do nothing by default } - private boolean internalIsDecorationEnabled(IProject[] projects) { - String[] providerIds = getProviderIds(projects); - for (int i = 0; i < providerIds.length; i++) { - String providerId = providerIds[i]; - if (internalIsDecorationEnabled(providerId)) { - return true; - } - } - return false; - } - - private String[] getProviderIds(IProject[] projects) { - Set providerIds = new HashSet(); - for (int i = 0; i < projects.length; i++) { - IProject project = projects[i]; - String id = getProviderId(project); - if (id != null) - providerIds.add(id); - } - return (String[]) providerIds.toArray(new String[providerIds.size()]); - } - - private int internalGetDecoratedStateMask(IProject[] projects) { - int stateMask = 0; - String[] providerIds = getProviderIds(projects); - for (int i = 0; i < providerIds.length; i++) { - String providerId = providerIds[i]; - stateMask |= internalGetDecoratedStateMask(providerId); - } - return stateMask; - } - - private String getProviderId(IProject project) { - RepositoryProvider provider = RepositoryProvider.getProvider(project); - if (provider != null) - return provider.getID(); - return null; - } - - private boolean internalIsDecorationEnabled(String providerId) { - String decoratorId = getDecoratorId(providerId); - if (decoratorId != null) { - return PlatformUI.getWorkbench().getDecoratorManager().getEnabled(decoratorId); - } - return false; - } - private int internalGetDecoratedStateMask(String providerId) { - TeamDecoratorDescription decoratorDescription = TeamDecoratorManager.getInstance().getDecoratorDescription(providerId); - if (decoratorDescription != null) - return decoratorDescription.getDecoratedDirectionFlags(); - return 0; - } - - private String getDecoratorId(String providerId) { - TeamDecoratorDescription decoratorDescription = TeamDecoratorManager.getInstance().getDecoratorDescription(providerId); - if (decoratorDescription != null) - return decoratorDescription.getDecoratorId(); - return null; - } } Index: src/org/eclipse/team/ui/synchronize/TeamStateDescription.java =================================================================== RCS file: src/org/eclipse/team/ui/synchronize/TeamStateDescription.java diff -N src/org/eclipse/team/ui/synchronize/TeamStateDescription.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ src/org/eclipse/team/ui/synchronize/TeamStateDescription.java 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,129 @@ +/******************************************************************************* + * Copyright (c) 2006 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.team.ui.synchronize; + +import java.util.HashMap; +import java.util.Map; + +import org.eclipse.team.core.diff.IThreeWayDiff; +import org.eclipse.team.core.diff.provider.Diff; +import org.eclipse.team.ui.mapping.ITeamStateDescription; + +/** + * An implementation of {@link ITeamStateDescription} which may be used or + * subclassed by clients. + * @since 3.2 + */ +public class TeamStateDescription implements ITeamStateDescription { + + private int state; + private Map properties = new HashMap(); + + /** + * Create a description with the given state. + * @param state the state + */ + public TeamStateDescription(int state) { + this.state = state; + } + + /* (non-Javadoc) + * @see org.eclipse.team.ui.mapping.IDecoratedStateDescription#getStateFlags() + */ + public int getStateFlags() { + return state; + } + + /* (non-Javadoc) + * @see org.eclipse.team.ui.mapping.IDecoratedStateDescription#getKind() + */ + public int getKind() { + return state & Diff.KIND_MASK; + } + + /* (non-Javadoc) + * @see org.eclipse.team.ui.mapping.IDecoratedStateDescription#getDirection() + */ + public int getDirection() { + return state & IThreeWayDiff.DIRECTION_MASK; + } + + /* (non-Javadoc) + * @see org.eclipse.team.ui.mapping.ITeamStateDescription#getProperties() + */ + public String[] getProperties() { + return (String[]) properties.keySet().toArray(new String[properties.size()]); + } + + /* (non-Javadoc) + * @see org.eclipse.team.ui.mapping.ITeamStateDescription#getProperty(java.lang.String) + */ + public Object getProperty(String property) { + return properties.get(property); + } + + /** + * Set the given property to the given value + * @param property the property + * @param value the value + */ + public void setProperty(String property, Object value) { + properties.put(property, value); + } + + /* (non-Javadoc) + * @see java.lang.Object#equals(java.lang.Object) + */ + public boolean equals(Object obj) { + if (obj instanceof TeamStateDescription) { + TeamStateDescription dsd = (TeamStateDescription) obj; + if (dsd.getStateFlags() == state) { + if (haveSameProperties(this, dsd)) { + String[] properties = getProperties(); + for (int i = 0; i < properties.length; i++) { + String property = properties[i]; + Object o1 = this.getProperty(property); + Object o2 = dsd.getProperty(property); + if (!o1.equals(o2)) { + return false; + } + } + return true; + } + } + return false; + } + return super.equals(obj); + } + + private boolean haveSameProperties(TeamStateDescription d1, TeamStateDescription d2) { + String[] p1 = d1.getProperties(); + String[] p2 = d2.getProperties(); + if (p1.length != p2.length) { + return false; + } + for (int i = 0; i < p1.length; i++) { + String s1 = p1[i]; + boolean found = false; + for (int j = 0; j < p2.length; j++) { + String s2 = p2[j]; + if (s1.equals(s2)) { + found = true; + break; + } + } + if (!found) + return false; + } + return true; + } + +} Index: src/org/eclipse/team/internal/ui/mapping/WorkspaceTeamStateProvider.java =================================================================== RCS file: src/org/eclipse/team/internal/ui/mapping/WorkspaceTeamStateProvider.java diff -N src/org/eclipse/team/internal/ui/mapping/WorkspaceTeamStateProvider.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ src/org/eclipse/team/internal/ui/mapping/WorkspaceTeamStateProvider.java 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,235 @@ +/******************************************************************************* + * Copyright (c) 2006 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.team.internal.ui.mapping; + +import java.util.HashMap; +import java.util.Map; + +import org.eclipse.core.resources.*; +import org.eclipse.core.resources.mapping.ResourceMapping; +import org.eclipse.core.resources.mapping.ResourceMappingContext; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.team.core.RepositoryProvider; +import org.eclipse.team.core.RepositoryProviderType; +import org.eclipse.team.internal.core.*; +import org.eclipse.team.internal.ui.Utils; +import org.eclipse.team.ui.mapping.*; +import org.eclipse.team.ui.synchronize.TeamStateProvider; + +/** + * A decorated state provider that delegates to the provider for the repository + * provider type that is associated with the projects that an element maps to + * using the ResourceMapping API. + * + */ +public class WorkspaceTeamStateProvider extends TeamStateProvider + implements ITeamStateChangeListener, IRepositoryProviderListener, + IResourceChangeListener { + + private Map providers = new HashMap(); + + public WorkspaceTeamStateProvider() { + RepositoryProviderManager.getInstance().addListener(this); + ResourcesPlugin.getWorkspace().addResourceChangeListener(this, + IResourceChangeEvent.POST_CHANGE); + IProject[] allProjects = ResourcesPlugin.getWorkspace().getRoot() + .getProjects(); + for (int i = 0; i < allProjects.length; i++) { + IProject project = allProjects[i]; + handleProject(project); + } + } + + public void dispose() { + RepositoryProviderManager.getInstance().removeListener(this); + ResourcesPlugin.getWorkspace().removeResourceChangeListener(this); + } + + /* (non-Javadoc) + * @see org.eclipse.team.ui.mapping.DecoratedStateProvider#isDecorationEnabled(java.lang.Object) + */ + public final boolean isDecorationEnabled(Object element) { + ITeamStateProvider provider = getDecoratedStateProvider(element); + if (provider != null) + return provider.isDecorationEnabled(element); + return false; + } + + /* (non-Javadoc) + * @see org.eclipse.team.ui.mapping.DecoratedStateProvider#isDecorated(java.lang.Object) + */ + public boolean hasDecoratedState(Object element) throws CoreException { + ITeamStateProvider provider = getDecoratedStateProvider(element); + if (provider != null) + provider.hasDecoratedState(element); + return false; + } + + /* (non-Javadoc) + * @see org.eclipse.team.ui.mapping.DecoratedStateProvider#getDecoratedStateMask(java.lang.Object) + */ + public final int getDecoratedStateMask(Object element) { + ITeamStateProvider provider = getDecoratedStateProvider(element); + if (provider != null) + return provider.getDecoratedStateMask(element); + return 0; + } + + /* (non-Javadoc) + * @see org.eclipse.team.ui.mapping.ITeamStateProvider#getDecoratedProperties(java.lang.Object) + */ + public String[] getDecoratedProperties(Object element) { + ITeamStateProvider provider = getDecoratedStateProvider(element); + if (provider != null) + return provider.getDecoratedProperties(element); + return new String[0]; + } + + + /* (non-Javadoc) + * @see org.eclipse.team.ui.mapping.DecoratedStateProvider#getState(java.lang.Object, int, org.eclipse.core.runtime.IProgressMonitor) + */ + public ITeamStateDescription getStateDescription(Object element, int stateMask, + String[] properties, IProgressMonitor monitor) throws CoreException { + ITeamStateProvider provider = getDecoratedStateProvider(element); + if (provider != null) + return provider.getStateDescription(element, stateMask, properties, monitor); + return null; + } + + /* (non-Javadoc) + * @see org.eclipse.team.ui.mapping.ITeamStateProvider#getResourceMappingContext(java.lang.Object) + */ + public ResourceMappingContext getResourceMappingContext(Object element) { + ITeamStateProvider provider = getDecoratedStateProvider(element); + if (provider != null) + return provider.getResourceMappingContext(element); + return ResourceMappingContext.LOCAL_CONTEXT; + } + + private ITeamStateProvider getDecoratedStateProvider(Object element) { + RepositoryProviderType type = getProviderType(element); + if (type != null) + return (ITeamStateProvider) Utils.getAdapter(type, + ITeamStateProvider.class); + return null; + } + + private ITeamStateProvider getDecoratedStateProviderForId(String id) { + RepositoryProviderType type = getProviderTypeForId(id); + if (type != null) + return (ITeamStateProvider) Utils.getAdapter(type, + ITeamStateProvider.class, true); + return null; + } + + private RepositoryProviderType getProviderType(Object element) { + ResourceMapping mapping = Utils.getResourceMapping(element); + if (mapping != null) { + String providerId = getProviderId(mapping.getProjects()); + if (providerId != null) + return getProviderTypeForId(providerId); + } + return null; + } + + private String getProviderId(IProject[] projects) { + String id = null; + for (int i = 0; i < projects.length; i++) { + IProject project = projects[i]; + String nextId = getProviderId(project); + if (id == null) + id = nextId; + else if (nextId != null && !id.equals(nextId)) + return null; + } + return id; + } + + private String getProviderId(IProject project) { + RepositoryProvider provider = RepositoryProvider.getProvider(project); + if (provider != null) + return provider.getID(); + return null; + } + + private RepositoryProviderType getProviderTypeForId(String providerId) { + return RepositoryProviderType.getProviderType(providerId); + } + + private void handleProject(IProject project) { + if (RepositoryProvider.isShared(project)) { + try { + String currentId = project + .getPersistentProperty(TeamPlugin.PROVIDER_PROP_KEY); + if (currentId != null) { + listenerForStateChangesForId(currentId); + } + } catch (CoreException e) { + TeamPlugin.log(e); + } + } + } + + private void listenerForStateChangesForId(String id) { + if (!providers.containsKey(id)) { + ITeamStateProvider provider = getDecoratedStateProviderForId(id); + if (provider != null) { + providers.put(id, provider); + provider.addDecoratedStateChangeListener(this); + } + } + } + + /* (non-Javadoc) + * @see org.eclipse.team.ui.mapping.IDecoratedStateChangeListener#decoratedStateChanged(org.eclipse.team.ui.mapping.IDecoratedStateChangeEvent) + */ + public void teamStateChanged(ITeamStateChangeEvent event) { + fireStateChangeEvent(event); + } + + /* (non-Javadoc) + * @see org.eclipse.team.internal.core.IRepositoryProviderListener#providerUnmapped(org.eclipse.core.resources.IProject) + */ + public void providerUnmapped(IProject project) { + // We don't need to worry about this + } + + /* (non-Javadoc) + * @see org.eclipse.team.internal.core.IRepositoryProviderListener#providerMapped(org.eclipse.team.core.RepositoryProvider) + */ + public void providerMapped(RepositoryProvider provider) { + String id = provider.getID(); + listenerForStateChangesForId(id); + } + + /* (non-Javadoc) + * @see org.eclipse.core.resources.IResourceChangeListener#resourceChanged(org.eclipse.core.resources.IResourceChangeEvent) + */ + public void resourceChanged(IResourceChangeEvent event) { + IResourceDelta delta = event.getDelta(); + IResourceDelta[] projectDeltas = delta + .getAffectedChildren(IResourceDelta.ADDED + | IResourceDelta.CHANGED); + for (int i = 0; i < projectDeltas.length; i++) { + IResourceDelta projectDelta = projectDeltas[i]; + IResource resource = projectDelta.getResource(); + if ((projectDelta.getFlags() & IResourceDelta.OPEN) != 0 + && resource.getType() == IResource.PROJECT) { + IProject project = (IProject) resource; + if (project.isAccessible()) { + handleProject(project); + } + } + } + } +} Index: src/org/eclipse/team/ui/mapping/ITeamStateChangeListener.java =================================================================== RCS file: src/org/eclipse/team/ui/mapping/ITeamStateChangeListener.java diff -N src/org/eclipse/team/ui/mapping/ITeamStateChangeListener.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ src/org/eclipse/team/ui/mapping/ITeamStateChangeListener.java 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,43 @@ +/******************************************************************************* + * Copyright (c) 2006 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.team.ui.mapping; + +import java.util.EventListener; + +import org.eclipse.core.resources.IWorkspace; +import org.eclipse.team.ui.synchronize.TeamStateProvider; + +/** + * A listener registered with an {@link TeamStateProvider} in order to + * receive change events when the team state of any + * resources change. It is the responsibility of clients to determine if + * a label update is required based on the changed resources. + *

    + * Change events may not be issued if a local change has resulted in a + * synchronization state change. It is up to clients to check whether + * a label update is required for a model element when local resources change + * by using the resource delta mechanism. + *

    + * Clients may implement this interface + * + * @see IWorkspace#addResourceChangeListener(org.eclipse.core.resources.IResourceChangeListener) + * @since 3.2 + */ +public interface ITeamStateChangeListener extends EventListener { + + /** + * Notification that the team state of resources + * has changed. + * @param event the event that describes which resources have changed + */ + public void teamStateChanged(ITeamStateChangeEvent event); + +} Index: src/org/eclipse/team/ui/mapping/ITeamStateChangeEvent.java =================================================================== RCS file: src/org/eclipse/team/ui/mapping/ITeamStateChangeEvent.java diff -N src/org/eclipse/team/ui/mapping/ITeamStateChangeEvent.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ src/org/eclipse/team/ui/mapping/ITeamStateChangeEvent.java 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,70 @@ +/******************************************************************************* + * Copyright (c) 2006 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.team.ui.mapping; + +import org.eclipse.core.resources.IResource; +import org.eclipse.team.ui.synchronize.TeamStateChangeEvent; + +/** + * A description of the team state changes that have occurred. This event + * indicates the resources for which the team state may have changed. + * However, it may be the case that the state did not actually change. Clients + * that wish to determine if the state ha changed must cache the previous state + * and re-obtain the state when they receive this event. Also, the event may + * not include team state changes that resulted from local changes. Clients should listen + * for resource changes as well. + *

    + * This interface is not intended to be implemented by clients. Clients should + * instead use {@link TeamStateChangeEvent}. + * + * @see ITeamStateChangeListener + * @see ITeamStateProvider + * @see TeamStateChangeEvent + * + * @since 3.2 + */ +public interface ITeamStateChangeEvent { + + /** + * Return the set of resources that were previously undecorated + * but are now decorated. + * @return the set of resources that were previously undecorated + * but are now decorated. + */ + public IResource[] getAddedRoots(); + + /** + * Return the set of resources that were previously decorated + * but are now undecorated. + * @return the set of resources that were previously decorated + * but are now undecorated. + */ + public IResource[] getRemovedRoots(); + + /** + * Return the set of resources whose decorated state has changed. + * @return the set of resources whose decorated state has changed. + */ + public IResource[] getChangedResources(); + + /** + * Return whether the resource has any state changes. This returns + * true if the resource is included in the set + * of changes returned by {@link #getChangedResources()} or + * if it is a descendant of a root that is present in a set + * returned by {@link #getAddedRoots()} or {@link #getRemovedRoots()}. + * + * @param resource the resource + * @return whether the resource has any state changes + */ + public boolean hasChange(IResource resource); + +} Index: src/org/eclipse/team/ui/synchronize/TeamStateProvider.java =================================================================== RCS file: src/org/eclipse/team/ui/synchronize/TeamStateProvider.java diff -N src/org/eclipse/team/ui/synchronize/TeamStateProvider.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ src/org/eclipse/team/ui/synchronize/TeamStateProvider.java 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,172 @@ +/******************************************************************************* + * Copyright (c) 2006 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.team.ui.synchronize; + +import java.util.HashSet; +import java.util.Set; + +import org.eclipse.core.resources.IProject; +import org.eclipse.core.resources.mapping.ResourceMapping; +import org.eclipse.core.runtime.*; +import org.eclipse.team.core.RepositoryProvider; +import org.eclipse.team.core.RepositoryProviderType; +import org.eclipse.team.internal.ui.Utils; +import org.eclipse.team.internal.ui.registry.TeamDecoratorDescription; +import org.eclipse.team.internal.ui.registry.TeamDecoratorManager; +import org.eclipse.team.ui.mapping.*; +import org.eclipse.ui.PlatformUI; + +/** + * A decorated state provider is used by the {@link SynchronizationStateTester} to obtain + * the decorated synchronization state for model elements. A decorated state provider is + * associated with a {@link RepositoryProviderType} using the adaptable mechanism. A default + * decoration provider that uses the subscriber of the type is provided. + * + * @see IAdapterManager + * @see RepositoryProviderType + * @since 3.2 + */ +public abstract class TeamStateProvider implements ITeamStateProvider { + + private ListenerList listeners = new ListenerList(ListenerList.IDENTITY); + + /** + * Determine if the decorator for the element is enabled by consulting the + * teamDecorator extension point to determine the decorator + * id associated with the resources the element maps to. Subclasses may + * override. + * + * @see org.eclipse.team.ui.mapping.ITeamStateProvider#isDecorationEnabled(java.lang.Object) + */ + public boolean isDecorationEnabled(Object element) { + ResourceMapping mapping = Utils.getResourceMapping(element); + if (mapping != null) { + IProject[] projects = mapping.getProjects(); + return internalIsDecorationEnabled(projects); + } + return false; + } + + /** + * Determine the decorated state for the element by consulting the + * teamDecorator extension point to get the decorated state + * mask associated with the resources the element maps to. Subclasses may + * override. + * + * @see org.eclipse.team.ui.mapping.ITeamStateProvider#getDecoratedStateMask(java.lang.Object) + */ + public int getDecoratedStateMask(Object element) { + ResourceMapping mapping = Utils.getResourceMapping(element); + if (mapping != null) { + IProject[] projects = mapping.getProjects(); + return internalGetDecoratedStateMask(projects); + } + return 0; + } + + /* (non-Javadoc) + * @see org.eclipse.team.ui.mapping.IDecoratedStateProvider#addDecoratedStateChangeListener(org.eclipse.team.ui.mapping.IDecoratedStateChangeListener) + */ + public void addDecoratedStateChangeListener(ITeamStateChangeListener listener) { + listeners.add(listener); + } + + /* (non-Javadoc) + * @see org.eclipse.team.ui.mapping.IDecoratedStateProvider#removeDecoratedStateChangeListener(org.eclipse.team.ui.mapping.IDecoratedStateChangeListener) + */ + public void removeDecoratedStateChangeListener(ITeamStateChangeListener listener) { + listeners.remove(listener); + } + + /** + * Fire the change event to all listeners + * @param event the change event + */ + protected void fireStateChangeEvent(final ITeamStateChangeEvent event) { + Object[] allListeners = listeners.getListeners(); + for (int i = 0; i < allListeners.length; i++) { + final ITeamStateChangeListener listener = (ITeamStateChangeListener)allListeners[i]; + SafeRunner.run(new ISafeRunnable() { + public void run() throws Exception { + listener.teamStateChanged(event); + } + public void handleException(Throwable exception) { + // Logged by the runner + } + }); + } + } + + private int internalGetDecoratedStateMask(IProject[] projects) { + int stateMask = 0; + String[] providerIds = getProviderIds(projects); + for (int i = 0; i < providerIds.length; i++) { + String providerId = providerIds[i]; + stateMask |= internalGetDecoratedStateMask(providerId); + } + return stateMask; + } + + private int internalGetDecoratedStateMask(String providerId) { + TeamDecoratorDescription decoratorDescription = TeamDecoratorManager + .getInstance().getDecoratorDescription(providerId); + if (decoratorDescription != null) + return decoratorDescription.getDecoratedDirectionFlags(); + return 0; + } + + private String[] getProviderIds(IProject[] projects) { + Set providerIds = new HashSet(); + for (int i = 0; i < projects.length; i++) { + IProject project = projects[i]; + String id = getProviderId(project); + if (id != null) + providerIds.add(id); + } + return (String[]) providerIds.toArray(new String[providerIds.size()]); + } + + private String getProviderId(IProject project) { + RepositoryProvider provider = RepositoryProvider.getProvider(project); + if (provider != null) + return provider.getID(); + return null; + } + + private boolean internalIsDecorationEnabled(IProject[] projects) { + String[] providerIds = getProviderIds(projects); + for (int i = 0; i < providerIds.length; i++) { + String providerId = providerIds[i]; + if (internalIsDecorationEnabled(providerId)) { + return true; + } + } + return false; + } + + private boolean internalIsDecorationEnabled(String providerId) { + String decoratorId = getDecoratorId(providerId); + if (decoratorId != null) { + return PlatformUI.getWorkbench().getDecoratorManager().getEnabled( + decoratorId); + } + return false; + } + + private String getDecoratorId(String providerId) { + TeamDecoratorDescription decoratorDescription = TeamDecoratorManager + .getInstance().getDecoratorDescription(providerId); + if (decoratorDescription != null) + return decoratorDescription.getDecoratorId(); + return null; + } + +} Index: src/org/eclipse/team/ui/synchronize/SubscriberTeamStateProvider.java =================================================================== RCS file: src/org/eclipse/team/ui/synchronize/SubscriberTeamStateProvider.java diff -N src/org/eclipse/team/ui/synchronize/SubscriberTeamStateProvider.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ src/org/eclipse/team/ui/synchronize/SubscriberTeamStateProvider.java 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,150 @@ +/******************************************************************************* + * Copyright (c) 2006 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.team.ui.synchronize; + +import org.eclipse.core.resources.IProject; +import org.eclipse.core.resources.IResource; +import org.eclipse.core.resources.mapping.*; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.team.core.RepositoryProviderType; +import org.eclipse.team.core.diff.IDiff; +import org.eclipse.team.core.subscribers.*; +import org.eclipse.team.internal.ui.Policy; +import org.eclipse.team.internal.ui.Utils; +import org.eclipse.team.ui.mapping.ITeamStateDescription; +import org.eclipse.team.ui.mapping.ITeamStateProvider; + +/** + * A team state provider that makes use of a {@link Subscriber} to determine the synchronization + * state. Repository provider types that have a subscriber will get one of these free through the adaptable mechanism. + * If a repository provider type does not have a subscriber, or it a repository provider type wishes to se a custom + * provider, they must adapt their {@link RepositoryProviderType} class to an appropriate {@link ITeamStateProvider}. + *

    + * Clients may subclass this class. + * + * @since 3.2 + */ +public class SubscriberTeamStateProvider extends TeamStateProvider implements ISubscriberChangeListener { + + private Subscriber subscriber; + + /** + * Create a provider that determines the synchronization state + * from the subscriber. This method registers this provider as a listener + * on the subscriber in order to know when to fire state change events. + * @param subscriber the subscriber for this provider + */ + public SubscriberTeamStateProvider(Subscriber subscriber) { + this.subscriber = subscriber; + subscriber.addListener(this); + } + + /* (non-Javadoc) + * @see org.eclipse.team.ui.mapping.DecoratedStateProvider#isDecorated(java.lang.Object) + */ + public boolean hasDecoratedState(Object element) throws CoreException { + ResourceMapping mapping = Utils.getResourceMapping(element); + if (mapping != null) { + ResourceTraversal[] traversals = mapping.getTraversals( + ResourceMappingContext.LOCAL_CONTEXT, null); + for (int i = 0; i < traversals.length; i++) { + ResourceTraversal traversal = traversals[i]; + IResource[] resources = traversal.getResources(); + for (int j = 0; j < resources.length; j++) { + IResource resource = resources[j]; + if (getSubscriber().isSupervised(resource)) + return true; + } + } + } + return false; + } + + /** + * Obtain the synchronization state of the element from the subscriber + * using {@link Subscriber#getState(ResourceMapping, int, IProgressMonitor)} + * @param element the element + * @param stateMask the state mask that indicates which state flags are desired + * @param monitor a progress monitor + * @return the synchronization state of the element + * @throws CoreException + */ + protected int getSynchronizationState(Object element, int stateMask, + IProgressMonitor monitor) throws CoreException { + ResourceMapping mapping = Utils.getResourceMapping(element); + if (mapping != null) { + try { + return getSubscriber().getState(mapping, stateMask, monitor); + } catch (CoreException e) { + IProject[] projects = mapping.getProjects(); + for (int i = 0; i < projects.length; i++) { + IProject project = projects[i]; + // Only through the exception if the project for the mapping + // is accessible + if (project.isAccessible()) { + throw e; + } + } + } + } + return IDiff.NO_CHANGE; + } + + /* (non-Javadoc) + * @see org.eclipse.team.ui.mapping.DecoratedStateProvider#getState(java.lang.Object, int, org.eclipse.core.runtime.IProgressMonitor) + */ + public ITeamStateDescription getStateDescription(Object element, int stateMask, + String[] properties, IProgressMonitor monitor) throws CoreException { + monitor = Policy.monitorFor(monitor); + if (stateMask == USE_DECORATED_STATE_MASK) + stateMask = getDecoratedStateMask(element); + return new TeamStateDescription(getSynchronizationState(element, stateMask, monitor)); + } + + /* (non-Javadoc) + * @see org.eclipse.team.ui.mapping.IDecoratedStateProvider#getResourceMappingContext(java.lang.Object) + */ + public ResourceMappingContext getResourceMappingContext(Object element) { + return new SubscriberResourceMappingContext(subscriber, false); + } + + /** + * Return the subscriber associated with this tester. + * + * @return the subscriber associated with this tester. + */ + protected Subscriber getSubscriber() { + return subscriber; + } + + /** + * Called when the provider is no longer needed. This + * method stops listening to the subscriber. + */ + public void dispose() { + subscriber.removeListener(this); + } + + /* (non-Javadoc) + * @see org.eclipse.team.core.subscribers.ISubscriberChangeListener#subscriberResourceChanged(org.eclipse.team.core.subscribers.ISubscriberChangeEvent[]) + */ + public void subscriberResourceChanged(ISubscriberChangeEvent[] deltas) { + fireStateChangeEvent(new TeamStateChangeEvent(deltas)); + } + + /* (non-Javadoc) + * @see org.eclipse.team.ui.mapping.ITeamStateProvider#getDecoratedProperties(java.lang.Object) + */ + public String[] getDecoratedProperties(Object element) { + return new String[0]; + } +} Index: src/org/eclipse/team/ui/mapping/ITeamStateProvider.java =================================================================== RCS file: src/org/eclipse/team/ui/mapping/ITeamStateProvider.java diff -N src/org/eclipse/team/ui/mapping/ITeamStateProvider.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ src/org/eclipse/team/ui/mapping/ITeamStateProvider.java 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,173 @@ +/******************************************************************************* + * Copyright (c) 2006 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.team.ui.mapping; + +import org.eclipse.core.resources.mapping.RemoteResourceMappingContext; +import org.eclipse.core.resources.mapping.ResourceMappingContext; +import org.eclipse.core.runtime.*; +import org.eclipse.team.core.RepositoryProviderType; +import org.eclipse.team.core.diff.IDiff; +import org.eclipse.team.core.diff.IThreeWayDiff; +import org.eclipse.team.ui.synchronize.TeamStateProvider; +import org.eclipse.team.ui.synchronize.SubscriberTeamStateProvider; + +/** + * A team state provider is used by the {@link SynchronizationStateTester} + * to obtain the team state for model elements. A team + * state provider is associated with a {@link RepositoryProviderType} using the + * adaptable mechanism. A default decoration provider that uses the subscriber + * of the type is provided. + *

    + * This interface is not intended to be implemented by clients. Clients should + * instead subclass {@link TeamStateProvider} or + * {@link SubscriberTeamStateProvider}. + * + * @see IAdapterManager + * @see RepositoryProviderType + * @see RepositoryProviderType#getSubscriber() + * @see TeamStateProvider + * @see SubscriberTeamStateProvider + * @see SynchronizationStateTester + * + * @since 3.2 + */ +public interface ITeamStateProvider { + + /** + * A state mask that can be passed to the {@link #getStateDescription(Object, int, String[], IProgressMonitor)} + * method to indicate that only the decorated state flags are desired. It is equivalent to + * passing he mask returned from {@link #getDecoratedStateMask(Object)}; + */ + public static final int USE_DECORATED_STATE_MASK = -1; + + /** + * Return whether decoration is enabled for the given model element. If + * decoration is not enabled, the model does not need to fire label change + * events when the team state of the element changes. + * + * @param element + * the model element + * @return whether decoration is enabled for the given model element + */ + public boolean isDecorationEnabled(Object element); + + /** + * Return whether the given element has any decorated state. + * + * @param element + * the element being decorated + * @return whether the given element has any decorated state + * @throws CoreException + */ + public boolean hasDecoratedState(Object element) throws CoreException; + + /** + * Return the mask that indicates what state the appropriate team decorator + * is capable of decorating. Clients can used this to obtain the current + * decorated state from + * {@link #getStateDescription(Object, int, String[], IProgressMonitor)} in + * order to determine if the decorated state has changed. + * + *

    + * The state mask can consist of the following standard flags: + *

      + *
    • The diff kinds of {@link IDiff#ADD}, {@link IDiff#REMOVE} and + * {@link IDiff#CHANGE}. + *
    • The directions {@link IThreeWayDiff#INCOMING} and + * {@link IThreeWayDiff#OUTGOING}. + *
    + * For convenience sake, if there are no kind flags but there is at least + * one direction flag then all kinds are assumed. + *

    + * The mask can also consist of flag bits that are unique to the repository + * provider associated with the resources that the element maps to. + * + * @param element + * the model element to be decorated + * @return the mask that indicates what state the appropriate team decorator + * will decorate + * @see IDiff + * @see IThreeWayDiff + */ + public int getDecoratedStateMask(Object element); + + /** + * Return the set of property identifiers that represent the set of + * properties that the team decorator would decorate for the given model + * element. + * + * @param element + * the model element to be decorated + * @return the set of decorated properties + */ + public String[] getDecoratedProperties(Object element); + + /** + * Return the state description for the given element. A null + * is return if the element is not decorated or if decoration is disabled. + * Only the portion of the synchronization state covered by + * stateMask is returned. The stateMask should + * be {@link #USE_DECORATED_STATE_MASK} or the mask returned from + * {@link #getDecoratedStateMask(Object)} and the requested properties + * should be null or the value returned from + * {@link #getDecoratedProperties(Object)} if the client wishes to obtain + * the current decorated state. + * + * @param element + * the model element + * @param stateMask + * the mask that identifies which synchronization state flags are + * desired if present + * @param properties + * the set of properties that should be included in the result or + * null if the decorated properties are desired + * @param monitor + * a progress monitor + * @return the state for the given element or null + * @throws CoreException + */ + public ITeamStateDescription getStateDescription(Object element, + int stateMask, String[] properties, IProgressMonitor monitor) + throws CoreException; + + /** + * Return a resource mapping context that gives access to the remote state + * of the resources associated with the provider. If a + * {@link RemoteResourceMappingContext} is returned, then the client may + * access the remote state. + * + * @param element + * the element for which remote contents are desired + * + * @return a resource mapping context that gives access to the remote state + * of the resources associated with the provider + */ + public ResourceMappingContext getResourceMappingContext(Object element); + + /** + * Add a decorated state change listener to the provider. + * + * @param listener + * the listener + */ + public void addDecoratedStateChangeListener( + ITeamStateChangeListener listener); + + /** + * Remove the decorated state change listener to the provider. + * + * @param listener + * the listener + */ + public void removeDecoratedStateChangeListener( + ITeamStateChangeListener listener); + +} Index: src/org/eclipse/team/ui/synchronize/TeamStateChangeEvent.java =================================================================== RCS file: src/org/eclipse/team/ui/synchronize/TeamStateChangeEvent.java diff -N src/org/eclipse/team/ui/synchronize/TeamStateChangeEvent.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ src/org/eclipse/team/ui/synchronize/TeamStateChangeEvent.java 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,117 @@ +/******************************************************************************* + * Copyright (c) 2006 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.team.ui.synchronize; + +import java.util.HashSet; +import java.util.Set; + +import org.eclipse.core.resources.IResource; +import org.eclipse.team.core.subscribers.ISubscriberChangeEvent; +import org.eclipse.team.ui.mapping.ITeamStateChangeEvent; + +/** + * An implementation of {@link ITeamStateChangeEvent}. + * @since 3.2 + */ +public class TeamStateChangeEvent implements ITeamStateChangeEvent { + + Set changes = new HashSet(); + Set addedRoots = new HashSet(); + Set removedRoots = new HashSet(); + + /** + * Convenience constructor for creating an event from a subscriber change. + * @param deltas the set of subscriber changes + */ + public TeamStateChangeEvent(ISubscriberChangeEvent[] deltas) { + for (int i = 0; i < deltas.length; i++) { + ISubscriberChangeEvent event = deltas[i]; + IResource resource = event.getResource(); + if ((event.getFlags() & ISubscriberChangeEvent.ROOT_ADDED) != 0) + rootAdded(resource); + if ((event.getFlags() & ISubscriberChangeEvent.ROOT_REMOVED) != 0) + rootRemoved(resource); + if ((event.getFlags() & ISubscriberChangeEvent.SYNC_CHANGED) != 0) + changed(resource); + // Indicate that the ancestors may have changed as well + while (resource.getType() != IResource.PROJECT) { + resource = resource.getParent(); + changed(resource); + } + } + } + + /** + * The given resource has changed state. + * @param resource the resource whose state has changed + */ + public void changed(IResource resource) { + changes.add(resource); + } + + /** + * The given root resource has been removed. + * @param resource the resource + */ + public void rootRemoved(IResource resource) { + removedRoots.add(resource); + } + + /** + * The given root resource has been added. + * @param resource the resource + */ + public void rootAdded(IResource resource) { + addedRoots.add(resource); + } + + /* (non-Javadoc) + * @see org.eclipse.team.ui.mapping.IDecoratedStateChangeEvent#getAddedRoots() + */ + public IResource[] getAddedRoots() { + return (IResource[]) addedRoots.toArray(new IResource[addedRoots.size()]); + } + + /* (non-Javadoc) + * @see org.eclipse.team.ui.mapping.IDecoratedStateChangeEvent#getRemovedRoots() + */ + public IResource[] getRemovedRoots() { + return (IResource[]) removedRoots.toArray(new IResource[removedRoots.size()]); + } + + /* (non-Javadoc) + * @see org.eclipse.team.ui.mapping.IDecoratedStateChangeEvent#getChangedResources() + */ + public IResource[] getChangedResources() { + return (IResource[]) changes.toArray(new IResource[changes.size()]); + } + + /* (non-Javadoc) + * @see org.eclipse.team.ui.mapping.IDecoratedStateChangeEvent#hasChange(org.eclipse.core.resources.IResource) + */ + public boolean hasChange(IResource resource) { + if (changes.contains(resource)) + return true; + if (isChildOfChangedRoot(resource)) { + return true; + } + return false; + } + + private boolean isChildOfChangedRoot(IResource resource) { + if (resource == null || resource.getType() == IResource.ROOT) + return false; + if (addedRoots.contains(resource) || removedRoots.contains(resource)) + return true; + return isChildOfChangedRoot(resource.getParent()); + } + +} Index: src/org/eclipse/team/ui/mapping/ITeamStateDescription.java =================================================================== RCS file: src/org/eclipse/team/ui/mapping/ITeamStateDescription.java diff -N src/org/eclipse/team/ui/mapping/ITeamStateDescription.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ src/org/eclipse/team/ui/mapping/ITeamStateDescription.java 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,81 @@ +/******************************************************************************* + * Copyright (c) 2006 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.team.ui.mapping; + +import org.eclipse.team.core.diff.IDiff; +import org.eclipse.team.core.diff.IThreeWayDiff; +import org.eclipse.team.core.mapping.IResourceDiff; +import org.eclipse.team.ui.synchronize.TeamStateDescription; +import org.eclipse.team.ui.synchronize.TeamStateProvider; + +/** + * A description of the the state of a logical model element with respect to a + * team repository. + *

    + * This interface is not intended to be implemented by clients. Clients that wish + * to create a description should use {@link TeamStateDescription}. + * + * @see TeamStateProvider + * @since 3.2 + */ +public interface ITeamStateDescription { + + /** + * Return the synchronization state flags for the element for which this + * state description was generated. Only the portion of the synchronization + * state covered by stateMask used when obtaining this + * description is returned. + * + * @return the synchronization state of the given element + * @see IDiff + * @see IThreeWayDiff + * @see IResourceDiff + */ + int getStateFlags(); + + /** + * Return the portion of the state flags that represent the kind associated + * with the element for which this description was generated. See + * {@link IDiff#getKind()} for a description of what this value represents. + * + * @return the kind associated with the element for which this description + * was generated + */ + int getKind(); + + /** + * Return the portion of the state flags that represent the direction + * associated with the element for which this description was generated. See + * {@link IThreeWayDiff#getDirection()} for a description of what this value + * represents. + * + * @return the direction associated with the element for which this + * description was generated + */ + int getDirection(); + + /** + * Return the properties names for all decorated properties associated with + * the element for which this description was generated. + * + * @return the properties names for all decorated properties + */ + public abstract String[] getProperties(); + + /** + * Return the value associated with the given property. A null + * is returned if the property has no value. + * @param property the property + * @return the value associated with the given property or null + */ + public abstract Object getProperty(String property); + +} #P org.eclipse.team.cvs.ui Index: src/org/eclipse/team/internal/ccvs/ui/model/CVSAdapterFactory.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/model/CVSAdapterFactory.java,v retrieving revision 1.16 diff -u -r1.16 CVSAdapterFactory.java --- src/org/eclipse/team/internal/ccvs/ui/model/CVSAdapterFactory.java 9 Mar 2006 19:34:56 -0000 1.16 +++ src/org/eclipse/team/internal/ccvs/ui/model/CVSAdapterFactory.java 16 Mar 2006 15:43:30 -0000 @@ -14,19 +14,23 @@ import org.eclipse.core.runtime.IAdapterFactory; import org.eclipse.team.internal.ccvs.core.*; import org.eclipse.team.internal.ccvs.ui.CVSHistoryPageSource; +import org.eclipse.team.internal.ccvs.ui.CVSTeamStateProvider; import org.eclipse.team.internal.ccvs.ui.repo.RepositoryRoot; import org.eclipse.team.ui.history.IHistoryPageSource; import org.eclipse.team.ui.mapping.ISynchronizationCompareAdapter; +import org.eclipse.team.ui.mapping.ITeamStateProvider; import org.eclipse.ui.model.IWorkbenchAdapter; import org.eclipse.ui.progress.IDeferredWorkbenchAdapter; import org.eclipse.ui.views.properties.IPropertySource; public class CVSAdapterFactory implements IAdapterFactory { - private Object fileAdapter = new RemoteFileElement(); - private Object folderAdapter = new RemoteFolderElement(); - private Object rootAdapter = new CVSRepositoryRootElement(); + private static Object fileAdapter = new RemoteFileElement(); + private static Object folderAdapter = new RemoteFolderElement(); + private static Object rootAdapter = new CVSRepositoryRootElement(); - private Object historyParticipant = new CVSHistoryPageSource(); + private static Object historyParticipant = new CVSHistoryPageSource(); + + private static Object teamStateProvider; // Property cache private Object cachedPropertyObject = null; @@ -56,6 +60,14 @@ return historyParticipant; } + if (ITeamStateProvider.class == adapterType) { + synchronized (this) { + if (teamStateProvider == null) + teamStateProvider = new CVSTeamStateProvider(CVSProviderPlugin.getPlugin().getCVSWorkspaceSubscriber()); + } + return teamStateProvider; + } + return null; } @@ -76,8 +88,11 @@ * Method declared on IAdapterFactory. */ public Class[] getAdapterList() { - return new Class[] {IWorkbenchAdapter.class, IPropertySource.class, IDeferredWorkbenchAdapter.class, IHistoryPageSource.class, ISynchronizationCompareAdapter.class}; + return new Class[] { IWorkbenchAdapter.class, IPropertySource.class, + IDeferredWorkbenchAdapter.class, IHistoryPageSource.class, + ISynchronizationCompareAdapter.class, ITeamStateProvider.class }; } + /** * Returns the property source for the given object. Caches * the result because the property sheet is extremely inefficient, Index: plugin.xml =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.team.cvs.ui/plugin.xml,v retrieving revision 1.244 diff -u -r1.244 plugin.xml --- plugin.xml 14 Mar 2006 14:33:23 -0000 1.244 +++ plugin.xml 16 Mar 2006 15:43:30 -0000 @@ -1550,6 +1550,11 @@ class="org.eclipse.team.internal.ccvs.ui.model.CVSAdapterFactory"> + + + Index: src/org/eclipse/team/internal/ccvs/ui/CVSDecoration.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/CVSDecoration.java,v retrieving revision 1.16 diff -u -r1.16 CVSDecoration.java --- src/org/eclipse/team/internal/ccvs/ui/CVSDecoration.java 16 Mar 2006 02:48:04 -0000 1.16 +++ src/org/eclipse/team/internal/ccvs/ui/CVSDecoration.java 16 Mar 2006 15:43:30 -0000 @@ -20,11 +20,13 @@ import org.eclipse.jface.resource.ImageDescriptor; import org.eclipse.jface.viewers.IDecoration; import org.eclipse.swt.graphics.*; +import org.eclipse.team.core.diff.IThreeWayDiff; import org.eclipse.team.internal.ccvs.core.ICVSRepositoryLocation; import org.eclipse.team.internal.ccvs.ui.repo.RepositoryManager; import org.eclipse.team.internal.ccvs.ui.repo.RepositoryRoot; import org.eclipse.team.internal.ui.TeamUIPlugin; import org.eclipse.team.ui.ISharedImages; +import org.eclipse.team.ui.synchronize.TeamStateDescription; import org.eclipse.ui.PlatformUI; import org.eclipse.ui.themes.ITheme; @@ -75,6 +77,7 @@ private String repository; private ICVSRepositoryLocation location; private String keywordSubstitution; + private int stateFlags; // Text formatters private String fileFormatter; @@ -93,7 +96,7 @@ // List of preferences used to configure the decorations that // are applied. private Preferences preferences; - + /* * Define a cached image descriptor which only creates the image data once */ @@ -286,6 +289,8 @@ if (isWatchEditEnabled() && resourceType == IResource.FILE && !isReadOnly() && isHasRemote()) { return edited; } + if (needsMerge) + return merged; // show checked in if (preferences.getBoolean(ICVSUIConstants.PREF_SHOW_HASREMOTE_DECORATION) && isHasRemote()) { if ((resourceType == IResource.FOLDER || resourceType == IResource.PROJECT) && isVirtualFolder()) { @@ -293,8 +298,6 @@ } return checkedIn; } - if (needsMerge) - return merged; //nothing matched return null; @@ -429,4 +432,34 @@ public void setVirtualFolder(boolean virtualFolder) { this.virtualFolder = virtualFolder; } + + public void setStateFlags(int stateFlags) { + this.stateFlags = stateFlags; + if ((stateFlags & IThreeWayDiff.OUTGOING) != 0) { + setDirty(true); + } + } + + public TeamStateDescription asTeamStateDescription(String[] properties) { + TeamStateDescription desc = new CVSTeamStateDescription(stateFlags); + Object o = computeImage(); + if (o != null && isRequestedProperty(properties, CVSTeamStateDescription.PROP_RESOURCE_STATE)) { + desc.setProperty(CVSTeamStateDescription.PROP_RESOURCE_STATE, o); + } + if (tag != null && isRequestedProperty(properties, CVSTeamStateDescription.PROP_TAG)) { + desc.setProperty(CVSTeamStateDescription.PROP_TAG, tag); + } + return desc; + } + + private boolean isRequestedProperty(String[] properties, String property) { + if (properties == null) + return true; + for (int i = 0; i < properties.length; i++) { + String string = properties[i]; + if (string.equals(property)) + return true; + } + return false; + } } Index: src/org/eclipse/team/internal/ccvs/ui/CVSLightweightDecorator.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.team.cvs.ui/src/org/eclipse/team/internal/ccvs/ui/CVSLightweightDecorator.java,v retrieving revision 1.66 diff -u -r1.66 CVSLightweightDecorator.java --- src/org/eclipse/team/internal/ccvs/ui/CVSLightweightDecorator.java 30 Jan 2006 15:56:44 -0000 1.66 +++ src/org/eclipse/team/internal/ccvs/ui/CVSLightweightDecorator.java 16 Mar 2006 15:43:30 -0000 @@ -15,7 +15,7 @@ import java.util.*; import org.eclipse.core.resources.*; -import org.eclipse.core.resources.mapping.ResourceMapping; +import org.eclipse.core.resources.mapping.*; import org.eclipse.core.runtime.*; import org.eclipse.jface.preference.IPreferenceStore; import org.eclipse.jface.util.IPropertyChangeListener; @@ -162,7 +162,7 @@ handleException(element, e); } catch (IllegalStateException e) { // This is thrown by Core if the workspace is in an illegal state - // If we are not active, ignore it. Otherwise, propogate it. + // If we are not active, ignore it. Otherwise, propagate it. // (see bug 78303) if (Platform.getBundle(CVSUIPlugin.ID).getState() == Bundle.ACTIVE) { throw e; @@ -170,7 +170,7 @@ } } - private IResource getResource(Object element) { + private static IResource getResource(Object element) { if (element instanceof ResourceMapping) { element = ((ResourceMapping) element).getModelObject(); } @@ -191,27 +191,41 @@ return false; } - private CVSDecoration decorate(Object element, SynchronizationStateTester tester) throws CoreException { + public static CVSDecoration decorate(Object element, SynchronizationStateTester tester) throws CoreException { IPreferenceStore store = CVSUIPlugin.getPlugin().getPreferenceStore(); CVSDecoration result = new CVSDecoration(); // First, decorate the synchronization state - if (tester.isStateDecorationEnabled()) { - if (tester.isSupervised(element)) { + int state = IDiff.NO_CHANGE; + if (tester.isDecorationEnabled(element)) { + if (isSupervised(element)) { result.setHasRemote(true); - int state = tester.getState(element, + state = tester.getState(element, store.getBoolean(ICVSUIConstants.PREF_CALCULATE_DIRTY) ? IDiff.ADD | IDiff.REMOVE | IDiff.CHANGE | IThreeWayDiff.OUTGOING : 0, new NullProgressMonitor()); - if ((state & IThreeWayDiff.OUTGOING) != 0) { - result.setDirty(true); - } + result.setStateFlags(state); } else { result.setIgnored(true); } } + // Tag + if (!result.isIgnored()) { + CVSTag tag = getTagToShow(element); + if (tag != null) { + String name = tag.getName(); + if (tag.getType() == CVSTag.DATE) { + Date date = tag.asDate(); + if (date != null) { + name = decorateFormatter.format(date); + } + } + result.setTag(name); + } + } + // If the element adapts to a single resource, add additional decorations IResource resource = getResource(element); if (resource == null) { @@ -219,9 +233,37 @@ } else { decorate(resource, result); } + tester.elementDecorated(element, result.asTeamStateDescription(null)); return result; } + private static boolean isSupervised(Object element) throws CoreException { + IResource[] resources = getTraversalRoots(element); + for (int i = 0; i < resources.length; i++) { + IResource resource = resources[i]; + if (getSubscriber().isSupervised(resource)) + return true; + } + return false; + } + + private static IResource[] getTraversalRoots(Object element) throws CoreException { + Set result = new HashSet(); + ResourceMapping mapping = Utils.getResourceMapping(element); + if (mapping != null) { + ResourceTraversal[] traversals = mapping.getTraversals(ResourceMappingContext.LOCAL_CONTEXT, null); + for (int i = 0; i < traversals.length; i++) { + ResourceTraversal traversal = traversals[i]; + IResource[] resources = traversal.getResources(); + for (int j = 0; j < resources.length; j++) { + IResource resource = resources[j]; + result.add(resource); + } + } + } + return (IResource[]) result.toArray(new IResource[result.size()]); + } + private static void decorate(IResource resource, CVSDecoration cvsDecoration) throws CVSException { IPreferenceStore store = CVSUIPlugin.getPlugin().getPreferenceStore(); ICVSResource cvsResource = CVSWorkspaceRoot.getCVSResourceFor(resource); @@ -250,18 +292,6 @@ // Has a remote //cvsDecoration.setHasRemote(CVSWorkspaceRoot.hasRemote(resource)); } - // Tag - CVSTag tag = getTagToShow(resource); - if (tag != null) { - String name = tag.getName(); - if (tag.getType() == CVSTag.DATE) { - Date date = tag.asDate(); - if (date != null) { - name = decorateFormatter.format(date); - } - } - cvsDecoration.setTag(name); - } // Is a new resource if (store.getBoolean(ICVSUIConstants.PREF_SHOW_NEWRESOURCE_DECORATION)) { if (cvsResource.exists()) { @@ -333,6 +363,37 @@ cvsDecoration.setWatchEditEnabled(provider.isWatchEditEnabled()); } + protected static CVSTag getTagToShow(Object element) throws CoreException { + IResource r = getResource(element); + if (r != null) + return getTagToShow(r); + IResource[] resources = getTraversalRoots(element); + boolean first = true; + CVSTag tag = null; + for (int i = 0; i < resources.length; i++) { + IResource resource = resources[i]; + if (getSubscriber().isSupervised(resource)) { + CVSTag nextTag = getTagToShow(resource); + if (first) { + tag = nextTag; + first = false; + } else if (!equals(tag, nextTag)) { + return null; + } + + } + } + return tag; + } + + private static boolean equals(CVSTag tag, CVSTag nextTag) { + if (tag == nextTag) + return true; + if (tag == null || nextTag == null) + return false; + return tag.getName().equals(nextTag.getName()); + } + /** * Only show the tag if the resources tag is different than the parents. Or else, tag * names will clutter the text decorations. Index: src/org/eclipse/team/internal/ccvs/ui/CVSTeamStateDescription.java =================================================================== RCS file: src/org/eclipse/team/internal/ccvs/ui/CVSTeamStateDescription.java diff -N src/org/eclipse/team/internal/ccvs/ui/CVSTeamStateDescription.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ src/org/eclipse/team/internal/ccvs/ui/CVSTeamStateDescription.java 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,31 @@ +/******************************************************************************* + * Copyright (c) 2006 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.team.internal.ccvs.ui; + +import org.eclipse.team.ui.synchronize.TeamStateDescription; + +/** + * A state description for the CVS decorations. We only need to + * enumerate the states that can be associated with model + * elements that don't have a one-to-one mapping to resources + */ +public class CVSTeamStateDescription extends TeamStateDescription { + + /** + * Property representing the image overlay + */ + public static final String PROP_RESOURCE_STATE = "resourceState"; //$NON-NLS-1$ + public static final String PROP_TAG = "tag"; //$NON-NLS-1$ + + public CVSTeamStateDescription(int state) { + super(state); + } +} Index: src/org/eclipse/team/internal/ccvs/ui/CVSTeamStateProvider.java =================================================================== RCS file: src/org/eclipse/team/internal/ccvs/ui/CVSTeamStateProvider.java diff -N src/org/eclipse/team/internal/ccvs/ui/CVSTeamStateProvider.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ src/org/eclipse/team/internal/ccvs/ui/CVSTeamStateProvider.java 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,39 @@ +/******************************************************************************* + * Copyright (c) 2006 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.team.internal.ccvs.ui; + +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.team.core.subscribers.Subscriber; +import org.eclipse.team.ui.mapping.*; +import org.eclipse.team.ui.synchronize.SubscriberTeamStateProvider; + +public class CVSTeamStateProvider extends SubscriberTeamStateProvider { + + public CVSTeamStateProvider(Subscriber subscriber) { + super(subscriber); + } + + public ITeamStateDescription getStateDescription(Object element, final int requestedStateMask, String[] properties, IProgressMonitor monitor) throws CoreException { + if (properties != null && properties.length == 0) { + return new CVSTeamStateDescription(getSynchronizationState(element, requestedStateMask, monitor)); + } + CVSDecoration d = CVSLightweightDecorator.decorate(element, new SynchronizationStateTester() { + public int getState(Object element, int stateMask, IProgressMonitor monitor) throws CoreException { + if (requestedStateMask != USE_DECORATED_STATE_MASK) { + stateMask = requestedStateMask & stateMask; + } + return getSynchronizationState(element, requestedStateMask & stateMask, monitor); + } + }); + return d.asTeamStateDescription(properties); + } +} #P org.eclipse.team.core Index: src/org/eclipse/team/internal/core/mapping/WorkspaceSubscriber.java =================================================================== RCS file: src/org/eclipse/team/internal/core/mapping/WorkspaceSubscriber.java diff -N src/org/eclipse/team/internal/core/mapping/WorkspaceSubscriber.java --- src/org/eclipse/team/internal/core/mapping/WorkspaceSubscriber.java 10 Feb 2006 16:54:23 -0000 1.8 +++ /dev/null 1 Jan 1970 00:00:00 -0000 @@ -1,350 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2006 IBM Corporation and others. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * IBM Corporation - initial API and implementation - *******************************************************************************/ -package org.eclipse.team.internal.core.mapping; - -import java.util.*; - -import org.eclipse.core.resources.*; -import org.eclipse.core.resources.mapping.ResourceMapping; -import org.eclipse.core.resources.mapping.ResourceTraversal; -import org.eclipse.core.runtime.*; -import org.eclipse.team.core.*; -import org.eclipse.team.core.diff.IDiff; -import org.eclipse.team.core.diff.IDiffVisitor; -import org.eclipse.team.core.subscribers.*; -import org.eclipse.team.core.synchronize.SyncInfo; -import org.eclipse.team.core.synchronize.SyncInfoSet; -import org.eclipse.team.core.variants.IResourceVariant; -import org.eclipse.team.core.variants.IResourceVariantComparator; -import org.eclipse.team.internal.core.*; - -/** - * A workspace subscriber is a special subscriber tat delegates to - * the subscribers associated with each project through the - * {@link RepositoryProvider} API. - * @since 3.2 - */ -public class WorkspaceSubscriber extends Subscriber implements ISubscriberChangeListener, IRepositoryProviderListener, IResourceChangeListener { - - private static WorkspaceSubscriber instance; - private Map projects = new HashMap(); - - public static synchronized WorkspaceSubscriber getInstance() { - if (instance == null) { - instance = new WorkspaceSubscriber(); - } - return instance; - } - - public WorkspaceSubscriber() { - // Add subscribers for all projects that have them - RepositoryProviderManager.getInstance().addListener(this); - ResourcesPlugin.getWorkspace().addResourceChangeListener(this, IResourceChangeEvent.POST_CHANGE); - IProject[] allProjects = ResourcesPlugin.getWorkspace().getRoot().getProjects(); - for (int i = 0; i < allProjects.length; i++) { - IProject project = allProjects[i]; - handleProject(project); - } - } - - private void handleProject(IProject project) { - if (RepositoryProvider.isShared(project)) { - try { - String currentId = project.getPersistentProperty(TeamPlugin.PROVIDER_PROP_KEY); - if (currentId != null) { - RepositoryProviderType type = RepositoryProviderType.getProviderType(currentId); - if (type != null) { - Subscriber subscriber = type.getSubscriber(); - if (subscriber != null) { - subscriber.addListener(this); - projects.put(project, subscriber); - } - } - } - } catch (CoreException e) { - TeamPlugin.log(e); - } - } - } - - /* (non-Javadoc) - * @see org.eclipse.team.core.subscribers.Subscriber#getName() - */ - public String getName() { - return Messages.WorkspaceSubscriber_0; - } - - /* (non-Javadoc) - * @see org.eclipse.team.core.subscribers.Subscriber#isSupervised(org.eclipse.core.resources.IResource) - */ - public boolean isSupervised(IResource resource) throws TeamException { - Subscriber subscriber = getSubscriber(resource); - if (subscriber != null) - return subscriber.isSupervised(resource); - return false; - } - - /* (non-Javadoc) - * @see org.eclipse.team.core.subscribers.Subscriber#members(org.eclipse.core.resources.IResource) - */ - public IResource[] members(IResource resource) throws TeamException { - Subscriber subscriber = getSubscriber(resource); - if (subscriber != null) - return subscriber.members(resource); - if (resource instanceof IContainer) { - IContainer container = (IContainer) resource; - try { - return container.members(); - } catch (CoreException e) { - throw TeamException.asTeamException(e); - } - } - return new IResource[0]; - } - - /* (non-Javadoc) - * @see org.eclipse.team.core.subscribers.Subscriber#roots() - */ - public IResource[] roots() { - return (IProject[]) projects.keySet().toArray(new IProject[projects.size()]); - } - - /* (non-Javadoc) - * @see org.eclipse.team.core.subscribers.Subscriber#getDiff(org.eclipse.core.resources.IResource) - */ - public IDiff getDiff(IResource resource) throws CoreException { - Subscriber subscriber = getSubscriber(resource); - if (subscriber != null) - return subscriber.getDiff(resource); - return super.getDiff(resource); - } - - /* (non-Javadoc) - * @see org.eclipse.team.core.subscribers.Subscriber#getSyncInfo(org.eclipse.core.resources.IResource) - */ - public SyncInfo getSyncInfo(IResource resource) throws TeamException { - Subscriber subscriber = getSubscriber(resource); - if (subscriber != null) - return subscriber.getSyncInfo(resource); - return null; - } - - /** - * Return a dummy comparator. The comparator should not be used by clients. - * - * @see org.eclipse.team.core.subscribers.Subscriber#getResourceComparator() - */ - public IResourceVariantComparator getResourceComparator() { - return new IResourceVariantComparator() { - public boolean isThreeWay() { - return true; - } - public boolean compare(IResourceVariant base, IResourceVariant remote) { - return false; - } - public boolean compare(IResource local, IResourceVariant remote) { - return false; - } - - }; - } - - /* (non-Javadoc) - * @see org.eclipse.team.core.subscribers.Subscriber#refresh(org.eclipse.core.resources.mapping.ResourceTraversal[], org.eclipse.core.runtime.IProgressMonitor) - */ - public void refresh(ResourceTraversal[] traversals, IProgressMonitor monitor) throws TeamException { - try { - List errors = new ArrayList(); - Subscriber[] subscribers = getSubscribers(); - monitor.beginTask(null, subscribers.length * 100); - for (int i = 0; i < subscribers.length; i++) { - Subscriber subscriber = subscribers[i]; - try { - subscriber.refresh(traversals, Policy.subMonitorFor(monitor, 100)); - } catch (TeamException e) { - errors.add(e); - } - } - try { - handleErrors((CoreException[]) errors.toArray(new CoreException[errors.size()])); - } catch (CoreException e) { - throw TeamException.asTeamException(e); - } - } finally { - monitor.done(); - } - } - - /* (non-Javadoc) - * @see org.eclipse.team.core.subscribers.Subscriber#refresh(org.eclipse.core.resources.IResource[], int, org.eclipse.core.runtime.IProgressMonitor) - */ - public void refresh(IResource[] resources, int depth, - IProgressMonitor monitor) throws TeamException { - refresh(new ResourceTraversal[] { new ResourceTraversal(resources, depth, IResource.NONE)}, monitor); - } - - /* (non-Javadoc) - * @see org.eclipse.team.core.subscribers.Subscriber#accept(org.eclipse.core.resources.mapping.ResourceTraversal[], org.eclipse.team.core.diff.IDiffVisitor) - */ - public void accept(ResourceTraversal[] traversals, IDiffVisitor visitor) throws CoreException { - List errors = new ArrayList(); - Subscriber[] subscribers = getSubscribers(); - for (int i = 0; i < subscribers.length; i++) { - Subscriber subscriber = subscribers[i]; - try { - subscriber.accept(traversals, visitor); - } catch (CoreException e) { - errors.add(e); - } - } - handleErrors((CoreException[]) errors.toArray(new CoreException[errors.size()])); - } - - /* (non-Javadoc) - * @see org.eclipse.team.core.subscribers.Subscriber#accept(org.eclipse.core.resources.IResource[], int, org.eclipse.team.core.diff.IDiffVisitor) - */ - public void accept(IResource[] resources, int depth, IDiffVisitor visitor) throws CoreException { - accept(new ResourceTraversal[] { new ResourceTraversal(resources, depth, IResource.NONE)}, visitor); - } - - /* (non-Javadoc) - * @see org.eclipse.team.core.subscribers.Subscriber#getState(org.eclipse.core.resources.mapping.ResourceMapping, int, org.eclipse.core.runtime.IProgressMonitor) - */ - public int getState(ResourceMapping mapping, int stateMask, IProgressMonitor monitor) throws CoreException { - int state = 0; - try { - List errors = new ArrayList(); - Subscriber[] subscribers = getSubscribers(mapping.getProjects()); - monitor.beginTask(null, subscribers.length * 100); - for (int i = 0; i < subscribers.length; i++) { - Subscriber subscriber = subscribers[i]; - try { - int subscriberState = subscriber.getState(mapping, stateMask, Policy.subMonitorFor(monitor, 100)); - state |= subscriberState; - } catch (TeamException e) { - errors.add(e); - } - } - handleErrors((CoreException[]) errors.toArray(new CoreException[errors.size()])); - } finally { - monitor.done(); - } - return state & stateMask; - } - - private Subscriber[] getSubscribers(IProject[] projects) { - for (int i = 0; i < projects.length; i++) { - IProject project = projects[i]; - if (!this.projects.containsKey(project)) { - handleProject(project); - } - } - return getSubscribers(); - } - - /* (non-Javadoc) - * @see org.eclipse.team.core.subscribers.Subscriber#collectOutOfSync(org.eclipse.core.resources.IResource[], int, org.eclipse.team.core.synchronize.SyncInfoSet, org.eclipse.core.runtime.IProgressMonitor) - */ - public void collectOutOfSync(IResource[] resources, int depth, SyncInfoSet set, IProgressMonitor monitor) { - try { - Subscriber[] subscribers = getSubscribers(); - monitor.beginTask(null, subscribers.length * 100); - for (int i = 0; i < subscribers.length; i++) { - Subscriber subscriber = subscribers[i]; - subscriber.collectOutOfSync(resources, depth, set, Policy.subMonitorFor(monitor, 100)); - } - } finally { - monitor.done(); - } - } - - private Subscriber[] getSubscribers() { - Set result = new HashSet(); - for (Iterator iter = projects.values().iterator(); iter.hasNext();) { - Subscriber subscriber = (Subscriber) iter.next(); - result.add(subscriber); - } - return (Subscriber[]) result.toArray(new Subscriber[result.size()]); - } - - /* - * Return the subscriber for the given resource if the resource - * is in the scope of this subscriber. - */ - private Subscriber getSubscriber(IResource resource) { - return (Subscriber)projects.get(resource.getProject()); - } - - private void handleErrors(CoreException[] exceptions) throws CoreException { - if (exceptions.length == 0) - return; - if (exceptions.length == 1) - throw exceptions[0]; - MultiStatus result = new MultiStatus(TeamPlugin.ID, 0, Messages.WorkspaceSubscriber_1, null); - for (int i = 0; i < exceptions.length; i++) { - CoreException exception = exceptions[i]; - IStatus status = new Status( - exception.getStatus().getSeverity(), - exception.getStatus().getPlugin(), - exception.getStatus().getCode(), - exception.getStatus().getMessage(), - exception); - result.add(status); - } - throw new TeamException(result); - } - - /* (non-Javadoc) - * @see org.eclipse.team.core.subscribers.ISubscriberChangeListener#subscriberResourceChanged(org.eclipse.team.core.subscribers.ISubscriberChangeEvent[]) - */ - public void subscriberResourceChanged(ISubscriberChangeEvent[] deltas) { - fireTeamResourceChange(deltas); - } - - /* (non-Javadoc) - * @see org.eclipse.team.internal.core.IRepositoryProviderListener#providerMapped(org.eclipse.team.core.RepositoryProvider) - */ - public void providerMapped(RepositoryProvider provider) { - // Record the subscriber. No need to fire an event since the subscriber should - Subscriber subscriber = provider.getSubscriber(); - if (subscriber != null) - projects.put(provider.getProject(), subscriber); - } - - /* (non-Javadoc) - * @see org.eclipse.team.internal.core.IRepositoryProviderListener#providerUnmapped(org.eclipse.core.resources.IProject) - */ - public void providerUnmapped(IProject project) { - // We'll remove the project. No need to fire an event since the subscriber should have done that - projects.remove(project); - } - - /* (non-Javadoc) - * @see org.eclipse.core.resources.IResourceChangeListener#resourceChanged(org.eclipse.core.resources.IResourceChangeEvent) - */ - public void resourceChanged(IResourceChangeEvent event) { - IResourceDelta delta = event.getDelta(); - IResourceDelta[] projectDeltas = delta.getAffectedChildren(IResourceDelta.ADDED | IResourceDelta.CHANGED); - for (int i = 0; i < projectDeltas.length; i++) { - IResourceDelta projectDelta = projectDeltas[i]; - IResource resource = projectDelta.getResource(); - if ((projectDelta.getFlags() & IResourceDelta.OPEN) != 0 - && resource.getType() == IResource.PROJECT) { - IProject project = (IProject)resource; - if (project.isAccessible()) { - handleProject(project); - } else { - projects.remove(project); - } - } - } - } -} Index: src/org/eclipse/team/core/Team.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.team.core/src/org/eclipse/team/core/Team.java,v retrieving revision 1.59 diff -u -r1.59 Team.java --- src/org/eclipse/team/core/Team.java 31 Jan 2006 15:35:51 -0000 1.59 +++ src/org/eclipse/team/core/Team.java 16 Mar 2006 15:43:31 -0000 @@ -18,9 +18,7 @@ import org.eclipse.core.runtime.Preferences.PropertyChangeEvent; import org.eclipse.core.runtime.content.IContentType; import org.eclipse.team.core.mapping.IStorageMerger; -import org.eclipse.team.core.subscribers.Subscriber; import org.eclipse.team.internal.core.*; -import org.eclipse.team.internal.core.mapping.WorkspaceSubscriber; /** * The Team class provides a global point of reference for the global ignore set @@ -457,19 +455,6 @@ return fFileContentManager; } - /** - * Returns a subscriber that provides access to the synchronization state - * of the workspace for those projects that provide it. - * - * @return a subscriber that provides access to the synchronization state - * of the workspace. - * - * @since 3.2 - */ - public static Subscriber getWorkspaceSubscriber() { - return WorkspaceSubscriber.getInstance(); - } - /** * Creates a storage merger for the given content type. * If no storage merger is registered for the given content type null is returned.