View Javadoc

1   /*
2    *  File: DefaultTableHeaderRenderer.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    * All rights reserved. This program and the accompanying materials
7    * are made available under the terms of the Common Public License v1.0
8    * which accompanies this distribution, and is available at
9    * http://www.eclipse.org/legal/cpl-v10.html
10   */
11  package de.jaret.util.ui.table.renderer;
12  
13  import org.eclipse.jface.resource.ImageDescriptor;
14  import org.eclipse.jface.resource.ImageRegistry;
15  import org.eclipse.swt.SWT;
16  import org.eclipse.swt.graphics.Color;
17  import org.eclipse.swt.graphics.Font;
18  import org.eclipse.swt.graphics.FontData;
19  import org.eclipse.swt.graphics.GC;
20  import org.eclipse.swt.graphics.Image;
21  import org.eclipse.swt.graphics.ImageData;
22  import org.eclipse.swt.graphics.Point;
23  import org.eclipse.swt.graphics.RGB;
24  import org.eclipse.swt.graphics.Rectangle;
25  import org.eclipse.swt.graphics.Transform;
26  import org.eclipse.swt.printing.Printer;
27  import org.eclipse.swt.widgets.Display;
28  
29  import de.jaret.util.swt.SwtGraphicsHelper;
30  import de.jaret.util.ui.table.model.IColumn;
31  
32  /***
33   * Default header renderer for the jaret table. The header renderer will render a simple header view. The renderer
34   * supports rotating the header text from 0 to 90 degrees anti-clock wise. If a rotation is set, the header is drawn
35   * using a white background. Several properties allow changing the drawing (always consider writing a specialized
36   * renderer!).
37   * 
38   * @author Peter Kliem
39   * @version $Id: DefaultTableHeaderRenderer.java 1077 2010-12-17 12:03:27Z kliem $
40   */
41  public class DefaultTableHeaderRenderer extends RendererBase implements ITableHeaderRenderer {
42      /*** Alignment enumeration. */
43      public enum Alignment {
44          LEFT, CENTER, RIGHT
45      };
46  
47      /*** default background rgb for non rotated drawing. */
48      private static RGB DEFAULTBACKGROUND = new RGB(220, 220, 220);
49  
50      /*** Alignment: default left. */
51      protected Alignment _alignment = Alignment.LEFT;
52  
53      /*** true if the header box should be drawn. */
54      protected boolean _drawBox = true;
55  
56      /*** background rgb value. */
57      protected RGB _backgroundRGB = DEFAULTBACKGROUND;
58      /*** allocated background color. */
59      protected Color _bgColor;
60  
61      /*** FOntadat of the font to use. */
62      protected FontData _fontData;
63      /*** font when aquired. */
64      protected Font _font;
65  
66      /*** rotation of the header text. */
67      protected int _rotation = 0;
68  
69      /*** Transformations for rotated text. */
70      protected Transform _transform;
71      /*** inverse transformation to reset gc. */
72      protected Transform _transformInv;
73  
74      protected ImageRegistry _imageRegistry;
75  
76      /*** key for uowards arrow. */
77      protected static final String UP = "up";
78      /*** key for downwards arrow. */
79      protected static final String DOWN = "down";
80      /*** width reserved for the sorting area. */
81      protected static final int SORTINGAREAINDICATORWIDTH = 16;
82  
83      /*** preferred height to use when more space is available. */
84      private static final int PREFHEIGHT = 20;
85  
86      /***
87       * Construct a header renderer for printing.
88       * 
89       * @param printer printer device
90       */
91      public DefaultTableHeaderRenderer(Printer printer) {
92          super(printer);
93      }
94  
95      /***
96       * Construct header renderer for a display.
97       */
98      public DefaultTableHeaderRenderer() {
99          super(null);
100     }
101 
102     /***
103      * Set the rotation of the header text. Please note that you have to call <code>redraw()</code> on the table
104      * yourself if you change the rotation while the table is showing.
105      * 
106      * @param rotation rotation in degrees anti clockwise between 0 and 90 degrees.
107      */
108     public void setRotation(int rotation) {
109         if (rotation < 0 || rotation > 90) {
110             throw new IllegalArgumentException("Rotation range 0..90");
111         }
112         if (_rotation != rotation) {
113             disposeTransformations();
114             _rotation = rotation;
115             _transform = new Transform(Display.getCurrent());
116             _transformInv = new Transform(Display.getCurrent());
117             _transform.rotate(-rotation);
118             _transformInv.rotate(-rotation);
119             _transformInv.invert();
120         }
121     }
122 
123     /***
124      * {@inheritDoc}
125      */
126     public void draw(GC gc, Rectangle drawingArea, IColumn column, int sortingOrder, boolean sortDir, boolean printing) {
127         Color bg = gc.getBackground();
128         Font font = gc.getFont();
129         String label = column.getHeaderLabel();
130 
131         if (_fontData != null && _font == null) {
132             _font = new Font(gc.getDevice(), _fontData);
133         }
134         if (_font != null) {
135             gc.setFont(_font);
136         }
137 
138         if (_rotation == 0) {
139             // classic rendering
140 
141             // allocate color when not allocated
142             if (_bgColor == null) {
143                 _bgColor = new Color(gc.getDevice(), _backgroundRGB);
144             }
145 
146             gc.setBackground(_bgColor);
147 
148             // if the available space is too big, restrict to pref height
149 //            if (drawingArea.height > PREFHEIGHT) {
150 //                drawingArea.y += drawingArea.height - PREFHEIGHT;
151 //                drawingArea.height = PREFHEIGHT;
152 //
153 //            }
154 
155             gc.fillRectangle(drawingArea);
156             if (sortingOrder > 0) {
157                 Image img = getImageRegistry().get(sortDir ? DOWN : UP);
158                 gc.drawImage(img, drawingArea.x + 2, drawingArea.y + drawingArea.height - img.getBounds().height - 1);
159             }
160             // box or line
161             if (_drawBox) {
162                 gc.drawRectangle(drawingArea.x, drawingArea.y, drawingArea.width - 1, drawingArea.height - 1);
163             } else {
164                 gc.drawLine(drawingArea.x, drawingArea.y + drawingArea.height - 1, drawingArea.width - 1, drawingArea.y
165                         + drawingArea.height - 1);
166             }
167 
168             // label
169             Point extent = gc.stringExtent(label);
170             int topY = drawingArea.y+(drawingArea.height-extent.y)/2;
171             int offx = column.supportsSorting() ? SORTINGAREAINDICATORWIDTH : 2;
172             if (_alignment.equals(Alignment.LEFT)) {
173                 gc.drawString(label, drawingArea.x + offx, topY);
174             } else if (_alignment.equals(Alignment.CENTER)) {
175                 Rectangle rect = new Rectangle(drawingArea.x + offx, topY, drawingArea.width
176                         - offx, drawingArea.height - 2 * scaleY(2));
177                 SwtGraphicsHelper.drawStringCentered(gc, label, rect);
178             } else if (_alignment.equals(Alignment.RIGHT)) {
179                 SwtGraphicsHelper.drawStringRightAlignedVTop(gc, label, drawingArea.x + drawingArea.width,
180                         topY);
181             }
182         } else {
183             // rotated drawing
184             gc.setBackground(gc.getDevice().getSystemColor(SWT.COLOR_WHITE));
185             Point extent = gc.stringExtent(label);
186             float[] cords = {(float) (drawingArea.x + ((drawingArea.width - extent.x / 2) / 2)),
187                     (float) (drawingArea.y + drawingArea.height - 9)};
188             _transformInv.transform(cords);
189 
190             gc.setTransform(_transform);
191             gc.drawString(label, (int) cords[0], (int) cords[1]);
192             gc.setTransform(null);
193         }
194 
195         gc.setFont(font);
196         gc.setBackground(bg);
197     }
198 
199     /***
200      * {@inheritDoc}
201      */
202     public boolean disableClipping() {
203         // disable clipping when rotated
204         return _rotation != 0;
205     }
206 
207     /***
208      * {@inheritDoc}
209      */
210     public void dispose() {
211         disposeTransformations();
212         if (_imageRegistry != null) {
213             _imageRegistry.dispose();
214         }
215         if (_bgColor != null) {
216             _bgColor.dispose();
217         }
218         if (_font != null) {
219             _font.dispose();
220         }
221 
222     }
223 
224     private ImageRegistry getImageRegistry() {
225         if (_imageRegistry == null) {
226             _imageRegistry = new ImageRegistry();
227             ImageDescriptor imgDesc = new LocalResourceImageDescriptor(
228                     "/de/jaret/util/ui/table/resource/smallarrow_down.gif");
229             _imageRegistry.put(DOWN, imgDesc.createImage());
230             imgDesc = new LocalResourceImageDescriptor("/de/jaret/util/ui/table/resource/smallarrow_up.gif");
231             _imageRegistry.put(UP, imgDesc.createImage());
232         }
233         return _imageRegistry;
234     }
235 
236     public class LocalResourceImageDescriptor extends ImageDescriptor {
237         String rscString;
238 
239         /***
240          * 
241          */
242         public LocalResourceImageDescriptor(String rscString) {
243             this.rscString = rscString;
244         }
245 
246         /***
247          * {@inheritDoc}
248          */
249         public ImageData getImageData() {
250             Image img = new Image(Display.getCurrent(), this.getClass().getResourceAsStream(rscString));
251             return img.getImageData();
252         }
253     }
254 
255     /***
256      * Dispose the transformations.
257      * 
258      */
259     private void disposeTransformations() {
260         if (_transform != null) {
261             _transform.dispose();
262         }
263         if (_transformInv != null) {
264             _transformInv.dispose();
265         }
266     }
267 
268     /***
269      * {@inheritDoc}
270      */
271     public boolean isSortingClick(Rectangle drawingArea, IColumn column, int x, int y) {
272         return x - drawingArea.x < SORTINGAREAINDICATORWIDTH;
273     }
274 
275     /***
276      * {@inheritDoc}
277      */
278     public ITableHeaderRenderer getPrintRenderer(Printer printer) {
279         return new DefaultTableHeaderRenderer(printer);
280     }
281 
282     /***
283      * Retrieve the alignment for the header label (only when not rotated).
284      * 
285      * @return the alignment
286      */
287     public Alignment getAlignment() {
288         return _alignment;
289     }
290 
291     /***
292      * Set the alignment for the header label (not used when rotated).
293      * 
294      * @param alignment alignment to be used
295      */
296     public void setAlignment(Alignment alignment) {
297         _alignment = alignment;
298     }
299 
300     /***
301      * Retrieve whether the header is drawn boxed.
302      * 
303      * @return true if a box is drawn around the header
304      */
305     public boolean getDrawBox() {
306         return _drawBox;
307     }
308 
309     /***
310      * Set whether the header should be drawn boxed.
311      * 
312      * @param drawBox true for boxed drawing
313      */
314     public void setDrawBox(boolean drawBox) {
315         _drawBox = drawBox;
316     }
317 
318     /***
319      * Get the background RGB value of the header (non rotated only).
320      * 
321      * @return the RGB value for the background
322      */
323     public RGB getBackgroundRGB() {
324         return _backgroundRGB;
325     }
326 
327     /***
328      * Set the background rgb value. The color will be aquired when used. Will only be used when non rotated.
329      * 
330      * @param backgroundRGB the RGB value
331      */
332     public void setBackgroundRGB(RGB backgroundRGB) {
333         if (_bgColor != null) {
334             _bgColor.dispose();
335             _bgColor = null;
336         }
337         _backgroundRGB = backgroundRGB;
338     }
339 
340     /***
341      * Get the fontdata for the font used to render the header label.
342      * 
343      * @return the fontdata
344      */
345     public FontData getFontData() {
346         return _fontData;
347     }
348 
349     /***
350      * Set the fontdata for the font to render the header. The font will be aquired when used.
351      * 
352      * @param fontData fontdat ato use
353      */
354     public void setFontData(FontData fontData) {
355         if (_font != null) {
356             _font.dispose();
357             _font = null;
358         }
359         _fontData = fontData;
360     }
361 
362 }