001 /*
002 * Copyright 2008-2015 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 attributes) throws 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 }
|