Skip to main content
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--org.eclipse.egit.ui.test/src/org/eclipse/egit/ui/internal/synchronize/model/GitModelCacheTest.java33
-rw-r--r--org.eclipse.egit.ui.test/src/org/eclipse/egit/ui/internal/synchronize/model/GitModelCacheTreeTest.java2
-rw-r--r--org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/synchronize/model/GitModelCache.java112
-rw-r--r--org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/synchronize/model/GitModelCacheTree.java44
-rw-r--r--org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/synchronize/model/GitModelCommit.java81
-rw-r--r--org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/synchronize/model/GitModelTree.java26
-rw-r--r--org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/synchronize/model/GitModelWorkingTree.java2
-rw-r--r--org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/synchronize/model/TreeBuilder.java140
8 files changed, 244 insertions, 196 deletions
diff --git a/org.eclipse.egit.ui.test/src/org/eclipse/egit/ui/internal/synchronize/model/GitModelCacheTest.java b/org.eclipse.egit.ui.test/src/org/eclipse/egit/ui/internal/synchronize/model/GitModelCacheTest.java
index 66bb5c7fbd..4668849c08 100644
--- a/org.eclipse.egit.ui.test/src/org/eclipse/egit/ui/internal/synchronize/model/GitModelCacheTest.java
+++ b/org.eclipse.egit.ui.test/src/org/eclipse/egit/ui/internal/synchronize/model/GitModelCacheTest.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (C) 2011, Dariusz Luksza <dariusz@luksza.org>
+ * Copyright (C) 2011, 2013 Dariusz Luksza <dariusz@luksza.org> and others.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
@@ -8,13 +8,20 @@
*******************************************************************************/
package org.eclipse.egit.ui.internal.synchronize.model;
+import static org.eclipse.jgit.junit.JGitTestUtil.writeTrashFile;
+import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.mock;
import java.io.File;
+import java.util.Map;
+import org.eclipse.egit.core.synchronize.GitCommitsModelCache.Change;
+import org.eclipse.egit.core.synchronize.StagedChangeCache;
import org.eclipse.egit.ui.Activator;
+import org.eclipse.jgit.api.Git;
+import org.eclipse.jgit.storage.file.FileRepository;
import org.junit.BeforeClass;
import org.junit.Test;
@@ -93,6 +100,30 @@ public class GitModelCacheTest extends GitModelTestCase {
assertFalse(actual);
}
+ @Test
+ public void shouldReturnChildren() throws Exception {
+ FileRepository repo = lookupRepository(leftRepoFile);
+ writeTrashFile(repo, "dir/a.txt", "trash");
+ writeTrashFile(repo, "dir/b.txt", "trash");
+ writeTrashFile(repo, "dir/c.txt", "trash");
+ writeTrashFile(repo, "dir/d.txt", "trash");
+ new Git(repo).add().addFilepattern("dir").call();
+
+ Map<String, Change> changes = StagedChangeCache.build(repo);
+ assertEquals(4, changes.size());
+
+ GitModelCache cache = new GitModelCache(createModelRepository(), repo,
+ changes);
+
+ GitModelObject[] cacheChildren = cache.getChildren();
+ assertEquals(1, cacheChildren.length);
+ GitModelObject dir = cacheChildren[0];
+ assertEquals("dir", dir.getName());
+
+ GitModelObject[] dirChildren = dir.getChildren();
+ assertEquals(4, dirChildren.length);
+ }
+
@BeforeClass public static void setupEnvironment() throws Exception {
leftRepoFile = createProjectAndCommitToRepository();
diff --git a/org.eclipse.egit.ui.test/src/org/eclipse/egit/ui/internal/synchronize/model/GitModelCacheTreeTest.java b/org.eclipse.egit.ui.test/src/org/eclipse/egit/ui/internal/synchronize/model/GitModelCacheTreeTest.java
index 25aa328033..20f2198e47 100644
--- a/org.eclipse.egit.ui.test/src/org/eclipse/egit/ui/internal/synchronize/model/GitModelCacheTreeTest.java
+++ b/org.eclipse.egit.ui.test/src/org/eclipse/egit/ui/internal/synchronize/model/GitModelCacheTreeTest.java
@@ -15,7 +15,7 @@ import static org.mockito.Mockito.mock;
import org.eclipse.core.runtime.IPath;
import org.eclipse.egit.core.synchronize.GitCommitsModelCache.Change;
import org.eclipse.egit.ui.Activator;
-import org.eclipse.egit.ui.internal.synchronize.model.GitModelCache.FileModelFactory;
+import org.eclipse.egit.ui.internal.synchronize.model.TreeBuilder.FileModelFactory;
import org.eclipse.jgit.lib.Repository;
import org.junit.BeforeClass;
import org.junit.Test;
diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/synchronize/model/GitModelCache.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/synchronize/model/GitModelCache.java
index d44013d2a8..d0f18c5919 100644
--- a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/synchronize/model/GitModelCache.java
+++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/synchronize/model/GitModelCache.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (C) 2010, Dariusz Luksza <dariusz@luksza.org>
+ * Copyright (C) 2010, 2013 Dariusz Luksza <dariusz@luksza.org> and others.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
@@ -8,17 +8,15 @@
*******************************************************************************/
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 java.util.Map.Entry;
import org.eclipse.compare.structuremergeviewer.Differencer;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.Path;
import org.eclipse.egit.core.synchronize.GitCommitsModelCache.Change;
import org.eclipse.egit.ui.UIText;
+import org.eclipse.egit.ui.internal.synchronize.model.TreeBuilder.FileModelFactory;
+import org.eclipse.egit.ui.internal.synchronize.model.TreeBuilder.TreeModelFactory;
import org.eclipse.jgit.lib.Repository;
/**
@@ -28,45 +26,9 @@ public class GitModelCache extends GitModelObjectContainer {
private final Path location;
- private final FileModelFactory fileFactory;
-
- private final Map<String, GitModelCacheTree> cacheTreeMap;
-
private final Repository repo;
- private final Map<String, Change> cache;
-
- /**
- * This interface enables creating proper instance of {@link GitModelBlob}
- * for cached and working files. In case of working files the left side
- * content of Compare View is loaded from local hard drive.
- */
- protected interface FileModelFactory {
- /**
- * Creates proper instance of {@link GitModelBlob} for cache and working
- * tree model representation
- *
- * @param objParent
- * 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 objParent,
- 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();
- }
+ private GitModelObject[] children;
/**
* Constructs model node that represents current status of Git cache.
@@ -100,19 +62,27 @@ public class GitModelCache extends GitModelObjectContainer {
* parent object
* @param repo
* repository associated with this object
- * @param cache
+ * @param changes
* list of changes associated with this object
* @param fileFactory
* leaf instance factory
*/
- protected GitModelCache(GitModelRepository parent, Repository repo, Map<String, Change> cache,
- FileModelFactory fileFactory) {
+ protected GitModelCache(GitModelRepository parent, final Repository repo,
+ Map<String, Change> changes, final FileModelFactory fileFactory) {
super(parent);
this.repo = repo;
- this.cache = cache;
- this.fileFactory = fileFactory;
- cacheTreeMap = new HashMap<String, GitModelCacheTree>();
- location = new Path(repo.getWorkTree().toString());
+ this.location = new Path(repo.getWorkTree().toString());
+
+ this.children = TreeBuilder.build(this, repo, changes, fileFactory,
+ new TreeModelFactory() {
+ public GitModelTree createTreeModel(
+ GitModelObjectContainer parentObject,
+ IPath fullPath,
+ int kind) {
+ return new GitModelCacheTree(parentObject, repo,
+ fullPath, fileFactory);
+ }
+ });
}
@Override
@@ -122,17 +92,7 @@ public class GitModelCache extends GitModelObjectContainer {
@Override
public GitModelObject[] getChildren() {
- List<GitModelObject> result = new ArrayList<GitModelObject>();
-
- for (Entry<String, Change> cacheEntry : cache.entrySet()) {
- GitModelObject entry = extractFromCache(cacheEntry.getValue(), cacheEntry.getKey());
- if (entry == null)
- continue;
-
- result.add(entry);
- }
-
- return result.toArray(new GitModelObject[result.size()]);
+ return children;
}
@Override
@@ -176,34 +136,10 @@ public class GitModelCache extends GitModelObjectContainer {
@Override
public void dispose() {
- for (GitModelTree modelTree : cacheTreeMap.values())
- modelTree.dispose();
-
- cache.clear();
- cacheTreeMap.clear();
- }
-
- private GitModelObject extractFromCache(Change change, String path) {
- if (path.contains("/")) //$NON-NLS-1$
- return handleCacheTree(change, path);
-
- return fileFactory.createFileModel(this, repo, change,
- location.append(path));
- }
-
- private GitModelObject handleCacheTree(Change change, String path) {
- int firstSlash = path.indexOf("/");//$NON-NLS-1$
- String pathKey = path.substring(0, firstSlash);
- GitModelCacheTree cacheTree = cacheTreeMap.get(pathKey);
- if (cacheTree == null) {
- IPath newPath = location.append(pathKey);
- cacheTree = new GitModelCacheTree(this, repo, newPath, fileFactory);
- cacheTreeMap.put(pathKey, cacheTree);
+ if (children != null) {
+ for (GitModelObject object : children)
+ object.dispose();
+ children = null;
}
-
- cacheTree.addChild(change, path.substring(firstSlash + 1));
-
- return cacheTree;
}
-
}
diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/synchronize/model/GitModelCacheTree.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/synchronize/model/GitModelCacheTree.java
index a5a9ed6bb4..94e488d162 100644
--- a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/synchronize/model/GitModelCacheTree.java
+++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/synchronize/model/GitModelCacheTree.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (C) 2010, Dariusz Luksza <dariusz@luksza.org>
+ * Copyright (C) 2010, 2013 Dariusz Luksza <dariusz@luksza.org> and others.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
@@ -11,13 +11,8 @@ package org.eclipse.egit.ui.internal.synchronize.model;
import static org.eclipse.compare.structuremergeviewer.Differencer.CHANGE;
import static org.eclipse.compare.structuremergeviewer.Differencer.RIGHT;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.Map;
-
import org.eclipse.core.runtime.IPath;
-import org.eclipse.egit.core.synchronize.GitCommitsModelCache.Change;
-import org.eclipse.egit.ui.internal.synchronize.model.GitModelCache.FileModelFactory;
+import org.eclipse.egit.ui.internal.synchronize.model.TreeBuilder.FileModelFactory;
import org.eclipse.jgit.lib.Repository;
/**
@@ -28,10 +23,6 @@ public class GitModelCacheTree extends GitModelTree {
private final FileModelFactory factory;
- private final Map<String, GitModelObject> cacheTreeMap;
-
- private final Repository repo;
-
/**
* @param parent
* parent object
@@ -44,16 +35,7 @@ public class GitModelCacheTree extends GitModelTree {
public GitModelCacheTree(GitModelObjectContainer parent, Repository repo,
IPath fullPath, FileModelFactory factory) {
super(parent, fullPath, RIGHT | CHANGE);
- this.repo = repo;
this.factory = factory;
- cacheTreeMap = new HashMap<String, GitModelObject>();
- }
-
- @Override
- public GitModelObject[] getChildren() {
- Collection<GitModelObject> values = cacheTreeMap.values();
-
- return values.toArray(new GitModelObject[values.size()]);
}
@Override
@@ -92,26 +74,4 @@ public class GitModelCacheTree extends GitModelTree {
return factory.isWorkingTree();
}
- void addChild(Change change, String nestedPath) {
- String pathKey;
- int firstSlash = nestedPath.indexOf("/"); //$NON-NLS-1$
- if (firstSlash > -1)
- pathKey = nestedPath.substring(0, firstSlash);
- else
- pathKey = nestedPath;
-
- IPath fullPath = getLocation().append(pathKey);
- if (nestedPath.contains("/")) { //$NON-NLS-1$
- GitModelCacheTree cacheEntry = (GitModelCacheTree) cacheTreeMap
- .get(pathKey);
- if (cacheEntry == null) {
- cacheEntry = new GitModelCacheTree(this, repo, fullPath, factory);
- cacheTreeMap.put(pathKey, cacheEntry);
- }
- cacheEntry.addChild(change, nestedPath.substring(firstSlash + 1));
- } else
- cacheTreeMap.put(pathKey,
- factory.createFileModel(this, repo, change, fullPath));
- }
-
}
diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/synchronize/model/GitModelCommit.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/synchronize/model/GitModelCommit.java
index 5bbc102638..91ee7df456 100644
--- a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/synchronize/model/GitModelCommit.java
+++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/synchronize/model/GitModelCommit.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (C) 2010, Dariusz Luksza <dariusz@luksza.org>
+ * Copyright (C) 2010, 2013 Dariusz Luksza <dariusz@luksza.org> and others.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
@@ -8,18 +8,14 @@
*******************************************************************************/
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 java.util.Map.Entry;
-
import org.eclipse.compare.structuremergeviewer.Differencer;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.Path;
import org.eclipse.egit.core.synchronize.GitCommitsModelCache.Change;
import org.eclipse.egit.core.synchronize.GitCommitsModelCache.Commit;
+import org.eclipse.egit.ui.internal.synchronize.model.TreeBuilder.FileModelFactory;
+import org.eclipse.egit.ui.internal.synchronize.model.TreeBuilder.TreeModelFactory;
import org.eclipse.jgit.lib.Repository;
/**
@@ -34,7 +30,7 @@ public class GitModelCommit extends GitModelObjectContainer implements
private final IProject[] projects;
- private final Map<String, GitModelObject> cachedTreeMap = new HashMap<String, GitModelObject>();
+ private GitModelObject[] children;
/**
* @param parent
@@ -81,16 +77,30 @@ public class GitModelCommit extends GitModelObjectContainer implements
@Override
public GitModelObject[] getChildren() {
- List<GitModelObject> result = new ArrayList<GitModelObject>();
+ if (children == null)
+ children = createChildren();
+ return children;
+ }
- if (commit.getChildren() != null) // prevent from NPE in empty commits
- for (Entry<String, Change> cacheEntry : commit.getChildren().entrySet()) {
- GitModelObject nested = addChild(cacheEntry.getValue(), cacheEntry.getKey());
- if (nested != null)
- result.add(nested);
+ private GitModelObject[] createChildren() {
+ FileModelFactory fileModelFactory = new FileModelFactory() {
+ public GitModelBlob createFileModel(GitModelObjectContainer parent,
+ Repository repository, Change change, IPath fullPath) {
+ return new GitModelBlob(parent, repository, change, fullPath);
}
- return result.toArray(new GitModelObject[result.size()]);
+ public boolean isWorkingTree() {
+ return false;
+ }
+ };
+ TreeModelFactory treeModelFactory = new TreeModelFactory() {
+ public GitModelTree createTreeModel(GitModelObjectContainer parent,
+ IPath fullPath, int kind) {
+ return new GitModelTree(parent, fullPath, kind);
+ }
+ };
+ return TreeBuilder.build(this, repo, commit.getChildren(),
+ fileModelFactory, treeModelFactory);
}
/**
@@ -102,10 +112,11 @@ public class GitModelCommit extends GitModelObjectContainer implements
@Override
public void dispose() {
- for (GitModelObject value : cachedTreeMap.values())
- value.dispose();
-
- cachedTreeMap.clear();
+ if (children != null) {
+ for (GitModelObject child : children)
+ child.dispose();
+ children = null;
+ }
}
@Override
@@ -134,36 +145,4 @@ public class GitModelCommit extends GitModelObjectContainer implements
return "ModelCommit[" + commit.getId() + "]"; //$NON-NLS-1$//$NON-NLS-2$
}
- private GitModelObject addChild(Change change, String nestedPath) {
- GitModelObject firstObject = null;
- IPath tmpLocation = getLocation();
- String[] segments = nestedPath.split("/"); //$NON-NLS-1$
- GitModelObjectContainer tmpPartent = this;
- Map<String, GitModelObject> tmpCache = cachedTreeMap;
-
- for (int i = 0; i < segments.length; i++) {
- String segment = segments[i];
- tmpLocation = tmpLocation.append(segment);
- if (i < segments.length - 1) {
- GitModelTree tree = (GitModelTree) tmpCache.get(segment);
- if (tree == null) {
- tree = new GitModelTree(tmpPartent, tmpLocation, change.getKind());
- tmpCache.put(segment, tree);
- }
- tmpPartent = tree;
- tmpCache = tree.cachedTreeMap;
- if (i == 0)
- firstObject = tmpPartent;
- } else { // handle last segment, it should be a file name
- GitModelBlob blob = new GitModelBlob(tmpPartent, repo, change,
- tmpLocation);
- tmpCache.put(segment, blob);
- if (i == 0)
- firstObject = blob;
- }
- }
-
- return firstObject;
- }
-
}
diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/synchronize/model/GitModelTree.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/synchronize/model/GitModelTree.java
index 0d4290a721..32154d20ed 100644
--- a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/synchronize/model/GitModelTree.java
+++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/synchronize/model/GitModelTree.java
@@ -1,6 +1,5 @@
/*******************************************************************************
-
- * Copyright (C) 2010, Dariusz Luksza <dariusz@luksza.org>
+ * Copyright (C) 2010, 2013 Dariusz Luksza <dariusz@luksza.org> and others.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
@@ -9,9 +8,7 @@
*******************************************************************************/
package org.eclipse.egit.ui.internal.synchronize.model;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.Map;
+import java.util.List;
import org.eclipse.core.runtime.IPath;
@@ -27,7 +24,7 @@ public class GitModelTree extends GitModelObjectContainer {
*/
protected final IPath path;
- final Map<String, GitModelObject> cachedTreeMap = new HashMap<String, GitModelObject>();
+ private GitModelObject[] children;
/**
* @param parent
@@ -66,9 +63,7 @@ public class GitModelTree extends GitModelObjectContainer {
@Override
public GitModelObject[] getChildren() {
- Collection<GitModelObject> values = cachedTreeMap.values();
-
- return values.toArray(new GitModelObject[values.size()]);
+ return children;
}
@Override
@@ -78,10 +73,11 @@ public class GitModelTree extends GitModelObjectContainer {
@Override
public void dispose() {
- for (GitModelObject value : cachedTreeMap.values())
- value.dispose();
-
- cachedTreeMap.clear();
+ if (children != null) {
+ for (GitModelObject object : children)
+ object.dispose();
+ children = null;
+ }
}
@Override
@@ -120,4 +116,8 @@ public class GitModelTree extends GitModelObjectContainer {
return "ModelTree[location=" + getLocation() + "]"; //$NON-NLS-1$ //$NON-NLS-2$
}
+ void setChildren(List<GitModelObject> children) {
+ this.children = children.toArray(new GitModelObject[children.size()]);
+ }
+
}
diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/synchronize/model/GitModelWorkingTree.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/synchronize/model/GitModelWorkingTree.java
index f61c127641..ecd47dc708 100644
--- a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/synchronize/model/GitModelWorkingTree.java
+++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/synchronize/model/GitModelWorkingTree.java
@@ -1,6 +1,7 @@
/*******************************************************************************
* Copyright (C) 2010, Dariusz Luksza <dariusz@luksza.org>
* Copyright (C) 2011, Matthias Sohn <matthias.sohn@sap.com>
+ * 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
@@ -15,6 +16,7 @@ import org.eclipse.compare.structuremergeviewer.Differencer;
import org.eclipse.core.runtime.IPath;
import org.eclipse.egit.core.synchronize.GitCommitsModelCache.Change;
import org.eclipse.egit.ui.UIText;
+import org.eclipse.egit.ui.internal.synchronize.model.TreeBuilder.FileModelFactory;
import org.eclipse.jgit.lib.Repository;
/**
diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/synchronize/model/TreeBuilder.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/synchronize/model/TreeBuilder.java
new file mode 100644
index 0000000000..aefa033681
--- /dev/null
+++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/synchronize/model/TreeBuilder.java
@@ -0,0 +1,140 @@
+/*******************************************************************************
+ * 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;
+ }
+ }
+}

Back to the top