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