/*******************************************************************************
- * Copyright (c) 2010, 2011, 2012 Ericsson
+ * Copyright (c) 2010, 2013 Ericsson
*
* All rights reserved. This program and the accompanying materials are
* made available under the terms of the Eclipse Public License v1.0 which
* Patrick Tasse - Factored out from events view
* Francois Chouinard - Replaced Table by TmfVirtualTable
* Patrick Tasse - Filter implementation (inspired by www.eclipse.org/mat)
+ * Ansgar Radermacher - Support navigation to model URIs (Bug 396956)
*******************************************************************************/
package org.eclipse.linuxtools.tmf.ui.viewers.events;
+import java.io.FileNotFoundException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IMarker;
import org.eclipse.core.resources.IResource;
+import org.eclipse.core.resources.IResourceVisitor;
+import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.ListenerList;
+import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.Job;
+import org.eclipse.emf.common.util.URI;
+import org.eclipse.emf.ecore.EValidator;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.action.IMenuListener;
import org.eclipse.jface.resource.FontDescriptor;
import org.eclipse.jface.resource.JFaceResources;
import org.eclipse.jface.resource.LocalResourceManager;
+import org.eclipse.jface.util.OpenStrategy;
+import org.eclipse.jface.util.SafeRunnable;
+import org.eclipse.jface.viewers.ArrayContentProvider;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.ISelectionChangedListener;
+import org.eclipse.jface.viewers.ISelectionProvider;
+import org.eclipse.jface.viewers.LabelProvider;
+import org.eclipse.jface.viewers.SelectionChangedEvent;
+import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.window.Window;
import org.eclipse.linuxtools.internal.tmf.ui.Activator;
import org.eclipse.linuxtools.internal.tmf.ui.Messages;
+import org.eclipse.linuxtools.internal.tmf.ui.dialogs.MultiLineInputDialog;
import org.eclipse.linuxtools.tmf.core.component.ITmfDataProvider;
import org.eclipse.linuxtools.tmf.core.component.TmfComponent;
+import org.eclipse.linuxtools.tmf.core.ctfadaptor.CtfConstants;
+import org.eclipse.linuxtools.tmf.core.ctfadaptor.CtfTmfCallsite;
+import org.eclipse.linuxtools.tmf.core.ctfadaptor.CtfTmfEvent;
import org.eclipse.linuxtools.tmf.core.event.ITmfEvent;
import org.eclipse.linuxtools.tmf.core.event.ITmfEventField;
-import org.eclipse.linuxtools.tmf.core.event.ITmfTimestamp;
import org.eclipse.linuxtools.tmf.core.event.TmfEventField;
-import org.eclipse.linuxtools.tmf.core.event.TmfTimestamp;
import org.eclipse.linuxtools.tmf.core.filter.ITmfFilter;
import org.eclipse.linuxtools.tmf.core.filter.model.ITmfFilterTreeNode;
import org.eclipse.linuxtools.tmf.core.filter.model.TmfFilterAndNode;
import org.eclipse.linuxtools.tmf.core.filter.model.TmfFilterNode;
import org.eclipse.linuxtools.tmf.core.request.ITmfDataRequest.ExecutionType;
import org.eclipse.linuxtools.tmf.core.request.TmfDataRequest;
-import org.eclipse.linuxtools.tmf.core.signal.TmfExperimentUpdatedSignal;
+import org.eclipse.linuxtools.tmf.core.signal.TmfEventFilterAppliedSignal;
+import org.eclipse.linuxtools.tmf.core.signal.TmfEventSearchAppliedSignal;
import org.eclipse.linuxtools.tmf.core.signal.TmfSignalHandler;
import org.eclipse.linuxtools.tmf.core.signal.TmfTimeSynchSignal;
import org.eclipse.linuxtools.tmf.core.signal.TmfTraceUpdatedSignal;
+import org.eclipse.linuxtools.tmf.core.timestamp.ITmfTimestamp;
+import org.eclipse.linuxtools.tmf.core.timestamp.TmfTimestamp;
import org.eclipse.linuxtools.tmf.core.trace.ITmfContext;
import org.eclipse.linuxtools.tmf.core.trace.ITmfLocation;
import org.eclipse.linuxtools.tmf.core.trace.ITmfTrace;
import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.swt.widgets.TableItem;
import org.eclipse.swt.widgets.Text;
+import org.eclipse.ui.IWorkbenchPage;
+import org.eclipse.ui.PartInitException;
import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.dialogs.ListDialog;
+import org.eclipse.ui.ide.IDE;
import org.eclipse.ui.ide.IGotoMarker;
import org.eclipse.ui.themes.ColorUtil;
* @version 1.0
* @author Francois Chouinard
* @author Patrick Tasse
+ * @since 2.0
*/
-public class TmfEventsTable extends TmfComponent implements IGotoMarker,
- IColorSettingsListener, ITmfEventsFilterProvider {
+public class TmfEventsTable extends TmfComponent implements IGotoMarker, IColorSettingsListener, ISelectionProvider {
private static final Image BOOKMARK_IMAGE = Activator.getDefault().getImageFromPath(
"icons/elcl16/bookmark_obj.gif"); //$NON-NLS-1$
// Table data
// ------------------------------------------------------------------------
- protected Composite fComposite;
- protected SashForm fSashForm;
+ /** The virtual event table */
protected TmfVirtualTable fTable;
- protected TmfRawEventViewer fRawViewer;
- protected ITmfTrace<?> fTrace;
- protected boolean fPackDone = false;
- protected HeaderState fHeaderState = HeaderState.SEARCH;
- protected long fSelectedRank = 0;
+
+ private Composite fComposite;
+ private SashForm fSashForm;
+ private TmfRawEventViewer fRawViewer;
+ private ITmfTrace fTrace;
+ private boolean fPackDone = false;
+ private HeaderState fHeaderState = HeaderState.SEARCH;
+ private long fSelectedRank = 0;
// Filter data
- protected long fFilterMatchCount;
- protected long fFilterCheckCount;
- protected FilterThread fFilterThread;
- protected boolean fFilterThreadResume = false;
- protected final Object fFilterSyncObj = new Object();
- protected SearchThread fSearchThread;
- protected final Object fSearchSyncObj = new Object();
- protected List<ITmfEventsFilterListener> fEventsFilterListeners = new ArrayList<ITmfEventsFilterListener>();
+ private long fFilterMatchCount;
+ private long fFilterCheckCount;
+ private FilterThread fFilterThread;
+ private boolean fFilterThreadResume = false;
+ private final Object fFilterSyncObj = new Object();
+ private SearchThread fSearchThread;
+ private final Object fSearchSyncObj = new Object();
+
+ /**
+ * List of selection change listeners (element type: <code>ISelectionChangedListener</code>).
+ *
+ * @see #fireSelectionChanged
+ */
+ private ListenerList selectionChangedListeners = new ListenerList();
// Bookmark map <Rank, MarkerId>
- protected Map<Long, Long> fBookmarksMap = new HashMap<Long, Long>();
- protected IFile fBookmarksFile;
- protected long fPendingGotoRank = -1;
+ private Map<Long, Long> fBookmarksMap = new HashMap<Long, Long>();
+ private IFile fBookmarksFile;
+ private long fPendingGotoRank = -1;
// SWT resources
- protected LocalResourceManager fResourceManager = new LocalResourceManager(JFaceResources.getResources());
- protected Color fGrayColor;
- protected Color fGreenColor;
- protected Font fBoldFont;
+ private LocalResourceManager fResourceManager = new LocalResourceManager(JFaceResources.getResources());
+ private Color fGrayColor;
+ private Color fGreenColor;
+ private Font fBoldFont;
// Table column names
- static private final String[] COLUMN_NAMES = new String[] { Messages.TmfEventsTable_TimestampColumnHeader,
+ private static final String[] COLUMN_NAMES = new String[] { Messages.TmfEventsTable_TimestampColumnHeader,
Messages.TmfEventsTable_SourceColumnHeader, Messages.TmfEventsTable_TypeColumnHeader,
Messages.TmfEventsTable_ReferenceColumnHeader, Messages.TmfEventsTable_ContentColumnHeader };
- static private final ColumnData[] COLUMN_DATA = new ColumnData[] { new ColumnData(COLUMN_NAMES[0], 100, SWT.LEFT),
+ private static final ColumnData[] COLUMN_DATA = new ColumnData[] { new ColumnData(COLUMN_NAMES[0], 100, SWT.LEFT),
new ColumnData(COLUMN_NAMES[1], 100, SWT.LEFT), new ColumnData(COLUMN_NAMES[2], 100, SWT.LEFT),
new ColumnData(COLUMN_NAMES[3], 100, SWT.LEFT), new ColumnData(COLUMN_NAMES[4], 100, SWT.LEFT) };
private boolean fDisposeOnClose;
// ------------------------------------------------------------------------
- // Constructor
+ // Constructors
// ------------------------------------------------------------------------
/**
}
}
}
+ fireSelectionChanged(new SelectionChangedEvent(TmfEventsTable.this, getSelection()));
}
});
- cacheSize = Math.max(cacheSize, Display.getDefault().getBounds().height / fTable.getItemHeight());
- cacheSize = Math.min(cacheSize, MAX_CACHE_SIZE);
- fCache = new TmfEventsCache(cacheSize, this);
+ int realCacheSize = Math.max(cacheSize, Display.getDefault().getBounds().height / fTable.getItemHeight());
+ realCacheSize = Math.min(realCacheSize, MAX_CACHE_SIZE);
+ fCache = new TmfEventsCache(realCacheSize, this);
// Handle the table item requests
fTable.addListener(SWT.SetData, new Listener() {
}
Point pt = fTable.toDisplay(event.x, y);
pt.x += BOOKMARK_IMAGE.getBounds().width;
- pt.y += size.y;
+ pt.y += item.getBounds().height;
tooltipShell.setBounds(pt.x, pt.y, size.x, size.y);
tooltipShell.setVisible(true);
break;
}
fTable.setSelection(index + 1); // +1 for header row
fSelectedRank = rank;
- } else if (e.data instanceof ITmfLocation<?>) {
+ } else if (e.data instanceof ITmfLocation) {
// DOES NOT WORK: rank undefined in context from seekLocation()
// ITmfLocation<?> location = (ITmfLocation<?>) e.data;
// TmfContext context = fTrace.seekLocation(location);
createPopupMenu();
}
+ /**
+ * Create a pop-up menu.
+ */
protected void createPopupMenu() {
final IAction showTableAction = new Action(Messages.TmfEventsTable_ShowTableActionText) {
@Override
}
};
+ final IAction openCallsiteAction = new Action(Messages.TmfEventsTable_OpenCallsiteActionText) {
+ @Override
+ public void run() {
+ final TableItem items[] = fTable.getSelection();
+ if (items.length != 1) {
+ return;
+ }
+ final TableItem item = items[0];
+
+ final Object data = item.getData();
+ if (data instanceof CtfTmfEvent) {
+ CtfTmfEvent event = (CtfTmfEvent) data;
+ CtfTmfCallsite cs = event.getCallsite();
+ if (cs == null || cs.getFileName() == null) {
+ return;
+ }
+ IMarker marker = null;
+ try {
+ String fileName = cs.getFileName();
+ final String trimmedPath = fileName.replaceAll("\\.\\./", ""); //$NON-NLS-1$ //$NON-NLS-2$
+ final ArrayList<IFile> files = new ArrayList<IFile>();
+ ResourcesPlugin.getWorkspace().getRoot().accept(new IResourceVisitor() {
+ @Override
+ public boolean visit(IResource resource) throws CoreException {
+ if (resource instanceof IFile && resource.getFullPath().toString().endsWith(trimmedPath)) {
+ files.add((IFile) resource);
+ }
+ return true;
+ }
+ });
+ IFile file = null;
+ if (files.size() > 1) {
+ ListDialog dialog = new ListDialog(getTable().getShell());
+ dialog.setContentProvider(ArrayContentProvider.getInstance());
+ dialog.setLabelProvider(new LabelProvider() {
+ @Override
+ public String getText(Object element) {
+ return ((IFile) element).getFullPath().toString();
+ }
+ });
+ dialog.setInput(files);
+ dialog.setTitle(Messages.TmfEventsTable_OpenCallsiteSelectFileDialogTitle);
+ dialog.setMessage(Messages.TmfEventsTable_OpenCallsiteSelectFileDialogTitle + '\n' + cs.toString());
+ dialog.open();
+ Object[] result = dialog.getResult();
+ if (result != null && result.length > 0) {
+ file = (IFile) result[0];
+ }
+ } else if (files.size() == 1) {
+ file = files.get(0);
+ }
+ if (file != null) {
+ marker = file.createMarker(IMarker.MARKER);
+ marker.setAttribute(IMarker.LINE_NUMBER, Long.valueOf(cs.getLineNumber()).intValue());
+ IDE.openEditor(PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage(), marker);
+ marker.delete();
+ } else if (files.size() == 0){
+ displayException(new FileNotFoundException('\'' + cs.toString() + '\'' + '\n' + Messages.TmfEventsTable_OpenCallsiteNotFound));
+ }
+ } catch (PartInitException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ } catch (CoreException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ }
+ }
+ };
+
+ final IAction openModelAction = new Action(Messages.TmfEventsTable_OpenModelActionText) {
+ @Override
+ public void run() {
+
+ final TableItem items[] = fTable.getSelection();
+ if (items.length != 1) {
+ return;
+ }
+ final TableItem item = items[0];
+
+ final Object eventData = item.getData();
+ if (eventData instanceof CtfTmfEvent) {
+ String modelURI = ((CtfTmfEvent) eventData).getCustomAttribute(CtfConstants.MODEL_URI_KEY);
+
+ if (modelURI != null) {
+ IWorkbenchPage activePage = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage();
+
+ IFile file = null;
+ final URI uri = URI.createURI(modelURI);
+ if (uri.isPlatformResource()) {
+ IPath path = new Path(uri.toPlatformString(true));
+ file = ResourcesPlugin.getWorkspace().getRoot().getFile(path);
+ } else if (uri.isFile() && !uri.isRelative()) {
+ file = ResourcesPlugin.getWorkspace().getRoot().getFileForLocation(
+ new Path(uri.toFileString()));
+ }
+
+ if (file != null) {
+ try {
+ /*
+ * create a temporary validation marker on the
+ * model file, remove it afterwards thus,
+ * navigation works with all model editors
+ * supporting the navigation to a marker
+ */
+ IMarker marker = file.createMarker(EValidator.MARKER);
+ marker.setAttribute(EValidator.URI_ATTRIBUTE, modelURI);
+ marker.setAttribute(IMarker.SEVERITY, IMarker.SEVERITY_INFO);
+
+ IDE.openEditor(activePage, marker, OpenStrategy.activateOnOpen());
+ marker.delete();
+ }
+ catch (CoreException e) {
+ displayException(e);
+ }
+ } else {
+ displayException(new FileNotFoundException('\'' + modelURI + '\'' + '\n' + Messages.TmfEventsTable_OpenModelUnsupportedURI));
+ }
+ }
+ }
+ }
+ };
+
final IAction showSearchBarAction = new Action(Messages.TmfEventsTable_ShowSearchBarActionText) {
@Override
public void run() {
return;
}
}
+
// Right-click on table
if (fTable.isVisible() && fRawViewer.isVisible()) {
tablePopupMenu.add(hideTableAction);
tablePopupMenu.add(showRawAction);
}
tablePopupMenu.add(new Separator());
+
+ if (item != null) {
+ final Object data = item.getData();
+ if (data instanceof CtfTmfEvent) {
+ Separator separator = null;
+ CtfTmfEvent event = (CtfTmfEvent) data;
+ if (event.getCallsite() != null) {
+ tablePopupMenu.add(openCallsiteAction);
+ separator = new Separator();
+ }
+ if (event.listCustomAttributes().contains(CtfConstants.MODEL_URI_KEY)) {
+ tablePopupMenu.add(openModelAction);
+ separator = new Separator();
+ }
+ if (separator != null) {
+ tablePopupMenu.add(separator);
+ }
+ }
+ }
+
tablePopupMenu.add(clearFiltersAction);
final ITmfFilterTreeNode[] savedFilters = FilterManager.getSavedFilters();
if (savedFilters.length > 0) {
fRawViewer.setMenu(menu);
}
+
+ /**
+ * Append an item to the event table's pop-up menu.
+ *
+ * @param tablePopupMenu
+ * The menu manager
+ * @param selectedItem
+ * The item to append
+ */
protected void appendToTablePopupMenu(final MenuManager tablePopupMenu, final TableItem selectedItem) {
// override to append more actions
}
+ /**
+ * Append an item to the raw viewer's pop-up menu.
+ *
+ * @param rawViewerPopupMenu
+ * The menu manager
+ */
protected void appendToRawPopupMenu(final MenuManager rawViewerPopupMenu) {
// override to append more actions
}
fTable.setColumnHeaders(columnData);
}
+ /**
+ * Set a table item's data.
+ *
+ * @param item
+ * The item to set
+ * @param event
+ * Which trace event to link with this entry
+ * @param rank
+ * Which rank this event has in the trace/experiment
+ */
protected void setItemData(final TableItem item, final ITmfEvent event, final long rank) {
final ITmfEventField[] fields = extractItemFields(event);
final String[] content = new String[fields.length];
content[i] = fields[i].getValue() != null ? fields[i].getValue().toString() : ""; //$NON-NLS-1$
}
item.setText(content);
+ item.setData(event);
item.setData(Key.TIMESTAMP, new TmfTimestamp(event.getTimestamp()));
item.setData(Key.RANK, rank);
}
}
+ /**
+ * Set the item data of the header row.
+ *
+ * @param item
+ * The item to use as table header
+ */
protected void setHeaderRowItemData(final TableItem item) {
String txtKey = null;
if (fHeaderState == HeaderState.SEARCH) {
}
}
+ /**
+ * Set the item data of the "filter status" row.
+ *
+ * @param item
+ * The item to use as filter status row
+ */
protected void setFilterStatusRowItemData(final TableItem item) {
for (int i = 0; i < fTable.getColumns().length; i++) {
if (i == 0) {
item.setText(i, ""); //$NON-NLS-1$
}
}
+ item.setData(null);
item.setData(Key.TIMESTAMP, null);
item.setData(Key.RANK, null);
item.setForeground(null);
item.setBackground(null);
}
+ /**
+ * Create an editor for the header.
+ */
protected void createHeaderEditor() {
final TableEditor tableEditor = fTable.createTableEditor();
tableEditor.horizontalAlignment = SWT.LEFT;
if (fHeaderState == HeaderState.SEARCH) {
stopSearchThread();
final TmfFilterAndNode filter = new TmfFilterAndNode(null);
- for (final TableColumn column : fTable.getColumns()) {
- final Object filterObj = column.getData(Key.SEARCH_OBJ);
+ for (final TableColumn col : fTable.getColumns()) {
+ final Object filterObj = col.getData(Key.SEARCH_OBJ);
if (filterObj instanceof ITmfFilterTreeNode) {
filter.addChild((ITmfFilterTreeNode) filterObj);
}
}
} else if (fHeaderState == HeaderState.FILTER) {
final TmfFilterAndNode filter = new TmfFilterAndNode(null);
- for (final TableColumn column : fTable.getColumns()) {
- final Object filterObj = column.getData(Key.FILTER_OBJ);
+ for (final TableColumn col : fTable.getColumns()) {
+ final Object filterObj = col.getData(Key.FILTER_OBJ);
if (filterObj instanceof ITmfFilterTreeNode) {
filter.addChild((ITmfFilterTreeNode) filterObj);
}
});
}
+ /**
+ * Send an event indicating a filter has been applied.
+ *
+ * @param filter
+ * The filter that was just applied
+ */
protected void fireFilterApplied(final ITmfFilter filter) {
- for (final ITmfEventsFilterListener listener : fEventsFilterListeners) {
- listener.filterApplied(filter, fTrace);
- }
+ broadcast(new TmfEventFilterAppliedSignal(this, fTrace, filter));
}
+ /**
+ * Send an event indicating that a search has been applied.
+ *
+ * @param filter
+ * The search filter that was just applied
+ */
protected void fireSearchApplied(final ITmfFilter filter) {
- for (final ITmfEventsFilterListener listener : fEventsFilterListeners) {
- listener.searchApplied(filter, fTrace);
- }
+ broadcast(new TmfEventSearchAppliedSignal(this, fTrace, filter));
}
+ /**
+ * Start the filtering thread.
+ */
protected void startFilterThread() {
synchronized (fFilterSyncObj) {
final ITmfFilterTreeNode filter = (ITmfFilterTreeNode) fTable.getData(Key.FILTER_OBJ);
}
}
+ /**
+ * Stop the filtering thread.
+ */
protected void stopFilterThread() {
synchronized (fFilterSyncObj) {
if (fFilterThread != null) {
}
/**
+ * Apply a filter.
+ *
+ * @param filter
+ * The filter to apply
* @since 1.1
*/
protected void applyFilter(ITmfFilter filter) {
- stopFilterThread();
- stopSearchThread();
+ stopFilterThread();
+ stopSearchThread();
fFilterMatchCount = 0;
fFilterCheckCount = 0;
fCache.applyFilter(filter);
fireFilterApplied(filter);
}
+ /**
+ * Clear all currently active filters.
+ */
protected void clearFilters() {
if (fTable.getData(Key.FILTER_OBJ) == null) {
return;
fireFilterApplied(null);
}
+ /**
+ * Wrapper Thread object for the filtering thread.
+ */
protected class FilterThread extends Thread {
private final ITmfFilterTreeNode filter;
- private TmfDataRequest<ITmfEvent> request;
+ private TmfDataRequest request;
private boolean refreshBusy = false;
private boolean refreshPending = false;
private final Object syncObj = new Object();
+ /**
+ * Constructor.
+ *
+ * @param filter
+ * The filter this thread will be processing
+ */
public FilterThread(final ITmfFilterTreeNode filter) {
super("Filter Thread"); //$NON-NLS-1$
this.filter = filter;
}
- @SuppressWarnings("unchecked")
@Override
public void run() {
if (fTrace == null) {
if (nbRequested <= 0) {
return;
}
- request = new TmfDataRequest<ITmfEvent>(ITmfEvent.class, (int) fFilterCheckCount,
+ request = new TmfDataRequest(ITmfEvent.class, (int) fFilterCheckCount,
nbRequested, fTrace.getCacheSize(), ExecutionType.BACKGROUND) {
@Override
public void handleData(final ITmfEvent event) {
final long rank = fFilterCheckCount;
final int index = (int) fFilterMatchCount;
fFilterMatchCount++;
- fCache.storeEvent(event.clone(), rank, index);
+ fCache.storeEvent(event, rank, index);
refreshTable();
} else if ((fFilterCheckCount % 100) == 0) {
refreshTable();
fFilterCheckCount++;
}
};
- ((ITmfDataProvider<ITmfEvent>) fTrace).sendRequest(request);
+ ((ITmfDataProvider) fTrace).sendRequest(request);
try {
request.waitForCompletion();
} catch (final InterruptedException e) {
}
}
+ /**
+ * Refresh the filter.
+ */
public void refreshTable() {
synchronized (syncObj) {
if (refreshBusy) {
});
}
+ /**
+ * Cancel this filtering thread.
+ */
public void cancel() {
if (request != null) {
request.cancel();
}
}
+ /**
+ * Go to the next item of a search.
+ */
protected void searchNext() {
synchronized (fSearchSyncObj) {
if (fSearchThread != null) {
startIndex = Math.max(0, fTable.getTopIndex() - 1); // -1 for header row
}
final ITmfFilterTreeNode eventFilter = (ITmfFilterTreeNode) fTable.getData(Key.FILTER_OBJ);
- if (eventFilter != null)
- {
+ if (eventFilter != null) {
startIndex = Math.max(0, startIndex - 1); // -1 for top filter status row
}
fSearchThread = new SearchThread(searchFilter, eventFilter, startIndex, fSelectedRank, Direction.FORWARD);
}
}
+ /**
+ * Go to the previous item of a search.
+ */
protected void searchPrevious() {
synchronized (fSearchSyncObj) {
if (fSearchThread != null) {
startIndex = fTable.getTopIndex() - 2; // -1 for header row, -1 for previous event
}
final ITmfFilterTreeNode eventFilter = (ITmfFilterTreeNode) fTable.getData(Key.FILTER_OBJ);
- if (eventFilter != null)
- {
+ if (eventFilter != null) {
startIndex = startIndex - 1; // -1 for top filter status row
}
fSearchThread = new SearchThread(searchFilter, eventFilter, startIndex, fSelectedRank, Direction.BACKWARD);
}
}
+ /**
+ * Stop the search thread.
+ */
protected void stopSearchThread() {
fPendingGotoRank = -1;
synchronized (fSearchSyncObj) {
}
}
+ /**
+ * Wrapper for the search thread.
+ */
protected class SearchThread extends Job {
- protected ITmfFilterTreeNode searchFilter;
- protected ITmfFilterTreeNode eventFilter;
- protected int startIndex;
- protected int direction;
- protected long rank;
- protected long foundRank = -1;
- protected TmfDataRequest<ITmfEvent> request;
+
+ private ITmfFilterTreeNode searchFilter;
+ private ITmfFilterTreeNode eventFilter;
+ private int startIndex;
+ private int direction;
+ private long rank;
+ private long foundRank = -1;
+ private TmfDataRequest request;
private ITmfTimestamp foundTimestamp = null;
- public SearchThread(final ITmfFilterTreeNode searchFilter, final ITmfFilterTreeNode eventFilter, final int startIndex,
+ /**
+ * Constructor.
+ *
+ * @param searchFilter
+ * The search filter
+ * @param eventFilter
+ * The event filter
+ * @param startIndex
+ * The index at which we should start searching
+ * @param currentRank
+ * The current rank
+ * @param direction
+ * In which direction should we search, forward or backwards
+ */
+ public SearchThread(final ITmfFilterTreeNode searchFilter,
+ final ITmfFilterTreeNode eventFilter, final int startIndex,
final long currentRank, final int direction) {
super(Messages.TmfEventsTable_SearchingJobName);
this.searchFilter = searchFilter;
this.direction = direction;
}
- @SuppressWarnings("unchecked")
@Override
protected IStatus run(final IProgressMonitor monitor) {
if (fTrace == null) {
if (direction == Direction.BACKWARD) {
rank = Math.max(0, rank - fTrace.getCacheSize() + 1);
}
- request = new TmfDataRequest<ITmfEvent>(ITmfEvent.class, (int) rank, nbRequested, fTrace.getCacheSize(), ExecutionType.BACKGROUND) {
+ request = new TmfDataRequest(ITmfEvent.class, (int) rank, nbRequested, fTrace.getCacheSize(), ExecutionType.BACKGROUND) {
long currentRank = rank;
@Override
currentRank++;
}
};
- ((ITmfDataProvider<ITmfEvent>) fTrace).sendRequest(request);
+ ((ITmfDataProvider) fTrace).sendRequest(request);
try {
request.waitForCompletion();
if (request.isCancelled()) {
if (foundTimestamp != null) {
broadcast(new TmfTimeSynchSignal(TmfEventsTable.this, foundTimestamp));
}
+ fireSelectionChanged(new SelectionChangedEvent(TmfEventsTable.this, getSelection()));
synchronized (fSearchSyncObj) {
fSearchThread = null;
}
}
}
+ /**
+ * Create the resources.
+ */
protected void createResources() {
fGrayColor = fResourceManager.createColor(ColorUtil.blend(fTable.getBackground().getRGB(), fTable
.getForeground().getRGB()));
fBoldFont = fResourceManager.createFont(FontDescriptor.createFrom(fTable.getFont()).setStyle(SWT.BOLD));
}
+ /**
+ * Pack the columns.
+ */
protected void packColumns() {
if (fPackDone) {
return;
}
- for (final TableColumn column : fTable.getColumns()) {
+ boolean isLinux = System.getProperty("os.name").contains("Linux") ? true : false; //$NON-NLS-1$ //$NON-NLS-2$
+
+ TableColumn tableColumns[] = fTable.getColumns();
+ for (int i = 0; i < tableColumns.length; i++) {
+ final TableColumn column = tableColumns[i];
final int headerWidth = column.getWidth();
column.pack();
+ // Workaround for Linux which doesn't consider the image width of
+ // search/filter row in TableColumn.pack() after having executed
+ // TableItem.setImage((Image)null) for other rows than search/filter row.
+ if (isLinux && (i == 0)) {
+ column.setWidth(column.getWidth() + SEARCH_IMAGE.getBounds().width);
+ }
+
if (column.getWidth() < headerWidth) {
column.setWidth(headerWidth);
}
}
/**
+ * Extract the fields of an event (item in the table).
+ *
* @param event
- * @return
+ * The event to extract from
+ * @return The array of fields
*
* FIXME: Add support for column selection
*/
final String source = event.getSource();
final String type = event.getType().getName();
final String reference = event.getReference();
- final ITmfEventField content = event.getContent();
- final String value = (content.getValue() != null) ? content.getValue().toString() : content.toString();
+ final String content = event.getContent().toString();
fields = new TmfEventField[] {
new TmfEventField(ITmfEvent.EVENT_FIELD_TIMESTAMP, timestamp),
new TmfEventField(ITmfEvent.EVENT_FIELD_SOURCE, source),
new TmfEventField(ITmfEvent.EVENT_FIELD_TYPE, type),
new TmfEventField(ITmfEvent.EVENT_FIELD_REFERENCE, reference),
- new TmfEventField(ITmfEvent.EVENT_FIELD_CONTENT, value)
+ new TmfEventField(ITmfEvent.EVENT_FIELD_CONTENT, content)
};
}
return fields;
* true if the trace should be disposed when the table is
* disposed
*/
- public void setTrace(final ITmfTrace<?> trace, final boolean disposeOnClose) {
+ public void setTrace(final ITmfTrace trace, final boolean disposeOnClose) {
if ((fTrace != null) && fDisposeOnClose) {
fTrace.dispose();
}
startFilterThread();
}
}
- fRawViewer.setTrace(fTrace);
}
+ fRawViewer.setTrace(fTrace);
}
});
}
}
}
+ /**
+ * Callback for when populating the table is complete.
+ */
protected void populateCompleted() {
// Nothing by default;
}
+ // ------------------------------------------------------------------------
+ // ISelectionProvider
+ // ------------------------------------------------------------------------
+
+ /* (non-Javadoc)
+ * @see org.eclipse.jface.viewers.ISelectionProvider#addSelectionChangedListener(org.eclipse.jface.viewers.ISelectionChangedListener)
+ */
+ /**
+ * @since 2.0
+ */
+ @Override
+ public void addSelectionChangedListener(ISelectionChangedListener listener) {
+ selectionChangedListeners.add(listener);
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.jface.viewers.ISelectionProvider#getSelection()
+ */
+ /**
+ * @since 2.0
+ */
+ @Override
+ public ISelection getSelection() {
+ if (fTable == null || fTable.isDisposed()) {
+ return StructuredSelection.EMPTY;
+ }
+ List<Object> list = new ArrayList<Object>(fTable.getSelection().length);
+ for (TableItem item : fTable.getSelection()) {
+ if (item.getData() != null) {
+ list.add(item.getData());
+ }
+ }
+ return new StructuredSelection(list);
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.jface.viewers.ISelectionProvider#removeSelectionChangedListener(org.eclipse.jface.viewers.ISelectionChangedListener)
+ */
+ /**
+ * @since 2.0
+ */
+ @Override
+ public void removeSelectionChangedListener(ISelectionChangedListener listener) {
+ selectionChangedListeners.remove(listener);
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.jface.viewers.ISelectionProvider#setSelection(org.eclipse.jface.viewers.ISelection)
+ */
+ /**
+ * @since 2.0
+ */
+ @Override
+ public void setSelection(ISelection selection) {
+ // not implemented
+ }
+
+ /**
+ * Notifies any selection changed listeners that the viewer's selection has changed.
+ * Only listeners registered at the time this method is called are notified.
+ *
+ * @param event a selection changed event
+ *
+ * @see ISelectionChangedListener#selectionChanged
+ * @since 2.0
+ */
+ protected void fireSelectionChanged(final SelectionChangedEvent event) {
+ Object[] listeners = selectionChangedListeners.getListeners();
+ for (int i = 0; i < listeners.length; ++i) {
+ final ISelectionChangedListener l = (ISelectionChangedListener) listeners[i];
+ SafeRunnable.run(new SafeRunnable() {
+ @Override
+ public void run() {
+ l.selectionChanged(event);
+ }
+ });
+ }
+ }
+
// ------------------------------------------------------------------------
// Bookmark handling
// ------------------------------------------------------------------------
if (tableItem.getData(Key.RANK) != null) {
final StringBuffer defaultMessage = new StringBuffer();
for (int i = 0; i < fTable.getColumns().length; i++) {
- if (i > 0)
- {
+ if (i > 0) {
defaultMessage.append(", "); //$NON-NLS-1$
}
defaultMessage.append(tableItem.getText(i));
}
- final InputDialog dialog = new InputDialog(PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell(),
- Messages.TmfEventsTable_AddBookmarkDialogTitle, Messages.TmfEventsTable_AddBookmarkDialogText,
- defaultMessage.toString(), null);
+ final InputDialog dialog = new MultiLineInputDialog(
+ PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell(),
+ Messages.TmfEventsTable_AddBookmarkDialogTitle,
+ Messages.TmfEventsTable_AddBookmarkDialogMessage,
+ defaultMessage.toString());
if (dialog.open() == Window.OK) {
final String message = dialog.getValue();
try {
} else if (rank >= fTable.getItemCount()) {
fPendingGotoRank = rank;
}
+ fSelectedRank = rank;
fTable.setSelection(index + 1); // +1 for header row
}
}
fTable.refresh();
}
- @Override
- public void addEventsFilterListener(final ITmfEventsFilterListener listener) {
- if (!fEventsFilterListeners.contains(listener)) {
- fEventsFilterListeners.add(listener);
- }
- }
-
- @Override
- public void removeEventsFilterListener(final ITmfEventsFilterListener listener) {
- fEventsFilterListeners.remove(listener);
- }
-
// ------------------------------------------------------------------------
// Signal handlers
// ------------------------------------------------------------------------
- /**
- * Handler for the experiment updated signal.
- *
- * @param signal
- * The incoming signal
- */
- @TmfSignalHandler
- public void experimentUpdated(final TmfExperimentUpdatedSignal signal) {
- if ((signal.getExperiment() != fTrace) || fTable.isDisposed()) {
- return;
- }
- // Perform the refresh on the UI thread
- Display.getDefault().asyncExec(new Runnable() {
- @Override
- public void run() {
- if (!fTable.isDisposed() && (fTrace != null)) {
- if (fTable.getData(Key.FILTER_OBJ) == null) {
- fTable.setItemCount((int) fTrace.getNbEvents() + 1); // +1 for header row
- if ((fPendingGotoRank != -1) && ((fPendingGotoRank + 1) < fTable.getItemCount())) { // +1 for header row
- fTable.setSelection((int) fPendingGotoRank + 1); // +1 for header row
- fPendingGotoRank = -1;
- }
- } else {
- startFilterThread();
- }
- }
- if (!fRawViewer.isDisposed() && (fTrace != null)) {
- fRawViewer.refreshEventCount();
- }
- }
- });
- }
-
/**
* Handler for the trace updated signal
*
* @param signal
* The incoming signal
*/
- @SuppressWarnings("unchecked")
@TmfSignalHandler
public void currentTimeUpdated(final TmfTimeSynchSignal signal) {
if ((signal.getSource() != this) && (fTrace != null) && (!fTable.isDisposed())) {
// Create a request for one event that will be queued after other ongoing requests. When this request is completed
// do the work to select the actual event with the timestamp specified in the signal. This procedure prevents
// the method fTrace.getRank() from interfering and delaying ongoing requests.
- final TmfDataRequest<ITmfEvent> subRequest = new TmfDataRequest<ITmfEvent>(ITmfEvent.class, 0, 1, ExecutionType.FOREGROUND) {
+ final TmfDataRequest subRequest = new TmfDataRequest(ITmfEvent.class, 0, 1, ExecutionType.FOREGROUND) {
TmfTimestamp ts = new TmfTimestamp(signal.getCurrentTime());
// Get the rank of the selected event in the table
final ITmfContext context = fTrace.seekEvent(timestamp);
final long rank = context.getRank();
+ context.dispose();
fSelectedRank = rank;
fTable.getDisplay().asyncExec(new Runnable() {
if (fTable.isDisposed()) {
return;
}
- if (fTable.getData(Key.FILTER_OBJ) != null)
- {
+ if (fTable.getData(Key.FILTER_OBJ) != null) {
index = fCache.getFilteredEventIndex(rank) + 1; // +1 for top filter status row
}
fTable.setSelection(index + 1); // +1 for header row
}
};
- ((ITmfDataProvider<ITmfEvent>) fTrace).sendRequest(subRequest);
+ ((ITmfDataProvider) fTrace).sendRequest(subRequest);
}
}
*/
private static void displayException(final Exception e) {
final MessageBox mb = new MessageBox(PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell());
- mb.setText(e.getClass().getName());
+ mb.setText(e.getClass().getSimpleName());
mb.setMessage(e.getMessage());
mb.open();
}
+ /**
+ * @since 2.0
+ */
+ public void refresh() {
+ fCache.clear();
+ fTable.refresh();
+ fTable.redraw();
+ }
}