KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > team > internal > core > subscribers > ActiveChangeSetManager


1 /*******************************************************************************
2  * Copyright (c) 2006-2007 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Eclipse Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/epl-v10.html
7  *
8  * Contributors:
9  * IBM Corporation - initial API and implementation
10  * Matt McCutchen <hashproduct+eclipse@gmail.com> - Bug 128429 [Change Sets] Change Sets with / in name do not get persited
11  *******************************************************************************/

12 package org.eclipse.team.internal.core.subscribers;
13
14 import java.util.*;
15
16 import org.eclipse.core.resources.*;
17 import org.eclipse.core.resources.mapping.ResourceTraversal;
18 import org.eclipse.core.runtime.*;
19 import org.eclipse.osgi.util.NLS;
20 import org.eclipse.team.core.diff.*;
21 import org.eclipse.team.core.mapping.IChangeGroupingRequestor;
22 import org.eclipse.team.core.mapping.IResourceDiffTree;
23 import org.eclipse.team.internal.core.*;
24 import org.eclipse.team.internal.core.mapping.CompoundResourceTraversal;
25 import org.osgi.service.prefs.BackingStoreException;
26 import org.osgi.service.prefs.Preferences;
27
28 /**
29  * A change set manager that contains sets that represent collections of
30  * related local changes.
31  */

32 public abstract class ActiveChangeSetManager extends ChangeSetManager implements IDiffChangeListener, IChangeGroupingRequestor {
33
34     private static final String JavaDoc CTX_DEFAULT_SET = "defaultSet"; //$NON-NLS-1$
35

36     private ActiveChangeSet defaultSet;
37
38     /**
39      * Return the Change Set whose sync info set is the
40      * one given.
41      * @param tree a diff tree
42      * @return the change set for the given diff tree
43      */

44     protected ChangeSet getChangeSet(IResourceDiffTree tree) {
45         ChangeSet[] sets = getSets();
46         for (int i = 0; i < sets.length; i++) {
47             ChangeSet changeSet = sets[i];
48             if (((DiffChangeSet)changeSet).getDiffTree() == tree) {
49                 return changeSet;
50             }
51         }
52         return null;
53     }
54     
55     /* (non-Javadoc)
56      * @see org.eclipse.team.internal.core.subscribers.ChangeSetManager#add(org.eclipse.team.internal.core.subscribers.ChangeSet)
57      */

58     public void add(ChangeSet set) {
59         Assert.isTrue(set instanceof ActiveChangeSet);
60         super.add(set);
61     }
62     
63     /* (non-Javadoc)
64      * @see org.eclipse.team.internal.core.subscribers.AbstractChangeSetCollector#handleSetAdded(org.eclipse.team.internal.core.subscribers.ChangeSet)
65      */

66     protected void handleSetAdded(ChangeSet set) {
67         Assert.isTrue(set instanceof ActiveChangeSet);
68         ((DiffChangeSet)set).getDiffTree().addDiffChangeListener(getDiffTreeListener());
69         super.handleSetAdded(set);
70         handleAddedResources(set, ((ActiveChangeSet)set).internalGetDiffTree().getDiffs());
71     }
72     
73     /* (non-Javadoc)
74      * @see org.eclipse.team.internal.core.subscribers.AbstractChangeSetCollector#handleSetRemoved(org.eclipse.team.internal.core.subscribers.ChangeSet)
75      */

76     protected void handleSetRemoved(ChangeSet set) {
77         ((DiffChangeSet)set).getDiffTree().removeDiffChangeListener(getDiffTreeListener());
78         super.handleSetRemoved(set);
79     }
80     
81     /**
82      * Return the listener that is registered with the diff trees associated with
83      * the sets for this manager.
84      * @return the listener that is registered with the diff trees associated with
85      * the sets for this manager
86      */

87     protected IDiffChangeListener getDiffTreeListener() {
88         return this;
89     }
90     
91     /* (non-Javadoc)
92      * @see org.eclipse.team.core.diff.IDiffChangeListener#diffsChanged(org.eclipse.team.core.diff.IDiffChangeEvent, org.eclipse.core.runtime.IProgressMonitor)
93      */

94     public void diffsChanged(IDiffChangeEvent event, IProgressMonitor monitor) {
95         IResourceDiffTree tree = (IResourceDiffTree)event.getTree();
96         handleSyncSetChange(tree, event.getAdditions(), getAllResources(event));
97     }
98     
99     /* (non-Javadoc)
100      * @see org.eclipse.team.core.diff.IDiffChangeListener#propertyChanged(org.eclipse.team.core.diff.IDiffTree, int, org.eclipse.core.runtime.IPath[])
101      */

102     public void propertyChanged(IDiffTree tree, int property, IPath[] paths) {
103         // ignore
104
}
105     
106     public boolean isModified(IFile file) throws CoreException {
107         IDiff diff = getDiff(file);
108         if (diff != null)
109             return isModified(diff);
110         return false;
111     }
112     
113     /**
114      * Return whether the given diff represents a local change.
115      * @param diff the diff
116      * @return whether the given diff represents a local change
117      */

118     public boolean isModified(IDiff diff) {
119         if (diff != null) {
120             if (diff instanceof IThreeWayDiff) {
121                 IThreeWayDiff twd = (IThreeWayDiff) diff;
122                 int dir = twd.getDirection();
123                 return dir == IThreeWayDiff.OUTGOING || dir == IThreeWayDiff.CONFLICTING;
124             } else {
125                 return diff.getKind() != IDiff.NO_CHANGE;
126             }
127         }
128         return false;
129     }
130
131     /**
132      * Return the set with the given name.
133      * @param name the name of the set
134      * @return the set with the given name
135      */

136     public ActiveChangeSet getSet(String JavaDoc name) {
137         ChangeSet[] sets = getSets();
138         for (int i = 0; i < sets.length; i++) {
139             ChangeSet set = sets[i];
140             if (set.getName().equals(name) && set instanceof ActiveChangeSet) {
141                 return (ActiveChangeSet)set;
142             }
143         }
144         return null;
145     }
146
147     /**
148      * Create a change set containing the given files if
149      * they have been modified locally.
150      * @param title the title of the commit set
151      * @param files the files contained in the set
152      * @return the created set
153      * @throws CoreException
154      */

155     public ActiveChangeSet createSet(String JavaDoc title, IFile[] files) throws CoreException {
156         List infos = new ArrayList();
157         for (int i = 0; i < files.length; i++) {
158             IFile file = files[i];
159             IDiff diff = getDiff(file);
160             if (diff != null) {
161                 infos.add(diff);
162             }
163         }
164         return createSet(title, (IDiff[]) infos.toArray(new IDiff[infos.size()]));
165     }
166
167     /**
168      * Create a commit set with the given title and files. The created
169      * set is not added to the control of the commit set manager
170      * so no events are fired. The set can be added using the
171      * <code>add</code> method.
172      * @param title the title of the commit set
173      * @param diffs the files contained in the set
174      * @return the created set
175      */

176     public ActiveChangeSet createSet(String JavaDoc title, IDiff[] diffs) {
177         ActiveChangeSet commitSet = doCreateSet(title);
178         if (diffs != null && diffs.length > 0) {
179             commitSet.add(diffs);
180         }
181         return commitSet;
182     }
183
184     /**
185      * Create a change set with the given name.
186      * @param name the name of the change set
187      * @return the created change set
188      */

189     protected ActiveChangeSet doCreateSet(String JavaDoc name) {
190         return new ActiveChangeSet(this, name);
191     }
192
193     public abstract IDiff getDiff(IResource resource) throws CoreException;
194
195     /**
196      * Return whether the manager allows a resource to
197      * be in multiple sets. By default, a resource
198      * may only be in one set.
199      * @return whether the manager allows a resource to
200      * be in multiple sets.
201      */

202     protected boolean isSingleSetPerResource() {
203         return true;
204     }
205
206     private IPath[] getAllResources(IDiffChangeEvent event) {
207         Set allResources = new HashSet();
208         IDiff[] addedResources = event.getAdditions();
209         for (int i = 0; i < addedResources.length; i++) {
210             IDiff diff = addedResources[i];
211             allResources.add(diff.getPath());
212         }
213         IDiff[] changedResources = event.getChanges();
214         for (int i = 0; i < changedResources.length; i++) {
215             IDiff diff = changedResources[i];
216             allResources.add(diff.getPath());
217         }
218         IPath[] removals = event.getRemovals();
219         for (int i = 0; i < removals.length; i++) {
220             IPath path = removals[i];
221             allResources.add(path);
222         }
223         return (IPath[]) allResources.toArray(new IPath[allResources.size()]);
224     }
225
226     /**
227      * React to the given diffs being added to the given set.
228      * @param set the set
229      * @param diffs the diffs
230      */

231     protected void handleAddedResources(ChangeSet set, IDiff[] diffs) {
232         if (isSingleSetPerResource() && ((ActiveChangeSet)set).isUserCreated()) {
233             IResource[] resources = new IResource[diffs.length];
234             for (int i = 0; i < resources.length; i++) {
235                 resources[i] = ((DiffChangeSet)set).getDiffTree().getResource(diffs[i]);
236             }
237             // Remove the added files from any other set that contains them
238
ChangeSet[] sets = getSets();
239             for (int i = 0; i < sets.length; i++) {
240                 ChangeSet otherSet = sets[i];
241                 if (otherSet != set && ((ActiveChangeSet)otherSet).isUserCreated()) {
242                     otherSet.remove(resources);
243                 }
244             }
245         }
246     }
247
248     private void handleSyncSetChange(IResourceDiffTree tree, IDiff[] addedDiffs, IPath[] allAffectedResources) {
249         ChangeSet changeSet = getChangeSet(tree);
250         if (tree.isEmpty() && changeSet != null) {
251             remove(changeSet);
252         }
253         fireResourcesChangedEvent(changeSet, allAffectedResources);
254         handleAddedResources(changeSet, addedDiffs);
255     }
256
257     /**
258      * Make the given set the default set into which all new modifications
259      * that are not already in another set go.
260      * @param set the set which is to become the default set
261      */

262     public void makeDefault(ActiveChangeSet set) {
263         // The default set must be an active set
264
if (!contains(set)) {
265             add(set);
266         }
267         ActiveChangeSet oldSet = defaultSet;
268         defaultSet = set;
269         fireDefaultChangedEvent(oldSet, defaultSet);
270     }
271
272     /**
273      * Return whether the given set is the default set into which all
274      * new modifications will be placed.
275      * @param set the set to test
276      * @return whether the set is the default set
277      */

278     public boolean isDefault(ActiveChangeSet set) {
279         return set == defaultSet;
280     }
281     
282     /**
283      * Return the set which is currently the default or
284      * <code>null</code> if there is no default set.
285      * @return the default change set
286      */

287     public ActiveChangeSet getDefaultSet() {
288         return defaultSet;
289     }
290     
291     /**
292      * If the given traversals contain any resources in the active change sets, ensure
293      * that the traversals cover all the resources in the overlapping change set.
294      * @param traversals the traversals
295      * @return the traversals adjusted to contain all the resources of intersecting change sets
296      */

297     public ResourceTraversal[] adjustInputTraversals(ResourceTraversal[] traversals) {
298         CompoundResourceTraversal traversal = new CompoundResourceTraversal();
299         traversal.addTraversals(traversals);
300         ChangeSet[] sets = getSets();
301         for (int i = 0; i < sets.length; i++) {
302             ChangeSet set = sets[i];
303             handleIntersect(traversal, set);
304         }
305         return traversal.asTraversals();
306     }
307
308     private void handleIntersect(CompoundResourceTraversal traversal, ChangeSet set) {
309         IResource[] resources = set.getResources();
310         for (int i = 0; i < resources.length; i++) {
311             IResource resource = resources[i];
312             if (traversal.isCovered(resource, IResource.DEPTH_ZERO)) {
313                 traversal.addResources(resources, IResource.DEPTH_ZERO);
314                 return;
315             }
316         }
317     }
318
319     /**
320      * Save the state of this manager including all its contained sets
321      * into the given preferences node.
322      * @param prefs a preferences node
323      */

324     protected void save(Preferences prefs) {
325         // No need to save the sets if the manager has never been initialized
326
if (!isInitialized())
327             return;
328         // Clear the persisted state before saving the new state
329
try {
330             String JavaDoc[] oldSetNames = prefs.childrenNames();
331             for (int i = 0; i < oldSetNames.length; i++) {
332                 String JavaDoc string = oldSetNames[i];
333                 prefs.node(string).removeNode();
334             }
335         } catch (BackingStoreException e) {
336             TeamPlugin.log(IStatus.ERROR, NLS.bind("An error occurred purging the commit set state for {0}", new String JavaDoc[] { getName() }), e); //$NON-NLS-1$
337
}
338         ChangeSet[] sets = getSets();
339         for (int i = 0; i < sets.length; i++) {
340             ChangeSet set = sets[i];
341             if (set instanceof ActiveChangeSet && !set.isEmpty()) {
342                 // Since the change set title is stored explicitly, the name of
343
// the child preference node doesn't matter as long as it
344
// doesn't contain / and no two change sets get the same name.
345
String JavaDoc childPrefName = escapePrefName(((ActiveChangeSet)set).getTitle());
346                 Preferences child = prefs.node(childPrefName);
347                 ((ActiveChangeSet)set).save(child);
348             }
349         }
350         if (getDefaultSet() != null) {
351             prefs.put(CTX_DEFAULT_SET, getDefaultSet().getTitle());
352         }
353         try {
354             prefs.flush();
355         } catch (BackingStoreException e) {
356             TeamPlugin.log(IStatus.ERROR, NLS.bind(Messages.SubscriberChangeSetCollector_3, new String JavaDoc[] { getName() }), e);
357         }
358     }
359     
360     /**
361      * Escape the given string for safe use as a preference node name by
362      * translating / to \s (so it's a single path component) and \ to \\ (to
363      * preserve uniqueness).
364      *
365      * @param string
366      * Input string
367      * @return Escaped output string
368      */

369     private static String JavaDoc escapePrefName(String JavaDoc string) {
370         StringBuffer JavaDoc out = new StringBuffer JavaDoc();
371         for (int i = 0; i < string.length(); i++) {
372             char c = string.charAt(i);
373             switch (c) {
374             case '/':
375                 out.append("\\s"); //$NON-NLS-1$
376
break;
377             case '\\':
378                 out.append("\\\\"); //$NON-NLS-1$
379
break;
380             default:
381                 out.append(c);
382             }
383         }
384         return out.toString();
385     }
386     
387     /**
388      * Load the manager's state from the given preferences node.
389      *
390      * @param prefs
391      * a preferences node
392      */

393     protected void load(Preferences prefs) {
394         String JavaDoc defaultSetTitle = prefs.get(CTX_DEFAULT_SET, null);
395         try {
396             String JavaDoc[] childNames = prefs.childrenNames();
397             for (int i = 0; i < childNames.length; i++) {
398                 String JavaDoc string = childNames[i];
399                 Preferences childPrefs = prefs.node(string);
400                 ActiveChangeSet set = createSet(childPrefs);
401                 if (!set.isEmpty()) {
402                     if (getDefaultSet() == null && defaultSetTitle != null && set.getTitle().equals(defaultSetTitle)) {
403                         makeDefault(set);
404                     }
405                     add(set);
406                 }
407             }
408         } catch (BackingStoreException e) {
409             TeamPlugin.log(IStatus.ERROR, NLS.bind(Messages.SubscriberChangeSetCollector_4, new String JavaDoc[] { getName() }), e);
410         }
411     }
412     
413     /**
414      * Return the name of this change set manager.
415      * @return the name of this change set manager
416      */

417     protected abstract String JavaDoc getName();
418
419     /**
420      * Create a change set from the given preferences that were
421      * previously saved.
422      * @param childPrefs the previously saved preferences
423      * @return the created change set
424      */

425     protected ActiveChangeSet createSet(Preferences childPrefs) {
426         // Don't specify a title when creating the change set; instead, let the
427
// change set read its title from the preferences.
428
ActiveChangeSet changeSet = doCreateSet(null);
429         changeSet.init(childPrefs);
430         return changeSet;
431     }
432     
433     /* (non-Javadoc)
434      * @see org.eclipse.team.internal.core.IChangeGroupingRequestor#ensureChangesGrouped(org.eclipse.core.resources.IProject, org.eclipse.core.resources.IFile[], java.lang.String)
435      */

436     public void ensureChangesGrouped(IProject project, IFile[] files,
437             String JavaDoc name) throws CoreException {
438         ActiveChangeSet set = getSet(name);
439         if (set == null) {
440             set = createSet(name, files);
441             set.setUserCreated(false);
442             add(set);
443         } else {
444             set.setUserCreated(false);
445             set.add(files);
446         }
447     }
448 }
449
Popular Tags