1 /*******************************************************************************
2 * Copyright (c) 2013, 2016 Ericsson and others.
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
10 * Patrick Tasse - Initial API and implementation
11 * Bernd Hufmann - Updated signal handling
12 * Marc-Andre Laperle - Map from binary file
13 *******************************************************************************/
15 package org
.eclipse
.tracecompass
.tmf
.ui
.views
.callstack
;
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
;
25 import org
.eclipse
.core
.runtime
.IProgressMonitor
;
26 import org
.eclipse
.jdt
.annotation
.NonNull
;
27 import org
.eclipse
.jdt
.annotation
.Nullable
;
28 import org
.eclipse
.jface
.action
.Action
;
29 import org
.eclipse
.jface
.action
.GroupMarker
;
30 import org
.eclipse
.jface
.action
.IAction
;
31 import org
.eclipse
.jface
.action
.IMenuManager
;
32 import org
.eclipse
.jface
.action
.IToolBarManager
;
33 import org
.eclipse
.jface
.action
.Separator
;
34 import org
.eclipse
.jface
.dialogs
.IDialogConstants
;
35 import org
.eclipse
.jface
.dialogs
.IDialogSettings
;
36 import org
.eclipse
.jface
.resource
.ImageDescriptor
;
37 import org
.eclipse
.jface
.util
.IPropertyChangeListener
;
38 import org
.eclipse
.jface
.util
.PropertyChangeEvent
;
39 import org
.eclipse
.jface
.viewers
.DoubleClickEvent
;
40 import org
.eclipse
.jface
.viewers
.IDoubleClickListener
;
41 import org
.eclipse
.jface
.viewers
.ISelection
;
42 import org
.eclipse
.jface
.viewers
.IStructuredSelection
;
43 import org
.eclipse
.swt
.SWT
;
44 import org
.eclipse
.swt
.events
.MouseAdapter
;
45 import org
.eclipse
.swt
.events
.MouseEvent
;
46 import org
.eclipse
.swt
.graphics
.Image
;
47 import org
.eclipse
.swt
.widgets
.Composite
;
48 import org
.eclipse
.swt
.widgets
.Display
;
49 import org
.eclipse
.tracecompass
.internal
.tmf
.ui
.Activator
;
50 import org
.eclipse
.tracecompass
.internal
.tmf
.ui
.ITmfImageConstants
;
51 import org
.eclipse
.tracecompass
.internal
.tmf
.ui
.Messages
;
52 import org
.eclipse
.tracecompass
.statesystem
.core
.ITmfStateSystem
;
53 import org
.eclipse
.tracecompass
.statesystem
.core
.StateSystemUtils
;
54 import org
.eclipse
.tracecompass
.statesystem
.core
.exceptions
.AttributeNotFoundException
;
55 import org
.eclipse
.tracecompass
.statesystem
.core
.exceptions
.StateSystemDisposedException
;
56 import org
.eclipse
.tracecompass
.statesystem
.core
.exceptions
.StateValueTypeException
;
57 import org
.eclipse
.tracecompass
.statesystem
.core
.exceptions
.TimeRangeException
;
58 import org
.eclipse
.tracecompass
.statesystem
.core
.interval
.ITmfStateInterval
;
59 import org
.eclipse
.tracecompass
.statesystem
.core
.statevalue
.ITmfStateValue
;
60 import org
.eclipse
.tracecompass
.statesystem
.core
.statevalue
.ITmfStateValue
.Type
;
61 import org
.eclipse
.tracecompass
.tmf
.core
.signal
.TmfSelectionRangeUpdatedSignal
;
62 import org
.eclipse
.tracecompass
.tmf
.core
.signal
.TmfSignalHandler
;
63 import org
.eclipse
.tracecompass
.tmf
.core
.signal
.TmfTraceClosedSignal
;
64 import org
.eclipse
.tracecompass
.tmf
.core
.signal
.TmfTraceSelectedSignal
;
65 import org
.eclipse
.tracecompass
.tmf
.core
.signal
.TmfWindowRangeUpdatedSignal
;
66 import org
.eclipse
.tracecompass
.tmf
.core
.timestamp
.ITmfTimestamp
;
67 import org
.eclipse
.tracecompass
.tmf
.core
.timestamp
.TmfTimeRange
;
68 import org
.eclipse
.tracecompass
.tmf
.core
.timestamp
.TmfTimestampDelta
;
69 import org
.eclipse
.tracecompass
.tmf
.core
.timestamp
.TmfTimestamp
;
70 import org
.eclipse
.tracecompass
.tmf
.core
.trace
.ITmfTrace
;
71 import org
.eclipse
.tracecompass
.tmf
.core
.trace
.TmfTraceUtils
;
72 import org
.eclipse
.tracecompass
.tmf
.ui
.editors
.ITmfTraceEditor
;
73 import org
.eclipse
.tracecompass
.tmf
.ui
.symbols
.ISymbolProvider
;
74 import org
.eclipse
.tracecompass
.tmf
.ui
.symbols
.ISymbolProviderPreferencePage
;
75 import org
.eclipse
.tracecompass
.tmf
.ui
.symbols
.SymbolProviderConfigDialog
;
76 import org
.eclipse
.tracecompass
.tmf
.ui
.symbols
.SymbolProviderManager
;
77 import org
.eclipse
.tracecompass
.tmf
.ui
.views
.timegraph
.AbstractTimeGraphView
;
78 import org
.eclipse
.tracecompass
.tmf
.ui
.widgets
.timegraph
.ITimeGraphTimeListener
;
79 import org
.eclipse
.tracecompass
.tmf
.ui
.widgets
.timegraph
.TimeGraphContentProvider
;
80 import org
.eclipse
.tracecompass
.tmf
.ui
.widgets
.timegraph
.TimeGraphTimeEvent
;
81 import org
.eclipse
.tracecompass
.tmf
.ui
.widgets
.timegraph
.TimeGraphViewer
;
82 import org
.eclipse
.tracecompass
.tmf
.ui
.widgets
.timegraph
.model
.ITimeEvent
;
83 import org
.eclipse
.tracecompass
.tmf
.ui
.widgets
.timegraph
.model
.ITimeGraphEntry
;
84 import org
.eclipse
.tracecompass
.tmf
.ui
.widgets
.timegraph
.model
.NullTimeEvent
;
85 import org
.eclipse
.tracecompass
.tmf
.ui
.widgets
.timegraph
.model
.TimeEvent
;
86 import org
.eclipse
.tracecompass
.tmf
.ui
.widgets
.timegraph
.model
.TimeGraphEntry
;
87 import org
.eclipse
.tracecompass
.tmf
.ui
.widgets
.timegraph
.widgets
.TimeGraphControl
;
88 import org
.eclipse
.tracecompass
.tmf
.ui
.widgets
.timegraph
.widgets
.TimeGraphSelection
;
89 import org
.eclipse
.ui
.IEditorPart
;
90 import org
.eclipse
.ui
.IWorkbenchActionConstants
;
93 * Main implementation for the Call Stack view
95 * @author Patrick Tasse
97 public class CallStackView
extends AbstractTimeGraphView
{
99 // ------------------------------------------------------------------------
101 // ------------------------------------------------------------------------
104 public static final String ID
= "org.eclipse.linuxtools.tmf.ui.views.callstack"; //$NON-NLS-1$
106 private static final String
[] COLUMN_NAMES
= new String
[] {
107 Messages
.CallStackView_FunctionColumn
,
108 Messages
.CallStackView_DepthColumn
,
109 Messages
.CallStackView_EntryTimeColumn
,
110 Messages
.CallStackView_ExitTimeColumn
,
111 Messages
.CallStackView_DurationColumn
114 private static final String
[] FILTER_COLUMN_NAMES
= new String
[] {
115 Messages
.CallStackView_ThreadColumn
118 /** Timeout between updates in the build thread in ms */
119 private static final long BUILD_UPDATE_TIMEOUT
= 500;
121 // Fraction of a function duration to be added as spacing
122 private static final double SPACING_RATIO
= 0.01;
124 private static final Image THREAD_IMAGE
= Activator
.getDefault().getImageFromPath("icons/obj16/thread_obj.gif"); //$NON-NLS-1$
125 private static final Image STACKFRAME_IMAGE
= Activator
.getDefault().getImageFromPath("icons/obj16/stckframe_obj.gif"); //$NON-NLS-1$
127 private static final String IMPORT_BINARY_ICON_PATH
= "icons/obj16/binaries_obj.gif"; //$NON-NLS-1$
129 private static final ImageDescriptor SORT_BY_NAME_ICON
= Activator
.getDefault().getImageDescripterFromPath("icons/etool16/sort_alpha.gif"); //$NON-NLS-1$
130 private static final ImageDescriptor SORT_BY_NAME_REV_ICON
= Activator
.getDefault().getImageDescripterFromPath("icons/etool16/sort_alpha_rev.gif"); //$NON-NLS-1$
131 private static final ImageDescriptor SORT_BY_ID_ICON
= Activator
.getDefault().getImageDescripterFromPath("icons/etool16/sort_num.gif"); //$NON-NLS-1$
132 private static final ImageDescriptor SORT_BY_ID_REV_ICON
= Activator
.getDefault().getImageDescripterFromPath("icons/etool16/sort_num_rev.gif"); //$NON-NLS-1$
133 private static final ImageDescriptor SORT_BY_TIME_ICON
= Activator
.getDefault().getImageDescripterFromPath("icons/etool16/sort_time.gif"); //$NON-NLS-1$
134 private static final ImageDescriptor SORT_BY_TIME_REV_ICON
= Activator
.getDefault().getImageDescripterFromPath("icons/etool16/sort_time_rev.gif"); //$NON-NLS-1$
135 private static final String SORT_OPTION_KEY
= "sort.option"; //$NON-NLS-1$
137 private enum SortOption
{
138 BY_NAME
, BY_NAME_REV
, BY_ID
, BY_ID_REV
, BY_TIME
, BY_TIME_REV
141 private @NonNull SortOption fSortOption
= SortOption
.BY_NAME
;
142 private @NonNull Comparator
<ITimeGraphEntry
> fThreadComparator
= new ThreadNameComparator(false);
143 private Action fSortByNameAction
;
144 private Action fSortByIdAction
;
145 private Action fSortByTimeAction
;
147 // ------------------------------------------------------------------------
149 // ------------------------------------------------------------------------
151 private final Map
<ITmfTrace
, ISymbolProvider
> fSymbolProviders
= new HashMap
<>();
153 // The next event action
154 private Action fNextEventAction
;
156 // The previous event action
157 private Action fPrevEventAction
;
159 // The next item action
160 private Action fNextItemAction
;
162 // The previous item action
163 private Action fPreviousItemAction
;
165 // The action to import a binary file mapping */
166 private Action fConfigureSymbolsAction
;
168 // The saved time sync. signal used when switching off the pinning of a view
169 private TmfSelectionRangeUpdatedSignal fSavedTimeSyncSignal
;
171 // The saved window range signal used when switching off the pinning of
173 private TmfWindowRangeUpdatedSignal fSavedRangeSyncSignal
;
175 // ------------------------------------------------------------------------
177 // ------------------------------------------------------------------------
179 private static class TraceEntry
extends TimeGraphEntry
{
180 public TraceEntry(String name
, long startTime
, long endTime
) {
181 super(name
, startTime
, endTime
);
185 public boolean hasTimeEvents() {
190 private static class ProcessEntry
extends TimeGraphEntry
{
192 public ProcessEntry(String name
, long startTime
, long endTime
) {
193 super(name
, startTime
, endTime
);
197 public boolean hasTimeEvents() {
202 private static class ThreadEntry
extends TimeGraphEntry
{
203 // The call stack quark
204 private final int fCallStackQuark
;
205 // The state system from which this entry comes
206 private final ITmfStateSystem fSS
;
208 private final long fThreadId
;
210 public ThreadEntry(ITmfStateSystem ss
, String name
, long threadId
, int callStackQuark
, long startTime
, long endTime
) {
211 super(name
, startTime
, endTime
);
212 fCallStackQuark
= callStackQuark
;
213 fThreadId
= threadId
;
218 public boolean hasTimeEvents() {
222 public int getCallStackQuark() {
223 return fCallStackQuark
;
226 public long getThreadId() {
231 public ITmfStateSystem
getStateSystem() {
236 private class CallStackComparator
implements Comparator
<ITimeGraphEntry
> {
238 public int compare(ITimeGraphEntry o1
, ITimeGraphEntry o2
) {
239 if (o1
instanceof ThreadEntry
&& o2
instanceof ThreadEntry
) {
240 return fThreadComparator
.compare(o1
, o2
);
246 private static class ThreadNameComparator
implements Comparator
<ITimeGraphEntry
> {
247 private boolean reverse
;
249 public ThreadNameComparator(boolean reverse
) {
250 this.reverse
= reverse
;
254 public int compare(ITimeGraphEntry o1
, ITimeGraphEntry o2
) {
255 return reverse ? o2
.getName().compareTo(o1
.getName()) :
256 o1
.getName().compareTo(o2
.getName());
260 private static class ThreadIdComparator
implements Comparator
<ITimeGraphEntry
> {
261 private boolean reverse
;
263 public ThreadIdComparator(boolean reverse
) {
264 this.reverse
= reverse
;
268 public int compare(ITimeGraphEntry o1
, ITimeGraphEntry o2
) {
269 ThreadEntry t1
= (ThreadEntry
) o1
;
270 ThreadEntry t2
= (ThreadEntry
) o2
;
271 return reverse ? Long
.compare(t2
.getThreadId(), t1
.getThreadId()) :
272 Long
.compare(t1
.getThreadId(), t2
.getThreadId());
276 private static class ThreadTimeComparator
implements Comparator
<ITimeGraphEntry
> {
277 private boolean reverse
;
279 public ThreadTimeComparator(boolean reverse
) {
280 this.reverse
= reverse
;
284 public int compare(ITimeGraphEntry o1
, ITimeGraphEntry o2
) {
285 return reverse ? Long
.compare(o2
.getStartTime(), o1
.getStartTime()) :
286 Long
.compare(o1
.getStartTime(), o2
.getStartTime());
290 private static class CallStackTreeLabelProvider
extends TreeLabelProvider
{
293 public Image
getColumnImage(Object element
, int columnIndex
) {
294 if (columnIndex
== 0) {
295 if (element
instanceof ThreadEntry
) {
297 } else if (element
instanceof CallStackEntry
) {
298 CallStackEntry entry
= (CallStackEntry
) element
;
299 if (entry
.getFunctionName().length() > 0) {
300 return STACKFRAME_IMAGE
;
308 public String
getColumnText(Object element
, int columnIndex
) {
309 if (element
instanceof CallStackEntry
) {
310 CallStackEntry entry
= (CallStackEntry
) element
;
311 if (columnIndex
== 0) {
312 return entry
.getFunctionName();
313 } else if (columnIndex
== 1 && entry
.getFunctionName().length() > 0) {
314 int depth
= entry
.getStackLevel();
315 return Integer
.toString(depth
);
316 } else if (columnIndex
== 2 && entry
.getFunctionName().length() > 0) {
317 ITmfTimestamp ts
= TmfTimestamp
.fromNanos(entry
.getFunctionEntryTime());
318 return ts
.toString();
319 } else if (columnIndex
== 3 && entry
.getFunctionName().length() > 0) {
320 ITmfTimestamp ts
= TmfTimestamp
.fromNanos(entry
.getFunctionExitTime());
321 return ts
.toString();
322 } else if (columnIndex
== 4 && entry
.getFunctionName().length() > 0) {
323 ITmfTimestamp ts
= new TmfTimestampDelta(entry
.getFunctionExitTime() - entry
.getFunctionEntryTime(), ITmfTimestamp
.NANOSECOND_SCALE
);
324 return ts
.toString();
326 } else if (element
instanceof ITimeGraphEntry
) {
327 if (columnIndex
== 0) {
328 return ((ITimeGraphEntry
) element
).getName();
331 return ""; //$NON-NLS-1$
336 private class CallStackFilterContentProvider
extends TimeGraphContentProvider
{
338 public boolean hasChildren(Object element
) {
339 if (element
instanceof TraceEntry
) {
340 return super.hasChildren(element
);
346 public ITimeGraphEntry
[] getChildren(Object parentElement
) {
347 if (parentElement
instanceof TraceEntry
) {
348 return super.getChildren(parentElement
);
350 return new ITimeGraphEntry
[0];
354 // ------------------------------------------------------------------------
356 // ------------------------------------------------------------------------
359 * Default constructor
361 public CallStackView() {
362 super(ID
, new CallStackPresentationProvider());
363 ((CallStackPresentationProvider
) getPresentationProvider()).setCallStackView(this);
364 setTreeColumns(COLUMN_NAMES
);
365 setTreeLabelProvider(new CallStackTreeLabelProvider());
366 setEntryComparator(new CallStackComparator());
367 setFilterColumns(FILTER_COLUMN_NAMES
);
368 setFilterContentProvider(new CallStackFilterContentProvider());
369 setFilterLabelProvider(new CallStackTreeLabelProvider());
372 // ------------------------------------------------------------------------
374 // ------------------------------------------------------------------------
377 public void createPartControl(Composite parent
) {
378 super.createPartControl(parent
);
380 getTimeGraphViewer().addTimeListener(new ITimeGraphTimeListener() {
382 public void timeSelected(TimeGraphTimeEvent event
) {
383 synchingToTime(event
.getBeginTime());
387 getTimeGraphCombo().getTreeViewer().addDoubleClickListener(new IDoubleClickListener() {
389 public void doubleClick(DoubleClickEvent event
) {
390 Object selection
= ((IStructuredSelection
) event
.getSelection()).getFirstElement();
391 if (selection
instanceof CallStackEntry
) {
392 CallStackEntry entry
= (CallStackEntry
) selection
;
393 if (entry
.getFunctionName().length() > 0) {
394 long entryTime
= entry
.getFunctionEntryTime();
395 long exitTime
= entry
.getFunctionExitTime();
396 long spacingTime
= (long) ((exitTime
- entryTime
) * SPACING_RATIO
);
397 entryTime
-= spacingTime
;
398 exitTime
+= spacingTime
;
399 TmfTimeRange range
= new TmfTimeRange(TmfTimestamp
.fromNanos(entryTime
), TmfTimestamp
.fromNanos(exitTime
));
400 broadcast(new TmfWindowRangeUpdatedSignal(CallStackView
.this, range
));
401 getTimeGraphViewer().setStartFinishTime(entryTime
, exitTime
);
402 startZoomThread(entryTime
, exitTime
);
408 getTimeGraphViewer().getTimeGraphControl().addMouseListener(new MouseAdapter() {
410 public void mouseDoubleClick(MouseEvent e
) {
411 TimeGraphControl timeGraphControl
= getTimeGraphViewer().getTimeGraphControl();
412 ISelection selection
= timeGraphControl
.getSelection();
413 if (selection
instanceof TimeGraphSelection
) {
414 Object o
= ((TimeGraphSelection
) selection
).getFirstElement();
415 if (o
instanceof CallStackEvent
) {
416 CallStackEvent event
= (CallStackEvent
) o
;
417 long startTime
= event
.getTime();
418 long endTime
= startTime
+ event
.getDuration();
419 long spacingTime
= (long) ((endTime
- startTime
) * SPACING_RATIO
);
420 startTime
-= spacingTime
;
421 endTime
+= spacingTime
;
422 TmfTimeRange range
= new TmfTimeRange(TmfTimestamp
.fromNanos(startTime
), TmfTimestamp
.fromNanos(endTime
));
423 broadcast(new TmfWindowRangeUpdatedSignal(CallStackView
.this, range
));
424 getTimeGraphViewer().setStartFinishTime(startTime
, endTime
);
425 startZoomThread(startTime
, endTime
);
431 contributeToActionBars();
434 IEditorPart editor
= getSite().getPage().getActiveEditor();
435 if (editor
instanceof ITmfTraceEditor
) {
436 ITmfTrace trace
= ((ITmfTraceEditor
) editor
).getTrace();
438 traceSelected(new TmfTraceSelectedSignal(this, trace
));
444 * Handler for the selection range signal.
447 * The incoming signal
452 public void selectionRangeUpdated(final TmfSelectionRangeUpdatedSignal signal
) {
454 fSavedTimeSyncSignal
= isPinned() ?
new TmfSelectionRangeUpdatedSignal(signal
.getSource(), signal
.getBeginTime(), signal
.getEndTime()) : null;
456 if (signal
.getSource() == this || getTrace() == null || isPinned()) {
459 final long beginTime
= signal
.getBeginTime().toNanos();
460 final long endTime
= signal
.getEndTime().toNanos();
461 Display
.getDefault().asyncExec(new Runnable() {
464 if (getTimeGraphCombo().isDisposed()) {
467 if (beginTime
== endTime
) {
468 getTimeGraphViewer().setSelectedTime(beginTime
, true);
470 getTimeGraphViewer().setSelectionRange(beginTime
, endTime
, true);
472 synchingToTime(beginTime
);
473 startZoomThread(getTimeGraphViewer().getTime0(), getTimeGraphViewer().getTime1());
474 List
<TimeGraphEntry
> traceEntries
= getEntryList(getTrace());
475 if (traceEntries
== null) {
478 TimeGraphViewer viewer
= getTimeGraphViewer();
479 for (TimeGraphEntry traceEntry
: traceEntries
) {
480 for (ITimeGraphEntry processEntry
: traceEntry
.getChildren()) {
481 for (ITimeGraphEntry aThreadEntry
: processEntry
.getChildren()) {
482 ThreadEntry threadEntry
= (ThreadEntry
) aThreadEntry
;
483 ITmfStateSystem ss
= threadEntry
.getStateSystem();
484 if (ss
== null || beginTime
< ss
.getStartTime() || beginTime
> ss
.getCurrentEndTime()) {
488 int quark
= threadEntry
.getCallStackQuark();
489 ITmfStateInterval stackInterval
= ss
.querySingleState(beginTime
, quark
);
490 if (beginTime
== stackInterval
.getStartTime()) {
491 int stackLevel
= stackInterval
.getStateValue().unboxInt();
492 ITimeGraphEntry selectedEntry
= threadEntry
.getChildren().get(Math
.max(0, stackLevel
- 1));
493 getTimeGraphCombo().setSelection(selectedEntry
);
494 viewer
.getTimeGraphControl().fireSelectionChanged();
497 } catch (AttributeNotFoundException
| TimeRangeException
| StateSystemDisposedException
| StateValueTypeException e
) {
498 Activator
.getDefault().logError("Error querying state system", e
); //$NON-NLS-1$
513 public void windowRangeUpdated(final TmfWindowRangeUpdatedSignal signal
) {
516 fSavedRangeSyncSignal
= new TmfWindowRangeUpdatedSignal(signal
.getSource(), signal
.getCurrentRange());
517 fSavedTimeSyncSignal
= null;
520 if ((signal
.getSource() == this) || isPinned()) {
523 super.windowRangeUpdated(signal
);
526 // ------------------------------------------------------------------------
528 // ------------------------------------------------------------------------
532 public void traceClosed(TmfTraceClosedSignal signal
) {
533 super.traceClosed(signal
);
534 synchronized(fSymbolProviders
){
535 for(ITmfTrace trace
: getTracesToBuild(signal
.getTrace())){
536 fSymbolProviders
.remove(trace
);
545 protected void refresh() {
547 updateConfigureSymbolsAction();
551 protected void buildEntryList(final ITmfTrace trace
, final ITmfTrace parentTrace
, final IProgressMonitor monitor
) {
552 if (monitor
.isCanceled()) {
555 AbstractCallStackAnalysis module
= getCallStackModule(trace
);
556 if (module
== null) {
557 addUnavailableEntry(trace
, parentTrace
);
560 ITmfStateSystem ss
= module
.getStateSystem();
562 addUnavailableEntry(trace
, parentTrace
);
566 Map
<ITmfTrace
, TraceEntry
> traceEntryMap
= new HashMap
<>();
567 Map
<Integer
, ProcessEntry
> processEntryMap
= new HashMap
<>();
568 Map
<Integer
, ThreadEntry
> threadEntryMap
= new HashMap
<>();
570 long start
= ss
.getStartTime();
572 boolean complete
= false;
574 if (monitor
.isCanceled()) {
577 complete
= ss
.waitUntilBuilt(BUILD_UPDATE_TIMEOUT
);
578 if (ss
.isCancelled()) {
581 long end
= ss
.getCurrentEndTime();
582 if (start
== end
&& !complete
) { // when complete execute one last time regardless of end time
586 ISymbolProvider provider
= fSymbolProviders
.get(trace
);
587 if (provider
== null) {
588 provider
= SymbolProviderManager
.getInstance().getSymbolProvider(trace
);
589 provider
.loadConfiguration(monitor
);
590 fSymbolProviders
.put(trace
, provider
);
593 getConfigureSymbolsAction().setEnabled(true);
596 TraceEntry traceEntry
= traceEntryMap
.get(trace
);
597 if (traceEntry
== null) {
598 traceEntry
= new TraceEntry(trace
.getName(), start
, end
+ 1);
599 traceEntryMap
.put(trace
, traceEntry
);
600 traceEntry
.sortChildren(fThreadComparator
);
601 addToEntryList(parentTrace
, Collections
.singletonList(traceEntry
));
603 traceEntry
.updateEndTime(end
);
606 List
<Integer
> processQuarks
= ss
.getQuarks(module
.getProcessesPattern());
607 for (Integer processQuark
: processQuarks
) {
609 /* Create the entry for the process */
610 ProcessEntry processEntry
= processEntryMap
.get(processQuark
);
611 if (processEntry
== null) {
612 String name
= ss
.getAttributeName(processQuark
.intValue());
613 processEntry
= new ProcessEntry(name
, start
, end
);
614 processEntryMap
.put(processQuark
, processEntry
);
615 traceEntry
.addChild(processEntry
);
617 processEntry
.updateEndTime(end
);
620 /* Create the threads under the process */
622 List
<Integer
> threadQuarks
= ss
.getSubAttributes(processQuark
, false, module
.getThreadsForProcessPattern());
625 * Only query startStates if necessary (threadEntry == null)
627 List
<ITmfStateInterval
> startStates
= null;
628 List
<ITmfStateInterval
> endStates
= ss
.queryFullState(ss
.getCurrentEndTime());
629 for (int i
= 0; i
< threadQuarks
.size(); i
++) {
630 if (monitor
.isCanceled()) {
633 int threadQuark
= threadQuarks
.get(i
);
635 String
[] callStackPath
= module
.getCallStackPathForThread();
636 int callStackQuark
= ss
.getQuarkRelative(threadQuark
, callStackPath
);
637 String threadName
= ss
.getAttributeName(threadQuark
);
638 long threadEnd
= end
+ 1;
639 ITmfStateInterval endInterval
= endStates
.get(callStackQuark
);
640 if (endInterval
.getStateValue().isNull() && endInterval
.getStartTime() != ss
.getStartTime()) {
641 threadEnd
= endInterval
.getStartTime();
643 ThreadEntry threadEntry
= threadEntryMap
.get(threadQuark
);
644 if (threadEntry
== null) {
645 if (startStates
== null) {
646 startStates
= ss
.queryFullState(ss
.getStartTime());
648 long threadId
= endInterval
.getStateValue().unboxLong();
649 long threadStart
= start
;
650 ITmfStateInterval startInterval
= startStates
.get(callStackQuark
);
651 if (startInterval
.getStateValue().isNull()) {
652 threadStart
= Math
.min(startInterval
.getEndTime() + 1, end
+ 1);
654 threadEntry
= new ThreadEntry(ss
, threadName
, threadId
, callStackQuark
, threadStart
, threadEnd
);
655 threadEntryMap
.put(threadQuark
, threadEntry
);
656 processEntry
.addChild(threadEntry
);
658 threadEntry
.updateEndTime(threadEnd
);
661 for (int stackLevelQuark
: ss
.getSubAttributes(callStackQuark
, false)) {
662 if (level
> threadEntry
.getChildren().size()) {
663 CallStackEntry callStackEntry
= new CallStackEntry(threadName
, stackLevelQuark
, level
, trace
, ss
);
664 threadEntry
.addChild(callStackEntry
);
669 } catch (AttributeNotFoundException e
) {
670 Activator
.getDefault().logError("Error querying state system", e
); //$NON-NLS-1$
671 } catch (StateSystemDisposedException e
) {
676 if (parentTrace
== getTrace()) {
677 synchronized (this) {
678 setStartTime(getStartTime() == SWT
.DEFAULT ? start
: Math
.min(getStartTime(), start
));
679 setEndTime(getEndTime() == SWT
.DEFAULT ? end
+ 1 : Math
.max(getEndTime(), end
+ 1));
681 synchingToTime(getTimeGraphViewer().getSelectionBegin());
685 for (ITimeGraphEntry processEntry
: traceEntry
.getChildren()) {
686 for (ITimeGraphEntry threadEntry
: processEntry
.getChildren()) {
687 for (ITimeGraphEntry callStackEntry
: threadEntry
.getChildren()) {
688 if (monitor
.isCanceled()) {
691 buildStatusEvents(parentTrace
, (CallStackEntry
) callStackEntry
, monitor
, ss
.getStartTime(), end
);
699 private void addUnavailableEntry(ITmfTrace trace
, ITmfTrace parentTrace
) {
700 String name
= Messages
.CallStackView_StackInfoNotAvailable
+ ' ' + '(' + trace
.getName() + ')';
701 TraceEntry unavailableEntry
= new TraceEntry(name
, 0, 0);
702 addToEntryList(parentTrace
, Collections
.singletonList(unavailableEntry
));
703 if (parentTrace
== getTrace()) {
708 private void buildStatusEvents(ITmfTrace trace
, CallStackEntry entry
, @NonNull IProgressMonitor monitor
, long start
, long end
) {
709 ITmfStateSystem ss
= entry
.getStateSystem();
710 long resolution
= Math
.max(1, (end
- ss
.getStartTime()) / getDisplayWidth());
711 List
<ITimeEvent
> eventList
= getEventList(entry
, start
, end
+ 1, resolution
, monitor
);
712 if (eventList
!= null) {
713 entry
.setEventList(eventList
);
715 if (trace
== getTrace()) {
724 protected final List
<ITimeEvent
> getEventList(TimeGraphEntry tgentry
, long startTime
, long endTime
, long resolution
, IProgressMonitor monitor
) {
725 if (!(tgentry
instanceof CallStackEntry
)) {
728 CallStackEntry entry
= (CallStackEntry
) tgentry
;
729 ITmfStateSystem ss
= entry
.getStateSystem();
730 long start
= Math
.max(startTime
, ss
.getStartTime());
731 long end
= Math
.min(endTime
, ss
.getCurrentEndTime() + 1);
735 boolean isZoomThread
= Thread
.currentThread() instanceof ZoomThread
;
736 List
<ITimeEvent
> eventList
= null;
738 List
<ITmfStateInterval
> stackIntervals
= StateSystemUtils
.queryHistoryRange(ss
, entry
.getQuark(), start
, end
- 1, resolution
, monitor
);
739 eventList
= new ArrayList
<>(stackIntervals
.size());
740 long lastEndTime
= -1;
741 boolean lastIsNull
= true;
742 for (ITmfStateInterval statusInterval
: stackIntervals
) {
743 if (monitor
.isCanceled()) {
746 long time
= statusInterval
.getStartTime();
747 long duration
= statusInterval
.getEndTime() - time
+ 1;
748 if (!statusInterval
.getStateValue().isNull()) {
749 final int modulo
= CallStackPresentationProvider
.NUM_COLORS
/ 2;
750 int value
= statusInterval
.getStateValue().toString().hashCode() % modulo
+ modulo
;
751 eventList
.add(new CallStackEvent(entry
, time
, duration
, value
));
754 if (lastEndTime
== -1 && isZoomThread
) {
755 // add null event if it intersects the start time
756 eventList
.add(new NullTimeEvent(entry
, time
, duration
));
758 if (lastEndTime
!= time
&& lastIsNull
) {
759 // add unknown event if between two null states
760 eventList
.add(new TimeEvent(entry
, lastEndTime
, time
- lastEndTime
));
762 if (time
+ duration
>= endTime
&& isZoomThread
) {
763 // add null event if it intersects the end time
764 eventList
.add(new NullTimeEvent(entry
, time
, duration
));
769 lastEndTime
= time
+ duration
;
771 } catch (AttributeNotFoundException e
) {
772 Activator
.getDefault().logError("Error querying state system", e
); //$NON-NLS-1$
773 } catch (TimeRangeException e
) {
774 Activator
.getDefault().logError("Error querying state system", e
); //$NON-NLS-1$
775 } catch (StateSystemDisposedException e
) {
785 protected void synchingToTime(long time
) {
786 List
<TimeGraphEntry
> entryList
= getEntryList(getTrace());
787 if (entryList
== null) {
790 for (TimeGraphEntry traceEntry
: entryList
) {
791 for (ITimeGraphEntry processEntry
: traceEntry
.getChildren()) {
792 for (ITimeGraphEntry threadEntry
: processEntry
.getChildren()) {
793 ITmfStateSystem ss
= ((ThreadEntry
) threadEntry
).getStateSystem();
797 if (ss
.isCancelled()) {
800 if (time
< ss
.getStartTime() || time
> ss
.getCurrentEndTime()) {
803 for (ITimeGraphEntry child
: threadEntry
.getChildren()) {
804 CallStackEntry callStackEntry
= (CallStackEntry
) child
;
805 ITmfTrace trace
= callStackEntry
.getTrace();
807 ITmfStateInterval stackLevelInterval
= ss
.querySingleState(time
, callStackEntry
.getQuark());
808 ITmfStateValue nameValue
= stackLevelInterval
.getStateValue();
809 String name
= getFunctionName(trace
, nameValue
);
810 callStackEntry
.setFunctionName(name
);
811 if (name
.length() > 0) {
812 callStackEntry
.setFunctionEntryTime(stackLevelInterval
.getStartTime());
813 callStackEntry
.setFunctionExitTime(stackLevelInterval
.getEndTime() + 1);
815 } catch (AttributeNotFoundException e
) {
816 Activator
.getDefault().logError("Error querying state system", e
); //$NON-NLS-1$
817 } catch (StateSystemDisposedException e
) {
824 if (Display
.getCurrent() != null) {
825 getTimeGraphCombo().refresh();
829 String
getFunctionName(ITmfTrace trace
, ITmfStateValue nameValue
) {
830 long address
= Long
.MAX_VALUE
;
831 String name
= ""; //$NON-NLS-1$
833 if (nameValue
.getType() == Type
.STRING
) {
834 name
= nameValue
.unboxStr();
836 address
= Long
.parseLong(name
, 16);
837 } catch (NumberFormatException e
) {
840 } else if (nameValue
.getType() == Type
.INTEGER
) {
841 name
= "0x" + Integer
.toHexString(nameValue
.unboxInt()); //$NON-NLS-1$
842 address
= nameValue
.unboxInt();
843 } else if (nameValue
.getType() == Type
.LONG
) {
844 name
= "0x" + Long
.toHexString(nameValue
.unboxLong()); //$NON-NLS-1$
845 address
= nameValue
.unboxLong();
847 } catch (StateValueTypeException e
) {
849 if (address
!= Long
.MAX_VALUE
) {
850 ISymbolProvider provider
= fSymbolProviders
.get(trace
);
851 if (provider
!= null) {
852 String symbol
= provider
.getSymbolText(address
);
853 if (symbol
!= null) {
861 private void makeActions() {
862 fPreviousItemAction
= getTimeGraphViewer().getPreviousItemAction();
863 fPreviousItemAction
.setText(Messages
.TmfTimeGraphViewer_PreviousItemActionNameText
);
864 fPreviousItemAction
.setToolTipText(Messages
.TmfTimeGraphViewer_PreviousItemActionToolTipText
);
865 fNextItemAction
= getTimeGraphViewer().getNextItemAction();
866 fNextItemAction
.setText(Messages
.TmfTimeGraphViewer_NextItemActionNameText
);
867 fNextItemAction
.setToolTipText(Messages
.TmfTimeGraphViewer_NextItemActionToolTipText
);
870 private void contributeToActionBars() {
872 contributePinActionToToolBar();
873 fPinAction
.addPropertyChangeListener(new IPropertyChangeListener() {
875 public void propertyChange(PropertyChangeEvent event
) {
876 if (IAction
.CHECKED
.equals(event
.getProperty()) && !isPinned()) {
877 if (fSavedRangeSyncSignal
!= null) {
878 windowRangeUpdated(fSavedRangeSyncSignal
);
879 fSavedRangeSyncSignal
= null;
882 if (fSavedTimeSyncSignal
!= null) {
883 selectionRangeUpdated(fSavedTimeSyncSignal
);
884 fSavedTimeSyncSignal
= null;
895 protected void fillLocalToolBar(IToolBarManager manager
) {
897 manager
.add(getConfigureSymbolsAction());
898 manager
.add(new Separator());
899 manager
.add(getSortByNameAction());
900 manager
.add(getSortByIdAction());
901 manager
.add(getSortByTimeAction());
902 manager
.add(new Separator());
903 manager
.add(getTimeGraphCombo().getShowFilterDialogAction());
904 manager
.add(new Separator());
905 manager
.add(getTimeGraphViewer().getResetScaleAction());
906 manager
.add(getPreviousEventAction());
907 manager
.add(getNextEventAction());
908 manager
.add(new Separator());
909 manager
.add(getTimeGraphViewer().getToggleBookmarkAction());
910 manager
.add(getTimeGraphViewer().getPreviousMarkerAction());
911 manager
.add(getTimeGraphViewer().getNextMarkerAction());
912 manager
.add(new Separator());
913 manager
.add(fPreviousItemAction
);
914 manager
.add(fNextItemAction
);
915 manager
.add(getTimeGraphViewer().getZoomInAction());
916 manager
.add(getTimeGraphViewer().getZoomOutAction());
923 protected void fillTimeGraphEntryContextMenu(IMenuManager contextMenu
) {
924 contextMenu
.add(new GroupMarker(IWorkbenchActionConstants
.GROUP_REORGANIZE
));
925 contextMenu
.add(getSortByNameAction());
926 contextMenu
.add(getSortByIdAction());
927 contextMenu
.add(getSortByTimeAction());
931 * Get the the next event action.
933 * @return The action object
935 private Action
getNextEventAction() {
936 if (fNextEventAction
== null) {
937 fNextEventAction
= new Action() {
940 TimeGraphViewer viewer
= getTimeGraphViewer();
941 ITimeGraphEntry entry
= viewer
.getSelection();
942 if (entry
instanceof CallStackEntry
) {
944 CallStackEntry callStackEntry
= (CallStackEntry
) entry
;
945 ITmfStateSystem ss
= callStackEntry
.getStateSystem();
946 long time
= Math
.max(ss
.getStartTime(), Math
.min(ss
.getCurrentEndTime(), viewer
.getSelectionBegin()));
947 ThreadEntry threadEntry
= (ThreadEntry
) callStackEntry
.getParent();
948 int quark
= ss
.getParentAttributeQuark(callStackEntry
.getQuark());
949 ITmfStateInterval stackInterval
= ss
.querySingleState(time
, quark
);
950 long newTime
= stackInterval
.getEndTime() + 1;
951 viewer
.setSelectedTimeNotify(newTime
, true);
952 stackInterval
= ss
.querySingleState(Math
.min(ss
.getCurrentEndTime(), newTime
), quark
);
953 int stackLevel
= stackInterval
.getStateValue().unboxInt();
954 ITimeGraphEntry selectedEntry
= threadEntry
.getChildren().get(Math
.max(0, stackLevel
- 1));
955 getTimeGraphCombo().setSelection(selectedEntry
);
956 viewer
.getTimeGraphControl().fireSelectionChanged();
957 startZoomThread(viewer
.getTime0(), viewer
.getTime1());
959 } catch (AttributeNotFoundException
| TimeRangeException
| StateSystemDisposedException
| StateValueTypeException e
) {
960 Activator
.getDefault().logError("Error querying state system", e
); //$NON-NLS-1$
966 fNextEventAction
.setText(Messages
.TmfTimeGraphViewer_NextEventActionNameText
);
967 fNextEventAction
.setToolTipText(Messages
.TmfTimeGraphViewer_NextEventActionToolTipText
);
968 fNextEventAction
.setImageDescriptor(Activator
.getDefault().getImageDescripterFromPath(ITmfImageConstants
.IMG_UI_NEXT_EVENT
));
971 return fNextEventAction
;
975 * Get the previous event action.
977 * @return The Action object
979 private Action
getPreviousEventAction() {
980 if (fPrevEventAction
== null) {
981 fPrevEventAction
= new Action() {
984 TimeGraphViewer viewer
= getTimeGraphCombo().getTimeGraphViewer();
985 ITimeGraphEntry entry
= viewer
.getSelection();
986 if (entry
instanceof CallStackEntry
) {
988 CallStackEntry callStackEntry
= (CallStackEntry
) entry
;
989 ITmfStateSystem ss
= callStackEntry
.getStateSystem();
990 long time
= Math
.max(ss
.getStartTime(), Math
.min(ss
.getCurrentEndTime(), viewer
.getSelectionBegin()));
991 ThreadEntry threadEntry
= (ThreadEntry
) callStackEntry
.getParent();
992 int quark
= ss
.getParentAttributeQuark(callStackEntry
.getQuark());
993 ITmfStateInterval stackInterval
= ss
.querySingleState(time
, quark
);
994 if (stackInterval
.getStartTime() == time
&& time
> ss
.getStartTime()) {
995 stackInterval
= ss
.querySingleState(time
- 1, quark
);
997 viewer
.setSelectedTimeNotify(stackInterval
.getStartTime(), true);
998 int stackLevel
= stackInterval
.getStateValue().unboxInt();
999 ITimeGraphEntry selectedEntry
= threadEntry
.getChildren().get(Math
.max(0, stackLevel
- 1));
1000 getTimeGraphCombo().setSelection(selectedEntry
);
1001 viewer
.getTimeGraphControl().fireSelectionChanged();
1002 startZoomThread(viewer
.getTime0(), viewer
.getTime1());
1004 } catch (AttributeNotFoundException
| TimeRangeException
| StateSystemDisposedException
| StateValueTypeException e
) {
1005 Activator
.getDefault().logError("Error querying state system", e
); //$NON-NLS-1$
1011 fPrevEventAction
.setText(Messages
.TmfTimeGraphViewer_PreviousEventActionNameText
);
1012 fPrevEventAction
.setToolTipText(Messages
.TmfTimeGraphViewer_PreviousEventActionToolTipText
);
1013 fPrevEventAction
.setImageDescriptor(Activator
.getDefault().getImageDescripterFromPath(ITmfImageConstants
.IMG_UI_PREV_EVENT
));
1016 return fPrevEventAction
;
1019 private static @Nullable AbstractCallStackAnalysis
getCallStackModule(@NonNull ITmfTrace trace
) {
1021 * Since we cannot know the exact analysis ID (in separate plugins), we
1022 * will search using the analysis type.
1024 Iterable
<AbstractCallStackAnalysis
> modules
=
1025 TmfTraceUtils
.getAnalysisModulesOfClass(trace
, AbstractCallStackAnalysis
.class);
1026 Iterator
<AbstractCallStackAnalysis
> it
= modules
.iterator();
1027 if (!it
.hasNext()) {
1028 /* This trace does not provide a call-stack analysis */
1033 * We only look at the first module we find.
1035 * TODO Handle the advanced case where one trace provides more than one
1036 * call-stack analysis.
1038 AbstractCallStackAnalysis module
= it
.next();
1039 /* This analysis is not automatic, we need to schedule it on-demand */
1041 if (!module
.waitForInitialization()) {
1042 /* The initialization did not succeed */
1048 // ------------------------------------------------------------------------
1049 // Methods related to function name mapping
1050 // ------------------------------------------------------------------------
1052 private Action
getSortByNameAction() {
1053 if (fSortByNameAction
== null) {
1054 fSortByNameAction
= new Action(Messages
.CallStackView_SortByThreadName
, IAction
.AS_CHECK_BOX
) {
1057 if (fSortOption
== SortOption
.BY_NAME
) {
1058 saveSortOption(SortOption
.BY_NAME_REV
);
1060 saveSortOption(SortOption
.BY_NAME
);
1064 fSortByNameAction
.setToolTipText(Messages
.CallStackView_SortByThreadName
);
1065 fSortByNameAction
.setImageDescriptor(SORT_BY_NAME_ICON
);
1067 return fSortByNameAction
;
1070 private Action
getSortByIdAction() {
1071 if (fSortByIdAction
== null) {
1072 fSortByIdAction
= new Action(Messages
.CallStackView_SortByThreadId
, IAction
.AS_CHECK_BOX
) {
1075 if (fSortOption
== SortOption
.BY_ID
) {
1076 saveSortOption(SortOption
.BY_ID_REV
);
1078 saveSortOption(SortOption
.BY_ID
);
1082 fSortByIdAction
.setToolTipText(Messages
.CallStackView_SortByThreadId
);
1083 fSortByIdAction
.setImageDescriptor(SORT_BY_ID_ICON
);
1085 return fSortByIdAction
;
1088 private Action
getSortByTimeAction() {
1089 if (fSortByTimeAction
== null) {
1090 fSortByTimeAction
= new Action(Messages
.CallStackView_SortByThreadTime
, IAction
.AS_CHECK_BOX
) {
1093 if (fSortOption
== SortOption
.BY_TIME
) {
1094 saveSortOption(SortOption
.BY_TIME_REV
);
1096 saveSortOption(SortOption
.BY_TIME
);
1100 fSortByTimeAction
.setToolTipText(Messages
.CallStackView_SortByThreadTime
);
1101 fSortByTimeAction
.setImageDescriptor(SORT_BY_TIME_ICON
);
1103 return fSortByTimeAction
;
1106 private void loadSortOption() {
1107 IDialogSettings settings
= Activator
.getDefault().getDialogSettings();
1108 IDialogSettings section
= settings
.getSection(getClass().getName());
1109 if (section
== null) {
1112 String sortOption
= section
.get(SORT_OPTION_KEY
);
1113 if (sortOption
== null) {
1118 getSortByNameAction().setChecked(false);
1119 getSortByNameAction().setImageDescriptor(SORT_BY_NAME_ICON
);
1120 getSortByIdAction().setChecked(false);
1121 getSortByIdAction().setImageDescriptor(SORT_BY_ID_ICON
);
1122 getSortByTimeAction().setChecked(false);
1123 getSortByTimeAction().setImageDescriptor(SORT_BY_TIME_ICON
);
1125 if (sortOption
.equals(SortOption
.BY_NAME
.name())) {
1126 fSortOption
= SortOption
.BY_NAME
;
1127 fThreadComparator
= new ThreadNameComparator(false);
1128 getSortByNameAction().setChecked(true);
1129 } else if (sortOption
.equals(SortOption
.BY_NAME_REV
.name())) {
1130 fSortOption
= SortOption
.BY_NAME_REV
;
1131 fThreadComparator
= new ThreadNameComparator(true);
1132 getSortByNameAction().setChecked(true);
1133 getSortByNameAction().setImageDescriptor(SORT_BY_NAME_REV_ICON
);
1134 } else if (sortOption
.equals(SortOption
.BY_ID
.name())) {
1135 fSortOption
= SortOption
.BY_ID
;
1136 fThreadComparator
= new ThreadIdComparator(false);
1137 getSortByIdAction().setChecked(true);
1138 } else if (sortOption
.equals(SortOption
.BY_ID_REV
.name())) {
1139 fSortOption
= SortOption
.BY_ID_REV
;
1140 fThreadComparator
= new ThreadIdComparator(true);
1141 getSortByIdAction().setChecked(true);
1142 getSortByIdAction().setImageDescriptor(SORT_BY_ID_REV_ICON
);
1143 } else if (sortOption
.equals(SortOption
.BY_TIME
.name())) {
1144 fSortOption
= SortOption
.BY_TIME
;
1145 fThreadComparator
= new ThreadTimeComparator(false);
1146 getSortByTimeAction().setChecked(true);
1147 } else if (sortOption
.equals(SortOption
.BY_TIME_REV
.name())) {
1148 fSortOption
= SortOption
.BY_TIME_REV
;
1149 fThreadComparator
= new ThreadTimeComparator(true);
1150 getSortByTimeAction().setChecked(true);
1151 getSortByTimeAction().setImageDescriptor(SORT_BY_TIME_REV_ICON
);
1155 private void saveSortOption(SortOption sortOption
) {
1156 IDialogSettings settings
= Activator
.getDefault().getDialogSettings();
1157 IDialogSettings section
= settings
.getSection(getClass().getName());
1158 if (section
== null) {
1159 section
= settings
.addNewSection(getClass().getName());
1161 section
.put(SORT_OPTION_KEY
, sortOption
.name());
1163 List
<TimeGraphEntry
> entryList
= getEntryList(getTrace());
1164 if (entryList
== null) {
1167 for (TimeGraphEntry traceEntry
: entryList
) {
1168 traceEntry
.sortChildren(fThreadComparator
);
1173 private Action
getConfigureSymbolsAction() {
1174 if (fConfigureSymbolsAction
!= null) {
1175 return fConfigureSymbolsAction
;
1178 fConfigureSymbolsAction
= new Action(Messages
.CallStackView_ConfigureSymbolProvidersText
) {
1181 SymbolProviderConfigDialog dialog
= new SymbolProviderConfigDialog(getSite().getShell(), getProviderPages());
1182 if (dialog
.open() == IDialogConstants
.OK_ID
) {
1188 fConfigureSymbolsAction
.setToolTipText(Messages
.CallStackView_ConfigureSymbolProvidersTooltip
);
1189 fConfigureSymbolsAction
.setImageDescriptor(Activator
.getDefault().getImageDescripterFromPath(IMPORT_BINARY_ICON_PATH
));
1190 fConfigureSymbolsAction
.setEnabled(false);
1192 return fConfigureSymbolsAction
;
1196 * @return an array of {@link ISymbolProviderPreferencePage} that will
1197 * configure the current traces
1199 private ISymbolProviderPreferencePage
[] getProviderPages() {
1200 List
<ISymbolProviderPreferencePage
> pages
= new ArrayList
<>();
1201 ITmfTrace trace
= getTrace();
1202 if (trace
!= null) {
1203 for (ITmfTrace subTrace
: getTracesToBuild(trace
)) {
1204 ISymbolProvider provider
= fSymbolProviders
.get(subTrace
);
1205 if (provider
!= null) {
1206 ISymbolProviderPreferencePage page
= provider
.createPreferencePage();
1213 return pages
.toArray(new ISymbolProviderPreferencePage
[pages
.size()]);
1217 * Update the enable status of the configure symbols action
1219 private void updateConfigureSymbolsAction() {
1220 ISymbolProviderPreferencePage
[] providerPages
= getProviderPages();
1221 getConfigureSymbolsAction().setEnabled(providerPages
.length
> 0);