Annotate often-used Collectors method
[deliverable/tracecompass.git] / tmf / org.eclipse.tracecompass.tmf.ui / src / org / eclipse / tracecompass / tmf / ui / views / callstack / CallStackView.java
CommitLineData
e8251298 1/*******************************************************************************
ed902a2b 2 * Copyright (c) 2013, 2015 Ericsson
e8251298
PT
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
fec1ac0b 11 * Bernd Hufmann - Updated signal handling
41d9ce5b 12 * Marc-Andre Laperle - Map from binary file
e8251298
PT
13 *******************************************************************************/
14
2bdf0193 15package org.eclipse.tracecompass.tmf.ui.views.callstack;
e8251298 16
1d83ed07
AM
17import static org.eclipse.tracecompass.common.core.NonNullUtils.checkNotNull;
18
5da83da5 19import java.io.File;
e8251298 20import java.util.ArrayList;
26c33ee2 21import java.util.Collections;
46cc1ade 22import java.util.Comparator;
e8251298
PT
23import java.util.HashMap;
24import java.util.Iterator;
25import java.util.List;
52974e38 26import java.util.Map;
26c33ee2 27import java.util.concurrent.CopyOnWriteArrayList;
e8251298
PT
28
29import org.eclipse.core.runtime.IProgressMonitor;
5da83da5 30import org.eclipse.core.runtime.IStatus;
e8251298 31import org.eclipse.core.runtime.NullProgressMonitor;
5da83da5
AM
32import org.eclipse.core.runtime.Status;
33import org.eclipse.core.runtime.jobs.Job;
1d83ed07 34import org.eclipse.jdt.annotation.NonNull;
50659279 35import org.eclipse.jdt.annotation.Nullable;
e8251298
PT
36import org.eclipse.jface.action.Action;
37import org.eclipse.jface.action.IAction;
0fcf3b09 38import org.eclipse.jface.action.IStatusLineManager;
e8251298 39import org.eclipse.jface.action.IToolBarManager;
46cc1ade 40import org.eclipse.jface.action.MenuManager;
e8251298 41import org.eclipse.jface.action.Separator;
46cc1ade
PT
42import org.eclipse.jface.dialogs.IDialogSettings;
43import org.eclipse.jface.resource.ImageDescriptor;
e8251298
PT
44import org.eclipse.jface.util.IPropertyChangeListener;
45import org.eclipse.jface.util.PropertyChangeEvent;
46import org.eclipse.jface.viewers.DoubleClickEvent;
47import org.eclipse.jface.viewers.IDoubleClickListener;
48import org.eclipse.jface.viewers.ILabelProviderListener;
49import org.eclipse.jface.viewers.ISelection;
50import org.eclipse.jface.viewers.IStructuredSelection;
51import org.eclipse.jface.viewers.ITableLabelProvider;
e8251298
PT
52import org.eclipse.swt.SWT;
53import org.eclipse.swt.events.ControlAdapter;
54import org.eclipse.swt.events.ControlEvent;
55import org.eclipse.swt.events.MouseAdapter;
56import org.eclipse.swt.events.MouseEvent;
57import org.eclipse.swt.graphics.Image;
58import org.eclipse.swt.widgets.Composite;
59import org.eclipse.swt.widgets.Display;
5da83da5 60import org.eclipse.swt.widgets.FileDialog;
46cc1ade
PT
61import org.eclipse.swt.widgets.Menu;
62import org.eclipse.swt.widgets.Tree;
318c06c9 63import org.eclipse.tracecompass.internal.tmf.core.callstack.FunctionNameMapper;
2bdf0193
AM
64import org.eclipse.tracecompass.internal.tmf.ui.Activator;
65import org.eclipse.tracecompass.internal.tmf.ui.ITmfImageConstants;
66import org.eclipse.tracecompass.internal.tmf.ui.Messages;
e894a508 67import org.eclipse.tracecompass.statesystem.core.ITmfStateSystem;
1dd75589 68import org.eclipse.tracecompass.statesystem.core.StateSystemUtils;
e894a508
AM
69import org.eclipse.tracecompass.statesystem.core.exceptions.AttributeNotFoundException;
70import org.eclipse.tracecompass.statesystem.core.exceptions.StateSystemDisposedException;
71import org.eclipse.tracecompass.statesystem.core.exceptions.StateValueTypeException;
72import org.eclipse.tracecompass.statesystem.core.exceptions.TimeRangeException;
73import org.eclipse.tracecompass.statesystem.core.interval.ITmfStateInterval;
74import org.eclipse.tracecompass.statesystem.core.statevalue.ITmfStateValue;
75import org.eclipse.tracecompass.statesystem.core.statevalue.ITmfStateValue.Type;
97c71024 76import org.eclipse.tracecompass.tmf.core.signal.TmfSelectionRangeUpdatedSignal;
17a54620 77import org.eclipse.tracecompass.tmf.core.signal.TmfSignalHandler;
2bdf0193
AM
78import org.eclipse.tracecompass.tmf.core.signal.TmfTraceClosedSignal;
79import org.eclipse.tracecompass.tmf.core.signal.TmfTraceOpenedSignal;
80import org.eclipse.tracecompass.tmf.core.signal.TmfTraceSelectedSignal;
17a54620 81import org.eclipse.tracecompass.tmf.core.signal.TmfWindowRangeUpdatedSignal;
2bdf0193
AM
82import org.eclipse.tracecompass.tmf.core.timestamp.ITmfTimestamp;
83import org.eclipse.tracecompass.tmf.core.timestamp.TmfNanoTimestamp;
84import org.eclipse.tracecompass.tmf.core.timestamp.TmfTimeRange;
85import org.eclipse.tracecompass.tmf.core.timestamp.TmfTimestamp;
86import org.eclipse.tracecompass.tmf.core.timestamp.TmfTimestampDelta;
87import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace;
21852dfa 88import org.eclipse.tracecompass.tmf.core.trace.TmfTraceContext;
2bdf0193 89import org.eclipse.tracecompass.tmf.core.trace.TmfTraceManager;
b8585c7c 90import org.eclipse.tracecompass.tmf.core.trace.TmfTraceUtils;
2bdf0193 91import org.eclipse.tracecompass.tmf.ui.editors.ITmfTraceEditor;
d2e4afa7
MAL
92import org.eclipse.tracecompass.tmf.ui.signal.TmfTimeViewAlignmentInfo;
93import org.eclipse.tracecompass.tmf.ui.views.ITmfTimeAligned;
2bdf0193 94import org.eclipse.tracecompass.tmf.ui.views.TmfView;
2bdf0193
AM
95import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.ITimeGraphRangeListener;
96import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.ITimeGraphTimeListener;
97import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.TimeGraphCombo;
d8a230f8 98import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.TimeGraphContentProvider;
2bdf0193
AM
99import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.TimeGraphRangeUpdateEvent;
100import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.TimeGraphTimeEvent;
101import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.TimeGraphViewer;
102import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.model.ITimeEvent;
103import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.model.ITimeGraphEntry;
104import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.model.NullTimeEvent;
105import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.model.TimeEvent;
106import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.model.TimeGraphEntry;
107import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.widgets.TimeGraphControl;
108import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.widgets.TimeGraphSelection;
109import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.widgets.Utils.TimeFormat;
e8251298
PT
110import org.eclipse.ui.IActionBars;
111import org.eclipse.ui.IEditorPart;
112
113/**
114 * Main implementation for the Call Stack view
115 *
116 * @author Patrick Tasse
e8251298 117 */
d2e4afa7 118public class CallStackView extends TmfView implements ITmfTimeAligned {
e8251298
PT
119
120 // ------------------------------------------------------------------------
121 // Constants
122 // ------------------------------------------------------------------------
123
124 /** View ID. */
125 public static final String ID = "org.eclipse.linuxtools.tmf.ui.views.callstack"; //$NON-NLS-1$
126
127 /**
128 * Redraw state enum
129 */
bac9c0df
MK
130 private enum State {
131 IDLE, BUSY, PENDING
132 }
e8251298 133
46cc1ade 134 private static final String[] COLUMN_TIMES = new String[] {
e8251298
PT
135 Messages.CallStackView_FunctionColumn,
136 Messages.CallStackView_DepthColumn,
137 Messages.CallStackView_EntryTimeColumn,
138 Messages.CallStackView_ExitTimeColumn,
139 Messages.CallStackView_DurationColumn
140 };
141
52974e38
PT
142 private static final int[] COLUMN_WIDTHS = new int[] {
143 200,
144 50,
145 120,
146 120,
147 120
148 };
149
26c33ee2
PT
150 /** Timeout between updates in the build thread in ms */
151 private static final long BUILD_UPDATE_TIMEOUT = 500;
152
52974e38
PT
153 // Fraction of a function duration to be added as spacing
154 private static final double SPACING_RATIO = 0.01;
155
e8251298
PT
156 private static final Image THREAD_IMAGE = Activator.getDefault().getImageFromPath("icons/obj16/thread_obj.gif"); //$NON-NLS-1$
157 private static final Image STACKFRAME_IMAGE = Activator.getDefault().getImageFromPath("icons/obj16/stckframe_obj.gif"); //$NON-NLS-1$
158
5da83da5 159 private static final String IMPORT_MAPPING_ICON_PATH = "icons/etool16/import.gif"; //$NON-NLS-1$
41d9ce5b 160 private static final String IMPORT_BINARY_ICON_PATH = "icons/obj16/binaries_obj.gif"; //$NON-NLS-1$
5da83da5 161
46cc1ade
PT
162 private static final ImageDescriptor SORT_BY_NAME_ICON = Activator.getDefault().getImageDescripterFromPath("icons/etool16/sort_alpha.gif"); //$NON-NLS-1$
163 private static final ImageDescriptor SORT_BY_NAME_REV_ICON = Activator.getDefault().getImageDescripterFromPath("icons/etool16/sort_alpha_rev.gif"); //$NON-NLS-1$
164 private static final ImageDescriptor SORT_BY_ID_ICON = Activator.getDefault().getImageDescripterFromPath("icons/etool16/sort_num.gif"); //$NON-NLS-1$
165 private static final ImageDescriptor SORT_BY_ID_REV_ICON = Activator.getDefault().getImageDescripterFromPath("icons/etool16/sort_num_rev.gif"); //$NON-NLS-1$
166 private static final ImageDescriptor SORT_BY_TIME_ICON = Activator.getDefault().getImageDescripterFromPath("icons/etool16/sort_time.gif"); //$NON-NLS-1$
167 private static final ImageDescriptor SORT_BY_TIME_REV_ICON = Activator.getDefault().getImageDescripterFromPath("icons/etool16/sort_time_rev.gif"); //$NON-NLS-1$
168 private static final String SORT_OPTION_KEY = "sort.option"; //$NON-NLS-1$
bac9c0df
MK
169
170 private enum SortOption {
171 BY_NAME, BY_NAME_REV, BY_ID, BY_ID_REV, BY_TIME, BY_TIME_REV
172 }
173
46cc1ade
PT
174 private SortOption fSortOption;
175 private Comparator<ITimeGraphEntry> fThreadComparator = null;
176 private Action fSortByNameAction;
177 private Action fSortByIdAction;
178 private Action fSortByTimeAction;
179
e8251298
PT
180 // ------------------------------------------------------------------------
181 // Fields
182 // ------------------------------------------------------------------------
183
184 // The time graph combo
52974e38 185 private TimeGraphCombo fTimeGraphCombo;
e8251298
PT
186
187 // The selected trace
188 private ITmfTrace fTrace;
189
190 // The selected thread map
507b1336 191 private final Map<ITmfTrace, String> fSelectedThreadMap = new HashMap<>();
e8251298
PT
192
193 // The time graph entry list
60b4d44c 194 private List<TraceEntry> fEntryList;
e8251298
PT
195
196 // The trace to entry list hash map
26c33ee2 197 private final Map<ITmfTrace, List<TraceEntry>> fEntryListMap = new HashMap<>();
e8251298
PT
198
199 // The trace to build thread hash map
507b1336 200 private final Map<ITmfTrace, BuildThread> fBuildThreadMap = new HashMap<>();
e8251298 201
5da83da5
AM
202 /** The map to map function addresses to function names */
203 private Map<String, String> fNameMapping;
204
e8251298 205 // The start time
17a54620 206 private long fStartTime = SWT.DEFAULT;
e8251298
PT
207
208 // The end time
17a54620 209 private long fEndTime = SWT.DEFAULT;
e8251298
PT
210
211 // The display width
212 private int fDisplayWidth;
213
214 // The next event action
215 private Action fNextEventAction;
216
217 // The previous event action
218 private Action fPrevEventAction;
219
220 // The next item action
221 private Action fNextItemAction;
222
223 // The previous item action
224 private Action fPreviousItemAction;
225
41d9ce5b 226 // The action to import a function-name mapping file
5da83da5
AM
227 private Action fImportMappingAction;
228
41d9ce5b
MAL
229 // The action to import a binary file mapping */
230 private Action fImportBinaryFileMappingAction;
231
e8251298
PT
232 // The zoom thread
233 private ZoomThread fZoomThread;
234
235 // The redraw state used to prevent unnecessary queuing of display runnables
236 private State fRedrawState = State.IDLE;
237
238 // The redraw synchronization object
52974e38 239 private final Object fSyncObj = new Object();
e8251298
PT
240
241 // The saved time sync. signal used when switching off the pinning of a view
97c71024 242 private TmfSelectionRangeUpdatedSignal fSavedTimeSyncSignal;
e8251298 243
97c71024 244 // The saved window range signal used when switching off the pinning of
bac9c0df 245 // a view
97c71024 246 private TmfWindowRangeUpdatedSignal fSavedRangeSyncSignal;
e8251298
PT
247
248 // ------------------------------------------------------------------------
249 // Classes
250 // ------------------------------------------------------------------------
251
60b4d44c
PT
252 private class TraceEntry extends TimeGraphEntry {
253 public TraceEntry(String name, long startTime, long endTime) {
254 super(name, startTime, endTime);
255 }
256
257 @Override
258 public boolean hasTimeEvents() {
259 return false;
260 }
261 }
262
263 private class ThreadEntry extends TimeGraphEntry {
da27e43a
PT
264 // The call stack quark
265 private final int fCallStackQuark;
50659279
AM
266 // The state system from which this entry comes
267 private final ITmfStateSystem fSS;
46cc1ade
PT
268 // The thread id
269 private final long fThreadId;
e8251298 270
46cc1ade 271 public ThreadEntry(ITmfStateSystem ss, String name, long threadId, int callStackQuark, long startTime, long endTime) {
60b4d44c 272 super(name, startTime, endTime);
da27e43a 273 fCallStackQuark = callStackQuark;
46cc1ade 274 fThreadId = threadId;
da27e43a 275 fSS = ss;
e8251298
PT
276 }
277
e8251298
PT
278 @Override
279 public boolean hasTimeEvents() {
280 return false;
281 }
282
da27e43a
PT
283 public int getCallStackQuark() {
284 return fCallStackQuark;
e8251298
PT
285 }
286
46cc1ade
PT
287 public long getThreadId() {
288 return fThreadId;
289 }
290
50659279
AM
291 @Nullable
292 public ITmfStateSystem getStateSystem() {
293 return fSS;
e8251298 294 }
e8251298
PT
295 }
296
46cc1ade
PT
297 private class ThreadNameComparator implements Comparator<ITimeGraphEntry> {
298 private boolean reverse;
bac9c0df 299
46cc1ade
PT
300 public ThreadNameComparator(boolean reverse) {
301 this.reverse = reverse;
302 }
bac9c0df 303
46cc1ade
PT
304 @Override
305 public int compare(ITimeGraphEntry o1, ITimeGraphEntry o2) {
306 return reverse ? o2.getName().compareTo(o1.getName()) :
bac9c0df 307 o1.getName().compareTo(o2.getName());
46cc1ade
PT
308 }
309 }
310
311 private class ThreadIdComparator implements Comparator<ITimeGraphEntry> {
312 private boolean reverse;
bac9c0df 313
46cc1ade
PT
314 public ThreadIdComparator(boolean reverse) {
315 this.reverse = reverse;
316 }
bac9c0df 317
46cc1ade
PT
318 @Override
319 public int compare(ITimeGraphEntry o1, ITimeGraphEntry o2) {
320 ThreadEntry t1 = (ThreadEntry) o1;
321 ThreadEntry t2 = (ThreadEntry) o2;
322 return reverse ? Long.compare(t2.getThreadId(), t1.getThreadId()) :
bac9c0df 323 Long.compare(t1.getThreadId(), t2.getThreadId());
46cc1ade
PT
324 }
325 }
326
327 private class ThreadTimeComparator implements Comparator<ITimeGraphEntry> {
328 private boolean reverse;
bac9c0df 329
46cc1ade
PT
330 public ThreadTimeComparator(boolean reverse) {
331 this.reverse = reverse;
332 }
bac9c0df 333
46cc1ade
PT
334 @Override
335 public int compare(ITimeGraphEntry o1, ITimeGraphEntry o2) {
336 return reverse ? Long.compare(o2.getStartTime(), o1.getStartTime()) :
bac9c0df 337 Long.compare(o1.getStartTime(), o2.getStartTime());
46cc1ade
PT
338 }
339 }
340
e8251298
PT
341 private class TreeLabelProvider implements ITableLabelProvider {
342
343 @Override
344 public void addListener(ILabelProviderListener listener) {
345 }
346
347 @Override
348 public void dispose() {
349 }
350
351 @Override
352 public boolean isLabelProperty(Object element, String property) {
353 return false;
354 }
355
356 @Override
357 public void removeListener(ILabelProviderListener listener) {
358 }
359
360 @Override
361 public Image getColumnImage(Object element, int columnIndex) {
362 if (columnIndex == 0) {
363 if (element instanceof ThreadEntry) {
364 return THREAD_IMAGE;
365 } else if (element instanceof CallStackEntry) {
366 CallStackEntry entry = (CallStackEntry) element;
367 if (entry.getFunctionName().length() > 0) {
368 return STACKFRAME_IMAGE;
369 }
370 }
371 }
372 return null;
373 }
374
375 @Override
376 public String getColumnText(Object element, int columnIndex) {
60b4d44c 377 if (element instanceof CallStackEntry) {
e8251298
PT
378 CallStackEntry entry = (CallStackEntry) element;
379 if (columnIndex == 0) {
380 return entry.getFunctionName();
52974e38
PT
381 } else if (columnIndex == 1 && entry.getFunctionName().length() > 0) {
382 int depth = entry.getStackLevel();
383 return Integer.toString(depth);
384 } else if (columnIndex == 2 && entry.getFunctionName().length() > 0) {
60b4d44c 385 ITmfTimestamp ts = new TmfTimestamp(entry.getFunctionEntryTime(), ITmfTimestamp.NANOSECOND_SCALE);
52974e38
PT
386 return ts.toString();
387 } else if (columnIndex == 3 && entry.getFunctionName().length() > 0) {
60b4d44c 388 ITmfTimestamp ts = new TmfTimestamp(entry.getFunctionExitTime(), ITmfTimestamp.NANOSECOND_SCALE);
52974e38
PT
389 return ts.toString();
390 } else if (columnIndex == 4 && entry.getFunctionName().length() > 0) {
60b4d44c 391 ITmfTimestamp ts = new TmfTimestampDelta(entry.getFunctionExitTime() - entry.getFunctionEntryTime(), ITmfTimestamp.NANOSECOND_SCALE);
52974e38 392 return ts.toString();
e8251298 393 }
60b4d44c
PT
394 } else if (element instanceof ITimeGraphEntry) {
395 if (columnIndex == 0) {
396 return ((ITimeGraphEntry) element).getName();
397 }
e8251298
PT
398 }
399 return ""; //$NON-NLS-1$
400 }
401
402 }
403
404 private class BuildThread extends Thread {
1d83ed07 405 private final @NonNull ITmfTrace fBuildTrace;
26c33ee2 406 private final ITmfTrace fParentTrace;
e8251298
PT
407 private final IProgressMonitor fMonitor;
408
1d83ed07 409 public BuildThread(@NonNull ITmfTrace trace, ITmfTrace parentTrace) {
e8251298
PT
410 super("CallStackView build"); //$NON-NLS-1$
411 fBuildTrace = trace;
26c33ee2 412 fParentTrace = parentTrace;
e8251298
PT
413 fMonitor = new NullProgressMonitor();
414 }
415
416 @Override
417 public void run() {
26c33ee2 418 buildThreadList(fBuildTrace, fParentTrace, fMonitor);
e8251298 419 synchronized (fBuildThreadMap) {
26c33ee2 420 fBuildThreadMap.remove(fBuildTrace);
e8251298
PT
421 }
422 }
423
424 public void cancel() {
425 fMonitor.setCanceled(true);
426 }
427 }
428
429 private class ZoomThread extends Thread {
60b4d44c 430 private final List<TraceEntry> fZoomEntryList;
e8251298
PT
431 private final long fZoomStartTime;
432 private final long fZoomEndTime;
433 private final IProgressMonitor fMonitor;
434
60b4d44c
PT
435 public ZoomThread(List<TraceEntry> entryList, long startTime, long endTime) {
436 super("CallStackView zoom"); //$NON-NLS-1$
e8251298
PT
437 fZoomEntryList = entryList;
438 fZoomStartTime = startTime;
439 fZoomEndTime = endTime;
440 fMonitor = new NullProgressMonitor();
441 }
442
443 @Override
444 public void run() {
445 if (fZoomEntryList == null) {
446 return;
447 }
448 long resolution = Math.max(1, (fZoomEndTime - fZoomStartTime) / fDisplayWidth);
60b4d44c
PT
449 for (TraceEntry traceEntry : fZoomEntryList) {
450 for (ITimeGraphEntry threadEntry : traceEntry.getChildren()) {
451 ITmfStateSystem ss = ((ThreadEntry) threadEntry).getStateSystem();
452 if (ss == null) {
453 continue;
e8251298 454 }
60b4d44c
PT
455 ss.waitUntilBuilt();
456 if (ss.isCancelled()) {
457 continue;
458 }
459 for (ITimeGraphEntry child : threadEntry.getChildren()) {
460 if (fMonitor.isCanceled()) {
461 break;
462 }
463 CallStackEntry entry = (CallStackEntry) child;
464 if (fZoomStartTime <= fStartTime && fZoomEndTime >= fEndTime) {
465 entry.setZoomedEventList(null);
466 } else {
467 List<ITimeEvent> zoomedEventList = getEventList(entry, fZoomStartTime, fZoomEndTime, resolution, fMonitor);
468 if (zoomedEventList != null) {
469 entry.setZoomedEventList(zoomedEventList);
470 }
e8251298 471 }
60b4d44c 472 redraw();
e8251298 473 }
e8251298
PT
474 }
475 }
476 }
477
478 public void cancel() {
479 fMonitor.setCanceled(true);
480 }
481 }
482
483 // ------------------------------------------------------------------------
484 // Constructors
485 // ------------------------------------------------------------------------
486
487 /**
488 * Default constructor
489 */
490 public CallStackView() {
491 super(ID);
492 fDisplayWidth = Display.getDefault().getBounds().width;
493 }
494
495 // ------------------------------------------------------------------------
496 // ViewPart
497 // ------------------------------------------------------------------------
498
499 @Override
500 public void createPartControl(Composite parent) {
d2e4afa7 501 super.createPartControl(parent);
e8251298
PT
502 fTimeGraphCombo = new TimeGraphCombo(parent, SWT.NONE);
503
d8a230f8 504 fTimeGraphCombo.setTreeContentProvider(new TimeGraphContentProvider());
e8251298
PT
505
506 fTimeGraphCombo.setTreeLabelProvider(new TreeLabelProvider());
507
46cc1ade 508 fTimeGraphCombo.setTreeColumns(COLUMN_TIMES);
e8251298 509
52974e38
PT
510 fTimeGraphCombo.getTreeViewer().getTree().getColumn(0).setWidth(COLUMN_WIDTHS[0]);
511 fTimeGraphCombo.getTreeViewer().getTree().getColumn(1).setWidth(COLUMN_WIDTHS[1]);
512 fTimeGraphCombo.getTreeViewer().getTree().getColumn(2).setWidth(COLUMN_WIDTHS[2]);
513 fTimeGraphCombo.getTreeViewer().getTree().getColumn(3).setWidth(COLUMN_WIDTHS[3]);
514 fTimeGraphCombo.getTreeViewer().getTree().getColumn(4).setWidth(COLUMN_WIDTHS[4]);
e8251298 515
26c33ee2 516 fTimeGraphCombo.setTimeGraphContentProvider(new TimeGraphContentProvider());
5da83da5 517 fTimeGraphCombo.setTimeGraphProvider(new CallStackPresentationProvider(this));
e8251298
PT
518 fTimeGraphCombo.getTimeGraphViewer().setTimeFormat(TimeFormat.CALENDAR);
519
520 fTimeGraphCombo.getTimeGraphViewer().addRangeListener(new ITimeGraphRangeListener() {
521 @Override
522 public void timeRangeUpdated(TimeGraphRangeUpdateEvent event) {
523 long startTime = event.getStartTime();
524 long endTime = event.getEndTime();
f566d40a 525 TmfTimeRange range = new TmfTimeRange(new TmfNanoTimestamp(startTime), new TmfNanoTimestamp(endTime));
97c71024 526 broadcast(new TmfWindowRangeUpdatedSignal(CallStackView.this, range));
e8251298
PT
527 startZoomThread(startTime, endTime);
528 }
529 });
530
531 fTimeGraphCombo.getTimeGraphViewer().addTimeListener(new ITimeGraphTimeListener() {
532 @Override
533 public void timeSelected(TimeGraphTimeEvent event) {
0fcf3b09
PT
534 long beginTime = event.getBeginTime();
535 long endTime = event.getEndTime();
26c33ee2 536 synchingToTime(beginTime);
97c71024 537 broadcast(new TmfSelectionRangeUpdatedSignal(CallStackView.this, new TmfNanoTimestamp(beginTime), new TmfNanoTimestamp(endTime)));
e8251298
PT
538 }
539 });
540
541 fTimeGraphCombo.getTimeGraphViewer().getControl().addControlListener(new ControlAdapter() {
542 @Override
543 public void controlResized(ControlEvent e) {
544 fDisplayWidth = fTimeGraphCombo.getTimeGraphViewer().getControl().getSize().x;
545 if (fEntryList != null) {
546 startZoomThread(fTimeGraphCombo.getTimeGraphViewer().getTime0(), fTimeGraphCombo.getTimeGraphViewer().getTime1());
547 }
548 }
549 });
550
551 fTimeGraphCombo.getTreeViewer().addDoubleClickListener(new IDoubleClickListener() {
552 @Override
553 public void doubleClick(DoubleClickEvent event) {
554 Object selection = ((IStructuredSelection) event.getSelection()).getFirstElement();
555 if (selection instanceof CallStackEntry) {
556 CallStackEntry entry = (CallStackEntry) selection;
557 if (entry.getFunctionName().length() > 0) {
60b4d44c
PT
558 long entryTime = entry.getFunctionEntryTime();
559 long exitTime = entry.getFunctionExitTime();
560 long spacingTime = (long) ((exitTime - entryTime) * SPACING_RATIO);
561 entryTime -= spacingTime;
562 exitTime += spacingTime;
563 TmfTimeRange range = new TmfTimeRange(new TmfNanoTimestamp(entryTime), new TmfNanoTimestamp(exitTime));
97c71024 564 broadcast(new TmfWindowRangeUpdatedSignal(CallStackView.this, range));
60b4d44c
PT
565 fTimeGraphCombo.getTimeGraphViewer().setStartFinishTime(entryTime, exitTime);
566 startZoomThread(entryTime, exitTime);
e8251298
PT
567 }
568 }
569 }
570 });
571
572 fTimeGraphCombo.getTimeGraphViewer().getTimeGraphControl().addMouseListener(new MouseAdapter() {
573 @Override
574 public void mouseDoubleClick(MouseEvent e) {
575 TimeGraphControl timeGraphControl = fTimeGraphCombo.getTimeGraphViewer().getTimeGraphControl();
576 ISelection selection = timeGraphControl.getSelection();
577 if (selection instanceof TimeGraphSelection) {
578 Object o = ((TimeGraphSelection) selection).getFirstElement();
579 if (o instanceof CallStackEvent) {
580 CallStackEvent event = (CallStackEvent) o;
581 long startTime = event.getTime();
582 long endTime = startTime + event.getDuration();
52974e38 583 long spacingTime = (long) ((endTime - startTime) * SPACING_RATIO);
e8251298
PT
584 startTime -= spacingTime;
585 endTime += spacingTime;
f566d40a 586 TmfTimeRange range = new TmfTimeRange(new TmfNanoTimestamp(startTime), new TmfNanoTimestamp(endTime));
97c71024 587 broadcast(new TmfWindowRangeUpdatedSignal(CallStackView.this, range));
e8251298
PT
588 fTimeGraphCombo.getTimeGraphViewer().setStartFinishTime(startTime, endTime);
589 startZoomThread(startTime, endTime);
590 }
591 }
592 }
593 });
594
0fcf3b09
PT
595 IStatusLineManager statusLineManager = getViewSite().getActionBars().getStatusLineManager();
596 fTimeGraphCombo.getTimeGraphViewer().getTimeGraphControl().setStatusLineManager(statusLineManager);
597
e8251298
PT
598 // View Action Handling
599 makeActions();
600 contributeToActionBars();
46cc1ade
PT
601 createContextMenu();
602 loadSortOption();
e8251298
PT
603
604 IEditorPart editor = getSite().getPage().getActiveEditor();
605 if (editor instanceof ITmfTraceEditor) {
606 ITmfTrace trace = ((ITmfTraceEditor) editor).getTrace();
607 if (trace != null) {
608 traceSelected(new TmfTraceSelectedSignal(this, trace));
609 }
610 }
611 }
612
613 @Override
614 public void setFocus() {
615 fTimeGraphCombo.setFocus();
616 }
617
618 // ------------------------------------------------------------------------
619 // Signal handlers
620 // ------------------------------------------------------------------------
fec1ac0b
BH
621 /**
622 * Handler for the trace opened signal.
bac9c0df 623 *
fec1ac0b
BH
624 * @param signal
625 * The incoming signal
fec1ac0b
BH
626 */
627 @TmfSignalHandler
628 public void traceOpened(TmfTraceOpenedSignal signal) {
629 fTrace = signal.getTrace();
630 loadTrace();
631 }
e8251298
PT
632
633 /**
634 * Handler for the trace selected signal
635 *
636 * @param signal
637 * The incoming signal
638 */
639 @TmfSignalHandler
640 public void traceSelected(final TmfTraceSelectedSignal signal) {
641 if (signal.getTrace() == fTrace) {
642 return;
643 }
644 fTrace = signal.getTrace();
fec1ac0b 645 loadTrace();
e8251298
PT
646 }
647
648 /**
649 * Trace is closed: clear the data structures and the view
650 *
bac9c0df
MK
651 * @param signal
652 * the signal received
e8251298
PT
653 */
654 @TmfSignalHandler
655 public void traceClosed(final TmfTraceClosedSignal signal) {
656 synchronized (fBuildThreadMap) {
c14c0757 657 for (ITmfTrace trace : TmfTraceManager.getTraceSet(signal.getTrace())) {
26c33ee2
PT
658 BuildThread buildThread = fBuildThreadMap.remove(trace);
659 if (buildThread != null) {
660 buildThread.cancel();
661 }
e8251298
PT
662 }
663 }
664 synchronized (fEntryListMap) {
665 fEntryListMap.remove(signal.getTrace());
666 }
667 fSelectedThreadMap.remove(signal.getTrace());
668 if (signal.getTrace() == fTrace) {
669 fTrace = null;
17a54620
PT
670 fStartTime = SWT.DEFAULT;
671 fEndTime = SWT.DEFAULT;
e8251298
PT
672 refresh();
673 }
674 }
675
676 /**
97c71024 677 * Handler for the selection range signal.
e8251298
PT
678 *
679 * @param signal
680 * The incoming signal
97c71024 681 * @since 1.0
e8251298
PT
682 */
683 @TmfSignalHandler
97c71024 684 public void selectionRangeUpdated(final TmfSelectionRangeUpdatedSignal signal) {
e8251298 685
97c71024 686 fSavedTimeSyncSignal = isPinned() ? new TmfSelectionRangeUpdatedSignal(signal.getSource(), signal.getBeginTime(), signal.getEndTime()) : null;
e8251298
PT
687
688 if (signal.getSource() == this || fTrace == null || isPinned()) {
689 return;
690 }
0fcf3b09
PT
691 final long beginTime = signal.getBeginTime().normalize(0, ITmfTimestamp.NANOSECOND_SCALE).getValue();
692 final long endTime = signal.getEndTime().normalize(0, ITmfTimestamp.NANOSECOND_SCALE).getValue();
e8251298
PT
693 Display.getDefault().asyncExec(new Runnable() {
694 @Override
695 public void run() {
696 if (fTimeGraphCombo.isDisposed()) {
697 return;
698 }
0fcf3b09
PT
699 if (beginTime == endTime) {
700 fTimeGraphCombo.getTimeGraphViewer().setSelectedTime(beginTime, true);
701 } else {
84c8aef7 702 fTimeGraphCombo.getTimeGraphViewer().setSelectionRange(beginTime, endTime, true);
0fcf3b09 703 }
26c33ee2 704 synchingToTime(beginTime);
e8251298
PT
705 startZoomThread(fTimeGraphCombo.getTimeGraphViewer().getTime0(), fTimeGraphCombo.getTimeGraphViewer().getTime1());
706 if (fEntryList == null) {
707 return;
708 }
709 TimeGraphViewer viewer = fTimeGraphCombo.getTimeGraphViewer();
60b4d44c
PT
710 for (TraceEntry traceEntry : fEntryList) {
711 for (ITimeGraphEntry child : traceEntry.getChildren()) {
712 ThreadEntry threadEntry = (ThreadEntry) child;
713 ITmfStateSystem ss = threadEntry.getStateSystem();
714 if (ss == null || beginTime < ss.getStartTime() || beginTime > ss.getCurrentEndTime()) {
715 continue;
716 }
717 try {
718 int quark = threadEntry.getCallStackQuark();
719 ITmfStateInterval stackInterval = ss.querySingleState(beginTime, quark);
720 if (beginTime == stackInterval.getStartTime()) {
721 int stackLevel = stackInterval.getStateValue().unboxInt();
722 ITimeGraphEntry selectedEntry = threadEntry.getChildren().get(Math.max(0, stackLevel - 1));
723 fTimeGraphCombo.setSelection(selectedEntry);
724 viewer.getTimeGraphControl().fireSelectionChanged();
725 break;
726 }
bac9c0df 727 } catch (AttributeNotFoundException | TimeRangeException | StateSystemDisposedException | StateValueTypeException e) {
60b4d44c 728 Activator.getDefault().logError("Error querying state system", e); //$NON-NLS-1$
e8251298 729 }
e8251298
PT
730 }
731 }
732 }
733 });
734 }
735
736 /**
97c71024 737 * Handler for the window range signal.
e8251298
PT
738 *
739 * @param signal
740 * The incoming signal
97c71024 741 * @since 1.0
e8251298
PT
742 */
743 @TmfSignalHandler
97c71024 744 public void windowRangeUpdated(final TmfWindowRangeUpdatedSignal signal) {
e8251298
PT
745
746 if (isPinned()) {
747 fSavedRangeSyncSignal =
97c71024 748 new TmfWindowRangeUpdatedSignal(signal.getSource(), new TmfTimeRange(signal.getCurrentRange().getStartTime(), signal.getCurrentRange().getEndTime()));
e8251298
PT
749
750 fSavedTimeSyncSignal = null;
751 }
752
753 if (signal.getSource() == this || fTrace == null || isPinned()) {
754 return;
755 }
756 if (signal.getCurrentRange().getIntersection(fTrace.getTimeRange()) == null) {
757 return;
758 }
759 final long startTime = signal.getCurrentRange().getStartTime().normalize(0, ITmfTimestamp.NANOSECOND_SCALE).getValue();
760 final long endTime = signal.getCurrentRange().getEndTime().normalize(0, ITmfTimestamp.NANOSECOND_SCALE).getValue();
e8251298
PT
761 Display.getDefault().asyncExec(new Runnable() {
762 @Override
763 public void run() {
764 if (fTimeGraphCombo.isDisposed()) {
765 return;
766 }
767 fTimeGraphCombo.getTimeGraphViewer().setStartFinishTime(startTime, endTime);
e8251298
PT
768 startZoomThread(startTime, endTime);
769 }
770 });
771 }
772
773 // ------------------------------------------------------------------------
774 // Internal
775 // ------------------------------------------------------------------------
5da83da5 776
fec1ac0b
BH
777 private void loadTrace() {
778 synchronized (fEntryListMap) {
779 fEntryList = fEntryListMap.get(fTrace);
780 if (fEntryList == null) {
17a54620
PT
781 fStartTime = SWT.DEFAULT;
782 fEndTime = SWT.DEFAULT;
6b8d11bd 783 refresh();
fec1ac0b 784 synchronized (fBuildThreadMap) {
c14c0757 785 for (ITmfTrace trace : TmfTraceManager.getTraceSet(fTrace)) {
1d83ed07 786 trace = checkNotNull(trace);
26c33ee2
PT
787 BuildThread buildThread = new BuildThread(trace, fTrace);
788 fBuildThreadMap.put(trace, buildThread);
789 buildThread.start();
790 }
fec1ac0b
BH
791 }
792 } else {
793 fStartTime = fTrace.getStartTime().normalize(0, ITmfTimestamp.NANOSECOND_SCALE).getValue();
794 fEndTime = fTrace.getEndTime().normalize(0, ITmfTimestamp.NANOSECOND_SCALE).getValue();
795 refresh();
796 }
797 }
798 }
e8251298 799
1d83ed07 800 private void buildThreadList(final @NonNull ITmfTrace trace, final ITmfTrace parentTrace, IProgressMonitor monitor) {
26c33ee2
PT
801 if (monitor.isCanceled()) {
802 return;
803 }
804 AbstractCallStackAnalysis module = getCallStackModule(trace);
805 if (module == null) {
806 addUnavailableEntry(trace, parentTrace);
807 return;
808 }
809 ITmfStateSystem ss = module.getStateSystem();
810 if (ss == null) {
811 addUnavailableEntry(trace, parentTrace);
812 return;
813 }
814
815 Map<ITmfTrace, TraceEntry> traceEntryMap = new HashMap<>();
816 Map<Integer, ThreadEntry> threadEntryMap = new HashMap<>();
817 String[] threadPaths = module.getThreadsPattern();
818
819 long start = ss.getStartTime();
820
821 boolean complete = false;
822 while (!complete) {
e8251298
PT
823 if (monitor.isCanceled()) {
824 return;
825 }
26c33ee2
PT
826 complete = ss.waitUntilBuilt(BUILD_UPDATE_TIMEOUT);
827 if (ss.isCancelled()) {
da27e43a
PT
828 return;
829 }
26c33ee2
PT
830 long end = ss.getCurrentEndTime();
831 if (start == end && !complete) { // when complete execute one last time regardless of end time
e8251298
PT
832 continue;
833 }
da27e43a 834 List<Integer> threadQuarks = ss.getQuarks(threadPaths);
26c33ee2
PT
835 TraceEntry traceEntry = traceEntryMap.get(trace);
836 if (traceEntry == null) {
837 traceEntry = new TraceEntry(trace.getName(), start, end + 1);
838 traceEntryMap.put(trace, traceEntry);
839 traceEntry.sortChildren(fThreadComparator);
840 addToEntryList(parentTrace, Collections.singletonList(traceEntry));
841 } else {
842 traceEntry.updateEndTime(end);
843 }
e8251298
PT
844 for (int i = 0; i < threadQuarks.size(); i++) {
845 if (monitor.isCanceled()) {
846 return;
847 }
848 int threadQuark = threadQuarks.get(i);
e8251298 849 try {
da27e43a
PT
850 String[] callStackPath = module.getCallStackPath();
851 int callStackQuark = ss.getQuarkRelative(threadQuark, callStackPath);
60b4d44c 852 String threadName = ss.getAttributeName(threadQuark);
26c33ee2 853 long threadEnd = end + 1;
46cc1ade 854 ITmfStateInterval endInterval = ss.querySingleState(ss.getCurrentEndTime(), callStackQuark);
26c33ee2
PT
855 if (endInterval.getStateValue().isNull() && endInterval.getStartTime() != ss.getStartTime()) {
856 threadEnd = endInterval.getStartTime();
857 }
858 ThreadEntry threadEntry = threadEntryMap.get(threadQuark);
859 if (threadEntry == null) {
860 long threadId = ss.querySingleState(ss.getCurrentEndTime(), threadQuark).getStateValue().unboxLong();
861 long threadStart = start;
862 ITmfStateInterval startInterval = ss.querySingleState(start, callStackQuark);
863 if (startInterval.getStateValue().isNull()) {
864 threadStart = Math.min(startInterval.getEndTime() + 1, end + 1);
865 }
866 threadEntry = new ThreadEntry(ss, threadName, threadId, callStackQuark, threadStart, threadEnd);
867 threadEntryMap.put(threadQuark, threadEntry);
868 traceEntry.addChild(threadEntry);
869 } else {
870 threadEntry.updateEndTime(threadEnd);
46cc1ade 871 }
e8251298 872 int level = 1;
da27e43a 873 for (int stackLevelQuark : ss.getSubAttributes(callStackQuark, false)) {
26c33ee2
PT
874 if (level > threadEntry.getChildren().size()) {
875 CallStackEntry callStackEntry = new CallStackEntry(threadName, stackLevelQuark, level, trace, ss);
876 threadEntry.addChild(callStackEntry);
877 }
878 level++;
e8251298
PT
879 }
880 } catch (AttributeNotFoundException e) {
52974e38 881 Activator.getDefault().logError("Error querying state system", e); //$NON-NLS-1$
46cc1ade
PT
882 } catch (StateSystemDisposedException e) {
883 /* Ignored */
e8251298
PT
884 }
885 }
26c33ee2
PT
886 if (parentTrace == fTrace) {
887 synchronized (fEntryListMap) {
17a54620
PT
888 fStartTime = fStartTime == SWT.DEFAULT ? start : Math.min(fStartTime, start);
889 fEndTime = fEndTime == SWT.DEFAULT ? end + 1 : Math.max(fEndTime, end + 1);
26c33ee2
PT
890 }
891 refresh();
892 }
60b4d44c
PT
893 for (ITimeGraphEntry threadEntry : traceEntry.getChildren()) {
894 for (ITimeGraphEntry callStackEntry : threadEntry.getChildren()) {
895 if (monitor.isCanceled()) {
896 return;
897 }
26c33ee2 898 buildStatusEvents(parentTrace, (CallStackEntry) callStackEntry, monitor, start, end);
e8251298 899 }
e8251298 900 }
26c33ee2 901 start = end;
e8251298
PT
902 }
903 }
904
26c33ee2
PT
905 private void addToEntryList(ITmfTrace trace, List<TraceEntry> list) {
906 synchronized (fEntryListMap) {
907 List<TraceEntry> entryList = fEntryListMap.get(trace);
908 if (entryList == null) {
909 fEntryListMap.put(trace, new CopyOnWriteArrayList<>(list));
910 } else {
911 entryList.addAll(list);
912 }
913 }
914 }
915
916 private void addUnavailableEntry(ITmfTrace trace, ITmfTrace parentTrace) {
60b4d44c
PT
917 String name = Messages.CallStackView_StackInfoNotAvailable + ' ' + '(' + trace.getName() + ')';
918 TraceEntry unavailableEntry = new TraceEntry(name, 0, 0);
26c33ee2
PT
919 addToEntryList(parentTrace, Collections.singletonList(unavailableEntry));
920 if (parentTrace == fTrace) {
921 refresh();
922 }
2002c638
AM
923 }
924
26c33ee2 925 private void buildStatusEvents(ITmfTrace trace, CallStackEntry entry, IProgressMonitor monitor, long start, long end) {
da27e43a 926 ITmfStateSystem ss = entry.getStateSystem();
26c33ee2
PT
927 long resolution = Math.max(1, (end - ss.getStartTime()) / fDisplayWidth);
928 List<ITimeEvent> eventList = getEventList(entry, start, end + 1, resolution, monitor);
929 if (eventList != null) {
930 for (ITimeEvent event : eventList) {
931 entry.addEvent(event);
932 }
e8251298 933 }
e8251298
PT
934 if (trace == fTrace) {
935 redraw();
936 }
937 }
938
939 private static List<ITimeEvent> getEventList(CallStackEntry entry,
940 long startTime, long endTime, long resolution,
941 IProgressMonitor monitor) {
da27e43a 942 ITmfStateSystem ss = entry.getStateSystem();
e8251298
PT
943 long start = Math.max(startTime, ss.getStartTime());
944 long end = Math.min(endTime, ss.getCurrentEndTime() + 1);
945 if (end <= start) {
946 return null;
947 }
948 List<ITimeEvent> eventList = null;
949 try {
1dd75589 950 List<ITmfStateInterval> stackIntervals = StateSystemUtils.queryHistoryRange(ss, entry.getQuark(), start, end - 1, resolution, monitor);
507b1336 951 eventList = new ArrayList<>(stackIntervals.size());
e8251298
PT
952 long lastEndTime = -1;
953 boolean lastIsNull = true;
954 for (ITmfStateInterval statusInterval : stackIntervals) {
955 if (monitor.isCanceled()) {
956 return null;
957 }
958 long time = statusInterval.getStartTime();
959 long duration = statusInterval.getEndTime() - time + 1;
960 if (!statusInterval.getStateValue().isNull()) {
52974e38
PT
961 final int modulo = CallStackPresentationProvider.NUM_COLORS / 2;
962 int value = statusInterval.getStateValue().toString().hashCode() % modulo + modulo;
e8251298
PT
963 eventList.add(new CallStackEvent(entry, time, duration, value));
964 lastIsNull = false;
965 } else {
beb1b921
PT
966 if (lastEndTime == -1) {
967 // add null event if it intersects the start time
968 eventList.add(new NullTimeEvent(entry, time, duration));
969 } else {
970 if (lastEndTime != time && lastIsNull) {
971 // add unknown event if between two null states
972 eventList.add(new TimeEvent(entry, lastEndTime, time - lastEndTime));
973 }
974 if (time + duration >= endTime) {
975 // add null event if it intersects the end time
976 eventList.add(new NullTimeEvent(entry, time, duration));
977 }
e8251298 978 }
e8251298
PT
979 lastIsNull = true;
980 }
981 lastEndTime = time + duration;
982 }
983 } catch (AttributeNotFoundException e) {
52974e38 984 Activator.getDefault().logError("Error querying state system", e); //$NON-NLS-1$
e8251298 985 } catch (TimeRangeException e) {
52974e38 986 Activator.getDefault().logError("Error querying state system", e); //$NON-NLS-1$
e8251298
PT
987 } catch (StateSystemDisposedException e) {
988 /* Ignored */
989 }
990 return eventList;
991 }
992
26c33ee2 993 private void synchingToTime(long time) {
e8251298
PT
994 if (fEntryList == null) {
995 return;
996 }
60b4d44c
PT
997 for (TraceEntry traceEntry : fEntryList) {
998 for (ITimeGraphEntry threadEntry : traceEntry.getChildren()) {
999 ITmfStateSystem ss = ((ThreadEntry) threadEntry).getStateSystem();
1000 if (ss == null) {
1001 continue;
1002 }
60b4d44c
PT
1003 if (ss.isCancelled()) {
1004 continue;
1005 }
26c33ee2
PT
1006 if (time < ss.getStartTime() || time > ss.getCurrentEndTime()) {
1007 continue;
1008 }
60b4d44c
PT
1009 for (ITimeGraphEntry child : threadEntry.getChildren()) {
1010 CallStackEntry callStackEntry = (CallStackEntry) child;
e8251298 1011 try {
26c33ee2 1012 ITmfStateInterval stackLevelInterval = ss.querySingleState(time, callStackEntry.getQuark());
60b4d44c
PT
1013 ITmfStateValue nameValue = stackLevelInterval.getStateValue();
1014 String name = ""; //$NON-NLS-1$
1015 try {
1016 if (nameValue.getType() == Type.STRING) {
1017 String address = nameValue.unboxStr();
1018 name = getFunctionName(address);
1019 } else if (nameValue.getType() == Type.INTEGER) {
1020 name = "0x" + Integer.toHexString(nameValue.unboxInt()); //$NON-NLS-1$
1021 } else if (nameValue.getType() == Type.LONG) {
1022 name = "0x" + Long.toHexString(nameValue.unboxLong()); //$NON-NLS-1$
1023 }
1024 } catch (StateValueTypeException e) {
e8251298 1025 }
60b4d44c
PT
1026 callStackEntry.setFunctionName(name);
1027 if (name.length() > 0) {
1028 callStackEntry.setFunctionEntryTime(stackLevelInterval.getStartTime());
1029 callStackEntry.setFunctionExitTime(stackLevelInterval.getEndTime() + 1);
1030 }
1031 } catch (AttributeNotFoundException e) {
1032 Activator.getDefault().logError("Error querying state system", e); //$NON-NLS-1$
60b4d44c 1033 } catch (StateSystemDisposedException e) {
26c33ee2 1034 /* Ignored */
e8251298 1035 }
e8251298
PT
1036 }
1037 }
1038 }
1039 fTimeGraphCombo.refresh();
e8251298
PT
1040 }
1041
1042 private void refresh() {
1043 Display.getDefault().asyncExec(new Runnable() {
1044 @Override
1045 public void run() {
1046 if (fTimeGraphCombo.isDisposed()) {
1047 return;
1048 }
e8251298
PT
1049 synchronized (fEntryListMap) {
1050 fEntryList = fEntryListMap.get(fTrace);
1051 if (fEntryList == null) {
507b1336 1052 fEntryList = new ArrayList<>();
e8251298 1053 }
46cc1ade
PT
1054 for (TraceEntry traceEntry : fEntryList) {
1055 traceEntry.sortChildren(fThreadComparator);
1056 }
e8251298 1057 }
26c33ee2
PT
1058 if (fEntryList != fTimeGraphCombo.getInput()) {
1059 fTimeGraphCombo.setInput(fEntryList);
1060 } else {
1061 fTimeGraphCombo.refresh();
1062 }
e8251298
PT
1063 fTimeGraphCombo.getTimeGraphViewer().setTimeBounds(fStartTime, fEndTime);
1064
21852dfa 1065 TmfTraceContext ctx = TmfTraceManager.getInstance().getCurrentTraceContext();
17a54620
PT
1066 long selectionBeginTime = fTrace == null ? SWT.DEFAULT : ctx.getSelectionRange().getStartTime().normalize(0, ITmfTimestamp.NANOSECOND_SCALE).getValue();
1067 long selectionEndTime = fTrace == null ? SWT.DEFAULT : ctx.getSelectionRange().getEndTime().normalize(0, ITmfTimestamp.NANOSECOND_SCALE).getValue();
1068 long startTime = fTrace == null ? SWT.DEFAULT : ctx.getWindowRange().getStartTime().normalize(0, ITmfTimestamp.NANOSECOND_SCALE).getValue();
1069 long endTime = fTrace == null ? SWT.DEFAULT : ctx.getWindowRange().getEndTime().normalize(0, ITmfTimestamp.NANOSECOND_SCALE).getValue();
1070 startTime = (fStartTime == SWT.DEFAULT ? SWT.DEFAULT : Math.max(startTime, fStartTime));
1071 endTime = (fEndTime == SWT.DEFAULT ? SWT.DEFAULT : Math.min(endTime, fEndTime));
84c8aef7 1072 fTimeGraphCombo.getTimeGraphViewer().setSelectionRange(selectionBeginTime, selectionEndTime, false);
26c33ee2 1073 synchingToTime(selectionBeginTime);
e8251298
PT
1074 fTimeGraphCombo.getTimeGraphViewer().setStartFinishTime(startTime, endTime);
1075 startZoomThread(startTime, endTime);
1076 }
1077 });
1078 }
1079
1080 private void redraw() {
1081 synchronized (fSyncObj) {
1082 if (fRedrawState == State.IDLE) {
1083 fRedrawState = State.BUSY;
1084 } else {
1085 fRedrawState = State.PENDING;
1086 return;
1087 }
1088 }
1089 Display.getDefault().asyncExec(new Runnable() {
1090 @Override
1091 public void run() {
1092 if (fTimeGraphCombo.isDisposed()) {
1093 return;
1094 }
1095 fTimeGraphCombo.redraw();
1096 fTimeGraphCombo.update();
1097 synchronized (fSyncObj) {
1098 if (fRedrawState == State.PENDING) {
1099 fRedrawState = State.IDLE;
1100 redraw();
1101 } else {
1102 fRedrawState = State.IDLE;
1103 }
1104 }
1105 }
1106 });
1107 }
1108
1109 private void startZoomThread(long startTime, long endTime) {
1110 if (fZoomThread != null) {
1111 fZoomThread.cancel();
1112 }
1113 fZoomThread = new ZoomThread(fEntryList, startTime, endTime);
1114 fZoomThread.start();
1115 }
1116
1117 private void makeActions() {
1118 fPreviousItemAction = fTimeGraphCombo.getTimeGraphViewer().getPreviousItemAction();
1119 fPreviousItemAction.setText(Messages.TmfTimeGraphViewer_PreviousItemActionNameText);
1120 fPreviousItemAction.setToolTipText(Messages.TmfTimeGraphViewer_PreviousItemActionToolTipText);
1121 fNextItemAction = fTimeGraphCombo.getTimeGraphViewer().getNextItemAction();
1122 fNextItemAction.setText(Messages.TmfTimeGraphViewer_NextItemActionNameText);
1123 fNextItemAction.setToolTipText(Messages.TmfTimeGraphViewer_NextItemActionToolTipText);
1124 }
1125
1126 private void contributeToActionBars() {
1127 IActionBars bars = getViewSite().getActionBars();
1128 fillLocalToolBar(bars.getToolBarManager());
1129
1130 // Create pin action
1131 contributePinActionToToolBar();
bac9c0df 1132 fPinAction.addPropertyChangeListener(new IPropertyChangeListener() {
e8251298
PT
1133 @Override
1134 public void propertyChange(PropertyChangeEvent event) {
52974e38
PT
1135 if (IAction.CHECKED.equals(event.getProperty()) && !isPinned()) {
1136 if (fSavedRangeSyncSignal != null) {
97c71024 1137 windowRangeUpdated(fSavedRangeSyncSignal);
52974e38
PT
1138 fSavedRangeSyncSignal = null;
1139 }
e8251298 1140
52974e38 1141 if (fSavedTimeSyncSignal != null) {
97c71024 1142 selectionRangeUpdated(fSavedTimeSyncSignal);
52974e38 1143 fSavedTimeSyncSignal = null;
e8251298
PT
1144 }
1145 }
1146 }
1147 });
1148 }
1149
1150 private void fillLocalToolBar(IToolBarManager manager) {
41d9ce5b 1151 manager.add(getImportBinaryAction());
5da83da5 1152 manager.add(getImportMappingAction());
46cc1ade
PT
1153 manager.add(new Separator());
1154 manager.add(getSortByNameAction());
1155 manager.add(getSortByIdAction());
1156 manager.add(getSortByTimeAction());
1157 manager.add(new Separator());
e8251298
PT
1158 manager.add(fTimeGraphCombo.getTimeGraphViewer().getResetScaleAction());
1159 manager.add(getPreviousEventAction());
1160 manager.add(getNextEventAction());
1161 manager.add(fPreviousItemAction);
1162 manager.add(fNextItemAction);
1163 manager.add(fTimeGraphCombo.getTimeGraphViewer().getZoomInAction());
1164 manager.add(fTimeGraphCombo.getTimeGraphViewer().getZoomOutAction());
1165 manager.add(new Separator());
1166 }
1167
46cc1ade
PT
1168 private void createContextMenu() {
1169 final MenuManager contextMenu = new MenuManager();
1170 contextMenu.add(getSortByNameAction());
1171 contextMenu.add(getSortByIdAction());
1172 contextMenu.add(getSortByTimeAction());
1173
1174 Tree tree = fTimeGraphCombo.getTreeViewer().getTree();
1175 Menu menu = contextMenu.createContextMenu(tree);
1176 tree.setMenu(menu);
1177 }
1178
e8251298
PT
1179 /**
1180 * Get the the next event action.
1181 *
1182 * @return The action object
1183 */
1184 private Action getNextEventAction() {
1185 if (fNextEventAction == null) {
1186 fNextEventAction = new Action() {
1187 @Override
1188 public void run() {
1189 TimeGraphViewer viewer = fTimeGraphCombo.getTimeGraphViewer();
1190 ITimeGraphEntry entry = viewer.getSelection();
1191 if (entry instanceof CallStackEntry) {
1192 try {
1193 CallStackEntry callStackEntry = (CallStackEntry) entry;
da27e43a 1194 ITmfStateSystem ss = callStackEntry.getStateSystem();
0fcf3b09 1195 long time = Math.max(ss.getStartTime(), Math.min(ss.getCurrentEndTime(), viewer.getSelectionBegin()));
e8251298 1196 ThreadEntry threadEntry = (ThreadEntry) callStackEntry.getParent();
da27e43a 1197 int quark = ss.getParentAttributeQuark(callStackEntry.getQuark());
e8251298
PT
1198 ITmfStateInterval stackInterval = ss.querySingleState(time, quark);
1199 long newTime = stackInterval.getEndTime() + 1;
1200 viewer.setSelectedTimeNotify(newTime, true);
1201 stackInterval = ss.querySingleState(Math.min(ss.getCurrentEndTime(), newTime), quark);
1202 int stackLevel = stackInterval.getStateValue().unboxInt();
a3188982 1203 ITimeGraphEntry selectedEntry = threadEntry.getChildren().get(Math.max(0, stackLevel - 1));
e8251298
PT
1204 fTimeGraphCombo.setSelection(selectedEntry);
1205 viewer.getTimeGraphControl().fireSelectionChanged();
1206 startZoomThread(viewer.getTime0(), viewer.getTime1());
50659279 1207
bac9c0df 1208 } catch (AttributeNotFoundException | TimeRangeException | StateSystemDisposedException | StateValueTypeException e) {
52974e38 1209 Activator.getDefault().logError("Error querying state system", e); //$NON-NLS-1$
e8251298
PT
1210 }
1211 }
1212 }
1213 };
1214
1215 fNextEventAction.setText(Messages.TmfTimeGraphViewer_NextEventActionNameText);
1216 fNextEventAction.setToolTipText(Messages.TmfTimeGraphViewer_NextEventActionToolTipText);
1217 fNextEventAction.setImageDescriptor(Activator.getDefault().getImageDescripterFromPath(ITmfImageConstants.IMG_UI_NEXT_EVENT));
1218 }
1219
1220 return fNextEventAction;
1221 }
1222
1223 /**
1224 * Get the previous event action.
1225 *
1226 * @return The Action object
1227 */
1228 private Action getPreviousEventAction() {
1229 if (fPrevEventAction == null) {
1230 fPrevEventAction = new Action() {
1231 @Override
1232 public void run() {
1233 TimeGraphViewer viewer = fTimeGraphCombo.getTimeGraphViewer();
1234 ITimeGraphEntry entry = viewer.getSelection();
1235 if (entry instanceof CallStackEntry) {
1236 try {
1237 CallStackEntry callStackEntry = (CallStackEntry) entry;
da27e43a 1238 ITmfStateSystem ss = callStackEntry.getStateSystem();
0fcf3b09 1239 long time = Math.max(ss.getStartTime(), Math.min(ss.getCurrentEndTime(), viewer.getSelectionBegin()));
e8251298 1240 ThreadEntry threadEntry = (ThreadEntry) callStackEntry.getParent();
da27e43a 1241 int quark = ss.getParentAttributeQuark(callStackEntry.getQuark());
e8251298
PT
1242 ITmfStateInterval stackInterval = ss.querySingleState(time, quark);
1243 if (stackInterval.getStartTime() == time && time > ss.getStartTime()) {
1244 stackInterval = ss.querySingleState(time - 1, quark);
1245 }
1246 viewer.setSelectedTimeNotify(stackInterval.getStartTime(), true);
1247 int stackLevel = stackInterval.getStateValue().unboxInt();
a3188982 1248 ITimeGraphEntry selectedEntry = threadEntry.getChildren().get(Math.max(0, stackLevel - 1));
e8251298
PT
1249 fTimeGraphCombo.setSelection(selectedEntry);
1250 viewer.getTimeGraphControl().fireSelectionChanged();
1251 startZoomThread(viewer.getTime0(), viewer.getTime1());
50659279 1252
bac9c0df 1253 } catch (AttributeNotFoundException | TimeRangeException | StateSystemDisposedException | StateValueTypeException e) {
52974e38 1254 Activator.getDefault().logError("Error querying state system", e); //$NON-NLS-1$
e8251298
PT
1255 }
1256 }
1257 }
1258 };
1259
1260 fPrevEventAction.setText(Messages.TmfTimeGraphViewer_PreviousEventActionNameText);
1261 fPrevEventAction.setToolTipText(Messages.TmfTimeGraphViewer_PreviousEventActionToolTipText);
1262 fPrevEventAction.setImageDescriptor(Activator.getDefault().getImageDescripterFromPath(ITmfImageConstants.IMG_UI_PREV_EVENT));
1263 }
1264
1265 return fPrevEventAction;
1266 }
1267
1d83ed07 1268 private static @Nullable AbstractCallStackAnalysis getCallStackModule(@NonNull ITmfTrace trace) {
50659279
AM
1269 /*
1270 * Since we cannot know the exact analysis ID (in separate plugins), we
1271 * will search using the analysis type.
1272 */
1273 Iterable<AbstractCallStackAnalysis> modules =
b8585c7c 1274 TmfTraceUtils.getAnalysisModulesOfClass(trace, AbstractCallStackAnalysis.class);
50659279
AM
1275 Iterator<AbstractCallStackAnalysis> it = modules.iterator();
1276 if (!it.hasNext()) {
1277 /* This trace does not provide a call-stack analysis */
1278 return null;
1279 }
1280
1281 /*
1282 * We only look at the first module we find.
1283 *
1284 * TODO Handle the advanced case where one trace provides more than one
1285 * call-stack analysis.
1286 */
1287 AbstractCallStackAnalysis module = it.next();
1288 /* This analysis is not automatic, we need to schedule it on-demand */
1289 module.schedule();
1290 module.waitForInitialization();
da27e43a 1291 return module;
50659279
AM
1292 }
1293
5da83da5
AM
1294 // ------------------------------------------------------------------------
1295 // Methods related to function name mapping
1296 // ------------------------------------------------------------------------
1297
41d9ce5b
MAL
1298 /**
1299 * Common code for all import file mapping actions
1300 */
1301 private abstract class AbstractImportFileMappingAction extends Action {
1302 private final String fDialogTitle;
1303
1304 private AbstractImportFileMappingAction(String dialogTitle) {
1305 fDialogTitle = dialogTitle;
1306 }
1307
1308 @Override
1309 public void run() {
1310 FileDialog dialog = new FileDialog(getViewSite().getShell());
1311 dialog.setText(fDialogTitle);
1312 final String filePath = dialog.open();
1313 if (filePath == null) {
1314 /* No file was selected, don't change anything */
1315 return;
1316 }
1317
1318 /*
bac9c0df
MK
1319 * Start the mapping import in a separate thread (we do not want to
1320 * UI thread to do this).
41d9ce5b
MAL
1321 */
1322 Job job = new Job(Messages.CallStackView_ImportMappingJobName) {
1323 @Override
1324 public IStatus run(IProgressMonitor monitor) {
1325 fNameMapping = doMapping(new File(filePath));
1326
26c33ee2
PT
1327 /* Refresh call stack entries and event labels */
1328 Display.getDefault().asyncExec(new Runnable() {
1329 @Override
1330 public void run() {
1331 synchingToTime(fTimeGraphCombo.getTimeGraphViewer().getSelectionBegin());
1332 }
1333 });
41d9ce5b
MAL
1334 return Status.OK_STATUS;
1335 }
1336 };
1337 job.schedule();
1338 }
1339
1340 abstract Map<String, String> doMapping(File file);
1341 }
1342
5da83da5
AM
1343 /**
1344 * Toolbar icon to import the function address-to-name mapping file.
1345 */
1346 private Action getImportMappingAction() {
1347 if (fImportMappingAction != null) {
1348 return fImportMappingAction;
1349 }
41d9ce5b 1350 fImportMappingAction = new AbstractImportFileMappingAction(Messages.CallStackView_ImportMappingDialogTitle) {
5da83da5 1351 @Override
41d9ce5b
MAL
1352 Map<String, String> doMapping(File file) {
1353 return FunctionNameMapper.mapFromNmTextFile(file);
5da83da5
AM
1354 }
1355 };
1356
1357 fImportMappingAction.setText(Messages.CallStackView_ImportMappingButtonText);
1358 fImportMappingAction.setToolTipText(Messages.CallStackView_ImportMappingButtonTooltip);
1359 fImportMappingAction.setImageDescriptor(Activator.getDefault().getImageDescripterFromPath(IMPORT_MAPPING_ICON_PATH));
1360
1361 return fImportMappingAction;
1362 }
1363
46cc1ade
PT
1364 private Action getSortByNameAction() {
1365 if (fSortByNameAction == null) {
1366 fSortByNameAction = new Action(Messages.CallStackView_SortByThreadName, IAction.AS_CHECK_BOX) {
1367 @Override
1368 public void run() {
1369 if (fSortOption == SortOption.BY_NAME) {
1370 saveSortOption(SortOption.BY_NAME_REV);
1371 } else {
1372 saveSortOption(SortOption.BY_NAME);
1373 }
1374 }
1375 };
1376 fSortByNameAction.setToolTipText(Messages.CallStackView_SortByThreadName);
6aea3caa 1377 fSortByNameAction.setImageDescriptor(SORT_BY_NAME_ICON);
46cc1ade
PT
1378 }
1379 return fSortByNameAction;
1380 }
1381
1382 private Action getSortByIdAction() {
1383 if (fSortByIdAction == null) {
1384 fSortByIdAction = new Action(Messages.CallStackView_SortByThreadId, IAction.AS_CHECK_BOX) {
1385 @Override
1386 public void run() {
1387 if (fSortOption == SortOption.BY_ID) {
1388 saveSortOption(SortOption.BY_ID_REV);
1389 } else {
1390 saveSortOption(SortOption.BY_ID);
1391 }
1392 }
1393 };
1394 fSortByIdAction.setToolTipText(Messages.CallStackView_SortByThreadId);
6aea3caa 1395 fSortByIdAction.setImageDescriptor(SORT_BY_ID_ICON);
46cc1ade
PT
1396 }
1397 return fSortByIdAction;
1398 }
1399
1400 private Action getSortByTimeAction() {
1401 if (fSortByTimeAction == null) {
1402 fSortByTimeAction = new Action(Messages.CallStackView_SortByThreadTime, IAction.AS_CHECK_BOX) {
1403 @Override
1404 public void run() {
1405 if (fSortOption == SortOption.BY_TIME) {
1406 saveSortOption(SortOption.BY_TIME_REV);
1407 } else {
1408 saveSortOption(SortOption.BY_TIME);
1409 }
1410 }
1411 };
1412 fSortByTimeAction.setToolTipText(Messages.CallStackView_SortByThreadTime);
6aea3caa 1413 fSortByTimeAction.setImageDescriptor(SORT_BY_TIME_ICON);
46cc1ade
PT
1414 }
1415 return fSortByTimeAction;
1416 }
1417
1418 private void loadSortOption() {
1419 IDialogSettings settings = Activator.getDefault().getDialogSettings();
1420 IDialogSettings section = settings.getSection(getClass().getName());
1421 if (section == null) {
1422 return;
1423 }
1424 String sortOption = section.get(SORT_OPTION_KEY);
6aea3caa
PT
1425 if (sortOption == null) {
1426 return;
1427 }
46cc1ade
PT
1428
1429 // reset defaults
1430 getSortByNameAction().setChecked(false);
1431 getSortByNameAction().setImageDescriptor(SORT_BY_NAME_ICON);
1432 getSortByIdAction().setChecked(false);
1433 getSortByIdAction().setImageDescriptor(SORT_BY_ID_ICON);
1434 getSortByTimeAction().setChecked(false);
1435 getSortByTimeAction().setImageDescriptor(SORT_BY_TIME_ICON);
1436
1437 if (sortOption.equals(SortOption.BY_NAME.name())) {
1438 fSortOption = SortOption.BY_NAME;
1439 fThreadComparator = new ThreadNameComparator(false);
1440 getSortByNameAction().setChecked(true);
1441 } else if (sortOption.equals(SortOption.BY_NAME_REV.name())) {
1442 fSortOption = SortOption.BY_NAME_REV;
1443 fThreadComparator = new ThreadNameComparator(true);
1444 getSortByNameAction().setChecked(true);
1445 getSortByNameAction().setImageDescriptor(SORT_BY_NAME_REV_ICON);
1446 } else if (sortOption.equals(SortOption.BY_ID.name())) {
1447 fSortOption = SortOption.BY_ID;
1448 fThreadComparator = new ThreadIdComparator(false);
1449 getSortByIdAction().setChecked(true);
1450 } else if (sortOption.equals(SortOption.BY_ID_REV.name())) {
1451 fSortOption = SortOption.BY_ID_REV;
1452 fThreadComparator = new ThreadIdComparator(true);
1453 getSortByIdAction().setChecked(true);
1454 getSortByIdAction().setImageDescriptor(SORT_BY_ID_REV_ICON);
1455 } else if (sortOption.equals(SortOption.BY_TIME.name())) {
1456 fSortOption = SortOption.BY_TIME;
1457 fThreadComparator = new ThreadTimeComparator(false);
1458 getSortByTimeAction().setChecked(true);
1459 } else if (sortOption.equals(SortOption.BY_TIME_REV.name())) {
1460 fSortOption = SortOption.BY_TIME_REV;
1461 fThreadComparator = new ThreadTimeComparator(true);
1462 getSortByTimeAction().setChecked(true);
1463 getSortByTimeAction().setImageDescriptor(SORT_BY_TIME_REV_ICON);
1464 }
1465 }
1466
1467 private void saveSortOption(SortOption sortOption) {
1468 IDialogSettings settings = Activator.getDefault().getDialogSettings();
1469 IDialogSettings section = settings.getSection(getClass().getName());
1470 if (section == null) {
1471 section = settings.addNewSection(getClass().getName());
1472 }
1473 section.put(SORT_OPTION_KEY, sortOption.name());
1474 loadSortOption();
1475 if (fEntryList == null) {
1476 return;
1477 }
1478 for (TraceEntry traceEntry : fEntryList) {
1479 traceEntry.sortChildren(fThreadComparator);
1480 }
1481 refresh();
1482 }
1483
41d9ce5b
MAL
1484 /**
1485 * Toolbar icon to import the function address-to-name mapping binary file.
1486 */
1487 private Action getImportBinaryAction() {
1488 if (fImportBinaryFileMappingAction != null) {
1489 return fImportBinaryFileMappingAction;
5da83da5
AM
1490 }
1491
41d9ce5b
MAL
1492 fImportBinaryFileMappingAction = new AbstractImportFileMappingAction(Messages.CallStackView_ImportBinaryFileDialogTitle) {
1493 @Override
1494 Map<String, String> doMapping(File file) {
1495 return FunctionNameMapper.mapFromBinaryFile(file);
1496 }
1497 };
5da83da5 1498
41d9ce5b
MAL
1499 fImportBinaryFileMappingAction.setText(Messages.CallStackView_ImportBinaryFileButtonText);
1500 fImportBinaryFileMappingAction.setToolTipText(Messages.CallStackView_ImportBinaryFileButtonTooltip);
1501 fImportBinaryFileMappingAction.setImageDescriptor(Activator.getDefault().getImageDescripterFromPath(IMPORT_BINARY_ICON_PATH));
5da83da5 1502
41d9ce5b 1503 return fImportBinaryFileMappingAction;
5da83da5
AM
1504 }
1505
1506 String getFunctionName(String address) {
1507 if (fNameMapping == null) {
1508 /* No mapping available, just print the addresses */
1509 return address;
1510 }
1511 String ret = fNameMapping.get(address);
1512 if (ret == null) {
bac9c0df
MK
1513 /*
1514 * We didn't find this address in the mapping file, just use the
1515 * address
1516 */
5da83da5
AM
1517 return address;
1518 }
1519 return ret;
1520 }
1521
d2e4afa7
MAL
1522 /**
1523 * @since 1.0
1524 */
1525 @Override
1526 public TmfTimeViewAlignmentInfo getTimeViewAlignmentInfo() {
1527 if (fTimeGraphCombo == null) {
1528 return null;
1529 }
1530 return fTimeGraphCombo.getTimeViewAlignmentInfo();
1531 }
1532
1533 /**
1534 * @since 1.0
1535 */
1536 @Override
1537 public int getAvailableWidth(int requestedOffset) {
1538 if (fTimeGraphCombo == null) {
1539 return 0;
1540 }
1541 return fTimeGraphCombo.getAvailableWidth(requestedOffset);
1542 }
1543
1544 /**
1545 * @since 1.0
1546 */
1547 @Override
1548 public void performAlign(int offset, int width) {
1549 fTimeGraphCombo.performAlign(offset, width);
1550 }
e8251298 1551}
This page took 0.164483 seconds and 5 git commands to generate.