analysis: Add count column to latency statistics view
[deliverable/tracecompass.git] / tmf / org.eclipse.tracecompass.tmf.ui / src / org / eclipse / tracecompass / tmf / ui / views / timegraph / AbstractTimeGraphView.java
CommitLineData
4999a196 1/*******************************************************************************
8910dea2 2 * Copyright (c) 2012, 2016 Ericsson, École Polytechnique de Montréal
4999a196
GB
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 * Patrick Tasse - Initial API and implementation
11 * Bernd Hufmann - Updated signal handling
12 * Geneviève Bastien - Move code to provide base classes for time graph view
c1cd9635 13 * Marc-Andre Laperle - Add time zone preference
bec1f1ac 14 * Geneviève Bastien - Add event links between entries
4999a196
GB
15 *******************************************************************************/
16
2bdf0193 17package org.eclipse.tracecompass.tmf.ui.views.timegraph;
4999a196 18
24333461
PT
19import static org.eclipse.tracecompass.common.core.NonNullUtils.checkNotNull;
20
4999a196 21import java.util.ArrayList;
4999a196
GB
22import java.util.Collections;
23import java.util.Comparator;
24import java.util.HashMap;
a924e2ed 25import java.util.LinkedHashSet;
4999a196
GB
26import java.util.List;
27import java.util.Map;
91512088 28import java.util.Set;
1cf25311 29import java.util.concurrent.CopyOnWriteArrayList;
156e9ead 30import java.util.concurrent.atomic.AtomicInteger;
9c274768
PT
31import java.util.regex.Matcher;
32import java.util.regex.Pattern;
33
34import org.eclipse.core.resources.IFile;
35import org.eclipse.core.resources.IMarker;
36import org.eclipse.core.resources.IMarkerDelta;
37import org.eclipse.core.resources.IResource;
38import org.eclipse.core.resources.IResourceChangeEvent;
39import org.eclipse.core.resources.IResourceChangeListener;
40import org.eclipse.core.resources.IWorkspaceRunnable;
41import org.eclipse.core.resources.ResourcesPlugin;
42import org.eclipse.core.runtime.CoreException;
4999a196
GB
43import org.eclipse.core.runtime.IProgressMonitor;
44import org.eclipse.core.runtime.NullProgressMonitor;
dfa0ef96 45import org.eclipse.jdt.annotation.NonNull;
d2120fb6 46import org.eclipse.jdt.annotation.Nullable;
4999a196 47import org.eclipse.jface.action.Action;
90bb3a0c 48import org.eclipse.jface.action.GroupMarker;
747adf5c 49import org.eclipse.jface.action.IAction;
90bb3a0c 50import org.eclipse.jface.action.IMenuListener;
91512088 51import org.eclipse.jface.action.IMenuManager;
0fcf3b09 52import org.eclipse.jface.action.IStatusLineManager;
4999a196 53import org.eclipse.jface.action.IToolBarManager;
90bb3a0c 54import org.eclipse.jface.action.MenuManager;
4999a196 55import org.eclipse.jface.action.Separator;
36299425 56import org.eclipse.jface.commands.ActionHandler;
5d021ccf 57import org.eclipse.jface.viewers.AbstractTreeViewer;
40b7b614 58import org.eclipse.jface.viewers.ILabelProvider;
4999a196 59import org.eclipse.jface.viewers.ILabelProviderListener;
747adf5c 60import org.eclipse.jface.viewers.ISelectionProvider;
4999a196 61import org.eclipse.jface.viewers.ITableLabelProvider;
cfcfd964 62import org.eclipse.jface.viewers.ITreeContentProvider;
82467e47 63import org.eclipse.jface.viewers.TreeSelection;
747adf5c 64import org.eclipse.jface.viewers.TreeViewer;
4923d7b9 65import org.eclipse.jface.viewers.ViewerFilter;
7697e148 66import org.eclipse.osgi.util.NLS;
4999a196 67import org.eclipse.swt.SWT;
9bdf1671
BH
68import org.eclipse.swt.events.MenuDetectEvent;
69import org.eclipse.swt.events.MenuDetectListener;
a4cddcbc
BH
70import org.eclipse.swt.events.SelectionAdapter;
71import org.eclipse.swt.events.SelectionEvent;
4999a196 72import org.eclipse.swt.graphics.Image;
9bdf1671 73import org.eclipse.swt.graphics.Point;
8910dea2 74import org.eclipse.swt.graphics.RGBA;
4999a196
GB
75import org.eclipse.swt.widgets.Composite;
76import org.eclipse.swt.widgets.Display;
90bb3a0c 77import org.eclipse.swt.widgets.Menu;
36299425 78import org.eclipse.swt.widgets.Shell;
a4cddcbc 79import org.eclipse.swt.widgets.Tree;
4999a196 80import org.eclipse.swt.widgets.TreeColumn;
9c274768 81import org.eclipse.tracecompass.internal.tmf.ui.Activator;
7697e148 82import org.eclipse.tracecompass.tmf.core.resources.ITmfMarker;
97c71024 83import org.eclipse.tracecompass.tmf.core.signal.TmfSelectionRangeUpdatedSignal;
d2e4afa7 84import org.eclipse.tracecompass.tmf.core.signal.TmfSignalHandler;
2bdf0193
AM
85import org.eclipse.tracecompass.tmf.core.signal.TmfTimestampFormatUpdateSignal;
86import org.eclipse.tracecompass.tmf.core.signal.TmfTraceClosedSignal;
87import org.eclipse.tracecompass.tmf.core.signal.TmfTraceOpenedSignal;
88import org.eclipse.tracecompass.tmf.core.signal.TmfTraceSelectedSignal;
d2e4afa7 89import org.eclipse.tracecompass.tmf.core.signal.TmfWindowRangeUpdatedSignal;
2bdf0193
AM
90import org.eclipse.tracecompass.tmf.core.timestamp.TmfNanoTimestamp;
91import org.eclipse.tracecompass.tmf.core.timestamp.TmfTimeRange;
92import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace;
24333461 93import org.eclipse.tracecompass.tmf.core.trace.TmfTraceAdapterManager;
21852dfa 94import org.eclipse.tracecompass.tmf.core.trace.TmfTraceContext;
2bdf0193
AM
95import org.eclipse.tracecompass.tmf.core.trace.TmfTraceManager;
96import org.eclipse.tracecompass.tmf.ui.TmfUiRefreshHandler;
d2e4afa7
MAL
97import org.eclipse.tracecompass.tmf.ui.signal.TmfTimeViewAlignmentInfo;
98import org.eclipse.tracecompass.tmf.ui.views.ITmfTimeAligned;
2bdf0193 99import org.eclipse.tracecompass.tmf.ui.views.TmfView;
9c274768 100import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.ITimeGraphBookmarkListener;
2bdf0193
AM
101import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.ITimeGraphContentProvider;
102import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.ITimeGraphPresentationProvider2;
103import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.ITimeGraphRangeListener;
104import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.ITimeGraphSelectionListener;
105import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.ITimeGraphTimeListener;
9c274768 106import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.TimeGraphBookmarkEvent;
2bdf0193 107import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.TimeGraphCombo;
d8a230f8 108import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.TimeGraphContentProvider;
2bdf0193
AM
109import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.TimeGraphPresentationProvider;
110import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.TimeGraphRangeUpdateEvent;
111import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.TimeGraphTimeEvent;
112import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.TimeGraphViewer;
113import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.model.ILinkEvent;
e790b877 114import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.model.IMarkerEvent;
24333461 115import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.model.IMarkerEventSource;
2bdf0193
AM
116import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.model.ITimeEvent;
117import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.model.ITimeGraphEntry;
9c274768 118import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.model.MarkerEvent;
2bdf0193 119import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.model.TimeGraphEntry;
9bdf1671 120import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.widgets.TimeGraphControl;
2bdf0193 121import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.widgets.Utils.TimeFormat;
4999a196 122import org.eclipse.ui.IActionBars;
36299425 123import org.eclipse.ui.IPartListener;
90bb3a0c 124import org.eclipse.ui.IWorkbenchActionConstants;
36299425
JCK
125import org.eclipse.ui.IWorkbenchPart;
126import org.eclipse.ui.PlatformUI;
127import org.eclipse.ui.actions.ActionFactory;
128import org.eclipse.ui.handlers.IHandlerActivation;
129import org.eclipse.ui.handlers.IHandlerService;
4999a196
GB
130
131/**
132 * An abstract view all time graph views can inherit
133 *
747adf5c
PT
134 * This view contains either a time graph viewer, or a time graph combo which is
135 * divided between a tree viewer on the left and a time graph viewer on the right.
4999a196 136 */
9c274768 137public abstract class AbstractTimeGraphView extends TmfView implements ITmfTimeAligned, IResourceChangeListener {
4999a196 138
5d021ccf
GB
139 /** Constant indicating that all levels of the time graph should be expanded */
140 protected static final int ALL_LEVELS = AbstractTreeViewer.ALL_LEVELS;
141
9c274768
PT
142 private static final Pattern RGBA_PATTERN = Pattern.compile("RGBA \\{(\\d+), (\\d+), (\\d+), (\\d+)\\}"); //$NON-NLS-1$
143
4999a196
GB
144 /**
145 * Redraw state enum
146 */
147 private enum State {
148 IDLE, BUSY, PENDING
149 }
150
151 // ------------------------------------------------------------------------
152 // Fields
153 // ------------------------------------------------------------------------
154
747adf5c
PT
155 /** The timegraph wrapper */
156 private ITimeGraphWrapper fTimeGraphWrapper;
4999a196 157
156e9ead
MAL
158 private AtomicInteger fDirty = new AtomicInteger();
159
6d28f3e8
MAL
160 private final Object fZoomThreadResultLock = new Object();
161
4999a196
GB
162 /** The selected trace */
163 private ITmfTrace fTrace;
164
9c274768
PT
165 /** The selected trace editor file*/
166 private IFile fEditorFile;
167
4999a196
GB
168 /** The timegraph entry list */
169 private List<TimeGraphEntry> fEntryList;
170
171 /** The trace to entry list hash map */
507b1336 172 private final Map<ITmfTrace, List<TimeGraphEntry>> fEntryListMap = new HashMap<>();
4999a196 173
4923d7b9 174 /** The trace to filters hash map */
2b7da5ec 175 private final Map<ITmfTrace, @NonNull ViewerFilter[]> fFiltersMap = new HashMap<>();
4923d7b9 176
1e5c4376
BH
177 /** The trace to view context hash map */
178 private final Map<ITmfTrace, ViewContext> fViewContext = new HashMap<>();
179
24333461
PT
180 /** The trace to marker event sources hash map */
181 private final Map<ITmfTrace, List<IMarkerEventSource>> fMarkerEventSourcesMap = new HashMap<>();
182
1cf25311 183 /** The trace to build thread hash map */
507b1336 184 private final Map<ITmfTrace, BuildThread> fBuildThreadMap = new HashMap<>();
4999a196
GB
185
186 /** The start time */
335b04e6 187 private long fStartTime = SWT.DEFAULT;
4999a196
GB
188
189 /** The end time */
335b04e6 190 private long fEndTime = SWT.DEFAULT;
4999a196
GB
191
192 /** The display width */
193 private final int fDisplayWidth;
194
195 /** The zoom thread */
196 private ZoomThread fZoomThread;
197
198 /** The next resource action */
199 private Action fNextResourceAction;
200
201 /** The previous resource action */
202 private Action fPreviousResourceAction;
203
4999a196
GB
204 /** A comparator class */
205 private Comparator<ITimeGraphEntry> fEntryComparator = null;
206
1cf25311 207 /** The redraw state used to prevent unnecessary queuing of display runnables */
4999a196
GB
208 private State fRedrawState = State.IDLE;
209
210 /** The redraw synchronization object */
211 private final Object fSyncObj = new Object();
212
213 /** The presentation provider for this view */
214 private final TimeGraphPresentationProvider fPresentation;
215
747adf5c
PT
216 /** The tree column label array, or null if combo is not used */
217 private String[] fColumns;
218
a4cddcbc
BH
219 private Comparator<ITimeGraphEntry>[] fColumnComparators;
220
747adf5c
PT
221 /** The tree label provider, or null if combo is not used */
222 private TreeLabelProvider fLabelProvider = null;
223
a12aae87
GB
224 /** The time graph content provider */
225 private @NonNull ITimeGraphContentProvider fTimeGraphContentProvider = new TimeGraphContentProvider();
226
747adf5c 227 /** The relative weight of the sash, ignored if combo is not used */
59387be3 228 private int[] fWeight = { 1, 3 };
747adf5c
PT
229
230 /** The filter column label array, or null if filter is not used */
231 private String[] fFilterColumns;
4999a196 232
1cf25311
PT
233 /** The pack done flag */
234 private boolean fPackDone = false;
235
737792b6
PT
236 /** The filter content provider, or null if filter is not used */
237 private ITreeContentProvider fFilterContentProvider;
238
a03b7ee4
PT
239 /** The filter label provider, or null if filter is not used */
240 private TreeLabelProvider fFilterLabelProvider;
241
5d021ccf
GB
242 private int fAutoExpandLevel = ALL_LEVELS;
243
a4cddcbc
BH
244 /** The default column index for sorting */
245 private int fInitialSortColumn = 0;
246
1e5c4376
BH
247 /** The default column index for sorting */
248 private int fCurrentSortColumn = 0;
249
250 /** The current sort direction */
251 private int fSortDirection = SWT.DOWN;
252
a4cddcbc
BH
253 /** Flag to indicate to reveal selection */
254 private volatile boolean fIsRevealSelection = false;
255
90bb3a0c
BH
256 /**
257 * Menu Manager for context-sensitive menu for time graph entries.
9bdf1671
BH
258 * This will be used on the tree viewer in case of the time graph combo
259 * or the on the namespace in case of a single time graph viewer.
90bb3a0c
BH
260 */
261 private final @NonNull MenuManager fEntryMenuManager = new MenuManager();
262
36299425
JCK
263 /** Time Graph View part listener */
264 private TimeGraphPartListener fPartListener;
265
266 /** Action for the find command. There is only one for all Time Graph views */
267 private static final ShowFindDialogAction FIND_ACTION = new ShowFindDialogAction();
268
269 /** The find action handler */
270 private static ActionHandler fFindActionHandler;
271
272 /** The find handler activation */
273 private static IHandlerActivation fFindHandlerActivation;
274
275 /** The find target to use */
276 private final FindTarget fFindTarget;
277
4999a196 278 // ------------------------------------------------------------------------
747adf5c 279 // Classes
4999a196
GB
280 // ------------------------------------------------------------------------
281
747adf5c 282 private interface ITimeGraphWrapper {
4999a196 283
cfcfd964
PT
284 void setTimeGraphContentProvider(ITimeGraphContentProvider timeGraphContentProvider);
285
286 void setTimeGraphPresentationProvider(TimeGraphPresentationProvider timeGraphPresentationProvider);
4999a196 287
747adf5c 288 TimeGraphViewer getTimeGraphViewer();
4999a196 289
cfcfd964 290 void addSelectionListener(ITimeGraphSelectionListener listener);
4999a196 291
747adf5c 292 ISelectionProvider getSelectionProvider();
4999a196 293
747adf5c 294 void setFocus();
4999a196 295
747adf5c 296 boolean isDisposed();
4999a196 297
747adf5c 298 void refresh();
4999a196 299
1cf25311
PT
300 void setInput(Object input);
301
302 Object getInput();
4999a196 303
367e2932 304 void setFilters(@NonNull ViewerFilter[] filters);
4923d7b9 305
367e2932 306 @NonNull ViewerFilter[] getFilters();
4923d7b9 307
747adf5c 308 void redraw();
4999a196 309
747adf5c 310 void update();
4999a196 311
5d021ccf
GB
312 void setAutoExpandLevel(int level);
313
82467e47
BH
314 boolean getExpandedState(ITimeGraphEntry entry);
315
316 void setExpandedState(ITimeGraphEntry entry, boolean expanded);
317
cfcfd964
PT
318 void setFilterColumns(String[] columnNames);
319
320 void setFilterContentProvider(ITreeContentProvider contentProvider);
321
322 void setFilterLabelProvider(ITableLabelProvider labelProvider);
323
324 IAction getShowFilterDialogAction();
325
d2e4afa7
MAL
326 void performAlign(int offset, int width);
327
328 TmfTimeViewAlignmentInfo getTimeViewAlignmentInfo();
329
330 int getAvailableWidth(int requestedOffset);
1e5c4376
BH
331
332 ITimeGraphEntry getSelection();
333
334 void setSelection(ITimeGraphEntry selection);
36299425
JCK
335
336 void selectAndReveal(@NonNull ITimeGraphEntry selection);
337
4999a196
GB
338 }
339
747adf5c
PT
340 private class TimeGraphViewerWrapper implements ITimeGraphWrapper {
341 private TimeGraphViewer viewer;
4999a196 342
747adf5c
PT
343 private TimeGraphViewerWrapper(Composite parent, int style) {
344 viewer = new TimeGraphViewer(parent, style);
4999a196 345 }
4999a196 346
747adf5c 347 @Override
cfcfd964
PT
348 public void setTimeGraphContentProvider(ITimeGraphContentProvider timeGraphContentProvider) {
349 viewer.setTimeGraphContentProvider(timeGraphContentProvider);
350 }
351
352 @Override
353 public void setTimeGraphPresentationProvider(TimeGraphPresentationProvider timeGraphPresentationProvider) {
354 viewer.setTimeGraphProvider(timeGraphPresentationProvider);
747adf5c 355 }
4999a196 356
747adf5c
PT
357 @Override
358 public TimeGraphViewer getTimeGraphViewer() {
359 return viewer;
360 }
4999a196 361
747adf5c
PT
362 @Override
363 public void addSelectionListener(ITimeGraphSelectionListener listener) {
364 viewer.addSelectionListener(listener);
365 }
4999a196 366
747adf5c
PT
367 @Override
368 public ISelectionProvider getSelectionProvider() {
369 return viewer.getSelectionProvider();
370 }
371
372 @Override
373 public void setFocus() {
374 viewer.setFocus();
375 }
376
377 @Override
378 public boolean isDisposed() {
379 return viewer.getControl().isDisposed();
380 }
381
382 @Override
1cf25311 383 public void setInput(Object input) {
747adf5c
PT
384 viewer.setInput(input);
385 }
386
1cf25311
PT
387 @Override
388 public Object getInput() {
389 return viewer.getInput();
390 }
391
cfcfd964
PT
392 @Override
393 public void setFilterColumns(String[] columnNames) {
394 viewer.setFilterColumns(columnNames);
395 }
396
397 @Override
398 public void setFilterContentProvider(ITreeContentProvider contentProvider) {
399 viewer.setFilterContentProvider(contentProvider);
400 }
401
402 @Override
403 public void setFilterLabelProvider(ITableLabelProvider labelProvider) {
404 viewer.setFilterLabelProvider(labelProvider);
405 }
406
4923d7b9 407 @Override
367e2932 408 public void setFilters(@NonNull ViewerFilter[] filters) {
4923d7b9
PT
409 viewer.setFilters(filters);
410 }
411
412 @Override
367e2932 413 public @NonNull ViewerFilter[] getFilters() {
4923d7b9
PT
414 return viewer.getFilters();
415 }
416
cfcfd964
PT
417 @Override
418 public IAction getShowFilterDialogAction() {
419 return viewer.getShowFilterDialogAction();
420 }
421
747adf5c
PT
422 @Override
423 public void refresh() {
424 viewer.refresh();
425 }
426
427 @Override
428 public void redraw() {
429 viewer.getControl().redraw();
430 }
431
432 @Override
433 public void update() {
434 viewer.getControl().update();
435 }
5d021ccf
GB
436
437 @Override
438 public void setAutoExpandLevel(int level) {
439 viewer.setAutoExpandLevel(level);
440 }
d2e4afa7 441
82467e47
BH
442 @Override
443 public boolean getExpandedState(ITimeGraphEntry entry) {
444 return viewer.getExpandedState(entry);
445 }
446
447 @Override
448 public void setExpandedState(ITimeGraphEntry entry, boolean expanded) {
449 viewer.setExpandedState(entry, expanded);
450 }
451
d2e4afa7
MAL
452 @Override
453 public void performAlign(int offset, int width) {
454 viewer.performAlign(offset, width);
455 }
456
457 @Override
458 public TmfTimeViewAlignmentInfo getTimeViewAlignmentInfo() {
459 return viewer.getTimeViewAlignmentInfo();
460 }
461
462 @Override
463 public int getAvailableWidth(int requestedOffset) {
464 return viewer.getAvailableWidth(requestedOffset);
465 }
1e5c4376
BH
466
467 @Override
468 public ITimeGraphEntry getSelection() {
469 return viewer.getSelection();
470 }
471
472 @Override
473 public void setSelection(ITimeGraphEntry selection) {
474 viewer.setSelection(selection);
475 }
36299425
JCK
476
477 @Override
478 public void selectAndReveal(@NonNull ITimeGraphEntry selection) {
479 viewer.selectAndReveal(selection);
480 }
4999a196
GB
481 }
482
747adf5c
PT
483 private class TimeGraphComboWrapper implements ITimeGraphWrapper {
484 private TimeGraphCombo combo;
485
486 private TimeGraphComboWrapper(Composite parent, int style) {
487 combo = new TimeGraphCombo(parent, style, fWeight);
488 }
489
490 @Override
cfcfd964
PT
491 public void setTimeGraphContentProvider(ITimeGraphContentProvider timeGraphContentProvider) {
492 combo.setTimeGraphContentProvider(timeGraphContentProvider);
493 }
494
495 @Override
496 public void setTimeGraphPresentationProvider(TimeGraphPresentationProvider timeGraphPresentationProvider) {
497 combo.setTimeGraphProvider(timeGraphPresentationProvider);
747adf5c
PT
498 }
499
500 @Override
501 public TimeGraphViewer getTimeGraphViewer() {
502 return combo.getTimeGraphViewer();
503 }
504
505 @Override
506 public void addSelectionListener(ITimeGraphSelectionListener listener) {
507 combo.addSelectionListener(listener);
508 }
509
510 @Override
511 public ISelectionProvider getSelectionProvider() {
512 return combo.getTreeViewer();
513 }
514
515 @Override
516 public void setFocus() {
517 combo.setFocus();
518 }
519
520 @Override
521 public boolean isDisposed() {
522 return combo.isDisposed();
523 }
524
525 @Override
1cf25311 526 public void setInput(Object input) {
747adf5c
PT
527 combo.setInput(input);
528 }
529
1cf25311
PT
530 @Override
531 public Object getInput() {
532 return combo.getInput();
533 }
534
cfcfd964
PT
535 @Override
536 public void setFilterColumns(String[] columnNames) {
537 combo.setFilterColumns(columnNames);
538 }
539
540 @Override
541 public void setFilterContentProvider(ITreeContentProvider contentProvider) {
542 combo.setFilterContentProvider(contentProvider);
543 }
544
545 @Override
546 public void setFilterLabelProvider(ITableLabelProvider labelProvider) {
547 combo.setFilterLabelProvider(labelProvider);
548 }
549
4923d7b9 550 @Override
367e2932 551 public void setFilters(@NonNull ViewerFilter[] filters) {
4923d7b9
PT
552 combo.setFilters(filters);
553 }
554
555 @Override
367e2932 556 public @NonNull ViewerFilter[] getFilters() {
4923d7b9
PT
557 return combo.getFilters();
558 }
559
cfcfd964
PT
560 @Override
561 public IAction getShowFilterDialogAction() {
562 return combo.getShowFilterDialogAction();
563 }
564
747adf5c
PT
565 @Override
566 public void refresh() {
567 combo.refresh();
568 }
569
570 @Override
571 public void redraw() {
572 combo.redraw();
573 }
574
575 @Override
576 public void update() {
577 combo.update();
578 }
579
5d021ccf
GB
580 @Override
581 public void setAutoExpandLevel(int level) {
582 combo.setAutoExpandLevel(level);
583 }
584
82467e47
BH
585 @Override
586 public boolean getExpandedState(ITimeGraphEntry entry) {
587 return combo.getExpandedState(entry);
588 }
589
590 @Override
591 public void setExpandedState(ITimeGraphEntry entry, boolean expanded) {
592 combo.setExpandedState(entry, expanded);
593 }
594
747adf5c
PT
595 TimeGraphCombo getTimeGraphCombo() {
596 return combo;
597 }
598
599 TreeViewer getTreeViewer() {
600 return combo.getTreeViewer();
601 }
602
d2e4afa7
MAL
603 @Override
604 public void performAlign(int offset, int width) {
605 combo.performAlign(offset, width);
606 }
607
608 @Override
609 public TmfTimeViewAlignmentInfo getTimeViewAlignmentInfo() {
610 return combo.getTimeViewAlignmentInfo();
611 }
612
613 @Override
614 public int getAvailableWidth(int requestedOffset) {
615 return combo.getAvailableWidth(requestedOffset);
616 }
1e5c4376
BH
617
618 @Override
619 public ITimeGraphEntry getSelection() {
620 return combo.getTimeGraphViewer().getSelection();
621 }
622
623 @Override
624 public void setSelection(ITimeGraphEntry selection) {
625 combo.setSelection(selection);
626 }
36299425
JCK
627
628 @Override
629 public void selectAndReveal(@NonNull ITimeGraphEntry selection) {
630 combo.selectAndReveal(selection);
631 }
747adf5c 632 }
4999a196 633
4999a196 634 /**
747adf5c
PT
635 * Base class to provide the labels for the tree viewer. Views extending
636 * this class typically need to override the getColumnText method if they
637 * have more than one column to display
4999a196 638 */
40b7b614 639 protected static class TreeLabelProvider implements ITableLabelProvider, ILabelProvider {
4999a196
GB
640
641 @Override
642 public void addListener(ILabelProviderListener listener) {
643 }
644
645 @Override
646 public void dispose() {
647 }
648
649 @Override
650 public boolean isLabelProperty(Object element, String property) {
651 return false;
652 }
653
654 @Override
655 public void removeListener(ILabelProviderListener listener) {
656 }
657
658 @Override
659 public Image getColumnImage(Object element, int columnIndex) {
660 return null;
661 }
662
663 @Override
664 public String getColumnText(Object element, int columnIndex) {
665 TimeGraphEntry entry = (TimeGraphEntry) element;
666 if (columnIndex == 0) {
667 return entry.getName();
668 }
76fccfb0 669 return new String();
4999a196
GB
670 }
671
40b7b614
GP
672 @Override
673 public Image getImage(Object element) {
674 return null;
675 }
676
40b7b614
GP
677 @Override
678 public String getText(Object element) {
679 TimeGraphEntry entry = (TimeGraphEntry) element;
680 return entry.getName();
681 }
682
4999a196
GB
683 }
684
685 private class BuildThread extends Thread {
dfa0ef96
GB
686 private final @NonNull ITmfTrace fBuildTrace;
687 private final @NonNull ITmfTrace fParentTrace;
688 private final @NonNull IProgressMonitor fMonitor;
4999a196 689
dfa0ef96 690 public BuildThread(final @NonNull ITmfTrace trace, final @NonNull ITmfTrace parentTrace, final String name) {
4999a196
GB
691 super(name + " build"); //$NON-NLS-1$
692 fBuildTrace = trace;
1cf25311 693 fParentTrace = parentTrace;
4999a196
GB
694 fMonitor = new NullProgressMonitor();
695 }
696
697 @Override
698 public void run() {
f8f46a52 699 buildEntryList(fBuildTrace, fParentTrace, fMonitor);
4999a196 700 synchronized (fBuildThreadMap) {
1cf25311 701 fBuildThreadMap.remove(fBuildTrace);
4999a196
GB
702 }
703 }
704
705 public void cancel() {
706 fMonitor.setCanceled(true);
707 }
708 }
709
6ae6c5bd
PT
710 /**
711 * Zoom thread
0336f981 712 * @since 1.1
6ae6c5bd
PT
713 */
714 protected abstract class ZoomThread extends Thread {
4999a196
GB
715 private final long fZoomStartTime;
716 private final long fZoomEndTime;
717 private final long fResolution;
dfa0ef96 718 private final @NonNull IProgressMonitor fMonitor;
4999a196 719
6ae6c5bd
PT
720 /**
721 * Constructor
722 *
723 * @param startTime
724 * the start time
725 * @param endTime
726 * the end time
727 * @param resolution
728 * the resolution
729 */
730 public ZoomThread(long startTime, long endTime, long resolution) {
731 super(AbstractTimeGraphView.this.getName() + " zoom"); //$NON-NLS-1$
4999a196
GB
732 fZoomStartTime = startTime;
733 fZoomEndTime = endTime;
6ae6c5bd 734 fResolution = resolution;
4999a196
GB
735 fMonitor = new NullProgressMonitor();
736 }
737
6ae6c5bd
PT
738 /**
739 * @return the zoom start time
740 */
741 public long getZoomStartTime() {
742 return fZoomStartTime;
743 }
744
745 /**
746 * @return the zoom end time
747 */
748 public long getZoomEndTime() {
749 return fZoomEndTime;
750 }
751
752 /**
753 * @return the resolution
754 */
755 public long getResolution() {
756 return fResolution;
757 }
758
759 /**
760 * @return the monitor
761 */
762 public @NonNull IProgressMonitor getMonitor() {
763 return fMonitor;
764 }
765
766 /**
767 * Cancel the zoom thread
768 */
769 public void cancel() {
770 fMonitor.setCanceled(true);
771 }
156e9ead
MAL
772
773 @Override
774 public final void run() {
775 doRun();
776 fDirty.decrementAndGet();
777 }
778
6d28f3e8
MAL
779 /**
780 * Applies the results of the ZoomThread calculations.
781 *
782 * Note: This method makes sure that only the results of the last
783 * created ZoomThread are applied.
784 *
785 * @param runnable
786 * the code to run in order to apply the results
787 * @since 2.0
788 */
789 protected void applyResults(Runnable runnable) {
790 synchronized (fZoomThreadResultLock) {
791 if (this == fZoomThread) {
792 runnable.run();
793 }
794 }
795 }
796
156e9ead
MAL
797 /**
798 * Run the zoom operation.
766ec163 799 * @since 2.0
156e9ead
MAL
800 */
801 public abstract void doRun();
6ae6c5bd
PT
802 }
803
804 private class ZoomThreadByEntry extends ZoomThread {
805 private final @NonNull List<TimeGraphEntry> fZoomEntryList;
806
807 public ZoomThreadByEntry(@NonNull List<TimeGraphEntry> entryList, long startTime, long endTime, long resolution) {
808 super(startTime, endTime, resolution);
809 fZoomEntryList = entryList;
810 }
811
4999a196 812 @Override
156e9ead 813 public void doRun() {
4999a196 814 for (TimeGraphEntry entry : fZoomEntryList) {
6ae6c5bd 815 if (getMonitor().isCanceled()) {
79ec0b89 816 return;
4999a196 817 }
dfa0ef96
GB
818 if (entry == null) {
819 break;
820 }
6ae6c5bd 821 zoom(entry, getMonitor());
4999a196 822 }
bec1f1ac 823 /* Refresh the arrows when zooming */
6ae6c5bd 824 List<ILinkEvent> events = getLinkList(getZoomStartTime(), getZoomEndTime(), getResolution(), getMonitor());
24333461
PT
825 /* Refresh the view-specific markers when zooming */
826 List<IMarkerEvent> markers = new ArrayList<>(getViewMarkerList(getZoomStartTime(), getZoomEndTime(), getResolution(), getMonitor()));
827 /* Refresh the trace-specific markers when zooming */
828 markers.addAll(getTraceMarkerList(getZoomStartTime(), getZoomEndTime(), getResolution(), getMonitor()));
6d28f3e8
MAL
829 applyResults(() -> {
830 if (events != null) {
831 fTimeGraphWrapper.getTimeGraphViewer().setLinks(events);
832 }
833 fTimeGraphWrapper.getTimeGraphViewer().setMarkers(markers);
834 redraw();
835 });
4999a196
GB
836 }
837
dfa0ef96 838 private void zoom(@NonNull TimeGraphEntry entry, @NonNull IProgressMonitor monitor) {
6ae6c5bd 839 if (getZoomStartTime() <= fStartTime && getZoomEndTime() >= fEndTime) {
6d28f3e8
MAL
840 applyResults(() -> {
841 entry.setZoomedEventList(null);
842 });
4999a196 843 } else {
6ae6c5bd 844 List<ITimeEvent> zoomedEventList = getEventList(entry, getZoomStartTime(), getZoomEndTime(), getResolution(), monitor);
4999a196 845 if (zoomedEventList != null) {
6d28f3e8
MAL
846 applyResults(() -> {
847 entry.setZoomedEventList(zoomedEventList);
848 });
4999a196
GB
849 }
850 }
851 redraw();
f8f46a52 852 for (TimeGraphEntry child : entry.getChildren()) {
6ae6c5bd 853 if (monitor.isCanceled()) {
4999a196
GB
854 return;
855 }
f8f46a52 856 zoom(child, monitor);
4999a196
GB
857 }
858 }
859
4999a196
GB
860 }
861
862 // ------------------------------------------------------------------------
863 // Constructors
864 // ------------------------------------------------------------------------
865
866 /**
747adf5c
PT
867 * Constructs a time graph view that contains either a time graph viewer or
868 * a time graph combo.
869 *
870 * By default, the view uses a time graph viewer. To use a time graph combo,
871 * the subclass constructor must call {@link #setTreeColumns(String[])} and
872 * {@link #setTreeLabelProvider(TreeLabelProvider)}.
4999a196
GB
873 *
874 * @param id
875 * The id of the view
4999a196
GB
876 * @param pres
877 * The presentation provider
878 */
747adf5c 879 public AbstractTimeGraphView(String id, TimeGraphPresentationProvider pres) {
4999a196 880 super(id);
4999a196
GB
881 fPresentation = pres;
882 fDisplayWidth = Display.getDefault().getBounds().width;
36299425 883 fFindTarget = new FindTarget();
4999a196
GB
884 }
885
886 // ------------------------------------------------------------------------
747adf5c 887 // Getters and setters
4999a196
GB
888 // ------------------------------------------------------------------------
889
747adf5c
PT
890 /**
891 * Getter for the time graph combo
892 *
893 * @return The time graph combo, or null if combo is not used
894 */
895 protected TimeGraphCombo getTimeGraphCombo() {
896 if (fTimeGraphWrapper instanceof TimeGraphComboWrapper) {
897 return ((TimeGraphComboWrapper) fTimeGraphWrapper).getTimeGraphCombo();
898 }
899 return null;
900 }
4999a196 901
747adf5c
PT
902 /**
903 * Getter for the time graph viewer
904 *
905 * @return The time graph viewer
906 */
907 protected TimeGraphViewer getTimeGraphViewer() {
908 return fTimeGraphWrapper.getTimeGraphViewer();
909 }
910
50c2da9e
GB
911 /**
912 * Getter for the presentation provider
913 *
914 * @return The time graph presentation provider
50c2da9e
GB
915 */
916 protected ITimeGraphPresentationProvider2 getPresentationProvider() {
917 return fPresentation;
918 }
919
747adf5c
PT
920 /**
921 * Sets the tree column labels.
f088b5ae 922 * <p>
747adf5c
PT
923 * This should be called from the constructor.
924 *
925 * @param columns
926 * The array of tree column labels
927 */
928 protected void setTreeColumns(final String[] columns) {
a4cddcbc
BH
929 setTreeColumns(columns, null, 0);
930 }
931
932 /**
933 * Sets the tree column labels.
934 * <p>
935 * This should be called from the constructor.
936 *
937 * @param columns
938 * The array of tree column labels
939 * @param comparators
940 * An array of column comparators for sorting of columns when
941 * clicking on column header
942 * @param initialSortColumn
943 * Index of column to sort initially
944 * @since 2.0
945 */
946 protected void setTreeColumns(final String[] columns, final Comparator<ITimeGraphEntry>[] comparators, int initialSortColumn) {
f088b5ae 947 checkPartNotCreated();
747adf5c 948 fColumns = columns;
a4cddcbc
BH
949 fColumnComparators = comparators;
950 fInitialSortColumn = initialSortColumn;
747adf5c
PT
951 }
952
953 /**
954 * Sets the tree label provider.
f088b5ae 955 * <p>
747adf5c
PT
956 * This should be called from the constructor.
957 *
958 * @param tlp
959 * The tree label provider
960 */
961 protected void setTreeLabelProvider(final TreeLabelProvider tlp) {
f088b5ae 962 checkPartNotCreated();
747adf5c
PT
963 fLabelProvider = tlp;
964 }
965
a12aae87 966 /**
f088b5ae
PT
967 * Sets the time graph content provider.
968 * <p>
969 * This should be called from the constructor.
a12aae87
GB
970 *
971 * @param tgcp
972 * The time graph content provider
973 * @since 1.0
974 */
975 protected void setTimeGraphContentProvider(final @NonNull ITimeGraphContentProvider tgcp) {
f088b5ae 976 checkPartNotCreated();
a12aae87
GB
977 fTimeGraphContentProvider = tgcp;
978 }
979
747adf5c
PT
980 /**
981 * Sets the relative weight of each part of the time graph combo.
f088b5ae 982 * <p>
747adf5c
PT
983 * This should be called from the constructor.
984 *
985 * @param weights
986 * The array (length 2) of relative weights of each part of the combo
987 */
988 protected void setWeight(final int[] weights) {
f088b5ae 989 checkPartNotCreated();
747adf5c
PT
990 fWeight = weights;
991 }
4999a196 992
747adf5c
PT
993 /**
994 * Sets the filter column labels.
f088b5ae 995 * <p>
747adf5c
PT
996 * This should be called from the constructor.
997 *
998 * @param filterColumns
999 * The array of filter column labels
1000 */
1001 protected void setFilterColumns(final String[] filterColumns) {
f088b5ae 1002 checkPartNotCreated();
747adf5c
PT
1003 fFilterColumns = filterColumns;
1004 }
4999a196 1005
737792b6
PT
1006 /**
1007 * Sets the filter content provider.
f088b5ae 1008 * <p>
737792b6
PT
1009 * This should be called from the constructor.
1010 *
1011 * @param contentProvider
1012 * The filter content provider
1013 * @since 2.0
1014 */
1015 protected void setFilterContentProvider(final ITreeContentProvider contentProvider) {
f088b5ae 1016 checkPartNotCreated();
737792b6
PT
1017 fFilterContentProvider = contentProvider;
1018 }
1019
a03b7ee4
PT
1020 /**
1021 * Sets the filter label provider.
f088b5ae 1022 * <p>
a03b7ee4
PT
1023 * This should be called from the constructor.
1024 *
1025 * @param labelProvider
1026 * The filter label provider
a03b7ee4
PT
1027 */
1028 protected void setFilterLabelProvider(final TreeLabelProvider labelProvider) {
f088b5ae 1029 checkPartNotCreated();
a03b7ee4
PT
1030 fFilterLabelProvider = labelProvider;
1031 }
1032
f088b5ae
PT
1033 private void checkPartNotCreated() {
1034 if (getParentComposite() != null) {
1035 throw new IllegalStateException("This method must be called before createPartControl."); //$NON-NLS-1$
1036 }
1037 }
1038
747adf5c
PT
1039 /**
1040 * Gets the display width
1041 *
1042 * @return the display width
1043 */
1044 protected int getDisplayWidth() {
1045 return fDisplayWidth;
1046 }
4999a196 1047
747adf5c
PT
1048 /**
1049 * Gets the comparator for the entries
1050 *
1051 * @return The entry comparator
1052 */
1053 protected Comparator<ITimeGraphEntry> getEntryComparator() {
1054 return fEntryComparator;
1055 }
4999a196 1056
747adf5c 1057 /**
304e446c
PT
1058 * Sets the comparator class for the entries.
1059 * <p>
1060 * This comparator will apply recursively to entries that implement
1061 * {@link TimeGraphEntry#sortChildren(Comparator)}.
747adf5c
PT
1062 *
1063 * @param comparator
1064 * A comparator object
1065 */
1066 protected void setEntryComparator(final Comparator<ITimeGraphEntry> comparator) {
1067 fEntryComparator = comparator;
1068 }
4999a196 1069
747adf5c
PT
1070 /**
1071 * Gets the trace displayed in the view
1072 *
1073 * @return The trace
1074 */
1075 protected ITmfTrace getTrace() {
1076 return fTrace;
1077 }
4999a196 1078
747adf5c
PT
1079 /**
1080 * Gets the start time
1081 *
1082 * @return The start time
1083 */
1084 protected long getStartTime() {
1085 return fStartTime;
1086 }
4999a196 1087
747adf5c
PT
1088 /**
1089 * Sets the start time
1090 *
1091 * @param time
1092 * The start time
1093 */
1094 protected void setStartTime(long time) {
1095 fStartTime = time;
1096 }
1097
1098 /**
1099 * Gets the end time
1100 *
1101 * @return The end time
1102 */
1103 protected long getEndTime() {
1104 return fEndTime;
1105 }
1106
1107 /**
1108 * Sets the end time
1109 *
1110 * @param time
1111 * The end time
1112 */
1113 protected void setEndTime(long time) {
1114 fEndTime = time;
1115 }
1116
5d021ccf
GB
1117 /**
1118 * Sets the auto-expand level to be used for the input of the view. The
1119 * value 0 means that there is no auto-expand; 1 means that top-level
1120 * elements are expanded, but not their children; 2 means that top-level
1121 * elements are expanded, and their children, but not grand-children; and so
1122 * on.
1123 * <p>
1124 * The value {@link #ALL_LEVELS} means that all subtrees should be expanded.
1125 * </p>
1126 *
1127 * @param level
1128 * non-negative level, or <code>ALL_LEVELS</code> to expand all
1129 * levels of the tree
1130 */
1131 protected void setAutoExpandLevel(int level) {
1132 fAutoExpandLevel = level;
1133 ITimeGraphWrapper tgWrapper = fTimeGraphWrapper;
1134 if (tgWrapper != null) {
1135 tgWrapper.setAutoExpandLevel(level);
1136 }
1137 }
1138
747adf5c 1139 /**
1cf25311
PT
1140 * Gets the entry list for a trace
1141 *
1142 * @param trace
1143 * the trace
747adf5c
PT
1144 *
1145 * @return the entry list map
1146 */
1cf25311
PT
1147 protected List<TimeGraphEntry> getEntryList(ITmfTrace trace) {
1148 synchronized (fEntryListMap) {
1149 return fEntryListMap.get(trace);
1150 }
747adf5c
PT
1151 }
1152
1153 /**
1cf25311 1154 * Adds a trace entry list to the entry list map
747adf5c
PT
1155 *
1156 * @param trace
1157 * the trace to add
1158 * @param list
1cf25311 1159 * the list of time graph entries
747adf5c
PT
1160 */
1161 protected void putEntryList(ITmfTrace trace, List<TimeGraphEntry> list) {
1cf25311
PT
1162 synchronized (fEntryListMap) {
1163 fEntryListMap.put(trace, new CopyOnWriteArrayList<>(list));
1164 }
1165 }
1166
1167 /**
1168 * Adds a list of entries to a trace's entry list
1169 *
1170 * @param trace
1171 * the trace
1172 * @param list
1173 * the list of time graph entries to add
1cf25311
PT
1174 */
1175 protected void addToEntryList(ITmfTrace trace, List<TimeGraphEntry> list) {
1176 synchronized (fEntryListMap) {
1177 List<TimeGraphEntry> entryList = fEntryListMap.get(trace);
1178 if (entryList == null) {
1179 fEntryListMap.put(trace, new CopyOnWriteArrayList<>(list));
1180 } else {
1181 entryList.addAll(list);
1182 }
1183 }
1184 }
1185
1186 /**
1187 * Removes a list of entries from a trace's entry list
1188 *
1189 * @param trace
1190 * the trace
1191 * @param list
1192 * the list of time graph entries to remove
1cf25311
PT
1193 */
1194 protected void removeFromEntryList(ITmfTrace trace, List<TimeGraphEntry> list) {
1195 synchronized (fEntryListMap) {
1196 List<TimeGraphEntry> entryList = fEntryListMap.get(trace);
1197 if (entryList != null) {
1198 entryList.removeAll(list);
1199 }
747adf5c
PT
1200 }
1201 }
4999a196 1202
747adf5c
PT
1203 /**
1204 * Text for the "next" button
1205 *
1206 * @return The "next" button text
1207 */
1208 protected String getNextText() {
1209 return Messages.AbstractTimeGraphtView_NextText;
1210 }
4999a196 1211
747adf5c
PT
1212 /**
1213 * Tooltip for the "next" button
1214 *
1215 * @return Tooltip for the "next" button
1216 */
1217 protected String getNextTooltip() {
1218 return Messages.AbstractTimeGraphView_NextTooltip;
1219 }
4999a196 1220
747adf5c
PT
1221 /**
1222 * Text for the "Previous" button
1223 *
1224 * @return The "Previous" button text
1225 */
1226 protected String getPrevText() {
1227 return Messages.AbstractTimeGraphView_PreviousText;
1228 }
4999a196 1229
747adf5c
PT
1230 /**
1231 * Tooltip for the "previous" button
1232 *
1233 * @return Tooltip for the "previous" button
1234 */
1235 protected String getPrevTooltip() {
1236 return Messages.AbstractTimeGraphView_PreviousTooltip;
1237 }
4999a196 1238
36299425
JCK
1239
1240 FindTarget getFindTarget() {
1241 return fFindTarget;
1242 }
1243
747adf5c
PT
1244 // ------------------------------------------------------------------------
1245 // ViewPart
1246 // ------------------------------------------------------------------------
4999a196 1247
747adf5c
PT
1248 @Override
1249 public void createPartControl(Composite parent) {
d2e4afa7 1250 super.createPartControl(parent);
747adf5c
PT
1251 if (fColumns == null || fLabelProvider == null) {
1252 fTimeGraphWrapper = new TimeGraphViewerWrapper(parent, SWT.NONE);
1253 } else {
1254 TimeGraphComboWrapper wrapper = new TimeGraphComboWrapper(parent, SWT.NONE);
1255 fTimeGraphWrapper = wrapper;
1256 TimeGraphCombo combo = wrapper.getTimeGraphCombo();
a12aae87 1257 combo.setTreeContentProvider(fTimeGraphContentProvider);
747adf5c
PT
1258 combo.setTreeLabelProvider(fLabelProvider);
1259 combo.setTreeColumns(fColumns);
a4cddcbc
BH
1260 if (fColumnComparators != null) {
1261 createColumnSelectionListener(combo.getTreeViewer());
1262 }
82467e47
BH
1263 // Add double click listener to tree viewer
1264 createDoubleClickListener(combo.getTreeViewer());
747adf5c 1265 }
cfcfd964 1266 fTimeGraphWrapper.setTimeGraphContentProvider(fTimeGraphContentProvider);
737792b6 1267 fTimeGraphWrapper.setFilterContentProvider(fFilterContentProvider != null ? fFilterContentProvider : fTimeGraphContentProvider);
cfcfd964
PT
1268 fTimeGraphWrapper.setFilterLabelProvider(fFilterLabelProvider);
1269 fTimeGraphWrapper.setFilterColumns(fFilterColumns);
4999a196 1270
cfcfd964 1271 fTimeGraphWrapper.setTimeGraphPresentationProvider(fPresentation);
5d021ccf 1272 fTimeGraphWrapper.setAutoExpandLevel(fAutoExpandLevel);
4999a196 1273
747adf5c 1274 fTimeGraphWrapper.getTimeGraphViewer().addRangeListener(new ITimeGraphRangeListener() {
4999a196
GB
1275 @Override
1276 public void timeRangeUpdated(TimeGraphRangeUpdateEvent event) {
1277 final long startTime = event.getStartTime();
1278 final long endTime = event.getEndTime();
f566d40a 1279 TmfTimeRange range = new TmfTimeRange(new TmfNanoTimestamp(startTime), new TmfNanoTimestamp(endTime));
97c71024 1280 broadcast(new TmfWindowRangeUpdatedSignal(AbstractTimeGraphView.this, range));
4999a196
GB
1281 startZoomThread(startTime, endTime);
1282 }
1283 });
1284
747adf5c 1285 fTimeGraphWrapper.getTimeGraphViewer().addTimeListener(new ITimeGraphTimeListener() {
4999a196
GB
1286 @Override
1287 public void timeSelected(TimeGraphTimeEvent event) {
f566d40a
PT
1288 TmfNanoTimestamp startTime = new TmfNanoTimestamp(event.getBeginTime());
1289 TmfNanoTimestamp endTime = new TmfNanoTimestamp(event.getEndTime());
97c71024 1290 broadcast(new TmfSelectionRangeUpdatedSignal(AbstractTimeGraphView.this, startTime, endTime));
4999a196
GB
1291 }
1292 });
1293
9c274768
PT
1294 fTimeGraphWrapper.getTimeGraphViewer().addBookmarkListener(new ITimeGraphBookmarkListener() {
1295 @Override
1296 public void bookmarkAdded(final TimeGraphBookmarkEvent event) {
1297 try {
1298 ResourcesPlugin.getWorkspace().run(new IWorkspaceRunnable() {
1299 @Override
1300 public void run(IProgressMonitor monitor) throws CoreException {
1301 IMarkerEvent bookmark = event.getBookmark();
1302 IMarker marker = fEditorFile.createMarker(IMarker.BOOKMARK);
1303 marker.setAttribute(IMarker.MESSAGE, bookmark.getLabel());
7697e148 1304 marker.setAttribute(ITmfMarker.MARKER_TIME, Long.toString(bookmark.getTime()));
9c274768 1305 if (bookmark.getDuration() > 0) {
7697e148 1306 marker.setAttribute(ITmfMarker.MARKER_DURATION, Long.toString(bookmark.getDuration()));
9c274768 1307 marker.setAttribute(IMarker.LOCATION,
7697e148
PT
1308 NLS.bind(org.eclipse.tracecompass.internal.tmf.ui.Messages.TmfMarker_LocationTimeRange,
1309 new TmfNanoTimestamp(bookmark.getTime()),
1310 new TmfNanoTimestamp(bookmark.getTime() + bookmark.getDuration())));
9c274768
PT
1311 } else {
1312 marker.setAttribute(IMarker.LOCATION,
7697e148
PT
1313 NLS.bind(org.eclipse.tracecompass.internal.tmf.ui.Messages.TmfMarker_LocationTime,
1314 new TmfNanoTimestamp(bookmark.getTime())));
9c274768 1315 }
8910dea2 1316 marker.setAttribute(ITmfMarker.MARKER_COLOR, bookmark.getColor().toString());
9c274768
PT
1317 }
1318 }, null);
1319 } catch (CoreException e) {
1320 Activator.getDefault().logError(e.getMessage());
1321 }
1322 }
1323
1324 @Override
1325 public void bookmarkRemoved(TimeGraphBookmarkEvent event) {
1326 try {
1327 IMarkerEvent bookmark = event.getBookmark();
1328 IMarker[] markers = fEditorFile.findMarkers(IMarker.BOOKMARK, false, IResource.DEPTH_ZERO);
1329 for (IMarker marker : markers) {
1330 if (bookmark.getLabel().equals(marker.getAttribute(IMarker.MESSAGE)) &&
7697e148
PT
1331 Long.toString(bookmark.getTime()).equals(marker.getAttribute(ITmfMarker.MARKER_TIME, (String) null)) &&
1332 Long.toString(bookmark.getDuration()).equals(marker.getAttribute(ITmfMarker.MARKER_DURATION, Long.toString(0))) &&
8910dea2 1333 bookmark.getColor().toString().equals(marker.getAttribute(ITmfMarker.MARKER_COLOR))) {
9c274768
PT
1334 marker.delete();
1335 break;
1336 }
1337 }
1338 } catch (CoreException e) {
1339 Activator.getDefault().logError(e.getMessage());
1340 }
1341 }
1342 });
1343
747adf5c 1344 fTimeGraphWrapper.getTimeGraphViewer().setTimeFormat(TimeFormat.CALENDAR);
4999a196 1345
0fcf3b09 1346 IStatusLineManager statusLineManager = getViewSite().getActionBars().getStatusLineManager();
747adf5c 1347 fTimeGraphWrapper.getTimeGraphViewer().getTimeGraphControl().setStatusLineManager(statusLineManager);
0fcf3b09 1348
4999a196
GB
1349 // View Action Handling
1350 makeActions();
1351 contributeToActionBars();
1352
21852dfa 1353 ITmfTrace trace = TmfTraceManager.getInstance().getActiveTrace();
4999a196
GB
1354 if (trace != null) {
1355 traceSelected(new TmfTraceSelectedSignal(this, trace));
1356 }
1357
1358 // make selection available to other views
747adf5c 1359 getSite().setSelectionProvider(fTimeGraphWrapper.getSelectionProvider());
9c274768
PT
1360
1361 ResourcesPlugin.getWorkspace().addResourceChangeListener(this, IResourceChangeEvent.POST_CHANGE);
90bb3a0c
BH
1362
1363 createContextMenu();
36299425
JCK
1364 fPartListener = new TimeGraphPartListener();
1365 getSite().getPage().addPartListener(fPartListener);
4999a196
GB
1366 }
1367
1368 @Override
1369 public void setFocus() {
747adf5c 1370 fTimeGraphWrapper.setFocus();
4999a196
GB
1371 }
1372
9c274768
PT
1373 @Override
1374 public void dispose() {
1375 super.dispose();
1376 ResourcesPlugin.getWorkspace().removeResourceChangeListener(this);
36299425 1377 getSite().getPage().removePartListener(fPartListener);
9c274768
PT
1378 }
1379
1380 /**
1381 * @since 2.0
1382 */
1383 @Override
1384 public void resourceChanged(final IResourceChangeEvent event) {
1385 for (final IMarkerDelta delta : event.findMarkerDeltas(IMarker.BOOKMARK, false)) {
1386 if (delta.getResource().equals(fEditorFile)) {
1387 fTimeGraphWrapper.getTimeGraphViewer().setBookmarks(refreshBookmarks(fEditorFile));
1388 redraw();
1389 return;
1390 }
1391 }
1392 }
1393
8910dea2 1394 private static List<IMarkerEvent> refreshBookmarks(final IFile editorFile) {
9c274768 1395 List<IMarkerEvent> bookmarks = new ArrayList<>();
7697e148
PT
1396 if (editorFile == null || !editorFile.exists()) {
1397 return bookmarks;
1398 }
9c274768 1399 try {
9c274768
PT
1400 IMarker[] markers = editorFile.findMarkers(IMarker.BOOKMARK, false, IResource.DEPTH_ZERO);
1401 for (IMarker marker : markers) {
1402 String label = marker.getAttribute(IMarker.MESSAGE, (String) null);
7697e148
PT
1403 String time = marker.getAttribute(ITmfMarker.MARKER_TIME, (String) null);
1404 String duration = marker.getAttribute(ITmfMarker.MARKER_DURATION, Long.toString(0));
1405 String rgba = marker.getAttribute(ITmfMarker.MARKER_COLOR, (String) null);
9c274768
PT
1406 if (label != null && time != null && rgba != null) {
1407 Matcher matcher = RGBA_PATTERN.matcher(rgba);
1408 if (matcher.matches()) {
1409 try {
1410 int red = Integer.valueOf(matcher.group(1));
1411 int green = Integer.valueOf(matcher.group(2));
1412 int blue = Integer.valueOf(matcher.group(3));
1413 int alpha = Integer.valueOf(matcher.group(4));
8910dea2 1414 RGBA color = new RGBA(red, green, blue, alpha);
91512088 1415 bookmarks.add(new MarkerEvent(null, Long.valueOf(time), Long.valueOf(duration), IMarkerEvent.BOOKMARKS, color, label, true));
9c274768
PT
1416 } catch (NumberFormatException e) {
1417 Activator.getDefault().logError(e.getMessage());
1418 }
1419 }
1420 }
1421 }
1422 } catch (CoreException e) {
1423 Activator.getDefault().logError(e.getMessage());
1424 }
1425 return bookmarks;
1426 }
1427
a4cddcbc
BH
1428
1429
4999a196
GB
1430 // ------------------------------------------------------------------------
1431 // Signal handlers
1432 // ------------------------------------------------------------------------
1433
1434 /**
1435 * Handler for the trace opened signal.
1436 *
1437 * @param signal
1438 * The incoming signal
4999a196
GB
1439 */
1440 @TmfSignalHandler
1441 public void traceOpened(TmfTraceOpenedSignal signal) {
4923d7b9 1442 loadTrace(signal.getTrace());
4999a196
GB
1443 }
1444
1445 /**
1446 * Handler for the trace selected signal
1447 *
1448 * @param signal
1449 * The incoming signal
1450 */
1451 @TmfSignalHandler
1452 public void traceSelected(final TmfTraceSelectedSignal signal) {
1453 if (signal.getTrace() == fTrace) {
1454 return;
1455 }
4923d7b9 1456 loadTrace(signal.getTrace());
4999a196
GB
1457 }
1458
1459 /**
1460 * Trace is closed: clear the data structures and the view
1461 *
1462 * @param signal
1463 * the signal received
1464 */
1465 @TmfSignalHandler
1466 public void traceClosed(final TmfTraceClosedSignal signal) {
1467 synchronized (fBuildThreadMap) {
41cc4f90 1468 for (ITmfTrace trace : getTracesToBuild(signal.getTrace())) {
1cf25311
PT
1469 BuildThread buildThread = fBuildThreadMap.remove(trace);
1470 if (buildThread != null) {
1471 buildThread.cancel();
1472 }
4999a196
GB
1473 }
1474 }
4e94ae24 1475 fMarkerEventSourcesMap.remove(signal.getTrace());
4999a196
GB
1476 synchronized (fEntryListMap) {
1477 fEntryListMap.remove(signal.getTrace());
1478 }
4923d7b9 1479 fFiltersMap.remove(signal.getTrace());
1e5c4376 1480 fViewContext.remove(signal.getTrace());
4999a196
GB
1481 if (signal.getTrace() == fTrace) {
1482 fTrace = null;
7697e148 1483 fEditorFile = null;
335b04e6
PT
1484 fStartTime = SWT.DEFAULT;
1485 fEndTime = SWT.DEFAULT;
4999a196
GB
1486 if (fZoomThread != null) {
1487 fZoomThread.cancel();
6ae6c5bd 1488 fZoomThread = null;
4999a196
GB
1489 }
1490 refresh();
1491 }
1492 }
1493
1494 /**
97c71024 1495 * Handler for the selection range signal.
4999a196
GB
1496 *
1497 * @param signal
1498 * The signal that's received
97c71024 1499 * @since 1.0
4999a196
GB
1500 */
1501 @TmfSignalHandler
97c71024 1502 public void selectionRangeUpdated(final TmfSelectionRangeUpdatedSignal signal) {
4999a196
GB
1503 if (signal.getSource() == this || fTrace == null) {
1504 return;
1505 }
16801c72
MK
1506 final long beginTime = signal.getBeginTime().toNanos();
1507 final long endTime = signal.getEndTime().toNanos();
4999a196
GB
1508
1509 Display.getDefault().asyncExec(new Runnable() {
1510 @Override
1511 public void run() {
747adf5c 1512 if (fTimeGraphWrapper.isDisposed()) {
4999a196
GB
1513 return;
1514 }
0fcf3b09 1515 if (beginTime == endTime) {
747adf5c 1516 fTimeGraphWrapper.getTimeGraphViewer().setSelectedTime(beginTime, true);
0fcf3b09 1517 } else {
84c8aef7 1518 fTimeGraphWrapper.getTimeGraphViewer().setSelectionRange(beginTime, endTime, true);
0fcf3b09 1519 }
64de182d 1520 synchingToTime(fTimeGraphWrapper.getTimeGraphViewer().getSelectionBegin());
4999a196
GB
1521 }
1522 });
1523 }
1524
1525 /**
97c71024 1526 * Handler for the window range signal.
4999a196
GB
1527 *
1528 * @param signal
1529 * The signal that's received
97c71024 1530 * @since 1.0
4999a196
GB
1531 */
1532 @TmfSignalHandler
97c71024 1533 public void windowRangeUpdated(final TmfWindowRangeUpdatedSignal signal) {
4999a196
GB
1534 if (signal.getSource() == this || fTrace == null) {
1535 return;
1536 }
1537 if (signal.getCurrentRange().getIntersection(fTrace.getTimeRange()) == null) {
1538 return;
1539 }
16801c72
MK
1540 final long startTime = signal.getCurrentRange().getStartTime().toNanos();
1541 final long endTime = signal.getCurrentRange().getEndTime().toNanos();
4999a196
GB
1542 Display.getDefault().asyncExec(new Runnable() {
1543 @Override
1544 public void run() {
747adf5c 1545 if (fTimeGraphWrapper.isDisposed()) {
4999a196
GB
1546 return;
1547 }
747adf5c 1548 fTimeGraphWrapper.getTimeGraphViewer().setStartFinishTime(startTime, endTime);
4999a196
GB
1549 startZoomThread(startTime, endTime);
1550 }
1551 });
1552 }
1553
c1cd9635
MAL
1554 /**
1555 * @param signal the format of the timestamps was updated.
1556 */
1557 @TmfSignalHandler
1558 public void updateTimeFormat( final TmfTimestampFormatUpdateSignal signal){
747adf5c 1559 fTimeGraphWrapper.refresh();
c1cd9635
MAL
1560 }
1561
4999a196
GB
1562 // ------------------------------------------------------------------------
1563 // Internal
1564 // ------------------------------------------------------------------------
1565
4923d7b9 1566 private void loadTrace(final ITmfTrace trace) {
6ae6c5bd
PT
1567 if (fZoomThread != null) {
1568 fZoomThread.cancel();
1569 fZoomThread = null;
1570 }
4923d7b9
PT
1571 if (fTrace != null) {
1572 /* save the filters of the previous trace */
1573 fFiltersMap.put(fTrace, fTimeGraphWrapper.getFilters());
1e5c4376 1574 fViewContext.put(fTrace, new ViewContext(fCurrentSortColumn, fSortDirection, fTimeGraphWrapper.getSelection()));
4923d7b9
PT
1575 }
1576 fTrace = trace;
1e5c4376 1577 restoreViewContext();
9c274768 1578 fEditorFile = TmfTraceManager.getInstance().getTraceEditorFile(trace);
4999a196
GB
1579 synchronized (fEntryListMap) {
1580 fEntryList = fEntryListMap.get(fTrace);
1581 if (fEntryList == null) {
50c2da9e 1582 rebuild();
4999a196 1583 } else {
16801c72
MK
1584 fStartTime = fTrace.getStartTime().toNanos();
1585 fEndTime = fTrace.getEndTime().toNanos();
4999a196
GB
1586 refresh();
1587 }
1588 }
1589 }
1590
50c2da9e
GB
1591 /**
1592 * Forces a rebuild of the entries list, even if entries already exist for this trace
50c2da9e
GB
1593 */
1594 protected void rebuild() {
1595 setStartTime(Long.MAX_VALUE);
1596 setEndTime(Long.MIN_VALUE);
6b8d11bd 1597 refresh();
dfa0ef96
GB
1598 ITmfTrace viewTrace = fTrace;
1599 if (viewTrace == null) {
1600 return;
1601 }
4e94ae24 1602 List<IMarkerEventSource> markerEventSources = new ArrayList<>();
50c2da9e 1603 synchronized (fBuildThreadMap) {
dfa0ef96
GB
1604 for (ITmfTrace trace : getTracesToBuild(viewTrace)) {
1605 if (trace == null) {
1606 break;
1607 }
4e94ae24 1608 markerEventSources.addAll(TmfTraceAdapterManager.getAdapters(trace, IMarkerEventSource.class));
dfa0ef96 1609 BuildThread buildThread = new BuildThread(trace, viewTrace, getName());
50c2da9e
GB
1610 fBuildThreadMap.put(trace, buildThread);
1611 buildThread.start();
1612 }
1613 }
4e94ae24 1614 fMarkerEventSourcesMap.put(viewTrace, markerEventSources);
50c2da9e
GB
1615 }
1616
4999a196
GB
1617 /**
1618 * Method called when synching to a given timestamp. Inheriting classes can
1619 * perform actions here to update the view at the given timestamp.
1620 *
1621 * @param time
1622 * The currently selected time
1623 */
1624 protected void synchingToTime(long time) {
1625
1626 }
1627
41cc4f90
GB
1628 /**
1629 * Return the list of traces whose data or analysis results will be used to
1630 * populate the view. By default, if the trace is an experiment, the traces
1631 * under it will be returned, otherwise, the trace itself is returned.
1632 *
1633 * A build thread will be started for each trace returned by this method,
1634 * some of which may receive events in live streaming mode.
1635 *
1636 * @param trace
1637 * The trace associated with this view
1638 * @return List of traces with data to display
41cc4f90 1639 */
dfa0ef96 1640 protected @NonNull Iterable<ITmfTrace> getTracesToBuild(@NonNull ITmfTrace trace) {
c14c0757 1641 return TmfTraceManager.getTraceSet(trace);
41cc4f90
GB
1642 }
1643
4999a196 1644 /**
f8f46a52
PT
1645 * Build the entry list to show in this time graph view.
1646 * <p>
1647 * Called from the BuildThread for each trace returned by
1648 * {@link #getTracesToBuild(ITmfTrace)}. The full event list is also
1649 * normally computed for every entry that is created.
4999a196
GB
1650 *
1651 * @param trace
1652 * The trace being built
1cf25311
PT
1653 * @param parentTrace
1654 * The parent of the trace set, or the trace itself
4999a196
GB
1655 * @param monitor
1656 * The progress monitor object
f8f46a52 1657 * @since 2.0
4999a196 1658 */
f8f46a52 1659 protected abstract void buildEntryList(@NonNull ITmfTrace trace, @NonNull ITmfTrace parentTrace, @NonNull IProgressMonitor monitor);
4999a196
GB
1660
1661 /**
f8f46a52
PT
1662 * Gets the list of event for an entry in a given time range.
1663 * <p>
1664 * Called from the ZoomThread for every entry to update the zoomed event
1665 * list. Can be an empty implementation if the view does not support zoomed
1666 * event lists. Can also be used to compute the full event list.
4999a196
GB
1667 *
1668 * @param entry
1669 * The entry to get events for
1670 * @param startTime
1671 * Start of the time range
1672 * @param endTime
1673 * End of the time range
1674 * @param resolution
1675 * The resolution
1676 * @param monitor
1677 * The progress monitor object
1678 * @return The list of events for the entry
1679 */
4c4e2816 1680 protected abstract @Nullable List<@NonNull ITimeEvent> getEventList(@NonNull TimeGraphEntry entry,
4999a196 1681 long startTime, long endTime, long resolution,
dfa0ef96 1682 @NonNull IProgressMonitor monitor);
4999a196 1683
bec1f1ac
GB
1684 /**
1685 * Gets the list of links (displayed as arrows) for a trace in a given
1686 * timerange. Default implementation returns an empty list.
1687 *
1688 * @param startTime
1689 * Start of the time range
1690 * @param endTime
1691 * End of the time range
1692 * @param resolution
1693 * The resolution
1694 * @param monitor
1695 * The progress monitor object
1696 * @return The list of link events
bec1f1ac 1697 */
4c4e2816 1698 protected @Nullable List<@NonNull ILinkEvent> getLinkList(long startTime, long endTime,
dfa0ef96 1699 long resolution, @NonNull IProgressMonitor monitor) {
507b1336 1700 return new ArrayList<>();
bec1f1ac
GB
1701 }
1702
91512088
PT
1703 /**
1704 * Gets the list of view-specific marker categories. Default implementation
1705 * returns an empty list.
1706 *
1707 * @return The list of marker categories
1708 * @since 2.0
1709 */
1710 protected @NonNull List<String> getViewMarkerCategories() {
1711 return new ArrayList<>();
1712 }
1713
e790b877 1714 /**
24333461
PT
1715 * Gets the list of view-specific markers for a trace in a given time range.
1716 * Default implementation returns an empty list.
e790b877
PT
1717 *
1718 * @param startTime
1719 * Start of the time range
1720 * @param endTime
1721 * End of the time range
1722 * @param resolution
1723 * The resolution
1724 * @param monitor
1725 * The progress monitor object
1726 * @return The list of marker events
1727 * @since 2.0
1728 */
24333461 1729 protected @NonNull List<IMarkerEvent> getViewMarkerList(long startTime, long endTime,
e790b877
PT
1730 long resolution, @NonNull IProgressMonitor monitor) {
1731 return new ArrayList<>();
1732 }
bec1f1ac 1733
24333461
PT
1734 /**
1735 * Gets the list of trace-specific markers for a trace in a given time range.
1736 *
1737 * @param startTime
1738 * Start of the time range
1739 * @param endTime
1740 * End of the time range
1741 * @param resolution
1742 * The resolution
1743 * @param monitor
1744 * The progress monitor object
1745 * @return The list of marker events
1746 * @since 2.0
1747 */
1748 protected @NonNull List<IMarkerEvent> getTraceMarkerList(long startTime, long endTime,
1749 long resolution, @NonNull IProgressMonitor monitor) {
1750 List<IMarkerEvent> markers = new ArrayList<>();
4e94ae24 1751 for (IMarkerEventSource markerEventSource : getMarkerEventSources(fTrace)) {
2f72084f
PT
1752 for (String category : markerEventSource.getMarkerCategories()) {
1753 if (monitor.isCanceled()) {
1754 break;
1755 }
0e4f957e 1756 markers.addAll(markerEventSource.getMarkerList(category, startTime, endTime, resolution, monitor));
24333461 1757 }
24333461
PT
1758 }
1759 return markers;
1760 }
1761
91512088
PT
1762 /**
1763 * Get the list of current marker categories.
1764 *
1765 * @return The list of marker categories
1766 * @since 2.0
1767 */
1768 private @NonNull List<String> getMarkerCategories() {
a924e2ed 1769 Set<String> categories = new LinkedHashSet<>(getViewMarkerCategories());
91512088
PT
1770 for (IMarkerEventSource markerEventSource : getMarkerEventSources(fTrace)) {
1771 categories.addAll(markerEventSource.getMarkerCategories());
1772 }
1773 return new ArrayList<>(categories);
1774 }
1775
24333461
PT
1776 /**
1777 * Gets the list of marker event sources for a given trace.
1778 *
1779 * @param trace
1780 * The trace
1781 * @return The list of marker event sources
1782 * @since 2.0
1783 */
91512088 1784 private @NonNull List<IMarkerEventSource> getMarkerEventSources(ITmfTrace trace) {
24333461
PT
1785 List<IMarkerEventSource> markerEventSources = fMarkerEventSourcesMap.get(trace);
1786 if (markerEventSources == null) {
0e4f957e 1787 markerEventSources = Collections.emptyList();
24333461
PT
1788 }
1789 return markerEventSources;
1790 }
1791
4999a196
GB
1792 /**
1793 * Refresh the display
1794 */
1795 protected void refresh() {
6ae6c5bd 1796 final boolean zoomThread = Thread.currentThread() instanceof ZoomThread;
08593856 1797 TmfUiRefreshHandler.getInstance().queueUpdate(this, new Runnable() {
4999a196
GB
1798 @Override
1799 public void run() {
747adf5c 1800 if (fTimeGraphWrapper.isDisposed()) {
4999a196
GB
1801 return;
1802 }
f149d124
MAL
1803 fDirty.incrementAndGet();
1804
1cf25311 1805 boolean hasEntries = false;
4999a196
GB
1806 synchronized (fEntryListMap) {
1807 fEntryList = fEntryListMap.get(fTrace);
1808 if (fEntryList == null) {
1cf25311
PT
1809 fEntryList = new CopyOnWriteArrayList<>();
1810 } else if (fEntryComparator != null) {
1811 List<TimeGraphEntry> list = new ArrayList<>(fEntryList);
1812 Collections.sort(list, fEntryComparator);
304e446c
PT
1813 for (ITimeGraphEntry entry : list) {
1814 sortChildren(entry, fEntryComparator);
1815 }
1cf25311
PT
1816 fEntryList.clear();
1817 fEntryList.addAll(list);
4999a196 1818 }
f3e09aa6 1819 hasEntries = !fEntryList.isEmpty();
4999a196 1820 }
f3e09aa6 1821 boolean inputChanged = fEntryList != fTimeGraphWrapper.getInput();
0eca62a1
BH
1822 TimeGraphCombo combo = getTimeGraphCombo();
1823 try {
1824 // Set redraw to false to only draw once
1825 if (combo != null) {
1826 combo.getTreeViewer().getTree().setRedraw(false);
1827 }
1828 getTimeGraphViewer().getTimeGraphControl().setRedraw(false);
1829 if (inputChanged) {
1e5c4376
BH
1830 fTimeGraphWrapper.setInput(fEntryList);
1831 /* restore the previously saved filters, if any */
1832 fTimeGraphWrapper.setFilters(fFiltersMap.get(fTrace));
1833 fTimeGraphWrapper.getTimeGraphViewer().setLinks(null);
1834 fTimeGraphWrapper.getTimeGraphViewer().setBookmarks(refreshBookmarks(fEditorFile));
1835 fTimeGraphWrapper.getTimeGraphViewer().setMarkerCategories(getMarkerCategories());
1836 fTimeGraphWrapper.getTimeGraphViewer().setMarkers(null);
1837 applyViewContext();
0eca62a1
BH
1838 } else {
1839 fTimeGraphWrapper.refresh();
1e5c4376 1840 }
0eca62a1
BH
1841 // reveal selection
1842 if (fIsRevealSelection) {
1843 fIsRevealSelection = false;
1844 ITimeGraphEntry entry1 = fTimeGraphWrapper.getSelection();
1845 fTimeGraphWrapper.setSelection(entry1);
1846 }
1847 } finally {
1848 if (combo != null) {
1849 combo.getTreeViewer().getTree().setRedraw(true);
1850 }
1851 getTimeGraphViewer().getTimeGraphControl().setRedraw(true);
4999a196 1852 }
335b04e6
PT
1853 long startBound = (fStartTime == Long.MAX_VALUE ? SWT.DEFAULT : fStartTime);
1854 long endBound = (fEndTime == Long.MIN_VALUE ? SWT.DEFAULT : fEndTime);
1855 fTimeGraphWrapper.getTimeGraphViewer().setTimeBounds(startBound, endBound);
4999a196 1856
21852dfa 1857 TmfTraceContext ctx = TmfTraceManager.getInstance().getCurrentTraceContext();
16801c72
MK
1858 long selectionBeginTime = fTrace == null ? SWT.DEFAULT : ctx.getSelectionRange().getStartTime().toNanos();
1859 long selectionEndTime = fTrace == null ? SWT.DEFAULT : ctx.getSelectionRange().getEndTime().toNanos();
1860 long startTime = fTrace == null ? SWT.DEFAULT : ctx.getWindowRange().getStartTime().toNanos();
1861 long endTime = fTrace == null ? SWT.DEFAULT : ctx.getWindowRange().getEndTime().toNanos();
335b04e6
PT
1862 startTime = (fStartTime == Long.MAX_VALUE ? SWT.DEFAULT : Math.max(startTime, fStartTime));
1863 endTime = (fEndTime == Long.MIN_VALUE ? SWT.DEFAULT : Math.min(endTime, fEndTime));
84c8aef7 1864 fTimeGraphWrapper.getTimeGraphViewer().setSelectionRange(selectionBeginTime, selectionEndTime, false);
747adf5c 1865 fTimeGraphWrapper.getTimeGraphViewer().setStartFinishTime(startTime, endTime);
4999a196 1866
f3e09aa6
PT
1867 if (inputChanged && selectionBeginTime != SWT.DEFAULT) {
1868 synchingToTime(selectionBeginTime);
1869 }
1870
1cf25311 1871 if (fTimeGraphWrapper instanceof TimeGraphComboWrapper && !fPackDone) {
747adf5c
PT
1872 for (TreeColumn column : ((TimeGraphComboWrapper) fTimeGraphWrapper).getTreeViewer().getTree().getColumns()) {
1873 column.pack();
1874 }
1cf25311
PT
1875 if (hasEntries) {
1876 fPackDone = true;
1877 }
4999a196
GB
1878 }
1879
6ae6c5bd
PT
1880 if (!zoomThread) {
1881 startZoomThread(startTime, endTime);
1882 }
f149d124 1883 fDirty.decrementAndGet();
4999a196
GB
1884 }
1885 });
1886 }
1887
1888 /**
1889 * Redraw the canvas
1890 */
1891 protected void redraw() {
1892 synchronized (fSyncObj) {
1893 if (fRedrawState == State.IDLE) {
1894 fRedrawState = State.BUSY;
1895 } else {
1896 fRedrawState = State.PENDING;
1897 return;
1898 }
1899 }
1900 Display.getDefault().asyncExec(new Runnable() {
1901 @Override
1902 public void run() {
747adf5c 1903 if (fTimeGraphWrapper.isDisposed()) {
4999a196
GB
1904 return;
1905 }
747adf5c
PT
1906 fTimeGraphWrapper.redraw();
1907 fTimeGraphWrapper.update();
4999a196
GB
1908 synchronized (fSyncObj) {
1909 if (fRedrawState == State.PENDING) {
1910 fRedrawState = State.IDLE;
1911 redraw();
1912 } else {
1913 fRedrawState = State.IDLE;
1914 }
1915 }
1916 }
1917 });
1918 }
1919
a4cddcbc 1920 private void sortChildren(ITimeGraphEntry entry, Comparator<ITimeGraphEntry> comparator) {
304e446c
PT
1921 if (entry instanceof TimeGraphEntry) {
1922 ((TimeGraphEntry) entry).sortChildren(comparator);
1923 }
1924 for (ITimeGraphEntry child : entry.getChildren()) {
1925 sortChildren(child, comparator);
1926 }
1927 }
1928
0c283816
PT
1929 /**
1930 * Start or restart the zoom thread.
1931 *
1932 * @param startTime
1933 * the zoom start time
1934 * @param endTime
1935 * the zoom end time
1936 * @since 2.0
1937 */
156e9ead 1938 protected final void startZoomThread(long startTime, long endTime) {
f149d124
MAL
1939 long clampedStartTime = Math.min(Math.max(startTime, fStartTime), fEndTime);
1940 long clampedEndTime = Math.max(Math.min(endTime, fEndTime), fStartTime);
156e9ead 1941 fDirty.incrementAndGet();
6ae6c5bd 1942 boolean restart = false;
4999a196
GB
1943 if (fZoomThread != null) {
1944 fZoomThread.cancel();
f149d124 1945 if (fZoomThread.fZoomStartTime == clampedStartTime && fZoomThread.fZoomEndTime == clampedEndTime) {
6ae6c5bd
PT
1946 restart = true;
1947 }
1948 }
f149d124
MAL
1949 long resolution = Math.max(1, (clampedEndTime - clampedStartTime) / fDisplayWidth);
1950 fZoomThread = createZoomThread(clampedStartTime, clampedEndTime, resolution, restart);
6ae6c5bd 1951 if (fZoomThread != null) {
6d28f3e8
MAL
1952 // Don't start a new thread right away if results are being applied
1953 // from an old ZoomThread. Otherwise, the old results might
1954 // overwrite the new results if it finishes after.
1955 synchronized (fZoomThreadResultLock) {
1956 fZoomThread.start();
1957 }
156e9ead
MAL
1958 } else {
1959 fDirty.decrementAndGet();
4999a196 1960 }
6ae6c5bd
PT
1961 }
1962
1963 /**
1964 * Create a zoom thread.
1965 *
1966 * @param startTime
1967 * the zoom start time
1968 * @param endTime
1969 * the zoom end time
1970 * @param resolution
1971 * the resolution
1972 * @param restart
1973 * true if restarting zoom for the same time range
1974 * @return a zoom thread
0336f981 1975 * @since 1.1
6ae6c5bd
PT
1976 */
1977 protected @Nullable ZoomThread createZoomThread(long startTime, long endTime, long resolution, boolean restart) {
dfa0ef96
GB
1978 final List<TimeGraphEntry> entryList = fEntryList;
1979 if (entryList == null) {
6ae6c5bd 1980 return null;
dfa0ef96 1981 }
6ae6c5bd 1982 return new ZoomThreadByEntry(entryList, startTime, endTime, resolution);
4999a196
GB
1983 }
1984
1985 private void makeActions() {
747adf5c 1986 fPreviousResourceAction = fTimeGraphWrapper.getTimeGraphViewer().getPreviousItemAction();
4999a196
GB
1987 fPreviousResourceAction.setText(getPrevText());
1988 fPreviousResourceAction.setToolTipText(getPrevTooltip());
747adf5c 1989 fNextResourceAction = fTimeGraphWrapper.getTimeGraphViewer().getNextItemAction();
4999a196
GB
1990 fNextResourceAction.setText(getNextText());
1991 fNextResourceAction.setToolTipText(getNextTooltip());
1992 }
1993
1994 private void contributeToActionBars() {
1995 IActionBars bars = getViewSite().getActionBars();
1996 fillLocalToolBar(bars.getToolBarManager());
91512088 1997 fillLocalMenu(bars.getMenuManager());
4999a196
GB
1998 }
1999
79ec0b89
PT
2000 /**
2001 * Add actions to local tool bar manager
2002 *
2003 * @param manager the tool bar manager
2004 */
2005 protected void fillLocalToolBar(IToolBarManager manager) {
cfcfd964
PT
2006 if (fFilterColumns != null && fFilterLabelProvider != null && fFilterColumns.length > 0) {
2007 manager.add(fTimeGraphWrapper.getShowFilterDialogAction());
4999a196 2008 }
747adf5c 2009 manager.add(fTimeGraphWrapper.getTimeGraphViewer().getShowLegendAction());
4999a196 2010 manager.add(new Separator());
747adf5c
PT
2011 manager.add(fTimeGraphWrapper.getTimeGraphViewer().getResetScaleAction());
2012 manager.add(fTimeGraphWrapper.getTimeGraphViewer().getPreviousEventAction());
2013 manager.add(fTimeGraphWrapper.getTimeGraphViewer().getNextEventAction());
91512088 2014 manager.add(new Separator());
1d012443 2015 manager.add(fTimeGraphWrapper.getTimeGraphViewer().getToggleBookmarkAction());
f72cd563
PT
2016 manager.add(fTimeGraphWrapper.getTimeGraphViewer().getPreviousMarkerAction());
2017 manager.add(fTimeGraphWrapper.getTimeGraphViewer().getNextMarkerAction());
91512088 2018 manager.add(new Separator());
4999a196
GB
2019 manager.add(fPreviousResourceAction);
2020 manager.add(fNextResourceAction);
747adf5c
PT
2021 manager.add(fTimeGraphWrapper.getTimeGraphViewer().getZoomInAction());
2022 manager.add(fTimeGraphWrapper.getTimeGraphViewer().getZoomOutAction());
4999a196
GB
2023 manager.add(new Separator());
2024 }
d2e4afa7 2025
91512088
PT
2026 /**
2027 * Add actions to local menu manager
2028 *
2029 * @param manager the tool bar manager
2030 * @since 2.0
2031 */
2032 protected void fillLocalMenu(IMenuManager manager) {
2033 manager.add(fTimeGraphWrapper.getTimeGraphViewer().getMarkersMenu());
2034 }
2035
d2e4afa7
MAL
2036 /**
2037 * @since 1.0
2038 */
2039 @Override
2040 public TmfTimeViewAlignmentInfo getTimeViewAlignmentInfo() {
2041 if (fTimeGraphWrapper == null) {
2042 return null;
2043 }
2044 return fTimeGraphWrapper.getTimeViewAlignmentInfo();
2045 }
2046
2047 /**
2048 * @since 1.0
2049 */
2050 @Override
2051 public int getAvailableWidth(int requestedOffset) {
2052 if (fTimeGraphWrapper == null) {
2053 return 0;
2054 }
2055 return fTimeGraphWrapper.getAvailableWidth(requestedOffset);
2056 }
2057
2058 /**
2059 * @since 1.0
2060 */
2061 @Override
2062 public void performAlign(int offset, int width) {
2063 if (fTimeGraphWrapper != null) {
2064 fTimeGraphWrapper.performAlign(offset, width);
2065 }
2066 }
156e9ead
MAL
2067
2068 /**
2069 * Returns whether or not the time graph view is dirty. The time graph view
2070 * is considered dirty if it has yet to completely update its model.
2071 *
f149d124
MAL
2072 * This method is meant to be used by tests in order to know when it is safe
2073 * to proceed.
2074 *
2075 * Note: If a trace is smaller than the initial window range (see
2076 * {@link ITmfTrace#getInitialRangeOffset}) this method will return true
2077 * forever.
2078 *
156e9ead
MAL
2079 * @return true if the time graph view has yet to completely update its
2080 * model, false otherwise
2081 * @since 2.0
2082 */
2083 public boolean isDirty() {
f149d124 2084 if (fTrace == null) {
156e9ead
MAL
2085 return false;
2086 }
f149d124
MAL
2087
2088 TmfTraceContext ctx = TmfTraceManager.getInstance().getCurrentTraceContext();
2089 long startTime = ctx.getWindowRange().getStartTime().toNanos();
2090 long endTime = ctx.getWindowRange().getEndTime().toNanos();
2091
2092 // If the time graph control hasn't updated all the way to the end of
2093 // the window range then it's dirty. A refresh should happen later.
2094 if (fTimeGraphWrapper.getTimeGraphViewer().getTime0() != startTime || fTimeGraphWrapper.getTimeGraphViewer().getTime1() != endTime) {
2095 return true;
2096 }
2097
2098 if (fZoomThread == null) {
2099 // The zoom thread is null but we might be just about to create it (refresh called).
2100 return fDirty.get() != 0;
2101 }
2102 // Dirty if the zoom thread is not done or if it hasn't zoomed all the
2103 // way to the end of the window range. In the latter case, there should be
2104 // a subsequent zoom thread that will be triggered.
2105 return fDirty.get() != 0 || fZoomThread.getZoomStartTime() != startTime || fZoomThread.getZoomEndTime() != endTime;
156e9ead
MAL
2106 }
2107
a4cddcbc
BH
2108 private void createColumnSelectionListener(TreeViewer treeViewer) {
2109 for (int i = 0; i < fColumnComparators.length; i++) {
1e5c4376
BH
2110 final int index = i;
2111 final Comparator<ITimeGraphEntry> comp = fColumnComparators[index];
a4cddcbc
BH
2112 final Tree tree = treeViewer.getTree();
2113 final TreeColumn column = tree.getColumn(i);
2114
2115 if (comp != null) {
2116 column.addSelectionListener(new SelectionAdapter() {
2117 @Override
2118 public void widgetSelected(SelectionEvent e) {
2119 TreeColumn prevSortcolumn = tree.getSortColumn();
1e5c4376 2120 int direction = tree.getSortDirection();
a4cddcbc 2121 if (prevSortcolumn == column) {
1e5c4376 2122 direction = (direction == SWT.DOWN) ? SWT.UP : SWT.DOWN;
a4cddcbc 2123 } else {
1e5c4376 2124 direction = SWT.DOWN;
a4cddcbc
BH
2125 }
2126 tree.setSortColumn(column);
1e5c4376
BH
2127 tree.setSortDirection(direction);
2128 fSortDirection = direction;
2129 fCurrentSortColumn = index;
a4cddcbc 2130 Comparator<ITimeGraphEntry> comparator = comp;
1e5c4376 2131
a4cddcbc 2132 if (comparator instanceof ITimeGraphEntryComparator) {
1e5c4376 2133 ((ITimeGraphEntryComparator) comparator).setDirection(direction);
a4cddcbc 2134 }
1e5c4376 2135 if (direction != SWT.DOWN) {
a4cddcbc
BH
2136 comparator = checkNotNull(Collections.reverseOrder(comparator));
2137 }
2138 setEntryComparator(comparator);
2139 fIsRevealSelection = true;
2140 if (fTimeGraphWrapper instanceof TimeGraphComboWrapper) {
2141 ((TimeGraphComboWrapper) fTimeGraphWrapper).getTreeViewer().getControl().setFocus();
2142 }
2143 refresh();
2144 }
2145 });
2146 }
2147 }
2148 }
2149
82467e47
BH
2150 private void createDoubleClickListener(TreeViewer treeViewer) {
2151 treeViewer.addDoubleClickListener(event -> {
2152 if (event.getSelection() instanceof TreeSelection) {
2153 TreeSelection selection = (TreeSelection) event.getSelection();
2154 if (selection.getFirstElement() instanceof ITimeGraphEntry) {
2155 ITimeGraphEntry entry = (ITimeGraphEntry) selection.getFirstElement();
2156 if (entry.hasChildren()) {
2157 fTimeGraphWrapper.setExpandedState(entry, !fTimeGraphWrapper.getExpandedState(entry));
2158 }
2159 }
2160 }
2161 });
2162 }
2163
2164
1e5c4376
BH
2165 private void restoreViewContext() {
2166 TimeGraphCombo combo = getTimeGraphCombo();
2167 ViewContext viewContext = fViewContext.get(fTrace);
2168 if (combo != null) {
2169 if (fColumnComparators != null) {
2170 // restore sort settings
2171 fSortDirection = SWT.DOWN;
2172 fCurrentSortColumn = fInitialSortColumn;
2173 if (viewContext != null) {
2174 fSortDirection = viewContext.getSortDirection();
2175 fCurrentSortColumn = viewContext.getSortColumn();
2176 }
2177 if ((fCurrentSortColumn < fColumnComparators.length) && (fColumnComparators[fCurrentSortColumn] != null)) {
2178 Comparator<ITimeGraphEntry> comparator = fColumnComparators[fCurrentSortColumn];
2179 if (comparator instanceof ITimeGraphEntryComparator) {
2180 ((ITimeGraphEntryComparator) comparator).setDirection(fSortDirection);
2181 }
2182 if (fSortDirection != SWT.DOWN) {
2183 comparator = checkNotNull(Collections.reverseOrder(comparator));
2184 }
2185 setEntryComparator(comparator);
2186 }
a4cddcbc 2187 }
1e5c4376
BH
2188 }
2189 }
2190
2191 private void applyViewContext() {
2192 TimeGraphCombo combo = getTimeGraphCombo();
2193 ViewContext viewContext = fViewContext.get(fTrace);
2194 if (combo != null) {
2195 TreeViewer treeViewer = combo.getTreeViewer();
a4cddcbc 2196 final Tree tree = treeViewer.getTree();
1e5c4376
BH
2197 final TreeColumn column = tree.getColumn(fCurrentSortColumn);
2198 tree.setSortDirection(fSortDirection);
a4cddcbc 2199 tree.setSortColumn(column);
1e5c4376
BH
2200 combo.getTreeViewer().getControl().setFocus();
2201 }
2202 // restore and reveal selection
2203 if ((viewContext != null) && (viewContext.getSelection() != null)) {
2204 fTimeGraphWrapper.setSelection(viewContext.getSelection());
2205 }
2206 fViewContext.remove(fTrace);
2207 }
2208
2209 private static class ViewContext {
2210 private int fSortColumnIndex;
2211 private int fSortDirection;
2212 private @Nullable ITimeGraphEntry fSelection;
2213
2214 ViewContext(int sortColunm, int sortDirection, ITimeGraphEntry selection) {
2215 fSortColumnIndex = sortColunm;
2216 fSortDirection = sortDirection;
2217 fSelection = selection;
2218 }
2219 /**
2220 * @return the sortColumn
2221 */
2222 public int getSortColumn() {
2223 return fSortColumnIndex;
2224 }
2225 /**
2226 * @return the sortDirection
2227 */
2228 public int getSortDirection() {
2229 return fSortDirection;
2230 }
2231 /**
2232 * @return the selection
2233 */
2234 public ITimeGraphEntry getSelection() {
2235 return fSelection;
a4cddcbc
BH
2236 }
2237 }
90bb3a0c
BH
2238
2239 private void createContextMenu() {
2240 TimeGraphCombo combo = getTimeGraphCombo();
9bdf1671 2241 fEntryMenuManager.setRemoveAllWhenShown(true);
90bb3a0c 2242 if (combo != null) {
90bb3a0c
BH
2243 TreeViewer treeViewer = combo.getTreeViewer();
2244 Tree tree = treeViewer.getTree();
2245 Menu menu = fEntryMenuManager.createContextMenu(tree);
2246 tree.setMenu(menu);
9bdf1671
BH
2247 } else {
2248 TimeGraphControl timeGraphControl = getTimeGraphViewer().getTimeGraphControl();
2249 final Menu entryMenu = fEntryMenuManager.createContextMenu(timeGraphControl);
2250 timeGraphControl.addTimeGraphEntryMenuListener(new MenuDetectListener() {
90bb3a0c 2251 @Override
9bdf1671
BH
2252 public void menuDetected(MenuDetectEvent event) {
2253 Point p = timeGraphControl.toControl(event.x, event.y);
2254 /*
2255 * The TimeGraphControl will call the TimeGraphEntryMenuListener
2256 * before the TimeEventMenuListener. If the event is
2257 * triggered on the namespace then show the menu else
2258 * clear the menu.
2259 */
2260 if (p.x < getTimeGraphViewer().getNameSpace()) {
2261 timeGraphControl.setMenu(entryMenu);
2262 } else {
2263 timeGraphControl.setMenu(null);
2264 event.doit = false;
2265 }
90bb3a0c
BH
2266 }
2267 });
90bb3a0c 2268 }
9bdf1671
BH
2269 fEntryMenuManager.addMenuListener(new IMenuListener() {
2270 @Override
2271 public void menuAboutToShow(IMenuManager manager) {
f8f46a52 2272 fillTimeGraphEntryContextMenu(fEntryMenuManager);
9bdf1671
BH
2273 fEntryMenuManager.add(new GroupMarker(IWorkbenchActionConstants.MB_ADDITIONS));
2274 }
2275 });
2276 getSite().registerContextMenu(fEntryMenuManager, fTimeGraphWrapper.getSelectionProvider());
90bb3a0c
BH
2277 }
2278
2279 /**
2280 * Fill context menu
2281 *
2282 * @param menuManager
2283 * a menuManager to fill
2284 * @since 2.0
2285 */
2286 protected void fillTimeGraphEntryContextMenu (@NonNull IMenuManager menuManager) {
36299425
JCK
2287 }
2288
2289 /*
2290 * Inner classes used for searching
2291 */
2292 class FindTarget {
2293 public ITimeGraphEntry getSelection() {
2294 return fTimeGraphWrapper.getSelection();
2295 }
90bb3a0c 2296
36299425
JCK
2297 public void selectAndReveal(@NonNull ITimeGraphEntry entry) {
2298 fTimeGraphWrapper.selectAndReveal(entry);
2299 }
2300
2301 public ITimeGraphEntry[] getEntries() {
2302 TimeGraphViewer viewer = getTimeGraphViewer();
2303 return viewer.getTimeGraphContentProvider().getElements(viewer.getInput());
2304 }
2305
2306 public Shell getShell() {
2307 return getSite().getShell();
2308 }
2309 }
2310
2311 class TimeGraphPartListener implements IPartListener {
2312 @Override
2313 public void partActivated(IWorkbenchPart part) {
2314 if (part == AbstractTimeGraphView.this) {
2315 synchronized (FIND_ACTION) {
2316 if (fFindActionHandler == null) {
2317 fFindActionHandler = new ActionHandler(FIND_ACTION);
2318 }
2319 final Object service = PlatformUI.getWorkbench().getService(IHandlerService.class);
2320 fFindHandlerActivation = ((IHandlerService) service).activateHandler(ActionFactory.FIND.getCommandId(), fFindActionHandler);
2321 }
2322 }
2323 // Notify action for all parts
2324 FIND_ACTION.partActivated(part);
2325 }
2326 @Override
2327 public void partDeactivated(IWorkbenchPart part) {
2328 if ((part == AbstractTimeGraphView.this) && (fFindHandlerActivation != null)) {
2329 final Object service = PlatformUI.getWorkbench().getService(IHandlerService.class);
2330 ((IHandlerService) service).deactivateHandler(fFindHandlerActivation);
2331 }
2332 }
2333 @Override
2334 public void partBroughtToTop(IWorkbenchPart part) {
2335 }
2336 @Override
2337 public void partClosed(IWorkbenchPart part) {
2338 }
2339 @Override
2340 public void partOpened(IWorkbenchPart part) {
2341 }
90bb3a0c 2342 }
4999a196 2343}
This page took 0.221586 seconds and 5 git commands to generate.