jrubyfx-fxmlloader 0.2-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.
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,5 @@
1
+ == FXMLLoader
2
+
3
+ Use with JRubyFX.
4
+
5
+ rake gem to build
@@ -0,0 +1,71 @@
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'
48
+ s.version = '0.2'
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
+ end
63
+
64
+ Gem::PackageTask.new(spec) do |p|
65
+ p.gem_spec = spec
66
+ p.need_tar = true
67
+ p.need_zip = true
68
+ end
69
+
70
+
71
+ task :default => :gem
Binary file
@@ -0,0 +1,564 @@
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
+ dputs callz + "Is it a collection? #{collection.inspect} <= #{@value.java_class}"
53
+ return collection;
54
+ end
55
+
56
+ def add(element)
57
+ dputs callz + "about to add #{element} to #{value.to_java}"
58
+ # If value is a list, add element to it; otherwise, get the value
59
+ # of the default property, which is assumed to be a list and add
60
+ # to that (coerce to the appropriate type)
61
+ if (@value.kind_of?(Enumerable) || @value.java_kind_of?(java.util.List))
62
+ value.to_java
63
+ else
64
+ type = value.java_class
65
+ defaultProperty = type.annotation(DefaultProperty.java_class);
66
+ defaultPropertyName = defaultProperty.to_java.value();
67
+
68
+ # Get the list value
69
+ list = getProperties[defaultPropertyName]
70
+
71
+ # Coerce the element to the list item type
72
+ if (!Map.java_class.assignable_from?(type))
73
+ listType = @valueAdapter.getGenericType(defaultPropertyName);
74
+ element = RubyWrapperBeanAdapter.coerce(element, RubyWrapperBeanAdapter.getListItemType(listType));
75
+ end
76
+ list = list.to_java if list.class == Java::JavaObject
77
+ list
78
+ end.add(element)
79
+ end
80
+
81
+ def set(value)
82
+ unless @value
83
+ raise LoadException.new("Cannot set value on this element.");
84
+ end
85
+
86
+ # Apply value to this element's properties
87
+ type = @value.java_class;
88
+ defaultProperty = type.getAnnotation(DefaultProperty.java_class);
89
+ if (defaultProperty == nil)
90
+ raise LoadException.new("Element does not define a default property.");
91
+ end
92
+
93
+ getProperties[defaultProperty.value] = value
94
+ end
95
+
96
+ def updateValue(value)
97
+ dputs callz + "Updating value from #{@value} to #{value.class}"
98
+ @value = value;
99
+ @valueAdapter = nil;
100
+ end
101
+
102
+ def isTyped()
103
+ dputs callz + "checking if typed"
104
+ dp @value.class
105
+ dp @value
106
+ q = !(@value.java_kind_of? Java::java.util.Map or @value.is_a? Hash );
107
+ dputs callz + "type result: #{q.inspect}"
108
+ q
109
+ end
110
+
111
+ def getValueAdapter()
112
+ if (@valueAdapter == nil)
113
+ dputs callz + "trying to get itqq"
114
+ dprint callz
115
+ dprint @value
116
+ dputs @value.class
117
+ dputs caller
118
+ if @value.class.to_s == "Java::JavafxFxml::ObjectBuilder"
119
+ dputs caller
120
+ end
121
+ if @value.is_a? java.lang.Object
122
+ dputs callz + "trying to call wrapper"
123
+ @valueAdapter = RubyWrapperBeanAdapter.new(@value);
124
+ else
125
+ dputs callz + "trying to call ruby object wrapper"
126
+ @valueAdapter = RubyObjectWrapperBeanAdapter.new(@value)
127
+ end
128
+ dputs callz + "got"
129
+ end
130
+ return @valueAdapter;
131
+ end
132
+
133
+ def getProperties()
134
+ return (isTyped()) ? getValueAdapter() : @value;
135
+ end
136
+
137
+ def processStartElement()
138
+ n = @xmlStreamReader.getAttributeCount()
139
+ n.times do |i|
140
+ prefix = @xmlStreamReader.getAttributePrefix(i);
141
+ localName = @xmlStreamReader.getAttributeLocalName(i);
142
+ value = @xmlStreamReader.getAttributeValue(i);
143
+
144
+ if (@loadListener && prefix && prefix == (FXL::FX_NAMESPACE_PREFIX))
145
+ @loadListener.readInternalAttribute(prefix + ":" + localName, value);
146
+ end
147
+
148
+ processAttribute(prefix, localName, value);
149
+ end
150
+ end
151
+
152
+ def processEndElement()
153
+ # No-op
154
+ end
155
+
156
+ def processCharacters()
157
+ raise LoadException.new("Unexpected characters in input stream.");
158
+ end
159
+
160
+ def processInstancePropertyAttributes()
161
+ if (@instancePropertyAttributes.length > 0)
162
+ for attribute in @instancePropertyAttributes
163
+ processPropertyAttribute(attribute);
164
+ end
165
+ end
166
+ end
167
+
168
+ def processAttribute(prefix, localName, value)
169
+ if (prefix == nil)
170
+ # Add the attribute to the appropriate list
171
+ if (localName.start_with?(FXL::EVENT_HANDLER_PREFIX))
172
+ if (@loadListener != nil)
173
+ @loadListener.readEventHandlerAttribute(localName, value);
174
+ end
175
+ dputs callz + "found eventHandler prefix #{prefix}, #{localName}, #{value}"
176
+ eventHandlerAttributes <<(Attribute.new(localName, nil, value));
177
+ else
178
+ i = localName.rindex('.');
179
+
180
+ if (i == nil)
181
+ # The attribute represents an instance property
182
+ if (@loadListener != nil)
183
+ @loadListener.readPropertyAttribute(localName, nil, value);
184
+ end
185
+
186
+ dputs callz + "found property attrib #{prefix}, #{localName}, #{value}"
187
+ instancePropertyAttributes << (Attribute.new(localName, nil, value));
188
+ else
189
+ # The attribute represents a static property
190
+ name = localName[(i + 1)..-1];
191
+ sourceType = parentLoader.getType(localName[0, i]);
192
+
193
+ dputs callz + "found static property #{prefix}, #{localName}, #{value}"
194
+ dputs callz + "and its #{sourceType}, #{staticLoad}"
195
+ if (sourceType != nil)
196
+ if (@loadListener != nil)
197
+ @loadListener.readPropertyAttribute(name, sourceType, value);
198
+ end
199
+
200
+ @staticPropertyAttributes << (Attribute.new(name, sourceType, value));
201
+ elsif (staticLoad)
202
+ if (@loadListener != nil)
203
+ @loadListener.readUnknownStaticPropertyAttribute(localName, value);
204
+ end
205
+ else
206
+ raise LoadException.new(localName + " is not a valid attribute.");
207
+ end
208
+ end
209
+
210
+ end
211
+ else
212
+ raise LoadException.new(prefix + ":" + localName +
213
+ " is not a valid attribute.");
214
+ end
215
+ end
216
+
217
+ def processPropertyAttribute(attribute)
218
+ value = attribute.value;
219
+ if (isBindingExpression(value))
220
+ dputs callz + "is a binding !"
221
+ # Resolve the expression
222
+
223
+ if (attribute.sourceType != nil)
224
+ raise LoadException.new("Cannot bind to static property.");
225
+ end
226
+
227
+ if (!isTyped())
228
+ raise LoadException.new("Cannot bind to untyped object.");
229
+ end
230
+
231
+ # TODO We may want to identify binding properties in processAttribute()
232
+ # and apply them after build() has been called
233
+ if (@value.is_a? Builder)
234
+ raise LoadException.new("Cannot bind to builder property.");
235
+ end
236
+
237
+ value = value[2..-2] # TODO: BINDING_EXPRESSION_PREFIX == ${
238
+ #value.length() - 1];
239
+ # TODO: this only works for 7, not 8
240
+ dputs "getting expression value of '#{value}' with #{parentLoader.namespace}"
241
+ expression = Expression.valueOf(value);
242
+ dputs callz + "got the expression as '#{expression}'"
243
+ dp expression
244
+ # Create the binding
245
+ targetAdapter = RubyWrapperBeanAdapter.new(@value);
246
+ dputs callz + "target adapter is #{targetAdapter} from #{value}"
247
+ propertyModel = targetAdapter.getPropertyModel(attribute.name).to_java
248
+ type = targetAdapter.getType(attribute.name);
249
+ dputs callz + "prop model is #{propertyModel.inspect} and type is #{type.inspect}"
250
+ if (propertyModel.is_a? Property)
251
+ dputs callz + "checking out value using #{parentLoader.namespace}"
252
+ #expression.value_property.addListener(JRExpressionTargetMapping.new(expression, getProperties(), Expression.split(value)));
253
+ ( propertyModel).bind(RRExpressionValue.new(parentLoader.namespace, expression, type));
254
+ dputs callz + "bound!"
255
+ end
256
+ elsif (isBidirectionalBindingExpression(value))
257
+ raise UnsupportedOperationException.new("This feature is not currently enabled.");
258
+ else
259
+ dputs callz + "processing 3 for #{attribute.sourceType}, #{attribute.name}, #{value}"
260
+ processValue3(attribute.sourceType, attribute.name, value);
261
+ end
262
+ end
263
+
264
+ def isBindingExpression(aValue)
265
+ dputs callz + "checking if '#{aValue}' is a binding prefix..."
266
+ # TODO: BINDING_EXPRESSION_PREFIX == ${
267
+ q = aValue.start_with?("${") && aValue.end_with?(FXL::BINDING_EXPRESSION_SUFFIX);
268
+ dputs callz + "it is? #{q.inspect}"
269
+ q
270
+ end
271
+
272
+ def isBidirectionalBindingExpression(aValue)
273
+ return aValue.start_with?(FXL::BI_DIRECTIONAL_BINDING_PREFIX);
274
+ end
275
+
276
+ def processValue3( sourceType, propertyName, aValue)
277
+
278
+
279
+ processed = false;
280
+ #process list or array first
281
+ if (sourceType == nil && isTyped())
282
+ dputs callz + "getting value adptr"
283
+ lvalueAdapter = getValueAdapter();
284
+ type = lvalueAdapter.getType(propertyName);
285
+
286
+ if (type == nil)
287
+ dputs "Processing values3 fails on: "
288
+ dp sourceType, propertyName, aValue
289
+ dp lvalueAdapter
290
+ dp caller
291
+ raise PropertyNotFoundException.new("Property \"" + propertyName + "\" does not exist" + " or is read-only.");
292
+ end
293
+ dputs "checking assignable"
294
+ if (List.java_class.assignable_from?(type) && lvalueAdapter.read_only?(propertyName))
295
+ populateListFromString(lvalueAdapter, propertyName, aValue);
296
+ processed = true;
297
+ elsif false #TODO: fix type.ruby_class.ancestors.include? Enumerable
298
+ applyProperty(propertyName, sourceType, populateArrayFromString(type, aValue));
299
+ processed = true;
300
+ end
301
+ end
302
+ dputs callz + "276"
303
+ if (!processed)
304
+ dputs callz + "Must appky it"
305
+ applyProperty(propertyName, sourceType, resolvePrefixedValue(aValue));
306
+ dputs callz + "280"
307
+ processed = true;
308
+ end
309
+ return processed;
310
+ end
311
+
312
+
313
+ # Resolves value prefixed with RELATIVE_PATH_PREFIX and
314
+ # RESOURCE_KEY_PREFIX.
315
+
316
+ def resolvePrefixedValue(aValue)
317
+ if (aValue.start_with?(FXL::ESCAPE_PREFIX))
318
+ aValue = aValue[FXL::ESCAPE_PREFIX.length..-1]
319
+
320
+ if (aValue.length == 0 || !(aValue.start_with?(FXL::ESCAPE_PREFIX) ||
321
+ aValue.start_with?(FXL::RELATIVE_PATH_PREFIX) ||
322
+ aValue.start_with?(FXL::RESOURCE_KEY_PREFIX) ||
323
+ aValue.start_with?(FXL::EXPRESSION_PREFIX) ||
324
+ aValue.start_with?(FXL::BI_DIRECTIONAL_BINDING_PREFIX)))
325
+ raise LoadException.new("Invalid escape sequence.");
326
+ end
327
+ return aValue;
328
+ elsif (aValue.start_with?(FXL::RELATIVE_PATH_PREFIX))
329
+ aValue = aValue[FXL::RELATIVE_PATH_PREFIX.length..-1]
330
+ if (aValue.length == 0)
331
+ raise LoadException.new("Missing relative path.");
332
+ end
333
+ if (aValue.start_with?(FXL::RELATIVE_PATH_PREFIX))
334
+ # The prefix was escaped
335
+ warnDeprecatedEscapeSequence(RELATIVE_PATH_PREFIX);
336
+ return aValue;
337
+ else
338
+ begin
339
+ return (aValue[0] == '/') ? classLoader.getResource(aValue[1..-1]).to_s : URL.new(parentLoader.location, aValue).to_s
340
+ rescue MalformedURLException => e
341
+ dp e
342
+ dputs "#{parentLoader.location} + /+ #{aValue}"
343
+ raise "whoops"
344
+ end
345
+ end
346
+ elsif (aValue.start_with?(FXL::RESOURCE_KEY_PREFIX))
347
+ aValue = aValue[FXL::RESOURCE_KEY_PREFIX.length..-1]
348
+ if (aValue.length() == 0)
349
+ raise LoadException.new("Missing resource key.");
350
+ end
351
+ if (aValue.start_with?(FXL::RESOURCE_KEY_PREFIX))
352
+ # The prefix was escaped
353
+ warnDeprecatedEscapeSequence(FXL::RESOURCE_KEY_PREFIX);
354
+ return aValue;
355
+ else
356
+ # Resolve the resource value
357
+ if (@resources == nil)
358
+ raise LoadException.new("No resources specified.");
359
+ end
360
+ if (!@resources.has_key?(aValue))
361
+ raise LoadException.new("Resource \"" + aValue + "\" not found.");
362
+ end
363
+ return @resources.getString(aValue);
364
+ end
365
+ elsif (aValue.start_with?(FXL::EXPRESSION_PREFIX))
366
+ aValue = aValue[FXL::EXPRESSION_PREFIX.length..-1]
367
+ if (aValue.length() == 0)
368
+ raise LoadException.new("Missing expression.");
369
+ end
370
+ if (aValue.start_with?(FXL::EXPRESSION_PREFIX))
371
+ # The prefix was escaped
372
+ warnDeprecatedEscapeSequence(FXL::EXPRESSION_PREFIX);
373
+ return aValue;
374
+ elsif (aValue == (FXL::NULL_KEYWORD))
375
+ # The attribute value is nil
376
+ return nil;
377
+ end
378
+ dputs callz + "Getting expression '#{aValue}'"
379
+ # remove all nils, them add one in at the end so [0] returns nil if empty
380
+ q = (KeyPath.parse(aValue).map{|i|parentLoader.namespace[i]} - [nil] + [nil])[0]
381
+ dputs callz + "Parsed Expression! #{q};;;;#{q.inspect}"
382
+ return q
383
+ end
384
+ return aValue;
385
+ end
386
+
387
+ =begin
388
+ * Creates an array of given type and populates it with values from a
389
+ * string where tokens are separated by ARRAY_COMPONENT_DELIMITER. If
390
+ * token is prefixed with RELATIVE_PATH_PREFIX a value added to the
391
+ * array becomes relative to document location.
392
+ =end
393
+ #TODO: fix this udp to use java arrays
394
+ def populateArrayFromString( type, stringValue)
395
+
396
+ propertyValue = nil;
397
+ # Split the string and set the values as an array
398
+ componentType = type.getComponentType();
399
+
400
+ if (stringValue.length > 0)
401
+ values = stringValue.split(FXL::ARRAY_COMPONENT_DELIMITER);
402
+ propertyValue = Array.newInstance(componentType, values.length);
403
+ values.length.times do |i|
404
+ Array.set(propertyValue, i,
405
+ RubyWrapperBeanAdapter.coerce(resolvePrefixedValue(values[i].strip),
406
+ type.getComponentType()));
407
+ end
408
+ else
409
+ propertyValue = Array.newInstance(componentType, 0);
410
+ end
411
+ return propertyValue;
412
+ end
413
+
414
+ =begin
415
+ * Populates list with values from a string where tokens are separated
416
+ * by ARRAY_COMPONENT_DELIMITER. If token is prefixed with
417
+ * RELATIVE_PATH_PREFIX a value added to the list becomes relative to
418
+ * document location.
419
+ =end
420
+ #TODO: check the types
421
+ def populateListFromString( valueAdapter, listPropertyName,stringValue)
422
+ # Split the string and add the values to the list
423
+ list = valueAdapter[listPropertyName].to_java
424
+ listType = valueAdapter.getGenericType(listPropertyName);
425
+ itemType = RubyWrapperBeanAdapter.getGenericListItemType(listType);
426
+
427
+ if (itemType.is_a? ParameterizedType)
428
+ itemType = ( itemType).getRawType();
429
+ end
430
+
431
+ if (stringValue.length() > 0)
432
+ values = stringValue.split(FXL::ARRAY_COMPONENT_DELIMITER)
433
+
434
+ for aValue in values
435
+ aValue = aValue.strip
436
+ list.add(
437
+ RubyWrapperBeanAdapter.coerce(resolvePrefixedValue(aValue),
438
+ itemType));
439
+ end
440
+ end
441
+ end
442
+
443
+ def warnDeprecatedEscapeSequence(prefix)
444
+ puts(prefix + prefix + " is a deprecated escape sequence. " + "Please use \\" + prefix + " instead.");
445
+ end
446
+
447
+ def applyProperty(name, sourceType, value)
448
+ if (sourceType == nil)
449
+ getProperties[name] = value
450
+ else
451
+ RubyWrapperBeanAdapter.put3(@value, sourceType, name, value);
452
+ end
453
+ end
454
+
455
+ def processEventHandlerAttributes()
456
+ if (@eventHandlerAttributes.length > 0 && !parentLoader.staticLoad)
457
+ for attribute in @eventHandlerAttributes
458
+ eventHandler = nil;
459
+ attrValue = attribute.value;
460
+
461
+ if (attrValue.start_with?(FXL::CONTROLLER_METHOD_PREFIX))
462
+ attrValue = attrValue[FXL::CONTROLLER_METHOD_PREFIX.length..-1]
463
+ if (!attrValue.start_with?(FXL::CONTROLLER_METHOD_PREFIX))
464
+ if (attrValue.length() == 0)
465
+ raise LoadException.new("Missing controller method.");
466
+ end
467
+ if (parentLoader.controller == nil)
468
+ dputs "eek"
469
+ raise LoadException.new("No controller specified. ");
470
+ end
471
+
472
+ # method = parentLoader.controller.method(attrValue)
473
+ #
474
+ # if (method == nil)
475
+ # raise LoadException.new("Controller method \"" + attrValue + "\" not found.");
476
+ # end
477
+ eventHandler = EventHandlerWrapper.new(parentLoader.controller, attrValue)
478
+ end
479
+
480
+ elsif (attrValue.start_with?(FXL::EXPRESSION_PREFIX))
481
+ attrValue = attrValue[FXL::EXPRESSION_PREFIX.length..-1]
482
+ if (attrValue.length() == 0)
483
+ raise LoadException.new("Missing expression reference.");
484
+ end
485
+ dputs callz + "exprValue!' #{attrValue}'"
486
+ expression = Expression.get(@namespace, KeyPath.parse(attrValue));
487
+ if (expression.is_a? EventHandler)
488
+ eventHandler = expression;
489
+ end
490
+
491
+ end
492
+ if (eventHandler == nil)
493
+ if (attrValue.length() == 0 || @scriptEngine == nil)
494
+ raise LoadException.new("Error resolving " + attribute.name + "='" + attribute.value +
495
+ "', either the event handler is not in the Namespace or there is an error in the script.");
496
+ end
497
+
498
+ eventHandler = ScriptEventHandler.new(attrValue, @scriptEngine);
499
+ end
500
+ # Add the handler
501
+ if (eventHandler != nil)
502
+
503
+ addEventHandler(attribute, eventHandler);
504
+ end
505
+ end
506
+ end
507
+ end
508
+
509
+ def addEventHandler(attribute, eventHandler)
510
+ if (attribute.name.end_with?(FXL::CHANGE_EVENT_HANDLER_SUFFIX))
511
+ i = FXL::EVENT_HANDLER_PREFIX.length();
512
+ j = attribute.name.length() - FXL::CHANGE_EVENT_HANDLER_SUFFIX.length();
513
+ if (i == j)
514
+ if (@value.is_a? ObservableList)
515
+ list = @value;
516
+ list.addListener(ObservableListChangeAdapter.new(list, eventHandler));
517
+ elsif (@value.is_a? ObservableMap)
518
+ map = @value;
519
+ map.addListener(ObservableMapChangeAdapter.new(map, eventHandler));
520
+ else
521
+ raise LoadException.new("Invalid event source.");
522
+ end
523
+ else
524
+ key = attribute.name[i].downcase + attribute.name[i + 1, j]
525
+ propertyModel = getValueAdapter().getPropertyModel(key);
526
+ if (propertyModel == nil)
527
+ raise LoadException.new(@value.getClass().getName() + " does not define" + " a property model for \"" + key + "\".");
528
+ end
529
+
530
+ propertyModel.addListener(PropertyChangeAdapter.new(@value, eventHandler));
531
+ end
532
+ else
533
+ getValueAdapter[attribute.name] = eventHandler
534
+ end
535
+ end
536
+ end
537
+
538
+ class Attribute
539
+ attr_accessor :name, :sourceType, :value
540
+ def initialize( paramString1,paramClass, paramString2)
541
+ @name = paramString1;
542
+ @sourceType = paramClass;
543
+ @value = paramString2;
544
+ end
545
+ end
546
+
547
+ class EventHandlerWrapper
548
+ include EventHandler
549
+ def initialize(ctrl, funcName)
550
+ @ctrl = ctrl
551
+ @funcName = funcName
552
+ end
553
+ def handle(eventArgs)
554
+ if @ctrl.respond_to? @funcName
555
+ if @ctrl.method(@funcName).arity == 0
556
+ @ctrl.send(@funcName)
557
+ else
558
+ @ctrl.send(@funcName, eventArgs)
559
+ end
560
+ else
561
+ dputs "Warning: method #{@funcName} was not found on controller #{@ctrl}"
562
+ end
563
+ end
564
+ end