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