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
next prev parent 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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).