jrubyfx-fxmlloader-master 0.4.master.2015.9.30-java

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: dc644450732228d58cf46b09e83897507682f050
4
+ data.tar.gz: 5182f75c1ca24b6071bc05a1d8aa5ec1f471bd6c
5
+ SHA512:
6
+ metadata.gz: 5af1098185d35a107bc1aaa56f4618df20a6d3ee5c23fcab8d0536543b0b3724a8e1c23997bf866431aaff03625fdd0d13f1d730b6b400193ad821b07b7ad1f1
7
+ data.tar.gz: 147737f1087b28239ce2939515a6ef5db4085a7ee14f5c979754d238d0b08a6befe91119f058027d1d87a6a01a458d7f99cb22004a017748b2b9fdc52354a106
data/LICENSE ADDED
@@ -0,0 +1,25 @@
1
+ =begin
2
+ * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
3
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4
+ *
5
+ * This code is free software; you can redistribute it and/or modify it
6
+ * under the terms of the GNU General Public License version 2 only, as
7
+ * published by the Free Software Foundation. Oracle designates this
8
+ * particular file as subject to the "Classpath" exception as provided
9
+ * by Oracle in the LICENSE file that accompanied this code.
10
+ *
11
+ * This code is distributed in the hope that it will be useful, but WITHOUT
12
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14
+ * version 2 for more details (a copy is included in the LICENSE file that
15
+ * accompanied this code).
16
+ *
17
+ * You should have received a copy of the GNU General Public License version
18
+ * 2 along with this work; if not, write to the Free Software Foundation,
19
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20
+ *
21
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22
+ * or visit www.oracle.com if you need additional information or have any
23
+ * questions.
24
+ */
25
+ =end
data/README ADDED
@@ -0,0 +1,17 @@
1
+ # JRubyFX-FxmlLoader
2
+
3
+ JRubyFX-FxmlLoader is the JIT-enabled FXML parser for the JRubyFX project based
4
+ on the official OpenJDK 8 FXML parser. FxmlLoader strives to be a nearly drop-in
5
+ replacement FxmlLoader, only differing in JRuby compatibility.
6
+
7
+ At this point,
8
+ most code is directly copied from OpenJDK and converted to ruby via regexes and
9
+ as such is far from idiomatic ruby. The JIT compiler is also a work in progress.
10
+
11
+ If you would like to help clean up the code please do but be careful about breaking
12
+ FXML. Any 100% standard Java FXML document should work *identically* when run as a JRuby FXML document and
13
+ vice-versa with the exception of JRuby support (like ruby classes & controllers).
14
+
15
+ Use with JRubyFX!
16
+
17
+ rake gem to build. Note that half of this project is java and must be compiled.
data/Rakefile ADDED
@@ -0,0 +1,72 @@
1
+ #
2
+ # To change this template, choose Tools | Templates
3
+ # and open the template in the editor.
4
+
5
+
6
+ require 'rubygems'
7
+ require 'rake'
8
+ require 'rake/clean'
9
+ require 'rubygems/package_task'
10
+ require 'ant'
11
+
12
+ build_dir = "build"
13
+ file build_dir
14
+
15
+ task :java_init => build_dir do
16
+ ant.property :name => "src.dir", :value => "src"
17
+ ant.path(:id => "project.class.path") do
18
+ pathelement :location => "classes"
19
+ end
20
+ ant.tstamp
21
+ ant.mkdir(:dir => build_dir)
22
+ end
23
+
24
+ task :compile => :java_init do
25
+ ant.javac(:destdir => build_dir) do
26
+ classpath :refid => "project.class.path"
27
+ src { pathelement :location => "${src.dir}" }
28
+ end
29
+ end
30
+
31
+ desc "Build the Java component"
32
+ task :jar => :compile do
33
+ ant.jar :destfile => "lib/FXMLLoader-j8.jar", :basedir => build_dir
34
+ end
35
+
36
+ task :java_clean do
37
+ ant.delete(:dir => build_dir)
38
+ ant.delete(:dir => "pkg")
39
+ ant.delete(:file => "lib/FXMLLoader-j8.jar")
40
+ end
41
+
42
+ task :clean => :java_clean
43
+
44
+ task :gem => :jar
45
+
46
+ spec = Gem::Specification.new do |s|
47
+ s.name = 'jrubyfx-fxmlloader-master'
48
+ s.version = '0.4.master.2015.9.30'
49
+ s.platform = 'java'
50
+ s.has_rdoc = true
51
+ s.extra_rdoc_files = ['README', 'LICENSE']
52
+ s.summary = 'GPL\'d JavaFX FXMLLoder class in Ruby for JRubyFX'
53
+ s.description = "JRubyFX FxmlLoader gem bits"
54
+ s.author = 'Patrick Plenefisch & JRubyFX team & Oracle'
55
+ s.email = 'simonpatp@gmail.com'
56
+ s.homepage = "https://github.com/byteit101/JRubyFX-FXMLLoader"
57
+ # s.executables = ['your_executable_here']
58
+ # manually specify it to avoid globbing issues
59
+ s.files = %w(LICENSE README Rakefile lib/FXMLLoader-j8.jar) + Dir.glob("{bin,lib,spec}/**/*")
60
+ s.require_path = "lib"
61
+ s.bindir = "bin"
62
+ s.license = "GPL-2.0-with-classpath-exception"
63
+ end
64
+
65
+ Gem::PackageTask.new(spec) do |p|
66
+ p.gem_spec = spec
67
+ p.need_tar = true
68
+ p.need_zip = true
69
+ end
70
+
71
+
72
+ task :default => :gem
Binary file
@@ -0,0 +1,576 @@
1
+ class JavaProxy
2
+ def default_property
3
+ self.java_class.getAnnotation(DefaultProperty.java_class);
4
+ end
5
+ end
6
+
7
+ class Element
8
+ attr_accessor :parent, :lineNumber, :current, :xmlStreamReader, :loadListener, :parentLoader
9
+ attr_accessor :value, :valueAdapter, :eventHandlerAttributes, :instancePropertyAttributes, :staticPropertyAttributes, :staticPropertyElements
10
+ def initialize(current, xmlStreamReader, loadListener, parentLoader)
11
+ @parent = current;
12
+ @lineNumber = xmlStreamReader.getLocation().getLineNumber();
13
+ @current = current;
14
+ @xmlStreamReader = xmlStreamReader
15
+ @loadListener = loadListener
16
+ @value = nil
17
+ @valueAdapter = nil
18
+ @eventHandlerAttributes = []
19
+ @instancePropertyAttributes = []
20
+ @staticPropertyAttributes = []
21
+ @staticPropertyElements = []
22
+ @parentLoader = parentLoader
23
+ end
24
+ def staticLoad
25
+ @parentLoader.staticLoad
26
+ end
27
+ def callz
28
+ numz = 1
29
+ pppn = @parent
30
+ while pppn
31
+ numz+=1
32
+ pppn = pppn.parent
33
+ end
34
+ (" " * numz) + @lineNumber.to_s + ": "
35
+ end
36
+
37
+ def isCollection()
38
+ # Return true if value is a list, or if the value's type defines
39
+ # a default property that is a list
40
+ collection = false
41
+ if (@value.kind_of?(Enumerable) || @value.java_kind_of?(Java.java.util.List))
42
+ collection = true;
43
+ else
44
+ defaultProperty = @value.java_class.annotation(DefaultProperty.java_class);
45
+
46
+ if (defaultProperty != nil)
47
+ collection = getProperties()[defaultProperty.value].java_kind_of?(Java.java.util.List)
48
+ else
49
+ collection = false;
50
+ end
51
+ end
52
+ return collection;
53
+ end
54
+
55
+ def add(element, prop_name=nil, rputs_elt=nil)
56
+ # If value is a list, add element to it; otherwise, get the value
57
+ # of the default property, which is assumed to be a list and add
58
+ # to that (coerce to the appropriate type)
59
+ if (@value.kind_of?(Enumerable) || @value.java_kind_of?(java.util.List))
60
+ if prop_name == nil
61
+ rputs value, "add(#{rget(element)||element.inspect})"
62
+ else
63
+ rputs @parent.value, "get#{prop_name[0].upcase}#{prop_name[1..-1]}.add(#{rputs_elt || rget(element)||element.inspect})"
64
+ end
65
+ value.to_java
66
+ else
67
+ type = value.java_class
68
+ defaultProperty = type.annotation(DefaultProperty.java_class);
69
+ defaultPropertyName = defaultProperty.to_java.value();
70
+
71
+ # Get the list value
72
+ list = getProperties[defaultPropertyName]
73
+
74
+ # Coerce the element to the list item type
75
+ if (!java.util.Map.java_class.assignable_from?(type))
76
+ listType = @valueAdapter.getGenericType(defaultPropertyName);
77
+ element = RubyWrapperBeanAdapter.coerce(element, RubyWrapperBeanAdapter.getListItemType(listType));
78
+ end
79
+ rputs @value, "get#{defaultPropertyName[0].upcase}#{defaultPropertyName[1..-1]}.add(#{rget(element)||element.inspect})"
80
+ list = list.to_java if list.class == Java::JavaObject
81
+ list
82
+ end.add(element)
83
+ end
84
+
85
+ def set(value)
86
+ unless @value
87
+ raise LoadException.new("Cannot set value on this element.");
88
+ end
89
+
90
+ # Apply value to this element's properties
91
+ type = @value.java_class;
92
+ defaultProperty = type.getAnnotation(DefaultProperty.java_class);
93
+ if (defaultProperty == nil)
94
+ raise LoadException.new("Element does not define a default property.");
95
+ end
96
+
97
+ getProperties[defaultProperty.value] = value
98
+ end
99
+
100
+ def updateValue(value)
101
+ @value = value;
102
+ @valueAdapter = nil;
103
+ end
104
+
105
+ def isTyped()
106
+ !(@value.java_kind_of? Java::java.util.Map or @value.is_a? Hash )
107
+ end
108
+
109
+ def getValueAdapter()
110
+ if (@valueAdapter == nil)
111
+ @valueAdapter = RubyWrapperBeanAdapter.for(@value)
112
+ end
113
+ return @valueAdapter;
114
+ end
115
+
116
+ def getProperties()
117
+ return (isTyped()) ? getValueAdapter() : @value;
118
+ end
119
+
120
+ def processStartElement()
121
+ n = @xmlStreamReader.getAttributeCount()
122
+ n.times do |i|
123
+ prefix = @xmlStreamReader.getAttributePrefix(i);
124
+ localName = @xmlStreamReader.getAttributeLocalName(i);
125
+ value = @xmlStreamReader.getAttributeValue(i);
126
+
127
+ if (@loadListener && prefix && prefix == (FXL::FX_NAMESPACE_PREFIX))
128
+ @loadListener.readInternalAttribute(prefix + ":" + localName, value);
129
+ end
130
+
131
+ processAttribute(prefix, localName, value);
132
+ end
133
+ end
134
+
135
+ def processEndElement()
136
+ # No-op
137
+ end
138
+
139
+ def processCharacters()
140
+ raise LoadException.new("Unexpected characters in input stream.");
141
+ end
142
+
143
+ def processInstancePropertyAttributes()
144
+ if (@instancePropertyAttributes.length > 0)
145
+ for attribute in @instancePropertyAttributes
146
+ processPropertyAttribute(attribute);
147
+ end
148
+ end
149
+ end
150
+
151
+ def processAttribute(prefix, localName, value)
152
+ if (prefix == nil)
153
+ # Add the attribute to the appropriate list
154
+ if (localName.start_with?(FXL::EVENT_HANDLER_PREFIX))
155
+ if (@loadListener != nil)
156
+ @loadListener.readEventHandlerAttribute(localName, value);
157
+ end
158
+ eventHandlerAttributes <<(Attribute.new(localName, nil, value));
159
+ else
160
+ i = localName.rindex('.');
161
+
162
+ if (i == nil)
163
+ # The attribute represents an instance property
164
+ if (@loadListener != nil)
165
+ @loadListener.readPropertyAttribute(localName, nil, value);
166
+ end
167
+
168
+ instancePropertyAttributes << (Attribute.new(localName, nil, value));
169
+ else
170
+ # The attribute represents a static property
171
+ name = localName[(i + 1)..-1];
172
+ sourceType = parentLoader.getType(localName[0, i]);
173
+
174
+ if (sourceType != nil)
175
+ if (@loadListener != nil)
176
+ @loadListener.readPropertyAttribute(name, sourceType, value);
177
+ end
178
+
179
+ @staticPropertyAttributes << (Attribute.new(name, sourceType, value));
180
+ elsif (staticLoad)
181
+ if (@loadListener != nil)
182
+ @loadListener.readUnknownStaticPropertyAttribute(localName, value);
183
+ end
184
+ else
185
+ raise LoadException.new(localName + " is not a valid attribute.");
186
+ end
187
+ end
188
+
189
+ end
190
+ else
191
+ raise LoadException.new(prefix + ":" + localName +
192
+ " is not a valid attribute.");
193
+ end
194
+ end
195
+
196
+ def processPropertyAttribute(attribute)
197
+ value = attribute.value;
198
+ if (isBindingExpression(value))
199
+ # Resolve the expression
200
+
201
+ if (attribute.sourceType != nil)
202
+ raise LoadException.new("Cannot bind to static property.");
203
+ end
204
+
205
+ if (!isTyped())
206
+ raise LoadException.new("Cannot bind to untyped object.");
207
+ end
208
+
209
+ # TODO We may want to identify binding properties in processAttribute()
210
+ # and apply them after build() has been called
211
+ if (@value.is_a? Builder)
212
+ raise LoadException.new("Cannot bind to builder property.");
213
+ end
214
+
215
+ value = value[2..-2] # TODO: BINDING_EXPRESSION_PREFIX == ${
216
+ #value.length() - 1];
217
+ # TODO: this only works for 7, not 8
218
+ expression = Expression.valueOf(value);
219
+ # Create the binding
220
+ targetAdapter = RubyWrapperBeanAdapter.new(@value);
221
+ propertyModel = targetAdapter.getPropertyModel(attribute.name).to_java
222
+ type = targetAdapter.getType(attribute.name);
223
+ if (propertyModel.is_a? Property)
224
+ rputs @value, "#{attribute.name}Property.bind(RRExpressionValue.new(__local_namespace, Java::org.jruby.jfx8.Expression.valueOf(#{value.inspect}), Java::#{type.name.gsub(/[\$\.]/, "::")}.java_class))"
225
+ #expression.value_property.addListener(JRExpressionTargetMapping.new(expression, getProperties(), Expression.split(value)));
226
+ ( propertyModel).bind(RRExpressionValue.new(parentLoader.namespace, expression, type));
227
+ end
228
+ elsif (isBidirectionalBindingExpression(value))
229
+ raise UnsupportedOperationException.new("This feature is not currently enabled.");
230
+ else
231
+ processValue3(attribute.sourceType, attribute.name, value);
232
+ end
233
+ end
234
+
235
+ def isBindingExpression(aValue)
236
+ # TODO: BINDING_EXPRESSION_PREFIX == ${
237
+ aValue.start_with?("${") && aValue.end_with?(FXL::BINDING_EXPRESSION_SUFFIX);
238
+ end
239
+
240
+ def isBidirectionalBindingExpression(aValue)
241
+ return aValue.start_with?(FXL::BI_DIRECTIONAL_BINDING_PREFIX);
242
+ end
243
+
244
+ def processValue3( sourceType, propertyName, aValue)
245
+
246
+
247
+ processed = false;
248
+ #process list or array first
249
+ if (sourceType == nil && isTyped())
250
+ lvalueAdapter = getValueAdapter();
251
+ type = lvalueAdapter.getType(propertyName);
252
+
253
+ if (type == nil)
254
+ dputs "Processing values3 fails on: "
255
+ dp sourceType, propertyName, aValue
256
+ dp lvalueAdapter
257
+ dp caller
258
+ raise("Property \"" + propertyName + "\" does not exist" + " or is read-only.");
259
+ end
260
+ if (List.java_class.assignable_from?(type) && lvalueAdapter.read_only?(propertyName))
261
+ populateListFromString(lvalueAdapter, propertyName, aValue);
262
+ processed = true;
263
+ elsif false #TODO: fix type.ruby_class.ancestors.include? Enumerable
264
+ applyProperty(propertyName, sourceType, populateArrayFromString(type, aValue));
265
+ processed = true;
266
+ end
267
+ end
268
+ if (!processed)
269
+ applyProperty(propertyName, sourceType, resolvePrefixedValue(aValue));
270
+ processed = true;
271
+ end
272
+ return processed;
273
+ end
274
+
275
+
276
+ # Resolves value prefixed with RELATIVE_PATH_PREFIX and
277
+ # RESOURCE_KEY_PREFIX.
278
+
279
+ def resolvePrefixedValue(aValue)
280
+ if (aValue.start_with?(FXL::ESCAPE_PREFIX))
281
+ aValue = aValue[FXL::ESCAPE_PREFIX.length..-1]
282
+
283
+ if (aValue.length == 0 || !(aValue.start_with?(FXL::ESCAPE_PREFIX) ||
284
+ aValue.start_with?(FXL::RELATIVE_PATH_PREFIX) ||
285
+ aValue.start_with?(FXL::RESOURCE_KEY_PREFIX) ||
286
+ aValue.start_with?(FXL::EXPRESSION_PREFIX) ||
287
+ aValue.start_with?(FXL::BI_DIRECTIONAL_BINDING_PREFIX)))
288
+ raise LoadException.new("Invalid escape sequence.");
289
+ end
290
+ return aValue;
291
+ elsif (aValue.start_with?(FXL::RELATIVE_PATH_PREFIX))
292
+ aValue = aValue[FXL::RELATIVE_PATH_PREFIX.length..-1]
293
+ if (aValue.length == 0)
294
+ raise LoadException.new("Missing relative path.");
295
+ end
296
+ if (aValue.start_with?(FXL::RELATIVE_PATH_PREFIX))
297
+ # The prefix was escaped
298
+ warnDeprecatedEscapeSequence(RELATIVE_PATH_PREFIX);
299
+ return aValue;
300
+ else
301
+ begin
302
+ if $JRUBYFX_AOT_COMPILING
303
+ return RelativeFXMLString.new(aValue, URL.new(parentLoader.location, aValue).to_s)
304
+ else
305
+ return (aValue[0] == '/') ? classLoader.getResource(aValue[1..-1]).to_s : URL.new(parentLoader.location, aValue).to_s
306
+ end
307
+ rescue MalformedURLException => e
308
+ dp e
309
+ dputs "#{parentLoader.location} + /+ #{aValue}"
310
+ raise "whoops"
311
+ end
312
+ end
313
+ elsif (aValue.start_with?(FXL::RESOURCE_KEY_PREFIX))
314
+ aValue = aValue[FXL::RESOURCE_KEY_PREFIX.length..-1]
315
+ if (aValue.length() == 0)
316
+ raise LoadException.new("Missing resource key.");
317
+ end
318
+ if (aValue.start_with?(FXL::RESOURCE_KEY_PREFIX))
319
+ # The prefix was escaped
320
+ warnDeprecatedEscapeSequence(FXL::RESOURCE_KEY_PREFIX);
321
+ return aValue;
322
+ else
323
+ # Resolve the resource value
324
+ if (@resources == nil)
325
+ raise LoadException.new("No resources specified.");
326
+ end
327
+ if (!@resources.has_key?(aValue))
328
+ raise LoadException.new("Resource \"" + aValue + "\" not found.");
329
+ end
330
+ return @resources.getString(aValue);
331
+ end
332
+ elsif (aValue.start_with?(FXL::EXPRESSION_PREFIX))
333
+ aValue = aValue[FXL::EXPRESSION_PREFIX.length..-1]
334
+ if (aValue.length() == 0)
335
+ raise LoadException.new("Missing expression.");
336
+ end
337
+ if (aValue.start_with?(FXL::EXPRESSION_PREFIX))
338
+ # The prefix was escaped
339
+ warnDeprecatedEscapeSequence(FXL::EXPRESSION_PREFIX);
340
+ return aValue;
341
+ elsif (aValue == (FXL::NULL_KEYWORD))
342
+ # The attribute value is nil
343
+ return nil;
344
+ end
345
+ # remove all nils, them add one in at the end so [0] returns nil if empty
346
+ q = (KeyPath.parse(aValue).map{|i|parentLoader.namespace[i]} - [nil] + [nil])[0]
347
+ return q
348
+ end
349
+ return aValue;
350
+ end
351
+
352
+ =begin
353
+ * Creates an array of given type and populates it with values from a
354
+ * string where tokens are separated by ARRAY_COMPONENT_DELIMITER. If
355
+ * token is prefixed with RELATIVE_PATH_PREFIX a value added to the
356
+ * array becomes relative to document location.
357
+ =end
358
+ #TODO: fix this udp to use java arrays
359
+ def populateArrayFromString( type, stringValue)
360
+
361
+ propertyValue = nil;
362
+ # Split the string and set the values as an array
363
+ componentType = type.getComponentType();
364
+
365
+ if (stringValue.length > 0)
366
+ values = stringValue.split(FXL::ARRAY_COMPONENT_DELIMITER);
367
+ propertyValue = Array.newInstance(componentType, values.length);
368
+ values.length.times do |i|
369
+ Array.set(propertyValue, i,
370
+ RubyWrapperBeanAdapter.coerce(resolvePrefixedValue(values[i].strip),
371
+ type.getComponentType()));
372
+ end
373
+ else
374
+ propertyValue = Array.newInstance(componentType, 0);
375
+ end
376
+ return propertyValue;
377
+ end
378
+
379
+ =begin
380
+ * Populates list with values from a string where tokens are separated
381
+ * by ARRAY_COMPONENT_DELIMITER. If token is prefixed with
382
+ * RELATIVE_PATH_PREFIX a value added to the list becomes relative to
383
+ * document location.
384
+ =end
385
+ #TODO: check the types
386
+ def populateListFromString( valueAdapter, listPropertyName,stringValue)
387
+ # Split the string and add the values to the list
388
+ list = valueAdapter[listPropertyName].to_java
389
+ listType = valueAdapter.getGenericType(listPropertyName);
390
+ itemType = RubyWrapperBeanAdapter.getGenericListItemType(listType);
391
+
392
+ if (itemType.is_a? ParameterizedType)
393
+ itemType = ( itemType).getRawType();
394
+ end
395
+
396
+ if (stringValue.length() > 0)
397
+ values = stringValue.split(FXL::ARRAY_COMPONENT_DELIMITER)
398
+
399
+ for aValue in values
400
+ aValue = aValue.strip
401
+ list.add(
402
+ RubyWrapperBeanAdapter.coerce(resolvePrefixedValue(aValue),
403
+ itemType));
404
+ end
405
+ end
406
+ end
407
+
408
+ def warnDeprecatedEscapeSequence(prefix)
409
+ puts(prefix + prefix + " is a deprecated escape sequence. " + "Please use \\" + prefix + " instead.");
410
+ end
411
+
412
+ def applyProperty(name, sourceType, value)
413
+ if (sourceType == nil)
414
+ getProperties[name] = value
415
+ else
416
+ RubyWrapperBeanAdapter.put3(@value, sourceType, name, value);
417
+ end
418
+ end
419
+
420
+ def processEventHandlerAttributes()
421
+ if (@eventHandlerAttributes.length > 0 && !parentLoader.staticLoad)
422
+ for attribute in @eventHandlerAttributes
423
+ eventHandler = nil;
424
+ attrValue = attribute.value;
425
+
426
+ if (attrValue.start_with?(FXL::CONTROLLER_METHOD_PREFIX))
427
+ attrValue = attrValue[FXL::CONTROLLER_METHOD_PREFIX.length..-1]
428
+ if (!attrValue.start_with?(FXL::CONTROLLER_METHOD_PREFIX))
429
+ if (attrValue.length() == 0)
430
+ raise LoadException.new("Missing controller method.");
431
+ end
432
+ if (parentLoader.controller == nil)
433
+ dputs "eek"
434
+ raise LoadException.new("No controller specified. ");
435
+ end
436
+
437
+ # method = parentLoader.controller.method(attrValue)
438
+ #
439
+ # if (method == nil)
440
+ # raise LoadException.new("Controller method \"" + attrValue + "\" not found.");
441
+ # end
442
+ eventHandler = EventHandlerWrapper.new(parentLoader.controller, attrValue)
443
+ end
444
+
445
+ elsif (attrValue.start_with?(FXL::EXPRESSION_PREFIX))
446
+ attrValue = attrValue[FXL::EXPRESSION_PREFIX.length..-1]
447
+ if (attrValue.length() == 0)
448
+ raise LoadException.new("Missing expression reference.");
449
+ end
450
+ expression = Expression.get(@namespace, KeyPath.parse(attrValue));
451
+ if (expression.is_a? EventHandler)
452
+ eventHandler = expression;
453
+ end
454
+
455
+ end
456
+ if (eventHandler == nil)
457
+ if (attrValue.length() == 0 || parentLoader.scriptEngine == nil)
458
+ raise LoadException.new("Error resolving " + attribute.name + "='" + attribute.value +
459
+ "', either the event handler is not in the Namespace or there is an error in the script.");
460
+ end
461
+
462
+ eventHandler = ScriptEventHandler.new(attrValue, parentLoader.scriptEngine);
463
+ end
464
+ # Add the handler
465
+ if (eventHandler != nil)
466
+
467
+ addEventHandler(attribute, eventHandler);
468
+ end
469
+ end
470
+ end
471
+ end
472
+
473
+ def addEventHandler(attribute, eventHandler)
474
+ if (attribute.name.end_with?(FXL::CHANGE_EVENT_HANDLER_SUFFIX))
475
+ i = FXL::EVENT_HANDLER_PREFIX.length();
476
+ j = attribute.name.length() - FXL::CHANGE_EVENT_HANDLER_SUFFIX.length();
477
+ if (i == j)
478
+ if (@value.is_a? ObservableList)
479
+ list = @value;
480
+ list.addListener(ObservableListChangeAdapter.new(list, eventHandler));
481
+ elsif (@value.is_a? ObservableMap)
482
+ map = @value;
483
+ map.addListener(ObservableMapChangeAdapter.new(map, eventHandler));
484
+ else
485
+ raise LoadException.new("Invalid event source.");
486
+ end
487
+ else
488
+ key = attribute.name[i].downcase + attribute.name[i + 1, j]
489
+ propertyModel = getValueAdapter().getPropertyModel(key);
490
+ if (propertyModel == nil)
491
+ raise LoadException.new(@value.getClass().getName() + " does not define" + " a property model for \"" + key + "\".");
492
+ end
493
+
494
+ propertyModel.addListener(PropertyChangeAdapter.new(@value, eventHandler));
495
+ end
496
+ else
497
+ getValueAdapter[attribute.name] = eventHandler
498
+ end
499
+ end
500
+ end
501
+
502
+ class Attribute
503
+ attr_accessor :name, :sourceType, :value
504
+ def initialize( paramString1,paramClass, paramString2)
505
+ @name = paramString1;
506
+ @sourceType = paramClass;
507
+ @value = paramString2;
508
+ end
509
+ end
510
+
511
+ class EventHandlerWrapper
512
+ include EventHandler
513
+ attr_reader :funcName
514
+ def initialize(ctrl, funcName)
515
+ @ctrl = ctrl
516
+ @funcName = funcName
517
+ end
518
+ def handle(eventArgs)
519
+ if @ctrl.respond_to? @funcName
520
+ if @ctrl.method(@funcName).arity == 0
521
+ @ctrl.send(@funcName)
522
+ else
523
+ @ctrl.send(@funcName, eventArgs)
524
+ end
525
+ else
526
+ puts "Warning: method #{@funcName} was not found on controller #{@ctrl}"
527
+ end
528
+ end
529
+ end
530
+
531
+ class ScriptEventHandler
532
+ include EventHandler
533
+ attr_reader :script, :scriptEngine
534
+ def initialize(script, scriptEngine)
535
+ @script = script;
536
+ @scriptEngine = scriptEngine;
537
+ end
538
+
539
+ def handle(event)
540
+ # Don't pollute the page namespace with values defined in the script
541
+ engineBindings = @scriptEngine.getBindings(ScriptContext::ENGINE_SCOPE);
542
+ #localBindings = @scriptEngine.createBindings(); # TODO: this causes errors with nashorn in jdk8 by creating a different kind of
543
+ # script object that doesn't respect the magic nashorn.global object
544
+ localBindings = Java::JavaxScript::SimpleBindings.new
545
+ localBindings.put_all(engineBindings)
546
+ localBindings.put(FXL::EVENT_KEY, event);
547
+ @scriptEngine.setBindings(localBindings, ScriptContext::ENGINE_SCOPE);
548
+
549
+ # Execute the script
550
+ begin
551
+ @scriptEngine.eval(@script);
552
+ rescue ScriptException => exception
553
+ raise exception
554
+ end
555
+
556
+ # Restore the original bindings
557
+ @scriptEngine.setBindings(engineBindings, ScriptContext::ENGINE_SCOPE);
558
+ end
559
+ end
560
+
561
+ class RelativeFXMLString < String
562
+ alias :super_inspect :inspect
563
+ def initialize(str, rel)
564
+ super(rel)
565
+ @rel = str
566
+ end
567
+ def inspect
568
+ "java.net.URL.new(__local_namespace['location'], #{@rel.inspect}).to_s"
569
+ end
570
+ def to_s
571
+ super
572
+ end
573
+ def class()
574
+ String
575
+ end
576
+ end