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