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