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