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