"Fossies" - the Fresh Open Source Software Archive

Member "groovy-3.0.9/subprojects/groovy-swing/src/main/groovy/groovy/swing/SwingBuilder.groovy" (3 Sep 2021, 23954 Bytes) of package /linux/misc/apache-groovy-src-3.0.9.zip:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) Java source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. See also the last Fossies "Diffs" side-by-side code changes report for "SwingBuilder.groovy": 3.0.8_vs_3.0.9.

    1 /*
    2  *  Licensed to the Apache Software Foundation (ASF) under one
    3  *  or more contributor license agreements.  See the NOTICE file
    4  *  distributed with this work for additional information
    5  *  regarding copyright ownership.  The ASF licenses this file
    6  *  to you under the Apache License, Version 2.0 (the
    7  *  "License"); you may not use this file except in compliance
    8  *  with the License.  You may obtain a copy of the License at
    9  *
   10  *    http://www.apache.org/licenses/LICENSE-2.0
   11  *
   12  *  Unless required by applicable law or agreed to in writing,
   13  *  software distributed under the License is distributed on an
   14  *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
   15  *  KIND, either express or implied.  See the License for the
   16  *  specific language governing permissions and limitations
   17  *  under the License.
   18  */
   19 package groovy.swing
   20 
   21 import groovy.swing.factory.ActionFactory
   22 import groovy.swing.factory.BevelBorderFactory
   23 import groovy.swing.factory.BindFactory
   24 import groovy.swing.factory.BindGroupFactory
   25 import groovy.swing.factory.BindProxyFactory
   26 import groovy.swing.factory.BoxFactory
   27 import groovy.swing.factory.BoxLayoutFactory
   28 import groovy.swing.factory.ButtonGroupFactory
   29 import groovy.swing.factory.CellEditorFactory
   30 import groovy.swing.factory.CellEditorGetValueFactory
   31 import groovy.swing.factory.CellEditorPrepareFactory
   32 import groovy.swing.factory.ClosureColumnFactory
   33 import groovy.swing.factory.CollectionFactory
   34 import groovy.swing.factory.ColumnFactory
   35 import groovy.swing.factory.ColumnModelFactory
   36 import groovy.swing.factory.ComboBoxFactory
   37 import groovy.swing.factory.ComponentFactory
   38 import groovy.swing.factory.CompoundBorderFactory
   39 import groovy.swing.factory.DialogFactory
   40 import groovy.swing.factory.EmptyBorderFactory
   41 import groovy.swing.factory.EtchedBorderFactory
   42 import groovy.swing.factory.FormattedTextFactory
   43 import groovy.swing.factory.FrameFactory
   44 import groovy.swing.factory.GlueFactory
   45 import groovy.swing.factory.GridBagFactory
   46 import groovy.swing.factory.HBoxFactory
   47 import groovy.swing.factory.HGlueFactory
   48 import groovy.swing.factory.HStrutFactory
   49 import groovy.swing.factory.ImageIconFactory
   50 import groovy.swing.factory.InternalFrameFactory
   51 import groovy.swing.factory.LayoutFactory
   52 import groovy.swing.factory.LineBorderFactory
   53 import groovy.swing.factory.ListFactory
   54 import groovy.swing.factory.MapFactory
   55 import groovy.swing.factory.MatteBorderFactory
   56 import groovy.swing.factory.PropertyColumnFactory
   57 import groovy.swing.factory.RendererFactory
   58 import groovy.swing.factory.RendererUpdateFactory
   59 import groovy.swing.factory.RichActionWidgetFactory
   60 import groovy.swing.factory.RigidAreaFactory
   61 import groovy.swing.factory.ScrollPaneFactory
   62 import groovy.swing.factory.SeparatorFactory
   63 import groovy.swing.factory.SplitPaneFactory
   64 import groovy.swing.factory.TDFactory
   65 import groovy.swing.factory.TRFactory
   66 import groovy.swing.factory.TabbedPaneFactory
   67 import groovy.swing.factory.TableFactory
   68 import groovy.swing.factory.TableLayoutFactory
   69 import groovy.swing.factory.TableModelFactory
   70 import groovy.swing.factory.TextArgWidgetFactory
   71 import groovy.swing.factory.TitledBorderFactory
   72 import groovy.swing.factory.VBoxFactory
   73 import groovy.swing.factory.VGlueFactory
   74 import groovy.swing.factory.VStrutFactory
   75 import groovy.swing.factory.WidgetFactory
   76 import groovy.swing.factory.WindowFactory
   77 import org.codehaus.groovy.runtime.MethodClosure
   78 
   79 import javax.swing.*
   80 import javax.swing.border.BevelBorder
   81 import javax.swing.border.EtchedBorder
   82 import javax.swing.table.TableColumn
   83 import java.awt.*
   84 import java.lang.reflect.InvocationTargetException
   85 import java.util.logging.Logger
   86 
   87 /**
   88  * A helper class for creating Swing widgets using GroovyMarkup
   89  */
   90 class SwingBuilder extends FactoryBuilderSupport {
   91 
   92     private static final Logger LOG = Logger.getLogger(SwingBuilder.name)
   93     private static boolean headless = false
   94 
   95     static final String DELEGATE_PROPERTY_OBJECT_ID = "_delegateProperty:id"
   96     static final String DEFAULT_DELEGATE_PROPERTY_OBJECT_ID = "id"
   97 
   98     private static final Random random = new Random()
   99 
  100     SwingBuilder(boolean init = true) {
  101         super(init)
  102         headless = GraphicsEnvironment.isHeadless()
  103         containingWindows = new LinkedList()
  104         this[DELEGATE_PROPERTY_OBJECT_ID] = DEFAULT_DELEGATE_PROPERTY_OBJECT_ID
  105     }
  106 
  107     def registerSupportNodes() {
  108         registerFactory("action", new ActionFactory())
  109         registerFactory("actions", new CollectionFactory())
  110         registerFactory("map", new MapFactory())
  111         registerFactory("imageIcon", new ImageIconFactory())
  112         registerFactory("buttonGroup", new ButtonGroupFactory())
  113         addAttributeDelegate(ButtonGroupFactory.&buttonGroupAttributeDelegate)
  114 
  115         //object id delegate, for propertyNotFound
  116         addAttributeDelegate(SwingBuilder.&objectIDAttributeDelegate)
  117 
  118         addAttributeDelegate(SwingBuilder.&clientPropertyAttributeDelegate)
  119         registerFactory("noparent", new CollectionFactory())
  120         registerExplicitMethod("keyStrokeAction", this.&createKeyStrokeAction)
  121         registerExplicitMethod("shortcut", this.&shortcut)
  122     }
  123 
  124     def registerBinding() {
  125         BindFactory bindFactory = new BindFactory()
  126         registerFactory("bind", bindFactory)
  127         addAttributeDelegate(bindFactory.&bindingAttributeDelegate)
  128         registerFactory("bindProxy", new BindProxyFactory())
  129         registerFactory ("bindGroup", new BindGroupFactory())
  130     }
  131 
  132     def registerPassThruNodes() {
  133         registerFactory("widget", new WidgetFactory(Component, true))
  134         registerFactory("container", new WidgetFactory(Component, false))
  135         registerFactory("bean", new WidgetFactory(Object, true))
  136     }
  137 
  138 
  139     def registerWindows() {
  140         registerFactory("dialog", new DialogFactory())
  141         registerBeanFactory("fileChooser", JFileChooser)
  142         registerFactory("frame", new FrameFactory())
  143         registerBeanFactory("optionPane", JOptionPane)
  144         registerFactory("window", new WindowFactory())
  145     }
  146 
  147     def registerActionButtonWidgets() {
  148         registerFactory("button", new RichActionWidgetFactory(JButton))
  149         registerFactory("checkBox", new RichActionWidgetFactory(JCheckBox))
  150         registerFactory("checkBoxMenuItem", new RichActionWidgetFactory(JCheckBoxMenuItem))
  151         registerFactory("menuItem", new RichActionWidgetFactory(JMenuItem))
  152         registerFactory("radioButton", new RichActionWidgetFactory(JRadioButton))
  153         registerFactory("radioButtonMenuItem", new RichActionWidgetFactory(JRadioButtonMenuItem))
  154         registerFactory("toggleButton", new RichActionWidgetFactory(JToggleButton))
  155     }
  156 
  157     def registerTextWidgets() {
  158         registerFactory("editorPane", new TextArgWidgetFactory(JEditorPane))
  159         registerFactory("label", new TextArgWidgetFactory(JLabel))
  160         registerFactory("passwordField", new TextArgWidgetFactory(JPasswordField))
  161         registerFactory("textArea", new TextArgWidgetFactory(JTextArea))
  162         registerFactory("textField", new TextArgWidgetFactory(JTextField))
  163         registerFactory("formattedTextField", new FormattedTextFactory())
  164         registerFactory("textPane", new TextArgWidgetFactory(JTextPane))
  165     }
  166 
  167     def registerMDIWidgets() {
  168         registerBeanFactory("desktopPane", JDesktopPane)
  169         registerFactory("internalFrame", new InternalFrameFactory())
  170     }
  171 
  172     def registerBasicWidgets() {
  173         registerBeanFactory("colorChooser", JColorChooser)
  174 
  175         registerFactory("comboBox", new ComboBoxFactory())
  176         registerFactory("list", new ListFactory())
  177         registerBeanFactory("progressBar", JProgressBar)
  178         registerFactory("separator", new SeparatorFactory())
  179         registerBeanFactory("scrollBar", JScrollBar)
  180         registerBeanFactory("slider", JSlider)
  181         registerBeanFactory("spinner", JSpinner)
  182         registerBeanFactory("tree", JTree)
  183     }
  184 
  185     def registerMenuWidgets() {
  186         registerBeanFactory("menu", JMenu)
  187         registerBeanFactory("menuBar", JMenuBar)
  188         registerBeanFactory("popupMenu", JPopupMenu)
  189     }
  190 
  191     def registerContainers() {
  192         registerBeanFactory("panel", JPanel)
  193         registerFactory("scrollPane", new ScrollPaneFactory())
  194         registerFactory("splitPane", new SplitPaneFactory())
  195         registerFactory("tabbedPane", new TabbedPaneFactory(JTabbedPane))
  196         registerBeanFactory("toolBar", JToolBar)
  197         registerBeanFactory("viewport", JViewport) // sub class?
  198         registerBeanFactory("layeredPane", JLayeredPane)
  199     }
  200 
  201     def registerDataModels() {
  202         registerBeanFactory("boundedRangeModel", DefaultBoundedRangeModel)
  203 
  204         // spinner models
  205         registerBeanFactory("spinnerDateModel", SpinnerDateModel)
  206         registerBeanFactory("spinnerListModel", SpinnerListModel)
  207         registerBeanFactory("spinnerNumberModel", SpinnerNumberModel)
  208     }
  209 
  210     def registerTableComponents() {
  211         registerFactory("table", new TableFactory())
  212         registerBeanFactory("tableColumn", TableColumn)
  213         registerFactory("tableModel", new TableModelFactory())
  214         registerFactory("propertyColumn", new PropertyColumnFactory())
  215         registerFactory("closureColumn", new ClosureColumnFactory())
  216         registerFactory("columnModel", new ColumnModelFactory())
  217         registerFactory("column", new ColumnFactory())
  218     }
  219 
  220     def registerBasicLayouts() {
  221         registerFactory("borderLayout", new LayoutFactory(BorderLayout))
  222         registerFactory("cardLayout", new LayoutFactory(CardLayout))
  223         registerFactory("flowLayout", new LayoutFactory(FlowLayout))
  224         registerFactory("gridLayout", new LayoutFactory(GridLayout))
  225         registerFactory("overlayLayout", new LayoutFactory(OverlayLayout))
  226         registerFactory("springLayout", new LayoutFactory(SpringLayout))
  227 
  228         registerFactory("gridBagLayout", new GridBagFactory())
  229         registerBeanFactory("gridBagConstraints", GridBagConstraints)
  230         registerBeanFactory("gbc", GridBagConstraints) // shortcut name
  231         // constraints delegate
  232         addAttributeDelegate(GridBagFactory.&processGridBagConstraintsAttributes)
  233 
  234         addAttributeDelegate(LayoutFactory.&constraintsAttributeDelegate)
  235     }
  236 
  237     def registerBoxLayout() {
  238         registerFactory("boxLayout", new BoxLayoutFactory())
  239         registerFactory("box", new BoxFactory())
  240         registerFactory("hbox", new HBoxFactory())
  241         registerFactory("hglue", new HGlueFactory())
  242         registerFactory("hstrut", new HStrutFactory())
  243         registerFactory("vbox", new VBoxFactory())
  244         registerFactory("vglue", new VGlueFactory())
  245         registerFactory("vstrut", new VStrutFactory())
  246         registerFactory("glue", new GlueFactory())
  247         registerFactory("rigidArea", new RigidAreaFactory())
  248     }
  249 
  250     def registerTableLayout() {
  251         registerFactory("tableLayout", new TableLayoutFactory())
  252         registerFactory("tr", new TRFactory())
  253         registerFactory("td", new TDFactory())
  254     }
  255 
  256     def registerBorders() {
  257         registerFactory("lineBorder", new LineBorderFactory())
  258         registerFactory("loweredBevelBorder", new BevelBorderFactory(BevelBorder.LOWERED))
  259         registerFactory("raisedBevelBorder", new BevelBorderFactory(BevelBorder.RAISED))
  260         registerFactory("etchedBorder", new EtchedBorderFactory(EtchedBorder.LOWERED))
  261         registerFactory("loweredEtchedBorder", new EtchedBorderFactory(EtchedBorder.LOWERED))
  262         registerFactory("raisedEtchedBorder", new EtchedBorderFactory(EtchedBorder.RAISED))
  263         registerFactory("titledBorder", new TitledBorderFactory())
  264         registerFactory("emptyBorder", new EmptyBorderFactory())
  265         registerFactory("compoundBorder", new CompoundBorderFactory())
  266         registerFactory("matteBorder", new MatteBorderFactory())
  267     }
  268 
  269     def registerRenderers() {
  270         RendererFactory renderFactory = new RendererFactory()
  271         registerFactory("tableCellRenderer", renderFactory)
  272         registerFactory("listCellRenderer", renderFactory)
  273         registerFactory("onRender", new RendererUpdateFactory())
  274         registerFactory("cellRenderer", renderFactory)
  275         registerFactory("headerRenderer", renderFactory)
  276     }
  277 
  278     def registerEditors() {
  279       registerFactory("cellEditor", new CellEditorFactory())
  280       registerFactory("editorValue", new CellEditorGetValueFactory())
  281       registerFactory("prepareEditor", new CellEditorPrepareFactory())
  282     }
  283 
  284     def registerThreading() {
  285         registerExplicitMethod "edt", this.&edt
  286         registerExplicitMethod "doOutside", this.&doOutside
  287         registerExplicitMethod "doLater", this.&doLater
  288     }
  289 
  290 
  291     /**
  292      * Do some overrides for standard component handlers, else use super
  293      */
  294     void registerBeanFactory(String nodeName, String groupName, Class klass) {
  295         // poke at the type to see if we need special handling
  296         if (LayoutManager.isAssignableFrom(klass)) {
  297             registerFactory(nodeName, groupName, new LayoutFactory(klass))
  298         } else if (JScrollPane.isAssignableFrom(klass)) {
  299             registerFactory(nodeName, groupName, new ScrollPaneFactory(klass))
  300         } else if (JTable.isAssignableFrom(klass)) {
  301             registerFactory(nodeName, groupName, new TableFactory(klass))
  302         } else if (JComponent.isAssignableFrom(klass)
  303             || JApplet.isAssignableFrom(klass)
  304             || JDialog.isAssignableFrom(klass)
  305             || JFrame.isAssignableFrom(klass)
  306             || JWindow.isAssignableFrom(klass)
  307         ) {
  308             registerFactory(nodeName, groupName, new ComponentFactory(klass))
  309         } else {
  310             super.registerBeanFactory(nodeName, groupName, klass)
  311         }
  312 
  313     }
  314 
  315     /**
  316      * Utility method to run a closure in EDT,
  317      * using <code>SwingUtilities.invokeAndWait</code>.
  318      *
  319      * @param c this closure is run in the EDT
  320      */
  321     SwingBuilder edt(@DelegatesTo(SwingBuilder) Closure c) {
  322         c.setDelegate(this)
  323         if (headless || SwingUtilities.isEventDispatchThread()) {
  324             c.call(this)
  325         } else {
  326             Map<String, Object> continuationData = getContinuationData()
  327             try {
  328                 if (!(c instanceof MethodClosure)) {
  329                     c = c.curry([this])
  330                 }
  331                 SwingUtilities.invokeAndWait {
  332                     restoreFromContinuationData(continuationData)
  333                     c()
  334                     continuationData = getContinuationData()
  335                 }
  336             } catch (InterruptedException e) {
  337                 Thread.currentThread().interrupt();
  338                 throw new GroovyRuntimeException("interrupted swing interaction", e)
  339             } catch (InvocationTargetException e) {
  340                 throw new GroovyRuntimeException("exception in event dispatch thread", e.getTargetException())
  341             } finally {
  342                 restoreFromContinuationData(continuationData)
  343             }
  344         }
  345         return this
  346     }
  347 
  348     /**
  349      * Utility method to run a closure in EDT,
  350      * using <code>SwingUtilities.invokeLater</code>.
  351      *
  352      * @param c this closure is run in the EDT
  353      */
  354     SwingBuilder doLater(@DelegatesTo(SwingBuilder) Closure c) {
  355         c.setDelegate(this)
  356         if (headless) {
  357             c.call()
  358         } else {
  359             if (!(c instanceof MethodClosure)) {
  360                 c = c.curry([this])
  361             }
  362             SwingUtilities.invokeLater(c)
  363         }
  364         return this
  365     }
  366 
  367     /**
  368      * Utility method to run a closure outside of the EDT.
  369      * <p>
  370      * The closure is wrapped in a thread, and the thread is started
  371      * immediately, only if the current thread is the EDT, otherwise the
  372      * closure will be called immediately.
  373      *
  374      * @param c this closure is started outside of the EDT
  375      */
  376     SwingBuilder doOutside(@DelegatesTo(SwingBuilder) Closure c) {
  377         c.setDelegate(this)
  378         if (!(c instanceof MethodClosure)) {
  379             c = c.curry([this])
  380         }
  381         if( SwingUtilities.isEventDispatchThread() )
  382             new Thread(c).start()
  383         else
  384             c.call()
  385         return this
  386     }
  387 
  388     /**
  389      * Factory method to create a SwingBuilder, and run the
  390      * the closure in it on the EDT
  391      *
  392      * @param c run this closure in the new builder using the edt method
  393      */
  394     static SwingBuilder edtBuilder(@DelegatesTo(SwingBuilder) Closure c) {
  395         SwingBuilder builder = new SwingBuilder()
  396         return builder.edt(c)
  397     }
  398 
  399     /**
  400      * Old factory method static SwingBuilder.build(Closure).
  401      * @param c run this closure in the builder using the edt method
  402      */
  403     @Deprecated
  404     static SwingBuilder '$static_methodMissing'(String method, Object args) {
  405         if (method == 'build' && args.length == 1 && args[0] instanceof Closure) {
  406             return edtBuilder(args[0])
  407         } else {
  408             throw new MissingMethodException(method, SwingBuilder, args, true)
  409         }
  410     }
  411 
  412     /**
  413      * Compatibility API.
  414      *
  415      * @param c run this closure in the builder
  416      */
  417     Object build(@DelegatesTo(SwingBuilder) Closure c) {
  418         c.setDelegate(this)
  419         return c.call()
  420     }
  421 
  422     KeyStroke shortcut(key, modifier = 0) {
  423         return KeyStroke.getKeyStroke(key, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask() | modifier)
  424     }
  425 
  426     KeyStroke shortcut(String key, modifier = 0) {
  427         KeyStroke ks = KeyStroke.getKeyStroke(key)
  428         if (ks == null) {
  429             return null
  430         } else {
  431             return KeyStroke.getKeyStroke(ks.getKeyCode(), ks.getModifiers() | modifier | Toolkit.getDefaultToolkit().getMenuShortcutKeyMask())        }
  432     }
  433 
  434     static LookAndFeel lookAndFeel(Object laf, Closure initCode) {
  435         lookAndFeel([:], laf, initCode)
  436     }
  437 
  438     static LookAndFeel lookAndFeel(Map attributes = [:], Object laf = null, Closure initCode = null) {
  439         // if we get rid of this warning, we can make it static.
  440         //if (context) {
  441         //    LOG.warning "For best result do not call lookAndFeel when it is a child of a SwingBuilder node, initialization of the Look and Feel may be inconsistent."
  442         //}
  443         groovy.swing.LookAndFeelHelper.instance.lookAndFeel(laf, attributes, initCode)
  444     }
  445 
  446     static LookAndFeel lookAndFeel(Object... lafs) {
  447         if (lafs.length == 1) {
  448             lookAndFeel([:], lafs[0], null as Closure)
  449         }
  450         for (Object laf in lafs) {
  451             try {
  452                 // (ab)use multi-methods
  453                 if (laf instanceof ArrayList) {
  454                     // multi-method bug
  455                     return _laf(*laf)
  456                 } else {
  457                     return _laf(laf)
  458                 }
  459             } catch (Throwable t) {
  460                 LOG.fine "Could not instantiate Look and Feel $laf because of ${t}. Attempting next option."
  461             }
  462         }
  463         LOG.warning "All Look and Feel options failed: $lafs"
  464         return null
  465     }
  466 
  467     private static LookAndFeel _laf(java.util.List s) {
  468         _laf(*s)
  469     }
  470 
  471     private static LookAndFeel _laf(String s, Map m) {
  472         lookAndFeel(m, s, null as Closure)
  473     }
  474 
  475     private static LookAndFeel _laf(LookAndFeel laf, Map m) {
  476         lookAndFeel(m, laf, null as Closure)
  477     }
  478 
  479     private static LookAndFeel _laf(String s) {
  480         lookAndFeel([:], s, null as Closure)
  481     }
  482 
  483     private static LookAndFeel _laf(LookAndFeel laf) {
  484         lookAndFeel([:], laf, null as Closure)
  485     }
  486 
  487     static objectIDAttributeDelegate(def builder, def node, def attributes) {
  488         def idAttr = builder.getAt(DELEGATE_PROPERTY_OBJECT_ID) ?: DEFAULT_DELEGATE_PROPERTY_OBJECT_ID
  489         def theID = attributes.remove(idAttr)
  490         if (theID) {
  491             builder.setVariable(theID, node)
  492             if(node) {
  493                 try {
  494                     if (!node.name) node.name = theID
  495                 } catch (MissingPropertyException mpe) {
  496                     // ignore
  497                 }
  498             }
  499         }
  500     }
  501 
  502     static clientPropertyAttributeDelegate(def builder, def node, def attributes) {
  503         def clientPropertyMap = attributes.remove("clientProperties")
  504         clientPropertyMap.each { key, value ->
  505            node.putClientProperty key, value
  506         }
  507         attributes.findAll { it.key =~ /clientProperty(\w)/ }.each { key, value ->
  508            attributes.remove(key)
  509            node.putClientProperty(key - "clientProperty", value)
  510         }
  511     }
  512 
  513     void createKeyStrokeAction( Map attributes, JComponent component = null ) {
  514         component = findTargetComponent(attributes, component)
  515         if( !attributes.containsKey("keyStroke") ) {
  516             throw new RuntimeException("You must define a value for keyStroke:")
  517         }
  518         if( !attributes.containsKey("action") ) {
  519             throw new RuntimeException("You must define a value for action:")
  520         }
  521 
  522         def condition = attributes.remove("condition") ?: JComponent.WHEN_FOCUSED
  523         if (condition instanceof GString) condition = condition as String
  524         if( condition instanceof String ) {
  525             condition = condition.toUpperCase().replace(" ", "_")
  526             if( !condition.startsWith("WHEN_") ) condition = "WHEN_"+condition
  527         }
  528         switch(condition) {
  529             case JComponent.WHEN_FOCUSED:
  530             case JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT:
  531             case JComponent.WHEN_IN_FOCUSED_WINDOW:
  532                 // everything is fine, no further processing
  533                 break
  534             case "WHEN_FOCUSED":
  535                 condition = JComponent.WHEN_FOCUSED
  536                 break
  537             case "WHEN_ANCESTOR_OF_FOCUSED_COMPONENT":
  538                 condition = JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT
  539                 break
  540             case "WHEN_IN_FOCUSED_WINDOW":
  541                 condition = JComponent.WHEN_IN_FOCUSED_WINDOW
  542                 break
  543             default:
  544                 // let's be lenient and assign WHEN_FOCUSED by default
  545                 condition = JComponent.WHEN_FOCUSED
  546         }
  547         def actionKey = attributes.remove("actionKey")
  548         if( !actionKey ) actionKey = "Action"+Math.abs(random.nextLong())
  549                            
  550         def keyStroke = attributes.remove("keyStroke")
  551         // accept String, Number, KeyStroke, List<String>, List<Number>, List<KeyStroke>
  552         def action = attributes.remove("action")
  553 
  554         if( keyStroke instanceof GString ) keyStroke = keyStroke as String
  555         if( keyStroke instanceof String || keyStroke instanceof Number ) keyStroke = [keyStroke]
  556         keyStroke.each { ks ->
  557             switch(ks) {
  558                 case KeyStroke:
  559                     component.getInputMap(condition).put(ks, actionKey)
  560                     break
  561                 case String:
  562                     component.getInputMap(condition).put(KeyStroke.getKeyStroke(ks), actionKey)
  563                     break
  564                 case Number:
  565                     component.getInputMap(condition).put(KeyStroke.getKeyStroke(ks.intValue()), actionKey)
  566                     break
  567                 default:
  568                     throw new RuntimeException("Cannot apply ${ks} as a KeyStroke value.")
  569             }
  570         }
  571         component.actionMap.put(actionKey, action)
  572     }
  573 
  574     private findTargetComponent( Map attributes, JComponent component ) {
  575         if( component ) return component
  576         if( attributes.containsKey("component") ) {
  577             def c = attributes.remove("component")
  578             if( !(c instanceof JComponent) ) {
  579                 throw new RuntimeException("The property component: is not of type JComponent.")
  580             }
  581             return c
  582         }
  583         def c = getCurrent()
  584         if( c instanceof JComponent ) {
  585             return c
  586         }
  587         throw new RuntimeException("You must define one of the following: a value of type JComponent, a component: attribute or nest this node inside another one that produces a JComponent.")
  588     }
  589 }