abb3bca922fb526e064a86ddb6a33354d274b39c
[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 synchronized (fBuildThreadMap) {
1378 fBuildThreadMap.values().forEach(buildThread -> {
1379 buildThread.cancel();
1380 });
1381 }
1382 if (fZoomThread != null) {
1383 fZoomThread.cancel();
1384 }
1385 ResourcesPlugin.getWorkspace().removeResourceChangeListener(this);
1386 getSite().getPage().removePartListener(fPartListener);
1387 }
1388
1389 /**
1390 * @since 2.0
1391 */
1392 @Override
1393 public void resourceChanged(final IResourceChangeEvent event) {
1394 for (final IMarkerDelta delta : event.findMarkerDeltas(IMarker.BOOKMARK, false)) {
1395 if (delta.getResource().equals(fEditorFile)) {
1396 fTimeGraphWrapper.getTimeGraphViewer().setBookmarks(refreshBookmarks(fEditorFile));
1397 redraw();
1398 return;
1399 }
1400 }
1401 }
1402
1403 private static List<IMarkerEvent> refreshBookmarks(final IFile editorFile) {
1404 List<IMarkerEvent> bookmarks = new ArrayList<>();
1405 if (editorFile == null || !editorFile.exists()) {
1406 return bookmarks;
1407 }
1408 try {
1409 IMarker[] markers = editorFile.findMarkers(IMarker.BOOKMARK, false, IResource.DEPTH_ZERO);
1410 for (IMarker marker : markers) {
1411 String label = marker.getAttribute(IMarker.MESSAGE, (String) null);
1412 String time = marker.getAttribute(ITmfMarker.MARKER_TIME, (String) null);
1413 String duration = marker.getAttribute(ITmfMarker.MARKER_DURATION, Long.toString(0));
1414 String rgba = marker.getAttribute(ITmfMarker.MARKER_COLOR, (String) null);
1415 if (label != null && time != null && rgba != null) {
1416 Matcher matcher = RGBA_PATTERN.matcher(rgba);
1417 if (matcher.matches()) {
1418 try {
1419 int red = Integer.valueOf(matcher.group(1));
1420 int green = Integer.valueOf(matcher.group(2));
1421 int blue = Integer.valueOf(matcher.group(3));
1422 int alpha = Integer.valueOf(matcher.group(4));
1423 RGBA color = new RGBA(red, green, blue, alpha);
1424 bookmarks.add(new MarkerEvent(null, Long.valueOf(time), Long.valueOf(duration), IMarkerEvent.BOOKMARKS, color, label, true));
1425 } catch (NumberFormatException e) {
1426 Activator.getDefault().logError(e.getMessage());
1427 }
1428 }
1429 }
1430 }
1431 } catch (CoreException e) {
1432 Activator.getDefault().logError(e.getMessage());
1433 }
1434 return bookmarks;
1435 }
1436
1437
1438
1439 // ------------------------------------------------------------------------
1440 // Signal handlers
1441 // ------------------------------------------------------------------------
1442
1443 /**
1444 * Handler for the trace opened signal.
1445 *
1446 * @param signal
1447 * The incoming signal
1448 */
1449 @TmfSignalHandler
1450 public void traceOpened(TmfTraceOpenedSignal signal) {
1451 loadTrace(signal.getTrace());
1452 }
1453
1454 /**
1455 * Handler for the trace selected signal
1456 *
1457 * @param signal
1458 * The incoming signal
1459 */
1460 @TmfSignalHandler
1461 public void traceSelected(final TmfTraceSelectedSignal signal) {
1462 if (signal.getTrace() == fTrace) {
1463 return;
1464 }
1465 loadTrace(signal.getTrace());
1466 }
1467
1468 /**
1469 * Trace is closed: clear the data structures and the view
1470 *
1471 * @param signal
1472 * the signal received
1473 */
1474 @TmfSignalHandler
1475 public void traceClosed(final TmfTraceClosedSignal signal) {
1476 resetView(signal.getTrace());
1477 if (signal.getTrace() == fTrace) {
1478 fTrace = null;
1479 fEditorFile = null;
1480 fStartTime = SWT.DEFAULT;
1481 fEndTime = SWT.DEFAULT;
1482 refresh();
1483 }
1484 }
1485
1486 /**
1487 * Handler for the selection range signal.
1488 *
1489 * @param signal
1490 * The signal that's received
1491 * @since 1.0
1492 */
1493 @TmfSignalHandler
1494 public void selectionRangeUpdated(final TmfSelectionRangeUpdatedSignal signal) {
1495 if (signal.getSource() == this || fTrace == null) {
1496 return;
1497 }
1498 final long beginTime = signal.getBeginTime().toNanos();
1499 final long endTime = signal.getEndTime().toNanos();
1500
1501 Display.getDefault().asyncExec(new Runnable() {
1502 @Override
1503 public void run() {
1504 if (fTimeGraphWrapper.isDisposed()) {
1505 return;
1506 }
1507 if (beginTime == endTime) {
1508 fTimeGraphWrapper.getTimeGraphViewer().setSelectedTime(beginTime, true);
1509 } else {
1510 fTimeGraphWrapper.getTimeGraphViewer().setSelectionRange(beginTime, endTime, true);
1511 }
1512 synchingToTime(fTimeGraphWrapper.getTimeGraphViewer().getSelectionBegin());
1513 }
1514 });
1515 }
1516
1517 /**
1518 * Handler for the window range signal.
1519 *
1520 * @param signal
1521 * The signal that's received
1522 * @since 1.0
1523 */
1524 @TmfSignalHandler
1525 public void windowRangeUpdated(final TmfWindowRangeUpdatedSignal signal) {
1526 if (signal.getSource() == this || fTrace == null) {
1527 return;
1528 }
1529 if (signal.getCurrentRange().getIntersection(fTrace.getTimeRange()) == null) {
1530 return;
1531 }
1532 final long startTime = signal.getCurrentRange().getStartTime().toNanos();
1533 final long endTime = signal.getCurrentRange().getEndTime().toNanos();
1534 Display.getDefault().asyncExec(new Runnable() {
1535 @Override
1536 public void run() {
1537 if (fTimeGraphWrapper.isDisposed()) {
1538 return;
1539 }
1540 fTimeGraphWrapper.getTimeGraphViewer().setStartFinishTime(startTime, endTime);
1541 startZoomThread(startTime, endTime);
1542 }
1543 });
1544 }
1545
1546 /**
1547 * @param signal the format of the timestamps was updated.
1548 */
1549 @TmfSignalHandler
1550 public void updateTimeFormat( final TmfTimestampFormatUpdateSignal signal){
1551 fTimeGraphWrapper.refresh();
1552 }
1553
1554 // ------------------------------------------------------------------------
1555 // Internal
1556 // ------------------------------------------------------------------------
1557
1558 private void loadTrace(final ITmfTrace trace) {
1559 if (fZoomThread != null) {
1560 fZoomThread.cancel();
1561 fZoomThread = null;
1562 }
1563 if (fTrace != null) {
1564 /* save the filters of the previous trace */
1565 fFiltersMap.put(fTrace, fTimeGraphWrapper.getFilters());
1566 fViewContext.put(fTrace, new ViewContext(fCurrentSortColumn, fSortDirection, fTimeGraphWrapper.getSelection()));
1567 }
1568 fTrace = trace;
1569 restoreViewContext();
1570 fEditorFile = TmfTraceManager.getInstance().getTraceEditorFile(trace);
1571 synchronized (fEntryListMap) {
1572 fEntryList = fEntryListMap.get(fTrace);
1573 if (fEntryList == null) {
1574 rebuild();
1575 } else {
1576 fStartTime = fTrace.getStartTime().toNanos();
1577 fEndTime = fTrace.getEndTime().toNanos();
1578 refresh();
1579 }
1580 }
1581 }
1582
1583 /**
1584 * Forces a rebuild of the entries list, even if entries already exist for this trace
1585 */
1586 protected void rebuild() {
1587 setStartTime(Long.MAX_VALUE);
1588 setEndTime(Long.MIN_VALUE);
1589 refresh();
1590 ITmfTrace viewTrace = fTrace;
1591 if (viewTrace == null) {
1592 return;
1593 }
1594 resetView(viewTrace);
1595
1596 List<IMarkerEventSource> markerEventSources = new ArrayList<>();
1597 synchronized (fBuildThreadMap) {
1598 for (ITmfTrace trace : getTracesToBuild(viewTrace)) {
1599 if (trace == null) {
1600 break;
1601 }
1602 markerEventSources.addAll(TmfTraceAdapterManager.getAdapters(trace, IMarkerEventSource.class));
1603 BuildThread buildThread = new BuildThread(trace, viewTrace, getName());
1604 fBuildThreadMap.put(trace, buildThread);
1605 buildThread.start();
1606 }
1607 }
1608 fMarkerEventSourcesMap.put(viewTrace, markerEventSources);
1609 }
1610
1611 /**
1612 * Method called when synching to a given timestamp. Inheriting classes can
1613 * perform actions here to update the view at the given timestamp.
1614 *
1615 * @param time
1616 * The currently selected time
1617 */
1618 protected void synchingToTime(long time) {
1619
1620 }
1621
1622 /**
1623 * Return the list of traces whose data or analysis results will be used to
1624 * populate the view. By default, if the trace is an experiment, the traces
1625 * under it will be returned, otherwise, the trace itself is returned.
1626 *
1627 * A build thread will be started for each trace returned by this method,
1628 * some of which may receive events in live streaming mode.
1629 *
1630 * @param trace
1631 * The trace associated with this view
1632 * @return List of traces with data to display
1633 */
1634 protected @NonNull Iterable<ITmfTrace> getTracesToBuild(@NonNull ITmfTrace trace) {
1635 return TmfTraceManager.getTraceSet(trace);
1636 }
1637
1638 /**
1639 * Build the entry list to show in this time graph view.
1640 * <p>
1641 * Called from the BuildThread for each trace returned by
1642 * {@link #getTracesToBuild(ITmfTrace)}. The full event list is also
1643 * normally computed for every entry that is created.
1644 *
1645 * @param trace
1646 * The trace being built
1647 * @param parentTrace
1648 * The parent of the trace set, or the trace itself
1649 * @param monitor
1650 * The progress monitor object
1651 * @since 2.0
1652 */
1653 protected abstract void buildEntryList(@NonNull ITmfTrace trace, @NonNull ITmfTrace parentTrace, @NonNull IProgressMonitor monitor);
1654
1655 /**
1656 * Gets the list of event for an entry in a given time range.
1657 * <p>
1658 * Called from the ZoomThread for every entry to update the zoomed event
1659 * list. Can be an empty implementation if the view does not support zoomed
1660 * event lists. Can also be used to compute the full event list.
1661 *
1662 * @param entry
1663 * The entry to get events for
1664 * @param startTime
1665 * Start of the time range
1666 * @param endTime
1667 * End of the time range
1668 * @param resolution
1669 * The resolution
1670 * @param monitor
1671 * The progress monitor object
1672 * @return The list of events for the entry
1673 */
1674 protected abstract @Nullable List<@NonNull ITimeEvent> getEventList(@NonNull TimeGraphEntry entry,
1675 long startTime, long endTime, long resolution,
1676 @NonNull IProgressMonitor monitor);
1677
1678 /**
1679 * Gets the list of links (displayed as arrows) for a trace in a given
1680 * timerange. Default implementation returns an empty list.
1681 *
1682 * @param startTime
1683 * Start of the time range
1684 * @param endTime
1685 * End of the time range
1686 * @param resolution
1687 * The resolution
1688 * @param monitor
1689 * The progress monitor object
1690 * @return The list of link events
1691 */
1692 protected @Nullable List<@NonNull ILinkEvent> getLinkList(long startTime, long endTime,
1693 long resolution, @NonNull IProgressMonitor monitor) {
1694 return new ArrayList<>();
1695 }
1696
1697 /**
1698 * Gets the list of view-specific marker categories. Default implementation
1699 * returns an empty list.
1700 *
1701 * @return The list of marker categories
1702 * @since 2.0
1703 */
1704 protected @NonNull List<String> getViewMarkerCategories() {
1705 return new ArrayList<>();
1706 }
1707
1708 /**
1709 * Gets the list of view-specific markers for a trace in a given time range.
1710 * Default implementation returns an empty list.
1711 *
1712 * @param startTime
1713 * Start of the time range
1714 * @param endTime
1715 * End of the time range
1716 * @param resolution
1717 * The resolution
1718 * @param monitor
1719 * The progress monitor object
1720 * @return The list of marker events
1721 * @since 2.0
1722 */
1723 protected @NonNull List<IMarkerEvent> getViewMarkerList(long startTime, long endTime,
1724 long resolution, @NonNull IProgressMonitor monitor) {
1725 return new ArrayList<>();
1726 }
1727
1728 /**
1729 * Gets the list of trace-specific markers for a trace in a given time range.
1730 *
1731 * @param startTime
1732 * Start of the time range
1733 * @param endTime
1734 * End of the time range
1735 * @param resolution
1736 * The resolution
1737 * @param monitor
1738 * The progress monitor object
1739 * @return The list of marker events
1740 * @since 2.0
1741 */
1742 protected @NonNull List<IMarkerEvent> getTraceMarkerList(long startTime, long endTime,
1743 long resolution, @NonNull IProgressMonitor monitor) {
1744 List<IMarkerEvent> markers = new ArrayList<>();
1745 for (IMarkerEventSource markerEventSource : getMarkerEventSources(fTrace)) {
1746 for (String category : markerEventSource.getMarkerCategories()) {
1747 if (monitor.isCanceled()) {
1748 break;
1749 }
1750 markers.addAll(markerEventSource.getMarkerList(category, startTime, endTime, resolution, monitor));
1751 }
1752 }
1753 return markers;
1754 }
1755
1756 /**
1757 * Get the list of current marker categories.
1758 *
1759 * @return The list of marker categories
1760 * @since 2.0
1761 */
1762 private @NonNull List<String> getMarkerCategories() {
1763 Set<String> categories = new LinkedHashSet<>(getViewMarkerCategories());
1764 for (IMarkerEventSource markerEventSource : getMarkerEventSources(fTrace)) {
1765 categories.addAll(markerEventSource.getMarkerCategories());
1766 }
1767 return new ArrayList<>(categories);
1768 }
1769
1770 /**
1771 * Gets the list of marker event sources for a given trace.
1772 *
1773 * @param trace
1774 * The trace
1775 * @return The list of marker event sources
1776 * @since 2.0
1777 */
1778 private @NonNull List<IMarkerEventSource> getMarkerEventSources(ITmfTrace trace) {
1779 List<IMarkerEventSource> markerEventSources = fMarkerEventSourcesMap.get(trace);
1780 if (markerEventSources == null) {
1781 markerEventSources = Collections.emptyList();
1782 }
1783 return markerEventSources;
1784 }
1785
1786 /**
1787 * Refresh the display
1788 */
1789 protected void refresh() {
1790 final boolean zoomThread = Thread.currentThread() instanceof ZoomThread;
1791 TmfUiRefreshHandler.getInstance().queueUpdate(this, new Runnable() {
1792 @Override
1793 public void run() {
1794 if (fTimeGraphWrapper.isDisposed()) {
1795 return;
1796 }
1797 fDirty.incrementAndGet();
1798
1799 boolean hasEntries = false;
1800 synchronized (fEntryListMap) {
1801 fEntryList = fEntryListMap.get(fTrace);
1802 if (fEntryList == null) {
1803 fEntryList = new CopyOnWriteArrayList<>();
1804 } else if (fEntryComparator != null) {
1805 List<TimeGraphEntry> list = new ArrayList<>(fEntryList);
1806 Collections.sort(list, fEntryComparator);
1807 for (ITimeGraphEntry entry : list) {
1808 sortChildren(entry, fEntryComparator);
1809 }
1810 fEntryList.clear();
1811 fEntryList.addAll(list);
1812 }
1813 hasEntries = !fEntryList.isEmpty();
1814 }
1815 boolean inputChanged = fEntryList != fTimeGraphWrapper.getInput();
1816 TimeGraphCombo combo = getTimeGraphCombo();
1817 try {
1818 // Set redraw to false to only draw once
1819 if (combo != null) {
1820 combo.getTreeViewer().getTree().setRedraw(false);
1821 }
1822 getTimeGraphViewer().getTimeGraphControl().setRedraw(false);
1823 if (inputChanged) {
1824 fTimeGraphWrapper.setInput(fEntryList);
1825 /* restore the previously saved filters, if any */
1826 fTimeGraphWrapper.setFilters(fFiltersMap.get(fTrace));
1827 fTimeGraphWrapper.getTimeGraphViewer().setLinks(null);
1828 fTimeGraphWrapper.getTimeGraphViewer().setBookmarks(refreshBookmarks(fEditorFile));
1829 fTimeGraphWrapper.getTimeGraphViewer().setMarkerCategories(getMarkerCategories());
1830 fTimeGraphWrapper.getTimeGraphViewer().setMarkers(null);
1831 applyViewContext();
1832 } else {
1833 fTimeGraphWrapper.refresh();
1834 }
1835 // reveal selection
1836 if (fIsRevealSelection) {
1837 fIsRevealSelection = false;
1838 ITimeGraphEntry entry1 = fTimeGraphWrapper.getSelection();
1839 fTimeGraphWrapper.setSelection(entry1);
1840 }
1841 } finally {
1842 if (combo != null) {
1843 combo.getTreeViewer().getTree().setRedraw(true);
1844 }
1845 getTimeGraphViewer().getTimeGraphControl().setRedraw(true);
1846 }
1847 long startBound = (fStartTime == Long.MAX_VALUE ? SWT.DEFAULT : fStartTime);
1848 long endBound = (fEndTime == Long.MIN_VALUE ? SWT.DEFAULT : fEndTime);
1849 fTimeGraphWrapper.getTimeGraphViewer().setTimeBounds(startBound, endBound);
1850
1851 TmfTraceContext ctx = TmfTraceManager.getInstance().getCurrentTraceContext();
1852 long selectionBeginTime = fTrace == null ? SWT.DEFAULT : ctx.getSelectionRange().getStartTime().toNanos();
1853 long selectionEndTime = fTrace == null ? SWT.DEFAULT : ctx.getSelectionRange().getEndTime().toNanos();
1854 long startTime = fTrace == null ? SWT.DEFAULT : ctx.getWindowRange().getStartTime().toNanos();
1855 long endTime = fTrace == null ? SWT.DEFAULT : ctx.getWindowRange().getEndTime().toNanos();
1856 startTime = (fStartTime == Long.MAX_VALUE ? SWT.DEFAULT : Math.max(startTime, fStartTime));
1857 endTime = (fEndTime == Long.MIN_VALUE ? SWT.DEFAULT : Math.min(endTime, fEndTime));
1858 fTimeGraphWrapper.getTimeGraphViewer().setSelectionRange(selectionBeginTime, selectionEndTime, false);
1859 fTimeGraphWrapper.getTimeGraphViewer().setStartFinishTime(startTime, endTime);
1860
1861 if (inputChanged && selectionBeginTime != SWT.DEFAULT) {
1862 synchingToTime(selectionBeginTime);
1863 }
1864
1865 if (fTimeGraphWrapper instanceof TimeGraphComboWrapper && !fPackDone) {
1866 for (TreeColumn column : ((TimeGraphComboWrapper) fTimeGraphWrapper).getTreeViewer().getTree().getColumns()) {
1867 column.pack();
1868 }
1869 if (hasEntries) {
1870 fPackDone = true;
1871 }
1872 }
1873
1874 if (!zoomThread) {
1875 startZoomThread(startTime, endTime);
1876 }
1877 fDirty.decrementAndGet();
1878 }
1879 });
1880 }
1881
1882 /**
1883 * Redraw the canvas
1884 */
1885 protected void redraw() {
1886 synchronized (fSyncObj) {
1887 if (fRedrawState == State.IDLE) {
1888 fRedrawState = State.BUSY;
1889 } else {
1890 fRedrawState = State.PENDING;
1891 return;
1892 }
1893 }
1894 Display.getDefault().asyncExec(new Runnable() {
1895 @Override
1896 public void run() {
1897 if (fTimeGraphWrapper.isDisposed()) {
1898 return;
1899 }
1900 fTimeGraphWrapper.redraw();
1901 fTimeGraphWrapper.update();
1902 synchronized (fSyncObj) {
1903 if (fRedrawState == State.PENDING) {
1904 fRedrawState = State.IDLE;
1905 redraw();
1906 } else {
1907 fRedrawState = State.IDLE;
1908 }
1909 }
1910 }
1911 });
1912 }
1913
1914 private void sortChildren(ITimeGraphEntry entry, Comparator<ITimeGraphEntry> comparator) {
1915 if (entry instanceof TimeGraphEntry) {
1916 ((TimeGraphEntry) entry).sortChildren(comparator);
1917 }
1918 for (ITimeGraphEntry child : entry.getChildren()) {
1919 sortChildren(child, comparator);
1920 }
1921 }
1922
1923 /**
1924 * Start or restart the zoom thread.
1925 *
1926 * @param startTime
1927 * the zoom start time
1928 * @param endTime
1929 * the zoom end time
1930 * @since 2.0
1931 */
1932 protected final void startZoomThread(long startTime, long endTime) {
1933 long clampedStartTime = Math.min(Math.max(startTime, fStartTime), fEndTime);
1934 long clampedEndTime = Math.max(Math.min(endTime, fEndTime), fStartTime);
1935 fDirty.incrementAndGet();
1936 boolean restart = false;
1937 if (fZoomThread != null) {
1938 fZoomThread.cancel();
1939 if (fZoomThread.fZoomStartTime == clampedStartTime && fZoomThread.fZoomEndTime == clampedEndTime) {
1940 restart = true;
1941 }
1942 }
1943 long resolution = Math.max(1, (clampedEndTime - clampedStartTime) / fDisplayWidth);
1944 fZoomThread = createZoomThread(clampedStartTime, clampedEndTime, resolution, restart);
1945 if (fZoomThread != null) {
1946 // Don't start a new thread right away if results are being applied
1947 // from an old ZoomThread. Otherwise, the old results might
1948 // overwrite the new results if it finishes after.
1949 synchronized (fZoomThreadResultLock) {
1950 fZoomThread.start();
1951 }
1952 } else {
1953 fDirty.decrementAndGet();
1954 }
1955 }
1956
1957 /**
1958 * Create a zoom thread.
1959 *
1960 * @param startTime
1961 * the zoom start time
1962 * @param endTime
1963 * the zoom end time
1964 * @param resolution
1965 * the resolution
1966 * @param restart
1967 * true if restarting zoom for the same time range
1968 * @return a zoom thread
1969 * @since 1.1
1970 */
1971 protected @Nullable ZoomThread createZoomThread(long startTime, long endTime, long resolution, boolean restart) {
1972 final List<TimeGraphEntry> entryList = fEntryList;
1973 if (entryList == null) {
1974 return null;
1975 }
1976 return new ZoomThreadByEntry(entryList, startTime, endTime, resolution);
1977 }
1978
1979 private void makeActions() {
1980 fPreviousResourceAction = fTimeGraphWrapper.getTimeGraphViewer().getPreviousItemAction();
1981 fPreviousResourceAction.setText(getPrevText());
1982 fPreviousResourceAction.setToolTipText(getPrevTooltip());
1983 fNextResourceAction = fTimeGraphWrapper.getTimeGraphViewer().getNextItemAction();
1984 fNextResourceAction.setText(getNextText());
1985 fNextResourceAction.setToolTipText(getNextTooltip());
1986 }
1987
1988 private void contributeToActionBars() {
1989 IActionBars bars = getViewSite().getActionBars();
1990 fillLocalToolBar(bars.getToolBarManager());
1991 fillLocalMenu(bars.getMenuManager());
1992 }
1993
1994 /**
1995 * Add actions to local tool bar manager
1996 *
1997 * @param manager the tool bar manager
1998 */
1999 protected void fillLocalToolBar(IToolBarManager manager) {
2000 if (fFilterColumns != null && fFilterLabelProvider != null && fFilterColumns.length > 0) {
2001 manager.add(fTimeGraphWrapper.getShowFilterDialogAction());
2002 }
2003 manager.add(fTimeGraphWrapper.getTimeGraphViewer().getShowLegendAction());
2004 manager.add(new Separator());
2005 manager.add(fTimeGraphWrapper.getTimeGraphViewer().getResetScaleAction());
2006 manager.add(fTimeGraphWrapper.getTimeGraphViewer().getPreviousEventAction());
2007 manager.add(fTimeGraphWrapper.getTimeGraphViewer().getNextEventAction());
2008 manager.add(new Separator());
2009 manager.add(fTimeGraphWrapper.getTimeGraphViewer().getToggleBookmarkAction());
2010 manager.add(fTimeGraphWrapper.getTimeGraphViewer().getPreviousMarkerAction());
2011 manager.add(fTimeGraphWrapper.getTimeGraphViewer().getNextMarkerAction());
2012 manager.add(new Separator());
2013 manager.add(fPreviousResourceAction);
2014 manager.add(fNextResourceAction);
2015 manager.add(fTimeGraphWrapper.getTimeGraphViewer().getZoomInAction());
2016 manager.add(fTimeGraphWrapper.getTimeGraphViewer().getZoomOutAction());
2017 manager.add(new Separator());
2018 }
2019
2020 /**
2021 * Add actions to local menu manager
2022 *
2023 * @param manager the tool bar manager
2024 * @since 2.0
2025 */
2026 protected void fillLocalMenu(IMenuManager manager) {
2027 manager.add(fTimeGraphWrapper.getTimeGraphViewer().getMarkersMenu());
2028 }
2029
2030 /**
2031 * @since 1.0
2032 */
2033 @Override
2034 public TmfTimeViewAlignmentInfo getTimeViewAlignmentInfo() {
2035 if (fTimeGraphWrapper == null) {
2036 return null;
2037 }
2038 return fTimeGraphWrapper.getTimeViewAlignmentInfo();
2039 }
2040
2041 /**
2042 * @since 1.0
2043 */
2044 @Override
2045 public int getAvailableWidth(int requestedOffset) {
2046 if (fTimeGraphWrapper == null) {
2047 return 0;
2048 }
2049 return fTimeGraphWrapper.getAvailableWidth(requestedOffset);
2050 }
2051
2052 /**
2053 * @since 1.0
2054 */
2055 @Override
2056 public void performAlign(int offset, int width) {
2057 if (fTimeGraphWrapper != null) {
2058 fTimeGraphWrapper.performAlign(offset, width);
2059 }
2060 }
2061
2062 /**
2063 * Returns whether or not the time graph view is dirty. The time graph view
2064 * is considered dirty if it has yet to completely update its model.
2065 *
2066 * This method is meant to be used by tests in order to know when it is safe
2067 * to proceed.
2068 *
2069 * Note: If a trace is smaller than the initial window range (see
2070 * {@link ITmfTrace#getInitialRangeOffset}) this method will return true
2071 * forever.
2072 *
2073 * @return true if the time graph view has yet to completely update its
2074 * model, false otherwise
2075 * @since 2.0
2076 */
2077 public boolean isDirty() {
2078 if (fTrace == null) {
2079 return false;
2080 }
2081
2082 TmfTraceContext ctx = TmfTraceManager.getInstance().getCurrentTraceContext();
2083 long startTime = ctx.getWindowRange().getStartTime().toNanos();
2084 long endTime = ctx.getWindowRange().getEndTime().toNanos();
2085
2086 // If the time graph control hasn't updated all the way to the end of
2087 // the window range then it's dirty. A refresh should happen later.
2088 if (fTimeGraphWrapper.getTimeGraphViewer().getTime0() != startTime || fTimeGraphWrapper.getTimeGraphViewer().getTime1() != endTime) {
2089 return true;
2090 }
2091
2092 if (fZoomThread == null) {
2093 // The zoom thread is null but we might be just about to create it (refresh called).
2094 return fDirty.get() != 0;
2095 }
2096 // Dirty if the zoom thread is not done or if it hasn't zoomed all the
2097 // way to the end of the window range. In the latter case, there should be
2098 // a subsequent zoom thread that will be triggered.
2099 return fDirty.get() != 0 || fZoomThread.getZoomStartTime() != startTime || fZoomThread.getZoomEndTime() != endTime;
2100 }
2101
2102 private void createColumnSelectionListener(TreeViewer treeViewer) {
2103 for (int i = 0; i < fColumnComparators.length; i++) {
2104 final int index = i;
2105 final Comparator<ITimeGraphEntry> comp = fColumnComparators[index];
2106 final Tree tree = treeViewer.getTree();
2107 final TreeColumn column = tree.getColumn(i);
2108
2109 if (comp != null) {
2110 column.addSelectionListener(new SelectionAdapter() {
2111 @Override
2112 public void widgetSelected(SelectionEvent e) {
2113 TreeColumn prevSortcolumn = tree.getSortColumn();
2114 int direction = tree.getSortDirection();
2115 if (prevSortcolumn == column) {
2116 direction = (direction == SWT.DOWN) ? SWT.UP : SWT.DOWN;
2117 } else {
2118 direction = SWT.DOWN;
2119 }
2120 tree.setSortColumn(column);
2121 tree.setSortDirection(direction);
2122 fSortDirection = direction;
2123 fCurrentSortColumn = index;
2124 Comparator<ITimeGraphEntry> comparator = comp;
2125
2126 if (comparator instanceof ITimeGraphEntryComparator) {
2127 ((ITimeGraphEntryComparator) comparator).setDirection(direction);
2128 }
2129 if (direction != SWT.DOWN) {
2130 comparator = checkNotNull(Collections.reverseOrder(comparator));
2131 }
2132 setEntryComparator(comparator);
2133 fIsRevealSelection = true;
2134 if (fTimeGraphWrapper instanceof TimeGraphComboWrapper) {
2135 ((TimeGraphComboWrapper) fTimeGraphWrapper).getTreeViewer().getControl().setFocus();
2136 }
2137 refresh();
2138 }
2139 });
2140 }
2141 }
2142 }
2143
2144 private void createDoubleClickListener(TreeViewer treeViewer) {
2145 treeViewer.addDoubleClickListener(event -> {
2146 if (event.getSelection() instanceof TreeSelection) {
2147 TreeSelection selection = (TreeSelection) event.getSelection();
2148 if (selection.getFirstElement() instanceof ITimeGraphEntry) {
2149 ITimeGraphEntry entry = (ITimeGraphEntry) selection.getFirstElement();
2150 if (entry.hasChildren()) {
2151 fTimeGraphWrapper.setExpandedState(entry, !fTimeGraphWrapper.getExpandedState(entry));
2152 }
2153 }
2154 }
2155 });
2156 }
2157
2158
2159 private void restoreViewContext() {
2160 TimeGraphCombo combo = getTimeGraphCombo();
2161 ViewContext viewContext = fViewContext.get(fTrace);
2162 if (combo != null) {
2163 if (fColumnComparators != null) {
2164 // restore sort settings
2165 fSortDirection = SWT.DOWN;
2166 fCurrentSortColumn = fInitialSortColumn;
2167 if (viewContext != null) {
2168 fSortDirection = viewContext.getSortDirection();
2169 fCurrentSortColumn = viewContext.getSortColumn();
2170 }
2171 if ((fCurrentSortColumn < fColumnComparators.length) && (fColumnComparators[fCurrentSortColumn] != null)) {
2172 Comparator<ITimeGraphEntry> comparator = fColumnComparators[fCurrentSortColumn];
2173 if (comparator instanceof ITimeGraphEntryComparator) {
2174 ((ITimeGraphEntryComparator) comparator).setDirection(fSortDirection);
2175 }
2176 if (fSortDirection != SWT.DOWN) {
2177 comparator = checkNotNull(Collections.reverseOrder(comparator));
2178 }
2179 setEntryComparator(comparator);
2180 }
2181 }
2182 }
2183 }
2184
2185 private void applyViewContext() {
2186 TimeGraphCombo combo = getTimeGraphCombo();
2187 ViewContext viewContext = fViewContext.get(fTrace);
2188 if (combo != null) {
2189 TreeViewer treeViewer = combo.getTreeViewer();
2190 final Tree tree = treeViewer.getTree();
2191 final TreeColumn column = tree.getColumn(fCurrentSortColumn);
2192 tree.setSortDirection(fSortDirection);
2193 tree.setSortColumn(column);
2194 combo.getTreeViewer().getControl().setFocus();
2195 }
2196 // restore and reveal selection
2197 if ((viewContext != null) && (viewContext.getSelection() != null)) {
2198 fTimeGraphWrapper.setSelection(viewContext.getSelection());
2199 }
2200 fViewContext.remove(fTrace);
2201 }
2202
2203 private static class ViewContext {
2204 private int fSortColumnIndex;
2205 private int fSortDirection;
2206 private @Nullable ITimeGraphEntry fSelection;
2207
2208 ViewContext(int sortColunm, int sortDirection, ITimeGraphEntry selection) {
2209 fSortColumnIndex = sortColunm;
2210 fSortDirection = sortDirection;
2211 fSelection = selection;
2212 }
2213 /**
2214 * @return the sortColumn
2215 */
2216 public int getSortColumn() {
2217 return fSortColumnIndex;
2218 }
2219 /**
2220 * @return the sortDirection
2221 */
2222 public int getSortDirection() {
2223 return fSortDirection;
2224 }
2225 /**
2226 * @return the selection
2227 */
2228 public ITimeGraphEntry getSelection() {
2229 return fSelection;
2230 }
2231 }
2232
2233 /**
2234 * Method to reset the view internal data for a given trace.
2235 *
2236 * When overriding this method make sure to call the super
2237 * implementation.
2238 *
2239 * @param viewTrace
2240 * trace to reset the view for.
2241 * @since 2.0
2242 */
2243 protected void resetView(ITmfTrace viewTrace) {
2244 if (viewTrace == null) {
2245 return;
2246 }
2247 synchronized (fBuildThreadMap) {
2248 for (ITmfTrace trace : getTracesToBuild(viewTrace)) {
2249 BuildThread buildThread = fBuildThreadMap.remove(trace);
2250 if (buildThread != null) {
2251 buildThread.cancel();
2252 }
2253 }
2254 }
2255 synchronized (fEntryListMap) {
2256 fEntryListMap.remove(viewTrace);
2257 }
2258 fViewContext.remove(viewTrace);
2259 fFiltersMap.remove(viewTrace);
2260 fMarkerEventSourcesMap.remove(viewTrace);
2261 if (viewTrace == fTrace) {
2262 if (fZoomThread != null) {
2263 fZoomThread.cancel();
2264 fZoomThread = null;
2265 }
2266 }
2267 }
2268
2269 private void createContextMenu() {
2270 TimeGraphCombo combo = getTimeGraphCombo();
2271 fEntryMenuManager.setRemoveAllWhenShown(true);
2272 if (combo != null) {
2273 TreeViewer treeViewer = combo.getTreeViewer();
2274 Tree tree = treeViewer.getTree();
2275 Menu menu = fEntryMenuManager.createContextMenu(tree);
2276 tree.setMenu(menu);
2277 } else {
2278 TimeGraphControl timeGraphControl = getTimeGraphViewer().getTimeGraphControl();
2279 final Menu entryMenu = fEntryMenuManager.createContextMenu(timeGraphControl);
2280 timeGraphControl.addTimeGraphEntryMenuListener(new MenuDetectListener() {
2281 @Override
2282 public void menuDetected(MenuDetectEvent event) {
2283 Point p = timeGraphControl.toControl(event.x, event.y);
2284 /*
2285 * The TimeGraphControl will call the TimeGraphEntryMenuListener
2286 * before the TimeEventMenuListener. If the event is
2287 * triggered on the namespace then show the menu else
2288 * clear the menu.
2289 */
2290 if (p.x < getTimeGraphViewer().getNameSpace()) {
2291 timeGraphControl.setMenu(entryMenu);
2292 } else {
2293 timeGraphControl.setMenu(null);
2294 event.doit = false;
2295 }
2296 }
2297 });
2298 }
2299 fEntryMenuManager.addMenuListener(new IMenuListener() {
2300 @Override
2301 public void menuAboutToShow(IMenuManager manager) {
2302 fillTimeGraphEntryContextMenu(fEntryMenuManager);
2303 fEntryMenuManager.add(new GroupMarker(IWorkbenchActionConstants.MB_ADDITIONS));
2304 }
2305 });
2306 getSite().registerContextMenu(fEntryMenuManager, fTimeGraphWrapper.getSelectionProvider());
2307 }
2308
2309 /**
2310 * Fill context menu
2311 *
2312 * @param menuManager
2313 * a menuManager to fill
2314 * @since 2.0
2315 */
2316 protected void fillTimeGraphEntryContextMenu (@NonNull IMenuManager menuManager) {
2317 }
2318
2319 /*
2320 * Inner classes used for searching
2321 */
2322 class FindTarget {
2323 public ITimeGraphEntry getSelection() {
2324 return fTimeGraphWrapper.getSelection();
2325 }
2326
2327 public void selectAndReveal(@NonNull ITimeGraphEntry entry) {
2328 fTimeGraphWrapper.selectAndReveal(entry);
2329 }
2330
2331 public ITimeGraphEntry[] getEntries() {
2332 TimeGraphViewer viewer = getTimeGraphViewer();
2333 return viewer.getTimeGraphContentProvider().getElements(viewer.getInput());
2334 }
2335
2336 public Shell getShell() {
2337 return getSite().getShell();
2338 }
2339 }
2340
2341 class TimeGraphPartListener implements IPartListener {
2342 @Override
2343 public void partActivated(IWorkbenchPart part) {
2344 if (part == AbstractTimeGraphView.this) {
2345 synchronized (FIND_ACTION) {
2346 if (fFindActionHandler == null) {
2347 fFindActionHandler = new ActionHandler(FIND_ACTION);
2348 }
2349 if (fFindHandlerActivation == null) {
2350 final Object service = PlatformUI.getWorkbench().getService(IHandlerService.class);
2351 fFindHandlerActivation = ((IHandlerService) service).activateHandler(ActionFactory.FIND.getCommandId(), fFindActionHandler);
2352 }
2353 }
2354 }
2355 // Notify action for all parts
2356 FIND_ACTION.partActivated(part);
2357 }
2358 @Override
2359 public void partDeactivated(IWorkbenchPart part) {
2360 if ((part == AbstractTimeGraphView.this) && (fFindHandlerActivation != null)) {
2361 final Object service = PlatformUI.getWorkbench().getService(IHandlerService.class);
2362 ((IHandlerService) service).deactivateHandler(fFindHandlerActivation);
2363 fFindHandlerActivation = null;
2364 }
2365 }
2366 @Override
2367 public void partBroughtToTop(IWorkbenchPart part) {
2368 }
2369 @Override
2370 public void partClosed(IWorkbenchPart part) {
2371 }
2372 @Override
2373 public void partOpened(IWorkbenchPart part) {
2374 }
2375 }
2376 }
This page took 0.088243 seconds and 4 git commands to generate.