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