aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPhilipp Thun2011-02-03 03:39:38 (EST)
committerChris Aniszczyk2011-02-03 11:02:37 (EST)
commitd422d75ee407a7e2476c0e3358766d367e5d6878 (patch)
treeb2d03ed6537c5ea1dd2ae9cf34eb88e80995487d
parentf0d22181d49a67bc7f81415475c7344823e29594 (diff)
downloadegit-d422d75ee407a7e2476c0e3358766d367e5d6878.zip
egit-d422d75ee407a7e2476c0e3358766d367e5d6878.tar.gz
egit-d422d75ee407a7e2476c0e3358766d367e5d6878.tar.bz2
Queue decoration requestsrefs/changes/83/2283/4
In order to avoid the creation of an individual TreeWalk for each resource, decoration requests are queued and then processed by a separate job using a single TreeWalk with n path filters (n = number of files). Project nodes and folders are processed as before. Bug: 325393 Change-Id: I0d63413c644b4dcfe9aaa6052e397673feaae6fb Signed-off-by: Philipp Thun <philipp.thun@sap.com> Signed-off-by: Chris Aniszczyk <caniszczyk@gmail.com>
-rw-r--r--org.eclipse.egit.ui/src/org/eclipse/egit/ui/Activator.java11
-rw-r--r--org.eclipse.egit.ui/src/org/eclipse/egit/ui/UIText.java6
-rw-r--r--org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/decorators/DecoratableResource.java118
-rw-r--r--org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/decorators/DecoratableResourceAdapter.java144
-rw-r--r--org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/decorators/DecoratableResourceHelper.java202
-rw-r--r--org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/decorators/GitDecoratorJob.java89
-rw-r--r--org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/decorators/GitLightweightDecorator.java132
-rw-r--r--org.eclipse.egit.ui/src/org/eclipse/egit/ui/uitext.properties4
8 files changed, 543 insertions, 163 deletions
diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/Activator.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/Activator.java
index 0f8b7eb..edaa760 100644
--- a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/Activator.java
+++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/Activator.java
@@ -552,6 +552,17 @@ public class Activator extends AbstractUIPlugin implements DebugOptionsListener
}
/**
+ * Creates an error status
+ *
+ * @param message
+ * a localized message
+ * @return a new Status object
+ */
+ public static IStatus createErrorStatus(String message) {
+ return new Status(IStatus.ERROR, getPluginId(), message);
+ }
+
+ /**
* @return the {@link RepositoryUtil} instance
*/
public RepositoryUtil getRepositoryUtil() {
diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/UIText.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/UIText.java
index c34ea9f..23226ac 100644
--- a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/UIText.java
+++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/UIText.java
@@ -2714,6 +2714,12 @@ public class UIText extends NLS {
public static String GitBranchSynchronizeWizardPage_deselectAll;
/** */
+ public static String GitLightweightDecorator_AsynchronousDecorationError;
+
+ /** */
+ public static String GitLightweightDecorator_ResourceError;
+
+ /** */
public static String GitTraceConfigurationDialog_ApplyButton;
/** */
diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/decorators/DecoratableResource.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/decorators/DecoratableResource.java
new file mode 100644
index 0000000..176964d
--- /dev/null
+++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/decorators/DecoratableResource.java
@@ -0,0 +1,118 @@
+/*******************************************************************************
+ * Copyright (C) 2011, Philipp Thun <philipp.thun@sap.com>
+ *
+ * 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.decorators;
+
+import org.eclipse.core.resources.IResource;
+
+/**
+ * Basic implementation of <code>IDecoratableResource</code>
+ *
+ * @see IDecoratableResource
+ */
+class DecoratableResource implements IDecoratableResource {
+
+ /**
+ * Resource to be decorated
+ */
+ IResource resource = null;
+
+ /**
+ * Name of the repository of the resource
+ */
+ String repositoryName = null;
+
+ /**
+ * Current branch of the resource
+ */
+ String branch = null;
+
+ /**
+ * Flag indicating whether or not the resource is tracked
+ */
+ boolean tracked = false;
+
+ /**
+ * Flag indicating whether or not the resource is ignored
+ */
+ boolean ignored = false;
+
+ /**
+ * Flag indicating whether or not the resource has changes that are not
+ * staged
+ */
+ boolean dirty = false;
+
+ /**
+ * Staged state of the resource
+ */
+ Staged staged = Staged.NOT_STAGED;
+
+ /**
+ * Flag indicating whether or not the resource has merge conflicts
+ */
+ boolean conflicts = false;
+
+ /**
+ * Flag indicating whether or not the resource is assumed valid
+ */
+ boolean assumeValid = false;
+
+ /**
+ * Constructs a new decoratable resource
+ *
+ * This object represents the state of a resource used as a basis for
+ * decoration.
+ *
+ * @param resource
+ * resource to be decorated
+ */
+ DecoratableResource(IResource resource) {
+ this.resource = resource;
+ }
+
+ public int getType() {
+ return resource != null ? resource.getType() : 0;
+ }
+
+ public String getName() {
+ return resource != null ? resource.getName() : null;
+ }
+
+ public String getRepositoryName() {
+ return repositoryName;
+ }
+
+ public String getBranch() {
+ return branch;
+ }
+
+ public boolean isTracked() {
+ return tracked;
+ }
+
+ public boolean isIgnored() {
+ return ignored;
+ }
+
+ public boolean isDirty() {
+ return dirty;
+ }
+
+ public Staged staged() {
+ return staged;
+ }
+
+ public boolean hasConflicts() {
+ return conflicts;
+ }
+
+ public boolean isAssumeValid() {
+ return assumeValid;
+ }
+}
diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/decorators/DecoratableResourceAdapter.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/decorators/DecoratableResourceAdapter.java
index 8d8e01d..3424c23 100644
--- a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/decorators/DecoratableResourceAdapter.java
+++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/decorators/DecoratableResourceAdapter.java
@@ -30,7 +30,6 @@ import org.eclipse.egit.ui.Activator;
import org.eclipse.egit.ui.UIPreferences;
import org.eclipse.egit.ui.internal.trace.GitTraceLocation;
import org.eclipse.jface.preference.IPreferenceStore;
-import org.eclipse.jgit.dircache.DirCacheEntry;
import org.eclipse.jgit.dircache.DirCacheIterator;
import org.eclipse.jgit.errors.IncorrectObjectTypeException;
import org.eclipse.jgit.errors.MissingObjectException;
@@ -48,9 +47,7 @@ import org.eclipse.jgit.treewalk.filter.AndTreeFilter;
import org.eclipse.jgit.treewalk.filter.PathFilterGroup;
import org.eclipse.jgit.treewalk.filter.TreeFilter;
-class DecoratableResourceAdapter implements IDecoratableResource {
-
- private final IResource resource;
+class DecoratableResourceAdapter extends DecoratableResource {
private final RepositoryMapping mapping;
@@ -60,35 +57,13 @@ class DecoratableResourceAdapter implements IDecoratableResource {
private final IPreferenceStore store;
- private final String branch;
-
- private final String repositoryName;
-
- private boolean tracked = false;
-
- private boolean ignored = false;
-
- private boolean dirty = false;
-
- private boolean conflicts = false;
-
- private boolean assumeValid = false;
-
- private Staged staged = Staged.NOT_STAGED;
-
private final boolean trace;
- static final int T_HEAD = 0;
-
- static final int T_INDEX = 1;
-
- static final int T_WORKSPACE = 2;
-
@SuppressWarnings("fallthrough")
public DecoratableResourceAdapter(IResource resourceToWrap)
throws IOException {
+ super(resourceToWrap);
trace = GitTraceLocation.DECORATION.isActive();
- resource = resourceToWrap;
long start = 0;
if (trace) {
GitTraceLocation.getTrace().trace(
@@ -154,59 +129,7 @@ class DecoratableResourceAdapter implements IDecoratableResource {
}
private void extractResourceProperties(TreeWalk treeWalk) throws IOException {
- final ContainerTreeIterator workspaceIterator = treeWalk.getTree(
- T_WORKSPACE, ContainerTreeIterator.class);
- final ResourceEntry resourceEntry = workspaceIterator != null ? workspaceIterator
- .getResourceEntry() : null;
-
- if (resourceEntry == null)
- return;
-
- if (workspaceIterator != null && workspaceIterator.isEntryIgnored()) {
- ignored = true;
- return;
- }
-
- final int mHead = treeWalk.getRawMode(T_HEAD);
- final int mIndex = treeWalk.getRawMode(T_INDEX);
-
- if (mHead == FileMode.MISSING.getBits()
- && mIndex == FileMode.MISSING.getBits())
- return;
-
- tracked = true;
-
- if (mHead == FileMode.MISSING.getBits()) {
- staged = Staged.ADDED;
- } else if (mIndex == FileMode.MISSING.getBits()) {
- staged = Staged.REMOVED;
- } else if (mHead != mIndex
- || (mIndex != FileMode.TREE.getBits() && !treeWalk.idEqual(
- T_HEAD, T_INDEX))) {
- staged = Staged.MODIFIED;
- } else {
- staged = Staged.NOT_STAGED;
- }
-
- final DirCacheIterator indexIterator = treeWalk.getTree(T_INDEX,
- DirCacheIterator.class);
- final DirCacheEntry indexEntry = indexIterator != null ? indexIterator
- .getDirCacheEntry() : null;
-
- if (indexEntry == null)
- return;
-
- if (indexEntry.getStage() > 0)
- conflicts = true;
-
- if (indexEntry.isAssumeValid()) {
- dirty = false;
- assumeValid = true;
- } else {
- if (workspaceIterator != null
- && workspaceIterator.isModified(indexEntry, true))
- dirty = true;
- }
+ DecoratableResourceHelper.decorateResource(this, treeWalk);
}
private class RecursiveStateFilter extends TreeFilter {
@@ -231,7 +154,8 @@ class DecoratableResourceAdapter implements IDecoratableResource {
GitTraceLocation.DECORATION.getLocation(),
treeWalk.getPathString());
final WorkingTreeIterator workingTreeIterator = treeWalk.getTree(
- T_WORKSPACE, WorkingTreeIterator.class);
+ DecoratableResourceHelper.T_WORKSPACE,
+ WorkingTreeIterator.class);
if (workingTreeIterator != null) {
if (workingTreeIterator instanceof ContainerTreeIterator) {
final ContainerTreeIterator workspaceIterator =
@@ -245,8 +169,10 @@ class DecoratableResourceAdapter implements IDecoratableResource {
}
if (resource.getFullPath().isPrefixOf(
resourceEntry.getResource().getFullPath())
- && treeWalk.getFileMode(T_HEAD) == FileMode.MISSING
- && treeWalk.getFileMode(T_INDEX) == FileMode.MISSING) {
+ && treeWalk
+ .getFileMode(DecoratableResourceHelper.T_HEAD) == FileMode.MISSING
+ && treeWalk
+ .getFileMode(DecoratableResourceHelper.T_INDEX) == FileMode.MISSING) {
// we reached the folder to decorate (or are beyond)
// we can cut if the current entry does not
// exist in head and index
@@ -272,8 +198,10 @@ class DecoratableResourceAdapter implements IDecoratableResource {
}
if (resPath.isPrefixOf(wdPath)
- && treeWalk.getFileMode(T_HEAD) == FileMode.MISSING
- && treeWalk.getFileMode(T_INDEX) == FileMode.MISSING) {
+ && treeWalk
+ .getFileMode(DecoratableResourceHelper.T_HEAD) == FileMode.MISSING
+ && treeWalk
+ .getFileMode(DecoratableResourceHelper.T_INDEX) == FileMode.MISSING) {
// we reached the folder to decorate (or are beyond)
// we can cut if the current entry does not
// exist in head and index
@@ -286,7 +214,8 @@ class DecoratableResourceAdapter implements IDecoratableResource {
}
}
- if (FileMode.TREE.equals(treeWalk.getRawMode(T_WORKSPACE)))
+ if (FileMode.TREE.equals(treeWalk
+ .getRawMode(DecoratableResourceHelper.T_WORKSPACE)))
return shouldRecurse(treeWalk);
// Backup current state so far
@@ -310,7 +239,8 @@ class DecoratableResourceAdapter implements IDecoratableResource {
private boolean shouldRecurse(TreeWalk treeWalk) throws IOException {
final WorkingTreeIterator workspaceIterator = treeWalk.getTree(
- T_WORKSPACE, WorkingTreeIterator.class);
+ DecoratableResourceHelper.T_WORKSPACE,
+ WorkingTreeIterator.class);
if (workspaceIterator instanceof AdaptableFileTreeIterator)
return true;
@@ -425,44 +355,4 @@ class DecoratableResourceAdapter implements IDecoratableResource {
treeWalk.addTree(IteratorService.createInitialIterator(repository));
return treeWalk;
}
-
- public String getName() {
- return resource.getName();
- }
-
- public int getType() {
- return resource.getType();
- }
-
- public String getRepositoryName() {
- return repositoryName;
- }
-
- public String getBranch() {
- return branch;
- }
-
- public boolean isTracked() {
- return tracked;
- }
-
- public boolean isIgnored() {
- return ignored;
- }
-
- public boolean isDirty() {
- return dirty;
- }
-
- public Staged staged() {
- return staged;
- }
-
- public boolean hasConflicts() {
- return conflicts;
- }
-
- public boolean isAssumeValid() {
- return assumeValid;
- }
}
diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/decorators/DecoratableResourceHelper.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/decorators/DecoratableResourceHelper.java
new file mode 100644
index 0000000..bfe3bdb
--- /dev/null
+++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/decorators/DecoratableResourceHelper.java
@@ -0,0 +1,202 @@
+/*******************************************************************************
+ * Copyright (C) 2011, Philipp Thun <philipp.thun@sap.com>
+ *
+ * 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.decorators;
+
+import java.io.IOException;
+import java.util.ArrayList;
+
+import org.eclipse.core.resources.IResource;
+import org.eclipse.egit.core.ContainerTreeIterator;
+import org.eclipse.egit.core.ContainerTreeIterator.ResourceEntry;
+import org.eclipse.egit.core.IteratorService;
+import org.eclipse.egit.core.project.RepositoryMapping;
+import org.eclipse.egit.ui.internal.decorators.IDecoratableResource.Staged;
+import org.eclipse.jgit.dircache.DirCacheEntry;
+import org.eclipse.jgit.dircache.DirCacheIterator;
+import org.eclipse.jgit.lib.Constants;
+import org.eclipse.jgit.lib.FileMode;
+import org.eclipse.jgit.lib.ObjectId;
+import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.revwalk.RevWalk;
+import org.eclipse.jgit.treewalk.EmptyTreeIterator;
+import org.eclipse.jgit.treewalk.TreeWalk;
+import org.eclipse.jgit.treewalk.filter.PathFilterGroup;
+
+/**
+ * Helper class to create decoratable resources
+ *
+ * @see IDecoratableResource
+ */
+class DecoratableResourceHelper {
+
+ static final int T_HEAD = 0;
+
+ static final int T_INDEX = 1;
+
+ static final int T_WORKSPACE = 2;
+
+ static IDecoratableResource[] createDecoratableResources(
+ final IResource[] resources) throws IOException {
+ // Use first (available) resource to get repository mapping
+ int i = 0;
+ while (resources[i] == null) {
+ i++;
+ if (i >= resources.length)
+ // Array only contains nulls
+ return null;
+ }
+ final RepositoryMapping mapping = RepositoryMapping
+ .getMapping(resources[i]);
+
+ final IDecoratableResource[] decoratableResources = new IDecoratableResource[resources.length];
+
+ ArrayList<String> resourcePaths = new ArrayList<String>();
+ for (i = 0; i < resources.length; i++) {
+ final IResource resource = resources[i];
+ if (resource != null && resource.getProject().isOpen()) {
+ switch (resource.getType()) {
+ case IResource.FILE:
+ // Add file path to list used for bulk decoration
+ resourcePaths.add(mapping.getRepoRelativePath(resource));
+ break;
+ case IResource.FOLDER:
+ case IResource.PROJECT:
+ // Decorate folder and project node separately
+ try {
+ decoratableResources[i] = new DecoratableResourceAdapter(
+ resource);
+ } catch (IOException e) {
+ // Ignore - decoratableResources[i] is null
+ }
+ resourcePaths.add(null);
+ break;
+ }
+ } else {
+ resourcePaths.add(null);
+ }
+ }
+
+ // Check resource paths before proceeding with bulk decoration
+ boolean containsAtLeastOnePath = false;
+ for (final String p : resourcePaths) {
+ if (p != null) {
+ containsAtLeastOnePath = true;
+ break;
+ }
+ }
+ if (!containsAtLeastOnePath)
+ return decoratableResources;
+
+ final TreeWalk treeWalk = createThreeWayTreeWalk(mapping, resourcePaths);
+ if (treeWalk != null)
+ while (treeWalk.next()) {
+ i = resourcePaths.indexOf(treeWalk.getPathString());
+ if (i != -1) {
+ try {
+ decoratableResources[i] = decorateResource(
+ new DecoratableResource(resources[i]), treeWalk);
+ } catch (IOException e) {
+ // Ignore - decoratableResources[i] is null
+ }
+ }
+ }
+ return decoratableResources;
+ }
+
+ private static TreeWalk createThreeWayTreeWalk(
+ final RepositoryMapping mapping,
+ final ArrayList<String> resourcePaths) throws IOException {
+ final Repository repository = mapping.getRepository();
+ final TreeWalk treeWalk = new TreeWalk(repository);
+
+ // Copy path list...
+ final ArrayList<String> paths = new ArrayList<String>(resourcePaths);
+ while (paths.remove(null)) {
+ // ... and remove nulls
+ }
+
+ treeWalk.setFilter(PathFilterGroup.createFromStrings(paths));
+ treeWalk.setRecursive(true);
+ treeWalk.reset();
+
+ // Repository
+ final ObjectId headId = repository.resolve(Constants.HEAD);
+ if (headId != null)
+ treeWalk.addTree(new RevWalk(repository).parseTree(headId));
+ else
+ treeWalk.addTree(new EmptyTreeIterator());
+
+ // Index
+ treeWalk.addTree(new DirCacheIterator(repository.readDirCache()));
+
+ // Working directory
+ treeWalk.addTree(IteratorService.createInitialIterator(repository));
+
+ return treeWalk;
+ }
+
+ static DecoratableResource decorateResource(
+ final DecoratableResource decoratableResource,
+ final TreeWalk treeWalk) throws IOException {
+ final ContainerTreeIterator workspaceIterator = treeWalk.getTree(
+ T_WORKSPACE, ContainerTreeIterator.class);
+ final ResourceEntry resourceEntry = workspaceIterator != null ? workspaceIterator
+ .getResourceEntry() : null;
+
+ if (resourceEntry == null)
+ return null;
+
+ if (workspaceIterator != null && workspaceIterator.isEntryIgnored()) {
+ decoratableResource.ignored = true;
+ return decoratableResource;
+ }
+
+ final int mHead = treeWalk.getRawMode(T_HEAD);
+ final int mIndex = treeWalk.getRawMode(T_INDEX);
+
+ if (mHead == FileMode.MISSING.getBits()
+ && mIndex == FileMode.MISSING.getBits())
+ return decoratableResource;
+
+ decoratableResource.tracked = true;
+
+ if (mHead == FileMode.MISSING.getBits()) {
+ decoratableResource.staged = Staged.ADDED;
+ } else if (mIndex == FileMode.MISSING.getBits()) {
+ decoratableResource.staged = Staged.REMOVED;
+ } else if (mHead != mIndex
+ || (mIndex != FileMode.TREE.getBits() && !treeWalk.idEqual(
+ T_HEAD, T_INDEX))) {
+ decoratableResource.staged = Staged.MODIFIED;
+ } else {
+ decoratableResource.staged = Staged.NOT_STAGED;
+ }
+
+ final DirCacheIterator indexIterator = treeWalk.getTree(T_INDEX,
+ DirCacheIterator.class);
+ final DirCacheEntry indexEntry = indexIterator != null ? indexIterator
+ .getDirCacheEntry() : null;
+
+ if (indexEntry == null)
+ return decoratableResource;
+
+ if (indexEntry.getStage() > 0)
+ decoratableResource.conflicts = true;
+
+ if (indexEntry.isAssumeValid()) {
+ decoratableResource.dirty = false;
+ decoratableResource.assumeValid = true;
+ } else {
+ if (workspaceIterator != null
+ && workspaceIterator.isModified(indexEntry, true))
+ decoratableResource.dirty = true;
+ }
+ return decoratableResource;
+ }
+}
diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/decorators/GitDecoratorJob.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/decorators/GitDecoratorJob.java
new file mode 100644
index 0000000..a148842
--- /dev/null
+++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/decorators/GitDecoratorJob.java
@@ -0,0 +1,89 @@
+/*******************************************************************************
+ * Copyright (C) 2011, Philipp Thun <philipp.thun@sap.com>
+ *
+ * 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.decorators;
+
+import java.util.HashMap;
+import java.util.HashSet;
+
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.core.runtime.jobs.Job;
+
+/**
+ * Job decorating Git resources asynchronously
+ */
+public class GitDecoratorJob extends Job {
+
+ /**
+ * Constant defining the delay between two runs of the GitDecoratorJob in
+ * milliseconds
+ */
+ private static final long DELAY = 10L;
+
+ /**
+ * There is one dedicated job for each repository
+ */
+ private static HashMap<String, GitDecoratorJob> jobs = new HashMap<String, GitDecoratorJob>();
+
+ /**
+ * Get the job dedicated for a given repository
+ *
+ * @param gitDir
+ * the .git directory's full path used as unique identifier of a
+ * repository
+ * @return GitDecoratorJob the job dedicated for the given repository
+ */
+ public static synchronized GitDecoratorJob getJobForRepository(
+ final String gitDir) {
+ GitDecoratorJob job = jobs.get(gitDir);
+ if (job == null) {
+ job = new GitDecoratorJob("GitDecoratorJob[" + gitDir + "]"); //$NON-NLS-1$ //$NON-NLS-2$
+ job.setSystem(true);
+ job.setPriority(DECORATE);
+ jobs.put(gitDir, job);
+ }
+ return job;
+ }
+
+ private GitDecoratorJob(final String name) {
+ super(name);
+ }
+
+ private HashSet<Object> elementList = new HashSet<Object>();
+
+ /**
+ * Add an element to the queue of decoration requests
+ *
+ * @param element
+ * the element to be decorated
+ */
+ public synchronized void addDecorationRequest(Object element) {
+ if (elementList.add(element)) {
+ // Schedule job
+ if (getState() == NONE)
+ schedule(DELAY);
+ }
+ }
+
+ @Override
+ public IStatus run(IProgressMonitor monitor) {
+ while (!elementList.isEmpty()) {
+ final Object[] elements;
+ synchronized (this) {
+ // Get decoration requests as array and clear the queue
+ elements = elementList.toArray(new Object[elementList.size()]);
+ elementList.clear();
+ }
+ // Call GitLightweightDecorator to process the decoration requests
+ GitLightweightDecorator.processDecoration(elements);
+ }
+ return Status.OK_STATUS;
+ }
+}
diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/decorators/GitLightweightDecorator.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/decorators/GitLightweightDecorator.java
index 3ae2e35..eef3678 100644
--- a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/decorators/GitLightweightDecorator.java
+++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/decorators/GitLightweightDecorator.java
@@ -34,7 +34,6 @@ import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.QualifiedName;
-import org.eclipse.core.runtime.Status;
import org.eclipse.egit.core.internal.util.ExceptionCollector;
import org.eclipse.egit.core.project.GitProjectData;
import org.eclipse.egit.core.project.RepositoryChangeListener;
@@ -216,61 +215,122 @@ public class GitLightweightDecorator extends LabelProvider implements
if (!resource.exists() && !resource.isPhantom())
return;
- // Don't decorate ignored resources (e.g. bin folder content)
- if (Team.isIgnoredHint(resource))
- return;
-
- // Make sure we're dealing with a project under Git revision control
- final RepositoryMapping mapping = RepositoryMapping
- .getMapping(resource);
- if (mapping == null)
- return;
-
- // Cannot decorate linked resources
- if (mapping.getRepoRelativePath(resource) == null)
- return;
-
try {
- IDecoratableResource decoratableResource = null;
- final DecorationHelper helper = new DecorationHelper(
- activator.getPreferenceStore());
-
final Long refreshed = (Long) resource
.getSessionProperty(REFRESHED_KEY);
if (refreshed != null) {
// Stored decoratable resource is available
- final IWorkspaceRoot root = resource.getWorkspace().getRoot();
- final Long refresh = (Long) root
+ final Long refresh = (Long) resource.getWorkspace().getRoot()
.getSessionProperty(REFRESH_KEY);
if (refresh == null
- || refresh.longValue() < refreshed.longValue()) {
+ || refresh.longValue() <= refreshed.longValue()) {
// Stored decoratable resource is up-to-date
- decoratableResource = (IDecoratableResource) resource
+ final IDecoratableResource decoratableResource = (IDecoratableResource) resource
.getSessionProperty(DECORATABLE_RESOURCE_KEY);
if (decoratableResource != null) {
// Use stored decoratable resource
+ final DecorationHelper helper = new DecorationHelper(
+ activator.getPreferenceStore());
helper.decorate(decoration, decoratableResource);
return;
}
}
}
+ } catch (CoreException e) {
+ handleException(resource, e);
+ return;
+ }
+
+ // Don't decorate ignored resources (e.g. bin folder content)
+ if (Team.isIgnoredHint(resource))
+ return;
+
+ // Make sure we're dealing with a project under Git revision control
+ final RepositoryMapping mapping = RepositoryMapping
+ .getMapping(resource);
+ if (mapping == null)
+ return;
+
+ // Cannot decorate linked resources
+ if (mapping.getRepoRelativePath(resource) == null)
+ return;
+
+ // No (up-to-date) stored decoratable resource is available, thus
+ // decoration request is added to the queue
+ GitDecoratorJob.getJobForRepository(
+ mapping.getGitDirAbsolutePath().toString())
+ .addDecorationRequest(element);
+ }
+
+ /**
+ * Process decoration requests for the given list of elements
+ *
+ * @param elements
+ * the list of elements to be decorated
+ */
+ static void processDecoration(final Object[] elements) {
+ final GitLightweightDecorator decorator = (GitLightweightDecorator) Activator
+ .getDefault().getWorkbench().getDecoratorManager()
+ .getBaseLabelProvider(DECORATOR_ID);
+ if (decorator != null)
+ decorator.prepareDecoration(elements);
+ else
+ exceptions
+ .handleException(new CoreException(
+ Activator
+ .createErrorStatus(UIText.GitLightweightDecorator_AsynchronousDecorationError)));
+ }
+
+ private void prepareDecoration(final Object[] elements) {
+ if (elements == null)
+ return;
- // No (up-to-date) stored decoratable resource is available
- decoratableResource = new DecoratableResourceAdapter(resource);
- helper.decorate(decoration, decoratableResource);
+ final IResource[] resources = new IResource[elements.length];
+ for (int i = 0; i < elements.length; i++) {
+ if (elements[i] != null)
+ resources[i] = getResource(elements[i]);
+ }
- // Store decoratable resource in session
- resource.setSessionProperty(DECORATABLE_RESOURCE_KEY,
- decoratableResource);
- // Set (new) 'refreshed' timestamp
- resource.setSessionProperty(REFRESHED_KEY,
- Long.valueOf(System.currentTimeMillis()));
+ try {
+ // Calculate resource decorations
+ IDecoratableResource[] decoratableResources = DecoratableResourceHelper
+ .createDecoratableResources(resources);
+
+ // Store decoration result in session property for each resource
+ for (int i = 0; i < decoratableResources.length; i++) {
+ try {
+ if (decoratableResources[i] != null) {
+ // Store decoratable resource in session
+ resources[i].setSessionProperty(
+ DECORATABLE_RESOURCE_KEY,
+ decoratableResources[i]);
+ // Set (new) 'refreshed' timestamp
+ resources[i].setSessionProperty(REFRESHED_KEY,
+ Long.valueOf(System.currentTimeMillis()));
+ } else {
+ if (resources[i] != null)
+ handleException(
+ resources[i],
+ new CoreException(
+ Activator
+ .createErrorStatus(UIText.GitLightweightDecorator_ResourceError)));
+ }
+ } catch (CoreException e) {
+ handleException(resources[i], e);
+ }
+ }
} catch (IOException e) {
- handleException(resource, new CoreException(new Status(
- IStatus.ERROR, Activator.getPluginId(), e.getMessage(), e)));
- } catch (CoreException e) {
- handleException(resource, e);
+ exceptions
+ .handleException(new CoreException(
+ Activator
+ .createErrorStatus(
+ UIText.GitLightweightDecorator_AsynchronousDecorationError,
+ e)));
+ return;
}
+
+ // Re-trigger decoration process (in UI thread)
+ fireLabelEvent(new LabelProviderChangedEvent(this));
}
/**
diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/uitext.properties b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/uitext.properties
index c383648..5f9323d 100644
--- a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/uitext.properties
+++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/uitext.properties
@@ -958,6 +958,10 @@ GitBranchSynchronizeWizardPage_repositories=Repositories
GitBranchSynchronizeWizardPage_branches=Branches
GitBranchSynchronizeWizardPage_selectAll=Select All
GitBranchSynchronizeWizardPage_deselectAll=Deselect All
+
+GitLightweightDecorator_AsynchronousDecorationError=Asynchronous decoration requests for Git resources could not be processed
+GitLightweightDecorator_ResourceError=Resource could not be decorated
+
GitTraceConfigurationDialog_ApplyButton=&Apply
GitTraceConfigurationDialog_DefaultButton=&Default
GitTraceConfigurationDialog_DialogTitle=Maintain the Git Trace Configuration