View Javadoc

1   /*
2    *  File: TimeBarPrinter.java 
3    *  Copyright (c) 2004-2007  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.util.ArrayList;
23  import java.util.HashMap;
24  import java.util.List;
25  import java.util.Map;
26  
27  import org.eclipse.swt.SWT;
28  import org.eclipse.swt.graphics.Color;
29  import org.eclipse.swt.graphics.Font;
30  import org.eclipse.swt.graphics.FontData;
31  import org.eclipse.swt.graphics.GC;
32  import org.eclipse.swt.graphics.Point;
33  import org.eclipse.swt.printing.Printer;
34  
35  import de.jaret.util.date.Interval;
36  import de.jaret.util.date.JaretDate;
37  import de.jaret.util.ui.timebars.TimeBarViewerDelegate;
38  import de.jaret.util.ui.timebars.TimeBarViewerInterface;
39  import de.jaret.util.ui.timebars.ViewConfiguration;
40  import de.jaret.util.ui.timebars.model.TimeBarRow;
41  import de.jaret.util.ui.timebars.strategy.ITickProvider;
42  import de.jaret.util.ui.timebars.swt.renderer.GlobalAssistantRenderer;
43  import de.jaret.util.ui.timebars.swt.renderer.GridRenderer;
44  import de.jaret.util.ui.timebars.swt.renderer.HeaderRenderer;
45  import de.jaret.util.ui.timebars.swt.renderer.HierarchyRenderer;
46  import de.jaret.util.ui.timebars.swt.renderer.IRelationRenderer;
47  import de.jaret.util.ui.timebars.swt.renderer.TimeBarGapRenderer;
48  import de.jaret.util.ui.timebars.swt.renderer.TimeBarMarkerRenderer;
49  import de.jaret.util.ui.timebars.swt.renderer.TimeBarRenderer;
50  import de.jaret.util.ui.timebars.swt.renderer.TimeScaleRenderer;
51  import de.jaret.util.ui.timebars.swt.renderer.TitleRenderer;
52  
53  /**
54   * Utility class for printing a time bar chart. All renderers used have to support the creation of a print renderer.
55   * 
56   * @author Peter Kliem
57   * @version $Id: TimeBarPrinter.java 1083 2011-07-01 20:29:16Z kliem $
58   */
59  public class TimeBarPrinter {
60      /** default margin in cm. */
61      private static final double DEFAULT_MARGIN = 1.0;
62  
63      /** default heigth for the footer line in cm. */
64      private static final double DEFAULT_FOOTER_HEIGHT = 0.5;
65  
66      /** screen dpi on x axis. */
67      private static final double SCREEN_DPI_X = 96.0;
68      /** screen dpi on y axis. */
69      private static final double SCREEN_DPI_Y = 96.0;
70  
71      /** one inch in cm. */
72      private static final double INCH_IN_CM = 2.54;
73  
74      /** printer font name. */
75      private static final String PRINTERFONTNAME = "Sans";
76      /** size of the printer font. */
77      private static final int PRINTERFONTSIZE = 6;
78  
79      /** printer device. */
80      protected Printer _printer;
81      /** scale factor horizontal. */
82      protected double _scaleX;
83      /** scale factor vertical. */
84      protected double _scaleY;
85  
86      /** time scale renderer. */
87      protected TimeScaleRenderer _timeScaleRenderer;
88      /** header renderer. */
89      protected HeaderRenderer _headerRenderer;
90      /** time bar renderer. */
91      protected TimeBarRenderer _renderer;
92      /** hierarchy renderer. */
93      protected HierarchyRenderer _hierarchyRenderer;
94      /** grid renderer. */
95      protected GridRenderer _gridRenderer;
96      /** gap raenderer. */
97      protected TimeBarGapRenderer _gapRenderer;
98      /** marker renderer. */
99      protected TimeBarMarkerRenderer _markerRenderer;
100     /** title renderer. */
101     protected TitleRenderer _titleRenderer;
102     /** global assistance renderer. */
103     protected GlobalAssistantRenderer _globalAssistantRenderer;
104     /** relation renderer. */
105     protected IRelationRenderer _relationRenderer;
106 
107     /** mapping between interval classes and renderers (printer). */
108     protected Map<Class<? extends Interval>, TimeBarRenderer> _printerRendererMap = new HashMap<Class<? extends Interval>, TimeBarRenderer>();
109 
110     /** timebarviewerdelegate works for the printer. */
111     protected TimeBarViewerDelegate _delegate = new TimeBarViewerDelegate(null);
112 
113     /** height of the footer in cm. */
114     protected double _footerHeight = DEFAULT_FOOTER_HEIGHT;
115 
116     /** top margin in cm. */
117     protected double _marginTop = DEFAULT_MARGIN;
118     /** bottom margin in cm. */
119     protected double _marginBottom = DEFAULT_MARGIN;
120     /** left margin in cm. */
121     protected double _marginLeft = DEFAULT_MARGIN;
122     /** right margin in cm. */
123     protected double _marginRight = DEFAULT_MARGIN;
124 
125     /**
126      * Construct a timebar printer.
127      * 
128      * @param printer printer device
129      */
130     public TimeBarPrinter(Printer printer) {
131         _printer = printer;
132         Point dpi = _printer.getDPI();
133         _scaleX = (double) dpi.x / SCREEN_DPI_X;
134         _scaleY = (double) dpi.y / SCREEN_DPI_Y;
135     }
136 
137     /**
138      * Scale a pixel value to printer coordinates (x axis).
139      * 
140      * @param in value to scale
141      * @return scaled value
142      */
143     public int scaleX(int in) {
144         return (int) Math.round(_scaleX * (double) in);
145     }
146 
147     /**
148      * Retrieve the scale factor for the x axis.
149      * 
150      * @return scale factor
151      */
152     public double getScaleX() {
153         return _scaleX;
154     }
155 
156     /**
157      * Scale a pixel value to printer coordinates (y axis).
158      * 
159      * @param in value to scale
160      * @return scaled value
161      */
162     public int scaleY(int in) {
163         return (int) Math.round(_scaleY * (double) in);
164     }
165 
166     /**
167      * Retrieve the scale factor for the y axis.
168      * 
169      * @return scale factor
170      */
171     public double getScaleY() {
172         return _scaleY;
173     }
174 
175     /**
176      * Convert a value in cm to a number of printer pixels (x axis).
177      * 
178      * @param cm value to convert
179      * @return converted value in printer pixel
180      */
181     protected int pixelForCmX(double cm) {
182         Point dpi = _printer.getDPI();
183         double inch = cm / INCH_IN_CM;
184         return (int) (dpi.x * inch);
185     }
186 
187     /**
188      * Convert a value in cm to a number of printer pixels (y axis).
189      * 
190      * @param cm value to convert
191      * @return converted value in printer pixel
192      */
193     protected int pixelForCmY(double cm) {
194         Point dpi = _printer.getDPI();
195         double inch = cm / INCH_IN_CM;
196         return (int) (dpi.y * inch);
197     }
198 
199     /**
200      * Retrieve the printer device.
201      * 
202      * @return the printer device
203      */
204     public Printer getPrinter() {
205         return _printer;
206     }
207 
208     /**
209      * Access to the delegate.
210      * 
211      * @return the delegate
212      */
213     public TimeBarViewerDelegate getDelegate() {
214         return _delegate;
215     }
216 
217     /**
218      * Init the timebarprinter with the appropriate rendereres and settings from the timebarviewer.
219      * 
220      * @param tbv timebarviewer giving the settings
221      */
222     public void init(TimeBarViewer tbv) {
223         // no optimized scrolling for printing
224         _delegate.setOptimizeScrolling(false);
225         // renderers
226         if (tbv.getTimeScaleRenderer() != null) {
227             _timeScaleRenderer = tbv.getTimeScaleRenderer().createPrintRenderer(_printer);
228         }
229         if (tbv.getHeaderRenderer() != null) {
230             _headerRenderer = tbv.getHeaderRenderer().createPrintRenderer(_printer);
231         }
232         if (tbv.getGridRenderer() != null) {
233             _gridRenderer = tbv.getGridRenderer().createPrintRenderer(_printer);
234         }
235         if (tbv.getHierarchyRenderer() != null) {
236             _hierarchyRenderer = tbv.getHierarchyRenderer().createPrintRenderer(_printer);
237         }
238         if (tbv.getGapRenderer() != null) {
239             _gapRenderer = tbv.getGapRenderer().createPrintRenderer(_printer);
240         }
241         if (tbv.getMarkerRenderer() != null) {
242             _markerRenderer = tbv.getMarkerRenderer().createPrintRenderer(_printer);
243         }
244         if (tbv.getTitleRenderer() != null) {
245             _titleRenderer = tbv.getTitleRenderer().createPrintRenderer(_printer);
246         }
247         if (tbv.getGlobalAssistantRenderer() != null) {
248             _globalAssistantRenderer = tbv.getGlobalAssistantRenderer().createPrintRenderer(_printer);
249         }
250         if (tbv.getRelationRenderer() != null) {
251             _relationRenderer = tbv.getRelationRenderer().createPrintRenderer(_printer);
252         }
253 
254         // renderer map
255         // create a print renderer for every renderer registerd with the viewer
256         Map<Class<? extends Interval>, TimeBarRenderer> rendererMap = tbv.getRendererMapping();
257         for (Class<? extends Interval> clazz : rendererMap.keySet()) {
258             TimeBarRenderer displayRenderer = rendererMap.get(clazz);
259             TimeBarRenderer printRenderer = displayRenderer.createPrintrenderer(_printer);
260             _printerRendererMap.put(clazz, printRenderer);
261         }
262 
263         // orientation
264         boolean horizontal = tbv.getTBOrientation().equals(TimeBarViewerInterface.Orientation.HORIZONTAL);
265         _delegate.setOrientation(tbv.getTBOrientation());
266 
267         // markers
268         _delegate.addMarkers(tbv.getMarkers());
269 
270         _delegate.setModel(tbv.getHierarchicalModel());
271         _delegate.setHierarchicalViewState(tbv.getHierarchicalViewState());
272         _delegate.setModel(tbv.getModel());
273 
274         _delegate.setXAxisHeight(scaleY(tbv.getXAxisHeight()));
275         if (_timeScaleRenderer.getHeight() > 0) {
276             _delegate.setXAxisHeight(_timeScaleRenderer.getHeight());
277         }
278         _delegate.setTimeScalePosition(tbv.getTimeScalePosition());
279 
280         _delegate.setYAxisWidth(scaleX(tbv.getYAxisWidth()));
281         _delegate.setHierarchyWidth(scaleX(tbv.getHierarchyWidth()));
282         // row heights
283         // default
284         _delegate.setRowHeight(scaleY(tbv.getRowHeight()));
285         if (tbv.getTimeBarViewState().getUseVariableRowHeights()) {
286             _delegate.getTimeBarViewState().setUseVariableRowHeights(true);
287             for (int i = 0; i < tbv.getModel().getRowCount(); i++) {
288                 TimeBarRow row = tbv.getModel().getRow(i);
289                 int height = tbv.getTimeBarViewState().getRowHeight(row);
290                 if (horizontal) {
291                     height = scaleY(height);
292                 } else {
293                     height = scaleX(height);
294                 }
295                 _delegate.getTimeBarViewState().setRowHeight(row, height);
296             }
297             // use the same strategy if set
298             _delegate.getTimeBarViewState().setRowHeightStrategy(tbv.getTimeBarViewState().getRowHeightStrategy());
299         }
300 
301         _delegate.setDrawRowGrid(tbv.getDrawRowGrid());
302 
303         // filter etcs
304         _delegate.setRowSorter(tbv.getRowSorter());
305         _delegate.setRowFilter(tbv.getRowFilter());
306         _delegate.setIntervalFilter(tbv.getIntervalFilter());
307 
308         _delegate.setDrawOverlapping(tbv.getDrawOverlapping());
309         _delegate.setTitle(tbv.getTitle());
310     }
311 
312     /**
313      * Retrieve a renderer for a given class. Checks all interfaces and all superclasses.
314      * 
315      * @param clazz class in question
316      * @return renderer or null
317      */
318     protected TimeBarRenderer getRenderer(Class<? extends Interval> clazz) {
319         TimeBarRenderer result = null;
320         result = _printerRendererMap.get(clazz);
321         if (result != null) {
322             return result;
323         }
324 
325         // direct interfaces
326         Class<?>[] interfaces = clazz.getInterfaces();
327         for (Class<?> c : interfaces) {
328             result = _printerRendererMap.get(c);
329             if (result != null) {
330                 return result;
331             }
332         }
333 
334         // superclasses
335         Class<?> sc = clazz.getSuperclass();
336 
337         while (sc != null) {
338             result = _printerRendererMap.get(sc);
339             if (result != null) {
340                 return result;
341             }
342             // interfaces of the superclass
343             Class<?>[] scinterfaces = sc.getInterfaces();
344             for (Class<?> c : scinterfaces) {
345                 result = _printerRendererMap.get(c);
346                 if (result != null) {
347                     return result;
348                 }
349             }
350             sc = sc.getSuperclass();
351         }
352 
353         return result;
354     }
355 
356     /**
357      * Do the printing.
358      * 
359      * @param vc configuration to use for printing.
360      */
361     public void print(ViewConfiguration vc) {
362 
363         int marginTop = pixelForCmY(_marginTop);
364         int marginBottom = pixelForCmY(_marginBottom);
365         int marginLeft = pixelForCmX(_marginLeft);
366         int marginRight = pixelForCmX(_marginRight);
367 
368         int footerHeight = pixelForCmX(_footerHeight);
369 
370         int width = _printer.getClientArea().width - marginLeft - marginRight;
371         int height = _printer.getClientArea().height - marginTop - marginBottom - footerHeight;
372 
373         _printer.startJob(vc.getName() != null ? vc.getName() : "timebars_print");
374 
375         // set a font that roughly matches the font size on screen
376         GC gc = new GC(_printer);
377         Font oldfont = gc.getFont();
378         FontData fontdata = new FontData(PRINTERFONTNAME, PRINTERFONTSIZE, SWT.NULL);
379         Font printerFont = new Font(_printer, fontdata);
380         gc.setFont(printerFont);
381 
382         int secTotal;
383         if (vc.getEndDate() != null) {
384             secTotal = vc.getEndDate().diffSeconds(vc.getStartDate());
385         } else {
386             secTotal = _delegate.getModel().getMaxDate().diffSeconds(vc.getStartDate());
387         }
388 
389         int totalyaxiswidth = _delegate.getHierarchyWidth() + _delegate.getYAxisWidth();
390 
391         _delegate.setDrawingOffset(marginLeft, marginTop);
392         _delegate.preparePaint(width, height);
393         // pps is determined by the seconds per page (first page with scales)
394         double pps = (double) _delegate.getDiagramRect().width / (double) vc.getSecondsPerPage();
395         _delegate.setPixelPerSecond(pps);
396 
397         // the number of pixels that will be needed to print all data
398         long totalPixelWidth = (long) ((double) secTotal * pps);
399 
400         // calculate the number of pages along the x axis
401         int pagesX;
402         if (vc.getRepeatYAxis()) {
403             pagesX = secTotal / vc.getSecondsPerPage();
404             // check for "broken page"
405             if (secTotal % vc.getSecondsPerPage() > 0) {
406                 pagesX += 1;
407             }
408         } else {
409             if (secTotal <= vc.getSecondsPerPage()) {
410                 pagesX = 1;
411             } else {
412                 long remain = totalPixelWidth;
413                 pagesX = 0;
414                 // first page with yscale
415                 pagesX++;
416                 remain -= _delegate.getDiagramRect().width;
417                 // subsequent pages
418                 pagesX += remain / (_delegate.getDiagramRect().width + totalyaxiswidth);
419                 // check for "broken page"
420                 if (remain % (_delegate.getDiagramRect().width + totalyaxiswidth) > 0) {
421                     pagesX++;
422                 }
423             }
424         }
425 
426         
427         // calculate the number of pages along the y axis
428         int pagesY;
429         List<Integer> firstRows = new ArrayList<Integer>();
430         List<Integer> firstRowOffsets = new ArrayList<Integer>();
431 
432         int y = 0;
433         int pageIdx = 0;
434         int rowIdx = 0;
435 
436         while (rowIdx < _delegate.getRowCount()) {
437             rowIdx = _delegate.getRowIdxForAbsoluteOffset(y);
438             firstRows.add(rowIdx);
439             firstRowOffsets.add(_delegate.getRowPixOffsetForAbsoluteOffset(rowIdx, y));
440             if (vc.getRepeatScale() || pageIdx == 0) {
441                 y += _delegate.getDiagramRect().height;
442             } else {
443                 y += _delegate.getDiagramRect().height + _delegate.getXAxisHeight();
444             }
445 
446             pageIdx++;
447             try {
448                 rowIdx = _delegate.getRowIdxForAbsoluteOffset(y);
449             } catch (Exception e) {
450                 rowIdx = -1;
451             }
452             if (rowIdx >= _delegate.getRowCount() || rowIdx == -1) {
453                 break;
454             }
455         }
456         pagesY = pageIdx;
457 
458         // System.out.println("pages x:" + pagesX + " pagesY:" + pagesY);
459 
460         int xaxisheigth = _delegate.getXAxisHeight();
461         int yaxisWidth = _delegate.getYAxisWidth();
462         int hierarchyWidth = _delegate.getHierarchyWidth();
463 
464         JaretDate pageStart = vc.getStartDate().copy();
465         for (int px = 0; px < pagesX; px++) {
466             _delegate.setStartDate(pageStart);
467             for (int py = 0; py < pagesY; py++) {
468                 String footerText = vc.getFootLine() != null ? vc.getFootLine() : "";
469                 footerText += "(" + (px + 1) + "/" + pagesX + "," + (py + 1) + "/" + pagesY + ")";
470                 _printer.startPage();
471                 if (vc.getRepeatScale()
472                         || (py == 0 && _delegate.getTimeScalePosition() == TimeBarViewerInterface.TIMESCALE_POSITION_TOP)
473                         || (py == pagesY - 1 && _delegate.getTimeScalePosition() == TimeBarViewerInterface.TIMESCALE_POSITION_BOTTOM)) {
474                     _delegate.setXAxisHeight(xaxisheigth);
475                 } else {
476                     _delegate.setXAxisHeight(0);
477                 }
478                 if (vc.getRepeatYAxis() || px == 0) {
479                     _delegate.setHierarchyWidth(hierarchyWidth);
480                     _delegate.setYAxisWidth(yaxisWidth);
481                 } else {
482                     _delegate.setHierarchyWidth(0);
483                     _delegate.setYAxisWidth(0);
484                 }
485 
486                 // do the geometry calculation
487                 _delegate.preparePaint(width, height);
488 
489                 print(gc, footerText, firstRows.get(py), firstRowOffsets.get(py), _delegate.getDiagramRect().height,
490                         footerHeight);
491                 _printer.endPage();
492             }
493             // advance the start date
494             pageStart = _delegate.getEndDate().copy();
495 
496         }
497         _printer.endJob();
498         gc.setFont(oldfont);
499         printerFont.dispose();
500         gc.dispose();
501     }
502 
503     /**
504      * Do the actual printing of one page.
505      * 
506      * @param gc GC to use
507      * @param footer footer string for the page
508      * @param firstRow the index of the first row to be painted
509      * @param firstRowOffset offset of the first row
510      * @param diagramHeight height of the diagram
511      * @param footerHeight the height of the footer in pixel
512      */
513     private void print(GC gc, String footer, int firstRow, int firstRowOffset, int diagramHeight, int footerHeight) {
514         // System.out.println("print "+firstRow+" offset "+firstRowOffset);
515         _delegate.setFirstRow(firstRow, firstRowOffset);
516 
517         // draw the axis first
518         RenderDelegate.drawXAxis(_delegate, _timeScaleRenderer, true, gc);
519         // use the timescale renderre as the tick provider if set and implemnting the interface
520         // TODO this is not exactly super clean since there might be another tick provider that have been set on the grid renderer
521         if (_timeScaleRenderer != null && _timeScaleRenderer instanceof ITickProvider) {
522             _gridRenderer.setTickProvider((ITickProvider)_timeScaleRenderer);
523         }
524         RenderDelegate.drawGrid(_delegate, _gridRenderer, true, gc);
525         if (_globalAssistantRenderer != null) {
526             _globalAssistantRenderer.doRenderingBeforeIntervals(_delegate, gc, true);
527         }
528 //        RenderDelegate.drawXAxis(_delegate, _timeScaleRenderer, true, gc);
529         drawRows(gc);
530         RenderDelegate.drawMarkers(_delegate, _markerRenderer, true, gc);
531         if (_delegate.getTitleRect().width > 0 && _delegate.getTitleRect().height > 0) {
532             RenderDelegate.drawTitle(_delegate, _titleRenderer, true, gc);
533         }
534         if (footer != null) {
535             drawFooter(gc, footer, _delegate.getDiagramRect().y + _delegate.getDiagramRect().height, footerHeight);
536         }
537         if (_globalAssistantRenderer != null) {
538             _globalAssistantRenderer.doRenderingLast(_delegate, gc, true);
539         }
540 
541         // WORKAROUND: since clipping seems to be unsupported by the printer gc
542         // clear the right margin
543         Color bg = gc.getBackground();
544         gc.fillRectangle(_delegate.getDiagramRect().x + _delegate.getDiagramRect().width, _delegate.getDiagramRect().y,
545                 pixelForCmX(_marginLeft), _delegate.getDiagramRect().height);
546         gc.setBackground(bg);
547 
548     }
549 
550     /**
551      * Draw the footer.
552      * 
553      * @param gc GC
554      * @param footer footer text
555      * @param footerStartY the y position of the footer
556      * @param footerHeight the height of the footer in pixel
557      */
558     private void drawFooter(GC gc, String footer, int footerStartY, int footerHeight) {
559         Point extent = gc.textExtent(footer);
560         int y = footerStartY + (footerHeight - extent.y) / 2;
561         gc.drawString(footer, _delegate.getHierarchyRect().x, y);
562     }
563 
564     /**
565      * Render all rows to the given gc.
566      * 
567      * @param gc GC to use
568      */
569     private void drawRows(GC gc) {
570 
571         // relation rendering
572         if (_relationRenderer != null) {
573             _relationRenderer.renderRelations(_delegate, gc, true);
574         }
575 
576         int firstRow = _delegate.getFirstRow();
577         // separating line to the header
578         // and the hierarchy area
579         int startY = Math.min(_delegate.getXAxisRect().y, _delegate.getDiagramRect().y);
580         int endY = Math.max(_delegate.getXAxisRect().y + _delegate.getXAxisRect().height, _delegate.getDiagramRect().y
581                 + _delegate.getDiagramRect().height);
582         // line between header and diagram
583         if (_delegate.getYAxisWidth() > 0) {
584             gc.drawLine(_delegate.getDiagramRect().x - 1, startY, _delegate.getDiagramRect().x - 1, endY);
585         }
586         // line between hierarchy and header
587         if (_delegate.getHierarchyWidth() > 0) {
588             gc.drawLine(_delegate.getHierarchyRect().x + _delegate.getHierarchyRect().width - 1, startY, _delegate
589                     .getHierarchyRect().x
590                     + _delegate.getHierarchyRect().width - 1, endY);
591         }
592         int upperYBound = 0;
593         int lowerYBound = _printer.getClientArea().height;
594         if (gc.isClipped()) {
595             upperYBound = gc.getClipping().y;
596             lowerYBound = upperYBound + gc.getClipping().height;
597         }
598         for (int r = firstRow; r <= firstRow + _delegate.getRowsDisplayed() + 1 && r < _delegate.getRowCount(); r++) {
599             TimeBarRow row = _delegate.getRow(r);
600             int y = _delegate.yForRow(row);
601             if (y == -1) {
602                 // no coord -> is not displayed
603                 break;
604             }
605             // row is drawn if either the beginning or the end is inside the
606             // clipping rect
607             // or if the upperBound is inside the row rect (clipping rect is
608             // inside the row rect
609             int rowHeight = _delegate.getTimeBarViewState().getRowHeight(row);
610             if ((y >= upperYBound && y <= lowerYBound)
611                     || (y + rowHeight >= upperYBound && y + rowHeight <= lowerYBound)
612                     || (upperYBound > y && upperYBound < y + rowHeight)) {
613                 RenderDelegate.drawRowSimple(_delegate, this, _headerRenderer, _hierarchyRenderer, true, gc, _delegate
614                         .getRow(r), y, false);
615                 // draw gaps if a renderer is set
616                 if (_gapRenderer != null) {
617                     RenderDelegate.drawRowGaps(_delegate, _gapRenderer, true, gc, 0, y, _delegate.getRow(r), false);
618                 }
619             }
620         }
621     }
622 
623     /**
624      * Dispose whatever needs disposal. The method has to be called by the user of the the timebar printer.
625      */
626     public void dispose() {
627         _delegate.dispose();
628         if (_headerRenderer != null) {
629             _headerRenderer.dispose();
630         }
631         if (_timeScaleRenderer != null) {
632             _timeScaleRenderer.dispose();
633         }
634         if (_renderer != null) {
635             _renderer.dispose();
636         }
637         if (_hierarchyRenderer != null) {
638             _hierarchyRenderer.dispose();
639         }
640         if (_gridRenderer != null) {
641             _gridRenderer.dispose();
642         }
643         if (_markerRenderer != null) {
644             _markerRenderer.dispose();
645         }
646         if (_titleRenderer != null) {
647             _titleRenderer.dispose();
648         }
649         if (_gapRenderer != null) {
650             _gapRenderer.dispose();
651         }
652         if (_globalAssistantRenderer != null) {
653             _globalAssistantRenderer.dispose();
654         }
655         if (_relationRenderer != null) {
656             _relationRenderer.dispose();
657         }
658 
659         // dispose all interval renderers
660         for (TimeBarRenderer renderer : _printerRendererMap.values()) {
661             renderer.dispose();
662         }
663 
664     }
665 
666     /**
667      * @return footerheigth in cm
668      */
669     public double getFooterHeight() {
670         return _footerHeight;
671     }
672 
673     /**
674      * 
675      * @param footerHeight height of the footer line in cm
676      */
677     public void setFooterHeight(double footerHeight) {
678         _footerHeight = footerHeight;
679     }
680 
681     /**
682      * Retrieve the top margin (cm).
683      * 
684      * @return margin in cm
685      */
686     public double getMarginTop() {
687         return _marginTop;
688     }
689 
690     /**
691      * Set the top margin (cm).
692      * 
693      * @param marginTop margin in cm
694      */
695     public void setMarginTop(double marginTop) {
696         _marginTop = marginTop;
697     }
698 
699     /**
700      * Retrieve the bottom margin (cm).
701      * 
702      * @return margin in cm
703      */
704     public double getMarginBottom() {
705         return _marginBottom;
706     }
707 
708     /**
709      * Set the bottom margin (cm).
710      * 
711      * @param marginBottom margin in cm
712      */
713     public void setMarginBottom(double marginBottom) {
714         _marginBottom = marginBottom;
715     }
716 
717     /**
718      * Retrieve the left margin (cm).
719      * 
720      * @return margin in cm
721      */
722     public double getMarginLeft() {
723         return _marginLeft;
724     }
725 
726     /**
727      * Set the left margin (cm).
728      * 
729      * @param marginLeft margin in cm
730      */
731     public void setMarginLeft(double marginLeft) {
732         _marginLeft = marginLeft;
733     }
734 
735     /**
736      * Retrieve the right margin (cm).
737      * 
738      * @return margin in cm
739      */
740     public double getMarginRight() {
741         return _marginRight;
742     }
743 
744     /**
745      * Set the right margin (cm).
746      * 
747      * @param marginRight margin in cm
748      */
749     public void setMarginRight(double marginRight) {
750         _marginRight = marginRight;
751     }
752 }