1
0
Fork 0
mirror of https://github.com/eclipse-cdt/cdt synced 2025-07-23 17:05:26 +02:00

Bug 315415 fixed performance issues of Executables view, esp. with files over networks

This commit is contained in:
Ed Swartz 2010-06-04 13:44:17 +00:00
parent 2314988bc2
commit 0a49af8c69
6 changed files with 336 additions and 97 deletions

View file

@ -279,34 +279,15 @@ public class ExecutablesView extends ViewPart {
{ {
// update the remove action // update the remove action
removeAction.setEnabled(!newSelection.isEmpty()); removeAction.setEnabled(!newSelection.isEmpty());
final Object firstElement = ((IStructuredSelection) newSelection).getFirstElement();
Job setectExeJob = new Job(Messages.ExecutablesView_Select_Executable) {
@Override // just immediately do this work: the source files content provider
protected IStatus run(IProgressMonitor monitor) { // will do the work in the background
if (firstElement instanceof Executable) { final Object firstElement = ((IStructuredSelection) newSelection).getFirstElement();
Executable executable = (Executable)firstElement;
this.setName(Messages.ExecutablesView_Finding_Sources_Job_Name + executable.getName()); sourceFilesViewer.setInput(firstElement);
executable.getSourceFiles(monitor);
}
// selection could be empty, so do this no matter what to update the source
// files viewer
UIJob selectExeUIJob = new UIJob(Messages.ExecutablesView_Select_Executable){
@Override
public IStatus runInUIThread(IProgressMonitor monitor) {
sourceFilesViewer.setInput(firstElement);
sourceFilesViewer.packColumns();
return Status.OK_STATUS;
}};
selectExeUIJob.schedule();
return Status.OK_STATUS;
}};
setectExeJob.schedule();
oldSelection = (IStructuredSelection) newSelection; oldSelection = (IStructuredSelection) newSelection;
} }
} }
} }
}); });

View file

@ -52,6 +52,8 @@ public class Messages extends NLS {
public static String ExecutablesViewer_Size; public static String ExecutablesViewer_Size;
public static String ExecutablesViewer_Type; public static String ExecutablesViewer_Type;
public static String SourceFilesContentProvider_NoFilesFound; public static String SourceFilesContentProvider_NoFilesFound;
public static String SourceFilesContentProvider_ReadingDebugSymbolInformationLabel;
public static String SourceFilesContentProvider_Refreshing;
public static String SourceFilesViewer_RefreshSourceFiles; public static String SourceFilesViewer_RefreshSourceFiles;
public static String SourceFilesViewer_Location; public static String SourceFilesViewer_Location;
public static String SourceFilesViewer_Modified; public static String SourceFilesViewer_Modified;

View file

@ -11,27 +11,82 @@
package org.eclipse.cdt.debug.internal.ui.views.executables; package org.eclipse.cdt.debug.internal.ui.views.executables;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.eclipse.cdt.core.model.ITranslationUnit; 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.Executable;
import org.eclipse.cdt.debug.core.executables.ExecutablesManager;
import org.eclipse.cdt.debug.core.executables.IExecutablesChangeListener;
import org.eclipse.cdt.debug.internal.ui.views.executables.SourceFilesViewer.TranslationUnitInfo;
import org.eclipse.cdt.ui.CElementContentProvider; import org.eclipse.cdt.ui.CElementContentProvider;
import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status; 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.Job;
import org.eclipse.core.runtime.jobs.JobChangeAdapter;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.swt.widgets.Display;
public class SourceFilesContentProvider extends CElementContentProvider { public class SourceFilesContentProvider extends CElementContentProvider implements IExecutablesChangeListener {
static class QuickParseJob extends Job {
final Executable executable;
ITranslationUnit[] tus;
public QuickParseJob(Executable executable) {
super (Messages.SourceFilesContentProvider_ReadingDebugSymbolInformationLabel
+ executable.getName());
this.executable = executable;
}
@Override
protected IStatus run(IProgressMonitor monitor) {
tus = executable.getSourceFiles(monitor);
return Status.OK_STATUS;
}
}
/** contains running jobs */
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 final SourceFilesViewer viewer;
public SourceFilesContentProvider(SourceFilesViewer viewer) { public SourceFilesContentProvider(SourceFilesViewer viewer) {
super(true, true); super(true, true);
this.viewer = viewer;
ExecutablesManager.getExecutablesManager().addExecutablesChangeListener(this);
} }
/* (non-Javadoc)
* @see org.eclipse.cdt.ui.CElementContentProvider#dispose()
*/
@Override
public void dispose() {
ExecutablesManager.getExecutablesManager().removeExecutablesChangeListener(this);
synchronized (fetchedExecutables) {
fetchedExecutables.clear();
}
synchronized (pathToJobMap) {
pathToJobMap.clear();
}
super.dispose();
}
@Override @Override
public boolean hasChildren(Object element) { public boolean hasChildren(Object element) {
if (element instanceof ITranslationUnit) { if (element instanceof ITranslationUnit) {
IPath path = ((ITranslationUnit) element).getLocation(); TranslationUnitInfo info = SourceFilesViewer.fetchTranslationUnitInfo(
if (path != null && !path.toFile().exists()) (Executable) viewer.getInput(), element);
if (info != null && !info.exists)
return false; return false;
} }
return super.hasChildren(element); return super.hasChildren(element);
@ -40,31 +95,127 @@ public class SourceFilesContentProvider extends CElementContentProvider {
public Object[] getElements(Object inputElement) { public Object[] getElements(Object inputElement) {
if (inputElement instanceof Executable) { if (inputElement instanceof Executable) {
final Executable executable = (Executable) inputElement; final Executable executable = (Executable) inputElement;
final ITranslationUnit[][] resultHolder = new ITranslationUnit[1][]; final IPath exePath = executable.getPath();
Job quickParseJob = new Job("Reading Debug Symbol Information: " + executable.getName()) {
@Override
protected IStatus run(IProgressMonitor monitor) {
ITranslationUnit[] sourceFiles = executable.getSourceFiles(monitor);
resultHolder[0] = sourceFiles;
return Status.OK_STATUS;
}
};
try { // look for a job that is currently fetching this info
quickParseJob.schedule(); QuickParseJob job;
quickParseJob.join(); synchronized (pathToJobMap) {
} catch (InterruptedException e) { job = pathToJobMap.get(exePath);
CDebugCorePlugin.log(e); }
if (job != null) {
// job is still running
return new String[] { Messages.SourceFilesContentProvider_Refreshing };
} }
ITranslationUnit[] sourceFiles = resultHolder[0]; // see if we already checked
if (sourceFiles.length == 0) synchronized (fetchedExecutables) {
return new String[] { Messages.SourceFilesContentProvider_NoFilesFound + executable.getName() }; if (fetchedExecutables.containsKey(exePath)) {
else return fetchedExecutables.get(exePath);
return sourceFiles; }
}
// start a background job to look for the sources
job = new QuickParseJob(executable);
synchronized (pathToJobMap) {
pathToJobMap.put(exePath, job);
}
// once the job finishes, update the viewer
final QuickParseJob theJob = job;
job.addJobChangeListener(new JobChangeAdapter() {
public void done(IJobChangeEvent event) {
if (event.getResult().isOK()) {
Display.getDefault().asyncExec(new Runnable() {
public void run() {
synchronized (pathToJobMap) {
pathToJobMap.values().remove(theJob);
}
synchronized (fetchedExecutables) {
fetchedExecutables.put(exePath, theJob.tus);
}
// update the viewer
if (!viewer.getControl().isDisposed()) {
viewer.getTree().setLayoutDeferred(true);
viewer.refresh(executable);
viewer.packColumns();
viewer.getTree().setLayoutDeferred(false);
}
}
});
}
}
});
job.schedule();
// while it's running...
return new String[] { Messages.SourceFilesContentProvider_Refreshing };
} }
return new Object[] {}; return new Object[] {};
} }
}
/* (non-Javadoc)
* @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();
}
/**
*
*/
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);
}
}
}
}
/* (non-Javadoc)
* @see org.eclipse.cdt.ui.CElementContentProvider#inputChanged(org.eclipse.jface.viewers.Viewer, java.lang.Object, java.lang.Object)
*/
@Override
public void inputChanged(Viewer viewer, Object oldInput, final Object newInput) {
super.inputChanged(viewer, oldInput, newInput);
Display.getDefault().asyncExec(new Runnable() {
public void run() {
// pack because the quick parse job won't run
if (newInput instanceof Executable
&& fetchedExecutables.containsKey(((Executable) newInput).getPath()))
SourceFilesContentProvider.this.viewer.packColumns();
}
});
}
}

View file

@ -12,23 +12,27 @@
package org.eclipse.cdt.debug.internal.ui.views.executables; package org.eclipse.cdt.debug.internal.ui.views.executables;
import com.ibm.icu.text.DateFormat; import com.ibm.icu.text.DateFormat;
import java.util.Date; import java.util.Date;
import java.util.List;
import org.eclipse.cdt.core.model.ITranslationUnit; import org.eclipse.cdt.core.model.ITranslationUnit;
import org.eclipse.cdt.debug.core.executables.Executable; 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.ui.CElementLabelProvider; import org.eclipse.cdt.ui.CElementLabelProvider;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.Path;
import org.eclipse.jface.resource.FontDescriptor; import org.eclipse.jface.resource.FontDescriptor;
import org.eclipse.jface.resource.JFaceResources; import org.eclipse.jface.resource.JFaceResources;
import org.eclipse.jface.resource.LocalResourceManager; import org.eclipse.jface.resource.LocalResourceManager;
import org.eclipse.jface.viewers.TreeColumnViewerLabelProvider; import org.eclipse.jface.viewers.TreeColumnViewerLabelProvider;
import org.eclipse.jface.viewers.ViewerCell; import org.eclipse.jface.viewers.ViewerCell;
import org.eclipse.swt.SWT; import org.eclipse.swt.SWT;
import org.eclipse.swt.events.DisposeEvent;
import org.eclipse.swt.events.DisposeListener;
import org.eclipse.swt.graphics.Font; import org.eclipse.swt.graphics.Font;
import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Display;
public class SourceFilesLabelProvider extends TreeColumnViewerLabelProvider { public class SourceFilesLabelProvider extends TreeColumnViewerLabelProvider implements IExecutablesChangeListener {
private SourceFilesViewer viewer; private SourceFilesViewer viewer;
@ -37,28 +41,42 @@ public class SourceFilesLabelProvider extends TreeColumnViewerLabelProvider {
public SourceFilesLabelProvider(SourceFilesViewer viewer) { public SourceFilesLabelProvider(SourceFilesViewer viewer) {
super(new CElementLabelProvider()); super(new CElementLabelProvider());
this.viewer = viewer; this.viewer = viewer;
// brute-force clear the cache when executables change
ExecutablesManager.getExecutablesManager().addExecutablesChangeListener(this);
viewer.getControl().addDisposeListener(new DisposeListener() {
public void widgetDisposed(DisposeEvent e) {
ExecutablesManager.getExecutablesManager().removeExecutablesChangeListener(SourceFilesLabelProvider.this);
}
});
} }
@Override @Override
public void update(ViewerCell cell) { public void update(ViewerCell cell) {
super.update(cell); super.update(cell);
SourceFilesViewer.TranslationUnitInfo tuInfo = null;
Object element = cell.getElement();
if (element instanceof ITranslationUnit) {
tuInfo = SourceFilesViewer.fetchTranslationUnitInfo((Executable) viewer.getInput(), element);
}
int orgColumnIndex = cell.getColumnIndex(); int orgColumnIndex = cell.getColumnIndex();
if (orgColumnIndex == 0) { if (orgColumnIndex == 0) {
if (cell.getElement() instanceof String) { if (element instanceof String) {
cell.setText((String) cell.getElement()); cell.setText((String) element);
Font boldFont = resourceManager.createFont(FontDescriptor.createFrom(viewer.getTree().getFont()).setStyle(SWT.BOLD)); Font italicFont = resourceManager.createFont(FontDescriptor.createFrom(viewer.getTree().getFont()).setStyle(SWT.ITALIC));
cell.setFont(boldFont); cell.setFont(italicFont);
} else {
cell.setFont(viewer.getTree().getFont());
} }
} else if (orgColumnIndex == 1) { } else if (orgColumnIndex == 1) {
cell.setText(null); cell.setText(null);
if (cell.getElement() instanceof ITranslationUnit) { if (tuInfo != null) {
ITranslationUnit tu = (ITranslationUnit) cell.getElement(); if (tuInfo.location != null) {
IPath path = tu.getLocation(); cell.setText(tuInfo.location.toOSString());
if (path != null) { if (tuInfo.exists)
cell.setText(path.toOSString());
if (path.toFile().exists())
cell.setForeground(Display.getDefault().getSystemColor(SWT.COLOR_BLACK)); cell.setForeground(Display.getDefault().getSystemColor(SWT.COLOR_BLACK));
else else
cell.setForeground(Display.getDefault().getSystemColor(SWT.COLOR_GRAY)); cell.setForeground(Display.getDefault().getSystemColor(SWT.COLOR_GRAY));
@ -67,11 +85,9 @@ public class SourceFilesLabelProvider extends TreeColumnViewerLabelProvider {
cell.setImage(null); cell.setImage(null);
} else if (orgColumnIndex == 2) { } else if (orgColumnIndex == 2) {
cell.setText(null); cell.setText(null);
if (cell.getElement() instanceof ITranslationUnit) { if (tuInfo != null && tuInfo.originalLocation != null) {
Executable executable = (Executable) viewer.getInput(); cell.setText(tuInfo.originalLocation.toOSString());
Path path = new Path(executable.getOriginalLocation((ITranslationUnit) cell.getElement())); if (tuInfo.originalExists)
cell.setText(path.toOSString());
if (path.toFile().exists())
cell.setForeground(Display.getDefault().getSystemColor(SWT.COLOR_BLACK)); cell.setForeground(Display.getDefault().getSystemColor(SWT.COLOR_BLACK));
else else
cell.setForeground(Display.getDefault().getSystemColor(SWT.COLOR_GRAY)); cell.setForeground(Display.getDefault().getSystemColor(SWT.COLOR_GRAY));
@ -79,34 +95,27 @@ public class SourceFilesLabelProvider extends TreeColumnViewerLabelProvider {
cell.setImage(null); cell.setImage(null);
} else if (orgColumnIndex == 3) { } else if (orgColumnIndex == 3) {
cell.setText(null); cell.setText(null);
if (cell.getElement() instanceof ITranslationUnit) { if (tuInfo != null) {
ITranslationUnit tu = (ITranslationUnit) cell.getElement(); if (tuInfo.exists) {
IPath path = tu.getLocation(); cell.setText(Long.toString(tuInfo.fileLength));
if (path != null && path.toFile().exists()) {
long fileLength = path.toFile().length();
cell.setText(Long.toString(fileLength));
} }
} }
cell.setImage(null); cell.setImage(null);
} else if (orgColumnIndex == 4) { } else if (orgColumnIndex == 4) {
cell.setText(null); cell.setText(null);
if (cell.getElement() instanceof ITranslationUnit) { if (tuInfo != null) {
ITranslationUnit tu = (ITranslationUnit) cell.getElement(); if (tuInfo.exists) {
IPath path = tu.getLocation(); String dateTimeString = DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT).format(
if (path != null && path.toFile().exists()) { new Date(tuInfo.lastModified));
long modified = path.toFile().lastModified();
String dateTimeString = DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT).format(new Date(modified));
cell.setText(dateTimeString); cell.setText(dateTimeString);
} }
} }
cell.setImage(null); cell.setImage(null);
} else if (orgColumnIndex == 5) { } else if (orgColumnIndex == 5) {
cell.setText(null); cell.setText(null);
if (cell.getElement() instanceof ITranslationUnit) { if (tuInfo != null) {
ITranslationUnit tu = (ITranslationUnit) cell.getElement(); if (tuInfo.location != null) {
IPath path = tu.getLocation(); String fileExtension = tuInfo.location.getFileExtension();
if (path != null) {
String fileExtension = path.getFileExtension();
if (fileExtension != null) if (fileExtension != null)
cell.setText(fileExtension.toLowerCase()); cell.setText(fileExtension.toLowerCase());
} }
@ -115,4 +124,20 @@ public class SourceFilesLabelProvider extends TreeColumnViewerLabelProvider {
} }
} }
/* (non-Javadoc)
* @see org.eclipse.cdt.debug.core.executables.IExecutablesChangeListener#executablesListChanged()
*/
public void executablesListChanged() {
SourceFilesViewer.flushTranslationUnitCache();
}
/* (non-Javadoc)
* @see org.eclipse.cdt.debug.core.executables.IExecutablesChangeListener#executablesChanged(java.util.List)
*/
public void executablesChanged(List<Executable> executables) {
// no mapping of executable -> TU maintained; just kill all for now
SourceFilesViewer.flushTranslationUnitCache();
}
} }

View file

@ -10,6 +10,8 @@
*******************************************************************************/ *******************************************************************************/
package org.eclipse.cdt.debug.internal.ui.views.executables; package org.eclipse.cdt.debug.internal.ui.views.executables;
import java.io.File;
import org.eclipse.cdt.core.model.ICElement; import org.eclipse.cdt.core.model.ICElement;
import org.eclipse.cdt.core.model.ISourceReference; import org.eclipse.cdt.core.model.ISourceReference;
import org.eclipse.cdt.core.model.ITranslationUnit; import org.eclipse.cdt.core.model.ITranslationUnit;
@ -17,13 +19,12 @@ import org.eclipse.cdt.debug.core.CDebugCorePlugin;
import org.eclipse.cdt.debug.core.executables.Executable; import org.eclipse.cdt.debug.core.executables.Executable;
import org.eclipse.cdt.debug.internal.ui.sourcelookup.CSourceNotFoundEditorInput; import org.eclipse.cdt.debug.internal.ui.sourcelookup.CSourceNotFoundEditorInput;
import org.eclipse.cdt.debug.ui.ICDebugUIConstants; 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.internal.ui.util.EditorUtility;
import org.eclipse.cdt.ui.CUIPlugin; import org.eclipse.cdt.ui.CUIPlugin;
import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.debug.core.DebugPlugin; import org.eclipse.debug.core.DebugPlugin;
import org.eclipse.debug.core.ILaunchConfiguration; import org.eclipse.debug.core.ILaunchConfiguration;
import org.eclipse.debug.core.ILaunchConfigurationListener; import org.eclipse.debug.core.ILaunchConfigurationListener;
@ -38,12 +39,12 @@ import org.eclipse.swt.SWT;
import org.eclipse.swt.events.DisposeEvent; import org.eclipse.swt.events.DisposeEvent;
import org.eclipse.swt.events.DisposeListener; import org.eclipse.swt.events.DisposeListener;
import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Tree; import org.eclipse.swt.widgets.Tree;
import org.eclipse.swt.widgets.TreeColumn; import org.eclipse.swt.widgets.TreeColumn;
import org.eclipse.ui.IEditorPart; import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.IWorkbenchPage; import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.PartInitException; import org.eclipse.ui.PartInitException;
import org.eclipse.ui.progress.UIJob;
/** /**
* Displays the list of source files for the executable selected in the * Displays the list of source files for the executable selected in the
@ -51,6 +52,24 @@ import org.eclipse.ui.progress.UIJob;
*/ */
public class SourceFilesViewer extends BaseViewer implements ISourceLookupParticipant, ILaunchConfigurationListener { public class SourceFilesViewer extends BaseViewer implements ISourceLookupParticipant, ILaunchConfigurationListener {
/** Information from an ITranslationUnit for the various displayed columns */
static class TranslationUnitInfo {
/** when do we next check these attributes? time in ms */
long nextCheckTimestamp;
/** the source file location */
IPath location;
/** does the file exist? */
boolean exists;
/** length of actual file in bytes */
long fileLength;
/** {@link File#lastModified()} time for source file */
long lastModified;
/** the original source file location, e.g. from debug info */
IPath originalLocation;
/** does the original file exist? */
boolean originalExists;
}
private static final String P_COLUMN_ORDER_KEY_SF = "columnOrderKeySF"; //$NON-NLS-1$ private static final String P_COLUMN_ORDER_KEY_SF = "columnOrderKeySF"; //$NON-NLS-1$
private static final String P_SORTED_COLUMN_INDEX_KEY_SF = "sortedColumnIndexKeySF"; //$NON-NLS-1$ private static final String P_SORTED_COLUMN_INDEX_KEY_SF = "sortedColumnIndexKeySF"; //$NON-NLS-1$
private static final String P_COLUMN_SORT_DIRECTION_KEY_SF = "columnSortDirectionKeySF"; //$NON-NLS-1$ private static final String P_COLUMN_SORT_DIRECTION_KEY_SF = "columnSortDirectionKeySF"; //$NON-NLS-1$
@ -59,6 +78,10 @@ public class SourceFilesViewer extends BaseViewer implements ISourceLookupPartic
TreeColumn originalLocationColumn; TreeColumn originalLocationColumn;
private Tree sourceFilesTree; private Tree sourceFilesTree;
/** Tradeoff expensiveness of checking filesystem against likelihood
* that files will be added/removed/changed in the given time period */
static final long FILE_CHECK_DELTA = 30 * 1000;
private static LRUCache<Object, TranslationUnitInfo> translationUnitInfoCache = new LRUCache<Object, TranslationUnitInfo>(1024);
public SourceFilesViewer(ExecutablesView view, Composite parent, int style) { public SourceFilesViewer(ExecutablesView view, Composite parent, int style) {
super(view, parent, style); super(view, parent, style);
@ -90,6 +113,8 @@ public class SourceFilesViewer extends BaseViewer implements ISourceLookupPartic
sourceFilesTree.addDisposeListener(new DisposeListener() { sourceFilesTree.addDisposeListener(new DisposeListener() {
public void widgetDisposed(DisposeEvent e) { public void widgetDisposed(DisposeEvent e) {
DebugPlugin.getDefault().getLaunchManager().removeLaunchConfigurationListener(SourceFilesViewer.this);
CDebugCorePlugin.getDefault().getCommonSourceLookupDirector().removeParticipants( CDebugCorePlugin.getDefault().getCommonSourceLookupDirector().removeParticipants(
new ISourceLookupParticipant[] { SourceFilesViewer.this }); new ISourceLookupParticipant[] { SourceFilesViewer.this });
} }
@ -213,19 +238,19 @@ public class SourceFilesViewer extends BaseViewer implements ISourceLookupPartic
} }
private void refreshContent() { private void refreshContent() {
UIJob refreshJob = new UIJob(Messages.SourceFilesViewer_RefreshSourceFiles) { Display.getDefault().asyncExec(new Runnable() {
public void run() {
@Override
public IStatus runInUIThread(IProgressMonitor monitor) {
Object input = getInput(); Object input = getInput();
if (input != null && input instanceof Executable) { if (input != null && input instanceof Executable) {
((Executable)input).setRemapSourceFiles(true); ((Executable)input).setRemapSourceFiles(true);
// TODO: be more selective; we don't know what TUs go with which executables yet
flushTranslationUnitCache();
refresh(true); refresh(true);
} }
return Status.OK_STATUS;
} }
}; });
refreshJob.schedule();
} }
@Override @Override
@ -280,5 +305,58 @@ public class SourceFilesViewer extends BaseViewer implements ISourceLookupPartic
refreshContent(); refreshContent();
} }
} }
static TranslationUnitInfo fetchTranslationUnitInfo(Executable executable, Object element) {
if (!(element instanceof ITranslationUnit)) {
return null;
}
ITranslationUnit tu = (ITranslationUnit) element;
long now = System.currentTimeMillis();
TranslationUnitInfo info;
synchronized (translationUnitInfoCache) {
info = (TranslationUnitInfo) translationUnitInfoCache.get(element);
}
if (info == null || info.nextCheckTimestamp <= now) {
if (info == null)
info = new TranslationUnitInfo();
info.location = tu.getLocation();
if (info.location != null) {
File file = info.location.toFile();
info.exists = file.exists();
info.fileLength = file.length();
info.lastModified = file.lastModified();
info.originalLocation = new Path(executable.getOriginalLocation(tu));
info.originalExists = info.originalLocation.toFile().exists();
} else {
info.exists = false;
info.fileLength = 0;
info.lastModified = 0;
info.originalExists = false;
info.originalLocation = null;
}
info.nextCheckTimestamp = System.currentTimeMillis() + FILE_CHECK_DELTA;
synchronized (translationUnitInfoCache) {
translationUnitInfoCache.put(element, info);
}
}
return info;
}
/**
*
*/
static void flushTranslationUnitCache() {
synchronized (translationUnitInfoCache) {
translationUnitInfoCache.flush();
}
}
} }

View file

@ -46,6 +46,8 @@ ExecutablesViewer_RefreshExecutablesView=Refresh Executables View
ExecutablesViewer_Size=Size ExecutablesViewer_Size=Size
ExecutablesViewer_Type=Type ExecutablesViewer_Type=Type
SourceFilesContentProvider_NoFilesFound=No source files found in SourceFilesContentProvider_NoFilesFound=No source files found in
SourceFilesContentProvider_ReadingDebugSymbolInformationLabel=Reading Debug Symbol Information:
SourceFilesContentProvider_Refreshing=Refreshing...
SourceFilesViewer_RefreshSourceFiles=Refresh Source Files SourceFilesViewer_RefreshSourceFiles=Refresh Source Files
SourceFilesViewer_Location=Location SourceFilesViewer_Location=Location
SourceFilesViewer_Modified=Modified SourceFilesViewer_Modified=Modified