View Javadoc

1   /*
2    *  File: TimeBarViewer.java 
3    *  Copyright (c) 2004-2008  Peter Kliem (Peter.Kliem@jaret.de)
4    *  A commercial license is available, see http://www.jaret.de.
5    *
6    *  This program is free software; you can redistribute it and/or modify
7    *  it under the terms of the GNU General Public License as published by
8    *  the Free Software Foundation; either version 2 of the License, or
9    *  (at your option) any later version.
10   *
11   *  This program is distributed in the hope that it will be useful,
12   *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13   *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14   *  GNU General Public License for more details.
15   *
16   *  You should have received a copy of the GNU General Public License
17   *  along with this program; if not, write to the Free Software
18   *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19   */
20  package de.jaret.util.ui.timebars.swt;
21  
22  import java.awt.Cursor;
23  import java.awt.event.InputEvent;
24  import java.beans.PropertyChangeListener;
25  import java.beans.PropertyChangeSupport;
26  import java.util.ArrayList;
27  import java.util.HashMap;
28  import java.util.List;
29  import java.util.Map;
30  import java.util.Vector;
31  
32  import org.eclipse.jface.viewers.ISelection;
33  import org.eclipse.jface.viewers.ISelectionChangedListener;
34  import org.eclipse.jface.viewers.ISelectionProvider;
35  import org.eclipse.jface.viewers.IStructuredSelection;
36  import org.eclipse.jface.viewers.SelectionChangedEvent;
37  import org.eclipse.jface.viewers.StructuredSelection;
38  import org.eclipse.swt.SWT;
39  import org.eclipse.swt.events.DisposeEvent;
40  import org.eclipse.swt.events.DisposeListener;
41  import org.eclipse.swt.events.KeyEvent;
42  import org.eclipse.swt.events.KeyListener;
43  import org.eclipse.swt.events.MouseEvent;
44  import org.eclipse.swt.events.MouseListener;
45  import org.eclipse.swt.events.MouseMoveListener;
46  import org.eclipse.swt.events.MouseTrackListener;
47  import org.eclipse.swt.events.PaintEvent;
48  import org.eclipse.swt.events.PaintListener;
49  import org.eclipse.swt.events.SelectionAdapter;
50  import org.eclipse.swt.events.SelectionEvent;
51  import org.eclipse.swt.graphics.Color;
52  import org.eclipse.swt.graphics.GC;
53  import org.eclipse.swt.graphics.Point;
54  import org.eclipse.swt.graphics.Rectangle;
55  import org.eclipse.swt.widgets.Canvas;
56  import org.eclipse.swt.widgets.Composite;
57  import org.eclipse.swt.widgets.Display;
58  import org.eclipse.swt.widgets.Event;
59  import org.eclipse.swt.widgets.Listener;
60  import org.eclipse.swt.widgets.Menu;
61  import org.eclipse.swt.widgets.ScrollBar;
62  import org.eclipse.swt.widgets.Shell;
63  
64  import de.jaret.util.date.Interval;
65  import de.jaret.util.date.JaretDate;
66  import de.jaret.util.misc.Pair;
67  import de.jaret.util.ui.timebars.TimeBarIntervalFilter;
68  import de.jaret.util.ui.timebars.TimeBarMarker;
69  import de.jaret.util.ui.timebars.TimeBarRowFilter;
70  import de.jaret.util.ui.timebars.TimeBarRowSorter;
71  import de.jaret.util.ui.timebars.TimeBarViewerDelegate;
72  import de.jaret.util.ui.timebars.TimeBarViewerInterface;
73  import de.jaret.util.ui.timebars.mod.IntervalModificator;
74  import de.jaret.util.ui.timebars.model.FocussedIntervalListener;
75  import de.jaret.util.ui.timebars.model.HierarchicalTimeBarModel;
76  import de.jaret.util.ui.timebars.model.HierarchicalViewState;
77  import de.jaret.util.ui.timebars.model.IIntervalRelation;
78  import de.jaret.util.ui.timebars.model.ISelectionRectListener;
79  import de.jaret.util.ui.timebars.model.ITimeBarChangeListener;
80  import de.jaret.util.ui.timebars.model.ITimeBarViewState;
81  import de.jaret.util.ui.timebars.model.TBRect;
82  import de.jaret.util.ui.timebars.model.TimeBarModel;
83  import de.jaret.util.ui.timebars.model.TimeBarNode;
84  import de.jaret.util.ui.timebars.model.TimeBarRow;
85  import de.jaret.util.ui.timebars.model.TimeBarSelectionModel;
86  import de.jaret.util.ui.timebars.model.TimeBarSelectionModelImpl;
87  import de.jaret.util.ui.timebars.strategy.IOverlapStrategy;
88  import de.jaret.util.ui.timebars.strategy.ITickProvider;
89  import de.jaret.util.ui.timebars.swt.renderer.AbstractGridRenderer;
90  import de.jaret.util.ui.timebars.swt.renderer.DefaultGridRenderer;
91  import de.jaret.util.ui.timebars.swt.renderer.DefaultHeaderRenderer;
92  import de.jaret.util.ui.timebars.swt.renderer.DefaultMiscRenderer;
93  import de.jaret.util.ui.timebars.swt.renderer.DefaultRenderer;
94  import de.jaret.util.ui.timebars.swt.renderer.DefaultTimeBarMarkerRenderer;
95  import de.jaret.util.ui.timebars.swt.renderer.DefaultTimeScaleRenderer;
96  import de.jaret.util.ui.timebars.swt.renderer.DefaultTitleRenderer;
97  import de.jaret.util.ui.timebars.swt.renderer.GlobalAssistantRenderer;
98  import de.jaret.util.ui.timebars.swt.renderer.GridRenderer;
99  import de.jaret.util.ui.timebars.swt.renderer.HeaderRenderer;
100 import de.jaret.util.ui.timebars.swt.renderer.HierarchyRenderer;
101 import de.jaret.util.ui.timebars.swt.renderer.IMiscRenderer;
102 import de.jaret.util.ui.timebars.swt.renderer.IRelationRenderer;
103 import de.jaret.util.ui.timebars.swt.renderer.TimeBarGapRenderer;
104 import de.jaret.util.ui.timebars.swt.renderer.TimeBarMarkerRenderer;
105 import de.jaret.util.ui.timebars.swt.renderer.TimeBarRenderer;
106 import de.jaret.util.ui.timebars.swt.renderer.TimeScaleRenderer;
107 import de.jaret.util.ui.timebars.swt.renderer.TitleRenderer;
108 import de.jaret.util.ui.timebars.swt.util.actions.JaretTimeBarsActionFactory;
109 
110 /**
111  * Viewer for a TimeBarModel (SWT version). Displays the intervals using a renderer. Supports sorting and/or filtering
112  * of the rows in the model without affecting the model itself.
113  * <p>
114  * The implementation depends on the <code>TimeBarViewerDelegate</code> for the operations and calculations that is
115  * shared between the Swing and the SWT implementation of the viewer. There is no accesor to access the delegate
116  * directly. However the documentation of the delegate can be helpful. The delegate can temporarily be accessed
117  * <code>getData("delegate")</code> for debugging and experimental features.
118  * </p>
119  * <p>
120  * The timebar viewer is an implementation of the ISelectionProvider working with structured selections containing rows
121  * and intervals.
122  * </p>
123  * <p>
124  * <b>Keyboard bindings</b>
125  * </p>
126  * <p>
127  * <ul>
128  * <li>cursor keys: move focus between intervals</li>
129  * <li>space: toggle select for focused intervals</li>
130  * <li>ctrl: if hold: add element to selection</li>
131  * <li>shift+arrow right/left: grow interval to the right/left (if allowed, steps can be configured by
132  * keyboardchangedelta)</li>
133  * <li>alt+arrow right/left: shrink interval from the right left (if allowed, steps can be configured by
134  * keyboardchangedelta)</li>
135  * <li>ctrl+arrow right/left: move focussed interval (if allowed, steps can be configured by keyboardchangedelta)</li>
136  * <li>escape: cancel internal drag/resize operation</li>
137  * </ul>
138  * </p>
139  * 
140  * @author Peter Kliem
141  * @version $Id: TimeBarViewer.java 1097 2011-11-06 21:44:47Z kliem $
142  */
143 public class TimeBarViewer extends Canvas implements TimeBarViewerInterface, ISelectionProvider {
144     /** DEBUGGING OPTION: if set to true the actual paint times will be printed to stdout. */
145     private static final boolean SHOWPAINTTIME = false;
146 
147     /** default color for rowgrid. */
148     public static final Color ROWGRID_COLOR = Display.getCurrent().getSystemColor(SWT.COLOR_GRAY);
149 
150     /** Number of seconds will be divided by this divisor for determing arrow incremtn of the scrollbar. */
151     protected static final int INCREMENTDIVISOR_X = 10;
152     /** Number of rows will be divided by this divisor for determing arrow incremtn of the scrollbar. */
153     protected static final int INCREMENTDIVISOR_Y = 10;
154 
155     /** Color used to render the limiting lines. */
156     protected static final Color LINECOLOR = Display.getCurrent().getSystemColor(SWT.COLOR_BLACK);
157     /** default alpha for ghost draw and row highlighting. */
158     public static final int DEFAULT_ALPHA = 70;
159 
160     /** color for row grid lines. */
161     protected Color _rowGridColor = ROWGRID_COLOR;
162     /** alpha for ghost drawing. */
163     protected int _ghostAlpha = DEFAULT_ALPHA;
164 
165     /** Identifier of the pop up button. */
166     private static final int POPUP_BUTTON = 3;
167 
168     /** scale factor for converting mouse wheel clicks for scrolling. */
169     private static final double MOUSEWHEEL_FACTOR = 2.5;
170 
171     /**
172      * This delegate encapsules the main part of the functionality of the the viewer.
173      */
174     protected TimeBarViewerDelegate _delegate;
175 
176     /** Renderer used to render the timescale. */
177     protected TimeScaleRenderer _timeScaleRenderer = new DefaultTimeScaleRenderer();
178     /** mapping between interval classes and renderers. */
179     protected Map<Class<? extends Interval>, TimeBarRenderer> _rendererMap = new HashMap<Class<? extends Interval>, TimeBarRenderer>();
180 
181     /** Renderer for the hierarchy view (tree structure). */
182     protected HierarchyRenderer _hierarchyRenderer;
183     /** Renderer for rendering the grid. */
184     protected GridRenderer _gridRenderer = new DefaultGridRenderer();
185     /** Renderer for doing global rendering. */
186     protected GlobalAssistantRenderer _globalRenderer;
187     /** Renderer for doing rendering in th egaps between intervals. */
188     protected TimeBarGapRenderer _gapRenderer = null;
189     /** Renderer to render the row headings. */
190     protected HeaderRenderer _headerRenderer = new DefaultHeaderRenderer();
191     /** renderer for drawing interval relations. no default renderer is setup. */
192     protected IRelationRenderer _relationRenderer = null;
193 
194     /** Renderer for the timebar markers. */
195     protected TimeBarMarkerRenderer _markerRenderer = new DefaultTimeBarMarkerRenderer();
196     /** Renderer for rendering the title area. */
197     protected TitleRenderer _titleRenderer = new DefaultTitleRenderer();
198 
199     /** Renderer for rendering various bits. */
200     protected IMiscRenderer _miscRenderer = new DefaultMiscRenderer();
201 
202     /** factory for creating standard actions. */
203     protected JaretTimeBarsActionFactory _actionFactory;
204 
205     /** context menu for the main viewer body. */
206     protected Menu _bodyContextMenu;
207 
208     /** context menu displayed for intervals. */
209     protected Menu _intervalContextMenu;
210 
211     /** context menu displayed for the time scale. */
212     protected Menu _scaleContextMenu;
213 
214     /** context menu for the title area. */
215     protected Menu _titleContextMenu;
216 
217     /** handler for retrieving a context menu for the hierarchy. */
218     protected RowContextMenuHandler _hierarchyCtxHandler;
219 
220     /** handler for retrieving a context menu for the header area. */
221     protected RowContextMenuHandler _headerCtxHandler;
222 
223     /** Delegate to handle property change listener support. */
224     protected PropertyChangeSupport _propertyChangeSupport;
225 
226     /** list of Iselction listeners. * */
227     protected List<ISelectionChangedListener> _selectionChangeListeners;
228 
229     /**
230      * Constructor for a timebarviewer. Scrollbars can be added using SWT.H_SCROLL and SWT.V_SCROLL style bits. All
231      * other stylebits will not be useful.
232      * 
233      * @param parent parent composite
234      * @param style style bits
235      */
236     public TimeBarViewer(Composite parent, int style) {
237         // super should have no background since otherweise the handling of the
238         // paint events
239         // will clear the widgets background causing the opimized scroll to fail
240         super(parent, style | SWT.NO_BACKGROUND | SWT.DOUBLE_BUFFERED);
241         // most of the operations are done by the delgate
242         _delegate = new TimeBarViewerDelegate(this);
243 
244         // set the delegate as a data object for accessing it in special cases
245         setData("delegate", _delegate);
246 
247         addPaintListener(new PaintListener() {
248             public void paintControl(PaintEvent event) {
249                 onPaint(event);
250             }
251         });
252 
253         addMouseListener(new MouseListener() {
254             public void mouseDoubleClick(MouseEvent me) {
255             }
256 
257             public void mouseDown(MouseEvent me) {
258                 forceFocus();
259                 _delegate.mousePressed(me.x, me.y, me.button == POPUP_BUTTON, convertModifierMaskToSwing(me.stateMask));
260             }
261 
262             public void mouseUp(MouseEvent me) {
263                 _delegate
264                         .mouseReleased(me.x, me.y, me.button == POPUP_BUTTON, convertModifierMaskToSwing(me.stateMask));
265             }
266         });
267 
268         addMouseMoveListener(new MouseMoveListener() {
269             public void mouseMove(MouseEvent me) {
270                 if ((me.stateMask & SWT.BUTTON1) != 0) {
271                     _delegate.mouseDragged(me.x, me.y, convertModifierMaskToSwing(me.stateMask));
272                 } else {
273                     _delegate.mouseMoved(me.x, me.y);
274                 }
275             }
276         });
277 
278         addMouseTrackListener(new MouseTrackListener() {
279             public void mouseEnter(MouseEvent arg0) {
280             }
281 
282             public void mouseExit(MouseEvent arg0) {
283             }
284 
285             public void mouseHover(MouseEvent me) {
286                 setToolTipText(_delegate.getToolTipText(me.x, me.y));
287             }
288         });
289 
290         addKeyListener(new KeyListener() {
291             public void keyPressed(KeyEvent e) {
292                 _delegate.handleKeyPressed(convertKeyCodeToSwing(e.keyCode), convertModifierMaskToSwing(e.stateMask));
293             }
294 
295             public void keyReleased(KeyEvent e) {
296             }
297         });
298 
299         addDisposeListener(new DisposeListener() {
300             public void widgetDisposed(DisposeEvent e) {
301                 onDispose();
302             }
303         });
304 
305         ScrollBar verticalBar = getVerticalBar();
306         if (verticalBar != null) {
307             verticalBar.addSelectionListener(new SelectionAdapter() {
308                 public void widgetSelected(SelectionEvent event) {
309                     handleVerticalScroll(event);
310                 }
311             });
312         }
313         ScrollBar horizontalBar = getHorizontalBar();
314         if (horizontalBar != null) {
315             horizontalBar.addSelectionListener(new SelectionAdapter() {
316                 public void widgetSelected(SelectionEvent event) {
317                     handleHorizontalScroll(event);
318                 }
319             });
320         }
321 
322         Listener listener = new Listener() {
323             public void handleEvent(Event event) {
324                 switch (event.type) {
325                 case SWT.Resize:
326                     //_delegate.updateScrollBars();
327                     _delegate.componentResized();
328                     break;
329                 default:
330                     // do nothing
331                     break;
332                 }
333             }
334         };
335         addListener(SWT.Resize, listener);
336 
337         // mousewheel for zooming (together with control)
338         addListener(SWT.MouseWheel, new Listener() {
339             public void handleEvent(Event event) {
340                 if ((event.stateMask & SWT.CONTROL) != 0) {
341                     int c = event.count;
342                     double factor = (double) Math.abs(c) / MOUSEWHEEL_FACTOR;
343                     if (c > 0) {
344                         _delegate.setPixelPerSecond(_delegate.getPixelPerSecond() * factor);
345                     } else {
346                         _delegate.setPixelPerSecond(_delegate.getPixelPerSecond() / factor);
347                     }
348                 }
349             }
350         });
351 
352         // register the default renderer for intervals
353         registerTimeBarRenderer(Interval.class, new DefaultRenderer());
354 
355         // default background is white
356         setBackground(Display.getCurrent().getSystemColor(SWT.COLOR_WHITE));
357 
358         // do the coupling of grid and timescale
359         _gridRenderer.setTickProvider((ITickProvider) _timeScaleRenderer);
360 
361     }
362 
363     /**
364      * Dispose all renderes.
365      */
366     public void onDispose() {
367         _delegate.dispose();
368         if (_hierarchyRenderer != null) {
369             _hierarchyRenderer.dispose();
370         }
371         if (_headerRenderer != null) {
372             _headerRenderer.dispose();
373         }
374         if (_timeScaleRenderer != null) {
375             _timeScaleRenderer.dispose();
376         }
377         if (_gridRenderer != null) {
378             _gridRenderer.dispose();
379         }
380         if (_gapRenderer != null) {
381             _gapRenderer.dispose();
382         }
383         disposeTimeBarRenderers();
384         if (_markerRenderer != null) {
385             _markerRenderer.dispose();
386         }
387         if (_titleRenderer != null) {
388             _titleRenderer.dispose();
389         }
390         if (_globalRenderer != null) {
391             _globalRenderer.dispose();
392         }
393         if (_relationRenderer != null) {
394             _relationRenderer.dispose();
395         }
396     }
397 
398     /**
399      * Dispose all registered renderers.
400      */
401     private void disposeTimeBarRenderers() {
402         for (TimeBarRenderer tbr : _rendererMap.values()) {
403             tbr.dispose();
404         }
405     }
406 
407     /**
408      * {@inheritDoc}
409      */
410     public int getWidth() {
411         return getClientArea().width;
412     }
413 
414     /**
415      * {@inheritDoc}
416      */
417     public int getHeight() {
418         return getClientArea().height;
419     }
420 
421     /**
422      * {@inheritDoc}
423      */
424     public void repaint() {
425         redraw();
426     }
427 
428     /**
429      * {@inheritDoc}
430      */
431     public void repaint(int x, int y, int width, int height) {
432         redraw(x, y, width, height, false);
433     }
434 
435     /**
436      * {@inheritDoc}
437      */
438     public void repaint(java.awt.Rectangle rectangle) {
439         repaint(rectangle.x, rectangle.y, rectangle.width + 1, rectangle.height + 1);
440     }
441 
442     /**
443      * Converts a swt statemask to an awt statemask (extended modifier mask of InputEvent).
444      * 
445      * @param stateMask swt statemask
446      * @return awt statemask
447      */
448     private int convertModifierMaskToSwing(int stateMask) {
449         int mask = 0;
450         if ((stateMask & SWT.CONTROL) != 0) {
451             mask = mask | InputEvent.CTRL_DOWN_MASK;
452         }
453         if ((stateMask & SWT.SHIFT) != 0) {
454             mask = mask | InputEvent.SHIFT_DOWN_MASK;
455         }
456         if ((stateMask & SWT.ALT) != 0) {
457             mask = mask | InputEvent.ALT_DOWN_MASK;
458         }
459         return mask;
460     }
461 
462     /**
463      * Convert SWT keyCodes to AWT/Swing constants.
464      * 
465      * @param keyCode key code to convert
466      * @return converted keycode.
467      */
468     private int convertKeyCodeToSwing(int keyCode) {
469         int result = keyCode;
470         switch (keyCode) {
471         case SWT.ARROW_LEFT:
472             result = java.awt.event.KeyEvent.VK_LEFT;
473             break;
474         case SWT.ARROW_RIGHT:
475             result = java.awt.event.KeyEvent.VK_RIGHT;
476             break;
477         case SWT.ARROW_UP:
478             result = java.awt.event.KeyEvent.VK_UP;
479             break;
480         case SWT.ARROW_DOWN:
481             result = java.awt.event.KeyEvent.VK_DOWN;
482             break;
483         case ' ': // SPACE
484             result = java.awt.event.KeyEvent.VK_SPACE;
485             break;
486         case SWT.ESC:
487             result = java.awt.event.KeyEvent.VK_ESCAPE;
488             break;
489 
490         default:
491             result = keyCode;
492             break;
493         }
494         return result;
495     }
496 
497     /**
498      * Handle movement of the horizontal scrollbar.
499      * 
500      * @param event SelectionEvent from the scroll bar
501      */
502     private void handleHorizontalScroll(SelectionEvent event) {
503         int value = getHorizontalBar().getSelection();
504         _delegate.handleHorizontalScroll(value, true);
505     }
506 
507     /**
508      * Handles value changes from the vertical scrollbar.
509      * 
510      * @param event Selection event from the vertical scroll bar
511      */
512     private void handleVerticalScroll(SelectionEvent event) {
513         int value = getVerticalBar().getSelection();
514         _delegate.handleVerticalScroll(value, true);
515     }
516 
517     /**
518      * {@inheritDoc}
519      */
520     public void updateXScrollBar(int max, int pos, int secondsDisplayed) {
521         ScrollBar scroll = getHorizontalBar();
522         if (scroll != null) {
523             scroll.setMinimum(0);
524             scroll.setMaximum(max);
525             scroll.setThumb(secondsDisplayed);
526             scroll.setIncrement(secondsDisplayed / INCREMENTDIVISOR_X); // increment for arrows
527             scroll.setPageIncrement(secondsDisplayed); // page increment areas
528             scroll.setSelection(pos);
529         }
530     }
531 
532     /**
533      * {@inheritDoc}
534      */
535     public void updateYScrollBar(int max, int pos, int rowsDisplayed) {
536         ScrollBar scroll = getVerticalBar();
537         // scroll may be null
538         if (scroll != null) {
539             scroll.setMinimum(0);
540             scroll.setMaximum(max);
541             scroll.setThumb(rowsDisplayed);
542             scroll.setIncrement(rowsDisplayed / INCREMENTDIVISOR_Y); // increment for arrows
543             scroll.setPageIncrement(rowsDisplayed); // page increment areas
544             scroll.setSelection(pos);
545         }
546     }
547 
548     /**
549      * Calculate the x coordinate for a given date.
550      * 
551      * @param date date to get the coordinate for
552      * @return x coordinate for the given date in the diagram area
553      */
554     public int xForDate(JaretDate date) {
555         return _delegate.xForDate(date);
556     }
557 
558     /**
559      * {@inheritDoc}
560      */
561     public Point computeSize(int wHint, int hHint, boolean changed) {
562         // if a hint is given just return the hint
563         if (wHint != SWT.DEFAULT || hHint != SWT.DEFAULT) {
564             return new Point(wHint != SWT.DEFAULT ? wHint : 100, hHint != SWT.DEFAULT ? hHint : 100);
565         }
566         // MAYBE: this only uses the default rowheight instead of the actual row heights
567         Point e = new Point((int) ((double) _delegate.getTotalSeconds() * _delegate.getPixelPerSecond()), _delegate
568                 .getRowCount()
569                 * _delegate.getTimeBarViewState().getDefaultRowHeight());
570         return e;
571     }
572 
573     /**
574      * {@inheritDoc}
575      */
576     public void setModel(TimeBarModel model) {
577         _delegate.setModel(model);
578     }
579 
580     /**
581      * {@inheritDoc}
582      */
583     public void setModel(HierarchicalTimeBarModel hModel) {
584         _delegate.setModel(hModel);
585     }
586 
587     /**
588      * {@inheritDoc}
589      */
590     public TimeBarModel getModel() {
591         return _delegate.getModel();
592     }
593 
594     /**
595      * {@inheritDoc}
596      */
597     public HierarchicalTimeBarModel getHierarchicalModel() {
598         return _delegate.getHierarchicalModel();
599     }
600 
601     /**
602      * {@inheritDoc}
603      */
604     public HierarchicalViewState getHierarchicalViewState() {
605         return _delegate.getHierarchicalViewState();
606     }
607 
608     /**
609      * {@inheritDoc}
610      */
611     public void setHierarchicalViewState(HierarchicalViewState hierarchicalViewState) {
612         _delegate.setHierarchicalViewState(hierarchicalViewState);
613     }
614 
615     /**
616      * Set the default renderer to be used for rendering the timebars.
617      * 
618      * @param renderer the renderer to be used if no other registered renderer is appropriate
619      */
620     public void setTimeBarRenderer(TimeBarRenderer renderer) {
621         registerTimeBarRenderer(Interval.class, renderer);
622     }
623 
624     /**
625      * Retrieve the default renderer currently used for rendering intervals (regsitered for Interval.class).
626      * 
627      * @return the renderer
628      */
629     public TimeBarRenderer getTimeBarRenderer() {
630         return _rendererMap.get(Interval.class);
631     }
632 
633     /**
634      * Register a renderer for an interval class or interface. The renderer registered for Interval.class is the default
635      * renderer if no other renderer can be found (obviously).
636      * 
637      * @param intervalClass class of the intervals
638      * @param renderer renderer for the given class
639      */
640     public void registerTimeBarRenderer(Class<? extends Interval> intervalClass, TimeBarRenderer renderer) {
641         _rendererMap.put(intervalClass, renderer);
642         repaint();
643     }
644 
645     /**
646      * Retrieve the complete renderer map. This method's purpose is mainly to feed the TimeBarPrinter.
647      * 
648      * @return the renderer map
649      */
650     public Map<Class<? extends Interval>, TimeBarRenderer> getRendererMapping() {
651         return _rendererMap;
652     }
653 
654     /**
655      * Retrieve a renderer for a given class. Checks all interfaces and all superclasses.
656      * 
657      * @param clazz class in question
658      * @return renderer or null
659      */
660     protected TimeBarRenderer getRenderer(Class<? extends Interval> clazz) {
661         TimeBarRenderer result = null;
662         result = _rendererMap.get(clazz);
663         if (result != null) {
664             return result;
665         }
666 
667         // direct interfaces
668         Class<?>[] interfaces = clazz.getInterfaces();
669         for (Class<?> c : interfaces) {
670             result = _rendererMap.get(c);
671             if (result != null) {
672                 return result;
673             }
674         }
675 
676         // superclasses
677         Class<?> sc = clazz.getSuperclass();
678 
679         while (sc != null) {
680             result = _rendererMap.get(sc);
681             if (result != null) {
682                 return result;
683             }
684             // interfaces of the superclass
685             Class<?>[] scinterfaces = sc.getInterfaces();
686             for (Class<?> c : scinterfaces) {
687                 result = _rendererMap.get(c);
688                 if (result != null) {
689                     return result;
690                 }
691             }
692             sc = sc.getSuperclass();
693         }
694 
695         return result;
696     }
697 
698     // *** Propertychange handling
699     /**
700      * {@inheritDoc}
701      */
702     public void firePropertyChange(String string, double oldValue, double newValue) {
703         firePropertyChangeX(string, Double.valueOf(oldValue), Double.valueOf(newValue));
704     }
705 
706     /**
707      * {@inheritDoc}
708      */
709     public void firePropertyChangeX(String propName, Object oldVal, Object newVal) {
710         if (_propertyChangeSupport != null) {
711             _propertyChangeSupport.firePropertyChange(propName, oldVal, newVal);
712         }
713     }
714 
715     /**
716      * {@inheritDoc}
717      */
718     public void addPropertyChangeListener(PropertyChangeListener listener) {
719         if (_propertyChangeSupport == null) {
720             _propertyChangeSupport = new PropertyChangeSupport(this);
721         }
722         _propertyChangeSupport.addPropertyChangeListener(listener);
723     }
724 
725     /**
726      * {@inheritDoc}
727      */
728     public void removePropertyChangeListener(PropertyChangeListener listener) {
729         if (_propertyChangeSupport != null) {
730             _propertyChangeSupport.removePropertyChangeListener(listener);
731         }
732     }
733 
734     // *** end of PropertyChange handling
735 
736     /**
737      * Do the painting.
738      * 
739      * @param event PaintEvent to be processed
740      */
741     synchronized void onPaint(PaintEvent event) {
742         GC gc = event.gc;
743         // first calculate the layout of the areas
744         _delegate.preparePaint(getWidth(), getHeight());
745 
746         // update the scrollbars
747         // especially for the first paint!
748         // TODO MAYBE restrict to one call for the first paint
749         _delegate.updateScrollBars();
750 
751         long time = System.currentTimeMillis();
752         long ntime = System.nanoTime();
753 
754         // clear background in the clipping rect
755         gc.setBackground(getBackground());
756         // gc.setBackground(new Color(Display.getCurrent(), 200, 200, 200));
757         gc.fillRectangle(gc.getClipping()); // background painting
758         try {
759             // draw x axis
760             RenderDelegate.drawXAxis(_delegate, _timeScaleRenderer, false, gc);
761             // draw grid
762             RenderDelegate.drawGrid(_delegate, _gridRenderer, false, gc);
763 
764             // if a global renderer is set, do rendering!
765             if (_globalRenderer != null) {
766                 _globalRenderer.doRenderingBeforeIntervals(_delegate, gc, false);
767             }
768             // draw rows
769             drawRows(gc);
770             // draw markers
771             RenderDelegate.drawMarkers(_delegate, _markerRenderer, false, gc);
772 
773             // draw the selection rect
774             Rectangle clipSave = gc.getClipping();
775             gc.setClipping(clipSave.intersection(convertRect(_delegate.getDiagramRect())));
776             drawSelectionRect(gc);
777             gc.setClipping(clipSave);
778 
779             // draw the title area
780             RenderDelegate.drawTitle(_delegate, _titleRenderer, false, gc);
781 
782             // draw the region rect
783             clipSave = gc.getClipping();
784             gc.setClipping(clipSave.intersection(convertRect(_delegate.getDiagramRect())));
785             _miscRenderer.renderRegionSelection(gc, this, _delegate);
786             gc.setClipping(clipSave);
787 
788             // if a global renderer is set, do rendering!
789             if (_globalRenderer != null) {
790                 _globalRenderer.doRenderingLast(_delegate, gc, false);
791             }
792 
793             // draw ghosts if present
794             drawGhosts(gc);
795 
796             time = System.currentTimeMillis() - time;
797             ntime = System.nanoTime() - ntime;
798             // primitive debug method to watch time that is spent during the painting
799             if (SHOWPAINTTIME) {
800                 System.out.println(_delegate.getName() + ": paint " + time + " ms " + ntime + " ns");
801             }
802         } catch (Throwable t) {
803             t.printStackTrace();
804         }
805     }
806 
807     /**
808      * Draw the rows.
809      * 
810      * @param gc GC
811      */
812     private void drawRows(GC gc) {
813         boolean horizontal = true;
814         if (_delegate.getOrientation() == Orientation.VERTICAL) {
815             horizontal = false;
816         }
817 
818         // separating line to the header
819         // and the hierarchy area
820         Color fg = gc.getForeground(); // save fg color
821         gc.setForeground(LINECOLOR);
822         if (horizontal) {
823             gc.drawLine(_delegate.getYAxisWidth() + _delegate.getHierarchyWidth() - 1, 0, _delegate.getYAxisWidth()
824                     + _delegate.getHierarchyWidth() - 1, getClientArea().height);
825             gc
826                     .drawLine(_delegate.getHierarchyWidth() - 1, 0, _delegate.getHierarchyWidth() - 1,
827                             getClientArea().height);
828         } else {
829             gc.drawLine(0, _delegate.getYAxisWidth() + _delegate.getHierarchyWidth() - 1, getClientArea().width,
830                     _delegate.getYAxisWidth() + _delegate.getHierarchyWidth() - 1);
831             gc.drawLine(0, _delegate.getHierarchyWidth() - 1, getClientArea().width, _delegate.getHierarchyWidth() - 1);
832         }
833         gc.setForeground(fg); // restore color
834 
835         // relation rendering
836         if (_relationRenderer != null) {
837             _relationRenderer.renderRelations(_delegate, gc, false);
838         }
839 
840         if (horizontal) {
841             drawRowsHorizontal(gc);
842         } else {
843             drawRowsVertical(gc);
844         }
845     }
846 
847     /**
848      * Draws the rows when orientation is horizontal.
849      * 
850      * @param gc GC
851      */
852     private void drawRowsHorizontal(GC gc) {
853         int firstRow = _delegate.getFirstRow();
854 
855         // set the clipping to include only the heigth of the diagram rect
856         Rectangle clipSave = gc.getClipping();
857         Rectangle nc = new Rectangle(0, _delegate.getDiagramRect().y, getWidth(), _delegate.getDiagramRect().height);
858         gc.setClipping(gc.getClipping().intersection(nc));
859 
860         int upperYBound = _delegate.getDiagramRect().y;
861         int lowerYBound = upperYBound + _delegate.getDiagramRect().height;
862         if (gc.isClipped()) {
863             upperYBound = gc.getClipping().y;
864             lowerYBound = upperYBound + gc.getClipping().height;
865         }
866 
867         for (int r = firstRow; r <= firstRow + _delegate.getRowsDisplayed() + 1 && r < _delegate.getRowCount(); r++) {
868             TimeBarRow row = _delegate.getRow(r);
869             int y = _delegate.yForRow(row);
870             if (y == -1) {
871                 // no coord -> is not displayed
872                 break;
873             }
874             // row is drawn if either the beginning or the end is inside the
875             // clipping rect
876             // or if the upperBound is inside the row rect (clipping rect is
877             // inside the row rect
878             int rowHeight = _delegate.getTimeBarViewState().getRowHeight(row);
879             if ((y >= upperYBound && y <= lowerYBound)
880                     || (y + rowHeight >= upperYBound && y + rowHeight <= lowerYBound)
881                     || (upperYBound > y && upperYBound < y + rowHeight)) {
882                 drawRowHorizontal(gc, _delegate.getRow(r), y, _delegate.getSelectionModel().isSelected(
883                         _delegate.getRow(r)));
884                 // draw gaps if a renderer is set
885                 if (_gapRenderer != null) {
886                     RenderDelegate.drawRowGaps(_delegate, _gapRenderer, false, gc, 0, y, _delegate.getRow(r), _delegate
887                             .getSelectionModel().isSelected(_delegate.getRow(r)));
888                 }
889             }
890         }
891         gc.setClipping(clipSave);
892     }
893 
894     /**
895      * Draws the rows when orientation is vertical.
896      * 
897      * @param gc GC
898      */
899     private void drawRowsVertical(GC gc) {
900         int firstRow = _delegate.getFirstRow();
901 
902         // set the clipping to include only the width of the diagram rect
903         Rectangle clipSave = gc.getClipping();
904         Rectangle nc = new Rectangle(_delegate.getDiagramRect().x, 0, _delegate.getDiagramRect().width, getHeight());
905         gc.setClipping(gc.getClipping().intersection(nc));
906 
907         int upperXBound = _delegate.getDiagramRect().x;
908         int lowerXBound = upperXBound + _delegate.getDiagramRect().width;
909         if (gc.isClipped()) {
910             upperXBound = gc.getClipping().x;
911             lowerXBound = upperXBound + gc.getClipping().width;
912         }
913 
914         for (int r = firstRow; r <= firstRow + _delegate.getRowsDisplayed() + 1 && r < _delegate.getRowCount(); r++) {
915             TimeBarRow row = _delegate.getRow(r);
916             int x = _delegate.yForRow(row);
917             if (x == -1) {
918                 // no coord
919                 break;
920             }
921             // row is drawn if either the beginning or the end is inside the
922             // clipping rect
923             // or if the upperBound is inside the row rect (clipping rect is
924             // inside the row rect
925             int rowHeight = _delegate.getTimeBarViewState().getRowHeight(row);
926             if ((x >= upperXBound && x <= lowerXBound)
927                     || (x + rowHeight >= upperXBound && x + rowHeight <= lowerXBound)
928                     || (upperXBound > x && upperXBound < x + rowHeight)) {
929                 drawRowVertical(gc, _delegate.getRow(r), x, _delegate.getSelectionModel().isSelected(
930                         _delegate.getRow(r)));
931                 // draw gaps if a renderer is set
932                 if (_gapRenderer != null) {
933                     RenderDelegate.drawRowGaps(_delegate, _gapRenderer, false, gc, x, 0, _delegate.getRow(r), _delegate
934                             .getSelectionModel().isSelected(_delegate.getRow(r)));
935                 }
936             }
937         }
938         gc.setClipping(clipSave);
939     }
940 
941     /**
942      * Draws the selection rectangle if present.
943      * 
944      * @param gc GC
945      */
946     private void drawSelectionRect(GC gc) {
947         if (_delegate.getSelectionRect() != null) {
948             // normalize and remember
949             _delegate.setLastSelRect(normalizeRectangle(_delegate.getSelectionRect()));
950             java.awt.Rectangle selRect = _delegate.getLastSelRect();
951             _miscRenderer.renderSelectionRect(gc, selRect);
952         }
953 
954     }
955 
956     /**
957      * Normalizes a rectangle to have its origin in the upper left corner.
958      * 
959      * @param rect rectangle to normalize
960      * @return normalized rectangle
961      */
962     private java.awt.Rectangle normalizeRectangle(java.awt.Rectangle rect) {
963         int x = Math.min(rect.x, rect.x + rect.width);
964         int y = Math.min(rect.y, rect.y + rect.height);
965         int width = Math.abs(rect.width);
966         int height = Math.abs(rect.height);
967         return new java.awt.Rectangle(x, y, width, height);
968     }
969 
970     /**
971      * Convert a java.awt.Rectangle to a org.eclipse.Rectangle.
972      * 
973      * @param rect awt rect
974      * @return eclipse rect or <code>null</code> if a null is passed in
975      */
976     public static Rectangle convertRect(java.awt.Rectangle rect) {
977         if (rect == null) {
978             return null;
979         }
980         return new Rectangle(rect.x, rect.y, rect.width, rect.height);
981     }
982 
983     /**
984      * Convert eclipse rect to awt rect.
985      * 
986      * @param rect eclipse rect
987      * @return awt rect
988      */
989     private java.awt.Rectangle convertRect(Rectangle rect) {
990         return new java.awt.Rectangle(rect.x, rect.y, rect.width, rect.height);
991     }
992 
993     /**
994      * Draw a single row (horizontal).
995      * 
996      * @param gc GC
997      * @param row row to paint
998      * @param y upper screen y for painting
999      * @param selected true if the row is selected
1000      */
1001     private void drawRowHorizontal(GC gc, TimeBarRow row, int y, boolean selected) {
1002         int rowHeight = _delegate.getTimeBarViewState().getRowHeight(row);
1003         // first of all draw the row header
1004         if (row.getRowHeader() != null) {
1005             RenderDelegate.drawRowHeaderHorizontal(_delegate, _headerRenderer, false, gc, y, row.getRowHeader(),
1006                     selected, row);
1007         }
1008 
1009         // the draw the hierarchy display if configured
1010         if (_hierarchyRenderer != null && _delegate.getHierarchyWidth() > 0) {
1011             RenderDelegate.drawHierarchy(_delegate, _hierarchyRenderer, false, gc, y, row, selected);
1012         }
1013 
1014         // TODO move to grid renderer
1015         // row grid if configured
1016         if (_delegate.getDrawRowGrid()) {
1017             Color fg = gc.getForeground();
1018             gc.setForeground(_rowGridColor);
1019             gc.drawLine(_delegate.getDiagramRect().x, y + rowHeight - 1, _delegate.getDiagramRect().x
1020                     + _delegate.getDiagramRect().width, y + rowHeight - 1);
1021             gc.setForeground(fg);
1022         }
1023 
1024         // do row grid rendering/selection rendering BEFORE interval painting
1025         Rectangle rowRect = null;
1026         if (_gridRenderer != null) {
1027             int markerHeight = rowHeight;
1028             // calculate height for clipping
1029             if (y + markerHeight > _delegate.getDiagramRect().y + _delegate.getDiagramRect().height) {
1030                 markerHeight = markerHeight
1031                         - (y + markerHeight - (_delegate.getDiagramRect().y + _delegate.getDiagramRect().height));
1032             }
1033             rowRect = new Rectangle(_delegate.getDiagramRect().x, y, getWidth() - _delegate.getDiagramRect().x,
1034                     markerHeight);
1035             _gridRenderer.drawRowBeforeIntervals(gc, _delegate, rowRect, row, selected, false);
1036         }
1037 
1038         // all intervals inside the bounds of the diagram plus the additional look ahead/lookBack time
1039         // if strictChecking is enabled
1040         JaretDate start;
1041         JaretDate end;
1042         if (_delegate.getStrictClipTimeCheck()) {
1043             start = _delegate.getStartDate();
1044             end = _delegate.getEndDate();
1045         } else {
1046             start = _delegate.getStartDate().copy().backMinutes(_delegate.getScrollLookBackMinutes());
1047             end = _delegate.getEndDate().copy().advanceMinutes(_delegate.getScrollLookForwardMinutes());
1048         }
1049         // use the clipping bounds to reduce the painted intervals
1050         // (when strict checking is enabled)
1051         if (gc.isClipped() && _delegate.getStrictClipTimeCheck()) {
1052             start = _delegate.dateForCoord(gc.getClipping().x);
1053             end = _delegate.dateForCoord(gc.getClipping().x + gc.getClipping().width);
1054         }
1055         List<Interval> intervalsUnfiltered = row.getIntervals(start, end);
1056 
1057         List<Interval> intervals = new ArrayList<Interval>();
1058         // apply filter on intervals if set
1059         if (_delegate.getIntervalFilter() != null) {
1060             for (Interval i : intervalsUnfiltered) {
1061                 if (_delegate.getIntervalFilter().isInResult(i)) {
1062                     intervals.add(i);
1063                 }
1064             }
1065         } else {
1066             intervals = intervalsUnfiltered;
1067         }
1068 
1069         for (Interval i : intervals) {
1070             TimeBarRenderer renderer = getRenderer(i.getClass());
1071             if (renderer == null) {
1072                 throw new RuntimeException("No suitable renderer for " + i.getClass());
1073             }
1074             if (_delegate.getTimeBarViewState().getDrawOverlapping(row)) {
1075                 RenderDelegate.drawIntervalHorizontal(_delegate, renderer, false, gc, y, i, null, row);
1076             } else {
1077                 RenderDelegate.drawIntervalHorizontal(_delegate, renderer, false, gc, y, i, _delegate
1078                         .getOverlapStrategy().getOverlapInfo(row, i), row);
1079             }
1080         }
1081         // do AFTER interval row rendering
1082         if (_gridRenderer != null) {
1083             _gridRenderer.drawRowAfterIntervals(gc, _delegate, rowRect, row, selected, false);
1084         }
1085     }
1086 
1087     /**
1088      * Draw a single row (vertical).
1089      * 
1090      * @param gc GC
1091      * @param row row to paint
1092      * @param x left screen x for painting
1093      * @param selected true if the row is selected
1094      */
1095     private void drawRowVertical(GC gc, TimeBarRow row, int x, boolean selected) {
1096         int rowHeight = _delegate.getTimeBarViewState().getRowHeight(row);
1097         // first of all draw the row header
1098         if (row.getRowHeader() != null) {
1099             RenderDelegate.drawRowHeaderVertical(_delegate, _headerRenderer, false, gc, x, row.getRowHeader(),
1100                     selected, row);
1101         }
1102 
1103         // the draw the hierarchy display if configured
1104         if (_hierarchyRenderer != null && _delegate.getHierarchyWidth() > 0) {
1105             RenderDelegate.drawHierarchyVertical(_delegate, _hierarchyRenderer, false, gc, x, row, selected);
1106         }
1107 
1108         // row grid if configured
1109         if (_delegate.getDrawRowGrid()) {
1110             Color fg = gc.getForeground();
1111             gc.setForeground(_rowGridColor);
1112             gc.drawLine(x + rowHeight - 1, _delegate.getDiagramRect().y, x + rowHeight - 1,
1113                     _delegate.getDiagramRect().y + _delegate.getDiagramRect().height);
1114             gc.setForeground(fg);
1115         }
1116 
1117         // do rendering BEFORE intervals
1118         Rectangle rowRect = null;
1119         if (_gridRenderer != null) {
1120             int markerWidth = rowHeight;
1121             // calculate width for clipping
1122             if (x + markerWidth > _delegate.getDiagramRect().x + _delegate.getDiagramRect().width) {
1123                 markerWidth = markerWidth
1124                         - (x + markerWidth - (_delegate.getDiagramRect().x + _delegate.getDiagramRect().width));
1125             }
1126             rowRect = new Rectangle(x, _delegate.getDiagramRect().y, markerWidth, getHeight()
1127                     - _delegate.getDiagramRect().y);
1128             _gridRenderer.drawRowBeforeIntervals(gc, _delegate, rowRect, row, selected, false);
1129         }
1130 
1131         // all intervals inside the bounds of the diagram plus the additional look ahead/lookBack time
1132         // if strictChecking is enabled
1133         JaretDate start;
1134         JaretDate end;
1135         if (_delegate.getStrictClipTimeCheck()) {
1136             start = _delegate.getStartDate();
1137             end = _delegate.getEndDate();
1138         } else {
1139             start = _delegate.getStartDate().copy().backMinutes(_delegate.getScrollLookBackMinutes());
1140             end = _delegate.getEndDate().copy().advanceMinutes(_delegate.getScrollLookForwardMinutes());
1141         }
1142         // use the clipping bounds to reduce the painted intervals
1143         // (when strict checking is enabled)
1144         if (gc.isClipped() && _delegate.getStrictClipTimeCheck()) {
1145             start = _delegate.dateForCoord(gc.getClipping().y);
1146             end = _delegate.dateForCoord(gc.getClipping().y + gc.getClipping().height);
1147         }
1148         List<Interval> intervalsUnfiltered = row.getIntervals(start, end);
1149         List<Interval> intervals = new ArrayList<Interval>();
1150         // apply filter on intervals if set
1151         if (_delegate.getIntervalFilter() != null) {
1152             for (Interval i : intervalsUnfiltered) {
1153                 if (_delegate.getIntervalFilter().isInResult(i)) {
1154                     intervals.add(i);
1155                 }
1156             }
1157         } else {
1158             intervals = intervalsUnfiltered;
1159         }
1160 
1161         for (Interval i : intervals) {
1162             TimeBarRenderer renderer = getRenderer(i.getClass());
1163             if (renderer == null) {
1164                 throw new RuntimeException("no suitable renderer for class " + i.getClass());
1165             }
1166             if (_delegate.getTimeBarViewState().getDrawOverlapping(row)) {
1167                 RenderDelegate.drawIntervalVertical(_delegate, renderer, false, gc, x, i, null, row);
1168             } else {
1169                 RenderDelegate.drawIntervalVertical(_delegate, renderer, false, gc, x, i, _delegate
1170                         .getOverlapStrategy().getOverlapInfo(row, i), row);
1171             }
1172         }
1173 
1174         // row rendering after intervals
1175         if (_gridRenderer != null) {
1176             _gridRenderer.drawRowAfterIntervals(gc, _delegate, rowRect, row, selected, false);
1177         }
1178 
1179     }
1180 
1181     /**
1182      * @return Returns the gridRenderer.
1183      */
1184     public GridRenderer getGridRenderer() {
1185         return _gridRenderer;
1186     }
1187 
1188     /**
1189      * @param gridRenderer The gridRenderer to set.
1190      */
1191     public void setGridRenderer(GridRenderer gridRenderer) {
1192         _gridRenderer = gridRenderer;
1193         if (_gridRenderer != null && _timeScaleRenderer != null && _timeScaleRenderer instanceof ITickProvider) {
1194             _gridRenderer.setTickProvider((ITickProvider) _timeScaleRenderer);
1195         }
1196         repaint();
1197     }
1198 
1199     /**
1200      * Set a global renderer doing rendering work other than oriented on one interval or row.
1201      * 
1202      * @param gar the renderer to be used
1203      */
1204     public void setGlobalAssistantRenderer(GlobalAssistantRenderer gar) {
1205         _globalRenderer = gar;
1206     }
1207 
1208     /**
1209      * Retrive the global assistant renderer if set.
1210      * 
1211      * @return global assistant renderer or null if not set
1212      */
1213     public GlobalAssistantRenderer getGlobalAssistantRenderer() {
1214         return _globalRenderer;
1215     }
1216 
1217     /**
1218      * @return Returns the gapRenderer.
1219      */
1220     public TimeBarGapRenderer getGapRenderer() {
1221         return _gapRenderer;
1222     }
1223 
1224     /**
1225      * @param gapRenderer The gapRenderer to set.
1226      */
1227     public void setGapRenderer(TimeBarGapRenderer gapRenderer) {
1228         _gapRenderer = gapRenderer;
1229         repaint();
1230     }
1231 
1232     /**
1233      * @return Returns the timeScaleRenderer.
1234      */
1235     public TimeScaleRenderer getTimeScaleRenderer() {
1236         return _timeScaleRenderer;
1237     }
1238 
1239     /**
1240      * Set a renderer for the x axis. The Height for the x axis will be set to the preferred height of the renderer if
1241      * the renderer supplies one.
1242      * 
1243      * @param timeScaleRenderer The timeScaleRenderer to set.
1244      */
1245     public void setTimeScaleRenderer(TimeScaleRenderer timeScaleRenderer) {
1246         _timeScaleRenderer = timeScaleRenderer;
1247         if (_timeScaleRenderer != null && _timeScaleRenderer.getHeight() != -1) {
1248             // get and set the height the renderer needs
1249             _delegate.setXAxisHeight(_timeScaleRenderer.getHeight());
1250         }
1251         // maybe the new time scale renderer is not a TickProvider ... tell the grid rederer
1252         if (_gridRenderer != null) {
1253             _gridRenderer.setTickProvider(null);
1254         }
1255         if (_timeScaleRenderer != null && _gridRenderer != null && _timeScaleRenderer instanceof ITickProvider
1256                 && _delegate.getTimeScalePosition() != TimeBarViewerInterface.TIMESCALE_POSITION_NONE) {
1257             _gridRenderer.setTickProvider((ITickProvider) _timeScaleRenderer);
1258         }
1259         repaint();
1260     }
1261 
1262     /**
1263      * Retrieve the current misc renderer.
1264      * 
1265      * @return the current misc renderer
1266      */
1267     public IMiscRenderer getMiscRenderer() {
1268         return _miscRenderer;
1269     }
1270 
1271     /**
1272      * Set the misc renderer to use.
1273      * 
1274      * @param miscRenderer the misc renderer to be used
1275      */
1276     public void setMiscRenderer(IMiscRenderer miscRenderer) {
1277         _miscRenderer = miscRenderer;
1278         repaint();
1279     }
1280 
1281     /**
1282      * Set a renderer to be used for renering markers.
1283      * 
1284      * @param markerRenderer marker renderer
1285      */
1286     public void setMarkerRenderer(TimeBarMarkerRenderer markerRenderer) {
1287         _markerRenderer = markerRenderer;
1288         repaint();
1289     }
1290 
1291     /**
1292      * Retrieve the used marker renderer.
1293      * 
1294      * @return the marker renderer
1295      */
1296     public TimeBarMarkerRenderer getMarkerRenderer() {
1297         return _markerRenderer;
1298     }
1299 
1300     /**
1301      * {@inheritDoc}
1302      */
1303     public int getMarkerWidth(TimeBarMarker marker) {
1304         if (_markerRenderer != null) {
1305             return _markerRenderer.getWidth(marker);
1306         } else {
1307             return 0;
1308         }
1309     }
1310 
1311     /**
1312      * Set a renderer for the hierachy elements. If the renderer announces a preferred width this will be set.
1313      * 
1314      * @param hierarchyRenderer the renderer to be used for hieryrchy painting
1315      */
1316     public void setHierarchyRenderer(HierarchyRenderer hierarchyRenderer) {
1317         _hierarchyRenderer = hierarchyRenderer;
1318         if (_hierarchyRenderer != null && _hierarchyRenderer.getPreferredWidth() != -1) {
1319             _delegate.setHierarchyWidth(_hierarchyRenderer.getPreferredWidth());
1320         }
1321     }
1322 
1323     /**
1324      * Retrieve the hierarchy renderer.
1325      * 
1326      * @return hierarchy renderer
1327      */
1328     public HierarchyRenderer getHierarchyRenderer() {
1329         return _hierarchyRenderer;
1330     }
1331 
1332     /**
1333      * @return Returns the headerRenderer.
1334      */
1335     public HeaderRenderer getHeaderRenderer() {
1336         return _headerRenderer;
1337     }
1338 
1339     /**
1340      * @param headerRenderer The headerRenderer to set.
1341      */
1342     public void setHeaderRenderer(HeaderRenderer headerRenderer) {
1343         _headerRenderer = headerRenderer;
1344         repaint();
1345     }
1346 
1347     /**
1348      * @return Returns the titleRenderer.
1349      */
1350     public TitleRenderer getTitleRenderer() {
1351         return _titleRenderer;
1352     }
1353 
1354     /**
1355      * @param titleRenderer The titleRenderer to set.
1356      */
1357     public void setTitleRenderer(TitleRenderer titleRenderer) {
1358         _titleRenderer = titleRenderer;
1359         repaint();
1360     }
1361 
1362     /**
1363      * Retrieve the relation renderer.
1364      * 
1365      * @return the releation renderer
1366      */
1367     public IRelationRenderer getRelationRenderer() {
1368         return _relationRenderer;
1369     }
1370 
1371     /**
1372      * Set the relation renderer. There is no relation render setup as a default.
1373      * 
1374      * @param relationRenderer renderer to use
1375      */
1376     public void setRelationRenderer(IRelationRenderer relationRenderer) {
1377         _relationRenderer = relationRenderer;
1378         repaint();
1379     }
1380 
1381     /**
1382      * {@inheritDoc}
1383      */
1384     public boolean timeBarContains(Interval interval, java.awt.Rectangle intervalRect, int x, int y, boolean overlapping) {
1385         TimeBarRenderer renderer = getRenderer(interval.getClass());
1386         if (renderer == null) {
1387             throw new RuntimeException("no suitable renderer");
1388         }
1389 
1390         return renderer.contains(interval, convertRect(intervalRect), x, y, overlapping);
1391     }
1392 
1393     /**
1394      * {@inheritDoc}
1395      */
1396     public java.awt.Rectangle timeBarContainingRect(Interval interval, java.awt.Rectangle intervalRect,
1397             boolean overlapping) {
1398         TimeBarRenderer renderer = getRenderer(interval.getClass());
1399         if (renderer == null) {
1400             throw new RuntimeException("no suitable renderer");
1401         }
1402         return convertRect(renderer.getContainingRectangle(interval, convertRect(intervalRect), overlapping));
1403     }
1404 
1405     /**
1406      * {@inheritDoc}
1407      */
1408     public void setCursor(int cursorType) {
1409         cursorType = convertCursorType(cursorType);
1410         setCursor(Display.getCurrent().getSystemCursor(cursorType));
1411     }
1412 
1413     /**
1414      * Convert Swing cursor type to SWT-Cursor type.
1415      * 
1416      * @param cursorType swing cursor constant
1417      * @return swt cursor constant
1418      */
1419     private int convertCursorType(int cursorType) {
1420         int result = SWT.CURSOR_ARROW;
1421         switch (cursorType) {
1422         case Cursor.HAND_CURSOR:
1423             result = SWT.CURSOR_HAND;
1424             break;
1425         case Cursor.MOVE_CURSOR:
1426             result = SWT.CURSOR_SIZEALL;
1427             break;
1428         case Cursor.E_RESIZE_CURSOR:
1429             result = SWT.CURSOR_SIZEE;
1430             break;
1431         case Cursor.W_RESIZE_CURSOR:
1432             result = SWT.CURSOR_SIZEW;
1433             break;
1434         case Cursor.N_RESIZE_CURSOR:
1435             result = SWT.CURSOR_SIZEN;
1436             break;
1437         case Cursor.S_RESIZE_CURSOR:
1438             result = SWT.CURSOR_SIZES;
1439             break;
1440 
1441         default:
1442             break;
1443         }
1444 
1445         return result;
1446     }
1447 
1448     /**
1449      * {@inheritDoc}
1450      */
1451     public String getIntervalToolTipText(Interval interval, java.awt.Rectangle intervalRect, int x, int y) {
1452         TimeBarRenderer renderer = getRenderer(interval.getClass());
1453         if (renderer == null) {
1454             throw new RuntimeException("no suitable renderer");
1455         }
1456         return renderer.getToolTipText(interval, convertRect(intervalRect), x, y, false);
1457     }
1458 
1459     /**
1460      * {@inheritDoc}
1461      */
1462     public double getPixelPerSecond() {
1463         return _delegate.getPixelPerSecond();
1464     }
1465 
1466     /**
1467      * {@inheritDoc}
1468      */
1469     public void setPixelPerSecond(double pixPerSecond) {
1470         _delegate.setPixelPerSecond(pixPerSecond);
1471     }
1472 
1473     /**
1474      * {@inheritDoc}
1475      */
1476     public int getRowHeight() {
1477         return _delegate.getTimeBarViewState().getDefaultRowHeight();
1478     }
1479 
1480     /**
1481      * {@inheritDoc}
1482      */
1483     public void setRowHeight(int rowHeight) {
1484         _delegate.setRowHeight(rowHeight);
1485     }
1486 
1487     /**
1488      * {@inheritDoc}
1489      */
1490     public int getXAxisHeight() {
1491         return _delegate.getXAxisHeight();
1492     }
1493 
1494     /**
1495      * {@inheritDoc}
1496      */
1497     public void setXAxisHeight(int height) {
1498         _delegate.setXAxisHeight(height);
1499     }
1500 
1501     /**
1502      * {@inheritDoc}
1503      */
1504     public JaretDate getStartDate() {
1505         return _delegate.getStartDate();
1506     }
1507 
1508     /**
1509      * {@inheritDoc}
1510      */
1511     public void setStartDate(JaretDate startDate) {
1512         _delegate.setStartDate(startDate);
1513     }
1514 
1515     /**
1516      * {@inheritDoc}
1517      */
1518     public JaretDate getMinDate() {
1519         return _delegate.getMinDate();
1520     }
1521 
1522     /**
1523      * {@inheritDoc}
1524      */
1525     public void setMinDate(JaretDate minDate) {
1526         _delegate.setMinDate(minDate);
1527     }
1528 
1529     /**
1530      * {@inheritDoc}
1531      */
1532     public JaretDate getMaxDate() {
1533         return _delegate.getMaxDate();
1534     }
1535 
1536     /**
1537      * {@inheritDoc}
1538      */
1539     public void setMaxDate(JaretDate maxDate) {
1540         _delegate.setMaxDate(maxDate);
1541     }
1542 
1543     /**
1544      * {@inheritDoc}
1545      */
1546     public TimeBarSelectionModel getSelectionModel() {
1547         return _delegate.getSelectionModel();
1548     }
1549 
1550     /**
1551      * {@inheritDoc}
1552      */
1553     public void setSelectionModel(TimeBarSelectionModel selectionModel) {
1554         _delegate.setSelectionModel(selectionModel);
1555     }
1556 
1557     /**
1558      * {@inheritDoc}
1559      */
1560     public int getFirstRowDisplayed() {
1561         return _delegate.getFirstRow();
1562     }
1563 
1564     /**
1565      * {@inheritDoc}
1566      */
1567     public void setFirstRowDisplayed(int rowIdx) {
1568         _delegate.setFirstRow(rowIdx);
1569     }
1570 
1571     /**
1572      * {@inheritDoc}
1573      */
1574     public void setFirstRowDisplayed(TimeBarRow row) {
1575         _delegate.setFirstRow(row);
1576     }
1577 
1578     /**
1579      * {@inheritDoc}
1580      */
1581     public int getFirstRowOffset() {
1582         return _delegate.getFirstRowOffset();
1583     }
1584 
1585     /**
1586      * {@inheritDoc}
1587      */
1588     public void setFirstRowOffset(int offset) {
1589         _delegate.setFirstRowOffset(offset);
1590     }
1591 
1592     /**
1593      * {@inheritDoc}
1594      */
1595     public void setFirstRow(int firstRow, int pixOffset) {
1596         _delegate.setFirstRow(firstRow, pixOffset);
1597     }
1598 
1599     /**
1600      * {@inheritDoc}
1601      */
1602     public void setLastRow(int index) {
1603     	_delegate.setLastRow(index);
1604     }
1605     
1606     /**
1607      * {@inheritDoc}
1608      */
1609     public void setLastRow(TimeBarRow row) {
1610     	_delegate.setLastRow(row);
1611     }
1612 
1613     /**
1614      * Get the las date painted.
1615      * 
1616      * @return the last date that has been painted
1617      */
1618     public JaretDate getEndDate() {
1619         return _delegate.getEndDate();
1620     }
1621 
1622     /**
1623      * {@inheritDoc}
1624      */
1625     public void setTimeScalePosition(int timeScalePosition) {
1626         if (timeScalePosition == TimeBarViewerInterface.TIMESCALE_POSITION_NONE) {
1627             if (_gridRenderer != null) {
1628                 _gridRenderer.setTickProvider(null);
1629             }
1630         } else {
1631             if (_gridRenderer != null && _timeScaleRenderer instanceof ITickProvider) {
1632                 _gridRenderer.setTickProvider((ITickProvider) _timeScaleRenderer);
1633             }
1634         }
1635         _delegate.setTimeScalePosition(timeScalePosition);
1636     }
1637 
1638     /**
1639      * {@inheritDoc}
1640      */
1641     public int getTimeScalePosition() {
1642         return _delegate.getTimeScalePosition();
1643     }
1644 
1645     /**
1646      * {@inheritDoc}
1647      */
1648     public void setAdjustMinMaxDatesByModel(boolean adjust) {
1649         _delegate.setAdjustMinMaxDatesByModel(adjust);
1650     }
1651 
1652     /**
1653      * {@inheritDoc}
1654      */
1655     public boolean getAdjustMinMaxDatesByModel() {
1656         return _delegate.getAdjustMinMaxDatesByModel();
1657     }
1658 
1659     /**
1660      * {@inheritDoc}
1661      */
1662     public TimeBarRow rowForY(int y) {
1663         return _delegate.rowForY(y);
1664     }
1665 
1666     /**
1667      * {@inheritDoc}
1668      */
1669     public JaretDate dateForX(int x) {
1670         return _delegate.dateForCoord(x);
1671     }
1672 
1673     /**
1674      * {@inheritDoc}
1675      */
1676     public JaretDate dateForXY(int x, int y) {
1677         return _delegate.dateForXY(x, y);
1678     }
1679 
1680     /**
1681      * {@inheritDoc}
1682      */
1683     public void highlightRow(int y) {
1684         _delegate.highlightRow(y);
1685     }
1686 
1687     /**
1688      * {@inheritDoc}
1689      */
1690     public void highlightRow(TimeBarRow timeBarRow) {
1691         _delegate.highlightRow(timeBarRow);
1692     }
1693 
1694     /**
1695      * {@inheritDoc}
1696      */
1697     public void deHighlightRow() {
1698         _delegate.deHighlightRow();
1699     }
1700 
1701     /**
1702      * {@inheritDoc}
1703      */
1704     public void setDrawRowGrid(boolean drawRowGrid) {
1705         _delegate.setDrawRowGrid(drawRowGrid);
1706     }
1707 
1708     /**
1709      * {@inheritDoc}
1710      */
1711     public boolean getDrawRowGrid() {
1712         return _delegate.getDrawRowGrid();
1713     }
1714 
1715     /**
1716      * Set a filter to select a subset of rows in the model to be displayed. The model itself will go unaffected.
1717      * 
1718      * @param rowFilter TimeBarRowFilter to be used or null to disable row filtering
1719      */
1720     public void setRowFilter(TimeBarRowFilter rowFilter) {
1721         _delegate.setRowFilter(rowFilter);
1722     }
1723 
1724     /**
1725      * Get the used row filter.
1726      * 
1727      * @return the row filter or null.
1728      */
1729     public TimeBarRowFilter getRowFilter() {
1730         return _delegate.getRowFilter();
1731     }
1732 
1733     /**
1734      * Set an interval filter to select a subset of intervals that will be displayed. The model will be unaffected.
1735      * 
1736      * @param intervalFilter filter to use or null to disable filtering
1737      */
1738     public void setIntervalFilter(TimeBarIntervalFilter intervalFilter) {
1739         _delegate.setIntervalFilter(intervalFilter);
1740     }
1741 
1742     /**
1743      * Retrieve the used interval filter.
1744      * 
1745      * @return interval filter or null
1746      */
1747     public TimeBarIntervalFilter getIntervalFilter() {
1748         return _delegate.getIntervalFilter();
1749     }
1750 
1751     /**
1752      * Set a sorter for sorting the displayed rows. The model itself will not be affected.
1753      * 
1754      * @param rowSorter TimeBarRowSorter to be used or <code>null</code> to disable sorting
1755      */
1756     public void setRowSorter(TimeBarRowSorter rowSorter) {
1757         _delegate.setRowSorter(rowSorter);
1758     }
1759 
1760     /**
1761      * Retrive sorter used.
1762      * 
1763      * @return sorter or <code>null</code>
1764      */
1765     public TimeBarRowSorter getRowSorter() {
1766         return _delegate.getRowSorter();
1767     }
1768 
1769     /**
1770      * {@inheritDoc}
1771      */
1772     public void addMarker(TimeBarMarker marker) {
1773         _delegate.addMarker(marker);
1774     }
1775 
1776     /**
1777      * {@inheritDoc}
1778      */
1779     public void remMarker(TimeBarMarker marker) {
1780         _delegate.remMarker(marker);
1781     }
1782 
1783     /**
1784      * {@inheritDoc}
1785      */
1786     public List<TimeBarMarker> getMarkers() {
1787         return _delegate.getMarkers();
1788     }
1789 
1790     /**
1791      * {@inheritDoc}
1792      */
1793     public void addMarkers(List<TimeBarMarker> markers) {
1794         _delegate.addMarkers(markers);
1795     }
1796 
1797     /**
1798      * {@inheritDoc}
1799      */
1800     public void setYAxisWidth(int width) {
1801         _delegate.setYAxisWidth(width);
1802     }
1803 
1804     /**
1805      * {@inheritDoc}
1806      */
1807     public int getYAxisWidth() {
1808         return _delegate.getYAxisWidth();
1809     }
1810 
1811     /**
1812      * {@inheritDoc}
1813      */
1814     public void setHierarchyWidth(int width) {
1815         _delegate.setHierarchyWidth(width);
1816     }
1817 
1818     /**
1819      * {@inheritDoc}
1820      */
1821     public int getHierarchyWidth() {
1822         return _delegate.getHierarchyWidth();
1823     }
1824 
1825     /**
1826      * {@inheritDoc}
1827      */
1828     public void setAutoscrollEnabled(boolean enableAutoscroll) {
1829         _delegate.setAutoscrollEnabled(enableAutoscroll);
1830     }
1831 
1832     /**
1833      * {@inheritDoc}
1834      */
1835     public boolean isAutoscrollEnabled() {
1836         return _delegate.isAutoscrollEnabled();
1837     }
1838 
1839     /**
1840      * {@inheritDoc}
1841      */
1842     public void addIntervalModificator(IntervalModificator intervalModificator) {
1843         _delegate.addIntervalModificator(intervalModificator);
1844     }
1845 
1846     /**
1847      * {@inheritDoc}
1848      */
1849     public void remIntervalModificator(IntervalModificator intervalModificator) {
1850         _delegate.remIntervalModificator(intervalModificator);
1851     }
1852 
1853     /**
1854      * {@inheritDoc}
1855      */
1856     public String getTimeScaleToolTipText(int x, int y) {
1857         if (_timeScaleRenderer != null) {
1858             String tooltip = _timeScaleRenderer.getToolTipText(this, convertRect(_delegate.getXAxisRect()), x, y);
1859             return tooltip;
1860         }
1861         return null;
1862     }
1863 
1864     /**
1865      * {@inheritDoc}
1866      */
1867     public String getHeaderToolTipText(TimeBarRow row, int x, int y) {
1868         if (_headerRenderer != null) {
1869             return _headerRenderer.getToolTipText(row, convertRect(_delegate.getYAxisRect()), x, y);
1870         }
1871         return null;
1872     }
1873 
1874     /**
1875      * {@inheritDoc}
1876      */
1877     public String getHierarchyToolTipText(TimeBarNode node, int x, int y) {
1878         if (_hierarchyRenderer != null) {
1879             return _hierarchyRenderer.getToolTipText(node, convertRect(_delegate.getHierarchyRect()), x, y);
1880         }
1881         return null;
1882     }
1883 
1884     /**
1885      * {@inheritDoc}
1886      */
1887     public boolean isInToggleArea(TimeBarNode node, int xx, int yy) {
1888         int x = _delegate.getHierarchyRect().x;
1889         int width = _delegate.getHierarchyWidth() - 1;
1890         int rowHeight = _delegate.getTimeBarViewState().getRowHeight(node);
1891         int y = _delegate.yForRow(node);
1892         Rectangle drawingArea = new Rectangle(x, y, width, rowHeight);
1893         return _hierarchyRenderer.isInToggleArea(this, node, drawingArea, xx, yy);
1894     }
1895 
1896     /**
1897      * {@inheritDoc}
1898      */
1899     public boolean isInHierarchySelectionArea(TimeBarNode node, int xx, int yy) {
1900         int x = _delegate.getHierarchyRect().x;
1901         int width = _delegate.getHierarchyWidth() - 1;
1902         int rowHeight = _delegate.getTimeBarViewState().getRowHeight(node);
1903         int y = _delegate.yForRow(node);
1904         Rectangle drawingArea = new Rectangle(x, y, width, rowHeight);
1905         return _hierarchyRenderer.isInHierarchySelectionArea(this, node, drawingArea, xx, yy);
1906     }
1907 
1908     /**
1909      * {@inheritDoc}
1910      */
1911     public void setTitle(String title) {
1912         _delegate.setTitle(title);
1913     }
1914 
1915     /**
1916      * {@inheritDoc}
1917      */
1918     public String getTitle() {
1919         return _delegate.getTitle();
1920     }
1921 
1922     /**
1923      * Helper method displaying a context menu.
1924      * 
1925      * @param contextMenu the menu to display
1926      * @param x x coordinate in the viewer
1927      * @param y y coordinate in the viewer
1928      */
1929     private void dispContextMenu(Menu contextMenu, int x, int y) {
1930         // System.out.println("x,y:" + x + "," + y + " locy " +
1931         // getLocation().y);
1932         Shell shell = Display.getCurrent().getActiveShell();
1933         if (shell != null && contextMenu != null) {
1934         	Point coords = Display.getCurrent().map(this, shell, x, y);
1935             contextMenu.setLocation(coords.x + shell.getLocation().x, coords.y + shell.getLocation().y);
1936             contextMenu.setVisible(true);
1937         }
1938     }
1939 
1940     /**
1941      * {@inheritDoc}
1942      */
1943     public void displayBodyContextMenu(int x, int y) {
1944         if (_bodyContextMenu != null) {
1945             dispContextMenu(_bodyContextMenu, x, y);
1946         }
1947     }
1948 
1949     /**
1950      * {@inheritDoc}
1951      */
1952     public void displayTimeScaleContextMenu(int x, int y) {
1953         if (_scaleContextMenu != null) {
1954             dispContextMenu(_scaleContextMenu, x, y);
1955         }
1956     }
1957 
1958     /**
1959      * {@inheritDoc}
1960      */
1961     public void displayIntervalContextMenu(Interval interval, int x, int y) {
1962         if (_intervalContextMenu != null) {
1963             dispContextMenu(_intervalContextMenu, x, y);
1964         }
1965     }
1966 
1967     /**
1968      * {@inheritDoc}
1969      */
1970     public void displayHeaderContextMenu(TimeBarRow row, int x, int y) {
1971         if (_headerCtxHandler != null) {
1972             Menu ctxMenu = _headerCtxHandler.getContextMenu(this, row);
1973             if (ctxMenu != null) {
1974                 dispContextMenu(ctxMenu, x, y);
1975             }
1976         }
1977     }
1978 
1979     /**
1980      * {@inheritDoc}
1981      */
1982     public void displayHierarchyContextMenu(TimeBarRow row, int x, int y) {
1983         if (_hierarchyCtxHandler != null) {
1984             Menu ctxMenu = _hierarchyCtxHandler.getContextMenu(this, row);
1985             if (ctxMenu != null) {
1986                 dispContextMenu(ctxMenu, x, y);
1987             }
1988         }
1989     }
1990 
1991     /**
1992      * {@inheritDoc}
1993      */
1994     public void displayTitleContextMenu(int x, int y) {
1995         if (_titleContextMenu != null) {
1996             dispContextMenu(_titleContextMenu, x, y);
1997         }
1998     }
1999 
2000     /**
2001      * @return Returns the bodyContextMenu.
2002      */
2003     public Menu getBodyContextMenu() {
2004         return _bodyContextMenu;
2005     }
2006 
2007     /**
2008      * @param bodyContextMenu The bodyContextMenu to set.
2009      */
2010     public void setBodyContextMenu(Menu bodyContextMenu) {
2011         _bodyContextMenu = bodyContextMenu;
2012     }
2013 
2014     /**
2015      * @return Returns the intervalContextMenu.
2016      */
2017     public Menu getIntervalContextMenu() {
2018         return _intervalContextMenu;
2019     }
2020 
2021     /**
2022      * Set the interval context menu.
2023      * 
2024      * @param intervalContextMenu context menu to set
2025      */
2026     public void setIntervalContextMenu(Menu intervalContextMenu) {
2027         _intervalContextMenu = intervalContextMenu;
2028     }
2029 
2030     /**
2031      * @return Returns the scaleContextMenu.
2032      */
2033     public Menu getScaleContextMenu() {
2034         return _scaleContextMenu;
2035     }
2036 
2037     /**
2038      * @param scaleContextMenu The scaleContextMenu to set.
2039      */
2040     public void setScaleContextMenu(Menu scaleContextMenu) {
2041         _scaleContextMenu = scaleContextMenu;
2042     }
2043 
2044     /**
2045      * @return Returns the titleContextMenu.
2046      */
2047     public Menu getTitleContextMenu() {
2048         return _titleContextMenu;
2049     }
2050 
2051     /**
2052      * @param titleContextMenu The titleContextMenu to set.
2053      */
2054     public void setTitleContextMenu(Menu titleContextMenu) {
2055         _titleContextMenu = titleContextMenu;
2056     }
2057 
2058     /**
2059      * @return Returns the headerCtxHandler.
2060      */
2061     public RowContextMenuHandler getHeaderCtxHandler() {
2062         return _headerCtxHandler;
2063     }
2064 
2065     /**
2066      * @param headerCtxHandler The headerCtxHandler to set.
2067      */
2068     public void setHeaderCtxHandler(RowContextMenuHandler headerCtxHandler) {
2069         _headerCtxHandler = headerCtxHandler;
2070     }
2071 
2072     /**
2073      * @return Returns the hierarchyCtxHandler.
2074      */
2075     public RowContextMenuHandler getHierarchyCtxHandler() {
2076         return _hierarchyCtxHandler;
2077     }
2078 
2079     /**
2080      * @param hierarchyCtxHandler The hierarchyCtxHandler to set.
2081      */
2082     public void setHierarchyCtxHandler(RowContextMenuHandler hierarchyCtxHandler) {
2083         _hierarchyCtxHandler = hierarchyCtxHandler;
2084     }
2085 
2086     /**
2087      * Retrieve the keyboardChangeDelta currently used.
2088      * 
2089      * @return the keyboardChangeDelta in seconds
2090      */
2091     public int getKeyboardChangeDelta() {
2092         return _delegate.getKeyboardChangeDelta();
2093     }
2094 
2095     /**
2096      * Set the delta for resizing and moving via keyboard.
2097      * 
2098      * @param keyboardChangeDelta the keyboardChangeDelta in seconds to set
2099      */
2100     public void setKeyboardChangeDelta(int keyboardChangeDelta) {
2101         _delegate.setKeyboardChangeDelta(keyboardChangeDelta);
2102     }
2103 
2104     /**
2105      * Set the new focussed interval.
2106      * 
2107      * @param interval new focussed interval
2108      */
2109     public void setFocussedInterval(Interval interval) {
2110         _delegate.setFocussedInterval(interval);
2111     }
2112 
2113     /**
2114      * Set the new focussed interval. Ths method should be used, if the row of the interval is known.
2115      * 
2116      * @param row row of the interval. May be <code>null</code> if the row of the interval is unknown.
2117      * @param interval interval to be focussed.
2118      */
2119     public void setFocussedInterval(TimeBarRow row, Interval interval) {
2120         _delegate.setFocussedInterval(row, interval);
2121     }
2122 
2123     /**
2124      * Retrieve the focussed interval.
2125      * 
2126      * @return the currently focussed interval or null if none is in focus
2127      */
2128     public Interval getFocussedInterval() {
2129         return _delegate.getFocussedInterval();
2130     }
2131 
2132     /**
2133      * @return the currently focussed row or null if none is in focus
2134      */
2135     public TimeBarRow getFocussedRow() {
2136         return _delegate.getFocussedRow();
2137     }
2138 
2139     /**
2140      * Check whether an interval is focussed.
2141      * 
2142      * @param interval interval to check
2143      * @return true if focussed
2144      */
2145     public boolean isFocussed(Interval interval) {
2146         return _delegate.isFocussed(interval);
2147     }
2148 
2149     /**
2150      * Scroll a date into the visible area of the viewer.
2151      * 
2152      * @param date date to be shown.
2153      */
2154     public int scrollDateToVisible(JaretDate date) {
2155         return _delegate.scrollDateToVisible(date);
2156     }
2157 
2158     /**
2159      * Make sure the specified row is visible.
2160      * 
2161      * @param row TimeBarRow to be in the visible area.
2162      */
2163     public void scrollRowToVisible(TimeBarRow row) {
2164         _delegate.scrollRowToVisible(row);
2165     }
2166 
2167     /**
2168      * Make sure the specified interval is in the visibe area of the viewer. If the interval does not fit in the visible
2169      * area, the beginning of the interval will be displayed.
2170      * 
2171      * @param row TimeBarRow of the interval
2172      * @param interval inteval.
2173      */
2174     public void scrollIntervalToVisible(TimeBarRow row, Interval interval) {
2175         _delegate.scrollIntervalToVisible(row, interval);
2176     }
2177 
2178     /**
2179      * Make sure the specified interval is in the visibe area of the viewer. If the interval does not fit in the visible
2180      * area, the beginning of the interval will be displayed.
2181      * 
2182      * @param interval interval
2183      */
2184     public void scrollIntervalToVisible(Interval interval) {
2185         _delegate.scrollIntervalToVisible(interval);
2186     }
2187 
2188     /**
2189      * Scroll an intervall into the visible area on a position specified by a ratio. The position according to the ratio
2190      * will be set for the upper row border and the begin of the interval. The horizontal position might be calculated
2191      * incorrectly when a variable x axis is used.
2192      * 
2193      * @param interval interval to scroll to
2194      * @param horizontalRatio ration between 0 and 1.0 (left to right)
2195      * @param verticalRatio ratio between 0 and 1.0 (top to bottom)
2196      */
2197     public void scrollIntervalToVisible(Interval interval, double horizontalRatio, double verticalRatio) {
2198         _delegate.scrollIntervalToVisible(interval, horizontalRatio, verticalRatio);
2199     }
2200 
2201     /**
2202      * {@inheritDoc}
2203      */
2204     public synchronized void addSelectionChangedListener(ISelectionChangedListener listener) {
2205         if (_selectionChangeListeners == null) {
2206             _selectionChangeListeners = new Vector<ISelectionChangedListener>();
2207         }
2208         _selectionChangeListeners.add(listener);
2209     }
2210 
2211     /**
2212      * {@inheritDoc}
2213      */
2214     public void removeSelectionChangedListener(ISelectionChangedListener listener) {
2215         if (_selectionChangeListeners != null) {
2216             _selectionChangeListeners.remove(listener);
2217         }
2218     }
2219 
2220     /**
2221      * {@inheritDoc} Will return a structured selection conaining selected rows and selected intervals.
2222      */
2223     public ISelection getSelection() {
2224         return getStrucuredSelection();
2225     }
2226 
2227     /**
2228      * {@inheritDoc} Will process a structured selection containing rows and intervals.
2229      */
2230     public void setSelection(ISelection selection) {
2231         setStructuredSelection(selection);
2232     }
2233 
2234     // ************** support
2235     /**
2236      * Create a StructuredSelection from the current selection of the viewer.
2237      * 
2238      * @return structured selection containing rows and intervals
2239      */
2240     @SuppressWarnings("unchecked")
2241     private ISelection getStrucuredSelection() {
2242         TimeBarSelectionModel tmSelection = getSelectionModel();
2243         if (tmSelection != null && !tmSelection.isEmpty()) {
2244             List list = new ArrayList();
2245             list.addAll(tmSelection.getSelectedRows());
2246             list.addAll(tmSelection.getSelectedIntervals());
2247             list.addAll(tmSelection.getSelectedRelations());
2248             StructuredSelection selection = new StructuredSelection(list);
2249             return selection;
2250         }
2251         return new StructuredSelection();
2252     }
2253 
2254     /**
2255      * Set the selection in the timebar viewer according to a structured selection.
2256      * 
2257      * @param selection structured selection to set
2258      */
2259     private void setStructuredSelection(ISelection selection) {
2260         TimeBarSelectionModel tmSelection = new TimeBarSelectionModelImpl();
2261         if (selection instanceof IStructuredSelection) {
2262             IStructuredSelection structured = (IStructuredSelection) selection;
2263             for (Object o : structured.toList()) {
2264                 if (o instanceof Interval) {
2265                     tmSelection.addSelectedInterval((Interval) o);
2266                 } else if (o instanceof TimeBarRow) {
2267                     tmSelection.addSelectedRow((TimeBarRow) o);
2268                 } else if (o instanceof IIntervalRelation) {
2269                     tmSelection.addSelectedRelation((IIntervalRelation) o);
2270                 } else {
2271                     throw new IllegalArgumentException("Type " + o.getClass().getName()
2272                             + " not supported for selection");
2273                 }
2274             }
2275         }
2276         setSelectionModel(tmSelection);
2277 
2278     }
2279 
2280     /**
2281      * Callback for delegate. This is not an ideal design but it will be ok to check in the delegate.
2282      */
2283     public void fireSelectionChanged() {
2284         SelectionChangedEvent evt = new SelectionChangedEvent(this, getStrucuredSelection());
2285         fireSelectionChanged(evt);
2286     }
2287 
2288     /**
2289      * Inform ISelection listeners about a change in the selection.
2290      * 
2291      * @param event event to be sent to the listeners.
2292      */
2293     private void fireSelectionChanged(SelectionChangedEvent event) {
2294         if (_selectionChangeListeners != null) {
2295             for (ISelectionChangedListener listener : _selectionChangeListeners) {
2296                 listener.selectionChanged(event);
2297             }
2298         }
2299     }
2300 
2301     // *************** ISelectionProvider
2302 
2303     /**
2304      * Retrieve a configured action factory.
2305      * 
2306      * @return a configured action factory
2307      */
2308     public JaretTimeBarsActionFactory getActionFactory() {
2309         if (_actionFactory == null) {
2310             _actionFactory = new JaretTimeBarsActionFactory(this, _delegate);
2311         }
2312         return _actionFactory;
2313     }
2314 
2315     /**
2316      * Set the drawing mode.
2317      * 
2318      * @param drawOverlapping if set to true intervals will be painted on another. If set to false, every interval will
2319      * only get a fraction of the space corresponding to the count of overlapping intervals.
2320      */
2321     public void setDrawOverlapping(boolean drawOverlapping) {
2322         _delegate.setDrawOverlapping(drawOverlapping);
2323     }
2324 
2325     /**
2326      * Retrieve the drawing mode.
2327      * 
2328      * @return the drawing mode
2329      */
2330     public boolean getDrawOverlapping() {
2331         return _delegate.isDrawOverlapping();
2332     }
2333 
2334     /**
2335      * Retrieves all intervals at a given point in the diagram pane.
2336      * 
2337      * @param x x coordinate
2338      * @param y y coordinate
2339      * @return List of all intervals at the point
2340      */
2341     public List<Interval> getIntervalsAt(int x, int y) {
2342         return _delegate.getIntervalsAt(x, y);
2343     }
2344 
2345     /**
2346      * Retrieve color for the row grid.
2347      * 
2348      * @return Color of the row grid
2349      */
2350     public Color getRowGridColor() {
2351         return _rowGridColor;
2352     }
2353 
2354     /**
2355      * Set the color for the row grid. The color will not be disposed by the viewer.
2356      * 
2357      * @param rowGridColor Color to be used for horizontal grid lines
2358      */
2359     public void setRowGridColor(Color rowGridColor) {
2360         _rowGridColor = rowGridColor;
2361     }
2362 
2363     /**
2364      * retrieve the color used for highlighting rows.
2365      * 
2366      * @return the highlight color
2367      * @deprecated use the default grid renderer directly (or your own grid renderer)
2368      */
2369     public Color getHighlightColor() {
2370         if (_gridRenderer != null && _gridRenderer instanceof AbstractGridRenderer) {
2371             AbstractGridRenderer renderer = (AbstractGridRenderer) _gridRenderer;
2372             return renderer.getHighlightColor();
2373         } else {
2374             throw new RuntimeException("not applicable since the grid renderer is not an AbstractGridRenderer");
2375         }
2376     }
2377 
2378     /**
2379      * Set the color for highlighting a row. The color will not be disposed by the viewer. Highlighting is done with the
2380      * methods <code>highlightRow</code> and <code>deHighlightRow</code>.
2381      * 
2382      * @param highlightColor color to be used for highlighting rows
2383      * @deprecated use the default grid renderer directly (or your own grid renderer)
2384      */
2385     public void setHighlightColor(Color highlightColor) {
2386         if (_gridRenderer != null && _gridRenderer instanceof AbstractGridRenderer) {
2387             AbstractGridRenderer renderer = (AbstractGridRenderer) _gridRenderer;
2388             renderer.setHighlightColor(highlightColor);
2389         } else {
2390             throw new RuntimeException("not applicable since the grid renderer is not an AbstractGridRenderer");
2391         }
2392     }
2393 
2394     /**
2395      * Retrieve the color used for marking selected rows.
2396      * 
2397      * @return color used for selecteted rows
2398      * @deprecated use the default grid renderer directly (or your own grid renderer)
2399      */
2400     public Color getRowSelectColor() {
2401         if (_gridRenderer != null && _gridRenderer instanceof AbstractGridRenderer) {
2402             AbstractGridRenderer renderer = (AbstractGridRenderer) _gridRenderer;
2403             return renderer.getRowSelectColor();
2404         } else {
2405             throw new RuntimeException("not applicable since the grid renderer is not an AbstractGridRenderer");
2406         }
2407     }
2408 
2409     /**
2410      * Set the color for drawing selected rows. The color will not be disposed by the viewer.
2411      * 
2412      * @param rowSelectColor color to be used to select rows
2413      * @deprecated use the default grid renderer directly (or your own grid renderer)
2414      */
2415     public void setRowSelectColor(Color rowSelectColor) {
2416         if (_gridRenderer != null && _gridRenderer instanceof AbstractGridRenderer) {
2417             AbstractGridRenderer renderer = (AbstractGridRenderer) _gridRenderer;
2418             renderer.setRowSelectColor(rowSelectColor);
2419         } else {
2420             throw new RuntimeException("not applicable since the grid renderer is not an AbstractGridRenderer");
2421         }
2422     }
2423 
2424     /**
2425      * Get the alpha used when drawing the highlighted row.
2426      * 
2427      * @return alpha for drawing the hightlight
2428      * @deprecated use the default grid renderer directly (or your own grid renderer)
2429      */
2430     public int getHighlightAlpha() {
2431         if (_gridRenderer != null && _gridRenderer instanceof AbstractGridRenderer) {
2432             AbstractGridRenderer renderer = (AbstractGridRenderer) _gridRenderer;
2433             return renderer.getHighlightAlpha();
2434         } else {
2435             throw new RuntimeException("not applicable since the grid renderer is not an AbstractGridRenderer");
2436         }
2437     }
2438 
2439     /**
2440      * Set the alpha value used for drawing the highlighted row.
2441      * 
2442      * @param highlightAlpha alpha to use
2443      * @deprecated use the default grid renderer directly (or your own grid renderer)
2444      */
2445     public void setHighlightAlpha(int highlightAlpha) {
2446         if (_gridRenderer != null && _gridRenderer instanceof AbstractGridRenderer) {
2447             AbstractGridRenderer renderer = (AbstractGridRenderer) _gridRenderer;
2448             renderer.setHighlightAlpha(highlightAlpha);
2449         } else {
2450             throw new RuntimeException("not applicable since the grid renderer is not an AbstractGridRenderer");
2451         }
2452     }
2453 
2454     /**
2455      * Get the alpha used when drawing ghosted intervals.
2456      * 
2457      * @return alpha for drawing ghost intervals
2458      */
2459     public int getGhostAlpha() {
2460         return _ghostAlpha;
2461     }
2462 
2463     /**
2464      * Set the alpha value used for drawing ghost intervals.
2465      * 
2466      * @param ghostAlpha alpha to use
2467      */
2468     public void setGhostAlpha(int ghostAlpha) {
2469         _ghostAlpha = ghostAlpha;
2470     }
2471 
2472     /**
2473      * {@inheritDoc}
2474      */
2475     public int getSelectionDelta() {
2476         return _delegate.getSelectionDelta();
2477     }
2478 
2479     /**
2480      * {@inheritDoc}
2481      */
2482     public void setSelectionDelta(int selectionDelta) {
2483         _delegate.setSelectionDelta(selectionDelta);
2484     }
2485 
2486     /**
2487      * {@inheritDoc}
2488      */
2489     public boolean isLineDraggingAllowed() {
2490         return _delegate.isLineDraggingAllowed();
2491     }
2492 
2493     /**
2494      * {@inheritDoc}
2495      */
2496     public void setLineDraggingAllowed(boolean lineDraggingAllowed) {
2497         _delegate.setLineDraggingAllowed(lineDraggingAllowed);
2498     }
2499 
2500     /**
2501      * {@inheritDoc}
2502      */
2503     public int getYForRow(TimeBarRow row) {
2504         return _delegate.yForRow(row);
2505     }
2506 
2507     /**
2508      * {@inheritDoc}. This is the same as rowForY.
2509      */
2510     public TimeBarRow getRowForY(int y) {
2511         return _delegate.rowForY(y);
2512     }
2513 
2514     /**
2515      * {@inheritDoc}
2516      */
2517     public TimeBarRow getRowForXY(int x, int y) {
2518         return _delegate.rowForXY(x, y);
2519     }
2520 
2521     /** list of ghost intervals to be painted. */
2522     protected List<Interval> _ghostIntervals;
2523     /** y offsets for the ghost intervals. */
2524     protected List<Integer> _ghostIntervalYCoordinates;
2525     /**
2526      * the origin for painting the ghost intervals/rows. The ghosted elements will paintetd relative to the y
2527      * coordinate.
2528      */
2529     protected Point _ghostOrigin;
2530     /** list of ghost rows to paint. */
2531     protected List<TimeBarRow> _ghostRows;
2532     /** y offsets for the ghost rows. */
2533     protected List<Integer> _ghostRowYCoordinates;
2534 
2535     /**
2536      * Set the list of ghost intervals to be drawn.
2537      * 
2538      * @param intervals list of intervals or <code>null</code> to delete ghosted intervals.
2539      * @param yCoordinates list of y offsets for the ghost intervals (maybe <code>null</code> when deleting ghost
2540      * intervals
2541      */
2542     public void setGhostIntervals(List<Interval> intervals, List<Integer> yCoordinates) {
2543         _ghostIntervals = intervals;
2544         _ghostIntervalYCoordinates = yCoordinates;
2545         redraw();
2546     }
2547 
2548     /**
2549      * Convenience method to set a single ghost interval.
2550      * 
2551      * @param interval interval or <code>null</code> to delete
2552      * @param y y offset
2553      */
2554     public void setGhostInterval(Interval interval, int y) {
2555         if (interval == null) {
2556             setGhostIntervals(null, null);
2557         } else {
2558             List<Interval> l = new ArrayList<Interval>(1);
2559             List<Integer> l2 = new ArrayList<Integer>(1);
2560             l.add(interval);
2561             l2.add(y);
2562             setGhostIntervals(l, l2);
2563         }
2564     }
2565 
2566     /**
2567      * Set the list of ghost rows to be drawn.
2568      * 
2569      * @param rows list of rows or <code>null</code> to delete ghosted rows.
2570      * @param yCoordinates list of y offsets for the ghost rows (maybe <code>null</code> when deleting ghost rows
2571      */
2572     public void setGhostRows(List<TimeBarRow> rows, List<Integer> yCoordinates) {
2573         _ghostRows = rows;
2574         _ghostRowYCoordinates = yCoordinates;
2575         redraw();
2576     }
2577 
2578     /**
2579      * Convenience method to set a single ghost row.
2580      * 
2581      * @param row row or <code>null</code> to delete
2582      * @param y y offset
2583      */
2584     public void setGhostRow(TimeBarRow row, int y) {
2585         if (row == null) {
2586             setGhostRows(null, null);
2587         } else {
2588             List<TimeBarRow> l = new ArrayList<TimeBarRow>(1);
2589             List<Integer> l2 = new ArrayList<Integer>(1);
2590             l.add(row);
2591             l2.add(y);
2592             setGhostRows(l, l2);
2593         }
2594     }
2595 
2596     /**
2597      * Set the origin (current drag position) to shift the ghost elements.
2598      * 
2599      * @param x x coordinate
2600      * @param y y coordniate
2601      */
2602     public void setGhostOrigin(int x, int y) {
2603         _ghostOrigin = new Point(x, y);
2604         if (_ghostIntervals != null || _ghostRows != null) {
2605             redraw();
2606         }
2607     }
2608 
2609     /**
2610      * Draw ghost intervals and rows.
2611      * 
2612      * @param gc GC
2613      */
2614     private void drawGhosts(GC gc) {
2615         drawGhostIntervals(gc);
2616         drawGhostRows(gc);
2617     }
2618 
2619     /**
2620      * Draw ghost intervals. Y positions are dependant from the ghost y offsets and the ghost origin. (Always uses the
2621      * defaultRowHeight.)
2622      * 
2623      * @param gc GC
2624      */
2625     private void drawGhostIntervals(GC gc) {
2626         if (_ghostOrigin != null && _ghostIntervals != null) {
2627             for (int i = 0; i < _ghostIntervals.size(); i++) {
2628                 Interval interval = _ghostIntervals.get(i);
2629                 int yoff = _ghostIntervalYCoordinates.get(i);
2630 
2631                 Rectangle drawingArea = convertRect(_delegate.getIntervalBounds(-1, interval));
2632                 if (_delegate.getOrientation().equals(Orientation.HORIZONTAL)) {
2633                     drawingArea.y = _ghostOrigin.y + yoff;
2634                     drawingArea.height = _delegate.getTimeBarViewState().getDefaultRowHeight();
2635                 } else {
2636                     drawingArea.x = _ghostOrigin.x + yoff;
2637                     drawingArea.width = _delegate.getTimeBarViewState().getDefaultRowHeight();
2638                 }
2639                 int alpha = gc.getAlpha();
2640                 gc.setAlpha(_ghostAlpha);
2641 
2642                 TimeBarRenderer renderer = getRenderer(interval.getClass());
2643                 if (renderer == null) {
2644                     throw new RuntimeException("no suitable renderer");
2645                 }
2646 
2647                 renderer.draw(gc, drawingArea, _delegate, interval, false, false, false);
2648                 gc.setAlpha(alpha);
2649             }
2650         }
2651     }
2652 
2653     /**
2654      * Draw ghost rows. Y positions are dependent from the ghost y offsets and the ghost origin.
2655      * 
2656      * @param gc GC
2657      */
2658     private void drawGhostRows(GC gc) {
2659         if (_ghostOrigin != null && _ghostRows != null) {
2660             int alpha = gc.getAlpha();
2661             gc.setAlpha(_ghostAlpha);
2662             for (int i = 0; i < _ghostRows.size(); i++) {
2663                 TimeBarRow row = _ghostRows.get(i);
2664                 int yoff = _ghostRowYCoordinates.get(i);
2665 
2666                 if (_delegate.getOrientation().equals(Orientation.HORIZONTAL)) {
2667                     int y = _ghostOrigin.y + yoff;
2668                     drawRowHorizontal(gc, row, y, false);
2669                 } else {
2670                     int x = _ghostOrigin.x + yoff;
2671                     drawRowVertical(gc, row, x, false);
2672                 }
2673             }
2674             gc.setAlpha(alpha);
2675         }
2676     }
2677 
2678     /**
2679      * {@inheritDoc}
2680      */
2681     public boolean isMilliAccuracy() {
2682         return _delegate.isMilliAccuracy();
2683     }
2684 
2685     /**
2686      * {@inheritDoc}
2687      */
2688     public void setMilliAccuracy(boolean milliAccuracy) {
2689         _delegate.setMilliAccuracy(milliAccuracy);
2690     }
2691 
2692     /**
2693      * {@inheritDoc}
2694      */
2695     public TimeBarNode getPpsRow() {
2696         return _delegate.getPpsRow();
2697     }
2698 
2699     /**
2700      * {@inheritDoc}
2701      */
2702     public boolean hasVariableXScale() {
2703         return _delegate.hasVariableXScale();
2704     }
2705 
2706     /**
2707      * {@inheritDoc}
2708      */
2709     public void setVariableXScale(boolean state) {
2710         _delegate.setVariableXScale(state);
2711     }
2712 
2713     /**
2714      * {@inheritDoc}
2715      */
2716     public void doScrollHorizontal(int diff) {
2717         java.awt.Rectangle d = new java.awt.Rectangle(_delegate.getDiagramRect());
2718         if (_delegate.getOrientation().equals(Orientation.HORIZONTAL)) {
2719             if (_delegate.getTimeScalePosition() != TIMESCALE_POSITION_NONE) {
2720                 if (_delegate.getTimeScalePosition() == TIMESCALE_POSITION_TOP) {
2721                     d.y = _delegate.getXAxisRect().y;
2722                 }
2723                 d.height += _delegate.getXAxisRect().height;
2724             }
2725         } else {
2726             d.y = 0;
2727             d.height = d.height + _delegate.getHierarchyWidth() + _delegate.getYAxisWidth();
2728         }
2729 
2730         if (diff > 0) {
2731             // to the right
2732             scroll(d.x, d.y, d.x + diff, d.y, d.width - diff, d.height, false);
2733         } else {
2734             diff = -diff;
2735             scroll(d.x + diff, d.y, d.x, d.y, d.width - diff, d.height, false);
2736         }
2737         
2738         // there might be timescale renderers not supporting optimized scrolling. In this case just
2739         // initiate a redraw of the x axis area
2740         if (_timeScaleRenderer != null && !_timeScaleRenderer.supportsOptimizedScrolling()) {
2741             Rectangle r = convertRect(_delegate.getXAxisRect());
2742             redraw(r.x, r.y, r.width, r.height, false);
2743         }
2744         
2745     }
2746 
2747     /**
2748      * {@inheritDoc}
2749      */
2750     public void doScrollVertical(int diff) {
2751         java.awt.Rectangle d = new java.awt.Rectangle(_delegate.getDiagramRect());
2752         if (_delegate.getOrientation().equals(Orientation.HORIZONTAL)) {
2753             d.x = d.x - _delegate.getHierarchyWidth() - _delegate.getYAxisWidth();
2754             d.width = d.width + _delegate.getHierarchyWidth() + _delegate.getYAxisWidth();
2755         } else {
2756             if (_delegate.getTimeScalePosition() == TIMESCALE_POSITION_TOP) {
2757                 d.x = d.x - _delegate.getXAxisHeight();
2758             }
2759             d.width = d.width + _delegate.getXAxisHeight();
2760         }
2761         if (diff > 0) {
2762             // downwards
2763             scroll(d.x, d.y, d.x, d.y + diff, d.width, d.height - diff, false);
2764         } else {
2765             diff = -diff;
2766             scroll(d.x, d.y + diff, d.x, d.y, d.width, d.height - diff, false);
2767         }
2768     }
2769 
2770     /**
2771      * {@inheritDoc}
2772      */
2773     public boolean getOptimizeScrolling() {
2774         return _delegate.getOptimizeScrolling();
2775     }
2776 
2777     /**
2778      * {@inheritDoc}
2779      */
2780     public void setOptimizeScrolling(boolean optimizeScrolling) {
2781         _delegate.setOptimizeScrolling(optimizeScrolling);
2782     }
2783 
2784     /**
2785      * {@inheritDoc}
2786      */
2787     public Orientation getTBOrientation() {
2788         return _delegate.getOrientation();
2789     }
2790 
2791     /**
2792      * {@inheritDoc}
2793      */
2794     public void setTBOrientation(Orientation orientation) {
2795         _delegate.setOrientation(orientation);
2796     }
2797 
2798     /**
2799      * {@inheritDoc}
2800      */
2801     public int getAutoScaleRows() {
2802         return _delegate.getAutoScaleRows();
2803     }
2804 
2805     /**
2806      * {@inheritDoc}
2807      */
2808     public void setAutoScaleRows(int rows) {
2809         _delegate.setAutoScaleRows(rows);
2810     }
2811 
2812     /**
2813      * Retrieve the bounding rect of an interval. ATTENTION: this uses the row for interval lookup in the model that may
2814      * be imperformant.
2815      * 
2816      * @param interval interval
2817      * @return the bounding rect or null
2818      */
2819     public Rectangle getIntervalBounds(Interval interval) {
2820         return convertRect(_delegate.getIntervalBounds(interval));
2821     }
2822 
2823     /**
2824      * {@inheritDoc}
2825      */
2826     public void addTimeBarChangeListener(ITimeBarChangeListener listener) {
2827         _delegate.addTimeBarChangeListener(listener);
2828     }
2829 
2830     /**
2831      * {@inheritDoc}
2832      */
2833     public void removeTimeBarChangeListener(ITimeBarChangeListener listener) {
2834         _delegate.removeTimeBarChangeListener(listener);
2835     }
2836 
2837     /**
2838      * {@inheritDoc}
2839      */
2840     public void addFocussedIntervalListener(FocussedIntervalListener listener) {
2841         _delegate.addFocussedIntervalListener(listener);
2842     }
2843 
2844     /**
2845      * {@inheritDoc}
2846      */
2847     public void remFocussedIntervalListener(FocussedIntervalListener listener) {
2848         _delegate.remFocussedIntervalListener(listener);
2849     }
2850 
2851     /**
2852      * {@inheritDoc}
2853      */
2854     public ITimeBarViewState getTimeBarViewState() {
2855         return _delegate.getTimeBarViewState();
2856     }
2857 
2858     /**
2859      * {@inheritDoc}
2860      */
2861     public boolean isRowHeightDragginAllowed() {
2862         return _delegate.isRowHeightDraggingAllowed();
2863     }
2864 
2865     /**
2866      * {@inheritDoc}
2867      */
2868     public void setRowHeightDraggingAllowed(boolean rowHeightDraggingAllowed) {
2869         _delegate.setRowHeightDraggingAllowed(rowHeightDraggingAllowed);
2870     }
2871 
2872     /**
2873      * {@inheritDoc}
2874      */
2875     public boolean rowLineHit(int x, int y) {
2876         return _delegate.rowLineHit(x, y);
2877     }
2878 
2879     /**
2880      * {@inheritDoc}
2881      */
2882     public boolean isInRowAxis(int x, int y) {
2883         return _delegate.isInRowAxis(x, y);
2884     }
2885 
2886     /**
2887      * {@inheritDoc}
2888      */
2889     public boolean isInDiagram(int x, int y) {
2890         return _delegate.isInDiagram(x, y);
2891     }
2892 
2893     /**
2894      * {@inheritDoc}
2895      */
2896     public boolean getStrictClipTimeCheck() {
2897         return _delegate.getStrictClipTimeCheck();
2898     }
2899 
2900     /**
2901      * {@inheritDoc}
2902      */
2903     public void setStrictClipTimeCheck(boolean strictClipTimeCheck) {
2904         _delegate.setStrictClipTimeCheck(strictClipTimeCheck);
2905     }
2906 
2907     /**
2908      * {@inheritDoc}
2909      */
2910     public int getSecondsDisplayed() {
2911         return _delegate.getSecondsDisplayed();
2912     }
2913 
2914     /**
2915      * {@inheritDoc}
2916      */
2917     public IOverlapStrategy getOverlapStrategy() {
2918         return _delegate.getOverlapStrategy();
2919     }
2920 
2921     /**
2922      * {@inheritDoc}
2923      */
2924     public void setOverlapStrategy(IOverlapStrategy overlapStrategy) {
2925         _delegate.setOverlapStrategy(overlapStrategy);
2926     }
2927 
2928     /**
2929      * {@inheritDoc}
2930      */
2931     public int getScrollLookBackMinutes() {
2932         return _delegate.getScrollLookBackMinutes();
2933     }
2934 
2935     /**
2936      * {@inheritDoc}
2937      */
2938     public void setScrollLookBackMinutes(int scrollLookBackMinutes) {
2939         _delegate.setScrollLookBackMinutes(scrollLookBackMinutes);
2940     }
2941 
2942     /**
2943      * {@inheritDoc}
2944      */
2945     public void setScrollLookForwardMinutes(int scrollLookForwardMinutes) {
2946         _delegate.setScrollLookForwardMinutes(scrollLookForwardMinutes);
2947     }
2948 
2949     /**
2950      * {@inheritDoc}
2951      */
2952     public int getScrollLookForwardMinutes() {
2953         return _delegate.getScrollLookForwardMinutes();
2954     }
2955 
2956     /**
2957      * {@inheritDoc}
2958      */
2959     public String getName() {
2960         return _delegate.getName();
2961     }
2962 
2963     /**
2964      * {@inheritDoc}
2965      */
2966     public void setName(String name) {
2967         _delegate.setName(name);
2968     }
2969 
2970     /**
2971      * {@inheritDoc}
2972      */
2973     public TimeBarViewerDelegate getDelegate() {
2974         return _delegate;
2975     }
2976 
2977     /**
2978      * {@inheritDoc}
2979      */
2980     public int getAutoscrollDelta() {
2981         return _delegate.getAutoscrollDelta();
2982     }
2983 
2984     /**
2985      * {@inheritDoc}
2986      */
2987     public void setAutoscrollDelta(int autoscrollDelta) {
2988         _delegate.setAutoscrollDelta(autoscrollDelta);
2989     }
2990 
2991     /**
2992      * {@inheritDoc}
2993      */
2994     public boolean getDragAllSelectedIntervals() {
2995         return _delegate.getDragAllSelectedIntervals();
2996     }
2997 
2998     /**
2999      * {@inheritDoc}
3000      */
3001     public void setDragAllSelectedIntervals(boolean dragAllSelectedIntervals) {
3002         _delegate.setDragAllSelectedIntervals(dragAllSelectedIntervals);
3003     }
3004 
3005     /**
3006      * {@inheritDoc}
3007      */
3008     public List<IIntervalRelation> getRelationsForCoord(int x, int y) {
3009         if (_relationRenderer != null) {
3010             return _relationRenderer.getRelationsForCoord(x, y);
3011         } else {
3012             return null;
3013         }
3014     }
3015 
3016     /**
3017      * {@inheritDoc}
3018      */
3019     public String getRelationTooltip(int x, int y) {
3020         if (_relationRenderer != null) {
3021             return _relationRenderer.getTooltip(x, y);
3022         }
3023         return null;
3024     }
3025 
3026     /**
3027      * {@inheritDoc}
3028      */
3029     public boolean getScrollOnFocus() {
3030         return _delegate.getScrollOnFocus();
3031     }
3032 
3033     /**
3034      * {@inheritDoc}
3035      */
3036     public void setScrollOnFocus(boolean scrollOnFocus) {
3037         _delegate.setScrollOnFocus(scrollOnFocus);
3038     }
3039 
3040     /**
3041      * {@inheritDoc}
3042      */
3043     public void addSelectionRectListener(ISelectionRectListener listener) {
3044         _delegate.addSelectionRectListener(listener);
3045     }
3046 
3047     /**
3048      * {@inheritDoc}
3049      */
3050     public void remSelectionRectListener(ISelectionRectListener listener) {
3051         _delegate.remSelectionRectListener(listener);
3052     }
3053 
3054     /**
3055      * {@inheritDoc}
3056      */
3057     public boolean getHideRoot() {
3058         return _delegate.getHideRoot();
3059     }
3060 
3061     /**
3062      * {@inheritDoc}
3063      */
3064     public void setHideRoot(boolean hideRoot) {
3065         _delegate.setHideRoot(hideRoot);
3066     }
3067 
3068     /**
3069      * {@inheritDoc}
3070      */
3071     public boolean getMarkerDraggingInDiagramArea() {
3072         return _delegate.getMarkerDraggingInDiagramArea();
3073     }
3074 
3075     /**
3076      * {@inheritDoc}
3077      */
3078     public void setMarkerDraggingInDiagramArea(boolean allowed) {
3079         _delegate.setMarkerDraggingInDiagramArea(allowed);
3080     }
3081 
3082     /**
3083      * {@inheritDoc}
3084      */
3085     public void clearRegionRect() {
3086         _delegate.clearRegionRect();
3087     }
3088 
3089     /**
3090      * {@inheritDoc}
3091      */
3092     public TBRect getRegionRect() {
3093         return _delegate.getRegionRect();
3094     }
3095 
3096     /**
3097      * {@inheritDoc}
3098      */
3099     public boolean getRegionRectEnable() {
3100         return _delegate.getRegionRectEnable();
3101     }
3102 
3103     /**
3104      * {@inheritDoc}
3105      */
3106     public void setRegionRectEnable(boolean enabled) {
3107         _delegate.setRegionRectEnable(enabled);
3108     }
3109 
3110     /**
3111      * {@inheritDoc}
3112      */
3113     public boolean getUseUniformHeight() {
3114         return _delegate.getUseUniformHeight();
3115     }
3116 
3117     /**
3118      * {@inheritDoc}
3119      */
3120     public void setUseUniformHeight(boolean useUniformHeight) {
3121         _delegate.setUseUniformHeight(useUniformHeight);
3122     }
3123 
3124     /**
3125      * {@inheritDoc}
3126      */
3127     public void setSecondsDisplayed(int seconds, boolean center) {
3128         _delegate.setSecondsDisplayed(seconds, center);
3129     }
3130 
3131     /**
3132      * {@inheritDoc}
3133      */
3134     public void setSecondsDisplayed(int seconds, JaretDate centerDate) {
3135         _delegate.setSecondsDisplayed(seconds, centerDate);
3136     }
3137 
3138     /**
3139      * {@inheritDoc}
3140      */
3141     public boolean isDisplayed(JaretDate date) {
3142         return _delegate.isDisplayed(date);
3143     }
3144     
3145     /**
3146      * {@inheritDoc}
3147      */
3148     public void setInitialDisplayRange(JaretDate startDate, int secondsDisplayed){
3149     	_delegate.setInitialDisplayRange(startDate, secondsDisplayed);
3150     }
3151 
3152     /**
3153      * {@inheritDoc}
3154      */
3155     public Pair<TimeBarRow, JaretDate> getPopUpInformation() {
3156         return _delegate.getPopUpInformation();
3157     }
3158 
3159 }