All of lore.kernel.org
 help / color / mirror / Atom feed
From: "Tor Arne Vestbø" <torarnv@gmail.com>
To: "Shawn O. Pearce" <spearce@spearce.org>,
	Robin Rosenberg <robin.rosenberg@dewire.com>
Cc: git@vger.kernel.org
Subject: [EGIT PATCH 11/11] Implement label decorations for folders and projects
Date: Thu,  5 Feb 2009 02:00:18 +0100	[thread overview]
Message-ID: <1233795618-20249-12-git-send-email-torarnv@gmail.com> (raw)
In-Reply-To: <1233795618-20249-11-git-send-email-torarnv@gmail.com>

The option "Inspect dirty state of children..." controls
if the decoration process should look at child resources
to decide if a container is dirty or not. For large/deep
projects this can be quite time consuming.

The other option, "Also re-decorate ancestors..." controls if
parents of a re-decorated resource also should be updated, for
example to signal that the containing folder is now dirty.

Signed-off-by: Tor Arne Vestbø <torarnv@gmail.com>
---
 org.spearce.egit.ui/.options                       |    8 +-
 .../src/org/spearce/egit/ui/Activator.java         |    2 +-
 .../egit/ui/PluginPreferenceInitializer.java       |    3 +-
 .../src/org/spearce/egit/ui/UIPreferences.java     |    4 +-
 .../src/org/spearce/egit/ui/UIText.java            |    5 +-
 .../decorators/GitLightweightDecorator.java        |  344 +++++++++++++++-----
 .../preferences/GitDecoratorPreferencePage.java    |   33 ++-
 .../src/org/spearce/egit/ui/uitext.properties      |    3 +-
 8 files changed, 311 insertions(+), 91 deletions(-)

diff --git a/org.spearce.egit.ui/.options b/org.spearce.egit.ui/.options
index a084b35..8fc1c19 100644
--- a/org.spearce.egit.ui/.options
+++ b/org.spearce.egit.ui/.options
@@ -1 +1,7 @@
-org.spearce.egit.ui/trace/verbose = false
+# Debugging options for the org.spearce.egit.ui plugin.
+
+# Show general verbose output
+org.spearce.egit.ui/verbose = false
+
+# Show debug output for label decorations
+org.spearce.egit.ui/decorations = false
\ No newline at end of file
diff --git a/org.spearce.egit.ui/src/org/spearce/egit/ui/Activator.java b/org.spearce.egit.ui/src/org/spearce/egit/ui/Activator.java
index 9d03c70..45010ce 100644
--- a/org.spearce.egit.ui/src/org/spearce/egit/ui/Activator.java
+++ b/org.spearce.egit.ui/src/org/spearce/egit/ui/Activator.java
@@ -190,7 +190,7 @@ public Activator() {
 
 	public void start(final BundleContext context) throws Exception {
 		super.start(context);
-		traceVerbose = isOptionSet("/trace/verbose");
+		traceVerbose = isOptionSet("/verbose");
 		setupSSH(context);
 		setupProxy(context);
 		setupRepoChangeScanner();
diff --git a/org.spearce.egit.ui/src/org/spearce/egit/ui/PluginPreferenceInitializer.java b/org.spearce.egit.ui/src/org/spearce/egit/ui/PluginPreferenceInitializer.java
index ef886cf..9af35bc 100644
--- a/org.spearce.egit.ui/src/org/spearce/egit/ui/PluginPreferenceInitializer.java
+++ b/org.spearce.egit.ui/src/org/spearce/egit/ui/PluginPreferenceInitializer.java
@@ -35,7 +35,8 @@ public void initializeDefaultPreferences() {
 		prefs.setDefault(UIPreferences.RESOURCEHISTORY_SHOW_REV_COMMENT, true);
 		prefs.setDefault(UIPreferences.RESOURCEHISTORY_SHOW_TOOLTIPS, false);
 
-		prefs.setDefault(UIPreferences.DECORATOR_CALCULATE_DIRTY, true);
+		prefs.setDefault(UIPreferences.DECORATOR_RECOMPUTE_ANCESTORS, true);
+		prefs.setDefault(UIPreferences.DECORATOR_COMPUTE_DEEP_DIRTY, true);
 		prefs.setDefault(UIPreferences.DECORATOR_FILETEXT_DECORATION,
 				UIText.DecoratorPreferencesPage_fileFormatDefault);
 		prefs.setDefault(UIPreferences.DECORATOR_FOLDERTEXT_DECORATION,
diff --git a/org.spearce.egit.ui/src/org/spearce/egit/ui/UIPreferences.java b/org.spearce.egit.ui/src/org/spearce/egit/ui/UIPreferences.java
index 409b335..f0a5e28 100644
--- a/org.spearce.egit.ui/src/org/spearce/egit/ui/UIPreferences.java
+++ b/org.spearce.egit.ui/src/org/spearce/egit/ui/UIPreferences.java
@@ -53,7 +53,9 @@
 	public final static String THEME_CommitMessageFont = "org.spearce.egit.ui.CommitMessageFont";
 
 	/** */
-	public final static String DECORATOR_CALCULATE_DIRTY = "decorator_calculate_dirty";
+	public final static String DECORATOR_RECOMPUTE_ANCESTORS = "decorator_recompute_ancestors";
+	/** */
+	public final static String DECORATOR_COMPUTE_DEEP_DIRTY = "decorator_compute_deep_dirty";
 	/** */
 	public final static String DECORATOR_FILETEXT_DECORATION = "decorator_filetext_decoration";
 	/** */
diff --git a/org.spearce.egit.ui/src/org/spearce/egit/ui/UIText.java b/org.spearce.egit.ui/src/org/spearce/egit/ui/UIText.java
index b62ca4c..5dd28df 100644
--- a/org.spearce.egit.ui/src/org/spearce/egit/ui/UIText.java
+++ b/org.spearce.egit.ui/src/org/spearce/egit/ui/UIText.java
@@ -920,7 +920,10 @@
 	public static String DecoratorPreferencesPage_addVariablesAction;
 
 	/** */
-	public static String DecoratorPreferencesPage_computeDeep;
+	public static String DecoratorPreferencesPage_recomputeAncestorDecorations;
+
+	/** */
+	public static String DecoratorPreferencesPage_computeDeepDirtyState;
 
 	/** */
 	public static String DecoratorPreferencesPage_description;
diff --git a/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/decorators/GitLightweightDecorator.java b/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/decorators/GitLightweightDecorator.java
index 45b9f83..c72bfdb 100644
--- a/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/decorators/GitLightweightDecorator.java
+++ b/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/decorators/GitLightweightDecorator.java
@@ -31,6 +31,7 @@
 import org.eclipse.core.runtime.CoreException;
 import org.eclipse.core.runtime.IAdaptable;
 import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Platform;
 import org.eclipse.jface.preference.IPreferenceStore;
 import org.eclipse.jface.resource.ImageDescriptor;
 import org.eclipse.jface.util.IPropertyChangeListener;
@@ -48,6 +49,7 @@
 import org.eclipse.team.ui.TeamUI;
 import org.eclipse.ui.IContributorResourceAdapter;
 import org.eclipse.ui.PlatformUI;
+import org.spearce.egit.core.ContainerTreeIterator;
 import org.spearce.egit.core.GitException;
 import org.spearce.egit.core.internal.util.ExceptionCollector;
 import org.spearce.egit.core.project.GitProjectData;
@@ -61,6 +63,8 @@
 import org.spearce.jgit.dircache.DirCache;
 import org.spearce.jgit.dircache.DirCacheEntry;
 import org.spearce.jgit.dircache.DirCacheIterator;
+import org.spearce.jgit.errors.IncorrectObjectTypeException;
+import org.spearce.jgit.errors.MissingObjectException;
 import org.spearce.jgit.lib.Constants;
 import org.spearce.jgit.lib.FileMode;
 import org.spearce.jgit.lib.IndexChangedEvent;
@@ -72,7 +76,11 @@
 import org.spearce.jgit.revwalk.RevWalk;
 import org.spearce.jgit.treewalk.EmptyTreeIterator;
 import org.spearce.jgit.treewalk.TreeWalk;
+import org.spearce.jgit.treewalk.WorkingTreeIterator;
+import org.spearce.jgit.treewalk.filter.AndTreeFilter;
 import org.spearce.jgit.treewalk.filter.PathFilterGroup;
+import org.spearce.jgit.treewalk.filter.TreeFilter;
+import org.spearce.jgit.util.FS;
 
 /**
  * Supplies annotations for displayed resources
@@ -110,6 +118,34 @@
 			IStatus.ERROR, Activator.getDefault().getLog());
 
 	/**
+	 * Property constant indicating if tracing/debugging of decorations is
+	 * enabled
+	 */
+	private static boolean DEBUG_DECORATIONS = false;
+
+	static {
+		DEBUG_DECORATIONS = "true".equals(Platform.getDebugOption(Activator.getPluginId() + "/decorations")); //$NON-NLS-1$ //$NON-NLS-2$
+	}
+
+	private static void debug(String what) {
+		StackTraceElement frame = Thread.currentThread().getStackTrace()[2];
+		if (frame.getMethodName().endsWith("access$1"))
+			frame = Thread.currentThread().getStackTrace()[3];
+		String className = frame.getClassName().substring(
+				frame.getClassName().lastIndexOf('.') + 1);
+		System.out.print(className + "::" + frame.getMethodName() + "(): ");
+
+		debug(what, 0);
+	}
+
+	private static void debug(String what, int numIndents) {
+		for (int i = 0; i < numIndents; ++i)
+			System.out.print("\t");
+
+		System.out.println(what);
+	}
+
+	/**
 	 * Constructs a new Git resource decorator
 	 */
 	public GitLightweightDecorator() {
@@ -174,6 +210,9 @@ public void decorate(Object element, IDecoration decoration) {
 		if (activator == null)
 			return;
 
+		if (DEBUG_DECORATIONS)
+			debug("deocrating '" + resource.getLocation() + "'");
+
 		try {
 			DecorationHelper helper = new DecorationHelper(activator
 					.getPreferenceStore());
@@ -184,7 +223,8 @@ public void decorate(Object element, IDecoration decoration) {
 		}
 	}
 
-	private class DecoratableResourceAdapter implements IDecoratableResource {
+	private static class DecoratableResourceAdapter implements
+			IDecoratableResource {
 
 		private final IResource resource;
 
@@ -212,6 +252,111 @@ public void decorate(Object element, IDecoration decoration) {
 
 		static final int T_WORKSPACE = 2;
 
+		private static class ContainerDiffFilter extends TreeFilter {
+			static final ContainerDiffFilter INSTANCE = new ContainerDiffFilter();
+
+			@Override
+			public boolean include(final TreeWalk tw)
+					throws MissingObjectException,
+					IncorrectObjectTypeException, IOException {
+
+				if (tw.getFileMode(T_HEAD) == FileMode.MISSING
+						&& tw.getFileMode(T_INDEX) == FileMode.MISSING)
+					return false; // Untracked and unstaged, so not dirty
+
+				if (DEBUG_DECORATIONS)
+					debug("checking '" + tw.getPathString() + "'");
+
+				int mHead = tw.getRawMode(T_HEAD);
+				int mIndex = tw.getRawMode(T_INDEX);
+				int mWorkspace = tw.getRawMode(T_WORKSPACE);
+
+				if (!FS.INSTANCE.supportsExecute()) {
+					// We need to clear the executable bits of the head and
+					// index modes, to prevent false positives when the
+					// resource is +x in the repository but not on disk
+					mHead &= (~0111);
+					mIndex &= (~0111);
+				}
+
+				if (DEBUG_DECORATIONS) {
+					debug("mHead=" + Integer.toOctalString(mHead) + " mIndex="
+							+ Integer.toOctalString(mIndex) + " mWorkspace="
+							+ Integer.toOctalString(mWorkspace), 1);
+				}
+
+				if (mHead != mIndex || mHead != mWorkspace) {
+					// If all three modes aren't identical there is a difference
+					// here. Its the fastest test we have and it neatly handles
+					// weird D->F/F->D style changes that may cause issues later
+
+					if (DEBUG_DECORATIONS) {
+						debug("Modes did not match, so concider the whole "
+								+ "tree dirty", 1);
+					}
+
+					return true;
+				}
+
+				if (FileMode.TREE.equals(mHead)) {
+					// We must include trees otherwise the walker won't recurse
+					// into a subtree for us. Computing anything more about a
+					// tree is too expensive from the workspace so we do not do
+					// a prune based on no changes.
+
+					final IPreferenceStore store = Activator.getDefault()
+							.getPreferenceStore();
+					return store
+							.getBoolean(UIPreferences.DECORATOR_COMPUTE_DEEP_DIRTY);
+				}
+
+				final DirCacheIterator iIndex = tw.getTree(T_INDEX,
+						DirCacheIterator.class);
+				final WorkingTreeIterator iWorkspace = tw.getTree(T_WORKSPACE,
+						WorkingTreeIterator.class);
+
+				if (!timestampMatches(iIndex, iWorkspace)) {
+					// If the modification time of the file differs we know the
+					// folder is (possibly) dirty and should be marked as such.
+					// This is faster than the id check below so it goes first.
+
+					if (DEBUG_DECORATIONS) {
+						debug("Timestamps did not match, so concider the "
+								+ "whole tree dirty", 1);
+					}
+
+					return true;
+				}
+
+				if (!tw.idEqual(T_HEAD, T_INDEX)) {
+					// Staged id difference indicates the path is modified.
+
+					if (DEBUG_DECORATIONS) {
+						debug("File is staged, so concider the whole "
+								+ "tree dirty", 1);
+					}
+
+					return true;
+				}
+
+				// TODO: Consider doing a content check here, to rule out false
+				// positives, as we might get mismatch between timestamps, even
+				// if the content is the same
+
+				return false;
+			}
+
+			@Override
+			public boolean shouldBeRecursive() {
+				return true;
+			}
+
+			@Override
+			public TreeFilter clone() {
+				return this;
+			}
+		}
+
 		public DecoratableResourceAdapter(IResource resourceToWrap)
 				throws IOException {
 			resource = resourceToWrap;
@@ -219,25 +364,12 @@ public DecoratableResourceAdapter(IResource resourceToWrap)
 			repository = mapping.getRepository();
 			headId = repository.resolve(Constants.HEAD);
 
-			switch (resource.getType()) {
-			case IResource.FILE:
-				extractFileProperties();
-				break;
-			case IResource.FOLDER:
-				extractContainerProperties();
-				break;
-			case IResource.PROJECT:
-				extractProjectProperties();
-				break;
-			}
-		}
+			// TODO: Add option to shorten branch name to 6 chars if it's a SHA
+			branch = repository.getBranch();
 
-		private void extractFileProperties() throws IOException {
 			TreeWalk treeWalk = createHeadVsIndexTreeWalk();
-			if (treeWalk == null)
-				return;
-
-			if (treeWalk.next())
+			if (resource.getType() == IResource.PROJECT
+					|| (treeWalk != null && treeWalk.next()))
 				tracked = true;
 			else
 				return;
@@ -248,6 +380,27 @@ private void extractFileProperties() throws IOException {
 				return;
 			}
 
+			switch (resource.getType()) {
+			case IResource.FILE:
+				extractFileProperties(treeWalk);
+				break;
+
+			case IResource.FOLDER:
+				extractContainerProperties();
+				break;
+
+			case IResource.PROJECT:
+				final IPreferenceStore store = Activator.getDefault()
+						.getPreferenceStore();
+				if (!store
+						.getBoolean(UIPreferences.DECORATOR_COMPUTE_DEEP_DIRTY))
+					return;
+				extractContainerProperties();
+				break;
+			}
+		}
+
+		private void extractFileProperties(TreeWalk treeWalk) {
 			final DirCacheIterator indexIterator = treeWalk.getTree(T_INDEX,
 					DirCacheIterator.class);
 			final DirCacheEntry indexEntry = indexIterator != null ? indexIterator
@@ -265,18 +418,7 @@ private void extractFileProperties() throws IOException {
 						.getBits()) {
 					staged = Staged.ADDED;
 				} else {
-					long indexEntryLastModified = indexEntry.getLastModified();
-					long resourceLastModified = resource.getLocalTimeStamp();
-
-					// C-Git under Windows stores timestamps with 1-seconds
-					// resolution, so we need to check to see if this is the
-					// case here, and possibly fix the timestamp of the resource
-					// to match the resolution of the index.
-					if (indexEntryLastModified % 1000 == 0) {
-						resourceLastModified -= resourceLastModified % 1000;
-					}
-
-					if (resourceLastModified != indexEntryLastModified) {
+					if (!timestampMatches(indexIterator, resource)) {
 						// TODO: Consider doing a content check here, to rule
 						// out false positives, as we might get mismatch between
 						// timestamps, even if the content is the same
@@ -290,37 +432,27 @@ private void extractFileProperties() throws IOException {
 					}
 				}
 			}
-
 		}
 
 		private void extractContainerProperties() throws IOException {
 			TreeWalk treeWalk = createHeadVsIndexTreeWalk();
-			if (treeWalk == null)
-				return;
-
-			if (treeWalk.next())
-				tracked = true;
+			treeWalk.setFilter(AndTreeFilter.create(treeWalk.getFilter(),
+					ContainerDiffFilter.INSTANCE));
+			treeWalk.setRecursive(true);
+
+			if (repository.getWorkDir().equals(
+					resource.getProject().getLocation().toFile()))
+				treeWalk.addTree(new ContainerTreeIterator(resource
+						.getProject()));
 			else
-				return;
-
-			// TODO: Also read ignores from .git/info/excludes et al.
-			if (Team.isIgnoredHint(resource)) {
-				ignored = true;
-				return;
-			}
-
-			// TODO: Compute dirty state for folder, using ContainerTreeIterator
-			// and ContainerDiffFilter
-
-		}
-
-		private void extractProjectProperties() throws IOException {
-			branch = repository.getBranch();
-			tracked = true;
-
-			// TODO: Compute dirty state for folder, using ContainerTreeIterator
-			// and ContainerDiffFilter
+				treeWalk.addTree(new ContainerTreeIterator(resource
+						.getWorkspace().getRoot()));
 
+			// TODO: Add fallback for projects with the repository more than
+			// one parent up, for example by using a stack of DummyIterators
+			
+			if (treeWalk.next())
+				dirty = true;
 		}
 
 		/**
@@ -328,9 +460,10 @@ private void extractProjectProperties() throws IOException {
 		 * those matching the resource specified by
 		 * <code>resourceToFilterBy</code>
 		 * <p>
-		 * If the resource does not exists in the current repository, or it has
-		 * an empty path (it is the project itself), the filter is not added,
-		 * and the method returns <code>null</code>.
+		 * If the resource does not exists in the current repository, no filter
+		 * is added and the method returns <code>false</code>. If the resource
+		 * is a project, no filter is added, but the operation is considered a
+		 * success.
 		 * 
 		 * @param treeWalk
 		 *            the tree walk to add the filter to
@@ -344,9 +477,12 @@ private boolean addResourceFilter(final TreeWalk treeWalk,
 				final IResource resourceToFilterBy) {
 			Set<String> repositoryPaths = Collections.singleton(mapping
 					.getRepoRelativePath(resourceToFilterBy));
-			if (repositoryPaths.isEmpty() || repositoryPaths.contains(""))
+			if (repositoryPaths.isEmpty())
 				return false;
 
+			if (repositoryPaths.contains(""))
+				return true; // Project filter
+
 			treeWalk.setFilter(PathFilterGroup
 					.createFromStrings(repositoryPaths));
 			return true;
@@ -376,6 +512,31 @@ private TreeWalk createHeadVsIndexTreeWalk() throws IOException {
 			return treeWalk;
 		}
 
+		private static boolean timestampMatches(DirCacheIterator index,
+				IResource workspaceResource) {
+			return timestampMatches(index.getDirCacheEntry().getLastModified(),
+					workspaceResource.getLocalTimeStamp());
+		}
+
+		private static boolean timestampMatches(DirCacheIterator index,
+				WorkingTreeIterator workspaceResource) {
+			return timestampMatches(index.getDirCacheEntry().getLastModified(),
+					workspaceResource.getEntryLastModified());
+		}
+
+		private static boolean timestampMatches(long index,
+				long workspaceResource) {
+			// C-Git under Windows stores timestamps with 1-seconds resolution,
+			// so we need to check to see if this is the case here, and possibly
+			// fix the timestamp of the resource to match the resolution of the
+			// index.
+			if (index % 1000 == 0) {
+				return index == (workspaceResource - (workspaceResource % 1000));
+			} else {
+				return index == workspaceResource;
+			}
+		}
+
 		public String getName() {
 			return resource.getName();
 		}
@@ -555,11 +716,13 @@ else if (staged == Staged.REMOVED)
 				}
 
 				// Conflicts override everything
-				if (store.getBoolean(UIPreferences.DECORATOR_SHOW_CONFLICTS_ICON)
+				if (store
+						.getBoolean(UIPreferences.DECORATOR_SHOW_CONFLICTS_ICON)
 						&& resource.hasConflicts())
 					overlay = conflictImage;
 
-			} else if (store.getBoolean(UIPreferences.DECORATOR_SHOW_UNTRACKED_ICON)) {
+			} else if (store
+					.getBoolean(UIPreferences.DECORATOR_SHOW_UNTRACKED_ICON)) {
 				overlay = untrackedImage;
 			}
 
@@ -657,6 +820,9 @@ public static void decorate(IDecoration decoration, String format,
 	 * Perform a blanket refresh of all decorations
 	 */
 	public static void refresh() {
+		if (DEBUG_DECORATIONS)
+			debug("blanket refesh");
+
 		Display.getDefault().asyncExec(new Runnable() {
 			public void run() {
 				Activator.getDefault().getWorkbench().getDecoratorManager()
@@ -679,6 +845,9 @@ public void propertyChange(PropertyChangeEvent event) {
 		if (prop.equals(TeamUI.GLOBAL_IGNORES_CHANGED)
 				|| prop.equals(TeamUI.GLOBAL_FILE_TYPES_CHANGED)
 				|| prop.equals(Activator.DECORATORS_CHANGED)) {
+			if (DEBUG_DECORATIONS)
+				debug("property=" + prop);
+
 			postLabelEvent(new LabelProviderChangedEvent(this));
 		}
 	}
@@ -696,9 +865,20 @@ public void propertyChange(PropertyChangeEvent event) {
 	public void resourceChanged(IResourceChangeEvent event) {
 		final Set<IResource> resourcesToUpdate = new HashSet<IResource>();
 
+		if (DEBUG_DECORATIONS)
+			debug("IResourceChangeEvent");
+
 		try { // Compute the changed resources by looking at the delta
 			event.getDelta().accept(new IResourceDeltaVisitor() {
 				public boolean visit(IResourceDelta delta) throws CoreException {
+
+					// If the file has changed but not in a way that we care
+					// about (e.g. marker changes to files) then ignore
+					if (delta.getKind() == IResourceDelta.CHANGED
+							&& (delta.getFlags() & INTERESTING_CHANGES) == 0) {
+						return true;
+					}
+
 					final IResource resource = delta.getResource();
 
 					// If the resource is not part of a project under Git
@@ -709,6 +889,11 @@ public boolean visit(IResourceDelta delta) throws CoreException {
 						// Ignore the change
 						return true;
 					}
+
+					if (DEBUG_DECORATIONS)
+						debug("Git resource: "
+								+ resource.getLocation().toString(), 1);
+
 					if (resource.getType() == IResource.ROOT) {
 						// Continue with the delta
 						return true;
@@ -720,16 +905,10 @@ public boolean visit(IResourceDelta delta) throws CoreException {
 							return false;
 					}
 
-					// If the file has changed but not in a way that we care
-					// about
-					// (e.g. marker changes to files) then ignore the change
-					if (delta.getKind() == IResourceDelta.CHANGED
-							&& (delta.getFlags() & INTERESTING_CHANGES) == 0) {
-						return true;
-					}
-
 					// All seems good, schedule the resource for update
 					resourcesToUpdate.add(resource);
+					if (DEBUG_DECORATIONS)
+						debug("Will update this resource", 2);
 					return true;
 				}
 			}, true /* includePhantoms */);
@@ -737,19 +916,25 @@ public boolean visit(IResourceDelta delta) throws CoreException {
 			handleException(null, e);
 		}
 
-		// If deep decorator calculation is enabled in the preferences we
-		// walk the ancestor tree of each of the changed resources and add
+		if (resourcesToUpdate.isEmpty())
+			return;
+
+		// If ancestor-decoration is enabled in the preferences we walk
+		// the ancestor tree of each of the changed resources and add
 		// their parents to the update set
 		final IPreferenceStore store = Activator.getDefault()
 				.getPreferenceStore();
-		if (store.getBoolean(UIPreferences.DECORATOR_CALCULATE_DIRTY)) {
+		if (store.getBoolean(UIPreferences.DECORATOR_RECOMPUTE_ANCESTORS)) {
+			if (DEBUG_DECORATIONS)
+				debug("Calulcating dirty ancestor..", 1);
+
 			final IResource[] changedResources = resourcesToUpdate
 					.toArray(new IResource[resourcesToUpdate.size()]);
-			for (int i = 0; i < changedResources.length; i++) {
-				IResource current = changedResources[i];
+			for (IResource current : changedResources) {
 				while (current.getType() != IResource.ROOT) {
 					current = current.getParent();
-					resourcesToUpdate.add(current);
+					if (resourcesToUpdate.add(current) && DEBUG_DECORATIONS)
+						debug("Will also update " + current.getLocation(), 2);
 				}
 			}
 		}
@@ -768,6 +953,9 @@ postLabelEvent(new LabelProviderChangedEvent(this, resourcesToUpdate
 	 *            The original change event
 	 */
 	private void repositoryChanged(RepositoryChangedEvent e) {
+		if (DEBUG_DECORATIONS)
+			debug("RepositoryChangedEvent=" + e.getRepository().getWorkDir());
+
 		final Set<RepositoryMapping> ms = new HashSet<RepositoryMapping>();
 		for (final IProject p : ResourcesPlugin.getWorkspace().getRoot()
 				.getProjects()) {
@@ -809,6 +997,9 @@ public void refsChanged(RefsChangedEvent e) {
 	 * @see org.spearce.egit.core.project.RepositoryChangeListener#repositoryChanged(org.spearce.egit.core.project.RepositoryMapping)
 	 */
 	public void repositoryChanged(RepositoryMapping mapping) {
+		if (DEBUG_DECORATIONS)
+			debug("RepositoryMapping=" + mapping.getWorkDir());
+
 		// Until we find a way to refresh visible labels within a project
 		// we have to use this blanket refresh that includes all projects.
 		postLabelEvent(new LabelProviderChangedEvent(this));
@@ -845,6 +1036,9 @@ private static IResource getResource(Object element) {
 	 *            The event to post
 	 */
 	private void postLabelEvent(final LabelProviderChangedEvent event) {
+		if (DEBUG_DECORATIONS)
+			debug("event=" + event.getElements());
+
 		Display.getDefault().asyncExec(new Runnable() {
 			public void run() {
 				fireLabelProviderChanged(event);
diff --git a/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/preferences/GitDecoratorPreferencePage.java b/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/preferences/GitDecoratorPreferencePage.java
index 74bc209..1a13a15 100644
--- a/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/preferences/GitDecoratorPreferencePage.java
+++ b/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/preferences/GitDecoratorPreferencePage.java
@@ -89,7 +89,9 @@
 
 	private Text projectTextFormat;
 
-	private Button computeDeepDirtyState;
+	private Button recomputeAncestorDecorations;
+
+	private Button computeDeepDirtyStateForContainers;
 
 	private Button showTracked;
 
@@ -204,8 +206,10 @@ private Control createGeneralDecoratorPage(Composite parent) {
 		data.horizontalAlignment = GridData.FILL;
 		composite.setLayoutData(data);
 
-		computeDeepDirtyState = SWTUtils.createCheckBox(composite,
-				UIText.DecoratorPreferencesPage_computeDeep);
+		recomputeAncestorDecorations = SWTUtils.createCheckBox(composite,
+				UIText.DecoratorPreferencesPage_recomputeAncestorDecorations);
+		computeDeepDirtyStateForContainers = SWTUtils.createCheckBox(composite,
+				UIText.DecoratorPreferencesPage_computeDeepDirtyState);
 
 		return composite;
 	}
@@ -317,8 +321,10 @@ public void handleEvent(Event event) {
 	private void initializeValues() {
 		final IPreferenceStore store = getPreferenceStore();
 
-		computeDeepDirtyState.setSelection(store
-				.getBoolean(UIPreferences.DECORATOR_CALCULATE_DIRTY));
+		recomputeAncestorDecorations.setSelection(store
+				.getBoolean(UIPreferences.DECORATOR_RECOMPUTE_ANCESTORS));
+		computeDeepDirtyStateForContainers.setSelection(store
+				.getBoolean(UIPreferences.DECORATOR_COMPUTE_DEEP_DIRTY));
 
 		fileTextFormat.setText(store
 				.getString(UIPreferences.DECORATOR_FILETEXT_DECORATION));
@@ -342,7 +348,9 @@ public void widgetSelected(SelectionEvent e) {
 			}
 		};
 
-		computeDeepDirtyState.addSelectionListener(selectionListener);
+		recomputeAncestorDecorations.addSelectionListener(selectionListener);
+		computeDeepDirtyStateForContainers
+				.addSelectionListener(selectionListener);
 		showTracked.addSelectionListener(selectionListener);
 		showUntracked.addSelectionListener(selectionListener);
 		showStaged.addSelectionListener(selectionListener);
@@ -384,8 +392,10 @@ public boolean performOk() {
 	 */
 	private boolean performOk(IPreferenceStore store) {
 
-		store.setValue(UIPreferences.DECORATOR_CALCULATE_DIRTY,
-				computeDeepDirtyState.getSelection());
+		store.setValue(UIPreferences.DECORATOR_RECOMPUTE_ANCESTORS,
+				recomputeAncestorDecorations.getSelection());
+		store.setValue(UIPreferences.DECORATOR_COMPUTE_DEEP_DIRTY,
+				computeDeepDirtyStateForContainers.getSelection());
 
 		store.setValue(UIPreferences.DECORATOR_FILETEXT_DECORATION,
 				fileTextFormat.getText());
@@ -414,8 +424,11 @@ protected void performDefaults() {
 		super.performDefaults();
 		IPreferenceStore store = getPreferenceStore();
 
-		computeDeepDirtyState.setSelection(store
-				.getDefaultBoolean(UIPreferences.DECORATOR_CALCULATE_DIRTY));
+		recomputeAncestorDecorations
+				.setSelection(store
+						.getDefaultBoolean(UIPreferences.DECORATOR_RECOMPUTE_ANCESTORS));
+		computeDeepDirtyStateForContainers.setSelection(store
+				.getDefaultBoolean(UIPreferences.DECORATOR_COMPUTE_DEEP_DIRTY));
 
 		fileTextFormat.setText(store
 				.getDefaultString(UIPreferences.DECORATOR_FILETEXT_DECORATION));
diff --git a/org.spearce.egit.ui/src/org/spearce/egit/ui/uitext.properties b/org.spearce.egit.ui/src/org/spearce/egit/ui/uitext.properties
index 2762d11..770de4a 100644
--- a/org.spearce.egit.ui/src/org/spearce/egit/ui/uitext.properties
+++ b/org.spearce.egit.ui/src/org/spearce/egit/ui/uitext.properties
@@ -344,7 +344,8 @@ Decorator_exceptionMessage=Errors occurred while applying Git decorations to res
 
 DecoratorPreferencesPage_addVariablesTitle=Add Variables
 DecoratorPreferencesPage_addVariablesAction=Add &Variables...
-DecoratorPreferencesPage_computeDeep=Include &ancestors when re-decorating changed resources
+DecoratorPreferencesPage_recomputeAncestorDecorations=Also re-decorate &ancestors when decorating changed resources
+DecoratorPreferencesPage_computeDeepDirtyState=Inspect dirty state of &children when decorating folders and projects
 DecoratorPreferencesPage_description=Shows Git specific information on resources in projects under version control.
 
 DecoratorPreferencesPage_decorationSettings=Decoration &settings:
-- 
1.6.1.2.309.g2ea3

  reply	other threads:[~2009-02-05  1:07 UTC|newest]

Thread overview: 31+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2009-02-05  1:00 [EGIT PATCH 00/11] Support customizable label decorations Tor Arne Vestbø
2009-02-05  1:00 ` [EGIT PATCH 01/11] Add support code to handle plugin property changes Tor Arne Vestbø
2009-02-05  1:00   ` [EGIT PATCH 02/11] Use Set instead of array to keep track of change listeners Tor Arne Vestbø
2009-02-05  1:00     ` [EGIT PATCH 03/11] Add a specialized team exception for Git Tor Arne Vestbø
2009-02-05  1:00       ` [EGIT PATCH 04/11] Add new class ExceptionCollector for grouping exceptions Tor Arne Vestbø
2009-02-05  1:00         ` [EGIT PATCH 05/11] Add new class SWTUtils with helper-methods for creating controls Tor Arne Vestbø
2009-02-05  1:00           ` [EGIT PATCH 06/11] Implement basic customizable label decorations with preferences Tor Arne Vestbø
2009-02-05  1:00             ` [EGIT PATCH 07/11] Add binding for name of the current branch Tor Arne Vestbø
2009-02-05  1:00               ` [EGIT PATCH 08/11] Add icon decoration for tracked and untracked resources Tor Arne Vestbø
2009-02-05  1:00                 ` [EGIT PATCH 09/11] Implement decorations of dirty, staged, and conflicting resources Tor Arne Vestbø
2009-02-05  1:00                   ` [EGIT PATCH 10/11] Don't decorate every single resource on repository change Tor Arne Vestbø
2009-02-05  1:00                     ` Tor Arne Vestbø [this message]
2009-02-05 20:02             ` [EGIT PATCH 06/11] Implement basic customizable label decorations with preferences Robin Rosenberg
2009-02-05 20:21               ` Tor Arne Vestbø
2009-02-05 21:00                 ` Tor Arne Vestbø
2009-02-05 21:36                   ` Robin Rosenberg
2009-02-05 21:44                     ` Tor Arne Vestbø
2009-02-05 20:04             ` Robin Rosenberg
2009-02-05 15:48     ` [EGIT PATCH 02/11] Use Set instead of array to keep track of change listeners Shawn O. Pearce
2009-02-05 16:36       ` Tor Arne Vestbø
2009-02-05 18:28         ` [EGIT PATCH 02/11 v2] " Tor Arne Vestbø
2009-02-05 15:53   ` [EGIT PATCH 01/11] Add support code to handle plugin property changes Shawn O. Pearce
2009-02-05 16:35     ` Tor Arne Vestbø
2009-02-05 16:40       ` Shawn O. Pearce
2009-02-05 18:22         ` [EGIT PATCH v2] " Tor Arne Vestbø
2009-02-05  1:04 ` [EGIT PATCH 00/11] Support customizable label decorations Tor Arne Vestbø
2009-02-05 16:06 ` Shawn O. Pearce
2009-02-05 16:17   ` Tor Arne Vestbø
2009-02-05 18:32   ` Robin Rosenberg
2009-02-05 18:37     ` Tor Arne Vestbø
2009-02-05 22:09       ` Robin Rosenberg

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1233795618-20249-12-git-send-email-torarnv@gmail.com \
    --to=torarnv@gmail.com \
    --cc=git@vger.kernel.org \
    --cc=robin.rosenberg@dewire.com \
    --cc=spearce@spearce.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.