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:
parent
2314988bc2
commit
0a49af8c69
6 changed files with 336 additions and 97 deletions
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -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();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -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
|
||||||
|
|
Loading…
Add table
Reference in a new issue