jrubyfx 1.1.0-java → 2.0.0-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.
@@ -0,0 +1,134 @@
1
+ require 'java'
2
+ require 'jruby/core_ext'
3
+
4
+ module JRubyFX::FxmlHelper
5
+ include_package 'javax.xml.stream'
6
+ include_package 'javafx.fxml'
7
+ import 'java.nio.charset.Charset'
8
+
9
+ # fxmlloader transformer, modifies clazz to be compatible with the fxml file
10
+ def self.transform(clazz, fxml_url)
11
+ packages = []
12
+ classes = {}
13
+ attribs = []
14
+
15
+ begin
16
+
17
+ # Read in the stream and set everything up
18
+
19
+ inputStream = fxml_url.open_stream
20
+ xmlInputFactory = XMLInputFactory.newFactory
21
+ xmlInputFactory.setProperty("javax.xml.stream.isCoalescing", true)
22
+
23
+ # Some stream readers incorrectly report an empty string as the prefix
24
+ # for the default namespace; correct this as needed
25
+ inputStreamReader = java.io.InputStreamReader.new(inputStream, Charset.forName("UTF-8"))
26
+ xmlStreamReader = xmlInputFactory.createXMLStreamReader(inputStreamReader)
27
+
28
+ # set up a quick map so we can easily look up java return values with jruby values for the xml events
29
+ dm = Hash[XMLStreamConstants.constants.map {|x| [XMLStreamConstants.const_get(x), x] }]
30
+
31
+ lastType = nil
32
+ while xmlStreamReader.hasNext
33
+ event = xmlStreamReader.next
34
+
35
+ case dm[event]
36
+ when :PROCESSING_INSTRUCTION
37
+ # PI's needs to be added to our package list
38
+ if xmlStreamReader.pi_target.strip == FXMLLoader::IMPORT_PROCESSING_INSTRUCTION
39
+ name = xmlStreamReader.pi_data.strip
40
+
41
+ # importing package vs class
42
+ if name.end_with? ".*"
43
+ packages << name[0...-2] # strip the .* and add to package list
44
+ else
45
+ i = name.index('.') # find the package/class split, should probably be backwards, but eh
46
+ i = name.index('.', i + 1) while i && i < name.length && name[i + 1] == name[i + 1].downcase
47
+
48
+ if i.nil? or i+1 >= name.length
49
+ raise LoadException.new(NameError.new(name))#TODO: rubyize the stack trace TODO: test
50
+ end
51
+
52
+ class_name = name[(i + 1)..-1]
53
+ pkg_name = "#{name[0...i]}.#{class_name.gsub('.', '$')}"
54
+
55
+ # now that we have the class name, look it up and add to the list, or if failure, assume ruby
56
+ classes[class_name] = begin
57
+ JavaUtilities.get_proxy_class(pkg_name).java_class.to_java
58
+ rescue NameError => ex # probably ruby class
59
+ begin
60
+ pkg_name.constantize_by(".")
61
+ rescue
62
+ raise LoadException.new(NameError.new(pkg_name)) # nope, not our issue anymore TODO: rubyize?
63
+ end
64
+ end
65
+
66
+ end
67
+ end
68
+ when :START_ELEMENT
69
+ # search start elements for ID's that we need to inject on init
70
+ lastType = xmlStreamReader.local_name
71
+
72
+ # search all atttribues for id and events
73
+ xmlStreamReader.attribute_count.times do |i|
74
+ prefix = xmlStreamReader.get_attribute_prefix(i)
75
+ localName = xmlStreamReader.get_attribute_local_name(i)
76
+ value = xmlStreamReader.get_attribute_value(i)
77
+
78
+ # if it is an id, save the id and annotate it as injectable by JavaFX. Default to object since ruby land doesn't care...
79
+ if localName == "id" and prefix == FXMLLoader::FX_NAMESPACE_PREFIX
80
+ #puts "GOT ID! #{lastType} #{value}"
81
+ attribs << value
82
+
83
+ # add the field to the controller
84
+ clazz.instance_eval do
85
+ # Note: we could detect the type, but Ruby doesn't care, and neither does JavaFX's FXMLLoader
86
+ java_field "@javafx.fxml.FXML java.lang.Object #{value}", instance_variable: true
87
+ end
88
+ # otherwise, if it is an event, add a forwarding call
89
+ elsif localName.start_with? "on" and value.start_with? "#"
90
+ mname = value[1..-1] # strip hash
91
+ aname = "jrubyfx_aliased_#{mname}"
92
+
93
+ # TODO: use java proxy rewrites
94
+ # add the method to the controller by aliasing the old method, and replacing it with our own fxml-annotated forwarding call
95
+ clazz.instance_eval do
96
+ alias_method aname.to_sym, mname.to_sym if method_defined? mname.to_sym
97
+ java_signature "@javafx.fxml.FXML void #{mname}(javafx.event.Event)"
98
+ define_method(mname) do |e|
99
+ if respond_to? aname
100
+ if method(aname).arity == 0
101
+ send(aname)
102
+ else
103
+ send(aname, e)
104
+ end
105
+ else
106
+ puts "Warning: method #{mname} was not found on controller #{self}"
107
+ end
108
+ end
109
+ end
110
+
111
+ end
112
+ end
113
+ end
114
+ end
115
+ # poorly dispose of stream reader
116
+ xmlStreamReader = nil
117
+
118
+ # have to jump through hoops to set the classwide list
119
+ class << clazz
120
+ define_method :__jruby_set_insts, &(lambda {|list|
121
+ @__jrubyfx_fxml_ids = list
122
+ })
123
+ define_method :__jruby_get_insts, &(lambda {
124
+ @__jrubyfx_fxml_ids
125
+ })
126
+ end
127
+ clazz.__jruby_set_insts(attribs)
128
+
129
+ clazz.become_java!
130
+ rescue XMLStreamException => exception
131
+ raise (exception)
132
+ end
133
+ end
134
+ end