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