1 /*******************************************************************************
2 * Copyright (c) 2012, 2013 Ericsson, École Polytechnique de Montréal
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 * Bernd Hufmann - Updated signal handling
12 * Geneviève Bastien - Move code to provide base classes for time graph view
13 *******************************************************************************/
15 package org
.eclipse
.linuxtools
.tmf
.ui
.views
.timegraph
;
17 import java
.util
.ArrayList
;
18 import java
.util
.Arrays
;
19 import java
.util
.Collections
;
20 import java
.util
.Comparator
;
21 import java
.util
.HashMap
;
22 import java
.util
.List
;
25 import org
.eclipse
.core
.runtime
.IProgressMonitor
;
26 import org
.eclipse
.core
.runtime
.NullProgressMonitor
;
27 import org
.eclipse
.jface
.action
.Action
;
28 import org
.eclipse
.jface
.action
.IToolBarManager
;
29 import org
.eclipse
.jface
.action
.Separator
;
30 import org
.eclipse
.jface
.viewers
.ILabelProviderListener
;
31 import org
.eclipse
.jface
.viewers
.ITableLabelProvider
;
32 import org
.eclipse
.jface
.viewers
.ITreeContentProvider
;
33 import org
.eclipse
.jface
.viewers
.Viewer
;
34 import org
.eclipse
.linuxtools
.tmf
.core
.ctfadaptor
.CtfTmfTimestamp
;
35 import org
.eclipse
.linuxtools
.tmf
.core
.signal
.TmfRangeSynchSignal
;
36 import org
.eclipse
.linuxtools
.tmf
.core
.signal
.TmfSignalHandler
;
37 import org
.eclipse
.linuxtools
.tmf
.core
.signal
.TmfTimeSynchSignal
;
38 import org
.eclipse
.linuxtools
.tmf
.core
.signal
.TmfTraceClosedSignal
;
39 import org
.eclipse
.linuxtools
.tmf
.core
.signal
.TmfTraceOpenedSignal
;
40 import org
.eclipse
.linuxtools
.tmf
.core
.signal
.TmfTraceSelectedSignal
;
41 import org
.eclipse
.linuxtools
.tmf
.core
.timestamp
.ITmfTimestamp
;
42 import org
.eclipse
.linuxtools
.tmf
.core
.timestamp
.TmfTimeRange
;
43 import org
.eclipse
.linuxtools
.tmf
.core
.timestamp
.TmfTimestamp
;
44 import org
.eclipse
.linuxtools
.tmf
.core
.trace
.ITmfTrace
;
45 import org
.eclipse
.linuxtools
.tmf
.ui
.views
.TmfView
;
46 import org
.eclipse
.linuxtools
.tmf
.ui
.widgets
.timegraph
.ITimeGraphRangeListener
;
47 import org
.eclipse
.linuxtools
.tmf
.ui
.widgets
.timegraph
.ITimeGraphSelectionListener
;
48 import org
.eclipse
.linuxtools
.tmf
.ui
.widgets
.timegraph
.ITimeGraphTimeListener
;
49 import org
.eclipse
.linuxtools
.tmf
.ui
.widgets
.timegraph
.TimeGraphCombo
;
50 import org
.eclipse
.linuxtools
.tmf
.ui
.widgets
.timegraph
.TimeGraphPresentationProvider
;
51 import org
.eclipse
.linuxtools
.tmf
.ui
.widgets
.timegraph
.TimeGraphRangeUpdateEvent
;
52 import org
.eclipse
.linuxtools
.tmf
.ui
.widgets
.timegraph
.TimeGraphSelectionEvent
;
53 import org
.eclipse
.linuxtools
.tmf
.ui
.widgets
.timegraph
.TimeGraphTimeEvent
;
54 import org
.eclipse
.linuxtools
.tmf
.ui
.widgets
.timegraph
.model
.ITimeEvent
;
55 import org
.eclipse
.linuxtools
.tmf
.ui
.widgets
.timegraph
.model
.ITimeGraphEntry
;
56 import org
.eclipse
.linuxtools
.tmf
.ui
.widgets
.timegraph
.model
.TimeGraphEntry
;
57 import org
.eclipse
.linuxtools
.tmf
.ui
.widgets
.timegraph
.widgets
.Utils
.TimeFormat
;
58 import org
.eclipse
.swt
.SWT
;
59 import org
.eclipse
.swt
.graphics
.Image
;
60 import org
.eclipse
.swt
.widgets
.Composite
;
61 import org
.eclipse
.swt
.widgets
.Display
;
62 import org
.eclipse
.swt
.widgets
.TreeColumn
;
63 import org
.eclipse
.ui
.IActionBars
;
66 * An abstract view all time graph views can inherit
68 * This view contains a time graph combo, divided between a treeview on the
69 * left, showing entries and a canvas on the right to draw something for these
74 public abstract class AbstractTimeGraphView
extends TmfView
{
76 private final String
[] fColumns
;
77 private final String
[] fFilterColumns
;
86 // ------------------------------------------------------------------------
88 // ------------------------------------------------------------------------
90 /** The timegraph combo */
91 private TimeGraphCombo fTimeGraphCombo
;
93 /** The selected trace */
94 private ITmfTrace fTrace
;
96 /** The timegraph entry list */
97 private List
<TimeGraphEntry
> fEntryList
;
99 /** The trace to entry list hash map */
100 private final Map
<ITmfTrace
, List
<TimeGraphEntry
>> fEntryListMap
= new HashMap
<ITmfTrace
, List
<TimeGraphEntry
>>();
102 /* The trace to build thread hash map */
103 private final Map
<ITmfTrace
, BuildThread
> fBuildThreadMap
= new HashMap
<ITmfTrace
, BuildThread
>();
105 /** The start time */
106 private long fStartTime
;
109 private long fEndTime
;
111 /** The display width */
112 private final int fDisplayWidth
;
114 /** The zoom thread */
115 private ZoomThread fZoomThread
;
117 /** The next resource action */
118 private Action fNextResourceAction
;
120 /** The previous resource action */
121 private Action fPreviousResourceAction
;
123 /** The relative weight of the sash */
124 private int[] fWeight
= { 1, 1 };
126 /** A comparator class */
127 private Comparator
<ITimeGraphEntry
> fEntryComparator
= null;
129 /** The redraw state used to prevent unnecessary queuing of display runnables */
130 private State fRedrawState
= State
.IDLE
;
132 /** The redraw synchronization object */
133 private final Object fSyncObj
= new Object();
135 /** The presentation provider for this view */
136 private final TimeGraphPresentationProvider fPresentation
;
138 private TreeLabelProvider fLabelProvider
= new TreeLabelProvider();
140 // ------------------------------------------------------------------------
141 // Getters and setters
142 // ------------------------------------------------------------------------
145 * Getter for the time graph combo
147 * @return The Time graph combo
149 protected TimeGraphCombo
getTimeGraphCombo() {
150 return fTimeGraphCombo
;
154 * Sets the tree label provider
157 * The tree label provider
159 protected void setTreeLabelProvider(final TreeLabelProvider tlp
) {
160 fLabelProvider
= tlp
;
164 * Sets the relative weight of each part of the time graph combo
167 * The array of relative weights of each part of the combo
169 protected void setWeight(final int[] weights
) {
174 * Gets the display width
176 * @return the display width
178 protected int getDisplayWidth() {
179 return fDisplayWidth
;
183 * Gets the comparator for the entries
185 * @return The entry comparator
187 protected Comparator
<ITimeGraphEntry
> getEntryComparator() {
188 return fEntryComparator
;
192 * Sets the comparator class for the entries * Gets the display width
195 * A comparator object
197 protected void setEntryComparator(final Comparator
<ITimeGraphEntry
> comparator
) {
198 fEntryComparator
= comparator
;
202 * Gets the trace displayed in the view
206 protected ITmfTrace
getTrace() {
211 * Sets the trace to display
216 protected void setTrace(final ITmfTrace trace
) {
221 * Gets the start time
223 * @return The start time
225 protected long getStartTime() {
230 * Sets the start time
235 protected void setStartTime(long time
) {
242 * @return The end time
244 protected long getEndTime() {
254 protected void setEndTime(long time
) {
259 * Gets the entry list map
261 * @return the entry list map
263 protected Map
<ITmfTrace
, List
<TimeGraphEntry
>> getEntryListMap() {
264 return Collections
.unmodifiableMap(fEntryListMap
);
268 * Adds an entry to the entry list
273 * The list of time graph entries
275 protected void putEntryList(ITmfTrace trace
, List
<TimeGraphEntry
> list
) {
276 synchronized(fEntryListMap
) {
277 fEntryListMap
.put(trace
, list
);
282 * Text for the "next" button
284 * @return The "next" button text
286 protected String
getNextText() {
287 return Messages
.AbstractTimeGraphtView_NextText
;
291 * Tooltip for the "next" button
293 * @return Tooltip for the "next" button
295 protected String
getNextTooltip() {
296 return Messages
.AbstractTimeGraphView_NextTooltip
;
300 * Text for the "Previous" button
302 * @return The "Previous" button text
304 protected String
getPrevText() {
305 return Messages
.AbstractTimeGraphView_PreviousText
;
309 * Tooltip for the "previous" button
311 * @return Tooltip for the "previous" button
313 protected String
getPrevTooltip() {
314 return Messages
.AbstractTimeGraphView_PreviousTooltip
;
317 // ------------------------------------------------------------------------
319 // ------------------------------------------------------------------------
321 private class TreeContentProvider
implements ITreeContentProvider
{
324 public void dispose() {
328 public void inputChanged(Viewer viewer
, Object oldInput
, Object newInput
) {
332 public Object
[] getElements(Object inputElement
) {
333 return (ITimeGraphEntry
[]) inputElement
;
337 public Object
[] getChildren(Object parentElement
) {
338 ITimeGraphEntry entry
= (ITimeGraphEntry
) parentElement
;
339 List
<?
extends ITimeGraphEntry
> children
= entry
.getChildren();
340 return children
.toArray(new ITimeGraphEntry
[children
.size()]);
344 public Object
getParent(Object element
) {
345 ITimeGraphEntry entry
= (ITimeGraphEntry
) element
;
346 return entry
.getParent();
350 public boolean hasChildren(Object element
) {
351 ITimeGraphEntry entry
= (ITimeGraphEntry
) element
;
352 return entry
.hasChildren();
358 * Base class to provide the labels for the left tree view entry. Views
359 * extending this class typically need to override the getColumnText method
360 * if they have more than one column to display
362 protected static class TreeLabelProvider
implements ITableLabelProvider
{
365 public void addListener(ILabelProviderListener listener
) {
369 public void dispose() {
373 public boolean isLabelProperty(Object element
, String property
) {
378 public void removeListener(ILabelProviderListener listener
) {
382 public Image
getColumnImage(Object element
, int columnIndex
) {
387 public String
getColumnText(Object element
, int columnIndex
) {
388 TimeGraphEntry entry
= (TimeGraphEntry
) element
;
389 if (columnIndex
== 0) {
390 return entry
.getName();
392 return ""; //$NON-NLS-1$
397 private class BuildThread
extends Thread
{
398 private final ITmfTrace fBuildTrace
;
399 private final IProgressMonitor fMonitor
;
401 public BuildThread(final ITmfTrace trace
, final String name
) {
402 super(name
+ " build"); //$NON-NLS-1$
404 fMonitor
= new NullProgressMonitor();
409 buildEventList(fBuildTrace
, fMonitor
);
410 synchronized (fBuildThreadMap
) {
411 fBuildThreadMap
.remove(this);
415 public void cancel() {
416 fMonitor
.setCanceled(true);
420 private class ZoomThread
extends Thread
{
421 private final List
<TimeGraphEntry
> fZoomEntryList
;
422 private final long fZoomStartTime
;
423 private final long fZoomEndTime
;
424 private final long fResolution
;
425 private final IProgressMonitor fMonitor
;
427 public ZoomThread(List
<TimeGraphEntry
> entryList
, long startTime
, long endTime
, String name
) {
428 super(name
+ " zoom"); //$NON-NLS-1$
429 fZoomEntryList
= entryList
;
430 fZoomStartTime
= startTime
;
431 fZoomEndTime
= endTime
;
432 fResolution
= Math
.max(1, (fZoomEndTime
- fZoomStartTime
) / fDisplayWidth
);
433 fMonitor
= new NullProgressMonitor();
438 if (fZoomEntryList
== null) {
441 for (TimeGraphEntry entry
: fZoomEntryList
) {
442 if (fMonitor
.isCanceled()) {
445 zoom(entry
, fMonitor
);
449 private void zoom(TimeGraphEntry entry
, IProgressMonitor monitor
) {
450 if (fZoomStartTime
<= fStartTime
&& fZoomEndTime
>= fEndTime
) {
451 entry
.setZoomedEventList(null);
453 List
<ITimeEvent
> zoomedEventList
= getEventList(entry
, fZoomStartTime
, fZoomEndTime
, fResolution
, monitor
);
454 if (zoomedEventList
!= null) {
455 entry
.setZoomedEventList(zoomedEventList
);
459 for (TimeGraphEntry child
: entry
.getChildren()) {
460 if (fMonitor
.isCanceled()) {
463 zoom(child
, monitor
);
467 public void cancel() {
468 fMonitor
.setCanceled(true);
472 // ------------------------------------------------------------------------
474 // ------------------------------------------------------------------------
482 * The columns to display in the tree view on the left
484 * The columns list to filter the view
486 * The presentation provider
488 public AbstractTimeGraphView(String id
, String
[] cols
, String
[] filterCols
,
489 TimeGraphPresentationProvider pres
) {
492 fFilterColumns
= filterCols
;
493 fPresentation
= pres
;
494 fDisplayWidth
= Display
.getDefault().getBounds().width
;
497 // ------------------------------------------------------------------------
499 // ------------------------------------------------------------------------
502 public void createPartControl(Composite parent
) {
503 fTimeGraphCombo
= new TimeGraphCombo(parent
, SWT
.NONE
, fWeight
);
505 fTimeGraphCombo
.setTreeContentProvider(new TreeContentProvider());
507 fTimeGraphCombo
.setTreeLabelProvider(fLabelProvider
);
509 fTimeGraphCombo
.setTimeGraphProvider(fPresentation
);
511 fTimeGraphCombo
.setTreeColumns(fColumns
);
513 fTimeGraphCombo
.setFilterContentProvider(new TreeContentProvider());
515 fTimeGraphCombo
.setFilterLabelProvider(new TreeLabelProvider());
517 fTimeGraphCombo
.setFilterColumns(fFilterColumns
);
519 fTimeGraphCombo
.getTimeGraphViewer().addRangeListener(new ITimeGraphRangeListener() {
521 public void timeRangeUpdated(TimeGraphRangeUpdateEvent event
) {
522 final long startTime
= event
.getStartTime();
523 final long endTime
= event
.getEndTime();
524 TmfTimeRange range
= new TmfTimeRange(new CtfTmfTimestamp(startTime
), new CtfTmfTimestamp(endTime
));
525 TmfTimestamp time
= new CtfTmfTimestamp(fTimeGraphCombo
.getTimeGraphViewer().getSelectedTime());
526 broadcast(new TmfRangeSynchSignal(AbstractTimeGraphView
.this, range
, time
));
527 if (fZoomThread
!= null) {
528 fZoomThread
.cancel();
530 startZoomThread(startTime
, endTime
);
534 fTimeGraphCombo
.getTimeGraphViewer().addTimeListener(new ITimeGraphTimeListener() {
536 public void timeSelected(TimeGraphTimeEvent event
) {
537 long time
= event
.getTime();
538 broadcast(new TmfTimeSynchSignal(AbstractTimeGraphView
.this, new CtfTmfTimestamp(time
)));
542 fTimeGraphCombo
.addSelectionListener(new ITimeGraphSelectionListener() {
544 public void selectionChanged(TimeGraphSelectionEvent event
) {
545 // ITimeGraphEntry selection = event.getSelection();
549 fTimeGraphCombo
.getTimeGraphViewer().setTimeFormat(TimeFormat
.CALENDAR
);
551 // View Action Handling
553 contributeToActionBars();
555 ITmfTrace trace
= getActiveTrace();
557 traceSelected(new TmfTraceSelectedSignal(this, trace
));
560 // make selection available to other views
561 getSite().setSelectionProvider(fTimeGraphCombo
.getTreeViewer());
565 public void setFocus() {
566 fTimeGraphCombo
.setFocus();
569 // ------------------------------------------------------------------------
571 // ------------------------------------------------------------------------
574 * Handler for the trace opened signal.
577 * The incoming signal
581 public void traceOpened(TmfTraceOpenedSignal signal
) {
582 fTrace
= signal
.getTrace();
587 * Handler for the trace selected signal
590 * The incoming signal
593 public void traceSelected(final TmfTraceSelectedSignal signal
) {
594 if (signal
.getTrace() == fTrace
) {
597 fTrace
= signal
.getTrace();
603 * Trace is closed: clear the data structures and the view
606 * the signal received
609 public void traceClosed(final TmfTraceClosedSignal signal
) {
610 synchronized (fBuildThreadMap
) {
611 BuildThread buildThread
= fBuildThreadMap
.remove(signal
.getTrace());
612 if (buildThread
!= null) {
613 buildThread
.cancel();
616 synchronized (fEntryListMap
) {
617 fEntryListMap
.remove(signal
.getTrace());
619 if (signal
.getTrace() == fTrace
) {
623 if (fZoomThread
!= null) {
624 fZoomThread
.cancel();
631 * Handler for the synch signal
634 * The signal that's received
637 public void synchToTime(final TmfTimeSynchSignal signal
) {
638 if (signal
.getSource() == this || fTrace
== null) {
641 final long time
= signal
.getCurrentTime().normalize(0, ITmfTimestamp
.NANOSECOND_SCALE
).getValue();
643 Display
.getDefault().asyncExec(new Runnable() {
646 if (fTimeGraphCombo
.isDisposed()) {
649 fTimeGraphCombo
.getTimeGraphViewer().setSelectedTime(time
, true);
650 startZoomThread(fTimeGraphCombo
.getTimeGraphViewer().getTime0(), fTimeGraphCombo
.getTimeGraphViewer().getTime1());
652 synchingToTime(time
);
658 * Handler for the range sync signal
661 * The signal that's received
664 public void synchToRange(final TmfRangeSynchSignal signal
) {
665 if (signal
.getSource() == this || fTrace
== null) {
668 if (signal
.getCurrentRange().getIntersection(fTrace
.getTimeRange()) == null) {
671 final long startTime
= signal
.getCurrentRange().getStartTime().normalize(0, ITmfTimestamp
.NANOSECOND_SCALE
).getValue();
672 final long endTime
= signal
.getCurrentRange().getEndTime().normalize(0, ITmfTimestamp
.NANOSECOND_SCALE
).getValue();
673 final long time
= signal
.getCurrentTime().normalize(0, ITmfTimestamp
.NANOSECOND_SCALE
).getValue();
674 Display
.getDefault().asyncExec(new Runnable() {
677 if (fTimeGraphCombo
.isDisposed()) {
680 fTimeGraphCombo
.getTimeGraphViewer().setStartFinishTime(startTime
, endTime
);
681 fTimeGraphCombo
.getTimeGraphViewer().setSelectedTime(time
, false);
682 startZoomThread(startTime
, endTime
);
687 // ------------------------------------------------------------------------
689 // ------------------------------------------------------------------------
691 private void loadTrace() {
692 synchronized (fEntryListMap
) {
693 fEntryList
= fEntryListMap
.get(fTrace
);
694 if (fEntryList
== null) {
695 synchronized (fBuildThreadMap
) {
696 BuildThread buildThread
= new BuildThread(fTrace
, this.getName());
697 fBuildThreadMap
.put(fTrace
, buildThread
);
701 fStartTime
= fTrace
.getStartTime().normalize(0, ITmfTimestamp
.NANOSECOND_SCALE
).getValue();
702 fEndTime
= fTrace
.getEndTime().normalize(0, ITmfTimestamp
.NANOSECOND_SCALE
).getValue();
709 * Method called when synching to a given timestamp. Inheriting classes can
710 * perform actions here to update the view at the given timestamp.
713 * The currently selected time
715 protected void synchingToTime(long time
) {
720 * Build the entries list to show in this time graph
722 * Called from the BuildThread
725 * The trace being built
727 * The progress monitor object
729 protected abstract void buildEventList(final ITmfTrace trace
, IProgressMonitor monitor
);
732 * Gets the list of event for an entry in a given timerange
735 * The entry to get events for
737 * Start of the time range
739 * End of the time range
743 * The progress monitor object
744 * @return The list of events for the entry
746 protected abstract List
<ITimeEvent
> getEventList(TimeGraphEntry entry
,
747 long startTime
, long endTime
, long resolution
,
748 IProgressMonitor monitor
);
751 * Refresh the display
753 protected void refresh() {
754 Display
.getDefault().asyncExec(new Runnable() {
757 if (fTimeGraphCombo
.isDisposed()) {
760 ITimeGraphEntry
[] entries
= null;
761 synchronized (fEntryListMap
) {
762 fEntryList
= fEntryListMap
.get(fTrace
);
763 if (fEntryList
== null) {
764 fEntryList
= new ArrayList
<TimeGraphEntry
>();
766 entries
= fEntryList
.toArray(new ITimeGraphEntry
[0]);
768 if (fEntryComparator
!= null) {
769 Arrays
.sort(entries
, fEntryComparator
);
771 fTimeGraphCombo
.setInput(entries
);
772 fTimeGraphCombo
.getTimeGraphViewer().setTimeBounds(fStartTime
, fEndTime
);
774 long timestamp
= fTrace
== null ?
0 : fTraceManager
.getCurrentTime().normalize(0, ITmfTimestamp
.NANOSECOND_SCALE
).getValue();
775 long startTime
= fTrace
== null ?
0 : fTraceManager
.getCurrentRange().getStartTime().normalize(0, ITmfTimestamp
.NANOSECOND_SCALE
).getValue();
776 long endTime
= fTrace
== null ?
0 : fTraceManager
.getCurrentRange().getEndTime().normalize(0, ITmfTimestamp
.NANOSECOND_SCALE
).getValue();
777 startTime
= Math
.max(startTime
, fStartTime
);
778 endTime
= Math
.min(endTime
, fEndTime
);
779 fTimeGraphCombo
.getTimeGraphViewer().setSelectedTime(timestamp
, false);
780 fTimeGraphCombo
.getTimeGraphViewer().setStartFinishTime(startTime
, endTime
);
782 for (TreeColumn column
: fTimeGraphCombo
.getTreeViewer().getTree().getColumns()) {
786 startZoomThread(startTime
, endTime
);
794 protected void redraw() {
795 synchronized (fSyncObj
) {
796 if (fRedrawState
== State
.IDLE
) {
797 fRedrawState
= State
.BUSY
;
799 fRedrawState
= State
.PENDING
;
803 Display
.getDefault().asyncExec(new Runnable() {
806 if (fTimeGraphCombo
.isDisposed()) {
809 fTimeGraphCombo
.redraw();
810 fTimeGraphCombo
.update();
811 synchronized (fSyncObj
) {
812 if (fRedrawState
== State
.PENDING
) {
813 fRedrawState
= State
.IDLE
;
816 fRedrawState
= State
.IDLE
;
823 private void startZoomThread(long startTime
, long endTime
) {
824 if (fZoomThread
!= null) {
825 fZoomThread
.cancel();
827 fZoomThread
= new ZoomThread(fEntryList
, startTime
, endTime
, getName());
831 private void makeActions() {
832 fPreviousResourceAction
= fTimeGraphCombo
.getTimeGraphViewer().getPreviousItemAction();
833 fPreviousResourceAction
.setText(getPrevText());
834 fPreviousResourceAction
.setToolTipText(getPrevTooltip());
835 fNextResourceAction
= fTimeGraphCombo
.getTimeGraphViewer().getNextItemAction();
836 fNextResourceAction
.setText(getNextText());
837 fNextResourceAction
.setToolTipText(getNextTooltip());
840 private void contributeToActionBars() {
841 IActionBars bars
= getViewSite().getActionBars();
842 fillLocalToolBar(bars
.getToolBarManager());
845 private void fillLocalToolBar(IToolBarManager manager
) {
846 if (fFilterColumns
.length
> 0) {
847 manager
.add(fTimeGraphCombo
.getShowFilterAction());
849 manager
.add(fTimeGraphCombo
.getTimeGraphViewer().getShowLegendAction());
850 manager
.add(new Separator());
851 manager
.add(fTimeGraphCombo
.getTimeGraphViewer().getResetScaleAction());
852 manager
.add(fTimeGraphCombo
.getTimeGraphViewer().getPreviousEventAction());
853 manager
.add(fTimeGraphCombo
.getTimeGraphViewer().getNextEventAction());
854 manager
.add(fPreviousResourceAction
);
855 manager
.add(fNextResourceAction
);
856 manager
.add(fTimeGraphCombo
.getTimeGraphViewer().getZoomInAction());
857 manager
.add(fTimeGraphCombo
.getTimeGraphViewer().getZoomOutAction());
858 manager
.add(new Separator());