9e5dfdaf79fc7aab5502e30cabe2c64a4e50cda2
[deliverable/tracecompass.git] / 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 private class ZoomThread extends Thread {
464 private final @NonNull List<TimeGraphEntry> fZoomEntryList;
465 private final long fZoomStartTime;
466 private final long fZoomEndTime;
467 private final long fResolution;
468 private final @NonNull IProgressMonitor fMonitor;
469
470 public ZoomThread(@NonNull List<TimeGraphEntry> entryList, long startTime, long endTime, String name) {
471 super(name + " zoom"); //$NON-NLS-1$
472 fZoomEntryList = entryList;
473 fZoomStartTime = startTime;
474 fZoomEndTime = endTime;
475 fResolution = Math.max(1, (fZoomEndTime - fZoomStartTime) / fDisplayWidth);
476 fMonitor = new NullProgressMonitor();
477 }
478
479 @Override
480 public void run() {
481 for (TimeGraphEntry entry : fZoomEntryList) {
482 if (fMonitor.isCanceled()) {
483 return;
484 }
485 if (entry == null) {
486 break;
487 }
488 zoom(entry, fMonitor);
489 }
490 /* Refresh the arrows when zooming */
491 List<ILinkEvent> events = getLinkList(fZoomStartTime, fZoomEndTime, fResolution, fMonitor);
492 if (events != null) {
493 fTimeGraphWrapper.getTimeGraphViewer().setLinks(events);
494 redraw();
495 }
496 }
497
498 private void zoom(@NonNull TimeGraphEntry entry, @NonNull IProgressMonitor monitor) {
499 if (fZoomStartTime <= fStartTime && fZoomEndTime >= fEndTime) {
500 entry.setZoomedEventList(null);
501 } else {
502 List<ITimeEvent> zoomedEventList = getEventList(entry, fZoomStartTime, fZoomEndTime, fResolution, monitor);
503 if (zoomedEventList != null) {
504 entry.setZoomedEventList(zoomedEventList);
505 }
506 }
507 redraw();
508 for (ITimeGraphEntry child : entry.getChildren()) {
509 if (fMonitor.isCanceled()) {
510 return;
511 }
512 if (child instanceof TimeGraphEntry) {
513 zoom((TimeGraphEntry) child, monitor);
514 }
515 }
516 }
517
518 public void cancel() {
519 fMonitor.setCanceled(true);
520 }
521 }
522
523 // ------------------------------------------------------------------------
524 // Constructors
525 // ------------------------------------------------------------------------
526
527 /**
528 * Constructs a time graph view that contains either a time graph viewer or
529 * a time graph combo.
530 *
531 * By default, the view uses a time graph viewer. To use a time graph combo,
532 * the subclass constructor must call {@link #setTreeColumns(String[])} and
533 * {@link #setTreeLabelProvider(TreeLabelProvider)}.
534 *
535 * @param id
536 * The id of the view
537 * @param pres
538 * The presentation provider
539 */
540 public AbstractTimeGraphView(String id, TimeGraphPresentationProvider pres) {
541 super(id);
542 fPresentation = pres;
543 fDisplayWidth = Display.getDefault().getBounds().width;
544 }
545
546 // ------------------------------------------------------------------------
547 // Getters and setters
548 // ------------------------------------------------------------------------
549
550 /**
551 * Getter for the time graph combo
552 *
553 * @return The time graph combo, or null if combo is not used
554 */
555 protected TimeGraphCombo getTimeGraphCombo() {
556 if (fTimeGraphWrapper instanceof TimeGraphComboWrapper) {
557 return ((TimeGraphComboWrapper) fTimeGraphWrapper).getTimeGraphCombo();
558 }
559 return null;
560 }
561
562 /**
563 * Getter for the time graph viewer
564 *
565 * @return The time graph viewer
566 */
567 protected TimeGraphViewer getTimeGraphViewer() {
568 return fTimeGraphWrapper.getTimeGraphViewer();
569 }
570
571 /**
572 * Getter for the presentation provider
573 *
574 * @return The time graph presentation provider
575 */
576 protected ITimeGraphPresentationProvider2 getPresentationProvider() {
577 return fPresentation;
578 }
579
580 /**
581 * Sets the tree column labels.
582 * This should be called from the constructor.
583 *
584 * @param columns
585 * The array of tree column labels
586 */
587 protected void setTreeColumns(final String[] columns) {
588 fColumns = columns;
589 }
590
591 /**
592 * Sets the tree label provider.
593 * This should be called from the constructor.
594 *
595 * @param tlp
596 * The tree label provider
597 */
598 protected void setTreeLabelProvider(final TreeLabelProvider tlp) {
599 fLabelProvider = tlp;
600 }
601
602 /**
603 * Sets the time graph content provider. This should be called from the
604 * constructor.
605 *
606 * @param tgcp
607 * The time graph content provider
608 * @since 1.0
609 */
610 protected void setTimeGraphContentProvider(final @NonNull ITimeGraphContentProvider tgcp) {
611 fTimeGraphContentProvider = tgcp;
612 }
613
614 /**
615 * Sets the relative weight of each part of the time graph combo.
616 * This should be called from the constructor.
617 *
618 * @param weights
619 * The array (length 2) of relative weights of each part of the combo
620 */
621 protected void setWeight(final int[] weights) {
622 fWeight = weights;
623 }
624
625 /**
626 * Sets the filter column labels.
627 * This should be called from the constructor.
628 *
629 * @param filterColumns
630 * The array of filter column labels
631 */
632 protected void setFilterColumns(final String[] filterColumns) {
633 fFilterColumns = filterColumns;
634 }
635
636 /**
637 * Sets the filter label provider.
638 * This should be called from the constructor.
639 *
640 * @param labelProvider
641 * The filter label provider
642 */
643 protected void setFilterLabelProvider(final TreeLabelProvider labelProvider) {
644 fFilterLabelProvider = labelProvider;
645 }
646
647 /**
648 * Gets the display width
649 *
650 * @return the display width
651 */
652 protected int getDisplayWidth() {
653 return fDisplayWidth;
654 }
655
656 /**
657 * Gets the comparator for the entries
658 *
659 * @return The entry comparator
660 */
661 protected Comparator<ITimeGraphEntry> getEntryComparator() {
662 return fEntryComparator;
663 }
664
665 /**
666 * Sets the comparator class for the entries
667 *
668 * @param comparator
669 * A comparator object
670 */
671 protected void setEntryComparator(final Comparator<ITimeGraphEntry> comparator) {
672 fEntryComparator = comparator;
673 }
674
675 /**
676 * Gets the trace displayed in the view
677 *
678 * @return The trace
679 */
680 protected ITmfTrace getTrace() {
681 return fTrace;
682 }
683
684 /**
685 * Gets the start time
686 *
687 * @return The start time
688 */
689 protected long getStartTime() {
690 return fStartTime;
691 }
692
693 /**
694 * Sets the start time
695 *
696 * @param time
697 * The start time
698 */
699 protected void setStartTime(long time) {
700 fStartTime = time;
701 }
702
703 /**
704 * Gets the end time
705 *
706 * @return The end time
707 */
708 protected long getEndTime() {
709 return fEndTime;
710 }
711
712 /**
713 * Sets the end time
714 *
715 * @param time
716 * The end time
717 */
718 protected void setEndTime(long time) {
719 fEndTime = time;
720 }
721
722 /**
723 * Sets the auto-expand level to be used for the input of the view. The
724 * value 0 means that there is no auto-expand; 1 means that top-level
725 * elements are expanded, but not their children; 2 means that top-level
726 * elements are expanded, and their children, but not grand-children; and so
727 * on.
728 * <p>
729 * The value {@link #ALL_LEVELS} means that all subtrees should be expanded.
730 * </p>
731 *
732 * @param level
733 * non-negative level, or <code>ALL_LEVELS</code> to expand all
734 * levels of the tree
735 */
736 protected void setAutoExpandLevel(int level) {
737 fAutoExpandLevel = level;
738 ITimeGraphWrapper tgWrapper = fTimeGraphWrapper;
739 if (tgWrapper != null) {
740 tgWrapper.setAutoExpandLevel(level);
741 }
742 }
743
744 /**
745 * Gets the entry list for a trace
746 *
747 * @param trace
748 * the trace
749 *
750 * @return the entry list map
751 */
752 protected List<TimeGraphEntry> getEntryList(ITmfTrace trace) {
753 synchronized (fEntryListMap) {
754 return fEntryListMap.get(trace);
755 }
756 }
757
758 /**
759 * Adds a trace entry list to the entry list map
760 *
761 * @param trace
762 * the trace to add
763 * @param list
764 * the list of time graph entries
765 */
766 protected void putEntryList(ITmfTrace trace, List<TimeGraphEntry> list) {
767 synchronized (fEntryListMap) {
768 fEntryListMap.put(trace, new CopyOnWriteArrayList<>(list));
769 }
770 }
771
772 /**
773 * Adds a list of entries to a trace's entry list
774 *
775 * @param trace
776 * the trace
777 * @param list
778 * the list of time graph entries to add
779 */
780 protected void addToEntryList(ITmfTrace trace, List<TimeGraphEntry> list) {
781 synchronized (fEntryListMap) {
782 List<TimeGraphEntry> entryList = fEntryListMap.get(trace);
783 if (entryList == null) {
784 fEntryListMap.put(trace, new CopyOnWriteArrayList<>(list));
785 } else {
786 entryList.addAll(list);
787 }
788 }
789 }
790
791 /**
792 * Removes a list of entries from a trace's entry list
793 *
794 * @param trace
795 * the trace
796 * @param list
797 * the list of time graph entries to remove
798 */
799 protected void removeFromEntryList(ITmfTrace trace, List<TimeGraphEntry> list) {
800 synchronized (fEntryListMap) {
801 List<TimeGraphEntry> entryList = fEntryListMap.get(trace);
802 if (entryList != null) {
803 entryList.removeAll(list);
804 }
805 }
806 }
807
808 /**
809 * Text for the "next" button
810 *
811 * @return The "next" button text
812 */
813 protected String getNextText() {
814 return Messages.AbstractTimeGraphtView_NextText;
815 }
816
817 /**
818 * Tooltip for the "next" button
819 *
820 * @return Tooltip for the "next" button
821 */
822 protected String getNextTooltip() {
823 return Messages.AbstractTimeGraphView_NextTooltip;
824 }
825
826 /**
827 * Text for the "Previous" button
828 *
829 * @return The "Previous" button text
830 */
831 protected String getPrevText() {
832 return Messages.AbstractTimeGraphView_PreviousText;
833 }
834
835 /**
836 * Tooltip for the "previous" button
837 *
838 * @return Tooltip for the "previous" button
839 */
840 protected String getPrevTooltip() {
841 return Messages.AbstractTimeGraphView_PreviousTooltip;
842 }
843
844 // ------------------------------------------------------------------------
845 // ViewPart
846 // ------------------------------------------------------------------------
847
848 @Override
849 public void createPartControl(Composite parent) {
850 super.createPartControl(parent);
851 if (fColumns == null || fLabelProvider == null) {
852 fTimeGraphWrapper = new TimeGraphViewerWrapper(parent, SWT.NONE);
853 TimeGraphViewer viewer = fTimeGraphWrapper.getTimeGraphViewer();
854 viewer.setTimeGraphContentProvider(fTimeGraphContentProvider);
855 } else {
856 TimeGraphComboWrapper wrapper = new TimeGraphComboWrapper(parent, SWT.NONE);
857 fTimeGraphWrapper = wrapper;
858 TimeGraphCombo combo = wrapper.getTimeGraphCombo();
859 combo.setTreeContentProvider(fTimeGraphContentProvider);
860 combo.setTreeLabelProvider(fLabelProvider);
861 combo.setTreeColumns(fColumns);
862 combo.setFilterContentProvider(fTimeGraphContentProvider);
863 combo.setFilterLabelProvider(fFilterLabelProvider);
864 combo.setFilterColumns(fFilterColumns);
865 combo.setTimeGraphContentProvider(fTimeGraphContentProvider);
866 }
867
868 fTimeGraphWrapper.setTimeGraphProvider(fPresentation);
869 fTimeGraphWrapper.setAutoExpandLevel(fAutoExpandLevel);
870
871 fTimeGraphWrapper.getTimeGraphViewer().addRangeListener(new ITimeGraphRangeListener() {
872 @Override
873 public void timeRangeUpdated(TimeGraphRangeUpdateEvent event) {
874 final long startTime = event.getStartTime();
875 final long endTime = event.getEndTime();
876 TmfTimeRange range = new TmfTimeRange(new TmfNanoTimestamp(startTime), new TmfNanoTimestamp(endTime));
877 broadcast(new TmfWindowRangeUpdatedSignal(AbstractTimeGraphView.this, range));
878 startZoomThread(startTime, endTime);
879 }
880 });
881
882 fTimeGraphWrapper.getTimeGraphViewer().addTimeListener(new ITimeGraphTimeListener() {
883 @Override
884 public void timeSelected(TimeGraphTimeEvent event) {
885 TmfNanoTimestamp startTime = new TmfNanoTimestamp(event.getBeginTime());
886 TmfNanoTimestamp endTime = new TmfNanoTimestamp(event.getEndTime());
887 broadcast(new TmfSelectionRangeUpdatedSignal(AbstractTimeGraphView.this, startTime, endTime));
888 }
889 });
890
891 fTimeGraphWrapper.getTimeGraphViewer().setTimeFormat(TimeFormat.CALENDAR);
892
893 IStatusLineManager statusLineManager = getViewSite().getActionBars().getStatusLineManager();
894 fTimeGraphWrapper.getTimeGraphViewer().getTimeGraphControl().setStatusLineManager(statusLineManager);
895
896 // View Action Handling
897 makeActions();
898 contributeToActionBars();
899
900 ITmfTrace trace = TmfTraceManager.getInstance().getActiveTrace();
901 if (trace != null) {
902 traceSelected(new TmfTraceSelectedSignal(this, trace));
903 }
904
905 // make selection available to other views
906 getSite().setSelectionProvider(fTimeGraphWrapper.getSelectionProvider());
907 }
908
909 @Override
910 public void setFocus() {
911 fTimeGraphWrapper.setFocus();
912 }
913
914 // ------------------------------------------------------------------------
915 // Signal handlers
916 // ------------------------------------------------------------------------
917
918 /**
919 * Handler for the trace opened signal.
920 *
921 * @param signal
922 * The incoming signal
923 */
924 @TmfSignalHandler
925 public void traceOpened(TmfTraceOpenedSignal signal) {
926 fTrace = signal.getTrace();
927 loadTrace();
928 }
929
930 /**
931 * Handler for the trace selected signal
932 *
933 * @param signal
934 * The incoming signal
935 */
936 @TmfSignalHandler
937 public void traceSelected(final TmfTraceSelectedSignal signal) {
938 if (signal.getTrace() == fTrace) {
939 return;
940 }
941 fTrace = signal.getTrace();
942
943 loadTrace();
944 }
945
946 /**
947 * Trace is closed: clear the data structures and the view
948 *
949 * @param signal
950 * the signal received
951 */
952 @TmfSignalHandler
953 public void traceClosed(final TmfTraceClosedSignal signal) {
954 synchronized (fBuildThreadMap) {
955 for (ITmfTrace trace : getTracesToBuild(signal.getTrace())) {
956 BuildThread buildThread = fBuildThreadMap.remove(trace);
957 if (buildThread != null) {
958 buildThread.cancel();
959 }
960 }
961 }
962 synchronized (fEntryListMap) {
963 fEntryListMap.remove(signal.getTrace());
964 }
965 if (signal.getTrace() == fTrace) {
966 fTrace = null;
967 fStartTime = 0;
968 fEndTime = 0;
969 if (fZoomThread != null) {
970 fZoomThread.cancel();
971 }
972 refresh();
973 }
974 }
975
976 /**
977 * Handler for the selection range signal.
978 *
979 * @param signal
980 * The signal that's received
981 * @since 1.0
982 */
983 @TmfSignalHandler
984 public void selectionRangeUpdated(final TmfSelectionRangeUpdatedSignal signal) {
985 if (signal.getSource() == this || fTrace == null) {
986 return;
987 }
988 final long beginTime = signal.getBeginTime().normalize(0, ITmfTimestamp.NANOSECOND_SCALE).getValue();
989 final long endTime = signal.getEndTime().normalize(0, ITmfTimestamp.NANOSECOND_SCALE).getValue();
990
991 Display.getDefault().asyncExec(new Runnable() {
992 @Override
993 public void run() {
994 if (fTimeGraphWrapper.isDisposed()) {
995 return;
996 }
997 if (beginTime == endTime) {
998 fTimeGraphWrapper.getTimeGraphViewer().setSelectedTime(beginTime, true);
999 } else {
1000 fTimeGraphWrapper.getTimeGraphViewer().setSelectionRange(beginTime, endTime);
1001 }
1002 startZoomThread(fTimeGraphWrapper.getTimeGraphViewer().getTime0(), fTimeGraphWrapper.getTimeGraphViewer().getTime1());
1003
1004 synchingToTime(beginTime);
1005 }
1006 });
1007 }
1008
1009 /**
1010 * Handler for the window range signal.
1011 *
1012 * @param signal
1013 * The signal that's received
1014 * @since 1.0
1015 */
1016 @TmfSignalHandler
1017 public void windowRangeUpdated(final TmfWindowRangeUpdatedSignal signal) {
1018 if (signal.getSource() == this || fTrace == null) {
1019 return;
1020 }
1021 if (signal.getCurrentRange().getIntersection(fTrace.getTimeRange()) == null) {
1022 return;
1023 }
1024 final long startTime = signal.getCurrentRange().getStartTime().normalize(0, ITmfTimestamp.NANOSECOND_SCALE).getValue();
1025 final long endTime = signal.getCurrentRange().getEndTime().normalize(0, ITmfTimestamp.NANOSECOND_SCALE).getValue();
1026 Display.getDefault().asyncExec(new Runnable() {
1027 @Override
1028 public void run() {
1029 if (fTimeGraphWrapper.isDisposed()) {
1030 return;
1031 }
1032 fTimeGraphWrapper.getTimeGraphViewer().setStartFinishTime(startTime, endTime);
1033 startZoomThread(startTime, endTime);
1034 }
1035 });
1036 }
1037
1038 /**
1039 * @param signal the format of the timestamps was updated.
1040 */
1041 @TmfSignalHandler
1042 public void updateTimeFormat( final TmfTimestampFormatUpdateSignal signal){
1043 fTimeGraphWrapper.refresh();
1044 }
1045
1046 // ------------------------------------------------------------------------
1047 // Internal
1048 // ------------------------------------------------------------------------
1049
1050 private void loadTrace() {
1051 synchronized (fEntryListMap) {
1052 fEntryList = fEntryListMap.get(fTrace);
1053 if (fEntryList == null) {
1054 rebuild();
1055 } else {
1056 fStartTime = fTrace.getStartTime().normalize(0, ITmfTimestamp.NANOSECOND_SCALE).getValue();
1057 fEndTime = fTrace.getEndTime().normalize(0, ITmfTimestamp.NANOSECOND_SCALE).getValue();
1058 refresh();
1059 }
1060 }
1061 }
1062
1063 /**
1064 * Forces a rebuild of the entries list, even if entries already exist for this trace
1065 */
1066 protected void rebuild() {
1067 setStartTime(Long.MAX_VALUE);
1068 setEndTime(Long.MIN_VALUE);
1069 refresh();
1070 ITmfTrace viewTrace = fTrace;
1071 if (viewTrace == null) {
1072 return;
1073 }
1074 synchronized (fBuildThreadMap) {
1075 for (ITmfTrace trace : getTracesToBuild(viewTrace)) {
1076 if (trace == null) {
1077 break;
1078 }
1079 BuildThread buildThread = new BuildThread(trace, viewTrace, getName());
1080 fBuildThreadMap.put(trace, buildThread);
1081 buildThread.start();
1082 }
1083 }
1084 }
1085
1086 /**
1087 * Method called when synching to a given timestamp. Inheriting classes can
1088 * perform actions here to update the view at the given timestamp.
1089 *
1090 * @param time
1091 * The currently selected time
1092 */
1093 protected void synchingToTime(long time) {
1094
1095 }
1096
1097 /**
1098 * Return the list of traces whose data or analysis results will be used to
1099 * populate the view. By default, if the trace is an experiment, the traces
1100 * under it will be returned, otherwise, the trace itself is returned.
1101 *
1102 * A build thread will be started for each trace returned by this method,
1103 * some of which may receive events in live streaming mode.
1104 *
1105 * @param trace
1106 * The trace associated with this view
1107 * @return List of traces with data to display
1108 */
1109 protected @NonNull Iterable<ITmfTrace> getTracesToBuild(@NonNull ITmfTrace trace) {
1110 return TmfTraceManager.getTraceSet(trace);
1111 }
1112
1113 /**
1114 * Build the entries list to show in this time graph
1115 *
1116 * Called from the BuildThread
1117 *
1118 * @param trace
1119 * The trace being built
1120 * @param parentTrace
1121 * The parent of the trace set, or the trace itself
1122 * @param monitor
1123 * The progress monitor object
1124 */
1125 protected abstract void buildEventList(@NonNull ITmfTrace trace, @NonNull ITmfTrace parentTrace, @NonNull IProgressMonitor monitor);
1126
1127 /**
1128 * Gets the list of event for an entry in a given timerange
1129 *
1130 * @param entry
1131 * The entry to get events for
1132 * @param startTime
1133 * Start of the time range
1134 * @param endTime
1135 * End of the time range
1136 * @param resolution
1137 * The resolution
1138 * @param monitor
1139 * The progress monitor object
1140 * @return The list of events for the entry
1141 */
1142 protected abstract @Nullable List<ITimeEvent> getEventList(@NonNull TimeGraphEntry entry,
1143 long startTime, long endTime, long resolution,
1144 @NonNull IProgressMonitor monitor);
1145
1146 /**
1147 * Gets the list of links (displayed as arrows) for a trace in a given
1148 * timerange. Default implementation returns an empty list.
1149 *
1150 * @param startTime
1151 * Start of the time range
1152 * @param endTime
1153 * End of the time range
1154 * @param resolution
1155 * The resolution
1156 * @param monitor
1157 * The progress monitor object
1158 * @return The list of link events
1159 */
1160 protected @Nullable List<ILinkEvent> getLinkList(long startTime, long endTime,
1161 long resolution, @NonNull IProgressMonitor monitor) {
1162 return new ArrayList<>();
1163 }
1164
1165
1166 /**
1167 * Refresh the display
1168 */
1169 protected void refresh() {
1170 TmfUiRefreshHandler.getInstance().queueUpdate(this, new Runnable() {
1171 @Override
1172 public void run() {
1173 if (fTimeGraphWrapper.isDisposed()) {
1174 return;
1175 }
1176 boolean hasEntries = false;
1177 synchronized (fEntryListMap) {
1178 fEntryList = fEntryListMap.get(fTrace);
1179 if (fEntryList == null) {
1180 fEntryList = new CopyOnWriteArrayList<>();
1181 } else if (fEntryComparator != null) {
1182 List<TimeGraphEntry> list = new ArrayList<>(fEntryList);
1183 Collections.sort(list, fEntryComparator);
1184 fEntryList.clear();
1185 fEntryList.addAll(list);
1186 }
1187 hasEntries = fEntryList.size() != 0;
1188 }
1189 if (fEntryList != fTimeGraphWrapper.getInput()) {
1190 fTimeGraphWrapper.setInput(fEntryList);
1191 } else {
1192 fTimeGraphWrapper.refresh();
1193 }
1194 fTimeGraphWrapper.getTimeGraphViewer().setTimeBounds(fStartTime, fEndTime);
1195
1196 TmfTraceContext ctx = TmfTraceManager.getInstance().getCurrentTraceContext();
1197 long selectionBeginTime = fTrace == null ? 0 : ctx.getSelectionRange().getStartTime().normalize(0, ITmfTimestamp.NANOSECOND_SCALE).getValue();
1198 long selectionEndTime = fTrace == null ? 0 : ctx.getSelectionRange().getEndTime().normalize(0, ITmfTimestamp.NANOSECOND_SCALE).getValue();
1199 long startTime = fTrace == null ? 0 : ctx.getWindowRange().getStartTime().normalize(0, ITmfTimestamp.NANOSECOND_SCALE).getValue();
1200 long endTime = fTrace == null ? 0 : ctx.getWindowRange().getEndTime().normalize(0, ITmfTimestamp.NANOSECOND_SCALE).getValue();
1201 startTime = Math.max(startTime, fStartTime);
1202 endTime = Math.min(endTime, fEndTime);
1203 fTimeGraphWrapper.getTimeGraphViewer().setSelectionRange(selectionBeginTime, selectionEndTime);
1204 fTimeGraphWrapper.getTimeGraphViewer().setStartFinishTime(startTime, endTime);
1205
1206 if (fTimeGraphWrapper instanceof TimeGraphComboWrapper && !fPackDone) {
1207 for (TreeColumn column : ((TimeGraphComboWrapper) fTimeGraphWrapper).getTreeViewer().getTree().getColumns()) {
1208 column.pack();
1209 }
1210 if (hasEntries) {
1211 fPackDone = true;
1212 }
1213 }
1214
1215 startZoomThread(startTime, endTime);
1216 }
1217 });
1218 }
1219
1220 /**
1221 * Redraw the canvas
1222 */
1223 protected void redraw() {
1224 synchronized (fSyncObj) {
1225 if (fRedrawState == State.IDLE) {
1226 fRedrawState = State.BUSY;
1227 } else {
1228 fRedrawState = State.PENDING;
1229 return;
1230 }
1231 }
1232 Display.getDefault().asyncExec(new Runnable() {
1233 @Override
1234 public void run() {
1235 if (fTimeGraphWrapper.isDisposed()) {
1236 return;
1237 }
1238 fTimeGraphWrapper.redraw();
1239 fTimeGraphWrapper.update();
1240 synchronized (fSyncObj) {
1241 if (fRedrawState == State.PENDING) {
1242 fRedrawState = State.IDLE;
1243 redraw();
1244 } else {
1245 fRedrawState = State.IDLE;
1246 }
1247 }
1248 }
1249 });
1250 }
1251
1252 private void startZoomThread(long startTime, long endTime) {
1253 if (fZoomThread != null) {
1254 fZoomThread.cancel();
1255 }
1256 final List<TimeGraphEntry> entryList = fEntryList;
1257 if (entryList == null) {
1258 return;
1259 }
1260 fZoomThread = new ZoomThread(entryList, startTime, endTime, getName());
1261 fZoomThread.start();
1262 }
1263
1264 private void makeActions() {
1265 fPreviousResourceAction = fTimeGraphWrapper.getTimeGraphViewer().getPreviousItemAction();
1266 fPreviousResourceAction.setText(getPrevText());
1267 fPreviousResourceAction.setToolTipText(getPrevTooltip());
1268 fNextResourceAction = fTimeGraphWrapper.getTimeGraphViewer().getNextItemAction();
1269 fNextResourceAction.setText(getNextText());
1270 fNextResourceAction.setToolTipText(getNextTooltip());
1271 }
1272
1273 private void contributeToActionBars() {
1274 IActionBars bars = getViewSite().getActionBars();
1275 fillLocalToolBar(bars.getToolBarManager());
1276 }
1277
1278 /**
1279 * Add actions to local tool bar manager
1280 *
1281 * @param manager the tool bar manager
1282 */
1283 protected void fillLocalToolBar(IToolBarManager manager) {
1284 if (fTimeGraphWrapper instanceof TimeGraphComboWrapper) {
1285 if (fFilterColumns != null && fFilterLabelProvider != null && fFilterColumns.length > 0) {
1286 manager.add(((TimeGraphComboWrapper) fTimeGraphWrapper).getShowFilterAction());
1287 }
1288 }
1289 manager.add(fTimeGraphWrapper.getTimeGraphViewer().getShowLegendAction());
1290 manager.add(new Separator());
1291 manager.add(fTimeGraphWrapper.getTimeGraphViewer().getResetScaleAction());
1292 manager.add(fTimeGraphWrapper.getTimeGraphViewer().getPreviousEventAction());
1293 manager.add(fTimeGraphWrapper.getTimeGraphViewer().getNextEventAction());
1294 manager.add(fPreviousResourceAction);
1295 manager.add(fNextResourceAction);
1296 manager.add(fTimeGraphWrapper.getTimeGraphViewer().getZoomInAction());
1297 manager.add(fTimeGraphWrapper.getTimeGraphViewer().getZoomOutAction());
1298 manager.add(new Separator());
1299 }
1300
1301 /**
1302 * @since 1.0
1303 */
1304 @Override
1305 public TmfTimeViewAlignmentInfo getTimeViewAlignmentInfo() {
1306 if (fTimeGraphWrapper == null) {
1307 return null;
1308 }
1309 return fTimeGraphWrapper.getTimeViewAlignmentInfo();
1310 }
1311
1312 /**
1313 * @since 1.0
1314 */
1315 @Override
1316 public int getAvailableWidth(int requestedOffset) {
1317 if (fTimeGraphWrapper == null) {
1318 return 0;
1319 }
1320 return fTimeGraphWrapper.getAvailableWidth(requestedOffset);
1321 }
1322
1323 /**
1324 * @since 1.0
1325 */
1326 @Override
1327 public void performAlign(int offset, int width) {
1328 if (fTimeGraphWrapper != null) {
1329 fTimeGraphWrapper.performAlign(offset, width);
1330 }
1331 }
1332 }
This page took 0.07356 seconds and 4 git commands to generate.