
org.eclipse.ui.progress.DeferredTreeContentManager Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of org.eclipse.ui.workbench Show documentation
Show all versions of org.eclipse.ui.workbench Show documentation
This is org.eclipse.ui.workbench jar used by Scout SDK
/*******************************************************************************
* Copyright (c) 2003, 2009 IBM Corporation 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:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.ui.progress;
import org.eclipse.core.runtime.Assert;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.ListenerList;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.IJobChangeEvent;
import org.eclipse.core.runtime.jobs.IJobChangeListener;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.core.runtime.jobs.JobChangeAdapter;
import org.eclipse.jface.viewers.AbstractTreeViewer;
import org.eclipse.jface.viewers.ITreeContentProvider;
import org.eclipse.osgi.util.NLS;
import org.eclipse.swt.widgets.Control;
import org.eclipse.ui.IWorkbenchPartSite;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.internal.progress.ProgressMessages;
import org.eclipse.ui.internal.util.Util;
import org.eclipse.ui.model.IWorkbenchAdapter;
/**
* The DeferredContentManager is a class that helps an ITreeContentProvider get
* its deferred input.
*
* NOTE AbstractTreeViewer#isExpandable may need to be implemented in
* AbstractTreeViewer subclasses with deferred content that use filtering as a
* call to #getChildren may be required to determine the correct state of the
* expanding control.
*
* AbstractTreeViewers which use this class may wish to sacrifice accuracy of
* the expandable state indicator for the performance benefits of deferring
* content.
*
* @see IDeferredWorkbenchAdapter
* @since 3.0
*/
public class DeferredTreeContentManager {
AbstractTreeViewer treeViewer;
IWorkbenchSiteProgressService progressService;
private ListenerList updateCompleteListenerList;
/**
* The DeferredContentFamily is a class used to keep track of a
* manager-object pair so that only jobs scheduled by the receiver are
* canceled by the receiver.
*
* @since 3.1
*
*/
class DeferredContentFamily {
protected DeferredTreeContentManager manager;
protected Object element;
/**
* Create a new instance of the receiver to define a family for object
* in a particular scheduling manager.
*
* @param schedulingManager
* @param object
*/
DeferredContentFamily(DeferredTreeContentManager schedulingManager,
Object object) {
this.manager = schedulingManager;
this.element = object;
}
}
/**
* Create a new instance of the receiver using the supplied content provider
* and viewer. Run any jobs using the site.
*
* @param provider
* @param viewer
* @param site
* @deprecated in 3.4. provider is not used by this class
*/
@Deprecated
public DeferredTreeContentManager(ITreeContentProvider provider,
AbstractTreeViewer viewer, IWorkbenchPartSite site) {
this(viewer, site);
}
/**
* Create a new instance of the receiver using the supplied content provider
* and viewer.
*
* @param provider
* The content provider that will be updated
* @param viewer
* The tree viewer that the results are added to
* @deprecated in 3.4. provider is not used by this class
*/
@Deprecated
public DeferredTreeContentManager(ITreeContentProvider provider,
AbstractTreeViewer viewer) {
this(viewer);
}
/**
* Create a new instance of the receiver using the supplied content provider
* and viewer. Run any jobs using the site.
*
* @param viewer
* @param site
*
* @since 3.4
*/
public DeferredTreeContentManager(AbstractTreeViewer viewer,
IWorkbenchPartSite site) {
this(viewer);
Object siteService = Util.getAdapter(site,
IWorkbenchSiteProgressService.class);
if (siteService != null) {
progressService = (IWorkbenchSiteProgressService) siteService;
}
}
/**
* Create a new instance of the receiver using the supplied content provider
* and viewer.
*
* @param viewer
* The tree viewer that the results are added to
*
* @since 3.4
*/
public DeferredTreeContentManager(AbstractTreeViewer viewer) {
treeViewer = viewer;
}
/**
* Provides an optimized lookup for determining if an element has children.
* This is required because elements that are populated lazilly can't answer
* getChildren
just to determine the potential for children.
* Throw an AssertionFailedException if element is null.
*
* @param element
* The Object being tested. This should not be null
.
* @return boolean true
if there are potentially children.
* @throws RuntimeException
* if the element is null.
*/
public boolean mayHaveChildren(Object element) {
Assert.isNotNull(element,
ProgressMessages.DeferredTreeContentManager_NotDeferred);
IDeferredWorkbenchAdapter adapter = getAdapter(element);
return adapter != null && adapter.isContainer();
}
/**
* Returns the child elements of the given element, or in the case of a
* deferred element, returns a placeholder. If a deferred element is used, a
* job is created to fetch the children in the background.
*
* @param parent
* The parent object.
* @return Object[] or null
if parent is not an instance of
* IDeferredWorkbenchAdapter.
*/
public Object[] getChildren(final Object parent) {
IDeferredWorkbenchAdapter element = getAdapter(parent);
if (element == null) {
return null;
}
PendingUpdateAdapter placeholder = createPendingUpdateAdapter();
startFetchingDeferredChildren(parent, element, placeholder);
return new Object[] { placeholder };
}
/**
* Factory method for creating the pending update adapter representing the
* placeholder node. Subclasses may override.
*
* @return a pending update adapter
* @since 3.2
*/
protected PendingUpdateAdapter createPendingUpdateAdapter() {
return new PendingUpdateAdapter();
}
/**
* Return the IDeferredWorkbenchAdapter for element or the element if it is
* an instance of IDeferredWorkbenchAdapter. If it does not exist return
* null.
*
* @param element
* @return IDeferredWorkbenchAdapter or null
*/
protected IDeferredWorkbenchAdapter getAdapter(Object element) {
return Util.getAdapter(element, IDeferredWorkbenchAdapter.class);
}
/**
* Starts a job and creates a collector for fetching the children of this
* deferred adapter. If children are waiting to be retrieved for this parent
* already, that job is cancelled and another is started.
*
* @param parent
* The parent object being filled in,
* @param adapter
* The adapter being used to fetch the children.
* @param placeholder
* The adapter that will be used to indicate that results are
* pending.
*/
protected void startFetchingDeferredChildren(final Object parent,
final IDeferredWorkbenchAdapter adapter,
final PendingUpdateAdapter placeholder) {
final IElementCollector collector = createElementCollector(parent,
placeholder);
// Cancel any jobs currently fetching children for the same parent
// instance.
cancel(parent);
String jobName = getFetchJobName(parent, adapter);
Job job = new Job(jobName) {
@Override
public IStatus run(IProgressMonitor monitor) {
adapter.fetchDeferredChildren(parent, collector, monitor);
if (monitor.isCanceled()) {
return Status.CANCEL_STATUS;
}
return Status.OK_STATUS;
}
@Override
public boolean belongsTo(Object family) {
if (family instanceof DeferredContentFamily) {
DeferredContentFamily contentFamily = (DeferredContentFamily) family;
if (contentFamily.manager == DeferredTreeContentManager.this) {
return isParent(contentFamily, parent);
}
}
return false;
}
/**
* Check if the parent of element is equal to the parent used in
* this job.
*
* @param family
* The DeferredContentFamily that defines a potential
* ancestor of the current parent in a particular
* manager.
* @param child
* The object to check against.
* @return boolean true
if the child or one of its
* parents are the same as the element of the family.
*/
private boolean isParent(DeferredContentFamily family, Object child) {
if (family.element.equals(child)) {
return true;
}
IWorkbenchAdapter workbenchAdapter = getWorkbenchAdapter(child);
if (workbenchAdapter == null) {
return false;
}
Object elementParent = workbenchAdapter.getParent(child);
if (elementParent == null) {
return false;
}
return isParent(family, elementParent);
}
/**
* Get the workbench adapter for the element.
*
* @param element
* The object we are adapting to.
*/
private IWorkbenchAdapter getWorkbenchAdapter(Object element) {
return Util.getAdapter(element, IWorkbenchAdapter.class);
}
};
job.addJobChangeListener(new JobChangeAdapter() {
@Override
public void done(IJobChangeEvent event) {
runClearPlaceholderJob(placeholder);
}
});
job.setRule(adapter.getRule(parent));
if (progressService == null) {
job.schedule();
} else {
progressService.schedule(job);
}
}
/**
* Returns a name to use for the job that fetches children of the given
* parent. Subclasses may override. Default job name is parent's label.
*
* @param parent
* parent that children are to be fetched for
* @param adapter
* parent's deferred adapter
* @return job name
*/
protected String getFetchJobName(Object parent,
IDeferredWorkbenchAdapter adapter) {
return NLS.bind(
ProgressMessages.DeferredTreeContentManager_FetchingName,
adapter.getLabel(parent));
}
/**
* Create a UIJob to add the children to the parent in the tree viewer.
*
* @param parent
* @param children
* @param monitor
*/
protected void addChildren(final Object parent, final Object[] children,
IProgressMonitor monitor) {
WorkbenchJob updateJob = new WorkbenchJob(
ProgressMessages.DeferredTreeContentManager_AddingChildren) {
@Override
public IStatus runInUIThread(IProgressMonitor updateMonitor) {
// Cancel the job if the tree viewer got closed
if (treeViewer.getControl().isDisposed()
|| updateMonitor.isCanceled()) {
return Status.CANCEL_STATUS;
}
treeViewer.add(parent, children);
return Status.OK_STATUS;
}
};
updateJob.setSystem(true);
updateJob.schedule();
}
/**
* Return whether or not the element is or adapts to an
* IDeferredWorkbenchAdapter.
*
* @param element
* @return boolean true
if the element is an
* IDeferredWorkbenchAdapter
*/
public boolean isDeferredAdapter(Object element) {
return getAdapter(element) != null;
}
/**
* Run a job to clear the placeholder. This is used when the update for the
* tree is complete so that the user is aware that no more updates are
* pending.
*
* @param placeholder
*/
protected void runClearPlaceholderJob(final PendingUpdateAdapter placeholder) {
if (placeholder.isRemoved() || !PlatformUI.isWorkbenchRunning()) {
return;
}
// Clear the placeholder if it is still there
WorkbenchJob clearJob = new WorkbenchJob(
ProgressMessages.DeferredTreeContentManager_ClearJob) {
@Override
public IStatus runInUIThread(IProgressMonitor monitor) {
if (!placeholder.isRemoved()) {
Control control = treeViewer.getControl();
if (control.isDisposed()) {
return Status.CANCEL_STATUS;
}
treeViewer.remove(placeholder);
placeholder.setRemoved(true);
}
return Status.OK_STATUS;
}
};
clearJob.setSystem(true);
if (updateCompleteListenerList != null) {
Object[] listeners = updateCompleteListenerList.getListeners();
for (int i = 0; i < listeners.length; i++) {
clearJob
.addJobChangeListener((IJobChangeListener) listeners[i]);
}
}
clearJob.schedule();
}
/**
* Cancel all jobs that are fetching content for the given parent or any of
* its children.
*
* @param parent
*/
public void cancel(Object parent) {
if (parent == null) {
return;
}
Job.getJobManager().cancel(new DeferredContentFamily(this, parent));
}
/**
* Create the element collector for the receiver.
*
* @param parent
* The parent object being filled in,
* @param placeholder
* The adapter that will be used to indicate that results are
* pending.
* @return IElementCollector
*/
protected IElementCollector createElementCollector(final Object parent,
final PendingUpdateAdapter placeholder) {
return new IElementCollector() {
@Override
public void add(Object element, IProgressMonitor monitor) {
add(new Object[] { element }, monitor);
}
@Override
public void add(Object[] elements, IProgressMonitor monitor) {
addChildren(parent, elements, monitor);
}
@Override
public void done() {
runClearPlaceholderJob(placeholder);
}
};
}
/**
* Add a listener to list of update complete listeners. These listeners are
* attached to the job that updates the viewer content (clears the pending
* entry, etc.) after all deferred content has been retrieved.
*
* This method has no effect if the listener has already been added to the
* list of listeners.
*
* Since 3.6, this listener is added to a list of listeners rather than
* replacing the previously added listener. For backward compatibility,
* adding a null listener will be interpreted as removal of a listener if
* only one listener has been registered.
*
* @param listener
* the listener to add to the list of update listeners
* @since 3.4
*/
public void addUpdateCompleteListener(IJobChangeListener listener){
// Maintain backward compatibility.
// Earlier only one listener was supported, so it can be removed by
// passing null
if (listener == null && updateCompleteListenerList != null) {
Object[] listeners = updateCompleteListenerList.getListeners();
if (listeners.length == 1) {
removeUpdateCompleteListener((IJobChangeListener) listeners[0]);
}
} else {
if (updateCompleteListenerList == null) {
updateCompleteListenerList = new ListenerList();
}
updateCompleteListenerList.add(listener);
}
}
/**
* Removes the listener from the list of update listeners that are attached
* to the job that updates the viewer content (clears the pending entry,
* etc.) after all deferred content has been retrieved. If the listener is
* already attached to a running job, it is not removed, but it will not be
* added to any subsequent jobs that are run.
*
* This method has no effect if the listener was not previously added to the
* listener list.
*
* @param listener
* the listener to be removed
* @since 3.6
*/
public void removeUpdateCompleteListener(IJobChangeListener listener) {
if (updateCompleteListenerList != null) {
updateCompleteListenerList.remove(listener);
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy