glimmer-dsl-swing 0.0.1

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,242 @@
1
+ # Copyright (c) 2021 Andy Maleh
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person obtaining
4
+ # a copy of this software and associated documentation files (the
5
+ # "Software"), to deal in the Software without restriction, including
6
+ # without limitation the rights to use, copy, modify, merge, publish,
7
+ # distribute, sublicense, and/or sell copies of the Software, and to
8
+ # permit persons to whom the Software is furnished to do so, subject to
9
+ # the following conditions:
10
+ #
11
+ # The above copyright notice and this permission notice shall be
12
+ # included in all copies or substantial portions of the Software.
13
+ #
14
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
+
22
+ require 'glimmer/swing/packages'
23
+ require 'glimmer/swing/component_listener_proxy'
24
+
25
+ module Glimmer
26
+ module Swing
27
+ # Proxy for Swing/AWT component objects
28
+ #
29
+ # Follows the Proxy Design Pattern
30
+ class ComponentProxy
31
+ include Packages
32
+
33
+ class << self
34
+ def exist?(keyword)
35
+ !!component_proxy_class(keyword)
36
+ end
37
+
38
+ def create(parent, keyword, *args, &block)
39
+ component_proxy_class(keyword).new(parent, keyword, *args, &block)
40
+ end
41
+
42
+ def component_proxy_class(keyword)
43
+ begin
44
+ class_name = component_proxy_class_symbol(keyword)
45
+ Glimmer::Swing::ComponentProxy.const_get(class_name)
46
+ rescue => e
47
+ Glimmer::Config.logger.debug e.full_message
48
+ Glimmer::Swing::ComponentProxy
49
+ end
50
+ end
51
+
52
+ def component_proxy_class_symbol(keyword)
53
+ "#{keyword.camelcase(:upper)}Proxy".to_sym
54
+ end
55
+
56
+ def component_class_symbol(keyword)
57
+ keyword.camelcase(:upper).to_sym
58
+ end
59
+
60
+ def keyword(component_proxy_class)
61
+ component_proxy_class.to_s.underscore.sub(/_proxy$/, '')
62
+ end
63
+
64
+ def component_class_manual_entries
65
+ # add mappings for any classes (minus the namespace) that conflict with standard Ruby classes
66
+ {
67
+ # example:
68
+ # 'date_time' => Java::OrgEclipseSwtWidgets::DateTime
69
+ }
70
+ end
71
+
72
+ def component_class(keyword)
73
+ unless flyweight_component_class.keys.include?(keyword)
74
+ begin
75
+ pd component_class_name = component_class_symbol(keyword).to_s
76
+ pd component_class = eval(component_class_name)
77
+ unless component_class.ancestors.include?(Java::JavaAwt::Component)
78
+ component_class = component_class_manual_entries[keyword]
79
+ if component_class.nil?
80
+ Glimmer::Config.logger.debug {"Class #{component_class} matching #{keyword} is not a subclass of java.awt.Component"}
81
+ return nil
82
+ end
83
+ end
84
+ flyweight_component_class[keyword] = component_class
85
+ rescue SyntaxError, NameError => e
86
+ Glimmer::Config.logger.debug {e.full_message}
87
+ nil
88
+ rescue => e
89
+ Glimmer::Config.logger.debug {e.full_message}
90
+ nil
91
+ end
92
+ end
93
+ flyweight_component_class[keyword]
94
+ end
95
+
96
+ # Flyweight Design Pattern memoization cache. Can be cleared if memory is needed.
97
+ def flyweight_component_class
98
+ @flyweight_component_class ||= {}
99
+ end
100
+ end
101
+
102
+ attr_reader :parent_proxy, :original, :args, :keyword, :block
103
+
104
+ def initialize(parent, keyword, *args, &block)
105
+ @parent_proxy = parent
106
+ @keyword = keyword
107
+ @args = args
108
+ @block = block
109
+ build_widget
110
+ post_add_content if @block.nil?
111
+ end
112
+
113
+ # Subclasses may override to perform post add_content work (normally must call super)
114
+ def post_add_content
115
+ @parent_proxy&.post_initialize_child(self)
116
+ end
117
+
118
+ # Subclasses may override to perform post initialization work on an added child (normally must also call super)
119
+ def post_initialize_child(child)
120
+ add(child)
121
+ end
122
+
123
+ def respond_to?(method_name, *args, &block)
124
+ respond_to_original?(method_name, *args, &block) ||
125
+ super(method_name, true)
126
+ end
127
+
128
+ def respond_to_original?(method_name, *args, &block)
129
+ @original.respond_to?(method_name, true) || @original.respond_to?("set_#{method_name}", true)
130
+ end
131
+
132
+ def method_missing(method_name, *args, &block)
133
+ if @original.respond_to?("set_#{method_name}", true) && !args.empty?
134
+ send_to_original("set_#{method_name}", *args, &block)
135
+ elsif @original.respond_to?(method_name, true)
136
+ send_to_original(method_name, *args, &block)
137
+ else
138
+ super
139
+ end
140
+ end
141
+
142
+ def send_to_original(method_name, *args, &block)
143
+ @original.send(method_name, *normalize_args(args), &block)
144
+ end
145
+
146
+ def content(&block)
147
+ Glimmer::DSL::Engine.add_content(self, Glimmer::DSL::Swing::ComponentExpression.new, @keyword, &block)
148
+ end
149
+
150
+ def can_handle_observation_request?(observation_request)
151
+ if observation_request.start_with?('on_')
152
+ event = observation_request.sub(/^on_/, '')
153
+ can_add_listener?(event)
154
+ end
155
+ end
156
+
157
+ def handle_observation_request(observation_request, &block)
158
+ if observation_request.start_with?('on_')
159
+ event = observation_request.sub(/^on_/, '')
160
+ if can_add_listener?(event)
161
+ event = observation_request.sub(/^on_/, '')
162
+ add_listener(event, &block)
163
+ end
164
+ end
165
+ end
166
+
167
+ def can_add_listener?(underscored_listener_name)
168
+ @original && !self.class.find_listener(@original.getClass, underscored_listener_name).empty?
169
+ end
170
+
171
+ def add_listener(underscored_listener_name, &block)
172
+ component_add_listener_method, listener_class, listener_method = self.class.find_listener(@original.getClass, underscored_listener_name)
173
+ component_listener_proxy = nil
174
+ listener = listener_class.new(listener_method => block)
175
+ @original.send(component_add_listener_method, listener)
176
+ ComponentListenerProxy.new(component: @original, listener: listener, component_add_listener_method: component_add_listener_method, listener_class: listener_class, listener_method: listener_method)
177
+ end
178
+
179
+ # Looks through SWT class add***Listener methods till it finds one for which
180
+ # the argument is a listener class that has an event method matching
181
+ # underscored_listener_name
182
+ def self.find_listener(component_class, underscored_listener_name)
183
+ @listeners ||= {}
184
+ listener_key = [component_class.name, underscored_listener_name]
185
+ unless @listeners.has_key?(listener_key)
186
+ listener_method_name = underscored_listener_name.camelcase(:lower)
187
+ component_class.getMethods.each do |component_add_listener_method|
188
+ if component_add_listener_method.getName.match(/add.*Listener/)
189
+ component_add_listener_method.getParameterTypes.each do |listener_type|
190
+ listener_type.getMethods.each do |listener_method|
191
+ if (listener_method.getName == listener_method_name)
192
+ @listeners[listener_key] = [component_add_listener_method.getName, listener_class(listener_type), listener_method.getName]
193
+ return @listeners[listener_key]
194
+ end
195
+ end
196
+ end
197
+ end
198
+ end
199
+ @listeners[listener_key] = []
200
+ end
201
+ @listeners[listener_key]
202
+ end
203
+
204
+ # Returns a Ruby class that implements listener type Java interface with ability to easily
205
+ # install a block that gets called upon calling a listener event method
206
+ def self.listener_class(listener_type)
207
+ @listener_classes ||= {}
208
+ listener_class_key = listener_type.name
209
+ unless @listener_classes.has_key?(listener_class_key)
210
+ @listener_classes[listener_class_key] = Class.new(Object).tap do |listener_class|
211
+ listener_class.send :include, (eval listener_type.name.sub("interface", ""))
212
+ listener_class.define_method('initialize') do |event_method_block_mapping|
213
+ @event_method_block_mapping = event_method_block_mapping
214
+ end
215
+ listener_type.getMethods.each do |event_method|
216
+ listener_class.define_method(event_method.getName) do |*args|
217
+ @event_method_block_mapping[event_method.getName]&.call(*args)
218
+ end
219
+ end
220
+ end
221
+ end
222
+ @listener_classes[listener_class_key]
223
+ end
224
+
225
+ private
226
+
227
+ def build_widget
228
+ pd keyword
229
+ pd ComponentProxy.component_class(keyword)
230
+ @original = ComponentProxy.component_class(keyword).new(*normalize_args(args))
231
+ end
232
+
233
+ def normalize_args(args)
234
+ args.map do |arg|
235
+ arg.is_a?(ComponentProxy) ? arg.original : arg
236
+ end
237
+ end
238
+ end
239
+ end
240
+ end
241
+
242
+ Dir[File.expand_path("./#{File.basename(__FILE__, '.rb')}/*.rb", __dir__)].each {|f| require f}
@@ -0,0 +1,86 @@
1
+ # Copyright (c) 2007-2021 Andy Maleh
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person obtaining
4
+ # a copy of this software and associated documentation files (the
5
+ # "Software"), to deal in the Software without restriction, including
6
+ # without limitation the rights to use, copy, modify, merge, publish,
7
+ # distribute, sublicense, and/or sell copies of the Software, and to
8
+ # permit persons to whom the Software is furnished to do so, subject to
9
+ # the following conditions:
10
+ #
11
+ # The above copyright notice and this permission notice shall be
12
+ # included in all copies or substantial portions of the Software.
13
+ #
14
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
+
22
+ require 'glimmer/config'
23
+
24
+ module Glimmer
25
+ module Config
26
+ DEFAULT_IMPORT_JAVA_PACKAGES = [
27
+ 'java.awt',
28
+ 'java.awt.color',
29
+ 'java.awt.datatransfer',
30
+ 'java.awt.dnd',
31
+ 'java.awt.event',
32
+ 'java.awt.font',
33
+ 'java.awt.geom',
34
+ 'java.awt.im',
35
+ 'java.awt.im.spi',
36
+ 'java.awt.image',
37
+ 'java.awt.image.renderable',
38
+ 'java.awt.print',
39
+ 'javax.swing',
40
+ 'javax.swing.border',
41
+ 'javax.swing.colorchooser',
42
+ 'javax.swing.event',
43
+ 'javax.swing.filechooser',
44
+ 'javax.swing.plaf',
45
+ 'javax.swing.plaf.basic',
46
+ 'javax.swing.plaf.metal',
47
+ 'javax.swing.plaf.multi',
48
+ 'javax.swing.plaf.nimbus',
49
+ 'javax.swing.plaf.synth',
50
+ 'javax.swing.table',
51
+ 'javax.swing.text',
52
+ 'javax.swing.text.html',
53
+ 'javax.swing.text.html.parser',
54
+ 'javax.swing.text.rtf',
55
+ 'javax.swing.tree',
56
+ 'javax.swing.undo',
57
+ ]
58
+
59
+ class << self
60
+ # Tells Glimmer to import Java packages into including class (default: true)
61
+ def import_java_packages=(value)
62
+ @@import_java_packages = value
63
+ end
64
+
65
+ # Returns whether Glimmer will import SWT packages into including class
66
+ def import_java_packages
67
+ @@import_java_packages = DEFAULT_IMPORT_JAVA_PACKAGES if !defined?(@@import_java_packages) || (defined?(@@import_java_packages) && @@import_java_packages == true)
68
+ @@import_java_packages
69
+ end
70
+
71
+ end
72
+
73
+ end
74
+
75
+ end
76
+
77
+ Glimmer::Config.excluded_keyword_checkers << lambda do |method_symbol, *args|
78
+ method = method_symbol.to_s
79
+ result = false
80
+ return true if method == 'load_iseq'
81
+ return true if method == 'post_initialize_child'
82
+ return true if method == 'handle'
83
+ return true if method.end_with?('=')
84
+ end
85
+
86
+ Glimmer::Config.loop_max_count = 300
@@ -0,0 +1,41 @@
1
+ # Copyright (c) 2021 Andy Maleh
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person obtaining
4
+ # a copy of this software and associated documentation files (the
5
+ # "Software"), to deal in the Software without restriction, including
6
+ # without limitation the rights to use, copy, modify, merge, publish,
7
+ # distribute, sublicense, and/or sell copies of the Software, and to
8
+ # permit persons to whom the Software is furnished to do so, subject to
9
+ # the following conditions:
10
+ #
11
+ # The above copyright notice and this permission notice shall be
12
+ # included in all copies or substantial portions of the Software.
13
+ #
14
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
+
22
+ require 'glimmer/swing/packages'
23
+
24
+ module Glimmer
25
+ class << self
26
+ def included(klass)
27
+ if Object.const_defined?(:ActiveSupport) && ActiveSupport.const_defined?(:Dependencies)
28
+ begin
29
+ ActiveSupport::Dependencies.unhook!
30
+ rescue => e
31
+ # noop TODO support logging unimportant details below debug level
32
+ end
33
+ end
34
+ if Config.import_java_packages
35
+ klass.include(Swing::Packages)
36
+ klass.extend(Swing::Packages)
37
+ end
38
+ klass.extend(Glimmer)
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,37 @@
1
+ # Copyright (c) 2021 Andy Maleh
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person obtaining
4
+ # a copy of this software and associated documentation files (the
5
+ # "Software"), to deal in the Software without restriction, including
6
+ # without limitation the rights to use, copy, modify, merge, publish,
7
+ # distribute, sublicense, and/or sell copies of the Software, and to
8
+ # permit persons to whom the Software is furnished to do so, subject to
9
+ # the following conditions:
10
+ #
11
+ # The above copyright notice and this permission notice shall be
12
+ # included in all copies or substantial portions of the Software.
13
+ #
14
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
+
22
+ require 'glimmer/swing/ext/glimmer/config'
23
+
24
+ module Glimmer
25
+ module Swing
26
+ # This contains Java imports of SWT Java packages
27
+ module Packages
28
+ class << self
29
+ def included(klass)
30
+ Glimmer::Config.import_java_packages.to_a.each do |package|
31
+ include_package(package) if package.is_a?(String)
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,25 @@
1
+ # Copyright (c) 2021 Andy Maleh
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person obtaining
4
+ # a copy of this software and associated documentation files (the
5
+ # "Software"), to deal in the Software without restriction, including
6
+ # without limitation the rights to use, copy, modify, merge, publish,
7
+ # distribute, sublicense, and/or sell copies of the Software, and to
8
+ # permit persons to whom the Software is furnished to do so, subject to
9
+ # the following conditions:
10
+ #
11
+ # The above copyright notice and this permission notice shall be
12
+ # included in all copies or substantial portions of the Software.
13
+ #
14
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
+
22
+ module Glimmer
23
+ module Swing
24
+ end
25
+ end
@@ -0,0 +1,44 @@
1
+ # Copyright (c) 2021 Andy Maleh
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person obtaining
4
+ # a copy of this software and associated documentation files (the
5
+ # "Software"), to deal in the Software without restriction, including
6
+ # without limitation the rights to use, copy, modify, merge, publish,
7
+ # distribute, sublicense, and/or sell copies of the Software, and to
8
+ # permit persons to whom the Software is furnished to do so, subject to
9
+ # the following conditions:
10
+ #
11
+ # The above copyright notice and this permission notice shall be
12
+ # included in all copies or substantial portions of the Software.
13
+ #
14
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
+
22
+ $LOAD_PATH.unshift(File.expand_path('.', __dir__))
23
+
24
+ # External requires
25
+ # require 'logging'
26
+ require 'puts_debuggerer' if ENV['pd'].to_s.downcase == 'true'
27
+ # require 'super_module'
28
+ require 'java'
29
+ require 'concurrent-ruby' # ensures glimmer relies on Concurrent data-structure classes (e.g. Concurrent::Array)
30
+ require 'glimmer'
31
+ require 'nested_inherited_jruby_include_package'
32
+ require 'os'
33
+ require 'array_include_methods'
34
+ require 'facets/string/underscore'
35
+ require 'facets/string/camelcase'
36
+ require 'facets/hash/stringify_keys'
37
+
38
+ # Internal requires
39
+ # require 'ext/glimmer/config'
40
+ # require 'ext/glimmer'
41
+ require 'glimmer/swing'
42
+ require 'glimmer/swing/ext/glimmer'
43
+ require 'glimmer/swing/ext/glimmer/config'
44
+ require 'glimmer/dsl/swing/dsl'
@@ -0,0 +1,13 @@
1
+ require 'glimmer-dsl-swing'
2
+
3
+ include Glimmer
4
+
5
+ jframe('Hello, Button!') {
6
+ @button = jbutton('Click To Increment: 0') {
7
+ on_action_performed {
8
+ button_text_match = @button.text.match(/(.*)(\d+)$/)
9
+ count = button_text_match[2].to_i + 1
10
+ @button.text = "#{button_text_match[1]}#{count}"
11
+ }
12
+ }
13
+ }.show
@@ -0,0 +1,7 @@
1
+ require 'glimmer-dsl-swing'
2
+
3
+ include Glimmer
4
+
5
+ jframe('Hello, World!') {
6
+ jlabel('Hello, World!')
7
+ }.show