tmf: Add an abstract state system time graph view
[deliverable/tracecompass.git] / tmf / org.eclipse.tracecompass.tmf.ui / src / org / eclipse / tracecompass / tmf / ui / views / timegraph / AbstractTimeGraphView.java
1 /*******************************************************************************
2 * Copyright (c) 2012, 2015 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 java.util.ArrayList;
20 import java.util.Collections;
21 import java.util.Comparator;
22 import java.util.HashMap;
23 import java.util.List;
24 import java.util.Map;
25 import java.util.concurrent.CopyOnWriteArrayList;
26
27 import org.eclipse.core.runtime.IProgressMonitor;
28 import org.eclipse.core.runtime.NullProgressMonitor;
29 import org.eclipse.jdt.annotation.NonNull;
30 import org.eclipse.jdt.annotation.Nullable;
31 import org.eclipse.jface.action.Action;
32 import org.eclipse.jface.action.IAction;
33 import org.eclipse.jface.action.IStatusLineManager;
34 import org.eclipse.jface.action.IToolBarManager;
35 import org.eclipse.jface.action.Separator;
36 import org.eclipse.jface.viewers.AbstractTreeViewer;
37 import org.eclipse.jface.viewers.ILabelProvider;
38 import org.eclipse.jface.viewers.ILabelProviderListener;
39 import org.eclipse.jface.viewers.ISelectionProvider;
40 import org.eclipse.jface.viewers.ITableLabelProvider;
41 import org.eclipse.jface.viewers.TreeViewer;
42 import org.eclipse.swt.SWT;
43 import org.eclipse.swt.graphics.Image;
44 import org.eclipse.swt.widgets.Composite;
45 import org.eclipse.swt.widgets.Display;
46 import org.eclipse.swt.widgets.TreeColumn;
47 import org.eclipse.tracecompass.tmf.core.signal.TmfSelectionRangeUpdatedSignal;
48 import org.eclipse.tracecompass.tmf.core.signal.TmfSignalHandler;
49 import org.eclipse.tracecompass.tmf.core.signal.TmfTimestampFormatUpdateSignal;
50 import org.eclipse.tracecompass.tmf.core.signal.TmfTraceClosedSignal;
51 import org.eclipse.tracecompass.tmf.core.signal.TmfTraceOpenedSignal;
52 import org.eclipse.tracecompass.tmf.core.signal.TmfTraceSelectedSignal;
53 import org.eclipse.tracecompass.tmf.core.signal.TmfWindowRangeUpdatedSignal;
54 import org.eclipse.tracecompass.tmf.core.timestamp.ITmfTimestamp;
55 import org.eclipse.tracecompass.tmf.core.timestamp.TmfNanoTimestamp;
56 import org.eclipse.tracecompass.tmf.core.timestamp.TmfTimeRange;
57 import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace;
58 import org.eclipse.tracecompass.tmf.core.trace.TmfTraceContext;
59 import org.eclipse.tracecompass.tmf.core.trace.TmfTraceManager;
60 import org.eclipse.tracecompass.tmf.ui.TmfUiRefreshHandler;
61 import org.eclipse.tracecompass.tmf.ui.signal.TmfTimeViewAlignmentInfo;
62 import org.eclipse.tracecompass.tmf.ui.views.ITmfTimeAligned;
63 import org.eclipse.tracecompass.tmf.ui.views.TmfView;
64 import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.ITimeGraphContentProvider;
65 import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.ITimeGraphPresentationProvider2;
66 import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.ITimeGraphRangeListener;
67 import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.ITimeGraphSelectionListener;
68 import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.ITimeGraphTimeListener;
69 import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.TimeGraphCombo;
70 import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.TimeGraphContentProvider;
71 import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.TimeGraphPresentationProvider;
72 import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.TimeGraphRangeUpdateEvent;
73 import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.TimeGraphTimeEvent;
74 import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.TimeGraphViewer;
75 import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.model.ILinkEvent;
76 import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.model.ITimeEvent;
77 import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.model.ITimeGraphEntry;
78 import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.model.TimeGraphEntry;
79 import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.widgets.Utils.TimeFormat;
80 import org.eclipse.ui.IActionBars;
81
82 /**
83 * An abstract view all time graph views can inherit
84 *
85 * This view contains either a time graph viewer, or a time graph combo which is
86 * divided between a tree viewer on the left and a time graph viewer on the right.
87 */
88 public abstract class AbstractTimeGraphView extends TmfView implements ITmfTimeAligned {
89
90 /** Constant indicating that all levels of the time graph should be expanded */
91 protected static final int ALL_LEVELS = AbstractTreeViewer.ALL_LEVELS;
92
93 /**
94 * Redraw state enum
95 */
96 private enum State {
97 IDLE, BUSY, PENDING
98 }
99
100 // ------------------------------------------------------------------------
101 // Fields
102 // ------------------------------------------------------------------------
103
104 /** The timegraph wrapper */
105 private ITimeGraphWrapper fTimeGraphWrapper;
106
107 /** The selected trace */
108 private ITmfTrace fTrace;
109
110 /** The timegraph entry list */
111 private List<TimeGraphEntry> fEntryList;
112
113 /** The trace to entry list hash map */
114 private final Map<ITmfTrace, List<TimeGraphEntry>> fEntryListMap = new HashMap<>();
115
116 /** The trace to build thread hash map */
117 private final Map<ITmfTrace, BuildThread> fBuildThreadMap = new HashMap<>();
118
119 /** The start time */
120 private long fStartTime;
121
122 /** The end time */
123 private long fEndTime;
124
125 /** The display width */
126 private final int fDisplayWidth;
127
128 /** The zoom thread */
129 private ZoomThread fZoomThread;
130
131 /** The next resource action */
132 private Action fNextResourceAction;
133
134 /** The previous resource action */
135 private Action fPreviousResourceAction;
136
137 /** A comparator class */
138 private Comparator<ITimeGraphEntry> fEntryComparator = null;
139
140 /** The redraw state used to prevent unnecessary queuing of display runnables */
141 private State fRedrawState = State.IDLE;
142
143 /** The redraw synchronization object */
144 private final Object fSyncObj = new Object();
145
146 /** The presentation provider for this view */
147 private final TimeGraphPresentationProvider fPresentation;
148
149 /** The tree column label array, or null if combo is not used */
150 private String[] fColumns;
151
152 /** The tree label provider, or null if combo is not used */
153 private TreeLabelProvider fLabelProvider = null;
154
155 /** The time graph content provider */
156 private @NonNull ITimeGraphContentProvider fTimeGraphContentProvider = new TimeGraphContentProvider();
157
158 /** The relative weight of the sash, ignored if combo is not used */
159 private int[] fWeight = { 1, 3 };
160
161 /** The filter column label array, or null if filter is not used */
162 private String[] fFilterColumns;
163
164 /** The pack done flag */
165 private boolean fPackDone = false;
166
167 /** The filter label provider, or null if filter is not used */
168 private TreeLabelProvider fFilterLabelProvider;
169
170 private int fAutoExpandLevel = ALL_LEVELS;
171
172 // ------------------------------------------------------------------------
173 // Classes
174 // ------------------------------------------------------------------------
175
176 private interface ITimeGraphWrapper {
177
178 void setTimeGraphProvider(TimeGraphPresentationProvider fPresentation);
179
180 TimeGraphViewer getTimeGraphViewer();
181
182 void addSelectionListener(ITimeGraphSelectionListener iTimeGraphSelectionListener);
183
184 ISelectionProvider getSelectionProvider();
185
186 void setFocus();
187
188 boolean isDisposed();
189
190 void refresh();
191
192 void setInput(Object input);
193
194 Object getInput();
195
196 void redraw();
197
198 void update();
199
200 void setAutoExpandLevel(int level);
201
202 void performAlign(int offset, int width);
203
204 TmfTimeViewAlignmentInfo getTimeViewAlignmentInfo();
205
206 int getAvailableWidth(int requestedOffset);
207 }
208
209 private class TimeGraphViewerWrapper implements ITimeGraphWrapper {
210 private TimeGraphViewer viewer;
211
212 private TimeGraphViewerWrapper(Composite parent, int style) {
213 viewer = new TimeGraphViewer(parent, style);
214 }
215
216 @Override
217 public void setTimeGraphProvider(TimeGraphPresentationProvider timeGraphProvider) {
218 viewer.setTimeGraphProvider(timeGraphProvider);
219 }
220
221 @Override
222 public TimeGraphViewer getTimeGraphViewer() {
223 return viewer;
224 }
225
226 @Override
227 public void addSelectionListener(ITimeGraphSelectionListener listener) {
228 viewer.addSelectionListener(listener);
229 }
230
231 @Override
232 public ISelectionProvider getSelectionProvider() {
233 return viewer.getSelectionProvider();
234 }
235
236 @Override
237 public void setFocus() {
238 viewer.setFocus();
239 }
240
241 @Override
242 public boolean isDisposed() {
243 return viewer.getControl().isDisposed();
244 }
245
246 @Override
247 public void setInput(Object input) {
248 viewer.setInput(input);
249 }
250
251 @Override
252 public Object getInput() {
253 return viewer.getInput();
254 }
255
256 @Override
257 public void refresh() {
258 viewer.refresh();
259 }
260
261 @Override
262 public void redraw() {
263 viewer.getControl().redraw();
264 }
265
266 @Override
267 public void update() {
268 viewer.getControl().update();
269 }
270
271 @Override
272 public void setAutoExpandLevel(int level) {
273 viewer.setAutoExpandLevel(level);
274 }
275
276 @Override
277 public void performAlign(int offset, int width) {
278 viewer.performAlign(offset, width);
279 }
280
281 @Override
282 public TmfTimeViewAlignmentInfo getTimeViewAlignmentInfo() {
283 return viewer.getTimeViewAlignmentInfo();
284 }
285
286 @Override
287 public int getAvailableWidth(int requestedOffset) {
288 return viewer.getAvailableWidth(requestedOffset);
289 }
290 }
291
292 private class TimeGraphComboWrapper implements ITimeGraphWrapper {
293 private TimeGraphCombo combo;
294
295 private TimeGraphComboWrapper(Composite parent, int style) {
296 combo = new TimeGraphCombo(parent, style, fWeight);
297 }
298
299 @Override
300 public void setTimeGraphProvider(TimeGraphPresentationProvider timeGraphProvider) {
301 combo.setTimeGraphProvider(timeGraphProvider);
302 }
303
304 @Override
305 public TimeGraphViewer getTimeGraphViewer() {
306 return combo.getTimeGraphViewer();
307 }
308
309 @Override
310 public void addSelectionListener(ITimeGraphSelectionListener listener) {
311 combo.addSelectionListener(listener);
312 }
313
314 @Override
315 public ISelectionProvider getSelectionProvider() {
316 return combo.getTreeViewer();
317 }
318
319 @Override
320 public void setFocus() {
321 combo.setFocus();
322 }
323
324 @Override
325 public boolean isDisposed() {
326 return combo.isDisposed();
327 }
328
329 @Override
330 public void setInput(Object input) {
331 combo.setInput(input);
332 }
333
334 @Override
335 public Object getInput() {
336 return combo.getInput();
337 }
338
339 @Override
340 public void refresh() {
341 combo.refresh();
342 }
343
344 @Override
345 public void redraw() {
346 combo.redraw();
347 }
348
349 @Override
350 public void update() {
351 combo.update();
352 }
353
354 @Override
355 public void setAutoExpandLevel(int level) {
356 combo.setAutoExpandLevel(level);
357 }
358
359 TimeGraphCombo getTimeGraphCombo() {
360 return combo;
361 }
362
363 TreeViewer getTreeViewer() {
364 return combo.getTreeViewer();
365 }
366
367 IAction getShowFilterAction() {
368 return combo.getShowFilterAction();
369 }
370
371 @Override
372 public void performAlign(int offset, int width) {
373 combo.performAlign(offset, width);
374 }
375
376 @Override
377 public TmfTimeViewAlignmentInfo getTimeViewAlignmentInfo() {
378 return combo.getTimeViewAlignmentInfo();
379 }
380
381 @Override
382 public int getAvailableWidth(int requestedOffset) {
383 return combo.getAvailableWidth(requestedOffset);
384 }
385 }
386
387 /**
388 * Base class to provide the labels for the tree viewer. Views extending
389 * this class typically need to override the getColumnText method if they
390 * have more than one column to display
391 */
392 protected static class TreeLabelProvider implements ITableLabelProvider, ILabelProvider {
393
394 @Override
395 public void addListener(ILabelProviderListener listener) {
396 }
397
398 @Override
399 public void dispose() {
400 }
401
402 @Override
403 public boolean isLabelProperty(Object element, String property) {
404 return false;
405 }
406
407 @Override
408 public void removeListener(ILabelProviderListener listener) {
409 }
410
411 @Override
412 public Image getColumnImage(Object element, int columnIndex) {
413 return null;
414 }
415
416 @Override
417 public String getColumnText(Object element, int columnIndex) {
418 TimeGraphEntry entry = (TimeGraphEntry) element;
419 if (columnIndex == 0) {
420 return entry.getName();
421 }
422 return new String();
423 }
424
425 @Override
426 public Image getImage(Object element) {
427 return null;
428 }
429
430 @Override
431 public String getText(Object element) {
432 TimeGraphEntry entry = (TimeGraphEntry) element;
433 return entry.getName();
434 }
435
436 }
437
438 private class BuildThread extends Thread {
439 private final @NonNull ITmfTrace fBuildTrace;
440 private final @NonNull ITmfTrace fParentTrace;
441 private final @NonNull IProgressMonitor fMonitor;
442
443 public BuildThread(final @NonNull ITmfTrace trace, final @NonNull ITmfTrace parentTrace, final String name) {
444 super(name + " build"); //$NON-NLS-1$
445 fBuildTrace = trace;
446 fParentTrace = parentTrace;
447 fMonitor = new NullProgressMonitor();
448 }
449
450 @Override
451 public void run() {
452 buildEventList(fBuildTrace, fParentTrace, fMonitor);
453 synchronized (fBuildThreadMap) {
454 fBuildThreadMap.remove(fBuildTrace);
455 }
456 }
457
458 public void cancel() {
459 fMonitor.setCanceled(true);
460 }
461 }
462
463 /**
464 * Zoom thread
465 * @since 1.1
466 */
467 protected abstract class ZoomThread extends Thread {
468 private final long fZoomStartTime;
469 private final long fZoomEndTime;
470 private final long fResolution;
471 private final @NonNull IProgressMonitor fMonitor;
472
473 /**
474 * Constructor
475 *
476 * @param startTime
477 * the start time
478 * @param endTime
479 * the end time
480 * @param resolution
481 * the resolution
482 */
483 public ZoomThread(long startTime, long endTime, long resolution) {
484 super(AbstractTimeGraphView.this.getName() + " zoom"); //$NON-NLS-1$
485 fZoomStartTime = startTime;
486 fZoomEndTime = endTime;
487 fResolution = resolution;
488 fMonitor = new NullProgressMonitor();
489 }
490
491 /**
492 * @return the zoom start time
493 */
494 public long getZoomStartTime() {
495 return fZoomStartTime;
496 }
497
498 /**
499 * @return the zoom end time
500 */
501 public long getZoomEndTime() {
502 return fZoomEndTime;
503 }
504
505 /**
506 * @return the resolution
507 */
508 public long getResolution() {
509 return fResolution;
510 }
511
512 /**
513 * @return the monitor
514 */
515 public @NonNull IProgressMonitor getMonitor() {
516 return fMonitor;
517 }
518
519 /**
520 * Cancel the zoom thread
521 */
522 public void cancel() {
523 fMonitor.setCanceled(true);
524 }
525 }
526
527 private class ZoomThreadByEntry extends ZoomThread {
528 private final @NonNull List<TimeGraphEntry> fZoomEntryList;
529
530 public ZoomThreadByEntry(@NonNull List<TimeGraphEntry> entryList, long startTime, long endTime, long resolution) {
531 super(startTime, endTime, resolution);
532 fZoomEntryList = entryList;
533 }
534
535 @Override
536 public void run() {
537 for (TimeGraphEntry entry : fZoomEntryList) {
538 if (getMonitor().isCanceled()) {
539 return;
540 }
541 if (entry == null) {
542 break;
543 }
544 zoom(entry, getMonitor());
545 }
546 /* Refresh the arrows when zooming */
547 List<ILinkEvent> events = getLinkList(getZoomStartTime(), getZoomEndTime(), getResolution(), getMonitor());
548 if (events != null) {
549 fTimeGraphWrapper.getTimeGraphViewer().setLinks(events);
550 redraw();
551 }
552 }
553
554 private void zoom(@NonNull TimeGraphEntry entry, @NonNull IProgressMonitor monitor) {
555 if (getZoomStartTime() <= fStartTime && getZoomEndTime() >= fEndTime) {
556 entry.setZoomedEventList(null);
557 } else {
558 List<ITimeEvent> zoomedEventList = getEventList(entry, getZoomStartTime(), getZoomEndTime(), getResolution(), monitor);
559 if (zoomedEventList != null) {
560 entry.setZoomedEventList(zoomedEventList);
561 }
562 }
563 redraw();
564 for (ITimeGraphEntry child : entry.getChildren()) {
565 if (monitor.isCanceled()) {
566 return;
567 }
568 if (child instanceof TimeGraphEntry) {
569 zoom((TimeGraphEntry) child, monitor);
570 }
571 }
572 }
573
574 }
575
576 // ------------------------------------------------------------------------
577 // Constructors
578 // ------------------------------------------------------------------------
579
580 /**
581 * Constructs a time graph view that contains either a time graph viewer or
582 * a time graph combo.
583 *
584 * By default, the view uses a time graph viewer. To use a time graph combo,
585 * the subclass constructor must call {@link #setTreeColumns(String[])} and
586 * {@link #setTreeLabelProvider(TreeLabelProvider)}.
587 *
588 * @param id
589 * The id of the view
590 * @param pres
591 * The presentation provider
592 */
593 public AbstractTimeGraphView(String id, TimeGraphPresentationProvider pres) {
594 super(id);
595 fPresentation = pres;
596 fDisplayWidth = Display.getDefault().getBounds().width;
597 }
598
599 // ------------------------------------------------------------------------
600 // Getters and setters
601 // ------------------------------------------------------------------------
602
603 /**
604 * Getter for the time graph combo
605 *
606 * @return The time graph combo, or null if combo is not used
607 */
608 protected TimeGraphCombo getTimeGraphCombo() {
609 if (fTimeGraphWrapper instanceof TimeGraphComboWrapper) {
610 return ((TimeGraphComboWrapper) fTimeGraphWrapper).getTimeGraphCombo();
611 }
612 return null;
613 }
614
615 /**
616 * Getter for the time graph viewer
617 *
618 * @return The time graph viewer
619 */
620 protected TimeGraphViewer getTimeGraphViewer() {
621 return fTimeGraphWrapper.getTimeGraphViewer();
622 }
623
624 /**
625 * Getter for the presentation provider
626 *
627 * @return The time graph presentation provider
628 */
629 protected ITimeGraphPresentationProvider2 getPresentationProvider() {
630 return fPresentation;
631 }
632
633 /**
634 * Sets the tree column labels.
635 * This should be called from the constructor.
636 *
637 * @param columns
638 * The array of tree column labels
639 */
640 protected void setTreeColumns(final String[] columns) {
641 fColumns = columns;
642 }
643
644 /**
645 * Sets the tree label provider.
646 * This should be called from the constructor.
647 *
648 * @param tlp
649 * The tree label provider
650 */
651 protected void setTreeLabelProvider(final TreeLabelProvider tlp) {
652 fLabelProvider = tlp;
653 }
654
655 /**
656 * Sets the time graph content provider. This should be called from the
657 * constructor.
658 *
659 * @param tgcp
660 * The time graph content provider
661 * @since 1.0
662 */
663 protected void setTimeGraphContentProvider(final @NonNull ITimeGraphContentProvider tgcp) {
664 fTimeGraphContentProvider = tgcp;
665 }
666
667 /**
668 * Sets the relative weight of each part of the time graph combo.
669 * This should be called from the constructor.
670 *
671 * @param weights
672 * The array (length 2) of relative weights of each part of the combo
673 */
674 protected void setWeight(final int[] weights) {
675 fWeight = weights;
676 }
677
678 /**
679 * Sets the filter column labels.
680 * This should be called from the constructor.
681 *
682 * @param filterColumns
683 * The array of filter column labels
684 */
685 protected void setFilterColumns(final String[] filterColumns) {
686 fFilterColumns = filterColumns;
687 }
688
689 /**
690 * Sets the filter label provider.
691 * This should be called from the constructor.
692 *
693 * @param labelProvider
694 * The filter label provider
695 */
696 protected void setFilterLabelProvider(final TreeLabelProvider labelProvider) {
697 fFilterLabelProvider = labelProvider;
698 }
699
700 /**
701 * Gets the display width
702 *
703 * @return the display width
704 */
705 protected int getDisplayWidth() {
706 return fDisplayWidth;
707 }
708
709 /**
710 * Gets the comparator for the entries
711 *
712 * @return The entry comparator
713 */
714 protected Comparator<ITimeGraphEntry> getEntryComparator() {
715 return fEntryComparator;
716 }
717
718 /**
719 * Sets the comparator class for the entries
720 *
721 * @param comparator
722 * A comparator object
723 */
724 protected void setEntryComparator(final Comparator<ITimeGraphEntry> comparator) {
725 fEntryComparator = comparator;
726 }
727
728 /**
729 * Gets the trace displayed in the view
730 *
731 * @return The trace
732 */
733 protected ITmfTrace getTrace() {
734 return fTrace;
735 }
736
737 /**
738 * Gets the start time
739 *
740 * @return The start time
741 */
742 protected long getStartTime() {
743 return fStartTime;
744 }
745
746 /**
747 * Sets the start time
748 *
749 * @param time
750 * The start time
751 */
752 protected void setStartTime(long time) {
753 fStartTime = time;
754 }
755
756 /**
757 * Gets the end time
758 *
759 * @return The end time
760 */
761 protected long getEndTime() {
762 return fEndTime;
763 }
764
765 /**
766 * Sets the end time
767 *
768 * @param time
769 * The end time
770 */
771 protected void setEndTime(long time) {
772 fEndTime = time;
773 }
774
775 /**
776 * Sets the auto-expand level to be used for the input of the view. The
777 * value 0 means that there is no auto-expand; 1 means that top-level
778 * elements are expanded, but not their children; 2 means that top-level
779 * elements are expanded, and their children, but not grand-children; and so
780 * on.
781 * <p>
782 * The value {@link #ALL_LEVELS} means that all subtrees should be expanded.
783 * </p>
784 *
785 * @param level
786 * non-negative level, or <code>ALL_LEVELS</code> to expand all
787 * levels of the tree
788 */
789 protected void setAutoExpandLevel(int level) {
790 fAutoExpandLevel = level;
791 ITimeGraphWrapper tgWrapper = fTimeGraphWrapper;
792 if (tgWrapper != null) {
793 tgWrapper.setAutoExpandLevel(level);
794 }
795 }
796
797 /**
798 * Gets the entry list for a trace
799 *
800 * @param trace
801 * the trace
802 *
803 * @return the entry list map
804 */
805 protected List<TimeGraphEntry> getEntryList(ITmfTrace trace) {
806 synchronized (fEntryListMap) {
807 return fEntryListMap.get(trace);
808 }
809 }
810
811 /**
812 * Adds a trace entry list to the entry list map
813 *
814 * @param trace
815 * the trace to add
816 * @param list
817 * the list of time graph entries
818 */
819 protected void putEntryList(ITmfTrace trace, List<TimeGraphEntry> list) {
820 synchronized (fEntryListMap) {
821 fEntryListMap.put(trace, new CopyOnWriteArrayList<>(list));
822 }
823 }
824
825 /**
826 * Adds a list of entries to a trace's entry list
827 *
828 * @param trace
829 * the trace
830 * @param list
831 * the list of time graph entries to add
832 */
833 protected void addToEntryList(ITmfTrace trace, List<TimeGraphEntry> list) {
834 synchronized (fEntryListMap) {
835 List<TimeGraphEntry> entryList = fEntryListMap.get(trace);
836 if (entryList == null) {
837 fEntryListMap.put(trace, new CopyOnWriteArrayList<>(list));
838 } else {
839 entryList.addAll(list);
840 }
841 }
842 }
843
844 /**
845 * Removes a list of entries from a trace's entry list
846 *
847 * @param trace
848 * the trace
849 * @param list
850 * the list of time graph entries to remove
851 */
852 protected void removeFromEntryList(ITmfTrace trace, List<TimeGraphEntry> list) {
853 synchronized (fEntryListMap) {
854 List<TimeGraphEntry> entryList = fEntryListMap.get(trace);
855 if (entryList != null) {
856 entryList.removeAll(list);
857 }
858 }
859 }
860
861 /**
862 * Text for the "next" button
863 *
864 * @return The "next" button text
865 */
866 protected String getNextText() {
867 return Messages.AbstractTimeGraphtView_NextText;
868 }
869
870 /**
871 * Tooltip for the "next" button
872 *
873 * @return Tooltip for the "next" button
874 */
875 protected String getNextTooltip() {
876 return Messages.AbstractTimeGraphView_NextTooltip;
877 }
878
879 /**
880 * Text for the "Previous" button
881 *
882 * @return The "Previous" button text
883 */
884 protected String getPrevText() {
885 return Messages.AbstractTimeGraphView_PreviousText;
886 }
887
888 /**
889 * Tooltip for the "previous" button
890 *
891 * @return Tooltip for the "previous" button
892 */
893 protected String getPrevTooltip() {
894 return Messages.AbstractTimeGraphView_PreviousTooltip;
895 }
896
897 // ------------------------------------------------------------------------
898 // ViewPart
899 // ------------------------------------------------------------------------
900
901 @Override
902 public void createPartControl(Composite parent) {
903 super.createPartControl(parent);
904 if (fColumns == null || fLabelProvider == null) {
905 fTimeGraphWrapper = new TimeGraphViewerWrapper(parent, SWT.NONE);
906 TimeGraphViewer viewer = fTimeGraphWrapper.getTimeGraphViewer();
907 viewer.setTimeGraphContentProvider(fTimeGraphContentProvider);
908 } else {
909 TimeGraphComboWrapper wrapper = new TimeGraphComboWrapper(parent, SWT.NONE);
910 fTimeGraphWrapper = wrapper;
911 TimeGraphCombo combo = wrapper.getTimeGraphCombo();
912 combo.setTreeContentProvider(fTimeGraphContentProvider);
913 combo.setTreeLabelProvider(fLabelProvider);
914 combo.setTreeColumns(fColumns);
915 combo.setFilterContentProvider(fTimeGraphContentProvider);
916 combo.setFilterLabelProvider(fFilterLabelProvider);
917 combo.setFilterColumns(fFilterColumns);
918 combo.setTimeGraphContentProvider(fTimeGraphContentProvider);
919 }
920
921 fTimeGraphWrapper.setTimeGraphProvider(fPresentation);
922 fTimeGraphWrapper.setAutoExpandLevel(fAutoExpandLevel);
923
924 fTimeGraphWrapper.getTimeGraphViewer().addRangeListener(new ITimeGraphRangeListener() {
925 @Override
926 public void timeRangeUpdated(TimeGraphRangeUpdateEvent event) {
927 final long startTime = event.getStartTime();
928 final long endTime = event.getEndTime();
929 TmfTimeRange range = new TmfTimeRange(new TmfNanoTimestamp(startTime), new TmfNanoTimestamp(endTime));
930 broadcast(new TmfWindowRangeUpdatedSignal(AbstractTimeGraphView.this, range));
931 startZoomThread(startTime, endTime);
932 }
933 });
934
935 fTimeGraphWrapper.getTimeGraphViewer().addTimeListener(new ITimeGraphTimeListener() {
936 @Override
937 public void timeSelected(TimeGraphTimeEvent event) {
938 TmfNanoTimestamp startTime = new TmfNanoTimestamp(event.getBeginTime());
939 TmfNanoTimestamp endTime = new TmfNanoTimestamp(event.getEndTime());
940 broadcast(new TmfSelectionRangeUpdatedSignal(AbstractTimeGraphView.this, startTime, endTime));
941 }
942 });
943
944 fTimeGraphWrapper.getTimeGraphViewer().setTimeFormat(TimeFormat.CALENDAR);
945
946 IStatusLineManager statusLineManager = getViewSite().getActionBars().getStatusLineManager();
947 fTimeGraphWrapper.getTimeGraphViewer().getTimeGraphControl().setStatusLineManager(statusLineManager);
948
949 // View Action Handling
950 makeActions();
951 contributeToActionBars();
952
953 ITmfTrace trace = TmfTraceManager.getInstance().getActiveTrace();
954 if (trace != null) {
955 traceSelected(new TmfTraceSelectedSignal(this, trace));
956 }
957
958 // make selection available to other views
959 getSite().setSelectionProvider(fTimeGraphWrapper.getSelectionProvider());
960 }
961
962 @Override
963 public void setFocus() {
964 fTimeGraphWrapper.setFocus();
965 }
966
967 // ------------------------------------------------------------------------
968 // Signal handlers
969 // ------------------------------------------------------------------------
970
971 /**
972 * Handler for the trace opened signal.
973 *
974 * @param signal
975 * The incoming signal
976 */
977 @TmfSignalHandler
978 public void traceOpened(TmfTraceOpenedSignal signal) {
979 fTrace = signal.getTrace();
980 loadTrace();
981 }
982
983 /**
984 * Handler for the trace selected signal
985 *
986 * @param signal
987 * The incoming signal
988 */
989 @TmfSignalHandler
990 public void traceSelected(final TmfTraceSelectedSignal signal) {
991 if (signal.getTrace() == fTrace) {
992 return;
993 }
994 fTrace = signal.getTrace();
995 loadTrace();
996 }
997
998 /**
999 * Trace is closed: clear the data structures and the view
1000 *
1001 * @param signal
1002 * the signal received
1003 */
1004 @TmfSignalHandler
1005 public void traceClosed(final TmfTraceClosedSignal signal) {
1006 synchronized (fBuildThreadMap) {
1007 for (ITmfTrace trace : getTracesToBuild(signal.getTrace())) {
1008 BuildThread buildThread = fBuildThreadMap.remove(trace);
1009 if (buildThread != null) {
1010 buildThread.cancel();
1011 }
1012 }
1013 }
1014 synchronized (fEntryListMap) {
1015 fEntryListMap.remove(signal.getTrace());
1016 }
1017 if (signal.getTrace() == fTrace) {
1018 fTrace = null;
1019 fStartTime = 0;
1020 fEndTime = 0;
1021 if (fZoomThread != null) {
1022 fZoomThread.cancel();
1023 fZoomThread = null;
1024 }
1025 refresh();
1026 }
1027 }
1028
1029 /**
1030 * Handler for the selection range signal.
1031 *
1032 * @param signal
1033 * The signal that's received
1034 * @since 1.0
1035 */
1036 @TmfSignalHandler
1037 public void selectionRangeUpdated(final TmfSelectionRangeUpdatedSignal signal) {
1038 if (signal.getSource() == this || fTrace == null) {
1039 return;
1040 }
1041 final long beginTime = signal.getBeginTime().normalize(0, ITmfTimestamp.NANOSECOND_SCALE).getValue();
1042 final long endTime = signal.getEndTime().normalize(0, ITmfTimestamp.NANOSECOND_SCALE).getValue();
1043
1044 Display.getDefault().asyncExec(new Runnable() {
1045 @Override
1046 public void run() {
1047 if (fTimeGraphWrapper.isDisposed()) {
1048 return;
1049 }
1050 if (beginTime == endTime) {
1051 fTimeGraphWrapper.getTimeGraphViewer().setSelectedTime(beginTime, true);
1052 } else {
1053 fTimeGraphWrapper.getTimeGraphViewer().setSelectionRange(beginTime, endTime);
1054 }
1055 startZoomThread(fTimeGraphWrapper.getTimeGraphViewer().getTime0(), fTimeGraphWrapper.getTimeGraphViewer().getTime1());
1056
1057 synchingToTime(beginTime);
1058 }
1059 });
1060 }
1061
1062 /**
1063 * Handler for the window range signal.
1064 *
1065 * @param signal
1066 * The signal that's received
1067 * @since 1.0
1068 */
1069 @TmfSignalHandler
1070 public void windowRangeUpdated(final TmfWindowRangeUpdatedSignal signal) {
1071 if (signal.getSource() == this || fTrace == null) {
1072 return;
1073 }
1074 if (signal.getCurrentRange().getIntersection(fTrace.getTimeRange()) == null) {
1075 return;
1076 }
1077 final long startTime = signal.getCurrentRange().getStartTime().normalize(0, ITmfTimestamp.NANOSECOND_SCALE).getValue();
1078 final long endTime = signal.getCurrentRange().getEndTime().normalize(0, ITmfTimestamp.NANOSECOND_SCALE).getValue();
1079 Display.getDefault().asyncExec(new Runnable() {
1080 @Override
1081 public void run() {
1082 if (fTimeGraphWrapper.isDisposed()) {
1083 return;
1084 }
1085 fTimeGraphWrapper.getTimeGraphViewer().setStartFinishTime(startTime, endTime);
1086 startZoomThread(startTime, endTime);
1087 }
1088 });
1089 }
1090
1091 /**
1092 * @param signal the format of the timestamps was updated.
1093 */
1094 @TmfSignalHandler
1095 public void updateTimeFormat( final TmfTimestampFormatUpdateSignal signal){
1096 fTimeGraphWrapper.refresh();
1097 }
1098
1099 // ------------------------------------------------------------------------
1100 // Internal
1101 // ------------------------------------------------------------------------
1102
1103 private void loadTrace() {
1104 if (fZoomThread != null) {
1105 fZoomThread.cancel();
1106 fZoomThread = null;
1107 }
1108 synchronized (fEntryListMap) {
1109 fEntryList = fEntryListMap.get(fTrace);
1110 if (fEntryList == null) {
1111 rebuild();
1112 } else {
1113 fStartTime = fTrace.getStartTime().normalize(0, ITmfTimestamp.NANOSECOND_SCALE).getValue();
1114 fEndTime = fTrace.getEndTime().normalize(0, ITmfTimestamp.NANOSECOND_SCALE).getValue();
1115 refresh();
1116 }
1117 }
1118 }
1119
1120 /**
1121 * Forces a rebuild of the entries list, even if entries already exist for this trace
1122 */
1123 protected void rebuild() {
1124 setStartTime(Long.MAX_VALUE);
1125 setEndTime(Long.MIN_VALUE);
1126 refresh();
1127 ITmfTrace viewTrace = fTrace;
1128 if (viewTrace == null) {
1129 return;
1130 }
1131 synchronized (fBuildThreadMap) {
1132 for (ITmfTrace trace : getTracesToBuild(viewTrace)) {
1133 if (trace == null) {
1134 break;
1135 }
1136 BuildThread buildThread = new BuildThread(trace, viewTrace, getName());
1137 fBuildThreadMap.put(trace, buildThread);
1138 buildThread.start();
1139 }
1140 }
1141 }
1142
1143 /**
1144 * Method called when synching to a given timestamp. Inheriting classes can
1145 * perform actions here to update the view at the given timestamp.
1146 *
1147 * @param time
1148 * The currently selected time
1149 */
1150 protected void synchingToTime(long time) {
1151
1152 }
1153
1154 /**
1155 * Return the list of traces whose data or analysis results will be used to
1156 * populate the view. By default, if the trace is an experiment, the traces
1157 * under it will be returned, otherwise, the trace itself is returned.
1158 *
1159 * A build thread will be started for each trace returned by this method,
1160 * some of which may receive events in live streaming mode.
1161 *
1162 * @param trace
1163 * The trace associated with this view
1164 * @return List of traces with data to display
1165 */
1166 protected @NonNull Iterable<ITmfTrace> getTracesToBuild(@NonNull ITmfTrace trace) {
1167 return TmfTraceManager.getTraceSet(trace);
1168 }
1169
1170 /**
1171 * Build the entries list to show in this time graph
1172 *
1173 * Called from the BuildThread
1174 *
1175 * @param trace
1176 * The trace being built
1177 * @param parentTrace
1178 * The parent of the trace set, or the trace itself
1179 * @param monitor
1180 * The progress monitor object
1181 */
1182 protected abstract void buildEventList(@NonNull ITmfTrace trace, @NonNull ITmfTrace parentTrace, @NonNull IProgressMonitor monitor);
1183
1184 /**
1185 * Gets the list of event for an entry in a given timerange
1186 *
1187 * @param entry
1188 * The entry to get events for
1189 * @param startTime
1190 * Start of the time range
1191 * @param endTime
1192 * End of the time range
1193 * @param resolution
1194 * The resolution
1195 * @param monitor
1196 * The progress monitor object
1197 * @return The list of events for the entry
1198 */
1199 protected abstract @Nullable List<ITimeEvent> getEventList(@NonNull TimeGraphEntry entry,
1200 long startTime, long endTime, long resolution,
1201 @NonNull IProgressMonitor monitor);
1202
1203 /**
1204 * Gets the list of links (displayed as arrows) for a trace in a given
1205 * timerange. Default implementation returns an empty list.
1206 *
1207 * @param startTime
1208 * Start of the time range
1209 * @param endTime
1210 * End of the time range
1211 * @param resolution
1212 * The resolution
1213 * @param monitor
1214 * The progress monitor object
1215 * @return The list of link events
1216 */
1217 protected @Nullable List<ILinkEvent> getLinkList(long startTime, long endTime,
1218 long resolution, @NonNull IProgressMonitor monitor) {
1219 return new ArrayList<>();
1220 }
1221
1222
1223 /**
1224 * Refresh the display
1225 */
1226 protected void refresh() {
1227 final boolean zoomThread = Thread.currentThread() instanceof ZoomThread;
1228 TmfUiRefreshHandler.getInstance().queueUpdate(this, new Runnable() {
1229 @Override
1230 public void run() {
1231 if (fTimeGraphWrapper.isDisposed()) {
1232 return;
1233 }
1234 boolean hasEntries = false;
1235 synchronized (fEntryListMap) {
1236 fEntryList = fEntryListMap.get(fTrace);
1237 if (fEntryList == null) {
1238 fEntryList = new CopyOnWriteArrayList<>();
1239 } else if (fEntryComparator != null) {
1240 List<TimeGraphEntry> list = new ArrayList<>(fEntryList);
1241 Collections.sort(list, fEntryComparator);
1242 fEntryList.clear();
1243 fEntryList.addAll(list);
1244 }
1245 hasEntries = fEntryList.size() != 0;
1246 }
1247 if (fEntryList != fTimeGraphWrapper.getInput()) {
1248 fTimeGraphWrapper.setInput(fEntryList);
1249 fTimeGraphWrapper.getTimeGraphViewer().setLinks(null);
1250 } else {
1251 fTimeGraphWrapper.refresh();
1252 }
1253 fTimeGraphWrapper.getTimeGraphViewer().setTimeBounds(fStartTime, fEndTime);
1254
1255 TmfTraceContext ctx = TmfTraceManager.getInstance().getCurrentTraceContext();
1256 long selectionBeginTime = fTrace == null ? 0 : ctx.getSelectionRange().getStartTime().normalize(0, ITmfTimestamp.NANOSECOND_SCALE).getValue();
1257 long selectionEndTime = fTrace == null ? 0 : ctx.getSelectionRange().getEndTime().normalize(0, ITmfTimestamp.NANOSECOND_SCALE).getValue();
1258 long startTime = fTrace == null ? 0 : ctx.getWindowRange().getStartTime().normalize(0, ITmfTimestamp.NANOSECOND_SCALE).getValue();
1259 long endTime = fTrace == null ? 0 : ctx.getWindowRange().getEndTime().normalize(0, ITmfTimestamp.NANOSECOND_SCALE).getValue();
1260 startTime = Math.max(startTime, fStartTime);
1261 endTime = Math.min(endTime, fEndTime);
1262 fTimeGraphWrapper.getTimeGraphViewer().setSelectionRange(selectionBeginTime, selectionEndTime);
1263 fTimeGraphWrapper.getTimeGraphViewer().setStartFinishTime(startTime, endTime);
1264
1265 if (fTimeGraphWrapper instanceof TimeGraphComboWrapper && !fPackDone) {
1266 for (TreeColumn column : ((TimeGraphComboWrapper) fTimeGraphWrapper).getTreeViewer().getTree().getColumns()) {
1267 column.pack();
1268 }
1269 if (hasEntries) {
1270 fPackDone = true;
1271 }
1272 }
1273
1274 if (!zoomThread) {
1275 startZoomThread(startTime, endTime);
1276 }
1277 }
1278 });
1279 }
1280
1281 /**
1282 * Redraw the canvas
1283 */
1284 protected void redraw() {
1285 synchronized (fSyncObj) {
1286 if (fRedrawState == State.IDLE) {
1287 fRedrawState = State.BUSY;
1288 } else {
1289 fRedrawState = State.PENDING;
1290 return;
1291 }
1292 }
1293 Display.getDefault().asyncExec(new Runnable() {
1294 @Override
1295 public void run() {
1296 if (fTimeGraphWrapper.isDisposed()) {
1297 return;
1298 }
1299 fTimeGraphWrapper.redraw();
1300 fTimeGraphWrapper.update();
1301 synchronized (fSyncObj) {
1302 if (fRedrawState == State.PENDING) {
1303 fRedrawState = State.IDLE;
1304 redraw();
1305 } else {
1306 fRedrawState = State.IDLE;
1307 }
1308 }
1309 }
1310 });
1311 }
1312
1313 private void startZoomThread(long startTime, long endTime) {
1314 boolean restart = false;
1315 if (fZoomThread != null) {
1316 fZoomThread.cancel();
1317 if (fZoomThread.fZoomStartTime == startTime && fZoomThread.fZoomEndTime == endTime) {
1318 restart = true;
1319 }
1320 }
1321 long resolution = Math.max(1, (endTime - startTime) / fDisplayWidth);
1322 fZoomThread = createZoomThread(startTime, endTime, resolution, restart);
1323 if (fZoomThread != null) {
1324 fZoomThread.start();
1325 }
1326 }
1327
1328 /**
1329 * Create a zoom thread.
1330 *
1331 * @param startTime
1332 * the zoom start time
1333 * @param endTime
1334 * the zoom end time
1335 * @param resolution
1336 * the resolution
1337 * @param restart
1338 * true if restarting zoom for the same time range
1339 * @return a zoom thread
1340 * @since 1.1
1341 */
1342 protected @Nullable ZoomThread createZoomThread(long startTime, long endTime, long resolution, boolean restart) {
1343 final List<TimeGraphEntry> entryList = fEntryList;
1344 if (entryList == null) {
1345 return null;
1346 }
1347 return new ZoomThreadByEntry(entryList, startTime, endTime, resolution);
1348 }
1349
1350 private void makeActions() {
1351 fPreviousResourceAction = fTimeGraphWrapper.getTimeGraphViewer().getPreviousItemAction();
1352 fPreviousResourceAction.setText(getPrevText());
1353 fPreviousResourceAction.setToolTipText(getPrevTooltip());
1354 fNextResourceAction = fTimeGraphWrapper.getTimeGraphViewer().getNextItemAction();
1355 fNextResourceAction.setText(getNextText());
1356 fNextResourceAction.setToolTipText(getNextTooltip());
1357 }
1358
1359 private void contributeToActionBars() {
1360 IActionBars bars = getViewSite().getActionBars();
1361 fillLocalToolBar(bars.getToolBarManager());
1362 }
1363
1364 /**
1365 * Add actions to local tool bar manager
1366 *
1367 * @param manager the tool bar manager
1368 */
1369 protected void fillLocalToolBar(IToolBarManager manager) {
1370 if (fTimeGraphWrapper instanceof TimeGraphComboWrapper) {
1371 if (fFilterColumns != null && fFilterLabelProvider != null && fFilterColumns.length > 0) {
1372 manager.add(((TimeGraphComboWrapper) fTimeGraphWrapper).getShowFilterAction());
1373 }
1374 }
1375 manager.add(fTimeGraphWrapper.getTimeGraphViewer().getShowLegendAction());
1376 manager.add(new Separator());
1377 manager.add(fTimeGraphWrapper.getTimeGraphViewer().getResetScaleAction());
1378 manager.add(fTimeGraphWrapper.getTimeGraphViewer().getPreviousEventAction());
1379 manager.add(fTimeGraphWrapper.getTimeGraphViewer().getNextEventAction());
1380 manager.add(fPreviousResourceAction);
1381 manager.add(fNextResourceAction);
1382 manager.add(fTimeGraphWrapper.getTimeGraphViewer().getZoomInAction());
1383 manager.add(fTimeGraphWrapper.getTimeGraphViewer().getZoomOutAction());
1384 manager.add(new Separator());
1385 }
1386
1387 /**
1388 * @since 1.0
1389 */
1390 @Override
1391 public TmfTimeViewAlignmentInfo getTimeViewAlignmentInfo() {
1392 if (fTimeGraphWrapper == null) {
1393 return null;
1394 }
1395 return fTimeGraphWrapper.getTimeViewAlignmentInfo();
1396 }
1397
1398 /**
1399 * @since 1.0
1400 */
1401 @Override
1402 public int getAvailableWidth(int requestedOffset) {
1403 if (fTimeGraphWrapper == null) {
1404 return 0;
1405 }
1406 return fTimeGraphWrapper.getAvailableWidth(requestedOffset);
1407 }
1408
1409 /**
1410 * @since 1.0
1411 */
1412 @Override
1413 public void performAlign(int offset, int width) {
1414 if (fTimeGraphWrapper != null) {
1415 fTimeGraphWrapper.performAlign(offset, width);
1416 }
1417 }
1418 }
This page took 0.06381 seconds and 6 git commands to generate.