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