tmf: Support for context-sensitive menu in Time Graph combos
[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
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.TmfNanoTimestamp;
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 THREAD_IMAGE = Activator.getDefault().getImageFromPath("icons/obj16/thread_obj.gif"); //$NON-NLS-1$
126 private static final Image STACKFRAME_IMAGE = Activator.getDefault().getImageFromPath("icons/obj16/stckframe_obj.gif"); //$NON-NLS-1$
127
128 private static final String IMPORT_BINARY_ICON_PATH = "icons/obj16/binaries_obj.gif"; //$NON-NLS-1$
129
130 private static final ImageDescriptor SORT_BY_NAME_ICON = Activator.getDefault().getImageDescripterFromPath("icons/etool16/sort_alpha.gif"); //$NON-NLS-1$
131 private static final ImageDescriptor SORT_BY_NAME_REV_ICON = Activator.getDefault().getImageDescripterFromPath("icons/etool16/sort_alpha_rev.gif"); //$NON-NLS-1$
132 private static final ImageDescriptor SORT_BY_ID_ICON = Activator.getDefault().getImageDescripterFromPath("icons/etool16/sort_num.gif"); //$NON-NLS-1$
133 private static final ImageDescriptor SORT_BY_ID_REV_ICON = Activator.getDefault().getImageDescripterFromPath("icons/etool16/sort_num_rev.gif"); //$NON-NLS-1$
134 private static final ImageDescriptor SORT_BY_TIME_ICON = Activator.getDefault().getImageDescripterFromPath("icons/etool16/sort_time.gif"); //$NON-NLS-1$
135 private static final ImageDescriptor SORT_BY_TIME_REV_ICON = Activator.getDefault().getImageDescripterFromPath("icons/etool16/sort_time_rev.gif"); //$NON-NLS-1$
136 private static final String SORT_OPTION_KEY = "sort.option"; //$NON-NLS-1$
137
138 private enum SortOption {
139 BY_NAME, BY_NAME_REV, BY_ID, BY_ID_REV, BY_TIME, BY_TIME_REV
140 }
141
142 private @NonNull SortOption fSortOption = SortOption.BY_NAME;
143 private @NonNull Comparator<ITimeGraphEntry> fThreadComparator = new ThreadNameComparator(false);
144 private Action fSortByNameAction;
145 private Action fSortByIdAction;
146 private Action fSortByTimeAction;
147
148 // ------------------------------------------------------------------------
149 // Fields
150 // ------------------------------------------------------------------------
151
152 private final Map<ITmfTrace, ISymbolProvider> fSymbolProviders = new HashMap<>();
153
154 // The next event action
155 private Action fNextEventAction;
156
157 // The previous event action
158 private Action fPrevEventAction;
159
160 // The next item action
161 private Action fNextItemAction;
162
163 // The previous item action
164 private Action fPreviousItemAction;
165
166 // The action to import a binary file mapping */
167 private Action fConfigureSymbolsAction;
168
169 // The saved time sync. signal used when switching off the pinning of a view
170 private TmfSelectionRangeUpdatedSignal fSavedTimeSyncSignal;
171
172 // The saved window range signal used when switching off the pinning of
173 // a view
174 private TmfWindowRangeUpdatedSignal fSavedRangeSyncSignal;
175
176 // ------------------------------------------------------------------------
177 // Classes
178 // ------------------------------------------------------------------------
179
180 private static class TraceEntry extends TimeGraphEntry {
181 public TraceEntry(String name, long startTime, long endTime) {
182 super(name, startTime, endTime);
183 }
184
185 @Override
186 public boolean hasTimeEvents() {
187 return false;
188 }
189 }
190
191 private static class ThreadEntry extends TimeGraphEntry {
192 // The call stack quark
193 private final int fCallStackQuark;
194 // The state system from which this entry comes
195 private final ITmfStateSystem fSS;
196 // The thread id
197 private final long fThreadId;
198
199 public ThreadEntry(ITmfStateSystem ss, String name, long threadId, int callStackQuark, long startTime, long endTime) {
200 super(name, startTime, endTime);
201 fCallStackQuark = callStackQuark;
202 fThreadId = threadId;
203 fSS = ss;
204 }
205
206 @Override
207 public boolean hasTimeEvents() {
208 return false;
209 }
210
211 public int getCallStackQuark() {
212 return fCallStackQuark;
213 }
214
215 public long getThreadId() {
216 return fThreadId;
217 }
218
219 @Nullable
220 public ITmfStateSystem getStateSystem() {
221 return fSS;
222 }
223 }
224
225 private class CallStackComparator implements Comparator<ITimeGraphEntry> {
226 @Override
227 public int compare(ITimeGraphEntry o1, ITimeGraphEntry o2) {
228 if (o1 instanceof ThreadEntry && o2 instanceof ThreadEntry) {
229 return fThreadComparator.compare(o1, o2);
230 }
231 return 0;
232 }
233 }
234
235 private static class ThreadNameComparator implements Comparator<ITimeGraphEntry> {
236 private boolean reverse;
237
238 public ThreadNameComparator(boolean reverse) {
239 this.reverse = reverse;
240 }
241
242 @Override
243 public int compare(ITimeGraphEntry o1, ITimeGraphEntry o2) {
244 return reverse ? o2.getName().compareTo(o1.getName()) :
245 o1.getName().compareTo(o2.getName());
246 }
247 }
248
249 private static class ThreadIdComparator implements Comparator<ITimeGraphEntry> {
250 private boolean reverse;
251
252 public ThreadIdComparator(boolean reverse) {
253 this.reverse = reverse;
254 }
255
256 @Override
257 public int compare(ITimeGraphEntry o1, ITimeGraphEntry o2) {
258 ThreadEntry t1 = (ThreadEntry) o1;
259 ThreadEntry t2 = (ThreadEntry) o2;
260 return reverse ? Long.compare(t2.getThreadId(), t1.getThreadId()) :
261 Long.compare(t1.getThreadId(), t2.getThreadId());
262 }
263 }
264
265 private static class ThreadTimeComparator implements Comparator<ITimeGraphEntry> {
266 private boolean reverse;
267
268 public ThreadTimeComparator(boolean reverse) {
269 this.reverse = reverse;
270 }
271
272 @Override
273 public int compare(ITimeGraphEntry o1, ITimeGraphEntry o2) {
274 return reverse ? Long.compare(o2.getStartTime(), o1.getStartTime()) :
275 Long.compare(o1.getStartTime(), o2.getStartTime());
276 }
277 }
278
279 private static class CallStackTreeLabelProvider extends TreeLabelProvider {
280
281 @Override
282 public Image getColumnImage(Object element, int columnIndex) {
283 if (columnIndex == 0) {
284 if (element instanceof ThreadEntry) {
285 return THREAD_IMAGE;
286 } else if (element instanceof CallStackEntry) {
287 CallStackEntry entry = (CallStackEntry) element;
288 if (entry.getFunctionName().length() > 0) {
289 return STACKFRAME_IMAGE;
290 }
291 }
292 }
293 return null;
294 }
295
296 @Override
297 public String getColumnText(Object element, int columnIndex) {
298 if (element instanceof CallStackEntry) {
299 CallStackEntry entry = (CallStackEntry) element;
300 if (columnIndex == 0) {
301 return entry.getFunctionName();
302 } else if (columnIndex == 1 && entry.getFunctionName().length() > 0) {
303 int depth = entry.getStackLevel();
304 return Integer.toString(depth);
305 } else if (columnIndex == 2 && entry.getFunctionName().length() > 0) {
306 ITmfTimestamp ts = new TmfTimestamp(entry.getFunctionEntryTime(), ITmfTimestamp.NANOSECOND_SCALE);
307 return ts.toString();
308 } else if (columnIndex == 3 && entry.getFunctionName().length() > 0) {
309 ITmfTimestamp ts = new TmfTimestamp(entry.getFunctionExitTime(), ITmfTimestamp.NANOSECOND_SCALE);
310 return ts.toString();
311 } else if (columnIndex == 4 && entry.getFunctionName().length() > 0) {
312 ITmfTimestamp ts = new TmfTimestampDelta(entry.getFunctionExitTime() - entry.getFunctionEntryTime(), ITmfTimestamp.NANOSECOND_SCALE);
313 return ts.toString();
314 }
315 } else if (element instanceof ITimeGraphEntry) {
316 if (columnIndex == 0) {
317 return ((ITimeGraphEntry) element).getName();
318 }
319 }
320 return ""; //$NON-NLS-1$
321 }
322
323 }
324
325 private class CallStackFilterContentProvider extends TimeGraphContentProvider {
326 @Override
327 public boolean hasChildren(Object element) {
328 if (element instanceof TraceEntry) {
329 return super.hasChildren(element);
330 }
331 return false;
332 }
333
334 @Override
335 public ITimeGraphEntry[] getChildren(Object parentElement) {
336 if (parentElement instanceof TraceEntry) {
337 return super.getChildren(parentElement);
338 }
339 return new ITimeGraphEntry[0];
340 }
341 }
342
343 // ------------------------------------------------------------------------
344 // Constructors
345 // ------------------------------------------------------------------------
346
347 /**
348 * Default constructor
349 */
350 public CallStackView() {
351 super(ID, new CallStackPresentationProvider());
352 ((CallStackPresentationProvider) getPresentationProvider()).setCallStackView(this);
353 setTreeColumns(COLUMN_NAMES);
354 setTreeLabelProvider(new CallStackTreeLabelProvider());
355 setEntryComparator(new CallStackComparator());
356 setFilterColumns(FILTER_COLUMN_NAMES);
357 setFilterContentProvider(new CallStackFilterContentProvider());
358 setFilterLabelProvider(new CallStackTreeLabelProvider());
359 }
360
361 // ------------------------------------------------------------------------
362 // ViewPart
363 // ------------------------------------------------------------------------
364
365 @Override
366 public void createPartControl(Composite parent) {
367 super.createPartControl(parent);
368
369 getTimeGraphViewer().addTimeListener(new ITimeGraphTimeListener() {
370 @Override
371 public void timeSelected(TimeGraphTimeEvent event) {
372 synchingToTime(event.getBeginTime());
373 }
374 });
375
376 getTimeGraphCombo().getTreeViewer().addDoubleClickListener(new IDoubleClickListener() {
377 @Override
378 public void doubleClick(DoubleClickEvent event) {
379 Object selection = ((IStructuredSelection) event.getSelection()).getFirstElement();
380 if (selection instanceof CallStackEntry) {
381 CallStackEntry entry = (CallStackEntry) selection;
382 if (entry.getFunctionName().length() > 0) {
383 long entryTime = entry.getFunctionEntryTime();
384 long exitTime = entry.getFunctionExitTime();
385 long spacingTime = (long) ((exitTime - entryTime) * SPACING_RATIO);
386 entryTime -= spacingTime;
387 exitTime += spacingTime;
388 TmfTimeRange range = new TmfTimeRange(new TmfNanoTimestamp(entryTime), new TmfNanoTimestamp(exitTime));
389 broadcast(new TmfWindowRangeUpdatedSignal(CallStackView.this, range));
390 getTimeGraphViewer().setStartFinishTime(entryTime, exitTime);
391 startZoomThread(entryTime, exitTime);
392 }
393 }
394 }
395 });
396
397 getTimeGraphViewer().getTimeGraphControl().addMouseListener(new MouseAdapter() {
398 @Override
399 public void mouseDoubleClick(MouseEvent e) {
400 TimeGraphControl timeGraphControl = getTimeGraphViewer().getTimeGraphControl();
401 ISelection selection = timeGraphControl.getSelection();
402 if (selection instanceof TimeGraphSelection) {
403 Object o = ((TimeGraphSelection) selection).getFirstElement();
404 if (o instanceof CallStackEvent) {
405 CallStackEvent event = (CallStackEvent) o;
406 long startTime = event.getTime();
407 long endTime = startTime + event.getDuration();
408 long spacingTime = (long) ((endTime - startTime) * SPACING_RATIO);
409 startTime -= spacingTime;
410 endTime += spacingTime;
411 TmfTimeRange range = new TmfTimeRange(new TmfNanoTimestamp(startTime), new TmfNanoTimestamp(endTime));
412 broadcast(new TmfWindowRangeUpdatedSignal(CallStackView.this, range));
413 getTimeGraphViewer().setStartFinishTime(startTime, endTime);
414 startZoomThread(startTime, endTime);
415 }
416 }
417 }
418 });
419
420 contributeToActionBars();
421 loadSortOption();
422
423 IEditorPart editor = getSite().getPage().getActiveEditor();
424 if (editor instanceof ITmfTraceEditor) {
425 ITmfTrace trace = ((ITmfTraceEditor) editor).getTrace();
426 if (trace != null) {
427 traceSelected(new TmfTraceSelectedSignal(this, trace));
428 }
429 }
430 }
431
432 /**
433 * Handler for the selection range signal.
434 *
435 * @param signal
436 * The incoming signal
437 * @since 1.0
438 */
439 @Override
440 @TmfSignalHandler
441 public void selectionRangeUpdated(final TmfSelectionRangeUpdatedSignal signal) {
442
443 fSavedTimeSyncSignal = isPinned() ? new TmfSelectionRangeUpdatedSignal(signal.getSource(), signal.getBeginTime(), signal.getEndTime()) : null;
444
445 if (signal.getSource() == this || getTrace() == null || isPinned()) {
446 return;
447 }
448 final long beginTime = signal.getBeginTime().toNanos();
449 final long endTime = signal.getEndTime().toNanos();
450 Display.getDefault().asyncExec(new Runnable() {
451 @Override
452 public void run() {
453 if (getTimeGraphCombo().isDisposed()) {
454 return;
455 }
456 if (beginTime == endTime) {
457 getTimeGraphViewer().setSelectedTime(beginTime, true);
458 } else {
459 getTimeGraphViewer().setSelectionRange(beginTime, endTime, true);
460 }
461 synchingToTime(beginTime);
462 startZoomThread(getTimeGraphViewer().getTime0(), getTimeGraphViewer().getTime1());
463 List<TimeGraphEntry> entryList = getEntryList(getTrace());
464 if (entryList == null) {
465 return;
466 }
467 TimeGraphViewer viewer = getTimeGraphViewer();
468 for (TimeGraphEntry traceEntry : entryList) {
469 for (ITimeGraphEntry child : traceEntry.getChildren()) {
470 ThreadEntry threadEntry = (ThreadEntry) child;
471 ITmfStateSystem ss = threadEntry.getStateSystem();
472 if (ss == null || beginTime < ss.getStartTime() || beginTime > ss.getCurrentEndTime()) {
473 continue;
474 }
475 try {
476 int quark = threadEntry.getCallStackQuark();
477 ITmfStateInterval stackInterval = ss.querySingleState(beginTime, quark);
478 if (beginTime == stackInterval.getStartTime()) {
479 int stackLevel = stackInterval.getStateValue().unboxInt();
480 ITimeGraphEntry selectedEntry = threadEntry.getChildren().get(Math.max(0, stackLevel - 1));
481 getTimeGraphCombo().setSelection(selectedEntry);
482 viewer.getTimeGraphControl().fireSelectionChanged();
483 break;
484 }
485 } catch (AttributeNotFoundException | TimeRangeException | StateSystemDisposedException | StateValueTypeException e) {
486 Activator.getDefault().logError("Error querying state system", e); //$NON-NLS-1$
487 }
488 }
489 }
490 }
491 });
492 }
493
494 // ------------------------------------------------------------------------
495 // Internal
496 // ------------------------------------------------------------------------
497
498 @Override
499 @TmfSignalHandler
500 public void traceClosed(TmfTraceClosedSignal signal) {
501 super.traceClosed(signal);
502 synchronized(fSymbolProviders){
503 for(ITmfTrace trace : getTracesToBuild(signal.getTrace())){
504 fSymbolProviders.remove(trace);
505 }
506 }
507 }
508
509 /**
510 * @since 2.0
511 */
512 @Override
513 protected void refresh() {
514 super.refresh();
515 updateConfigureSymbolsAction();
516 }
517
518 @Override
519 protected void buildEventList(final ITmfTrace trace, final ITmfTrace parentTrace, final IProgressMonitor monitor) {
520 if (monitor.isCanceled()) {
521 return;
522 }
523 AbstractCallStackAnalysis module = getCallStackModule(trace);
524 if (module == null) {
525 addUnavailableEntry(trace, parentTrace);
526 return;
527 }
528 ITmfStateSystem ss = module.getStateSystem();
529 if (ss == null) {
530 addUnavailableEntry(trace, parentTrace);
531 return;
532 }
533
534 Map<ITmfTrace, TraceEntry> traceEntryMap = new HashMap<>();
535 Map<Integer, ThreadEntry> threadEntryMap = new HashMap<>();
536 String[] threadPaths = module.getThreadsPattern();
537
538 long start = ss.getStartTime();
539
540 boolean complete = false;
541 while (!complete) {
542 if (monitor.isCanceled()) {
543 return;
544 }
545 complete = ss.waitUntilBuilt(BUILD_UPDATE_TIMEOUT);
546 if (ss.isCancelled()) {
547 return;
548 }
549 long end = ss.getCurrentEndTime();
550 if (start == end && !complete) { // when complete execute one last time regardless of end time
551 continue;
552 }
553
554 ISymbolProvider provider = fSymbolProviders.get(trace);
555 if (provider == null) {
556 provider = SymbolProviderManager.getInstance().getSymbolProvider(trace);
557 provider.loadConfiguration(monitor);
558 fSymbolProviders.put(trace, provider);
559 }
560
561 getConfigureSymbolsAction().setEnabled(true);
562
563 List<Integer> threadQuarks = ss.getQuarks(threadPaths);
564 TraceEntry traceEntry = traceEntryMap.get(trace);
565 if (traceEntry == null) {
566 traceEntry = new TraceEntry(trace.getName(), start, end + 1);
567 traceEntryMap.put(trace, traceEntry);
568 traceEntry.sortChildren(fThreadComparator);
569 addToEntryList(parentTrace, Collections.singletonList(traceEntry));
570 } else {
571 traceEntry.updateEndTime(end);
572 }
573 for (int i = 0; i < threadQuarks.size(); i++) {
574 if (monitor.isCanceled()) {
575 return;
576 }
577 int threadQuark = threadQuarks.get(i);
578 try {
579 String[] callStackPath = module.getCallStackPath();
580 int callStackQuark = ss.getQuarkRelative(threadQuark, callStackPath);
581 String threadName = ss.getAttributeName(threadQuark);
582 long threadEnd = end + 1;
583 ITmfStateInterval endInterval = ss.querySingleState(ss.getCurrentEndTime(), callStackQuark);
584 if (endInterval.getStateValue().isNull() && endInterval.getStartTime() != ss.getStartTime()) {
585 threadEnd = endInterval.getStartTime();
586 }
587 ThreadEntry threadEntry = threadEntryMap.get(threadQuark);
588 if (threadEntry == null) {
589 long threadId = ss.querySingleState(ss.getCurrentEndTime(), threadQuark).getStateValue().unboxLong();
590 long threadStart = start;
591 ITmfStateInterval startInterval = ss.querySingleState(start, callStackQuark);
592 if (startInterval.getStateValue().isNull()) {
593 threadStart = Math.min(startInterval.getEndTime() + 1, end + 1);
594 }
595 threadEntry = new ThreadEntry(ss, threadName, threadId, callStackQuark, threadStart, threadEnd);
596 threadEntryMap.put(threadQuark, threadEntry);
597 traceEntry.addChild(threadEntry);
598 } else {
599 threadEntry.updateEndTime(threadEnd);
600 }
601 int level = 1;
602 for (int stackLevelQuark : ss.getSubAttributes(callStackQuark, false)) {
603 if (level > threadEntry.getChildren().size()) {
604 CallStackEntry callStackEntry = new CallStackEntry(threadName, stackLevelQuark, level, trace, ss);
605 threadEntry.addChild(callStackEntry);
606 }
607 level++;
608 }
609 } catch (AttributeNotFoundException e) {
610 Activator.getDefault().logError("Error querying state system", e); //$NON-NLS-1$
611 } catch (StateSystemDisposedException e) {
612 /* Ignored */
613 }
614 }
615 if (parentTrace == getTrace()) {
616 synchronized (this) {
617 setStartTime(getStartTime() == SWT.DEFAULT ? start : Math.min(getStartTime(), start));
618 setEndTime(getEndTime() == SWT.DEFAULT ? end + 1 : Math.max(getEndTime(), end + 1));
619 }
620 synchingToTime(getTimeGraphViewer().getSelectionBegin());
621 refresh();
622 }
623 for (ITimeGraphEntry threadEntry : traceEntry.getChildren()) {
624 for (ITimeGraphEntry callStackEntry : threadEntry.getChildren()) {
625 if (monitor.isCanceled()) {
626 return;
627 }
628 buildStatusEvents(parentTrace, (CallStackEntry) callStackEntry, monitor, start, end);
629 }
630 }
631 start = end;
632 }
633 }
634
635 private void addUnavailableEntry(ITmfTrace trace, ITmfTrace parentTrace) {
636 String name = Messages.CallStackView_StackInfoNotAvailable + ' ' + '(' + trace.getName() + ')';
637 TraceEntry unavailableEntry = new TraceEntry(name, 0, 0);
638 addToEntryList(parentTrace, Collections.singletonList(unavailableEntry));
639 if (parentTrace == getTrace()) {
640 refresh();
641 }
642 }
643
644 private void buildStatusEvents(ITmfTrace trace, CallStackEntry entry, @NonNull IProgressMonitor monitor, long start, long end) {
645 ITmfStateSystem ss = entry.getStateSystem();
646 long resolution = Math.max(1, (end - ss.getStartTime()) / getDisplayWidth());
647 List<ITimeEvent> eventList = getEventList(entry, start, end + 1, resolution, monitor);
648 if (eventList != null) {
649 for (ITimeEvent event : eventList) {
650 entry.addEvent(event);
651 }
652 }
653 if (trace == getTrace()) {
654 redraw();
655 }
656 }
657
658 /**
659 * @since 2.0
660 */
661 @Override
662 protected final List<ITimeEvent> getEventList(TimeGraphEntry tgentry, long startTime, long endTime, long resolution, IProgressMonitor monitor) {
663 if (!(tgentry instanceof CallStackEntry)) {
664 return null;
665 }
666 CallStackEntry entry = (CallStackEntry) tgentry;
667 ITmfStateSystem ss = entry.getStateSystem();
668 long start = Math.max(startTime, ss.getStartTime());
669 long end = Math.min(endTime, ss.getCurrentEndTime() + 1);
670 if (end <= start) {
671 return null;
672 }
673 List<ITimeEvent> eventList = null;
674 try {
675 List<ITmfStateInterval> stackIntervals = StateSystemUtils.queryHistoryRange(ss, entry.getQuark(), start, end - 1, resolution, monitor);
676 eventList = new ArrayList<>(stackIntervals.size());
677 long lastEndTime = -1;
678 boolean lastIsNull = true;
679 for (ITmfStateInterval statusInterval : stackIntervals) {
680 if (monitor.isCanceled()) {
681 return null;
682 }
683 long time = statusInterval.getStartTime();
684 long duration = statusInterval.getEndTime() - time + 1;
685 if (!statusInterval.getStateValue().isNull()) {
686 final int modulo = CallStackPresentationProvider.NUM_COLORS / 2;
687 int value = statusInterval.getStateValue().toString().hashCode() % modulo + modulo;
688 eventList.add(new CallStackEvent(entry, time, duration, value));
689 lastIsNull = false;
690 } else {
691 if (lastEndTime == -1) {
692 // add null event if it intersects the start time
693 eventList.add(new NullTimeEvent(entry, time, duration));
694 } else {
695 if (lastEndTime != time && lastIsNull) {
696 // add unknown event if between two null states
697 eventList.add(new TimeEvent(entry, lastEndTime, time - lastEndTime));
698 }
699 if (time + duration >= endTime) {
700 // add null event if it intersects the end time
701 eventList.add(new NullTimeEvent(entry, time, duration));
702 }
703 }
704 lastIsNull = true;
705 }
706 lastEndTime = time + duration;
707 }
708 } catch (AttributeNotFoundException e) {
709 Activator.getDefault().logError("Error querying state system", e); //$NON-NLS-1$
710 } catch (TimeRangeException e) {
711 Activator.getDefault().logError("Error querying state system", e); //$NON-NLS-1$
712 } catch (StateSystemDisposedException e) {
713 /* Ignored */
714 }
715 return eventList;
716 }
717
718 /**
719 * @since 2.0
720 */
721 @Override
722 protected void synchingToTime(long time) {
723 List<TimeGraphEntry> entryList = getEntryList(getTrace());
724 if (entryList == null) {
725 return;
726 }
727 for (TimeGraphEntry traceEntry : entryList) {
728 for (ITimeGraphEntry threadEntry : traceEntry.getChildren()) {
729 ITmfStateSystem ss = ((ThreadEntry) threadEntry).getStateSystem();
730 if (ss == null) {
731 continue;
732 }
733 if (ss.isCancelled()) {
734 continue;
735 }
736 if (time < ss.getStartTime() || time > ss.getCurrentEndTime()) {
737 continue;
738 }
739 for (ITimeGraphEntry child : threadEntry.getChildren()) {
740 CallStackEntry callStackEntry = (CallStackEntry) child;
741 ITmfTrace trace = callStackEntry.getTrace();
742 try {
743 ITmfStateInterval stackLevelInterval = ss.querySingleState(time, callStackEntry.getQuark());
744 ITmfStateValue nameValue = stackLevelInterval.getStateValue();
745 String name = getFunctionName(trace, nameValue);
746 callStackEntry.setFunctionName(name);
747 if (name.length() > 0) {
748 callStackEntry.setFunctionEntryTime(stackLevelInterval.getStartTime());
749 callStackEntry.setFunctionExitTime(stackLevelInterval.getEndTime() + 1);
750 }
751 } catch (AttributeNotFoundException e) {
752 Activator.getDefault().logError("Error querying state system", e); //$NON-NLS-1$
753 } catch (StateSystemDisposedException e) {
754 /* Ignored */
755 }
756 }
757 }
758 }
759 if (Display.getCurrent() != null) {
760 getTimeGraphCombo().refresh();
761 }
762 }
763
764 String getFunctionName(ITmfTrace trace, ITmfStateValue nameValue) {
765 long address = Long.MAX_VALUE;
766 String name = ""; //$NON-NLS-1$
767 try {
768 if (nameValue.getType() == Type.STRING) {
769 name = nameValue.unboxStr();
770 try {
771 address = Long.parseLong(name, 16);
772 } catch (NumberFormatException e) {
773 // ignore
774 }
775 } else if (nameValue.getType() == Type.INTEGER) {
776 name = "0x" + Integer.toHexString(nameValue.unboxInt()); //$NON-NLS-1$
777 address = nameValue.unboxInt();
778 } else if (nameValue.getType() == Type.LONG) {
779 name = "0x" + Long.toHexString(nameValue.unboxLong()); //$NON-NLS-1$
780 address = nameValue.unboxLong();
781 }
782 } catch (StateValueTypeException e) {
783 }
784 if (address != Long.MAX_VALUE) {
785 ISymbolProvider provider = fSymbolProviders.get(trace);
786 if (provider != null) {
787 String symbol = provider.getSymbolText(address);
788 if (symbol != null) {
789 name = symbol;
790 }
791 }
792 }
793 return name;
794 }
795
796 private void makeActions() {
797 fPreviousItemAction = getTimeGraphViewer().getPreviousItemAction();
798 fPreviousItemAction.setText(Messages.TmfTimeGraphViewer_PreviousItemActionNameText);
799 fPreviousItemAction.setToolTipText(Messages.TmfTimeGraphViewer_PreviousItemActionToolTipText);
800 fNextItemAction = getTimeGraphViewer().getNextItemAction();
801 fNextItemAction.setText(Messages.TmfTimeGraphViewer_NextItemActionNameText);
802 fNextItemAction.setToolTipText(Messages.TmfTimeGraphViewer_NextItemActionToolTipText);
803 }
804
805 private void contributeToActionBars() {
806 // Create pin action
807 contributePinActionToToolBar();
808 fPinAction.addPropertyChangeListener(new IPropertyChangeListener() {
809 @Override
810 public void propertyChange(PropertyChangeEvent event) {
811 if (IAction.CHECKED.equals(event.getProperty()) && !isPinned()) {
812 if (fSavedRangeSyncSignal != null) {
813 windowRangeUpdated(fSavedRangeSyncSignal);
814 fSavedRangeSyncSignal = null;
815 }
816
817 if (fSavedTimeSyncSignal != null) {
818 selectionRangeUpdated(fSavedTimeSyncSignal);
819 fSavedTimeSyncSignal = null;
820 }
821 }
822 }
823 });
824 }
825
826 /**
827 * @since 2.0
828 */
829 @Override
830 protected void fillLocalToolBar(IToolBarManager manager) {
831 makeActions();
832 manager.add(getConfigureSymbolsAction());
833 manager.add(new Separator());
834 manager.add(getSortByNameAction());
835 manager.add(getSortByIdAction());
836 manager.add(getSortByTimeAction());
837 manager.add(new Separator());
838 manager.add(getTimeGraphCombo().getShowFilterDialogAction());
839 manager.add(new Separator());
840 manager.add(getTimeGraphViewer().getResetScaleAction());
841 manager.add(getPreviousEventAction());
842 manager.add(getNextEventAction());
843 manager.add(new Separator());
844 manager.add(getTimeGraphViewer().getToggleBookmarkAction());
845 manager.add(getTimeGraphViewer().getPreviousMarkerAction());
846 manager.add(getTimeGraphViewer().getNextMarkerAction());
847 manager.add(new Separator());
848 manager.add(fPreviousItemAction);
849 manager.add(fNextItemAction);
850 manager.add(getTimeGraphViewer().getZoomInAction());
851 manager.add(getTimeGraphViewer().getZoomOutAction());
852 }
853
854 /**
855 * @since 2.0
856 */
857 @Override
858 protected void fillTimeGraphEntryContextMenu(IMenuManager contextMenu) {
859 contextMenu.add(new GroupMarker(IWorkbenchActionConstants.GROUP_REORGANIZE));
860 contextMenu.add(getSortByNameAction());
861 contextMenu.add(getSortByIdAction());
862 contextMenu.add(getSortByTimeAction());
863 }
864
865 /**
866 * Get the the next event action.
867 *
868 * @return The action object
869 */
870 private Action getNextEventAction() {
871 if (fNextEventAction == null) {
872 fNextEventAction = new Action() {
873 @Override
874 public void run() {
875 TimeGraphViewer viewer = getTimeGraphViewer();
876 ITimeGraphEntry entry = viewer.getSelection();
877 if (entry instanceof CallStackEntry) {
878 try {
879 CallStackEntry callStackEntry = (CallStackEntry) entry;
880 ITmfStateSystem ss = callStackEntry.getStateSystem();
881 long time = Math.max(ss.getStartTime(), Math.min(ss.getCurrentEndTime(), viewer.getSelectionBegin()));
882 ThreadEntry threadEntry = (ThreadEntry) callStackEntry.getParent();
883 int quark = ss.getParentAttributeQuark(callStackEntry.getQuark());
884 ITmfStateInterval stackInterval = ss.querySingleState(time, quark);
885 long newTime = stackInterval.getEndTime() + 1;
886 viewer.setSelectedTimeNotify(newTime, true);
887 stackInterval = ss.querySingleState(Math.min(ss.getCurrentEndTime(), newTime), quark);
888 int stackLevel = stackInterval.getStateValue().unboxInt();
889 ITimeGraphEntry selectedEntry = threadEntry.getChildren().get(Math.max(0, stackLevel - 1));
890 getTimeGraphCombo().setSelection(selectedEntry);
891 viewer.getTimeGraphControl().fireSelectionChanged();
892 startZoomThread(viewer.getTime0(), viewer.getTime1());
893
894 } catch (AttributeNotFoundException | TimeRangeException | StateSystemDisposedException | StateValueTypeException e) {
895 Activator.getDefault().logError("Error querying state system", e); //$NON-NLS-1$
896 }
897 }
898 }
899 };
900
901 fNextEventAction.setText(Messages.TmfTimeGraphViewer_NextEventActionNameText);
902 fNextEventAction.setToolTipText(Messages.TmfTimeGraphViewer_NextEventActionToolTipText);
903 fNextEventAction.setImageDescriptor(Activator.getDefault().getImageDescripterFromPath(ITmfImageConstants.IMG_UI_NEXT_EVENT));
904 }
905
906 return fNextEventAction;
907 }
908
909 /**
910 * Get the previous event action.
911 *
912 * @return The Action object
913 */
914 private Action getPreviousEventAction() {
915 if (fPrevEventAction == null) {
916 fPrevEventAction = new Action() {
917 @Override
918 public void run() {
919 TimeGraphViewer viewer = getTimeGraphCombo().getTimeGraphViewer();
920 ITimeGraphEntry entry = viewer.getSelection();
921 if (entry instanceof CallStackEntry) {
922 try {
923 CallStackEntry callStackEntry = (CallStackEntry) entry;
924 ITmfStateSystem ss = callStackEntry.getStateSystem();
925 long time = Math.max(ss.getStartTime(), Math.min(ss.getCurrentEndTime(), viewer.getSelectionBegin()));
926 ThreadEntry threadEntry = (ThreadEntry) callStackEntry.getParent();
927 int quark = ss.getParentAttributeQuark(callStackEntry.getQuark());
928 ITmfStateInterval stackInterval = ss.querySingleState(time, quark);
929 if (stackInterval.getStartTime() == time && time > ss.getStartTime()) {
930 stackInterval = ss.querySingleState(time - 1, quark);
931 }
932 viewer.setSelectedTimeNotify(stackInterval.getStartTime(), true);
933 int stackLevel = stackInterval.getStateValue().unboxInt();
934 ITimeGraphEntry selectedEntry = threadEntry.getChildren().get(Math.max(0, stackLevel - 1));
935 getTimeGraphCombo().setSelection(selectedEntry);
936 viewer.getTimeGraphControl().fireSelectionChanged();
937 startZoomThread(viewer.getTime0(), viewer.getTime1());
938
939 } catch (AttributeNotFoundException | TimeRangeException | StateSystemDisposedException | StateValueTypeException e) {
940 Activator.getDefault().logError("Error querying state system", e); //$NON-NLS-1$
941 }
942 }
943 }
944 };
945
946 fPrevEventAction.setText(Messages.TmfTimeGraphViewer_PreviousEventActionNameText);
947 fPrevEventAction.setToolTipText(Messages.TmfTimeGraphViewer_PreviousEventActionToolTipText);
948 fPrevEventAction.setImageDescriptor(Activator.getDefault().getImageDescripterFromPath(ITmfImageConstants.IMG_UI_PREV_EVENT));
949 }
950
951 return fPrevEventAction;
952 }
953
954 private static @Nullable AbstractCallStackAnalysis getCallStackModule(@NonNull ITmfTrace trace) {
955 /*
956 * Since we cannot know the exact analysis ID (in separate plugins), we
957 * will search using the analysis type.
958 */
959 Iterable<AbstractCallStackAnalysis> modules =
960 TmfTraceUtils.getAnalysisModulesOfClass(trace, AbstractCallStackAnalysis.class);
961 Iterator<AbstractCallStackAnalysis> it = modules.iterator();
962 if (!it.hasNext()) {
963 /* This trace does not provide a call-stack analysis */
964 return null;
965 }
966
967 /*
968 * We only look at the first module we find.
969 *
970 * TODO Handle the advanced case where one trace provides more than one
971 * call-stack analysis.
972 */
973 AbstractCallStackAnalysis module = it.next();
974 /* This analysis is not automatic, we need to schedule it on-demand */
975 module.schedule();
976 if (!module.waitForInitialization()) {
977 /* The initialization did not succeed */
978 return null;
979 }
980 return module;
981 }
982
983 // ------------------------------------------------------------------------
984 // Methods related to function name mapping
985 // ------------------------------------------------------------------------
986
987 private Action getSortByNameAction() {
988 if (fSortByNameAction == null) {
989 fSortByNameAction = new Action(Messages.CallStackView_SortByThreadName, IAction.AS_CHECK_BOX) {
990 @Override
991 public void run() {
992 if (fSortOption == SortOption.BY_NAME) {
993 saveSortOption(SortOption.BY_NAME_REV);
994 } else {
995 saveSortOption(SortOption.BY_NAME);
996 }
997 }
998 };
999 fSortByNameAction.setToolTipText(Messages.CallStackView_SortByThreadName);
1000 fSortByNameAction.setImageDescriptor(SORT_BY_NAME_ICON);
1001 }
1002 return fSortByNameAction;
1003 }
1004
1005 private Action getSortByIdAction() {
1006 if (fSortByIdAction == null) {
1007 fSortByIdAction = new Action(Messages.CallStackView_SortByThreadId, IAction.AS_CHECK_BOX) {
1008 @Override
1009 public void run() {
1010 if (fSortOption == SortOption.BY_ID) {
1011 saveSortOption(SortOption.BY_ID_REV);
1012 } else {
1013 saveSortOption(SortOption.BY_ID);
1014 }
1015 }
1016 };
1017 fSortByIdAction.setToolTipText(Messages.CallStackView_SortByThreadId);
1018 fSortByIdAction.setImageDescriptor(SORT_BY_ID_ICON);
1019 }
1020 return fSortByIdAction;
1021 }
1022
1023 private Action getSortByTimeAction() {
1024 if (fSortByTimeAction == null) {
1025 fSortByTimeAction = new Action(Messages.CallStackView_SortByThreadTime, IAction.AS_CHECK_BOX) {
1026 @Override
1027 public void run() {
1028 if (fSortOption == SortOption.BY_TIME) {
1029 saveSortOption(SortOption.BY_TIME_REV);
1030 } else {
1031 saveSortOption(SortOption.BY_TIME);
1032 }
1033 }
1034 };
1035 fSortByTimeAction.setToolTipText(Messages.CallStackView_SortByThreadTime);
1036 fSortByTimeAction.setImageDescriptor(SORT_BY_TIME_ICON);
1037 }
1038 return fSortByTimeAction;
1039 }
1040
1041 private void loadSortOption() {
1042 IDialogSettings settings = Activator.getDefault().getDialogSettings();
1043 IDialogSettings section = settings.getSection(getClass().getName());
1044 if (section == null) {
1045 return;
1046 }
1047 String sortOption = section.get(SORT_OPTION_KEY);
1048 if (sortOption == null) {
1049 return;
1050 }
1051
1052 // reset defaults
1053 getSortByNameAction().setChecked(false);
1054 getSortByNameAction().setImageDescriptor(SORT_BY_NAME_ICON);
1055 getSortByIdAction().setChecked(false);
1056 getSortByIdAction().setImageDescriptor(SORT_BY_ID_ICON);
1057 getSortByTimeAction().setChecked(false);
1058 getSortByTimeAction().setImageDescriptor(SORT_BY_TIME_ICON);
1059
1060 if (sortOption.equals(SortOption.BY_NAME.name())) {
1061 fSortOption = SortOption.BY_NAME;
1062 fThreadComparator = new ThreadNameComparator(false);
1063 getSortByNameAction().setChecked(true);
1064 } else if (sortOption.equals(SortOption.BY_NAME_REV.name())) {
1065 fSortOption = SortOption.BY_NAME_REV;
1066 fThreadComparator = new ThreadNameComparator(true);
1067 getSortByNameAction().setChecked(true);
1068 getSortByNameAction().setImageDescriptor(SORT_BY_NAME_REV_ICON);
1069 } else if (sortOption.equals(SortOption.BY_ID.name())) {
1070 fSortOption = SortOption.BY_ID;
1071 fThreadComparator = new ThreadIdComparator(false);
1072 getSortByIdAction().setChecked(true);
1073 } else if (sortOption.equals(SortOption.BY_ID_REV.name())) {
1074 fSortOption = SortOption.BY_ID_REV;
1075 fThreadComparator = new ThreadIdComparator(true);
1076 getSortByIdAction().setChecked(true);
1077 getSortByIdAction().setImageDescriptor(SORT_BY_ID_REV_ICON);
1078 } else if (sortOption.equals(SortOption.BY_TIME.name())) {
1079 fSortOption = SortOption.BY_TIME;
1080 fThreadComparator = new ThreadTimeComparator(false);
1081 getSortByTimeAction().setChecked(true);
1082 } else if (sortOption.equals(SortOption.BY_TIME_REV.name())) {
1083 fSortOption = SortOption.BY_TIME_REV;
1084 fThreadComparator = new ThreadTimeComparator(true);
1085 getSortByTimeAction().setChecked(true);
1086 getSortByTimeAction().setImageDescriptor(SORT_BY_TIME_REV_ICON);
1087 }
1088 }
1089
1090 private void saveSortOption(SortOption sortOption) {
1091 IDialogSettings settings = Activator.getDefault().getDialogSettings();
1092 IDialogSettings section = settings.getSection(getClass().getName());
1093 if (section == null) {
1094 section = settings.addNewSection(getClass().getName());
1095 }
1096 section.put(SORT_OPTION_KEY, sortOption.name());
1097 loadSortOption();
1098 List<TimeGraphEntry> entryList = getEntryList(getTrace());
1099 if (entryList == null) {
1100 return;
1101 }
1102 for (TimeGraphEntry traceEntry : entryList) {
1103 traceEntry.sortChildren(fThreadComparator);
1104 }
1105 refresh();
1106 }
1107
1108 private Action getConfigureSymbolsAction() {
1109 if (fConfigureSymbolsAction != null) {
1110 return fConfigureSymbolsAction;
1111 }
1112
1113 fConfigureSymbolsAction = new Action(Messages.CallStackView_ConfigureSymbolProvidersText) {
1114 @Override
1115 public void run() {
1116 SymbolProviderConfigDialog dialog = new SymbolProviderConfigDialog(getSite().getShell(), getProviderPages());
1117 if (dialog.open() == IDialogConstants.OK_ID) {
1118 refresh();
1119 }
1120 }
1121 };
1122
1123 fConfigureSymbolsAction.setToolTipText(Messages.CallStackView_ConfigureSymbolProvidersTooltip);
1124 fConfigureSymbolsAction.setImageDescriptor(Activator.getDefault().getImageDescripterFromPath(IMPORT_BINARY_ICON_PATH));
1125 fConfigureSymbolsAction.setEnabled(false);
1126
1127 return fConfigureSymbolsAction;
1128 }
1129
1130 /**
1131 * @return an array of {@link ISymbolProviderPreferencePage} that will
1132 * configure the current traces
1133 */
1134 private ISymbolProviderPreferencePage[] getProviderPages() {
1135 List<ISymbolProviderPreferencePage> pages = new ArrayList<>();
1136 ITmfTrace trace = getTrace();
1137 if (trace != null) {
1138 for (ITmfTrace subTrace : getTracesToBuild(trace)) {
1139 ISymbolProvider provider = fSymbolProviders.get(subTrace);
1140 if (provider != null) {
1141 ISymbolProviderPreferencePage page = provider.createPreferencePage();
1142 if (page != null) {
1143 pages.add(page);
1144 }
1145 }
1146 }
1147 }
1148 return pages.toArray(new ISymbolProviderPreferencePage[pages.size()]);
1149 }
1150
1151 /**
1152 * Update the enable status of the configure symbols action
1153 */
1154 private void updateConfigureSymbolsAction() {
1155 ISymbolProviderPreferencePage[] providerPages = getProviderPages();
1156 getConfigureSymbolsAction().setEnabled(providerPages.length > 0);
1157 }
1158
1159 }
This page took 0.06616 seconds and 6 git commands to generate.