private List generateChildDiffItems()

in source/com.microsoft.tfs.client.clc/src/com/microsoft/tfs/client/clc/vc/commands/CommandDifference.java [928:1245]


    private List<DiffItem> generateChildDiffItems(
        final DiffItem rootItem,
        final Workspace workspace,
        final boolean recursive,
        final VersionSpec version,
        final File tempDirectory) {
        Check.notNull(rootItem, "rootItem"); //$NON-NLS-1$
        Check.notNull(workspace, "workspace"); //$NON-NLS-1$
        Check.notNull(tempDirectory, "tempDirectory"); //$NON-NLS-1$

        final List<DiffItem> directoryList = new ArrayList<DiffItem>();
        final boolean isWorkspaceVersionSpec = (version instanceof WorkspaceVersionSpec);

        /*
         * Query all the items from the server that match the given root item
         * (at the given version spec). These items come back sorted so related
         * items are contiguous for faster searching.
         */
        Item[] itemArray = null;

        if (version != null) {
            itemArray = getFilteredServerItemList(rootItem.getServerPath(), version, false, recursive, false, true);
        } else if (rootItem.isInRepository()) {
            itemArray = getFilteredServerItemList(
                rootItem.getServerPath(),
                new WorkspaceVersionSpec(workspace),
                false,
                recursive,
                false,
                true);
        }

        /*
         * Start with the root item.
         */
        directoryList.add(rootItem);

        /*
         * If there are server items, iterate through them, and for each item
         * keep walking in an inner loop to find items in the same directory.
         * Then continue iterating after passing the related items.
         */
        if (itemArray != null && itemArray.length > 0) {
            /*
             * Query the pending changes for edit changes and keep a map so we
             * can look them up during iteration.
             */

            final Map<String, PendingChange> serverPathToExistingAPendingChanges = new HashMap<String, PendingChange>();

            if (isWorkspaceVersionSpec) {
                final PendingSet pendingChangeSet = workspace.getPendingChanges(new String[] {
                    rootItem.getServerPath()
                }, recursive ? RecursionType.FULL : RecursionType.NONE, false);

                if (pendingChangeSet != null
                    && pendingChangeSet.getPendingChanges() != null
                    && pendingChangeSet.getPendingChanges().length > 0) {
                    for (int i = 0; i < pendingChangeSet.getPendingChanges().length; i++) {
                        final PendingChange change = pendingChangeSet.getPendingChanges()[i];

                        if (change != null && change.getChangeType().contains(ChangeType.EDIT)) {
                            serverPathToExistingAPendingChanges.put(change.getServerItem(), change);
                        }
                    }
                }
            }

            /*
             * Build the list of directory items (each item can have children).
             *
             * Iterate over the items from the starting index, and iterate over
             * the remainder in a second loop inside to collapse contiguous
             * items into one diff item (the items list is sorted).
             *
             * The variables in the outer loop start with "first" and the
             * variables in the inner start with "second".
             */

            String localPath = null;
            String serverPath = null;
            String path = null;

            int index = 1;
            while (index < itemArray.length) {
                final Item firstItem = itemArray[index];

                final String firstFolderName = ServerPath.getParent(firstItem.getServerItem());
                final DiffFolderItem firstDiffFolderItem =
                    new DiffFolderItem(firstFolderName, null, null, rootItem, false, version);

                /*
                 * If no version was given, see if the directory really exists
                 * on disk.
                 */
                boolean firstLocalFolderExists = true;
                if (version == null) {
                    final PathTranslation firstTranslation = workspace.translateServerPathToLocalPath(firstFolderName);

                    if (firstTranslation != null && firstTranslation.isCloaked() == false) {
                        firstLocalFolderExists = new File(firstTranslation.getTranslatedPath()).exists();
                    } else {
                        firstLocalFolderExists = false;
                    }
                }

                /*
                 * If the server path is the root folder "$/", chop the length
                 * to just "$".
                 */
                int firstPathOffset = firstFolderName.length();
                if (firstPathOffset == 2) {
                    firstPathOffset = 1;
                }

                /*
                 * Save the starting index and loop over the remaining items
                 * until we match one in a different directory.
                 */
                final int startingIndex = index;
                while (index < itemArray.length) {
                    final Item secondItem = itemArray[index];

                    /*
                     * Assign the second item's server path to the outer loop's
                     * serverPath variable.
                     */
                    serverPath = secondItem.getServerItem();

                    /*
                     * If the second item is not a child of the first item, or
                     * if it has a path separator after our first path's offset
                     * (which mean it's a whole directory underneath the first
                     * item), then we stop iterating because it can't be a
                     * direct child and needs its own diff item later.
                     */
                    if (ServerPath.isChild(firstFolderName, serverPath) == false
                        || serverPath.indexOf(ServerPath.PREFERRED_SEPARATOR_CHARACTER, firstPathOffset + 1) >= 0) {
                        break;
                    }

                    /*
                     * If the item is a folder and we were given a version to
                     * fetch, or it exists locally, process its children.
                     */
                    if ((version != null || firstLocalFolderExists) && secondItem.getItemType() == ItemType.FOLDER) {
                        /*
                         * See if it's mapped. It may not be mapped
                         */
                        final PathTranslation secondTranslation = workspace.translateServerPathToLocalPath(serverPath);

                        if (secondTranslation != null && secondTranslation.isCloaked() == false) {
                            /*
                             * Assign to the outer loop's local path.
                             */
                            localPath = secondTranslation.getTranslatedPath();
                        }

                        /*
                         * If there was a version given, use a temp file for it,
                         * otherwise use the actual local file.
                         */
                        if (version != null) {
                            path = constructTempFile(tempDirectory, serverPath);
                        } else {
                            path = localPath;
                        }

                        Check.notNull(path, "path"); //$NON-NLS-1$

                        try {
                            if (version != null || new File(path).exists()) {
                                final DiffFolderItem secondDiffFolderItem =
                                    new DiffFolderItem(serverPath, localPath, path, rootItem, true, version);

                                /*
                                 * If the first item has already been added to
                                 * the list, add the second item to its
                                 * children.
                                 */
                                final int indexOfFirstItem = directoryList.indexOf(firstDiffFolderItem);
                                if (indexOfFirstItem >= 0) {
                                    final DiffFolderItem parent = (DiffFolderItem) directoryList.get(indexOfFirstItem);
                                    parent.addDirectory(secondDiffFolderItem);
                                }

                                /*
                                 * Add it to the end of the list so it will be
                                 * processed on further iteration in the outer
                                 * loop.
                                 */
                                if (recursive) {
                                    directoryList.add(secondDiffFolderItem);
                                }
                            }
                        } catch (final Throwable t) {
                            log.error("Inner exception evaluating diff items", t); //$NON-NLS-1$
                        }
                    }

                    /*
                     * Move on to the next list item in the inner loop.
                     */
                    index++;
                }

                /*
                 * The inner loop has stopped moving because it found a
                 * different directory, so process all the files between the
                 * startingIndex to the current index.
                 */

                if (version != null || firstLocalFolderExists) {
                    for (int i = startingIndex; i < index; i++) {
                        if (itemArray[i].getItemType() != ItemType.FOLDER) {
                            serverPath = itemArray[i].getServerItem();

                            final PathTranslation thirdTranslation =
                                workspace.translateServerPathToLocalPath(serverPath);

                            if (thirdTranslation != null && thirdTranslation.isCloaked() == false) {
                                localPath = thirdTranslation.getTranslatedPath();
                            }

                            if (version != null) {
                                path = constructTempFile(tempDirectory, serverPath);
                            } else {
                                path = localPath;
                            }

                            final DiffItem fileDiffItem =
                                new DiffItem(itemArray[i], localPath, path, rootItem, version);

                            if (serverPathToExistingAPendingChanges.containsKey((itemArray[i].getServerItem()))) {
                                fileDiffItem.setIsPendingChange(true);
                            }

                            if (isWorkspaceVersionSpec && localPath != null) {
                                final FileSystemAttributes localFileAttributes =
                                    FileSystemUtils.getInstance().getAttributes(localPath);

                                if (localFileAttributes.exists() && localFileAttributes.isReadOnly() == false) {
                                    fileDiffItem.setWritable(true);
                                }
                            }

                            if (version != null || new File(path).exists()) {
                                /*
                                 * Find the parent to put this file into.
                                 */
                                final int indexOfFirstItem = directoryList.indexOf(firstDiffFolderItem);
                                if (indexOfFirstItem >= 0) {
                                    ((DiffFolderItem) directoryList.get(indexOfFirstItem)).addFile(fileDiffItem);
                                }
                            }
                        }
                    }
                }
            }
        }

        /*
         * Walk down from the root item to find any filesystem items that don't
         * have a corresponding server item.
         */
        if (version == null) {
            String[] onDiskSubdirectories = null;

            /*
             * If the root item is on disk, and exists, list the subdirectories
             * in it.
             */
            if (rootItem.getLocalPath() != null) {
                final File rootFile = new File(rootItem.getLocalPath());

                if (rootFile.isDirectory() && rootFile.exists()) {
                    /*
                     * List all the subdirectories.
                     */
                    onDiskSubdirectories = rootFile.list(new DirectoriesOnlyFilter());

                    makePathsAbsolute(onDiskSubdirectories, rootFile);

                    /*
                     * Sort them.
                     */
                    Arrays.sort(onDiskSubdirectories, LocalPath.TOP_DOWN_COMPARATOR);
                }
            }

            if (onDiskSubdirectories != null) {
                for (int i = 0; i < onDiskSubdirectories.length; i++) {
                    final String subDirectoryName = onDiskSubdirectories[i];

                    final DiffFolderItem subDirectoryDiffFolderItem =
                        new DiffFolderItem(null, subDirectoryName, subDirectoryName, rootItem, false, version);

                    ((DiffFolderItem) rootItem).addDirectory(subDirectoryDiffFolderItem);
                }
            }

            if (recursive) {
                final List<DiffFolderItem> subdirectoryList = new ArrayList<DiffFolderItem>();

                /*
                 * Iterate over all the directories we've added so far and
                 * expand them.
                 */
                for (int i = 0; i < directoryList.size(); i++) {
                    getSubDirectoryDiffItems((DiffFolderItem) directoryList.get(i), directoryList, subdirectoryList);
                }

                directoryList.addAll(subdirectoryList);
            }
        }

        return directoryList;
    }