tmf.ui: convert long list of catches to a multi-catch
[deliverable/tracecompass.git] / org.eclipse.tracecompass.tmf.ui / src / org / eclipse / tracecompass / tmf / ui / viewers / events / TmfEventsTable.java
CommitLineData
db4721fb 1/*******************************************************************************
60ae41e1 2 * Copyright (c) 2010, 2014 Ericsson
db4721fb
PT
3 *
4 * All rights reserved. This program and the accompanying materials are
5 * made available under the terms of the Eclipse Public License v1.0 which
6 * accompanies this distribution, and is available at
7 * http://www.eclipse.org/legal/epl-v10.html
8 *
9 * Contributors:
baafe54c
AM
10 * Francois Chouinard - Initial API and implementation, replaced Table by TmfVirtualTable
11 * Patrick Tasse - Factored out from events view,
12 * Filter implementation (inspired by www.eclipse.org/mat)
ac44ef71 13 * Ansgar Radermacher - Support navigation to model URIs (Bug 396956)
f47ed727 14 * Bernd Hufmann - Updated call site and model URI implementation
baafe54c 15 * Alexandre Montplaisir - Update to new column API
db4721fb
PT
16 *******************************************************************************/
17
2bdf0193 18package org.eclipse.tracecompass.tmf.ui.viewers.events;
db4721fb 19
60fb38b8 20import java.io.FileNotFoundException;
db4721fb 21import java.util.ArrayList;
2db176a0 22import java.util.Collection;
db4721fb 23import java.util.HashMap;
baafe54c 24import java.util.LinkedList;
db4721fb 25import java.util.List;
db4721fb
PT
26import java.util.Map.Entry;
27import java.util.regex.Pattern;
28import java.util.regex.PatternSyntaxException;
29
d3de0920
XR
30import org.eclipse.core.commands.Command;
31import org.eclipse.core.commands.ExecutionException;
32import org.eclipse.core.commands.NotEnabledException;
33import org.eclipse.core.commands.NotHandledException;
34import org.eclipse.core.commands.ParameterizedCommand;
35import org.eclipse.core.commands.common.NotDefinedException;
36import org.eclipse.core.expressions.IEvaluationContext;
db4721fb
PT
37import org.eclipse.core.resources.IFile;
38import org.eclipse.core.resources.IMarker;
39import org.eclipse.core.resources.IResource;
60fb38b8 40import org.eclipse.core.resources.IResourceVisitor;
ac44ef71 41import org.eclipse.core.resources.ResourcesPlugin;
db4721fb 42import org.eclipse.core.runtime.CoreException;
ac44ef71 43import org.eclipse.core.runtime.IPath;
db4721fb
PT
44import org.eclipse.core.runtime.IProgressMonitor;
45import org.eclipse.core.runtime.IStatus;
93bfd50a 46import org.eclipse.core.runtime.ListenerList;
ac44ef71 47import org.eclipse.core.runtime.Path;
db4721fb
PT
48import org.eclipse.core.runtime.Status;
49import org.eclipse.core.runtime.jobs.Job;
ac44ef71
AR
50import org.eclipse.emf.common.util.URI;
51import org.eclipse.emf.ecore.EValidator;
46671228 52import org.eclipse.jdt.annotation.NonNull;
db4721fb
PT
53import org.eclipse.jface.action.Action;
54import org.eclipse.jface.action.IAction;
55import org.eclipse.jface.action.IMenuListener;
56import org.eclipse.jface.action.IMenuManager;
3f43dc48 57import org.eclipse.jface.action.IStatusLineManager;
db4721fb
PT
58import org.eclipse.jface.action.MenuManager;
59import org.eclipse.jface.action.Separator;
60import org.eclipse.jface.dialogs.InputDialog;
61import org.eclipse.jface.dialogs.MessageDialog;
62import org.eclipse.jface.resource.FontDescriptor;
63import org.eclipse.jface.resource.JFaceResources;
64import org.eclipse.jface.resource.LocalResourceManager;
ac44ef71 65import org.eclipse.jface.util.OpenStrategy;
93bfd50a 66import org.eclipse.jface.util.SafeRunnable;
60fb38b8 67import org.eclipse.jface.viewers.ArrayContentProvider;
93bfd50a
PT
68import org.eclipse.jface.viewers.ISelection;
69import org.eclipse.jface.viewers.ISelectionChangedListener;
70import org.eclipse.jface.viewers.ISelectionProvider;
60fb38b8 71import org.eclipse.jface.viewers.LabelProvider;
93bfd50a
PT
72import org.eclipse.jface.viewers.SelectionChangedEvent;
73import org.eclipse.jface.viewers.StructuredSelection;
db4721fb 74import org.eclipse.jface.window.Window;
db4721fb
PT
75import org.eclipse.swt.SWT;
76import org.eclipse.swt.custom.SashForm;
77import org.eclipse.swt.custom.TableEditor;
6817308e
PT
78import org.eclipse.swt.events.ControlAdapter;
79import org.eclipse.swt.events.ControlEvent;
db4721fb
PT
80import org.eclipse.swt.events.FocusAdapter;
81import org.eclipse.swt.events.FocusEvent;
82import org.eclipse.swt.events.KeyAdapter;
83import org.eclipse.swt.events.KeyEvent;
84import org.eclipse.swt.events.MouseAdapter;
85import org.eclipse.swt.events.MouseEvent;
86import org.eclipse.swt.events.SelectionAdapter;
87import org.eclipse.swt.events.SelectionEvent;
88import org.eclipse.swt.graphics.Color;
89import org.eclipse.swt.graphics.Font;
90import org.eclipse.swt.graphics.Image;
91import org.eclipse.swt.graphics.Point;
92import org.eclipse.swt.graphics.Rectangle;
93import org.eclipse.swt.layout.FillLayout;
94import org.eclipse.swt.layout.GridData;
95import org.eclipse.swt.layout.GridLayout;
96import org.eclipse.swt.widgets.Composite;
97import org.eclipse.swt.widgets.Display;
98import org.eclipse.swt.widgets.Event;
99import org.eclipse.swt.widgets.Label;
100import org.eclipse.swt.widgets.Listener;
101import org.eclipse.swt.widgets.Menu;
102import org.eclipse.swt.widgets.MessageBox;
103import org.eclipse.swt.widgets.Shell;
104import org.eclipse.swt.widgets.TableColumn;
105import org.eclipse.swt.widgets.TableItem;
106import org.eclipse.swt.widgets.Text;
2bdf0193
AM
107import org.eclipse.tracecompass.internal.tmf.core.filter.TmfCollapseFilter;
108import org.eclipse.tracecompass.internal.tmf.ui.Activator;
109import org.eclipse.tracecompass.internal.tmf.ui.Messages;
110import org.eclipse.tracecompass.internal.tmf.ui.commands.ExportToTextCommandHandler;
111import org.eclipse.tracecompass.internal.tmf.ui.dialogs.MultiLineInputDialog;
112import org.eclipse.tracecompass.tmf.core.component.ITmfEventProvider;
113import org.eclipse.tracecompass.tmf.core.component.TmfComponent;
114import org.eclipse.tracecompass.tmf.core.event.ITmfEvent;
9447c7ee
AM
115import org.eclipse.tracecompass.tmf.core.event.aspect.ITmfEventAspect;
116import org.eclipse.tracecompass.tmf.core.event.aspect.TmfEventFieldAspect;
2bdf0193
AM
117import org.eclipse.tracecompass.tmf.core.event.collapse.ITmfCollapsibleEvent;
118import org.eclipse.tracecompass.tmf.core.event.lookup.ITmfCallsite;
119import org.eclipse.tracecompass.tmf.core.event.lookup.ITmfModelLookup;
120import org.eclipse.tracecompass.tmf.core.event.lookup.ITmfSourceLookup;
121import org.eclipse.tracecompass.tmf.core.filter.ITmfFilter;
122import org.eclipse.tracecompass.tmf.core.filter.model.ITmfFilterTreeNode;
123import org.eclipse.tracecompass.tmf.core.filter.model.TmfFilterAndNode;
124import org.eclipse.tracecompass.tmf.core.filter.model.TmfFilterMatchesNode;
125import org.eclipse.tracecompass.tmf.core.filter.model.TmfFilterNode;
126import org.eclipse.tracecompass.tmf.core.request.ITmfEventRequest.ExecutionType;
127import org.eclipse.tracecompass.tmf.core.request.TmfEventRequest;
128import org.eclipse.tracecompass.tmf.core.signal.TmfEventFilterAppliedSignal;
129import org.eclipse.tracecompass.tmf.core.signal.TmfEventSearchAppliedSignal;
130import org.eclipse.tracecompass.tmf.core.signal.TmfEventSelectedSignal;
131import org.eclipse.tracecompass.tmf.core.signal.TmfSignalHandler;
132import org.eclipse.tracecompass.tmf.core.signal.TmfTimeSynchSignal;
133import org.eclipse.tracecompass.tmf.core.signal.TmfTraceUpdatedSignal;
134import org.eclipse.tracecompass.tmf.core.timestamp.ITmfTimestamp;
135import org.eclipse.tracecompass.tmf.core.timestamp.TmfTimeRange;
136import org.eclipse.tracecompass.tmf.core.timestamp.TmfTimestamp;
137import org.eclipse.tracecompass.tmf.core.trace.ITmfContext;
138import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace;
b04903a2 139import org.eclipse.tracecompass.tmf.core.trace.TmfTrace;
2bdf0193
AM
140import org.eclipse.tracecompass.tmf.core.trace.TmfTraceManager;
141import org.eclipse.tracecompass.tmf.core.trace.location.ITmfLocation;
142import org.eclipse.tracecompass.tmf.ui.viewers.events.TmfEventsCache.CachedEvent;
143import org.eclipse.tracecompass.tmf.ui.viewers.events.columns.TmfEventTableColumn;
2bdf0193
AM
144import org.eclipse.tracecompass.tmf.ui.views.colors.ColorSetting;
145import org.eclipse.tracecompass.tmf.ui.views.colors.ColorSettingsManager;
146import org.eclipse.tracecompass.tmf.ui.views.colors.IColorSettingsListener;
147import org.eclipse.tracecompass.tmf.ui.views.filter.FilterManager;
148import org.eclipse.tracecompass.tmf.ui.widgets.rawviewer.TmfRawEventViewer;
149import org.eclipse.tracecompass.tmf.ui.widgets.virtualtable.TmfVirtualTable;
ac44ef71 150import org.eclipse.ui.IWorkbenchPage;
db4721fb 151import org.eclipse.ui.PlatformUI;
d3de0920 152import org.eclipse.ui.commands.ICommandService;
60fb38b8 153import org.eclipse.ui.dialogs.ListDialog;
d3de0920 154import org.eclipse.ui.handlers.IHandlerService;
ac44ef71 155import org.eclipse.ui.ide.IDE;
db4721fb
PT
156import org.eclipse.ui.ide.IGotoMarker;
157import org.eclipse.ui.themes.ColorUtil;
158
2db176a0
PT
159import com.google.common.base.Joiner;
160import com.google.common.collect.HashMultimap;
baafe54c 161import com.google.common.collect.ImmutableList;
2db176a0
PT
162import com.google.common.collect.Multimap;
163
db4721fb
PT
164/**
165 * The generic TMF Events table
166 *
167 * This is a view that will list events that are read from a trace.
168 *
db4721fb
PT
169 * @author Francois Chouinard
170 * @author Patrick Tasse
93bfd50a 171 * @since 2.0
db4721fb 172 */
faa38350 173public class TmfEventsTable extends TmfComponent implements IGotoMarker, IColorSettingsListener, ISelectionProvider {
db4721fb 174
cf37ad9f
AM
175 /**
176 * Empty string array, used by {@link #getItemStrings}.
177 * @since 3.0
178 */
46671228 179 protected static final @NonNull String[] EMPTY_STRING_ARRAY = new String[0];
cf37ad9f 180
baafe54c
AM
181 /**
182 * Empty string
183 * @since 3.1
184 */
185 protected static final @NonNull String EMPTY_STRING = ""; //$NON-NLS-1$
186
03142470
BH
187 private static final boolean IS_LINUX = System.getProperty("os.name").contains("Linux") ? true : false; //$NON-NLS-1$ //$NON-NLS-2$
188
db4721fb
PT
189 private static final Image BOOKMARK_IMAGE = Activator.getDefault().getImageFromPath(
190 "icons/elcl16/bookmark_obj.gif"); //$NON-NLS-1$
191 private static final Image SEARCH_IMAGE = Activator.getDefault().getImageFromPath("icons/elcl16/search.gif"); //$NON-NLS-1$
192 private static final Image SEARCH_MATCH_IMAGE = Activator.getDefault().getImageFromPath(
193 "icons/elcl16/search_match.gif"); //$NON-NLS-1$
194 private static final Image SEARCH_MATCH_BOOKMARK_IMAGE = Activator.getDefault().getImageFromPath(
195 "icons/elcl16/search_match_bookmark.gif"); //$NON-NLS-1$
196 private static final Image FILTER_IMAGE = Activator.getDefault()
197 .getImageFromPath("icons/elcl16/filter_items.gif"); //$NON-NLS-1$
198 private static final Image STOP_IMAGE = Activator.getDefault().getImageFromPath("icons/elcl16/stop.gif"); //$NON-NLS-1$
199 private static final String SEARCH_HINT = Messages.TmfEventsTable_SearchHint;
200 private static final String FILTER_HINT = Messages.TmfEventsTable_FilterHint;
201 private static final int MAX_CACHE_SIZE = 1000;
202
03142470
BH
203 private static final int MARGIN_COLUMN_INDEX = 0;
204 private static final int FILTER_SUMMARY_INDEX = 1;
205 private static final int EVENT_COLUMNS_START_INDEX = MARGIN_COLUMN_INDEX + 1;
206
db4721fb
PT
207 /**
208 * The events table search/filter keys
209 *
210 * @version 1.0
211 * @author Patrick Tasse
212 */
213 public interface Key {
214 /** Search text */
215 String SEARCH_TXT = "$srch_txt"; //$NON-NLS-1$
216
217 /** Search object */
218 String SEARCH_OBJ = "$srch_obj"; //$NON-NLS-1$
219
220 /** Filter text */
221 String FILTER_TXT = "$fltr_txt"; //$NON-NLS-1$
222
223 /** Filter object */
224 String FILTER_OBJ = "$fltr_obj"; //$NON-NLS-1$
225
dadf6e1a 226 /** Timestamp */
db4721fb
PT
227 String TIMESTAMP = "$time"; //$NON-NLS-1$
228
229 /** Rank */
230 String RANK = "$rank"; //$NON-NLS-1$
231
232 /** Field ID */
233 String FIELD_ID = "$field_id"; //$NON-NLS-1$
234
235 /** Bookmark indicator */
236 String BOOKMARK = "$bookmark"; //$NON-NLS-1$
237 }
238
239 /**
240 * The events table search/filter state
241 *
242 * @version 1.0
243 * @author Patrick Tasse
244 */
245 public static enum HeaderState {
246 /** A search is being run */
247 SEARCH,
248
249 /** A filter is applied */
250 FILTER
251 }
252
253 interface Direction {
254 int FORWARD = +1;
255 int BACKWARD = -1;
256 }
257
258 // ------------------------------------------------------------------------
259 // Table data
260 // ------------------------------------------------------------------------
261
a0a88f65 262 /** The virtual event table */
db4721fb 263 protected TmfVirtualTable fTable;
a0a88f65
AM
264
265 private Composite fComposite;
266 private SashForm fSashForm;
267 private TmfRawEventViewer fRawViewer;
268 private ITmfTrace fTrace;
03142470 269 volatile private boolean fPackDone = false;
a0a88f65
AM
270 private HeaderState fHeaderState = HeaderState.SEARCH;
271 private long fSelectedRank = 0;
3f43dc48
PT
272 private ITmfTimestamp fSelectedBeginTimestamp = null;
273 private IStatusLineManager fStatusLineManager = null;
db4721fb
PT
274
275 // Filter data
a0a88f65
AM
276 private long fFilterMatchCount;
277 private long fFilterCheckCount;
278 private FilterThread fFilterThread;
279 private boolean fFilterThreadResume = false;
280 private final Object fFilterSyncObj = new Object();
281 private SearchThread fSearchThread;
282 private final Object fSearchSyncObj = new Object();
db4721fb 283
93bfd50a
PT
284 /**
285 * List of selection change listeners (element type: <code>ISelectionChangedListener</code>).
286 *
287 * @see #fireSelectionChanged
288 */
289 private ListenerList selectionChangedListeners = new ListenerList();
290
db4721fb 291 // Bookmark map <Rank, MarkerId>
2db176a0 292 private Multimap<Long, Long> fBookmarksMap = HashMultimap.create();
a0a88f65
AM
293 private IFile fBookmarksFile;
294 private long fPendingGotoRank = -1;
db4721fb
PT
295
296 // SWT resources
a0a88f65
AM
297 private LocalResourceManager fResourceManager = new LocalResourceManager(JFaceResources.getResources());
298 private Color fGrayColor;
299 private Color fGreenColor;
300 private Font fBoldFont;
db4721fb 301
baafe54c 302 private final List<TmfEventTableColumn> fColumns = new LinkedList<>();
db4721fb
PT
303
304 // Event cache
305 private final TmfEventsCache fCache;
306 private boolean fCacheUpdateBusy = false;
307 private boolean fCacheUpdatePending = false;
308 private boolean fCacheUpdateCompleted = false;
309 private final Object fCacheUpdateSyncObj = new Object();
310
311 private boolean fDisposeOnClose;
312
313 // ------------------------------------------------------------------------
a0a88f65 314 // Constructors
db4721fb
PT
315 // ------------------------------------------------------------------------
316
317 /**
baafe54c 318 * Basic constructor, using the default set of columns
db4721fb
PT
319 *
320 * @param parent
321 * The parent composite UI object
322 * @param cacheSize
323 * The size of the event table cache
324 */
325 public TmfEventsTable(final Composite parent, final int cacheSize) {
b04903a2 326 this(parent, cacheSize, TmfTrace.BASE_ASPECTS);
db4721fb
PT
327 }
328
329 /**
baafe54c 330 * Legacy constructor, using ColumnData to define columns
db4721fb
PT
331 *
332 * @param parent
333 * The parent composite UI object
334 * @param cacheSize
335 * The size of the event table cache
336 * @param columnData
baafe54c
AM
337 * Unused
338 * @deprecated Deprecated constructor, use
339 * {@link #TmfEventsTable(Composite, int, Collection)}
340 */
341 @Deprecated
342 public TmfEventsTable(final Composite parent, int cacheSize,
2bdf0193 343 final org.eclipse.tracecompass.tmf.ui.widgets.virtualtable.ColumnData[] columnData) {
baafe54c
AM
344 /*
345 * We'll do a "best-effort" to keep trace types still using this API to
346 * keep working, by defining a TmfEventTableFieldColumn for each
347 * ColumnData they passed.
348 */
349 this(parent, cacheSize, convertFromColumnData(columnData));
350 }
351
352 @Deprecated
8192209b 353 private static @NonNull Iterable<ITmfEventAspect> convertFromColumnData(
2bdf0193 354 org.eclipse.tracecompass.tmf.ui.widgets.virtualtable.ColumnData[] columnData) {
baafe54c 355
b04903a2 356 ImmutableList.Builder<ITmfEventAspect> builder = new ImmutableList.Builder<>();
2bdf0193 357 for (org.eclipse.tracecompass.tmf.ui.widgets.virtualtable.ColumnData col : columnData) {
9447c7ee
AM
358 String fieldName = col.header;
359 if (fieldName != null) {
b04903a2 360 builder.add(new TmfEventFieldAspect(fieldName, fieldName));
baafe54c
AM
361 }
362 }
8192209b
AM
363 @SuppressWarnings("null")
364 @NonNull Iterable<ITmfEventAspect> ret = builder.build();
365 return ret;
baafe54c
AM
366 }
367
368 /**
369 * Standard constructor, where we define which columns to use.
370 *
371 * @param parent
372 * The parent composite UI object
373 * @param cacheSize
374 * The size of the event table cache
b04903a2
AM
375 * @param aspects
376 * The event aspects to display in this table. One column per
377 * aspect will be created.
baafe54c
AM
378 * <p>
379 * The iteration order of this collection will correspond to the
b04903a2 380 * initial ordering of the columns in the table.
baafe54c
AM
381 * </p>
382 * @since 3.1
db4721fb 383 */
baafe54c 384 public TmfEventsTable(final Composite parent, int cacheSize,
8192209b 385 @NonNull Iterable<ITmfEventAspect> aspects) {
db4721fb
PT
386 super("TmfEventsTable"); //$NON-NLS-1$
387
388 fComposite = new Composite(parent, SWT.NONE);
389 final GridLayout gl = new GridLayout(1, false);
390 gl.marginHeight = 0;
391 gl.marginWidth = 0;
392 gl.verticalSpacing = 0;
393 fComposite.setLayout(gl);
394
395 fSashForm = new SashForm(fComposite, SWT.HORIZONTAL);
396 fSashForm.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
397
398 // Create a virtual table
3f43dc48 399 final int style = SWT.H_SCROLL | SWT.V_SCROLL | SWT.MULTI | SWT.FULL_SELECTION;
db4721fb
PT
400 fTable = new TmfVirtualTable(fSashForm, style);
401
402 // Set the table layout
403 final GridData layoutData = new GridData(SWT.FILL, SWT.FILL, true, true);
404 fTable.setLayoutData(layoutData);
405
406 // Some cosmetic enhancements
407 fTable.setHeaderVisible(true);
408 fTable.setLinesVisible(true);
409
baafe54c 410 // Setup the columns
8192209b
AM
411 for (ITmfEventAspect aspect : aspects) {
412 if (aspect != null) {
413 fColumns.add(new TmfEventTableColumn(aspect));
b04903a2 414 }
db4721fb
PT
415 }
416
03142470
BH
417 TmfMarginColumn collapseCol = new TmfMarginColumn();
418 fColumns.add(MARGIN_COLUMN_INDEX, collapseCol);
419
baafe54c 420 // Create the UI columns in the table
2fcd5eea
AM
421 for (TmfEventTableColumn col : fColumns) {
422 TableColumn column = fTable.newTableColumn(SWT.LEFT);
423 column.setText(col.getHeaderName());
424 column.setToolTipText(col.getHeaderTooltip());
425 column.setData(Key.FIELD_ID, col.getFilterFieldId());
426 column.pack();
03142470
BH
427 if (col instanceof TmfMarginColumn) {
428 column.setResizable(false);
6817308e
PT
429 column.addControlListener(new ControlAdapter() {
430 /*
431 * Make sure that the margin column is always first
432 */
433 @Override
434 public void controlMoved(ControlEvent e) {
435 int[] order = fTable.getColumnOrder();
436 if (order[0] == MARGIN_COLUMN_INDEX) {
437 return;
438 }
439 for (int i = order.length - 1; i > 0; i--) {
440 if (order[i] == MARGIN_COLUMN_INDEX) {
441 order[i] = order[i - 1];
442 order[i - 1] = MARGIN_COLUMN_INDEX;
443 }
444 }
445 fTable.setColumnOrder(order);
446 }
447 });
448 } else {
449 column.setMoveable(true);
03142470 450 }
2fcd5eea 451 }
baafe54c 452
db4721fb
PT
453 // Set the frozen row for header row
454 fTable.setFrozenRowCount(1);
455
456 // Create the header row cell editor
457 createHeaderEditor();
458
459 // Handle the table item selection
460 fTable.addSelectionListener(new SelectionAdapter() {
461 @Override
462 public void widgetSelected(final SelectionEvent e) {
3f43dc48
PT
463 if (e.item == null) {
464 return;
465 }
466 updateStatusLine(null);
467 if (fTable.getSelectionIndices().length > 0) {
468 if (e.item.getData(Key.RANK) instanceof Long) {
469 fSelectedRank = (Long) e.item.getData(Key.RANK);
470 fRawViewer.selectAndReveal((Long) e.item.getData(Key.RANK));
471 }
472 if (e.item.getData(Key.TIMESTAMP) instanceof ITmfTimestamp) {
473 final ITmfTimestamp ts = (ITmfTimestamp) e.item.getData(Key.TIMESTAMP);
474 if (fTable.getSelectionIndices().length == 1) {
475 fSelectedBeginTimestamp = ts;
476 }
477 if (fSelectedBeginTimestamp != null) {
478 if (fSelectedBeginTimestamp.compareTo(ts) <= 0) {
479 broadcast(new TmfTimeSynchSignal(TmfEventsTable.this, fSelectedBeginTimestamp, ts));
480 if (fTable.getSelectionIndices().length == 2) {
481 updateStatusLine(ts.getDelta(fSelectedBeginTimestamp));
482 }
483 } else {
484 broadcast(new TmfTimeSynchSignal(TmfEventsTable.this, ts, fSelectedBeginTimestamp));
dadf6e1a 485 updateStatusLine(fSelectedBeginTimestamp.getDelta(ts));
3f43dc48 486 }
db4721fb 487 }
3f43dc48
PT
488 } else {
489 if (fTable.getSelectionIndices().length == 1) {
490 fSelectedBeginTimestamp = null;
db4721fb
PT
491 }
492 }
493 }
6b44794a
MK
494 if (e.item.getData() instanceof ITmfEvent) {
495 broadcast(new TmfEventSelectedSignal(TmfEventsTable.this, (ITmfEvent) e.item.getData()));
3f43dc48
PT
496 fireSelectionChanged(new SelectionChangedEvent(TmfEventsTable.this, new StructuredSelection(e.item.getData())));
497 } else {
498 fireSelectionChanged(new SelectionChangedEvent(TmfEventsTable.this, StructuredSelection.EMPTY));
499 }
db4721fb
PT
500 }
501 });
502
41b5c37f
AM
503 int realCacheSize = Math.max(cacheSize, Display.getDefault().getBounds().height / fTable.getItemHeight());
504 realCacheSize = Math.min(realCacheSize, MAX_CACHE_SIZE);
505 fCache = new TmfEventsCache(realCacheSize, this);
db4721fb
PT
506
507 // Handle the table item requests
508 fTable.addListener(SWT.SetData, new Listener() {
509
510 @Override
511 public void handleEvent(final Event event) {
512
513 final TableItem item = (TableItem) event.item;
514 int index = event.index - 1; // -1 for the header row
515
516 if (event.index == 0) {
517 setHeaderRowItemData(item);
518 return;
519 }
520
521 if (fTable.getData(Key.FILTER_OBJ) != null) {
522 if ((event.index == 1) || (event.index == (fTable.getItemCount() - 1))) {
523 setFilterStatusRowItemData(item);
524 return;
525 }
526 index = index - 1; // -1 for top filter status row
527 }
528
529 final CachedEvent cachedEvent = fCache.getEvent(index);
530 if (cachedEvent != null) {
03142470 531 setItemData(item, cachedEvent, cachedEvent.rank);
db4721fb
PT
532 return;
533 }
534
535 // Else, fill the cache asynchronously (and off the UI thread)
536 event.doit = false;
537 }
538 });
539
540 fTable.addMouseListener(new MouseAdapter() {
541 @Override
542 public void mouseDoubleClick(final MouseEvent event) {
543 if (event.button != 1) {
544 return;
545 }
546 // Identify the selected row
547 final Point point = new Point(event.x, event.y);
548 final TableItem item = fTable.getItem(point);
549 if (item != null) {
550 final Rectangle imageBounds = item.getImageBounds(0);
551 imageBounds.width = BOOKMARK_IMAGE.getBounds().width;
552 if (imageBounds.contains(point)) {
553 final Long rank = (Long) item.getData(Key.RANK);
554 if (rank != null) {
555 toggleBookmark(rank);
556 }
557 }
558 }
559 }
560 });
561
562 final Listener tooltipListener = new Listener () {
563 Shell tooltipShell = null;
564 @Override
565 public void handleEvent(final Event event) {
566 switch (event.type) {
567 case SWT.MouseHover:
568 final TableItem item = fTable.getItem(new Point(event.x, event.y));
569 if (item == null) {
570 return;
571 }
572 final Long rank = (Long) item.getData(Key.RANK);
573 if (rank == null) {
574 return;
575 }
576 final String tooltipText = (String) item.getData(Key.BOOKMARK);
577 final Rectangle bounds = item.getImageBounds(0);
578 bounds.width = BOOKMARK_IMAGE.getBounds().width;
579 if (!bounds.contains(event.x,event.y)) {
580 return;
581 }
582 if ((tooltipShell != null) && !tooltipShell.isDisposed()) {
583 tooltipShell.dispose();
584 }
585 tooltipShell = new Shell(fTable.getShell(), SWT.ON_TOP | SWT.NO_FOCUS | SWT.TOOL);
586 tooltipShell.setBackground(PlatformUI.getWorkbench().getDisplay().getSystemColor(SWT.COLOR_INFO_BACKGROUND));
587 final FillLayout layout = new FillLayout();
588 layout.marginWidth = 2;
589 tooltipShell.setLayout(layout);
590 final Label label = new Label(tooltipShell, SWT.WRAP);
03142470 591 String text = rank.toString() + (tooltipText != null ? ": " + tooltipText : EMPTY_STRING); //$NON-NLS-1$
db4721fb
PT
592 label.setForeground(PlatformUI.getWorkbench().getDisplay().getSystemColor(SWT.COLOR_INFO_FOREGROUND));
593 label.setBackground(PlatformUI.getWorkbench().getDisplay().getSystemColor(SWT.COLOR_INFO_BACKGROUND));
594 label.setText(text);
595 label.addListener(SWT.MouseExit, this);
596 label.addListener(SWT.MouseDown, this);
597 label.addListener(SWT.MouseWheel, this);
598 final Point size = tooltipShell.computeSize(SWT.DEFAULT, SWT.DEFAULT);
599 /*
600 * Bug in Linux. The coordinates of the event have an origin that excludes the table header but
601 * the method toDisplay() expects coordinates relative to an origin that includes the table header.
602 */
603 int y = event.y;
03142470 604 if (IS_LINUX) {
db4721fb
PT
605 y += fTable.getHeaderHeight();
606 }
607 Point pt = fTable.toDisplay(event.x, y);
608 pt.x += BOOKMARK_IMAGE.getBounds().width;
3be2946f 609 pt.y += item.getBounds().height;
db4721fb
PT
610 tooltipShell.setBounds(pt.x, pt.y, size.x, size.y);
611 tooltipShell.setVisible(true);
612 break;
613 case SWT.Dispose:
614 case SWT.KeyDown:
615 case SWT.MouseMove:
616 case SWT.MouseExit:
617 case SWT.MouseDown:
618 case SWT.MouseWheel:
619 if (tooltipShell != null) {
620 tooltipShell.dispose();
621 tooltipShell = null;
622 }
623 break;
624 default:
625 break;
626 }
627 }
628 };
629
630 fTable.addListener(SWT.MouseHover, tooltipListener);
631 fTable.addListener(SWT.Dispose, tooltipListener);
632 fTable.addListener(SWT.KeyDown, tooltipListener);
633 fTable.addListener(SWT.MouseMove, tooltipListener);
634 fTable.addListener(SWT.MouseExit, tooltipListener);
635 fTable.addListener(SWT.MouseDown, tooltipListener);
636 fTable.addListener(SWT.MouseWheel, tooltipListener);
637
638 // Create resources
639 createResources();
640
641 ColorSettingsManager.addColorSettingsListener(this);
642
643 fTable.setItemCount(1); // +1 for header row
644
645 fRawViewer = new TmfRawEventViewer(fSashForm, SWT.H_SCROLL | SWT.V_SCROLL);
646
647 fRawViewer.addSelectionListener(new Listener() {
648 @Override
649 public void handleEvent(final Event e) {
650 if (e.data instanceof Long) {
651 final long rank = (Long) e.data;
652 int index = (int) rank;
653 if (fTable.getData(Key.FILTER_OBJ) != null) {
654 index = fCache.getFilteredEventIndex(rank) + 1; // +1 for top filter status row
655 }
656 fTable.setSelection(index + 1); // +1 for header row
657 fSelectedRank = rank;
3f43dc48 658 updateStatusLine(null);
1e1bef82 659 } else if (e.data instanceof ITmfLocation) {
db4721fb
PT
660 // DOES NOT WORK: rank undefined in context from seekLocation()
661 // ITmfLocation<?> location = (ITmfLocation<?>) e.data;
662 // TmfContext context = fTrace.seekLocation(location);
663 // fTable.setSelection((int) context.getRank());
664 return;
665 } else {
666 return;
667 }
668 final TableItem[] selection = fTable.getSelection();
669 if ((selection != null) && (selection.length > 0)) {
670 final TmfTimestamp ts = (TmfTimestamp) fTable.getSelection()[0].getData(Key.TIMESTAMP);
671 if (ts != null) {
672 broadcast(new TmfTimeSynchSignal(TmfEventsTable.this, ts));
673 }
674 }
675 }
676 });
677
678 fSashForm.setWeights(new int[] { 1, 1 });
679 fRawViewer.setVisible(false);
680
681 createPopupMenu();
682 }
683
baafe54c
AM
684 // ------------------------------------------------------------------------
685 // Operations
686 // ------------------------------------------------------------------------
687
a0a88f65
AM
688 /**
689 * Create a pop-up menu.
690 */
db4721fb
PT
691 protected void createPopupMenu() {
692 final IAction showTableAction = new Action(Messages.TmfEventsTable_ShowTableActionText) {
693 @Override
694 public void run() {
695 fTable.setVisible(true);
696 fSashForm.layout();
697 }
698 };
699
700 final IAction hideTableAction = new Action(Messages.TmfEventsTable_HideTableActionText) {
701 @Override
702 public void run() {
703 fTable.setVisible(false);
704 fSashForm.layout();
705 }
706 };
707
708 final IAction showRawAction = new Action(Messages.TmfEventsTable_ShowRawActionText) {
709 @Override
710 public void run() {
711 fRawViewer.setVisible(true);
712 fSashForm.layout();
713 final int index = fTable.getSelectionIndex();
dadf6e1a 714 if (index >= 1) {
db4721fb
PT
715 fRawViewer.selectAndReveal(index - 1);
716 }
717 }
718 };
719
720 final IAction hideRawAction = new Action(Messages.TmfEventsTable_HideRawActionText) {
721 @Override
722 public void run() {
723 fRawViewer.setVisible(false);
724 fSashForm.layout();
725 }
726 };
727
029df6e3 728 final IAction openCallsiteAction = new Action(Messages.TmfEventsTable_OpenSourceCodeActionText) {
60fb38b8
PT
729 @Override
730 public void run() {
731 final TableItem items[] = fTable.getSelection();
732 if (items.length != 1) {
733 return;
734 }
735 final TableItem item = items[0];
736
737 final Object data = item.getData();
f47ed727
BH
738 if (data instanceof ITmfSourceLookup) {
739 ITmfSourceLookup event = (ITmfSourceLookup) data;
740 ITmfCallsite cs = event.getCallsite();
60fb38b8
PT
741 if (cs == null || cs.getFileName() == null) {
742 return;
743 }
744 IMarker marker = null;
745 try {
746 String fileName = cs.getFileName();
03142470 747 final String trimmedPath = fileName.replaceAll("\\.\\./", EMPTY_STRING); //$NON-NLS-1$
507b1336 748 final ArrayList<IFile> files = new ArrayList<>();
60fb38b8
PT
749 ResourcesPlugin.getWorkspace().getRoot().accept(new IResourceVisitor() {
750 @Override
751 public boolean visit(IResource resource) throws CoreException {
752 if (resource instanceof IFile && resource.getFullPath().toString().endsWith(trimmedPath)) {
753 files.add((IFile) resource);
754 }
755 return true;
756 }
757 });
758 IFile file = null;
759 if (files.size() > 1) {
760 ListDialog dialog = new ListDialog(getTable().getShell());
761 dialog.setContentProvider(ArrayContentProvider.getInstance());
762 dialog.setLabelProvider(new LabelProvider() {
763 @Override
764 public String getText(Object element) {
765 return ((IFile) element).getFullPath().toString();
766 }
767 });
768 dialog.setInput(files);
029df6e3
JCK
769 dialog.setTitle(Messages.TmfEventsTable_OpenSourceCodeSelectFileDialogTitle);
770 dialog.setMessage(Messages.TmfEventsTable_OpenSourceCodeSelectFileDialogTitle + '\n' + cs.toString());
60fb38b8
PT
771 dialog.open();
772 Object[] result = dialog.getResult();
773 if (result != null && result.length > 0) {
774 file = (IFile) result[0];
775 }
776 } else if (files.size() == 1) {
777 file = files.get(0);
778 }
779 if (file != null) {
780 marker = file.createMarker(IMarker.MARKER);
781 marker.setAttribute(IMarker.LINE_NUMBER, Long.valueOf(cs.getLineNumber()).intValue());
782 IDE.openEditor(PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage(), marker);
783 marker.delete();
784 } else if (files.size() == 0){
029df6e3 785 displayException(new FileNotFoundException('\'' + cs.toString() + '\'' + '\n' + Messages.TmfEventsTable_OpenSourceCodeNotFound));
60fb38b8 786 }
60fb38b8 787 } catch (CoreException e) {
8e95e814 788 displayException(e);
60fb38b8
PT
789 }
790 }
791 }
792 };
793
794 final IAction openModelAction = new Action(Messages.TmfEventsTable_OpenModelActionText) {
ac44ef71
AR
795 @Override
796 public void run() {
797
798 final TableItem items[] = fTable.getSelection();
799 if (items.length != 1) {
800 return;
801 }
802 final TableItem item = items[0];
803
804 final Object eventData = item.getData();
f47ed727
BH
805 if (eventData instanceof ITmfModelLookup) {
806 String modelURI = ((ITmfModelLookup) eventData).getModelUri();
ac44ef71
AR
807
808 if (modelURI != null) {
809 IWorkbenchPage activePage = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage();
810
811 IFile file = null;
812 final URI uri = URI.createURI(modelURI);
813 if (uri.isPlatformResource()) {
814 IPath path = new Path(uri.toPlatformString(true));
815 file = ResourcesPlugin.getWorkspace().getRoot().getFile(path);
816 } else if (uri.isFile() && !uri.isRelative()) {
817 file = ResourcesPlugin.getWorkspace().getRoot().getFileForLocation(
818 new Path(uri.toFileString()));
819 }
820
821 if (file != null) {
822 try {
823 /*
824 * create a temporary validation marker on the
825 * model file, remove it afterwards thus,
826 * navigation works with all model editors
827 * supporting the navigation to a marker
828 */
829 IMarker marker = file.createMarker(EValidator.MARKER);
830 marker.setAttribute(EValidator.URI_ATTRIBUTE, modelURI);
831 marker.setAttribute(IMarker.SEVERITY, IMarker.SEVERITY_INFO);
832
833 IDE.openEditor(activePage, marker, OpenStrategy.activateOnOpen());
834 marker.delete();
835 }
836 catch (CoreException e) {
837 displayException(e);
838 }
60fb38b8
PT
839 } else {
840 displayException(new FileNotFoundException('\'' + modelURI + '\'' + '\n' + Messages.TmfEventsTable_OpenModelUnsupportedURI));
ac44ef71
AR
841 }
842 }
843 }
844 }
845 };
60fb38b8 846
d3de0920
XR
847 final IAction exportToTextAction = new Action(Messages.TmfEventsTable_Export_to_text) {
848 @Override
849 public void run() {
850 IWorkbenchPage activePage = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage();
346fa221
MAL
851 Object handlerServiceObject = activePage.getActiveEditor().getSite().getService(IHandlerService.class);
852 IHandlerService handlerService = (IHandlerService) handlerServiceObject;
853 Object cmdServiceObject = activePage.getActiveEditor().getSite().getService(ICommandService.class);
854 ICommandService cmdService = (ICommandService) cmdServiceObject;
d3de0920 855 try {
507b1336 856 HashMap<String, Object> parameters = new HashMap<>();
d3de0920 857 Command command = cmdService.getCommand(ExportToTextCommandHandler.COMMAND_ID);
03142470
BH
858 ParameterizedCommand cmd = ParameterizedCommand.generateCommand(command, parameters);
859
d3de0920 860 IEvaluationContext context = handlerService.getCurrentState();
6817308e
PT
861 List<TmfEventTableColumn> exportColumns = new ArrayList<>();
862 for (int i : fTable.getColumnOrder()) {
863 // Omit the margin column
864 if (i >= EVENT_COLUMNS_START_INDEX) {
865 exportColumns.add(fColumns.get(i));
866 }
867 }
03142470
BH
868 context.addVariable(ExportToTextCommandHandler.TMF_EVENT_TABLE_COLUMNS_ID, exportColumns);
869
d3de0920 870 handlerService.executeCommandInContext(cmd, null, context);
23c625f1 871 } catch (ExecutionException | NotDefinedException | NotEnabledException | NotHandledException e) {
d3de0920
XR
872 displayException(e);
873 }
874 }
875 };
876
db4721fb
PT
877 final IAction showSearchBarAction = new Action(Messages.TmfEventsTable_ShowSearchBarActionText) {
878 @Override
879 public void run() {
880 fHeaderState = HeaderState.SEARCH;
881 fTable.refresh();
882 }
883 };
884
885 final IAction showFilterBarAction = new Action(Messages.TmfEventsTable_ShowFilterBarActionText) {
886 @Override
887 public void run() {
888 fHeaderState = HeaderState.FILTER;
889 fTable.refresh();
890 }
891 };
892
893 final IAction clearFiltersAction = new Action(Messages.TmfEventsTable_ClearFiltersActionText) {
894 @Override
895 public void run() {
896 clearFilters();
897 }
898 };
899
03142470
BH
900 final IAction collapseAction = new Action(Messages.TmfEventsTable_CollapseFilterMenuName) {
901 @Override
902 public void run() {
903 applyFilter(new TmfCollapseFilter());
904 }
905 };
906
db4721fb 907 class ToggleBookmarkAction extends Action {
0126a8ca 908 Long fRank;
db4721fb 909
0126a8ca 910 public ToggleBookmarkAction(final String text, final Long rank) {
db4721fb
PT
911 super(text);
912 fRank = rank;
913 }
914
915 @Override
916 public void run() {
917 toggleBookmark(fRank);
918 }
919 }
920
921 final MenuManager tablePopupMenu = new MenuManager();
922 tablePopupMenu.setRemoveAllWhenShown(true);
923 tablePopupMenu.addMenuListener(new IMenuListener() {
924 @Override
925 public void menuAboutToShow(final IMenuManager manager) {
926 if (fTable.getSelectionIndex() == 0) {
927 // Right-click on header row
928 if (fHeaderState == HeaderState.FILTER) {
929 tablePopupMenu.add(showSearchBarAction);
930 } else {
931 tablePopupMenu.add(showFilterBarAction);
932 }
933 return;
934 }
935 final Point point = fTable.toControl(Display.getDefault().getCursorLocation());
936 final TableItem item = fTable.getSelection().length > 0 ? fTable.getSelection()[0] : null;
937 if (item != null) {
938 final Rectangle imageBounds = item.getImageBounds(0);
939 imageBounds.width = BOOKMARK_IMAGE.getBounds().width;
940 if (point.x <= (imageBounds.x + imageBounds.width)) {
941 // Right-click on left margin
942 final Long rank = (Long) item.getData(Key.RANK);
943 if ((rank != null) && (fBookmarksFile != null)) {
944 if (fBookmarksMap.containsKey(rank)) {
945 tablePopupMenu.add(new ToggleBookmarkAction(
946 Messages.TmfEventsTable_RemoveBookmarkActionText, rank));
947 } else {
948 tablePopupMenu.add(new ToggleBookmarkAction(
949 Messages.TmfEventsTable_AddBookmarkActionText, rank));
950 }
951 }
952 return;
953 }
954 }
60fb38b8 955
db4721fb
PT
956 // Right-click on table
957 if (fTable.isVisible() && fRawViewer.isVisible()) {
958 tablePopupMenu.add(hideTableAction);
959 tablePopupMenu.add(hideRawAction);
960 } else if (!fTable.isVisible()) {
961 tablePopupMenu.add(showTableAction);
962 } else if (!fRawViewer.isVisible()) {
963 tablePopupMenu.add(showRawAction);
964 }
d3de0920 965 tablePopupMenu.add(exportToTextAction);
db4721fb 966 tablePopupMenu.add(new Separator());
60fb38b8 967
ac44ef71 968 if (item != null) {
60fb38b8 969 final Object data = item.getData();
f47ed727
BH
970 Separator separator = null;
971 if (data instanceof ITmfSourceLookup) {
972 ITmfSourceLookup event = (ITmfSourceLookup) data;
60fb38b8
PT
973 if (event.getCallsite() != null) {
974 tablePopupMenu.add(openCallsiteAction);
975 separator = new Separator();
976 }
f47ed727
BH
977 }
978
979 if (data instanceof ITmfModelLookup) {
980 ITmfModelLookup event = (ITmfModelLookup) data;
981 if (event.getModelUri() != null) {
60fb38b8
PT
982 tablePopupMenu.add(openModelAction);
983 separator = new Separator();
984 }
f47ed727 985
60fb38b8
PT
986 if (separator != null) {
987 tablePopupMenu.add(separator);
ac44ef71
AR
988 }
989 }
990 }
60fb38b8 991
03142470
BH
992 // only show collapse filter if at least one trace can be collapsed
993 boolean isCollapsible = false;
994 if (fTrace != null) {
995 ITmfTrace traces[] = TmfTraceManager.getTraceSet(fTrace);
996 for (ITmfTrace trace : traces) {
997 Class <? extends ITmfEvent> eventClass = trace.getEventType();
998 isCollapsible = ITmfCollapsibleEvent.class.isAssignableFrom(eventClass);
999 if (isCollapsible) {
1000 break;
1001 }
1002 }
1003 }
1004
1005 if (isCollapsible && !(fTable.getData(Key.FILTER_OBJ) instanceof TmfCollapseFilter)) {
1006 tablePopupMenu.add(collapseAction);
1007 tablePopupMenu.add(new Separator());
1008 }
1009
db4721fb
PT
1010 tablePopupMenu.add(clearFiltersAction);
1011 final ITmfFilterTreeNode[] savedFilters = FilterManager.getSavedFilters();
1012 if (savedFilters.length > 0) {
1013 final MenuManager subMenu = new MenuManager(Messages.TmfEventsTable_ApplyPresetFilterMenuName);
1014 for (final ITmfFilterTreeNode node : savedFilters) {
1015 if (node instanceof TmfFilterNode) {
1016 final TmfFilterNode filter = (TmfFilterNode) node;
1017 subMenu.add(new Action(filter.getFilterName()) {
1018 @Override
1019 public void run() {
1020 applyFilter(filter);
1021 }
1022 });
1023 }
1024 }
1025 tablePopupMenu.add(subMenu);
1026 }
1027 appendToTablePopupMenu(tablePopupMenu, item);
1028 }
1029 });
1030
1031 final MenuManager rawViewerPopupMenu = new MenuManager();
1032 rawViewerPopupMenu.setRemoveAllWhenShown(true);
1033 rawViewerPopupMenu.addMenuListener(new IMenuListener() {
1034 @Override
1035 public void menuAboutToShow(final IMenuManager manager) {
1036 if (fTable.isVisible() && fRawViewer.isVisible()) {
1037 rawViewerPopupMenu.add(hideTableAction);
1038 rawViewerPopupMenu.add(hideRawAction);
1039 } else if (!fTable.isVisible()) {
1040 rawViewerPopupMenu.add(showTableAction);
1041 } else if (!fRawViewer.isVisible()) {
1042 rawViewerPopupMenu.add(showRawAction);
1043 }
1044 appendToRawPopupMenu(tablePopupMenu);
1045 }
1046 });
1047
1048 Menu menu = tablePopupMenu.createContextMenu(fTable);
1049 fTable.setMenu(menu);
1050
1051 menu = rawViewerPopupMenu.createContextMenu(fRawViewer);
1052 fRawViewer.setMenu(menu);
1053 }
1054
f8177ba2 1055
a0a88f65
AM
1056 /**
1057 * Append an item to the event table's pop-up menu.
1058 *
1059 * @param tablePopupMenu
1060 * The menu manager
1061 * @param selectedItem
1062 * The item to append
1063 */
db4721fb
PT
1064 protected void appendToTablePopupMenu(final MenuManager tablePopupMenu, final TableItem selectedItem) {
1065 // override to append more actions
1066 }
1067
a0a88f65
AM
1068 /**
1069 * Append an item to the raw viewer's pop-up menu.
1070 *
1071 * @param rawViewerPopupMenu
1072 * The menu manager
1073 */
db4721fb
PT
1074 protected void appendToRawPopupMenu(final MenuManager rawViewerPopupMenu) {
1075 // override to append more actions
1076 }
1077
1078 @Override
1079 public void dispose() {
1080 stopSearchThread();
1081 stopFilterThread();
1082 ColorSettingsManager.removeColorSettingsListener(this);
1083 fComposite.dispose();
1084 if ((fTrace != null) && fDisposeOnClose) {
1085 fTrace.dispose();
1086 }
1087 fResourceManager.dispose();
3a97628a 1088 fRawViewer.dispose();
db4721fb
PT
1089 super.dispose();
1090 }
1091
1092 /**
1093 * Assign a layout data object to this view.
1094 *
1095 * @param layoutData
1096 * The layout data to assign
1097 */
1098 public void setLayoutData(final Object layoutData) {
1099 fComposite.setLayoutData(layoutData);
1100 }
1101
1102 /**
1103 * Get the virtual table contained in this event table.
1104 *
1105 * @return The TMF virtual table
1106 */
1107 public TmfVirtualTable getTable() {
1108 return fTable;
1109 }
1110
1111 /**
1112 * @param columnData
baafe54c
AM
1113 * columnData
1114 * @deprecated The column headers are now set at the constructor, this
1115 * shouldn't be called anymore.
db4721fb 1116 */
baafe54c 1117 @Deprecated
2bdf0193 1118 protected void setColumnHeaders(final org.eclipse.tracecompass.tmf.ui.widgets.virtualtable.ColumnData [] columnData) {
baafe54c 1119 /* No-op */
db4721fb
PT
1120 }
1121
a0a88f65
AM
1122 /**
1123 * Set a table item's data.
1124 *
1125 * @param item
1126 * The item to set
1127 * @param event
1128 * Which trace event to link with this entry
1129 * @param rank
1130 * Which rank this event has in the trace/experiment
1131 */
db4721fb 1132 protected void setItemData(final TableItem item, final ITmfEvent event, final long rank) {
03142470
BH
1133 String[] itemStrings = getItemStrings(fColumns, event);
1134 item.setText(itemStrings);
93bfd50a 1135 item.setData(event);
db4721fb
PT
1136 item.setData(Key.TIMESTAMP, new TmfTimestamp(event.getTimestamp()));
1137 item.setData(Key.RANK, rank);
1138
2db176a0
PT
1139 final Collection<Long> markerIds = fBookmarksMap.get(rank);
1140 if (!markerIds.isEmpty()) {
1141 Joiner joiner = Joiner.on("\n -").skipNulls(); //$NON-NLS-1$
1142 List<Object> parts = new ArrayList<>();
1143 if (markerIds.size() > 1) {
1144 parts.add(Messages.TmfEventsTable_MultipleBookmarksToolTip);
1145 }
db4721fb 1146 try {
2db176a0
PT
1147 for (long markerId : markerIds) {
1148 final IMarker marker = fBookmarksFile.findMarker(markerId);
1149 parts.add(marker.getAttribute(IMarker.MESSAGE));
1150 }
1151 } catch (CoreException e) {
db4721fb
PT
1152 displayException(e);
1153 }
2db176a0 1154 item.setData(Key.BOOKMARK, joiner.join(parts));
db4721fb
PT
1155 } else {
1156 item.setData(Key.BOOKMARK, null);
1157 }
1158
1159 boolean searchMatch = false;
1160 boolean searchNoMatch = false;
1161 final ITmfFilter searchFilter = (ITmfFilter) fTable.getData(Key.SEARCH_OBJ);
1162 if (searchFilter != null) {
1163 if (searchFilter.matches(event)) {
1164 searchMatch = true;
1165 } else {
1166 searchNoMatch = true;
1167 }
1168 }
1169
1170 final ColorSetting colorSetting = ColorSettingsManager.getColorSetting(event);
1171 if (searchNoMatch) {
1172 item.setForeground(colorSetting.getDimmedForegroundColor());
1173 item.setBackground(colorSetting.getDimmedBackgroundColor());
1174 } else {
1175 item.setForeground(colorSetting.getForegroundColor());
1176 item.setBackground(colorSetting.getBackgroundColor());
1177 }
1178
1179 if (searchMatch) {
2db176a0 1180 if (!markerIds.isEmpty()) {
db4721fb
PT
1181 item.setImage(SEARCH_MATCH_BOOKMARK_IMAGE);
1182 } else {
1183 item.setImage(SEARCH_MATCH_IMAGE);
1184 }
2db176a0 1185 } else if (!markerIds.isEmpty()) {
db4721fb
PT
1186 item.setImage(BOOKMARK_IMAGE);
1187 } else {
1188 item.setImage((Image) null);
1189 }
03142470
BH
1190
1191 if ((itemStrings[MARGIN_COLUMN_INDEX] != null) && !itemStrings[MARGIN_COLUMN_INDEX].isEmpty()) {
1192 packMarginColumn();
1193 }
db4721fb
PT
1194 }
1195
a0a88f65
AM
1196 /**
1197 * Set the item data of the header row.
1198 *
1199 * @param item
1200 * The item to use as table header
1201 */
db4721fb
PT
1202 protected void setHeaderRowItemData(final TableItem item) {
1203 String txtKey = null;
1204 if (fHeaderState == HeaderState.SEARCH) {
1205 item.setImage(SEARCH_IMAGE);
1206 txtKey = Key.SEARCH_TXT;
1207 } else if (fHeaderState == HeaderState.FILTER) {
1208 item.setImage(FILTER_IMAGE);
1209 txtKey = Key.FILTER_TXT;
1210 }
1211 item.setForeground(fGrayColor);
03142470
BH
1212 // Ignore collapse and image column
1213 for (int i = EVENT_COLUMNS_START_INDEX; i < fTable.getColumns().length; i++) {
db4721fb
PT
1214 final TableColumn column = fTable.getColumns()[i];
1215 final String filter = (String) column.getData(txtKey);
1216 if (filter == null) {
1217 if (fHeaderState == HeaderState.SEARCH) {
1218 item.setText(i, SEARCH_HINT);
1219 } else if (fHeaderState == HeaderState.FILTER) {
1220 item.setText(i, FILTER_HINT);
1221 }
1222 item.setForeground(i, fGrayColor);
1223 item.setFont(i, fTable.getFont());
1224 } else {
1225 item.setText(i, filter);
1226 item.setForeground(i, fGreenColor);
1227 item.setFont(i, fBoldFont);
1228 }
1229 }
1230 }
1231
a0a88f65
AM
1232 /**
1233 * Set the item data of the "filter status" row.
1234 *
1235 * @param item
1236 * The item to use as filter status row
1237 */
db4721fb
PT
1238 protected void setFilterStatusRowItemData(final TableItem item) {
1239 for (int i = 0; i < fTable.getColumns().length; i++) {
03142470 1240 if (i == MARGIN_COLUMN_INDEX) {
db4721fb
PT
1241 if ((fTrace == null) || (fFilterCheckCount == fTrace.getNbEvents())) {
1242 item.setImage(FILTER_IMAGE);
1243 } else {
1244 item.setImage(STOP_IMAGE);
1245 }
03142470
BH
1246 }
1247
1248 if (i == FILTER_SUMMARY_INDEX) {
1249 item.setText(FILTER_SUMMARY_INDEX, fFilterMatchCount + "/" + fFilterCheckCount); //$NON-NLS-1$
db4721fb 1250 } else {
03142470 1251 item.setText(i, EMPTY_STRING);
db4721fb
PT
1252 }
1253 }
93bfd50a 1254 item.setData(null);
db4721fb
PT
1255 item.setData(Key.TIMESTAMP, null);
1256 item.setData(Key.RANK, null);
1257 item.setForeground(null);
1258 item.setBackground(null);
1259 }
1260
a0a88f65
AM
1261 /**
1262 * Create an editor for the header.
1263 */
db4721fb
PT
1264 protected void createHeaderEditor() {
1265 final TableEditor tableEditor = fTable.createTableEditor();
1266 tableEditor.horizontalAlignment = SWT.LEFT;
1267 tableEditor.verticalAlignment = SWT.CENTER;
1268 tableEditor.grabHorizontal = true;
1269 tableEditor.minimumWidth = 50;
1270
1271 // Handle the header row selection
1272 fTable.addMouseListener(new MouseAdapter() {
1273 int columnIndex;
1274 TableColumn column;
1275 TableItem item;
1276
1277 @Override
1278 public void mouseDown(final MouseEvent event) {
1279 if (event.button != 1) {
1280 return;
1281 }
1282 // Identify the selected row
1283 final Point point = new Point(event.x, event.y);
1284 item = fTable.getItem(point);
1285
1286 // Header row selected
1287 if ((item != null) && (fTable.indexOf(item) == 0)) {
1288
1289 // Icon selected
1290 if (item.getImageBounds(0).contains(point)) {
1291 if (fHeaderState == HeaderState.SEARCH) {
1292 fHeaderState = HeaderState.FILTER;
1293 } else if (fHeaderState == HeaderState.FILTER) {
1294 fHeaderState = HeaderState.SEARCH;
1295 }
3f43dc48 1296 fTable.setSelection(0);
db4721fb
PT
1297 fTable.refresh();
1298 return;
1299 }
1300
1301 // Identify the selected column
1302 columnIndex = -1;
1303 for (int i = 0; i < fTable.getColumns().length; i++) {
1304 final Rectangle rect = item.getBounds(i);
1305 if (rect.contains(point)) {
1306 columnIndex = i;
1307 break;
1308 }
1309 }
1310
1311 if (columnIndex == -1) {
1312 return;
1313 }
1314
1315 column = fTable.getColumns()[columnIndex];
1316
1317 String txtKey = null;
1318 if (fHeaderState == HeaderState.SEARCH) {
1319 txtKey = Key.SEARCH_TXT;
1320 } else if (fHeaderState == HeaderState.FILTER) {
1321 txtKey = Key.FILTER_TXT;
1322 }
1323
1324 // The control that will be the editor must be a child of the Table
1325 final Text newEditor = (Text) fTable.createTableEditorControl(Text.class);
1326 final String headerString = (String) column.getData(txtKey);
1327 if (headerString != null) {
1328 newEditor.setText(headerString);
1329 }
1330 newEditor.addFocusListener(new FocusAdapter() {
1331 @Override
1332 public void focusLost(final FocusEvent e) {
1333 final boolean changed = updateHeader(newEditor.getText());
1334 if (changed) {
1335 applyHeader();
1336 }
1337 }
1338 });
1339 newEditor.addKeyListener(new KeyAdapter() {
1340 @Override
1341 public void keyPressed(final KeyEvent e) {
1342 if (e.character == SWT.CR) {
1343 updateHeader(newEditor.getText());
1344 applyHeader();
d81b17ea
MAL
1345
1346 // Set focus on the table so that the next carriage return goes to the next result
1347 TmfEventsTable.this.getTable().setFocus();
db4721fb
PT
1348 } else if (e.character == SWT.ESC) {
1349 tableEditor.getEditor().dispose();
1350 }
1351 }
1352 });
1353 newEditor.selectAll();
1354 newEditor.setFocus();
1355 tableEditor.setEditor(newEditor, item, columnIndex);
1356 }
1357 }
1358
1359 /*
1360 * returns true is value was changed
1361 */
1362 private boolean updateHeader(final String text) {
1363 String objKey = null;
1364 String txtKey = null;
1365 if (fHeaderState == HeaderState.SEARCH) {
1366 objKey = Key.SEARCH_OBJ;
1367 txtKey = Key.SEARCH_TXT;
1368 } else if (fHeaderState == HeaderState.FILTER) {
1369 objKey = Key.FILTER_OBJ;
1370 txtKey = Key.FILTER_TXT;
1371 }
1372 if (text.trim().length() > 0) {
1373 try {
1374 final String regex = TmfFilterMatchesNode.regexFix(text);
1375 Pattern.compile(regex);
1376 if (regex.equals(column.getData(txtKey))) {
1377 tableEditor.getEditor().dispose();
1378 return false;
1379 }
1380 final TmfFilterMatchesNode filter = new TmfFilterMatchesNode(null);
1381 String fieldId = (String) column.getData(Key.FIELD_ID);
1382 if (fieldId == null) {
1383 fieldId = column.getText();
1384 }
1385 filter.setField(fieldId);
1386 filter.setRegex(regex);
1387 column.setData(objKey, filter);
1388 column.setData(txtKey, regex);
1389 } catch (final PatternSyntaxException ex) {
1390 tableEditor.getEditor().dispose();
1391 MessageDialog.openError(PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell(),
1392 ex.getDescription(), ex.getMessage());
1393 return false;
1394 }
1395 } else {
1396 if (column.getData(txtKey) == null) {
1397 tableEditor.getEditor().dispose();
1398 return false;
1399 }
1400 column.setData(objKey, null);
1401 column.setData(txtKey, null);
1402 }
1403 return true;
1404 }
1405
1406 private void applyHeader() {
1407 if (fHeaderState == HeaderState.SEARCH) {
1408 stopSearchThread();
1409 final TmfFilterAndNode filter = new TmfFilterAndNode(null);
3dca7aa5
AM
1410 for (final TableColumn col : fTable.getColumns()) {
1411 final Object filterObj = col.getData(Key.SEARCH_OBJ);
db4721fb
PT
1412 if (filterObj instanceof ITmfFilterTreeNode) {
1413 filter.addChild((ITmfFilterTreeNode) filterObj);
1414 }
1415 }
1416 if (filter.getChildrenCount() > 0) {
1417 fTable.setData(Key.SEARCH_OBJ, filter);
1418 fTable.refresh();
1419 searchNext();
1420 fireSearchApplied(filter);
1421 } else {
1422 fTable.setData(Key.SEARCH_OBJ, null);
1423 fTable.refresh();
1424 fireSearchApplied(null);
1425 }
1426 } else if (fHeaderState == HeaderState.FILTER) {
1427 final TmfFilterAndNode filter = new TmfFilterAndNode(null);
3dca7aa5
AM
1428 for (final TableColumn col : fTable.getColumns()) {
1429 final Object filterObj = col.getData(Key.FILTER_OBJ);
db4721fb
PT
1430 if (filterObj instanceof ITmfFilterTreeNode) {
1431 filter.addChild((ITmfFilterTreeNode) filterObj);
1432 }
1433 }
1434 if (filter.getChildrenCount() > 0) {
1435 applyFilter(filter);
1436 } else {
1437 clearFilters();
1438 }
1439 }
1440
1441 tableEditor.getEditor().dispose();
1442 }
1443 });
1444
1445 fTable.addKeyListener(new KeyAdapter() {
1446 @Override
1447 public void keyPressed(final KeyEvent e) {
1448 e.doit = false;
1449 if (e.character == SWT.ESC) {
1450 stopFilterThread();
1451 stopSearchThread();
1452 fTable.refresh();
1453 } else if (e.character == SWT.DEL) {
1454 if (fHeaderState == HeaderState.SEARCH) {
1455 stopSearchThread();
1456 for (final TableColumn column : fTable.getColumns()) {
1457 column.setData(Key.SEARCH_OBJ, null);
1458 column.setData(Key.SEARCH_TXT, null);
1459 }
1460 fTable.setData(Key.SEARCH_OBJ, null);
1461 fTable.refresh();
1462 fireSearchApplied(null);
1463 } else if (fHeaderState == HeaderState.FILTER) {
1464 clearFilters();
1465 }
1466 } else if (e.character == SWT.CR) {
1467 if ((e.stateMask & SWT.SHIFT) == 0) {
1468 searchNext();
1469 } else {
1470 searchPrevious();
1471 }
1472 }
1473 }
1474 });
1475 }
1476
a0a88f65
AM
1477 /**
1478 * Send an event indicating a filter has been applied.
1479 *
1480 * @param filter
1481 * The filter that was just applied
1482 */
db4721fb 1483 protected void fireFilterApplied(final ITmfFilter filter) {
faa38350 1484 broadcast(new TmfEventFilterAppliedSignal(this, fTrace, filter));
db4721fb
PT
1485 }
1486
a0a88f65
AM
1487 /**
1488 * Send an event indicating that a search has been applied.
1489 *
1490 * @param filter
1491 * The search filter that was just applied
1492 */
db4721fb 1493 protected void fireSearchApplied(final ITmfFilter filter) {
faa38350 1494 broadcast(new TmfEventSearchAppliedSignal(this, fTrace, filter));
db4721fb
PT
1495 }
1496
a0a88f65
AM
1497 /**
1498 * Start the filtering thread.
1499 */
db4721fb
PT
1500 protected void startFilterThread() {
1501 synchronized (fFilterSyncObj) {
1502 final ITmfFilterTreeNode filter = (ITmfFilterTreeNode) fTable.getData(Key.FILTER_OBJ);
1503 if (fFilterThread == null || fFilterThread.filter != filter) {
1504 if (fFilterThread != null) {
1505 fFilterThread.cancel();
1506 fFilterThreadResume = false;
1507 }
1508 fFilterThread = new FilterThread(filter);
1509 fFilterThread.start();
1510 } else {
1511 fFilterThreadResume = true;
1512 }
1513 }
1514 }
1515
a0a88f65
AM
1516 /**
1517 * Stop the filtering thread.
1518 */
db4721fb
PT
1519 protected void stopFilterThread() {
1520 synchronized (fFilterSyncObj) {
1521 if (fFilterThread != null) {
1522 fFilterThread.cancel();
1523 fFilterThread = null;
1524 fFilterThreadResume = false;
1525 }
1526 }
1527 }
1528
1529 /**
a0a88f65
AM
1530 * Apply a filter.
1531 *
1532 * @param filter
1533 * The filter to apply
db4721fb
PT
1534 * @since 1.1
1535 */
1536 protected void applyFilter(ITmfFilter filter) {
f29f8868
BH
1537 stopFilterThread();
1538 stopSearchThread();
db4721fb
PT
1539 fFilterMatchCount = 0;
1540 fFilterCheckCount = 0;
1541 fCache.applyFilter(filter);
1542 fTable.clearAll();
1543 fTable.setData(Key.FILTER_OBJ, filter);
1544 fTable.setItemCount(3); // +1 for header row, +2 for top and bottom filter status rows
1545 startFilterThread();
1546 fireFilterApplied(filter);
1547 }
1548
a0a88f65
AM
1549 /**
1550 * Clear all currently active filters.
1551 */
db4721fb
PT
1552 protected void clearFilters() {
1553 if (fTable.getData(Key.FILTER_OBJ) == null) {
1554 return;
1555 }
1556 stopFilterThread();
1557 stopSearchThread();
1558 fCache.clearFilter();
1559 fTable.clearAll();
1560 for (final TableColumn column : fTable.getColumns()) {
1561 column.setData(Key.FILTER_OBJ, null);
1562 column.setData(Key.FILTER_TXT, null);
1563 }
1564 fTable.setData(Key.FILTER_OBJ, null);
1565 if (fTrace != null) {
1566 fTable.setItemCount((int) fTrace.getNbEvents() + 1); // +1 for header row
1567 } else {
1568 fTable.setItemCount(1); // +1 for header row
1569 }
1570 fFilterMatchCount = 0;
1571 fFilterCheckCount = 0;
1572 if (fSelectedRank >= 0) {
1573 fTable.setSelection((int) fSelectedRank + 1); // +1 for header row
1574 } else {
1575 fTable.setSelection(0);
1576 }
1577 fireFilterApplied(null);
3f43dc48 1578 updateStatusLine(null);
03142470
BH
1579
1580 // Set original width
1581 fTable.getColumns()[MARGIN_COLUMN_INDEX].setWidth(0);
1582 packMarginColumn();
db4721fb
PT
1583 }
1584
a0a88f65
AM
1585 /**
1586 * Wrapper Thread object for the filtering thread.
1587 */
db4721fb
PT
1588 protected class FilterThread extends Thread {
1589 private final ITmfFilterTreeNode filter;
fd3f1eff 1590 private TmfEventRequest request;
db4721fb
PT
1591 private boolean refreshBusy = false;
1592 private boolean refreshPending = false;
1593 private final Object syncObj = new Object();
1594
a0a88f65
AM
1595 /**
1596 * Constructor.
1597 *
1598 * @param filter
1599 * The filter this thread will be processing
1600 */
db4721fb
PT
1601 public FilterThread(final ITmfFilterTreeNode filter) {
1602 super("Filter Thread"); //$NON-NLS-1$
1603 this.filter = filter;
1604 }
1605
1606 @Override
1607 public void run() {
1608 if (fTrace == null) {
1609 return;
1610 }
1611 final int nbRequested = (int) (fTrace.getNbEvents() - fFilterCheckCount);
1612 if (nbRequested <= 0) {
1613 return;
1614 }
fd3f1eff
AM
1615 request = new TmfEventRequest(ITmfEvent.class, TmfTimeRange.ETERNITY,
1616 (int) fFilterCheckCount, nbRequested, ExecutionType.BACKGROUND) {
db4721fb
PT
1617 @Override
1618 public void handleData(final ITmfEvent event) {
1619 super.handleData(event);
1620 if (request.isCancelled()) {
1621 return;
1622 }
03142470 1623 boolean refresh = false;
db4721fb
PT
1624 if (filter.matches(event)) {
1625 final long rank = fFilterCheckCount;
1626 final int index = (int) fFilterMatchCount;
1627 fFilterMatchCount++;
bd54d363 1628 fCache.storeEvent(event, rank, index);
03142470
BH
1629 refresh = true;
1630 } else {
1631 if (filter instanceof TmfCollapseFilter) {
1632 fCache.updateCollapsedEvent((int) fFilterMatchCount - 1);
1633 }
1634 }
1635
1636 if (refresh || (fFilterCheckCount % 100) == 0) {
db4721fb
PT
1637 refreshTable();
1638 }
1639 fFilterCheckCount++;
1640 }
1641 };
fd3f1eff 1642 ((ITmfEventProvider) fTrace).sendRequest(request);
db4721fb
PT
1643 try {
1644 request.waitForCompletion();
1645 } catch (final InterruptedException e) {
1646 }
1647 refreshTable();
1648 synchronized (fFilterSyncObj) {
1649 fFilterThread = null;
1650 if (fFilterThreadResume) {
1651 fFilterThreadResume = false;
1652 fFilterThread = new FilterThread(filter);
1653 fFilterThread.start();
1654 }
1655 }
1656 }
1657
a0a88f65
AM
1658 /**
1659 * Refresh the filter.
1660 */
db4721fb
PT
1661 public void refreshTable() {
1662 synchronized (syncObj) {
1663 if (refreshBusy) {
1664 refreshPending = true;
1665 return;
1666 }
1667 refreshBusy = true;
1668 }
1669 Display.getDefault().asyncExec(new Runnable() {
1670 @Override
1671 public void run() {
1672 if (request.isCancelled()) {
1673 return;
1674 }
1675 if (fTable.isDisposed()) {
1676 return;
1677 }
1678 fTable.setItemCount((int) fFilterMatchCount + 3); // +1 for header row, +2 for top and bottom filter status rows
1679 fTable.refresh();
1680 synchronized (syncObj) {
1681 refreshBusy = false;
1682 if (refreshPending) {
1683 refreshPending = false;
1684 refreshTable();
1685 }
1686 }
1687 }
1688 });
1689 }
1690
a0a88f65
AM
1691 /**
1692 * Cancel this filtering thread.
1693 */
db4721fb
PT
1694 public void cancel() {
1695 if (request != null) {
1696 request.cancel();
1697 }
1698 }
1699 }
1700
a0a88f65
AM
1701 /**
1702 * Go to the next item of a search.
1703 */
db4721fb
PT
1704 protected void searchNext() {
1705 synchronized (fSearchSyncObj) {
1706 if (fSearchThread != null) {
1707 return;
1708 }
1709 final ITmfFilterTreeNode searchFilter = (ITmfFilterTreeNode) fTable.getData(Key.SEARCH_OBJ);
1710 if (searchFilter == null) {
1711 return;
1712 }
1713 final int selectionIndex = fTable.getSelectionIndex();
1714 int startIndex;
1715 if (selectionIndex > 0) {
1716 startIndex = selectionIndex; // -1 for header row, +1 for next event
1717 } else {
1718 // header row is selected, start at top event
1719 startIndex = Math.max(0, fTable.getTopIndex() - 1); // -1 for header row
1720 }
1721 final ITmfFilterTreeNode eventFilter = (ITmfFilterTreeNode) fTable.getData(Key.FILTER_OBJ);
60fb38b8 1722 if (eventFilter != null) {
db4721fb
PT
1723 startIndex = Math.max(0, startIndex - 1); // -1 for top filter status row
1724 }
1725 fSearchThread = new SearchThread(searchFilter, eventFilter, startIndex, fSelectedRank, Direction.FORWARD);
1726 fSearchThread.schedule();
1727 }
1728 }
1729
a0a88f65
AM
1730 /**
1731 * Go to the previous item of a search.
1732 */
db4721fb
PT
1733 protected void searchPrevious() {
1734 synchronized (fSearchSyncObj) {
1735 if (fSearchThread != null) {
1736 return;
1737 }
1738 final ITmfFilterTreeNode searchFilter = (ITmfFilterTreeNode) fTable.getData(Key.SEARCH_OBJ);
1739 if (searchFilter == null) {
1740 return;
1741 }
1742 final int selectionIndex = fTable.getSelectionIndex();
1743 int startIndex;
1744 if (selectionIndex > 0) {
1745 startIndex = selectionIndex - 2; // -1 for header row, -1 for previous event
1746 } else {
1747 // header row is selected, start at precedent of top event
1748 startIndex = fTable.getTopIndex() - 2; // -1 for header row, -1 for previous event
1749 }
1750 final ITmfFilterTreeNode eventFilter = (ITmfFilterTreeNode) fTable.getData(Key.FILTER_OBJ);
60fb38b8 1751 if (eventFilter != null) {
db4721fb
PT
1752 startIndex = startIndex - 1; // -1 for top filter status row
1753 }
1754 fSearchThread = new SearchThread(searchFilter, eventFilter, startIndex, fSelectedRank, Direction.BACKWARD);
1755 fSearchThread.schedule();
1756 }
1757 }
1758
a0a88f65
AM
1759 /**
1760 * Stop the search thread.
1761 */
db4721fb
PT
1762 protected void stopSearchThread() {
1763 fPendingGotoRank = -1;
1764 synchronized (fSearchSyncObj) {
1765 if (fSearchThread != null) {
1766 fSearchThread.cancel();
1767 fSearchThread = null;
1768 }
1769 }
1770 }
1771
a0a88f65
AM
1772 /**
1773 * Wrapper for the search thread.
1774 */
db4721fb 1775 protected class SearchThread extends Job {
a0a88f65
AM
1776
1777 private ITmfFilterTreeNode searchFilter;
1778 private ITmfFilterTreeNode eventFilter;
1779 private int startIndex;
1780 private int direction;
1781 private long rank;
1782 private long foundRank = -1;
fd3f1eff 1783 private TmfEventRequest request;
ae3ffd37 1784 private ITmfTimestamp foundTimestamp = null;
db4721fb 1785
a0a88f65
AM
1786 /**
1787 * Constructor.
1788 *
1789 * @param searchFilter
1790 * The search filter
1791 * @param eventFilter
1792 * The event filter
1793 * @param startIndex
1794 * The index at which we should start searching
1795 * @param currentRank
1796 * The current rank
1797 * @param direction
1798 * In which direction should we search, forward or backwards
1799 */
1800 public SearchThread(final ITmfFilterTreeNode searchFilter,
1801 final ITmfFilterTreeNode eventFilter, final int startIndex,
db4721fb
PT
1802 final long currentRank, final int direction) {
1803 super(Messages.TmfEventsTable_SearchingJobName);
1804 this.searchFilter = searchFilter;
1805 this.eventFilter = eventFilter;
1806 this.startIndex = startIndex;
1807 this.rank = currentRank;
1808 this.direction = direction;
1809 }
1810
1811 @Override
1812 protected IStatus run(final IProgressMonitor monitor) {
1813 if (fTrace == null) {
1814 return Status.OK_STATUS;
1815 }
1816 final Display display = Display.getDefault();
1817 if (startIndex < 0) {
1818 rank = (int) fTrace.getNbEvents() - 1;
1819 } else if (startIndex >= (fTable.getItemCount() - (eventFilter == null ? 1 : 3))) { // -1 for header row, -2 for top and bottom filter status rows
1820 rank = 0;
1821 } else {
1822 int idx = startIndex;
1823 while (foundRank == -1) {
1824 final CachedEvent event = fCache.peekEvent(idx);
1825 if (event == null) {
1826 break;
1827 }
1828 rank = event.rank;
1829 if (searchFilter.matches(event.event) && ((eventFilter == null) || eventFilter.matches(event.event))) {
1830 foundRank = event.rank;
ae3ffd37 1831 foundTimestamp = event.event.getTimestamp();
db4721fb
PT
1832 break;
1833 }
1834 if (direction == Direction.FORWARD) {
1835 idx++;
1836 } else {
1837 idx--;
1838 }
1839 }
1840 if (foundRank == -1) {
1841 if (direction == Direction.FORWARD) {
1842 rank++;
1843 if (rank > (fTrace.getNbEvents() - 1)) {
1844 rank = 0;
1845 }
1846 } else {
1847 rank--;
1848 if (rank < 0) {
1849 rank = (int) fTrace.getNbEvents() - 1;
1850 }
1851 }
1852 }
1853 }
1854 final int startRank = (int) rank;
1855 boolean wrapped = false;
1856 while (!monitor.isCanceled() && (foundRank == -1) && (fTrace != null)) {
1857 int nbRequested = (direction == Direction.FORWARD ? Integer.MAX_VALUE : Math.min((int) rank + 1, fTrace.getCacheSize()));
1858 if (direction == Direction.BACKWARD) {
1859 rank = Math.max(0, rank - fTrace.getCacheSize() + 1);
1860 }
fd3f1eff
AM
1861 request = new TmfEventRequest(ITmfEvent.class, TmfTimeRange.ETERNITY,
1862 (int) rank, nbRequested, ExecutionType.BACKGROUND) {
db4721fb
PT
1863 long currentRank = rank;
1864
1865 @Override
1866 public void handleData(final ITmfEvent event) {
1867 super.handleData(event);
1868 if (searchFilter.matches(event) && ((eventFilter == null) || eventFilter.matches(event))) {
1869 foundRank = currentRank;
ae3ffd37 1870 foundTimestamp = event.getTimestamp();
db4721fb
PT
1871 if (direction == Direction.FORWARD) {
1872 done();
1873 return;
1874 }
1875 }
1876 currentRank++;
1877 }
1878 };
fd3f1eff 1879 ((ITmfEventProvider) fTrace).sendRequest(request);
db4721fb
PT
1880 try {
1881 request.waitForCompletion();
1882 if (request.isCancelled()) {
1883 return Status.OK_STATUS;
1884 }
1885 } catch (final InterruptedException e) {
1886 synchronized (fSearchSyncObj) {
1887 fSearchThread = null;
1888 }
1889 return Status.OK_STATUS;
1890 }
1891 if (foundRank == -1) {
1892 if (direction == Direction.FORWARD) {
1893 if (rank == 0) {
1894 synchronized (fSearchSyncObj) {
1895 fSearchThread = null;
1896 }
1897 return Status.OK_STATUS;
1898 }
1899 nbRequested = (int) rank;
1900 rank = 0;
1901 wrapped = true;
1902 } else {
1903 rank--;
1904 if (rank < 0) {
1905 rank = (int) fTrace.getNbEvents() - 1;
1906 wrapped = true;
1907 }
1908 if ((rank <= startRank) && wrapped) {
1909 synchronized (fSearchSyncObj) {
1910 fSearchThread = null;
1911 }
1912 return Status.OK_STATUS;
1913 }
1914 }
1915 }
1916 }
1917 int index = (int) foundRank;
1918 if (eventFilter != null) {
1919 index = fCache.getFilteredEventIndex(foundRank);
1920 }
1921 final int selection = index + 1 + (eventFilter != null ? +1 : 0); // +1 for header row, +1 for top filter status row
1922
1923 display.asyncExec(new Runnable() {
1924 @Override
1925 public void run() {
1926 if (monitor.isCanceled()) {
1927 return;
1928 }
1929 if (fTable.isDisposed()) {
1930 return;
1931 }
1932 fTable.setSelection(selection);
1933 fSelectedRank = foundRank;
ae3ffd37
PT
1934 fRawViewer.selectAndReveal(fSelectedRank);
1935 if (foundTimestamp != null) {
1936 broadcast(new TmfTimeSynchSignal(TmfEventsTable.this, foundTimestamp));
1937 }
a56ec2b8 1938 fireSelectionChanged(new SelectionChangedEvent(TmfEventsTable.this, getSelection()));
db4721fb
PT
1939 synchronized (fSearchSyncObj) {
1940 fSearchThread = null;
1941 }
3f43dc48 1942 updateStatusLine(null);
db4721fb
PT
1943 }
1944 });
1945 return Status.OK_STATUS;
1946 }
1947
1948 @Override
1949 protected void canceling() {
1950 request.cancel();
1951 synchronized (fSearchSyncObj) {
1952 fSearchThread = null;
1953 }
1954 }
1955 }
1956
a0a88f65
AM
1957 /**
1958 * Create the resources.
1959 */
db4721fb
PT
1960 protected void createResources() {
1961 fGrayColor = fResourceManager.createColor(ColorUtil.blend(fTable.getBackground().getRGB(), fTable
1962 .getForeground().getRGB()));
1963 fGreenColor = fTable.getDisplay().getSystemColor(SWT.COLOR_DARK_GREEN);
1964 fBoldFont = fResourceManager.createFont(FontDescriptor.createFrom(fTable.getFont()).setStyle(SWT.BOLD));
1965 }
1966
a0a88f65
AM
1967 /**
1968 * Pack the columns.
1969 */
db4721fb
PT
1970 protected void packColumns() {
1971 if (fPackDone) {
1972 return;
1973 }
d3bc98ee 1974 fTable.setRedraw(false);
03142470
BH
1975 try {
1976 TableColumn tableColumns[] = fTable.getColumns();
1977 for (int i = 0; i < tableColumns.length; i++) {
1978 final TableColumn column = tableColumns[i];
1979 packSingleColumn(i, column);
1980 }
1981 } finally {
1982 // Make sure that redraw is always enabled.
1983 fTable.setRedraw(true);
1984 }
1985 fPackDone = true;
1986 }
d3bc98ee 1987
f29f8868 1988
03142470
BH
1989 private void packMarginColumn() {
1990 TableColumn[] columns = fTable.getColumns();
1991 if (columns.length > 0) {
1992 packSingleColumn(0, columns[0]);
1993 }
1994 }
f29f8868 1995
03142470
BH
1996 private void packSingleColumn(int i, final TableColumn column) {
1997 final int headerWidth = column.getWidth();
1998 column.pack();
1999 // Workaround for Linux which doesn't consider the image width of
2000 // search/filter row in TableColumn.pack() after having executed
2001 // TableItem.setImage((Image)null) for other rows than search/filter row.
2002 boolean isCollapseFilter = fTable.getData(Key.FILTER_OBJ) instanceof TmfCollapseFilter;
2003 if (IS_LINUX && (i == 0) && isCollapseFilter) {
2004 column.setWidth(column.getWidth() + SEARCH_IMAGE.getBounds().width);
db4721fb 2005 }
d3bc98ee 2006
03142470
BH
2007 if (column.getWidth() < headerWidth) {
2008 column.setWidth(headerWidth);
2009 }
db4721fb
PT
2010 }
2011
d3de0920 2012 /**
baafe54c
AM
2013 * Get the array of item strings (e.g., what to display in each cell of the
2014 * table row) corresponding to the columns and trace event passed in
2015 * parameter. The order of the Strings in the returned array will correspond
2016 * to the iteration order of 'columns'.
d3de0920 2017 *
baafe54c
AM
2018 * <p>
2019 * To ensure consistent results, make sure only call this within a scope
2020 * synchronized on 'columns'! If the order of 'columns' changes right after
2021 * this method is called, the returned value won't be ordered correctly
2022 * anymore.
2023 */
2024 private static String[] getItemStrings(List<TmfEventTableColumn> columns, ITmfEvent event) {
2025 if (event == null) {
2026 return EMPTY_STRING_ARRAY;
2027 }
2028 synchronized (columns) {
2029 List<String> itemStrings = new ArrayList<>(columns.size());
2030 for (TmfEventTableColumn column : columns) {
03142470
BH
2031 ITmfEvent passedEvent = event;
2032 if (!(column instanceof TmfMarginColumn) && (event instanceof CachedEvent)) {
2033 // Make sure that the event object from the trace is passed
2034 // to all columns but the TmfMarginColumn
2035 passedEvent = ((CachedEvent) event).event;
2036 }
2037 if (passedEvent == null) {
2038 itemStrings.add(EMPTY_STRING);
2039 } else {
2040 itemStrings.add(column.getItemString(passedEvent));
2041 }
2042
baafe54c
AM
2043 }
2044 return itemStrings.toArray(new String[0]);
2045 }
2046 }
2047
2048 /**
2049 * Get the contents of the row in the events table corresponding to an
2050 * event. The order of the elements corresponds to the current order of the
2051 * columns.
a0a88f65 2052 *
db4721fb 2053 * @param event
cf37ad9f
AM
2054 * The event printed in this row
2055 * @return The event row entries
2056 * @since 3.0
db4721fb 2057 */
cf37ad9f 2058 public String[] getItemStrings(ITmfEvent event) {
6817308e
PT
2059 List<TmfEventTableColumn> columns = new ArrayList<>();
2060 for (int i : fTable.getColumnOrder()) {
2061 columns.add(fColumns.get(i));
2062 }
2063 return getItemStrings(columns, event);
db4721fb
PT
2064 }
2065
2066 /**
2067 * Notify this table that is got the UI focus.
2068 */
2069 public void setFocus() {
2070 fTable.setFocus();
2071 }
2072
2073 /**
2074 * Assign a new trace to this event table.
2075 *
2076 * @param trace
2077 * The trace to assign to this event table
2078 * @param disposeOnClose
2079 * true if the trace should be disposed when the table is
2080 * disposed
2081 */
2082 public void setTrace(final ITmfTrace trace, final boolean disposeOnClose) {
2083 if ((fTrace != null) && fDisposeOnClose) {
2084 fTrace.dispose();
2085 }
2086 fTrace = trace;
2087 fPackDone = false;
2088 fSelectedRank = 0;
2089 fDisposeOnClose = disposeOnClose;
2090
2091 // Perform the updates on the UI thread
2092 fTable.getDisplay().syncExec(new Runnable() {
2093 @Override
2094 public void run() {
2095 fTable.removeAll();
2096 fCache.setTrace(fTrace); // Clear the cache
2097 if (fTrace != null) {
2098 if (!fTable.isDisposed() && (fTrace != null)) {
2099 if (fTable.getData(Key.FILTER_OBJ) == null) {
2100 fTable.setItemCount((int) fTrace.getNbEvents() + 1); // +1 for header row
2101 } else {
2102 stopFilterThread();
2103 fFilterMatchCount = 0;
2104 fFilterCheckCount = 0;
2105 fTable.setItemCount(3); // +1 for header row, +2 for top and bottom filter status rows
2106 startFilterThread();
2107 }
2108 }
db4721fb 2109 }
ea279a69 2110 fRawViewer.setTrace(fTrace);
db4721fb
PT
2111 }
2112 });
2113 }
2114
3f43dc48
PT
2115 /**
2116 * Assign the status line manager
2117 *
2118 * @param statusLineManager
2119 * The status line manager, or null to disable status line messages
4b121c48 2120 * @since 2.1
3f43dc48
PT
2121 */
2122 public void setStatusLineManager(IStatusLineManager statusLineManager) {
2123 if (fStatusLineManager != null && statusLineManager == null) {
03142470 2124 fStatusLineManager.setMessage(EMPTY_STRING);
3f43dc48
PT
2125 }
2126 fStatusLineManager = statusLineManager;
2127 }
2128
2129 private void updateStatusLine(ITmfTimestamp delta) {
2130 if (fStatusLineManager != null) {
2131 if (delta != null) {
2132 fStatusLineManager.setMessage("\u0394: " + delta); //$NON-NLS-1$
2133 } else {
2134 fStatusLineManager.setMessage(null);
2135 }
2136 }
2137 }
2138
db4721fb
PT
2139 // ------------------------------------------------------------------------
2140 // Event cache
2141 // ------------------------------------------------------------------------
2142
2143 /**
2144 * Notify that the event cache has been updated
2145 *
2146 * @param completed
2147 * Also notify if the populating of the cache is complete, or
2148 * not.
2149 */
2150 public void cacheUpdated(final boolean completed) {
2151 synchronized (fCacheUpdateSyncObj) {
2152 if (fCacheUpdateBusy) {
2153 fCacheUpdatePending = true;
2154 fCacheUpdateCompleted = completed;
2155 return;
2156 }
2157 fCacheUpdateBusy = true;
2158 }
2159 // Event cache is now updated. Perform update on the UI thread
2160 if (!fTable.isDisposed()) {
2161 fTable.getDisplay().asyncExec(new Runnable() {
2162 @Override
2163 public void run() {
2164 if (!fTable.isDisposed()) {
2165 fTable.refresh();
2166 packColumns();
2167 }
2168 if (completed) {
2169 populateCompleted();
2170 }
2171 synchronized (fCacheUpdateSyncObj) {
2172 fCacheUpdateBusy = false;
2173 if (fCacheUpdatePending) {
2174 fCacheUpdatePending = false;
2175 cacheUpdated(fCacheUpdateCompleted);
2176 }
2177 }
2178 }
2179 });
2180 }
2181 }
2182
a0a88f65
AM
2183 /**
2184 * Callback for when populating the table is complete.
2185 */
db4721fb
PT
2186 protected void populateCompleted() {
2187 // Nothing by default;
2188 }
2189
93bfd50a
PT
2190 // ------------------------------------------------------------------------
2191 // ISelectionProvider
2192 // ------------------------------------------------------------------------
2193
93bfd50a
PT
2194 /**
2195 * @since 2.0
2196 */
2197 @Override
2198 public void addSelectionChangedListener(ISelectionChangedListener listener) {
2199 selectionChangedListeners.add(listener);
2200 }
2201
93bfd50a
PT
2202 /**
2203 * @since 2.0
2204 */
2205 @Override
2206 public ISelection getSelection() {
2207 if (fTable == null || fTable.isDisposed()) {
2208 return StructuredSelection.EMPTY;
2209 }
507b1336 2210 List<Object> list = new ArrayList<>(fTable.getSelection().length);
93bfd50a
PT
2211 for (TableItem item : fTable.getSelection()) {
2212 if (item.getData() != null) {
2213 list.add(item.getData());
2214 }
2215 }
2216 return new StructuredSelection(list);
2217 }
2218
93bfd50a
PT
2219 /**
2220 * @since 2.0
2221 */
2222 @Override
2223 public void removeSelectionChangedListener(ISelectionChangedListener listener) {
2224 selectionChangedListeners.remove(listener);
2225 }
2226
93bfd50a
PT
2227 /**
2228 * @since 2.0
2229 */
2230 @Override
2231 public void setSelection(ISelection selection) {
2232 // not implemented
2233 }
2234
2235 /**
2236 * Notifies any selection changed listeners that the viewer's selection has changed.
2237 * Only listeners registered at the time this method is called are notified.
2238 *
2239 * @param event a selection changed event
2240 *
2241 * @see ISelectionChangedListener#selectionChanged
2242 * @since 2.0
2243 */
2244 protected void fireSelectionChanged(final SelectionChangedEvent event) {
2245 Object[] listeners = selectionChangedListeners.getListeners();
2246 for (int i = 0; i < listeners.length; ++i) {
2247 final ISelectionChangedListener l = (ISelectionChangedListener) listeners[i];
2248 SafeRunnable.run(new SafeRunnable() {
faa38350 2249 @Override
93bfd50a
PT
2250 public void run() {
2251 l.selectionChanged(event);
2252 }
2253 });
2254 }
2255 }
2256
db4721fb
PT
2257 // ------------------------------------------------------------------------
2258 // Bookmark handling
2259 // ------------------------------------------------------------------------
2260
2261 /**
2262 * Add a bookmark to this event table.
2263 *
2264 * @param bookmarksFile
2265 * The file to use for the bookmarks
2266 */
2267 public void addBookmark(final IFile bookmarksFile) {
2268 fBookmarksFile = bookmarksFile;
2269 final TableItem[] selection = fTable.getSelection();
2270 if (selection.length > 0) {
2271 final TableItem tableItem = selection[0];
2272 if (tableItem.getData(Key.RANK) != null) {
2273 final StringBuffer defaultMessage = new StringBuffer();
2274 for (int i = 0; i < fTable.getColumns().length; i++) {
60fb38b8 2275 if (i > 0) {
db4721fb
PT
2276 defaultMessage.append(", "); //$NON-NLS-1$
2277 }
2278 defaultMessage.append(tableItem.getText(i));
2279 }
3be2946f
PT
2280 final InputDialog dialog = new MultiLineInputDialog(
2281 PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell(),
2282 Messages.TmfEventsTable_AddBookmarkDialogTitle,
2283 Messages.TmfEventsTable_AddBookmarkDialogMessage,
2284 defaultMessage.toString());
db4721fb
PT
2285 if (dialog.open() == Window.OK) {
2286 final String message = dialog.getValue();
2287 try {
2288 final IMarker bookmark = bookmarksFile.createMarker(IMarker.BOOKMARK);
2289 if (bookmark.exists()) {
2290 bookmark.setAttribute(IMarker.MESSAGE, message.toString());
0126a8ca
AM
2291 final Long rank = (Long) tableItem.getData(Key.RANK);
2292 final int location = rank.intValue();
2293 bookmark.setAttribute(IMarker.LOCATION, Integer.valueOf(location));
db4721fb
PT
2294 fBookmarksMap.put(rank, bookmark.getId());
2295 fTable.refresh();
2296 }
2297 } catch (final CoreException e) {
2298 displayException(e);
2299 }
2300 }
2301 }
2302 }
2303
2304 }
2305
2306 /**
2307 * Remove a bookmark from this event table.
2308 *
2309 * @param bookmark
2310 * The bookmark to remove
2311 */
2312 public void removeBookmark(final IMarker bookmark) {
2db176a0 2313 for (final Entry<Long, Long> entry : fBookmarksMap.entries()) {
db4721fb 2314 if (entry.getValue().equals(bookmark.getId())) {
2db176a0 2315 fBookmarksMap.remove(entry.getKey(), entry.getValue());
db4721fb
PT
2316 fTable.refresh();
2317 return;
2318 }
2319 }
2320 }
2321
0126a8ca 2322 private void toggleBookmark(final Long rank) {
db4721fb
PT
2323 if (fBookmarksFile == null) {
2324 return;
2325 }
2326 if (fBookmarksMap.containsKey(rank)) {
2db176a0 2327 final Collection<Long> markerIds = fBookmarksMap.removeAll(rank);
db4721fb
PT
2328 fTable.refresh();
2329 try {
2db176a0
PT
2330 for (long markerId : markerIds) {
2331 final IMarker bookmark = fBookmarksFile.findMarker(markerId);
2332 if (bookmark != null) {
2333 bookmark.delete();
2334 }
db4721fb
PT
2335 }
2336 } catch (final CoreException e) {
2337 displayException(e);
2338 }
2339 } else {
2340 addBookmark(fBookmarksFile);
2341 }
2342 }
2343
2344 /**
2345 * Refresh the bookmarks assigned to this trace, from the contents of a
2346 * bookmark file.
2347 *
2348 * @param bookmarksFile
2349 * The bookmark file to use
2350 */
2351 public void refreshBookmarks(final IFile bookmarksFile) {
2352 fBookmarksFile = bookmarksFile;
2353 if (bookmarksFile == null) {
2354 fBookmarksMap.clear();
2355 fTable.refresh();
2356 return;
2357 }
2358 try {
2359 fBookmarksMap.clear();
2360 for (final IMarker bookmark : bookmarksFile.findMarkers(IMarker.BOOKMARK, false, IResource.DEPTH_ZERO)) {
2361 final int location = bookmark.getAttribute(IMarker.LOCATION, -1);
2362 if (location != -1) {
2363 final long rank = location;
2364 fBookmarksMap.put(rank, bookmark.getId());
2365 }
2366 }
2367 fTable.refresh();
2368 } catch (final CoreException e) {
2369 displayException(e);
2370 }
2371 }
2372
2373 @Override
2374 public void gotoMarker(final IMarker marker) {
2375 final int rank = marker.getAttribute(IMarker.LOCATION, -1);
2376 if (rank != -1) {
2377 int index = rank;
2378 if (fTable.getData(Key.FILTER_OBJ) != null) {
2379 index = fCache.getFilteredEventIndex(rank) + 1; // +1 for top filter status row
2380 } else if (rank >= fTable.getItemCount()) {
2381 fPendingGotoRank = rank;
2382 }
a56ec2b8 2383 fSelectedRank = rank;
db4721fb 2384 fTable.setSelection(index + 1); // +1 for header row
3f43dc48 2385 updateStatusLine(null);
db4721fb
PT
2386 }
2387 }
2388
2389 // ------------------------------------------------------------------------
2390 // Listeners
2391 // ------------------------------------------------------------------------
2392
db4721fb
PT
2393 @Override
2394 public void colorSettingsChanged(final ColorSetting[] colorSettings) {
2395 fTable.refresh();
2396 }
2397
db4721fb
PT
2398 // ------------------------------------------------------------------------
2399 // Signal handlers
2400 // ------------------------------------------------------------------------
2401
db4721fb
PT
2402 /**
2403 * Handler for the trace updated signal
2404 *
2405 * @param signal
2406 * The incoming signal
2407 */
2408 @TmfSignalHandler
2409 public void traceUpdated(final TmfTraceUpdatedSignal signal) {
2410 if ((signal.getTrace() != fTrace) || fTable.isDisposed()) {
2411 return;
2412 }
2413 // Perform the refresh on the UI thread
2414 Display.getDefault().asyncExec(new Runnable() {
2415 @Override
2416 public void run() {
2417 if (!fTable.isDisposed() && (fTrace != null)) {
2418 if (fTable.getData(Key.FILTER_OBJ) == null) {
2419 fTable.setItemCount((int) fTrace.getNbEvents() + 1); // +1 for header row
2420 if ((fPendingGotoRank != -1) && ((fPendingGotoRank + 1) < fTable.getItemCount())) { // +1 for header row
2421 fTable.setSelection((int) fPendingGotoRank + 1); // +1 for header row
2422 fPendingGotoRank = -1;
3f43dc48 2423 updateStatusLine(null);
db4721fb
PT
2424 }
2425 } else {
2426 startFilterThread();
2427 }
2428 }
2429 if (!fRawViewer.isDisposed() && (fTrace != null)) {
2430 fRawViewer.refreshEventCount();
2431 }
2432 }
2433 });
2434 }
2435
2436 /**
2437 * Handler for the time synch signal.
2438 *
2439 * @param signal
2440 * The incoming signal
2441 */
2442 @TmfSignalHandler
2443 public void currentTimeUpdated(final TmfTimeSynchSignal signal) {
2444 if ((signal.getSource() != this) && (fTrace != null) && (!fTable.isDisposed())) {
2445
2446 // Create a request for one event that will be queued after other ongoing requests. When this request is completed
2447 // do the work to select the actual event with the timestamp specified in the signal. This procedure prevents
2448 // the method fTrace.getRank() from interfering and delaying ongoing requests.
fd3f1eff
AM
2449 final TmfEventRequest subRequest = new TmfEventRequest(ITmfEvent.class,
2450 TmfTimeRange.ETERNITY, 0, 1, ExecutionType.FOREGROUND) {
db4721fb 2451
0fcf3b09 2452 TmfTimestamp ts = new TmfTimestamp(signal.getBeginTime());
db4721fb
PT
2453
2454 @Override
2455 public void handleData(final ITmfEvent event) {
2456 super.handleData(event);
2457 }
2458
2459 @Override
73fce654
AM
2460 public void handleSuccess() {
2461 super.handleSuccess();
db4721fb
PT
2462 if (fTrace == null) {
2463 return;
2464 }
2465
2466 // Verify if the event is within the trace range and adjust if necessary
2467 ITmfTimestamp timestamp = ts;
065cc19b 2468 if (timestamp.compareTo(fTrace.getStartTime()) == -1) {
db4721fb
PT
2469 timestamp = fTrace.getStartTime();
2470 }
065cc19b 2471 if (timestamp.compareTo(fTrace.getEndTime()) == 1) {
db4721fb
PT
2472 timestamp = fTrace.getEndTime();
2473 }
2474
2475 // Get the rank of the selected event in the table
2476 final ITmfContext context = fTrace.seekEvent(timestamp);
2477 final long rank = context.getRank();
4c9f2944 2478 context.dispose();
db4721fb
PT
2479 fSelectedRank = rank;
2480
2481 fTable.getDisplay().asyncExec(new Runnable() {
2482 @Override
2483 public void run() {
2484 // Return if table is disposed
2485 if (fTable.isDisposed()) {
2486 return;
2487 }
2488
2489 int index = (int) rank;
2490 if (fTable.isDisposed()) {
2491 return;
2492 }
60fb38b8 2493 if (fTable.getData(Key.FILTER_OBJ) != null) {
db4721fb
PT
2494 index = fCache.getFilteredEventIndex(rank) + 1; // +1 for top filter status row
2495 }
2496 fTable.setSelection(index + 1); // +1 for header row
2497 fRawViewer.selectAndReveal(rank);
3f43dc48 2498 updateStatusLine(null);
db4721fb
PT
2499 }
2500 });
2501 }
2502 };
2503
fd3f1eff 2504 ((ITmfEventProvider) fTrace).sendRequest(subRequest);
db4721fb
PT
2505 }
2506 }
2507
2508 // ------------------------------------------------------------------------
2509 // Error handling
2510 // ------------------------------------------------------------------------
2511
2512 /**
2513 * Display an exception in a message box
2514 *
2515 * @param e the exception
2516 */
2517 private static void displayException(final Exception e) {
2518 final MessageBox mb = new MessageBox(PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell());
60fb38b8 2519 mb.setText(e.getClass().getSimpleName());
db4721fb
PT
2520 mb.setMessage(e.getMessage());
2521 mb.open();
2522 }
2523
f8177ba2
FC
2524 /**
2525 * @since 2.0
2526 */
2527 public void refresh() {
2528 fCache.clear();
2529 fTable.refresh();
2530 fTable.redraw();
2531 }
03142470
BH
2532
2533 /**
9447c7ee
AM
2534 * Margin column for images and special text (e.g. collapse count)
2535 */
2536 private static final class TmfMarginColumn extends TmfEventTableColumn {
2537
2538 private static final @NonNull ITmfEventAspect MARGIN_ASPECT = new ITmfEventAspect() {
2539
2540 @Override
2541 public String getName() {
2542 return EMPTY_STRING;
2543 }
2544
2545 @Override
2546 public String resolve(ITmfEvent event) {
2547 if (!(event instanceof CachedEvent) || ((CachedEvent) event).repeatCount == 0) {
2548 return EMPTY_STRING;
2549 }
2550 return "+" + ((CachedEvent) event).repeatCount; //$NON-NLS-1$
2551 }
2552
2553 @Override
2554 public String getHelpText() {
2555 return EMPTY_STRING;
2556 }
2557
2558 @Override
2559 public String getFilterId() {
2560 return null;
2561 }
2562 };
2563
2564 /**
2565 * Constructor
2566 */
2567 public TmfMarginColumn() {
2568 super(MARGIN_ASPECT);
2569 }
2570 }
03142470 2571
db4721fb 2572}
This page took 0.212901 seconds and 5 git commands to generate.