KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > wings > SGridBagLayout


1 /*
2  * $Id: SGridBagLayout.java,v 1.5 2005/06/03 13:16:16 blueshift Exp $
3  * Copyright 2000,2005 wingS development team.
4  *
5  * This file is part of wingS (http://www.j-wings.org).
6  *
7  * wingS is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU Lesser General Public License
9  * as published by the Free Software Foundation; either version 2.1
10  * of the License, or (at your option) any later version.
11  *
12  * Please see COPYING for the complete licence.
13  */

14 package org.wings;
15
16 import org.wings.event.SComponentEvent;
17 import org.wings.event.SComponentListener;
18
19 import java.awt.*;
20 import java.util.HashMap JavaDoc;
21 import java.util.Iterator JavaDoc;
22
23 /**
24  * This is a gridbag layout.
25  * <p/>
26  * This layout is similar to Swing's GridBagLayout, though it can't
27  * implement all functionalities because of the limitations of
28  * HTML-table. It probably doesn't work exactly like its
29  * Swing-counterpart - as a general hint: don't be too clever...
30  * <P>
31  * <p/>
32  * SComponents are usually added using an instance of
33  * java.awt.GridBagConstraints which is copied while adding it (so you
34  * might reuse it to add other SComponents). There are basically two
35  * ways of adding: explicitly setting gridx and gridy or leaving
36  * those at the default (RELATIVE) and let SGridBagLayout decide where
37  * to put them. Normally they will be added horizontally, unless you
38  * explicitly set gridx, which will add the SComponents
39  * vertically. With setting gridy you can choose a row in which the
40  * SComponents will be added. If you want to finish a row/column, you
41  * can set gridwidth/gridheight to REMAINDER or RELATIVE - REMAINDER
42  * marks the row/column to be finished while RELATIVE tells
43  * SGridBagLayout that the <em>next</em> added SComponent will be the
44  * last cell of the row/column which will always be placed at the end
45  * (while the 'RELATIVE'-SComponent will be expanded to fill the gap).
46  * <P>
47  * <p/>
48  * <em>Important:</em> When choosing a new row/column, the next
49  * gridx/gridy-value that SGridLayout will choose will always be 0,
50  * even if there is already a SComponent at that position. If you
51  * really need to be clever, explicitly set gridx and gridy,
52  * especially if you plan to dynamically add and remove SComponents.
53  * <P>
54  * <p/>
55  * The size of a cell can be influenced in two ways: either set
56  * gridwidth/gridheight to a value larger than 1 to say how many
57  * regular cells this cell should span or use weightx/weighty to tell
58  * the browser how much of the empty space this cell should eat up
59  * (e.g. if there are 3 cells with each weight=1, they will all get
60  * 33%). The last method has two disadvantages: firstly, it uses the
61  * deprecated width/height-parameters of the HTML-td statement and
62  * secondly, it must be carefully used to get the correct result: all
63  * cells of a row/column should have the same weighty/weightx or 0, so
64  * it might be easier to set these values only in the first
65  * column/row.
66  * <P>
67  * <p/>
68  * GridBagConstraints has many more options than those described
69  * above, but the current implementation can't use them.
70  *
71  * @author <a HREF="mailto:js@trollhead.net">Jochen Scharrlach</a>
72  * @version $Revision $
73  */

74 public class SGridBagLayout
75         extends SAbstractLayoutManager implements SComponentListener {
76     /**
77      * Map of all managed components (key: component, value: constraint)
78      */

79     protected HashMap JavaDoc components = new HashMap JavaDoc();
80
81     /**
82      * Row for the next horizontal add (gridx=RELATIVE). If gridy is
83      * not RELATIVE and does not match nextHorRow, the SComponent will
84      * be added at gridx=0.
85      */

86     protected int nextHorRow = 0;
87
88     /**
89      * Column for the next horizontal add (gridx=RELATIVE)
90      */

91     protected int nextHorCol = 0;
92
93     /**
94      * Row for the next vertical add (gridx != RELATIVE, gridy =
95      * RELATIVE).
96      */

97     protected int nextVertRow = 0;
98
99     /**
100      * Column for the next vertical add (gridx != RELATIVE, gridy =
101      * RELATIVE). If gridx does not match nextVertCol, the SComponent
102      * will be added at gridy=0.
103      */

104     protected int nextVertCol = 0;
105
106     /**
107      * @see #getBorder
108      */

109     protected int border = 0;
110
111     /**
112      * The horizontal gap (in pixels) specifiying the space
113      * between columns. They can be changed at any time.
114      * This should be a non-negative integer.
115      */

116     protected int hgap = 0;
117
118     /**
119      * The vertical gap (in pixels) which specifiying the space
120      * between rows. They can be changed at any time.
121      * This should be a non negative integer.
122      */

123     protected int vgap = 0;
124
125     /**
126      * @see #getHeader
127      */

128     protected boolean header = false;
129
130     /**
131      * The defaults to use if the addComponent()-call does not give
132      * the constraints.
133      */

134     protected GridBagConstraints defaultConstraints =
135             new GridBagConstraints();
136
137     /**
138      * Contains a pre-calculated grid (or null)
139      */

140     protected Grid currentGrid;
141
142     /**
143      * Indicates that the corresponding SComponent should be at the
144      * end of the row/column. This value is only for internal use and
145      * cannot be used with addComponent.
146      */

147     public static final int LAST_CELL = -1;
148
149     /**
150      * creats a new gridbag layout
151      */

152     public SGridBagLayout() {}
153
154     /**
155      * Add the given component with the given constraints to the
156      * layout.
157      *
158      * @param comp the component to add
159      * @param constraint instance of GridBagConstraints or null
160      * @param index ignored
161      */

162     public void addComponent(SComponent comp, Object JavaDoc constraint, int index) {
163         // The grid has to be rebuilt
164
currentGrid = null;
165
166         GridBagConstraints c = (GridBagConstraints) constraint;
167         if (c == null) {
168             c = defaultConstraints;
169         }
170         c = (GridBagConstraints) c.clone();
171
172         if (c.gridx >= 0) {
173             if (c.gridx != nextVertCol) {
174                 nextVertRow = 0;
175             }
176
177             if (c.gridy < 0) {
178                 c.gridy = nextVertRow;
179             }
180         } else {
181             if (c.gridy >= 0 && c.gridy != nextHorRow) {
182                 nextHorCol = 0;
183             }
184
185             if (c.gridy < 0) {
186                 c.gridy = nextHorRow;
187             } else if (c.gridy != nextHorRow) {
188                 nextHorCol = 0;
189             }
190             c.gridx = nextHorCol;
191         }
192
193         comp.addComponentListener(this);
194         components.put(comp, c);
195
196         if (c.gridx == LAST_CELL) {
197             if (c.gridy == LAST_CELL) {
198                 nextHorRow = 0;
199                 nextVertRow = 0;
200             } else {
201                 nextHorRow = c.gridy + 1;
202                 nextVertRow = c.gridy + 1;
203             }
204             nextHorCol = 0;
205             nextVertCol = 0;
206         } else {
207             if (c.gridy == LAST_CELL) {
208                 nextHorRow = 0;
209                 nextVertRow = 0;
210                 nextHorCol = c.gridx + 1;
211                 nextVertCol = c.gridx + 1;
212             } else {
213                 nextHorCol = c.gridx;
214                 nextVertCol = c.gridx;
215                 nextHorRow = c.gridy;
216                 nextVertRow = c.gridy;
217
218                 if (c.gridwidth == GridBagConstraints.RELATIVE) {
219                     nextHorCol = LAST_CELL;
220                 } else if (c.gridwidth == GridBagConstraints.REMAINDER) {
221                     nextHorCol = 0;
222                     nextHorRow++;
223                 } else {
224                     if (c.gridwidth > 0) {
225                         nextHorCol += c.gridwidth;
226                     } else {
227                         nextHorCol++;
228                     }
229                 }
230
231                 if (c.gridheight == GridBagConstraints.RELATIVE) {
232                     nextVertRow = LAST_CELL;
233                 } else if (c.gridheight == GridBagConstraints.REMAINDER) {
234                     nextVertRow = 0;
235                     nextVertCol++;
236                 } else {
237                     if (c.gridheight > 0) {
238                         nextVertRow += c.gridheight;
239                     } else {
240                         nextVertRow++;
241                     }
242                 }
243             }
244         }
245     }
246
247     public void removeComponent(SComponent c) {
248         // The grid has to be rebuilt
249
currentGrid = null;
250         components.remove(c);
251         c.removeComponentListener(this);
252     }
253
254     public void componentHidden(SComponentEvent e) {
255         // The grid has to be rebuilt
256
currentGrid = null;
257     }
258
259     public void componentMoved(SComponentEvent e) {
260         // ignored
261
}
262
263     public void componentResized(SComponentEvent e) {
264         // ignored
265
}
266
267     public void componentShown(SComponentEvent e) {
268         // The grid has to be rebuilt
269
currentGrid = null;
270     }
271
272     /**
273      * Gets the horizontal gap between components in pixel. Rendered half as margin left and margin right
274      * Some PLAFs might ignore this property.
275      *
276      * @return the horizontal gap between components
277      */

278     public int getHgap() {
279         return hgap;
280     }
281
282     /**
283      * Sets the horizontal gap between components to the specified value in pixe. Rendered half as margin left and margin right
284      * Some PLAFs might ignore this property.
285      *
286      * @param hgap the horizontal gap between components
287      */

288     public void setHgap(int hgap) {
289         this.hgap = hgap;
290     }
291
292     /**
293      * Gets the vertical gap between components in pixel. Rendered half as margin top and margin bottom
294      * Some PLAFs might ignore this property.
295      *
296      * @return the vertical gap between components
297      */

298     public int getVgap() {
299         return vgap;
300     }
301
302     /**
303      * Sets the vertical gap between components to the specified value in pixel.
304      * Rendered half as margin top and margin bottom. Some PLAFs might ignore this property.
305      *
306      * @param vgap the vertical gap between components
307      */

308     public void setVgap(int vgap) {
309         this.vgap = vgap;
310     }
311
312     /**
313      * Set the border width.
314      *
315      * @param pixel the new border width in pixels
316      */

317     public void setBorder(int pixel) {
318         border = pixel;
319     }
320
321     /**
322      * Get the border width.
323      *
324      * @return the border width in pixels
325      */

326     public int getBorder() { return border; }
327
328     /**
329      * Specify if the first row should be printed as header
330      *
331      * @param b true=the first row is used as header
332      */

333     public void setHeader(boolean b) {
334         header = b;
335     }
336
337     /**
338      * Query if the first row will be printed as header
339      *
340      * @return true=the first row is used as header
341      */

342     public boolean getHeader() { return header; }
343
344     // Some helper functions for CGs
345

346     /**
347      * This class prepares all information necessary to plot the
348      * layout to the output device. The information will be outdated as
349      * soon as components will be added or removed from the layout.
350      */

351     public class Grid {
352         /**
353          * Number of columns
354          */

355         public int cols;
356
357         /**
358          * Number of rows
359          */

360         public int rows;
361
362         /**
363          * The matrix with all known SComponents. A SComponent might
364          * appear in more than one cell, indicating that it spans more
365          * than one cell - usually it will only be plotted if its
366          * value for gridx/gridy matches the current cell (exception:
367          * gridx/gridy might also be set to LAST_CELL).
368          */

369         public SComponent[][] grid;
370
371         /**
372          * The total column-weight of a row(!). The cumulated weightx
373          * of all cells of a row..
374          */

375         public double[] colweight;
376
377         /**
378          * The total row-weight of a column(!). The cumulated weighty
379          * of all cells of a column..
380          */

381         public double[] rowweight;
382
383         /**
384          * The first row that contains cells
385          */

386         public int firstRow;
387
388         /**
389          * The first column that contains cells
390          */

391         public int firstCol;
392
393         /**
394          * Initialize all members
395          */

396         public Grid() {
397             cols = 0;
398             rows = 0;
399
400             for (Iterator JavaDoc i = components.keySet().iterator();
401                  i.hasNext();) {
402                 SComponent comp = (SComponent) i.next();
403                 if (!comp.isVisible()) {
404                     continue;
405                 }
406
407                 GridBagConstraints c = (GridBagConstraints)
408                         components.get(comp);
409                 if (c.gridx != SGridBagLayout.LAST_CELL) {
410                     int col = c.gridx;
411                     if (c.gridwidth == GridBagConstraints.RELATIVE) {
412                         col++;
413                     } else if (c.gridwidth > 1) {
414                         col += c.gridwidth - 1;
415                     }
416
417                     int row = c.gridy;
418                     if (c.gridheight == GridBagConstraints.RELATIVE) {
419                         row++;
420                     } else if (c.gridheight > 1) {
421                         row += c.gridheight - 1;
422                     }
423
424                     if (col >= cols) {
425                         cols = col + 1;
426                     }
427                     if (row >= rows) {
428                         rows = row + 1;
429                     }
430                 }
431             }
432
433             grid = new SComponent[cols][rows];
434             rowweight = new double[cols];
435             colweight = new double[rows];
436
437             for (Iterator JavaDoc i = components.keySet().iterator();
438                  i.hasNext();) {
439                 SComponent comp = (SComponent) i.next();
440                 if (!comp.isVisible()) {
441                     continue;
442                 }
443                 GridBagConstraints c = (GridBagConstraints)
444                         components.get(comp);
445
446                 int maxcol = c.gridx + c.gridwidth;
447                 int maxrow = c.gridy + c.gridheight;
448
449                 if (c.gridwidth == GridBagConstraints.RELATIVE) {
450                     maxcol = cols - 1;
451                 } else if (c.gridwidth == GridBagConstraints.REMAINDER) {
452                     maxcol = cols;
453                 }
454                 if (c.gridheight == GridBagConstraints.RELATIVE) {
455                     maxrow = rows - 1;
456                 } else if (c.gridheight == GridBagConstraints.REMAINDER) {
457                     maxrow = rows;
458                 }
459                 int col = c.gridx;
460                 if (col == SGridBagLayout.LAST_CELL) {
461                     col = cols - 1;
462                     maxcol = cols;
463                 }
464                 int row = c.gridy;
465                 if (row == SGridBagLayout.LAST_CELL) {
466                     row = rows - 1;
467                     maxrow = rows;
468                 }
469                 colweight[row] += c.weightx;
470                 rowweight[col] += c.weighty;
471
472                 for (; col < maxcol; col++) {
473                     for (int r = row; r < maxrow; r++) {
474                         grid[col][r] = comp;
475                     }
476                 }
477             }
478             for (firstRow = 0; firstRow < rows; firstRow++) {
479                 int col;
480                 for (col = 0; col < cols; col++) {
481                     if (grid[col][firstRow] != null) {
482                         break;
483                     }
484                 }
485                 if (col < cols) {
486                     break;
487                 }
488             }
489             for (firstCol = 0; firstCol < cols; firstCol++) {
490                 int row;
491                 for (row = 0; row < rows; row++) {
492                     if (grid[firstCol][row] != null) {
493                         break;
494                     }
495                 }
496                 if (row < rows) {
497                     break;
498                 }
499             }
500         }
501     }
502
503     /**
504      * Build a grid from the current configuration. Make sure the
505      * layout is not altered while using the Grid!
506      *
507      * @return the Grid-instance
508      */

509     public Grid getGrid() {
510         if (currentGrid == null) {
511             currentGrid = new Grid();
512         }
513         return currentGrid;
514     }
515
516     /**
517      * Retrieve the constraint of a SComponent. The constraint must
518      * not be altered!
519      *
520      * @param comp the component
521      * @return the constraint or null if the component is unknown
522      */

523     final public GridBagConstraints getConstraints(SComponent comp) {
524         // It might be better to return a copy of the constraint,
525
// but that would hurt the performance
526
return (GridBagConstraints) components.get(comp);
527     }
528 }
529
530
531
Popular Tags