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 }