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

Sign up to get free protection for your applications and to get access to all the features.
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