tmf: Rename "Next/Previous Event" action to "Next/Previous State Change"
[deliverable/tracecompass.git] / tmf / org.eclipse.tracecompass.tmf.ui / src / org / eclipse / tracecompass / tmf / ui / views / callstack / CallStackView.java
CommitLineData
e8251298 1/*******************************************************************************
d2fb9e0f 2 * Copyright (c) 2013, 2016 Ericsson and others.
e8251298
PT
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
fec1ac0b 11 * Bernd Hufmann - Updated signal handling
41d9ce5b 12 * Marc-Andre Laperle - Map from binary file
e8251298
PT
13 *******************************************************************************/
14
2bdf0193 15package org.eclipse.tracecompass.tmf.ui.views.callstack;
e8251298
PT
16
17import java.util.ArrayList;
26c33ee2 18import java.util.Collections;
46cc1ade 19import java.util.Comparator;
e8251298
PT
20import java.util.HashMap;
21import java.util.Iterator;
22import java.util.List;
52974e38 23import java.util.Map;
1302015b 24import java.util.function.Consumer;
e8251298
PT
25
26import org.eclipse.core.runtime.IProgressMonitor;
1d83ed07 27import org.eclipse.jdt.annotation.NonNull;
50659279 28import org.eclipse.jdt.annotation.Nullable;
e8251298 29import org.eclipse.jface.action.Action;
d2fb9e0f 30import org.eclipse.jface.action.GroupMarker;
e8251298 31import org.eclipse.jface.action.IAction;
90bb3a0c 32import org.eclipse.jface.action.IMenuManager;
e8251298
PT
33import org.eclipse.jface.action.IToolBarManager;
34import org.eclipse.jface.action.Separator;
d90ae2a5 35import org.eclipse.jface.dialogs.IDialogConstants;
46cc1ade
PT
36import org.eclipse.jface.dialogs.IDialogSettings;
37import org.eclipse.jface.resource.ImageDescriptor;
e8251298
PT
38import org.eclipse.jface.util.IPropertyChangeListener;
39import org.eclipse.jface.util.PropertyChangeEvent;
40import org.eclipse.jface.viewers.DoubleClickEvent;
41import org.eclipse.jface.viewers.IDoubleClickListener;
e8251298
PT
42import org.eclipse.jface.viewers.ISelection;
43import org.eclipse.jface.viewers.IStructuredSelection;
e8251298 44import org.eclipse.swt.SWT;
e8251298
PT
45import org.eclipse.swt.events.MouseAdapter;
46import org.eclipse.swt.events.MouseEvent;
47import org.eclipse.swt.graphics.Image;
48import org.eclipse.swt.widgets.Composite;
49import org.eclipse.swt.widgets.Display;
2bdf0193
AM
50import org.eclipse.tracecompass.internal.tmf.ui.Activator;
51import org.eclipse.tracecompass.internal.tmf.ui.ITmfImageConstants;
52import org.eclipse.tracecompass.internal.tmf.ui.Messages;
e894a508 53import org.eclipse.tracecompass.statesystem.core.ITmfStateSystem;
1dd75589 54import org.eclipse.tracecompass.statesystem.core.StateSystemUtils;
e894a508
AM
55import org.eclipse.tracecompass.statesystem.core.exceptions.AttributeNotFoundException;
56import org.eclipse.tracecompass.statesystem.core.exceptions.StateSystemDisposedException;
57import org.eclipse.tracecompass.statesystem.core.exceptions.StateValueTypeException;
58import org.eclipse.tracecompass.statesystem.core.exceptions.TimeRangeException;
59import org.eclipse.tracecompass.statesystem.core.interval.ITmfStateInterval;
60import org.eclipse.tracecompass.statesystem.core.statevalue.ITmfStateValue;
61import org.eclipse.tracecompass.statesystem.core.statevalue.ITmfStateValue.Type;
97c71024 62import org.eclipse.tracecompass.tmf.core.signal.TmfSelectionRangeUpdatedSignal;
17a54620 63import org.eclipse.tracecompass.tmf.core.signal.TmfSignalHandler;
d90ae2a5 64import org.eclipse.tracecompass.tmf.core.signal.TmfTraceClosedSignal;
2bdf0193 65import org.eclipse.tracecompass.tmf.core.signal.TmfTraceSelectedSignal;
17a54620 66import org.eclipse.tracecompass.tmf.core.signal.TmfWindowRangeUpdatedSignal;
2bdf0193 67import org.eclipse.tracecompass.tmf.core.timestamp.ITmfTimestamp;
2bdf0193 68import org.eclipse.tracecompass.tmf.core.timestamp.TmfTimeRange;
b2c971ec 69import org.eclipse.tracecompass.tmf.core.timestamp.TmfTimestamp;
e4bbed4b 70import org.eclipse.tracecompass.tmf.core.timestamp.TmfTimestampDelta;
2bdf0193 71import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace;
b8585c7c 72import org.eclipse.tracecompass.tmf.core.trace.TmfTraceUtils;
2bdf0193 73import org.eclipse.tracecompass.tmf.ui.editors.ITmfTraceEditor;
d90ae2a5
RK
74import org.eclipse.tracecompass.tmf.ui.symbols.ISymbolProvider;
75import org.eclipse.tracecompass.tmf.ui.symbols.ISymbolProviderPreferencePage;
76import org.eclipse.tracecompass.tmf.ui.symbols.SymbolProviderConfigDialog;
77import org.eclipse.tracecompass.tmf.ui.symbols.SymbolProviderManager;
ade0a3c5 78import org.eclipse.tracecompass.tmf.ui.views.timegraph.AbstractTimeGraphView;
2bdf0193 79import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.ITimeGraphTimeListener;
d8a230f8 80import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.TimeGraphContentProvider;
2bdf0193
AM
81import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.TimeGraphTimeEvent;
82import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.TimeGraphViewer;
83import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.model.ITimeEvent;
84import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.model.ITimeGraphEntry;
85import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.model.NullTimeEvent;
86import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.model.TimeEvent;
87import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.model.TimeGraphEntry;
88import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.widgets.TimeGraphControl;
89import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.widgets.TimeGraphSelection;
e8251298 90import org.eclipse.ui.IEditorPart;
d2fb9e0f 91import org.eclipse.ui.IWorkbenchActionConstants;
e8251298
PT
92
93/**
94 * Main implementation for the Call Stack view
95 *
96 * @author Patrick Tasse
e8251298 97 */
ade0a3c5 98public class CallStackView extends AbstractTimeGraphView {
e8251298
PT
99
100 // ------------------------------------------------------------------------
101 // Constants
102 // ------------------------------------------------------------------------
103
104 /** View ID. */
105 public static final String ID = "org.eclipse.linuxtools.tmf.ui.views.callstack"; //$NON-NLS-1$
106
ade0a3c5 107 private static final String[] COLUMN_NAMES = new String[] {
e8251298
PT
108 Messages.CallStackView_FunctionColumn,
109 Messages.CallStackView_DepthColumn,
110 Messages.CallStackView_EntryTimeColumn,
111 Messages.CallStackView_ExitTimeColumn,
112 Messages.CallStackView_DurationColumn
113 };
114
ade0a3c5
PT
115 private static final String[] FILTER_COLUMN_NAMES = new String[] {
116 Messages.CallStackView_ThreadColumn
52974e38
PT
117 };
118
26c33ee2
PT
119 /** Timeout between updates in the build thread in ms */
120 private static final long BUILD_UPDATE_TIMEOUT = 500;
121
52974e38
PT
122 // Fraction of a function duration to be added as spacing
123 private static final double SPACING_RATIO = 0.01;
124
1302015b 125 private static final Image PROCESS_IMAGE = Activator.getDefault().getImageFromPath("icons/obj16/process_obj.gif"); //$NON-NLS-1$
e8251298
PT
126 private static final Image THREAD_IMAGE = Activator.getDefault().getImageFromPath("icons/obj16/thread_obj.gif"); //$NON-NLS-1$
127 private static final Image STACKFRAME_IMAGE = Activator.getDefault().getImageFromPath("icons/obj16/stckframe_obj.gif"); //$NON-NLS-1$
128
41d9ce5b 129 private static final String IMPORT_BINARY_ICON_PATH = "icons/obj16/binaries_obj.gif"; //$NON-NLS-1$
5da83da5 130
46cc1ade
PT
131 private static final ImageDescriptor SORT_BY_NAME_ICON = Activator.getDefault().getImageDescripterFromPath("icons/etool16/sort_alpha.gif"); //$NON-NLS-1$
132 private static final ImageDescriptor SORT_BY_NAME_REV_ICON = Activator.getDefault().getImageDescripterFromPath("icons/etool16/sort_alpha_rev.gif"); //$NON-NLS-1$
133 private static final ImageDescriptor SORT_BY_ID_ICON = Activator.getDefault().getImageDescripterFromPath("icons/etool16/sort_num.gif"); //$NON-NLS-1$
134 private static final ImageDescriptor SORT_BY_ID_REV_ICON = Activator.getDefault().getImageDescripterFromPath("icons/etool16/sort_num_rev.gif"); //$NON-NLS-1$
135 private static final ImageDescriptor SORT_BY_TIME_ICON = Activator.getDefault().getImageDescripterFromPath("icons/etool16/sort_time.gif"); //$NON-NLS-1$
136 private static final ImageDescriptor SORT_BY_TIME_REV_ICON = Activator.getDefault().getImageDescripterFromPath("icons/etool16/sort_time_rev.gif"); //$NON-NLS-1$
137 private static final String SORT_OPTION_KEY = "sort.option"; //$NON-NLS-1$
bac9c0df
MK
138
139 private enum SortOption {
140 BY_NAME, BY_NAME_REV, BY_ID, BY_ID_REV, BY_TIME, BY_TIME_REV
141 }
142
ade0a3c5
PT
143 private @NonNull SortOption fSortOption = SortOption.BY_NAME;
144 private @NonNull Comparator<ITimeGraphEntry> fThreadComparator = new ThreadNameComparator(false);
46cc1ade
PT
145 private Action fSortByNameAction;
146 private Action fSortByIdAction;
147 private Action fSortByTimeAction;
148
e8251298
PT
149 // ------------------------------------------------------------------------
150 // Fields
151 // ------------------------------------------------------------------------
152
d90ae2a5 153 private final Map<ITmfTrace, ISymbolProvider> fSymbolProviders = new HashMap<>();
5da83da5 154
e8251298
PT
155 // The next event action
156 private Action fNextEventAction;
157
158 // The previous event action
159 private Action fPrevEventAction;
160
161 // The next item action
162 private Action fNextItemAction;
163
164 // The previous item action
165 private Action fPreviousItemAction;
166
41d9ce5b 167 // The action to import a binary file mapping */
d90ae2a5 168 private Action fConfigureSymbolsAction;
41d9ce5b 169
e8251298 170 // The saved time sync. signal used when switching off the pinning of a view
97c71024 171 private TmfSelectionRangeUpdatedSignal fSavedTimeSyncSignal;
e8251298 172
97c71024 173 // The saved window range signal used when switching off the pinning of
bac9c0df 174 // a view
97c71024 175 private TmfWindowRangeUpdatedSignal fSavedRangeSyncSignal;
e8251298 176
1302015b
PT
177 // When set to true, syncToTime() will select the first call stack entry
178 // whose current state start time exactly matches the sync time.
179 private boolean fSyncSelection = false;
180
e8251298
PT
181 // ------------------------------------------------------------------------
182 // Classes
183 // ------------------------------------------------------------------------
184
658e0268 185 private static class TraceEntry extends TimeGraphEntry {
60b4d44c
PT
186 public TraceEntry(String name, long startTime, long endTime) {
187 super(name, startTime, endTime);
188 }
189
190 @Override
191 public boolean hasTimeEvents() {
192 return false;
193 }
194 }
195
7f86b721
AM
196 private static class ProcessEntry extends TimeGraphEntry {
197
4ce4d8af
AM
198 private final int fProcessId;
199
200 public ProcessEntry(String name, int processId, long startTime, long endTime) {
7f86b721 201 super(name, startTime, endTime);
4ce4d8af
AM
202 fProcessId = processId;
203 }
204
7f86b721
AM
205 @Override
206 public boolean hasTimeEvents() {
207 return false;
208 }
209 }
210
658e0268 211 private static class ThreadEntry extends TimeGraphEntry {
46cc1ade
PT
212 // The thread id
213 private final long fThreadId;
e8251298 214
1302015b 215 public ThreadEntry(String name, long threadId, long startTime, long endTime) {
60b4d44c 216 super(name, startTime, endTime);
46cc1ade 217 fThreadId = threadId;
e8251298
PT
218 }
219
e8251298
PT
220 @Override
221 public boolean hasTimeEvents() {
222 return false;
223 }
224
46cc1ade
PT
225 public long getThreadId() {
226 return fThreadId;
227 }
e8251298
PT
228 }
229
ade0a3c5
PT
230 private class CallStackComparator implements Comparator<ITimeGraphEntry> {
231 @Override
232 public int compare(ITimeGraphEntry o1, ITimeGraphEntry o2) {
233 if (o1 instanceof ThreadEntry && o2 instanceof ThreadEntry) {
234 return fThreadComparator.compare(o1, o2);
4ce4d8af
AM
235 } else if (o1 instanceof ProcessEntry && o2 instanceof ProcessEntry) {
236 return Integer.compare(((ProcessEntry) o1).fProcessId, ((ProcessEntry) o2).fProcessId);
ade0a3c5
PT
237 }
238 return 0;
239 }
240 }
241
658e0268 242 private static class ThreadNameComparator implements Comparator<ITimeGraphEntry> {
46cc1ade 243 private boolean reverse;
bac9c0df 244
46cc1ade
PT
245 public ThreadNameComparator(boolean reverse) {
246 this.reverse = reverse;
247 }
bac9c0df 248
46cc1ade
PT
249 @Override
250 public int compare(ITimeGraphEntry o1, ITimeGraphEntry o2) {
251 return reverse ? o2.getName().compareTo(o1.getName()) :
bac9c0df 252 o1.getName().compareTo(o2.getName());
46cc1ade
PT
253 }
254 }
255
658e0268 256 private static class ThreadIdComparator implements Comparator<ITimeGraphEntry> {
46cc1ade 257 private boolean reverse;
bac9c0df 258
46cc1ade
PT
259 public ThreadIdComparator(boolean reverse) {
260 this.reverse = reverse;
261 }
bac9c0df 262
46cc1ade
PT
263 @Override
264 public int compare(ITimeGraphEntry o1, ITimeGraphEntry o2) {
7e0d06ba
PT
265 if (o1 instanceof ThreadEntry && o2 instanceof ThreadEntry) {
266 ThreadEntry t1 = (ThreadEntry) o1;
267 ThreadEntry t2 = (ThreadEntry) o2;
268 return reverse ? Long.compare(t2.getThreadId(), t1.getThreadId()) :
bac9c0df 269 Long.compare(t1.getThreadId(), t2.getThreadId());
7e0d06ba
PT
270 }
271 return 0;
46cc1ade
PT
272 }
273 }
274
658e0268 275 private static class ThreadTimeComparator implements Comparator<ITimeGraphEntry> {
46cc1ade 276 private boolean reverse;
bac9c0df 277
46cc1ade
PT
278 public ThreadTimeComparator(boolean reverse) {
279 this.reverse = reverse;
280 }
bac9c0df 281
46cc1ade
PT
282 @Override
283 public int compare(ITimeGraphEntry o1, ITimeGraphEntry o2) {
284 return reverse ? Long.compare(o2.getStartTime(), o1.getStartTime()) :
bac9c0df 285 Long.compare(o1.getStartTime(), o2.getStartTime());
46cc1ade
PT
286 }
287 }
288
658e0268 289 private static class CallStackTreeLabelProvider extends TreeLabelProvider {
e8251298
PT
290
291 @Override
292 public Image getColumnImage(Object element, int columnIndex) {
293 if (columnIndex == 0) {
1302015b
PT
294 if (element instanceof ProcessEntry) {
295 return PROCESS_IMAGE;
296 } else if (element instanceof ThreadEntry) {
e8251298
PT
297 return THREAD_IMAGE;
298 } else if (element instanceof CallStackEntry) {
299 CallStackEntry entry = (CallStackEntry) element;
300 if (entry.getFunctionName().length() > 0) {
301 return STACKFRAME_IMAGE;
302 }
303 }
304 }
305 return null;
306 }
307
308 @Override
309 public String getColumnText(Object element, int columnIndex) {
60b4d44c 310 if (element instanceof CallStackEntry) {
e8251298
PT
311 CallStackEntry entry = (CallStackEntry) element;
312 if (columnIndex == 0) {
313 return entry.getFunctionName();
52974e38
PT
314 } else if (columnIndex == 1 && entry.getFunctionName().length() > 0) {
315 int depth = entry.getStackLevel();
316 return Integer.toString(depth);
317 } else if (columnIndex == 2 && entry.getFunctionName().length() > 0) {
b2c971ec 318 ITmfTimestamp ts = TmfTimestamp.fromNanos(entry.getFunctionEntryTime());
52974e38
PT
319 return ts.toString();
320 } else if (columnIndex == 3 && entry.getFunctionName().length() > 0) {
b2c971ec 321 ITmfTimestamp ts = TmfTimestamp.fromNanos(entry.getFunctionExitTime());
52974e38
PT
322 return ts.toString();
323 } else if (columnIndex == 4 && entry.getFunctionName().length() > 0) {
60b4d44c 324 ITmfTimestamp ts = new TmfTimestampDelta(entry.getFunctionExitTime() - entry.getFunctionEntryTime(), ITmfTimestamp.NANOSECOND_SCALE);
52974e38 325 return ts.toString();
e8251298 326 }
60b4d44c
PT
327 } else if (element instanceof ITimeGraphEntry) {
328 if (columnIndex == 0) {
329 return ((ITimeGraphEntry) element).getName();
330 }
e8251298
PT
331 }
332 return ""; //$NON-NLS-1$
333 }
334
335 }
336
ade0a3c5 337 private class CallStackFilterContentProvider extends TimeGraphContentProvider {
e8251298 338 @Override
ade0a3c5
PT
339 public boolean hasChildren(Object element) {
340 if (element instanceof TraceEntry) {
341 return super.hasChildren(element);
e8251298 342 }
ade0a3c5 343 return false;
e8251298
PT
344 }
345
346 @Override
ade0a3c5
PT
347 public ITimeGraphEntry[] getChildren(Object parentElement) {
348 if (parentElement instanceof TraceEntry) {
349 return super.getChildren(parentElement);
e8251298 350 }
ade0a3c5 351 return new ITimeGraphEntry[0];
e8251298
PT
352 }
353 }
354
355 // ------------------------------------------------------------------------
356 // Constructors
357 // ------------------------------------------------------------------------
358
359 /**
360 * Default constructor
361 */
362 public CallStackView() {
ade0a3c5
PT
363 super(ID, new CallStackPresentationProvider());
364 ((CallStackPresentationProvider) getPresentationProvider()).setCallStackView(this);
365 setTreeColumns(COLUMN_NAMES);
366 setTreeLabelProvider(new CallStackTreeLabelProvider());
367 setEntryComparator(new CallStackComparator());
368 setFilterColumns(FILTER_COLUMN_NAMES);
369 setFilterContentProvider(new CallStackFilterContentProvider());
370 setFilterLabelProvider(new CallStackTreeLabelProvider());
e8251298
PT
371 }
372
373 // ------------------------------------------------------------------------
374 // ViewPart
375 // ------------------------------------------------------------------------
376
377 @Override
378 public void createPartControl(Composite parent) {
d2e4afa7 379 super.createPartControl(parent);
e8251298 380
ade0a3c5 381 getTimeGraphViewer().addTimeListener(new ITimeGraphTimeListener() {
e8251298
PT
382 @Override
383 public void timeSelected(TimeGraphTimeEvent event) {
ade0a3c5 384 synchingToTime(event.getBeginTime());
e8251298
PT
385 }
386 });
387
ade0a3c5 388 getTimeGraphCombo().getTreeViewer().addDoubleClickListener(new IDoubleClickListener() {
e8251298
PT
389 @Override
390 public void doubleClick(DoubleClickEvent event) {
391 Object selection = ((IStructuredSelection) event.getSelection()).getFirstElement();
392 if (selection instanceof CallStackEntry) {
393 CallStackEntry entry = (CallStackEntry) selection;
394 if (entry.getFunctionName().length() > 0) {
60b4d44c
PT
395 long entryTime = entry.getFunctionEntryTime();
396 long exitTime = entry.getFunctionExitTime();
397 long spacingTime = (long) ((exitTime - entryTime) * SPACING_RATIO);
398 entryTime -= spacingTime;
399 exitTime += spacingTime;
b2c971ec 400 TmfTimeRange range = new TmfTimeRange(TmfTimestamp.fromNanos(entryTime), TmfTimestamp.fromNanos(exitTime));
97c71024 401 broadcast(new TmfWindowRangeUpdatedSignal(CallStackView.this, range));
ade0a3c5 402 getTimeGraphViewer().setStartFinishTime(entryTime, exitTime);
60b4d44c 403 startZoomThread(entryTime, exitTime);
e8251298
PT
404 }
405 }
406 }
407 });
408
ade0a3c5 409 getTimeGraphViewer().getTimeGraphControl().addMouseListener(new MouseAdapter() {
e8251298
PT
410 @Override
411 public void mouseDoubleClick(MouseEvent e) {
ade0a3c5 412 TimeGraphControl timeGraphControl = getTimeGraphViewer().getTimeGraphControl();
e8251298
PT
413 ISelection selection = timeGraphControl.getSelection();
414 if (selection instanceof TimeGraphSelection) {
415 Object o = ((TimeGraphSelection) selection).getFirstElement();
416 if (o instanceof CallStackEvent) {
417 CallStackEvent event = (CallStackEvent) o;
418 long startTime = event.getTime();
419 long endTime = startTime + event.getDuration();
52974e38 420 long spacingTime = (long) ((endTime - startTime) * SPACING_RATIO);
e8251298
PT
421 startTime -= spacingTime;
422 endTime += spacingTime;
b2c971ec 423 TmfTimeRange range = new TmfTimeRange(TmfTimestamp.fromNanos(startTime), TmfTimestamp.fromNanos(endTime));
97c71024 424 broadcast(new TmfWindowRangeUpdatedSignal(CallStackView.this, range));
ade0a3c5 425 getTimeGraphViewer().setStartFinishTime(startTime, endTime);
e8251298
PT
426 startZoomThread(startTime, endTime);
427 }
428 }
429 }
430 });
431
e8251298 432 contributeToActionBars();
46cc1ade 433 loadSortOption();
e8251298
PT
434
435 IEditorPart editor = getSite().getPage().getActiveEditor();
436 if (editor instanceof ITmfTraceEditor) {
437 ITmfTrace trace = ((ITmfTraceEditor) editor).getTrace();
438 if (trace != null) {
439 traceSelected(new TmfTraceSelectedSignal(this, trace));
440 }
441 }
442 }
443
e8251298 444 /**
97c71024 445 * Handler for the selection range signal.
e8251298
PT
446 *
447 * @param signal
448 * The incoming signal
97c71024 449 * @since 1.0
e8251298 450 */
ade0a3c5 451 @Override
e8251298 452 @TmfSignalHandler
97c71024 453 public void selectionRangeUpdated(final TmfSelectionRangeUpdatedSignal signal) {
e8251298 454
97c71024 455 fSavedTimeSyncSignal = isPinned() ? new TmfSelectionRangeUpdatedSignal(signal.getSource(), signal.getBeginTime(), signal.getEndTime()) : null;
e8251298 456
ade0a3c5 457 if (signal.getSource() == this || getTrace() == null || isPinned()) {
e8251298
PT
458 return;
459 }
16801c72
MK
460 final long beginTime = signal.getBeginTime().toNanos();
461 final long endTime = signal.getEndTime().toNanos();
e8251298
PT
462 Display.getDefault().asyncExec(new Runnable() {
463 @Override
464 public void run() {
ade0a3c5 465 if (getTimeGraphCombo().isDisposed()) {
e8251298
PT
466 return;
467 }
0fcf3b09 468 if (beginTime == endTime) {
ade0a3c5 469 getTimeGraphViewer().setSelectedTime(beginTime, true);
0fcf3b09 470 } else {
ade0a3c5 471 getTimeGraphViewer().setSelectionRange(beginTime, endTime, true);
0fcf3b09 472 }
1302015b 473 fSyncSelection = true;
26c33ee2 474 synchingToTime(beginTime);
1302015b 475 fSyncSelection = false;
ade0a3c5 476 startZoomThread(getTimeGraphViewer().getTime0(), getTimeGraphViewer().getTime1());
e8251298
PT
477 }
478 });
7f86b721 479
e8251298
PT
480 }
481
37838e00
BH
482 /**
483 * @since 2.0
484 */
485 @Override
486 @TmfSignalHandler
487 public void windowRangeUpdated(final TmfWindowRangeUpdatedSignal signal) {
488
489 if (isPinned()) {
490 fSavedRangeSyncSignal = new TmfWindowRangeUpdatedSignal(signal.getSource(), signal.getCurrentRange());
491 fSavedTimeSyncSignal = null;
492 }
493
494 if ((signal.getSource() == this) || isPinned()) {
495 return;
496 }
497 super.windowRangeUpdated(signal);
498 }
499
e8251298
PT
500 // ------------------------------------------------------------------------
501 // Internal
502 // ------------------------------------------------------------------------
5da83da5 503
d90ae2a5
RK
504 @Override
505 @TmfSignalHandler
506 public void traceClosed(TmfTraceClosedSignal signal) {
507 super.traceClosed(signal);
508 synchronized(fSymbolProviders){
509 for(ITmfTrace trace : getTracesToBuild(signal.getTrace())){
510 fSymbolProviders.remove(trace);
511 }
512 }
513 }
514
515 /**
516 * @since 2.0
517 */
518 @Override
519 protected void refresh() {
520 super.refresh();
521 updateConfigureSymbolsAction();
522 }
523
ade0a3c5 524 @Override
f8f46a52 525 protected void buildEntryList(final ITmfTrace trace, final ITmfTrace parentTrace, final IProgressMonitor monitor) {
26c33ee2
PT
526 if (monitor.isCanceled()) {
527 return;
528 }
cc5baabc
AM
529
530 /*
531 * Load the symbol provider for the current trace, even if it does not
532 * provide a call stack analysis module. See
533 * https://bugs.eclipse.org/bugs/show_bug.cgi?id=494212
534 */
535 ISymbolProvider provider = fSymbolProviders.get(trace);
536 if (provider == null) {
537 provider = SymbolProviderManager.getInstance().getSymbolProvider(trace);
538 provider.loadConfiguration(null);
539 fSymbolProviders.put(trace, provider);
540 }
541
542 /* Continue with the call stack view specific operations */
26c33ee2
PT
543 AbstractCallStackAnalysis module = getCallStackModule(trace);
544 if (module == null) {
545 addUnavailableEntry(trace, parentTrace);
546 return;
547 }
548 ITmfStateSystem ss = module.getStateSystem();
549 if (ss == null) {
550 addUnavailableEntry(trace, parentTrace);
551 return;
552 }
553
554 Map<ITmfTrace, TraceEntry> traceEntryMap = new HashMap<>();
7f86b721 555 Map<Integer, ProcessEntry> processEntryMap = new HashMap<>();
26c33ee2 556 Map<Integer, ThreadEntry> threadEntryMap = new HashMap<>();
26c33ee2
PT
557
558 long start = ss.getStartTime();
559
560 boolean complete = false;
561 while (!complete) {
e8251298
PT
562 if (monitor.isCanceled()) {
563 return;
564 }
26c33ee2
PT
565 complete = ss.waitUntilBuilt(BUILD_UPDATE_TIMEOUT);
566 if (ss.isCancelled()) {
da27e43a
PT
567 return;
568 }
26c33ee2
PT
569 long end = ss.getCurrentEndTime();
570 if (start == end && !complete) { // when complete execute one last time regardless of end time
e8251298
PT
571 continue;
572 }
d90ae2a5 573
26c33ee2
PT
574 TraceEntry traceEntry = traceEntryMap.get(trace);
575 if (traceEntry == null) {
576 traceEntry = new TraceEntry(trace.getName(), start, end + 1);
577 traceEntryMap.put(trace, traceEntry);
578 traceEntry.sortChildren(fThreadComparator);
579 addToEntryList(parentTrace, Collections.singletonList(traceEntry));
580 } else {
581 traceEntry.updateEndTime(end);
582 }
1a0ff02c 583
7f2bc9ff
PT
584 try {
585 List<ITmfStateInterval> endStates = ss.queryFullState(ss.getCurrentEndTime());
586
587 List<Integer> processQuarks = ss.getQuarks(module.getProcessesPattern());
588 for (int processQuark : processQuarks) {
589
590 /*
591 * Default to trace entry, overwrite if a process entry exists.
592 */
593 TimeGraphEntry threadParent = traceEntry;
594 int processId = -1;
595 if (processQuark != ITmfStateSystem.ROOT_ATTRIBUTE) {
596 /* Create the entry for the process */
597 ProcessEntry processEntry = processEntryMap.get(processQuark);
598 if (processEntry == null) {
599 String processName = ss.getAttributeName(processQuark);
600 ITmfStateValue processStateValue = endStates.get(processQuark).getStateValue();
601 if (processStateValue.getType() == Type.INTEGER) {
602 processId = processStateValue.unboxInt();
603 } else {
604 try {
605 processId = Integer.parseInt(processName);
606 } catch (NumberFormatException e) {
607 /* use default processId */
608 }
609 }
610 processEntry = new ProcessEntry(processName, processId, start, end);
611 processEntryMap.put(processQuark, processEntry);
612 traceEntry.addChild(processEntry);
613 } else {
614 processEntry.updateEndTime(end);
615 }
616 /* The parent of the thread entries will be a process */
617 threadParent = processEntry;
1302015b 618 }
7f86b721 619
7f2bc9ff 620 /* Create the threads under the process */
1302015b 621 List<Integer> threadQuarks = ss.getQuarks(processQuark, module.getThreadsPattern());
7f86b721
AM
622
623 /*
624 * Only query startStates if necessary (threadEntry == null)
625 */
626 List<ITmfStateInterval> startStates = null;
1302015b 627 for (int threadQuark : threadQuarks) {
7f86b721
AM
628 if (monitor.isCanceled()) {
629 return;
1a0ff02c 630 }
7f86b721 631
1302015b 632 String[] callStackPath = module.getCallStackPath();
7f86b721
AM
633 int callStackQuark = ss.getQuarkRelative(threadQuark, callStackPath);
634 String threadName = ss.getAttributeName(threadQuark);
635 long threadEnd = end + 1;
636 ITmfStateInterval endInterval = endStates.get(callStackQuark);
637 if (endInterval.getStateValue().isNull() && endInterval.getStartTime() != ss.getStartTime()) {
638 threadEnd = endInterval.getStartTime();
26c33ee2 639 }
1302015b
PT
640 /*
641 * Default to process/trace entry, overwrite if a thread entry exists.
642 */
643 TimeGraphEntry callStackParent = threadParent;
644 if (threadQuark != processQuark) {
645 ThreadEntry threadEntry = threadEntryMap.get(threadQuark);
646 if (threadEntry == null) {
647 if (startStates == null) {
648 startStates = ss.queryFullState(ss.getStartTime());
649 }
7f2bc9ff
PT
650 long threadId = -1;
651 ITmfStateValue threadStateValue = endStates.get(threadQuark).getStateValue();
652 if (threadStateValue.getType() == Type.LONG || threadStateValue.getType() == Type.INTEGER) {
653 threadId = threadStateValue.unboxLong();
654 } else {
655 try {
656 threadId = Long.parseLong(threadName);
657 } catch (NumberFormatException e) {
658 /* use default threadId */
659 }
660 }
1302015b
PT
661 long threadStart = start;
662 ITmfStateInterval startInterval = startStates.get(callStackQuark);
663 if (startInterval.getStateValue().isNull()) {
664 threadStart = Math.min(startInterval.getEndTime() + 1, end + 1);
665 }
666 threadEntry = new ThreadEntry(threadName, threadId, threadStart, threadEnd);
667 threadEntryMap.put(threadQuark, threadEntry);
668 threadParent.addChild(threadEntry);
669 } else {
670 threadEntry.updateEndTime(threadEnd);
7f86b721 671 }
1302015b
PT
672 /* The parent of the call stack entries will be a thread */
673 callStackParent = threadEntry;
7f86b721
AM
674 }
675 int level = 1;
676 for (int stackLevelQuark : ss.getSubAttributes(callStackQuark, false)) {
1302015b 677 if (level > callStackParent.getChildren().size()) {
4ce4d8af 678 CallStackEntry callStackEntry = new CallStackEntry(threadName, stackLevelQuark, level, processId, trace, ss);
1302015b 679 callStackParent.addChild(callStackEntry);
7f86b721
AM
680 }
681 level++;
26c33ee2 682 }
e8251298 683 }
e8251298 684 }
7f2bc9ff
PT
685 } catch (AttributeNotFoundException e) {
686 Activator.getDefault().logError("Error querying state system", e); //$NON-NLS-1$
687 } catch (StateSystemDisposedException e) {
688 /* Ignored */
e8251298 689 }
7f86b721 690
ade0a3c5
PT
691 if (parentTrace == getTrace()) {
692 synchronized (this) {
693 setStartTime(getStartTime() == SWT.DEFAULT ? start : Math.min(getStartTime(), start));
694 setEndTime(getEndTime() == SWT.DEFAULT ? end + 1 : Math.max(getEndTime(), end + 1));
26c33ee2 695 }
ade0a3c5 696 synchingToTime(getTimeGraphViewer().getSelectionBegin());
26c33ee2
PT
697 refresh();
698 }
7f86b721 699
6e65b8a3
PT
700 Consumer<TimeGraphEntry> consumer = new Consumer<TimeGraphEntry>() {
701 @Override
702 public void accept(TimeGraphEntry entry) {
703 if (monitor.isCanceled()) {
704 return;
60b4d44c 705 }
6e65b8a3
PT
706 if (entry instanceof CallStackEntry) {
707 buildStatusEvents(parentTrace, (CallStackEntry) entry, monitor, ss.getStartTime(), end);
708 return;
709 }
710 entry.getChildren().forEach(this);
e8251298 711 }
6e65b8a3
PT
712 };
713 traceEntry.getChildren().forEach(consumer);
714
26c33ee2 715 start = end;
e8251298
PT
716 }
717 }
718
26c33ee2 719 private void addUnavailableEntry(ITmfTrace trace, ITmfTrace parentTrace) {
60b4d44c
PT
720 String name = Messages.CallStackView_StackInfoNotAvailable + ' ' + '(' + trace.getName() + ')';
721 TraceEntry unavailableEntry = new TraceEntry(name, 0, 0);
26c33ee2 722 addToEntryList(parentTrace, Collections.singletonList(unavailableEntry));
ade0a3c5 723 if (parentTrace == getTrace()) {
26c33ee2
PT
724 refresh();
725 }
2002c638
AM
726 }
727
ade0a3c5 728 private void buildStatusEvents(ITmfTrace trace, CallStackEntry entry, @NonNull IProgressMonitor monitor, long start, long end) {
da27e43a 729 ITmfStateSystem ss = entry.getStateSystem();
ade0a3c5 730 long resolution = Math.max(1, (end - ss.getStartTime()) / getDisplayWidth());
26c33ee2
PT
731 List<ITimeEvent> eventList = getEventList(entry, start, end + 1, resolution, monitor);
732 if (eventList != null) {
8d5d4aa4 733 entry.setEventList(eventList);
e8251298 734 }
ade0a3c5 735 if (trace == getTrace()) {
e8251298
PT
736 redraw();
737 }
738 }
739
ade0a3c5 740 /**
066b02aa 741 * @since 1.2
ade0a3c5
PT
742 */
743 @Override
744 protected final List<ITimeEvent> getEventList(TimeGraphEntry tgentry, long startTime, long endTime, long resolution, IProgressMonitor monitor) {
745 if (!(tgentry instanceof CallStackEntry)) {
746 return null;
747 }
748 CallStackEntry entry = (CallStackEntry) tgentry;
da27e43a 749 ITmfStateSystem ss = entry.getStateSystem();
e8251298
PT
750 long start = Math.max(startTime, ss.getStartTime());
751 long end = Math.min(endTime, ss.getCurrentEndTime() + 1);
752 if (end <= start) {
753 return null;
754 }
8d5d4aa4 755 boolean isZoomThread = Thread.currentThread() instanceof ZoomThread;
e8251298
PT
756 List<ITimeEvent> eventList = null;
757 try {
1dd75589 758 List<ITmfStateInterval> stackIntervals = StateSystemUtils.queryHistoryRange(ss, entry.getQuark(), start, end - 1, resolution, monitor);
507b1336 759 eventList = new ArrayList<>(stackIntervals.size());
e8251298 760 long lastEndTime = -1;
fb70173e 761 boolean lastIsNull = false;
e8251298
PT
762 for (ITmfStateInterval statusInterval : stackIntervals) {
763 if (monitor.isCanceled()) {
764 return null;
765 }
766 long time = statusInterval.getStartTime();
767 long duration = statusInterval.getEndTime() - time + 1;
768 if (!statusInterval.getStateValue().isNull()) {
52974e38
PT
769 final int modulo = CallStackPresentationProvider.NUM_COLORS / 2;
770 int value = statusInterval.getStateValue().toString().hashCode() % modulo + modulo;
e8251298
PT
771 eventList.add(new CallStackEvent(entry, time, duration, value));
772 lastIsNull = false;
773 } else {
8d5d4aa4 774 if (lastEndTime == -1 && isZoomThread) {
beb1b921
PT
775 // add null event if it intersects the start time
776 eventList.add(new NullTimeEvent(entry, time, duration));
777 } else {
778 if (lastEndTime != time && lastIsNull) {
779 // add unknown event if between two null states
780 eventList.add(new TimeEvent(entry, lastEndTime, time - lastEndTime));
781 }
8d5d4aa4 782 if (time + duration >= endTime && isZoomThread) {
beb1b921
PT
783 // add null event if it intersects the end time
784 eventList.add(new NullTimeEvent(entry, time, duration));
785 }
e8251298 786 }
e8251298
PT
787 lastIsNull = true;
788 }
789 lastEndTime = time + duration;
790 }
791 } catch (AttributeNotFoundException e) {
52974e38 792 Activator.getDefault().logError("Error querying state system", e); //$NON-NLS-1$
e8251298 793 } catch (TimeRangeException e) {
52974e38 794 Activator.getDefault().logError("Error querying state system", e); //$NON-NLS-1$
e8251298
PT
795 } catch (StateSystemDisposedException e) {
796 /* Ignored */
797 }
798 return eventList;
799 }
800
ade0a3c5 801 /**
066b02aa 802 * @since 1.2
ade0a3c5
PT
803 */
804 @Override
1302015b
PT
805 protected void synchingToTime(final long time) {
806 List<TimeGraphEntry> traceEntries = getEntryList(getTrace());
807 Map<ITmfStateSystem, List<ITmfStateInterval>> fullStateMap = new HashMap<>();
808 if (traceEntries == null) {
e8251298
PT
809 return;
810 }
1302015b
PT
811 Consumer<TimeGraphEntry> consumer = new Consumer<TimeGraphEntry>() {
812 @Override
813 public void accept(TimeGraphEntry entry) {
814 if (entry instanceof CallStackEntry) {
815 CallStackEntry callStackEntry = (CallStackEntry) entry;
816 ITmfStateSystem ss = callStackEntry.getStateSystem();
7f86b721 817 if (time < ss.getStartTime() || time > ss.getCurrentEndTime()) {
1302015b 818 return;
7f86b721 819 }
1302015b
PT
820 ITmfTrace trace = callStackEntry.getTrace();
821 try {
822 List<ITmfStateInterval> fullState = getFullState(ss);
823 ITmfStateInterval stackLevelInterval = fullState.get(callStackEntry.getQuark());
824 ITmfStateValue nameValue = stackLevelInterval.getStateValue();
825
826 String name = getFunctionName(trace, callStackEntry.getProcessId(), time, nameValue);
827 callStackEntry.setFunctionName(name);
828 if (!name.isEmpty()) {
829 callStackEntry.setFunctionEntryTime(stackLevelInterval.getStartTime());
830 callStackEntry.setFunctionExitTime(stackLevelInterval.getEndTime() + 1);
831 }
832 if (fSyncSelection) {
833 int callStackQuark = ss.getParentAttributeQuark(callStackEntry.getQuark());
834 ITmfStateInterval stackInterval = fullState.get(callStackQuark);
835 if (time == stackInterval.getStartTime()) {
836 ITmfStateValue stackLevelState = stackInterval.getStateValue();
837 if (stackLevelState.unboxInt() == callStackEntry.getStackLevel() || stackLevelState.isNull()) {
838 Display.getDefault().asyncExec(() -> {
839 getTimeGraphCombo().setSelection(callStackEntry);
840 getTimeGraphViewer().getTimeGraphControl().fireSelectionChanged();
841 fSyncSelection = false;
842 });
843 }
7f86b721 844 }
60b4d44c 845 }
1302015b
PT
846 } catch (StateSystemDisposedException e) {
847 /* Ignored */
e8251298 848 }
1302015b 849 return;
e8251298 850 }
1302015b 851 entry.getChildren().forEach(this);
e8251298 852 }
1302015b
PT
853
854 private List<ITmfStateInterval> getFullState(ITmfStateSystem ss) throws StateSystemDisposedException {
855 List<ITmfStateInterval> fullState = fullStateMap.get(ss);
856 if (fullState == null) {
857 fullState = ss.queryFullState(time);
858 fullStateMap.put(ss, fullState);
859 }
860 return fullState;
861 }
862 };
863 traceEntries.forEach(consumer);
ade0a3c5
PT
864 if (Display.getCurrent() != null) {
865 getTimeGraphCombo().refresh();
e8251298 866 }
e8251298
PT
867 }
868
4ce4d8af 869 String getFunctionName(ITmfTrace trace, int processId, long timestamp, ITmfStateValue nameValue) {
d90ae2a5
RK
870 long address = Long.MAX_VALUE;
871 String name = ""; //$NON-NLS-1$
872 try {
873 if (nameValue.getType() == Type.STRING) {
874 name = nameValue.unboxStr();
875 try {
876 address = Long.parseLong(name, 16);
877 } catch (NumberFormatException e) {
878 // ignore
879 }
880 } else if (nameValue.getType() == Type.INTEGER) {
c3777c23 881 name = "0x" + Integer.toUnsignedString(nameValue.unboxInt(), 16); //$NON-NLS-1$
d90ae2a5
RK
882 address = nameValue.unboxInt();
883 } else if (nameValue.getType() == Type.LONG) {
c3777c23 884 name = "0x" + Long.toUnsignedString(nameValue.unboxLong(), 16); //$NON-NLS-1$
d90ae2a5
RK
885 address = nameValue.unboxLong();
886 }
887 } catch (StateValueTypeException e) {
888 }
889 if (address != Long.MAX_VALUE) {
890 ISymbolProvider provider = fSymbolProviders.get(trace);
891 if (provider != null) {
4ce4d8af 892 String symbol = provider.getSymbolText(processId, timestamp, address);
d90ae2a5
RK
893 if (symbol != null) {
894 name = symbol;
895 }
896 }
897 }
898 return name;
899 }
900
e8251298 901 private void makeActions() {
ade0a3c5 902 fPreviousItemAction = getTimeGraphViewer().getPreviousItemAction();
e8251298
PT
903 fPreviousItemAction.setText(Messages.TmfTimeGraphViewer_PreviousItemActionNameText);
904 fPreviousItemAction.setToolTipText(Messages.TmfTimeGraphViewer_PreviousItemActionToolTipText);
ade0a3c5 905 fNextItemAction = getTimeGraphViewer().getNextItemAction();
e8251298
PT
906 fNextItemAction.setText(Messages.TmfTimeGraphViewer_NextItemActionNameText);
907 fNextItemAction.setToolTipText(Messages.TmfTimeGraphViewer_NextItemActionToolTipText);
908 }
909
910 private void contributeToActionBars() {
e8251298
PT
911 // Create pin action
912 contributePinActionToToolBar();
bac9c0df 913 fPinAction.addPropertyChangeListener(new IPropertyChangeListener() {
e8251298
PT
914 @Override
915 public void propertyChange(PropertyChangeEvent event) {
52974e38
PT
916 if (IAction.CHECKED.equals(event.getProperty()) && !isPinned()) {
917 if (fSavedRangeSyncSignal != null) {
97c71024 918 windowRangeUpdated(fSavedRangeSyncSignal);
52974e38
PT
919 fSavedRangeSyncSignal = null;
920 }
e8251298 921
52974e38 922 if (fSavedTimeSyncSignal != null) {
97c71024 923 selectionRangeUpdated(fSavedTimeSyncSignal);
52974e38 924 fSavedTimeSyncSignal = null;
e8251298
PT
925 }
926 }
927 }
928 });
929 }
930
ade0a3c5 931 /**
066b02aa 932 * @since 1.2
ade0a3c5
PT
933 */
934 @Override
935 protected void fillLocalToolBar(IToolBarManager manager) {
936 makeActions();
d90ae2a5 937 manager.add(getConfigureSymbolsAction());
46cc1ade
PT
938 manager.add(new Separator());
939 manager.add(getSortByNameAction());
940 manager.add(getSortByIdAction());
941 manager.add(getSortByTimeAction());
942 manager.add(new Separator());
ade0a3c5
PT
943 manager.add(getTimeGraphCombo().getShowFilterDialogAction());
944 manager.add(new Separator());
945 manager.add(getTimeGraphViewer().getResetScaleAction());
e8251298
PT
946 manager.add(getPreviousEventAction());
947 manager.add(getNextEventAction());
ade0a3c5
PT
948 manager.add(new Separator());
949 manager.add(getTimeGraphViewer().getToggleBookmarkAction());
950 manager.add(getTimeGraphViewer().getPreviousMarkerAction());
951 manager.add(getTimeGraphViewer().getNextMarkerAction());
952 manager.add(new Separator());
e8251298
PT
953 manager.add(fPreviousItemAction);
954 manager.add(fNextItemAction);
ade0a3c5
PT
955 manager.add(getTimeGraphViewer().getZoomInAction());
956 manager.add(getTimeGraphViewer().getZoomOutAction());
e8251298
PT
957 }
958
90bb3a0c
BH
959 /**
960 * @since 2.0
961 */
962 @Override
963 protected void fillTimeGraphEntryContextMenu(IMenuManager contextMenu) {
d2fb9e0f 964 contextMenu.add(new GroupMarker(IWorkbenchActionConstants.GROUP_REORGANIZE));
46cc1ade
PT
965 contextMenu.add(getSortByNameAction());
966 contextMenu.add(getSortByIdAction());
967 contextMenu.add(getSortByTimeAction());
46cc1ade
PT
968 }
969
e8251298
PT
970 /**
971 * Get the the next event action.
972 *
973 * @return The action object
974 */
975 private Action getNextEventAction() {
976 if (fNextEventAction == null) {
977 fNextEventAction = new Action() {
978 @Override
979 public void run() {
ade0a3c5 980 TimeGraphViewer viewer = getTimeGraphViewer();
e8251298
PT
981 ITimeGraphEntry entry = viewer.getSelection();
982 if (entry instanceof CallStackEntry) {
983 try {
984 CallStackEntry callStackEntry = (CallStackEntry) entry;
da27e43a 985 ITmfStateSystem ss = callStackEntry.getStateSystem();
0fcf3b09 986 long time = Math.max(ss.getStartTime(), Math.min(ss.getCurrentEndTime(), viewer.getSelectionBegin()));
e8251298 987 ThreadEntry threadEntry = (ThreadEntry) callStackEntry.getParent();
da27e43a 988 int quark = ss.getParentAttributeQuark(callStackEntry.getQuark());
e8251298
PT
989 ITmfStateInterval stackInterval = ss.querySingleState(time, quark);
990 long newTime = stackInterval.getEndTime() + 1;
991 viewer.setSelectedTimeNotify(newTime, true);
992 stackInterval = ss.querySingleState(Math.min(ss.getCurrentEndTime(), newTime), quark);
993 int stackLevel = stackInterval.getStateValue().unboxInt();
a3188982 994 ITimeGraphEntry selectedEntry = threadEntry.getChildren().get(Math.max(0, stackLevel - 1));
ade0a3c5 995 getTimeGraphCombo().setSelection(selectedEntry);
e8251298
PT
996 viewer.getTimeGraphControl().fireSelectionChanged();
997 startZoomThread(viewer.getTime0(), viewer.getTime1());
50659279 998
ed48dc75 999 } catch (TimeRangeException | StateSystemDisposedException | StateValueTypeException e) {
52974e38 1000 Activator.getDefault().logError("Error querying state system", e); //$NON-NLS-1$
e8251298
PT
1001 }
1002 }
1003 }
1004 };
1005
5bb21f6b
AM
1006 fNextEventAction.setText(Messages.TmfTimeGraphViewer_NextStateChangeActionNameText);
1007 fNextEventAction.setToolTipText(Messages.TmfTimeGraphViewer_NextStateChangeActionToolTipText);
1008 fNextEventAction.setImageDescriptor(Activator.getDefault().getImageDescripterFromPath(ITmfImageConstants.IMG_UI_NEXT_STATE_CHANGE));
e8251298
PT
1009 }
1010
1011 return fNextEventAction;
1012 }
1013
1014 /**
1015 * Get the previous event action.
1016 *
1017 * @return The Action object
1018 */
1019 private Action getPreviousEventAction() {
1020 if (fPrevEventAction == null) {
1021 fPrevEventAction = new Action() {
1022 @Override
1023 public void run() {
ade0a3c5 1024 TimeGraphViewer viewer = getTimeGraphCombo().getTimeGraphViewer();
e8251298
PT
1025 ITimeGraphEntry entry = viewer.getSelection();
1026 if (entry instanceof CallStackEntry) {
1027 try {
1028 CallStackEntry callStackEntry = (CallStackEntry) entry;
da27e43a 1029 ITmfStateSystem ss = callStackEntry.getStateSystem();
0fcf3b09 1030 long time = Math.max(ss.getStartTime(), Math.min(ss.getCurrentEndTime(), viewer.getSelectionBegin()));
e8251298 1031 ThreadEntry threadEntry = (ThreadEntry) callStackEntry.getParent();
da27e43a 1032 int quark = ss.getParentAttributeQuark(callStackEntry.getQuark());
e8251298
PT
1033 ITmfStateInterval stackInterval = ss.querySingleState(time, quark);
1034 if (stackInterval.getStartTime() == time && time > ss.getStartTime()) {
1035 stackInterval = ss.querySingleState(time - 1, quark);
1036 }
1037 viewer.setSelectedTimeNotify(stackInterval.getStartTime(), true);
1038 int stackLevel = stackInterval.getStateValue().unboxInt();
a3188982 1039 ITimeGraphEntry selectedEntry = threadEntry.getChildren().get(Math.max(0, stackLevel - 1));
ade0a3c5 1040 getTimeGraphCombo().setSelection(selectedEntry);
e8251298
PT
1041 viewer.getTimeGraphControl().fireSelectionChanged();
1042 startZoomThread(viewer.getTime0(), viewer.getTime1());
50659279 1043
ed48dc75 1044 } catch (TimeRangeException | StateSystemDisposedException | StateValueTypeException e) {
52974e38 1045 Activator.getDefault().logError("Error querying state system", e); //$NON-NLS-1$
e8251298
PT
1046 }
1047 }
1048 }
1049 };
1050
5bb21f6b
AM
1051 fPrevEventAction.setText(Messages.TmfTimeGraphViewer_PreviousStateChangeActionNameText);
1052 fPrevEventAction.setToolTipText(Messages.TmfTimeGraphViewer_PreviousStateChangeActionToolTipText);
1053 fPrevEventAction.setImageDescriptor(Activator.getDefault().getImageDescripterFromPath(ITmfImageConstants.IMG_UI_PREV_STATE_CHANGE));
e8251298
PT
1054 }
1055
1056 return fPrevEventAction;
1057 }
1058
1d83ed07 1059 private static @Nullable AbstractCallStackAnalysis getCallStackModule(@NonNull ITmfTrace trace) {
50659279
AM
1060 /*
1061 * Since we cannot know the exact analysis ID (in separate plugins), we
1062 * will search using the analysis type.
1063 */
1064 Iterable<AbstractCallStackAnalysis> modules =
b8585c7c 1065 TmfTraceUtils.getAnalysisModulesOfClass(trace, AbstractCallStackAnalysis.class);
50659279
AM
1066 Iterator<AbstractCallStackAnalysis> it = modules.iterator();
1067 if (!it.hasNext()) {
1068 /* This trace does not provide a call-stack analysis */
1069 return null;
1070 }
1071
1072 /*
1073 * We only look at the first module we find.
1074 *
1075 * TODO Handle the advanced case where one trace provides more than one
1076 * call-stack analysis.
1077 */
1078 AbstractCallStackAnalysis module = it.next();
1079 /* This analysis is not automatic, we need to schedule it on-demand */
1080 module.schedule();
c81ffdf2
JCK
1081 if (!module.waitForInitialization()) {
1082 /* The initialization did not succeed */
1083 return null;
1084 }
da27e43a 1085 return module;
50659279
AM
1086 }
1087
5da83da5
AM
1088 // ------------------------------------------------------------------------
1089 // Methods related to function name mapping
1090 // ------------------------------------------------------------------------
1091
46cc1ade
PT
1092 private Action getSortByNameAction() {
1093 if (fSortByNameAction == null) {
1094 fSortByNameAction = new Action(Messages.CallStackView_SortByThreadName, IAction.AS_CHECK_BOX) {
1095 @Override
1096 public void run() {
1097 if (fSortOption == SortOption.BY_NAME) {
1098 saveSortOption(SortOption.BY_NAME_REV);
1099 } else {
1100 saveSortOption(SortOption.BY_NAME);
1101 }
1102 }
1103 };
1104 fSortByNameAction.setToolTipText(Messages.CallStackView_SortByThreadName);
6aea3caa 1105 fSortByNameAction.setImageDescriptor(SORT_BY_NAME_ICON);
46cc1ade
PT
1106 }
1107 return fSortByNameAction;
1108 }
1109
1110 private Action getSortByIdAction() {
1111 if (fSortByIdAction == null) {
1112 fSortByIdAction = new Action(Messages.CallStackView_SortByThreadId, IAction.AS_CHECK_BOX) {
1113 @Override
1114 public void run() {
1115 if (fSortOption == SortOption.BY_ID) {
1116 saveSortOption(SortOption.BY_ID_REV);
1117 } else {
1118 saveSortOption(SortOption.BY_ID);
1119 }
1120 }
1121 };
1122 fSortByIdAction.setToolTipText(Messages.CallStackView_SortByThreadId);
6aea3caa 1123 fSortByIdAction.setImageDescriptor(SORT_BY_ID_ICON);
46cc1ade
PT
1124 }
1125 return fSortByIdAction;
1126 }
1127
1128 private Action getSortByTimeAction() {
1129 if (fSortByTimeAction == null) {
1130 fSortByTimeAction = new Action(Messages.CallStackView_SortByThreadTime, IAction.AS_CHECK_BOX) {
1131 @Override
1132 public void run() {
1133 if (fSortOption == SortOption.BY_TIME) {
1134 saveSortOption(SortOption.BY_TIME_REV);
1135 } else {
1136 saveSortOption(SortOption.BY_TIME);
1137 }
1138 }
1139 };
1140 fSortByTimeAction.setToolTipText(Messages.CallStackView_SortByThreadTime);
6aea3caa 1141 fSortByTimeAction.setImageDescriptor(SORT_BY_TIME_ICON);
46cc1ade
PT
1142 }
1143 return fSortByTimeAction;
1144 }
1145
1146 private void loadSortOption() {
1147 IDialogSettings settings = Activator.getDefault().getDialogSettings();
1148 IDialogSettings section = settings.getSection(getClass().getName());
1149 if (section == null) {
1150 return;
1151 }
1152 String sortOption = section.get(SORT_OPTION_KEY);
6aea3caa
PT
1153 if (sortOption == null) {
1154 return;
1155 }
46cc1ade
PT
1156
1157 // reset defaults
1158 getSortByNameAction().setChecked(false);
1159 getSortByNameAction().setImageDescriptor(SORT_BY_NAME_ICON);
1160 getSortByIdAction().setChecked(false);
1161 getSortByIdAction().setImageDescriptor(SORT_BY_ID_ICON);
1162 getSortByTimeAction().setChecked(false);
1163 getSortByTimeAction().setImageDescriptor(SORT_BY_TIME_ICON);
1164
1165 if (sortOption.equals(SortOption.BY_NAME.name())) {
1166 fSortOption = SortOption.BY_NAME;
1167 fThreadComparator = new ThreadNameComparator(false);
1168 getSortByNameAction().setChecked(true);
1169 } else if (sortOption.equals(SortOption.BY_NAME_REV.name())) {
1170 fSortOption = SortOption.BY_NAME_REV;
1171 fThreadComparator = new ThreadNameComparator(true);
1172 getSortByNameAction().setChecked(true);
1173 getSortByNameAction().setImageDescriptor(SORT_BY_NAME_REV_ICON);
1174 } else if (sortOption.equals(SortOption.BY_ID.name())) {
1175 fSortOption = SortOption.BY_ID;
1176 fThreadComparator = new ThreadIdComparator(false);
1177 getSortByIdAction().setChecked(true);
1178 } else if (sortOption.equals(SortOption.BY_ID_REV.name())) {
1179 fSortOption = SortOption.BY_ID_REV;
1180 fThreadComparator = new ThreadIdComparator(true);
1181 getSortByIdAction().setChecked(true);
1182 getSortByIdAction().setImageDescriptor(SORT_BY_ID_REV_ICON);
1183 } else if (sortOption.equals(SortOption.BY_TIME.name())) {
1184 fSortOption = SortOption.BY_TIME;
1185 fThreadComparator = new ThreadTimeComparator(false);
1186 getSortByTimeAction().setChecked(true);
1187 } else if (sortOption.equals(SortOption.BY_TIME_REV.name())) {
1188 fSortOption = SortOption.BY_TIME_REV;
1189 fThreadComparator = new ThreadTimeComparator(true);
1190 getSortByTimeAction().setChecked(true);
1191 getSortByTimeAction().setImageDescriptor(SORT_BY_TIME_REV_ICON);
1192 }
1193 }
1194
1195 private void saveSortOption(SortOption sortOption) {
1196 IDialogSettings settings = Activator.getDefault().getDialogSettings();
1197 IDialogSettings section = settings.getSection(getClass().getName());
1198 if (section == null) {
1199 section = settings.addNewSection(getClass().getName());
1200 }
1201 section.put(SORT_OPTION_KEY, sortOption.name());
1202 loadSortOption();
ade0a3c5
PT
1203 List<TimeGraphEntry> entryList = getEntryList(getTrace());
1204 if (entryList == null) {
46cc1ade
PT
1205 return;
1206 }
ade0a3c5 1207 for (TimeGraphEntry traceEntry : entryList) {
46cc1ade
PT
1208 traceEntry.sortChildren(fThreadComparator);
1209 }
1210 refresh();
1211 }
1212
d90ae2a5
RK
1213 private Action getConfigureSymbolsAction() {
1214 if (fConfigureSymbolsAction != null) {
1215 return fConfigureSymbolsAction;
5da83da5
AM
1216 }
1217
d90ae2a5 1218 fConfigureSymbolsAction = new Action(Messages.CallStackView_ConfigureSymbolProvidersText) {
41d9ce5b 1219 @Override
d90ae2a5
RK
1220 public void run() {
1221 SymbolProviderConfigDialog dialog = new SymbolProviderConfigDialog(getSite().getShell(), getProviderPages());
1222 if (dialog.open() == IDialogConstants.OK_ID) {
1223 refresh();
1224 }
41d9ce5b
MAL
1225 }
1226 };
5da83da5 1227
d90ae2a5
RK
1228 fConfigureSymbolsAction.setToolTipText(Messages.CallStackView_ConfigureSymbolProvidersTooltip);
1229 fConfigureSymbolsAction.setImageDescriptor(Activator.getDefault().getImageDescripterFromPath(IMPORT_BINARY_ICON_PATH));
cc5baabc
AM
1230
1231 /*
1232 * The updateConfigureSymbolsAction() method (called by refresh()) will
1233 * set the action to true if applicable after the symbol provider has
1234 * been properly loaded.
1235 */
d90ae2a5 1236 fConfigureSymbolsAction.setEnabled(false);
5da83da5 1237
d90ae2a5 1238 return fConfigureSymbolsAction;
5da83da5
AM
1239 }
1240
d90ae2a5
RK
1241 /**
1242 * @return an array of {@link ISymbolProviderPreferencePage} that will
1243 * configure the current traces
1244 */
1245 private ISymbolProviderPreferencePage[] getProviderPages() {
1246 List<ISymbolProviderPreferencePage> pages = new ArrayList<>();
1247 ITmfTrace trace = getTrace();
1248 if (trace != null) {
1249 for (ITmfTrace subTrace : getTracesToBuild(trace)) {
1250 ISymbolProvider provider = fSymbolProviders.get(subTrace);
1251 if (provider != null) {
1252 ISymbolProviderPreferencePage page = provider.createPreferencePage();
1253 if (page != null) {
1254 pages.add(page);
1255 }
1256 }
1257 }
5da83da5 1258 }
d90ae2a5
RK
1259 return pages.toArray(new ISymbolProviderPreferencePage[pages.size()]);
1260 }
1261
1262 /**
1263 * Update the enable status of the configure symbols action
1264 */
1265 private void updateConfigureSymbolsAction() {
1266 ISymbolProviderPreferencePage[] providerPages = getProviderPages();
1267 getConfigureSymbolsAction().setEnabled(providerPages.length > 0);
5da83da5
AM
1268 }
1269
e8251298 1270}
This page took 0.16383 seconds and 5 git commands to generate.