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