| 1 46 package groovy.swing; 47 48 import groovy.lang.Closure; 49 50 import groovy.model.DefaultTableModel; 51 import groovy.model.ValueHolder; 52 import groovy.model.ValueModel; 53 54 import groovy.swing.impl.ComponentFacade; 55 import groovy.swing.impl.ContainerFacade; 56 import groovy.swing.impl.DefaultAction; 57 import groovy.swing.impl.Factory; 58 import groovy.swing.impl.Startable; 59 import groovy.swing.impl.TableLayout; 60 import groovy.swing.impl.TableLayoutCell; 61 import groovy.swing.impl.TableLayoutRow; 62 63 import groovy.util.BuilderSupport; 64 65 import java.awt.BorderLayout ; 66 import java.awt.CardLayout ; 67 import java.awt.Component ; 68 import java.awt.Container ; 69 import java.awt.Dimension ; 70 import java.awt.Dialog ; 71 import java.awt.FlowLayout ; 72 import java.awt.Frame ; 73 import java.awt.GridBagConstraints ; 74 import java.awt.GridBagLayout ; 75 import java.awt.GridLayout ; 76 import java.awt.LayoutManager ; 77 import java.awt.Window ; 78 79 import java.text.Format ; 80 81 import java.util.ArrayList ; 82 import java.util.Collections ; 83 import java.util.HashMap ; 84 import java.util.HashSet ; 85 import java.util.Iterator ; 86 import java.util.LinkedList ; 87 import java.util.List ; 88 import java.util.Map ; 89 import java.util.Set ; 90 import java.util.Vector ; 91 import java.util.logging.Level ; 92 import java.util.logging.Logger ; 93 94 import javax.swing.AbstractButton ; 95 import javax.swing.Action ; 96 import javax.swing.Box ; 97 import javax.swing.BoxLayout ; 98 import javax.swing.ButtonGroup ; 99 import javax.swing.DefaultBoundedRangeModel ; 100 import javax.swing.JButton ; 101 import javax.swing.JCheckBox ; 102 import javax.swing.JCheckBoxMenuItem ; 103 import javax.swing.JColorChooser ; 104 import javax.swing.JComboBox ; 105 import javax.swing.JComponent ; 106 import javax.swing.JDesktopPane ; 107 import javax.swing.JDialog ; 108 import javax.swing.JEditorPane ; 109 import javax.swing.JFileChooser ; 110 import javax.swing.JFormattedTextField ; 111 import javax.swing.JFrame ; 112 import javax.swing.JInternalFrame ; 113 import javax.swing.JLabel ; 114 import javax.swing.JLayeredPane ; 115 import javax.swing.JList ; 116 import javax.swing.JMenu ; 117 import javax.swing.JMenuBar ; 118 import javax.swing.JMenuItem ; 119 import javax.swing.JOptionPane ; 120 import javax.swing.JPanel ; 121 import javax.swing.JPasswordField ; 122 import javax.swing.JPopupMenu ; 123 import javax.swing.JProgressBar ; 124 import javax.swing.JRadioButton ; 125 import javax.swing.JRadioButtonMenuItem ; 126 import javax.swing.JScrollBar ; 127 import javax.swing.JScrollPane ; 128 import javax.swing.JSeparator ; 129 import javax.swing.JSlider ; 130 import javax.swing.JSpinner ; 131 import javax.swing.JSplitPane ; 132 import javax.swing.JTabbedPane ; 133 import javax.swing.JTable ; 134 import javax.swing.JTextArea ; 135 import javax.swing.JTextField ; 136 import javax.swing.JTextPane ; 137 import javax.swing.JToggleButton ; 138 import javax.swing.JToolBar ; 139 import javax.swing.JToolTip ; 140 import javax.swing.JTree ; 141 import javax.swing.JViewport ; 142 import javax.swing.JWindow ; 143 import javax.swing.KeyStroke ; 144 import javax.swing.OverlayLayout ; 145 import javax.swing.RootPaneContainer ; 146 import javax.swing.SpinnerDateModel ; 147 import javax.swing.SpinnerListModel ; 148 import javax.swing.SpinnerNumberModel ; 149 import javax.swing.SpringLayout ; 150 import javax.swing.table.TableColumn ; 151 import javax.swing.table.TableModel ; 152 153 import org.codehaus.groovy.runtime.InvokerHelper; 154 155 161 public class SwingBuilder extends BuilderSupport { 162 163 private Logger log = Logger.getLogger(getClass().getName()); 164 private Map factories = new HashMap (); 165 private Object constraints; 166 private Map passThroughNodes = new HashMap (); 167 private Map widgets = new HashMap (); 168 private LinkedList containingWindows = new LinkedList (); 170 171 public SwingBuilder() { 172 registerWidgets(); 173 } 174 175 public Object getProperty(String name) { 176 Object widget = widgets.get(name); 177 if (widget == null) { 178 return super.getProperty(name); 179 } 180 return widget; 181 } 182 183 protected void setParent(Object parent, Object child) { 184 if (child instanceof Action) { 185 Action action = (Action) child; 186 try { 187 InvokerHelper.setProperty(parent, "action", action); 188 } catch (RuntimeException re) { 189 } 192 Object keyStroke = action.getValue("KeyStroke"); 193 if (parent instanceof JComponent ) { 195 JComponent component = (JComponent ) parent; 196 KeyStroke stroke = null; 197 if (keyStroke instanceof String ) { 198 stroke = KeyStroke.getKeyStroke((String ) keyStroke); 199 } 200 else if (keyStroke instanceof KeyStroke ) { 201 stroke = (KeyStroke ) keyStroke; 202 } 203 if (stroke != null) { 204 String key = action.toString(); 205 component.getInputMap().put(stroke, key); 206 component.getActionMap().put(key, action); 207 } 208 } 209 } 210 else if (child instanceof LayoutManager ) { 211 if (parent instanceof RootPaneContainer ) { 212 RootPaneContainer rpc = (RootPaneContainer ) parent; 213 parent = rpc.getContentPane(); 214 } 215 InvokerHelper.setProperty(parent, "layout", child); 216 } 217 else if (child instanceof JToolTip && parent instanceof JComponent ) { 218 ((JToolTip )child).setComponent((JComponent )parent); 219 } 220 else if (parent instanceof JTable && child instanceof TableColumn ) { 221 JTable table = (JTable ) parent; 222 TableColumn column = (TableColumn ) child; 223 table.addColumn(column); 224 } 225 else if (parent instanceof JTabbedPane && child instanceof Component ) { 226 JTabbedPane tabbedPane = (JTabbedPane ) parent; 227 tabbedPane.add((Component )child); 228 } 229 else if (child instanceof Window ) { 230 } 234 else { 235 Component component = null; 236 if (child instanceof Component ) { 237 component = (Component ) child; 238 } 239 else if (child instanceof ComponentFacade) { 240 ComponentFacade facade = (ComponentFacade) child; 241 component = facade.getComponent(); 242 } 243 if (component != null) { 244 if (parent instanceof JFrame && component instanceof JMenuBar ) { 245 JFrame frame = (JFrame ) parent; 246 frame.setJMenuBar((JMenuBar ) component); 247 } 248 else if (parent instanceof RootPaneContainer ) { 249 RootPaneContainer rpc = (RootPaneContainer ) parent; 250 rpc.getContentPane().add(component); 251 } 252 else if (parent instanceof JScrollPane ) { 253 JScrollPane scrollPane = (JScrollPane ) parent; 254 if (child instanceof JViewport ) { 255 scrollPane.setViewport((JViewport )component); 256 } 257 else { 258 scrollPane.setViewportView(component); 259 } 260 } 261 else if (parent instanceof JSplitPane ) { 262 JSplitPane splitPane = (JSplitPane ) parent; 263 if (splitPane.getOrientation() == JSplitPane.HORIZONTAL_SPLIT) { 264 if (splitPane.getTopComponent() == null) { 265 splitPane.setTopComponent(component); 266 } 267 else { 268 splitPane.setBottomComponent(component); 269 } 270 } 271 else { 272 if (splitPane.getLeftComponent() == null) { 273 splitPane.setLeftComponent(component); 274 } 275 else { 276 splitPane.setRightComponent(component); 277 } 278 } 279 } 280 else if (parent instanceof JMenuBar && component instanceof JMenu ) { 281 JMenuBar menuBar = (JMenuBar ) parent; 282 menuBar.add((JMenu ) component); 283 } 284 else if (parent instanceof Container ) { 285 Container container = (Container ) parent; 286 if (constraints != null) { 287 container.add(component, constraints); 288 } 289 else { 290 container.add(component); 291 } 292 } 293 else if (parent instanceof ContainerFacade) { 294 ContainerFacade facade = (ContainerFacade) parent; 295 facade.addComponent(component); 296 } 297 } 298 } 299 } 300 301 protected void nodeCompleted(Object parent, Object node) { 302 if (node instanceof TableModel && parent instanceof JTable ) { 304 JTable table = (JTable ) parent; 305 TableModel model = (TableModel) node; 306 table.setModel(model); 307 } 308 if (node instanceof Startable) { 309 Startable startable = (Startable) node; 310 startable.start(); 311 } 312 if (node instanceof Window ) { 313 if (!containingWindows.isEmpty() && containingWindows.getLast() == node) { 314 containingWindows.removeLast(); 315 } 316 } 317 } 318 319 protected Object createNode(Object name) { 320 return createNode(name, Collections.EMPTY_MAP); 321 } 322 323 protected Object createNode(Object name, Object value) { 324 if (passThroughNodes.containsKey(name) && (value != null) && ((Class )passThroughNodes.get(name)).isAssignableFrom(value.getClass())) { 325 if (value instanceof Window ) { 327 containingWindows.add(value); 328 } 329 return value; 330 } 331 else { 332 Object widget = createNode(name); 333 if (widget != null && value instanceof String ) { 334 InvokerHelper.invokeMethod(widget, "setText", value); 335 } 336 return widget; 337 } 338 } 339 340 protected Object createNode(Object name, Map attributes, Object value) { 341 if (passThroughNodes.containsKey(name) && (value != null) && ((Class )passThroughNodes.get(name)).isAssignableFrom(value.getClass())) { 342 if (value instanceof Window ) { 344 containingWindows.add(value); 345 } 346 handleWidgetAttributes(value, attributes); 347 return value; 348 } 349 else { 350 Object widget = createNode(name, attributes); 351 if (widget != null) { 352 InvokerHelper.invokeMethod(widget, "setText", value.toString()); 353 } 354 return widget; 355 } 356 } 357 358 protected Object createNode(Object name, Map attributes) { 359 String widgetName = (String ) attributes.remove("id"); 360 constraints = attributes.remove("constraints"); 361 Object widget = null; 362 if (passThroughNodes.containsKey(name)) { 363 widget = attributes.get(name); 364 if ((widget != null) && ((Class )passThroughNodes.get(name)).isAssignableFrom(widget.getClass())) { 365 if (widget instanceof Window ) { 367 containingWindows.add(widget); 368 } 369 attributes.remove(name); 370 } 371 else { 372 widget = null; 373 } 374 } 375 if (widget == null) { 376 Factory factory = (Factory) factories.get(name); 377 if (factory != null) { 378 try { 379 widget = factory.newInstance(attributes); 380 if (widgetName != null) { 381 widgets.put(widgetName, widget); 382 } 383 if (widget == null) { 384 log.log(Level.WARNING, "Factory for name: " + name + " returned null"); 385 } 386 else { 387 if (log.isLoggable(Level.FINE)) { 388 log.fine("For name: " + name + " created widget: " + widget); 389 } 390 } 391 } 392 catch (Exception e) { 393 throw new RuntimeException ("Failed to create component for" + name + " reason: " + e, e); 394 } 395 } 396 else { 397 log.log(Level.WARNING, "Could not find match for name: " + name); 398 } 399 } 400 handleWidgetAttributes(widget, attributes); 401 return widget; 402 } 403 404 protected void handleWidgetAttributes(Object widget, Map attributes) { 405 if (widget != null) { 406 if (widget instanceof Action) { 407 408 Action action = (Action) widget; 409 410 Closure closure = (Closure) attributes.remove("closure"); 411 if (closure != null && action instanceof DefaultAction) { 412 DefaultAction defaultAction = (DefaultAction) action; 413 defaultAction.setClosure(closure); 414 } 415 416 Object accel = attributes.remove("accelerator"); 417 KeyStroke stroke = null; 418 if (accel instanceof KeyStroke ) { 419 stroke = (KeyStroke ) accel; 420 } else if (accel != null) { 421 stroke = KeyStroke.getKeyStroke(accel.toString()); 422 } 423 action.putValue(Action.ACCELERATOR_KEY, stroke); 424 425 Object mnemonic = attributes.remove("mnemonic"); 426 if ((mnemonic != null) && !(mnemonic instanceof Number )) { 427 mnemonic = new Integer (mnemonic.toString().charAt(0)); 428 } 429 action.putValue(Action.MNEMONIC_KEY, mnemonic); 430 431 for (Iterator iter = attributes.entrySet().iterator(); iter.hasNext();) { 432 Map.Entry entry = (Map.Entry ) iter.next(); 433 String actionName = (String ) entry.getKey(); 434 435 actionName = capitalize(actionName); 437 Object value = entry.getValue(); 438 439 action.putValue(actionName, value); 440 } 441 442 } 443 else { 444 if (attributes.containsKey("buttonGroup")) { 446 Object o = attributes.get("buttonGroup"); 447 if ((o instanceof ButtonGroup ) && (widget instanceof AbstractButton )) { 448 ((AbstractButton )widget).getModel().setGroup((ButtonGroup )o); 449 attributes.remove("buttonGroup"); 450 } 451 } 452 453 Object mnemonic = attributes.remove("mnemonic"); 455 if ((mnemonic != null) && (mnemonic instanceof Number )) { 456 InvokerHelper.setProperty(widget, "mnemonic", new Character ((char)((Number )mnemonic).intValue())); 457 } 458 else if (mnemonic != null) { 459 InvokerHelper.setProperty(widget, "mnemonic", new Character (mnemonic.toString().charAt(0))); 460 } 461 462 for (Iterator iter = attributes.entrySet().iterator(); iter.hasNext();) { 464 Map.Entry entry = (Map.Entry ) iter.next(); 465 String property = entry.getKey().toString(); 466 Object value = entry.getValue(); 467 InvokerHelper.setProperty(widget, property, value); 468 } 469 } 470 } 471 } 472 473 protected String capitalize(String text) { 474 char ch = text.charAt(0); 475 if (Character.isUpperCase(ch)) { 476 return text; 477 } 478 StringBuffer buffer = new StringBuffer (text.length()); 479 buffer.append(Character.toUpperCase(ch)); 480 buffer.append(text.substring(1)); 481 return buffer.toString(); 482 } 483 484 protected void registerWidgets() { 485 registerBeanFactory("action", DefaultAction.class); 489 passThroughNodes.put("action", javax.swing.Action .class); 490 registerBeanFactory("buttonGroup", ButtonGroup .class); 491 registerFactory("map", new Factory() { 492 public Object newInstance(Map properties) 493 throws InstantiationException , InstantiationException , IllegalAccessException { 494 return properties; 495 } 496 }); 497 passThroughNodes.put("widget", java.awt.Component .class); 499 500 registerFactory("dialog", new Factory() { 504 public Object newInstance(Map properties) 505 throws InstantiationException , InstantiationException , IllegalAccessException { 506 return createDialog(properties); 507 } 508 }); 509 registerFactory("frame", new Factory() { 510 public Object newInstance(Map properties) 511 throws InstantiationException , InstantiationException , IllegalAccessException { 512 return createFrame(properties); 513 } 514 }); 515 registerBeanFactory("fileChooser", JFileChooser .class); 516 registerFactory("frame", new Factory() { 517 public Object newInstance(Map properties) 518 throws InstantiationException , InstantiationException , IllegalAccessException { 519 return createFrame(properties); 520 } 521 }); 522 registerBeanFactory("optionPane", JOptionPane .class); 523 registerFactory("window", new Factory() { 524 public Object newInstance(Map properties) 525 throws InstantiationException , InstantiationException , IllegalAccessException { 526 return createWindow(properties); 527 } 528 }); 529 530 registerBeanFactory("button", JButton .class); 534 registerBeanFactory("checkBox", JCheckBox .class); 535 registerBeanFactory("checkBoxMenuItem", JCheckBoxMenuItem .class); 536 registerBeanFactory("colorChooser", JColorChooser .class); 537 registerFactory("comboBox", new Factory() { 538 public Object newInstance(Map properties) 539 throws InstantiationException , InstantiationException , IllegalAccessException { 540 return createComboBox(properties); 541 } 542 }); 543 registerBeanFactory("desktopPane", JDesktopPane .class); 544 registerBeanFactory("editorPane", JEditorPane .class); 545 registerFactory("formattedTextField", new Factory() { 546 public Object newInstance(Map properties) 547 throws InstantiationException , InstantiationException , IllegalAccessException { 548 return createFormattedTextField(properties); 549 } 550 }); 551 registerBeanFactory("internalFrame", JInternalFrame .class); 552 registerBeanFactory("label", JLabel .class); 553 registerBeanFactory("layeredPane", JLayeredPane .class); 554 registerBeanFactory("list", JList .class); 555 registerBeanFactory("menu", JMenu .class); 556 registerBeanFactory("menuBar", JMenuBar .class); 557 registerBeanFactory("menuItem", JMenuItem .class); 558 registerBeanFactory("panel", JPanel .class); 559 registerBeanFactory("passwordField", JPasswordField .class); 560 registerBeanFactory("popupMenu", JPopupMenu .class); 561 registerBeanFactory("progressBar", JProgressBar .class); 562 registerBeanFactory("radioButton", JRadioButton .class); 563 registerBeanFactory("radioButtonMenuItem", JRadioButtonMenuItem .class); 564 registerBeanFactory("scrollBar", JScrollBar .class); 565 registerBeanFactory("scrollPane", JScrollPane  |