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 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).