mirror of
https://github.com/eclipse-cdt/cdt
synced 2025-04-29 19:45:01 +02:00
PR# 104605
When exploding a binary in the CView not to do it in the UI thread and use a deferred manager to show "pending" while we finish the parsing.
This commit is contained in:
parent
67654f8f4f
commit
55f06e88cb
4 changed files with 928 additions and 5 deletions
|
@ -22,35 +22,63 @@ import org.eclipse.cdt.core.model.ICElement;
|
||||||
import org.eclipse.cdt.core.model.ICProject;
|
import org.eclipse.cdt.core.model.ICProject;
|
||||||
import org.eclipse.cdt.core.model.IIncludeReference;
|
import org.eclipse.cdt.core.model.IIncludeReference;
|
||||||
import org.eclipse.cdt.core.model.ILibraryReference;
|
import org.eclipse.cdt.core.model.ILibraryReference;
|
||||||
|
import org.eclipse.cdt.internal.ui.util.RemoteTreeContentManager;
|
||||||
|
import org.eclipse.cdt.internal.ui.util.RemoteTreeViewer;
|
||||||
import org.eclipse.cdt.ui.CElementContentProvider;
|
import org.eclipse.cdt.ui.CElementContentProvider;
|
||||||
import org.eclipse.core.resources.IContainer;
|
import org.eclipse.core.resources.IContainer;
|
||||||
import org.eclipse.core.runtime.IPath;
|
import org.eclipse.core.runtime.IPath;
|
||||||
|
import org.eclipse.jface.viewers.TreeViewer;
|
||||||
|
import org.eclipse.jface.viewers.Viewer;
|
||||||
|
import org.eclipse.ui.IWorkbenchPartSite;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* CViewContentProvider
|
* CViewContentProvider
|
||||||
*/
|
*/
|
||||||
public class CViewContentProvider extends CElementContentProvider {
|
public class CViewContentProvider extends CElementContentProvider {
|
||||||
|
private RemoteTreeContentManager fManager;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public CViewContentProvider() {
|
public CViewContentProvider(TreeViewer viewer, IWorkbenchPartSite site) {
|
||||||
super();
|
super();
|
||||||
|
fManager = createContentManager(viewer, site);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param provideMembers
|
* @param provideMembers
|
||||||
* @param provideWorkingCopy
|
* @param provideWorkingCopy
|
||||||
*/
|
*/
|
||||||
public CViewContentProvider(boolean provideMembers, boolean provideWorkingCopy) {
|
public CViewContentProvider(TreeViewer viewer, IWorkbenchPartSite site, boolean provideMembers, boolean provideWorkingCopy) {
|
||||||
super(provideMembers, provideWorkingCopy);
|
super(provideMembers, provideWorkingCopy);
|
||||||
|
fManager = createContentManager(viewer, site);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected RemoteTreeContentManager createContentManager(TreeViewer viewer, IWorkbenchPartSite site) {
|
||||||
|
if (site == null) {
|
||||||
|
return new RemoteTreeContentManager(this, (RemoteTreeViewer)viewer, null);
|
||||||
|
}
|
||||||
|
return new RemoteTreeContentManager(this, (RemoteTreeViewer)viewer, site);
|
||||||
|
}
|
||||||
|
|
||||||
/* (non-Javadoc)
|
/* (non-Javadoc)
|
||||||
* @see org.eclipse.jface.viewers.ITreeContentProvider#getChildren(java.lang.Object)
|
* @see org.eclipse.jface.viewers.ITreeContentProvider#getChildren(java.lang.Object)
|
||||||
*/
|
*/
|
||||||
public Object[] getChildren(Object element) {
|
public Object[] getChildren(Object element) {
|
||||||
Object[] objs = super.getChildren(element);
|
Object[] objs = null;
|
||||||
|
|
||||||
|
// use the the deferred manager for some cases
|
||||||
|
if (element instanceof IBinary) {
|
||||||
|
// It takes sometimes to parse binaries deferred it
|
||||||
|
objs = fManager.getChildren(element);
|
||||||
|
} else if (element instanceof IArchive) {
|
||||||
|
// It takes sometimes to parse archives deferred it
|
||||||
|
objs = fManager.getChildren(element);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (objs == null) {
|
||||||
|
objs = super.getChildren(element);
|
||||||
|
}
|
||||||
Object[] extras = null;
|
Object[] extras = null;
|
||||||
try {
|
try {
|
||||||
if (element instanceof ICProject) {
|
if (element instanceof ICProject) {
|
||||||
|
@ -170,7 +198,11 @@ public class CViewContentProvider extends CElementContentProvider {
|
||||||
* @see org.eclipse.jface.viewers.ITreeContentProvider#hasChildren(java.lang.Object)
|
* @see org.eclipse.jface.viewers.ITreeContentProvider#hasChildren(java.lang.Object)
|
||||||
*/
|
*/
|
||||||
public boolean hasChildren(Object element) {
|
public boolean hasChildren(Object element) {
|
||||||
if (element instanceof IBinaryContainer) {
|
if (element instanceof IBinary) {
|
||||||
|
return fManager.mayHaveChildren(element);
|
||||||
|
} else if (element instanceof IArchive) {
|
||||||
|
return fManager.mayHaveChildren(element);
|
||||||
|
} else if (element instanceof IBinaryContainer) {
|
||||||
try {
|
try {
|
||||||
IBinaryContainer cont = (IBinaryContainer)element;
|
IBinaryContainer cont = (IBinaryContainer)element;
|
||||||
IBinary[] bins = getBinaries(cont);
|
IBinary[] bins = getBinaries(cont);
|
||||||
|
@ -199,4 +231,23 @@ public class CViewContentProvider extends CElementContentProvider {
|
||||||
}
|
}
|
||||||
return super.hasChildren(element);
|
return super.hasChildren(element);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc)
|
||||||
|
* @see org.eclipse.jface.viewers.IContentProvider#dispose()
|
||||||
|
*/
|
||||||
|
public void dispose() {
|
||||||
|
if (fManager != null) {
|
||||||
|
fManager.cancel();
|
||||||
|
}
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc)
|
||||||
|
* @see org.eclipse.jface.viewers.IContentProvider#inputChanged(org.eclipse.jface.viewers.Viewer, java.lang.Object, java.lang.Object)
|
||||||
|
*/
|
||||||
|
public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
|
||||||
|
fManager.cancel();
|
||||||
|
super.inputChanged(viewer, oldInput, newInput);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,84 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (c) 2003, 2005 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.cdt.internal.ui.util;
|
||||||
|
|
||||||
|
import org.eclipse.core.runtime.IAdaptable;
|
||||||
|
import org.eclipse.jface.resource.ImageDescriptor;
|
||||||
|
import org.eclipse.ui.model.IWorkbenchAdapter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The PendingUpdateAdapter is a convenience object that can be used
|
||||||
|
* by a BaseWorkbenchContentProvider that wants to show a pending update.
|
||||||
|
*/
|
||||||
|
public class PendingUpdateAdapter implements IWorkbenchAdapter, IAdaptable {
|
||||||
|
|
||||||
|
boolean removed = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return whether or not this has been removed from the tree.
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
public boolean isRemoved() {
|
||||||
|
return removed;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set whether or not this has been removed from the tree.
|
||||||
|
* @param removedValue boolean
|
||||||
|
*/
|
||||||
|
public void setRemoved(boolean removedValue) {
|
||||||
|
this.removed = removedValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new instance of the receiver.
|
||||||
|
*/
|
||||||
|
public PendingUpdateAdapter() {
|
||||||
|
//No initial behavior
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc)
|
||||||
|
* @see org.eclipse.core.runtime.IAdaptable#getAdapter(java.lang.Class)
|
||||||
|
*/
|
||||||
|
public Object getAdapter(Class adapter) {
|
||||||
|
if (adapter == IWorkbenchAdapter.class)
|
||||||
|
return this;
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc)
|
||||||
|
* @see org.eclipse.ui.model.IWorkbenchAdapter#getChildren(java.lang.Object)
|
||||||
|
*/
|
||||||
|
public Object[] getChildren(Object o) {
|
||||||
|
return new Object[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc)
|
||||||
|
* @see org.eclipse.ui.model.IWorkbenchAdapter#getImageDescriptor(java.lang.Object)
|
||||||
|
*/
|
||||||
|
public ImageDescriptor getImageDescriptor(Object object) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc)
|
||||||
|
* @see org.eclipse.ui.model.IWorkbenchAdapter#getLabel(java.lang.Object)
|
||||||
|
*/
|
||||||
|
public String getLabel(Object o) {
|
||||||
|
return "Pending"; //$NON-NLS-1$
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc)
|
||||||
|
* @see org.eclipse.ui.model.IWorkbenchAdapter#getParent(java.lang.Object)
|
||||||
|
*/
|
||||||
|
public Object getParent(Object o) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,357 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (c) 2000, 2005 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.cdt.internal.ui.util;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.eclipse.core.runtime.IAdaptable;
|
||||||
|
import org.eclipse.core.runtime.IProgressMonitor;
|
||||||
|
import org.eclipse.core.runtime.IStatus;
|
||||||
|
import org.eclipse.core.runtime.Status;
|
||||||
|
import org.eclipse.core.runtime.jobs.Job;
|
||||||
|
import org.eclipse.jface.viewers.ITreeContentProvider;
|
||||||
|
import org.eclipse.swt.widgets.Control;
|
||||||
|
import org.eclipse.ui.IWorkbenchPartSite;
|
||||||
|
import org.eclipse.ui.PlatformUI;
|
||||||
|
import org.eclipse.ui.progress.IDeferredWorkbenchAdapter;
|
||||||
|
import org.eclipse.ui.progress.IElementCollector;
|
||||||
|
import org.eclipse.ui.progress.IWorkbenchSiteProgressService;
|
||||||
|
import org.eclipse.ui.progress.WorkbenchJob;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A remote content manager that merges content into a tree rather then replacing
|
||||||
|
* its children with a "pending" node, and then the real children when they are available.
|
||||||
|
* This avoids collapsing the viewer when a refresh is performed. This implementation is
|
||||||
|
* currently tied to the <code>RemoteTreeViewer</code>.
|
||||||
|
*
|
||||||
|
* @since 3.1
|
||||||
|
*/
|
||||||
|
public class RemoteTreeContentManager {
|
||||||
|
private RemoteTreeViewer fViewer;
|
||||||
|
private IWorkbenchSiteProgressService progressService;
|
||||||
|
private ITreeContentProvider fProvider;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Job to fetch children
|
||||||
|
*/
|
||||||
|
private Job fFetchJob = new FetchJob();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Queue of parents to fetch children for, and
|
||||||
|
* associated element collectors and deferred adapters.
|
||||||
|
*/
|
||||||
|
private List fElementQueue = new ArrayList();
|
||||||
|
private List fCollectors = new ArrayList();
|
||||||
|
private List fAdapaters = new ArrayList();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetching children is done in a single background job.
|
||||||
|
* This makes fetching single threaded/serial per view.
|
||||||
|
*/
|
||||||
|
class FetchJob extends Job {
|
||||||
|
|
||||||
|
public FetchJob() {
|
||||||
|
super("FetchJob"); //$NON-NLS-1$
|
||||||
|
setSystem(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc)
|
||||||
|
* @see org.eclipse.core.runtime.jobs.Job#run(org.eclipse.core.runtime.IProgressMonitor)
|
||||||
|
*/
|
||||||
|
protected IStatus run(IProgressMonitor monitor) {
|
||||||
|
while (!fElementQueue.isEmpty() && !monitor.isCanceled()) {
|
||||||
|
Object element = null;
|
||||||
|
IElementCollector collector = null;
|
||||||
|
IDeferredWorkbenchAdapter adapter = null;
|
||||||
|
synchronized (fElementQueue) {
|
||||||
|
// could have been cancelled after entering the while loop
|
||||||
|
if (fElementQueue.isEmpty()) {
|
||||||
|
return Status.CANCEL_STATUS;
|
||||||
|
}
|
||||||
|
element = fElementQueue.remove(0);
|
||||||
|
collector = (IElementCollector) fCollectors.remove(0);
|
||||||
|
adapter = (IDeferredWorkbenchAdapter) fAdapaters.remove(0);
|
||||||
|
}
|
||||||
|
adapter.fetchDeferredChildren(element, collector, monitor);
|
||||||
|
}
|
||||||
|
if (monitor.isCanceled()) {
|
||||||
|
return Status.CANCEL_STATUS;
|
||||||
|
}
|
||||||
|
return Status.OK_STATUS;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Element collector
|
||||||
|
*/
|
||||||
|
public class Collector implements IElementCollector {
|
||||||
|
// number of children added to the tree
|
||||||
|
int offset = 0;
|
||||||
|
Object fParent;
|
||||||
|
|
||||||
|
public Collector(Object parent) {
|
||||||
|
fParent = parent;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* (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) {
|
||||||
|
Object[] filtered = fViewer.filter(elements);
|
||||||
|
if (filtered.length > 0) {
|
||||||
|
replaceChildren(fParent, filtered, offset, monitor);
|
||||||
|
offset = offset + filtered.length;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see org.eclipse.jface.progress.IElementCollector#done()
|
||||||
|
*/
|
||||||
|
public void done() {
|
||||||
|
prune(fParent, offset);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Contructs a new content manager.
|
||||||
|
*
|
||||||
|
* @param provider content provider
|
||||||
|
* @param viewer viewer
|
||||||
|
* @param site part site
|
||||||
|
*/
|
||||||
|
public RemoteTreeContentManager(ITreeContentProvider provider, RemoteTreeViewer viewer, IWorkbenchPartSite site) {
|
||||||
|
fViewer = viewer;
|
||||||
|
fProvider = provider;
|
||||||
|
if (site != null) {
|
||||||
|
Object siteService = site.getAdapter(IWorkbenchSiteProgressService.class);
|
||||||
|
if (siteService != null) {
|
||||||
|
progressService = (IWorkbenchSiteProgressService) siteService;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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, possibly <code>null</code>
|
||||||
|
* @return IElementCollector
|
||||||
|
*/
|
||||||
|
protected IElementCollector createElementCollector(Object parent, PendingUpdateAdapter placeholder) {
|
||||||
|
return new Collector(parent);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 <code>null</code> if parent is not an instance of
|
||||||
|
* IDeferredWorkbenchAdapter.
|
||||||
|
*/
|
||||||
|
public Object[] getChildren(final Object parent) {
|
||||||
|
IDeferredWorkbenchAdapter element = getAdapter(parent);
|
||||||
|
if (element == null)
|
||||||
|
return null;
|
||||||
|
Object[] currentChildren = fViewer.getCurrentChildren(parent);
|
||||||
|
PendingUpdateAdapter placeholder = null;
|
||||||
|
if (currentChildren == null || currentChildren.length == 0) {
|
||||||
|
placeholder = new PendingUpdateAdapter();
|
||||||
|
}
|
||||||
|
startFetchingDeferredChildren(parent, element, placeholder);
|
||||||
|
if (placeholder == null) {
|
||||||
|
return currentChildren;
|
||||||
|
}
|
||||||
|
return new Object[] { placeholder };
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a UIJob to replace the children of the parent in the tree viewer.
|
||||||
|
*
|
||||||
|
* @param parent the parent for which children are to be replaced
|
||||||
|
* @param children the replacement children
|
||||||
|
* @param offset the offset at which to start replacing children
|
||||||
|
* @param monitor progress monitor
|
||||||
|
*/
|
||||||
|
protected void replaceChildren(final Object parent, final Object[] children, final int offset, IProgressMonitor monitor) {
|
||||||
|
if (monitor.isCanceled()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
WorkbenchJob updateJob = new WorkbenchJob("IncrementalDeferredTreeContentManager") { //$NON-NLS-1$
|
||||||
|
/*
|
||||||
|
* (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 (fViewer.getControl().isDisposed())
|
||||||
|
return Status.CANCEL_STATUS;
|
||||||
|
fViewer.replace(parent, children, offset);
|
||||||
|
return Status.OK_STATUS;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
updateJob.setSystem(true);
|
||||||
|
updateJob.setPriority(Job.INTERACTIVE);
|
||||||
|
updateJob.schedule();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a UIJob to prune the children of the parent in the tree viewer, starting
|
||||||
|
* at the given offset.
|
||||||
|
*
|
||||||
|
* @param parent the parent for which children should be pruned
|
||||||
|
* @param offset the offset at which children should be pruned. All children at and after
|
||||||
|
* this index will be removed from the tree.
|
||||||
|
* @param monitor
|
||||||
|
*/
|
||||||
|
protected void prune(final Object parent, final int offset) {
|
||||||
|
WorkbenchJob updateJob = new WorkbenchJob("DeferredTree") { //$NON-NLS-1$
|
||||||
|
/*
|
||||||
|
* (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 (fViewer.getControl().isDisposed())
|
||||||
|
return Status.CANCEL_STATUS;
|
||||||
|
fViewer.prune(parent, offset);
|
||||||
|
return Status.OK_STATUS;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
updateJob.setSystem(true);
|
||||||
|
updateJob.setPriority(Job.INTERACTIVE);
|
||||||
|
updateJob.schedule();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 == null || placeholder.isRemoved() || !PlatformUI.isWorkbenchRunning())
|
||||||
|
return;
|
||||||
|
//Clear the placeholder if it is still there
|
||||||
|
WorkbenchJob clearJob = new WorkbenchJob("DeferredTreeContentManager_ClearJob") { //$NON-NLS-1$
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see org.eclipse.ui.progress.UIJob#runInUIThread(org.eclipse.core.runtime.IProgressMonitor)
|
||||||
|
*/
|
||||||
|
public IStatus runInUIThread(IProgressMonitor monitor) {
|
||||||
|
if (!placeholder.isRemoved()) {
|
||||||
|
Control control = fViewer.getControl();
|
||||||
|
if (control.isDisposed())
|
||||||
|
return Status.CANCEL_STATUS;
|
||||||
|
fViewer.remove(placeholder);
|
||||||
|
placeholder.setRemoved(true);
|
||||||
|
}
|
||||||
|
return Status.OK_STATUS;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
clearJob.setSystem(true);
|
||||||
|
clearJob.schedule();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc)
|
||||||
|
* @see org.eclipse.ui.progress.DeferredTreeContentManager#getFetchJobName(java.lang.Object, org.eclipse.ui.progress.IDeferredWorkbenchAdapter)
|
||||||
|
*/
|
||||||
|
protected String getFetchJobName(Object parent, IDeferredWorkbenchAdapter adapter) {
|
||||||
|
return "RemoteTreeContentManager"; //$NON-NLS-1$
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 <code>null</code>
|
||||||
|
*/
|
||||||
|
protected IDeferredWorkbenchAdapter getAdapter(Object element) {
|
||||||
|
if (element instanceof IDeferredWorkbenchAdapter)
|
||||||
|
return (IDeferredWorkbenchAdapter) element;
|
||||||
|
if (!(element instanceof IAdaptable))
|
||||||
|
return null;
|
||||||
|
Object adapter = ((IAdaptable) element)
|
||||||
|
.getAdapter(IDeferredWorkbenchAdapter.class);
|
||||||
|
if (adapter == null)
|
||||||
|
return null;
|
||||||
|
return (IDeferredWorkbenchAdapter) adapter;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void startFetchingDeferredChildren(final Object parent, final IDeferredWorkbenchAdapter adapter, PendingUpdateAdapter placeholder) {
|
||||||
|
final IElementCollector collector = createElementCollector(parent, placeholder);
|
||||||
|
synchronized (fElementQueue) {
|
||||||
|
if (!fElementQueue.contains(parent)) {
|
||||||
|
fElementQueue.add(parent);
|
||||||
|
fCollectors.add(collector);
|
||||||
|
fAdapaters.add(adapter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (progressService == null)
|
||||||
|
fFetchJob.schedule();
|
||||||
|
else
|
||||||
|
progressService.schedule(fFetchJob);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides an optimized lookup for determining if an element has children.
|
||||||
|
* This is required because elements that are populated lazilly can't
|
||||||
|
* answer <code>getChildren</code> just to determine the potential for
|
||||||
|
* children. Throw an AssertionFailedException if element is null.
|
||||||
|
*
|
||||||
|
* @param element The Object being tested. This should not be
|
||||||
|
* <code>null</code>.
|
||||||
|
* @return boolean <code>true</code> 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();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cancels any content this provider is currently fetching.
|
||||||
|
*/
|
||||||
|
public void cancel() {
|
||||||
|
synchronized (fElementQueue) {
|
||||||
|
fFetchJob.cancel();
|
||||||
|
fElementQueue.clear();
|
||||||
|
fAdapaters.clear();
|
||||||
|
fCollectors.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,431 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (c) 2000, 2005 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.cdt.internal.ui.util;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.eclipse.cdt.core.model.ITranslationUnit;
|
||||||
|
import org.eclipse.core.runtime.IAdaptable;
|
||||||
|
import org.eclipse.core.runtime.IProgressMonitor;
|
||||||
|
import org.eclipse.core.runtime.IStatus;
|
||||||
|
import org.eclipse.core.runtime.Status;
|
||||||
|
import org.eclipse.core.runtime.jobs.Job;
|
||||||
|
import org.eclipse.jface.viewers.IStructuredSelection;
|
||||||
|
import org.eclipse.swt.events.DisposeEvent;
|
||||||
|
import org.eclipse.swt.events.DisposeListener;
|
||||||
|
import org.eclipse.swt.widgets.Composite;
|
||||||
|
import org.eclipse.swt.widgets.Item;
|
||||||
|
import org.eclipse.swt.widgets.Tree;
|
||||||
|
import org.eclipse.swt.widgets.TreeItem;
|
||||||
|
import org.eclipse.swt.widgets.Widget;
|
||||||
|
import org.eclipse.ui.model.IWorkbenchAdapter;
|
||||||
|
import org.eclipse.ui.progress.UIJob;
|
||||||
|
|
||||||
|
public class RemoteTreeViewer extends ProblemTreeViewer {
|
||||||
|
private ExpansionJob fExpansionJob = null;
|
||||||
|
private SelectionJob fSelectionJob = null;
|
||||||
|
|
||||||
|
|
||||||
|
class ExpansionJob extends UIJob {
|
||||||
|
|
||||||
|
private Object element;
|
||||||
|
private List parents = new ArrayList(); // top down
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constucts a job to expand the given element.
|
||||||
|
*
|
||||||
|
* @param target the element to expand
|
||||||
|
*/
|
||||||
|
public ExpansionJob() {
|
||||||
|
super("Expansion"); //$NON-NLS-1$
|
||||||
|
setPriority(Job.INTERACTIVE);
|
||||||
|
setSystem(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc)
|
||||||
|
* @see org.eclipse.ui.progress.UIJob#runInUIThread(org.eclipse.core.runtime.IProgressMonitor)
|
||||||
|
*/
|
||||||
|
public IStatus runInUIThread(IProgressMonitor monitor) {
|
||||||
|
if (getControl().isDisposed() || element == null) {
|
||||||
|
return Status.OK_STATUS;
|
||||||
|
}
|
||||||
|
synchronized (RemoteTreeViewer.this) {
|
||||||
|
boolean allParentsExpanded = true;
|
||||||
|
Iterator iterator = parents.iterator();
|
||||||
|
while (iterator.hasNext() && !monitor.isCanceled()) {
|
||||||
|
Object parent = iterator.next();
|
||||||
|
Widget item = findItem(parent);
|
||||||
|
if (item != null) {
|
||||||
|
expandToLevel(parent, 1);
|
||||||
|
} else {
|
||||||
|
allParentsExpanded = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (allParentsExpanded) {
|
||||||
|
Widget item = findItem(element);
|
||||||
|
if (item != null) {
|
||||||
|
if (isExpandable(element)) {
|
||||||
|
expandToLevel(element, 1);
|
||||||
|
}
|
||||||
|
element = null;
|
||||||
|
parents.clear();
|
||||||
|
return Status.OK_STATUS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Status.OK_STATUS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void validate(Object object) {
|
||||||
|
if (element != null) {
|
||||||
|
if (element.equals(object) || parents.contains(object)) {
|
||||||
|
cancel();
|
||||||
|
element = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDeferredExpansion(Object toExpand) {
|
||||||
|
element = toExpand;
|
||||||
|
parents.clear();
|
||||||
|
addAllParents(parents, element);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
class SelectionJob extends UIJob {
|
||||||
|
|
||||||
|
private IStructuredSelection selection;
|
||||||
|
private Object first;
|
||||||
|
private List parents = new ArrayList(); // top down
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constucts a job to select the given element.
|
||||||
|
*
|
||||||
|
* @param target the element to select
|
||||||
|
*/
|
||||||
|
public SelectionJob() {
|
||||||
|
super("Selection"); //$NON-NLS-1$
|
||||||
|
setPriority(Job.INTERACTIVE);
|
||||||
|
setSystem(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc)
|
||||||
|
* @see org.eclipse.ui.progress.UIJob#runInUIThread(org.eclipse.core.runtime.IProgressMonitor)
|
||||||
|
*/
|
||||||
|
public IStatus runInUIThread(IProgressMonitor monitor) {
|
||||||
|
if (getControl().isDisposed() || selection == null) {
|
||||||
|
return Status.OK_STATUS;
|
||||||
|
}
|
||||||
|
synchronized (RemoteTreeViewer.this) {
|
||||||
|
boolean allParentsExpanded = true;
|
||||||
|
Iterator iterator = parents.iterator();
|
||||||
|
while (iterator.hasNext() && !monitor.isCanceled()) {
|
||||||
|
Object parent = iterator.next();
|
||||||
|
Widget item = findItem(parent);
|
||||||
|
if (item != null) {
|
||||||
|
expandToLevel(parent, 1);
|
||||||
|
} else {
|
||||||
|
allParentsExpanded = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (allParentsExpanded) {
|
||||||
|
if (findItem(first) != null) {
|
||||||
|
setSelection(selection, true);
|
||||||
|
selection = null;
|
||||||
|
first = null;
|
||||||
|
parents.clear();
|
||||||
|
return Status.OK_STATUS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Status.OK_STATUS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDeferredSelection(IStructuredSelection sel) {
|
||||||
|
selection = sel;
|
||||||
|
first = selection.getFirstElement();
|
||||||
|
parents.clear();
|
||||||
|
addAllParents(parents, first);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void validate(Object object) {
|
||||||
|
if (first != null) {
|
||||||
|
if (first.equals(object) || parents.contains(object)) {
|
||||||
|
cancel();
|
||||||
|
selection = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a remote tree viewer parented by the given composite.
|
||||||
|
*
|
||||||
|
* @param parent parent composite
|
||||||
|
*/
|
||||||
|
public RemoteTreeViewer(Composite parent) {
|
||||||
|
super(parent);
|
||||||
|
addDisposeListener();
|
||||||
|
fExpansionJob = new ExpansionJob();
|
||||||
|
fSelectionJob = new SelectionJob();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a remote tree viewer parented by the given composite
|
||||||
|
* with the given style.
|
||||||
|
*
|
||||||
|
* @param parent parent composite
|
||||||
|
* @param style style bits
|
||||||
|
*/
|
||||||
|
public RemoteTreeViewer(Composite parent, int style) {
|
||||||
|
super(parent, style);
|
||||||
|
addDisposeListener();
|
||||||
|
fExpansionJob = new ExpansionJob();
|
||||||
|
fSelectionJob = new SelectionJob();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a remote tree viewer with the given tree.
|
||||||
|
*
|
||||||
|
* @param tree tree widget
|
||||||
|
*/
|
||||||
|
public RemoteTreeViewer(Tree tree) {
|
||||||
|
super(tree);
|
||||||
|
addDisposeListener();
|
||||||
|
fExpansionJob = new ExpansionJob();
|
||||||
|
fSelectionJob = new SelectionJob();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addDisposeListener() {
|
||||||
|
getControl().addDisposeListener(new DisposeListener() {
|
||||||
|
public void widgetDisposed(DisposeEvent e) {
|
||||||
|
cancelJobs();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void runDeferredUpdates() {
|
||||||
|
if (fExpansionJob != null) {
|
||||||
|
fExpansionJob.schedule();
|
||||||
|
}
|
||||||
|
if (fSelectionJob != null) {
|
||||||
|
fSelectionJob.schedule();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The given element is being removed from the tree. Cancel
|
||||||
|
* any deferred updates for the element.
|
||||||
|
*
|
||||||
|
* @param element
|
||||||
|
*/
|
||||||
|
protected void validateDeferredUpdates(Object element) {
|
||||||
|
if (element != null) {
|
||||||
|
if (fExpansionJob != null) {
|
||||||
|
fExpansionJob.validate(element);
|
||||||
|
}
|
||||||
|
if (fSelectionJob != null) {
|
||||||
|
fSelectionJob.validate(element);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc)
|
||||||
|
* @see org.eclipse.jface.viewers.AbstractTreeViewer#add(java.lang.Object, java.lang.Object)
|
||||||
|
*/
|
||||||
|
public synchronized void add(Object parentElement, Object childElement) {
|
||||||
|
super.add(parentElement, childElement);
|
||||||
|
runDeferredUpdates();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc)
|
||||||
|
* @see org.eclipse.jface.viewers.AbstractTreeViewer#add(java.lang.Object, java.lang.Object[])
|
||||||
|
*/
|
||||||
|
public synchronized void add(Object parentElement, Object[] childElements) {
|
||||||
|
super.add(parentElement, childElements);
|
||||||
|
runDeferredUpdates();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc)
|
||||||
|
* @see org.eclipse.jface.viewers.AbstractTreeViewer#remove(java.lang.Object)
|
||||||
|
*/
|
||||||
|
public synchronized void remove(Object element) {
|
||||||
|
validateDeferredUpdates(element);
|
||||||
|
super.remove(element);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc)
|
||||||
|
* @see org.eclipse.jface.viewers.AbstractTreeViewer#remove(java.lang.Object[])
|
||||||
|
*/
|
||||||
|
public synchronized void remove(Object[] elements) {
|
||||||
|
for (int i = 0; i < elements.length; i++) {
|
||||||
|
validateDeferredUpdates(elements[i]);
|
||||||
|
}
|
||||||
|
super.remove(elements);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cancels any deferred updates currently scheduled/running.
|
||||||
|
*/
|
||||||
|
public void cancelJobs() {
|
||||||
|
cancel(fSelectionJob);
|
||||||
|
cancel(fExpansionJob);
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized void deferExpansion(Object element) {
|
||||||
|
TreeItem treeItem = (TreeItem) findItem(element);
|
||||||
|
if (treeItem == null) {
|
||||||
|
fExpansionJob.setDeferredExpansion(element);
|
||||||
|
fExpansionJob.schedule();
|
||||||
|
} else {
|
||||||
|
if (!getExpanded(treeItem)) {
|
||||||
|
fExpansionJob.setDeferredExpansion(element);
|
||||||
|
fExpansionJob.schedule();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized void deferSelection(IStructuredSelection selection) {
|
||||||
|
if (fSelectionJob == null) {
|
||||||
|
fSelectionJob = new SelectionJob();
|
||||||
|
}
|
||||||
|
|
||||||
|
fSelectionJob.setDeferredSelection(selection);
|
||||||
|
fSelectionJob.schedule();
|
||||||
|
}
|
||||||
|
|
||||||
|
public IStructuredSelection getDeferredSelection() {
|
||||||
|
if (fSelectionJob != null) {
|
||||||
|
return fSelectionJob.selection;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void cancel(Job job) {
|
||||||
|
if (job != null) {
|
||||||
|
job.cancel();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addAllParents(List list, Object element) {
|
||||||
|
if (element instanceof IAdaptable) {
|
||||||
|
IAdaptable adaptable = (IAdaptable) element;
|
||||||
|
IWorkbenchAdapter adapter = (IWorkbenchAdapter) adaptable.getAdapter(IWorkbenchAdapter.class);
|
||||||
|
if (adapter != null) {
|
||||||
|
Object parent = adapter.getParent(element);
|
||||||
|
if (parent != null) {
|
||||||
|
list.add(0, parent);
|
||||||
|
if (!(parent instanceof ITranslationUnit))
|
||||||
|
addAllParents(list, parent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Object[] filter(Object[] elements) {
|
||||||
|
return super.filter(elements);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Object[] getCurrentChildren(Object parent) {
|
||||||
|
Widget widget = findItem(parent);
|
||||||
|
if (widget != null) {
|
||||||
|
Item[] items = getChildren(widget);
|
||||||
|
Object[] children = new Object[items.length];
|
||||||
|
for (int i = 0; i < children.length; i++) {
|
||||||
|
Object data = items[i].getData();
|
||||||
|
if (data == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
children[i] = data;
|
||||||
|
}
|
||||||
|
return children;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized void prune(final Object parent, final int offset) {
|
||||||
|
Widget widget = findItem(parent);
|
||||||
|
if (widget != null) {
|
||||||
|
final Item[] currentChildren = getChildren(widget);
|
||||||
|
if (offset < currentChildren.length) {
|
||||||
|
preservingSelection(new Runnable() {
|
||||||
|
public void run() {
|
||||||
|
for (int i = offset; i < currentChildren.length; i++) {
|
||||||
|
if (currentChildren[i].getData() != null) {
|
||||||
|
disassociate(currentChildren[i]);
|
||||||
|
}
|
||||||
|
currentChildren[i].dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized void replace(final Object parent, final Object[] children, final int offset) {
|
||||||
|
preservingSelection(new Runnable() {
|
||||||
|
public void run() {
|
||||||
|
Widget widget = findItem(parent);
|
||||||
|
if (widget == null) {
|
||||||
|
add(parent, children);
|
||||||
|
} else {
|
||||||
|
Item[] currentChildren = getChildren(widget);
|
||||||
|
int pos = offset;
|
||||||
|
if (pos >= currentChildren.length) {
|
||||||
|
// append
|
||||||
|
add(parent, children);
|
||||||
|
} else {
|
||||||
|
// replace
|
||||||
|
for (int i = 0; i < children.length; i++) {
|
||||||
|
Object child = children[i];
|
||||||
|
if (pos < currentChildren.length) {
|
||||||
|
// replace
|
||||||
|
Item item = currentChildren[pos];
|
||||||
|
Object data = item.getData();
|
||||||
|
if (!child.equals(data)) {
|
||||||
|
// no need to cancel pending updates here, the child may have shifted up/down
|
||||||
|
internalRefresh(item, child, true, true);
|
||||||
|
} else {
|
||||||
|
// If it's the same child, the label/content may still have changed
|
||||||
|
doUpdateItem(item, child);
|
||||||
|
updatePlus(item, child);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// add
|
||||||
|
int numLeft = children.length - i;
|
||||||
|
if (numLeft > 1) {
|
||||||
|
Object[] others = new Object[numLeft];
|
||||||
|
System.arraycopy(children, i, others, 0, numLeft);
|
||||||
|
add(parent, others);
|
||||||
|
} else {
|
||||||
|
add(parent, child);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
pos++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
runDeferredUpdates();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
Loading…
Add table
Reference in a new issue