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