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