[EGIT PATCH v2 09/12] Implement icon and text decorations of various resource states

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



  - Dirty
  - Staged
  - Conflict
  - Assume valid

Signed-off-by: Tor Arne Vestbø <torarnv@xxxxxxxxx>
---
 org.spearce.egit.ui/icons/ovr/assume_valid.gif     |  Bin 0 -> 85 bytes
 org.spearce.egit.ui/icons/ovr/assumevalid.gif      |  Bin 64 -> 0 bytes
 org.spearce.egit.ui/icons/ovr/conflict.gif         |  Bin 64 -> 194 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 -> 169 bytes
 org.spearce.egit.ui/icons/ovr/staged_removed.gif   |  Bin 0 -> 176 bytes
 .../egit/ui/PluginPreferenceInitializer.java       |    3 +
 .../src/org/spearce/egit/ui/UIIcons.java           |   15 +-
 .../src/org/spearce/egit/ui/UIPreferences.java     |    6 +
 .../src/org/spearce/egit/ui/UIText.java            |   17 +-
 .../decorators/GitLightweightDecorator.java        |  299 +++++++++++++++++---
 .../internal/decorators/IDecoratableResource.java  |   46 +++
 .../preferences/GitDecoratorPreferencePage.java    |  152 +++++++++--
 .../src/org/spearce/egit/ui/uitext.properties      |   15 +-
 16 files changed, 477 insertions(+), 76 deletions(-)
 create mode 100644 org.spearce.egit.ui/icons/ovr/assume_valid.gif
 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/assume_valid.gif b/org.spearce.egit.ui/icons/ovr/assume_valid.gif
new file mode 100644
index 0000000000000000000000000000000000000000..b6d7167cb38b147aa0fcc115121f3166276f6688
GIT binary patch
literal 85
zcmZ?wbhEHb<Y3@pSj5Wk|Nno6&}sGa_b)s3!M=V!hzkaaKUo+V7+4u}Ks=CI24<;<
gU94*oY!sY|O?Vb;E(m>L;^NQ~(4hBvvkHSX0J)kQGXMYp

literal 0
HcmV?d00001

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..fce456a49a0d6b19feaef4e1fb8615d8083c674c 100644
GIT binary patch
literal 194
zcmZ?wbhEHb<YwSvIKsfNSXBI}k=aul+s7VW3poWA@dz#iA)&<rB8vn>o~Y|S);7GW
zV|+_e`Ie;0T?OrX8YZiZHCF1XE!R_9uBNn9O6ro5(lQ147ctTQ!GHl3DE?$&WMGhD
z&;bd9>||iIU!ayIII}ZDEm63-?}`D3QE8g^;`e8!hE6+n_+o~G)HE-)gh(9`Kkf%@
d8(7v&JK{arFoJ8^;WC#KQvzQ|Td^=$0|4|&KIZ@c

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..c65d16a191f259e0feb55c9244e7545c9063f2ee
GIT binary patch
literal 169
zcmZ?wbhEHb<Y3@nI3mv=<D+lc6C~rUFXwNhSM8ymWTTpFZ&2l?k?oi~MbDtt!(w8P
zX13k6n|3NGHU_nBa)HL3YfROWEiL<k^{d^EU9;|4ZK_}8(Y4mhqBp>NLa2<7LGmO+
zwPfqgH75W6|5yCU!pOiN&!EEq1Ry&ZSk)e=_dO9$3EpXP>xYb&Yrys66%*4FPo$Ud
U`8i&abQEg7#HJw7%D`X^09=zc+W-In

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..8aaadfb9b9300594a3448986650b82841398287c
GIT binary patch
literal 176
zcmZ?wbhEHb<Y3@nI3mX2@9!TQ8ygf96c`wooSa-&SLf&FS5i_E8XDTx)|Q{29~>Oq
z-rk;)l2TY$7#SHE5D<`;mlqcoS6p2D;Qr&HqN4x*|1;nQia%Kx85qPEbU;c#b~3Q)
zE>P`DcJ&Dn4ViXC=E@Y0u&)L|A2*0x3h8BCs@CD4#4P3#=;_K}%6y8ku!Vua8UVS)
BGb{iA

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..a3196f4 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,9 @@ 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);
+		prefs.setDefault(UIPreferences.DECORATOR_SHOW_ASSUME_VALID_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 4c0d189..952816c 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;
@@ -84,11 +88,12 @@
 
 	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");
+		OVR_ASSUMEVALID = map("ovr/assume_valid.gif");
 		ELCL16_FIND = map("elcl16/find.gif");
 		ELCL16_NEXT = map("elcl16/next.gif");
 		ELCL16_PREVIOUS = map("elcl16/previous.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..e812716 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,12 @@
 	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";
+	/** */
+	public final static String DECORATOR_SHOW_ASSUME_VALID_ICON = "decorator_show_assume_valid_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 60e4eaa..7e26337 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
@@ -968,12 +968,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;
 
 	/** */
@@ -994,6 +1000,15 @@
 	/** */
 	public static String DecoratorPreferencesPage_iconsShowUntracked;
 
+	/** */
+	public static String DecoratorPreferencesPage_iconsShowStaged;
+
+	/** */
+	public static String DecoratorPreferencesPage_iconsShowConflicts;
+
+	/** */
+	public static String DecoratorPreferencesPage_iconsShowAssumeValid;
+
 	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..c23ce24 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,20 @@ public void decorate(Object element, IDecoration decoration) {
 
 		private boolean ignored = false;
 
+		private boolean dirty = false;
+
+		private boolean conflicts = false;
+
+		private boolean assumeValid = 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 +224,162 @@ 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;
+					assumeValid = true;
+				} 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 +401,22 @@ public boolean isTracked() {
 		public boolean isIgnored() {
 			return ignored;
 		}
+
+		public boolean isDirty() {
+			return dirty;
+		}
+
+		public Staged staged() {
+			return staged;
+		}
+
+		public boolean hasConflicts() {
+			return conflicts;
+		}
+
+		public boolean isAssumeValid() {
+			return assumeValid;
+		}
 	}
 
 	/**
@@ -298,6 +434,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 +467,26 @@ public ImageData getImageData() {
 
 		private static ImageDescriptor untrackedImage;
 
+		private static ImageDescriptor stagedImage;
+
+		private static ImageDescriptor stagedAddedImage;
+
+		private static ImageDescriptor stagedRemovedImage;
+
+		private static ImageDescriptor conflictImage;
+
+		private static ImageDescriptor assumeValidImage;
+
 		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);
+			assumeValidImage = new CachedImageDescriptor(UIIcons.OVR_ASSUMEVALID);
 		}
 
 		/**
@@ -354,6 +512,9 @@ public DecorationHelper(IPreferenceStore preferencesStore) {
 		 */
 		public void decorate(IDecoration decoration,
 				IDecoratableResource resource) {
+			if (resource.isIgnored())
+				return;
+
 			decorateText(decoration, resource);
 			decorateIcons(decoration, resource);
 		}
@@ -379,22 +540,49 @@ 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;
+
+				if (store
+						.getBoolean(UIPreferences.DECORATOR_SHOW_ASSUME_VALID_ICON)
+						&& resource.isAssumeValid())
+					overlay = assumeValidImage;
+
+				// 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 +599,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 +614,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 +630,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 +719,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..b864a10 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,34 @@
 	 * @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();
+
+	/**
+	 * Returns whether or not the resource is assumed valid
+	 * 
+	 * @return whether or not the resource is assumed valid
+	 */
+	boolean isAssumeValid();
 }
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 7b637e3..f72ceb7 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
@@ -55,6 +55,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;
@@ -71,8 +72,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
@@ -94,22 +96,43 @@
 
 	private Preview preview;
 
+	private Button showStaged;
+
+	private Button showConflicts;
+
+	private Button showAssumeValid;
+
 	private static final Collection PREVIEW_FILESYSTEM_ROOT;
 
 	private static IPropertyChangeListener themeListener;
 
 	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, 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, false)); //$NON-NLS-1$
+		children.add(new PreviewResource(
+						"tracked.txt", IResource.FILE, null, true, false, false, Staged.NOT_STAGED, false, 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, 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, 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, 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, false)); //$NON-NLS-1$
+		children.add(new PreviewResource(
+						"partially-staged.txt", IResource.FILE, null, true, false, true, Staged.MODIFIED, false, false)); //$NON-NLS-1$
+		children.add(new PreviewResource(
+						"added.txt", IResource.FILE, null, true, false, false, Staged.ADDED, false, false)); //$NON-NLS-1$
+		children.add(new PreviewResource(
+						"removed.txt", IResource.FILE, null, true, false, false, Staged.REMOVED, false, false)); //$NON-NLS-1$
+		children.add(new PreviewResource(
+						"conflict.txt", IResource.FILE, null, true, false, true, Staged.NOT_STAGED, true, false)); //$NON-NLS-1$
+		children.add(new PreviewResource(
+						"assume-valid.txt", IResource.FILE, null, true, false, false, Staged.NOT_STAGED, false, true)); //$NON-NLS-1$
 		project.children = children;
 		PREVIEW_FILESYSTEM_ROOT = Collections.singleton(project);
 	}
@@ -190,22 +213,29 @@ private Control createTextDecoratorPage(Composite parent) {
 		Composite fileTextGroup = SWTUtils.createHVFillComposite(parent,
 				SWTUtils.MARGINS_DEFAULT, 3);
 
+		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;
@@ -219,17 +249,29 @@ 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);
+		showAssumeValid = SWTUtils.createCheckBox(imageGroup,
+				UIText.DecoratorPreferencesPage_iconsShowAssumeValid);
 
 		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();
@@ -273,16 +315,25 @@ 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));
+		showAssumeValid.setSelection(store
+				.getBoolean(UIPreferences.DECORATOR_SHOW_ASSUME_VALID_ICON));
 
 		SelectionListener selectionListener = new SelectionAdapter() {
 			public void widgetSelected(SelectionEvent e) {
-				fPreview.refresh();
+				preview.refresh();
 			}
 		};
 
 		computeDeepDirtyState.addSelectionListener(selectionListener);
 		showTracked.addSelectionListener(selectionListener);
 		showUntracked.addSelectionListener(selectionListener);
+		showStaged.addSelectionListener(selectionListener);
+		showConflicts.addSelectionListener(selectionListener);
+		showAssumeValid.addSelectionListener(selectionListener);
 
 		setValid(true);
 	}
@@ -334,6 +385,12 @@ 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());
+		store.setValue(UIPreferences.DECORATOR_SHOW_ASSUME_VALID_ICON,
+				showAssumeValid.getSelection());
 
 		return true;
 	}
@@ -363,6 +420,14 @@ 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));
+		showAssumeValid
+				.setSelection(store
+						.getDefaultBoolean(UIPreferences.DECORATOR_SHOW_ASSUME_VALID_ICON));
 	}
 
 	/**
@@ -473,7 +538,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;
 	}
 
@@ -486,7 +555,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;
 	}
 
@@ -499,7 +572,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;
@@ -658,14 +735,28 @@ private PreviewDecoration getDecoration(Object element) {
 
 		private boolean ignored;
 
+		private boolean dirty;
+
+		private boolean conflicts;
+
+		private Staged staged;
+
+		private boolean assumeValid;
+
 		public PreviewResource(String name, int type, String branch,
-				boolean tracked, boolean ignored) {
+				boolean tracked, boolean ignored, boolean dirty, Staged staged,
+				boolean conflicts, boolean assumeValid) {
+
 			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;
+			this.assumeValid = assumeValid; 
 		}
 
 		public String getName() {
@@ -687,6 +778,22 @@ public boolean isTracked() {
 		public boolean isIgnored() {
 			return ignored;
 		}
+
+		public boolean isDirty() {
+			return dirty;
+		}
+
+		public Staged staged() {
+			return staged;
+		}
+
+		public boolean hasConflicts() {
+			return conflicts;
+		}
+
+		public boolean isAssumeValid() {
+			return assumeValid;
+		}
 	}
 
 	private class PreviewDecoration implements IDecoration {
@@ -703,12 +810,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 9940177..e9a2321 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
@@ -358,17 +358,24 @@ 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
 DecoratorPreferencesPage_iconLabel=&Icon Decorations
 DecoratorPreferencesPage_iconsShowTracked=Tracked resources
 DecoratorPreferencesPage_iconsShowUntracked=Untracked resources
+DecoratorPreferencesPage_iconsShowStaged=Staged resources
+DecoratorPreferencesPage_iconsShowConflicts=Conflicting resources
+DecoratorPreferencesPage_iconsShowAssumeValid=Assumed unchanged resources
+
+Decorator_exceptionMessage=Errors occurred while applying Git decorations to resources.
 
-- 
1.6.1.2.309.g2ea3

--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Linux Kernel Development]     [Gcc Help]     [IETF Annouce]     [DCCP]     [Netdev]     [Networking]     [Security]     [V4L]     [Bugtraq]     [Yosemite]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux SCSI]     [Fedora Users]

  Powered by Linux