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