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