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