Lines 132-208
Link Here
|
132 |
if (!parent.getProject().isAccessible()) |
132 |
if (!parent.getProject().isAccessible()) |
133 |
return; |
133 |
return; |
134 |
|
134 |
|
135 |
// get the list of resources in the file system |
135 |
boolean shouldBeFloating = (((IContainer) node.resource).isFlatten()); |
136 |
// don't ask for local children if we know it doesn't exist locally |
136 |
if (shouldBeFloating) { |
137 |
IFileInfo[] list = node.existsInFileSystem() ? getLocalList(node) : NO_CHILDREN; |
137 |
// create linked resources for each given file store |
138 |
int localIndex = 0; |
138 |
// get the list of resources in the file system |
139 |
|
139 |
// don't ask for local children if we know it doesn't exist locally |
140 |
// See if the children of this resource have been computed before |
140 |
IFileStore[] list = node.existsInFileSystem() ? getLocalFlattenList(node) : new IFileStore[0]; |
141 |
ResourceInfo resourceInfo = parent.getResourceInfo(false, false); |
141 |
int localIndex = 0; |
142 |
int flags = parent.getFlags(resourceInfo); |
142 |
|
143 |
boolean unknown = ResourceInfo.isSet(flags, ICoreConstants.M_CHILDREN_UNKNOWN); |
143 |
Project project = (Project) parent.getProject(); |
144 |
|
144 |
UniqueFileStoreName[] uniqueList = generateUniqueList(list); |
145 |
// get the list of resources in the workspace |
145 |
|
146 |
if (!unknown && (parentType == IResource.FOLDER || parentType == IResource.PROJECT) && parent.exists(flags, true)) { |
146 |
// See if the children of this resource have been computed before |
147 |
IResource target = null; |
147 |
ResourceInfo resourceInfo = parent.getResourceInfo(false, false); |
148 |
UnifiedTreeNode child = null; |
148 |
int flags = parent.getFlags(resourceInfo); |
149 |
IResource[] members; |
149 |
boolean unknown = ResourceInfo.isSet(flags, ICoreConstants.M_CHILDREN_UNKNOWN); |
150 |
try { |
150 |
|
151 |
members = ((IContainer) parent).members(IContainer.INCLUDE_TEAM_PRIVATE_MEMBERS | IContainer.INCLUDE_HIDDEN); |
151 |
// get the list of resources in the workspace |
152 |
} catch (CoreException e) { |
152 |
if (!unknown && (parentType == IResource.FOLDER || parentType == IResource.PROJECT) && parent.exists(flags, true)) { |
153 |
members = NO_RESOURCES; |
153 |
IResource target = null; |
154 |
} |
154 |
UnifiedTreeNode child = null; |
155 |
int workspaceIndex = 0; |
155 |
IResource[] members; |
156 |
//iterate simultaneously over file system and workspace members |
156 |
try { |
157 |
while (workspaceIndex < members.length) { |
157 |
members = ((IContainer) parent).members(IContainer.INCLUDE_TEAM_PRIVATE_MEMBERS | IContainer.INCLUDE_HIDDEN); |
158 |
target = members[workspaceIndex]; |
158 |
} catch (CoreException e) { |
159 |
String name = target.getName(); |
159 |
members = NO_RESOURCES; |
160 |
IFileInfo localInfo = localIndex < list.length ? list[localIndex] : null; |
160 |
} |
161 |
int comp = localInfo != null ? name.compareTo(localInfo.getName()) : -1; |
161 |
int workspaceIndex = 0; |
162 |
//special handling for linked resources |
162 |
//iterate simultaneously over file system and workspace members |
163 |
if (target.isLinked()) { |
163 |
while (workspaceIndex < members.length) { |
164 |
//child will be null if location is undefined |
164 |
target = members[workspaceIndex]; |
165 |
child = createChildForLinkedResource(target); |
165 |
String name = target.getName(); |
166 |
workspaceIndex++; |
166 |
UniqueFileStoreName info = localIndex < uniqueList.length ? uniqueList[localIndex] : null; |
167 |
//if there is a matching local file, skip it - it will be blocked by the linked resource |
167 |
int comp = info != null ? name.compareTo(info.name) : -1; |
168 |
if (comp == 0) |
168 |
//special handling for linked resources |
|
|
169 |
if (!target.isLinked()) { |
170 |
// a flatten folder can only contain linked resources |
171 |
child = createNode(target, null, null, true); |
172 |
workspaceIndex++; |
173 |
} else if (!target.isFloating()) { |
174 |
child = createChildForLinkedResource(target); |
175 |
workspaceIndex++; |
176 |
//if there is a matching local file (a floating linked resource), skip it - it will be blocked by the linked resource |
177 |
if (comp == 0) |
178 |
localIndex++; |
179 |
} else if (comp == 0) { |
180 |
// resource exists in workspace and file system --> localInfo is non-null |
181 |
child = createNode(target, info.store, info.info, true); |
182 |
localIndex++; |
183 |
workspaceIndex++; |
184 |
} else if (comp > 0) { |
185 |
// resource exists only in file system |
186 |
//don't create a node for symbolic links that create a cycle |
187 |
child = createNewFloatingLinkedResourceNode(project, node, info); |
169 |
localIndex++; |
188 |
localIndex++; |
170 |
} else if (comp == 0) { |
189 |
} else { |
171 |
// resource exists in workspace and file system --> localInfo is non-null |
190 |
// resource exists only in the workspace |
172 |
//create workspace-only node for symbolic link that creates a cycle |
|
|
173 |
if (localInfo.getAttribute(EFS.ATTRIBUTE_SYMLINK) && localInfo.isDirectory() && isRecursiveLink(node.getStore(), localInfo)) |
174 |
child = createNode(target, null, null, true); |
191 |
child = createNode(target, null, null, true); |
175 |
else |
192 |
workspaceIndex++; |
176 |
child = createNode(target, null, localInfo, true); |
193 |
} |
177 |
localIndex++; |
194 |
if (child != null) |
178 |
workspaceIndex++; |
195 |
addChildToTree(node, child); |
179 |
} else if (comp > 0) { |
|
|
180 |
// resource exists only in file system |
181 |
//don't create a node for symbolic links that create a cycle |
182 |
if (localInfo.getAttribute(EFS.ATTRIBUTE_SYMLINK) && localInfo.isDirectory() && isRecursiveLink(node.getStore(), localInfo)) |
183 |
child = null; |
184 |
else |
185 |
child = createChildNodeFromFileSystem(node, localInfo); |
186 |
localIndex++; |
187 |
} else { |
188 |
// resource exists only in the workspace |
189 |
child = createNode(target, null, null, true); |
190 |
workspaceIndex++; |
191 |
} |
196 |
} |
192 |
if (child != null) |
197 |
/* process any remaining resource from the file system */ |
193 |
addChildToTree(node, child); |
198 |
addChildrenFromFileSystem(project, node, uniqueList, localIndex); |
194 |
} |
199 |
} |
195 |
} |
|
|
196 |
|
200 |
|
197 |
/* process any remaining resource from the file system */ |
201 |
/* Mark the children as now known */ |
198 |
addChildrenFromFileSystem(node, list, localIndex); |
202 |
if (unknown) { |
|
|
203 |
// Don't open the info - we might not be inside a workspace-modifying operation |
204 |
resourceInfo = parent.getResourceInfo(false, false); |
205 |
if (resourceInfo != null) |
206 |
resourceInfo.clear(ICoreConstants.M_CHILDREN_UNKNOWN); |
207 |
} |
208 |
} else { |
209 |
// get the list of resources in the file system |
210 |
// don't ask for local children if we know it doesn't exist locally |
211 |
IFileInfo[] list = node.existsInFileSystem() ? getLocalList(node) : NO_CHILDREN; |
212 |
int localIndex = 0; |
213 |
|
214 |
// See if the children of this resource have been computed before |
215 |
ResourceInfo resourceInfo = parent.getResourceInfo(false, false); |
216 |
int flags = parent.getFlags(resourceInfo); |
217 |
boolean unknown = ResourceInfo.isSet(flags, ICoreConstants.M_CHILDREN_UNKNOWN); |
218 |
|
219 |
// get the list of resources in the workspace |
220 |
if (!unknown && (parentType == IResource.FOLDER || parentType == IResource.PROJECT) && parent.exists(flags, true)) { |
221 |
IResource target = null; |
222 |
UnifiedTreeNode child = null; |
223 |
IResource[] members; |
224 |
try { |
225 |
members = ((IContainer) parent).members(IContainer.INCLUDE_TEAM_PRIVATE_MEMBERS | IContainer.INCLUDE_HIDDEN); |
226 |
} catch (CoreException e) { |
227 |
members = NO_RESOURCES; |
228 |
} |
229 |
int workspaceIndex = 0; |
230 |
//iterate simultaneously over file system and workspace members |
231 |
while (workspaceIndex < members.length) { |
232 |
target = members[workspaceIndex]; |
233 |
String name = target.getName(); |
234 |
IFileInfo localInfo = localIndex < list.length ? list[localIndex] : null; |
235 |
int comp = localInfo != null ? name.compareTo(localInfo.getName()) : -1; |
236 |
//special handling for linked resources |
237 |
if (target.isFloating()) { |
238 |
// remove all floating resources |
239 |
child = createNode(target, null, null, true); |
240 |
workspaceIndex++; |
241 |
} else if (target.isLinked()) { |
242 |
//child will be null if location is undefined |
243 |
child = createChildForLinkedResource(target); |
244 |
workspaceIndex++; |
245 |
//if there is a matching local file, skip it - it will be blocked by the linked resource |
246 |
if (comp == 0) |
247 |
localIndex++; |
248 |
} else if (comp == 0) { |
249 |
// resource exists in workspace and file system --> localInfo is non-null |
250 |
//create workspace-only node for symbolic link that creates a cycle |
251 |
if (localInfo.getAttribute(EFS.ATTRIBUTE_SYMLINK) && localInfo.isDirectory() && isRecursiveLink(node.getStore(), localInfo)) |
252 |
child = createNode(target, null, null, true); |
253 |
else |
254 |
child = createNode(target, null, localInfo, true); |
255 |
localIndex++; |
256 |
workspaceIndex++; |
257 |
} else if (comp > 0) { |
258 |
// resource exists only in file system |
259 |
//don't create a node for symbolic links that create a cycle |
260 |
if (localInfo.getAttribute(EFS.ATTRIBUTE_SYMLINK) && localInfo.isDirectory() && isRecursiveLink(node.getStore(), localInfo)) |
261 |
child = null; |
262 |
else |
263 |
child = createChildNodeFromFileSystem(node, localInfo); |
264 |
localIndex++; |
265 |
} else { |
266 |
// resource exists only in the workspace |
267 |
child = createNode(target, null, null, true); |
268 |
workspaceIndex++; |
269 |
} |
270 |
if (child != null) |
271 |
addChildToTree(node, child); |
272 |
} |
273 |
} |
274 |
/* process any remaining resource from the file system */ |
275 |
addChildrenFromFileSystem(node, list, localIndex); |
199 |
|
276 |
|
200 |
/* Mark the children as now known */ |
277 |
/* Mark the children as now known */ |
201 |
if (unknown) { |
278 |
if (unknown) { |
202 |
// Don't open the info - we might not be inside a workspace-modifying operation |
279 |
// Don't open the info - we might not be inside a workspace-modifying operation |
203 |
resourceInfo = parent.getResourceInfo(false, false); |
280 |
resourceInfo = parent.getResourceInfo(false, false); |
204 |
if (resourceInfo != null) |
281 |
if (resourceInfo != null) |
205 |
resourceInfo.clear(ICoreConstants.M_CHILDREN_UNKNOWN); |
282 |
resourceInfo.clear(ICoreConstants.M_CHILDREN_UNKNOWN); |
|
|
283 |
} |
206 |
} |
284 |
} |
207 |
|
285 |
|
208 |
/* if we added children, add the childMarker separator */ |
286 |
/* if we added children, add the childMarker separator */ |
Lines 210-215
Link Here
|
210 |
addChildrenMarker(); |
288 |
addChildrenMarker(); |
211 |
} |
289 |
} |
212 |
|
290 |
|
|
|
291 |
private static class UniqueFileStoreName { |
292 |
public UniqueFileStoreName(String name, IFileStore store, IFileInfo info) { |
293 |
this.name = name; |
294 |
this.store = store; |
295 |
this.info = info; |
296 |
} |
297 |
|
298 |
public String name; |
299 |
public IFileStore store; |
300 |
public IFileInfo info; |
301 |
} |
302 |
|
303 |
// The names are suffixed with the directory in which they belong, if there's a conflict. |
304 |
// For instance, if two files (foo/bar.txt and folder/bar.txt) shared the same name, the second |
305 |
// file will have its immediate parent appended as follows: "bar.txt (folder)". |
306 |
// if multiple files share the same name, the parent directory names are appended with a "-" |
307 |
// delimiter, as follows: "bar.txt (root-folder)" since the "/" delimiter isn't a valid name |
308 |
// character. |
309 |
private UniqueFileStoreName[] generateUniqueList(IFileStore[] list) { |
310 |
// the list is already sorted by name, so identical named items are consecutives |
311 |
UniqueFileStoreName[] uniqueList = new UniqueFileStoreName[list.length]; |
312 |
boolean changed = false; |
313 |
uniqueList[0] = new UniqueFileStoreName(list[0].getName(), list[0], list[0].fetchInfo()); |
314 |
for (int i = 1; i < list.length; i++) { |
315 |
String name = list[i].getName(); |
316 |
if (list[i - 1].getName().equals(name)) { |
317 |
IFileStore parent = list[i].getParent(); |
318 |
String suffix = parent.getName(); |
319 |
String tentativeName = name + " (" + suffix + ")"; //$NON-NLS-1$ //$NON-NLS-2$ |
320 |
while (nameExistsInList(tentativeName, uniqueList, list, i - 1)) { |
321 |
parent = parent.getParent(); |
322 |
suffix = parent.getName() + ' ' + suffix; |
323 |
tentativeName = name + " (" + suffix + ")"; //$NON-NLS-1$ //$NON-NLS-2$ |
324 |
} |
325 |
name = tentativeName; |
326 |
changed = true; |
327 |
} |
328 |
uniqueList[i] = new UniqueFileStoreName(name, list[i], list[i].fetchInfo()); |
329 |
} |
330 |
if (changed) { |
331 |
Arrays.sort(uniqueList, new Comparator() { |
332 |
public int compare(Object arg0, Object arg1) { |
333 |
UniqueFileStoreName a = (UniqueFileStoreName) arg0; |
334 |
UniqueFileStoreName b = (UniqueFileStoreName) arg1; |
335 |
return a.name.compareTo(b.name); |
336 |
} |
337 |
}); |
338 |
} |
339 |
return uniqueList; |
340 |
} |
341 |
|
342 |
private boolean nameExistsInList(String tentativeName, UniqueFileStoreName[] uniqueList, IFileStore[] list, int i) { |
343 |
while (i >= 0 && list[i].getName().equals(list[i + 1].getName())) { |
344 |
if (uniqueList[i].name.equals(tentativeName)) |
345 |
return true; |
346 |
i--; |
347 |
} |
348 |
return false; |
349 |
} |
350 |
|
213 |
protected void addChildrenFromFileSystem(UnifiedTreeNode node, IFileInfo[] childInfos, int index) { |
351 |
protected void addChildrenFromFileSystem(UnifiedTreeNode node, IFileInfo[] childInfos, int index) { |
214 |
if (childInfos == null) |
352 |
if (childInfos == null) |
215 |
return; |
353 |
return; |
Lines 221-226
Link Here
|
221 |
} |
359 |
} |
222 |
} |
360 |
} |
223 |
|
361 |
|
|
|
362 |
protected void addChildrenFromFileSystem(Project project, UnifiedTreeNode node, UniqueFileStoreName[] elements, int index) { |
363 |
if (elements == null) |
364 |
return; |
365 |
for (int i = index; i < elements.length; i++) { |
366 |
UnifiedTreeNode child = createNewFloatingLinkedResourceNode(project, node, elements[i]); |
367 |
addChildToTree(node, child); |
368 |
} |
369 |
} |
370 |
|
371 |
private UnifiedTreeNode createNewFloatingLinkedResourceNode(Project project, UnifiedTreeNode node, UniqueFileStoreName element) { |
372 |
UnifiedTreeNode child = createChildNodeFromFileSystem(node, element); |
373 |
child.setFlagMasks(ICoreConstants.M_LINK | ICoreConstants.M_FLOATING); |
374 |
return child; |
375 |
} |
376 |
|
224 |
protected void addChildrenMarker() { |
377 |
protected void addChildrenMarker() { |
225 |
addElementToQueue(childrenMarker); |
378 |
addElementToQueue(childrenMarker); |
226 |
} |
379 |
} |
Lines 283-288
Link Here
|
283 |
} |
436 |
} |
284 |
|
437 |
|
285 |
/** |
438 |
/** |
|
|
439 |
* Creates a child node for a location in the file system. Does nothing and returns null if the location does not correspond to a valid file/folder. |
440 |
*/ |
441 |
protected UnifiedTreeNode createChildNodeFromFileSystem(UnifiedTreeNode parent, UniqueFileStoreName element) { |
442 |
IPath childPath = parent.getResource().getFullPath().append(element.name); |
443 |
int type = element.info.isDirectory() ? IResource.FOLDER : IResource.FILE; |
444 |
IResource target = getWorkspace().newResource(childPath, type); |
445 |
return createNode(target, element.store, element.info, false); |
446 |
} |
447 |
|
448 |
/** |
286 |
* Factory method for creating a node for this tree. If the file exists on |
449 |
* Factory method for creating a node for this tree. If the file exists on |
287 |
* disk, either the parent store or child store can be provided. Providing |
450 |
* disk, either the parent store or child store can be provided. Providing |
288 |
* only the parent store avoids creation of the child store in cases where |
451 |
* only the parent store avoids creation of the child store in cases where |
Lines 335-347
Link Here
|
335 |
return level; |
498 |
return level; |
336 |
} |
499 |
} |
337 |
|
500 |
|
|
|
501 |
protected IFileStore[] getLocalFlattenList(UnifiedTreeNode node) { |
502 |
try { |
503 |
final IFileStore store = node.getStore(); |
504 |
IFileStore[] list = fileTree != null ? fileTree.getChildStores(store) : store.childStores(EFS.NONE, null); |
505 |
if (list == null || list.length == 0) |
506 |
return new IFileStore[0]; |
507 |
list = (IFileStore[]) ((Resource) node.getResource()).filterChildren(list, false); |
508 |
|
509 |
// flatten the directory structure |
510 |
ArrayList finalList = new ArrayList(); |
511 |
Stack foldersToFlatten = new Stack(); |
512 |
for (int i = 0; i < list.length; i++) { |
513 |
if (list[i].fetchInfo().isDirectory()) |
514 |
foldersToFlatten.push(list[i]); |
515 |
else |
516 |
finalList.add(list[i]); |
517 |
} |
518 |
while (!foldersToFlatten.isEmpty()) { |
519 |
IFileStore folder = (IFileStore) foldersToFlatten.pop(); |
520 |
IFileStore[] children = fileTree != null ? fileTree.getChildStores(folder) : folder.childStores(EFS.NONE, null); |
521 |
children = (IFileStore[]) ((Resource) node.getResource()).filterChildren(children, false); |
522 |
for (int i = 0; i < children.length; i++) { |
523 |
if (children[i].fetchInfo().isDirectory()) |
524 |
foldersToFlatten.push(children[i]); |
525 |
else |
526 |
finalList.add(children[i]); |
527 |
} |
528 |
} |
529 |
|
530 |
IFileStore[] uriList = (IFileStore[]) finalList.toArray(new IFileStore[0]); |
531 |
Arrays.sort(uriList, new Comparator() { |
532 |
public int compare(Object arg0, Object arg1) { |
533 |
IFileStore a = (IFileStore) arg0; |
534 |
IFileStore b = (IFileStore) arg1; |
535 |
return a.getName().compareTo(b.getName()); |
536 |
} |
537 |
}); |
538 |
return uriList; |
539 |
} catch (CoreException e) { |
540 |
//treat failure to access the directory as a non-existent directory |
541 |
return new IFileStore[0]; |
542 |
} |
543 |
} |
544 |
|
338 |
protected IFileInfo[] getLocalList(UnifiedTreeNode node) { |
545 |
protected IFileInfo[] getLocalList(UnifiedTreeNode node) { |
339 |
try { |
546 |
try { |
340 |
final IFileStore store = node.getStore(); |
547 |
final IFileStore store = node.getStore(); |
341 |
IFileInfo[] list = fileTree != null ? fileTree.getChildInfos(store) : store.childInfos(EFS.NONE, null); |
548 |
IFileInfo[] list = fileTree != null ? fileTree.getChildInfos(store) : store.childInfos(EFS.NONE, null); |
342 |
if (list == null || list.length == 0) |
549 |
if (list == null || list.length == 0) |
343 |
return NO_CHILDREN; |
550 |
return NO_CHILDREN; |
344 |
list = ((Resource) node.getResource()).filterChildren(list, false); |
551 |
list = (IFileInfo[]) ((Resource) node.getResource()).filterChildren(list, false); |
345 |
int size = list.length; |
552 |
int size = list.length; |
346 |
if (size > 1) |
553 |
if (size > 1) |
347 |
quickSort(list, 0, size - 1); |
554 |
quickSort(list, 0, size - 1); |