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 workbench Show documentation
Show all versions of workbench Show documentation
This plug-in contains the bulk of the Workbench implementation, and depends on JFace, SWT, and Core Runtime. It cannot be used independently from org.eclipse.ui. Workbench client plug-ins should not depend directly on this plug-in.
The newest version!
/*******************************************************************************
* Copyright (c) 2003, 2007 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.Platform;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.IJobChangeEvent;
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 {
ITreeContentProvider contentProvider;
AbstractTreeViewer treeViewer;
IWorkbenchSiteProgressService progressService;
/**
* The DeferredContentFamily is a class used to keep track of a
* manager-object pair so that only jobs scheduled by the receiver
* are cancelled 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
*/
public DeferredTreeContentManager(ITreeContentProvider provider,
AbstractTreeViewer viewer, IWorkbenchPartSite site) {
this(provider, 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 provider The content provider that will be updated
* @param viewer The tree viewer that the results are added to
*/
public DeferredTreeContentManager(ITreeContentProvider provider,
AbstractTreeViewer viewer) {
contentProvider = provider;
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 (IDeferredWorkbenchAdapter)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) {
/* (non-Javadoc)
* @see org.eclipse.core.jobs.Job#run(org.eclipse.core.runtime.IProgressMonitor)
*/
public IStatus run(IProgressMonitor monitor) {
adapter.fetchDeferredChildren(parent, collector, monitor);
if(monitor.isCanceled()) {
return Status.CANCEL_STATUS;
}
return Status.OK_STATUS;
}
/* (non-Javadoc)
* @see org.eclipse.core.jobs.Job#belongsTo(java.lang.Object)
*/
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 particualr 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 (IWorkbenchAdapter) Util.getAdapter(element, IWorkbenchAdapter.class);
}
};
job.addJobChangeListener(new JobChangeAdapter() {
/*
* (non-Javadoc)
*
* @see org.eclipse.core.runtime.jobs.JobChangeAdapter#done(org.eclipse.core.runtime.jobs.IJobChangeEvent)
*/
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) {
/*
* (non-Javadoc)
*
* @see org.eclipse.ui.progress.UIJob#runInUIThread(org.eclipse.core.runtime.IProgressMonitor)
*/
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) {
/*
* (non-Javadoc)
*
* @see org.eclipse.ui.progress.UIJob#runInUIThread(org.eclipse.core.runtime.IProgressMonitor)
*/
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);
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;
}
Platform.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() {
/*
* (non-Javadoc)
* @see org.eclipse.jface.progress.IElementCollector#add(java.lang.Object, org.eclipse.core.runtime.IProgressMonitor)
*/
public void add(Object element, IProgressMonitor monitor) {
add(new Object[] { element }, monitor);
}
/*
* (non-Javadoc)
* @see org.eclipse.jface.progress.IElementCollector#add(java.lang.Object[], org.eclipse.core.runtime.IProgressMonitor)
*/
public void add(Object[] elements, IProgressMonitor monitor) {
addChildren(parent, elements, monitor);
}
/*
* (non-Javadoc)
*
* @see org.eclipse.jface.progress.IElementCollector#done()
*/
public void done() {
runClearPlaceholderJob(placeholder);
}
};
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy