Skip to main content
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJohn Cortell2011-04-14 16:31:22 -0400
committerJohn Cortell2011-04-14 16:31:22 -0400
commit9782f044c75004609e2eef2caf43dcff75a84012 (patch)
tree854b494ad83961cb08f97fc56c50d85aefffd6cd /debug/org.eclipse.cdt.debug.ui/src/org
parent78cb17e7084bf121bac4b87d2caf098d7833be36 (diff)
downloadorg.eclipse.cdt-9782f044c75004609e2eef2caf43dcff75a84012.tar.gz
org.eclipse.cdt-9782f044c75004609e2eef2caf43dcff75a84012.tar.xz
org.eclipse.cdt-9782f044c75004609e2eef2caf43dcff75a84012.zip
Bug 342141 - Executables view content goes stale in various scenarios
Diffstat (limited to 'debug/org.eclipse.cdt.debug.ui/src/org')
-rw-r--r--debug/org.eclipse.cdt.debug.ui/src/org/eclipse/cdt/debug/internal/ui/views/executables/ExecutablesContentProvider.java46
-rw-r--r--debug/org.eclipse.cdt.debug.ui/src/org/eclipse/cdt/debug/internal/ui/views/executables/ExecutablesView.java13
-rw-r--r--debug/org.eclipse.cdt.debug.ui/src/org/eclipse/cdt/debug/internal/ui/views/executables/ExecutablesViewer.java53
-rw-r--r--debug/org.eclipse.cdt.debug.ui/src/org/eclipse/cdt/debug/internal/ui/views/executables/Messages.java1
-rw-r--r--debug/org.eclipse.cdt.debug.ui/src/org/eclipse/cdt/debug/internal/ui/views/executables/Messages.properties1
-rw-r--r--debug/org.eclipse.cdt.debug.ui/src/org/eclipse/cdt/debug/internal/ui/views/executables/SourceFilesContentProvider.java403
-rw-r--r--debug/org.eclipse.cdt.debug.ui/src/org/eclipse/cdt/debug/internal/ui/views/executables/SourceFilesViewer.java122
7 files changed, 409 insertions, 230 deletions
diff --git a/debug/org.eclipse.cdt.debug.ui/src/org/eclipse/cdt/debug/internal/ui/views/executables/ExecutablesContentProvider.java b/debug/org.eclipse.cdt.debug.ui/src/org/eclipse/cdt/debug/internal/ui/views/executables/ExecutablesContentProvider.java
index 18e7ced7a4..132c4a45fb 100644
--- a/debug/org.eclipse.cdt.debug.ui/src/org/eclipse/cdt/debug/internal/ui/views/executables/ExecutablesContentProvider.java
+++ b/debug/org.eclipse.cdt.debug.ui/src/org/eclipse/cdt/debug/internal/ui/views/executables/ExecutablesContentProvider.java
@@ -11,28 +11,44 @@
package org.eclipse.cdt.debug.internal.ui.views.executables;
-import com.ibm.icu.text.DateFormat;
import java.util.Date;
+import java.util.List;
import org.eclipse.cdt.debug.core.executables.Executable;
import org.eclipse.cdt.debug.core.executables.ExecutablesManager;
+import org.eclipse.cdt.debug.core.executables.IExecutablesChangeListener;
import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
import org.eclipse.jface.viewers.ColumnLabelProvider;
import org.eclipse.jface.viewers.IStructuredContentProvider;
import org.eclipse.jface.viewers.ITreeContentProvider;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.jface.viewers.ViewerCell;
+import org.eclipse.ui.progress.WorkbenchJob;
+
+import com.ibm.icu.text.DateFormat;
-class ExecutablesContentProvider extends ColumnLabelProvider implements IStructuredContentProvider, ITreeContentProvider {
+class ExecutablesContentProvider extends ColumnLabelProvider implements IStructuredContentProvider, ITreeContentProvider, IExecutablesChangeListener {
- public ExecutablesContentProvider(TreeViewer viewer) {
+ final private TreeViewer viewer;
+
+ public ExecutablesContentProvider(final TreeViewer viewer) {
+ this.viewer = viewer;
+ ExecutablesManager.getExecutablesManager().addExecutablesChangeListener(this);
}
public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
}
+ /* (non-Javadoc)
+ * @see org.eclipse.jface.viewers.BaseLabelProvider#dispose()
+ */
+ @Override
public void dispose() {
+ ExecutablesManager.getExecutablesManager().removeExecutablesChangeListener(this);
}
public Object[] getElements(final Object inputElement) {
@@ -100,4 +116,28 @@ class ExecutablesContentProvider extends ColumnLabelProvider implements IStructu
return new Object[] {};
}
+ /* (non-Javadoc)
+ * @see org.eclipse.cdt.debug.core.executables.IExecutablesChangeListener#executablesListChanged()
+ */
+ public void executablesListChanged() {
+ new WorkbenchJob("execs list changed") { //$NON-NLS-1$
+ @Override
+ public IStatus runInUIThread(IProgressMonitor monitor) {
+ viewer.refresh(null);
+ if (viewer instanceof BaseViewer) {
+ ((BaseViewer)viewer).packColumns();
+ }
+ return Status.OK_STATUS;
+ }
+ }.schedule();
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.cdt.debug.core.executables.IExecutablesChangeListener#executablesChanged(java.util.List)
+ */
+ public void executablesChanged(List<Executable> executables) {
+ // Our concern is only if the list of executables changed. The
+ // content provider for the source files viewer will care about
+ // whether the Executables themselves change
+ }
} \ No newline at end of file
diff --git a/debug/org.eclipse.cdt.debug.ui/src/org/eclipse/cdt/debug/internal/ui/views/executables/ExecutablesView.java b/debug/org.eclipse.cdt.debug.ui/src/org/eclipse/cdt/debug/internal/ui/views/executables/ExecutablesView.java
index 4a35f5c5b0..83b37d6be7 100644
--- a/debug/org.eclipse.cdt.debug.ui/src/org/eclipse/cdt/debug/internal/ui/views/executables/ExecutablesView.java
+++ b/debug/org.eclipse.cdt.debug.ui/src/org/eclipse/cdt/debug/internal/ui/views/executables/ExecutablesView.java
@@ -58,7 +58,7 @@ import org.eclipse.ui.XMLMemento;
import org.eclipse.ui.actions.ActionFactory;
import org.eclipse.ui.dialogs.ListSelectionDialog;
import org.eclipse.ui.part.ViewPart;
-import org.eclipse.ui.progress.UIJob;
+import org.eclipse.ui.progress.WorkbenchJob;
/**
* ExecutablesView displays a list of executable files either in the workspace
@@ -176,6 +176,7 @@ public class ExecutablesView extends ViewPart {
class ColumnLabelProvider extends LabelProvider {
+ @Override
public String getText(Object element) {
return (String) element;
}
@@ -193,6 +194,7 @@ public class ExecutablesView extends ViewPart {
*
* @see org.eclipse.jface.action.Action#run()
*/
+ @Override
public void run() {
ListSelectionDialog dialog = new ListSelectionDialog(ExecutablesView.this.getExecutablesViewer().getTree().getShell(), this,
new ColumnContentProvider(), new ColumnLabelProvider(), Messages.ExecutablesView_SelectColumns);
@@ -250,7 +252,6 @@ public class ExecutablesView extends ViewPart {
// Create the two sub viewers.
executablesViewer = new ExecutablesViewer(this, sashForm, SWT.FULL_SELECTION | SWT.BORDER | SWT.MULTI);
focusedViewer = executablesViewer;
- ExecutablesManager.getExecutablesManager().addExecutablesChangeListener(executablesViewer);
sourceFilesViewer = new SourceFilesViewer(this, sashForm, SWT.BORDER | SWT.MULTI);
executablesViewer.getTree().addFocusListener(new FocusListener() {
@@ -416,6 +417,7 @@ public class ExecutablesView extends ViewPart {
private Action createRemoveAction() {
Action action = new Action(Messages.ExecutablesView_Remove) {
+ @Override
public void run() {
ISelection selection = getExecutablesViewer().getSelection();
if (selection instanceof IStructuredSelection)
@@ -432,8 +434,9 @@ public class ExecutablesView extends ViewPart {
if (confirm)
{
- Job removeJob = new UIJob(Messages.ExecutablesView_RemoveExes) {
+ Job removeJob = new WorkbenchJob(Messages.ExecutablesView_RemoveExes) {
+ @Override
public IStatus runInUIThread(IProgressMonitor monitor) {
IStatus result = ExecutablesManager.getExecutablesManager().removeExecutables(selectedExesArray, monitor);
if (result.getSeverity() != IStatus.OK)
@@ -490,6 +493,7 @@ public class ExecutablesView extends ViewPart {
private Action createImportAction() {
Action action = new Action(Messages.ExecutablesView_Import) {
+ @Override
public void run() {
FileDialog dialog = new FileDialog(getViewSite().getShell(), SWT.NONE);
dialog.setText(Messages.ExecutablesView_SelectExeFile);
@@ -515,8 +519,10 @@ public class ExecutablesView extends ViewPart {
private Action createRefreshAction() {
Action action = new Action(Messages.ExecutablesView_Refresh) {
+ @Override
public void run() {
ExecutablesManager.getExecutablesManager().refresh(null);
+ sourceFilesViewer.restartCanceledExecutableParse();
}
};
action.setToolTipText(Messages.ExecutablesView_RefreshList);
@@ -574,7 +580,6 @@ public class ExecutablesView extends ViewPart {
@Override
public void dispose() {
- ExecutablesManager.getExecutablesManager().removeExecutablesChangeListener(executablesViewer);
super.dispose();
}
diff --git a/debug/org.eclipse.cdt.debug.ui/src/org/eclipse/cdt/debug/internal/ui/views/executables/ExecutablesViewer.java b/debug/org.eclipse.cdt.debug.ui/src/org/eclipse/cdt/debug/internal/ui/views/executables/ExecutablesViewer.java
index bc5f2135c4..cd225886b7 100644
--- a/debug/org.eclipse.cdt.debug.ui/src/org/eclipse/cdt/debug/internal/ui/views/executables/ExecutablesViewer.java
+++ b/debug/org.eclipse.cdt.debug.ui/src/org/eclipse/cdt/debug/internal/ui/views/executables/ExecutablesViewer.java
@@ -10,19 +10,12 @@
*******************************************************************************/
package org.eclipse.cdt.debug.internal.ui.views.executables;
-import java.util.List;
-
import org.eclipse.cdt.debug.core.executables.Executable;
import org.eclipse.cdt.debug.core.executables.ExecutablesManager;
-import org.eclipse.cdt.debug.core.executables.IExecutablesChangeListener;
-import org.eclipse.core.runtime.IProgressMonitor;
-import org.eclipse.core.runtime.IStatus;
-import org.eclipse.core.runtime.Status;
import org.eclipse.jface.action.IMenuListener;
import org.eclipse.jface.action.IMenuManager;
import org.eclipse.jface.action.MenuManager;
import org.eclipse.jface.action.Separator;
-import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.jface.viewers.ViewerComparator;
import org.eclipse.jface.viewers.ViewerDropAdapter;
@@ -35,12 +28,11 @@ import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.widgets.TreeColumn;
import org.eclipse.ui.IWorkbenchActionConstants;
-import org.eclipse.ui.progress.UIJob;
/**
* Displays the list of executables gathered by the ExecutablesManager
*/
-public class ExecutablesViewer extends BaseViewer implements IExecutablesChangeListener {
+public class ExecutablesViewer extends BaseViewer {
private static final String P_COLUMN_ORDER_KEY_EXE = "columnOrderKeyEXE"; //$NON-NLS-1$
private static final String P_SORTED_COLUMN_INDEX_KEY_EXE = "sortedColumnIndexKeyEXE"; //$NON-NLS-1$
@@ -155,6 +147,7 @@ public class ExecutablesViewer extends BaseViewer implements IExecutablesChangeL
protected ViewerComparator getViewerComparator(int sortType) {
if (sortType == ExecutablesView.PROJECT) {
return new ExecutablesViewerComparator(sortType, column_sort_order[ExecutablesView.PROJECT]) {
+ @Override
@SuppressWarnings("unchecked")
public int compare(Viewer viewer, Object e1, Object e2) {
Executable entry1 = (Executable) e1;
@@ -192,46 +185,4 @@ public class ExecutablesViewer extends BaseViewer implements IExecutablesChangeL
// default visible columns
return "1,1,1,0,0,0"; //$NON-NLS-1$
}
-
- public void executablesChanged(final List<Executable> executables) {
- // some executables have been updated. if one of them is currently
- // selected, we need to update the source file list
- UIJob refreshJob = new UIJob(Messages.ExecutablesViewer_RefreshExecutablesView) {
-
- @Override
- public IStatus runInUIThread(IProgressMonitor monitor) {
- // if the user has selected an executable, they expect its
- // list of source files to be refreshed automatically
- if (getSelection() != null &&
- getSelection() instanceof IStructuredSelection) {
- IStructuredSelection selection = (IStructuredSelection)getSelection();
-
- Object firstElement = selection.getFirstElement();
- if (firstElement instanceof Executable) {
- Executable executable = (Executable) firstElement;
- if (executables.contains(executable)) {
- executable.setRefreshSourceFiles(true);
- setSelection(selection);
- }
- }
- }
- return Status.OK_STATUS;
- }
- };
- refreshJob.schedule();
- }
-
- public void executablesListChanged() {
- // Executables list has changed so refresh the view.
- UIJob refreshJob = new UIJob(Messages.ExecutablesViewer_RefreshExecutablesView) {
-
- @Override
- public IStatus runInUIThread(IProgressMonitor monitor) {
- refresh(null);
- packColumns();
- return Status.OK_STATUS;
- }
- };
- refreshJob.schedule();
- }
} \ No newline at end of file
diff --git a/debug/org.eclipse.cdt.debug.ui/src/org/eclipse/cdt/debug/internal/ui/views/executables/Messages.java b/debug/org.eclipse.cdt.debug.ui/src/org/eclipse/cdt/debug/internal/ui/views/executables/Messages.java
index 1507dfb3d1..be16c63a60 100644
--- a/debug/org.eclipse.cdt.debug.ui/src/org/eclipse/cdt/debug/internal/ui/views/executables/Messages.java
+++ b/debug/org.eclipse.cdt.debug.ui/src/org/eclipse/cdt/debug/internal/ui/views/executables/Messages.java
@@ -53,6 +53,7 @@ public class Messages extends NLS {
public static String SourceFilesContentProvider_NoFilesFound;
public static String SourceFilesContentProvider_ReadingDebugSymbolInformationLabel;
public static String SourceFilesContentProvider_Refreshing;
+ public static String SourceFilesContentProvider_Canceled;
public static String SourceFilesViewer_RefreshSourceFiles;
public static String SourceFilesViewer_Location;
public static String SourceFilesViewer_Modified;
diff --git a/debug/org.eclipse.cdt.debug.ui/src/org/eclipse/cdt/debug/internal/ui/views/executables/Messages.properties b/debug/org.eclipse.cdt.debug.ui/src/org/eclipse/cdt/debug/internal/ui/views/executables/Messages.properties
index 4262cb72bc..1cf86d51dd 100644
--- a/debug/org.eclipse.cdt.debug.ui/src/org/eclipse/cdt/debug/internal/ui/views/executables/Messages.properties
+++ b/debug/org.eclipse.cdt.debug.ui/src/org/eclipse/cdt/debug/internal/ui/views/executables/Messages.properties
@@ -48,6 +48,7 @@ ExecutablesViewer_Type=Type
SourceFilesContentProvider_NoFilesFound=No source files found in
SourceFilesContentProvider_ReadingDebugSymbolInformationLabel=Reading Debug Symbol Information:
SourceFilesContentProvider_Refreshing=Refreshing...
+SourceFilesContentProvider_Canceled=Parse canceled. Hit refresh to restart.
SourceFilesViewer_RefreshSourceFiles=Refresh Source Files
SourceFilesViewer_Location=Location
SourceFilesViewer_Modified=Modified
diff --git a/debug/org.eclipse.cdt.debug.ui/src/org/eclipse/cdt/debug/internal/ui/views/executables/SourceFilesContentProvider.java b/debug/org.eclipse.cdt.debug.ui/src/org/eclipse/cdt/debug/internal/ui/views/executables/SourceFilesContentProvider.java
index 80a2ffe999..b515756542 100644
--- a/debug/org.eclipse.cdt.debug.ui/src/org/eclipse/cdt/debug/internal/ui/views/executables/SourceFilesContentProvider.java
+++ b/debug/org.eclipse.cdt.debug.ui/src/org/eclipse/cdt/debug/internal/ui/views/executables/SourceFilesContentProvider.java
@@ -18,7 +18,8 @@ import java.util.Map;
import org.eclipse.cdt.core.model.ITranslationUnit;
import org.eclipse.cdt.debug.core.executables.Executable;
import org.eclipse.cdt.debug.core.executables.ExecutablesManager;
-import org.eclipse.cdt.debug.core.executables.IExecutablesChangeListener;
+import org.eclipse.cdt.debug.core.executables.IExecutablesChangeListener2;
+import org.eclipse.cdt.debug.internal.core.Trace;
import org.eclipse.cdt.debug.internal.ui.views.executables.SourceFilesViewer.TranslationUnitInfo;
import org.eclipse.cdt.ui.CElementContentProvider;
import org.eclipse.core.runtime.IPath;
@@ -30,8 +31,9 @@ import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.core.runtime.jobs.JobChangeAdapter;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.swt.widgets.Display;
+import org.eclipse.ui.progress.WorkbenchJob;
-public class SourceFilesContentProvider extends CElementContentProvider implements IExecutablesChangeListener {
+public class SourceFilesContentProvider extends CElementContentProvider implements IExecutablesChangeListener2 {
static class QuickParseJob extends Job {
final Executable executable;
@@ -45,18 +47,65 @@ public class SourceFilesContentProvider extends CElementContentProvider implemen
@Override
protected IStatus run(IProgressMonitor monitor) {
- tus = executable.getSourceFiles(monitor);
- return Status.OK_STATUS;
+ if (Trace.DEBUG_EXECUTABLES) Trace.getTrace().trace(null, "Quick parsing of executable for source files has begun (" + this + ')'); //$NON-NLS-1$
+
+ // Ask the Executable for its source files. This could take a while...
+ ITranslationUnit[] mytus = executable.getSourceFiles(monitor);
+
+ IStatus status;
+ if (!monitor.isCanceled()) {
+ tus = mytus;
+ status = Status.OK_STATUS;
+ }
+ else {
+ status = Status.CANCEL_STATUS;
+ }
+
+ if (Trace.DEBUG_EXECUTABLES) Trace.getTrace().trace(null, "Quick parsing of executable has finished, status is " + status); //$NON-NLS-1$
+ return status;
}
}
- /** contains running jobs */
+ /**
+ * The collection of running file parsing jobs. Each executable file (not
+ * object) can independently be parsed, and these parses can happen
+ * simultaneously. Normally, each executable file has at most one ongoing
+ * parse. An exception is when a search is canceled. We don't wait for the
+ * search to actually end if a subsequent search comes in shortly after the
+ * first one is canceled. We cancel the first one, remove it from this list,
+ * schedule a new one, then add that to the list. It's safe to assume the
+ * canceled one will complete before the new one.
+ *
+ * <p> This collection must be accessed only from the UI thread
+ */
private Map<IPath, QuickParseJob> pathToJobMap = new HashMap<IPath, SourceFilesContentProvider.QuickParseJob>();
/** those executables for which we asked the question and got a result.
* NOTE: this contains a duplicate of into in Executable, because we can't
* guarantee or check whether Executable still has the info itself. */
- private Map<IPath, ITranslationUnit[]> fetchedExecutables = new HashMap<IPath, ITranslationUnit[]>();
+ private static class TUData{
+ /** Constructor used when search completes successfully */
+ public TUData(ITranslationUnit[] tus, long timestamp) {
+ this.tus = tus;
+ this.timestamp = timestamp;
+ }
+
+ /** Constructor used when search is canceled */
+ public TUData() {
+ this.canceled = true;
+ }
+
+ ITranslationUnit[] tus;
+ /** IResource.getModificationStamp value of when this data was last updated */
+ long timestamp;
+
+ boolean canceled;
+ }
+
+ /**
+ * The cached file info. Key is the path of the executable. This collection must be accessed only on the UI thread.
+ */
+ private Map<IPath, TUData> fetchedExecutables = new HashMap<IPath, TUData>();
private final SourceFilesViewer viewer;
@@ -72,12 +121,14 @@ public class SourceFilesContentProvider extends CElementContentProvider implemen
@Override
public void dispose() {
ExecutablesManager.getExecutablesManager().removeExecutablesChangeListener(this);
- synchronized (fetchedExecutables) {
- fetchedExecutables.clear();
- }
- synchronized (pathToJobMap) {
- pathToJobMap.clear();
- }
+ new WorkbenchJob("") { //$NON-NLS-1$
+ @Override
+ public IStatus runInUIThread(IProgressMonitor monitor) {
+ fetchedExecutables.clear();
+ pathToJobMap.clear();
+ return Status.OK_STATUS;
+ }
+ }.schedule();
super.dispose();
}
@@ -92,63 +143,71 @@ public class SourceFilesContentProvider extends CElementContentProvider implemen
return super.hasChildren(element);
}
+ /* (non-Javadoc)
+ * @see org.eclipse.cdt.internal.ui.BaseCElementContentProvider#getElements(java.lang.Object)
+ */
+ @Override
public Object[] getElements(Object inputElement) {
+ if (Trace.DEBUG_EXECUTABLES) Trace.getTrace().traceEntry(null, inputElement);
+
if (inputElement instanceof Executable) {
final Executable executable = (Executable) inputElement;
final IPath exePath = executable.getPath();
// look for a job that is currently fetching this info
QuickParseJob job;
- synchronized (pathToJobMap) {
- job = pathToJobMap.get(exePath);
- }
+ job = pathToJobMap.get(exePath);
if (job != null) {
// job is still running
return new String[] { Messages.SourceFilesContentProvider_Refreshing };
}
+ // create a background job to look for the sources but don't start it yet
+ job = new QuickParseJob(executable);
+ pathToJobMap.put(exePath, job);
- // see if we already checked
- synchronized (fetchedExecutables) {
- if (fetchedExecutables.containsKey(exePath)) {
- return fetchedExecutables.get(exePath);
- }
+ // See if we have the result cached for this executable. If so
+ // return that. It's also possible that the most resent search was
+ // canceled
+ Object[] cachedResult = null;
+ TUData tud = fetchedExecutables.get(exePath);
+ if (tud != null) {
+ if (tud.canceled)
+ cachedResult = new String[]{Messages.SourceFilesContentProvider_Canceled};
+ else
+ cachedResult = tud.tus;
}
-
- // start a background job to look for the sources
- job = new QuickParseJob(executable);
- synchronized (pathToJobMap) {
- pathToJobMap.put(exePath, job);
+ if (cachedResult != null) {
+ pathToJobMap.remove(exePath); // removed the unused search job
+ return cachedResult;
}
- // once the job finishes, update the viewer
+ // Schedule the job; once it finishes, update the viewer
final QuickParseJob theJob = job;
job.addJobChangeListener(new JobChangeAdapter() {
- public void done(IJobChangeEvent event) {
- synchronized (pathToJobMap) {
- pathToJobMap.values().remove(theJob);
- }
- if (event.getResult().isOK()) {
- synchronized (fetchedExecutables) {
- fetchedExecutables.put(exePath, theJob.tus);
- }
- Display.getDefault().asyncExec(new Runnable() {
- public void run() {
- // update the viewer
- if (!viewer.getControl().isDisposed()) {
- viewer.getTree().setLayoutDeferred(true);
- viewer.refresh(executable);
- viewer.packColumns();
- viewer.getTree().setLayoutDeferred(false);
- }
+ @Override
+ public void done(final IJobChangeEvent event) {
+ new WorkbenchJob("refreshing source files viewer"){ //$NON-NLS-1$
+ @Override
+ public IStatus runInUIThread(IProgressMonitor monitor) {
+ if (event.getResult().isOK()) {
+ fetchedExecutables.put(exePath, new TUData(theJob.tus, theJob.executable.getResource().getModificationStamp()));
}
- });
- }
+ else {
+ fetchedExecutables.put(exePath, new TUData());
+ }
+
+ pathToJobMap.values().remove(theJob);
+
+ refreshViewer(executable);
+ return Status.OK_STATUS;
+ }
+ }.schedule();
}
});
-
+
job.schedule();
- // while it's running...
+ // show the user a string that lets him know we're searching
return new String[] { Messages.SourceFilesContentProvider_Refreshing };
}
return new Object[] {};
@@ -159,46 +218,62 @@ public class SourceFilesContentProvider extends CElementContentProvider implemen
* @see org.eclipse.cdt.debug.core.executables.IExecutablesChangeListener#executablesListChanged()
*/
public void executablesListChanged() {
- // Don't clear executables -- closing/opening project doesn't imply
- // the info is different. But cancel all the jobs in case projects
- // were closed. It's non-obvious how to map executables to projects,
- // so just bail and cancel all the current parsing. The viewer
- // will be refreshed and re-request source lists for any executables
- // that are still applicable.
- cancelQuickParseJobs();
+ // we react via IExecutablesChangeListener2 methods
}
- /**
- *
- */
- private void cancelQuickParseJobs() {
- synchronized (pathToJobMap) {
- for (QuickParseJob job : pathToJobMap.values()) {
- job.cancel();
- }
- pathToJobMap.clear();
- }
-
- }
-
/* (non-Javadoc)
* @see org.eclipse.cdt.debug.core.executables.IExecutablesChangeListener#executablesChanged(java.util.List)
*/
- public void executablesChanged(List<Executable> executables) {
- for (Executable executable : executables) {
- IPath exePath = executable.getPath();
- synchronized (fetchedExecutables) {
- fetchedExecutables.remove(exePath);
- }
- synchronized (pathToJobMap) {
- QuickParseJob job = pathToJobMap.get(exePath);
- if (job != null) {
- job.cancel();
- pathToJobMap.remove(exePath);
+ public void executablesChanged(final List<Executable> executables) {
+ if (Trace.DEBUG_EXECUTABLES) Trace.getTrace().traceEntry(null, executables);
+
+ new WorkbenchJob("Refreshing viewer") { //$NON-NLS-1$
+ @Override
+ public IStatus runInUIThread(IProgressMonitor monitor) {
+ for (Executable executable : executables) {
+ IPath exePath = executable.getPath();
+ fetchedExecutables.remove(exePath);
+ QuickParseJob job = pathToJobMap.get(exePath);
+ if (job != null) {
+ if (Trace.DEBUG_EXECUTABLES) Trace.getTrace().trace(null, "Cancelling QuickParseJob: " + job); //$NON-NLS-1$
+ job.cancel();
+ pathToJobMap.remove(exePath);
+ }
+ }
+
+ if (!viewer.getControl().isDisposed()) {
+ // See if our current input is one of the executables that has changed.
+ for (Executable executable : executables) {
+ if (executable.equals(fInput)) {
+ // Executable.equals() is not a simple reference
+ // check. Two Executable objects are equal if they
+ // represent the same file on disk. I.e., our input
+ // object might not be one of the instances on the
+ // changed-list, but for sure the file on disk has
+ // changed. Now, the manager that called this
+ // listener has already told the Executable
+ // instances on the changed list to flush their
+ // source files list. However, if our input is not
+ // exactly one of those references, it means the
+ // manager is no longer managing the Executable
+ // that's our input. In that case, it's up to us to
+ // tell that Executable to flush its source file
+ // cache so that refreshing the viewer will cause a
+ // fresh fetch of the source file information.
+ Executable execInput = (Executable)fInput;
+ if (executable != execInput) {
+ execInput.setRefreshSourceFiles(true);
+ }
+ refreshViewer(execInput);
+ break;
+ }
+ }
}
+ return Status.OK_STATUS;
}
- }
+
+ }.schedule();
}
/* (non-Javadoc)
@@ -208,14 +283,178 @@ public class SourceFilesContentProvider extends CElementContentProvider implemen
public void inputChanged(Viewer viewer, Object oldInput, final Object newInput) {
super.inputChanged(viewer, oldInput, newInput);
- Display.getDefault().asyncExec(new Runnable() {
- public void run() {
+ new WorkbenchJob("Refreshing viewer") { //$NON-NLS-1$
+ @Override
+ public IStatus runInUIThread(IProgressMonitor monitor) {
// pack because the quick parse job won't run
if (newInput instanceof Executable
&& fetchedExecutables.containsKey(((Executable) newInput).getPath()))
SourceFilesContentProvider.this.viewer.packColumns();
+ return Status.OK_STATUS;
+ }
+ }.schedule();
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.cdt.debug.core.executables.IExecutablesChangeListener2#executablesAdded(java.util.List)
+ */
+ public void executablesAdded(final List<Executable> executables) {
+ if (Trace.DEBUG_EXECUTABLES) Trace.getTrace().traceEntry(null, executables);
+
+ // Throw out our cached translation units for the executable *file* but
+ // only if the file hasn't changed. Executable objects come and go
+ // independently of the file on disk.
+ new WorkbenchJob("executables removed") { //$NON-NLS-1$
+ @Override
+ public IStatus runInUIThread(IProgressMonitor monitor) {
+ for (Executable exec : executables) {
+ final IPath exePath = exec.getPath();
+ final long timestamp = exec.getResource().getModificationStamp();
+ TUData tud = fetchedExecutables.get(exePath);
+ if (tud != null && tud.timestamp != timestamp) {
+ fetchedExecutables.remove(exePath);
+ }
+ }
+
+ if (!viewer.getControl().isDisposed()) {
+ // See if current viewer input is one of the executables that
+ // was added. If so, this is likely an exec that was rebuilt
+ // and CDT missed sending a REMOVED model event. There's
+ // some crazy race condition going on, but basically CDT
+ // sends out an event that the binary has changed, then
+ // sends one that says it was added. Anyway, the best thing
+ // for us to do is to cause a refresh of the viewer since
+ // the addition notification probably caused us to cancel
+ // the parse of the exec that was initiated by the change
+ // event and the viewer will be stuck with a "canceled"
+ // message in the viewer table.
+ for (Executable executable : executables) {
+ if (executable.equals(fInput)) {
+ if (Trace.DEBUG_EXECUTABLES) Trace.getTrace().trace(null, "refreshing viewer; added executable is our current input"); //$NON-NLS-1$
+ refreshViewer((Executable)fInput);
+ break;
+ }
+ }
+ }
+
+ return Status.OK_STATUS;
+ }
+ }.schedule();
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.cdt.debug.core.executables.IExecutablesChangeListener2#executablesRemoved(java.util.List)
+ */
+ public void executablesRemoved(final List<Executable> executables) {
+ if (Trace.DEBUG_EXECUTABLES) Trace.getTrace().traceEntry(null, executables);
+
+ // The fact that the Executable was removed from the workspace doesn't
+ // mean we need to throw out the source file info we've cached. If a
+ // project is closed then reopened, we are able to reuse the info as
+ // long as the timestamp of the resource hasn't changed. But, there's no
+ // point in continuing any ongoing searches in the executables.
+ new WorkbenchJob("executables removed") { //$NON-NLS-1$
+ @Override
+ public IStatus runInUIThread(IProgressMonitor monitor) {
+ for (Executable exec : executables) {
+ final IPath exePath = exec.getPath();
+ QuickParseJob job = pathToJobMap.get(exePath);
+ if (job != null) {
+ if (Trace.DEBUG_EXECUTABLES) Trace.getTrace().trace(null, "Cancelling QuickParseJob: " + job); //$NON-NLS-1$
+ job.cancel();
+ pathToJobMap.remove(exePath);
+ }
+ }
+ return Status.OK_STATUS;
+ }
+ }.schedule();
+ }
+
+ /**
+ * Restarts a parse of the current input (Executable) if and only if its
+ * last search was canceled. The viewer is refresh accordingly.
+ *
+ * <p>
+ * Must be called on the UI thread
+ *
+ */
+ public void restartCanceledExecutableParse() {
+ assert Display.getCurrent() != null;
+
+ Object input = viewer.getInput();
+ if (input instanceof Executable) {
+ final Executable executable = (Executable)input;
+ final IPath exePath = executable.getPath();
+
+ // Ignore restart if there's an ongoing search.
+ QuickParseJob job;
+ job = pathToJobMap.get(exePath);
+ if (job != null) {
+ return;
+ }
+
+ TUData tud = fetchedExecutables.get(exePath);
+
+ // Ignore request if the most recent search wasn't canceled
+ if (tud != null && !tud.canceled) {
+ pathToJobMap.remove(exePath);
+ return;
}
- });
+
+ // Create and schedule a parse job. Once the job finishes, update
+ // the viewer
+ job = new QuickParseJob(executable);
+ pathToJobMap.put(exePath, job);
+ final QuickParseJob theJob = job;
+ job.addJobChangeListener(new JobChangeAdapter() {
+ @Override
+ public void done(final IJobChangeEvent event) {
+
+ new WorkbenchJob("refreshing source files viewer"){ //$NON-NLS-1$
+ @Override
+ public IStatus runInUIThread(IProgressMonitor monitor) {
+ // Update the model with the search results
+ if (event.getResult().isOK()) {
+ fetchedExecutables.put(exePath, new TUData(theJob.tus, theJob.executable.getResource().getModificationStamp()));
+ }
+ else {
+ // The search job apparently always completes
+ // successfully or it was canceled (failure was
+ // not a considered outcome). If it was canceled,
+ // well then we're back to where we started
+ fetchedExecutables.put(exePath, new TUData());
+ }
+ pathToJobMap.values().remove(theJob);
+
+ refreshViewer(executable);
+ return Status.OK_STATUS;
+ }
+ }.schedule();
+ }
+ });
+
+ job.schedule();
+
+ // The viewer is currently showing "search canceled". Cause an
+ // immediate refresh so that it shows "refreshing" while the new
+ // search is ongoing
+ refreshViewer(executable);
+ }
+ }
+
+ /**
+ * Utility method to invoke a viewer refresh for the given element
+ * @param input the Executable to show content for
+ *
+ * <p> Must be called on the UI thread
+ */
+ private void refreshViewer(Executable input) {
+ if (!viewer.getControl().isDisposed()) {
+ viewer.getTree().setLayoutDeferred(true);
+ viewer.refresh(input);
+ viewer.packColumns();
+ viewer.getTree().setLayoutDeferred(false);
+ }
}
}
diff --git a/debug/org.eclipse.cdt.debug.ui/src/org/eclipse/cdt/debug/internal/ui/views/executables/SourceFilesViewer.java b/debug/org.eclipse.cdt.debug.ui/src/org/eclipse/cdt/debug/internal/ui/views/executables/SourceFilesViewer.java
index f69c3f7c84..640ba1291f 100644
--- a/debug/org.eclipse.cdt.debug.ui/src/org/eclipse/cdt/debug/internal/ui/views/executables/SourceFilesViewer.java
+++ b/debug/org.eclipse.cdt.debug.ui/src/org/eclipse/cdt/debug/internal/ui/views/executables/SourceFilesViewer.java
@@ -11,35 +11,28 @@
package org.eclipse.cdt.debug.internal.ui.views.executables;
import java.io.File;
+import java.util.List;
import org.eclipse.cdt.core.model.ICElement;
import org.eclipse.cdt.core.model.ISourceReference;
import org.eclipse.cdt.core.model.ITranslationUnit;
-import org.eclipse.cdt.debug.core.CDebugCorePlugin;
import org.eclipse.cdt.debug.core.executables.Executable;
+import org.eclipse.cdt.debug.core.executables.ExecutablesManager;
+import org.eclipse.cdt.debug.core.executables.IExecutablesChangeListener;
import org.eclipse.cdt.debug.internal.ui.sourcelookup.CSourceNotFoundEditorInput;
import org.eclipse.cdt.debug.ui.ICDebugUIConstants;
import org.eclipse.cdt.internal.core.util.LRUCache;
import org.eclipse.cdt.internal.ui.util.EditorUtility;
import org.eclipse.cdt.ui.CUIPlugin;
-import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.Path;
-import org.eclipse.debug.core.DebugPlugin;
-import org.eclipse.debug.core.ILaunchConfiguration;
-import org.eclipse.debug.core.ILaunchConfigurationListener;
-import org.eclipse.debug.core.sourcelookup.ISourceLookupDirector;
-import org.eclipse.debug.core.sourcelookup.ISourceLookupParticipant;
import org.eclipse.jface.viewers.IOpenListener;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.OpenEvent;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.jface.viewers.ViewerComparator;
import org.eclipse.swt.SWT;
-import org.eclipse.swt.events.DisposeEvent;
-import org.eclipse.swt.events.DisposeListener;
import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Tree;
import org.eclipse.swt.widgets.TreeColumn;
import org.eclipse.ui.IEditorPart;
@@ -50,7 +43,7 @@ import org.eclipse.ui.PartInitException;
* Displays the list of source files for the executable selected in the
* ExecutablesViewer.
*/
-public class SourceFilesViewer extends BaseViewer implements ISourceLookupParticipant, ILaunchConfigurationListener {
+public class SourceFilesViewer extends BaseViewer {
/** Information from an ITranslationUnit for the various displayed columns */
static class TranslationUnitInfo {
@@ -100,25 +93,21 @@ public class SourceFilesViewer extends BaseViewer implements ISourceLookupPartic
openSourceFile(event);
}
});
-
- // We implement ISourceLookupParticipant so we can listen for changes to
- // source lookup as this viewer shows both original and remapped
- // locations
- CDebugCorePlugin.getDefault().getCommonSourceLookupDirector().addParticipants(new ISourceLookupParticipant[] { this });
- // We also look for launch configuration changes, since their source
- // locators are involved in source path remapping, too
- DebugPlugin.getDefault().getLaunchManager().addLaunchConfigurationListener(this);
-
- sourceFilesTree.addDisposeListener(new DisposeListener() {
-
- public void widgetDisposed(DisposeEvent e) {
- DebugPlugin.getDefault().getLaunchManager().removeLaunchConfigurationListener(SourceFilesViewer.this);
-
- CDebugCorePlugin.getDefault().getCommonSourceLookupDirector().removeParticipants(
- new ISourceLookupParticipant[] { SourceFilesViewer.this });
+ ExecutablesManager.getExecutablesManager().addExecutablesChangeListener(new IExecutablesChangeListener(){
+ public void executablesListChanged() {
+ // this doesn't directly affect us
}
- });
+
+ public void executablesChanged(List<Executable> executables) {
+ // TODO: be more selective; we don't know what TUs go with which executables yet
+ flushTranslationUnitCache();
+
+ // Note that we don't invoke a viewer refresh. Our content
+ // provider needs to also be listening for this notification.
+ // It's up to him to invoke a refresh on us if the model has
+ // been affected by the Executable change
+ }});
}
private void openSourceFile(OpenEvent event) {
@@ -198,10 +187,12 @@ public class SourceFilesViewer extends BaseViewer implements ISourceLookupPartic
typeColumn.addSelectionListener(new ColumnSelectionAdapter(ExecutablesView.TYPE));
}
+ @Override
protected ViewerComparator getViewerComparator(int sortType) {
if (sortType == ExecutablesView.ORG_LOCATION) {
return new ExecutablesViewerComparator(sortType, column_sort_order[ExecutablesView.ORG_LOCATION]) {
+ @Override
@SuppressWarnings("unchecked")
public int compare(Viewer viewer, Object e1, Object e2) {
if (e1 instanceof ITranslationUnit && e2 instanceof ITranslationUnit) {
@@ -219,40 +210,6 @@ public class SourceFilesViewer extends BaseViewer implements ISourceLookupPartic
return new ExecutablesViewerComparator(sortType, column_sort_order[sortType]);
}
- public void dispose() {
- }
-
- public Object[] findSourceElements(Object object) throws CoreException {
- return new Object[0];
- }
-
- public String getSourceName(Object object) throws CoreException {
- return ""; //$NON-NLS-1$
- }
-
- public void init(ISourceLookupDirector director) {
- }
-
- public void sourceContainersChanged(ISourceLookupDirector director) {
- refreshContent();
- }
-
- private void refreshContent() {
- Display.getDefault().asyncExec(new Runnable() {
- public void run() {
- Object input = getInput();
- if (input != null && input instanceof Executable) {
- ((Executable)input).setRemapSourceFiles(true);
-
- // TODO: be more selective; we don't know what TUs go with which executables yet
- flushTranslationUnitCache();
-
- refresh(true);
- }
- }
- });
- }
-
@Override
protected String getColumnOrderKey() {
return P_COLUMN_ORDER_KEY_SF;
@@ -279,34 +236,6 @@ public class SourceFilesViewer extends BaseViewer implements ISourceLookupPartic
return "1,1,0,0,0,0"; //$NON-NLS-1$
}
- /* (non-Javadoc)
- * @see org.eclipse.debug.core.ILaunchConfigurationListener#launchConfigurationAdded(org.eclipse.debug.core.ILaunchConfiguration)
- */
- public void launchConfigurationAdded(ILaunchConfiguration configuration) {
- if (!configuration.isWorkingCopy()) {
- refreshContent();
- }
- }
-
- /* (non-Javadoc)
- * @see org.eclipse.debug.core.ILaunchConfigurationListener#launchConfigurationChanged(org.eclipse.debug.core.ILaunchConfiguration)
- */
- public void launchConfigurationChanged(ILaunchConfiguration configuration) {
- if (!configuration.isWorkingCopy()) {
- refreshContent();
- }
- }
-
- /* (non-Javadoc)
- * @see org.eclipse.debug.core.ILaunchConfigurationListener#launchConfigurationRemoved(org.eclipse.debug.core.ILaunchConfiguration)
- */
- public void launchConfigurationRemoved(ILaunchConfiguration configuration) {
- if (!configuration.isWorkingCopy()) {
- refreshContent();
- }
- }
-
-
static TranslationUnitInfo fetchTranslationUnitInfo(Executable executable, Object element) {
if (!(element instanceof ITranslationUnit)) {
return null;
@@ -359,4 +288,17 @@ public class SourceFilesViewer extends BaseViewer implements ISourceLookupPartic
}
+ /**
+ * The view's refresh action calls this to restart an executable parse for
+ * the current input if the most recent search (for that element) was
+ * canceled. If it wasn't canceled, this is a no-op.
+ */
+ public void restartCanceledExecutableParse() {
+ SourceFilesContentProvider provider = (SourceFilesContentProvider)getContentProvider();
+ if (provider != null) {
+ provider.restartCanceledExecutableParse();
+ }
+
+ }
+
} \ No newline at end of file

Back to the top