001 /* 002 $Id: SwingBuilder.java,v 1.13 2005/06/10 09:55:30 cstein Exp $ 003 004 Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved. 005 006 Redistribution and use of this software and associated documentation 007 ("Software"), with or without modification, are permitted provided 008 that the following conditions are met: 009 010 1. Redistributions of source code must retain copyright 011 statements and notices. Redistributions must also contain a 012 copy of this document. 013 014 2. Redistributions in binary form must reproduce the 015 above copyright notice, this list of conditions and the 016 following disclaimer in the documentation and/or other 017 materials provided with the distribution. 018 019 3. The name "groovy" must not be used to endorse or promote 020 products derived from this Software without prior written 021 permission of The Codehaus. For written permission, 022 please contact info@codehaus.org. 023 024 4. Products derived from this Software may not be called "groovy" 025 nor may "groovy" appear in their names without prior written 026 permission of The Codehaus. "groovy" is a registered 027 trademark of The Codehaus. 028 029 5. Due credit should be given to The Codehaus - 030 http://groovy.codehaus.org/ 031 032 THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS 033 ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT 034 NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 035 FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 036 THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 037 INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 038 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 039 SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 040 HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 041 STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 042 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 043 OF THE POSSIBILITY OF SUCH DAMAGE. 044 045 */ 046 package groovy.swing; 047 048 import groovy.lang.Closure; 049 import groovy.lang.MissingMethodException; 050 051 import groovy.model.DefaultTableModel; 052 import groovy.model.ValueHolder; 053 import groovy.model.ValueModel; 054 055 import groovy.swing.impl.ComponentFacade; 056 import groovy.swing.impl.ContainerFacade; 057 import groovy.swing.impl.DefaultAction; 058 import groovy.swing.impl.Factory; 059 import groovy.swing.impl.Startable; 060 import groovy.swing.impl.TableLayout; 061 import groovy.swing.impl.TableLayoutCell; 062 import groovy.swing.impl.TableLayoutRow; 063 064 import groovy.util.BuilderSupport; 065 066 import java.awt.BorderLayout; 067 import java.awt.CardLayout; 068 import java.awt.Component; 069 import java.awt.Container; 070 import java.awt.Dimension; 071 import java.awt.Dialog; 072 import java.awt.FlowLayout; 073 import java.awt.Frame; 074 import java.awt.GridBagConstraints; 075 import java.awt.GridBagLayout; 076 import java.awt.GridLayout; 077 import java.awt.LayoutManager; 078 import java.awt.Window; 079 080 import java.text.Format; 081 082 import java.util.ArrayList; 083 import java.util.Collections; 084 import java.util.HashMap; 085 import java.util.Iterator; 086 import java.util.LinkedList; 087 import java.util.List; 088 import java.util.Map; 089 import java.util.Vector; 090 import java.util.logging.Level; 091 import java.util.logging.Logger; 092 093 import javax.swing.AbstractButton; 094 import javax.swing.Action; 095 import javax.swing.Box; 096 import javax.swing.BoxLayout; 097 import javax.swing.ButtonGroup; 098 import javax.swing.DefaultBoundedRangeModel; 099 import javax.swing.JButton; 100 import javax.swing.JCheckBox; 101 import javax.swing.JCheckBoxMenuItem; 102 import javax.swing.JColorChooser; 103 import javax.swing.JComboBox; 104 import javax.swing.JComponent; 105 import javax.swing.JDesktopPane; 106 import javax.swing.JDialog; 107 import javax.swing.JEditorPane; 108 import javax.swing.JFileChooser; 109 import javax.swing.JFormattedTextField; 110 import javax.swing.JFrame; 111 import javax.swing.JInternalFrame; 112 import javax.swing.JLabel; 113 import javax.swing.JLayeredPane; 114 import javax.swing.JList; 115 import javax.swing.JMenu; 116 import javax.swing.JMenuBar; 117 import javax.swing.JMenuItem; 118 import javax.swing.JOptionPane; 119 import javax.swing.JPanel; 120 import javax.swing.JPasswordField; 121 import javax.swing.JPopupMenu; 122 import javax.swing.JProgressBar; 123 import javax.swing.JRadioButton; 124 import javax.swing.JRadioButtonMenuItem; 125 import javax.swing.JScrollBar; 126 import javax.swing.JScrollPane; 127 import javax.swing.JSeparator; 128 import javax.swing.JSlider; 129 import javax.swing.JSpinner; 130 import javax.swing.JSplitPane; 131 import javax.swing.JTabbedPane; 132 import javax.swing.JTable; 133 import javax.swing.JTextArea; 134 import javax.swing.JTextField; 135 import javax.swing.JTextPane; 136 import javax.swing.JToggleButton; 137 import javax.swing.JToolBar; 138 import javax.swing.JToolTip; 139 import javax.swing.JTree; 140 import javax.swing.JViewport; 141 import javax.swing.JWindow; 142 import javax.swing.KeyStroke; 143 import javax.swing.OverlayLayout; 144 import javax.swing.RootPaneContainer; 145 import javax.swing.SpinnerDateModel; 146 import javax.swing.SpinnerListModel; 147 import javax.swing.SpinnerNumberModel; 148 import javax.swing.SpringLayout; 149 import javax.swing.table.TableColumn; 150 import javax.swing.table.TableModel; 151 152 import org.codehaus.groovy.runtime.InvokerHelper; 153 154 /** 155 * A helper class for creating Swing widgets using GroovyMarkup 156 * 157 * @author <a href="mailto:james@coredevelopers.net">James Strachan</a> 158 * @version $Revision: 1.13 $ 159 */ 160 public class SwingBuilder extends BuilderSupport { 161 162 private Logger log = Logger.getLogger(getClass().getName()); 163 private Map factories = new HashMap(); 164 private Object constraints; 165 private Map passThroughNodes = new HashMap(); 166 private Map widgets = new HashMap(); 167 // tracks all containing windows, for auto-owned dialogs 168 private LinkedList containingWindows = new LinkedList(); 169 170 public SwingBuilder() { 171 registerWidgets(); 172 } 173 174 public Object getProperty(String name) { 175 Object widget = widgets.get(name); 176 if (widget == null) { 177 return super.getProperty(name); 178 } 179 return widget; 180 } 181 182 protected void setParent(Object parent, Object child) { 183 if (child instanceof Action) { 184 Action action = (Action) child; 185 try { 186 InvokerHelper.setProperty(parent, "action", action); 187 } catch (RuntimeException re) { 188 // must not have an action property... 189 // so we ignore it and go on 190 } 191 Object keyStroke = action.getValue("KeyStroke"); 192 //System.out.println("keystroke: " + keyStroke + " for: " + action); 193 if (parent instanceof JComponent) { 194 JComponent component = (JComponent) parent; 195 KeyStroke stroke = null; 196 if (keyStroke instanceof String) { 197 stroke = KeyStroke.getKeyStroke((String) keyStroke); 198 } 199 else if (keyStroke instanceof KeyStroke) { 200 stroke = (KeyStroke) keyStroke; 201 } 202 if (stroke != null) { 203 String key = action.toString(); 204 component.getInputMap().put(stroke, key); 205 component.getActionMap().put(key, action); 206 } 207 } 208 } 209 else if (child instanceof LayoutManager) { 210 if (parent instanceof RootPaneContainer) { 211 RootPaneContainer rpc = (RootPaneContainer) parent; 212 parent = rpc.getContentPane(); 213 } 214 InvokerHelper.setProperty(parent, "layout", child); 215 } 216 else if (child instanceof JToolTip && parent instanceof JComponent) { 217 ((JToolTip)child).setComponent((JComponent)parent); 218 } 219 else if (parent instanceof JTable && child instanceof TableColumn) { 220 JTable table = (JTable) parent; 221 TableColumn column = (TableColumn) child; 222 table.addColumn(column); 223 } 224 else if (parent instanceof JTabbedPane && child instanceof Component) { 225 JTabbedPane tabbedPane = (JTabbedPane) parent; 226 tabbedPane.add((Component)child); 227 } 228 else if (child instanceof Window) { 229 // do nothing. owner of window is set elsewhere, and this 230 // shouldn't get added to any parent as a child 231 // if it is a top level component anyway 232 } 233 else { 234 Component component = null; 235 if (child instanceof Component) { 236 component = (Component) child; 237 } 238 else if (child instanceof ComponentFacade) { 239 ComponentFacade facade = (ComponentFacade) child; 240 component = facade.getComponent(); 241 } 242 if (component != null) { 243 if (parent instanceof JFrame && component instanceof JMenuBar) { 244 JFrame frame = (JFrame) parent; 245 frame.setJMenuBar((JMenuBar) component); 246 } 247 else if (parent instanceof RootPaneContainer) { 248 RootPaneContainer rpc = (RootPaneContainer) parent; 249 rpc.getContentPane().add(component); 250 } 251 else if (parent instanceof JScrollPane) { 252 JScrollPane scrollPane = (JScrollPane) parent; 253 if (child instanceof JViewport) { 254 scrollPane.setViewport((JViewport)component); 255 } 256 else { 257 scrollPane.setViewportView(component); 258 } 259 } 260 else if (parent instanceof JSplitPane) { 261 JSplitPane splitPane = (JSplitPane) parent; 262 if (splitPane.getOrientation() == JSplitPane.HORIZONTAL_SPLIT) { 263 if (splitPane.getTopComponent() == null) { 264 splitPane.setTopComponent(component); 265 } 266 else { 267 splitPane.setBottomComponent(component); 268 } 269 } 270 else { 271 if (splitPane.getLeftComponent() == null) { 272 splitPane.setLeftComponent(component); 273 } 274 else { 275 splitPane.setRightComponent(component); 276 } 277 } 278 } 279 else if (parent instanceof JMenuBar && component instanceof JMenu) { 280 JMenuBar menuBar = (JMenuBar) parent; 281 menuBar.add((JMenu) component); 282 } 283 else if (parent instanceof Container) { 284 Container container = (Container) parent; 285 if (constraints != null) { 286 container.add(component, constraints); 287 } 288 else { 289 container.add(component); 290 } 291 } 292 else if (parent instanceof ContainerFacade) { 293 ContainerFacade facade = (ContainerFacade) parent; 294 facade.addComponent(component); 295 } 296 } 297 } 298 } 299 300 protected void nodeCompleted(Object parent, Object node) { 301 // set models after the node has been completed 302 if (node instanceof TableModel && parent instanceof JTable) { 303 JTable table = (JTable) parent; 304 TableModel model = (TableModel) node; 305 table.setModel(model); 306 } 307 if (node instanceof Startable) { 308 Startable startable = (Startable) node; 309 startable.start(); 310 } 311 if (node instanceof Window) { 312 if (!containingWindows.isEmpty() && containingWindows.getLast() == node) { 313 containingWindows.removeLast(); 314 } 315 } 316 } 317 318 protected Object createNode(Object name) { 319 return createNode(name, Collections.EMPTY_MAP); 320 } 321 322 protected Object createNode(Object name, Object value) { 323 if (passThroughNodes.containsKey(name) && (value != null) && ((Class)passThroughNodes.get(name)).isAssignableFrom(value.getClass())) { 324 // value may need to go into containing windows list 325 if (value instanceof Window) { 326 containingWindows.add(value); 327 } 328 return value; 329 } 330 else if (value instanceof String) { 331 Object widget = createNode(name); 332 if (widget != null) { 333 InvokerHelper.invokeMethod(widget, "setText", value); 334 } 335 return widget; 336 } 337 else { 338 throw new MissingMethodException((String) name, getClass(), new Object[] {value}); 339 } 340 } 341 342 protected Object createNode(Object name, Map attributes, Object value) { 343 if (passThroughNodes.containsKey(name) && (value != null) && ((Class)passThroughNodes.get(name)).isAssignableFrom(value.getClass())) { 344 // value may need to go into containing windows list 345 if (value instanceof Window) { 346 containingWindows.add(value); 347 } 348 handleWidgetAttributes(value, attributes); 349 return value; 350 } 351 else { 352 Object widget = createNode(name, attributes); 353 if (widget != null) { 354 InvokerHelper.invokeMethod(widget, "setText", value.toString()); 355 } 356 return widget; 357 } 358 } 359 360 protected Object createNode(Object name, Map attributes) { 361 String widgetName = (String) attributes.remove("id"); 362 constraints = attributes.remove("constraints"); 363 Object widget = null; 364 if (passThroughNodes.containsKey(name)) { 365 widget = attributes.get(name); 366 if ((widget != null) && ((Class)passThroughNodes.get(name)).isAssignableFrom(widget.getClass())) { 367 // value may need to go into containing windows list 368 if (widget instanceof Window) { 369 containingWindows.add(widget); 370 } 371 attributes.remove(name); 372 } 373 else { 374 widget = null; 375 } 376 } 377 if (widget == null) { 378 Factory factory = (Factory) factories.get(name); 379 if (factory != null) { 380 try { 381 widget = factory.newInstance(attributes); 382 if (widgetName != null) { 383 widgets.put(widgetName, widget); 384 } 385 if (widget == null) { 386 log.log(Level.WARNING, "Factory for name: " + name + " returned null"); 387 } 388 else { 389 if (log.isLoggable(Level.FINE)) { 390 log.fine("For name: " + name + " created widget: " + widget); 391 } 392 } 393 } 394 catch (Exception e) { 395 throw new RuntimeException("Failed to create component for" + name + " reason: " + e, e); 396 } 397 } 398 else { 399 log.log(Level.WARNING, "Could not find match for name: " + name); 400 } 401 } 402 handleWidgetAttributes(widget, attributes); 403 return widget; 404 } 405 406 protected void handleWidgetAttributes(Object widget, Map attributes) { 407 if (widget != null) { 408 if (widget instanceof Action) { 409 /** @todo we could move this custom logic into the MetaClass for Action */ 410 Action action = (Action) widget; 411 412 Closure closure = (Closure) attributes.remove("closure"); 413 if (closure != null && action instanceof DefaultAction) { 414 DefaultAction defaultAction = (DefaultAction) action; 415 defaultAction.setClosure(closure); 416 } 417 418 Object accel = attributes.remove("accelerator"); 419 KeyStroke stroke = null; 420 if (accel instanceof KeyStroke) { 421 stroke = (KeyStroke) accel; 422 } else if (accel != null) { 423 stroke = KeyStroke.getKeyStroke(accel.toString()); 424 } 425 action.putValue(Action.ACCELERATOR_KEY, stroke); 426 427 Object mnemonic = attributes.remove("mnemonic"); 428 if ((mnemonic != null) && !(mnemonic instanceof Number)) { 429 mnemonic = new Integer(mnemonic.toString().charAt(0)); 430 } 431 action.putValue(Action.MNEMONIC_KEY, mnemonic); 432 433 for (Iterator iter = attributes.entrySet().iterator(); iter.hasNext();) { 434 Map.Entry entry = (Map.Entry) iter.next(); 435 String actionName = (String) entry.getKey(); 436 437 // typically standard Action names start with upper case, so lets upper case it 438 actionName = capitalize(actionName); 439 Object value = entry.getValue(); 440 441 action.putValue(actionName, value); 442 } 443 444 } 445 else { 446 // some special cases... 447 if (attributes.containsKey("buttonGroup")) { 448 Object o = attributes.get("buttonGroup"); 449 if ((o instanceof ButtonGroup) && (widget instanceof AbstractButton)) { 450 ((AbstractButton)widget).getModel().setGroup((ButtonGroup)o); 451 attributes.remove("buttonGroup"); 452 } 453 } 454 455 // this next statement nd if/else is a workaround until GROOVY-305 is fixed 456 Object mnemonic = attributes.remove("mnemonic"); 457 if ((mnemonic != null) && (mnemonic instanceof Number)) { 458 InvokerHelper.setProperty(widget, "mnemonic", new Character((char)((Number)mnemonic).intValue())); 459 } 460 else if (mnemonic != null) { 461 InvokerHelper.setProperty(widget, "mnemonic", new Character(mnemonic.toString().charAt(0))); 462 } 463 464 // set the properties 465 for (Iterator iter = attributes.entrySet().iterator(); iter.hasNext();) { 466 Map.Entry entry = (Map.Entry) iter.next(); 467 String property = entry.getKey().toString(); 468 Object value = entry.getValue(); 469 InvokerHelper.setProperty(widget, property, value); 470 } 471 } 472 } 473 } 474 475 protected String capitalize(String text) { 476 char ch = text.charAt(0); 477 if (Character.isUpperCase(ch)) { 478 return text; 479 } 480 StringBuffer buffer = new StringBuffer(text.length()); 481 buffer.append(Character.toUpperCase(ch)); 482 buffer.append(text.substring(1)); 483 return buffer.toString(); 484 } 485 486 protected void registerWidgets() { 487 // 488 // non-widget support classes 489 // 490 registerBeanFactory("action", DefaultAction.class); 491 passThroughNodes.put("action", javax.swing.Action.class); 492 registerBeanFactory("buttonGroup", ButtonGroup.class); 493 registerFactory("map", new Factory() { 494 public Object newInstance(Map properties) 495 throws InstantiationException, InstantiationException, IllegalAccessException { 496 return properties; 497 } 498 }); 499 // ulimate pass through type 500 passThroughNodes.put("widget", java.awt.Component.class); 501 502 // 503 // standalone window classes 504 // 505 registerFactory("dialog", new Factory() { 506 public Object newInstance(Map properties) 507 throws InstantiationException, InstantiationException, IllegalAccessException { 508 return createDialog(properties); 509 } 510 }); 511 registerFactory("frame", new Factory() { 512 public Object newInstance(Map properties) 513 throws InstantiationException, InstantiationException, IllegalAccessException { 514 return createFrame(properties); 515 } 516 }); 517 registerBeanFactory("fileChooser", JFileChooser.class); 518 registerFactory("frame", new Factory() { 519 public Object newInstance(Map properties) 520 throws InstantiationException, InstantiationException, IllegalAccessException { 521 return createFrame(properties); 522 } 523 }); 524 registerBeanFactory("optionPane", JOptionPane.class); 525 registerFactory("window", new Factory() { 526 public Object newInstance(Map properties) 527 throws InstantiationException, InstantiationException, IllegalAccessException { 528 return createWindow(properties); 529 } 530 }); 531 532 // 533 // widgets 534 // 535 registerBeanFactory("button", JButton.class); 536 registerBeanFactory("checkBox", JCheckBox.class); 537 registerBeanFactory("checkBoxMenuItem", JCheckBoxMenuItem.class); 538 registerBeanFactory("colorChooser", JColorChooser.class); 539 registerFactory("comboBox", new Factory() { 540 public Object newInstance(Map properties) 541 throws InstantiationException, InstantiationException, IllegalAccessException { 542 return createComboBox(properties); 543 } 544 }); 545 registerBeanFactory("desktopPane", JDesktopPane.class); 546 registerBeanFactory("editorPane", JEditorPane.class); 547 registerFactory("formattedTextField", new Factory() { 548 public Object newInstance(Map properties) 549 throws InstantiationException, InstantiationException, IllegalAccessException { 550 return createFormattedTextField(properties); 551 } 552 }); 553 registerBeanFactory("internalFrame", JInternalFrame.class); 554 registerBeanFactory("label", JLabel.class); 555 registerBeanFactory("layeredPane", JLayeredPane.class); 556 registerBeanFactory("list", JList.class); 557 registerBeanFactory("menu", JMenu.class); 558 registerBeanFactory("menuBar", JMenuBar.class); 559 registerBeanFactory("menuItem", JMenuItem.class); 560 registerBeanFactory("panel", JPanel.class); 561 registerBeanFactory("passwordField", JPasswordField.class); 562 registerBeanFactory("popupMenu", JPopupMenu.class); 563 registerBeanFactory("progressBar", JProgressBar.class); 564 registerBeanFactory("radioButton", JRadioButton.class); 565 registerBeanFactory("radioButtonMenuItem", JRadioButtonMenuItem.class); 566 registerBeanFactory("scrollBar", JScrollBar.class); 567 registerBeanFactory("scrollPane", JScrollPane.class); 568 registerBeanFactory("separator", JSeparator.class); 569 registerBeanFactory("slider", JSlider.class); 570 registerBeanFactory("spinner", JSpinner.class); 571 registerFactory("splitPane", new Factory() { 572 public Object newInstance(Map properties) { 573 JSplitPane answer = new JSplitPane(); 574 answer.setLeftComponent(null); 575 answer.setRightComponent(null); 576 answer.setTopComponent(null); 577 answer.setBottomComponent(null); 578 return answer; 579 } 580 }); 581 registerBeanFactory("tabbedPane", JTabbedPane.class); 582 registerBeanFactory("table", JTable.class); 583 registerBeanFactory("textArea", JTextArea.class); 584 registerBeanFactory("textPane", JTextPane.class); 585 registerBeanFactory("textField", JTextField.class); 586 registerBeanFactory("toggleButton", JToggleButton.class); 587 registerBeanFactory("toolBar", JToolBar.class); 588 //registerBeanFactory("tooltip", JToolTip.class); // doens't work, user toolTipText property 589 registerBeanFactory("tree", JTree.class); 590 registerBeanFactory("viewport", JViewport.class); // sub class? 591 592 // 593 // MVC models 594 // 595 registerBeanFactory("boundedRangeModel", DefaultBoundedRangeModel.class); 596 597 // spinner models 598 registerBeanFactory("spinnerDateModel", SpinnerDateModel.class); 599 registerBeanFactory("spinnerListModel", SpinnerListModel.class); 600 registerBeanFactory("spinnerNumberModel", SpinnerNumberModel.class); 601 602 // table models 603 registerFactory("tableModel", new Factory() { 604 public Object newInstance(Map properties) { 605 ValueModel model = (ValueModel) properties.remove("model"); 606 if (model == null) { 607 Object list = properties.remove("list"); 608 if (list == null) { 609 list = new ArrayList(); 610 } 611 model = new ValueHolder(list); 612 } 613 return new DefaultTableModel(model); 614 } 615 }); 616 passThroughNodes.put("tableModel", javax.swing.table.TableModel.class); 617 618 registerFactory("propertyColumn", new Factory() { 619 public Object newInstance(Map properties) { 620 Object current = getCurrent(); 621 if (current instanceof DefaultTableModel) { 622 DefaultTableModel model = (DefaultTableModel) current; 623 Object header = properties.remove("header"); 624 if (header == null) { 625 header = ""; 626 } 627 String property = (String) properties.remove("propertyName"); 628 if (property == null) { 629 throw new IllegalArgumentException("Must specify a property for a propertyColumn"); 630 } 631 Class type = (Class) properties.remove("type"); 632 if (type == null) { 633 type = Object.class; 634 } 635 return model.addPropertyColumn(header, property, type); 636 } 637 else { 638 throw new RuntimeException("propertyColumn must be a child of a tableModel"); 639 } 640 } 641 }); 642 643 registerFactory("closureColumn", new Factory() { 644 public Object newInstance(Map properties) { 645 Object current = getCurrent(); 646 if (current instanceof DefaultTableModel) { 647 DefaultTableModel model = (DefaultTableModel) current; 648 Object header = properties.remove("header"); 649 if (header == null) { 650 header = ""; 651 } 652 Closure readClosure = (Closure) properties.remove("read"); 653 if (readClosure == null) { 654 throw new IllegalArgumentException("Must specify 'read' Closure property for a closureColumn"); 655 } 656 Closure writeClosure = (Closure) properties.remove("write"); 657 Class type = (Class) properties.remove("type"); 658 if (type == null) { 659 type = Object.class; 660 } 661 return model.addClosureColumn(header, readClosure, writeClosure, type); 662 } 663 else { 664 throw new RuntimeException("propertyColumn must be a child of a tableModel"); 665 } 666 } 667 }); 668 669 670 //Standard Layouts 671 registerBeanFactory("borderLayout", BorderLayout.class); 672 registerBeanFactory("cardLayout", CardLayout.class); 673 registerBeanFactory("flowLayout", FlowLayout.class); 674 registerBeanFactory("gridBagLayout", GridBagLayout.class); 675 registerBeanFactory("gridLayout", GridLayout.class); 676 registerBeanFactory("overlayLayout", OverlayLayout.class); 677 registerBeanFactory("springLayout", SpringLayout.class); 678 registerBeanFactory("gridBagConstarints", GridBagConstraints.class); 679 registerBeanFactory("gbc", GridBagConstraints.class); // shortcut name 680 681 // box layout 682 registerFactory("boxLayout", new Factory() { 683 public Object newInstance(Map properties) 684 throws InstantiationException, InstantiationException, IllegalAccessException { 685 return createBoxLayout(properties); 686 } 687 }); 688 689 // Box related layout components 690 registerFactory("hbox", new Factory() { 691 public Object newInstance(Map properties) { 692 return Box.createHorizontalBox(); 693 } 694 }); 695 registerFactory("hglue", new Factory() { 696 public Object newInstance(Map properties) { 697 return Box.createHorizontalGlue(); 698 } 699 }); 700 registerFactory("hstrut", new Factory() { 701 public Object newInstance(Map properties) { 702 try { 703 Object num = properties.remove("width"); 704 if (num instanceof Number) { 705 return Box.createHorizontalStrut(((Number)num).intValue()); 706 } else { 707 return Box.createHorizontalStrut(6); 708 } 709 } catch (RuntimeException re) { 710 re.printStackTrace(System.out); 711 throw re; 712 } 713 } 714 }); 715 registerFactory("vbox", new Factory() { 716 public Object newInstance(Map properties) { 717 return Box.createVerticalBox(); 718 } 719 }); 720 registerFactory("vglue", new Factory() { 721 public Object newInstance(Map properties) { 722 return Box.createVerticalGlue(); 723 } 724 }); 725 registerFactory("vstrut", new Factory() { 726 public Object newInstance(Map properties) { 727 Object num = properties.remove("height"); 728 if (num instanceof Number) { 729 return Box.createVerticalStrut(((Number)num).intValue()); 730 } else { 731 return Box.createVerticalStrut(6); 732 } 733 } 734 }); 735 registerFactory("glue", new Factory() { 736 public Object newInstance(Map properties) { 737 return Box.createGlue(); 738 } 739 }); 740 registerFactory("rigidArea", new Factory() { 741 public Object newInstance(Map properties) { 742 Dimension dim; 743 Object o = properties.remove("size"); 744 if (o instanceof Dimension) { 745 dim = (Dimension) o; 746 } else { 747 int w, h; 748 o = properties.remove("width"); 749 w = ((o instanceof Number)) ? ((Number)o).intValue() : 6; 750 o = properties.remove("height"); 751 h = ((o instanceof Number)) ? ((Number)o).intValue() : 6; 752 dim = new Dimension(w, h); 753 } 754 return Box.createRigidArea(dim); 755 } 756 }); 757 758 // table layout 759 registerBeanFactory("tableLayout", TableLayout.class); 760 registerFactory("tr", new Factory() { 761 public Object newInstance(Map properties) { 762 Object parent = getCurrent(); 763 if (parent instanceof TableLayout) { 764 return new TableLayoutRow((TableLayout) parent); 765 } 766 else { 767 throw new RuntimeException("'tr' must be within a 'tableLayout'"); 768 } 769 } 770 }); 771 registerFactory("td", new Factory() { 772 public Object newInstance(Map properties) { 773 Object parent = getCurrent(); 774 if (parent instanceof TableLayoutRow) { 775 return new TableLayoutCell((TableLayoutRow) parent); 776 } 777 else { 778 throw new RuntimeException("'td' must be within a 'tr'"); 779 } 780 } 781 }); 782 } 783 784 protected Object createBoxLayout(Map properties) { 785 Object parent = getCurrent(); 786 if (parent instanceof Container) { 787 Object axisObject = properties.remove("axis"); 788 int axis = 0; 789 if (axisObject != null) { 790 Integer i = (Integer) axisObject; 791 axis = i.intValue(); 792 } 793 BoxLayout answer = new BoxLayout((Container) parent, axis); 794 795 // now lets try set the layout property 796 InvokerHelper.setProperty(parent, "layout", answer); 797 return answer; 798 } 799 else { 800 throw new RuntimeException("Must be nested inside a Container"); 801 } 802 } 803 804 protected Object createDialog(Map properties) { 805 JDialog dialog; 806 Object owner = properties.remove("owner"); 807 // if owner not explicit, use the last window type in the list 808 if ((owner == null) && !containingWindows.isEmpty()) { 809 owner = containingWindows.getLast(); 810 } 811 if (owner instanceof Frame) { 812 dialog = new JDialog((Frame) owner); 813 } 814 else if (owner instanceof Dialog) { 815 dialog = new JDialog((Dialog) owner); 816 } 817 else { 818 dialog = new JDialog(); 819 } 820 containingWindows.add(dialog); 821 return dialog; 822 } 823 824 /** 825 * Uses 'format," or "value," (in order) 826 * 827 */ 828 protected Object createFormattedTextField(Map properties) { 829 JFormattedTextField ftf; 830 if (properties.containsKey("format")) { 831 ftf = new JFormattedTextField((Format) properties.remove("format")); 832 } 833 else if (properties.containsKey("value")) { 834 ftf = new JFormattedTextField(properties.remove("value")); 835 } 836 else { 837 ftf = new JFormattedTextField(); 838 } 839 return ftf; 840 } 841 842 protected Object createFrame(Map properties) { 843 JFrame frame = new JFrame(); 844 containingWindows.add(frame); 845 return frame; 846 } 847 848 protected Object createWindow(Map properties) { 849 JWindow window; 850 Object owner = properties.remove("owner"); 851 // if owner not explicit, use the last window type in the list 852 if ((owner == null) && !containingWindows.isEmpty()) { 853 owner = containingWindows.getLast(); 854 } 855 if (owner instanceof Frame) { 856 window = new JWindow((Frame) owner); 857 } 858 else if (owner instanceof Window) { 859 window = new JWindow((Window) owner); 860 } 861 else { 862 window = new JWindow(); 863 } 864 containingWindows.add(window); 865 return window; 866 } 867 868 protected Object createComboBox(Map properties) { 869 Object items = properties.remove("items"); 870 if (items instanceof Vector) { 871 return new JComboBox((Vector) items); 872 } 873 else if (items instanceof List) { 874 List list = (List) items; 875 return new JComboBox(list.toArray()); 876 } 877 else if (items instanceof Object[]) { 878 return new JComboBox((Object[]) items); 879 } 880 else { 881 return new JComboBox(); 882 } 883 } 884 885 protected void registerBeanFactory(String name, final Class beanClass) { 886 registerFactory(name, new Factory() { 887 public Object newInstance(Map properties) throws InstantiationException, IllegalAccessException { 888 return beanClass.newInstance(); 889 } 890 }); 891 892 } 893 894 protected void registerFactory(String name, Factory factory) { 895 factories.put(name, factory); 896 } 897 }