001 /*
002 * Copyright 2002-2004 the original author or authors.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
005 * use this file except in compliance with the License. You may obtain a copy of
006 * the License at
007 *
008 * http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
012 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
013 * License for the specific language governing permissions and limitations under
014 * the License.
015 */
016 package org.springframework.richclient.layout;
017
018 import java.awt.Component;
019 import java.awt.GridBagConstraints;
020 import java.awt.GridBagLayout;
021 import java.awt.Insets;
022 import java.util.ArrayList;
023 import java.util.List;
024
025 import javax.swing.JComponent;
026 import javax.swing.JLabel;
027 import javax.swing.JPanel;
028 import javax.swing.SwingConstants;
029
030 import org.apache.commons.logging.Log;
031 import org.apache.commons.logging.LogFactory;
032 import org.springframework.richclient.application.ApplicationServicesLocator;
033 import org.springframework.richclient.factory.ComponentFactory;
034 import org.springframework.richclient.util.GridBagLayoutDebugPanel;
035
036 /**
037 * This provides an easy way to create panels using a {@link GridBagLayout}.
038 * <p />
039 *
040 * Usage is:
041 *
042 * <pre>
043 * GridBagLayoutBuilder builder = new GridBagLayoutBuilder();
044 *
045 * builder.appendRightLabel("label.field1").appendField(field1);
046 * builder.appendRightLabel("label.field2").appendField(field2);
047 * builder.nextLine();
048 *
049 * builder.appendRightLabel("label.field3").appendField(field3);
050 * // because "field3" is the last component on this line, but the panel has
051 * // 4 columns, "field3" will span 3 columns
052 * builder.nextLine();
053 *
054 * // once everything's been put into the builder, ask it to build a panel
055 * // to use in the UI.
056 * JPanel panel = builder.getPanel();
057 * </pre>
058 *
059 * @author Jim Moore
060 * @see #setAutoSpanLastComponent(boolean)
061 * @see #setShowGuidelines(boolean)
062 * @see #setComponentFactory(ComponentFactory)
063 */
064 public class GridBagLayoutBuilder implements LayoutBuilder {
065 private static final Log LOG = LogFactory.getLog(GridBagLayoutBuilder.class);
066
067 private Insets defaultInsets = new Insets(0, 0, 4, 4);
068
069 private boolean showGuidelines = false;
070
071 private boolean autoSpanLastComponent = true;
072
073 private int currentCol;
074
075 private int currentRow;
076
077 private List rows;
078
079 private List currentRowList;
080
081 private int maxCol = 0;
082
083 private ComponentFactory componentFactory;
084
085 private static final Item NULL_ITEM = new Item(null, null);
086
087 public GridBagLayoutBuilder() {
088 super();
089 init();
090 }
091
092 private void init() {
093 currentCol = 0;
094 currentRow = 0;
095 rows = new ArrayList();
096 currentRowList = new ArrayList();
097 }
098
099 /**
100 * Returns the default {@link Insets}used when adding components
101 */
102 public Insets getDefaultInsets() {
103 return defaultInsets;
104 }
105
106 /**
107 * Sets the default {@link Insets}used when adding components
108 */
109 public void setDefaultInsets(Insets defaultInsets) {
110 this.defaultInsets = defaultInsets;
111 }
112
113 /**
114 * Returns the current row (zero-based) that the builder is putting
115 * components in
116 */
117 public int getCurrentRow() {
118 return currentRow;
119 }
120
121 /**
122 * Returns the current column (zero-based) that the builder is putting
123 * components in
124 */
125 public int getCurrentCol() {
126 return currentCol;
127 }
128
129 public ComponentFactory getComponentFactory() {
130 if (componentFactory == null) {
131 componentFactory = (ComponentFactory)ApplicationServicesLocator.services().getService(ComponentFactory.class);
132 }
133 return componentFactory;
134 }
135
136 public void setComponentFactory(ComponentFactory componentFactory) {
137 this.componentFactory = componentFactory;
138 }
139
140 /**
141 * Appends the given component to the end of the current line, using the
142 * default insets and no expansion
143 *
144 * @param component the component to add to the current line
145 *
146 * @return "this" to make it easier to string together append calls
147 */
148 public GridBagLayoutBuilder append(Component component) {
149 return append(component, 1, 1);
150 }
151
152 /**
153 * Appends the given component to the end of the current line, using the
154 * default insets and no expansion
155 *
156 * @param component the component to add to the current line
157 * @param colSpan the number of columns to span
158 * @param rowSpan the number of rows to span
159 *
160 * @return "this" to make it easier to string together append calls
161 */
162 public GridBagLayoutBuilder append(Component component, int colSpan, int rowSpan) {
163 return append(component, colSpan, rowSpan, 0.0, 0.0);
164 }
165
166 /**
167 * Appends the given component to the end of the current line, using the
168 * default insets
169 *
170 * @param component the component to add to the current line
171 * @param colSpan the number of columns to span
172 * @param rowSpan the number of rows to span
173 * @param expandX should the component "grow" horrizontally?
174 * @param expandY should the component "grow" vertically?
175 *
176 * @return "this" to make it easier to string together append calls
177 */
178 public GridBagLayoutBuilder append(Component component, int colSpan, int rowSpan, boolean expandX, boolean expandY) {
179 return append(component, colSpan, rowSpan, expandX, expandY, defaultInsets);
180 }
181
182 /**
183 * Appends the given component to the end of the current line
184 *
185 * @param component the component to add to the current line
186 * @param colSpan the number of columns to span
187 * @param rowSpan the number of rows to span
188 * @param expandX should the component "grow" horrizontally?
189 * @param expandY should the component "grow" vertically?
190 * @param insets the insets to use for this component
191 *
192 * @return "this" to make it easier to string together append calls
193 */
194 public GridBagLayoutBuilder append(Component component, int colSpan, int rowSpan, boolean expandX, boolean expandY,
195 Insets insets) {
196 if (expandX && expandY)
197 return append(component, colSpan, rowSpan, 1.0, 1.0, insets);
198 else if (expandX)
199 return append(component, colSpan, rowSpan, 1.0, 0.0, insets);
200 else if (expandY)
201 return append(component, colSpan, rowSpan, 0.0, 1.0, insets);
202 else
203 return append(component, colSpan, rowSpan, 0.0, 0.0, insets);
204 }
205
206 /**
207 * Appends the given component to the end of the current line
208 *
209 * @param component the component to add to the current line
210 * @param x the column to put the component
211 * @param y the row to put the component
212 * @param colSpan the number of columns to span
213 * @param rowSpan the number of rows to span
214 * @param expandX should the component "grow" horrizontally?
215 * @param expandY should the component "grow" vertically?
216 * @param insets the insets to use for this component
217 *
218 * @return "this" to make it easier to string together append calls
219 */
220 public GridBagLayoutBuilder append(Component component, int x, int y, int colSpan, int rowSpan, boolean expandX,
221 boolean expandY, Insets insets) {
222 if (expandX && expandY)
223 return append(component, x, y, colSpan, rowSpan, 1.0, 1.0, insets);
224 else if (expandX)
225 return append(component, x, y, colSpan, rowSpan, 1.0, 0.0, insets);
226 else if (expandY)
227 return append(component, x, y, colSpan, rowSpan, 0.0, 1.0, insets);
228 else
229 return append(component, x, y, colSpan, rowSpan, 0.0, 0.0, insets);
230 }
231
232 /**
233 * Appends the given component to the end of the current line, using the
234 * default insets
235 *
236 * @param component the component to add to the current line
237 * @param colSpan the number of columns to span
238 * @param rowSpan the number of rows to span
239 * @param xweight the "growth weight" horrizontally
240 * @param yweight the "growth weight" horrizontally
241 *
242 * @return "this" to make it easier to string together append calls
243 *
244 * @see GridBagConstraints#weightx
245 * @see GridBagConstraints#weighty
246 */
247 public GridBagLayoutBuilder append(Component component, int colSpan, int rowSpan, double xweight, double yweight) {
248 return append(component, colSpan, rowSpan, xweight, yweight, defaultInsets);
249 }
250
251 /**
252 * Appends the given component to the end of the current line
253 *
254 * @param component the component to add to the current line
255 * @param colSpan the number of columns to span
256 * @param rowSpan the number of rows to span
257 * @param xweight the "growth weight" horrizontally
258 * @param yweight the "growth weight" horrizontally
259 * @param insets the insets to use for this component
260 *
261 * @return "this" to make it easier to string together append calls
262 *
263 * @see GridBagConstraints#weightx
264 * @see GridBagConstraints#weighty
265 */
266 public GridBagLayoutBuilder append(Component component, int colSpan, int rowSpan, double xweight, double yweight,
267 Insets insets) {
268 return append(component, getCurrentCol(), getCurrentRow(), colSpan, rowSpan, xweight, yweight, insets);
269 }
270
271 /**
272 * Appends a label and field to the end of the current line.
273 * <p />
274 *
275 * The label will be to the left of the field, and be right-justified.
276 * <br />
277 * The field will "grow" horizontally as space allows.
278 * <p />
279 *
280 * @param propertyName the name of the property to create the controls for
281 *
282 * @return "this" to make it easier to string together append calls
283 */
284 public GridBagLayoutBuilder appendLabeledField(String propertyName, final JComponent field,
285 LabelOrientation labelOrientation) {
286 return appendLabeledField(propertyName, field, labelOrientation, 1);
287 }
288
289 /**
290 * Appends a label and field to the end of the current line.
291 * <p />
292 *
293 * The label will be to the left of the field, and be right-justified.
294 * <br />
295 * The field will "grow" horizontally as space allows.
296 * <p />
297 *
298 * @param propertyName the name of the property to create the controls for
299 * @param colSpan the number of columns the field should span
300 *
301 * @return "this" to make it easier to string together append calls
302 */
303 public GridBagLayoutBuilder appendLabeledField(String propertyName, final JComponent field,
304 LabelOrientation labelOrientation, int colSpan) {
305 return appendLabeledField(propertyName, field, labelOrientation, colSpan, 1, true, false);
306 }
307
308 /**
309 * Appends a label and field to the end of the current line.<p />
310 *
311 * The label will be to the left of the field, and be right-justified.<br />
312 * The field will "grow" horizontally as space allows.<p />
313 *
314 * @param propertyName the name of the property to create the controls for
315 * @param colSpan the number of columns the field should span
316 *
317 * @return "this" to make it easier to string together append calls
318 */
319 public GridBagLayoutBuilder appendLabeledField(String propertyName, final JComponent field,
320 LabelOrientation labelOrientation, int colSpan, int rowSpan, boolean expandX, boolean expandY) {
321 JLabel label = createLabel(propertyName);
322 return appendLabeledField(label, field, labelOrientation, colSpan, rowSpan, expandX, expandY);
323 }
324
325 protected JLabel createLabel(String propertyName) {
326 return getComponentFactory().createLabel(propertyName);
327 }
328
329 /**
330 * Appends a label and field to the end of the current line.<p />
331 *
332 * The label will be to the left of the field, and be right-justified.<br />
333 * The field will "grow" horizontally as space allows.<p />
334 *
335 * @param label the label to associate and layout with the field
336 * @param colSpan the number of columns the field should span
337 *
338 * @return "this" to make it easier to string together append calls
339 */
340 public GridBagLayoutBuilder appendLabeledField(final JLabel label, final JComponent field,
341 LabelOrientation labelOrientation, int colSpan, int rowSpan, boolean expandX, boolean expandY) {
342 label.setLabelFor(field);
343
344 final int col = getCurrentCol();
345 final int row = getCurrentRow();
346 final Insets insets = getDefaultInsets();
347
348 if (labelOrientation == LabelOrientation.LEFT || labelOrientation == null) {
349 label.setHorizontalAlignment(SwingConstants.RIGHT);
350 append(label, col, row, 1, 1, false, expandY, insets);
351 append(field, col + 1, row, colSpan, rowSpan, expandX, expandY, insets);
352 }
353 else if (labelOrientation == LabelOrientation.RIGHT) {
354 label.setHorizontalAlignment(SwingConstants.LEFT);
355 append(field, col, row, colSpan, rowSpan, expandX, expandY, insets);
356 append(label, col + colSpan, row, 1, rowSpan, false, expandY, insets);
357 }
358 else if (labelOrientation == LabelOrientation.TOP) {
359 label.setHorizontalAlignment(SwingConstants.LEFT);
360 append(label, col, row, colSpan, 1, expandX, false, insets);
361 append(field, col, row + 1, colSpan, rowSpan, expandX, expandY, insets);
362 }
363 else if (labelOrientation == LabelOrientation.BOTTOM) {
364 label.setHorizontalAlignment(SwingConstants.LEFT);
365 append(field, col, row, colSpan, rowSpan, expandX, expandY, insets);
366 append(label, col, row + rowSpan, colSpan, 1, expandX, false, insets);
367 }
368
369 return this;
370 }
371
372 /**
373 * Appends the given component to the end of the current line
374 *
375 * @param component the component to add to the current line
376 * @param x the column to put the component
377 * @param y the row to put the component
378 * @param colSpan the number of columns to span
379 * @param rowSpan the number of rows to span
380 * @param xweight the "growth weight" horrizontally
381 * @param yweight the "growth weight" horrizontally
382 * @param insets the insets to use for this component
383 *
384 * @return "this" to make it easier to string together append calls
385 *
386 * @see GridBagConstraints#weightx
387 * @see GridBagConstraints#weighty
388 */
389 public GridBagLayoutBuilder append(Component component, int x, int y, int colSpan, int rowSpan, double xweight,
390 double yweight, Insets insets) {
391 final List rowList = getRow(y);
392 ensureCapacity(rowList, Math.max(x, maxCol) + 1);
393
394 final int col = bypassPlaceholders(rowList, x);
395
396 insertPlaceholdersIfNeeded(rowSpan, y, col, component, colSpan);
397
398 final GridBagConstraints gbc = createGridBagConstraint(col, y, colSpan, rowSpan, xweight, yweight, insets);
399
400 rowList.set(col, new Item(component, gbc));
401 if (LOG.isDebugEnabled())
402 LOG.debug(getDebugString(component, gbc));
403
404 // keep track of the largest column this has seen...
405 this.maxCol = Math.max(this.maxCol, col);
406
407 currentCol = col + colSpan;
408
409 return this;
410 }
411
412 private void insertPlaceholdersIfNeeded(final int rowSpan, final int y, final int col, final Component component,
413 final int colSpan) {
414 if (rowSpan > 1) {
415 growRowsIfNeeded(rowSpan);
416 for (int i = 1; i < (y + rowSpan); i++) {
417 final List row = getRow(i);
418 ensureCapacity(row, col + colSpan + 1);
419 if (row.get(col) != null) {
420 // sanity check -- shouldn't ever happen
421 throw new IllegalStateException("Trying to overwrite another component: " + component + ", " + col
422 + " " + y);
423 }
424 for (int j = 0; j < colSpan; j++) {
425 row.set(col + j, NULL_ITEM);
426 }
427 }
428 }
429 }
430
431 private List getRow(final int i) {
432 ensureCapacity(rows, i + 1);
433 List row = (List)rows.get(i);
434 if (row == null) {
435 row = new ArrayList();
436 rows.set(i, row);
437 }
438 return row;
439 }
440
441 private int bypassPlaceholders(final List list, final int col) {
442 int theCol = col;
443 while (theCol < list.size() && list.get(theCol) != null) {
444 theCol++;
445 }
446 return theCol;
447 }
448
449 private void ensureCapacity(List list, int minSize) {
450 for (int i = list.size(); i < minSize; i++) {
451 list.add(null);
452 }
453 }
454
455 private void growRowsIfNeeded(final int rowSpan) {
456 final int minNeededSize = currentRow + rowSpan;
457 ensureCapacity(rows, minNeededSize);
458 final int delta = minNeededSize - rows.size();
459 if (delta > 0) {
460 rows.set(currentRow, currentRowList);
461 for (int i = 0; i < delta; i++) {
462 rows.set(currentRow + i, new ArrayList());
463 }
464 }
465 }
466
467 /**
468 * Appends the given label to the end of the current line. The label does
469 * not "grow."
470 *
471 * @param label the label to append
472 *
473 * @return "this" to make it easier to string together append calls
474 */
475 public GridBagLayoutBuilder appendLabel(JLabel label) {
476 return appendLabel(label, 1);
477 }
478
479 /**
480 * Appends the given label to the end of the current line. The label does
481 * not "grow."
482 *
483 * @param label the label to append
484 * @param colSpan the number of columns to span
485 *
486 * @return "this" to make it easier to string together append calls
487 */
488 public GridBagLayoutBuilder appendLabel(JLabel label, int colSpan) {
489 return append(label, colSpan, 1, false, false);
490 }
491
492 /**
493 * Appends a right-justified label to the end of the given line, using the
494 * provided string as the key to look in the
495 * {@link #setComponentFactory(ComponentFactory) ComponentFactory's}message
496 * bundle for the text to use.
497 *
498 * @param labelKey the key into the message bundle; if not found the key is used
499 * as the text to display
500 *
501 * @return "this" to make it easier to string together append calls
502 */
503 public GridBagLayoutBuilder appendRightLabel(String labelKey) {
504 return appendRightLabel(labelKey, 1);
505 }
506
507 /**
508 * Appends a right-justified label to the end of the given line, using the
509 * provided string as the key to look in the
510 * {@link #setComponentFactory(ComponentFactory) ComponentFactory's}message
511 * bundle for the text to use.
512 *
513 * @param labelKey the key into the message bundle; if not found the key is used
514 * as the text to display
515 * @param colSpan the number of columns to span
516 *
517 * @return "this" to make it easier to string together append calls
518 */
519 public GridBagLayoutBuilder appendRightLabel(String labelKey, int colSpan) {
520 final JLabel label = createLabel(labelKey);
521 label.setHorizontalAlignment(SwingConstants.RIGHT);
522 return appendLabel(label, colSpan);
523 }
524
525 /**
526 * Appends a left-justified label to the end of the given line, using the
527 * provided string as the key to look in the
528 * {@link #setComponentFactory(ComponentFactory) ComponentFactory's}message
529 * bundle for the text to use.
530 *
531 * @param labelKey the key into the message bundle; if not found the key is used
532 * as the text to display
533 *
534 * @return "this" to make it easier to string together append calls
535 */
536 public GridBagLayoutBuilder appendLeftLabel(String labelKey) {
537 return appendLeftLabel(labelKey, 1);
538 }
539
540 /**
541 * Appends a left-justified label to the end of the given line, using the
542 * provided string as the key to look in the
543 * {@link #setComponentFactory(ComponentFactory) ComponentFactory's}message
544 * bundle for the text to use.
545 *
546 * @param labelKey the key into the message bundle; if not found the key is used
547 * as the text to display
548 * @param colSpan the number of columns to span
549 *
550 * @return "this" to make it easier to string together append calls
551 */
552 public GridBagLayoutBuilder appendLeftLabel(String labelKey, int colSpan) {
553 final JLabel label = createLabel(labelKey);
554 label.setHorizontalAlignment(SwingConstants.LEFT);
555 return appendLabel(label, colSpan);
556 }
557
558 /**
559 * Appends the given component to the end of the current line. The component
560 * will "grow" horizontally as space allows.
561 *
562 * @param component the item to append
563 *
564 * @return "this" to make it easier to string together append calls
565 */
566 public GridBagLayoutBuilder appendField(Component component) {
567 return appendField(component, 1);
568 }
569
570 /**
571 * Appends the given component to the end of the current line. The component
572 * will "grow" horizontally as space allows.
573 *
574 * @param component the item to append
575 * @param colSpan the number of columns to span
576 *
577 * @return "this" to make it easier to string together append calls
578 */
579 public GridBagLayoutBuilder appendField(Component component, int colSpan) {
580 return append(component, colSpan, 1, true, false);
581 }
582
583 /**
584 * Appends a seperator (usually a horizonal line). Has an implicit
585 * {@link #nextLine()}before and after it.
586 *
587 * @return "this" to make it easier to string together append calls
588 */
589 public GridBagLayoutBuilder appendSeparator() {
590 return appendSeparator(null);
591 }
592
593 /**
594 * Appends a seperator (usually a horizonal line) using the provided string
595 * as the key to look in the
596 * {@link #setComponentFactory(ComponentFactory) ComponentFactory's}message
597 * bundle for the text to put along with the seperator. Has an implicit
598 * {@link #nextLine()}before and after it.
599 *
600 * @return "this" to make it easier to string together append calls
601 */
602 public GridBagLayoutBuilder appendSeparator(String labelKey) {
603 if (this.currentRowList.size() > 0) {
604 nextLine();
605 }
606 final JComponent separator = getComponentFactory().createLabeledSeparator(labelKey);
607 return append(separator, 1, 1, true, false).nextLine();
608 }
609
610 /**
611 * Ends the current line and starts a new one
612 *
613 * @return "this" to make it easier to string together append calls
614 */
615 public GridBagLayoutBuilder nextLine() {
616 currentRow++;
617 this.currentCol = 0;
618
619 return this;
620 }
621
622 private GridBagConstraints createGridBagConstraint(int x, int y, int colSpan, int rowSpan, double xweight,
623 double yweight, Insets insets) {
624 final GridBagConstraints gbc = new GridBagConstraints();
625 gbc.gridx = x;
626 gbc.gridy = y;
627 gbc.gridwidth = colSpan;
628 gbc.gridheight = rowSpan;
629 gbc.weightx = xweight;
630 gbc.weighty = yweight;
631 gbc.insets = insets;
632
633 // in theory other ones can be used, but I've never seen why...
634 gbc.fill = GridBagConstraints.BOTH;
635
636 return gbc;
637 }
638
639 /**
640 * Should this show "guidelines"? Useful for debugging layouts.
641 */
642 public void setShowGuidelines(boolean showGuidelines) {
643 this.showGuidelines = showGuidelines;
644 }
645
646 /**
647 * Creates and returns a JPanel with all the given components in it, using
648 * the "hints" that were provided to the builder.
649 *
650 * @return a new JPanel with the components laid-out in it
651 */
652 public JPanel getPanel() {
653 if (this.currentRowList.size() > 0) {
654 this.rows.add(this.currentRowList);
655 }
656
657 final JPanel panel = this.showGuidelines ? new GridBagLayoutDebugPanel() : new JPanel(new GridBagLayout());
658
659 final int lastRowIndex = this.rows.size() - 1;
660 for (int currentRowIndex = 0; currentRowIndex <= lastRowIndex; currentRowIndex++) {
661 final List row = getRow(currentRowIndex);
662 addRow(row, currentRowIndex, lastRowIndex, panel);
663 }
664 return panel;
665 }
666
667 private void addRow(final List row, final int currentRowIndex, final int lastRowIndex, final JPanel panel) {
668 final int lastColIndex = row.size() - 1;
669
670 for (int currentColIndex = 0; currentColIndex <= lastColIndex; currentColIndex++) {
671 final Item item = (Item)row.get(currentColIndex);
672
673 if (item != null && item != NULL_ITEM) {
674 final GridBagConstraints gbc = item.gbc;
675
676 if (gbc.gridy + gbc.gridheight - 1 == lastRowIndex) {
677 formatLastRow(gbc);
678 }
679
680 if (gbc.gridx + gbc.gridwidth - 1 == lastColIndex) {
681 formatLastColumn(gbc, currentColIndex);
682 }
683
684 if (LOG.isDebugEnabled()) {
685 LOG.debug("Adding to panel: " + getDebugString(item.component, gbc));
686 }
687 panel.add(item.component, gbc);
688 }
689 }
690 }
691
692 private String getDebugString(Component component, GridBagConstraints gbc) {
693 final StringBuffer buffer = new StringBuffer();
694
695 if (component instanceof JComponent) {
696 final JComponent jcomp = (JComponent)component;
697 final String name = jcomp.getName();
698 if (name != null && !"".equals(jcomp.getName())) {
699 buffer.append(name);
700 }
701 else {
702 if (jcomp instanceof JLabel) {
703 buffer.append(((JLabel)jcomp).getText());
704 }
705 else {
706 buffer.append(jcomp.toString());
707 }
708 }
709 }
710 else {
711 buffer.append(component.toString());
712 }
713
714 buffer.append(", ");
715 buffer.append("GridBagConstraint[");
716 buffer.append("anchor=").append(gbc.anchor).append(",");
717 buffer.append("fill=").append(gbc.fill).append(",");
718 buffer.append("gridheight=").append(gbc.gridheight).append(",");
719 buffer.append("gridwidth=").append(gbc.gridwidth).append(",");
720 buffer.append("gridx=").append(gbc.gridx).append(",");
721 buffer.append("gridy=").append(gbc.gridy).append(",");
722 buffer.append("weightx=").append(gbc.weightx).append(",");
723 buffer.append("weighty=").append(gbc.weighty).append("]");
724 return buffer.toString();
725 }
726
727 private void formatLastRow(final GridBagConstraints gbc) {
728 // remove any insets at the bottom of the GBC
729 final Insets oldInset = gbc.insets;
730 gbc.insets = new Insets(oldInset.top, oldInset.left, 0, oldInset.right);
731 }
732
733 /**
734 * Should the last column before a {@link #nextLine()}automaticly span to
735 * the end of the panel?
736 * <p />
737 *
738 * For example, if you have
739 *
740 * <pre>
741 * append(a).append(b).append(c).nextLine();
742 * append(d).append(e).nextLine();
743 * </pre>
744 *
745 * then "e" would automaticly span two columns.
746 *
747 * @param autoSpanLastComponent default is true
748 */
749 public void setAutoSpanLastComponent(boolean autoSpanLastComponent) {
750 this.autoSpanLastComponent = autoSpanLastComponent;
751 }
752
753 private void formatLastColumn(final GridBagConstraints gbc, final int currentColIndex) {
754 // remove any insets at the right of the GBC
755 final Insets oldInset = gbc.insets;
756 gbc.insets = new Insets(oldInset.top, oldInset.left, oldInset.bottom, 0);
757
758 if (this.autoSpanLastComponent) {
759 // increase the gridwidth if needed
760 final int colSpan = (this.maxCol - currentColIndex) + 1;
761 if (colSpan > gbc.gridwidth) {
762 if (LOG.isDebugEnabled()) {
763 LOG.debug("Increasing gridwidth from " + gbc.gridwidth + " to " + colSpan);
764 }
765 gbc.gridwidth = colSpan;
766 }
767 }
768 }
769
770 //*************************************************************************
771 //
772 // INNER CLASSES
773 //
774 //*************************************************************************
775
776 private static class Item {
777 public Component component;
778
779 public GridBagConstraints gbc;
780
781 public Item(Component component, GridBagConstraints gbc) {
782 this.component = component;
783 this.gbc = gbc;
784 }
785 }
786
787 }