diff options
| author | Philipp Thun | 2011-01-27 20:28:30 +0000 |
|---|---|---|
| committer | Chris Aniszczyk | 2011-01-31 15:44:07 +0000 |
| commit | 29113c22054efe10092ce8ff5d6ea9710e325962 (patch) | |
| tree | 485fc0533d268acad18d65103ff5f7ee52ccf0ec | |
| parent | 342d00eb46190f7a6c7cfcbf91e0706778d31194 (diff) | |
| download | egit-29113c22054efe10092ce8ff5d6ea9710e325962.tar.gz egit-29113c22054efe10092ce8ff5d6ea9710e325962.tar.xz egit-29113c22054efe10092ce8ff5d6ea9710e325962.zip | |
Introduce caching for resource decorations
With this change a simple caching mechanism for resource decorations
is introduced that is based on two timestamps: one timestamp is
resource-specific and the other one is valid for the entire
workspace.
There are mainly two types of events that GitLightWeightDecorator
handles: on the one hand IResourceChangeEvent, an event that only
affects a dedicated set of resources, and on the other hand various
events that are related to the connected Git repository.
The Git repository events are generic and thus result in firing a
LabelProviderChangedEvent that is handled by views showing decorated
content (e.g. package explorer). Before firing this event the
timestamp on workspace-level now is updated to indicate that all
cached decorations (with a lower timestamp) are invalid.
When handling an IResourceChangeEvent the resource-specific timestamp
is cleared. This means that the cached decoration for this specific
resource is no longer valid. Afterwards the same generic
LabelProviderChangedEvent is fired instead of an event for the
dedicated set of changed resources. This allows every view to
decide what to update instead of forcing an update of invisible
resources as well - which was the case before. This leads to more
re-decorations, but due to the fact that for all unchanged resources
cached information is available, this is very fast and in the end
avoids unnecessary decorations of invisible resources - as mentioned
above.
Change-Id: Iafd0fa15db3ec65d7ce8668f21819ec50733d820
Signed-off-by: Philipp Thun <philipp.thun@sap.com>
Signed-off-by: Chris Aniszczyk <caniszczyk@gmail.com>
| -rw-r--r-- | org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/decorators/GitLightweightDecorator.java | 116 |
1 files changed, 85 insertions, 31 deletions
diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/decorators/GitLightweightDecorator.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/decorators/GitLightweightDecorator.java index 253d81c7e2..9ddc7e7b00 100644 --- a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/decorators/GitLightweightDecorator.java +++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/decorators/GitLightweightDecorator.java @@ -22,17 +22,18 @@ import java.util.Map; import java.util.Set; import org.eclipse.core.resources.IContainer; -import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IResource; import org.eclipse.core.resources.IResourceChangeEvent; import org.eclipse.core.resources.IResourceChangeListener; import org.eclipse.core.resources.IResourceDelta; import org.eclipse.core.resources.IResourceDeltaVisitor; +import org.eclipse.core.resources.IWorkspaceRoot; import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.resources.mapping.ResourceMapping; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IAdaptable; import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.QualifiedName; import org.eclipse.core.runtime.Status; import org.eclipse.egit.core.internal.util.ExceptionCollector; import org.eclipse.egit.core.project.GitProjectData; @@ -56,7 +57,6 @@ import org.eclipse.jgit.events.IndexChangedListener; import org.eclipse.jgit.events.ListenerHandle; import org.eclipse.jgit.events.RefsChangedEvent; import org.eclipse.jgit.events.RefsChangedListener; -import org.eclipse.jgit.events.RepositoryEvent; import org.eclipse.jgit.lib.Constants; import org.eclipse.jgit.lib.Repository; import org.eclipse.osgi.util.TextProcessor; @@ -90,6 +90,15 @@ public class GitLightweightDecorator extends LabelProvider implements */ public static final String DECORATOR_ID = "org.eclipse.egit.ui.internal.decorators.GitLightweightDecorator"; //$NON-NLS-1$ + private static final QualifiedName REFRESH_KEY = new QualifiedName( + Activator.getPluginId(), "refresh"); //$NON-NLS-1$ + + private static final QualifiedName REFRESHED_KEY = new QualifiedName( + Activator.getPluginId(), "refreshed"); //$NON-NLS-1$ + + private static final QualifiedName DECORATABLE_RESOURCE_KEY = new QualifiedName( + Activator.getPluginId(), "decoratableResource"); //$NON-NLS-1$ + /** * Bit-mask describing interesting changes for IResourceChangeListener * events @@ -195,7 +204,7 @@ public class GitLightweightDecorator extends LabelProvider implements return; // Don't decorate if UI plugin is not running - Activator activator = Activator.getDefault(); + final Activator activator = Activator.getDefault(); if (activator == null) return; @@ -206,9 +215,11 @@ public class GitLightweightDecorator extends LabelProvider implements // Don't decorate non-existing resources if (!resource.exists() && !resource.isPhantom()) return; + // Don't decorate ignored resources (e.g. bin folder content) if (Team.isIgnoredHint(resource)) return; + // Make sure we're dealing with a project under Git revision control final RepositoryMapping mapping = RepositoryMapping .getMapping(resource); @@ -220,13 +231,45 @@ public class GitLightweightDecorator extends LabelProvider implements return; try { - DecorationHelper helper = new DecorationHelper(activator - .getPreferenceStore()); - helper.decorate(decoration, - new DecoratableResourceAdapter(resource)); + IDecoratableResource decoratableResource = null; + final DecorationHelper helper = new DecorationHelper( + activator.getPreferenceStore()); + + final Long refreshed = (Long) resource + .getSessionProperty(REFRESHED_KEY); + if (refreshed != null) { + // Stored decoratable resource is available + final IWorkspaceRoot root = resource.getWorkspace().getRoot(); + final Long refresh = (Long) root + .getSessionProperty(REFRESH_KEY); + if (refresh == null + || refresh.longValue() < refreshed.longValue()) { + // Stored decoratable resource is up-to-date + decoratableResource = (IDecoratableResource) resource + .getSessionProperty(DECORATABLE_RESOURCE_KEY); + if (decoratableResource != null) { + // Use stored decoratable resource + helper.decorate(decoration, decoratableResource); + return; + } + } + } + + // No (up-to-date) stored decoratable resource is available + decoratableResource = new DecoratableResourceAdapter(resource); + helper.decorate(decoration, decoratableResource); + + // Store decoratable resource in session + resource.setSessionProperty(DECORATABLE_RESOURCE_KEY, + decoratableResource); + // Set (new) 'refreshed' timestamp + resource.setSessionProperty(REFRESHED_KEY, + new Long(System.currentTimeMillis())); } catch (IOException e) { handleException(resource, new CoreException(new Status( IStatus.ERROR, Activator.getPluginId(), e.getMessage(), e))); + } catch (CoreException e) { + handleException(resource, e); } } @@ -654,34 +697,12 @@ public class GitLightweightDecorator extends LabelProvider implements .toArray())); } - /** - * Callback for RepositoryListener events - * - * We resolve the repository mapping for the changed repository and forward - * that to repositoryChanged(RepositoryMapping). - * - * @param e - * The original change event - */ - private void repositoryChanged(RepositoryEvent e) { - final Set<RepositoryMapping> ms = new HashSet<RepositoryMapping>(); - for (final IProject p : ResourcesPlugin.getWorkspace().getRoot() - .getProjects()) { - final RepositoryMapping mapping = RepositoryMapping.getMapping(p); - if (mapping != null && mapping.getRepository() == e.getRepository()) - ms.add(mapping); - } - for (final RepositoryMapping m : ms) { - repositoryChanged(m); - } - } - public void onIndexChanged(IndexChangedEvent e) { - repositoryChanged(e); + postLabelEvent(new LabelProviderChangedEvent(this)); } public void onRefsChanged(RefsChangedEvent e) { - repositoryChanged(e); + postLabelEvent(new LabelProviderChangedEvent(this)); } /** @@ -728,6 +749,39 @@ public class GitLightweightDecorator extends LabelProvider implements * The event to post */ private void postLabelEvent(final LabelProviderChangedEvent event) { + if (event.getElement() == null) { + // Update all elements + final IWorkspaceRoot root = ResourcesPlugin.getWorkspace() + .getRoot(); + try { + // Set (new) 'refresh' timestamp + root.setSessionProperty(REFRESH_KEY, + new Long(System.currentTimeMillis())); + } catch (CoreException e) { + handleException(root, e); + } + + fireLabelEvent(event); + } else { + // Update specific elements + Object[] elements = event.getElements(); + for (Object element : elements) { + final IResource resource = getResource(element); + if (resource != null) + try { + // Remove 'refreshed' property + resource.setSessionProperty(REFRESHED_KEY, null); + } catch (CoreException e) { + // Ignore + } + } + + // Fire a generic event + fireLabelEvent(new LabelProviderChangedEvent(this)); + } + } + + private void fireLabelEvent(final LabelProviderChangedEvent event) { Display.getDefault().asyncExec(new Runnable() { public void run() { fireLabelProviderChanged(event); |
