Refactor TmfEventType and TmfEventField
[deliverable/tracecompass.git] / org.eclipse.linuxtools.tmf.ui / src / org / eclipse / linuxtools / tmf / ui / viewers / events / TmfEventsTable.java
1 /*******************************************************************************
2 * Copyright (c) 2010 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
16 package org.eclipse.linuxtools.tmf.ui.viewers.events;
17
18 import java.util.ArrayList;
19 import java.util.Arrays;
20 import java.util.HashMap;
21 import java.util.Map;
22 import java.util.Map.Entry;
23 import java.util.regex.Pattern;
24 import java.util.regex.PatternSyntaxException;
25
26 import org.eclipse.core.resources.IMarker;
27 import org.eclipse.core.resources.IResource;
28 import org.eclipse.core.runtime.CoreException;
29 import org.eclipse.core.runtime.IProgressMonitor;
30 import org.eclipse.core.runtime.IStatus;
31 import org.eclipse.core.runtime.Status;
32 import org.eclipse.core.runtime.jobs.Job;
33 import org.eclipse.jface.action.Action;
34 import org.eclipse.jface.action.IAction;
35 import org.eclipse.jface.action.IMenuListener;
36 import org.eclipse.jface.action.IMenuManager;
37 import org.eclipse.jface.action.MenuManager;
38 import org.eclipse.jface.action.Separator;
39 import org.eclipse.jface.dialogs.Dialog;
40 import org.eclipse.jface.dialogs.InputDialog;
41 import org.eclipse.jface.dialogs.MessageDialog;
42 import org.eclipse.jface.resource.FontDescriptor;
43 import org.eclipse.jface.resource.JFaceResources;
44 import org.eclipse.jface.resource.LocalResourceManager;
45 import org.eclipse.linuxtools.tmf.core.component.ITmfDataProvider;
46 import org.eclipse.linuxtools.tmf.core.component.TmfComponent;
47 import org.eclipse.linuxtools.tmf.core.event.ITmfTimestamp;
48 import org.eclipse.linuxtools.tmf.core.event.TmfEvent;
49 import org.eclipse.linuxtools.tmf.core.event.TmfEventContent;
50 import org.eclipse.linuxtools.tmf.core.event.TmfTimeRange;
51 import org.eclipse.linuxtools.tmf.core.event.TmfTimestamp;
52 import org.eclipse.linuxtools.tmf.core.filter.ITmfFilter;
53 import org.eclipse.linuxtools.tmf.core.filter.model.ITmfFilterTreeNode;
54 import org.eclipse.linuxtools.tmf.core.filter.model.TmfFilterAndNode;
55 import org.eclipse.linuxtools.tmf.core.filter.model.TmfFilterMatchesNode;
56 import org.eclipse.linuxtools.tmf.core.filter.model.TmfFilterNode;
57 import org.eclipse.linuxtools.tmf.core.request.ITmfDataRequest.ExecutionType;
58 import org.eclipse.linuxtools.tmf.core.request.TmfDataRequest;
59 import org.eclipse.linuxtools.tmf.core.request.TmfEventRequest;
60 import org.eclipse.linuxtools.tmf.core.signal.TmfExperimentRangeUpdatedSignal;
61 import org.eclipse.linuxtools.tmf.core.signal.TmfSignalHandler;
62 import org.eclipse.linuxtools.tmf.core.signal.TmfTimeSynchSignal;
63 import org.eclipse.linuxtools.tmf.core.signal.TmfTraceUpdatedSignal;
64 import org.eclipse.linuxtools.tmf.core.trace.ITmfLocation;
65 import org.eclipse.linuxtools.tmf.core.trace.ITmfTrace;
66 import org.eclipse.linuxtools.tmf.ui.TmfUiPlugin;
67 import org.eclipse.linuxtools.tmf.ui.internal.Messages;
68 import org.eclipse.linuxtools.tmf.ui.viewers.events.TmfEventsCache.CachedEvent;
69 import org.eclipse.linuxtools.tmf.ui.views.colors.ColorSetting;
70 import org.eclipse.linuxtools.tmf.ui.views.colors.ColorSettingsManager;
71 import org.eclipse.linuxtools.tmf.ui.views.colors.IColorSettingsListener;
72 import org.eclipse.linuxtools.tmf.ui.views.filter.FilterManager;
73 import org.eclipse.linuxtools.tmf.ui.widgets.ColumnData;
74 import org.eclipse.linuxtools.tmf.ui.widgets.TmfRawEventViewer;
75 import org.eclipse.linuxtools.tmf.ui.widgets.TmfVirtualTable;
76 import org.eclipse.swt.SWT;
77 import org.eclipse.swt.custom.SashForm;
78 import org.eclipse.swt.custom.TableEditor;
79 import org.eclipse.swt.events.FocusAdapter;
80 import org.eclipse.swt.events.FocusEvent;
81 import org.eclipse.swt.events.KeyAdapter;
82 import org.eclipse.swt.events.KeyEvent;
83 import org.eclipse.swt.events.MouseAdapter;
84 import org.eclipse.swt.events.MouseEvent;
85 import org.eclipse.swt.events.SelectionAdapter;
86 import org.eclipse.swt.events.SelectionEvent;
87 import org.eclipse.swt.graphics.Color;
88 import org.eclipse.swt.graphics.Font;
89 import org.eclipse.swt.graphics.Image;
90 import org.eclipse.swt.graphics.Point;
91 import org.eclipse.swt.graphics.Rectangle;
92 import org.eclipse.swt.layout.GridData;
93 import org.eclipse.swt.layout.GridLayout;
94 import org.eclipse.swt.widgets.Composite;
95 import org.eclipse.swt.widgets.Display;
96 import org.eclipse.swt.widgets.Event;
97 import org.eclipse.swt.widgets.Listener;
98 import org.eclipse.swt.widgets.Menu;
99 import org.eclipse.swt.widgets.TableColumn;
100 import org.eclipse.swt.widgets.TableItem;
101 import org.eclipse.swt.widgets.Text;
102 import org.eclipse.ui.PlatformUI;
103 import org.eclipse.ui.ide.IGotoMarker;
104 import org.eclipse.ui.themes.ColorUtil;
105
106 /**
107 * <b><u>TmfEventsTable</u></b>
108 */
109 public class TmfEventsTable extends TmfComponent implements IGotoMarker, IColorSettingsListener,
110 ITmfEventsFilterProvider {
111
112 private static final Image BOOKMARK_IMAGE = TmfUiPlugin.getDefault().getImageFromPath(
113 "icons/elcl16/bookmark_obj.gif"); //$NON-NLS-1$
114 private static final Image SEARCH_IMAGE = TmfUiPlugin.getDefault().getImageFromPath("icons/elcl16/search.gif"); //$NON-NLS-1$
115 private static final Image SEARCH_MATCH_IMAGE = TmfUiPlugin.getDefault().getImageFromPath(
116 "icons/elcl16/search_match.gif"); //$NON-NLS-1$
117 private static final Image SEARCH_MATCH_BOOKMARK_IMAGE = TmfUiPlugin.getDefault().getImageFromPath(
118 "icons/elcl16/search_match_bookmark.gif"); //$NON-NLS-1$
119 private static final Image FILTER_IMAGE = TmfUiPlugin.getDefault()
120 .getImageFromPath("icons/elcl16/filter_items.gif"); //$NON-NLS-1$
121 private static final Image STOP_IMAGE = TmfUiPlugin.getDefault().getImageFromPath("icons/elcl16/stop.gif"); //$NON-NLS-1$
122 private static final String SEARCH_HINT = Messages.TmfEventsTable_SearchHint;
123 private static final String FILTER_HINT = Messages.TmfEventsTable_FilterHint;
124
125 public interface Key {
126 String SEARCH_TXT = "$srch_txt"; //$NON-NLS-1$
127 String SEARCH_OBJ = "$srch_obj"; //$NON-NLS-1$
128 String FILTER_TXT = "$fltr_txt"; //$NON-NLS-1$
129 String FILTER_OBJ = "$fltr_obj"; //$NON-NLS-1$
130 String TIMESTAMP = "$time"; //$NON-NLS-1$
131 String RANK = "$rank"; //$NON-NLS-1$
132 String FIELD_ID = "$field_id"; //$NON-NLS-1$
133 }
134
135 public static enum HeaderState {
136 SEARCH, FILTER
137 }
138
139 interface Direction {
140 int FORWARD = +1;
141 int BACKWARD = -1;
142 }
143
144 // ------------------------------------------------------------------------
145 // Table data
146 // ------------------------------------------------------------------------
147
148 protected Composite fComposite;
149 protected SashForm fSashForm;
150 protected TmfVirtualTable fTable;
151 protected TmfRawEventViewer fRawViewer;
152 protected ITmfTrace<?> fTrace;
153 protected boolean fPackDone = false;
154 protected HeaderState fHeaderState = HeaderState.SEARCH;
155 protected long fSelectedRank = 0;
156
157 // Filter data
158 protected long fFilterMatchCount;
159 protected long fFilterCheckCount;
160 protected FilterThread fFilterThread;
161 protected final Object fFilterSyncObj = new Object();
162 protected SearchThread fSearchThread;
163 protected final Object fSearchSyncObj = new Object();
164 protected ArrayList<ITmfEventsFilterListener> fEventsFilterListeners = new ArrayList<ITmfEventsFilterListener>();
165
166 // Bookmark map <Rank, MarkerId>
167 protected Map<Long, Long> fBookmarksMap = new HashMap<Long, Long>();
168 protected IResource fBookmarksResource;
169 protected long fPendingGotoRank = -1;
170
171 // SWT resources
172 protected LocalResourceManager fResourceManager = new LocalResourceManager(JFaceResources.getResources());
173 protected Color fGrayColor;
174 protected Color fGreenColor;
175 protected Font fBoldFont;
176
177 // Table column names
178 static private final String[] COLUMN_NAMES = new String[] { Messages.TmfEventsTable_TimestampColumnHeader,
179 Messages.TmfEventsTable_SourceColumnHeader, Messages.TmfEventsTable_TypeColumnHeader,
180 Messages.TmfEventsTable_ReferenceColumnHeader, Messages.TmfEventsTable_ContentColumnHeader };
181
182 static private ColumnData[] COLUMN_DATA = new ColumnData[] { new ColumnData(COLUMN_NAMES[0], 100, SWT.LEFT),
183 new ColumnData(COLUMN_NAMES[1], 100, SWT.LEFT), new ColumnData(COLUMN_NAMES[2], 100, SWT.LEFT),
184 new ColumnData(COLUMN_NAMES[3], 100, SWT.LEFT), new ColumnData(COLUMN_NAMES[4], 100, SWT.LEFT) };
185
186 // Event cache
187 private final TmfEventsCache fCache;
188 private boolean fCacheUpdateBusy = false;
189 private boolean fCacheUpdatePending = false;
190 private boolean fCacheUpdateCompleted = false;
191 private Object fCacheUpdateSyncObj = new Object();
192
193 private boolean fDisposeOnClose;
194
195 // ------------------------------------------------------------------------
196 // Constructor
197 // ------------------------------------------------------------------------
198
199 public TmfEventsTable(Composite parent, int cacheSize) {
200 this(parent, cacheSize, COLUMN_DATA);
201 }
202
203 public TmfEventsTable(Composite parent, int cacheSize, ColumnData[] columnData) {
204 super("TmfEventsTable"); //$NON-NLS-1$
205
206 fComposite = new Composite(parent, SWT.NONE);
207 GridLayout gl = new GridLayout(1, false);
208 gl.marginHeight = 0;
209 gl.marginWidth = 0;
210 gl.verticalSpacing = 0;
211 fComposite.setLayout(gl);
212
213 fSashForm = new SashForm(fComposite, SWT.HORIZONTAL);
214 fSashForm.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
215
216 // Create a virtual table
217 final int style = SWT.H_SCROLL | SWT.V_SCROLL | SWT.SINGLE | SWT.FULL_SELECTION;
218 fTable = new TmfVirtualTable(fSashForm, style);
219
220 // Set the table layout
221 GridData layoutData = new GridData(SWT.FILL, SWT.FILL, true, true);
222 fTable.setLayoutData(layoutData);
223
224 // Some cosmetic enhancements
225 fTable.setHeaderVisible(true);
226 fTable.setLinesVisible(true);
227
228 // Set the columns
229 setColumnHeaders(columnData);
230
231 // Set the default column field ids if this is not a subclass
232 if (Arrays.equals(columnData, COLUMN_DATA)) {
233 fTable.getColumns()[0].setData(Key.FIELD_ID, TmfEventContent.FIELD_ID_TIMESTAMP);
234 fTable.getColumns()[1].setData(Key.FIELD_ID, TmfEventContent.FIELD_ID_SOURCE);
235 fTable.getColumns()[2].setData(Key.FIELD_ID, TmfEventContent.FIELD_ID_TYPE);
236 fTable.getColumns()[3].setData(Key.FIELD_ID, TmfEventContent.FIELD_ID_REFERENCE);
237 fTable.getColumns()[4].setData(Key.FIELD_ID, TmfEventContent.FIELD_ID_CONTENT);
238 }
239
240 // Set the frozen row for header row
241 fTable.setFrozenRowCount(1);
242
243 // Create the header row cell editor
244 createHeaderEditor();
245
246 // Handle the table item selection
247 fTable.addSelectionListener(new SelectionAdapter() {
248 @Override
249 public void widgetSelected(SelectionEvent e) {
250 TableItem[] selection = fTable.getSelection();
251 if (selection.length > 0) {
252 TableItem selectedTableItem = selection[0];
253 if (selectedTableItem != null) {
254 if (selectedTableItem.getData(Key.RANK) instanceof Long) {
255 fSelectedRank = (Long) selectedTableItem.getData(Key.RANK);
256 fRawViewer.selectAndReveal((Long) selectedTableItem.getData(Key.RANK));
257 }
258 if (selectedTableItem.getData(Key.TIMESTAMP) instanceof TmfTimestamp) {
259 TmfTimestamp ts = (TmfTimestamp) selectedTableItem.getData(Key.TIMESTAMP);
260 broadcast(new TmfTimeSynchSignal(fTable, ts));
261 }
262 }
263 }
264 }
265 });
266
267 cacheSize = Math.max(cacheSize, Display.getDefault().getBounds().height / fTable.getItemHeight());
268 fCache = new TmfEventsCache(cacheSize, this);
269
270 // Handle the table item requests
271 fTable.addListener(SWT.SetData, new Listener() {
272
273 @Override
274 public void handleEvent(Event event) {
275
276 final TableItem item = (TableItem) event.item;
277 int index = event.index - 1; // -1 for the header row
278
279 if (event.index == 0) {
280 setHeaderRowItemData(item);
281 return;
282 }
283
284 if (fTable.getData(Key.FILTER_OBJ) != null) {
285 if (event.index == 1 || event.index == fTable.getItemCount() - 1) {
286 setFilterStatusRowItemData(item);
287 return;
288 }
289 index = index - 1; // -1 for top filter status row
290 }
291
292 CachedEvent cachedEvent = fCache.getEvent(index);
293 if (cachedEvent != null) {
294 setItemData(item, cachedEvent.event, cachedEvent.rank);
295 return;
296 }
297
298 // Else, fill the cache asynchronously (and off the UI thread)
299 event.doit = false;
300 }
301 });
302
303 fTable.addMouseListener(new MouseAdapter() {
304 @Override
305 public void mouseDoubleClick(MouseEvent event) {
306 if (event.button != 1) {
307 return;
308 }
309 // Identify the selected row
310 Point point = new Point(event.x, event.y);
311 TableItem item = fTable.getItem(point);
312 if (item != null) {
313 Rectangle imageBounds = item.getImageBounds(0);
314 imageBounds.width = BOOKMARK_IMAGE.getBounds().width;
315 if (imageBounds.contains(point)) {
316 Long rank = (Long) item.getData(Key.RANK);
317 if (rank != null) {
318 toggleBookmark(rank);
319 }
320 }
321 }
322 }
323 });
324
325 // Create resources
326 createResources();
327
328 ColorSettingsManager.addColorSettingsListener(this);
329
330 fTable.setItemCount(1); // +1 for header row
331
332 fRawViewer = new TmfRawEventViewer(fSashForm, SWT.H_SCROLL | SWT.V_SCROLL);
333
334 fRawViewer.addSelectionListener(new SelectionAdapter() {
335 @Override
336 public void widgetSelected(SelectionEvent e) {
337 if (e.data instanceof Long) {
338 long rank = (Long) e.data;
339 int index = (int) rank;
340 if (fTable.getData(Key.FILTER_OBJ) != null) {
341 index = fCache.getFilteredEventIndex(rank) + 1; // +1 for top filter status row
342 }
343 fTable.setSelection(index + 1); // +1 for header row
344 fSelectedRank = rank;
345 } else if (e.data instanceof ITmfLocation<?>) {
346 // DOES NOT WORK: rank undefined in context from seekLocation()
347 // ITmfLocation<?> location = (ITmfLocation<?>) e.data;
348 // TmfContext context = fTrace.seekLocation(location);
349 // fTable.setSelection((int) context.getRank());
350 return;
351 } else {
352 return;
353 }
354 TableItem[] selection = fTable.getSelection();
355 if (selection != null && selection.length > 0) {
356 TmfTimestamp ts = (TmfTimestamp) fTable.getSelection()[0].getData(Key.TIMESTAMP);
357 if (ts != null) {
358 broadcast(new TmfTimeSynchSignal(fTable, ts));
359 }
360 }
361 }
362 });
363
364 fSashForm.setWeights(new int[] { 1, 1 });
365 fRawViewer.setVisible(false);
366
367 createPopupMenu();
368 }
369
370 protected void createPopupMenu() {
371 final IAction showTableAction = new Action(Messages.TmfEventsTable_ShowTableActionText) {
372 @Override
373 public void run() {
374 fTable.setVisible(true);
375 fSashForm.layout();
376 }
377 };
378
379 final IAction hideTableAction = new Action(Messages.TmfEventsTable_HideTableActionText) {
380 @Override
381 public void run() {
382 fTable.setVisible(false);
383 fSashForm.layout();
384 }
385 };
386
387 final IAction showRawAction = new Action(Messages.TmfEventsTable_ShowRawActionText) {
388 @Override
389 public void run() {
390 fRawViewer.setVisible(true);
391 fSashForm.layout();
392 int index = fTable.getSelectionIndex();
393 if (index >= +1) { // +1 for header row
394 fRawViewer.selectAndReveal(index - 1);
395 }
396 }
397 };
398
399 final IAction hideRawAction = new Action(Messages.TmfEventsTable_HideRawActionText) {
400 @Override
401 public void run() {
402 fRawViewer.setVisible(false);
403 fSashForm.layout();
404 }
405 };
406
407 final IAction showSearchBarAction = new Action(Messages.TmfEventsTable_ShowSearchBarActionText) {
408 @Override
409 public void run() {
410 fHeaderState = HeaderState.SEARCH;
411 fTable.refresh();
412 }
413 };
414
415 final IAction showFilterBarAction = new Action(Messages.TmfEventsTable_ShowFilterBarActionText) {
416 @Override
417 public void run() {
418 fHeaderState = HeaderState.FILTER;
419 fTable.refresh();
420 }
421 };
422
423 final IAction clearFiltersAction = new Action(Messages.TmfEventsTable_ClearFiltersActionText) {
424 @Override
425 public void run() {
426 stopFilterThread();
427 stopSearchThread();
428 clearFilters();
429 }
430 };
431
432 class ToggleBookmarkAction extends Action {
433 long fRank;
434
435 public ToggleBookmarkAction(String text, long rank) {
436 super(text);
437 fRank = rank;
438 }
439
440 @Override
441 public void run() {
442 toggleBookmark(fRank);
443 }
444 }
445
446 final MenuManager tablePopupMenu = new MenuManager();
447 tablePopupMenu.setRemoveAllWhenShown(true);
448 tablePopupMenu.addMenuListener(new IMenuListener() {
449 @Override
450 public void menuAboutToShow(IMenuManager manager) {
451 if (fTable.getSelectionIndex() == 0) {
452 // Right-click on header row
453 if (fHeaderState == HeaderState.FILTER) {
454 tablePopupMenu.add(showSearchBarAction);
455 } else {
456 tablePopupMenu.add(showFilterBarAction);
457 }
458 return;
459 }
460 Point point = fTable.toControl(Display.getDefault().getCursorLocation());
461 TableItem item = fTable.getSelection().length > 0 ? fTable.getSelection()[0] : null;
462 if (item != null) {
463 Rectangle imageBounds = item.getImageBounds(0);
464 imageBounds.width = BOOKMARK_IMAGE.getBounds().width;
465 if (point.x <= imageBounds.x + imageBounds.width) {
466 // Right-click on left margin
467 Long rank = (Long) item.getData(Key.RANK);
468 if (rank != null && fBookmarksResource != null) {
469 if (fBookmarksMap.containsKey(rank)) {
470 tablePopupMenu.add(new ToggleBookmarkAction(
471 Messages.TmfEventsTable_RemoveBookmarkActionText, rank));
472 } else {
473 tablePopupMenu.add(new ToggleBookmarkAction(
474 Messages.TmfEventsTable_AddBookmarkActionText, rank));
475 }
476 }
477 return;
478 }
479 }
480 // Right-click on table
481 if (fTable.isVisible() && fRawViewer.isVisible()) {
482 tablePopupMenu.add(hideTableAction);
483 tablePopupMenu.add(hideRawAction);
484 } else if (!fTable.isVisible()) {
485 tablePopupMenu.add(showTableAction);
486 } else if (!fRawViewer.isVisible()) {
487 tablePopupMenu.add(showRawAction);
488 }
489 tablePopupMenu.add(new Separator());
490 tablePopupMenu.add(clearFiltersAction);
491 ITmfFilterTreeNode[] savedFilters = FilterManager.getSavedFilters();
492 if (savedFilters.length > 0) {
493 MenuManager subMenu = new MenuManager(Messages.TmfEventsTable_ApplyPresetFilterMenuName);
494 for (ITmfFilterTreeNode node : savedFilters) {
495 if (node instanceof TmfFilterNode) {
496 final TmfFilterNode filter = (TmfFilterNode) node;
497 subMenu.add(new Action(filter.getFilterName()) {
498 @Override
499 public void run() {
500 stopFilterThread();
501 fFilterMatchCount = 0;
502 fFilterCheckCount = 0;
503 fCache.applyFilter(filter);
504 fTable.clearAll();
505 fTable.setData(Key.FILTER_OBJ, filter);
506 fTable.setItemCount(3); // +1 for header row, +2 for top and bottom filter status
507 // rows
508 startFilterThread();
509 fireFilterApplied(filter);
510 }
511 });
512 }
513 }
514 tablePopupMenu.add(subMenu);
515 }
516 appendToTablePopupMenu(tablePopupMenu, item);
517 }
518 });
519
520 final MenuManager rawViewerPopupMenu = new MenuManager();
521 rawViewerPopupMenu.setRemoveAllWhenShown(true);
522 rawViewerPopupMenu.addMenuListener(new IMenuListener() {
523 @Override
524 public void menuAboutToShow(IMenuManager manager) {
525 if (fTable.isVisible() && fRawViewer.isVisible()) {
526 rawViewerPopupMenu.add(hideTableAction);
527 rawViewerPopupMenu.add(hideRawAction);
528 } else if (!fTable.isVisible()) {
529 rawViewerPopupMenu.add(showTableAction);
530 } else if (!fRawViewer.isVisible()) {
531 rawViewerPopupMenu.add(showRawAction);
532 }
533 appendToRawPopupMenu(tablePopupMenu);
534 }
535 });
536
537 Menu menu = tablePopupMenu.createContextMenu(fTable);
538 fTable.setMenu(menu);
539
540 menu = rawViewerPopupMenu.createContextMenu(fRawViewer);
541 fRawViewer.setMenu(menu);
542 }
543
544 protected void appendToTablePopupMenu(MenuManager tablePopupMenu, TableItem selectedItem) {
545 // override to append more actions
546 }
547
548 protected void appendToRawPopupMenu(MenuManager rawViewerPopupMenu) {
549 // override to append more actions
550 }
551
552 @Override
553 public void dispose() {
554 stopSearchThread();
555 stopFilterThread();
556 ColorSettingsManager.removeColorSettingsListener(this);
557 fComposite.dispose();
558 if (fTrace != null && fDisposeOnClose) {
559 fTrace.dispose();
560 }
561 fResourceManager.dispose();
562 super.dispose();
563 }
564
565 public void setLayoutData(Object layoutData) {
566 fComposite.setLayoutData(layoutData);
567 }
568
569 public TmfVirtualTable getTable() {
570 return fTable;
571 }
572
573 /**
574 * @param table
575 *
576 * FIXME: Add support for column selection
577 */
578 protected void setColumnHeaders(ColumnData[] columnData) {
579 fTable.setColumnHeaders(columnData);
580 }
581
582 protected void setItemData(TableItem item, TmfEvent event, long rank) {
583 item.setText(extractItemFields(event));
584 item.setData(Key.TIMESTAMP, new TmfTimestamp(event.getTimestamp()));
585 item.setData(Key.RANK, rank);
586
587 boolean bookmark = false;
588 if (fBookmarksMap.containsKey(rank)) {
589 bookmark = true;
590 }
591
592 boolean searchMatch = false;
593 boolean searchNoMatch = false;
594 ITmfFilter searchFilter = (ITmfFilter) fTable.getData(Key.SEARCH_OBJ);
595 if (searchFilter != null) {
596 if (searchFilter.matches(event)) {
597 searchMatch = true;
598 } else {
599 searchNoMatch = true;
600 }
601 }
602
603 ColorSetting colorSetting = ColorSettingsManager.getColorSetting(event);
604 if (searchNoMatch) {
605 item.setForeground(colorSetting.getDimmedForegroundColor());
606 item.setBackground(colorSetting.getDimmedBackgroundColor());
607 } else {
608 item.setForeground(colorSetting.getForegroundColor());
609 item.setBackground(colorSetting.getBackgroundColor());
610 }
611
612 if (searchMatch) {
613 if (bookmark) {
614 item.setImage(SEARCH_MATCH_BOOKMARK_IMAGE);
615 } else {
616 item.setImage(SEARCH_MATCH_IMAGE);
617 }
618 } else if (bookmark) {
619 item.setImage(BOOKMARK_IMAGE);
620 } else {
621 item.setImage((Image) null);
622 }
623 }
624
625 protected void setHeaderRowItemData(TableItem item) {
626 String txtKey = null;
627 if (fHeaderState == HeaderState.SEARCH) {
628 item.setImage(SEARCH_IMAGE);
629 txtKey = Key.SEARCH_TXT;
630 } else if (fHeaderState == HeaderState.FILTER) {
631 item.setImage(FILTER_IMAGE);
632 txtKey = Key.FILTER_TXT;
633 }
634 item.setForeground(fGrayColor);
635 for (int i = 0; i < fTable.getColumns().length; i++) {
636 TableColumn column = fTable.getColumns()[i];
637 String filter = (String) column.getData(txtKey);
638 if (filter == null) {
639 if (fHeaderState == HeaderState.SEARCH) {
640 item.setText(i, SEARCH_HINT);
641 } else if (fHeaderState == HeaderState.FILTER) {
642 item.setText(i, FILTER_HINT);
643 }
644 item.setForeground(i, fGrayColor);
645 item.setFont(i, fTable.getFont());
646 } else {
647 item.setText(i, filter);
648 item.setForeground(i, fGreenColor);
649 item.setFont(i, fBoldFont);
650 }
651 }
652 }
653
654 protected void setFilterStatusRowItemData(TableItem item) {
655 for (int i = 0; i < fTable.getColumns().length; i++) {
656 if (i == 0) {
657 if (fTrace == null || fFilterCheckCount == fTrace.getNbEvents()) {
658 item.setImage(FILTER_IMAGE);
659 } else {
660 item.setImage(STOP_IMAGE);
661 }
662 item.setText(0, fFilterMatchCount + "/" + fFilterCheckCount); //$NON-NLS-1$
663 } else {
664 item.setText(i, ""); //$NON-NLS-1$
665 }
666 }
667 item.setData(Key.TIMESTAMP, null);
668 item.setData(Key.RANK, null);
669 item.setForeground(null);
670 item.setBackground(null);
671 }
672
673 protected void createHeaderEditor() {
674 final TableEditor tableEditor = fTable.createTableEditor();
675 tableEditor.horizontalAlignment = SWT.LEFT;
676 tableEditor.verticalAlignment = SWT.CENTER;
677 tableEditor.grabHorizontal = true;
678 tableEditor.minimumWidth = 50;
679
680 // Handle the header row selection
681 fTable.addMouseListener(new MouseAdapter() {
682 int columnIndex;
683 TableColumn column;
684 TableItem item;
685
686 @Override
687 public void mouseDown(MouseEvent event) {
688 if (event.button != 1) {
689 return;
690 }
691 // Identify the selected row
692 Point point = new Point(event.x, event.y);
693 item = fTable.getItem(point);
694
695 // Header row selected
696 if (item != null && fTable.indexOf(item) == 0) {
697
698 // Icon selected
699 if (item.getImageBounds(0).contains(point)) {
700 if (fHeaderState == HeaderState.SEARCH) {
701 fHeaderState = HeaderState.FILTER;
702 } else if (fHeaderState == HeaderState.FILTER) {
703 fHeaderState = HeaderState.SEARCH;
704 }
705 fTable.refresh();
706 return;
707 }
708
709 // Identify the selected column
710 columnIndex = -1;
711 for (int i = 0; i < fTable.getColumns().length; i++) {
712 Rectangle rect = item.getBounds(i);
713 if (rect.contains(point)) {
714 columnIndex = i;
715 break;
716 }
717 }
718
719 if (columnIndex == -1) {
720 return;
721 }
722
723 column = fTable.getColumns()[columnIndex];
724
725 String txtKey = null;
726 if (fHeaderState == HeaderState.SEARCH) {
727 txtKey = Key.SEARCH_TXT;
728 } else if (fHeaderState == HeaderState.FILTER) {
729 txtKey = Key.FILTER_TXT;
730 }
731
732 // The control that will be the editor must be a child of the Table
733 final Text newEditor = (Text) fTable.createTableEditorControl(Text.class);
734 String headerString = (String) column.getData(txtKey);
735 if (headerString != null) {
736 newEditor.setText(headerString);
737 }
738 newEditor.addFocusListener(new FocusAdapter() {
739 @Override
740 public void focusLost(FocusEvent e) {
741 boolean changed = updateHeader(newEditor.getText());
742 if (changed) {
743 applyHeader();
744 }
745 }
746 });
747 newEditor.addKeyListener(new KeyAdapter() {
748 @Override
749 public void keyPressed(KeyEvent e) {
750 if (e.character == SWT.CR) {
751 updateHeader(newEditor.getText());
752 applyHeader();
753 } else if (e.character == SWT.ESC) {
754 tableEditor.getEditor().dispose();
755 }
756 }
757 });
758 newEditor.selectAll();
759 newEditor.setFocus();
760 tableEditor.setEditor(newEditor, item, columnIndex);
761 }
762 }
763
764 /*
765 * returns true is value was changed
766 */
767 private boolean updateHeader(String text) {
768 String objKey = null;
769 String txtKey = null;
770 if (fHeaderState == HeaderState.SEARCH) {
771 objKey = Key.SEARCH_OBJ;
772 txtKey = Key.SEARCH_TXT;
773 } else if (fHeaderState == HeaderState.FILTER) {
774 objKey = Key.FILTER_OBJ;
775 txtKey = Key.FILTER_TXT;
776 }
777 if (text.trim().length() > 0) {
778 try {
779 String regex = TmfFilterMatchesNode.regexFix(text);
780 Pattern.compile(regex);
781 if (regex.equals(column.getData(txtKey))) {
782 tableEditor.getEditor().dispose();
783 return false;
784 }
785 TmfFilterMatchesNode filter = new TmfFilterMatchesNode(null);
786 String fieldId = (String) column.getData(Key.FIELD_ID);
787 if (fieldId == null) {
788 fieldId = column.getText();
789 }
790 filter.setField(fieldId);
791 filter.setRegex(regex);
792 column.setData(objKey, filter);
793 column.setData(txtKey, regex);
794 } catch (PatternSyntaxException ex) {
795 tableEditor.getEditor().dispose();
796 MessageDialog.openError(PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell(),
797 ex.getDescription(), ex.getMessage());
798 return false;
799 }
800 } else {
801 if (column.getData(txtKey) == null) {
802 tableEditor.getEditor().dispose();
803 return false;
804 }
805 column.setData(objKey, null);
806 column.setData(txtKey, null);
807 }
808 return true;
809 }
810
811 private void applyHeader() {
812 stopSearchThread();
813 if (fHeaderState == HeaderState.SEARCH) {
814 final TmfFilterAndNode filter = new TmfFilterAndNode(null);
815 for (TableColumn column : fTable.getColumns()) {
816 Object filterObj = column.getData(Key.SEARCH_OBJ);
817 if (filterObj instanceof ITmfFilterTreeNode) {
818 filter.addChild((ITmfFilterTreeNode) filterObj);
819 }
820 }
821 if (filter.getChildrenCount() > 0) {
822 fTable.setData(Key.SEARCH_OBJ, filter);
823 fTable.refresh();
824 searchNext();
825 fireSearchApplied(filter);
826 } else {
827 fTable.setData(Key.SEARCH_OBJ, null);
828 fTable.refresh();
829 fireSearchApplied(null);
830 }
831 } else if (fHeaderState == HeaderState.FILTER) {
832 stopFilterThread();
833 fFilterMatchCount = 0;
834 fFilterCheckCount = 0;
835 TmfFilterAndNode filter = new TmfFilterAndNode(null);
836 for (TableColumn column : fTable.getColumns()) {
837 Object filterObj = column.getData(Key.FILTER_OBJ);
838 if (filterObj instanceof ITmfFilterTreeNode) {
839 filter.addChild((ITmfFilterTreeNode) filterObj);
840 }
841 }
842 if (filter.getChildrenCount() > 0) {
843 fCache.applyFilter(filter);
844 fTable.clearAll();
845 fTable.setData(Key.FILTER_OBJ, filter);
846 fTable.setItemCount(3); // +1 for header row, +2 for top and bottom filter status rows
847 startFilterThread();
848 fireFilterApplied(filter);
849 } else {
850 fCache.clearFilter();
851 stopFilterThread();
852 fTable.clearAll();
853 fTable.setData(Key.FILTER_OBJ, null);
854 if (fTrace != null) {
855 fTable.setItemCount((int) fTrace.getNbEvents() + 1); // +1 for header row
856 } else {
857 fTable.setItemCount(1); // +1 for header row
858 }
859 fireFilterApplied(null);
860 }
861 }
862
863 tableEditor.getEditor().dispose();
864 }
865 });
866
867 fTable.addKeyListener(new KeyAdapter() {
868 @Override
869 public void keyPressed(KeyEvent e) {
870 e.doit = false;
871 if (e.character == SWT.ESC) {
872 stopFilterThread();
873 stopSearchThread();
874 fTable.refresh();
875 } else if (e.character == SWT.DEL) {
876 stopFilterThread();
877 stopSearchThread();
878 if (fHeaderState == HeaderState.SEARCH) {
879 for (TableColumn column : fTable.getColumns()) {
880 column.setData(Key.SEARCH_OBJ, null);
881 column.setData(Key.SEARCH_TXT, null);
882 }
883 fTable.setData(Key.SEARCH_OBJ, null);
884 fTable.refresh();
885 fireSearchApplied(null);
886 } else if (fHeaderState == HeaderState.FILTER) {
887 clearFilters();
888 }
889 } else if (e.character == SWT.CR) {
890 if ((e.stateMask & SWT.SHIFT) == 0) {
891 searchNext();
892 } else {
893 searchPrevious();
894 }
895 }
896 }
897 });
898 }
899
900 protected void fireFilterApplied(ITmfFilter filter) {
901 for (ITmfEventsFilterListener listener : fEventsFilterListeners) {
902 listener.filterApplied(filter, fTrace);
903 }
904 }
905
906 protected void fireSearchApplied(ITmfFilter filter) {
907 for (ITmfEventsFilterListener listener : fEventsFilterListeners) {
908 listener.searchApplied(filter, fTrace);
909 }
910 }
911
912 protected void startFilterThread() {
913 synchronized (fFilterSyncObj) {
914 if (fFilterThread != null) {
915 fFilterThread.cancel();
916 }
917 final ITmfFilterTreeNode filter = (ITmfFilterTreeNode) fTable.getData(Key.FILTER_OBJ);
918 fFilterThread = new FilterThread(filter);
919 fFilterThread.start();
920 }
921 }
922
923 protected void stopFilterThread() {
924 synchronized (fFilterSyncObj) {
925 if (fFilterThread != null) {
926 fFilterThread.cancel();
927 }
928 }
929 }
930
931 protected void clearFilters() {
932 if (fTable.getData(Key.FILTER_OBJ) == null) {
933 return;
934 }
935 fCache.clearFilter();
936 fTable.clearAll();
937 for (TableColumn column : fTable.getColumns()) {
938 column.setData(Key.FILTER_OBJ, null);
939 column.setData(Key.FILTER_TXT, null);
940 }
941 fTable.setData(Key.FILTER_OBJ, null);
942 if (fTrace != null) {
943 fTable.setItemCount((int) fTrace.getNbEvents() + 1); // +1 for header row
944 } else {
945 fTable.setItemCount(1); // +1 for header row
946 }
947 fFilterMatchCount = 0;
948 fFilterCheckCount = 0;
949 if (fSelectedRank >= 0) {
950 fTable.setSelection((int) fSelectedRank + 1); // +1 for header row
951 } else {
952 fTable.setSelection(0);
953 }
954 fireFilterApplied(null);
955 }
956
957 protected class FilterThread extends Thread {
958 private final ITmfFilterTreeNode filter;
959 private TmfEventRequest<TmfEvent> request;
960 private boolean refreshBusy = false;
961 private boolean refreshPending = false;
962 private Object syncObj = new Object();
963
964 public FilterThread(ITmfFilterTreeNode filter) {
965 super("Filter Thread"); //$NON-NLS-1$
966 this.filter = filter;
967 }
968
969 @SuppressWarnings("unchecked")
970 @Override
971 public void run() {
972 if (fTrace == null) {
973 return;
974 }
975 int nbRequested = (int) (fTrace.getNbEvents() - fFilterCheckCount);
976 if (nbRequested <= 0) {
977 return;
978 }
979 request = new TmfEventRequest<TmfEvent>(TmfEvent.class, TmfTimeRange.Eternity, (int) fFilterCheckCount,
980 nbRequested, fTrace.getCacheSize(), ExecutionType.BACKGROUND) {
981 @Override
982 public void handleData(TmfEvent event) {
983 super.handleData(event);
984 if (request.isCancelled())
985 return;
986 if (filter.matches(event)) {
987 long rank = fFilterCheckCount;
988 int index = (int) fFilterMatchCount;
989 fFilterMatchCount++;
990 fCache.storeEvent(event.clone(), rank, index);
991 refreshTable();
992 } else if (fFilterCheckCount % 100 == 0) {
993 refreshTable();
994 }
995 fFilterCheckCount++;
996 }
997 };
998 ((ITmfDataProvider<TmfEvent>) fTrace).sendRequest(request);
999 try {
1000 request.waitForCompletion();
1001 } catch (InterruptedException e) {
1002 }
1003 refreshTable();
1004 }
1005
1006 public void refreshTable() {
1007 synchronized (syncObj) {
1008 if (refreshBusy) {
1009 refreshPending = true;
1010 return;
1011 } else {
1012 refreshBusy = true;
1013 }
1014 }
1015 Display.getDefault().asyncExec(new Runnable() {
1016 @Override
1017 public void run() {
1018 if (request.isCancelled())
1019 return;
1020 if (fTable.isDisposed())
1021 return;
1022 fTable.setItemCount((int) fFilterMatchCount + 3); // +1 for header row, +2 for top and bottom filter
1023 // status rows
1024 fTable.refresh();
1025 synchronized (syncObj) {
1026 refreshBusy = false;
1027 if (refreshPending) {
1028 refreshPending = false;
1029 refreshTable();
1030 }
1031 }
1032 }
1033 });
1034 }
1035
1036 public void cancel() {
1037 if (request != null) {
1038 request.cancel();
1039 }
1040 }
1041 }
1042
1043 protected void searchNext() {
1044 synchronized (fSearchSyncObj) {
1045 if (fSearchThread != null) {
1046 return;
1047 }
1048 final ITmfFilterTreeNode searchFilter = (ITmfFilterTreeNode) fTable.getData(Key.SEARCH_OBJ);
1049 if (searchFilter == null) {
1050 return;
1051 }
1052 int selectionIndex = fTable.getSelectionIndex();
1053 int startIndex;
1054 if (selectionIndex > 0) {
1055 startIndex = selectionIndex; // -1 for header row, +1 for next event
1056 } else {
1057 // header row is selected, start at top event
1058 startIndex = Math.max(0, fTable.getTopIndex() - 1); // -1 for header row
1059 }
1060 final ITmfFilterTreeNode eventFilter = (ITmfFilterTreeNode) fTable.getData(Key.FILTER_OBJ);
1061 if (eventFilter != null) {
1062 startIndex = Math.max(0, startIndex - 1); // -1 for top filter status row
1063 }
1064 fSearchThread = new SearchThread(searchFilter, eventFilter, startIndex, fSelectedRank, Direction.FORWARD);
1065 fSearchThread.schedule();
1066 }
1067 }
1068
1069 protected void searchPrevious() {
1070 synchronized (fSearchSyncObj) {
1071 if (fSearchThread != null) {
1072 return;
1073 }
1074 final ITmfFilterTreeNode searchFilter = (ITmfFilterTreeNode) fTable.getData(Key.SEARCH_OBJ);
1075 if (searchFilter == null) {
1076 return;
1077 }
1078 int selectionIndex = fTable.getSelectionIndex();
1079 int startIndex;
1080 if (selectionIndex > 0) {
1081 startIndex = selectionIndex - 2; // -1 for header row, -1 for previous event
1082 } else {
1083 // header row is selected, start at precedent of top event
1084 startIndex = fTable.getTopIndex() - 2; // -1 for header row, -1 for previous event
1085 }
1086 final ITmfFilterTreeNode eventFilter = (ITmfFilterTreeNode) fTable.getData(Key.FILTER_OBJ);
1087 if (eventFilter != null) {
1088 startIndex = startIndex - 1; // -1 for top filter status row
1089 }
1090 fSearchThread = new SearchThread(searchFilter, eventFilter, startIndex, fSelectedRank, Direction.BACKWARD);
1091 fSearchThread.schedule();
1092 }
1093 }
1094
1095 protected void stopSearchThread() {
1096 fPendingGotoRank = -1;
1097 synchronized (fSearchSyncObj) {
1098 if (fSearchThread != null) {
1099 fSearchThread.cancel();
1100 fSearchThread = null;
1101 }
1102 }
1103 }
1104
1105 protected class SearchThread extends Job {
1106 protected ITmfFilterTreeNode searchFilter;
1107 protected ITmfFilterTreeNode eventFilter;
1108 protected int startIndex;
1109 protected int direction;
1110 protected long rank;
1111 protected long foundRank = -1;
1112 protected TmfDataRequest<TmfEvent> request;
1113
1114 public SearchThread(ITmfFilterTreeNode searchFilter, ITmfFilterTreeNode eventFilter, int startIndex,
1115 long currentRank, int direction) {
1116 super(Messages.TmfEventsTable_SearchingJobName);
1117 this.searchFilter = searchFilter;
1118 this.eventFilter = eventFilter;
1119 this.startIndex = startIndex;
1120 this.rank = currentRank;
1121 this.direction = direction;
1122 }
1123
1124 @SuppressWarnings("unchecked")
1125 @Override
1126 protected IStatus run(final IProgressMonitor monitor) {
1127 if (fTrace == null) {
1128 return Status.OK_STATUS;
1129 }
1130 final Display display = Display.getDefault();
1131 if (startIndex < 0) {
1132 rank = (int) fTrace.getNbEvents() - 1;
1133 } else if (startIndex >= fTable.getItemCount() - (eventFilter == null ? 1 : 3)) { // -1 for header row, -2
1134 // for top and bottom
1135 // filter status rows
1136 rank = 0;
1137 } else {
1138 int idx = startIndex;
1139 while (foundRank == -1) {
1140 CachedEvent event = fCache.peekEvent(idx);
1141 if (event == null) {
1142 break;
1143 }
1144 rank = event.rank;
1145 if (searchFilter.matches(event.event) && (eventFilter == null || eventFilter.matches(event.event))) {
1146 foundRank = event.rank;
1147 break;
1148 }
1149 if (direction == Direction.FORWARD) {
1150 idx++;
1151 } else {
1152 idx--;
1153 }
1154 }
1155 if (foundRank == -1) {
1156 if (direction == Direction.FORWARD) {
1157 rank++;
1158 if (rank > fTrace.getNbEvents() - 1) {
1159 rank = 0;
1160 }
1161 } else {
1162 rank--;
1163 if (rank < 0) {
1164 rank = (int) fTrace.getNbEvents() - 1;
1165 }
1166 }
1167 }
1168 }
1169 int startRank = (int) rank;
1170 boolean wrapped = false;
1171 while (!monitor.isCanceled() && foundRank == -1 && fTrace != null) {
1172 int nbRequested = (direction == Direction.FORWARD ? Integer.MAX_VALUE : Math.min((int) rank + 1,
1173 fTrace.getCacheSize()));
1174 if (direction == Direction.BACKWARD) {
1175 rank = Math.max(0, rank - fTrace.getCacheSize() + 1);
1176 }
1177 request = new TmfDataRequest<TmfEvent>(TmfEvent.class, (int) rank, nbRequested) {
1178 long currentRank = rank;
1179
1180 @Override
1181 public void handleData(TmfEvent event) {
1182 super.handleData(event);
1183 if (searchFilter.matches(event) && (eventFilter == null || eventFilter.matches(event))) {
1184 foundRank = currentRank;
1185 if (direction == Direction.FORWARD) {
1186 done();
1187 return;
1188 }
1189 }
1190 currentRank++;
1191 }
1192 };
1193 ((ITmfDataProvider<TmfEvent>) fTrace).sendRequest(request);
1194 try {
1195 request.waitForCompletion();
1196 if (request.isCancelled()) {
1197 return Status.OK_STATUS;
1198 }
1199 } catch (InterruptedException e) {
1200 synchronized (fSearchSyncObj) {
1201 fSearchThread = null;
1202 }
1203 return Status.OK_STATUS;
1204 }
1205 if (foundRank == -1) {
1206 if (direction == Direction.FORWARD) {
1207 if (rank == 0) {
1208 synchronized (fSearchSyncObj) {
1209 fSearchThread = null;
1210 }
1211 return Status.OK_STATUS;
1212 } else {
1213 nbRequested = (int) rank;
1214 rank = 0;
1215 wrapped = true;
1216 }
1217 } else {
1218 rank--;
1219 if (rank < 0) {
1220 rank = (int) fTrace.getNbEvents() - 1;
1221 wrapped = true;
1222 }
1223 if (rank <= startRank && wrapped) {
1224 synchronized (fSearchSyncObj) {
1225 fSearchThread = null;
1226 }
1227 return Status.OK_STATUS;
1228 }
1229 }
1230 }
1231 }
1232 int index = (int) foundRank;
1233 if (eventFilter != null) {
1234 index = fCache.getFilteredEventIndex(foundRank);
1235 }
1236 final int selection = index + 1 + (eventFilter != null ? +1 : 0); // +1 for header row, +1 for top filter
1237 // status row
1238
1239 display.asyncExec(new Runnable() {
1240 @Override
1241 public void run() {
1242 if (monitor.isCanceled())
1243 return;
1244 if (fTable.isDisposed())
1245 return;
1246 fTable.setSelection(selection);
1247 fSelectedRank = foundRank;
1248 synchronized (fSearchSyncObj) {
1249 fSearchThread = null;
1250 }
1251 }
1252 });
1253 return Status.OK_STATUS;
1254 }
1255
1256 @Override
1257 protected void canceling() {
1258 request.cancel();
1259 synchronized (fSearchSyncObj) {
1260 fSearchThread = null;
1261 }
1262 }
1263 }
1264
1265 protected void createResources() {
1266 fGrayColor = fResourceManager.createColor(ColorUtil.blend(fTable.getBackground().getRGB(), fTable
1267 .getForeground().getRGB()));
1268 fGreenColor = fTable.getDisplay().getSystemColor(SWT.COLOR_DARK_GREEN);
1269 fBoldFont = fResourceManager.createFont(FontDescriptor.createFrom(fTable.getFont()).setStyle(SWT.BOLD));
1270 }
1271
1272 protected void packColumns() {
1273 if (fPackDone)
1274 return;
1275 for (TableColumn column : fTable.getColumns()) {
1276 int headerWidth = column.getWidth();
1277 column.pack();
1278 if (column.getWidth() < headerWidth) {
1279 column.setWidth(headerWidth);
1280 }
1281 }
1282 fPackDone = true;
1283 }
1284
1285 /**
1286 * @param event
1287 * @return
1288 *
1289 * FIXME: Add support for column selection
1290 */
1291 protected String[] extractItemFields(TmfEvent event) {
1292 String[] fields = new String[0];
1293 if (event != null) {
1294 fields = new String[] { new Long(event.getTimestamp().getValue()).toString(),
1295 event.getSource(), event.getType().getId(),
1296 event.getReference(), event.getContent().toString() };
1297 }
1298 return fields;
1299 }
1300
1301 public void setFocus() {
1302 fTable.setFocus();
1303 }
1304
1305 /**
1306 * @param trace
1307 * @param disposeOnClose
1308 * true if the trace should be disposed when the table is disposed
1309 */
1310 public void setTrace(ITmfTrace<?> trace, boolean disposeOnClose) {
1311 if (fTrace != null && fDisposeOnClose) {
1312 fTrace.dispose();
1313 }
1314 fTrace = trace;
1315 fPackDone = false;
1316 fSelectedRank = 0;
1317 fDisposeOnClose = disposeOnClose;
1318
1319 // Perform the updates on the UI thread
1320 fTable.getDisplay().syncExec(new Runnable() {
1321 @Override
1322 public void run() {
1323 fTable.removeAll();
1324 fCache.setTrace(fTrace); // Clear the cache
1325 if (fTrace != null) {
1326 if (!fTable.isDisposed() && fTrace != null) {
1327 if (fTable.getData(Key.FILTER_OBJ) == null) {
1328 fTable.setItemCount((int) fTrace.getNbEvents() + 1); // +1 for header row
1329 } else {
1330 stopFilterThread();
1331 fFilterMatchCount = 0;
1332 fFilterCheckCount = 0;
1333 fTable.setItemCount(3); // +1 for header row, +2 for top and bottom filter status rows
1334 startFilterThread();
1335 }
1336 }
1337 fRawViewer.setTrace(fTrace);
1338 }
1339 }
1340 });
1341 }
1342
1343 // ------------------------------------------------------------------------
1344 // Event cache
1345 // ------------------------------------------------------------------------
1346
1347 public void cacheUpdated(final boolean completed) {
1348 synchronized (fCacheUpdateSyncObj) {
1349 if (fCacheUpdateBusy) {
1350 fCacheUpdatePending = true;
1351 fCacheUpdateCompleted = completed;
1352 return;
1353 } else {
1354 fCacheUpdateBusy = true;
1355 }
1356 }
1357 // Event cache is now updated. Perform update on the UI thread
1358 if (!fTable.isDisposed()) {
1359 fTable.getDisplay().asyncExec(new Runnable() {
1360 @Override
1361 public void run() {
1362 if (!fTable.isDisposed()) {
1363 fTable.refresh();
1364 packColumns();
1365 }
1366 if (completed) {
1367 populateCompleted();
1368 }
1369 synchronized (fCacheUpdateSyncObj) {
1370 fCacheUpdateBusy = false;
1371 if (fCacheUpdatePending) {
1372 fCacheUpdatePending = false;
1373 cacheUpdated(fCacheUpdateCompleted);
1374 }
1375 }
1376 }
1377 });
1378 }
1379 }
1380
1381 protected void populateCompleted() {
1382 // Nothing by default;
1383 }
1384
1385 // ------------------------------------------------------------------------
1386 // Bookmark handling
1387 // ------------------------------------------------------------------------
1388
1389 public void addBookmark(IResource resource) {
1390 fBookmarksResource = resource;
1391 TableItem[] selection = fTable.getSelection();
1392 if (selection.length > 0) {
1393 TableItem tableItem = selection[0];
1394 if (tableItem.getData(Key.RANK) != null) {
1395 StringBuffer defaultMessage = new StringBuffer();
1396 for (int i = 0; i < fTable.getColumns().length; i++) {
1397 if (i > 0) {
1398 defaultMessage.append(", "); //$NON-NLS-1$
1399 }
1400 defaultMessage.append(tableItem.getText(i));
1401 }
1402 InputDialog dialog = new InputDialog(PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell(),
1403 Messages.TmfEventsTable_AddBookmarkDialogTitle, Messages.TmfEventsTable_AddBookmarkDialogText,
1404 defaultMessage.toString(), null);
1405 if (dialog.open() == Dialog.OK) {
1406 String message = dialog.getValue();
1407 try {
1408 IMarker bookmark = resource.createMarker(IMarker.BOOKMARK);
1409 if (bookmark.exists()) {
1410 bookmark.setAttribute(IMarker.MESSAGE, message.toString());
1411 long rank = (Long) tableItem.getData(Key.RANK);
1412 int location = (int) rank;
1413 bookmark.setAttribute(IMarker.LOCATION, (Integer) location);
1414 fBookmarksMap.put(rank, bookmark.getId());
1415 fTable.refresh();
1416 }
1417 } catch (CoreException e) {
1418 e.printStackTrace();
1419 }
1420 }
1421 }
1422 }
1423
1424 }
1425
1426 public void removeBookmark(IMarker bookmark) {
1427 for (Entry<Long, Long> entry : fBookmarksMap.entrySet()) {
1428 if (entry.getValue().equals(bookmark.getId())) {
1429 fBookmarksMap.remove(entry.getKey());
1430 fTable.refresh();
1431 return;
1432 }
1433 }
1434 }
1435
1436 private void toggleBookmark(long rank) {
1437 if (fBookmarksResource == null) {
1438 return;
1439 }
1440 if (fBookmarksMap.containsKey(rank)) {
1441 Long markerId = fBookmarksMap.remove(rank);
1442 fTable.refresh();
1443 try {
1444 IMarker bookmark = fBookmarksResource.findMarker(markerId);
1445 if (bookmark != null) {
1446 bookmark.delete();
1447 }
1448 } catch (CoreException e) {
1449 e.printStackTrace();
1450 }
1451 } else {
1452 addBookmark(fBookmarksResource);
1453 }
1454 }
1455
1456 public void refreshBookmarks(IResource resource) {
1457 fBookmarksResource = resource;
1458 try {
1459 fBookmarksMap.clear();
1460 for (IMarker bookmark : resource.findMarkers(IMarker.BOOKMARK, false, IResource.DEPTH_ZERO)) {
1461 int location = bookmark.getAttribute(IMarker.LOCATION, -1);
1462 if (location != -1) {
1463 long rank = location;
1464 fBookmarksMap.put(rank, bookmark.getId());
1465 }
1466 }
1467 fTable.refresh();
1468 } catch (CoreException e) {
1469 e.printStackTrace();
1470 }
1471 }
1472
1473 @Override
1474 public void gotoMarker(IMarker marker) {
1475 int rank = marker.getAttribute(IMarker.LOCATION, -1);
1476 if (rank != -1) {
1477 int index = rank;
1478 if (fTable.getData(Key.FILTER_OBJ) != null) {
1479 index = fCache.getFilteredEventIndex(rank) + 1; // +1 for top filter status row
1480 } else if (rank >= fTable.getItemCount()) {
1481 fPendingGotoRank = rank;
1482 }
1483 fTable.setSelection(index + 1); // +1 for header row
1484 }
1485 }
1486
1487 // ------------------------------------------------------------------------
1488 // Listeners
1489 // ------------------------------------------------------------------------
1490
1491 /*
1492 * (non-Javadoc)
1493 *
1494 * @see
1495 * org.eclipse.linuxtools.tmf.ui.views.colors.IColorSettingsListener#colorSettingsChanged(org.eclipse.linuxtools
1496 * .tmf.ui.views.colors.ColorSetting[])
1497 */
1498 @Override
1499 public void colorSettingsChanged(ColorSetting[] colorSettings) {
1500 fTable.refresh();
1501 }
1502
1503 @Override
1504 public void addEventsFilterListener(ITmfEventsFilterListener listener) {
1505 if (!fEventsFilterListeners.contains(listener)) {
1506 fEventsFilterListeners.add(listener);
1507 }
1508 }
1509
1510 @Override
1511 public void removeEventsFilterListener(ITmfEventsFilterListener listener) {
1512 fEventsFilterListeners.remove(listener);
1513 }
1514
1515 // ------------------------------------------------------------------------
1516 // Signal handlers
1517 // ------------------------------------------------------------------------
1518
1519 // @TmfSignalHandler
1520 // public void experimentUpdated(TmfExperimentUpdatedSignal signal) {
1521 // if ((signal.getExperiment() != fTrace) || fTable.isDisposed()) return;
1522 // // Perform the refresh on the UI thread
1523 // Display.getDefault().asyncExec(new Runnable() {
1524 // @Override
1525 // public void run() {
1526 // if (!fTable.isDisposed() && fTrace != null) {
1527 // if (fTable.getData(Key.FILTER_OBJ) == null) {
1528 // fTable.setItemCount((int) fTrace.getNbEvents() + 1); // +1 for header row
1529 // if (fPendingGotoRank != -1 && fPendingGotoRank + 1 < fTable.getItemCount()) { // +1 for header row
1530 // fTable.setSelection((int) fPendingGotoRank + 1); // +1 for header row
1531 // fPendingGotoRank = -1;
1532 // }
1533 // } else {
1534 // startFilterThread();
1535 // }
1536 // }
1537 // if (!fRawViewer.isDisposed() && fTrace != null) {
1538 // fRawViewer.refreshEventCount();
1539 // }
1540 // }
1541 // });
1542 // }
1543
1544 @TmfSignalHandler
1545 public void experimentUpdated(TmfExperimentRangeUpdatedSignal signal) {
1546 if ((signal.getExperiment() != fTrace) || fTable.isDisposed())
1547 return;
1548 // Perform the refresh on the UI thread
1549 Display.getDefault().asyncExec(new Runnable() {
1550 @Override
1551 public void run() {
1552 if (!fTable.isDisposed() && fTrace != null) {
1553 if (fTable.getData(Key.FILTER_OBJ) == null) {
1554 fTable.setItemCount((int) fTrace.getNbEvents() + 1); // +1 for header row
1555 if (fPendingGotoRank != -1 && fPendingGotoRank + 1 < fTable.getItemCount()) { // +1 for header
1556 // row
1557 fTable.setSelection((int) fPendingGotoRank + 1); // +1 for header row
1558 fPendingGotoRank = -1;
1559 }
1560 } else {
1561 startFilterThread();
1562 }
1563 }
1564 if (!fRawViewer.isDisposed() && fTrace != null) {
1565 fRawViewer.refreshEventCount();
1566 }
1567 }
1568 });
1569 }
1570
1571 @TmfSignalHandler
1572 public void traceUpdated(TmfTraceUpdatedSignal signal) {
1573 if ((signal.getTrace() != fTrace) || fTable.isDisposed())
1574 return;
1575 // Perform the refresh on the UI thread
1576 Display.getDefault().asyncExec(new Runnable() {
1577 @Override
1578 public void run() {
1579 if (!fTable.isDisposed() && fTrace != null) {
1580 if (fTable.getData(Key.FILTER_OBJ) == null) {
1581 fTable.setItemCount((int) fTrace.getNbEvents() + 1); // +1 for header row
1582 if (fPendingGotoRank != -1 && fPendingGotoRank + 1 < fTable.getItemCount()) { // +1 for header
1583 // row
1584 fTable.setSelection((int) fPendingGotoRank + 1); // +1 for header row
1585 fPendingGotoRank = -1;
1586 }
1587 } else {
1588 startFilterThread();
1589 }
1590 }
1591 if (!fRawViewer.isDisposed() && fTrace != null) {
1592 fRawViewer.refreshEventCount();
1593 }
1594 }
1595 });
1596 }
1597
1598 @SuppressWarnings("unchecked")
1599 @TmfSignalHandler
1600 public void currentTimeUpdated(final TmfTimeSynchSignal signal) {
1601 if ((signal.getSource() != fTable) && (fTrace != null) && (!fTable.isDisposed())) {
1602
1603 // Create a request for one event that will be queued after other ongoing requests. When this request is
1604 // completed
1605 // do the work to select the actual event with the timestamp specified in the signal. This procedure
1606 // prevents
1607 // the method fTrace.getRank() from interfering and delaying ongoing requests.
1608 final TmfDataRequest<TmfEvent> subRequest = new TmfDataRequest<TmfEvent>(TmfEvent.class, 0, 1,
1609 ExecutionType.FOREGROUND) {
1610
1611 TmfTimestamp ts = new TmfTimestamp(signal.getCurrentTime());
1612
1613 @Override
1614 public void handleData(TmfEvent event) {
1615 super.handleData(event);
1616 }
1617
1618 @Override
1619 public void handleCompleted() {
1620 super.handleCompleted();
1621 if (fTrace == null) {
1622 return;
1623 }
1624 // Verify if event is within the trace range
1625 final ITmfTimestamp timestamp[] = new TmfTimestamp[1];
1626 timestamp[0] = ts; // signal.getCurrentTime();
1627 if (timestamp[0].compareTo(fTrace.getStartTime(), true) == -1) {
1628 timestamp[0] = fTrace.getStartTime();
1629 }
1630 if (timestamp[0].compareTo(fTrace.getEndTime(), true) == 1) {
1631 timestamp[0] = fTrace.getEndTime();
1632 }
1633
1634 // Get the rank for the event selection in the table
1635 final long rank = fTrace.getRank(timestamp[0]);
1636 fSelectedRank = rank;
1637
1638 fTable.getDisplay().asyncExec(new Runnable() {
1639 @Override
1640 public void run() {
1641 // Return if table is disposed
1642 if (fTable.isDisposed())
1643 return;
1644
1645 int index = (int) rank;
1646 if (fTable.isDisposed())
1647 return;
1648 if (fTable.getData(Key.FILTER_OBJ) != null) {
1649 index = fCache.getFilteredEventIndex(rank) + 1; // +1 for top filter status row
1650 }
1651 fTable.setSelection(index + 1); // +1 for header row
1652 fRawViewer.selectAndReveal(rank);
1653 }
1654 });
1655 }
1656 };
1657
1658 ((ITmfDataProvider<TmfEvent>) fTrace).sendRequest(subRequest);
1659 }
1660 }
1661
1662 }
This page took 0.0723780000000001 seconds and 5 git commands to generate.