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