org.eclipse.egit.ui.internal.synchronize.model.TreeBuilder.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipse.egit.ui.internal.synchronize.model.TreeBuilder.java

Source

/*******************************************************************************
 * Copyright (C) 2013 Robin Stocker <robin@nibor.org>
 *
 * 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
 *******************************************************************************/
package org.eclipse.egit.ui.internal.synchronize.model;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.Path;
import org.eclipse.egit.core.synchronize.GitCommitsModelCache.Change;
import org.eclipse.jgit.lib.Repository;

/**
 * For building trees of directory and file nodes out of a flat list of changes.
 */
class TreeBuilder {

    /**
     * This interface enables creating the right instances of
     * {@link GitModelBlob} for files.
     */
    interface FileModelFactory {
        /**
         * Creates proper instance of {@link GitModelBlob} for file nodes
         *
         * @param parent
         *            parent object
         * @param repo
         *            repository associated with file that will be created
         * @param change
         *            change associated with file that will be created
         * @param fullPath
         *            absolute path
         * @return instance of {@link GitModelBlob}
         */
        GitModelBlob createFileModel(GitModelObjectContainer parent, Repository repo, Change change,
                IPath fullPath);

        /**
         * Distinguish working tree from changed/staged tree
         *
         * @return {@code true} when this tree is working tree, {@code false}
         *         when it is a cached tree
         */
        boolean isWorkingTree();
    }

    /**
     * Interface for creating the desired instances of {@link GitModelTree}.
     */
    interface TreeModelFactory {
        GitModelTree createTreeModel(GitModelObjectContainer parent, IPath fullPath, int kind);
    }

    /**
     *
     * @param root
     *            the root node of the tree to build, which will become the
     *            parent of the first level of children
     * @param repo
     * @param changes
     * @param fileFactory
     * @param treeFactory
     * @return the children of the root nodes
     */
    public static GitModelObject[] build(final GitModelObjectContainer root, final Repository repo,
            final Map<String, Change> changes, final FileModelFactory fileFactory,
            final TreeModelFactory treeFactory) {

        if (changes == null || changes.isEmpty())
            return new GitModelObject[] {};

        final IPath rootPath = new Path(repo.getWorkTree().getAbsolutePath());
        final List<GitModelObject> rootChildren = new ArrayList<GitModelObject>();

        final Map<IPath, Node> nodes = new HashMap<IPath, Node>();

        for (Map.Entry<String, Change> entry : changes.entrySet()) {
            String repoRelativePath = entry.getKey();
            Change change = entry.getValue();

            GitModelObjectContainer parent = root;
            List<GitModelObject> children = rootChildren;
            IPath path = rootPath;

            String[] segments = repoRelativePath.split("/"); //$NON-NLS-1$

            for (int i = 0; i < segments.length; i++) {
                path = path.append(segments[i]);

                // Changes represent files, so the last segment is the file name
                boolean fileNode = (i == segments.length - 1);
                if (!fileNode) {
                    Node node = nodes.get(path);
                    if (node == null) {
                        GitModelTree tree = treeFactory.createTreeModel(parent, path, change.getKind());
                        node = new Node(tree);
                        nodes.put(path, node);
                        children.add(tree);
                    }
                    parent = node.tree;
                    children = node.children;
                } else {
                    GitModelBlob file = fileFactory.createFileModel(parent, repo, change, path);
                    children.add(file);
                }
            }
        }

        for (Node object : nodes.values()) {
            GitModelTree tree = object.tree;
            tree.setChildren(object.children);
        }

        return rootChildren.toArray(new GitModelObject[rootChildren.size()]);
    }

    private static class Node {
        private final GitModelTree tree;

        private final List<GitModelObject> children = new ArrayList<GitModelObject>();

        public Node(GitModelTree tree) {
            this.tree = tree;
        }
    }
}