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