{"thread":{"id":"14401","subject":"[EGIT PATCH 0/3] Resource decorator improvements","startedAt":"2008-07-10T22:41:05Z","lastAt":"2008-07-10T22:41:08Z","messageCount":4,"participants":["Robin Rosenberg"],"isPatch":true,"patchVersion":1,"patchTotal":3},"messages":[{"id":"82870","messageId":"1215729668-26865-1-git-send-email-robin.rosenberg@dewire.com","threadId":"14401","inReplyTo":null,"subject":"[EGIT PATCH 0/3] Resource decorator improvements","fromName":"Robin Rosenberg","fromEmail":"robin.rosenberg@dewire.com","sentAt":"2008-07-10T22:41:05Z","receivedAt":"2008-07-10T22:41:05Z","isPatch":true,"sender":{"key":"robin.rosenberg@dewire.com","avatar":"https://avatars.githubusercontent.com/u/46357?v=4"},"body":"Connect the decorator and fix some problems. The first patch depends\non the repository event mechanism.\n\n-- robin\n\nRobin Rosenberg (3):\n  Use a job for the resource decorator\n  Avoid errors by allowing phantoms during traversal in the resource\n    decorator\n  Log decoration problems more silently\n\n .../internal/decorators/GitResourceDecorator.java  |  168 ++++++++++++--------\n 1 files changed, 98 insertions(+), 70 deletions(-)\n"},{"id":"82881","messageId":"1215729668-26865-2-git-send-email-robin.rosenberg@dewire.com","threadId":"14401","inReplyTo":"1215729668-26865-1-git-send-email-robin.rosenberg@dewire.com","subject":"[EGIT PATCH 1/3] Use a job for the resource decorator","fromName":"Robin Rosenberg","fromEmail":"robin.rosenberg@dewire.com","sentAt":"2008-07-10T22:41:06Z","receivedAt":"2008-07-10T22:41:06Z","isPatch":true,"sender":{"key":"robin.rosenberg@dewire.com","avatar":"https://avatars.githubusercontent.com/u/46357?v=4"},"body":"Scanning directories for changes is slow so we want to use\na background job. We also connect to the repository event mechanism\n\nSigned-off-by: Robin Rosenberg <robin.rosenberg@dewire.com>\n---\n .../internal/decorators/GitResourceDecorator.java  |  162 +++++++++++---------\n 1 files changed, 92 insertions(+), 70 deletions(-)\n\ndiff --git a/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/decorators/GitResourceDecorator.java b/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/decorators/GitResourceDecorator.java\nindex dcb87b7..c625ce6 100644\n--- a/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/decorators/GitResourceDecorator.java\n+++ b/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/decorators/GitResourceDecorator.java\n@@ -11,6 +11,8 @@ package org.spearce.egit.ui.internal.decorators;\n \n import java.io.IOException;\n import java.util.HashSet;\n+import java.util.Iterator;\n+import java.util.LinkedHashSet;\n import java.util.Set;\n \n import org.eclipse.core.resources.IContainer;\n@@ -25,14 +27,19 @@ import org.eclipse.core.resources.IResourceVisitor;\n import org.eclipse.core.resources.ResourcesPlugin;\n import org.eclipse.core.runtime.CoreException;\n import org.eclipse.core.runtime.IAdaptable;\n+import org.eclipse.core.runtime.IProgressMonitor;\n+import org.eclipse.core.runtime.IStatus;\n import org.eclipse.core.runtime.QualifiedName;\n+import org.eclipse.core.runtime.Status;\n+import org.eclipse.core.runtime.jobs.ISchedulingRule;\n+import org.eclipse.core.runtime.jobs.Job;\n import org.eclipse.jface.viewers.IDecoration;\n import org.eclipse.jface.viewers.ILightweightLabelDecorator;\n import org.eclipse.jface.viewers.LabelProvider;\n import org.eclipse.jface.viewers.LabelProviderChangedEvent;\n import org.eclipse.swt.widgets.Display;\n import org.eclipse.team.core.Team;\n-import org.eclipse.ui.PlatformUI;\n+import org.eclipse.ui.IDecoratorManager;\n import org.spearce.egit.core.project.GitProjectData;\n import org.spearce.egit.core.project.RepositoryChangeListener;\n import org.spearce.egit.core.project.RepositoryMapping;\n@@ -65,17 +72,24 @@ import org.spearce.jgit.lib.GitIndex.Entry;\n public class GitResourceDecorator extends LabelProvider implements\n \t\tILightweightLabelDecorator {\n \n-\tprivate static final RCL myrcl = new RCL();\n+\tstatic final String decoratorId = \"org.spearce.egit.ui.internal.decorators.GitResourceDecorator\";\n+\tstatic class ResCL extends Job implements IResourceChangeListener, RepositoryChangeListener, RepositoryListener {\n \n-\tstatic class RCL implements RepositoryChangeListener, RepositoryListener, Runnable {\n-\t\tprivate boolean requested;\n+\t\tResCL() {\n+\t\t\tsuper(\"Git resource decorator trigger\");\n+\t\t}\n \n-\t\tpublic synchronized void run() {\n-\t\t\trequested = false;\n-\t\t\tPlatformUI.getWorkbench().getDecoratorManager().update(\n-\t\t\t\t\tGitResourceDecorator.class.getName());\n+\t\tGitResourceDecorator getActiveDecorator() {\n+\t\t\tIDecoratorManager decoratorManager = Activator.getDefault()\n+\t\t\t\t\t.getWorkbench().getDecoratorManager();\n+\t\t\tif (decoratorManager.getEnabled(decoratorId))\n+\t\t\t\treturn (GitResourceDecorator) decoratorManager\n+\t\t\t\t\t\t.getLightweightLabelDecorator(decoratorId);\n+\t\t\treturn null;\n \t\t}\n \n+\t\tprivate Set<IResource> resources = new LinkedHashSet<IResource>();\n+\n \t\tpublic void refsChanged(RefsChangedEvent e) {\n \t\t\trepositoryChanged(e);\n \t\t}\n@@ -97,76 +111,87 @@ public class GitResourceDecorator extends LabelProvider implements\n \t\t}\n \n \t\tpublic void repositoryChanged(final RepositoryMapping which) {\n-\t\t\ttry {\n-\t\t\t\twhich.getContainer().accept(new IResourceVisitor() {\n-\t\t\t\t\tpublic boolean visit(IResource resource) throws CoreException {\n-\t\t\t\t\t\tif (resource instanceof IContainer)\n-\t\t\t\t\t\t\tclearDecorationState(resource);\n-\t\t\t\t\t\treturn true;\n-\t\t\t\t\t}\n-\t\t\t\t});\n-\t\t\t} catch (CoreException e) {\n-\t\t\t\t// TODO Auto-generated catch block\n-\t\t\t\te.printStackTrace();\n+\t\t\tsynchronized (resources) {\n+\t\t\t\tresources.add(which.getContainer());\n \t\t\t}\n-\t\t\tstart();\n+\t\t\tschedule();\n \t\t}\n \n-\t\tsynchronized void start() {\n-\t\t\tif (requested)\n-\t\t\t\treturn;\n-\t\t\tfinal Display d = PlatformUI.getWorkbench().getDisplay();\n-\t\t\tif (d.getThread() == Thread.currentThread())\n-\t\t\t\trun();\n-\t\t\telse {\n-\t\t\t\trequested = true;\n-\t\t\t\td.asyncExec(this);\n+\t\t@Override\n+\t\tprotected IStatus run(IProgressMonitor arg0) {\n+\t\t\ttry {\n+\t\t\t\tif (resources.size() > 0) {\n+\t\t\t\t\tIResource m;\n+\t\t\t\t\tsynchronized(resources) {\n+\t\t\t\t\t\tIterator<IResource> i = resources.iterator();\n+\t\t\t\t\t\tm = i.next();\n+\t\t\t\t\t\ti.remove();\n+\t\t\t\t\t\tif (resources.size() > 0)\n+\t\t\t\t\t\t\tschedule();\n+\t\t\t\t\t}\n+\t\t\t\t\tISchedulingRule markerRule = m.getWorkspace().getRuleFactory().markerRule(m);\n+\t\t\t\t\tgetJobManager().beginRule(markerRule, arg0);\n+\t\t\t\t\ttry {\n+\t\t\t\t\t\tm.accept(new IResourceVisitor() {\n+\t\t\t\t\t\t\tpublic boolean visit(IResource resource) throws CoreException {\n+\t\t\t\t\t\t\t\tgetActiveDecorator().clearDecorationState(resource);\n+\t\t\t\t\t\t\t\treturn true;\n+\t\t\t\t\t\t\t}\n+\t\t\t\t\t\t});\n+\t\t\t\t\t} finally {\n+\t\t\t\t\t\tgetJobManager().endRule(markerRule);\n+\t\t\t\t\t}\n+\t\t\t\t}\n+\t\t\t\treturn Status.OK_STATUS;\n+\t\t\t} catch (Exception e) {\n+\t\t\t\treturn new Status(IStatus.ERROR, Activator.getPluginId(), \"Failed to trigger resource decoration\", e);\n \t\t\t}\n \t\t}\n-\t}\n \n-\tstatic class ResCL implements IResourceChangeListener {\n \t\tpublic void resourceChanged(IResourceChangeEvent event) {\n \t\t\tif (event.getType() != IResourceChangeEvent.POST_CHANGE) {\n \t\t\t\treturn;\n \t\t\t}\n \t\t\ttry {\n \t\t\t\tevent.getDelta().accept(new IResourceDeltaVisitor() {\n-\n \t\t\t\t\tpublic boolean visit(IResourceDelta delta)\n \t\t\t\t\t\t\tthrows CoreException {\n \t\t\t\t\t\tfor (IResource r = delta.getResource(); r.getType() != IResource.ROOT; r = r\n \t\t\t\t\t\t\t\t.getParent()) {\n-\t\t\t\t\t\t\ttry {\n-\t\t\t\t\t\t\t\tclearDecorationState(r);\n-\t\t\t\t\t\t\t} catch (CoreException e) {\n-\t\t\t\t\t\t\t\t// TODO Auto-generated catch block\n-\t\t\t\t\t\t\t\te.printStackTrace();\n+\t\t\t\t\t\t\tsynchronized (resources) {\n+\t\t\t\t\t\t\t\tresources.add(r);\n \t\t\t\t\t\t\t}\n \t\t\t\t\t\t}\n \t\t\t\t\t\treturn true;\n \t\t\t\t\t}\n-\n \t\t\t\t});\n-\t\t\t} catch (CoreException e2) {\n-\t\t\t\t// TODO Auto-generated catch block\n-\t\t\t\te2.printStackTrace();\n-\t\t\t\treturn;\n+\t\t\t} catch (Exception e) {\n+\t\t\t\tActivator.logError(\"Problem during decorations. Stopped\", e);\n \t\t\t}\n-\t\t\tmyrcl.start();\n+\t\t\tschedule();\n \t\t}\n-\t}\n \n-\tstatic void clearDecorationState(IResource r) throws CoreException {\n+\t\tvoid force() {\n+\t\t\tfor (IProject p : ResourcesPlugin.getWorkspace().getRoot().getProjects()) {\n+\t\t\t\tsynchronized (resources) {\n+\t\t\t\t\tresources.add(p);\n+\t\t\t\t}\n+\t\t\t}\n+\t\t\tschedule();\n+\t\t}\n+\t} // End ResCL\n+\n+\tvoid clearDecorationState(IResource r) throws CoreException {\n \t\tif (r.isAccessible())\n \t\t\tr.setSessionProperty(GITFOLDERDIRTYSTATEPROPERTY, null);\n+\t\tfireLabelProviderChanged(new LabelProviderChangedEvent(this, r));\n \t}\n \n \tstatic ResCL myrescl = new ResCL();\n \n \tstatic {\n-\t\tRepository.addAnyRepositoryChangedListener(myrcl);\n-\t\tGitProjectData.addRepositoryChangeListener(myrcl);\n+\t\tRepository.addAnyRepositoryChangedListener(myrescl);\n+\t\tGitProjectData.addRepositoryChangeListener(myrescl);\n \t\tResourcesPlugin.getWorkspace().addResourceChangeListener(myrescl,\n \t\t\t\tIResourceChangeEvent.POST_CHANGE);\n \t}\n@@ -179,7 +204,7 @@ public class GitResourceDecorator extends LabelProvider implements\n \t * </p>\n \t */\n \tpublic static void refresh() {\n-\t\tmyrcl.start();\n+\t\tmyrescl.force();\n \t}\n \n \tprivate static IResource toIResource(final Object e) {\n@@ -368,36 +393,33 @@ public class GitResourceDecorator extends LabelProvider implements\n \n \t\ttry {\n \t\t\tInteger dirty = (Integer) rsrc.getSessionProperty(GITFOLDERDIRTYSTATEPROPERTY);\n+\t\t\tRunnable runnable = new Runnable() {\n+\t\t\t\tpublic void run() {\n+\t\t\t\t\t// Async could be called after a\n+\t\t\t\t\t// project is closed or a\n+\t\t\t\t\t// resource is deleted\n+\t\t\t\t\tif (!rsrc.isAccessible())\n+\t\t\t\t\t\treturn;\n+\t\t\t\t\tfireLabelProviderChanged(new LabelProviderChangedEvent(\n+\t\t\t\t\t\t\tGitResourceDecorator.this, rsrc));\n+\t\t\t\t}\n+\t\t\t};\n \t\t\tif (dirty == null) {\n \t\t\t\trsrc.setSessionProperty(GITFOLDERDIRTYSTATEPROPERTY, new Integer(flag));\n \t\t\t\torState(rsrc.getParent(), flag);\n-\t\t\t\tDisplay.getDefault().asyncExec(new Runnable() {\n-\t\t\t\t\tpublic void run() {\n-\t\t\t\t\t\t// Async could be called after a\n-\t\t\t\t\t\t// project is closed or a\n-\t\t\t\t\t\t// resource is deleted\n-\t\t\t\t\t\tif (!rsrc.isAccessible())\n-\t\t\t\t\t\t\treturn;\n-\t\t\t\t\t\tfireLabelProviderChanged(new LabelProviderChangedEvent(\n-\t\t\t\t\t\t\t\tGitResourceDecorator.this, rsrc));\n-\t\t\t\t\t}\n-\t\t\t\t});\n+//\t\t\t\tif (Thread.currentThread() == Display.getDefault().getThread())\n+//\t\t\t\t\trunnable.run();\n+//\t\t\t\telse\n+\t\t\t\t\tDisplay.getDefault().asyncExec(runnable);\n \t\t\t} else {\n \t\t\t\tif ((dirty.intValue() | flag) != dirty.intValue()) {\n \t\t\t\t\tdirty = new Integer(dirty.intValue() | flag);\n \t\t\t\t\trsrc.setSessionProperty(GITFOLDERDIRTYSTATEPROPERTY, dirty);\n \t\t\t\t\torState(rsrc.getParent(), dirty.intValue());\n-\t\t\t\t\tDisplay.getDefault().asyncExec(new Runnable() {\n-\t\t\t\t\t\tpublic void run() {\n-\t\t\t\t\t\t\t// Async could be called after a\n-\t\t\t\t\t\t\t// project is closed or a\n-\t\t\t\t\t\t\t// resource is deleted\n-\t\t\t\t\t\t\tif (!rsrc.isAccessible())\n-\t\t\t\t\t\t\t\treturn;\n-\t\t\t\t\t\t\tfireLabelProviderChanged(new LabelProviderChangedEvent(\n-\t\t\t\t\t\t\t\t\tGitResourceDecorator.this, rsrc));\n-\t\t\t\t\t\t}\n-\t\t\t\t\t});\n+//\t\t\t\t\tif (Thread.currentThread() == Display.getDefault().getThread())\n+//\t\t\t\t\t\trunnable.run();\n+//\t\t\t\t\telse\n+\t\t\t\t\t\tDisplay.getDefault().asyncExec(runnable);\n \t\t\t\t}\n \t\t\t}\n \t\t} catch (CoreException e) {\n-- \n1.5.6.2.220.g44701\n"},{"id":"82873","messageId":"1215729668-26865-3-git-send-email-robin.rosenberg@dewire.com","threadId":"14401","inReplyTo":"1215729668-26865-2-git-send-email-robin.rosenberg@dewire.com","subject":"[EGIT PATCH 2/3] Avoid errors by allowing phantoms during traversal in the resource decorator","fromName":"Robin Rosenberg","fromEmail":"robin.rosenberg@dewire.com","sentAt":"2008-07-10T22:41:07Z","receivedAt":"2008-07-10T22:41:07Z","isPatch":true,"sender":{"key":"robin.rosenberg@dewire.com","avatar":"https://avatars.githubusercontent.com/u/46357?v=4"},"body":"Signed-off-by: Robin Rosenberg <robin.rosenberg@dewire.com>\n---\n .../internal/decorators/GitResourceDecorator.java  |    8 ++++++--\n 1 files changed, 6 insertions(+), 2 deletions(-)\n\ndiff --git a/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/decorators/GitResourceDecorator.java b/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/decorators/GitResourceDecorator.java\nindex c625ce6..8d4a7c7 100644\n--- a/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/decorators/GitResourceDecorator.java\n+++ b/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/decorators/GitResourceDecorator.java\n@@ -137,7 +137,9 @@ public class GitResourceDecorator extends LabelProvider implements\n \t\t\t\t\t\t\t\tgetActiveDecorator().clearDecorationState(resource);\n \t\t\t\t\t\t\t\treturn true;\n \t\t\t\t\t\t\t}\n-\t\t\t\t\t\t});\n+\t\t\t\t\t\t},\n+\t\t\t\t\t\tIResource.DEPTH_INFINITE,\n+\t\t\t\t\t\ttrue);\n \t\t\t\t\t} finally {\n \t\t\t\t\t\tgetJobManager().endRule(markerRule);\n \t\t\t\t\t}\n@@ -164,7 +166,9 @@ public class GitResourceDecorator extends LabelProvider implements\n \t\t\t\t\t\t}\n \t\t\t\t\t\treturn true;\n \t\t\t\t\t}\n-\t\t\t\t});\n+\t\t\t\t},\n+\t\t\t\ttrue\n+\t\t\t\t);\n \t\t\t} catch (Exception e) {\n \t\t\t\tActivator.logError(\"Problem during decorations. Stopped\", e);\n \t\t\t}\n-- \n1.5.6.2.220.g44701\n"},{"id":"82883","messageId":"1215729668-26865-4-git-send-email-robin.rosenberg@dewire.com","threadId":"14401","inReplyTo":"1215729668-26865-3-git-send-email-robin.rosenberg@dewire.com","subject":"[EGIT PATCH 3/3] Log decoration problems more silently","fromName":"Robin Rosenberg","fromEmail":"robin.rosenberg@dewire.com","sentAt":"2008-07-10T22:41:08Z","receivedAt":"2008-07-10T22:41:08Z","isPatch":true,"sender":{"key":"robin.rosenberg@dewire.com","avatar":"https://avatars.githubusercontent.com/u/46357?v=4"},"body":"Seems our logging caused too much alerts in the UI.\n\nSigned-off-by: Robin Rosenberg <robin.rosenberg@dewire.com>\n---\n .../internal/decorators/GitResourceDecorator.java  |    4 +++-\n 1 files changed, 3 insertions(+), 1 deletions(-)\n\ndiff --git a/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/decorators/GitResourceDecorator.java b/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/decorators/GitResourceDecorator.java\nindex 8d4a7c7..6d2f88e 100644\n--- a/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/decorators/GitResourceDecorator.java\n+++ b/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/decorators/GitResourceDecorator.java\n@@ -146,7 +146,9 @@ public class GitResourceDecorator extends LabelProvider implements\n \t\t\t\t}\n \t\t\t\treturn Status.OK_STATUS;\n \t\t\t} catch (Exception e) {\n-\t\t\t\treturn new Status(IStatus.ERROR, Activator.getPluginId(), \"Failed to trigger resource decoration\", e);\n+\t\t\t\t// We must be silent here or the UI will panic with lots of error messages\n+\t\t\t\tActivator.logError(\"Failed to trigger resource re-decoration\", e);\n+\t\t\t\treturn Status.OK_STATUS;\n \t\t\t}\n \t\t}\n \n-- \n1.5.6.2.220.g44701\n"}]}