Subject: [EGIT PATCH 08/11] Add icon decoration for tracked and untracked resources

From: Tor Arne Vestbø <[email-masked]>
Date: Thu, 5 Feb 2009 02:00:15 +0100

Can be enabled/disabled in the preferences

Signed-off-by: Tor Arne Vestbø <[email-masked]>
---
 org.spearce.egit.ui/icons/ovr/shared.gif           |  Bin 106 -> 0 bytes
 org.spearce.egit.ui/icons/ovr/untracked.gif        |  Bin 0 -> 79 bytes
 .../egit/ui/PluginPreferenceInitializer.java       |    4 +-
 .../src/org/spearce/egit/ui/UIIcons.java           |    6 +-
 .../src/org/spearce/egit/ui/UIPreferences.java     |    4 +
 .../src/org/spearce/egit/ui/UIText.java            |    6 +
 .../decorators/GitLightweightDecorator.java        |  162 ++++++++++++++++++--
 .../internal/decorators/IDecoratableResource.java  |   15 ++
 .../preferences/GitDecoratorPreferencePage.java    |   89 +++++++++--
 .../src/org/spearce/egit/ui/uitext.properties      |    2 +
 10 files changed, 259 insertions(+), 29 deletions(-)
 delete mode 100644 org.spearce.egit.ui/icons/ovr/shared.gif
 create mode 100644 org.spearce.egit.ui/icons/ovr/untracked.gif

diff --git a/org.spearce.egit.ui/icons/ovr/shared.gif b/org.spearce.egit.ui/icons/ovr/shared.gif
deleted file mode 100644
index eb71a3c742e133c2ed61c958e237c71e0f7cb6aa..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 106
zcmZ?wbhEHbWM|-D*v!E2|KHF5k5c|0Q~7_){{ITmE8U{M-dx?8EBgQce+Fzo@h1x-
p15m3DND^cQ1B<x8$xa82iYrMhmeJo^<v0pdEtw8K%o1d<1^~aoAP)cl

diff --git a/org.spearce.egit.ui/icons/ovr/untracked.gif b/org.spearce.egit.ui/icons/ovr/untracked.gif
new file mode 100644
index 0000000000000000000000000000000000000000..45ca32060700d71abcb88bbcdb1000d503fe11cf
GIT binary patch
literal 79
zcmZ?wbhEHbWM|-DSj51<z}U+mGMhnsAy57};pVIV!2l?%_>+Z^fq{)d2gqgssbydm
biP#m!(lAAgdxkboj%vJ&f(EaJDuXouU6m8v

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 79c2665..7465444 100644
--- a/org.spearce.egit.ui/src/org/spearce/egit/ui/PluginPreferenceInitializer.java
+++ b/org.spearce.egit.ui/src/org/spearce/egit/ui/PluginPreferenceInitializer.java
@@ -35,13 +35,15 @@ public void initializeDefaultPreferences() {
 		prefs.setDefault(UIPreferences.RESOURCEHISTORY_SHOW_REV_COMMENT, true);
 		prefs.setDefault(UIPreferences.RESOURCEHISTORY_SHOW_TOOLTIPS, false);
 
+		prefs.setDefault(UIPreferences.DECORATOR_CALCULATE_DIRTY, true);
 		prefs.setDefault(UIPreferences.DECORATOR_FILETEXT_DECORATION,
 				UIText.DecoratorPreferencesPage_fileFormatDefault);
 		prefs.setDefault(UIPreferences.DECORATOR_FOLDERTEXT_DECORATION,
 				UIText.DecoratorPreferencesPage_folderFormatDefault);
 		prefs.setDefault(UIPreferences.DECORATOR_PROJECTTEXT_DECORATION,
 				UIText.DecoratorPreferencesPage_projectFormatDefault);
-		prefs.setDefault(UIPreferences.DECORATOR_CALCULATE_DIRTY, true);
+		prefs.setDefault(UIPreferences.DECORATOR_SHOW_TRACKED_ICON, true);
+		prefs.setDefault(UIPreferences.DECORATOR_SHOW_UNTRACKED_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 1697542..0cead29 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
@@ -24,8 +24,8 @@
 	/** Decoration for resource removed from the index but not commit. */
 	public static final ImageDescriptor OVR_PENDING_REMOVE;
 
-	/** Decoration for resource tracked and committed in git. */
-	public static final ImageDescriptor OVR_SHARED;
+	/** Decoration for resource not being tracked by Git */
+	public static final ImageDescriptor OVR_UNTRACKED;
 
 	/** Decoration for tracked resource with a merge conflict.  */
 	public static final ImageDescriptor OVR_CONFLICT;
@@ -77,7 +77,7 @@
 		base = init();
 		OVR_PENDING_ADD = map("ovr/pending_add.gif");
 		OVR_PENDING_REMOVE = map("ovr/pending_remove.gif");
-		OVR_SHARED = map("ovr/shared.gif");
+		OVR_UNTRACKED = map("ovr/untracked.gif");
 		OVR_CONFLICT = map("ovr/conflict.gif");
 		OVR_ASSUMEVALID = map("ovr/assumevalid.gif");
 		ELCL16_FIND = map("elcl16/find.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 a6168a0..7916cea 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
@@ -60,6 +60,10 @@
 	public final static String DECORATOR_FOLDERTEXT_DECORATION = "decorator_foldertext_decoration";
 	/** */
 	public final static String DECORATOR_PROJECTTEXT_DECORATION = "decorator_projecttext_decoration";
+	/** */
+	public final static String DECORATOR_SHOW_TRACKED_ICON = "decorator_show_tracked_icon";
+	/** */
+	public final static String DECORATOR_SHOW_UNTRACKED_ICON = "decorator_show_untracked_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 f939558..fe62d0a 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
@@ -973,6 +973,12 @@
 	/** */
 	public static String DecoratorPreferencesPage_labelDecorationsLink;
 
+	/** */
+	public static String DecoratorPreferencesPage_iconsShowTracked;
+
+	/** */
+	public static String DecoratorPreferencesPage_iconsShowUntracked;
+
 	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 265d5a3..b20070a 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
@@ -15,6 +15,7 @@
 
 import java.io.IOException;
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
@@ -34,6 +35,7 @@
 import org.eclipse.core.runtime.IAdaptable;
 import org.eclipse.core.runtime.IStatus;
 import org.eclipse.jface.preference.IPreferenceStore;
+import org.eclipse.jface.resource.ImageDescriptor;
 import org.eclipse.jface.util.IPropertyChangeListener;
 import org.eclipse.jface.util.PropertyChangeEvent;
 import org.eclipse.jface.viewers.IDecoration;
@@ -41,7 +43,11 @@
 import org.eclipse.jface.viewers.LabelProvider;
 import org.eclipse.jface.viewers.LabelProviderChangedEvent;
 import org.eclipse.osgi.util.TextProcessor;
+import org.eclipse.swt.graphics.ImageData;
 import org.eclipse.swt.widgets.Display;
+import org.eclipse.team.core.Team;
+import org.eclipse.team.ui.ISharedImages;
+import org.eclipse.team.ui.TeamImages;
 import org.eclipse.team.ui.TeamUI;
 import org.eclipse.ui.IContributorResourceAdapter;
 import org.eclipse.ui.PlatformUI;
@@ -51,13 +57,22 @@
 import org.spearce.egit.core.project.RepositoryChangeListener;
 import org.spearce.egit.core.project.RepositoryMapping;
 import org.spearce.egit.ui.Activator;
+import org.spearce.egit.ui.UIIcons;
 import org.spearce.egit.ui.UIPreferences;
 import org.spearce.egit.ui.UIText;
+import org.spearce.jgit.dircache.DirCache;
+import org.spearce.jgit.dircache.DirCacheIterator;
+import org.spearce.jgit.lib.Constants;
 import org.spearce.jgit.lib.IndexChangedEvent;
+import org.spearce.jgit.lib.ObjectId;
 import org.spearce.jgit.lib.RefsChangedEvent;
 import org.spearce.jgit.lib.Repository;
 import org.spearce.jgit.lib.RepositoryChangedEvent;
 import org.spearce.jgit.lib.RepositoryListener;
+import org.spearce.jgit.revwalk.RevWalk;
+import org.spearce.jgit.treewalk.EmptyTreeIterator;
+import org.spearce.jgit.treewalk.TreeWalk;
+import org.spearce.jgit.treewalk.filter.PathFilterGroup;
 
 /**
  * Supplies annotations for displayed resources
@@ -144,7 +159,7 @@ public void decorate(Object element, IDecoration decoration) {
 		if (!resource.exists() && !resource.isPhantom())
 			return;
 
-		// Make sure we're dealing with a Git project
+		// Make sure we're dealing with a project under Git revision control
 		final RepositoryMapping mapping = RepositoryMapping
 				.getMapping(resource);
 		if (mapping == null)
@@ -171,14 +186,80 @@ public void decorate(Object element, IDecoration decoration) {
 
 	private class DecoratableResourceAdapter implements IDecoratableResource {
 
-		private IResource resource;
-		private String branch;
+		private final IResource resource;
 
-		public DecoratableResourceAdapter(IResource resourceToWrap) throws IOException {
+		private final RepositoryMapping mapping;
+
+		private final Repository repository;
+
+		private final ObjectId headId;
+
+		private String branch = "";
+
+		private boolean tracked = false;
+
+		private boolean ignored = false;
+
+		public DecoratableResourceAdapter(IResource resourceToWrap)
+				throws IOException {
 			resource = resourceToWrap;
-			RepositoryMapping mapping = RepositoryMapping.getMapping(resource);
-			Repository repository = mapping.getRepository();
+			mapping = RepositoryMapping.getMapping(resource);
+			repository = mapping.getRepository();
+			headId = repository.resolve(Constants.HEAD);
+
+			initializeValues();
+		}
+
+		/**
+		 * 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();
+
+			// Resolve tracked state
+			if (getType() == IResource.PROJECT) {
+				tracked = true;
+			} 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());
+
+					treeWalk.addTree(new DirCacheIterator(DirCache
+							.read(repository)));
+					if (treeWalk.next()) {
+						tracked = true;
+					}
+				}
+			}
+
+			// Resolve ignored state (currently only reads the global Eclipse
+			// ignores)
+			// TODO: Also read ignores from .git/info/excludes et al.
+			if (Team.isIgnoredHint(resource)) {
+				ignored = true;
+			}
 		}
 
 		public String getName() {
@@ -192,6 +273,14 @@ public int getType() {
 		public String getBranch() {
 			return branch;
 		}
+
+		public boolean isTracked() {
+			return tracked;
+		}
+
+		public boolean isIgnored() {
+			return ignored;
+		}
 	}
 
 	/**
@@ -203,13 +292,45 @@ public String getBranch() {
 	 */
 	public static class DecorationHelper {
 
-		private IPreferenceStore store;
-
 		/** */
 		public static final String BINDING_RESOURCE_NAME = "name"; //$NON-NLS-1$
+
 		/** */
 		public static final String BINDING_BRANCH_NAME = "branch"; //$NON-NLS-1$
 
+		private IPreferenceStore store;
+
+		/**
+		 * Define a cached image descriptor which only creates the image data
+		 * once
+		 */
+		private static class CachedImageDescriptor extends ImageDescriptor {
+			ImageDescriptor descriptor;
+
+			ImageData data;
+
+			public CachedImageDescriptor(ImageDescriptor descriptor) {
+				this.descriptor = descriptor;
+			}
+
+			public ImageData getImageData() {
+				if (data == null) {
+					data = descriptor.getImageData();
+				}
+				return data;
+			}
+		}
+
+		private static ImageDescriptor trackedImage;
+
+		private static ImageDescriptor untrackedImage;
+
+		static {
+			trackedImage = new CachedImageDescriptor(TeamImages
+					.getImageDescriptor(ISharedImages.IMG_CHECKEDIN_OVR));
+			untrackedImage = new CachedImageDescriptor(UIIcons.OVR_UNTRACKED);
+		}
+
 		/**
 		 * Constructs a decorator using the rules from the given
 		 * <code>preferencesStore</code>
@@ -233,6 +354,12 @@ public DecorationHelper(IPreferenceStore preferencesStore) {
 		 */
 		public void decorate(IDecoration decoration,
 				IDecoratableResource resource) {
+			decorateText(decoration, resource);
+			decorateIcons(decoration, resource);
+		}
+
+		private void decorateText(IDecoration decoration,
+				IDecoratableResource resource) {
 			String format = "";
 			switch (resource.getType()) {
 			case IResource.FILE:
@@ -256,9 +383,24 @@ public void decorate(IDecoration decoration,
 			decorate(decoration, format, bindings);
 		}
 
+		private void decorateIcons(IDecoration decoration,
+				IDecoratableResource resource) {
+			if (resource.isIgnored())
+				return;
+
+			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);
+			}
+		}
+
 		/**
-		 * Decorates the given <code>decoration</code>, using the given
-		 * <code>format</code>, and mapped using <code>bindings</code>
+		 * Decorates the given <code>decoration</code>, using the specified text
+		 * <code>format</code>, and mapped using the variable bindings from
+		 * <code>bindings</code>
 		 * 
 		 * @param decoration
 		 *            the decoration to decorate
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 6b36e0e..f144214 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
@@ -36,4 +36,19 @@
 	 *         applicable
 	 */
 	String getBranch();
+
+	/**
+	 * Returns whether or not the resource is tracked by Git
+	 * 
+	 * @return whether or not the resource is tracked by Git
+	 */
+	boolean isTracked();
+
+	/**
+	 * Returns whether or not the resource is ignored, either by a global team
+	 * ignore in Eclipse, or by .git/info/exclude et al.
+	 * 
+	 * @return whether or not the resource is ignored
+	 */
+	boolean isIgnored();
 }
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 2a1a3a8..2cbf07a 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
@@ -44,6 +44,9 @@
 import org.eclipse.swt.SWT;
 import org.eclipse.swt.events.ModifyEvent;
 import org.eclipse.swt.events.ModifyListener;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.events.SelectionListener;
 import org.eclipse.swt.graphics.Color;
 import org.eclipse.swt.graphics.Font;
 import org.eclipse.swt.graphics.Image;
@@ -84,7 +87,11 @@
 
 	private Text projectTextFormat;
 
-	private Button showDirty;
+	private Button computeDeepDirtyState;
+
+	private Button showTracked;
+
+	private Button showUntracked;
 
 	private Preview fPreview;
 
@@ -94,10 +101,16 @@
 
 	static {
 		final PreviewResource project = new PreviewResource(
-				"Project", IResource.PROJECT, "master"); //$NON-NLS-1$1
+				"Project", IResource.PROJECT, "master", true, false); //$NON-NLS-1$1
 		final ArrayList<PreviewResource> children = new ArrayList<PreviewResource>();
-		children.add(new PreviewResource("folder", IResource.FOLDER, null)); //$NON-NLS-1$
-		children.add(new PreviewResource("file.txt", IResource.FILE, null)); //$NON-NLS-1$
+		children.add(new PreviewResource(
+				"folder", IResource.FOLDER, null, true, false)); //$NON-NLS-1$
+		children.add(new PreviewResource(
+				"file.txt", IResource.FILE, null, true, false)); //$NON-NLS-1$
+		children.add(new PreviewResource(
+				"untracked.txt", IResource.FILE, null, false, false)); //$NON-NLS-1$
+		children.add(new PreviewResource(
+				"ignored.txt", IResource.FILE, null, false, true)); //$NON-NLS-1$
 		project.children = children;
 		PREVIEW_FILESYSTEM_ROOT = Collections.singleton(project);
 	}
@@ -171,7 +184,7 @@ private Control createGeneralDecoratorPage(Composite parent) {
 		data.horizontalAlignment = GridData.FILL;
 		composite.setLayoutData(data);
 
-		showDirty = SWTUtils.createCheckBox(composite,
+		computeDeepDirtyState = SWTUtils.createCheckBox(composite,
 				UIText.DecoratorPreferencesPage_computeDeep);
 
 		return composite;
@@ -222,6 +235,11 @@ private Control createIconDecoratorPage(Composite parent) {
 		data.horizontalAlignment = GridData.FILL;
 		imageGroup.setLayoutData(data);
 
+		showTracked = SWTUtils.createCheckBox(imageGroup,
+				UIText.DecoratorPreferencesPage_iconsShowTracked);
+		showUntracked = SWTUtils.createCheckBox(imageGroup,
+				UIText.DecoratorPreferencesPage_iconsShowUntracked);
+
 		return imageGroup;
 	}
 
@@ -261,6 +279,9 @@ public void handleEvent(Event event) {
 	private void initializeValues() {
 		final IPreferenceStore store = getPreferenceStore();
 
+		computeDeepDirtyState.setSelection(store
+				.getBoolean(UIPreferences.DECORATOR_CALCULATE_DIRTY));
+
 		fileTextFormat.setText(store
 				.getString(UIPreferences.DECORATOR_FILETEXT_DECORATION));
 		folderTextFormat.setText(store
@@ -268,8 +289,20 @@ private void initializeValues() {
 		projectTextFormat.setText(store
 				.getString(UIPreferences.DECORATOR_PROJECTTEXT_DECORATION));
 
-		showDirty.setSelection(store
-				.getBoolean(UIPreferences.DECORATOR_CALCULATE_DIRTY));
+		showTracked.setSelection(store
+				.getBoolean(UIPreferences.DECORATOR_SHOW_TRACKED_ICON));
+		showUntracked.setSelection(store
+				.getBoolean(UIPreferences.DECORATOR_SHOW_UNTRACKED_ICON));
+
+		SelectionListener selectionListener = new SelectionAdapter() {
+			public void widgetSelected(SelectionEvent e) {
+				fPreview.refresh();
+			}
+		};
+
+		computeDeepDirtyState.addSelectionListener(selectionListener);
+		showTracked.addSelectionListener(selectionListener);
+		showUntracked.addSelectionListener(selectionListener);
 
 		setValid(true);
 	}
@@ -307,6 +340,9 @@ public boolean performOk() {
 	 */
 	private boolean performOk(IPreferenceStore store) {
 
+		store.setValue(UIPreferences.DECORATOR_CALCULATE_DIRTY,
+				computeDeepDirtyState.getSelection());
+
 		store.setValue(UIPreferences.DECORATOR_FILETEXT_DECORATION,
 				fileTextFormat.getText());
 		store.setValue(UIPreferences.DECORATOR_FOLDERTEXT_DECORATION,
@@ -314,8 +350,10 @@ private boolean performOk(IPreferenceStore store) {
 		store.setValue(UIPreferences.DECORATOR_PROJECTTEXT_DECORATION,
 				projectTextFormat.getText());
 
-		store.setValue(UIPreferences.DECORATOR_CALCULATE_DIRTY, showDirty
+		store.setValue(UIPreferences.DECORATOR_SHOW_TRACKED_ICON, showTracked
 				.getSelection());
+		store.setValue(UIPreferences.DECORATOR_SHOW_UNTRACKED_ICON,
+				showUntracked.getSelection());
 
 		return true;
 	}
@@ -328,6 +366,9 @@ protected void performDefaults() {
 		super.performDefaults();
 		IPreferenceStore store = getPreferenceStore();
 
+		computeDeepDirtyState.setSelection(store
+				.getDefaultBoolean(UIPreferences.DECORATOR_CALCULATE_DIRTY));
+
 		fileTextFormat.setText(store
 				.getDefaultString(UIPreferences.DECORATOR_FILETEXT_DECORATION));
 		folderTextFormat
@@ -337,8 +378,11 @@ protected void performDefaults() {
 				.setText(store
 						.getDefaultString(UIPreferences.DECORATOR_PROJECTTEXT_DECORATION));
 
-		showDirty.setSelection(store
-				.getDefaultBoolean(UIPreferences.DECORATOR_CALCULATE_DIRTY));
+		showTracked.setSelection(store
+				.getDefaultBoolean(UIPreferences.DECORATOR_SHOW_TRACKED_ICON));
+		showUntracked
+				.setSelection(store
+						.getDefaultBoolean(UIPreferences.DECORATOR_SHOW_UNTRACKED_ICON));
 	}
 
 	/**
@@ -635,19 +679,26 @@ private PreviewDecoration getDecoration(Object element) {
 	}
 
 	private static class PreviewResource implements IDecoratableResource {
-		public final String name;
+		private final String name;
+
+		private final String branch;
 
-		public final String branch;
+		private final int type;
 
-		public final int type;
+		private Collection children;
 
-		public Collection children;
+		private boolean tracked;
 
-		public PreviewResource(String name, int type, String branch) {
+		private boolean ignored;
+
+		public PreviewResource(String name, int type, String branch,
+				boolean tracked, boolean ignored) {
 			this.name = name;
 			this.branch = branch;
 			this.type = type;
 			this.children = Collections.EMPTY_LIST;
+			this.tracked = tracked;
+			this.ignored = ignored;
 		}
 
 		public String getName() {
@@ -661,6 +712,14 @@ public int getType() {
 		public String getBranch() {
 			return branch;
 		}
+
+		public boolean isTracked() {
+			return tracked;
+		}
+
+		public boolean isIgnored() {
+			return ignored;
+		}
 	}
 
 	private class PreviewDecoration implements IDecoration {
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 58cb9e6..05fdba9 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
@@ -363,4 +363,6 @@ DecoratorPreferencesPage_selectFormats=Select the format for file, folders, and
 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
 
-- 
1.6.1.2.309.g2ea3