001/* 002 * Copyright (c) 2004-2007 by Michael Connor. All Rights Reserved. 003 * 004 * Redistribution and use in source and binary forms, with or without 005 * modification, are permitted provided that the following conditions are met: 006 * 007 * o Redistributions of source code must retain the above copyright notice, 008 * this list of conditions and the following disclaimer. 009 * 010 * o Redistributions in binary form must reproduce the above copyright notice, 011 * this list of conditions and the following disclaimer in the documentation 012 * and/or other materials provided with the distribution. 013 * 014 * o Neither the name of FormLayoutBuilder or Michael Connor nor the names of 015 * its contributors may be used to endorse or promote products derived 016 * from this software without specific prior written permission. 017 * 018 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 019 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 020 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 021 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 022 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 023 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 024 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 025 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 026 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 027 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 028 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 029 */ 030package org.mlc.swing.layout; 031 032import java.awt.BorderLayout; 033import java.awt.Color; 034import java.awt.Component; 035import java.awt.Container; 036import java.awt.Font; 037import java.awt.Frame; 038import java.awt.Insets; 039import java.awt.Point; 040import java.awt.Rectangle; 041import java.awt.event.ActionEvent; 042import java.awt.event.ActionListener; 043import java.awt.event.InputEvent; 044import java.awt.event.KeyEvent; 045import java.awt.event.MouseAdapter; 046import java.awt.event.MouseEvent; 047import java.util.ArrayList; 048import java.util.HashMap; 049import java.util.HashSet; 050import java.util.List; 051import java.util.Locale; 052import java.util.Map; 053import java.util.Set; 054 055import javax.swing.AbstractAction; 056import javax.swing.AbstractListModel; 057import javax.swing.AbstractSpinnerModel; 058import javax.swing.Action; 059import javax.swing.ImageIcon; 060import javax.swing.JButton; 061import javax.swing.JComboBox; 062import javax.swing.JDialog; 063import javax.swing.JFrame; 064import javax.swing.JLabel; 065import javax.swing.JList; 066import javax.swing.JOptionPane; 067import javax.swing.JPanel; 068import javax.swing.JScrollPane; 069import javax.swing.JSpinner; 070import javax.swing.JSplitPane; 071import javax.swing.JTable; 072import javax.swing.JTextField; 073import javax.swing.JToolBar; 074import javax.swing.JViewport; 075import javax.swing.KeyStroke; 076import javax.swing.ListCellRenderer; 077import javax.swing.ListModel; 078import javax.swing.ListSelectionModel; 079import javax.swing.SpinnerNumberModel; 080import javax.swing.SwingUtilities; 081import javax.swing.UIManager; 082import javax.swing.border.Border; 083import javax.swing.border.EmptyBorder; 084import javax.swing.event.ChangeEvent; 085import javax.swing.event.ChangeListener; 086import javax.swing.event.ListSelectionEvent; 087import javax.swing.event.ListSelectionListener; 088import javax.swing.table.DefaultTableCellRenderer; 089 090import com.jgoodies.forms.factories.Borders; 091import com.jgoodies.forms.factories.DefaultComponentFactory; 092import com.jgoodies.forms.layout.CellConstraints; 093 094/** 095 * This is the main panel that is used in LayoutFrame serving as the user 096 * interface for the builder. This is a pretty juicy file because there is a lot 097 * going on here. Better docs to come... 098 * 099 * @author Michael Connor mlconnor@yahoo.com 100@version $Id$ 101@since Ptolemy II 8.0 102 */ 103@SuppressWarnings("serial") 104public class FormEditor extends JPanel { 105 String[] verticalAlignmentList = { LayoutConstraintsManager.DEFAULT, 106 LayoutConstraintsManager.FILL, LayoutConstraintsManager.CENTER, 107 LayoutConstraintsManager.TOP, LayoutConstraintsManager.BOTTOM }; 108 109 String[] horizontalAlignmentList = { LayoutConstraintsManager.DEFAULT, 110 LayoutConstraintsManager.FILL, LayoutConstraintsManager.CENTER, 111 LayoutConstraintsManager.LEFT, LayoutConstraintsManager.RIGHT }; 112 113 ColSpanSpinnerModel colSpinnerModel = new ColSpanSpinnerModel(); 114 115 RowSpanSpinnerModel rowSpinnerModel = new RowSpanSpinnerModel(); 116 117 Action newComponentAction = new NewComponentAction(); 118 119 Action removeComponentAction = new RemoveComponentAction(); 120 121 Action insertRowBeforeAction = new InsertRowBeforeAction(); 122 123 Action insertRowAfterAction = new InsertRowAfterAction(); 124 125 Action deleteRowAction = new DeleteRowAction(); 126 127 Action insertColumnBeforeAction = new InsertColumnBeforeAction(); 128 129 Action insertColumnAfterAction = new InsertColumnAfterAction(); 130 131 Action deleteColumnAction = new DeleteColumnAction(); 132 133 JComboBox verticalAlignmentCombo = new JComboBox(verticalAlignmentList); 134 135 JComboBox horizontalAlignmentCombo = new JComboBox(horizontalAlignmentList); 136 137 JSpinner rowSpanSpinner = new JSpinner(rowSpinnerModel); 138 139 JSpinner columnSpanSpinner = new JSpinner(colSpinnerModel); 140 141 JLabel columnSpanLabel = new JLabel("Column Span"); 142 143 JLabel horizontalAlignmentLabel = new JLabel("Horizontal Alignment"); 144 145 JLabel rowSpanLabel = new JLabel("Row Span"); 146 147 JLabel verticalAlignmentLabel = new JLabel("Vertical Alignment"); 148 149 JPanel contentPanel = new JPanel(); 150 151 JPanel insetsPanel = new JPanel(); 152 153 SpinnerNumberModel rightInsetSpinnerModel = new SpinnerNumberModel(0, 0, 154 Integer.MAX_VALUE, 1); 155 156 SpinnerNumberModel topInsetSpinnerModel = new SpinnerNumberModel(0, 0, 157 Integer.MAX_VALUE, 1); 158 159 SpinnerNumberModel bottomInsetSpinnerModel = new SpinnerNumberModel(0, 0, 160 Integer.MAX_VALUE, 1); 161 162 SpinnerNumberModel leftInsetSpinnerModel = new SpinnerNumberModel(0, 0, 163 Integer.MAX_VALUE, 1); 164 165 JSpinner rightInsetSpinner = new JSpinner(rightInsetSpinnerModel); 166 167 JSpinner bottomInsetSpinner = new JSpinner(bottomInsetSpinnerModel); 168 169 JSpinner leftInsetSpinner = new JSpinner(leftInsetSpinnerModel); 170 171 JSpinner topInsetSpinner = new JSpinner(topInsetSpinnerModel); 172 173 GridTableModel tableModel = new GridTableModel(); 174 175 JLabel insetsLabel = new JLabel("Insets"); 176 177 JLabel componentsLabel = new JLabel("Components (Drag n Drop)"); 178 179 JLabel componentPaletteLabel = new JLabel("Palette (Drag n Drop)"); 180 181 ComponentPaletteListModel componentPaletteListModel = new ComponentPaletteListModel(); 182 183 // KBR JList componentPalette = new JList(componentPaletteListModel); 184 DndList componentPalette = new DndList(this, componentPaletteListModel); 185 186 JScrollPane componentPaletteScrollPane = new JScrollPane(componentPalette); 187 188 ComponentSelectionListModel componentSelectionListModel = new ComponentSelectionListModel(); 189 190 DndList componentList = new DndList(this, componentSelectionListModel); 191 192 JScrollPane componentListScrollPane = new JScrollPane(componentList); 193 194 ComponentListCellRenderer componentListCellRenderer = new ComponentListCellRenderer(); 195 196 Component constraintsSeparator = DefaultComponentFactory.getInstance() 197 .createSeparator("Component Constraints"); 198 199 Component positionsSeparator = DefaultComponentFactory.getInstance() 200 .createSeparator("Component Positions (Drag n Drop)"); 201 202 JPanel componentsPanel = new JPanel(); 203 204 JPanel propertiesPanel = new JPanel(); 205 206 JSplitPane componentsSplitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT, 207 componentsPanel, propertiesPanel); 208 209 JTextField colSpecField = new JTextField(); 210 211 JTextField rowSpecField = new JTextField(); 212 213 Set<Component> newComponents = new HashSet<Component>(); 214 215 LayoutConstraintsManager layoutConstraintsManager; 216 217 JToolBar toolbar = new JToolBar(); 218 219 JButton newComponentButton = new JButton(newComponentAction); 220 221 JButton removeComponentButton = new JButton(removeComponentAction); 222 223 JButton columnDeleteButton = new JButton(deleteColumnAction); 224 225 JButton columnInsertAfterButton = new JButton(insertColumnAfterAction); 226 227 JButton columnInsertBeforeButton = new JButton(insertColumnBeforeAction); 228 229 JButton rowDeleteButton = new JButton(deleteRowAction); 230 231 JButton rowInsertBeforeButton = new JButton(insertRowBeforeAction); 232 233 JButton rowInsertAfterButton = new JButton(insertRowAfterAction); 234 235 Container container; 236 237 ContainerLayout containerLayout; 238 239 MultiContainerFrame layoutFrame; 240 DnDTable table = null; 241 JScrollPane tableScrollPane = null; 242 JSplitPane constraintsSplitPane = null; 243 244 Component topComponent = null; 245 246 boolean suspendConstraintControlUpdates = false; 247 248 void setContainer(Container container) { 249 java.awt.LayoutManager layoutManager = container.getLayout(); 250 if (!(layoutManager instanceof ContainerLayout)) { 251 throw new RuntimeException( 252 "Container layout must be of type ContainerLayout"); 253 } 254 this.container = container; 255 } 256 257 public FormEditor(MultiContainerFrame layoutFrame, ContainerLayout layout, 258 Container container) { 259 super(); 260 261 this.layoutFrame = layoutFrame; 262 table = new DnDTable(layoutFrame, this); 263 tableScrollPane = new JScrollPane(table); 264 constraintsSplitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, 265 tableScrollPane, componentsSplitPane); 266 267 setContainer(container); 268 containerLayout = layout; 269 270 table.setBackground(java.awt.Color.white); 271 table.setSelectionBackground(new Color(220, 220, 255)); 272 table.setSelectionForeground(Color.black); 273 274 table.setDefaultRenderer(Object.class, 275 new ConstraintTableCellRenderer()); 276 table.setRowHeight(20); 277 table.setModel(tableModel); 278 table.setCellSelectionEnabled(true); 279 table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); 280 281 // let's put the cursor in the table so the create component 282 // icon is enabled. at least then the user knows what to do... 283 if (tableModel.getRowCount() > 1 && tableModel.getColumnCount() > 1) { 284 // KBR do NOT force visible so constraints row can still be seen 285 setSelectedCell(1, 1, false); 286 } 287 288 componentList.setCellRenderer(componentListCellRenderer); 289 290 // let's setup all of the usability stuff... 291 componentsLabel.setLabelFor(componentListScrollPane); 292 // componentsLabel.setDisplayedMnemonic(KeyEvent.VK_S); 293 verticalAlignmentLabel.setLabelFor(verticalAlignmentCombo); 294 verticalAlignmentLabel.setDisplayedMnemonic(KeyEvent.VK_V); 295 horizontalAlignmentLabel.setLabelFor(horizontalAlignmentCombo); 296 horizontalAlignmentLabel.setDisplayedMnemonic(KeyEvent.VK_H); 297 columnSpanLabel.setLabelFor(columnSpanSpinner); 298 columnSpanLabel.setDisplayedMnemonic(KeyEvent.VK_C); 299 rowSpanLabel.setLabelFor(rowSpanSpinner); 300 rowSpanLabel.setDisplayedMnemonic(KeyEvent.VK_R); 301 302 columnInsertAfterButton 303 .setToolTipText("Insert a column after this column"); 304 columnInsertBeforeButton 305 .setToolTipText("Insert a column before this column"); 306 columnDeleteButton.setToolTipText("Delete this column"); 307 rowInsertBeforeButton.setToolTipText("Insert a row before this row"); 308 rowInsertAfterButton.setToolTipText("Insert a row after this row"); 309 310 // let's setup the table toolbar 311 toolbar.add(newComponentButton); 312 toolbar.add(removeComponentButton); 313 toolbar.addSeparator(); 314 toolbar.add(columnDeleteButton); 315 toolbar.add(columnInsertBeforeButton); 316 toolbar.add(columnInsertAfterButton); 317 toolbar.addSeparator(); 318 toolbar.add(rowDeleteButton); 319 toolbar.add(rowInsertBeforeButton); 320 toolbar.add(rowInsertAfterButton); 321 322 setFormComponent(null); 323 324 layoutConstraintsManager = LayoutConstraintsManager 325 .getLayoutConstraintsManager(this.getClass() 326 .getResourceAsStream("editableLayoutConstraints.xml")); 327 328 layoutConstraintsManager.setLayout("mainLayout", contentPanel); 329 layoutConstraintsManager.setLayout("insetsLayout", insetsPanel); 330 layoutConstraintsManager.setLayout("componentsLayout", componentsPanel); 331 layoutConstraintsManager.setLayout("propertiesLayout", propertiesPanel); 332 333 insetsPanel.add(rightInsetSpinner, "rightInsetSpinner"); 334 insetsPanel.add(leftInsetSpinner, "leftInsetSpinner"); 335 insetsPanel.add(topInsetSpinner, "topInsetSpinner"); 336 insetsPanel.add(bottomInsetSpinner, "bottomInsetSpinner"); 337 338 componentsPanel.add(componentListScrollPane, "componentListScrollPane"); 339 componentsPanel.add(componentsLabel, "componentsLabel"); 340 propertiesPanel.add(componentPaletteScrollPane, 341 "componentPaletteScrollPane"); 342 componentPalette.setCellRenderer(new ComponentPaletteListRenderer()); 343 propertiesPanel.add(componentPaletteLabel, "componentPaletteLabel"); 344 345 contentPanel.add(rowSpanLabel, "rowSpanLabel"); 346 contentPanel.add(horizontalAlignmentCombo, "horizontalAlignmentCombo"); 347 contentPanel.add(horizontalAlignmentLabel, "horizontalAlignmentLabel"); 348 contentPanel.add(rowSpanSpinner, "rowSpanSpinner"); 349 contentPanel.add(verticalAlignmentCombo, "verticalAlignmentCombo"); 350 contentPanel.add(columnSpanLabel, "columnSpanLabel"); 351 contentPanel.add(verticalAlignmentLabel, "verticalAlignmentLabel"); 352 contentPanel.add(columnSpanSpinner, "columnSpanSpinner"); 353 contentPanel.add(insetsPanel, "insetsPanel"); 354 contentPanel.add(insetsLabel, "insetsLabel"); 355 contentPanel.add(constraintsSeparator, "constraintsSeparator"); 356 contentPanel.add(positionsSeparator, "positionsSeparator"); 357 contentPanel.add(toolbar, "toolbar"); 358 contentPanel.add(constraintsSplitPane, "constraintsSplitPane"); 359 360 constraintsSplitPane.setDividerLocation(605); 361 362 contentPanel.setBorder(Borders.DIALOG_BORDER); 363 364 setLayout(new BorderLayout()); 365 add(contentPanel, BorderLayout.CENTER); 366 367 setupListeners(); 368 } 369 370 private void setupListeners() { 371 372 verticalAlignmentCombo.addActionListener(new ActionListener() { 373 @Override 374 public void actionPerformed(ActionEvent e) { 375 Component component = table.getSelectedControl(); 376 if (component != null) { 377 CellConstraints cellConstraints = getComponentConstraints( 378 component); 379 cellConstraints.vAlign = LayoutConstraintsManager 380 .getAlignment((String) verticalAlignmentCombo 381 .getSelectedItem()); 382 updateLayout(component); 383 } 384 } 385 }); 386 387 horizontalAlignmentCombo.addActionListener(new ActionListener() { 388 @Override 389 public void actionPerformed(ActionEvent e) { 390 Component component = table.getSelectedControl(); 391 if (component != null) { 392 CellConstraints cellConstraints = getComponentConstraints( 393 component); 394 cellConstraints.hAlign = LayoutConstraintsManager 395 .getAlignment((String) horizontalAlignmentCombo 396 .getSelectedItem()); 397 updateLayout(component); 398 } 399 } 400 }); 401 402 topInsetSpinnerModel.addChangeListener(new ChangeListener() { 403 @Override 404 public void stateChanged(ChangeEvent e) { 405 if (!suspendConstraintControlUpdates) { 406 Component component = table.getSelectedControl(); 407 CellConstraints constraints = getComponentConstraints( 408 component); 409 Insets insets = new Insets( 410 topInsetSpinnerModel.getNumber().intValue(), 411 constraints.insets.left, constraints.insets.bottom, 412 constraints.insets.right); 413 constraints.insets = insets; 414 updateLayout(component); 415 } 416 } 417 }); 418 419 leftInsetSpinnerModel.addChangeListener(new ChangeListener() { 420 @Override 421 public void stateChanged(ChangeEvent e) { 422 if (!suspendConstraintControlUpdates) { 423 Component component = table.getSelectedControl(); 424 CellConstraints constraints = getComponentConstraints( 425 component); 426 Insets insets = new Insets(constraints.insets.top, 427 leftInsetSpinnerModel.getNumber().intValue(), 428 constraints.insets.bottom, 429 constraints.insets.right); 430 constraints.insets = insets; 431 updateLayout(component); 432 } 433 } 434 }); 435 436 rightInsetSpinnerModel.addChangeListener(new ChangeListener() { 437 @Override 438 public void stateChanged(ChangeEvent e) { 439 if (!suspendConstraintControlUpdates) { 440 Component component = table.getSelectedControl(); 441 CellConstraints constraints = getComponentConstraints( 442 component); 443 Insets insets = new Insets(constraints.insets.top, 444 constraints.insets.left, constraints.insets.bottom, 445 rightInsetSpinnerModel.getNumber().intValue()); 446 constraints.insets = insets; 447 updateLayout(component); 448 } 449 } 450 }); 451 452 bottomInsetSpinnerModel.addChangeListener(new ChangeListener() { 453 @Override 454 public void stateChanged(ChangeEvent e) { 455 if (!suspendConstraintControlUpdates) { 456 Component component = table.getSelectedControl(); 457 CellConstraints constraints = getComponentConstraints( 458 component); 459 Insets insets = new Insets(constraints.insets.top, 460 constraints.insets.left, 461 bottomInsetSpinnerModel.getNumber().intValue(), 462 constraints.insets.right); 463 constraints.insets = insets; 464 updateLayout(component); 465 } 466 } 467 }); 468 469 table.addMouseListener(new MouseAdapter() { 470 @Override 471 public void mouseClicked(MouseEvent e) { 472 if (e.getClickCount() == 2) { 473 Point p = e.getPoint(); 474 int row = table.rowAtPoint(p); 475 int col = table.columnAtPoint(p); 476 // support double-click: 477 Component component = table.getSelectedControl(); 478 if (component == null) { 479 return; 480 } 481 482 /* invoke componentDef editor on double-clicked control */ 483 String name = getComponentName(component); 484 ComponentDef componentDef = containerLayout 485 .getComponentDef(name); 486 if (componentDef != null) { 487 editComponent(componentDef, component, 488 new CellConstraints(col, row)); 489 } 490 } 491 } 492 }); 493 componentList.addListSelectionListener(new ListSelectionListener() { 494 @Override 495 public void valueChanged(ListSelectionEvent e) { 496 if (!e.getValueIsAdjusting()) { 497 /* set selected component as selected, which causes a 498 * scroll-to-visible in the table */ 499 Component thisComponent = (Component) componentList 500 .getSelectedValue(); 501 502 CellConstraints constraints = getComponentConstraints( 503 thisComponent); 504 if (constraints == null) { 505 throw new RuntimeException( 506 "Unable to find constraints for component " 507 + thisComponent + " in layout " 508 + containerLayout.getName()); 509 } 510 int col = constraints.gridX; 511 int row = constraints.gridY; 512 513 table.changeSelection(row, col, false, false); 514 topComponent = thisComponent; 515 } 516 } 517 }); 518 519 componentList.addMouseListener(new MouseAdapter() { 520 @Override 521 public void mouseClicked(MouseEvent e) { 522 if (e.getClickCount() == 2) { 523 int index = componentList.locationToIndex(e.getPoint()); 524 if (index == -1) { 525 return; 526 } 527 528 // Get item 529 ListModel lm = ((DndList) e.getSource()).getModel(); 530 Component thisComponent = (Component) lm 531 .getElementAt(index); 532 533 String name = getComponentName(thisComponent); 534 ComponentDef compDef = containerLayout 535 .getComponentDef(name); 536 CellConstraints constraints = getComponentConstraints( 537 thisComponent); 538 if (constraints == null) { 539 throw new RuntimeException( 540 "Unable to find constraints for component " 541 + thisComponent + " in layout " 542 + containerLayout.getName()); 543 } 544 editComponent(compDef, thisComponent, constraints); 545 } 546 } 547 }); 548 } 549 550 String getComponentName(Component control) { 551 return containerLayout.getComponentName(control); 552 } 553 554 CellConstraints getComponentConstraints(Component component) { 555 return containerLayout.getComponentConstraints(component); 556 } 557 558 private void specsChanged() { 559 updateLayouts(); 560 561 // lets go down the tree 562 Component[] children = container.getComponents(); 563 for (Component component : children) { 564 if (component instanceof Container) { 565 ((Container) component).doLayout(); 566 } 567 } 568 } 569 570 void updateLayouts() { 571 container.validate(); 572 container.doLayout(); 573 574 Container parent = container; 575 576 while (parent != null) { 577 parent.validate(); 578 parent = parent.getParent(); 579 } 580 } 581 582 private void setSelectedCell(int columnIndex, int rowIndex, 583 boolean forceVisible) { 584 // we don't want to update the selection interval if nothing changed... 585 table.getSelectionModel().setSelectionInterval(rowIndex, rowIndex); 586 table.getColumnModel().getSelectionModel() 587 .setSelectionInterval(columnIndex, columnIndex); 588 589 if (forceVisible) { 590 // let's make sure the cell is in the visible range... 591 JViewport viewport = (JViewport) table.getParent(); 592 Rectangle rect = table.getCellRect(rowIndex, columnIndex, true); 593 Point pt = viewport.getViewPosition(); 594 rect.setLocation(rect.x - pt.x, rect.y - pt.y); 595 viewport.scrollRectToVisible(rect); 596 } 597 } 598 599 private class ComponentSelectionListModel 600 extends javax.swing.AbstractListModel { 601 // private String selectedName = null; 602 603 List<Component> sortedComponents = new ArrayList<Component>(); 604 605 public ComponentSelectionListModel() { 606 super(); 607 } 608 609 // Bug: when the user does the following: 610 // 1) drags a new control into place 611 // 2) drags a 2nd new control into place 612 // 3) deletes the 2nd control 613 // 4) drags a new 2nd control into place 614 // we get an array out of bounds exception in getElementAt. The 615 // delete probably failed to update our list. 616 @Override 617 public Object getElementAt(int index) { 618 Component component = sortedComponents.get(index); 619 return component; 620 } 621 622 @Override 623 public int getSize() { 624 sortedComponents = new ArrayList<Component>(); 625 626 if (container != null) { 627 Component[] containerComponents = container.getComponents(); 628 for (Component insertComponent : containerComponents) { 629 String insertComponentName = getComponentName( 630 insertComponent); 631 632 int insertIndex = 0; 633 while (insertIndex < sortedComponents.size() 634 && insertComponentName != null) { 635 Component testComponent = sortedComponents 636 .get(insertIndex); 637 String testName = getComponentName(testComponent); 638 if (testName != null) { 639 testName = testName 640 .toUpperCase(Locale.getDefault()); 641 } 642 if (insertComponentName.toUpperCase(Locale.getDefault()) 643 .compareTo(testName) <= 0) { 644 break; 645 } else { 646 insertIndex++; 647 } 648 } 649 sortedComponents.add(insertIndex, insertComponent); 650 } 651 } 652 653 return container != null ? container.getComponentCount() : 0; 654 } 655 656 public void fireDelete() { 657 super.fireContentsChanged(this, 0, 658 Math.max(0, container.getComponents().length - 1)); 659 } 660 661 public void fireInsert() { 662 super.fireContentsChanged(this, 0, 663 Math.max(0, container.getComponents().length - 1)); 664 } 665 } 666 667 class ComponentListCellRenderer extends JLabel implements ListCellRenderer { 668 private static final long serialVersionUID = 1L; 669 Border noFocusBorder = new EmptyBorder(1, 1, 1, 1); 670 671 public ComponentListCellRenderer() { 672 super(); 673 setOpaque(true); 674 } 675 676 @Override 677 public Component getListCellRendererComponent(JList list, Object value, 678 int index, boolean isSelected, boolean cellHasFocus) { 679 Component component = (Component) value; 680 String name = getComponentName(component); 681 682 setComponentOrientation(list.getComponentOrientation()); 683 if (isSelected) { 684 setBackground(list.getSelectionBackground()); 685 setForeground(list.getSelectionForeground()); 686 } else { 687 setBackground(list.getBackground()); 688 setForeground(list.getForeground()); 689 } 690 691 setText(name != null ? name : "(Untitled)"); 692 693 setEnabled(list.isEnabled()); 694 Font font = list.getFont(); 695 setFont(font.deriveFont( 696 component.isVisible() ? Font.PLAIN : Font.BOLD)); 697 setBorder(cellHasFocus 698 ? UIManager.getBorder("List.focusCellHighlightBorder") 699 : noFocusBorder); 700 701 return this; 702 } 703 } 704 705 private void insertColumn(int column) { 706 for (int index = 0; index < container.getComponentCount(); index++) { 707 Component component = container.getComponent(index); 708 CellConstraints constraints = getComponentConstraints(component); 709 if (constraints.gridX > column) { 710 constraints.gridX++; 711 } 712 } 713 714 try { 715 containerLayout.addColumnSpec(column, "pref"); 716 tableModel.fireTableStructureChanged(); 717 setSelectedCell(column + 1, 0, true); 718 specsChanged(); 719 } catch (IllegalArgumentException iae) { 720 JOptionPane.showMessageDialog(FormEditor.this, iae.getMessage(), 721 "Invalid Layout", JOptionPane.ERROR_MESSAGE); 722 } 723 } 724 725 private void insertRow(int rowIndex) { 726 for (int index = 0; index < container.getComponentCount(); index++) { 727 Component component = container.getComponent(index); 728 CellConstraints constraints = getComponentConstraints(component); 729 if (constraints.gridY > rowIndex) { 730 constraints.gridY++; 731 } 732 } 733 734 try { 735 containerLayout.addRowSpec(rowIndex, "pref"); 736 tableModel.fireTableStructureChanged(); 737 setSelectedCell(0, rowIndex + 1, true); 738 specsChanged(); 739 } catch (IllegalArgumentException iae) { 740 JOptionPane.showMessageDialog(FormEditor.this, iae.getMessage(), 741 "Invalid Layout", JOptionPane.ERROR_MESSAGE); 742 } 743 } 744 745 Component formComponent = null; 746 747 // this method will act as the controller for the buttons 748 // and the cell constraints form 749 public void setFormComponent(Component component) { 750 // KBR with this, selecting header row then table body row, doesn't enable 751 // 'add' 752 // if ( component == formComponent ) 753 // return; 754 formComponent = component; 755 756 CellConstraints constraints = formComponent != null 757 ? getComponentConstraints(formComponent) 758 : null; 759 760 suspendConstraintControlUpdates = true; 761 762 if (formComponent != null) { 763 rowSpinnerModel.setComponent(formComponent); 764 colSpinnerModel.setComponent(formComponent); 765 verticalAlignmentCombo.setSelectedItem( 766 LayoutConstraintsManager.getAlignment(constraints.vAlign)); 767 horizontalAlignmentCombo.setSelectedItem( 768 LayoutConstraintsManager.getAlignment(constraints.hAlign)); 769 topInsetSpinnerModel 770 .setValue(Integer.valueOf(constraints.insets.top)); 771 bottomInsetSpinnerModel 772 .setValue(Integer.valueOf(constraints.insets.bottom)); 773 rightInsetSpinnerModel 774 .setValue(Integer.valueOf(constraints.insets.right)); 775 leftInsetSpinnerModel 776 .setValue(Integer.valueOf(constraints.insets.left)); 777 } 778 779 verticalAlignmentCombo.setEnabled(constraints != null); 780 horizontalAlignmentCombo.setEnabled(constraints != null); 781 rightInsetSpinner.setEnabled(constraints != null); 782 leftInsetSpinner.setEnabled(constraints != null); 783 topInsetSpinner.setEnabled(constraints != null); 784 bottomInsetSpinner.setEnabled(constraints != null); 785 rowSpanSpinner.setEnabled(constraints != null); 786 columnSpanSpinner.setEnabled(constraints != null); 787 788 int col = table.getSelectedColumn(); 789 int row = table.getSelectedRow(); 790 791 // Don't allow 'add' on top of existing component 792 newComponentAction 793 .setEnabled(col > 0 && row > 0 && formComponent == null); 794 removeComponentAction.setEnabled(constraints != null); 795 columnDeleteButton.setEnabled( 796 row == 0 && col > 0 && containerLayout.getColumnCount() > 1); 797 columnInsertAfterButton.setEnabled(col > -1); 798 columnInsertBeforeButton.setEnabled(col > 0); 799 rowDeleteButton.setEnabled( 800 col == 0 && row > 0 && containerLayout.getRowCount() > 1); 801 rowInsertBeforeButton.setEnabled(row > 0); 802 rowInsertAfterButton.setEnabled(row > -1); 803 804 suspendConstraintControlUpdates = false; 805 } 806 807 public void updateLayout(Component component) { 808 if (suspendConstraintControlUpdates) { 809 return; 810 } 811 812 CellConstraints constraints = getComponentConstraints(component); 813 814 // we have to update the containerLayout which is the keeper of all 815 // constraints. if we didn't do this then we wouldn't notice any changes 816 // when we went to print everything out. 817 String name = getComponentName(component); 818 // i don't like this direct access thing. this should be changed... 819 containerLayout.setCellConstraints(name, constraints); 820 // updateForm(); 821 822 // be careful when modifying the next few lines of code. this 823 // is tricky to get right. this seems to work. 824 container.invalidate(); 825 container.doLayout(); 826 827 // KBR list (for example) doesn't seem to re-layout properly on drag&drop 828 // without these 829 container.validate(); 830 container.repaint(); 831 832 if (component instanceof Container) { 833 Container cContainer = (Container) component; 834 cContainer.invalidate(); 835 cContainer.doLayout(); 836 } 837 } 838 839 private class ColSpanSpinnerModel extends AbstractSpinnerModel { 840 CellConstraints constraints; 841 842 Component component; 843 844 public ColSpanSpinnerModel() { 845 } 846 847 public void setComponent(Component component) { 848 this.component = component; 849 if (component != null) { 850 constraints = getComponentConstraints(component); 851 fireStateChanged(); 852 } else { 853 constraints = null; 854 } 855 } 856 857 @Override 858 public Object getNextValue() { 859 if (constraints == null) { 860 return null; 861 } 862 Integer next = constraints.gridX + constraints.gridWidth 863 - 1 < containerLayout.getColumnCount() 864 ? Integer.valueOf(constraints.gridWidth + 1) 865 : null; 866 return next; 867 } 868 869 @Override 870 public Object getPreviousValue() { 871 if (constraints == null) { 872 return null; 873 } else { 874 Integer previous = constraints.gridWidth > 1 875 ? Integer.valueOf(constraints.gridWidth - 1) 876 : null; 877 return previous; 878 } 879 } 880 881 @Override 882 public Object getValue() { 883 if (constraints == null) { 884 return ""; 885 } else { 886 return Integer.valueOf(constraints.gridWidth); 887 } 888 } 889 890 @Override 891 public void setValue(Object value) { 892 if (constraints == null || value == null) { 893 return; 894 } 895 896 // Number val = (Number) value; 897 constraints.gridWidth = ((Number) value).intValue(); 898 super.fireStateChanged(); 899 updateLayout(component); 900 901 // firing table data changed messes up the 902 // selection so we'll get it and then restore it... 903 int col = table.getSelectedColumn(); 904 int row = table.getSelectedRow(); 905 tableModel.fireTableDataChanged(); 906 setSelectedCell(col, row, true); 907 } 908 } 909 910 private class RowSpanSpinnerModel extends AbstractSpinnerModel { 911 CellConstraints constraints; 912 913 Component component; 914 915 public RowSpanSpinnerModel() { 916 } 917 918 public void setComponent(Component component) { 919 this.component = component; 920 if (component != null) { 921 constraints = getComponentConstraints(component); 922 fireStateChanged(); 923 } else { 924 constraints = null; 925 } 926 } 927 928 @Override 929 public Object getNextValue() { 930 if (constraints == null) { 931 return null; 932 } else { 933 Integer next = constraints.gridY + constraints.gridHeight 934 - 1 < containerLayout.getRowCount() 935 ? Integer.valueOf(constraints.gridHeight + 1) 936 : null; 937 return next; 938 } 939 } 940 941 @Override 942 public Object getPreviousValue() { 943 if (constraints == null) { 944 return null; 945 } else { 946 Integer previous = constraints.gridHeight > 1 947 ? Integer.valueOf(constraints.gridHeight - 1) 948 : null; 949 return previous; 950 } 951 } 952 953 @Override 954 public Object getValue() { 955 if (constraints == null) { 956 return ""; 957 } else { 958 return Integer.valueOf(constraints.gridHeight); 959 } 960 } 961 962 @Override 963 public void setValue(Object value) { 964 if (constraints == null || value == null) { 965 return; 966 } 967 // Number val = (Number) value; 968 constraints.gridHeight = ((Number) value).intValue(); 969 super.fireStateChanged(); 970 updateLayout(component); 971 972 // firing table data changed messes up the 973 // selection so we'll get it and then restore it... 974 int col = table.getSelectedColumn(); 975 int row = table.getSelectedRow(); 976 tableModel.fireTableDataChanged(); 977 setSelectedCell(col, row, true); 978 } 979 } 980 981 /** 982 * Returns true if the named component was created by hand in this session 983 */ 984 public boolean isNewComponent(Component component) { 985 return newComponents.contains(component); 986 } 987 988 private class NewComponentDialog0 extends JDialog { 989 JTextField nameField = new JTextField(); 990 991 JLabel nameLabel = new JLabel("Name"); 992 993 JLabel typeLabel = new JLabel("Type"); 994 995 JButton okButton = new JButton("OK"); 996 997 JButton cancelButton = new JButton("Cancel"); 998 999 JComboBox typeCombo = new JComboBox(); 1000 1001 PropertyTableModel propertyTableModel = new PropertyTableModel(); 1002 1003 JTable propertyTable = new JTable(); 1004 1005 JScrollPane propertyScrollPane = new JScrollPane(propertyTable); 1006 1007 boolean wasSuccessful = false; 1008 1009 Component component = null; 1010 1011 Map<String, Object> controlProperties = new HashMap<String, Object>(); 1012 1013 public NewComponentDialog0(Frame owner) throws Exception { 1014 super(owner, "Add Component", true); 1015 1016 okButton.setMnemonic(KeyEvent.VK_O); 1017 cancelButton.setMnemonic(KeyEvent.VK_C); 1018 nameLabel.setDisplayedMnemonic(KeyEvent.VK_N); 1019 typeLabel.setDisplayedMnemonic(KeyEvent.VK_T); 1020 nameLabel.setLabelFor(nameField); 1021 typeLabel.setLabelFor(typeCombo); 1022 1023 // FormLayout layout = new FormLayout("right:max(40dlu;pref), 3dlu, 130dlu", 1024 // ""); 1025 JPanel content = new JPanel(); 1026 content.setBorder(Borders.DIALOG_BORDER); 1027 layoutConstraintsManager.setLayout("newComponentContent", content); 1028 getContentPane().setLayout(new BorderLayout()); 1029 getContentPane().add(content, BorderLayout.CENTER); 1030 1031 content.add(typeCombo, "typeCombo"); 1032 content.add(nameField, "nameField"); 1033 content.add(typeLabel, "typeLabel"); 1034 content.add(nameLabel, "nameLabel"); 1035 content.add(propertyScrollPane, "propertyScrollPane"); 1036 content.add( 1037 com.jgoodies.forms.factories.ButtonBarFactory 1038 .buildRightAlignedBar( 1039 new JButton[] { okButton, cancelButton }), 1040 "buttonPanel"); 1041 1042 propertyTable.putClientProperty("terminateEditOnFocusLost", 1043 Boolean.TRUE); 1044 propertyTable.setModel(propertyTableModel); 1045 1046 pack(); 1047 1048 typeCombo.addItem(new DefaultComponentBuilder( 1049 javax.swing.JButton.class, new String[] { "text" })); 1050 typeCombo.addItem(new DefaultComponentBuilder( 1051 javax.swing.JCheckBox.class, new String[] { "text" })); 1052 typeCombo.addItem( 1053 new DefaultComponentBuilder(javax.swing.JComboBox.class)); 1054 typeCombo.addItem(new DefaultComponentBuilder( 1055 javax.swing.JLabel.class, new String[] { "text" })); 1056 typeCombo.addItem(new JListComponentBuilder()); 1057 typeCombo.addItem( 1058 new DefaultComponentBuilder(javax.swing.JPanel.class)); 1059 typeCombo.addItem(new DefaultComponentBuilder( 1060 javax.swing.JPasswordField.class)); 1061 typeCombo.addItem(new DefaultComponentBuilder( 1062 javax.swing.JRadioButton.class, new String[] { "text" })); 1063 typeCombo.addItem( 1064 new DefaultComponentBuilder(javax.swing.JScrollPane.class)); 1065 typeCombo.addItem( 1066 new DefaultComponentBuilder(javax.swing.JSpinner.class)); 1067 typeCombo.addItem(new JTableComponentBuilder()); 1068 typeCombo.addItem( 1069 new DefaultComponentBuilder(javax.swing.JTextArea.class)); 1070 typeCombo.addItem( 1071 new DefaultComponentBuilder(javax.swing.JTextField.class)); 1072 typeCombo.addItem(new JToolBarComponentBuilder()); 1073 typeCombo.addItem(new JTreeComponentBuilder()); 1074 typeCombo.addItem(new SeparatorComponentBuilder()); 1075 typeCombo.addItem(new ButtonBarComponentBuilder()); 1076 1077 typeCombo.addActionListener(new ActionListener() { 1078 @Override 1079 public void actionPerformed(ActionEvent e) { 1080 controlProperties = new HashMap<String, Object>(); 1081 propertyTableModel.fireTableDataChanged(); 1082 } 1083 }); 1084 1085 okButton.addActionListener(new ActionListener() { 1086 @Override 1087 public void actionPerformed(ActionEvent e) { 1088 1089 try { 1090 if (nameField.getText().trim().length() == 0) { 1091 throw new Exception("The name field is required"); 1092 } 1093 1094 // int currentCol = propertyTable.getSelectedColumn(); 1095 // int currentRow = propertyTable.getSelectedRow(); 1096 1097 ComponentBuilder builder = (ComponentBuilder) typeCombo 1098 .getSelectedItem(); 1099 component = builder.getInstance(controlProperties); 1100 1101 wasSuccessful = true; 1102 dispose(); 1103 1104 } catch (Exception exception) { 1105 exception.printStackTrace(); 1106 wasSuccessful = false; 1107 JOptionPane.showMessageDialog(null, 1108 exception.getMessage(), 1109 "Error Creating Component", 1110 JOptionPane.ERROR_MESSAGE); 1111 } 1112 } 1113 }); 1114 1115 cancelButton.addActionListener(new ActionListener() { 1116 @Override 1117 public void actionPerformed(ActionEvent e) { 1118 wasSuccessful = false; 1119 dispose(); 1120 } 1121 }); 1122 } 1123 1124 public boolean wasSuccessful() { 1125 return wasSuccessful; 1126 } 1127 1128 public String getComponentName() { 1129 return nameField.getText(); 1130 } 1131 1132 // public String getComponentDeclaration() { 1133 // ComponentBuilder builder = (ComponentBuilder) typeCombo 1134 // .getSelectedItem(); 1135 // return builder 1136 // .getDeclaration(getComponentName(), controlProperties); 1137 // } 1138 1139 public boolean isUsingLayoutComponent() { 1140 ComponentBuilder builder = (ComponentBuilder) typeCombo 1141 .getSelectedItem(); 1142 return builder.isComponentALayoutContainer(); 1143 } 1144 1145 public Component getComponent() { 1146 return component; 1147 } 1148 1149 public ComponentDef getComponentDef() { 1150 ComponentBuilder builder = (ComponentBuilder) typeCombo 1151 .getSelectedItem(); 1152 return builder.getComponentDef(getComponentName(), 1153 controlProperties); 1154 } 1155 1156 private class PropertyTableModel 1157 extends javax.swing.table.AbstractTableModel { 1158 @Override 1159 public int getColumnCount() { 1160 return 2; 1161 } 1162 1163 @Override 1164 public int getRowCount() { 1165 ComponentBuilder builder = (ComponentBuilder) typeCombo 1166 .getSelectedItem(); 1167 return builder != null ? builder.getProperties().size() : 0; 1168 } 1169 1170 @Override 1171 public boolean isCellEditable(int row, int col) { 1172 return col == 1; 1173 } 1174 1175 @Override 1176 public String getColumnName(int col) { 1177 return col == 0 ? "Property" : "Value"; 1178 } 1179 1180 @Override 1181 public void setValueAt(Object aValue, int row, int col) { 1182 ComponentBuilder builder = (ComponentBuilder) typeCombo 1183 .getSelectedItem(); 1184 List<BeanProperty> properties = builder.getProperties(); 1185 BeanProperty property = properties.get(row); 1186 controlProperties.put(property.getName(), aValue); 1187 } 1188 1189 @Override 1190 public Object getValueAt(int rowIndex, int columnIndex) { 1191 ComponentBuilder builder = (ComponentBuilder) typeCombo 1192 .getSelectedItem(); 1193 List<BeanProperty> properties = builder.getProperties(); 1194 BeanProperty property = properties.get(rowIndex); 1195 1196 return columnIndex == 0 ? property.getName() 1197 : controlProperties.get(property.getName()); 1198 } 1199 1200 // public Component getComponent() throws Exception { 1201 // ComponentBuilder builder = (ComponentBuilder) typeCombo 1202 // .getSelectedItem(); 1203 // Component instance = builder.getInstance(controlProperties); 1204 // return instance; 1205 // } 1206 } 1207 } 1208 1209 private class ConstraintTableCellRenderer extends DefaultTableCellRenderer { 1210 @Override 1211 public Component getTableCellRendererComponent(JTable table, 1212 Object value, boolean isSelected, boolean hasFocus, int row, 1213 int column) { 1214 String stringValue = null; 1215 if (value != null) { 1216 if (value instanceof Component) { 1217 String name = getComponentName((Component) value); 1218 stringValue = name == null ? "(Untitled)" : name; 1219 } else { 1220 // in this case it's a row or col header 1221 stringValue = (String) value; 1222 } 1223 } 1224 1225 return super.getTableCellRendererComponent(table, stringValue, 1226 isSelected, hasFocus, row, column); 1227 } 1228 } 1229 1230 private class GridTableModel extends javax.swing.table.AbstractTableModel { 1231 1232 @Override 1233 public int getColumnCount() { 1234 return containerLayout != null 1235 ? containerLayout.getColumnCount() + 1 1236 : 1; 1237 } 1238 1239 @Override 1240 public int getRowCount() { 1241 return containerLayout != null ? containerLayout.getRowCount() + 1 1242 : 1; 1243 } 1244 1245 @Override 1246 public boolean isCellEditable(int row, int col) { 1247 return (row == 0 || col == 0) && !(row == 0 && col == 0); 1248 } 1249 1250 @Override 1251 public String getColumnName(int col) { 1252 return col == 0 ? "*" : "" + col; 1253 } 1254 1255 @Override 1256 public void setValueAt(Object aValue, int row, int col) { 1257 String value = (String) aValue; 1258 if (row == 0) // a column was changed 1259 { 1260 try { 1261 containerLayout.setColumnSpec(col - 1, value); 1262 specsChanged(); 1263 } catch (IllegalArgumentException iae) { 1264 JOptionPane.showMessageDialog(FormEditor.this, 1265 iae.getMessage(), "Invalid Layout", 1266 JOptionPane.ERROR_MESSAGE); 1267 } 1268 } else if (col == 0) { 1269 try { 1270 containerLayout.setRowSpec(row - 1, value); 1271 specsChanged(); 1272 } catch (Exception e) { 1273 JOptionPane.showMessageDialog(null, e.getMessage(), 1274 "Invalid row specification", 1275 JOptionPane.ERROR_MESSAGE); 1276 } 1277 } 1278 } 1279 1280 @Override 1281 public Object getValueAt(int rowIndex, int columnIndex) { 1282 if (rowIndex == 0 && columnIndex == 0) { 1283 return null; 1284 } 1285 if (rowIndex == 0) { 1286 return containerLayout.getColumnSpec(columnIndex - 1); 1287 } 1288 if (columnIndex == 0) { 1289 return containerLayout.getRowSpec(rowIndex - 1); 1290 } 1291 1292 Component component = null; 1293 1294 for (int index = 0; index < container 1295 .getComponentCount(); index++) { 1296 Component thisComponent = container.getComponent(index); 1297 // we don't want to show invisible components. we 1298 // have decided to make components that are added without 1299 // constraints invisible until they are dropped onto the form. 1300 // this is our way of hiding them. 1301 if (thisComponent.isVisible()) { 1302 CellConstraints constraints = getComponentConstraints( 1303 thisComponent); 1304 if (constraints == null) { 1305 throw new RuntimeException( 1306 "Unable to find constraints for component " 1307 + thisComponent + " in layout " 1308 + containerLayout.getName()); 1309 } 1310 if (columnIndex >= constraints.gridX 1311 && columnIndex < constraints.gridX 1312 + constraints.gridWidth 1313 && rowIndex >= constraints.gridY 1314 && rowIndex < constraints.gridY 1315 + constraints.gridHeight) { 1316 component = thisComponent; 1317 if (component == topComponent) { 1318 break; 1319 } 1320 } 1321 } 1322 } 1323 1324 return component; 1325 } 1326 } 1327 1328 private class RemoveComponentAction extends AbstractAction { 1329 public RemoveComponentAction() { 1330 super(); 1331 putValue(Action.SHORT_DESCRIPTION, "Remove the component (Alt+D)"); 1332 putValue(Action.LONG_DESCRIPTION, "Remove the component (Alt+D)"); 1333 putValue(Action.SMALL_ICON, new ImageIcon( 1334 FormEditor.class.getResource("Remove24.gif"))); 1335 putValue(Action.ACCELERATOR_KEY, KeyStroke 1336 .getKeyStroke(KeyEvent.VK_D, InputEvent.CTRL_MASK)); 1337 } 1338 1339 @Override 1340 public void actionPerformed(ActionEvent e) { 1341 Component selectedControl = table.getSelectedControl(); 1342 String controlName = getComponentName(selectedControl); 1343 container.remove(selectedControl); 1344 tableModel.fireTableDataChanged(); 1345 1346 if (selectedControl instanceof Container 1347 && layoutFrame.hasContainer(controlName)) { 1348 layoutFrame.removeContainer(controlName); 1349 } 1350 container.doLayout(); 1351 container.repaint(); 1352 componentSelectionListModel.fireDelete(); 1353 1354 setFormComponent(null); 1355 table.requestFocus(); 1356 } 1357 } 1358 1359 private class NewComponentAction extends AbstractAction { 1360 public NewComponentAction() { 1361 super(); 1362 putValue(Action.SHORT_DESCRIPTION, 1363 "Create a new component (Alt+N)"); 1364 putValue(Action.LONG_DESCRIPTION, "Create a new component (Alt+N)"); 1365 putValue(Action.SMALL_ICON, 1366 new ImageIcon(FormEditor.class.getResource("New24.gif"))); 1367 putValue(Action.MNEMONIC_KEY, Integer.valueOf(KeyEvent.VK_N)); 1368 } 1369 1370 @Override 1371 public void actionPerformed(ActionEvent e) { 1372 Frame frame = (Frame) SwingUtilities.getAncestorOfClass(Frame.class, 1373 FormEditor.this); 1374 1375 NewComponentDialog0 newComponentDialog = null; 1376 int columnIndex = table.getSelectedColumn(); 1377 int rowIndex = table.getSelectedRow(); 1378 1379 try { 1380 newComponentDialog = new NewComponentDialog0(frame); 1381 newComponentDialog.setVisible(true); 1382 } catch (Exception ex) { 1383 ex.printStackTrace(); 1384 } 1385 1386 if (newComponentDialog.wasSuccessful()) { 1387 String controlName = newComponentDialog.getComponentName(); 1388 Component newControl = newComponentDialog.getComponent(); 1389 ComponentDef newCD = newComponentDialog.getComponentDef(); 1390 1391 if (containerLayout.getCellConstraints(controlName) != null) { 1392 JOptionPane.showMessageDialog(FormEditor.this, 1393 "A component named '" + controlName 1394 + "' already exists", 1395 "Error", JOptionPane.ERROR_MESSAGE); 1396 } else { 1397 // the best way to add this control is to setup the constraints 1398 // in the map of name->constraints and then add it to the container. 1399 // this layout manager will intercept it, find the constraints and 1400 // then 1401 // set it up properly in the table and assign the maps. 1402 CellConstraints newConstraints = new CellConstraints( 1403 columnIndex, rowIndex); 1404 if (newCD != null) { 1405 containerLayout.addComponent(controlName, newCD, 1406 newConstraints); 1407 } 1408 containerLayout.getCellConstraints().put(controlName, 1409 newConstraints); 1410 container.add(newControl, controlName); 1411 1412 // we need to keep track of the new components added so we can present 1413 // some code to the user to add back into their module. 1414 // newComponents.put(controlName, 1415 // newComponentDialog.getComponentDeclaration()); 1416 1417 // if it's a panel, let's add it to the LayoutFrame so it can be 1418 // manipulated too... 1419 if (newComponentDialog.isUsingLayoutComponent()) { 1420 Container newContainer = (Container) newControl; 1421 layoutFrame.addContainer(controlName, newContainer); 1422 } 1423 1424 componentSelectionListModel.fireInsert(); 1425 1426 table.changeSelection(newConstraints.gridY, 1427 newConstraints.gridX, false, false); 1428 updateLayout(newControl); // relayout preview 1429 updateLayouts(); // relayout all panels 1430 1431 newComponents.add(newControl); // we're not generating code unless this happens 1432 } 1433 } 1434 1435 table.requestFocus(); 1436 } 1437 } 1438 1439 private class InsertRowBeforeAction extends AbstractAction { 1440 public InsertRowBeforeAction() { 1441 super(); 1442 putValue(Action.SHORT_DESCRIPTION, 1443 "Inserts a row before the selected row"); 1444 putValue(Action.LONG_DESCRIPTION, 1445 "Inserts a row before the selected row"); 1446 putValue(Action.SMALL_ICON, new ImageIcon( 1447 FormEditor.class.getResource("RowInsertBefore24.gif"))); 1448 putValue(Action.MNEMONIC_KEY, Integer.valueOf(KeyEvent.VK_I)); 1449 } 1450 1451 @Override 1452 public void actionPerformed(ActionEvent e) { 1453 int row = table.getSelectedRow(); 1454 insertRow(row - 1); 1455 table.requestFocus(); 1456 } 1457 } 1458 1459 private class InsertRowAfterAction extends AbstractAction { 1460 public InsertRowAfterAction() { 1461 super(); 1462 putValue(Action.SHORT_DESCRIPTION, 1463 "Inserts a row after the selected row"); 1464 putValue(Action.LONG_DESCRIPTION, 1465 "Inserts a row after the selected row"); 1466 putValue(Action.SMALL_ICON, new ImageIcon( 1467 FormEditor.class.getResource("RowInsertAfter24.gif"))); 1468 putValue(Action.MNEMONIC_KEY, Integer.valueOf(KeyEvent.VK_O)); 1469 } 1470 1471 @Override 1472 public void actionPerformed(ActionEvent e) { 1473 int row = table.getSelectedRow(); 1474 insertRow(row); 1475 table.requestFocus(); 1476 } 1477 } 1478 1479 private class InsertColumnBeforeAction extends AbstractAction { 1480 public InsertColumnBeforeAction() { 1481 super(); 1482 putValue(Action.SHORT_DESCRIPTION, 1483 "Inserts a column before the selected column"); 1484 putValue(Action.LONG_DESCRIPTION, 1485 "Inserts a column before the selected column"); 1486 putValue(Action.SMALL_ICON, new ImageIcon( 1487 FormEditor.class.getResource("ColumnInsertBefore24.gif"))); 1488 putValue(Action.MNEMONIC_KEY, Integer.valueOf(KeyEvent.VK_K)); 1489 } 1490 1491 @Override 1492 public void actionPerformed(ActionEvent e) { 1493 int column = table.getSelectedColumn(); 1494 insertColumn(column - 1); 1495 table.requestFocus(); 1496 } 1497 } 1498 1499 private class InsertColumnAfterAction extends AbstractAction { 1500 public InsertColumnAfterAction() { 1501 super(); 1502 putValue(Action.SHORT_DESCRIPTION, 1503 "Inserts a column after the selected column"); 1504 putValue(Action.LONG_DESCRIPTION, 1505 "Inserts a column after the selected column"); 1506 putValue(Action.SMALL_ICON, new ImageIcon( 1507 FormEditor.class.getResource("ColumnInsertAfter24.gif"))); 1508 putValue(Action.MNEMONIC_KEY, Integer.valueOf(KeyEvent.VK_L)); 1509 } 1510 1511 @Override 1512 public void actionPerformed(ActionEvent e) { 1513 int column = table.getSelectedColumn(); 1514 insertColumn(column); 1515 table.requestFocus(); 1516 } 1517 } 1518 1519 private class DeleteRowAction extends AbstractAction { 1520 public DeleteRowAction() { 1521 super(); 1522 putValue(Action.SHORT_DESCRIPTION, "Deletes the selected row"); 1523 putValue(Action.LONG_DESCRIPTION, "Deletes the selected row"); 1524 putValue(Action.SMALL_ICON, new ImageIcon( 1525 FormEditor.class.getResource("RowDelete24.gif"))); 1526 putValue(Action.MNEMONIC_KEY, Integer.valueOf(KeyEvent.VK_D)); 1527 } 1528 1529 @Override 1530 public void actionPerformed(ActionEvent e) { 1531 int rowIndex = table.getSelectedRow(); 1532 1533 // move any components that are on the deleted row or 1534 // above it down one 1535 for (int index = 0; index < container 1536 .getComponentCount(); index++) { 1537 Component component = container.getComponent(index); 1538 CellConstraints constraints = getComponentConstraints( 1539 component); 1540 1541 if (constraints.gridY >= rowIndex && constraints.gridY > 1) { 1542 constraints.gridY--; 1543 } else { 1544 // if the row deleted was within the span of the component and the 1545 // component 1546 // is bigger than one cell... 1547 if (constraints.gridY + constraints.gridHeight 1548 - 1 >= rowIndex && constraints.gridHeight > 1) { 1549 constraints.gridHeight--; 1550 } 1551 } 1552 } 1553 1554 containerLayout.removeRowSpec(rowIndex - 1); 1555 1556 tableModel.fireTableRowsDeleted(rowIndex, rowIndex); 1557 table.changeSelection( 1558 Math.min(rowIndex, containerLayout.getRowCount()), 0, false, 1559 false); 1560 specsChanged(); 1561 table.requestFocus(); 1562 } 1563 } 1564 1565 private class DeleteColumnAction extends AbstractAction { 1566 public DeleteColumnAction() { 1567 super(); 1568 putValue(Action.SHORT_DESCRIPTION, "Deletes the selected column"); 1569 putValue(Action.LONG_DESCRIPTION, "Deletes the selected column"); 1570 putValue(Action.SMALL_ICON, new ImageIcon( 1571 FormEditor.class.getResource("ColumnDelete24.gif"))); 1572 putValue(Action.MNEMONIC_KEY, Integer.valueOf(KeyEvent.VK_C)); 1573 } 1574 1575 @Override 1576 public void actionPerformed(ActionEvent e) { 1577 int columnIndex = table.getSelectedColumn(); 1578 1579 for (int index = 0; index < container 1580 .getComponentCount(); index++) { 1581 Component component = container.getComponent(index); 1582 CellConstraints constraints = getComponentConstraints( 1583 component); 1584 1585 if (constraints.gridX >= columnIndex && constraints.gridX > 1) { 1586 constraints.gridX--; 1587 } else { 1588 // if the col deleted was within the span of the component and the 1589 // component 1590 // is bigger than one cell... 1591 if (constraints.gridX + constraints.gridWidth 1592 - 1 >= columnIndex && constraints.gridWidth > 1) { 1593 constraints.gridWidth--; 1594 } 1595 } 1596 } 1597 1598 containerLayout.removeColumnSpec(columnIndex - 1); 1599 tableModel.fireTableStructureChanged(); 1600 table.changeSelection(0, 1601 Math.min(columnIndex, containerLayout.getColumnCount()), 1602 false, false); 1603 specsChanged(); 1604 table.requestFocus(); 1605 } 1606 } 1607 1608 class ComponentPaletteListModel extends AbstractListModel { 1609 List<ComponentDef> componentDefs = ComponentDef.createComponentDefs(); 1610 1611 @Override 1612 public int getSize() { 1613 return componentDefs.size(); 1614 } 1615 1616 @Override 1617 public Object getElementAt(int index) { 1618 return componentDefs.get(index); 1619 } 1620 } 1621 1622 class ComponentPaletteListRenderer extends JLabel 1623 implements ListCellRenderer { 1624 public ComponentPaletteListRenderer() { 1625 setOpaque(true); 1626 } 1627 1628 /* 1629 * This method finds the image and text corresponding to the selected value 1630 * and returns the label, set up to display the text and image. 1631 */ 1632 @Override 1633 public Component getListCellRendererComponent(JList list, Object value, 1634 int index, boolean isSelected, boolean cellHasFocus) { 1635 ComponentDef componentDef = (ComponentDef) value; 1636 setIcon(componentDef.icon != null ? componentDef.icon : null); 1637 setText(componentDef.name); 1638 if (isSelected) { 1639 setBackground(list.getSelectionBackground()); 1640 setForeground(list.getSelectionForeground()); 1641 } else { 1642 setBackground(list.getBackground()); 1643 setForeground(list.getForeground()); 1644 } 1645 return this; 1646 } 1647 } 1648 1649 public void updateList() { 1650 componentSelectionListModel.fireInsert(); 1651 } 1652 1653 public String uniqueName(String name, Component comp) { 1654 // insure the component name doesn't collide 1655 1656 String newname = name; 1657 int suffix = 1; 1658 for (;;) { 1659 Component temp = containerLayout.getComponentByName(newname); 1660 // no such component, or found component was ourself, stop the search 1661 if (temp == null || temp == comp) { 1662 break; // exitloop 1663 } 1664 1665 newname = name + "_" + suffix; 1666 suffix++; 1667 } 1668 return newname; 1669 } 1670 1671 public boolean editComponent(ComponentDef componentDef, Component component, 1672 CellConstraints cellConstraints) { 1673 if (componentDef.isContainer) { 1674 return false; //punt! 1675 } 1676 1677 // get original name for remove 1678 String name = getComponentName(component); 1679 1680 NewComponentDialog dlg = NewComponentDialog 1681 .editDialog((JFrame) layoutFrame, componentDef); 1682 if (!dlg.succeeded()) { 1683 return false; 1684 } 1685 1686 componentDef.name = uniqueName(dlg.getComponentName(), component); 1687 String newname = componentDef.name; 1688 1689 Component newcomponent = dlg.getInstance(); 1690 containerLayout.removeLayoutComponent(component); 1691 containerLayout.addComponent(newname, componentDef, cellConstraints); 1692 1693 container.remove(component); 1694 container.add(newcomponent, newname); 1695 1696 newComponents.remove(component); 1697 newComponents.add(newcomponent); 1698 1699 if (componentDef.isContainer) { 1700 /** @todo losing components INSIDE the container!! */ 1701 // layoutFrame.replaceContainer(name, newName, (Container) newcomponent); 1702 layoutFrame.removeContainer(name); 1703 layoutFrame.addContainer(newname, (Container) newcomponent); 1704 } 1705 1706 updateLayout(newcomponent); 1707 updateList(); 1708 updateLayouts(); 1709 repaint(); 1710 return true; 1711 } 1712}