lttng/tmf: Enable and fix parameter assignment warnings
[deliverable/tracecompass.git] / org.eclipse.linuxtools.tmf.ui / src / org / eclipse / linuxtools / tmf / ui / viewers / events / TmfEventsTable.java
CommitLineData
db4721fb
PT
1/*******************************************************************************
2 * Copyright (c) 2010, 2011, 2012 Ericsson
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:
10 * Francois Chouinard - Initial API and implementation
11 * Patrick Tasse - Factored out from events view
12 * Francois Chouinard - Replaced Table by TmfVirtualTable
13 * Patrick Tasse - Filter implementation (inspired by www.eclipse.org/mat)
14 *******************************************************************************/
15
16package org.eclipse.linuxtools.tmf.ui.viewers.events;
17
18import java.util.ArrayList;
19import java.util.Arrays;
20import java.util.HashMap;
21import java.util.List;
22import java.util.Map;
23import java.util.Map.Entry;
24import java.util.regex.Pattern;
25import java.util.regex.PatternSyntaxException;
26
27import org.eclipse.core.resources.IFile;
28import org.eclipse.core.resources.IMarker;
29import org.eclipse.core.resources.IResource;
30import org.eclipse.core.runtime.CoreException;
31import org.eclipse.core.runtime.IProgressMonitor;
32import org.eclipse.core.runtime.IStatus;
93bfd50a 33import org.eclipse.core.runtime.ListenerList;
db4721fb
PT
34import org.eclipse.core.runtime.Status;
35import org.eclipse.core.runtime.jobs.Job;
36import org.eclipse.jface.action.Action;
37import org.eclipse.jface.action.IAction;
38import org.eclipse.jface.action.IMenuListener;
39import org.eclipse.jface.action.IMenuManager;
40import org.eclipse.jface.action.MenuManager;
41import org.eclipse.jface.action.Separator;
42import org.eclipse.jface.dialogs.InputDialog;
43import org.eclipse.jface.dialogs.MessageDialog;
44import org.eclipse.jface.resource.FontDescriptor;
45import org.eclipse.jface.resource.JFaceResources;
46import org.eclipse.jface.resource.LocalResourceManager;
93bfd50a
PT
47import org.eclipse.jface.util.SafeRunnable;
48import org.eclipse.jface.viewers.ISelection;
49import org.eclipse.jface.viewers.ISelectionChangedListener;
50import org.eclipse.jface.viewers.ISelectionProvider;
93bfd50a
PT
51import org.eclipse.jface.viewers.SelectionChangedEvent;
52import org.eclipse.jface.viewers.StructuredSelection;
db4721fb
PT
53import org.eclipse.jface.window.Window;
54import org.eclipse.linuxtools.internal.tmf.ui.Activator;
55import org.eclipse.linuxtools.internal.tmf.ui.Messages;
3be2946f 56import org.eclipse.linuxtools.internal.tmf.ui.dialogs.MultiLineInputDialog;
db4721fb
PT
57import org.eclipse.linuxtools.tmf.core.component.ITmfDataProvider;
58import org.eclipse.linuxtools.tmf.core.component.TmfComponent;
59import org.eclipse.linuxtools.tmf.core.event.ITmfEvent;
60import org.eclipse.linuxtools.tmf.core.event.ITmfEventField;
61import org.eclipse.linuxtools.tmf.core.event.ITmfTimestamp;
62import org.eclipse.linuxtools.tmf.core.event.TmfEventField;
63import org.eclipse.linuxtools.tmf.core.event.TmfTimestamp;
64import org.eclipse.linuxtools.tmf.core.filter.ITmfFilter;
65import org.eclipse.linuxtools.tmf.core.filter.model.ITmfFilterTreeNode;
66import org.eclipse.linuxtools.tmf.core.filter.model.TmfFilterAndNode;
67import org.eclipse.linuxtools.tmf.core.filter.model.TmfFilterMatchesNode;
68import org.eclipse.linuxtools.tmf.core.filter.model.TmfFilterNode;
69import org.eclipse.linuxtools.tmf.core.request.ITmfDataRequest.ExecutionType;
70import org.eclipse.linuxtools.tmf.core.request.TmfDataRequest;
faa38350
PT
71import org.eclipse.linuxtools.tmf.core.signal.TmfEventFilterAppliedSignal;
72import org.eclipse.linuxtools.tmf.core.signal.TmfEventSearchAppliedSignal;
db4721fb
PT
73import org.eclipse.linuxtools.tmf.core.signal.TmfSignalHandler;
74import org.eclipse.linuxtools.tmf.core.signal.TmfTimeSynchSignal;
75import org.eclipse.linuxtools.tmf.core.signal.TmfTraceUpdatedSignal;
76import org.eclipse.linuxtools.tmf.core.trace.ITmfContext;
77import org.eclipse.linuxtools.tmf.core.trace.ITmfLocation;
78import org.eclipse.linuxtools.tmf.core.trace.ITmfTrace;
79import org.eclipse.linuxtools.tmf.ui.viewers.events.TmfEventsCache.CachedEvent;
80import org.eclipse.linuxtools.tmf.ui.views.colors.ColorSetting;
81import org.eclipse.linuxtools.tmf.ui.views.colors.ColorSettingsManager;
82import org.eclipse.linuxtools.tmf.ui.views.colors.IColorSettingsListener;
83import org.eclipse.linuxtools.tmf.ui.views.filter.FilterManager;
84import org.eclipse.linuxtools.tmf.ui.widgets.rawviewer.TmfRawEventViewer;
85import org.eclipse.linuxtools.tmf.ui.widgets.virtualtable.ColumnData;
86import org.eclipse.linuxtools.tmf.ui.widgets.virtualtable.TmfVirtualTable;
87import org.eclipse.swt.SWT;
88import org.eclipse.swt.custom.SashForm;
89import org.eclipse.swt.custom.TableEditor;
90import org.eclipse.swt.events.FocusAdapter;
91import org.eclipse.swt.events.FocusEvent;
92import org.eclipse.swt.events.KeyAdapter;
93import org.eclipse.swt.events.KeyEvent;
94import org.eclipse.swt.events.MouseAdapter;
95import org.eclipse.swt.events.MouseEvent;
96import org.eclipse.swt.events.SelectionAdapter;
97import org.eclipse.swt.events.SelectionEvent;
98import org.eclipse.swt.graphics.Color;
99import org.eclipse.swt.graphics.Font;
100import org.eclipse.swt.graphics.Image;
101import org.eclipse.swt.graphics.Point;
102import org.eclipse.swt.graphics.Rectangle;
103import org.eclipse.swt.layout.FillLayout;
104import org.eclipse.swt.layout.GridData;
105import org.eclipse.swt.layout.GridLayout;
106import org.eclipse.swt.widgets.Composite;
107import org.eclipse.swt.widgets.Display;
108import org.eclipse.swt.widgets.Event;
109import org.eclipse.swt.widgets.Label;
110import org.eclipse.swt.widgets.Listener;
111import org.eclipse.swt.widgets.Menu;
112import org.eclipse.swt.widgets.MessageBox;
113import org.eclipse.swt.widgets.Shell;
114import org.eclipse.swt.widgets.TableColumn;
115import org.eclipse.swt.widgets.TableItem;
116import org.eclipse.swt.widgets.Text;
117import org.eclipse.ui.PlatformUI;
118import org.eclipse.ui.ide.IGotoMarker;
119import org.eclipse.ui.themes.ColorUtil;
120
121/**
122 * The generic TMF Events table
123 *
124 * This is a view that will list events that are read from a trace.
125 *
126 * @version 1.0
127 * @author Francois Chouinard
128 * @author Patrick Tasse
93bfd50a 129 * @since 2.0
db4721fb 130 */
faa38350 131public class TmfEventsTable extends TmfComponent implements IGotoMarker, IColorSettingsListener, ISelectionProvider {
db4721fb
PT
132
133 private static final Image BOOKMARK_IMAGE = Activator.getDefault().getImageFromPath(
134 "icons/elcl16/bookmark_obj.gif"); //$NON-NLS-1$
135 private static final Image SEARCH_IMAGE = Activator.getDefault().getImageFromPath("icons/elcl16/search.gif"); //$NON-NLS-1$
136 private static final Image SEARCH_MATCH_IMAGE = Activator.getDefault().getImageFromPath(
137 "icons/elcl16/search_match.gif"); //$NON-NLS-1$
138 private static final Image SEARCH_MATCH_BOOKMARK_IMAGE = Activator.getDefault().getImageFromPath(
139 "icons/elcl16/search_match_bookmark.gif"); //$NON-NLS-1$
140 private static final Image FILTER_IMAGE = Activator.getDefault()
141 .getImageFromPath("icons/elcl16/filter_items.gif"); //$NON-NLS-1$
142 private static final Image STOP_IMAGE = Activator.getDefault().getImageFromPath("icons/elcl16/stop.gif"); //$NON-NLS-1$
143 private static final String SEARCH_HINT = Messages.TmfEventsTable_SearchHint;
144 private static final String FILTER_HINT = Messages.TmfEventsTable_FilterHint;
145 private static final int MAX_CACHE_SIZE = 1000;
146
147 /**
148 * The events table search/filter keys
149 *
150 * @version 1.0
151 * @author Patrick Tasse
152 */
153 public interface Key {
154 /** Search text */
155 String SEARCH_TXT = "$srch_txt"; //$NON-NLS-1$
156
157 /** Search object */
158 String SEARCH_OBJ = "$srch_obj"; //$NON-NLS-1$
159
160 /** Filter text */
161 String FILTER_TXT = "$fltr_txt"; //$NON-NLS-1$
162
163 /** Filter object */
164 String FILTER_OBJ = "$fltr_obj"; //$NON-NLS-1$
165
166 /** Timestamp*/
167 String TIMESTAMP = "$time"; //$NON-NLS-1$
168
169 /** Rank */
170 String RANK = "$rank"; //$NON-NLS-1$
171
172 /** Field ID */
173 String FIELD_ID = "$field_id"; //$NON-NLS-1$
174
175 /** Bookmark indicator */
176 String BOOKMARK = "$bookmark"; //$NON-NLS-1$
177 }
178
179 /**
180 * The events table search/filter state
181 *
182 * @version 1.0
183 * @author Patrick Tasse
184 */
185 public static enum HeaderState {
186 /** A search is being run */
187 SEARCH,
188
189 /** A filter is applied */
190 FILTER
191 }
192
193 interface Direction {
194 int FORWARD = +1;
195 int BACKWARD = -1;
196 }
197
198 // ------------------------------------------------------------------------
199 // Table data
200 // ------------------------------------------------------------------------
201
a0a88f65 202 /** The virtual event table */
db4721fb 203 protected TmfVirtualTable fTable;
a0a88f65
AM
204
205 private Composite fComposite;
206 private SashForm fSashForm;
207 private TmfRawEventViewer fRawViewer;
208 private ITmfTrace fTrace;
209 private boolean fPackDone = false;
210 private HeaderState fHeaderState = HeaderState.SEARCH;
211 private long fSelectedRank = 0;
db4721fb
PT
212
213 // Filter data
a0a88f65
AM
214 private long fFilterMatchCount;
215 private long fFilterCheckCount;
216 private FilterThread fFilterThread;
217 private boolean fFilterThreadResume = false;
218 private final Object fFilterSyncObj = new Object();
219 private SearchThread fSearchThread;
220 private final Object fSearchSyncObj = new Object();
db4721fb 221
93bfd50a
PT
222 /**
223 * List of selection change listeners (element type: <code>ISelectionChangedListener</code>).
224 *
225 * @see #fireSelectionChanged
226 */
227 private ListenerList selectionChangedListeners = new ListenerList();
228
db4721fb 229 // Bookmark map <Rank, MarkerId>
a0a88f65
AM
230 private Map<Long, Long> fBookmarksMap = new HashMap<Long, Long>();
231 private IFile fBookmarksFile;
232 private long fPendingGotoRank = -1;
db4721fb
PT
233
234 // SWT resources
a0a88f65
AM
235 private LocalResourceManager fResourceManager = new LocalResourceManager(JFaceResources.getResources());
236 private Color fGrayColor;
237 private Color fGreenColor;
238 private Font fBoldFont;
db4721fb
PT
239
240 // Table column names
a0a88f65 241 private static final String[] COLUMN_NAMES = new String[] { Messages.TmfEventsTable_TimestampColumnHeader,
db4721fb
PT
242 Messages.TmfEventsTable_SourceColumnHeader, Messages.TmfEventsTable_TypeColumnHeader,
243 Messages.TmfEventsTable_ReferenceColumnHeader, Messages.TmfEventsTable_ContentColumnHeader };
244
a0a88f65 245 private static final ColumnData[] COLUMN_DATA = new ColumnData[] { new ColumnData(COLUMN_NAMES[0], 100, SWT.LEFT),
db4721fb
PT
246 new ColumnData(COLUMN_NAMES[1], 100, SWT.LEFT), new ColumnData(COLUMN_NAMES[2], 100, SWT.LEFT),
247 new ColumnData(COLUMN_NAMES[3], 100, SWT.LEFT), new ColumnData(COLUMN_NAMES[4], 100, SWT.LEFT) };
248
249 // Event cache
250 private final TmfEventsCache fCache;
251 private boolean fCacheUpdateBusy = false;
252 private boolean fCacheUpdatePending = false;
253 private boolean fCacheUpdateCompleted = false;
254 private final Object fCacheUpdateSyncObj = new Object();
255
256 private boolean fDisposeOnClose;
257
258 // ------------------------------------------------------------------------
a0a88f65 259 // Constructors
db4721fb
PT
260 // ------------------------------------------------------------------------
261
262 /**
263 * Basic constructor, will use default column data.
264 *
265 * @param parent
266 * The parent composite UI object
267 * @param cacheSize
268 * The size of the event table cache
269 */
270 public TmfEventsTable(final Composite parent, final int cacheSize) {
271 this(parent, cacheSize, COLUMN_DATA);
272 }
273
274 /**
275 * Advanced constructor, where we also define which column data to use.
276 *
277 * @param parent
278 * The parent composite UI object
279 * @param cacheSize
280 * The size of the event table cache
281 * @param columnData
282 * The column data to use for this table
283 */
284 public TmfEventsTable(final Composite parent, int cacheSize, final ColumnData[] columnData) {
285 super("TmfEventsTable"); //$NON-NLS-1$
286
287 fComposite = new Composite(parent, SWT.NONE);
288 final GridLayout gl = new GridLayout(1, false);
289 gl.marginHeight = 0;
290 gl.marginWidth = 0;
291 gl.verticalSpacing = 0;
292 fComposite.setLayout(gl);
293
294 fSashForm = new SashForm(fComposite, SWT.HORIZONTAL);
295 fSashForm.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
296
297 // Create a virtual table
298 final int style = SWT.H_SCROLL | SWT.V_SCROLL | SWT.SINGLE | SWT.FULL_SELECTION;
299 fTable = new TmfVirtualTable(fSashForm, style);
300
301 // Set the table layout
302 final GridData layoutData = new GridData(SWT.FILL, SWT.FILL, true, true);
303 fTable.setLayoutData(layoutData);
304
305 // Some cosmetic enhancements
306 fTable.setHeaderVisible(true);
307 fTable.setLinesVisible(true);
308
309 // Set the columns
310 setColumnHeaders(columnData);
311
312 // Set the default column field ids if this is not a subclass
313 if (Arrays.equals(columnData, COLUMN_DATA)) {
314 fTable.getColumns()[0].setData(Key.FIELD_ID, ITmfEvent.EVENT_FIELD_TIMESTAMP);
315 fTable.getColumns()[1].setData(Key.FIELD_ID, ITmfEvent.EVENT_FIELD_SOURCE);
316 fTable.getColumns()[2].setData(Key.FIELD_ID, ITmfEvent.EVENT_FIELD_TYPE);
317 fTable.getColumns()[3].setData(Key.FIELD_ID, ITmfEvent.EVENT_FIELD_REFERENCE);
318 fTable.getColumns()[4].setData(Key.FIELD_ID, ITmfEvent.EVENT_FIELD_CONTENT);
319 }
320
321 // Set the frozen row for header row
322 fTable.setFrozenRowCount(1);
323
324 // Create the header row cell editor
325 createHeaderEditor();
326
327 // Handle the table item selection
328 fTable.addSelectionListener(new SelectionAdapter() {
329 @Override
330 public void widgetSelected(final SelectionEvent e) {
331 final TableItem[] selection = fTable.getSelection();
332 if (selection.length > 0) {
333 final TableItem selectedTableItem = selection[0];
334 if (selectedTableItem != null) {
335 if (selectedTableItem.getData(Key.RANK) instanceof Long) {
336 fSelectedRank = (Long) selectedTableItem.getData(Key.RANK);
337 fRawViewer.selectAndReveal((Long) selectedTableItem.getData(Key.RANK));
338 }
339 if (selectedTableItem.getData(Key.TIMESTAMP) instanceof TmfTimestamp) {
340 final TmfTimestamp ts = (TmfTimestamp) selectedTableItem.getData(Key.TIMESTAMP);
341 broadcast(new TmfTimeSynchSignal(TmfEventsTable.this, ts));
342 }
343 }
344 }
93bfd50a 345 fireSelectionChanged(new SelectionChangedEvent(TmfEventsTable.this, getSelection()));
db4721fb
PT
346 }
347 });
348
41b5c37f
AM
349 int realCacheSize = Math.max(cacheSize, Display.getDefault().getBounds().height / fTable.getItemHeight());
350 realCacheSize = Math.min(realCacheSize, MAX_CACHE_SIZE);
351 fCache = new TmfEventsCache(realCacheSize, this);
db4721fb
PT
352
353 // Handle the table item requests
354 fTable.addListener(SWT.SetData, new Listener() {
355
356 @Override
357 public void handleEvent(final Event event) {
358
359 final TableItem item = (TableItem) event.item;
360 int index = event.index - 1; // -1 for the header row
361
362 if (event.index == 0) {
363 setHeaderRowItemData(item);
364 return;
365 }
366
367 if (fTable.getData(Key.FILTER_OBJ) != null) {
368 if ((event.index == 1) || (event.index == (fTable.getItemCount() - 1))) {
369 setFilterStatusRowItemData(item);
370 return;
371 }
372 index = index - 1; // -1 for top filter status row
373 }
374
375 final CachedEvent cachedEvent = fCache.getEvent(index);
376 if (cachedEvent != null) {
377 setItemData(item, cachedEvent.event, cachedEvent.rank);
378 return;
379 }
380
381 // Else, fill the cache asynchronously (and off the UI thread)
382 event.doit = false;
383 }
384 });
385
386 fTable.addMouseListener(new MouseAdapter() {
387 @Override
388 public void mouseDoubleClick(final MouseEvent event) {
389 if (event.button != 1) {
390 return;
391 }
392 // Identify the selected row
393 final Point point = new Point(event.x, event.y);
394 final TableItem item = fTable.getItem(point);
395 if (item != null) {
396 final Rectangle imageBounds = item.getImageBounds(0);
397 imageBounds.width = BOOKMARK_IMAGE.getBounds().width;
398 if (imageBounds.contains(point)) {
399 final Long rank = (Long) item.getData(Key.RANK);
400 if (rank != null) {
401 toggleBookmark(rank);
402 }
403 }
404 }
405 }
406 });
407
408 final Listener tooltipListener = new Listener () {
409 Shell tooltipShell = null;
410 @Override
411 public void handleEvent(final Event event) {
412 switch (event.type) {
413 case SWT.MouseHover:
414 final TableItem item = fTable.getItem(new Point(event.x, event.y));
415 if (item == null) {
416 return;
417 }
418 final Long rank = (Long) item.getData(Key.RANK);
419 if (rank == null) {
420 return;
421 }
422 final String tooltipText = (String) item.getData(Key.BOOKMARK);
423 final Rectangle bounds = item.getImageBounds(0);
424 bounds.width = BOOKMARK_IMAGE.getBounds().width;
425 if (!bounds.contains(event.x,event.y)) {
426 return;
427 }
428 if ((tooltipShell != null) && !tooltipShell.isDisposed()) {
429 tooltipShell.dispose();
430 }
431 tooltipShell = new Shell(fTable.getShell(), SWT.ON_TOP | SWT.NO_FOCUS | SWT.TOOL);
432 tooltipShell.setBackground(PlatformUI.getWorkbench().getDisplay().getSystemColor(SWT.COLOR_INFO_BACKGROUND));
433 final FillLayout layout = new FillLayout();
434 layout.marginWidth = 2;
435 tooltipShell.setLayout(layout);
436 final Label label = new Label(tooltipShell, SWT.WRAP);
437 String text = rank.toString() + (tooltipText != null ? ": " + tooltipText : ""); //$NON-NLS-1$ //$NON-NLS-2$
438 label.setForeground(PlatformUI.getWorkbench().getDisplay().getSystemColor(SWT.COLOR_INFO_FOREGROUND));
439 label.setBackground(PlatformUI.getWorkbench().getDisplay().getSystemColor(SWT.COLOR_INFO_BACKGROUND));
440 label.setText(text);
441 label.addListener(SWT.MouseExit, this);
442 label.addListener(SWT.MouseDown, this);
443 label.addListener(SWT.MouseWheel, this);
444 final Point size = tooltipShell.computeSize(SWT.DEFAULT, SWT.DEFAULT);
445 /*
446 * Bug in Linux. The coordinates of the event have an origin that excludes the table header but
447 * the method toDisplay() expects coordinates relative to an origin that includes the table header.
448 */
449 int y = event.y;
450 if (System.getProperty("os.name").contains("Linux")) { //$NON-NLS-1$ //$NON-NLS-2$
451 y += fTable.getHeaderHeight();
452 }
453 Point pt = fTable.toDisplay(event.x, y);
454 pt.x += BOOKMARK_IMAGE.getBounds().width;
3be2946f 455 pt.y += item.getBounds().height;
db4721fb
PT
456 tooltipShell.setBounds(pt.x, pt.y, size.x, size.y);
457 tooltipShell.setVisible(true);
458 break;
459 case SWT.Dispose:
460 case SWT.KeyDown:
461 case SWT.MouseMove:
462 case SWT.MouseExit:
463 case SWT.MouseDown:
464 case SWT.MouseWheel:
465 if (tooltipShell != null) {
466 tooltipShell.dispose();
467 tooltipShell = null;
468 }
469 break;
470 default:
471 break;
472 }
473 }
474 };
475
476 fTable.addListener(SWT.MouseHover, tooltipListener);
477 fTable.addListener(SWT.Dispose, tooltipListener);
478 fTable.addListener(SWT.KeyDown, tooltipListener);
479 fTable.addListener(SWT.MouseMove, tooltipListener);
480 fTable.addListener(SWT.MouseExit, tooltipListener);
481 fTable.addListener(SWT.MouseDown, tooltipListener);
482 fTable.addListener(SWT.MouseWheel, tooltipListener);
483
484 // Create resources
485 createResources();
486
487 ColorSettingsManager.addColorSettingsListener(this);
488
489 fTable.setItemCount(1); // +1 for header row
490
491 fRawViewer = new TmfRawEventViewer(fSashForm, SWT.H_SCROLL | SWT.V_SCROLL);
492
493 fRawViewer.addSelectionListener(new Listener() {
494 @Override
495 public void handleEvent(final Event e) {
496 if (e.data instanceof Long) {
497 final long rank = (Long) e.data;
498 int index = (int) rank;
499 if (fTable.getData(Key.FILTER_OBJ) != null) {
500 index = fCache.getFilteredEventIndex(rank) + 1; // +1 for top filter status row
501 }
502 fTable.setSelection(index + 1); // +1 for header row
503 fSelectedRank = rank;
1e1bef82 504 } else if (e.data instanceof ITmfLocation) {
db4721fb
PT
505 // DOES NOT WORK: rank undefined in context from seekLocation()
506 // ITmfLocation<?> location = (ITmfLocation<?>) e.data;
507 // TmfContext context = fTrace.seekLocation(location);
508 // fTable.setSelection((int) context.getRank());
509 return;
510 } else {
511 return;
512 }
513 final TableItem[] selection = fTable.getSelection();
514 if ((selection != null) && (selection.length > 0)) {
515 final TmfTimestamp ts = (TmfTimestamp) fTable.getSelection()[0].getData(Key.TIMESTAMP);
516 if (ts != null) {
517 broadcast(new TmfTimeSynchSignal(TmfEventsTable.this, ts));
518 }
519 }
520 }
521 });
522
523 fSashForm.setWeights(new int[] { 1, 1 });
524 fRawViewer.setVisible(false);
525
526 createPopupMenu();
527 }
528
a0a88f65
AM
529 /**
530 * Create a pop-up menu.
531 */
db4721fb
PT
532 protected void createPopupMenu() {
533 final IAction showTableAction = new Action(Messages.TmfEventsTable_ShowTableActionText) {
534 @Override
535 public void run() {
536 fTable.setVisible(true);
537 fSashForm.layout();
538 }
539 };
540
541 final IAction hideTableAction = new Action(Messages.TmfEventsTable_HideTableActionText) {
542 @Override
543 public void run() {
544 fTable.setVisible(false);
545 fSashForm.layout();
546 }
547 };
548
549 final IAction showRawAction = new Action(Messages.TmfEventsTable_ShowRawActionText) {
550 @Override
551 public void run() {
552 fRawViewer.setVisible(true);
553 fSashForm.layout();
554 final int index = fTable.getSelectionIndex();
555 if (index >= +1) {
556 fRawViewer.selectAndReveal(index - 1);
557 }
558 }
559 };
560
561 final IAction hideRawAction = new Action(Messages.TmfEventsTable_HideRawActionText) {
562 @Override
563 public void run() {
564 fRawViewer.setVisible(false);
565 fSashForm.layout();
566 }
567 };
568
569 final IAction showSearchBarAction = new Action(Messages.TmfEventsTable_ShowSearchBarActionText) {
570 @Override
571 public void run() {
572 fHeaderState = HeaderState.SEARCH;
573 fTable.refresh();
574 }
575 };
576
577 final IAction showFilterBarAction = new Action(Messages.TmfEventsTable_ShowFilterBarActionText) {
578 @Override
579 public void run() {
580 fHeaderState = HeaderState.FILTER;
581 fTable.refresh();
582 }
583 };
584
585 final IAction clearFiltersAction = new Action(Messages.TmfEventsTable_ClearFiltersActionText) {
586 @Override
587 public void run() {
588 clearFilters();
589 }
590 };
591
592 class ToggleBookmarkAction extends Action {
593 long fRank;
594
595 public ToggleBookmarkAction(final String text, final long rank) {
596 super(text);
597 fRank = rank;
598 }
599
600 @Override
601 public void run() {
602 toggleBookmark(fRank);
603 }
604 }
605
606 final MenuManager tablePopupMenu = new MenuManager();
607 tablePopupMenu.setRemoveAllWhenShown(true);
608 tablePopupMenu.addMenuListener(new IMenuListener() {
609 @Override
610 public void menuAboutToShow(final IMenuManager manager) {
611 if (fTable.getSelectionIndex() == 0) {
612 // Right-click on header row
613 if (fHeaderState == HeaderState.FILTER) {
614 tablePopupMenu.add(showSearchBarAction);
615 } else {
616 tablePopupMenu.add(showFilterBarAction);
617 }
618 return;
619 }
620 final Point point = fTable.toControl(Display.getDefault().getCursorLocation());
621 final TableItem item = fTable.getSelection().length > 0 ? fTable.getSelection()[0] : null;
622 if (item != null) {
623 final Rectangle imageBounds = item.getImageBounds(0);
624 imageBounds.width = BOOKMARK_IMAGE.getBounds().width;
625 if (point.x <= (imageBounds.x + imageBounds.width)) {
626 // Right-click on left margin
627 final Long rank = (Long) item.getData(Key.RANK);
628 if ((rank != null) && (fBookmarksFile != null)) {
629 if (fBookmarksMap.containsKey(rank)) {
630 tablePopupMenu.add(new ToggleBookmarkAction(
631 Messages.TmfEventsTable_RemoveBookmarkActionText, rank));
632 } else {
633 tablePopupMenu.add(new ToggleBookmarkAction(
634 Messages.TmfEventsTable_AddBookmarkActionText, rank));
635 }
636 }
637 return;
638 }
639 }
640 // Right-click on table
641 if (fTable.isVisible() && fRawViewer.isVisible()) {
642 tablePopupMenu.add(hideTableAction);
643 tablePopupMenu.add(hideRawAction);
644 } else if (!fTable.isVisible()) {
645 tablePopupMenu.add(showTableAction);
646 } else if (!fRawViewer.isVisible()) {
647 tablePopupMenu.add(showRawAction);
648 }
649 tablePopupMenu.add(new Separator());
650 tablePopupMenu.add(clearFiltersAction);
651 final ITmfFilterTreeNode[] savedFilters = FilterManager.getSavedFilters();
652 if (savedFilters.length > 0) {
653 final MenuManager subMenu = new MenuManager(Messages.TmfEventsTable_ApplyPresetFilterMenuName);
654 for (final ITmfFilterTreeNode node : savedFilters) {
655 if (node instanceof TmfFilterNode) {
656 final TmfFilterNode filter = (TmfFilterNode) node;
657 subMenu.add(new Action(filter.getFilterName()) {
658 @Override
659 public void run() {
660 applyFilter(filter);
661 }
662 });
663 }
664 }
665 tablePopupMenu.add(subMenu);
666 }
667 appendToTablePopupMenu(tablePopupMenu, item);
668 }
669 });
670
671 final MenuManager rawViewerPopupMenu = new MenuManager();
672 rawViewerPopupMenu.setRemoveAllWhenShown(true);
673 rawViewerPopupMenu.addMenuListener(new IMenuListener() {
674 @Override
675 public void menuAboutToShow(final IMenuManager manager) {
676 if (fTable.isVisible() && fRawViewer.isVisible()) {
677 rawViewerPopupMenu.add(hideTableAction);
678 rawViewerPopupMenu.add(hideRawAction);
679 } else if (!fTable.isVisible()) {
680 rawViewerPopupMenu.add(showTableAction);
681 } else if (!fRawViewer.isVisible()) {
682 rawViewerPopupMenu.add(showRawAction);
683 }
684 appendToRawPopupMenu(tablePopupMenu);
685 }
686 });
687
688 Menu menu = tablePopupMenu.createContextMenu(fTable);
689 fTable.setMenu(menu);
690
691 menu = rawViewerPopupMenu.createContextMenu(fRawViewer);
692 fRawViewer.setMenu(menu);
693 }
694
f8177ba2 695
a0a88f65
AM
696 /**
697 * Append an item to the event table's pop-up menu.
698 *
699 * @param tablePopupMenu
700 * The menu manager
701 * @param selectedItem
702 * The item to append
703 */
db4721fb
PT
704 protected void appendToTablePopupMenu(final MenuManager tablePopupMenu, final TableItem selectedItem) {
705 // override to append more actions
706 }
707
a0a88f65
AM
708 /**
709 * Append an item to the raw viewer's pop-up menu.
710 *
711 * @param rawViewerPopupMenu
712 * The menu manager
713 */
db4721fb
PT
714 protected void appendToRawPopupMenu(final MenuManager rawViewerPopupMenu) {
715 // override to append more actions
716 }
717
718 @Override
719 public void dispose() {
720 stopSearchThread();
721 stopFilterThread();
722 ColorSettingsManager.removeColorSettingsListener(this);
723 fComposite.dispose();
724 if ((fTrace != null) && fDisposeOnClose) {
725 fTrace.dispose();
726 }
727 fResourceManager.dispose();
728 super.dispose();
729 }
730
731 /**
732 * Assign a layout data object to this view.
733 *
734 * @param layoutData
735 * The layout data to assign
736 */
737 public void setLayoutData(final Object layoutData) {
738 fComposite.setLayoutData(layoutData);
739 }
740
741 /**
742 * Get the virtual table contained in this event table.
743 *
744 * @return The TMF virtual table
745 */
746 public TmfVirtualTable getTable() {
747 return fTable;
748 }
749
750 /**
751 * @param columnData
752 *
753 * FIXME: Add support for column selection
754 */
755 protected void setColumnHeaders(final ColumnData[] columnData) {
756 fTable.setColumnHeaders(columnData);
757 }
758
a0a88f65
AM
759 /**
760 * Set a table item's data.
761 *
762 * @param item
763 * The item to set
764 * @param event
765 * Which trace event to link with this entry
766 * @param rank
767 * Which rank this event has in the trace/experiment
768 */
db4721fb
PT
769 protected void setItemData(final TableItem item, final ITmfEvent event, final long rank) {
770 final ITmfEventField[] fields = extractItemFields(event);
771 final String[] content = new String[fields.length];
772 for (int i = 0; i < fields.length; i++) {
773 content[i] = fields[i].getValue() != null ? fields[i].getValue().toString() : ""; //$NON-NLS-1$
774 }
775 item.setText(content);
93bfd50a 776 item.setData(event);
db4721fb
PT
777 item.setData(Key.TIMESTAMP, new TmfTimestamp(event.getTimestamp()));
778 item.setData(Key.RANK, rank);
779
780 boolean bookmark = false;
781 final Long markerId = fBookmarksMap.get(rank);
782 if (markerId != null) {
783 bookmark = true;
784 try {
785 final IMarker marker = fBookmarksFile.findMarker(markerId);
786 item.setData(Key.BOOKMARK, marker.getAttribute(IMarker.MESSAGE));
787 } catch (final CoreException e) {
788 displayException(e);
789 }
790 } else {
791 item.setData(Key.BOOKMARK, null);
792 }
793
794 boolean searchMatch = false;
795 boolean searchNoMatch = false;
796 final ITmfFilter searchFilter = (ITmfFilter) fTable.getData(Key.SEARCH_OBJ);
797 if (searchFilter != null) {
798 if (searchFilter.matches(event)) {
799 searchMatch = true;
800 } else {
801 searchNoMatch = true;
802 }
803 }
804
805 final ColorSetting colorSetting = ColorSettingsManager.getColorSetting(event);
806 if (searchNoMatch) {
807 item.setForeground(colorSetting.getDimmedForegroundColor());
808 item.setBackground(colorSetting.getDimmedBackgroundColor());
809 } else {
810 item.setForeground(colorSetting.getForegroundColor());
811 item.setBackground(colorSetting.getBackgroundColor());
812 }
813
814 if (searchMatch) {
815 if (bookmark) {
816 item.setImage(SEARCH_MATCH_BOOKMARK_IMAGE);
817 } else {
818 item.setImage(SEARCH_MATCH_IMAGE);
819 }
820 } else if (bookmark) {
821 item.setImage(BOOKMARK_IMAGE);
822 } else {
823 item.setImage((Image) null);
824 }
825 }
826
a0a88f65
AM
827 /**
828 * Set the item data of the header row.
829 *
830 * @param item
831 * The item to use as table header
832 */
db4721fb
PT
833 protected void setHeaderRowItemData(final TableItem item) {
834 String txtKey = null;
835 if (fHeaderState == HeaderState.SEARCH) {
836 item.setImage(SEARCH_IMAGE);
837 txtKey = Key.SEARCH_TXT;
838 } else if (fHeaderState == HeaderState.FILTER) {
839 item.setImage(FILTER_IMAGE);
840 txtKey = Key.FILTER_TXT;
841 }
842 item.setForeground(fGrayColor);
843 for (int i = 0; i < fTable.getColumns().length; i++) {
844 final TableColumn column = fTable.getColumns()[i];
845 final String filter = (String) column.getData(txtKey);
846 if (filter == null) {
847 if (fHeaderState == HeaderState.SEARCH) {
848 item.setText(i, SEARCH_HINT);
849 } else if (fHeaderState == HeaderState.FILTER) {
850 item.setText(i, FILTER_HINT);
851 }
852 item.setForeground(i, fGrayColor);
853 item.setFont(i, fTable.getFont());
854 } else {
855 item.setText(i, filter);
856 item.setForeground(i, fGreenColor);
857 item.setFont(i, fBoldFont);
858 }
859 }
860 }
861
a0a88f65
AM
862 /**
863 * Set the item data of the "filter status" row.
864 *
865 * @param item
866 * The item to use as filter status row
867 */
db4721fb
PT
868 protected void setFilterStatusRowItemData(final TableItem item) {
869 for (int i = 0; i < fTable.getColumns().length; i++) {
870 if (i == 0) {
871 if ((fTrace == null) || (fFilterCheckCount == fTrace.getNbEvents())) {
872 item.setImage(FILTER_IMAGE);
873 } else {
874 item.setImage(STOP_IMAGE);
875 }
876 item.setText(0, fFilterMatchCount + "/" + fFilterCheckCount); //$NON-NLS-1$
877 } else {
878 item.setText(i, ""); //$NON-NLS-1$
879 }
880 }
93bfd50a 881 item.setData(null);
db4721fb
PT
882 item.setData(Key.TIMESTAMP, null);
883 item.setData(Key.RANK, null);
884 item.setForeground(null);
885 item.setBackground(null);
886 }
887
a0a88f65
AM
888 /**
889 * Create an editor for the header.
890 */
db4721fb
PT
891 protected void createHeaderEditor() {
892 final TableEditor tableEditor = fTable.createTableEditor();
893 tableEditor.horizontalAlignment = SWT.LEFT;
894 tableEditor.verticalAlignment = SWT.CENTER;
895 tableEditor.grabHorizontal = true;
896 tableEditor.minimumWidth = 50;
897
898 // Handle the header row selection
899 fTable.addMouseListener(new MouseAdapter() {
900 int columnIndex;
901 TableColumn column;
902 TableItem item;
903
904 @Override
905 public void mouseDown(final MouseEvent event) {
906 if (event.button != 1) {
907 return;
908 }
909 // Identify the selected row
910 final Point point = new Point(event.x, event.y);
911 item = fTable.getItem(point);
912
913 // Header row selected
914 if ((item != null) && (fTable.indexOf(item) == 0)) {
915
916 // Icon selected
917 if (item.getImageBounds(0).contains(point)) {
918 if (fHeaderState == HeaderState.SEARCH) {
919 fHeaderState = HeaderState.FILTER;
920 } else if (fHeaderState == HeaderState.FILTER) {
921 fHeaderState = HeaderState.SEARCH;
922 }
923 fTable.refresh();
924 return;
925 }
926
927 // Identify the selected column
928 columnIndex = -1;
929 for (int i = 0; i < fTable.getColumns().length; i++) {
930 final Rectangle rect = item.getBounds(i);
931 if (rect.contains(point)) {
932 columnIndex = i;
933 break;
934 }
935 }
936
937 if (columnIndex == -1) {
938 return;
939 }
940
941 column = fTable.getColumns()[columnIndex];
942
943 String txtKey = null;
944 if (fHeaderState == HeaderState.SEARCH) {
945 txtKey = Key.SEARCH_TXT;
946 } else if (fHeaderState == HeaderState.FILTER) {
947 txtKey = Key.FILTER_TXT;
948 }
949
950 // The control that will be the editor must be a child of the Table
951 final Text newEditor = (Text) fTable.createTableEditorControl(Text.class);
952 final String headerString = (String) column.getData(txtKey);
953 if (headerString != null) {
954 newEditor.setText(headerString);
955 }
956 newEditor.addFocusListener(new FocusAdapter() {
957 @Override
958 public void focusLost(final FocusEvent e) {
959 final boolean changed = updateHeader(newEditor.getText());
960 if (changed) {
961 applyHeader();
962 }
963 }
964 });
965 newEditor.addKeyListener(new KeyAdapter() {
966 @Override
967 public void keyPressed(final KeyEvent e) {
968 if (e.character == SWT.CR) {
969 updateHeader(newEditor.getText());
970 applyHeader();
971 } else if (e.character == SWT.ESC) {
972 tableEditor.getEditor().dispose();
973 }
974 }
975 });
976 newEditor.selectAll();
977 newEditor.setFocus();
978 tableEditor.setEditor(newEditor, item, columnIndex);
979 }
980 }
981
982 /*
983 * returns true is value was changed
984 */
985 private boolean updateHeader(final String text) {
986 String objKey = null;
987 String txtKey = null;
988 if (fHeaderState == HeaderState.SEARCH) {
989 objKey = Key.SEARCH_OBJ;
990 txtKey = Key.SEARCH_TXT;
991 } else if (fHeaderState == HeaderState.FILTER) {
992 objKey = Key.FILTER_OBJ;
993 txtKey = Key.FILTER_TXT;
994 }
995 if (text.trim().length() > 0) {
996 try {
997 final String regex = TmfFilterMatchesNode.regexFix(text);
998 Pattern.compile(regex);
999 if (regex.equals(column.getData(txtKey))) {
1000 tableEditor.getEditor().dispose();
1001 return false;
1002 }
1003 final TmfFilterMatchesNode filter = new TmfFilterMatchesNode(null);
1004 String fieldId = (String) column.getData(Key.FIELD_ID);
1005 if (fieldId == null) {
1006 fieldId = column.getText();
1007 }
1008 filter.setField(fieldId);
1009 filter.setRegex(regex);
1010 column.setData(objKey, filter);
1011 column.setData(txtKey, regex);
1012 } catch (final PatternSyntaxException ex) {
1013 tableEditor.getEditor().dispose();
1014 MessageDialog.openError(PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell(),
1015 ex.getDescription(), ex.getMessage());
1016 return false;
1017 }
1018 } else {
1019 if (column.getData(txtKey) == null) {
1020 tableEditor.getEditor().dispose();
1021 return false;
1022 }
1023 column.setData(objKey, null);
1024 column.setData(txtKey, null);
1025 }
1026 return true;
1027 }
1028
1029 private void applyHeader() {
1030 if (fHeaderState == HeaderState.SEARCH) {
1031 stopSearchThread();
1032 final TmfFilterAndNode filter = new TmfFilterAndNode(null);
3dca7aa5
AM
1033 for (final TableColumn col : fTable.getColumns()) {
1034 final Object filterObj = col.getData(Key.SEARCH_OBJ);
db4721fb
PT
1035 if (filterObj instanceof ITmfFilterTreeNode) {
1036 filter.addChild((ITmfFilterTreeNode) filterObj);
1037 }
1038 }
1039 if (filter.getChildrenCount() > 0) {
1040 fTable.setData(Key.SEARCH_OBJ, filter);
1041 fTable.refresh();
1042 searchNext();
1043 fireSearchApplied(filter);
1044 } else {
1045 fTable.setData(Key.SEARCH_OBJ, null);
1046 fTable.refresh();
1047 fireSearchApplied(null);
1048 }
1049 } else if (fHeaderState == HeaderState.FILTER) {
1050 final TmfFilterAndNode filter = new TmfFilterAndNode(null);
3dca7aa5
AM
1051 for (final TableColumn col : fTable.getColumns()) {
1052 final Object filterObj = col.getData(Key.FILTER_OBJ);
db4721fb
PT
1053 if (filterObj instanceof ITmfFilterTreeNode) {
1054 filter.addChild((ITmfFilterTreeNode) filterObj);
1055 }
1056 }
1057 if (filter.getChildrenCount() > 0) {
1058 applyFilter(filter);
1059 } else {
1060 clearFilters();
1061 }
1062 }
1063
1064 tableEditor.getEditor().dispose();
1065 }
1066 });
1067
1068 fTable.addKeyListener(new KeyAdapter() {
1069 @Override
1070 public void keyPressed(final KeyEvent e) {
1071 e.doit = false;
1072 if (e.character == SWT.ESC) {
1073 stopFilterThread();
1074 stopSearchThread();
1075 fTable.refresh();
1076 } else if (e.character == SWT.DEL) {
1077 if (fHeaderState == HeaderState.SEARCH) {
1078 stopSearchThread();
1079 for (final TableColumn column : fTable.getColumns()) {
1080 column.setData(Key.SEARCH_OBJ, null);
1081 column.setData(Key.SEARCH_TXT, null);
1082 }
1083 fTable.setData(Key.SEARCH_OBJ, null);
1084 fTable.refresh();
1085 fireSearchApplied(null);
1086 } else if (fHeaderState == HeaderState.FILTER) {
1087 clearFilters();
1088 }
1089 } else if (e.character == SWT.CR) {
1090 if ((e.stateMask & SWT.SHIFT) == 0) {
1091 searchNext();
1092 } else {
1093 searchPrevious();
1094 }
1095 }
1096 }
1097 });
1098 }
1099
a0a88f65
AM
1100 /**
1101 * Send an event indicating a filter has been applied.
1102 *
1103 * @param filter
1104 * The filter that was just applied
1105 */
db4721fb 1106 protected void fireFilterApplied(final ITmfFilter filter) {
faa38350 1107 broadcast(new TmfEventFilterAppliedSignal(this, fTrace, filter));
db4721fb
PT
1108 }
1109
a0a88f65
AM
1110 /**
1111 * Send an event indicating that a search has been applied.
1112 *
1113 * @param filter
1114 * The search filter that was just applied
1115 */
db4721fb 1116 protected void fireSearchApplied(final ITmfFilter filter) {
faa38350 1117 broadcast(new TmfEventSearchAppliedSignal(this, fTrace, filter));
db4721fb
PT
1118 }
1119
a0a88f65
AM
1120 /**
1121 * Start the filtering thread.
1122 */
db4721fb
PT
1123 protected void startFilterThread() {
1124 synchronized (fFilterSyncObj) {
1125 final ITmfFilterTreeNode filter = (ITmfFilterTreeNode) fTable.getData(Key.FILTER_OBJ);
1126 if (fFilterThread == null || fFilterThread.filter != filter) {
1127 if (fFilterThread != null) {
1128 fFilterThread.cancel();
1129 fFilterThreadResume = false;
1130 }
1131 fFilterThread = new FilterThread(filter);
1132 fFilterThread.start();
1133 } else {
1134 fFilterThreadResume = true;
1135 }
1136 }
1137 }
1138
a0a88f65
AM
1139 /**
1140 * Stop the filtering thread.
1141 */
db4721fb
PT
1142 protected void stopFilterThread() {
1143 synchronized (fFilterSyncObj) {
1144 if (fFilterThread != null) {
1145 fFilterThread.cancel();
1146 fFilterThread = null;
1147 fFilterThreadResume = false;
1148 }
1149 }
1150 }
1151
1152 /**
a0a88f65
AM
1153 * Apply a filter.
1154 *
1155 * @param filter
1156 * The filter to apply
db4721fb
PT
1157 * @since 1.1
1158 */
1159 protected void applyFilter(ITmfFilter filter) {
f29f8868
BH
1160 stopFilterThread();
1161 stopSearchThread();
db4721fb
PT
1162 fFilterMatchCount = 0;
1163 fFilterCheckCount = 0;
1164 fCache.applyFilter(filter);
1165 fTable.clearAll();
1166 fTable.setData(Key.FILTER_OBJ, filter);
1167 fTable.setItemCount(3); // +1 for header row, +2 for top and bottom filter status rows
1168 startFilterThread();
1169 fireFilterApplied(filter);
1170 }
1171
a0a88f65
AM
1172 /**
1173 * Clear all currently active filters.
1174 */
db4721fb
PT
1175 protected void clearFilters() {
1176 if (fTable.getData(Key.FILTER_OBJ) == null) {
1177 return;
1178 }
1179 stopFilterThread();
1180 stopSearchThread();
1181 fCache.clearFilter();
1182 fTable.clearAll();
1183 for (final TableColumn column : fTable.getColumns()) {
1184 column.setData(Key.FILTER_OBJ, null);
1185 column.setData(Key.FILTER_TXT, null);
1186 }
1187 fTable.setData(Key.FILTER_OBJ, null);
1188 if (fTrace != null) {
1189 fTable.setItemCount((int) fTrace.getNbEvents() + 1); // +1 for header row
1190 } else {
1191 fTable.setItemCount(1); // +1 for header row
1192 }
1193 fFilterMatchCount = 0;
1194 fFilterCheckCount = 0;
1195 if (fSelectedRank >= 0) {
1196 fTable.setSelection((int) fSelectedRank + 1); // +1 for header row
1197 } else {
1198 fTable.setSelection(0);
1199 }
1200 fireFilterApplied(null);
1201 }
1202
a0a88f65
AM
1203 /**
1204 * Wrapper Thread object for the filtering thread.
1205 */
db4721fb
PT
1206 protected class FilterThread extends Thread {
1207 private final ITmfFilterTreeNode filter;
1208 private TmfDataRequest request;
1209 private boolean refreshBusy = false;
1210 private boolean refreshPending = false;
1211 private final Object syncObj = new Object();
1212
a0a88f65
AM
1213 /**
1214 * Constructor.
1215 *
1216 * @param filter
1217 * The filter this thread will be processing
1218 */
db4721fb
PT
1219 public FilterThread(final ITmfFilterTreeNode filter) {
1220 super("Filter Thread"); //$NON-NLS-1$
1221 this.filter = filter;
1222 }
1223
1224 @Override
1225 public void run() {
1226 if (fTrace == null) {
1227 return;
1228 }
1229 final int nbRequested = (int) (fTrace.getNbEvents() - fFilterCheckCount);
1230 if (nbRequested <= 0) {
1231 return;
1232 }
1233 request = new TmfDataRequest(ITmfEvent.class, (int) fFilterCheckCount,
1234 nbRequested, fTrace.getCacheSize(), ExecutionType.BACKGROUND) {
1235 @Override
1236 public void handleData(final ITmfEvent event) {
1237 super.handleData(event);
1238 if (request.isCancelled()) {
1239 return;
1240 }
1241 if (filter.matches(event)) {
1242 final long rank = fFilterCheckCount;
1243 final int index = (int) fFilterMatchCount;
1244 fFilterMatchCount++;
1245 fCache.storeEvent(event.clone(), rank, index);
1246 refreshTable();
1247 } else if ((fFilterCheckCount % 100) == 0) {
1248 refreshTable();
1249 }
1250 fFilterCheckCount++;
1251 }
1252 };
1253 ((ITmfDataProvider) fTrace).sendRequest(request);
1254 try {
1255 request.waitForCompletion();
1256 } catch (final InterruptedException e) {
1257 }
1258 refreshTable();
1259 synchronized (fFilterSyncObj) {
1260 fFilterThread = null;
1261 if (fFilterThreadResume) {
1262 fFilterThreadResume = false;
1263 fFilterThread = new FilterThread(filter);
1264 fFilterThread.start();
1265 }
1266 }
1267 }
1268
a0a88f65
AM
1269 /**
1270 * Refresh the filter.
1271 */
db4721fb
PT
1272 public void refreshTable() {
1273 synchronized (syncObj) {
1274 if (refreshBusy) {
1275 refreshPending = true;
1276 return;
1277 }
1278 refreshBusy = true;
1279 }
1280 Display.getDefault().asyncExec(new Runnable() {
1281 @Override
1282 public void run() {
1283 if (request.isCancelled()) {
1284 return;
1285 }
1286 if (fTable.isDisposed()) {
1287 return;
1288 }
1289 fTable.setItemCount((int) fFilterMatchCount + 3); // +1 for header row, +2 for top and bottom filter status rows
1290 fTable.refresh();
1291 synchronized (syncObj) {
1292 refreshBusy = false;
1293 if (refreshPending) {
1294 refreshPending = false;
1295 refreshTable();
1296 }
1297 }
1298 }
1299 });
1300 }
1301
a0a88f65
AM
1302 /**
1303 * Cancel this filtering thread.
1304 */
db4721fb
PT
1305 public void cancel() {
1306 if (request != null) {
1307 request.cancel();
1308 }
1309 }
1310 }
1311
a0a88f65
AM
1312 /**
1313 * Go to the next item of a search.
1314 */
db4721fb
PT
1315 protected void searchNext() {
1316 synchronized (fSearchSyncObj) {
1317 if (fSearchThread != null) {
1318 return;
1319 }
1320 final ITmfFilterTreeNode searchFilter = (ITmfFilterTreeNode) fTable.getData(Key.SEARCH_OBJ);
1321 if (searchFilter == null) {
1322 return;
1323 }
1324 final int selectionIndex = fTable.getSelectionIndex();
1325 int startIndex;
1326 if (selectionIndex > 0) {
1327 startIndex = selectionIndex; // -1 for header row, +1 for next event
1328 } else {
1329 // header row is selected, start at top event
1330 startIndex = Math.max(0, fTable.getTopIndex() - 1); // -1 for header row
1331 }
1332 final ITmfFilterTreeNode eventFilter = (ITmfFilterTreeNode) fTable.getData(Key.FILTER_OBJ);
1333 if (eventFilter != null)
1334 {
1335 startIndex = Math.max(0, startIndex - 1); // -1 for top filter status row
1336 }
1337 fSearchThread = new SearchThread(searchFilter, eventFilter, startIndex, fSelectedRank, Direction.FORWARD);
1338 fSearchThread.schedule();
1339 }
1340 }
1341
a0a88f65
AM
1342 /**
1343 * Go to the previous item of a search.
1344 */
db4721fb
PT
1345 protected void searchPrevious() {
1346 synchronized (fSearchSyncObj) {
1347 if (fSearchThread != null) {
1348 return;
1349 }
1350 final ITmfFilterTreeNode searchFilter = (ITmfFilterTreeNode) fTable.getData(Key.SEARCH_OBJ);
1351 if (searchFilter == null) {
1352 return;
1353 }
1354 final int selectionIndex = fTable.getSelectionIndex();
1355 int startIndex;
1356 if (selectionIndex > 0) {
1357 startIndex = selectionIndex - 2; // -1 for header row, -1 for previous event
1358 } else {
1359 // header row is selected, start at precedent of top event
1360 startIndex = fTable.getTopIndex() - 2; // -1 for header row, -1 for previous event
1361 }
1362 final ITmfFilterTreeNode eventFilter = (ITmfFilterTreeNode) fTable.getData(Key.FILTER_OBJ);
1363 if (eventFilter != null)
1364 {
1365 startIndex = startIndex - 1; // -1 for top filter status row
1366 }
1367 fSearchThread = new SearchThread(searchFilter, eventFilter, startIndex, fSelectedRank, Direction.BACKWARD);
1368 fSearchThread.schedule();
1369 }
1370 }
1371
a0a88f65
AM
1372 /**
1373 * Stop the search thread.
1374 */
db4721fb
PT
1375 protected void stopSearchThread() {
1376 fPendingGotoRank = -1;
1377 synchronized (fSearchSyncObj) {
1378 if (fSearchThread != null) {
1379 fSearchThread.cancel();
1380 fSearchThread = null;
1381 }
1382 }
1383 }
1384
a0a88f65
AM
1385 /**
1386 * Wrapper for the search thread.
1387 */
db4721fb 1388 protected class SearchThread extends Job {
a0a88f65
AM
1389
1390 private ITmfFilterTreeNode searchFilter;
1391 private ITmfFilterTreeNode eventFilter;
1392 private int startIndex;
1393 private int direction;
1394 private long rank;
1395 private long foundRank = -1;
1396 private TmfDataRequest request;
ae3ffd37 1397 private ITmfTimestamp foundTimestamp = null;
db4721fb 1398
a0a88f65
AM
1399 /**
1400 * Constructor.
1401 *
1402 * @param searchFilter
1403 * The search filter
1404 * @param eventFilter
1405 * The event filter
1406 * @param startIndex
1407 * The index at which we should start searching
1408 * @param currentRank
1409 * The current rank
1410 * @param direction
1411 * In which direction should we search, forward or backwards
1412 */
1413 public SearchThread(final ITmfFilterTreeNode searchFilter,
1414 final ITmfFilterTreeNode eventFilter, final int startIndex,
db4721fb
PT
1415 final long currentRank, final int direction) {
1416 super(Messages.TmfEventsTable_SearchingJobName);
1417 this.searchFilter = searchFilter;
1418 this.eventFilter = eventFilter;
1419 this.startIndex = startIndex;
1420 this.rank = currentRank;
1421 this.direction = direction;
1422 }
1423
1424 @Override
1425 protected IStatus run(final IProgressMonitor monitor) {
1426 if (fTrace == null) {
1427 return Status.OK_STATUS;
1428 }
1429 final Display display = Display.getDefault();
1430 if (startIndex < 0) {
1431 rank = (int) fTrace.getNbEvents() - 1;
1432 } else if (startIndex >= (fTable.getItemCount() - (eventFilter == null ? 1 : 3))) { // -1 for header row, -2 for top and bottom filter status rows
1433 rank = 0;
1434 } else {
1435 int idx = startIndex;
1436 while (foundRank == -1) {
1437 final CachedEvent event = fCache.peekEvent(idx);
1438 if (event == null) {
1439 break;
1440 }
1441 rank = event.rank;
1442 if (searchFilter.matches(event.event) && ((eventFilter == null) || eventFilter.matches(event.event))) {
1443 foundRank = event.rank;
ae3ffd37 1444 foundTimestamp = event.event.getTimestamp();
db4721fb
PT
1445 break;
1446 }
1447 if (direction == Direction.FORWARD) {
1448 idx++;
1449 } else {
1450 idx--;
1451 }
1452 }
1453 if (foundRank == -1) {
1454 if (direction == Direction.FORWARD) {
1455 rank++;
1456 if (rank > (fTrace.getNbEvents() - 1)) {
1457 rank = 0;
1458 }
1459 } else {
1460 rank--;
1461 if (rank < 0) {
1462 rank = (int) fTrace.getNbEvents() - 1;
1463 }
1464 }
1465 }
1466 }
1467 final int startRank = (int) rank;
1468 boolean wrapped = false;
1469 while (!monitor.isCanceled() && (foundRank == -1) && (fTrace != null)) {
1470 int nbRequested = (direction == Direction.FORWARD ? Integer.MAX_VALUE : Math.min((int) rank + 1, fTrace.getCacheSize()));
1471 if (direction == Direction.BACKWARD) {
1472 rank = Math.max(0, rank - fTrace.getCacheSize() + 1);
1473 }
1474 request = new TmfDataRequest(ITmfEvent.class, (int) rank, nbRequested, fTrace.getCacheSize(), ExecutionType.BACKGROUND) {
1475 long currentRank = rank;
1476
1477 @Override
1478 public void handleData(final ITmfEvent event) {
1479 super.handleData(event);
1480 if (searchFilter.matches(event) && ((eventFilter == null) || eventFilter.matches(event))) {
1481 foundRank = currentRank;
ae3ffd37 1482 foundTimestamp = event.getTimestamp();
db4721fb
PT
1483 if (direction == Direction.FORWARD) {
1484 done();
1485 return;
1486 }
1487 }
1488 currentRank++;
1489 }
1490 };
1491 ((ITmfDataProvider) fTrace).sendRequest(request);
1492 try {
1493 request.waitForCompletion();
1494 if (request.isCancelled()) {
1495 return Status.OK_STATUS;
1496 }
1497 } catch (final InterruptedException e) {
1498 synchronized (fSearchSyncObj) {
1499 fSearchThread = null;
1500 }
1501 return Status.OK_STATUS;
1502 }
1503 if (foundRank == -1) {
1504 if (direction == Direction.FORWARD) {
1505 if (rank == 0) {
1506 synchronized (fSearchSyncObj) {
1507 fSearchThread = null;
1508 }
1509 return Status.OK_STATUS;
1510 }
1511 nbRequested = (int) rank;
1512 rank = 0;
1513 wrapped = true;
1514 } else {
1515 rank--;
1516 if (rank < 0) {
1517 rank = (int) fTrace.getNbEvents() - 1;
1518 wrapped = true;
1519 }
1520 if ((rank <= startRank) && wrapped) {
1521 synchronized (fSearchSyncObj) {
1522 fSearchThread = null;
1523 }
1524 return Status.OK_STATUS;
1525 }
1526 }
1527 }
1528 }
1529 int index = (int) foundRank;
1530 if (eventFilter != null) {
1531 index = fCache.getFilteredEventIndex(foundRank);
1532 }
1533 final int selection = index + 1 + (eventFilter != null ? +1 : 0); // +1 for header row, +1 for top filter status row
1534
1535 display.asyncExec(new Runnable() {
1536 @Override
1537 public void run() {
1538 if (monitor.isCanceled()) {
1539 return;
1540 }
1541 if (fTable.isDisposed()) {
1542 return;
1543 }
1544 fTable.setSelection(selection);
1545 fSelectedRank = foundRank;
ae3ffd37
PT
1546 fRawViewer.selectAndReveal(fSelectedRank);
1547 if (foundTimestamp != null) {
1548 broadcast(new TmfTimeSynchSignal(TmfEventsTable.this, foundTimestamp));
1549 }
db4721fb
PT
1550 synchronized (fSearchSyncObj) {
1551 fSearchThread = null;
1552 }
1553 }
1554 });
1555 return Status.OK_STATUS;
1556 }
1557
1558 @Override
1559 protected void canceling() {
1560 request.cancel();
1561 synchronized (fSearchSyncObj) {
1562 fSearchThread = null;
1563 }
1564 }
1565 }
1566
a0a88f65
AM
1567 /**
1568 * Create the resources.
1569 */
db4721fb
PT
1570 protected void createResources() {
1571 fGrayColor = fResourceManager.createColor(ColorUtil.blend(fTable.getBackground().getRGB(), fTable
1572 .getForeground().getRGB()));
1573 fGreenColor = fTable.getDisplay().getSystemColor(SWT.COLOR_DARK_GREEN);
1574 fBoldFont = fResourceManager.createFont(FontDescriptor.createFrom(fTable.getFont()).setStyle(SWT.BOLD));
1575 }
1576
a0a88f65
AM
1577 /**
1578 * Pack the columns.
1579 */
db4721fb
PT
1580 protected void packColumns() {
1581 if (fPackDone) {
1582 return;
1583 }
f29f8868
BH
1584 boolean isLinux = System.getProperty("os.name").contains("Linux") ? true : false; //$NON-NLS-1$ //$NON-NLS-2$
1585
1586 TableColumn tableColumns[] = fTable.getColumns();
1587 for (int i = 0; i < tableColumns.length; i++) {
1588 final TableColumn column = tableColumns[i];
db4721fb
PT
1589 final int headerWidth = column.getWidth();
1590 column.pack();
f29f8868
BH
1591 // Workaround for Linux which doesn't consider the image width of
1592 // search/filter row in TableColumn.pack() after having executed
1593 // TableItem.setImage((Image)null) for other rows than search/filter row.
1594 if (isLinux && (i == 0)) {
1595 column.setWidth(column.getWidth() + SEARCH_IMAGE.getBounds().width);
1596 }
1597
db4721fb
PT
1598 if (column.getWidth() < headerWidth) {
1599 column.setWidth(headerWidth);
1600 }
1601 }
1602 fPackDone = true;
1603 }
1604
1605 /**
a0a88f65
AM
1606 * Extract the fields of an event (item in the table).
1607 *
db4721fb 1608 * @param event
a0a88f65
AM
1609 * The event to extract from
1610 * @return The array of fields
db4721fb
PT
1611 *
1612 * FIXME: Add support for column selection
1613 */
1614 protected ITmfEventField[] extractItemFields(final ITmfEvent event) {
1615 ITmfEventField[] fields = new TmfEventField[0];
1616 if (event != null) {
1617 final String timestamp = event.getTimestamp().toString();
1618 final String source = event.getSource();
1619 final String type = event.getType().getName();
1620 final String reference = event.getReference();
a4a6acf4 1621 final String content = event.getContent().toString();
db4721fb
PT
1622 fields = new TmfEventField[] {
1623 new TmfEventField(ITmfEvent.EVENT_FIELD_TIMESTAMP, timestamp),
1624 new TmfEventField(ITmfEvent.EVENT_FIELD_SOURCE, source),
1625 new TmfEventField(ITmfEvent.EVENT_FIELD_TYPE, type),
1626 new TmfEventField(ITmfEvent.EVENT_FIELD_REFERENCE, reference),
a4a6acf4 1627 new TmfEventField(ITmfEvent.EVENT_FIELD_CONTENT, content)
db4721fb
PT
1628 };
1629 }
1630 return fields;
1631 }
1632
1633 /**
1634 * Notify this table that is got the UI focus.
1635 */
1636 public void setFocus() {
1637 fTable.setFocus();
1638 }
1639
1640 /**
1641 * Assign a new trace to this event table.
1642 *
1643 * @param trace
1644 * The trace to assign to this event table
1645 * @param disposeOnClose
1646 * true if the trace should be disposed when the table is
1647 * disposed
1648 */
1649 public void setTrace(final ITmfTrace trace, final boolean disposeOnClose) {
1650 if ((fTrace != null) && fDisposeOnClose) {
1651 fTrace.dispose();
1652 }
1653 fTrace = trace;
1654 fPackDone = false;
1655 fSelectedRank = 0;
1656 fDisposeOnClose = disposeOnClose;
1657
1658 // Perform the updates on the UI thread
1659 fTable.getDisplay().syncExec(new Runnable() {
1660 @Override
1661 public void run() {
1662 fTable.removeAll();
1663 fCache.setTrace(fTrace); // Clear the cache
1664 if (fTrace != null) {
1665 if (!fTable.isDisposed() && (fTrace != null)) {
1666 if (fTable.getData(Key.FILTER_OBJ) == null) {
1667 fTable.setItemCount((int) fTrace.getNbEvents() + 1); // +1 for header row
1668 } else {
1669 stopFilterThread();
1670 fFilterMatchCount = 0;
1671 fFilterCheckCount = 0;
1672 fTable.setItemCount(3); // +1 for header row, +2 for top and bottom filter status rows
1673 startFilterThread();
1674 }
1675 }
db4721fb 1676 }
ea279a69 1677 fRawViewer.setTrace(fTrace);
db4721fb
PT
1678 }
1679 });
1680 }
1681
1682 // ------------------------------------------------------------------------
1683 // Event cache
1684 // ------------------------------------------------------------------------
1685
1686 /**
1687 * Notify that the event cache has been updated
1688 *
1689 * @param completed
1690 * Also notify if the populating of the cache is complete, or
1691 * not.
1692 */
1693 public void cacheUpdated(final boolean completed) {
1694 synchronized (fCacheUpdateSyncObj) {
1695 if (fCacheUpdateBusy) {
1696 fCacheUpdatePending = true;
1697 fCacheUpdateCompleted = completed;
1698 return;
1699 }
1700 fCacheUpdateBusy = true;
1701 }
1702 // Event cache is now updated. Perform update on the UI thread
1703 if (!fTable.isDisposed()) {
1704 fTable.getDisplay().asyncExec(new Runnable() {
1705 @Override
1706 public void run() {
1707 if (!fTable.isDisposed()) {
1708 fTable.refresh();
1709 packColumns();
1710 }
1711 if (completed) {
1712 populateCompleted();
1713 }
1714 synchronized (fCacheUpdateSyncObj) {
1715 fCacheUpdateBusy = false;
1716 if (fCacheUpdatePending) {
1717 fCacheUpdatePending = false;
1718 cacheUpdated(fCacheUpdateCompleted);
1719 }
1720 }
1721 }
1722 });
1723 }
1724 }
1725
a0a88f65
AM
1726 /**
1727 * Callback for when populating the table is complete.
1728 */
db4721fb
PT
1729 protected void populateCompleted() {
1730 // Nothing by default;
1731 }
1732
93bfd50a
PT
1733 // ------------------------------------------------------------------------
1734 // ISelectionProvider
1735 // ------------------------------------------------------------------------
1736
1737 /* (non-Javadoc)
1738 * @see org.eclipse.jface.viewers.ISelectionProvider#addSelectionChangedListener(org.eclipse.jface.viewers.ISelectionChangedListener)
1739 */
1740 /**
1741 * @since 2.0
1742 */
1743 @Override
1744 public void addSelectionChangedListener(ISelectionChangedListener listener) {
1745 selectionChangedListeners.add(listener);
1746 }
1747
1748 /* (non-Javadoc)
1749 * @see org.eclipse.jface.viewers.ISelectionProvider#getSelection()
1750 */
1751 /**
1752 * @since 2.0
1753 */
1754 @Override
1755 public ISelection getSelection() {
1756 if (fTable == null || fTable.isDisposed()) {
1757 return StructuredSelection.EMPTY;
1758 }
1759 List<Object> list = new ArrayList<Object>(fTable.getSelection().length);
1760 for (TableItem item : fTable.getSelection()) {
1761 if (item.getData() != null) {
1762 list.add(item.getData());
1763 }
1764 }
1765 return new StructuredSelection(list);
1766 }
1767
1768 /* (non-Javadoc)
1769 * @see org.eclipse.jface.viewers.ISelectionProvider#removeSelectionChangedListener(org.eclipse.jface.viewers.ISelectionChangedListener)
1770 */
1771 /**
1772 * @since 2.0
1773 */
1774 @Override
1775 public void removeSelectionChangedListener(ISelectionChangedListener listener) {
1776 selectionChangedListeners.remove(listener);
1777 }
1778
1779 /* (non-Javadoc)
1780 * @see org.eclipse.jface.viewers.ISelectionProvider#setSelection(org.eclipse.jface.viewers.ISelection)
1781 */
1782 /**
1783 * @since 2.0
1784 */
1785 @Override
1786 public void setSelection(ISelection selection) {
1787 // not implemented
1788 }
1789
1790 /**
1791 * Notifies any selection changed listeners that the viewer's selection has changed.
1792 * Only listeners registered at the time this method is called are notified.
1793 *
1794 * @param event a selection changed event
1795 *
1796 * @see ISelectionChangedListener#selectionChanged
1797 * @since 2.0
1798 */
1799 protected void fireSelectionChanged(final SelectionChangedEvent event) {
1800 Object[] listeners = selectionChangedListeners.getListeners();
1801 for (int i = 0; i < listeners.length; ++i) {
1802 final ISelectionChangedListener l = (ISelectionChangedListener) listeners[i];
1803 SafeRunnable.run(new SafeRunnable() {
faa38350 1804 @Override
93bfd50a
PT
1805 public void run() {
1806 l.selectionChanged(event);
1807 }
1808 });
1809 }
1810 }
1811
db4721fb
PT
1812 // ------------------------------------------------------------------------
1813 // Bookmark handling
1814 // ------------------------------------------------------------------------
1815
1816 /**
1817 * Add a bookmark to this event table.
1818 *
1819 * @param bookmarksFile
1820 * The file to use for the bookmarks
1821 */
1822 public void addBookmark(final IFile bookmarksFile) {
1823 fBookmarksFile = bookmarksFile;
1824 final TableItem[] selection = fTable.getSelection();
1825 if (selection.length > 0) {
1826 final TableItem tableItem = selection[0];
1827 if (tableItem.getData(Key.RANK) != null) {
1828 final StringBuffer defaultMessage = new StringBuffer();
1829 for (int i = 0; i < fTable.getColumns().length; i++) {
1830 if (i > 0)
1831 {
1832 defaultMessage.append(", "); //$NON-NLS-1$
1833 }
1834 defaultMessage.append(tableItem.getText(i));
1835 }
3be2946f
PT
1836 final InputDialog dialog = new MultiLineInputDialog(
1837 PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell(),
1838 Messages.TmfEventsTable_AddBookmarkDialogTitle,
1839 Messages.TmfEventsTable_AddBookmarkDialogMessage,
1840 defaultMessage.toString());
db4721fb
PT
1841 if (dialog.open() == Window.OK) {
1842 final String message = dialog.getValue();
1843 try {
1844 final IMarker bookmark = bookmarksFile.createMarker(IMarker.BOOKMARK);
1845 if (bookmark.exists()) {
1846 bookmark.setAttribute(IMarker.MESSAGE, message.toString());
1847 final long rank = (Long) tableItem.getData(Key.RANK);
1848 final int location = (int) rank;
1849 bookmark.setAttribute(IMarker.LOCATION, (Integer) location);
1850 fBookmarksMap.put(rank, bookmark.getId());
1851 fTable.refresh();
1852 }
1853 } catch (final CoreException e) {
1854 displayException(e);
1855 }
1856 }
1857 }
1858 }
1859
1860 }
1861
1862 /**
1863 * Remove a bookmark from this event table.
1864 *
1865 * @param bookmark
1866 * The bookmark to remove
1867 */
1868 public void removeBookmark(final IMarker bookmark) {
1869 for (final Entry<Long, Long> entry : fBookmarksMap.entrySet()) {
1870 if (entry.getValue().equals(bookmark.getId())) {
1871 fBookmarksMap.remove(entry.getKey());
1872 fTable.refresh();
1873 return;
1874 }
1875 }
1876 }
1877
1878 private void toggleBookmark(final long rank) {
1879 if (fBookmarksFile == null) {
1880 return;
1881 }
1882 if (fBookmarksMap.containsKey(rank)) {
1883 final Long markerId = fBookmarksMap.remove(rank);
1884 fTable.refresh();
1885 try {
1886 final IMarker bookmark = fBookmarksFile.findMarker(markerId);
1887 if (bookmark != null) {
1888 bookmark.delete();
1889 }
1890 } catch (final CoreException e) {
1891 displayException(e);
1892 }
1893 } else {
1894 addBookmark(fBookmarksFile);
1895 }
1896 }
1897
1898 /**
1899 * Refresh the bookmarks assigned to this trace, from the contents of a
1900 * bookmark file.
1901 *
1902 * @param bookmarksFile
1903 * The bookmark file to use
1904 */
1905 public void refreshBookmarks(final IFile bookmarksFile) {
1906 fBookmarksFile = bookmarksFile;
1907 if (bookmarksFile == null) {
1908 fBookmarksMap.clear();
1909 fTable.refresh();
1910 return;
1911 }
1912 try {
1913 fBookmarksMap.clear();
1914 for (final IMarker bookmark : bookmarksFile.findMarkers(IMarker.BOOKMARK, false, IResource.DEPTH_ZERO)) {
1915 final int location = bookmark.getAttribute(IMarker.LOCATION, -1);
1916 if (location != -1) {
1917 final long rank = location;
1918 fBookmarksMap.put(rank, bookmark.getId());
1919 }
1920 }
1921 fTable.refresh();
1922 } catch (final CoreException e) {
1923 displayException(e);
1924 }
1925 }
1926
1927 @Override
1928 public void gotoMarker(final IMarker marker) {
1929 final int rank = marker.getAttribute(IMarker.LOCATION, -1);
1930 if (rank != -1) {
1931 int index = rank;
1932 if (fTable.getData(Key.FILTER_OBJ) != null) {
1933 index = fCache.getFilteredEventIndex(rank) + 1; // +1 for top filter status row
1934 } else if (rank >= fTable.getItemCount()) {
1935 fPendingGotoRank = rank;
1936 }
1937 fTable.setSelection(index + 1); // +1 for header row
1938 }
1939 }
1940
1941 // ------------------------------------------------------------------------
1942 // Listeners
1943 // ------------------------------------------------------------------------
1944
1945 /*
1946 * (non-Javadoc)
1947 *
1948 * @see org.eclipse.linuxtools.tmf.ui.views.colors.IColorSettingsListener#colorSettingsChanged(org.eclipse.linuxtools.tmf.ui.views.colors.ColorSetting[])
1949 */
1950 @Override
1951 public void colorSettingsChanged(final ColorSetting[] colorSettings) {
1952 fTable.refresh();
1953 }
1954
db4721fb
PT
1955 // ------------------------------------------------------------------------
1956 // Signal handlers
1957 // ------------------------------------------------------------------------
1958
db4721fb
PT
1959 /**
1960 * Handler for the trace updated signal
1961 *
1962 * @param signal
1963 * The incoming signal
1964 */
1965 @TmfSignalHandler
1966 public void traceUpdated(final TmfTraceUpdatedSignal signal) {
1967 if ((signal.getTrace() != fTrace) || fTable.isDisposed()) {
1968 return;
1969 }
1970 // Perform the refresh on the UI thread
1971 Display.getDefault().asyncExec(new Runnable() {
1972 @Override
1973 public void run() {
1974 if (!fTable.isDisposed() && (fTrace != null)) {
1975 if (fTable.getData(Key.FILTER_OBJ) == null) {
1976 fTable.setItemCount((int) fTrace.getNbEvents() + 1); // +1 for header row
1977 if ((fPendingGotoRank != -1) && ((fPendingGotoRank + 1) < fTable.getItemCount())) { // +1 for header row
1978 fTable.setSelection((int) fPendingGotoRank + 1); // +1 for header row
1979 fPendingGotoRank = -1;
1980 }
1981 } else {
1982 startFilterThread();
1983 }
1984 }
1985 if (!fRawViewer.isDisposed() && (fTrace != null)) {
1986 fRawViewer.refreshEventCount();
1987 }
1988 }
1989 });
1990 }
1991
1992 /**
1993 * Handler for the time synch signal.
1994 *
1995 * @param signal
1996 * The incoming signal
1997 */
1998 @TmfSignalHandler
1999 public void currentTimeUpdated(final TmfTimeSynchSignal signal) {
2000 if ((signal.getSource() != this) && (fTrace != null) && (!fTable.isDisposed())) {
2001
2002 // Create a request for one event that will be queued after other ongoing requests. When this request is completed
2003 // do the work to select the actual event with the timestamp specified in the signal. This procedure prevents
2004 // the method fTrace.getRank() from interfering and delaying ongoing requests.
2005 final TmfDataRequest subRequest = new TmfDataRequest(ITmfEvent.class, 0, 1, ExecutionType.FOREGROUND) {
2006
2007 TmfTimestamp ts = new TmfTimestamp(signal.getCurrentTime());
2008
2009 @Override
2010 public void handleData(final ITmfEvent event) {
2011 super.handleData(event);
2012 }
2013
2014 @Override
2015 public void handleCompleted() {
2016 super.handleCompleted();
2017 if (fTrace == null) {
2018 return;
2019 }
2020
2021 // Verify if the event is within the trace range and adjust if necessary
2022 ITmfTimestamp timestamp = ts;
2023 if (timestamp.compareTo(fTrace.getStartTime(), true) == -1) {
2024 timestamp = fTrace.getStartTime();
2025 }
2026 if (timestamp.compareTo(fTrace.getEndTime(), true) == 1) {
2027 timestamp = fTrace.getEndTime();
2028 }
2029
2030 // Get the rank of the selected event in the table
2031 final ITmfContext context = fTrace.seekEvent(timestamp);
2032 final long rank = context.getRank();
4c9f2944 2033 context.dispose();
db4721fb
PT
2034 fSelectedRank = rank;
2035
2036 fTable.getDisplay().asyncExec(new Runnable() {
2037 @Override
2038 public void run() {
2039 // Return if table is disposed
2040 if (fTable.isDisposed()) {
2041 return;
2042 }
2043
2044 int index = (int) rank;
2045 if (fTable.isDisposed()) {
2046 return;
2047 }
2048 if (fTable.getData(Key.FILTER_OBJ) != null)
2049 {
2050 index = fCache.getFilteredEventIndex(rank) + 1; // +1 for top filter status row
2051 }
2052 fTable.setSelection(index + 1); // +1 for header row
2053 fRawViewer.selectAndReveal(rank);
2054 }
2055 });
2056 }
2057 };
2058
2059 ((ITmfDataProvider) fTrace).sendRequest(subRequest);
2060 }
2061 }
2062
2063 // ------------------------------------------------------------------------
2064 // Error handling
2065 // ------------------------------------------------------------------------
2066
2067 /**
2068 * Display an exception in a message box
2069 *
2070 * @param e the exception
2071 */
2072 private static void displayException(final Exception e) {
2073 final MessageBox mb = new MessageBox(PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell());
2074 mb.setText(e.getClass().getName());
2075 mb.setMessage(e.getMessage());
2076 mb.open();
2077 }
2078
f8177ba2
FC
2079 /**
2080 * @since 2.0
2081 */
2082 public void refresh() {
2083 fCache.clear();
2084 fTable.refresh();
2085 fTable.redraw();
2086 }
db4721fb 2087}
This page took 0.119212 seconds and 5 git commands to generate.