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