KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > team > core > synchronize > SyncInfoTree


1 /*******************************************************************************
2  * Copyright (c) 2000, 2006 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  *******************************************************************************/

11 package org.eclipse.team.core.synchronize;
12
13 import java.util.ArrayList JavaDoc;
14 import java.util.Collections JavaDoc;
15 import java.util.HashMap JavaDoc;
16 import java.util.HashSet JavaDoc;
17 import java.util.Iterator JavaDoc;
18 import java.util.List JavaDoc;
19 import java.util.Map JavaDoc;
20 import java.util.Set JavaDoc;
21
22 import org.eclipse.core.resources.IContainer;
23 import org.eclipse.core.resources.IResource;
24 import org.eclipse.core.resources.IWorkspaceRoot;
25 import org.eclipse.core.runtime.IPath;
26 import org.eclipse.core.runtime.IStatus;
27 import org.eclipse.core.runtime.Path;
28 import org.eclipse.team.internal.core.Messages;
29 import org.eclipse.team.internal.core.TeamPlugin;
30 import org.eclipse.team.internal.core.subscribers.SyncInfoTreeChangeEvent;
31 import org.eclipse.team.internal.core.subscribers.SyncSetChangedEvent;
32
33 /**
34  * Provides addition API for accessing the <code>SyncInfo</code> in the set through
35  * their resource's hierarchical relationships.
36  * <p>
37  * Events fired from a <code>SyncInfoTree</code> will be instances of <code>ISyncInfoTreeChangeEvent</code>.
38  * </p>
39  * @see SyncInfoSet
40  * @since 3.0
41  */

42 public class SyncInfoTree extends SyncInfoSet {
43
44     protected Map JavaDoc parents = Collections.synchronizedMap(new HashMap JavaDoc());
45     
46     /**
47      * Create an empty sync info tree.
48      */

49     public SyncInfoTree() {
50         super();
51     }
52     
53     /**
54      * Create a sync info tree containing the given sync info elements.
55      *
56      * @param infos the sync info elements
57      */

58     public SyncInfoTree(SyncInfo[] infos) {
59         super(infos);
60         for (int i = 0; i < infos.length; i++) {
61             SyncInfo info = infos[i];
62             IResource local = info.getLocal();
63             addToParents(local, local);
64         }
65     }
66
67     /**
68      * Return whether the given resource has any children in the sync set. The children
69      * could be either out-of-sync resources that are contained by the set or containers
70      * that are ancestors of out-of-sync resources contained by the set.
71      *
72      * @param resource the resource to check for children.
73      * @return <code>true</code> if the resource has children in the set.
74      */

75     public synchronized boolean hasMembers(IResource resource) {
76         if (resource.getType() == IResource.FILE) return false;
77         IContainer parent = (IContainer)resource;
78         if (parent.getType() == IResource.ROOT) return !isEmpty();
79         IPath path = parent.getFullPath();
80         Set JavaDoc allDescendants = (Set JavaDoc)parents.get(path);
81         return (allDescendants != null && !allDescendants.isEmpty());
82     }
83
84     /**
85      * Return the <code>SyncInfo</code> for each out-of-sync resource in the subtree rooted at the given resource
86      * to the depth specified. The depth is one of:
87      * <ul>
88      * <li><code>IResource.DEPTH_ZERO</code>: the resource only,
89      * <li><code>IResource.DEPTH_ONE</code>: the resource or its direct children,
90      * <li><code>IResource.DEPTH_INFINITE</code>: the resource and all of it's descendants.
91      * <ul>
92      * If the given resource is out of sync, it will be included in the result.
93      * <p>
94      * The default implementation makes use of <code>getSyncInfo(IResource)</code>,
95      * <code>members(IResource)</code> and <code>getSyncInfos()</code>
96      * to provide the varying depths. Subclasses may override to optimize.
97      * </p>
98      * @param resource the root of the resource subtree
99      * @param depth the depth of the subtree
100      * @return the <code>SyncInfo</code> for any out-of-sync resources
101      */

102     public synchronized SyncInfo[] getSyncInfos(IResource resource, int depth) {
103         if (depth == IResource.DEPTH_ZERO || resource.getType() == IResource.FILE) {
104             SyncInfo info = getSyncInfo(resource);
105             if (info == null) {
106                 return new SyncInfo[0];
107             } else {
108                 return new SyncInfo[] { info };
109             }
110         }
111         if (depth == IResource.DEPTH_ONE) {
112             List JavaDoc result = new ArrayList JavaDoc();
113             SyncInfo info = getSyncInfo(resource);
114             if (info != null) {
115                 result.add(info);
116             }
117             IResource[] members = members(resource);
118             for (int i = 0; i < members.length; i++) {
119                 IResource member = members[i];
120                 info = getSyncInfo(member);
121                 if (info != null) {
122                     result.add(info);
123                 }
124             }
125             return (SyncInfo[]) result.toArray(new SyncInfo[result.size()]);
126         }
127         // if it's the root then return all out of sync resources.
128
if(resource.getType() == IResource.ROOT) {
129             return getSyncInfos();
130         }
131         // for folders return all children deep.
132
return internalGetDeepSyncInfo((IContainer)resource);
133     }
134
135     /*
136      * Return the <code>SyncInfo</code> for all out-of-sync resources in the
137      * set that are at or below the given resource in the resource hierarchy.
138      * @param resource the root resource
139      * @return the <code>SyncInfo</code> for all out-of-sync resources at or below the given resource
140      */

141     private synchronized SyncInfo[] internalGetDeepSyncInfo(IContainer resource) {
142         List JavaDoc infos = new ArrayList JavaDoc();
143         IResource[] children = internalGetOutOfSyncDescendants(resource);
144         for (int i = 0; i < children.length; i++) {
145             IResource child = children[i];
146             SyncInfo info = getSyncInfo(child);
147             if(info != null) {
148                 infos.add(info);
149             } else {
150                 TeamPlugin.log(IStatus.INFO, Messages.SyncInfoTree_0 + child.getFullPath(), null);
151             }
152         }
153         return (SyncInfo[]) infos.toArray(new SyncInfo[infos.size()]);
154     }
155
156     /**
157      * Overrides inherited method to provide an instance of
158      * <code>ISyncInfoTreeChangeEvent</code>.
159      */

160     protected SyncSetChangedEvent createEmptyChangeEvent() {
161         return new SyncInfoTreeChangeEvent(this);
162     }
163
164     /* (non-Javadoc)
165      * @see org.eclipse.team.core.synchronize.SyncInfoSet#add(org.eclipse.team.core.synchronize.SyncInfo)
166      */

167     public void add(SyncInfo info) {
168         try {
169             beginInput();
170             boolean alreadyExists = getSyncInfo(info.getLocal()) != null;
171             super.add(info);
172             if(! alreadyExists) {
173                 IResource local = info.getLocal();
174                 addToParents(local, local);
175             }
176         } finally {
177             endInput(null);
178         }
179     }
180
181     /* (non-Javadoc)
182      * @see org.eclipse.team.core.synchronize.SyncInfoSet#remove(org.eclipse.core.resources.IResource)
183      */

184     public void remove(IResource resource) {
185         try {
186             beginInput();
187             super.remove(resource);
188             removeFromParents(resource, resource);
189         } finally {
190             endInput(null);
191         }
192     
193     }
194
195     /* (non-Javadoc)
196      * @see org.eclipse.team.core.synchronize.SyncInfoSet#clear()
197      */

198     public void clear() {
199         try {
200             beginInput();
201             super.clear();
202             synchronized(this) {
203                 parents.clear();
204             }
205         } finally {
206             endInput(null);
207         }
208     }
209
210     private synchronized boolean addToParents(IResource resource, IResource parent) {
211         if (parent.getType() == IResource.ROOT) {
212             return false;
213         }
214         // this flag is used to indicate if the parent was previously in the set
215
boolean addedParent = false;
216         if (parent.getType() == IResource.FILE) {
217             // the file is new
218
addedParent = true;
219         } else {
220             Set JavaDoc children = (Set JavaDoc)parents.get(parent.getFullPath());
221             if (children == null) {
222                 children = new HashSet JavaDoc();
223                 parents.put(parent.getFullPath(), children);
224                 // this is a new folder in the sync set
225
addedParent = true;
226             }
227             children.add(resource);
228         }
229         // if the parent already existed and the resource is new, record it
230
if (!addToParents(resource, parent.getParent()) && addedParent) {
231             internalAddedSubtreeRoot(parent);
232         }
233         return addedParent;
234     }
235
236     private synchronized boolean removeFromParents(IResource resource, IResource parent) {
237         if (parent.getType() == IResource.ROOT) {
238             return false;
239         }
240         // this flag is used to indicate if the parent was removed from the set
241
boolean removedParent = false;
242         if (parent.getType() == IResource.FILE) {
243             // the file will be removed
244
removedParent = true;
245         } else {
246             Set JavaDoc children = (Set JavaDoc)parents.get(parent.getFullPath());
247             if (children != null) {
248                 children.remove(resource);
249                 if (children.isEmpty()) {
250                     parents.remove(parent.getFullPath());
251                     removedParent = true;
252                 }
253             }
254         }
255         // if the parent wasn't removed and the resource was, record it
256
if (!removeFromParents(resource, parent.getParent()) && removedParent) {
257             internalRemovedSubtreeRoot(parent);
258         }
259         return removedParent;
260     }
261
262     private void internalAddedSubtreeRoot(IResource parent) {
263         ((SyncInfoTreeChangeEvent)getChangeEvent()).addedSubtreeRoot(parent);
264     }
265
266     private void internalRemovedSubtreeRoot(IResource parent) {
267         ((SyncInfoTreeChangeEvent)getChangeEvent()).removedSubtreeRoot(parent);
268     }
269
270     /**
271      * Remove from this set the <code>SyncInfo</code> for the given resource and any of its descendants
272      * within the specified depth. The depth is one of:
273      * <ul>
274      * <li><code>IResource.DEPTH_ZERO</code>: the resource only,
275      * <li><code>IResource.DEPTH_ONE</code>: the resource or its direct children,
276      * <li><code>IResource.DEPTH_INFINITE</code>: the resource and all of it's descendants.
277      * <ul>
278      * @param resource the root of the resource subtree
279      * @param depth the depth of the subtree
280      */

281     public void remove(IResource resource, int depth) {
282         try {
283             beginInput();
284             if (getSyncInfo(resource) != null) {
285                 remove(resource);
286             }
287             if (depth == IResource.DEPTH_ZERO || resource.getType() == IResource.FILE) return;
288             if (depth == IResource.DEPTH_ONE) {
289                 IResource[] members = members(resource);
290                 for (int i = 0; i < members.length; i++) {
291                     IResource member = members[i];
292                     if (getSyncInfo(member) != null) {
293                         remove(member);
294                     }
295                 }
296             } else if (depth == IResource.DEPTH_INFINITE) {
297                 IResource [] toRemove = internalGetOutOfSyncDescendants((IContainer)resource);
298                 for (int i = 0; i < toRemove.length; i++) {
299                     remove(toRemove[i]);
300                 }
301             }
302         } finally {
303             endInput(null);
304         }
305     }
306
307     /**
308      * This is an internal method and is not intended to be invoked or
309      * overridden by clients.
310      */

311     protected synchronized IResource[] internalGetOutOfSyncDescendants(IContainer resource) {
312         // The parent map contains a set of all out-of-sync children
313
Set JavaDoc allChildren = (Set JavaDoc)parents.get(resource.getFullPath());
314         if (allChildren == null) return new IResource[0];
315         return (IResource[]) allChildren.toArray(new IResource[allChildren.size()]);
316     }
317
318     private synchronized IResource[] internalMembers(IWorkspaceRoot root) {
319         Set JavaDoc possibleChildren = parents.keySet();
320         Set JavaDoc children = new HashSet JavaDoc();
321         for (Iterator JavaDoc it = possibleChildren.iterator(); it.hasNext();) {
322             Object JavaDoc next = it.next();
323             IResource element = root.findMember((IPath)next);
324             if (element != null) {
325                 children.add(element.getProject());
326             }
327         }
328         return (IResource[]) children.toArray(new IResource[children.size()]);
329     }
330
331     /**
332      * Return the immediate children of the given resource who are either out-of-sync
333      * or contain out-of-sync resources.
334      *
335      * @param resource the parent resource
336      * @return the children of the resource that are either out-of-sync or are ancestors of
337      * out-of-sync resources contained in the set
338      */

339     public synchronized IResource[] members(IResource resource) {
340         if (resource.getType() == IResource.FILE) return new IResource[0];
341         IContainer parent = (IContainer)resource;
342         if (parent.getType() == IResource.ROOT) return internalMembers((IWorkspaceRoot)parent);
343         // OPTIMIZE: could be optimized so that we don't traverse all the deep
344
// children to find the immediate ones.
345
Set JavaDoc children = new HashSet JavaDoc();
346         IPath path = parent.getFullPath();
347         Set JavaDoc possibleChildren = (Set JavaDoc)parents.get(path);
348         if(possibleChildren != null) {
349             for (Iterator JavaDoc it = possibleChildren.iterator(); it.hasNext();) {
350                 Object JavaDoc next = it.next();
351                 IResource element = (IResource)next;
352                 IPath childPath = element.getFullPath();
353                 IResource modelObject = null;
354                 if(childPath.segmentCount() == (path.segmentCount() + 1)) {
355                     modelObject = element;
356     
357                 } else if (childPath.segmentCount() > path.segmentCount()) {
358                     IContainer childFolder = parent.getFolder(new Path(null, childPath.segment(path.segmentCount())));
359                     modelObject = childFolder;
360                 }
361                 if (modelObject != null) {
362                     children.add(modelObject);
363                 }
364             }
365         }
366         return (IResource[]) children.toArray(new IResource[children.size()]);
367     }
368
369 }
370
Popular Tags