blob: 99cf525f19e7bbdd2bcfd623c168ece4dd12086b [file] [log] [blame]
/**
* <copyright>
*
* Copyright (c) 2016 itemis and others.
* 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
*
* Contributors:
* itemis - Initial API and implementation
* itemis - [501109] The tree viewer state restoration upon Eclipse startup and viewer refreshed still running in cases where it is not needed
*
* </copyright>
*/
package org.eclipse.sphinx.emf.explorer.refresh;
import java.util.HashSet;
import java.util.Set;
import org.eclipse.core.runtime.Assert;
import org.eclipse.jface.viewers.StructuredViewer;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.sphinx.emf.explorer.IModelCommonContentProvider;
import org.eclipse.sphinx.emf.workspace.ui.viewers.state.ITreeViewerState;
/**
* Represents a refresh operation on a JFace {@link Viewer viewer} that follows some specific strategy. Optionally
* records the underlying viewer's expansion and selection state before the refresh operation and restored it
* thereafter.
* <p>
* Clients are supposed to subclass this class and implement its {@link #refresh(Viewer)} method. In the most simple
* case, this can be done by just invoking {@link Viewer#refresh()}. However, the main purpose of this class is to
* enable clients to implement a some more sophisticated logic that performs a selective refresh of the viewer items
* that are actually need to be refreshed which can save a lot of runtime-performance in many situations.
* </p>
*/
public abstract class AbstractRefreshStrategy<T> implements Runnable {
protected final IModelCommonContentProvider contentProvider;
private final boolean preserveTreeViewerState;
private Set<T> treeElementsToRefresh = null;
public AbstractRefreshStrategy(IModelCommonContentProvider contentProvider, boolean preserveTreeViewerState) {
Assert.isNotNull(contentProvider);
this.contentProvider = contentProvider;
this.preserveTreeViewerState = preserveTreeViewerState;
}
public Set<T> getTreeElementsToRefresh() {
if (treeElementsToRefresh == null) {
treeElementsToRefresh = new HashSet<T>();
}
return treeElementsToRefresh;
}
/*
* @see java.lang.Runnable#run()
*/
@Override
public final void run() {
if (canRun()) {
final Viewer viewer = contentProvider.getViewer();
if (viewer != null && viewer.getControl() != null && !viewer.getControl().isDisposed()) {
viewer.getControl().getDisplay().asyncExec(new Runnable() {
@Override
public void run() {
if (viewer != null && viewer.getControl() != null && !viewer.getControl().isDisposed()) {
// Record current tree viewer expansion and selection state if needed
ITreeViewerState state = null;
if (preserveTreeViewerState) {
state = contentProvider.recordViewerState();
}
// Perform viewer refresh relying on implemented refresh strategy
refresh(viewer);
// Restore previous tree viewer expansion and selection state if needed
if (preserveTreeViewerState) {
contentProvider.applyViewerState(state);
}
}
}
});
}
}
}
protected boolean canRun() {
return !getTreeElementsToRefresh().isEmpty();
}
protected final void refresh(Viewer viewer) {
/*
* Performance optimization: Perform selective refresh on affected viewer items only if number of the latter is
* reasonably low.
*/
if (viewer instanceof StructuredViewer && shouldPerformSelectiveRefresh()) {
// Perform a selective viewer refresh
performSelectiveRefresh((StructuredViewer) viewer);
} else {
// Perform a full viewer refresh otherwise
viewer.refresh();
}
}
protected abstract boolean shouldPerformSelectiveRefresh();
protected abstract void performSelectiveRefresh(StructuredViewer viewer);
}