FXMLFactory.groovy
001 /*
002  * Copyright 2008-2016 the original author or authors.
003  *
004  * Licensed under the Apache License, Version 2.0 (the "License");
005  * you may not use this file except in compliance with the License.
006  * You may obtain a copy of the License at
007  *
008  *     http://www.apache.org/licenses/LICENSE-2.0
009  *
010  * Unless required by applicable law or agreed to in writing, software
011  * distributed under the License is distributed on an "AS IS" BASIS,
012  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013  * See the License for the specific language governing permissions and
014  * limitations under the License.
015  */
016 package griffon.builder.javafx.factory
017 
018 import griffon.javafx.support.JavaFXUtils
019 import groovyx.javafx.factory.AbstractNodeFactory
020 import javafx.fxml.FXMLLoader
021 import javafx.scene.Group
022 import javafx.scene.Node
023 
024 /**
025  @author jimclarke
026  @author Andres Almiray
027  @since 2.4.0
028  */
029 class FXMLFactory extends AbstractNodeFactory {
030 
031     private FXMLLoader loader
032 
033     FXMLFactory() {
034         super(Node)
035     }
036 
037     FXMLFactory(Class<Node> beanClass) {
038         super(beanClass)
039     }
040 
041     public Object newInstance(FactoryBuilderSupport builder, Object name, Object value, Map attributesthrows InstantiationException, IllegalAccessException {
042         Node result
043         if (value != null) {
044             result = processValue(value)
045             if (result == null)
046                 throw new Exception("In $name value must be an instanceof InputStream or one of its subclasses, java.net.URL, java.net.URI or a String  to be used as embedded content.")
047         else if (attributes.containsKey("location"|| attributes.containsKey("url")) {
048             def location = attributes.remove("location")
049             if (location == null) {
050                 location = attributes.remove("url")
051             }
052             if (location instanceof String)
053                 location = new URL(location)
054             result = loadInput(location)
055         else if (attributes.containsKey("uri")) {
056             def uri = attributes.remove("uri")
057             if (uri instanceof String)
058                 uri = new URI(uri)
059             result = loadInput(uri.toURL())
060         else if (attributes.containsKey("xml")) {
061             def xml = attributes.remove("xml")
062             result = loadXML(xml)
063         else if (attributes.containsKey("input")) {
064             def input = attributes.remove("input")
065             result = loadInput(input)
066         else // default case
067             result = new Group()
068         }
069 
070         return result
071     }
072 
073     private Node processValue(Object value) {
074         Node result = null
075         switch (value) {
076             case Node:
077                 result = value
078                 break
079             case CharSequence:
080                 try {
081                     URL url = new URL(value.toString())
082                     result = loadInput(url)
083                 catch (MalformedURLException mfe) {
084                     result = loadXML(value.toString())
085                 }
086                 break
087             case InputStream:
088                 result = loadInput(value)
089                 break
090             case URL:
091                 result = loadInput(value)
092                 break
093             case URI:
094                 result = loadInput(value.toURL())
095                 break
096         }
097         result
098     }
099 
100 
101     private Object loadXML(String xml) {
102         this.@loader new FXMLLoader()
103         def ins = new ByteArrayInputStream(xml.getBytes())
104         try {
105             return loader.load(ins)
106         finally {
107             ins.close()
108         }
109     }
110 
111     private Object loadInput(input) {
112         this.@loader new FXMLLoader()
113         return loader.load(input)
114     }
115 
116     @Override
117     public void setChild(FactoryBuilderSupport builder, Object parent, Object child) {
118         Node childNode = processValue(child)
119         if (childNode != null) {
120             parent.children.add(childNode)
121         else {
122             super.setChild(builder, parent, child)
123         }
124     }
125 
126     @Override
127     boolean onNodeChildren(FactoryBuilderSupport builder, Object node, Closure childContent) {
128         childContent.delegate = new FXMLDelegate(loader, node, childContent.delegate)
129         childContent.call()
130         return false
131     }
132 
133     @Override
134     boolean isHandlesNodeChildren() {
135         return true
136     }
137 }
138 
139 class FXMLDelegate {
140     FXMLDelegate(FXMLLoader loader, Node node, GroovyObject superObject) {
141         this.loader = loader
142         this.node = node
143         this.superObject = superObject
144     }
145 
146     private FXMLLoader loader
147     private Node node
148     private GroovyObject superObject
149 
150     @Override
151     def getProperty(String property) {
152         return this.@loader.namespace[property?: this.@node.lookup("#$property"?: JavaFXUtils.findElement(this.@node, property?: this.@superObject.getProperty(property)
153     }
154 }