Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRobin Stocker2012-07-25 21:06:23 +0000
committerRobin Stocker2012-08-28 15:14:40 +0000
commit37160e084363d3156e76f53811b2d1687a68d563 (patch)
treee994089fa36d9aca80dedbc7b77260ba7d780dbf
parentc6a7ffee2b6a0f9298f733bf4987d0a9e75d4e80 (diff)
downloadegit-37160e084363d3156e76f53811b2d1687a68d563.tar.gz
egit-37160e084363d3156e76f53811b2d1687a68d563.tar.xz
egit-37160e084363d3156e76f53811b2d1687a68d563.zip
Show problem decorations in staging view and commit dialog
This makes errors/warnings on the files visible while committing. Before, these could only be noticed in other places before committing (e.g. the package explorer). In an earlier version of this change, IDecoratorManager was used. The problem with that was that it could be turned off in the preferences and that updating behavior was not correct. So in this version, a plain ILabelDecorator is used and the decorations are updated using a IResourceChangeListener. Bug: 382755 Change-Id: I142a5f20b35f98675b90170dc1328ea637468c06 Signed-off-by: Robin Stocker <robin@nibor.org>
-rw-r--r--org.eclipse.egit.core/src/org/eclipse/egit/core/internal/util/ResourceUtil.java19
-rw-r--r--org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/decorators/IProblemDecoratable.java37
-rw-r--r--org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/decorators/ProblemLabelDecorator.java139
-rw-r--r--org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/dialogs/CommitDialog.java60
-rw-r--r--org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/staging/StagingEntry.java18
-rw-r--r--org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/staging/StagingView.java12
6 files changed, 270 insertions, 15 deletions
diff --git a/org.eclipse.egit.core/src/org/eclipse/egit/core/internal/util/ResourceUtil.java b/org.eclipse.egit.core/src/org/eclipse/egit/core/internal/util/ResourceUtil.java
index f7ad02095a..65beef52ae 100644
--- a/org.eclipse.egit.core/src/org/eclipse/egit/core/internal/util/ResourceUtil.java
+++ b/org.eclipse.egit.core/src/org/eclipse/egit/core/internal/util/ResourceUtil.java
@@ -18,6 +18,7 @@ import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IWorkspaceRoot;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.Path;
import org.eclipse.egit.core.project.RepositoryMapping;
import org.eclipse.jgit.lib.Repository;
@@ -42,6 +43,24 @@ public class ResourceUtil {
}
/**
+ * Get the {@link IFile} corresponding to the arguments, using
+ * {@link IWorkspaceRoot#getFileForLocation(org.eclipse.core.runtime.IPath)}
+ * .
+ *
+ * @param repository
+ * the repository of the file
+ * @param repoRelativePath
+ * the repository-relative path of the file to search for
+ * @return the IFile corresponding to this path, or null
+ */
+ public static IFile getFileForLocation(Repository repository,
+ String repoRelativePath) {
+ IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot();
+ IPath path = new Path(repository.getWorkTree().getAbsolutePath()).append(repoRelativePath);
+ return root.getFileForLocation(path);
+ }
+
+ /**
* The method splits the given resources by their repository. For each
* occurring repository a list is built containing the repository relative
* paths of the related resources.
diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/decorators/IProblemDecoratable.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/decorators/IProblemDecoratable.java
new file mode 100644
index 0000000000..3818966f7c
--- /dev/null
+++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/decorators/IProblemDecoratable.java
@@ -0,0 +1,37 @@
+/*******************************************************************************
+ * Copyright (C) 2012, Robin Stocker <robin@nibor.org>
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *******************************************************************************/
+package org.eclipse.egit.ui.internal.decorators;
+
+import org.eclipse.core.resources.IMarker;
+import org.eclipse.core.resources.IResource;
+
+/**
+ * Interface which decoratable element classes must implement to be decorated by
+ * the {@link ProblemLabelDecorator}.
+ */
+public interface IProblemDecoratable {
+
+ /**
+ * Indication for no problem.
+ */
+ public static int SEVERITY_NONE = -1;
+
+ /**
+ * Should return the problem severity of the decoratable element, e.g.
+ * {@link IMarker#SEVERITY_ERROR}. Return
+ * {@link IProblemDecoratable#SEVERITY_NONE} for no problem.
+ * <p>
+ * Implementation can use
+ * {@link IResource#findMaxProblemSeverity(String, boolean, int)} for
+ * resources.
+ *
+ * @return problem severity
+ */
+ int getProblemSeverity();
+}
diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/decorators/ProblemLabelDecorator.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/decorators/ProblemLabelDecorator.java
new file mode 100644
index 0000000000..cf146c74b0
--- /dev/null
+++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/decorators/ProblemLabelDecorator.java
@@ -0,0 +1,139 @@
+/*******************************************************************************
+ * Copyright (C) 2012, Robin Stocker <robin@nibor.org>
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *******************************************************************************/
+package org.eclipse.egit.ui.internal.decorators;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.eclipse.core.resources.IMarker;
+import org.eclipse.core.resources.IMarkerDelta;
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.resources.IResourceChangeEvent;
+import org.eclipse.core.resources.IResourceChangeListener;
+import org.eclipse.core.resources.ResourcesPlugin;
+import org.eclipse.egit.core.AdapterUtils;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.jface.resource.JFaceResources;
+import org.eclipse.jface.resource.LocalResourceManager;
+import org.eclipse.jface.resource.ResourceManager;
+import org.eclipse.jface.viewers.BaseLabelProvider;
+import org.eclipse.jface.viewers.DecorationOverlayIcon;
+import org.eclipse.jface.viewers.IDecoration;
+import org.eclipse.jface.viewers.ILabelDecorator;
+import org.eclipse.jface.viewers.IStructuredContentProvider;
+import org.eclipse.jface.viewers.StructuredViewer;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.team.ui.ISharedImages;
+import org.eclipse.team.ui.TeamImages;
+
+/**
+ * Label decorator for warning/error problem markers (used in Staging View and
+ * Commit Dialog).
+ * <p>
+ * Users must make the decoratable element implement {@link IProblemDecoratable}.
+ */
+public class ProblemLabelDecorator extends BaseLabelProvider implements
+ ILabelDecorator, IResourceChangeListener {
+
+ private final StructuredViewer viewer;
+
+ private final ResourceManager resourceManager = new LocalResourceManager(
+ JFaceResources.getResources());
+
+ /**
+ * @param viewer
+ * the viewer to use for label updates because of changed
+ * resources, or null for none
+ */
+ public ProblemLabelDecorator(StructuredViewer viewer) {
+ this.viewer = viewer;
+ if (this.viewer != null)
+ ResourcesPlugin.getWorkspace().addResourceChangeListener(this);
+ }
+
+ public void dispose() {
+ resourceManager.dispose();
+ if (this.viewer != null)
+ ResourcesPlugin.getWorkspace().removeResourceChangeListener(this);
+ super.dispose();
+ }
+
+ public Image decorateImage(Image image, Object element) {
+ IProblemDecoratable decoratable = getProblemDecoratable(element);
+ if (decoratable != null) {
+ int problemSeverity = decoratable.getProblemSeverity();
+ if (problemSeverity == IMarker.SEVERITY_ERROR)
+ return getDecoratedImage(image, ISharedImages.IMG_ERROR_OVR);
+ else if (problemSeverity == IMarker.SEVERITY_WARNING)
+ return getDecoratedImage(image, ISharedImages.IMG_WARNING_OVR);
+ }
+ return null;
+ }
+
+ public String decorateText(String text, Object element) {
+ // No decoration
+ return null;
+ }
+
+ private IProblemDecoratable getProblemDecoratable(Object element) {
+ if (element instanceof IProblemDecoratable)
+ return (IProblemDecoratable) element;
+ else
+ return null;
+ }
+
+ private Image getDecoratedImage(Image base, String teamImageId) {
+ ImageDescriptor overlay = TeamImages.getImageDescriptor(teamImageId);
+ DecorationOverlayIcon decorated = new DecorationOverlayIcon(base,
+ overlay, IDecoration.BOTTOM_LEFT);
+ return (Image) this.resourceManager.get(decorated);
+ }
+
+ public void resourceChanged(IResourceChangeEvent event) {
+ Set<IResource> resources = new HashSet<IResource>();
+
+ IMarkerDelta[] markerDeltas = event.findMarkerDeltas(IMarker.PROBLEM,
+ true);
+ for (IMarkerDelta delta : markerDeltas)
+ resources.add(delta.getResource());
+
+ if (!resources.isEmpty())
+ updateLabels(resources);
+ }
+
+ private void updateLabels(Set<IResource> changedResources) {
+ List<Object> elements = getAffectedElements(changedResources);
+ if (!elements.isEmpty()) {
+ final Object[] updateElements = elements.toArray(new Object[elements.size()]);
+ Display display = viewer.getControl().getDisplay();
+ display.asyncExec(new Runnable() {
+ public void run() {
+ viewer.update(updateElements, null);
+ }
+ });
+ }
+ }
+
+ private List<Object> getAffectedElements(Set<IResource> resources) {
+ List<Object> result = new ArrayList<Object>();
+ if (viewer.getContentProvider() instanceof IStructuredContentProvider) {
+ IStructuredContentProvider contentProvider = (IStructuredContentProvider) viewer.getContentProvider();
+ Object[] elements = contentProvider.getElements(null);
+ for (Object element : elements) {
+ IResource resource = AdapterUtils.adapt(element, IResource.class);
+ if (resource != null && resources.contains(resource))
+ result.add(element);
+ }
+ }
+ return result;
+ }
+}
diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/dialogs/CommitDialog.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/dialogs/CommitDialog.java
index 62dc919da0..5e57d4685c 100644
--- a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/dialogs/CommitDialog.java
+++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/dialogs/CommitDialog.java
@@ -26,11 +26,15 @@ import java.util.Iterator;
import java.util.Set;
import org.eclipse.core.resources.IFile;
+import org.eclipse.core.resources.IMarker;
+import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.Assert;
+import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.Path;
import org.eclipse.egit.core.Activator;
import org.eclipse.egit.core.AdaptableFileTreeIterator;
+import org.eclipse.egit.core.internal.util.ResourceUtil;
import org.eclipse.egit.ui.UIIcons;
import org.eclipse.egit.ui.UIPreferences;
import org.eclipse.egit.ui.UIText;
@@ -39,6 +43,8 @@ import org.eclipse.egit.ui.internal.CompareUtils;
import org.eclipse.egit.ui.internal.commit.CommitHelper;
import org.eclipse.egit.ui.internal.commit.CommitMessageHistory;
import org.eclipse.egit.ui.internal.commit.CommitProposalProcessor;
+import org.eclipse.egit.ui.internal.decorators.IProblemDecoratable;
+import org.eclipse.egit.ui.internal.decorators.ProblemLabelDecorator;
import org.eclipse.egit.ui.internal.dialogs.CommitItem.Status;
import org.eclipse.egit.ui.internal.dialogs.CommitMessageComponent.CommitStatus;
import org.eclipse.jface.dialogs.IDialogConstants;
@@ -57,14 +63,19 @@ import org.eclipse.jface.resource.ResourceManager;
import org.eclipse.jface.text.DocumentEvent;
import org.eclipse.jface.text.IDocumentListener;
import org.eclipse.jface.viewers.ArrayContentProvider;
+import org.eclipse.jface.viewers.BaseLabelProvider;
+import org.eclipse.jface.viewers.CellLabelProvider;
import org.eclipse.jface.viewers.CheckStateChangedEvent;
import org.eclipse.jface.viewers.CheckboxTableViewer;
import org.eclipse.jface.viewers.ColumnLabelProvider;
import org.eclipse.jface.viewers.ColumnViewerToolTipSupport;
+import org.eclipse.jface.viewers.DecoratingStyledCellLabelProvider;
import org.eclipse.jface.viewers.DecorationOverlayIcon;
+import org.eclipse.jface.viewers.DelegatingStyledCellLabelProvider.IStyledLabelProvider;
import org.eclipse.jface.viewers.ICheckStateListener;
import org.eclipse.jface.viewers.IDecoration;
import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.viewers.StyledString;
import org.eclipse.jface.viewers.TableViewerColumn;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.jface.viewers.ViewerComparator;
@@ -121,7 +132,8 @@ public class CommitDialog extends TitleAreaDialog {
return org.eclipse.egit.ui.Activator.getDefault().getPreferenceStore();
}
- static class CommitStatusLabelProvider extends ColumnLabelProvider {
+ static class CommitStatusLabelProvider extends BaseLabelProvider implements
+ IStyledLabelProvider {
private Image DEFAULT = PlatformUI.getWorkbench().getSharedImages()
.getImage(ISharedImages.IMG_OBJ_FILE);
@@ -151,8 +163,8 @@ public class CommitDialog extends TitleAreaDialog {
return (Image) this.resourceManager.get(decorated);
}
- public String getText(Object obj) {
- return ""; //$NON-NLS-1$
+ public StyledString getStyledText(Object element) {
+ return new StyledString();
}
public Image getImage(Object element) {
@@ -178,16 +190,12 @@ public class CommitDialog extends TitleAreaDialog {
decorator) : getEditorImage(item);
}
- public String getToolTipText(Object element) {
- return ((CommitItem) element).status.getText();
- }
-
+ @Override
public void dispose() {
SUBMODULE.dispose();
resourceManager.dispose();
super.dispose();
}
-
}
static class CommitPathLabelProvider extends ColumnLabelProvider {
@@ -413,6 +421,7 @@ public class CommitDialog extends TitleAreaDialog {
item.status = getFileStatus(path, indexDiff);
item.submodule = FileMode.GITLINK == indexDiff.getIndexMode(path);
item.path = path;
+ item.problemSeverity = getProblemSeverity(repository, path);
items.add(item);
}
@@ -784,7 +793,7 @@ public class CommitDialog extends TitleAreaDialog {
filesViewer = new CheckboxTableViewer(resourcesTable);
new TableViewerColumn(filesViewer, statCol)
- .setLabelProvider(new CommitStatusLabelProvider());
+ .setLabelProvider(createStatusLabelProvider());
new TableViewerColumn(filesViewer, resourceCol)
.setLabelProvider(new CommitPathLabelProvider());
ColumnViewerToolTipSupport.enableFor(filesViewer);
@@ -925,6 +934,17 @@ public class CommitDialog extends TitleAreaDialog {
return container;
}
+ private static CellLabelProvider createStatusLabelProvider() {
+ CommitStatusLabelProvider baseProvider = new CommitStatusLabelProvider();
+ ProblemLabelDecorator decorator = new ProblemLabelDecorator(null);
+ return new DecoratingStyledCellLabelProvider(baseProvider, decorator, null) {
+ @Override
+ public String getToolTipText(Object element) {
+ return ((CommitItem) element).status.getText();
+ }
+ };
+ }
+
private void updateMessage() {
String message = null;
int type = IMessageProvider.NONE;
@@ -1069,6 +1089,19 @@ public class CommitDialog extends TitleAreaDialog {
return Status.UNKNOWN;
}
+ private static int getProblemSeverity(Repository repository, String path) {
+ IFile file = ResourceUtil.getFileForLocation(repository, path);
+ if (file != null) {
+ try {
+ int severity = file.findMaxProblemSeverity(IMarker.PROBLEM, true, IResource.DEPTH_ONE);
+ return severity;
+ } catch (CoreException e) {
+ // Fall back to below
+ }
+ }
+ return IProblemDecoratable.SEVERITY_NONE;
+ }
+
@Override
protected void okPressed() {
if (!isCommitWithoutFilesAllowed()) {
@@ -1113,13 +1146,20 @@ public class CommitDialog extends TitleAreaDialog {
}
}
-class CommitItem {
+class CommitItem implements IProblemDecoratable {
+
Status status;
String path;
boolean submodule;
+ int problemSeverity;
+
+ public int getProblemSeverity() {
+ return problemSeverity;
+ }
+
/** The ordinal of this {@link Enum} is used to provide the "native" sorting of the list */
public static enum Status {
/** */
diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/staging/StagingEntry.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/staging/StagingEntry.java
index 5717d10286..a1f2cf2fd3 100644
--- a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/staging/StagingEntry.java
+++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/staging/StagingEntry.java
@@ -14,19 +14,22 @@ import java.util.EnumSet;
import java.util.Set;
import org.eclipse.core.resources.IFile;
+import org.eclipse.core.resources.IMarker;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IWorkspaceRoot;
import org.eclipse.core.resources.ResourcesPlugin;
+import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.Path;
+import org.eclipse.egit.ui.internal.decorators.IProblemDecoratable;
import org.eclipse.jgit.lib.Repository;
/**
* A staged/unstaged entry in the table
*/
-public class StagingEntry implements IAdaptable {
+public class StagingEntry implements IAdaptable, IProblemDecoratable {
/**
* State of the node
*/
@@ -161,6 +164,19 @@ public class StagingEntry implements IAdaptable {
return absolutePath;
}
+ public int getProblemSeverity() {
+ IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot();
+ IFile file = root.getFileForLocation(getLocation());
+ if (file == null)
+ return SEVERITY_NONE;
+
+ try {
+ return file.findMaxProblemSeverity(IMarker.PROBLEM, true, IResource.DEPTH_ONE);
+ } catch (CoreException e) {
+ return SEVERITY_NONE;
+ }
+ }
+
public Object getAdapter(Class adapter) {
if (adapter == IResource.class) {
return getFile();
diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/staging/StagingView.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/staging/StagingView.java
index 404e44d097..c060fd3a4d 100644
--- a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/staging/StagingView.java
+++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/staging/StagingView.java
@@ -55,6 +55,7 @@ import org.eclipse.egit.ui.internal.commit.CommitMessageHistory;
import org.eclipse.egit.ui.internal.commit.CommitProposalProcessor;
import org.eclipse.egit.ui.internal.commit.CommitUI;
import org.eclipse.egit.ui.internal.components.ToggleableWarningLabel;
+import org.eclipse.egit.ui.internal.decorators.ProblemLabelDecorator;
import org.eclipse.egit.ui.internal.dialogs.CommitMessageArea;
import org.eclipse.egit.ui.internal.dialogs.CommitMessageComponent;
import org.eclipse.egit.ui.internal.dialogs.CommitMessageComponentState;
@@ -77,6 +78,7 @@ import org.eclipse.jface.preference.IPersistentPreferenceStore;
import org.eclipse.jface.preference.IPreferenceStore;
import org.eclipse.jface.util.LocalSelectionTransfer;
import org.eclipse.jface.viewers.ContentViewer;
+import org.eclipse.jface.viewers.DecoratingStyledCellLabelProvider;
import org.eclipse.jface.viewers.DelegatingStyledCellLabelProvider;
import org.eclipse.jface.viewers.DelegatingStyledCellLabelProvider.IStyledLabelProvider;
import org.eclipse.jface.viewers.IBaseLabelProvider;
@@ -346,7 +348,7 @@ public class StagingView extends ViewPart {
unstagedTableViewer.getTable().setData(FormToolkit.KEY_DRAW_BORDER,
FormToolkit.TREE_BORDER);
unstagedTableViewer.getTable().setLinesVisible(true);
- unstagedTableViewer.setLabelProvider(createLabelProvider());
+ unstagedTableViewer.setLabelProvider(createLabelProvider(unstagedTableViewer));
unstagedTableViewer.setContentProvider(new StagingViewContentProvider(
true));
unstagedTableViewer.addDragSupport(DND.DROP_MOVE | DND.DROP_COPY
@@ -466,7 +468,7 @@ public class StagingView extends ViewPart {
stagedTableViewer.getTable().setData(FormToolkit.KEY_DRAW_BORDER,
FormToolkit.TREE_BORDER);
stagedTableViewer.getTable().setLinesVisible(true);
- stagedTableViewer.setLabelProvider(createLabelProvider());
+ stagedTableViewer.setLabelProvider(createLabelProvider(stagedTableViewer));
stagedTableViewer.setContentProvider(new StagingViewContentProvider(
false));
stagedTableViewer.addDragSupport(
@@ -736,11 +738,13 @@ public class StagingView extends ViewPart {
undoRedoActionGroup.fillActionBars(actionBars);
}
- private IBaseLabelProvider createLabelProvider() {
+ private IBaseLabelProvider createLabelProvider(TableViewer tableViewer) {
StagingViewLabelProvider baseProvider = new StagingViewLabelProvider();
baseProvider.setFileNameMode(getPreferenceStore().getBoolean(
UIPreferences.STAGING_VIEW_FILENAME_MODE));
- return new DelegatingStyledCellLabelProvider(baseProvider);
+
+ ProblemLabelDecorator decorator = new ProblemLabelDecorator(tableViewer);
+ return new DecoratingStyledCellLabelProvider(baseProvider, decorator, null);
}
private IPreferenceStore getPreferenceStore() {

Back to the top