1 /*******************************************************************************
2 * Copyright (c) 2012 Ericsson
4 * All rights reserved. This program and the accompanying materials are
5 * made available under the terms of the Eclipse Public License v1.0 which
6 * accompanies this distribution, and is available at
7 * http://www.eclipse.org/legal/epl-v10.html
10 * Patrick Tasse - Initial API and implementation
11 *******************************************************************************/
13 package org
.eclipse
.linuxtools
.internal
.lttng2
.kernel
.ui
.views
.controlflow
;
15 import java
.util
.ArrayList
;
16 import java
.util
.Arrays
;
17 import java
.util
.HashMap
;
18 import java
.util
.List
;
21 import org
.eclipse
.jface
.action
.Action
;
22 import org
.eclipse
.jface
.action
.IToolBarManager
;
23 import org
.eclipse
.jface
.action
.Separator
;
24 import org
.eclipse
.jface
.viewers
.ILabelProviderListener
;
25 import org
.eclipse
.jface
.viewers
.ITableLabelProvider
;
26 import org
.eclipse
.jface
.viewers
.ITreeContentProvider
;
27 import org
.eclipse
.jface
.viewers
.Viewer
;
28 import org
.eclipse
.linuxtools
.internal
.lttng2
.kernel
.ui
.Messages
;
29 import org
.eclipse
.linuxtools
.lttng2
.kernel
.core
.trace
.Attributes
;
30 import org
.eclipse
.linuxtools
.lttng2
.kernel
.core
.trace
.CtfKernelTrace
;
31 import org
.eclipse
.linuxtools
.tmf
.core
.ctfadaptor
.CtfTmfTimestamp
;
32 import org
.eclipse
.linuxtools
.tmf
.core
.event
.ITmfEvent
;
33 import org
.eclipse
.linuxtools
.tmf
.core
.event
.TmfTimeRange
;
34 import org
.eclipse
.linuxtools
.tmf
.core
.event
.TmfTimestamp
;
35 import org
.eclipse
.linuxtools
.tmf
.core
.exceptions
.AttributeNotFoundException
;
36 import org
.eclipse
.linuxtools
.tmf
.core
.exceptions
.StateValueTypeException
;
37 import org
.eclipse
.linuxtools
.tmf
.core
.exceptions
.TimeRangeException
;
38 import org
.eclipse
.linuxtools
.tmf
.core
.interval
.ITmfStateInterval
;
39 import org
.eclipse
.linuxtools
.tmf
.core
.signal
.TmfExperimentSelectedSignal
;
40 import org
.eclipse
.linuxtools
.tmf
.core
.signal
.TmfRangeSynchSignal
;
41 import org
.eclipse
.linuxtools
.tmf
.core
.signal
.TmfSignalHandler
;
42 import org
.eclipse
.linuxtools
.tmf
.core
.signal
.TmfTimeSynchSignal
;
43 import org
.eclipse
.linuxtools
.tmf
.core
.statesystem
.IStateSystemQuerier
;
44 import org
.eclipse
.linuxtools
.tmf
.core
.trace
.ITmfTrace
;
45 import org
.eclipse
.linuxtools
.tmf
.core
.trace
.TmfExperiment
;
46 import org
.eclipse
.linuxtools
.tmf
.ui
.views
.TmfView
;
47 import org
.eclipse
.linuxtools
.tmf
.ui
.widgets
.timegraph
.ITimeGraphRangeListener
;
48 import org
.eclipse
.linuxtools
.tmf
.ui
.widgets
.timegraph
.ITimeGraphSelectionListener
;
49 import org
.eclipse
.linuxtools
.tmf
.ui
.widgets
.timegraph
.ITimeGraphTimeListener
;
50 import org
.eclipse
.linuxtools
.tmf
.ui
.widgets
.timegraph
.StateItem
;
51 import org
.eclipse
.linuxtools
.tmf
.ui
.widgets
.timegraph
.TimeGraphCombo
;
52 import org
.eclipse
.linuxtools
.tmf
.ui
.widgets
.timegraph
.TimeGraphPresentationProvider
;
53 import org
.eclipse
.linuxtools
.tmf
.ui
.widgets
.timegraph
.TimeGraphRangeUpdateEvent
;
54 import org
.eclipse
.linuxtools
.tmf
.ui
.widgets
.timegraph
.TimeGraphSelectionEvent
;
55 import org
.eclipse
.linuxtools
.tmf
.ui
.widgets
.timegraph
.TimeGraphTimeEvent
;
56 import org
.eclipse
.linuxtools
.tmf
.ui
.widgets
.timegraph
.model
.ITimeEvent
;
57 import org
.eclipse
.linuxtools
.tmf
.ui
.widgets
.timegraph
.model
.ITimeGraphEntry
;
58 import org
.eclipse
.linuxtools
.tmf
.ui
.widgets
.timegraph
.model
.TimeEvent
;
59 import org
.eclipse
.linuxtools
.tmf
.ui
.widgets
.timegraph
.widgets
.Utils
;
60 import org
.eclipse
.linuxtools
.tmf
.ui
.widgets
.timegraph
.widgets
.Utils
.Resolution
;
61 import org
.eclipse
.linuxtools
.tmf
.ui
.widgets
.timegraph
.widgets
.Utils
.TimeFormat
;
62 import org
.eclipse
.swt
.SWT
;
63 import org
.eclipse
.swt
.graphics
.Image
;
64 import org
.eclipse
.swt
.graphics
.RGB
;
65 import org
.eclipse
.swt
.widgets
.Composite
;
66 import org
.eclipse
.swt
.widgets
.Display
;
67 import org
.eclipse
.swt
.widgets
.TreeColumn
;
68 import org
.eclipse
.ui
.IActionBars
;
70 public class ControlFlowView
extends TmfView
{
72 // ------------------------------------------------------------------------
74 // ------------------------------------------------------------------------
79 public static final String ID
= "org.eclipse.linuxtools.lttng2.kernel.ui.views.controlflow"; //$NON-NLS-1$
81 private static final String PROCESS_COLUMN
= Messages
.ControlFlowView_processColumn
;
82 private static final String TID_COLUMN
= Messages
.ControlFlowView_tidColumn
;
83 private static final String PPID_COLUMN
= Messages
.ControlFlowView_ppidColumn
;
84 private static final String BIRTH_TIME_COLUMN
= Messages
.ControlFlowView_birthTimeColumn
;
85 private static final String TRACE_COLUMN
= Messages
.ControlFlowView_traceColumn
;
87 private final String
[] COLUMN_NAMES
= new String
[] {
95 // ------------------------------------------------------------------------
97 // ------------------------------------------------------------------------
99 // The timegraph combo
100 private TimeGraphCombo fTimeGraphCombo
;
102 // The selected experiment
103 private TmfExperiment
<ITmfEvent
> fSelectedExperiment
;
105 // The timegraph entry list
106 private ArrayList
<ControlFlowEntry
> fEntryList
;
109 private long fStartTime
;
112 private long fEndTime
;
115 private int fDisplayWidth
;
118 private ZoomThread fZoomThread
;
120 // The next resource action
121 private Action fNextResourceAction
;
123 // The previous resource action
124 private Action fPreviousResourceAction
;
126 // ------------------------------------------------------------------------
128 // ------------------------------------------------------------------------
130 private class TreeContentProvider
implements ITreeContentProvider
{
133 public void dispose() {
137 public void inputChanged(Viewer viewer
, Object oldInput
, Object newInput
) {
141 public Object
[] getElements(Object inputElement
) {
142 return (ITimeGraphEntry
[]) inputElement
;
146 public Object
[] getChildren(Object parentElement
) {
147 ITimeGraphEntry entry
= (ITimeGraphEntry
) parentElement
;
148 return entry
.getChildren();
152 public Object
getParent(Object element
) {
153 ITimeGraphEntry entry
= (ITimeGraphEntry
) element
;
154 return entry
.getParent();
158 public boolean hasChildren(Object element
) {
159 ITimeGraphEntry entry
= (ITimeGraphEntry
) element
;
160 return entry
.hasChildren();
165 private class TreeLabelProvider
implements ITableLabelProvider
{
168 public void addListener(ILabelProviderListener listener
) {
172 public void dispose() {
176 public boolean isLabelProperty(Object element
, String property
) {
181 public void removeListener(ILabelProviderListener listener
) {
185 public Image
getColumnImage(Object element
, int columnIndex
) {
190 public String
getColumnText(Object element
, int columnIndex
) {
191 ControlFlowEntry entry
= (ControlFlowEntry
) element
;
192 if (columnIndex
== 0) {
193 return entry
.getName();
194 } else if (columnIndex
== 1) {
195 return Integer
.toString(entry
.getThreadId());
196 } else if (columnIndex
== 2) {
197 if (entry
.getPPID() > 0) {
198 return Integer
.toString(entry
.getPPID());
200 } else if (columnIndex
== 3) {
201 return Utils
.formatTime(entry
.getBirthTime(), TimeFormat
.ABSOLUTE
, Resolution
.NANOSEC
);
202 } else if (columnIndex
== 4) {
203 return entry
.getTrace().getName();
205 return ""; //$NON-NLS-1$
210 private class ZoomThread
extends Thread
{
211 private long fStartTime
;
212 private long fEndTime
;
213 private long fResolution
;
214 private boolean fCancelled
= false;
216 public ZoomThread(long startTime
, long endTime
) {
217 super("ControlFlowView zoom"); //$NON-NLS-1$
218 fStartTime
= startTime
;
220 fResolution
= Math
.max(1, (fEndTime
- fStartTime
) / fDisplayWidth
);
225 if (fEntryList
== null) {
228 for (ControlFlowEntry entry
: fEntryList
) {
237 private void zoom(ControlFlowEntry entry
) {
238 List
<ITimeEvent
> zoomedEventList
= getEventList(entry
, fStartTime
, fEndTime
, fResolution
);
239 entry
.setZoomedEventList(zoomedEventList
);
240 for (ControlFlowEntry child
: entry
.getChildren()) {
248 public void cancel() {
253 // ------------------------------------------------------------------------
255 // ------------------------------------------------------------------------
257 public ControlFlowView() {
259 fDisplayWidth
= Display
.getDefault().getBounds().width
;
262 // ------------------------------------------------------------------------
264 // ------------------------------------------------------------------------
267 * @see org.eclipse.linuxtools.tmf.ui.views.TmfView#createPartControl(org.eclipse.swt.widgets.Composite)
270 public void createPartControl(Composite parent
) {
271 fTimeGraphCombo
= new TimeGraphCombo(parent
, SWT
.NONE
);
273 fTimeGraphCombo
.setTreeContentProvider(new TreeContentProvider());
275 fTimeGraphCombo
.setTreeLabelProvider(new TreeLabelProvider());
277 fTimeGraphCombo
.setTimeGraphProvider(new TimeGraphPresentationProvider() {
278 private static final String UNKNOWN
= "UNKNOWN"; //$NON-NLS-1$
279 private static final String WAIT
= "WAIT"; //$NON-NLS-1$
280 private static final String USERMODE
= "USERMODE"; //$NON-NLS-1$
281 private static final String SYSCALL
= "SYSCALL"; //$NON-NLS-1$
282 private static final String INTERRUPTED
= "INTERRUPTED"; //$NON-NLS-1$
285 public String
getStateTypeName() {
286 return Messages
.ControlFlowView_stateTypeName
;
290 public StateItem
[] getStateTable() {
291 return new StateItem
[] {
292 new StateItem(new RGB(100, 100, 100), UNKNOWN
),
293 new StateItem(new RGB(150, 150, 0), WAIT
),
294 new StateItem(new RGB(0, 200, 0), USERMODE
),
295 new StateItem(new RGB(0, 0, 200), SYSCALL
),
296 new StateItem(new RGB(200, 100, 100), INTERRUPTED
)
301 public int getEventTableIndex(ITimeEvent event
) {
302 if (event
instanceof ControlFlowEvent
) {
303 int status
= ((ControlFlowEvent
) event
).getStatus();
304 if (status
== Attributes
.STATUS_WAIT
) {
306 } else if (status
== Attributes
.STATUS_RUN_USERMODE
) {
308 } else if (status
== Attributes
.STATUS_RUN_SYSCALL
) {
310 } else if (status
== Attributes
.STATUS_INTERRUPTED
) {
318 public String
getEventName(ITimeEvent event
) {
319 if (event
instanceof ControlFlowEvent
) {
320 int status
= ((ControlFlowEvent
) event
).getStatus();
321 if (status
== Attributes
.STATUS_WAIT
) {
323 } else if (status
== Attributes
.STATUS_RUN_USERMODE
) {
325 } else if (status
== Attributes
.STATUS_RUN_SYSCALL
) {
327 } else if (status
== Attributes
.STATUS_INTERRUPTED
) {
335 public Map
<String
, String
> getEventHoverToolTipInfo(ITimeEvent event
) {
336 return new HashMap
<String
, String
>();
340 fTimeGraphCombo
.setTreeColumns(COLUMN_NAMES
);
342 fTimeGraphCombo
.getTimeGraphViewer().addRangeListener(new ITimeGraphRangeListener() {
344 public void timeRangeUpdated(TimeGraphRangeUpdateEvent event
) {
345 final long startTime
= event
.getStartTime();
346 final long endTime
= event
.getEndTime();
347 TmfTimeRange range
= new TmfTimeRange(new CtfTmfTimestamp(startTime
), new CtfTmfTimestamp(endTime
));
348 TmfTimestamp time
= new CtfTmfTimestamp(fTimeGraphCombo
.getTimeGraphViewer().getSelectedTime());
349 broadcast(new TmfRangeSynchSignal(ControlFlowView
.this, range
, time
));
350 if (fZoomThread
!= null) {
351 fZoomThread
.cancel();
353 fZoomThread
= new ZoomThread(startTime
, endTime
);
358 fTimeGraphCombo
.getTimeGraphViewer().addTimeListener(new ITimeGraphTimeListener() {
360 public void timeSelected(TimeGraphTimeEvent event
) {
361 long time
= event
.getTime();
362 broadcast(new TmfTimeSynchSignal(ControlFlowView
.this, new CtfTmfTimestamp(time
)));
366 fTimeGraphCombo
.addSelectionListener(new ITimeGraphSelectionListener() {
368 public void selectionChanged(TimeGraphSelectionEvent event
) {
369 //ITimeGraphEntry selection = event.getSelection();
373 fTimeGraphCombo
.getTimeGraphViewer().setTimeCalendarFormat(true);
375 final Thread thread
= new Thread("ControlFlowView build") { //$NON-NLS-1$
378 if (TmfExperiment
.getCurrentExperiment() != null) {
379 selectExperiment(TmfExperiment
.getCurrentExperiment());
385 // View Action Handling
387 contributeToActionBars();
391 * @see org.eclipse.ui.part.WorkbenchPart#setFocus()
394 public void setFocus() {
395 fTimeGraphCombo
.setFocus();
398 // ------------------------------------------------------------------------
400 // ------------------------------------------------------------------------
403 public void experimentSelected(final TmfExperimentSelectedSignal
<?
extends ITmfEvent
> signal
) {
404 if (signal
.getExperiment().equals(fSelectedExperiment
)) {
408 final Thread thread
= new Thread("ControlFlowView build") { //$NON-NLS-1$
411 selectExperiment(signal
.getExperiment());
417 public void synchToTime(final TmfTimeSynchSignal signal
) {
418 if (signal
.getSource() == this) {
421 final long time
= signal
.getCurrentTime().normalize(0, -9).getValue();
422 Display
.getDefault().asyncExec(new Runnable() {
425 if (fTimeGraphCombo
.isDisposed()) {
428 fTimeGraphCombo
.getTimeGraphViewer().setSelectedTime(time
, true, signal
.getSource());
434 public void synchToRange(final TmfRangeSynchSignal signal
) {
435 if (signal
.getSource() == this) {
438 final long startTime
= signal
.getCurrentRange().getStartTime().normalize(0, -9).getValue();
439 final long endTime
= signal
.getCurrentRange().getEndTime().normalize(0, -9).getValue();
440 final long time
= signal
.getCurrentTime().normalize(0, -9).getValue();
441 Display
.getDefault().asyncExec(new Runnable() {
444 if (fTimeGraphCombo
.isDisposed()) {
447 fTimeGraphCombo
.getTimeGraphViewer().setStartFinishTime(startTime
, endTime
);
448 fTimeGraphCombo
.getTimeGraphViewer().setSelectedTime(time
, false, signal
.getSource());
453 // ------------------------------------------------------------------------
455 // ------------------------------------------------------------------------
457 @SuppressWarnings("unchecked")
458 private void selectExperiment(TmfExperiment
<?
> experiment
) {
459 fStartTime
= Long
.MAX_VALUE
;
460 fEndTime
= Long
.MIN_VALUE
;
461 fSelectedExperiment
= (TmfExperiment
<ITmfEvent
>) experiment
;
462 fEntryList
= new ArrayList
<ControlFlowEntry
>();
463 for (ITmfTrace
<?
> trace
: experiment
.getTraces()) {
464 if (trace
instanceof CtfKernelTrace
) {
465 CtfKernelTrace ctfKernelTrace
= (CtfKernelTrace
) trace
;
466 IStateSystemQuerier ssq
= ctfKernelTrace
.getStateSystem();
467 long start
= ssq
.getStartTime();
468 long end
= ssq
.getCurrentEndTime();
469 fStartTime
= Math
.min(fStartTime
, start
);
470 fEndTime
= Math
.max(fEndTime
, end
);
471 List
<Integer
> threadQuarks
= ssq
.getQuarks(Attributes
.THREADS
, "*"); //$NON-NLS-1$
472 for (int threadQuark
: threadQuarks
) {
473 String threadName
= ssq
.getAttributeName(threadQuark
);
476 threadId
= Integer
.parseInt(threadName
);
477 } catch (NumberFormatException e1
) {
480 if (threadId
== 0) { // ignore the swapper thread
483 int execNameQuark
= -1;
486 execNameQuark
= ssq
.getQuarkRelative(threadQuark
, Attributes
.EXEC_NAME
);
487 } catch (AttributeNotFoundException e
) {
490 int ppidQuark
= ssq
.getQuarkRelative(threadQuark
, Attributes
.PPID
);
491 List
<ITmfStateInterval
> execNameIntervals
= ssq
.queryHistoryRange(execNameQuark
, start
, end
);
493 for (ITmfStateInterval execNameInterval
: execNameIntervals
) {
494 if (!execNameInterval
.getStateValue().isNull() && execNameInterval
.getStateValue().getType() == 1) {
495 String execName
= execNameInterval
.getStateValue().unboxStr();
496 long startTime
= execNameInterval
.getStartTime();
497 long endTime
= execNameInterval
.getEndTime() + 1;
498 if (birthTime
== -1) {
499 birthTime
= startTime
;
502 if (ppidQuark
!= -1) {
503 ITmfStateInterval ppidInterval
= ssq
.querySingleState(startTime
, ppidQuark
);
504 ppid
= ppidInterval
.getStateValue().unboxInt();
506 ControlFlowEntry entry
= new ControlFlowEntry(threadQuark
, ctfKernelTrace
, execName
, threadId
, ppid
, birthTime
, startTime
, endTime
);
507 fEntryList
.add(entry
);
508 entry
.addEvent(new TimeEvent(entry
, startTime
, endTime
- startTime
));
513 } catch (AttributeNotFoundException e
) {
515 } catch (TimeRangeException e
) {
517 } catch (StateValueTypeException e
) {
524 ControlFlowEntry
[] entries
= fEntryList
.toArray(new ControlFlowEntry
[0]);
525 Arrays
.sort(entries
);
526 for (ControlFlowEntry entry
: entries
) {
527 buildStatusEvents(entry
);
532 private void buildTree() {
533 ArrayList
<ControlFlowEntry
> rootList
= new ArrayList
<ControlFlowEntry
>();
534 for (ControlFlowEntry entry
: fEntryList
) {
536 if (entry
.getPPID() > 0) {
537 for (ControlFlowEntry parent
: fEntryList
) {
538 if (parent
.getThreadId() == entry
.getPPID() &&
539 entry
.getStartTime() >= parent
.getStartTime() &&
540 entry
.getStartTime() <= parent
.getEndTime()) {
541 parent
.addChild(entry
);
551 fEntryList
= rootList
;
554 private void buildStatusEvents(ControlFlowEntry entry
) {
555 IStateSystemQuerier ssq
= entry
.getTrace().getStateSystem();
556 long start
= ssq
.getStartTime();
557 long end
= ssq
.getCurrentEndTime();
558 long resolution
= Math
.max(1, (end
- start
) / fDisplayWidth
);
559 List
<ITimeEvent
> eventList
= getEventList(entry
, entry
.getStartTime(), entry
.getEndTime(), resolution
);
560 entry
.setEventList(eventList
);
562 for (ITimeGraphEntry child
: entry
.getChildren()) {
563 buildStatusEvents((ControlFlowEntry
) child
);
567 private List
<ITimeEvent
> getEventList(ControlFlowEntry entry
, long startTime
, long endTime
, long resolution
) {
568 startTime
= Math
.max(startTime
, entry
.getStartTime());
569 endTime
= Math
.min(endTime
, entry
.getEndTime());
570 if (endTime
<= startTime
) {
573 IStateSystemQuerier ssq
= entry
.getTrace().getStateSystem();
574 List
<ITimeEvent
> eventList
= null;
576 int statusQuark
= ssq
.getQuarkRelative(entry
.getThreadQuark(), Attributes
.STATUS
);
577 List
<ITmfStateInterval
> statusIntervals
= ssq
.queryHistoryRange(statusQuark
, startTime
, endTime
- 1, resolution
);
578 eventList
= new ArrayList
<ITimeEvent
>(statusIntervals
.size());
579 long lastEndTime
= -1;
580 for (ITmfStateInterval statusInterval
: statusIntervals
) {
581 long time
= statusInterval
.getStartTime();
582 long duration
= statusInterval
.getEndTime() - time
+ 1;
585 status
= statusInterval
.getStateValue().unboxInt();
586 } catch (StateValueTypeException e
) {
589 if (lastEndTime
!= time
&& lastEndTime
!= -1) {
590 eventList
.add(new ControlFlowEvent(entry
, lastEndTime
, time
- lastEndTime
, 0));
592 eventList
.add(new ControlFlowEvent(entry
, time
, duration
, status
));
593 lastEndTime
= time
+ duration
;
595 } catch (AttributeNotFoundException e
) {
597 } catch (TimeRangeException e
) {
603 private void refresh() {
604 Display
.getDefault().asyncExec(new Runnable() {
607 if (fTimeGraphCombo
.isDisposed()) {
610 ITimeGraphEntry
[] entries
= fEntryList
.toArray(new ITimeGraphEntry
[0]);
611 Arrays
.sort(entries
);
612 fTimeGraphCombo
.setInput(entries
);
613 fTimeGraphCombo
.getTimeGraphViewer().setTimeBounds(fStartTime
, fEndTime
);
614 fTimeGraphCombo
.getTimeGraphViewer().setStartFinishTime(fStartTime
, fEndTime
);
615 for (TreeColumn column
: fTimeGraphCombo
.getTreeViewer().getTree().getColumns()) {
622 private void redraw() {
623 Display
.getDefault().asyncExec(new Runnable() {
626 if (fTimeGraphCombo
.isDisposed()) {
629 fTimeGraphCombo
.redraw();
630 fTimeGraphCombo
.update();
635 private void makeActions() {
636 fPreviousResourceAction
= fTimeGraphCombo
.getTimeGraphViewer().getPreviousItemAction();
637 fPreviousResourceAction
.setText(Messages
.ControlFlowView_previousProcessActionNameText
);
638 fPreviousResourceAction
.setToolTipText(Messages
.ControlFlowView_previousProcessActionToolTipText
);
639 fNextResourceAction
= fTimeGraphCombo
.getTimeGraphViewer().getNextItemAction();
640 fNextResourceAction
.setText(Messages
.ControlFlowView_nextProcessActionNameText
);
641 fNextResourceAction
.setToolTipText(Messages
.ControlFlowView_nextProcessActionToolTipText
);
644 private void contributeToActionBars() {
645 IActionBars bars
= getViewSite().getActionBars();
646 fillLocalToolBar(bars
.getToolBarManager());
649 private void fillLocalToolBar(IToolBarManager manager
) {
650 manager
.add(fTimeGraphCombo
.getTimeGraphViewer().getShowLegendAction());
651 manager
.add(new Separator());
652 manager
.add(fTimeGraphCombo
.getTimeGraphViewer().getResetScaleAction());
653 manager
.add(fTimeGraphCombo
.getTimeGraphViewer().getPreviousEventAction());
654 manager
.add(fTimeGraphCombo
.getTimeGraphViewer().getNextEventAction());
655 manager
.add(fPreviousResourceAction
);
656 manager
.add(fNextResourceAction
);
657 manager
.add(fTimeGraphCombo
.getTimeGraphViewer().getZoomInAction());
658 manager
.add(fTimeGraphCombo
.getTimeGraphViewer().getZoomOutAction());
659 manager
.add(new Separator());