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