1   package org.wcb.gui.renderer.jtable;
2   
3   import java.awt.Component;
4   import java.awt.Dimension;
5   import java.awt.Graphics;
6   import java.awt.Rectangle;
7   import java.util.Enumeration;
8   import java.util.Hashtable;
9   import java.util.Iterator;
10  import java.util.Vector;
11  import javax.swing.JComponent;
12  import javax.swing.plaf.basic.BasicTableHeaderUI;
13  import javax.swing.table.TableCellRenderer;
14  import javax.swing.table.TableColumn;
15  import javax.swing.table.TableColumnModel;
16  
17  /**
18   * <small>
19   * <p/>
20   * This library is free software; you can redistribute it and/or
21   * modify it under the terms of the GNU Lesser General Public
22   * License as published by the Free Software Foundation; either
23   * version 2.1 of the License, or (at your option) any later version.
24   *
25   * This library is distributed in the hope that it will be useful,
26   * but WITHOUT ANY WARRANTY; without even the implied warranty of
27   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
28   * Lesser General Public License for more details.
29   *
30   * You should have received a copy of the GNU Lesser General Public
31   * License along with this library; if not, write to the Free Software
32   * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
33   * <p/>
34   * $File:  $ <br>
35   * $Change:  $ submitted by $Author: wbogaardt $ at $DateTime: Sep 7, 2006 1:51:53 PM $ <br>
36   * </small>
37   *
38   * @author wbogaardt
39   */
40  /**
41   * This class paints groupable header cells. These can be a combination of
42   * normal header cells and groupable cells.
43   */
44  
45  public class GroupableTableHeaderUI extends BasicTableHeaderUI {
46  
47      /**
48       * Contains a list of ColumnGroups that have already been painted
49       * in the current paint request.
50       */
51      protected Vector paintedGroups = new Vector();
52  
53      /**
54       * Paint a representation of the table header.
55       * @param g the Graphics context in which to paint
56       * @param c the component being painted; this argument is often ignored
57       */
58      public void paint(Graphics g, JComponent c) {
59          Rectangle clipBounds = g.getClipBounds();
60          GroupableTableColumnModel cm = (GroupableTableColumnModel)header.getColumnModel();
61          if (cm == null) return;
62          ((GroupableTableHeader)header).setColumnMargin();
63          int column = 0;
64          Dimension size = header.getSize();
65          Rectangle cellRect  = new Rectangle(0, 0, size.width, size.height);
66          Hashtable h = new Hashtable();
67  
68          Enumeration columns = cm.getColumns();
69          while (columns.hasMoreElements()) {
70              cellRect.height = size.height;
71              cellRect.y      = 0;
72              TableColumn aColumn = (TableColumn)columns.nextElement();
73              Iterator colGrpIter = cm.getColumnGroups(aColumn);
74              if (colGrpIter != null) {
75                  int groupHeight = 0;
76                  while (colGrpIter.hasNext()) {
77                      ColumnGroup cGroup = (ColumnGroup)colGrpIter.next();
78                      Rectangle groupRect = (Rectangle)h.get(cGroup);
79                      if (groupRect == null) {
80                          groupRect = new Rectangle(cellRect);
81                          Dimension d = cGroup.getSize(header.getTable());
82                          groupRect.width  = d.width;
83                          groupRect.height = d.height;
84                          h.put(cGroup, groupRect);
85                      }
86                      if(!paintedGroups.contains(cGroup)) {
87                          paintCell(g, groupRect, cGroup);
88                          paintedGroups.add(cGroup);
89                      }
90                      groupHeight += groupRect.height;
91                      cellRect.height = size.height - groupHeight;
92                      cellRect.y      = groupHeight;
93                  }
94              }
95              cellRect.width = aColumn.getWidth();
96              if (cellRect.intersects(clipBounds)) {
97                  paintCell(g, cellRect, column);
98              }
99              cellRect.x += cellRect.width;
100             column++;
101         }
102         paintedGroups.clear();
103     }
104 
105     /**
106      * Paints a header column cell.
107      * @param g Graphics context
108      * @param cellRect The rectangle to contain the cell
109      * @param columnIndex The header column to be painted
110      */
111     private void paintCell(Graphics g, Rectangle cellRect, int columnIndex) {
112         TableColumn aColumn = header.getColumnModel().getColumn(columnIndex);
113         TableCellRenderer renderer = aColumn.getHeaderRenderer();
114         if(renderer == null) {
115             renderer = header.getDefaultRenderer();
116         }
117         Component component = renderer.getTableCellRendererComponent(
118         header.getTable(), aColumn.getHeaderValue(),false, false, -1, columnIndex);
119         rendererPane.add(component);
120         rendererPane.paintComponent(g, component, header, cellRect.x, cellRect.y,
121         cellRect.width, cellRect.height, true);
122     }
123 
124     /**
125      * Paint group column cell.
126      * @param g Graphics context
127      * @param cellRect Rectangle that the cell with be painted in
128      * @param cGroup Current column group
129      */
130     private void paintCell(Graphics g, Rectangle cellRect,ColumnGroup cGroup) {
131         TableCellRenderer renderer = cGroup.getHeaderRenderer();
132         Component component = renderer.getTableCellRendererComponent(
133         header.getTable(), cGroup.getHeaderValue(),false, false, -1, -1);
134         rendererPane.add(component);
135         rendererPane.paintComponent(g, component, header, cellRect.x, cellRect.y,
136         cellRect.width, cellRect.height, true);
137     }
138 
139     /**
140      * Calculate and return the height of the header.
141      * @return Header Height
142      */
143     private int getHeaderHeight() {
144         int height = 0;
145         GroupableTableColumnModel columnModel = (GroupableTableColumnModel)header.getColumnModel();
146         for(int column = 0; column < columnModel.getColumnCount(); column++) {
147             TableColumn aColumn = columnModel.getColumn(column);
148             TableCellRenderer renderer = aColumn.getHeaderRenderer();
149             if(renderer == null) {
150                 renderer = header.getDefaultRenderer();
151             }
152             Component comp = renderer.getTableCellRendererComponent(
153             header.getTable(), aColumn.getHeaderValue(), false, false,-1, column);
154             int cHeight = comp.getPreferredSize().height;
155             Iterator iter = columnModel.getColumnGroups(aColumn);
156             if (iter != null) {
157                 while (iter.hasNext()) {
158                     ColumnGroup cGroup = (ColumnGroup)iter.next();
159                     cHeight += cGroup.getSize(header.getTable()).height;
160                 }
161             }
162             height = Math.max(height, cHeight);
163         }
164         return height;
165     }
166 
167     /**
168      * Calculate and return the dimension of the header.
169      * @param width Starting width to be used.
170      * @return Dimension of the header
171      */
172     private Dimension createHeaderSize(long width) {
173         TableColumnModel columnModel = header.getColumnModel();
174         width += columnModel.getColumnMargin() * columnModel.getColumnCount();
175         if (width > Integer.MAX_VALUE) {
176             width = Integer.MAX_VALUE;
177         }
178         return new Dimension((int)width, getHeaderHeight());
179     }
180 
181     /**
182      * Invokes the getPreferredSize method on each UI handled by this object.
183      * @param c the component whose preferred size is being queried; this argument is ignored.
184      * @return the dimension of the whole header
185      */
186     public Dimension getPreferredSize(JComponent c) {
187         long width = 0;
188         Enumeration columns = header.getColumnModel().getColumns();
189         while (columns.hasMoreElements()) {
190             TableColumn aColumn = (TableColumn)columns.nextElement();
191             width = width + aColumn.getPreferredWidth();
192         }
193         return createHeaderSize(width);
194     }
195 }