001/* A panel for editing the layout of a customizable run control panel. 002 003 Copyright (c) 2007-2018 The Regents of the University of California. 004 All rights reserved. 005 Permission is hereby granted, without written agreement and without 006 license or royalty fees, to use, copy, modify, and distribute this 007 software and its documentation for any purpose, provided that the above 008 copyright notice and the following two paragraphs appear in all copies 009 of this software. 010 011 IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY 012 FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES 013 ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF 014 THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF 015 SUCH DAMAGE. 016 017 THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES, 018 INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 019 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE 020 PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF 021 CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, 022 ENHANCEMENTS, OR MODIFICATIONS. 023 024 PT_COPYRIGHT_VERSION_2 025 COPYRIGHTENDKEY 026 027 This class is based on FormEditor by Michael Connor, which 028 bears the following copyright: 029 030 * Copyright (c) 2004-2018 by Michael Connor. All Rights Reserved. 031 * 032 * Redistribution and use in source and binary forms, with or without 033 * modification, are permitted provided that the following conditions are met: 034 * 035 * o Redistributions of source code must retain the above copyright notice, 036 * this list of conditions and the following disclaimer. 037 * 038 * o Redistributions in binary form must reproduce the above copyright notice, 039 * this list of conditions and the following disclaimer in the documentation 040 * and/or other materials provided with the distribution. 041 * 042 * o Neither the name of FormLayoutBuilder or Michael Connor nor the names of 043 * its contributors may be used to endorse or promote products derived 044 * from this software without specific prior written permission. 045 * 046 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 047 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 048 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 049 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 050 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 051 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 052 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 053 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 054 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 055 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 056 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 057 */ 058package ptolemy.actor.gui.run; 059 060import java.awt.BorderLayout; 061import java.awt.Color; 062import java.awt.Component; 063import java.awt.Container; 064import java.awt.Insets; 065import java.awt.Point; 066import java.awt.Rectangle; 067import java.awt.Window; 068import java.awt.event.ActionEvent; 069import java.awt.event.ActionListener; 070import java.awt.event.KeyEvent; 071import java.awt.event.MouseAdapter; 072import java.awt.event.MouseEvent; 073import java.beans.BeanInfo; 074import java.beans.Introspector; 075import java.beans.PropertyDescriptor; 076import java.io.IOException; 077import java.lang.reflect.Method; 078import java.util.HashMap; 079import java.util.HashSet; 080import java.util.Iterator; 081import java.util.LinkedList; 082import java.util.List; 083import java.util.Map; 084import java.util.Set; 085 086import javax.swing.AbstractAction; 087import javax.swing.AbstractListModel; 088import javax.swing.AbstractSpinnerModel; 089import javax.swing.Action; 090import javax.swing.ImageIcon; 091import javax.swing.JButton; 092import javax.swing.JComboBox; 093import javax.swing.JLabel; 094import javax.swing.JList; 095import javax.swing.JOptionPane; 096import javax.swing.JPanel; 097import javax.swing.JScrollPane; 098import javax.swing.JSpinner; 099import javax.swing.JSplitPane; 100import javax.swing.JTable; 101import javax.swing.JToolBar; 102import javax.swing.JViewport; 103import javax.swing.KeyStroke; 104import javax.swing.ListCellRenderer; 105import javax.swing.ListSelectionModel; 106import javax.swing.SpinnerNumberModel; 107import javax.swing.event.ChangeEvent; 108import javax.swing.event.ChangeListener; 109import javax.swing.table.DefaultTableCellRenderer; 110 111import org.mlc.swing.layout.ContainerLayout; 112import org.mlc.swing.layout.FormEditor; 113import org.mlc.swing.layout.LayoutConstraintsManager; 114 115import com.jgoodies.forms.factories.Borders; 116import com.jgoodies.forms.factories.DefaultComponentFactory; 117import com.jgoodies.forms.layout.CellConstraints; 118 119import ptolemy.actor.gui.Placeable; 120import ptolemy.actor.injection.PortablePlaceable; 121import ptolemy.gui.ComponentDialog; 122import ptolemy.gui.Query; 123import ptolemy.kernel.util.NamedObj; 124import ptolemy.util.FileUtilities; 125 126/////////////////////////////////////////////////////////////////// 127//// PtolemyFormEditor 128 129/** 130A customized version of the FormEditor class by 131Michael Connor (mlconnor@yahoo.com). 132 133@see FormEditor 134@author Michael Connor and Edward A. Lee 135@version $Id$ 136@since Ptolemy II 8.0 137@Pt.ProposedRating Yellow (eal) 138@Pt.AcceptedRating Red (cxh) 139 */ 140@SuppressWarnings("serial") 141public class PtolemyFormEditor extends JPanel { 142 143 /** Construct a new form editor. 144 * @param layoutFrame The frame within which this editor will be added. 145 * @param layout The layout manager. 146 * @param container The container. 147 */ 148 public PtolemyFormEditor(RunLayoutFrame layoutFrame, ContainerLayout layout, 149 Container container) { 150 super(); 151 _layoutFrame = layoutFrame; 152 153 // Create the layout table. 154 _table = new LayoutTable(_layoutFrame, this); 155 JScrollPane tableScrollPane = new JScrollPane(_table); 156 157 // Create the component palette for this Ptolemy model. 158 ComponentPaletteListModel componentPaletteListModel = new ComponentPaletteListModel(); 159 PaletteList componentPalette = new PaletteList(this, 160 componentPaletteListModel); 161 JScrollPane componentPaletteScrollPane = new JScrollPane( 162 componentPalette); 163 164 JPanel propertiesPanel = new JPanel(); 165 166 _container = container; 167 _containerLayout = layout; 168 169 _table.setBackground(java.awt.Color.white); 170 _table.setSelectionBackground(new Color(220, 220, 255)); 171 _table.setSelectionForeground(Color.black); 172 173 _table.setDefaultRenderer(Object.class, 174 new ConstraintTableCellRenderer()); 175 _table.setRowHeight(20); 176 _table.setModel(_tableModel); 177 _table.setCellSelectionEnabled(true); 178 _table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); 179 180 JLabel verticalAlignmentLabel = new JLabel("Vertical Alignment"); 181 verticalAlignmentLabel.setLabelFor(_verticalAlignmentCombo); 182 verticalAlignmentLabel.setDisplayedMnemonic(KeyEvent.VK_V); 183 184 JLabel horizontalAlignmentLabel = new JLabel("Horizontal Alignment"); 185 horizontalAlignmentLabel.setLabelFor(_horizontalAlignmentCombo); 186 horizontalAlignmentLabel.setDisplayedMnemonic(KeyEvent.VK_H); 187 188 JLabel columnSpanLabel = new JLabel("Column Span"); 189 columnSpanLabel.setLabelFor(_columnSpanSpinner); 190 columnSpanLabel.setDisplayedMnemonic(KeyEvent.VK_C); 191 192 JLabel rowSpanLabel = new JLabel("Row Span"); 193 rowSpanLabel.setLabelFor(_rowSpanSpinner); 194 rowSpanLabel.setDisplayedMnemonic(KeyEvent.VK_R); 195 196 _columnInsertAfterButton 197 .setToolTipText("Insert a column after this column"); 198 _columnInsertBeforeButton 199 .setToolTipText("Insert a column before this column"); 200 _columnDeleteButton.setToolTipText("Delete this column"); 201 _rowInsertBeforeButton.setToolTipText("Insert a row before this row"); 202 _rowInsertAfterButton.setToolTipText("Insert a row after this row"); 203 204 JToolBar toolbar = new JToolBar(); 205 toolbar.add(_removeComponentButton); 206 toolbar.addSeparator(); 207 toolbar.add(_columnDeleteButton); 208 toolbar.add(_columnInsertBeforeButton); 209 toolbar.add(_columnInsertAfterButton); 210 toolbar.addSeparator(); 211 toolbar.add(_rowDeleteButton); 212 toolbar.add(_rowInsertBeforeButton); 213 toolbar.add(_rowInsertAfterButton); 214 toolbar.addSeparator(); 215 toolbar.add(_packAction); 216 217 // Specify that no component is selected. 218 setFormComponent(null); 219 220 LayoutConstraintsManager layoutConstraintsManager = LayoutConstraintsManager 221 .getLayoutConstraintsManager( 222 this.getClass().getClassLoader().getResourceAsStream( 223 "/ptolemy/actor/gui/run/editableLayoutConstraints.xml")); 224 225 JPanel insetsPanel = new JPanel(); 226 JPanel contentPanel = new JPanel(); 227 228 layoutConstraintsManager.setLayout("mainLayout", contentPanel); 229 layoutConstraintsManager.setLayout("insetsLayout", insetsPanel); 230 layoutConstraintsManager.setLayout("propertiesLayout", propertiesPanel); 231 232 insetsPanel.add(_rightInsetSpinner, "rightInsetSpinner"); 233 insetsPanel.add(_leftInsetSpinner, "leftInsetSpinner"); 234 insetsPanel.add(_topInsetSpinner, "topInsetSpinner"); 235 insetsPanel.add(_bottomInsetSpinner, "bottomInsetSpinner"); 236 237 propertiesPanel.add(componentPaletteScrollPane, 238 "componentPaletteScrollPane"); 239 componentPalette.setCellRenderer(new ComponentPaletteListRenderer()); 240 JLabel componentPaletteLabel = new JLabel("Palette"); 241 propertiesPanel.add(componentPaletteLabel, "componentPaletteLabel"); 242 243 contentPanel.add(rowSpanLabel, "rowSpanLabel"); 244 contentPanel.add(_horizontalAlignmentCombo, "horizontalAlignmentCombo"); 245 contentPanel.add(horizontalAlignmentLabel, "horizontalAlignmentLabel"); 246 contentPanel.add(_rowSpanSpinner, "rowSpanSpinner"); 247 contentPanel.add(_verticalAlignmentCombo, "verticalAlignmentCombo"); 248 contentPanel.add(columnSpanLabel, "columnSpanLabel"); 249 contentPanel.add(verticalAlignmentLabel, "verticalAlignmentLabel"); 250 contentPanel.add(_columnSpanSpinner, "columnSpanSpinner"); 251 contentPanel.add(insetsPanel, "insetsPanel"); 252 JLabel insetsLabel = new JLabel("Insets"); 253 contentPanel.add(insetsLabel, "insetsLabel"); 254 Component constraintsSeparator = DefaultComponentFactory.getInstance() 255 .createSeparator("Component Constraints"); 256 contentPanel.add(constraintsSeparator, "constraintsSeparator"); 257 Component positionsSeparator = DefaultComponentFactory.getInstance() 258 .createSeparator("Component Positions"); 259 contentPanel.add(positionsSeparator, "positionsSeparator"); 260 contentPanel.add(toolbar, "toolbar"); 261 262 // Put the layout table and palette side-by-side. 263 JSplitPane constraintsSplitPane = new JSplitPane( 264 JSplitPane.HORIZONTAL_SPLIT, tableScrollPane, propertiesPanel); 265 contentPanel.add(constraintsSplitPane, "constraintsSplitPane"); 266 // The following would make the palette invisible! 267 // constraintsSplitPane.setDividerLocation(605); 268 269 contentPanel.setBorder(Borders.DIALOG_BORDER); 270 271 setLayout(new BorderLayout()); 272 add(contentPanel, BorderLayout.CENTER); 273 274 _setupListeners(); 275 } 276 277 /////////////////////////////////////////////////////////////////// 278 //// public methods //// 279 280 /** Edit the component by presenting a dialog that infers the 281 * settable properties of the components. 282 * @param component The component. 283 * @return true upon successful completion. 284 */ 285 public boolean editComponent(Component component) { 286 String name = _containerLayout.getComponentName(component); 287 Query query = new Query(); 288 try { 289 BeanInfo beanInfo = Introspector.getBeanInfo(component.getClass()); 290 PropertyDescriptor[] props = beanInfo.getPropertyDescriptors(); 291 Map<String, String> previousValues = new HashMap<String, String>(); 292 for (PropertyDescriptor propertyDescriptor : props) { 293 // Present String and Color-valued properties. 294 if (propertyDescriptor.getPropertyType() == String.class) { 295 String propertyName = propertyDescriptor.getName(); 296 if (_propertiesToIgnore.contains(propertyName)) { 297 continue; 298 } 299 Method readMethod = propertyDescriptor.getReadMethod(); 300 String value = (String) readMethod.invoke(component, 301 new Object[] {}); 302 query.addLine(propertyName, propertyName, value); 303 previousValues.put(propertyName, value); 304 } else if (propertyDescriptor 305 .getPropertyType() == Color.class) { 306 String propertyName = propertyDescriptor.getName(); 307 Method readMethod = propertyDescriptor.getReadMethod(); 308 Color value = (Color) readMethod.invoke(component, 309 new Object[] {}); 310 float[] components = value.getRGBComponents(null); 311 StringBuffer string = new StringBuffer("{"); 312 // Use the syntax of arrays to present the color. 313 for (int j = 0; j < components.length; j++) { 314 string.append(components[j]); 315 if (j < components.length - 1) { 316 string.append(","); 317 } else { 318 string.append("}"); 319 } 320 } 321 query.addColorChooser(propertyName, propertyName, 322 string.toString()); 323 previousValues.put(propertyName, string.toString()); 324 } 325 } 326 ComponentDialog dialog = new ComponentDialog(_layoutFrame, name, 327 query); 328 if (dialog.buttonPressed().equals("OK")) { 329 // Set each property that has changed. 330 for (PropertyDescriptor propertyDescriptor : props) { 331 // Present String and Color-valued properties. 332 if (propertyDescriptor.getPropertyType() == String.class) { 333 String propertyName = propertyDescriptor.getName(); 334 if (_propertiesToIgnore.contains(propertyName)) { 335 continue; 336 } 337 String newValue = query.getStringValue(propertyName); 338 if (!newValue 339 .equals(previousValues.get(propertyName))) { 340 Method writeMethod = propertyDescriptor 341 .getWriteMethod(); 342 writeMethod.invoke(component, 343 new Object[] { newValue }); 344 _containerLayout.setProperty(name, propertyName, 345 newValue); 346 } 347 } else if (propertyDescriptor 348 .getPropertyType() == Color.class) { 349 String propertyName = propertyDescriptor.getName(); 350 String newValue = query.getStringValue(propertyName); 351 Color newColor = Query.stringToColor(newValue); 352 if (!newValue 353 .equals(previousValues.get(propertyName))) { 354 Method writeMethod = propertyDescriptor 355 .getWriteMethod(); 356 writeMethod.invoke(component, 357 new Object[] { newColor }); 358 _containerLayout.setProperty(name, propertyName, 359 newColor); 360 } 361 } 362 } 363 } 364 } catch (Throwable throwable) { 365 // FIXME Auto-generated catch block 366 throwable.printStackTrace(); 367 } 368 369 /* FIXME 370 * 371 372 NewComponentDialog dlg = NewComponentDialog.editDialog( 373 (JFrame) _layoutFrame, componentDef); 374 if (!dlg.succeeded()) 375 return false; 376 377 componentDef.name = uniqueName(dlg.getComponentName(), component); 378 String newname = componentDef.name; 379 380 Component newcomponent = dlg.getInstance(); 381 containerLayout.removeLayoutComponent(component); 382 containerLayout.addComponent(newname, componentDef, cellConstraints); 383 384 container.remove(component); 385 container.add(newcomponent, newname); 386 387 newComponents.remove(component); 388 newComponents.add(newcomponent); 389 390 if (componentDef.isContainer) { 391 // @todo losing components INSIDE the container!! 392 //layoutFrame.replaceContainer(name, newName, (Container) newcomponent); 393 layoutFrame.removeContainer(name); 394 layoutFrame.addContainer(newname, (Container) newcomponent); 395 } 396 397 updateLayout(newcomponent); 398 _updateList(); 399 */ 400 _updateLayouts(); 401 repaint(); 402 return true; 403 } 404 405 /** Specify the selected component. This causes the various 406 * constraints controls for the component to be enabled and 407 * to show the current values for the component. 408 * @param component The selected component. 409 */ 410 public void setFormComponent(Component component) { 411 CellConstraints constraints = component != null 412 ? _getComponentConstraints(component) 413 : null; 414 415 _suspendConstraintControlUpdates = true; 416 417 if (component != null) { 418 _rowSpanSpinnerModel.setComponent(component); 419 _columnSpanSpinnerModel.setComponent(component); 420 _verticalAlignmentCombo.setSelectedItem( 421 LayoutConstraintsManager.getAlignment(constraints.vAlign)); 422 _horizontalAlignmentCombo.setSelectedItem( 423 LayoutConstraintsManager.getAlignment(constraints.hAlign)); 424 _topInsetSpinnerModel 425 .setValue(Integer.valueOf(constraints.insets.top)); 426 _bottomInsetSpinnerModel 427 .setValue(Integer.valueOf(constraints.insets.bottom)); 428 _rightInsetSpinnerModel 429 .setValue(Integer.valueOf(constraints.insets.right)); 430 _leftInsetSpinnerModel 431 .setValue(Integer.valueOf(constraints.insets.left)); 432 } 433 434 _verticalAlignmentCombo.setEnabled(constraints != null); 435 _horizontalAlignmentCombo.setEnabled(constraints != null); 436 _rightInsetSpinner.setEnabled(constraints != null); 437 _leftInsetSpinner.setEnabled(constraints != null); 438 _topInsetSpinner.setEnabled(constraints != null); 439 _bottomInsetSpinner.setEnabled(constraints != null); 440 _rowSpanSpinner.setEnabled(constraints != null); 441 _columnSpanSpinner.setEnabled(constraints != null); 442 443 int col = _table.getSelectedColumn(); 444 int row = _table.getSelectedRow(); 445 446 _removeComponentAction.setEnabled(constraints != null); 447 _columnDeleteButton.setEnabled( 448 row == 0 && col > 0 && _containerLayout.getColumnCount() > 1); 449 _columnInsertAfterButton.setEnabled(col > -1); 450 _columnInsertBeforeButton.setEnabled(col > 0); 451 _rowDeleteButton.setEnabled( 452 col == 0 && row > 0 && _containerLayout.getRowCount() > 1); 453 _rowInsertBeforeButton.setEnabled(row > 0); 454 _rowInsertAfterButton.setEnabled(row > -1); 455 456 _suspendConstraintControlUpdates = false; 457 } 458 459 /** Update the layout for the specified component. 460 * @param component The component to have its layout updated. 461 */ 462 public void updateLayout(Component component) { 463 if (_suspendConstraintControlUpdates) { 464 return; 465 } 466 CellConstraints constraints = _getComponentConstraints(component); 467 468 // we have to update the _containerLayout which is the keeper of all 469 // constraints. if we didn't do this then we wouldn't notice any changes 470 // when we went to print everything out. 471 String name = _getComponentName(component); 472 // i don't like this direct access thing. this should be changed... 473 _containerLayout.setCellConstraints(name, constraints); 474 // updateForm(); 475 476 // be careful when modifying the next few lines of code. this 477 // is tricky to get right. this seems to work. 478 _container.invalidate(); 479 _container.doLayout(); 480 481 // KBR list (for example) doesn't seem to re-layout properly on drag&drop 482 // without these 483 _container.validate(); 484 _container.repaint(); 485 486 if (component instanceof Container) { 487 Container cContainer = (Container) component; 488 cContainer.invalidate(); 489 cContainer.doLayout(); 490 } 491 } 492 493 /////////////////////////////////////////////////////////////////// 494 //// protected methods //// 495 496 /** Update the layouts. */ 497 protected void _updateLayouts() { 498 _container.validate(); 499 _container.doLayout(); 500 501 Container parent = _container; 502 503 while (parent != null) { 504 parent.validate(); 505 if (parent instanceof Window) { 506 // Packing has the unfortunate 507 // side effect of centering on the 508 // screen, which is annoying... 509 // ((Window)parent).pack(); 510 parent.setVisible(true); 511 } 512 parent = parent.getParent(); 513 } 514 } 515 516 /////////////////////////////////////////////////////////////////// 517 //// private methods //// 518 519 /** Return the component constraints from the layout manager. 520 * @param component The component. 521 * @return The constraints. 522 */ 523 private CellConstraints _getComponentConstraints(Component component) { 524 return _containerLayout.getComponentConstraints(component); 525 } 526 527 /** Return the name of the specified component as known by the layout 528 * controller. 529 * @param control The component. 530 * @return The name of the component in the layout. 531 */ 532 private String _getComponentName(Component control) { 533 return _containerLayout.getComponentName(control); 534 } 535 536 /** Insert a column. 537 * @param column The column index. 538 */ 539 private void _insertColumn(int column) { 540 for (int index = 0; index < _container.getComponentCount(); index++) { 541 Component component = _container.getComponent(index); 542 CellConstraints constraints = _getComponentConstraints(component); 543 if (constraints.gridX > column) { 544 constraints.gridX++; 545 } 546 } 547 548 try { 549 _containerLayout.addColumnSpec(column, "pref"); 550 _tableModel.fireTableStructureChanged(); 551 _setSelectedCell(column + 1, 0, true); 552 _specsChanged(); 553 } catch (IllegalArgumentException iae) { 554 // FIXME: Use our error reporting. 555 JOptionPane.showMessageDialog(PtolemyFormEditor.this, 556 iae.getMessage(), "Invalid Layout", 557 JOptionPane.ERROR_MESSAGE); 558 } 559 } 560 561 /** Insert a row. 562 * @param rowIndex The row index. 563 */ 564 private void _insertRow(int rowIndex) { 565 for (int index = 0; index < _container.getComponentCount(); index++) { 566 Component component = _container.getComponent(index); 567 CellConstraints constraints = _getComponentConstraints(component); 568 if (constraints.gridY > rowIndex) { 569 constraints.gridY++; 570 } 571 } 572 573 try { 574 _containerLayout.addRowSpec(rowIndex, "pref"); 575 _tableModel.fireTableStructureChanged(); 576 _setSelectedCell(0, rowIndex + 1, true); 577 _specsChanged(); 578 } catch (IllegalArgumentException iae) { 579 // FIXME: Use our error reporting. 580 JOptionPane.showMessageDialog(PtolemyFormEditor.this, 581 iae.getMessage(), "Invalid Layout", 582 JOptionPane.ERROR_MESSAGE); 583 } 584 } 585 586 /** Put an icon onto an AbstractAction. */ 587 private void _putValue(AbstractAction abstractAction, String iconName) { 588 String iconDirectory = "$CLASSPATH/ptolemy/actor/gui/run/"; 589 try { 590 // We use nameToURL() here so that this code will work 591 // in webstart. 592 // FIXME: we should use rollover icons like what is in 593 // vergil.basic.BasicGraphFrame, where we call 594 // diva.util.GUIUtilities. 595 abstractAction.putValue(Action.SMALL_ICON, 596 new ImageIcon(FileUtilities 597 .nameToURL(iconDirectory + iconName, null, null))); 598 } catch (IOException ex) { 599 System.out.println("Failed to open " + iconDirectory + iconName); 600 ex.printStackTrace(); 601 } 602 } 603 604 /** Specify the cell in the table that is selected. */ 605 private void _setSelectedCell(int columnIndex, int rowIndex, 606 boolean forceVisible) { 607 // we don't want to update the selection interval if nothing changed... 608 _table.getSelectionModel().setSelectionInterval(rowIndex, rowIndex); 609 _table.getColumnModel().getSelectionModel() 610 .setSelectionInterval(columnIndex, columnIndex); 611 612 if (forceVisible) { 613 // let's make sure the cell is in the visible range... 614 JViewport viewport = (JViewport) _table.getParent(); 615 Rectangle rect = _table.getCellRect(rowIndex, columnIndex, true); 616 Point pt = viewport.getViewPosition(); 617 rect.setLocation(rect.x - pt.x, rect.y - pt.y); 618 viewport.scrollRectToVisible(rect); 619 } 620 } 621 622 /** Set up the listeners. */ 623 private void _setupListeners() { 624 _verticalAlignmentCombo.addActionListener(new ActionListener() { 625 @Override 626 public void actionPerformed(ActionEvent e) { 627 Component component = _table.getSelectedControl(); 628 if (component != null) { 629 CellConstraints cellConstraints = _getComponentConstraints( 630 component); 631 cellConstraints.vAlign = LayoutConstraintsManager 632 .getAlignment((String) _verticalAlignmentCombo 633 .getSelectedItem()); 634 updateLayout(component); 635 } 636 } 637 }); 638 _horizontalAlignmentCombo.addActionListener(new ActionListener() { 639 @Override 640 public void actionPerformed(ActionEvent e) { 641 Component component = _table.getSelectedControl(); 642 if (component != null) { 643 CellConstraints cellConstraints = _getComponentConstraints( 644 component); 645 cellConstraints.hAlign = LayoutConstraintsManager 646 .getAlignment((String) _horizontalAlignmentCombo 647 .getSelectedItem()); 648 updateLayout(component); 649 } 650 } 651 }); 652 _topInsetSpinnerModel.addChangeListener(new ChangeListener() { 653 @Override 654 public void stateChanged(ChangeEvent e) { 655 if (!_suspendConstraintControlUpdates) { 656 Component component = _table.getSelectedControl(); 657 CellConstraints constraints = _getComponentConstraints( 658 component); 659 Insets insets = new Insets( 660 _topInsetSpinnerModel.getNumber().intValue(), 661 constraints.insets.left, constraints.insets.bottom, 662 constraints.insets.right); 663 constraints.insets = insets; 664 updateLayout(component); 665 } 666 } 667 }); 668 _leftInsetSpinnerModel.addChangeListener(new ChangeListener() { 669 @Override 670 public void stateChanged(ChangeEvent e) { 671 if (!_suspendConstraintControlUpdates) { 672 Component component = _table.getSelectedControl(); 673 CellConstraints constraints = _getComponentConstraints( 674 component); 675 Insets insets = new Insets(constraints.insets.top, 676 _leftInsetSpinnerModel.getNumber().intValue(), 677 constraints.insets.bottom, 678 constraints.insets.right); 679 constraints.insets = insets; 680 updateLayout(component); 681 } 682 } 683 }); 684 _rightInsetSpinnerModel.addChangeListener(new ChangeListener() { 685 @Override 686 public void stateChanged(ChangeEvent e) { 687 if (!_suspendConstraintControlUpdates) { 688 Component component = _table.getSelectedControl(); 689 CellConstraints constraints = _getComponentConstraints( 690 component); 691 Insets insets = new Insets(constraints.insets.top, 692 constraints.insets.left, constraints.insets.bottom, 693 _rightInsetSpinnerModel.getNumber().intValue()); 694 constraints.insets = insets; 695 updateLayout(component); 696 } 697 } 698 }); 699 _bottomInsetSpinnerModel.addChangeListener(new ChangeListener() { 700 @Override 701 public void stateChanged(ChangeEvent e) { 702 if (!_suspendConstraintControlUpdates) { 703 Component component = _table.getSelectedControl(); 704 CellConstraints constraints = _getComponentConstraints( 705 component); 706 Insets insets = new Insets(constraints.insets.top, 707 constraints.insets.left, 708 _bottomInsetSpinnerModel.getNumber().intValue(), 709 constraints.insets.right); 710 constraints.insets = insets; 711 updateLayout(component); 712 } 713 } 714 }); 715 _table.addMouseListener(new MouseAdapter() { 716 @Override 717 public void mouseClicked(MouseEvent e) { 718 if (e.getClickCount() == 2) { 719 //Point p = e.getPoint(); 720 //int row = _table.rowAtPoint(p); 721 //int col = _table.columnAtPoint(p); 722 // support double-click: 723 Component component = _table.getSelectedControl(); 724 if (component == null) { 725 return; 726 } 727 728 /* invoke componentDef editor on double-clicked control */ 729 //String name = _getComponentName(component); 730 editComponent(component); 731 } 732 } 733 }); 734 } 735 736 /** Specify that the specifications have changed. */ 737 private void _specsChanged() { 738 _updateLayouts(); 739 740 // lets go down the tree 741 Component[] children = _container.getComponents(); 742 for (Component component : children) { 743 if (component instanceof Container) { 744 ((Container) component).doLayout(); 745 } 746 } 747 } 748 749 /////////////////////////////////////////////////////////////////// 750 //// inner classes //// 751 752 /** Model for the column span control. */ 753 private class ColSpanSpinnerModel extends AbstractSpinnerModel { 754 CellConstraints constraints; 755 756 Component component; 757 758 public ColSpanSpinnerModel() { 759 } 760 761 public void setComponent(Component component) { 762 this.component = component; 763 if (component != null) { 764 constraints = _getComponentConstraints(component); 765 fireStateChanged(); 766 } else { 767 constraints = null; 768 } 769 } 770 771 @Override 772 public Object getNextValue() { 773 if (constraints == null) { 774 return null; 775 } 776 Integer next = constraints.gridX + constraints.gridWidth 777 - 1 < _containerLayout.getColumnCount() 778 ? Integer.valueOf(constraints.gridWidth + 1) 779 : null; 780 return next; 781 } 782 783 @Override 784 public Object getPreviousValue() { 785 if (constraints == null) { 786 return null; 787 } else { 788 Integer previous = constraints.gridWidth > 1 789 ? Integer.valueOf(constraints.gridWidth - 1) 790 : null; 791 return previous; 792 } 793 } 794 795 @Override 796 public Object getValue() { 797 if (constraints == null) { 798 return ""; 799 } else { 800 return Integer.valueOf(constraints.gridWidth); 801 } 802 } 803 804 @Override 805 public void setValue(Object value) { 806 if (constraints == null || value == null) { 807 return; 808 } 809 810 constraints.gridWidth = ((Number) value).intValue(); 811 super.fireStateChanged(); 812 updateLayout(component); 813 814 // firing _table data changed messes up the 815 // selection so we'll get it and then restore it... 816 int col = _table.getSelectedColumn(); 817 int row = _table.getSelectedRow(); 818 _tableModel.fireTableDataChanged(); 819 _setSelectedCell(col, row, true); 820 } 821 } 822 823 /** Model for the palette. */ 824 private class ComponentPaletteListModel extends AbstractListModel { 825 List<String> components = new LinkedList<String>(); 826 827 public ComponentPaletteListModel() { 828 // FIXME: The text of the following buttons can in theory be customized. 829 // How to provide the interface for that? 830 components.add("GoButton"); 831 components.add("PauseButton"); 832 components.add("ResumeButton"); 833 components.add("StopButton"); 834 835 components.add("ConfigureTopLevel"); 836 components.add("ConfigureDirector"); 837 838 components.add("Label"); 839 840 // Iterate over all the components that implement Placeable. 841 if (_layoutFrame._pane._model != null) { 842 Iterator atomicEntities = _layoutFrame._pane._model 843 .allAtomicEntityList().iterator(); 844 while (atomicEntities.hasNext()) { 845 NamedObj object = (NamedObj) atomicEntities.next(); 846 if (object instanceof Placeable 847 || object instanceof PortablePlaceable) { 848 components.add("Placeable:" 849 + object.getName(_layoutFrame._pane._model)); 850 } 851 } 852 } 853 854 // FIXME: Do we need to be able to customize the name? 855 components.add("Subpanel:Subpanel"); 856 857 // FIXME: This isn't useful without being able to specify the entity. 858 components.add("Configure:Entity"); 859 } 860 861 @Override 862 public int getSize() { 863 return components.size(); 864 } 865 866 @Override 867 public Object getElementAt(int index) { 868 return components.get(index); 869 } 870 } 871 872 /** Renderer for the palette items. */ 873 private static class ComponentPaletteListRenderer extends JLabel 874 implements ListCellRenderer { 875 // FindBugs suggests making this class static so as to decrease 876 // the size of instances and avoid dangling references. 877 878 public ComponentPaletteListRenderer() { 879 setOpaque(true); 880 } 881 882 @Override 883 public Component getListCellRendererComponent(JList list, Object value, 884 int index, boolean isSelected, boolean cellHasFocus) { 885 setText(value.toString()); 886 if (isSelected) { 887 setBackground(list.getSelectionBackground()); 888 setForeground(list.getSelectionForeground()); 889 } else { 890 setBackground(list.getBackground()); 891 setForeground(list.getForeground()); 892 } 893 return this; 894 } 895 } 896 897 /** Renderer for table cells. */ 898 private class ConstraintTableCellRenderer extends DefaultTableCellRenderer { 899 @Override 900 public Component getTableCellRendererComponent(JTable table, 901 Object value, boolean isSelected, boolean hasFocus, int row, 902 int column) { 903 String stringValue = null; 904 if (value != null) { 905 if (value instanceof Component) { 906 String name = _getComponentName((Component) value); 907 stringValue = name == null ? "(Untitled)" : name; 908 } else { 909 // in this case it's a row or col header 910 stringValue = (String) value; 911 } 912 } 913 914 return super.getTableCellRendererComponent(table, stringValue, 915 isSelected, hasFocus, row, column); 916 } 917 } 918 919 /** Action to delete a column. */ 920 private class DeleteColumnAction extends AbstractAction { 921 public DeleteColumnAction() { 922 super(); 923 putValue(Action.SHORT_DESCRIPTION, "Deletes the selected column"); 924 putValue(Action.LONG_DESCRIPTION, "Deletes the selected column"); 925 _putValue(this, "ColumnDelete24.gif"); 926 putValue(Action.MNEMONIC_KEY, Integer.valueOf(KeyEvent.VK_C)); 927 } 928 929 @Override 930 public void actionPerformed(ActionEvent e) { 931 int columnIndex = _table.getSelectedColumn(); 932 for (int index = 0; index < _container 933 .getComponentCount(); index++) { 934 Component component = _container.getComponent(index); 935 CellConstraints constraints = _getComponentConstraints( 936 component); 937 if (constraints.gridX >= columnIndex && constraints.gridX > 1) { 938 constraints.gridX--; 939 } else { 940 // if the col deleted was within the span of the component and the 941 // component 942 // is bigger than one cell... 943 if (constraints.gridX + constraints.gridWidth 944 - 1 >= columnIndex && constraints.gridWidth > 1) { 945 constraints.gridWidth--; 946 } 947 } 948 } 949 _containerLayout.removeColumnSpec(columnIndex - 1); 950 _tableModel.fireTableStructureChanged(); 951 _table.changeSelection(0, 952 Math.min(columnIndex, _containerLayout.getColumnCount()), 953 false, false); 954 _specsChanged(); 955 _table.requestFocus(); 956 } 957 } 958 959 /** Action to delete a row. */ 960 private class DeleteRowAction extends AbstractAction { 961 public DeleteRowAction() { 962 super(); 963 putValue(Action.SHORT_DESCRIPTION, "Deletes the selected row"); 964 putValue(Action.LONG_DESCRIPTION, "Deletes the selected row"); 965 _putValue(this, "RowDelete24.gif"); 966 putValue(Action.MNEMONIC_KEY, Integer.valueOf(KeyEvent.VK_D)); 967 } 968 969 @Override 970 public void actionPerformed(ActionEvent e) { 971 int rowIndex = _table.getSelectedRow(); 972 973 // move any components that are on the deleted row or 974 // above it down one 975 for (int index = 0; index < _container 976 .getComponentCount(); index++) { 977 Component component = _container.getComponent(index); 978 CellConstraints constraints = _getComponentConstraints( 979 component); 980 981 if (constraints.gridY >= rowIndex && constraints.gridY > 1) { 982 constraints.gridY--; 983 } else { 984 // if the row deleted was within the span of the component and the 985 // component 986 // is bigger than one cell... 987 if (constraints.gridY + constraints.gridHeight 988 - 1 >= rowIndex && constraints.gridHeight > 1) { 989 constraints.gridHeight--; 990 } 991 } 992 } 993 _containerLayout.removeRowSpec(rowIndex - 1); 994 _tableModel.fireTableRowsDeleted(rowIndex, rowIndex); 995 _table.changeSelection( 996 Math.min(rowIndex, _containerLayout.getRowCount()), 0, 997 false, false); 998 _specsChanged(); 999 _table.requestFocus(); 1000 } 1001 } 1002 1003 /** The data model for the table. */ 1004 private class GridTableModel extends javax.swing.table.AbstractTableModel { 1005 @Override 1006 public int getColumnCount() { 1007 return _containerLayout != null 1008 ? _containerLayout.getColumnCount() + 1 1009 : 1; 1010 } 1011 1012 @Override 1013 public int getRowCount() { 1014 return _containerLayout != null ? _containerLayout.getRowCount() + 1 1015 : 1; 1016 } 1017 1018 @Override 1019 public boolean isCellEditable(int row, int col) { 1020 return (row == 0 || col == 0) && !(row == 0 && col == 0); 1021 } 1022 1023 @Override 1024 public String getColumnName(int col) { 1025 return col == 0 ? "*" : "" + col; 1026 } 1027 1028 @Override 1029 public void setValueAt(Object aValue, int row, int col) { 1030 String value = (String) aValue; 1031 if (row == 0) { 1032 // a column was changed 1033 try { 1034 _containerLayout.setColumnSpec(col - 1, value); 1035 _specsChanged(); 1036 } catch (IllegalArgumentException iae) { 1037 JOptionPane.showMessageDialog(PtolemyFormEditor.this, 1038 iae.getMessage(), "Invalid Layout", 1039 JOptionPane.ERROR_MESSAGE); 1040 } 1041 } else if (col == 0) { 1042 try { 1043 _containerLayout.setRowSpec(row - 1, value); 1044 _specsChanged(); 1045 } catch (Exception e) { 1046 JOptionPane.showMessageDialog(null, e.getMessage(), 1047 "Invalid row specification", 1048 JOptionPane.ERROR_MESSAGE); 1049 } 1050 } 1051 } 1052 1053 @Override 1054 public Object getValueAt(int rowIndex, int columnIndex) { 1055 if (rowIndex == 0 && columnIndex == 0) { 1056 return null; 1057 } 1058 if (rowIndex == 0) { 1059 return _containerLayout.getColumnSpec(columnIndex - 1); 1060 } 1061 if (columnIndex == 0) { 1062 return _containerLayout.getRowSpec(rowIndex - 1); 1063 } 1064 Component component = null; 1065 for (int index = 0; index < _container 1066 .getComponentCount(); index++) { 1067 Component thisComponent = _container.getComponent(index); 1068 // we don't want to show invisible components. we 1069 // have decided to make components that are added without 1070 // constraints invisible until they are dropped onto the form. 1071 // this is our way of hiding them. 1072 if (thisComponent.isVisible()) { 1073 CellConstraints constraints = _getComponentConstraints( 1074 thisComponent); 1075 if (constraints == null) { 1076 throw new RuntimeException( 1077 "Unable to find constraints for component " 1078 + thisComponent + " in layout " 1079 + _containerLayout.getName()); 1080 } 1081 if (columnIndex >= constraints.gridX 1082 && columnIndex < constraints.gridX 1083 + constraints.gridWidth 1084 && rowIndex >= constraints.gridY 1085 && rowIndex < constraints.gridY 1086 + constraints.gridHeight) { 1087 component = thisComponent; 1088 if (component == topComponent) { 1089 break; 1090 } 1091 } 1092 } 1093 } 1094 return component; 1095 } 1096 } 1097 1098 /** Action to insert a column after the selected column. */ 1099 private class InsertColumnAfterAction extends AbstractAction { 1100 public InsertColumnAfterAction() { 1101 super(); 1102 putValue(Action.SHORT_DESCRIPTION, 1103 "Inserts a column after the selected column"); 1104 putValue(Action.LONG_DESCRIPTION, 1105 "Inserts a column after the selected column"); 1106 _putValue(this, "ColumnInsertAfter24.gif"); 1107 putValue(Action.MNEMONIC_KEY, Integer.valueOf(KeyEvent.VK_L)); 1108 } 1109 1110 @Override 1111 public void actionPerformed(ActionEvent e) { 1112 int column = _table.getSelectedColumn(); 1113 _insertColumn(column); 1114 _table.requestFocus(); 1115 } 1116 } 1117 1118 /** Action to insert a column before the selected column. */ 1119 private class InsertColumnBeforeAction extends AbstractAction { 1120 public InsertColumnBeforeAction() { 1121 super(); 1122 putValue(Action.SHORT_DESCRIPTION, 1123 "Inserts a column before the selected column"); 1124 putValue(Action.LONG_DESCRIPTION, 1125 "Inserts a column before the selected column"); 1126 _putValue(this, "ColumnInsertBefore24.gif"); 1127 putValue(Action.MNEMONIC_KEY, Integer.valueOf(KeyEvent.VK_K)); 1128 } 1129 1130 @Override 1131 public void actionPerformed(ActionEvent e) { 1132 int column = _table.getSelectedColumn(); 1133 _insertColumn(column - 1); 1134 _table.requestFocus(); 1135 } 1136 } 1137 1138 /** Action to insert a row after the selected one. */ 1139 private class InsertRowAfterAction extends AbstractAction { 1140 public InsertRowAfterAction() { 1141 super(); 1142 putValue(Action.SHORT_DESCRIPTION, 1143 "Inserts a row after the selected row"); 1144 putValue(Action.LONG_DESCRIPTION, 1145 "Inserts a row after the selected row"); 1146 _putValue(this, "RowInsertAfter24.gif"); 1147 putValue(Action.MNEMONIC_KEY, Integer.valueOf(KeyEvent.VK_O)); 1148 } 1149 1150 @Override 1151 public void actionPerformed(ActionEvent e) { 1152 int row = _table.getSelectedRow(); 1153 _insertRow(row); 1154 _table.requestFocus(); 1155 } 1156 } 1157 1158 /** Action to insert a row before the selected one. */ 1159 private class InsertRowBeforeAction extends AbstractAction { 1160 public InsertRowBeforeAction() { 1161 super(); 1162 putValue(Action.SHORT_DESCRIPTION, 1163 "Inserts a row before the selected row"); 1164 putValue(Action.LONG_DESCRIPTION, 1165 "Inserts a row before the selected row"); 1166 _putValue(this, "RowInsertBefore24.gif"); 1167 putValue(Action.MNEMONIC_KEY, Integer.valueOf(KeyEvent.VK_I)); 1168 } 1169 1170 @Override 1171 public void actionPerformed(ActionEvent e) { 1172 int row = _table.getSelectedRow(); 1173 _insertRow(row - 1); 1174 _table.requestFocus(); 1175 } 1176 } 1177 1178 /** Action to pack the run control panel. */ 1179 private class PackAction extends AbstractAction { 1180 public PackAction() { 1181 super(); 1182 putValue(Action.SHORT_DESCRIPTION, "Pack the run control panel"); 1183 putValue(Action.LONG_DESCRIPTION, "Pack the run control panel"); 1184 _putValue(this, "Pack.gif"); 1185 putValue(Action.ACCELERATOR_KEY, 1186 KeyStroke.getKeyStroke(KeyEvent.VK_P, 0)); 1187 putValue(Action.MNEMONIC_KEY, Integer.valueOf(KeyEvent.VK_P)); 1188 } 1189 1190 @Override 1191 public void actionPerformed(ActionEvent e) { 1192 _container.validate(); 1193 _container.doLayout(); 1194 1195 Container parent = _container; 1196 1197 while (parent != null) { 1198 parent.validate(); 1199 if (parent instanceof Window) { 1200 ((Window) parent).pack(); 1201 parent.setVisible(true); 1202 } 1203 parent = parent.getParent(); 1204 } 1205 } 1206 } 1207 1208 /** Action to remove a component. */ 1209 private class RemoveComponentAction extends AbstractAction { 1210 public RemoveComponentAction() { 1211 super(); 1212 putValue(Action.SHORT_DESCRIPTION, "Delete the component"); 1213 putValue(Action.LONG_DESCRIPTION, "Delete the selected component. " 1214 + "A component must be selected for this to be enabled."); 1215 _putValue(this, "Remove24.gif"); 1216 putValue(Action.ACCELERATOR_KEY, 1217 KeyStroke.getKeyStroke(KeyEvent.VK_DELETE, 0)); 1218 putValue(Action.MNEMONIC_KEY, Integer.valueOf(KeyEvent.VK_D)); 1219 } 1220 1221 @Override 1222 public void actionPerformed(ActionEvent e) { 1223 Component selectedControl = _table.getSelectedControl(); 1224 String controlName = _getComponentName(selectedControl); 1225 _container.remove(selectedControl); 1226 _tableModel.fireTableDataChanged(); 1227 1228 if (selectedControl instanceof Container 1229 && _layoutFrame.hasContainer(controlName)) { 1230 _layoutFrame.removeContainer(controlName); 1231 } 1232 _container.doLayout(); 1233 _container.repaint(); 1234 setFormComponent(null); 1235 _table.requestFocus(); 1236 } 1237 } 1238 1239 /** Model for the row span control. */ 1240 private class RowSpanSpinnerModel extends AbstractSpinnerModel { 1241 CellConstraints constraints; 1242 1243 Component component; 1244 1245 public RowSpanSpinnerModel() { 1246 } 1247 1248 public void setComponent(Component component) { 1249 this.component = component; 1250 if (component != null) { 1251 constraints = _getComponentConstraints(component); 1252 fireStateChanged(); 1253 } else { 1254 constraints = null; 1255 } 1256 } 1257 1258 @Override 1259 public Object getNextValue() { 1260 if (constraints == null) { 1261 return null; 1262 } else { 1263 Integer next = constraints.gridY + constraints.gridHeight 1264 - 1 < _containerLayout.getRowCount() 1265 ? Integer.valueOf(constraints.gridHeight + 1) 1266 : null; 1267 return next; 1268 } 1269 } 1270 1271 @Override 1272 public Object getPreviousValue() { 1273 if (constraints == null) { 1274 return null; 1275 } else { 1276 Integer previous = constraints.gridHeight > 1 1277 ? Integer.valueOf(constraints.gridHeight - 1) 1278 : null; 1279 return previous; 1280 } 1281 } 1282 1283 @Override 1284 public Object getValue() { 1285 if (constraints == null) { 1286 return ""; 1287 } else { 1288 return Integer.valueOf(constraints.gridHeight); 1289 } 1290 } 1291 1292 @Override 1293 public void setValue(Object value) { 1294 if (constraints == null || value == null) { 1295 return; 1296 } 1297 // Number val = (Number) value; 1298 constraints.gridHeight = ((Number) value).intValue(); 1299 super.fireStateChanged(); 1300 updateLayout(component); 1301 1302 // firing _table data changed messes up the 1303 // selection so we'll get it and then restore it... 1304 int col = _table.getSelectedColumn(); 1305 int row = _table.getSelectedRow(); 1306 _tableModel.fireTableDataChanged(); 1307 _setSelectedCell(col, row, true); 1308 } 1309 } 1310 1311 /////////////////////////////////////////////////////////////////// 1312 //// protected variables //// 1313 1314 /** The layout manager. */ 1315 protected ContainerLayout _containerLayout; 1316 1317 /** The container. */ 1318 protected Container _container; 1319 1320 /** The set of new components. */ 1321 protected Set<Component> newComponents = new HashSet<Component>(); 1322 1323 /** The top level component. */ 1324 protected Component topComponent = null; 1325 1326 /////////////////////////////////////////////////////////////////// 1327 //// private variables //// 1328 1329 /** Model for the bottom inset control. */ 1330 private SpinnerNumberModel _bottomInsetSpinnerModel = new SpinnerNumberModel( 1331 0, 0, Integer.MAX_VALUE, 1); 1332 1333 /** The bottom inset control. */ 1334 private JSpinner _bottomInsetSpinner = new JSpinner( 1335 _bottomInsetSpinnerModel); 1336 1337 /** The button to delete a column. */ 1338 private JButton _columnDeleteButton = new JButton(new DeleteColumnAction()); 1339 1340 /** The button to insert after the selected column. */ 1341 private JButton _columnInsertAfterButton = new JButton( 1342 new InsertColumnAfterAction()); 1343 1344 /** The button to insert before the selected column. */ 1345 private JButton _columnInsertBeforeButton = new JButton( 1346 new InsertColumnBeforeAction()); 1347 1348 /** The model for the column span control. */ 1349 private ColSpanSpinnerModel _columnSpanSpinnerModel = new ColSpanSpinnerModel(); 1350 1351 /** The column span control. */ 1352 private JSpinner _columnSpanSpinner = new JSpinner(_columnSpanSpinnerModel); 1353 1354 /** The list of horizontal alignment options. */ 1355 private String[] _horizontalAlignmentList = { 1356 LayoutConstraintsManager.DEFAULT, LayoutConstraintsManager.FILL, 1357 LayoutConstraintsManager.CENTER, LayoutConstraintsManager.LEFT, 1358 LayoutConstraintsManager.RIGHT }; 1359 1360 /** The horizontal alignment control. */ 1361 private JComboBox _horizontalAlignmentCombo = new JComboBox( 1362 _horizontalAlignmentList); 1363 1364 /** The layout frame. */ 1365 private RunLayoutFrame _layoutFrame; 1366 1367 /** Model for the left inset control. */ 1368 private SpinnerNumberModel _leftInsetSpinnerModel = new SpinnerNumberModel( 1369 0, 0, Integer.MAX_VALUE, 1); 1370 1371 /** The left inset control. */ 1372 private JSpinner _leftInsetSpinner = new JSpinner(_leftInsetSpinnerModel); 1373 1374 /** Action to pack the run control window. */ 1375 private Action _packAction = new PackAction(); 1376 1377 /** Button to pack the run control window. */ 1378 //private JButton _packButton = new JButton(_packAction); 1379 /** Properties to ignore and not present to the user. */ 1380 private static Set<String> _propertiesToIgnore = new HashSet<String>(); 1381 static { 1382 _propertiesToIgnore.add("actionCommand"); 1383 _propertiesToIgnore.add("name"); 1384 _propertiesToIgnore.add("UIClassID"); 1385 } 1386 1387 /** Action to remove a component. */ 1388 private Action _removeComponentAction = new RemoveComponentAction(); 1389 1390 /** Button to remove a component. */ 1391 private JButton _removeComponentButton = new JButton( 1392 _removeComponentAction); 1393 1394 /** Model for the right inset control. */ 1395 private SpinnerNumberModel _rightInsetSpinnerModel = new SpinnerNumberModel( 1396 0, 0, Integer.MAX_VALUE, 1); 1397 1398 /** The right inset control. */ 1399 private JSpinner _rightInsetSpinner = new JSpinner(_rightInsetSpinnerModel); 1400 1401 /** The button to delete a row. */ 1402 private JButton _rowDeleteButton = new JButton(new DeleteRowAction()); 1403 1404 /** The button to insert a row after the selected one. */ 1405 private JButton _rowInsertAfterButton = new JButton( 1406 new InsertRowAfterAction()); 1407 1408 /** The button to insert a row before the selected one. */ 1409 private JButton _rowInsertBeforeButton = new JButton( 1410 new InsertRowBeforeAction()); 1411 1412 /** The model for the row span control. */ 1413 private RowSpanSpinnerModel _rowSpanSpinnerModel = new RowSpanSpinnerModel(); 1414 1415 /** The row span control. */ 1416 private JSpinner _rowSpanSpinner = new JSpinner(_rowSpanSpinnerModel); 1417 1418 /** Flag to suspend updates. */ 1419 private boolean _suspendConstraintControlUpdates = false; 1420 1421 /** The layout table, built in the constructor. */ 1422 private LayoutTable _table = null; 1423 1424 /** The data model for the table. */ 1425 private GridTableModel _tableModel = new GridTableModel(); 1426 1427 /** Model for the top inset control. */ 1428 private SpinnerNumberModel _topInsetSpinnerModel = new SpinnerNumberModel(0, 1429 0, Integer.MAX_VALUE, 1); 1430 1431 /** The top inset control. */ 1432 private JSpinner _topInsetSpinner = new JSpinner(_topInsetSpinnerModel); 1433 1434 /** The list of vertical alignment options. */ 1435 private String[] _verticalAlignmentList = { 1436 LayoutConstraintsManager.DEFAULT, LayoutConstraintsManager.FILL, 1437 LayoutConstraintsManager.CENTER, LayoutConstraintsManager.TOP, 1438 LayoutConstraintsManager.BOTTOM }; 1439 1440 /** The vertical alignment control. */ 1441 private JComboBox _verticalAlignmentCombo = new JComboBox( 1442 _verticalAlignmentList); 1443}