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