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 09/11] Implement decorations of dirty, staged, and conflicting resources
Date: Thu, 5 Feb 2009 02:00:16 +0100 [thread overview]
Message-ID: <1233795618-20249-10-git-send-email-torarnv@gmail.com> (raw)
In-Reply-To: <1233795618-20249-9-git-send-email-torarnv@gmail.com>
Signed-off-by: Tor Arne Vestbø <torarnv@gmail.com>
---
org.spearce.egit.ui/icons/ovr/assumevalid.gif | Bin 64 -> 0 bytes
org.spearce.egit.ui/icons/ovr/conflict.gif | Bin 64 -> 164 bytes
org.spearce.egit.ui/icons/ovr/pending_add.gif | Bin 64 -> 0 bytes
org.spearce.egit.ui/icons/ovr/pending_remove.gif | Bin 111 -> 0 bytes
org.spearce.egit.ui/icons/ovr/staged.gif | Bin 0 -> 114 bytes
org.spearce.egit.ui/icons/ovr/staged_added.gif | Bin 0 -> 114 bytes
org.spearce.egit.ui/icons/ovr/staged_removed.gif | Bin 0 -> 114 bytes
.../egit/ui/PluginPreferenceInitializer.java | 2 +
.../src/org/spearce/egit/ui/UIIcons.java | 13 +-
.../src/org/spearce/egit/ui/UIPreferences.java | 4 +
.../src/org/spearce/egit/ui/UIText.java | 14 +-
.../decorators/GitLightweightDecorator.java | 284 ++++++++++++++++----
.../internal/decorators/IDecoratableResource.java | 39 +++
.../preferences/GitDecoratorPreferencePage.java | 131 ++++++++--
.../src/org/spearce/egit/ui/uitext.properties | 14 +-
15 files changed, 427 insertions(+), 74 deletions(-)
delete mode 100644 org.spearce.egit.ui/icons/ovr/assumevalid.gif
delete mode 100644 org.spearce.egit.ui/icons/ovr/pending_add.gif
delete mode 100644 org.spearce.egit.ui/icons/ovr/pending_remove.gif
create mode 100644 org.spearce.egit.ui/icons/ovr/staged.gif
create mode 100644 org.spearce.egit.ui/icons/ovr/staged_added.gif
create mode 100644 org.spearce.egit.ui/icons/ovr/staged_removed.gif
diff --git a/org.spearce.egit.ui/icons/ovr/assumevalid.gif b/org.spearce.egit.ui/icons/ovr/assumevalid.gif
deleted file mode 100644
index c7262ed4e3f9437a51806f70fbc851e3a6f951d3..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001
literal 64
zcmZ?wbhEHbWM|-D_{abP{~H+o{|7M?f3h$#FfcRdfH)v|1}4Ed_6CP$GF;`pupzry
Lj9oc|fx#L8z0(dE
diff --git a/org.spearce.egit.ui/icons/ovr/conflict.gif b/org.spearce.egit.ui/icons/ovr/conflict.gif
index b444be94a2d09561b212138b1514d5c07610cc07..186345711bb5443b440c4265fe62b099cce5def0 100644
GIT binary patch
literal 164
zcmZ?wbhEHbWM|-DIKseS;8EwAJi|S8rcc&9znlfG$<y4^W_f1J^~{*<m%Cuej;o77
z=*sb{&yHVx`snqS|6ssCG*JA>!pOiN$e;t#0kV^URWU)OPmsZ3MW&ETlG9;j{ud8T
Wc$>JmHcJQuD+C104Qdczum%A1Q!l9i
literal 64
zcmZ?wbhEHbWM|-D_{hM}z`*dI0SXj<vM@3*Ffr(W_#k-(Cc!EF3&kHON*Qck_+rIG
KhIgS14AuZ~{td7I
diff --git a/org.spearce.egit.ui/icons/ovr/pending_add.gif b/org.spearce.egit.ui/icons/ovr/pending_add.gif
deleted file mode 100644
index f2306024b2872e50db4143a790bca93189ef8d5f..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001
literal 64
zcmZ?wbhEHbWM|-Dn8?6je1?HxCd2>#{}~t<6o0a?iZC!S=m6OaAbAER!723%B?Oj5
R<v1{ie-xgi8_2+54FJ_W4pRUC
diff --git a/org.spearce.egit.ui/icons/ovr/pending_remove.gif b/org.spearce.egit.ui/icons/ovr/pending_remove.gif
deleted file mode 100644
index 4ecce038e66f904af8345f88c2c007706a4bc3d0..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001
literal 111
zcmZ?wbhEHbWM|-D*v!E2;Qr&bwzj&uy5i#Ew6wIy$jG3eAU{99|Ns9pU;~OjSy)AY
sT6I8@ATt<PWC|uQx@~OiE8rFvPw;68lw@ATcdKBBRM#03Aw~vk0Ht*t9{>OV
diff --git a/org.spearce.egit.ui/icons/ovr/staged.gif b/org.spearce.egit.ui/icons/ovr/staged.gif
new file mode 100644
index 0000000000000000000000000000000000000000..dc0b8c01673b32fde0f9b11c8302ad1ca0a1e902
GIT binary patch
literal 114
zcmZ?wbhEHb<Y3@n*v!E2>(@D15q3p!E=^fpC2=k-SzZ$rK|38WV-+D!6DfNgu|P{%
zPh+VN3xogv|1&T!DE?$&WMJT9&;hc6CU7t?u*hFHX*qrG>5bPI{QDmDwl|kFq+1-m
RA=-DKlJ_A?g`5k6H30u&A6)<d
literal 0
HcmV?d00001
diff --git a/org.spearce.egit.ui/icons/ovr/staged_added.gif b/org.spearce.egit.ui/icons/ovr/staged_added.gif
new file mode 100644
index 0000000000000000000000000000000000000000..f2b87e274667c441897d0853e6a437ba5487f51c
GIT binary patch
literal 114
zcmZ?wbhEHb<Y3@n*v!E2>(@D15q3p!E=^fpC2=k-SzZ$rK|38WV-+D!6DfNgu|P{%
zPh+VN3xogv|1&T!DE?$&WMJT9&;hc6CU7t?u*hFHX*qrG>5bPI{QC}7o_(m`FiYy3
RK~byn9^Qv66>=^N)&TbU9;*NV
literal 0
HcmV?d00001
diff --git a/org.spearce.egit.ui/icons/ovr/staged_removed.gif b/org.spearce.egit.ui/icons/ovr/staged_removed.gif
new file mode 100644
index 0000000000000000000000000000000000000000..b6b4911d9eba72838d54fbcf6109eaf3836bf0db
GIT binary patch
literal 114
zcmZ?wbhEHb<Y3@n*v!E2>(@D15q3p!E=^fpC2=k-SzZ$rK|38WV-+D!6DfNgu|P{%
zPh+VN3xogv|1&T!DE?$&WMJT9&;hc6CU7t?u*hFHX*qrG>5bPI{QC~|wl_0qWLX?O
RA=-DKlJ_A?g`5k6H304c9%KLj
literal 0
HcmV?d00001
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 7465444..ef886cf 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
@@ -44,6 +44,8 @@ public void initializeDefaultPreferences() {
UIText.DecoratorPreferencesPage_projectFormatDefault);
prefs.setDefault(UIPreferences.DECORATOR_SHOW_TRACKED_ICON, true);
prefs.setDefault(UIPreferences.DECORATOR_SHOW_UNTRACKED_ICON, true);
+ prefs.setDefault(UIPreferences.DECORATOR_SHOW_STAGED_ICON, true);
+ prefs.setDefault(UIPreferences.DECORATOR_SHOW_CONFLICTS_ICON, true);
w = new int[] { 500, 500 };
UIPreferences.setDefault(prefs,
diff --git a/org.spearce.egit.ui/src/org/spearce/egit/ui/UIIcons.java b/org.spearce.egit.ui/src/org/spearce/egit/ui/UIIcons.java
index 0cead29..302637e 100644
--- a/org.spearce.egit.ui/src/org/spearce/egit/ui/UIIcons.java
+++ b/org.spearce.egit.ui/src/org/spearce/egit/ui/UIIcons.java
@@ -18,11 +18,15 @@
* Icons for the the Eclipse plugin. Mostly decorations.
*/
public class UIIcons {
+
+ /** Decoration for resource in the index but not yet committed. */
+ public static final ImageDescriptor OVR_STAGED;
+
/** Decoration for resource added to index but not yet committed. */
- public static final ImageDescriptor OVR_PENDING_ADD;
+ public static final ImageDescriptor OVR_STAGED_ADD;
/** Decoration for resource removed from the index but not commit. */
- public static final ImageDescriptor OVR_PENDING_REMOVE;
+ public static final ImageDescriptor OVR_STAGED_REMOVE;
/** Decoration for resource not being tracked by Git */
public static final ImageDescriptor OVR_UNTRACKED;
@@ -75,8 +79,9 @@
static {
base = init();
- OVR_PENDING_ADD = map("ovr/pending_add.gif");
- OVR_PENDING_REMOVE = map("ovr/pending_remove.gif");
+ OVR_STAGED = map("ovr/staged.gif");
+ OVR_STAGED_ADD = map("ovr/staged_added.gif");
+ OVR_STAGED_REMOVE = map("ovr/staged_removed.gif");
OVR_UNTRACKED = map("ovr/untracked.gif");
OVR_CONFLICT = map("ovr/conflict.gif");
OVR_ASSUMEVALID = map("ovr/assumevalid.gif");
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 7916cea..409b335 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
@@ -64,6 +64,10 @@
public final static String DECORATOR_SHOW_TRACKED_ICON = "decorator_show_tracked_icon";
/** */
public final static String DECORATOR_SHOW_UNTRACKED_ICON = "decorator_show_untracked_icon";
+ /** */
+ public final static String DECORATOR_SHOW_STAGED_ICON = "decorator_show_staged_icon";
+ /** */
+ public final static String DECORATOR_SHOW_CONFLICTS_ICON = "decorator_show_conflicts_icon";
/**
* Get the preference values associated with a fixed integer array.
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 fe62d0a..b62ca4c 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
@@ -953,12 +953,18 @@
public static String DecoratorPreferencesPage_generalTabFolder;
/** */
- public static String DecoratorPreferencesPage_nameResourceVariable;
+ public static String DecoratorPreferencesPage_bindingResourceName;
/** */
public static String DecoratorPreferencesPage_bindingBranchName;
/** */
+ public static String DecoratorPreferencesPage_bindingDirtyFlag;
+
+ /** */
+ public static String DecoratorPreferencesPage_bindingStagedFlag;
+
+ /** */
public static String DecoratorPreferencesPage_selectFormats;
/** */
@@ -979,6 +985,12 @@
/** */
public static String DecoratorPreferencesPage_iconsShowUntracked;
+ /** */
+ public static String DecoratorPreferencesPage_iconsShowStaged;
+
+ /** */
+ public static String DecoratorPreferencesPage_iconsShowConflicts;
+
static {
initializeMessages(UIText.class.getPackage().getName() + ".uitext",
UIText.class);
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 b20070a..aa6a261 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
@@ -60,9 +60,12 @@
import org.spearce.egit.ui.UIIcons;
import org.spearce.egit.ui.UIPreferences;
import org.spearce.egit.ui.UIText;
+import org.spearce.egit.ui.internal.decorators.IDecoratableResource.Staged;
import org.spearce.jgit.dircache.DirCache;
+import org.spearce.jgit.dircache.DirCacheEntry;
import org.spearce.jgit.dircache.DirCacheIterator;
import org.spearce.jgit.lib.Constants;
+import org.spearce.jgit.lib.FileMode;
import org.spearce.jgit.lib.IndexChangedEvent;
import org.spearce.jgit.lib.ObjectId;
import org.spearce.jgit.lib.RefsChangedEvent;
@@ -200,6 +203,18 @@ public void decorate(Object element, IDecoration decoration) {
private boolean ignored = false;
+ private boolean dirty = false;
+
+ private boolean conflicts = false;
+
+ private Staged staged = Staged.NOT_STAGED;
+
+ static final int T_HEAD = 0;
+
+ static final int T_INDEX = 1;
+
+ static final int T_WORKSPACE = 2;
+
public DecoratableResourceAdapter(IResource resourceToWrap)
throws IOException {
resource = resourceToWrap;
@@ -207,59 +222,161 @@ public DecoratableResourceAdapter(IResource resourceToWrap)
repository = mapping.getRepository();
headId = repository.resolve(Constants.HEAD);
- initializeValues();
+ switch (resource.getType()) {
+ case IResource.FILE:
+ extractFileProperties();
+ break;
+ case IResource.FOLDER:
+ extractContainerProperties();
+ break;
+ case IResource.PROJECT:
+ extractProjectProperties();
+ break;
+ }
}
- /**
- * Initialize the various values that are used for making decoration
- * decisions later on.
- *
- * We might as well pre-load these now, instead of using lazy
- * initialization, because they are all read by the decorator when
- * building variable bindings and computing the preferred overlay.
- *
- * @throws IOException
- */
- private void initializeValues() throws IOException {
-
- // Resolve current branch
- branch = repository.getBranch();
+ private void extractFileProperties() throws IOException {
+ TreeWalk treeWalk = createHeadVsIndexTreeWalk();
+ if (treeWalk == null)
+ return;
- // Resolve tracked state
- if (getType() == IResource.PROJECT) {
+ if (treeWalk.next())
tracked = true;
+ else
+ return;
+
+ // TODO: Also read ignores from .git/info/excludes et al.
+ if (Team.isIgnoredHint(resource)) {
+ ignored = true;
+ return;
+ }
+
+ final DirCacheIterator indexIterator = treeWalk.getTree(T_INDEX,
+ DirCacheIterator.class);
+ final DirCacheEntry indexEntry = indexIterator != null ? indexIterator
+ .getDirCacheEntry()
+ : null;
+
+ if (indexEntry == null) {
+ staged = Staged.REMOVED;
} else {
- final TreeWalk treeWalk = new TreeWalk(repository);
-
- Set<String> repositoryPaths = Collections.singleton(mapping
- .getRepoRelativePath(resource));
- if (!(repositoryPaths.isEmpty() || repositoryPaths.contains(""))) {
- treeWalk.setFilter(PathFilterGroup
- .createFromStrings(repositoryPaths));
- treeWalk.setRecursive(treeWalk.getFilter()
- .shouldBeRecursive());
- treeWalk.reset();
-
- if (headId != null)
- treeWalk.addTree(new RevWalk(repository)
- .parseTree(headId));
- else
- treeWalk.addTree(new EmptyTreeIterator());
+ if (indexEntry.isAssumeValid()) {
+ dirty = false;
+ } else if (indexEntry.getStage() > 0) {
+ conflicts = true;
+ } else if (treeWalk.getRawMode(T_HEAD) == FileMode.MISSING
+ .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) {
+ // 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
+ dirty = true;
+ }
- treeWalk.addTree(new DirCacheIterator(DirCache
- .read(repository)));
- if (treeWalk.next()) {
- tracked = true;
+ if (treeWalk.getRawMode(T_HEAD) != treeWalk
+ .getRawMode(T_INDEX)
+ || !treeWalk.idEqual(T_HEAD, T_INDEX)) {
+ staged = Staged.MODIFIED;
}
}
}
- // Resolve ignored state (currently only reads the global Eclipse
- // ignores)
+ }
+
+ private void extractContainerProperties() throws IOException {
+ TreeWalk treeWalk = createHeadVsIndexTreeWalk();
+ if (treeWalk == null)
+ return;
+
+ if (treeWalk.next())
+ tracked = true;
+ 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
+
+ }
+
+ /**
+ * Adds a filter to the specified tree walk limiting the results to only
+ * 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>.
+ *
+ * @param treeWalk
+ * the tree walk to add the filter to
+ * @param resourceToFilterBy
+ * the resource to filter by
+ *
+ * @return <code>true</code> if the filter could be added,
+ * <code>false</code> otherwise
+ */
+ private boolean addResourceFilter(final TreeWalk treeWalk,
+ final IResource resourceToFilterBy) {
+ Set<String> repositoryPaths = Collections.singleton(mapping
+ .getRepoRelativePath(resourceToFilterBy));
+ if (repositoryPaths.isEmpty() || repositoryPaths.contains(""))
+ return false;
+
+ treeWalk.setFilter(PathFilterGroup
+ .createFromStrings(repositoryPaths));
+ return true;
+ }
+
+ /**
+ * Helper method to create a new tree walk between HEAD and the index.
+ *
+ * @return the created tree walk, or null if it could not be created
+ * @throws IOException
+ * if there were errors when creating the tree walk
+ */
+ private TreeWalk createHeadVsIndexTreeWalk() throws IOException {
+ final TreeWalk treeWalk = new TreeWalk(repository);
+ if (!addResourceFilter(treeWalk, resource))
+ return null;
+
+ treeWalk.setRecursive(treeWalk.getFilter().shouldBeRecursive());
+ treeWalk.reset();
+
+ if (headId != null)
+ treeWalk.addTree(new RevWalk(repository).parseTree(headId));
+ else
+ treeWalk.addTree(new EmptyTreeIterator());
+
+ treeWalk.addTree(new DirCacheIterator(DirCache.read(repository)));
+ return treeWalk;
}
public String getName() {
@@ -281,6 +398,18 @@ public boolean isTracked() {
public boolean isIgnored() {
return ignored;
}
+
+ public boolean isDirty() {
+ return dirty;
+ }
+
+ public Staged staged() {
+ return staged;
+ }
+
+ public boolean hasConflicts() {
+ return conflicts;
+ }
}
/**
@@ -298,6 +427,12 @@ public boolean isIgnored() {
/** */
public static final String BINDING_BRANCH_NAME = "branch"; //$NON-NLS-1$
+ /** */
+ public static final String BINDING_DIRTY_FLAG = "dirty"; //$NON-NLS-1$
+
+ /** */
+ public static final String BINDING_STAGED_FLAG = "staged"; //$NON-NLS-1$
+
private IPreferenceStore store;
/**
@@ -325,10 +460,23 @@ public ImageData getImageData() {
private static ImageDescriptor untrackedImage;
+ private static ImageDescriptor stagedImage;
+
+ private static ImageDescriptor stagedAddedImage;
+
+ private static ImageDescriptor stagedRemovedImage;
+
+ private static ImageDescriptor conflictImage;
+
static {
trackedImage = new CachedImageDescriptor(TeamImages
.getImageDescriptor(ISharedImages.IMG_CHECKEDIN_OVR));
untrackedImage = new CachedImageDescriptor(UIIcons.OVR_UNTRACKED);
+ stagedImage = new CachedImageDescriptor(UIIcons.OVR_STAGED);
+ stagedAddedImage = new CachedImageDescriptor(UIIcons.OVR_STAGED_ADD);
+ stagedRemovedImage = new CachedImageDescriptor(
+ UIIcons.OVR_STAGED_REMOVE);
+ conflictImage = new CachedImageDescriptor(UIIcons.OVR_CONFLICT);
}
/**
@@ -354,6 +502,9 @@ public DecorationHelper(IPreferenceStore preferencesStore) {
*/
public void decorate(IDecoration decoration,
IDecoratableResource resource) {
+ if (resource.isIgnored())
+ return;
+
decorateText(decoration, resource);
decorateIcons(decoration, resource);
}
@@ -379,22 +530,44 @@ private void decorateText(IDecoration decoration,
Map<String, String> bindings = new HashMap<String, String>();
bindings.put(BINDING_RESOURCE_NAME, resource.getName());
bindings.put(BINDING_BRANCH_NAME, resource.getBranch());
+ bindings.put(BINDING_DIRTY_FLAG, resource.isDirty() ? ">" : null);
+ bindings.put(BINDING_STAGED_FLAG,
+ resource.staged() != Staged.NOT_STAGED ? "*" : null);
decorate(decoration, format, bindings);
}
private void decorateIcons(IDecoration decoration,
IDecoratableResource resource) {
- if (resource.isIgnored())
- return;
+ ImageDescriptor overlay = null;
if (resource.isTracked()) {
if (store.getBoolean(UIPreferences.DECORATOR_SHOW_TRACKED_ICON))
- decoration.addOverlay(trackedImage);
- } else if (store
- .getBoolean(UIPreferences.DECORATOR_SHOW_UNTRACKED_ICON)) {
- decoration.addOverlay(untrackedImage);
+ overlay = trackedImage;
+
+ // Staged overrides tracked
+ Staged staged = resource.staged();
+ if (store.getBoolean(UIPreferences.DECORATOR_SHOW_STAGED_ICON)
+ && staged != Staged.NOT_STAGED) {
+ if (staged == Staged.ADDED)
+ overlay = stagedAddedImage;
+ else if (staged == Staged.REMOVED)
+ overlay = stagedRemovedImage;
+ else
+ overlay = stagedImage;
+ }
+
+ // Conflicts override everything
+ if (store.getBoolean(UIPreferences.DECORATOR_SHOW_CONFLICTS_ICON)
+ && resource.hasConflicts())
+ overlay = conflictImage;
+
+ } else if (store.getBoolean(UIPreferences.DECORATOR_SHOW_UNTRACKED_ICON)) {
+ overlay = untrackedImage;
}
+
+ // Overlays can only be added once, so do it at the end
+ decoration.addOverlay(overlay);
}
/**
@@ -411,7 +584,7 @@ private void decorateIcons(IDecoration decoration,
* values
*/
public static void decorate(IDecoration decoration, String format,
- Map bindings) {
+ Map<String, String> bindings) {
StringBuffer prefix = new StringBuffer();
StringBuffer suffix = new StringBuffer();
StringBuffer output = prefix;
@@ -426,6 +599,15 @@ public static void decorate(IDecoration decoration, String format,
String key = format.substring(end + 1, start);
String s;
+ // Allow users to override the binding
+ if (key.indexOf(':') > -1) {
+ String[] keyAndBinding = key.split(":", 2);
+ key = keyAndBinding[0];
+ if (keyAndBinding.length > 1
+ && bindings.get(key) != null)
+ bindings.put(key, keyAndBinding[1]);
+ }
+
// We use the BINDING_RESOURCE_NAME key to determine if
// we are doing the prefix or suffix. The name isn't
// actually part of either.
@@ -433,7 +615,7 @@ public static void decorate(IDecoration decoration, String format,
output = suffix;
s = null;
} else {
- s = (String) bindings.get(key);
+ s = bindings.get(key);
}
if (s != null) {
@@ -522,6 +704,14 @@ public void resourceChanged(IResourceChangeEvent event) {
public boolean visit(IResourceDelta delta) throws CoreException {
final IResource resource = delta.getResource();
+ // If the resource is not part of a project under Git
+ // revision control
+ final RepositoryMapping mapping = RepositoryMapping
+ .getMapping(resource);
+ if (mapping == null) {
+ // Ignore the change
+ return true;
+ }
if (resource.getType() == IResource.ROOT) {
// Continue with the delta
return true;
diff --git a/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/decorators/IDecoratableResource.java b/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/decorators/IDecoratableResource.java
index f144214..d2b6b5c 100644
--- a/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/decorators/IDecoratableResource.java
+++ b/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/decorators/IDecoratableResource.java
@@ -16,6 +16,22 @@
public interface IDecoratableResource {
/**
+ * Set of possible staging states for a resource
+ */
+ public enum Staged {
+ /** Represents a resource that is not staged */
+ NOT_STAGED,
+ /** Represents a resource that has been modified */
+ MODIFIED,
+ /** Represents a resource that is added to Git */
+ ADDED,
+ /** Represents a resource that is removed from Git */
+ REMOVED,
+ /** Represents a resource that has been renamed */
+ RENAMED
+ }
+
+ /**
* Gets the type of the resource as defined by {@link IResource}
*
* @return the type of the resource
@@ -51,4 +67,27 @@
* @return whether or not the resource is ignored
*/
boolean isIgnored();
+
+ /**
+ * Returns whether or not the resource has changes that are not staged
+ *
+ * @return whether or not the resource is dirty
+ */
+ boolean isDirty();
+
+ /**
+ * Returns the staged state of the resource
+ *
+ * The set of allowed values are defined by the <code>Staged</code> enum
+ *
+ * @return the staged state of the resource
+ */
+ Staged staged();
+
+ /**
+ * Returns whether or not the resource has merge conflicts
+ *
+ * @return whether or not the resource has merge conflicts
+ */
+ boolean hasConflicts();
}
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 2cbf07a..74bc209 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
@@ -56,6 +56,7 @@
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Event;
+import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.TabFolder;
import org.eclipse.swt.widgets.TabItem;
@@ -72,8 +73,9 @@
import org.spearce.egit.ui.UIPreferences;
import org.spearce.egit.ui.UIText;
import org.spearce.egit.ui.internal.SWTUtils;
-import org.spearce.egit.ui.internal.decorators.GitLightweightDecorator.DecorationHelper;
import org.spearce.egit.ui.internal.decorators.IDecoratableResource;
+import org.spearce.egit.ui.internal.decorators.GitLightweightDecorator.DecorationHelper;
+import org.spearce.egit.ui.internal.decorators.IDecoratableResource.Staged;
/**
* Preference page for customizing Git label decorations
@@ -93,6 +95,10 @@
private Button showUntracked;
+ private Button showStaged;
+
+ private Button showConflicts;
+
private Preview fPreview;
private static final Collection PREVIEW_FILESYSTEM_ROOT;
@@ -101,16 +107,29 @@
static {
final PreviewResource project = new PreviewResource(
- "Project", IResource.PROJECT, "master", true, false); //$NON-NLS-1$1
+ "Project", IResource.PROJECT, "master", true, false, false, Staged.NOT_STAGED, false); //$NON-NLS-1$1
final ArrayList<PreviewResource> children = new ArrayList<PreviewResource>();
+
+ children.add(new PreviewResource(
+ "folder", IResource.FOLDER, null, true, false, false, Staged.NOT_STAGED, false)); //$NON-NLS-1$
+ children.add(new PreviewResource(
+ "tracked.txt", IResource.FILE, null, true, false, false, Staged.NOT_STAGED, false)); //$NON-NLS-1$
children.add(new PreviewResource(
- "folder", IResource.FOLDER, null, true, false)); //$NON-NLS-1$
+ "untracked.txt", IResource.FILE, null, false, false, false, Staged.NOT_STAGED, false)); //$NON-NLS-1$
children.add(new PreviewResource(
- "file.txt", IResource.FILE, null, true, false)); //$NON-NLS-1$
+ "ignored.txt", IResource.FILE, null, false, true, false, Staged.NOT_STAGED, false)); //$NON-NLS-1$
children.add(new PreviewResource(
- "untracked.txt", IResource.FILE, null, false, false)); //$NON-NLS-1$
+ "dirty.txt", IResource.FILE, null, true, false, true, Staged.NOT_STAGED, false)); //$NON-NLS-1$
children.add(new PreviewResource(
- "ignored.txt", IResource.FILE, null, false, true)); //$NON-NLS-1$
+ "staged.txt", IResource.FILE, null, true, false, false, Staged.MODIFIED, false)); //$NON-NLS-1$
+ children.add(new PreviewResource(
+ "partially-staged.txt", IResource.FILE, null, true, false, true, Staged.MODIFIED, false)); //$NON-NLS-1$
+ children.add(new PreviewResource(
+ "added.txt", IResource.FILE, null, true, false, false, Staged.ADDED, false)); //$NON-NLS-1$
+ children.add(new PreviewResource(
+ "removed.txt", IResource.FILE, null, true, false, false, Staged.REMOVED, false)); //$NON-NLS-1$
+ children.add(new PreviewResource(
+ "conflict.txt", IResource.FILE, null, true, false, true, Staged.NOT_STAGED, true)); //$NON-NLS-1$
project.children = children;
PREVIEW_FILESYSTEM_ROOT = Collections.singleton(project);
}
@@ -179,6 +198,7 @@ private Control createGeneralDecoratorPage(Composite parent) {
Composite composite = new Composite(parent, SWT.NULL);
GridLayout layout = new GridLayout();
+ layout.marginHeight = 10;
composite.setLayout(layout);
GridData data = new GridData();
data.horizontalAlignment = GridData.FILL;
@@ -206,22 +226,29 @@ private Control createTextDecoratorPage(Composite parent) {
data.horizontalAlignment = GridData.FILL;
fileTextGroup.setLayoutData(data);
+ int labelWidth = convertWidthInCharsToPixels(Math.max(
+ UIText.DecoratorPreferencesPage_fileFormatLabel.length(),
+ Math.max(UIText.DecoratorPreferencesPage_folderFormatLabel
+ .length(),
+ UIText.DecoratorPreferencesPage_projectFormatLabel
+ .length())));
+
TextPair format = createFormatEditorControl(fileTextGroup,
UIText.DecoratorPreferencesPage_fileFormatLabel,
UIText.DecoratorPreferencesPage_addVariablesAction,
- getFileBindingDescriptions());
+ getFileBindingDescriptions(), labelWidth);
fileTextFormat = format.t1;
format = createFormatEditorControl(fileTextGroup,
UIText.DecoratorPreferencesPage_folderFormatLabel,
UIText.DecoratorPreferencesPage_addVariablesAction,
- getFolderBindingDescriptions());
+ getFolderBindingDescriptions(), labelWidth);
folderTextFormat = format.t1;
format = createFormatEditorControl(fileTextGroup,
UIText.DecoratorPreferencesPage_projectFormatLabel,
UIText.DecoratorPreferencesPage_addVariablesAction,
- getProjectBindingDescriptions());
+ getProjectBindingDescriptions(), labelWidth);
projectTextFormat = format.t1;
return fileTextGroup;
@@ -230,6 +257,7 @@ private Control createTextDecoratorPage(Composite parent) {
private Control createIconDecoratorPage(Composite parent) {
Composite imageGroup = new Composite(parent, SWT.NULL);
GridLayout layout = new GridLayout();
+ layout.marginHeight = 10;
imageGroup.setLayout(layout);
GridData data = new GridData();
data.horizontalAlignment = GridData.FILL;
@@ -239,17 +267,27 @@ private Control createIconDecoratorPage(Composite parent) {
UIText.DecoratorPreferencesPage_iconsShowTracked);
showUntracked = SWTUtils.createCheckBox(imageGroup,
UIText.DecoratorPreferencesPage_iconsShowUntracked);
+ showStaged = SWTUtils.createCheckBox(imageGroup,
+ UIText.DecoratorPreferencesPage_iconsShowStaged);
+ showConflicts = SWTUtils.createCheckBox(imageGroup,
+ UIText.DecoratorPreferencesPage_iconsShowConflicts);
return imageGroup;
}
private TextPair createFormatEditorControl(Composite composite,
- String title, String buttonText, final Map supportedBindings) {
+ String title, String buttonText, final Map supportedBindings,
+ int labelWidth) {
- SWTUtils.createLabel(composite, title);
+ Label label = SWTUtils.createLabel(composite, title);
+ GridData labelGridData = new GridData();
+ labelGridData.widthHint = labelWidth;
+ label.setLayoutData(labelGridData);
Text format = new Text(composite, SWT.BORDER);
- format.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
+ GridData textGridData = new GridData(GridData.FILL_HORIZONTAL);
+ textGridData.widthHint = 200;
+ format.setLayoutData(textGridData);
format.addModifyListener(new ModifyListener() {
public void modifyText(ModifyEvent e) {
updatePreview();
@@ -293,6 +331,10 @@ private void initializeValues() {
.getBoolean(UIPreferences.DECORATOR_SHOW_TRACKED_ICON));
showUntracked.setSelection(store
.getBoolean(UIPreferences.DECORATOR_SHOW_UNTRACKED_ICON));
+ showStaged.setSelection(store
+ .getBoolean(UIPreferences.DECORATOR_SHOW_STAGED_ICON));
+ showConflicts.setSelection(store
+ .getBoolean(UIPreferences.DECORATOR_SHOW_CONFLICTS_ICON));
SelectionListener selectionListener = new SelectionAdapter() {
public void widgetSelected(SelectionEvent e) {
@@ -303,6 +345,8 @@ public void widgetSelected(SelectionEvent e) {
computeDeepDirtyState.addSelectionListener(selectionListener);
showTracked.addSelectionListener(selectionListener);
showUntracked.addSelectionListener(selectionListener);
+ showStaged.addSelectionListener(selectionListener);
+ showConflicts.addSelectionListener(selectionListener);
setValid(true);
}
@@ -354,6 +398,10 @@ private boolean performOk(IPreferenceStore store) {
.getSelection());
store.setValue(UIPreferences.DECORATOR_SHOW_UNTRACKED_ICON,
showUntracked.getSelection());
+ store.setValue(UIPreferences.DECORATOR_SHOW_STAGED_ICON, showStaged
+ .getSelection());
+ store.setValue(UIPreferences.DECORATOR_SHOW_CONFLICTS_ICON,
+ showConflicts.getSelection());
return true;
}
@@ -383,6 +431,11 @@ protected void performDefaults() {
showUntracked
.setSelection(store
.getDefaultBoolean(UIPreferences.DECORATOR_SHOW_UNTRACKED_ICON));
+ showStaged.setSelection(store
+ .getDefaultBoolean(UIPreferences.DECORATOR_SHOW_STAGED_ICON));
+ showConflicts
+ .setSelection(store
+ .getDefaultBoolean(UIPreferences.DECORATOR_SHOW_CONFLICTS_ICON));
}
/**
@@ -505,7 +558,11 @@ TextPair(Text t1, Text t2) {
private Map getFileBindingDescriptions() {
Map<String, String> bindings = new HashMap<String, String>();
bindings.put(DecorationHelper.BINDING_RESOURCE_NAME,
- UIText.DecoratorPreferencesPage_nameResourceVariable);
+ UIText.DecoratorPreferencesPage_bindingResourceName);
+ bindings.put(DecorationHelper.BINDING_DIRTY_FLAG,
+ UIText.DecoratorPreferencesPage_bindingDirtyFlag);
+ bindings.put(DecorationHelper.BINDING_STAGED_FLAG,
+ UIText.DecoratorPreferencesPage_bindingStagedFlag);
return bindings;
}
@@ -518,7 +575,11 @@ private Map getFileBindingDescriptions() {
private Map getFolderBindingDescriptions() {
Map<String, String> bindings = new HashMap<String, String>();
bindings.put(DecorationHelper.BINDING_RESOURCE_NAME,
- UIText.DecoratorPreferencesPage_nameResourceVariable);
+ UIText.DecoratorPreferencesPage_bindingResourceName);
+ bindings.put(DecorationHelper.BINDING_DIRTY_FLAG,
+ UIText.DecoratorPreferencesPage_bindingDirtyFlag);
+ bindings.put(DecorationHelper.BINDING_STAGED_FLAG,
+ UIText.DecoratorPreferencesPage_bindingStagedFlag);
return bindings;
}
@@ -531,7 +592,11 @@ private Map getFolderBindingDescriptions() {
private Map getProjectBindingDescriptions() {
Map<String, String> bindings = new HashMap<String, String>();
bindings.put(DecorationHelper.BINDING_RESOURCE_NAME,
- UIText.DecoratorPreferencesPage_nameResourceVariable);
+ UIText.DecoratorPreferencesPage_bindingResourceName);
+ bindings.put(DecorationHelper.BINDING_DIRTY_FLAG,
+ UIText.DecoratorPreferencesPage_bindingDirtyFlag);
+ bindings.put(DecorationHelper.BINDING_STAGED_FLAG,
+ UIText.DecoratorPreferencesPage_bindingStagedFlag);
bindings.put(DecorationHelper.BINDING_BRANCH_NAME,
UIText.DecoratorPreferencesPage_bindingBranchName);
return bindings;
@@ -691,14 +756,25 @@ private PreviewDecoration getDecoration(Object element) {
private boolean ignored;
+ private boolean dirty;
+
+ private boolean conflicts;
+
+ private Staged staged;
+
public PreviewResource(String name, int type, String branch,
- boolean tracked, boolean ignored) {
+ boolean tracked, boolean ignored, boolean dirty, Staged staged,
+ boolean conflicts) {
+
this.name = name;
this.branch = branch;
this.type = type;
this.children = Collections.EMPTY_LIST;
this.tracked = tracked;
this.ignored = ignored;
+ this.dirty = dirty;
+ this.staged = staged;
+ this.conflicts = conflicts;
}
public String getName() {
@@ -720,6 +796,18 @@ public boolean isTracked() {
public boolean isIgnored() {
return ignored;
}
+
+ public boolean isDirty() {
+ return dirty;
+ }
+
+ public Staged staged() {
+ return staged;
+ }
+
+ public boolean hasConflicts() {
+ return conflicts;
+ }
}
private class PreviewDecoration implements IDecoration {
@@ -736,12 +824,19 @@ public boolean isIgnored() {
private Color foregroundColor;
+ /**
+ * Adds an icon overlay to the decoration
+ * <p>
+ * Copies the behavior of <code>DecorationBuilder</code> of only
+ * allowing the overlay to be set once.
+ */
public void addOverlay(ImageDescriptor overlayImage) {
- overlay = overlayImage;
+ if (overlay == null)
+ overlay = overlayImage;
}
public void addOverlay(ImageDescriptor overlayImage, int quadrant) {
- overlay = overlayImage;
+ addOverlay(overlayImage);
}
public void addPrefix(String prefix) {
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 05fdba9..2762d11 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
@@ -352,13 +352,15 @@ DecoratorPreferencesPage_preview=Preview:
DecoratorPreferencesPage_fileFormatLabel=&Files:
DecoratorPreferencesPage_folderFormatLabel=F&olders:
DecoratorPreferencesPage_projectFormatLabel=&Projects:
-DecoratorPreferencesPage_fileFormatDefault={name}
-DecoratorPreferencesPage_folderFormatDefault={name}
-DecoratorPreferencesPage_projectFormatDefault={name} [{branch}]
+DecoratorPreferencesPage_fileFormatDefault={dirty:>} {name}
+DecoratorPreferencesPage_folderFormatDefault={dirty:>} {name}
+DecoratorPreferencesPage_projectFormatDefault={dirty:>} {name} [{branch}]
DecoratorPreferencesPage_labelDecorationsLink=See <a>''{0}''</a> to enable or disable Git decorations.
DecoratorPreferencesPage_generalTabFolder=&General
-DecoratorPreferencesPage_nameResourceVariable=name of the resource being decorated
+DecoratorPreferencesPage_bindingResourceName=name of the resource being decorated
DecoratorPreferencesPage_bindingBranchName=current branch of the project
+DecoratorPreferencesPage_bindingDirtyFlag=flag indicating whether or not the resource is dirty
+DecoratorPreferencesPage_bindingStagedFlag=flag indicating whether or not the resource is staged
DecoratorPreferencesPage_selectFormats=Select the format for file, folders, and project text labels:
DecoratorPreferencesPage_selectVariablesToAdd=Select the &variables to add to the decoration format:
DecoratorPreferencesPage_textLabel=T&ext Decorations
@@ -366,3 +368,7 @@ DecoratorPreferencesPage_iconLabel=&Icon Decorations
DecoratorPreferencesPage_iconsShowTracked=Tracked resources
DecoratorPreferencesPage_iconsShowUntracked=Untracked resources
+Decorator_exceptionMessage=Errors occurred while applying Git decorations to resources.
+
+DecoratorPreferencesPage_iconsShowStaged=Staged resources
+DecoratorPreferencesPage_iconsShowConflicts=Conflicting resources
--
1.6.1.2.309.g2ea3
next prev parent reply other threads:[~2009-02-05 1:02 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 ` Tor Arne Vestbø [this message]
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 ` [EGIT PATCH 11/11] Implement label decorations for folders and projects Tor Arne Vestbø
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-10-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.