glimmer-dsl-swt 0.6.1 → 0.6.6

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.
Files changed (50) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +3 -2
  3. data/VERSION +1 -1
  4. data/bin/girb +1 -1
  5. data/bin/glimmer +5 -1
  6. data/icons/scaffold_app.png +0 -0
  7. data/lib/ext/glimmer/config.rb +13 -1
  8. data/lib/glimmer-dsl-swt.rb +5 -9
  9. data/lib/glimmer/Rakefile +5 -0
  10. data/lib/glimmer/data_binding/table_items_binding.rb +4 -1
  11. data/lib/glimmer/dsl/swt/cursor_expression.rb +1 -4
  12. data/lib/glimmer/dsl/swt/dsl.rb +1 -0
  13. data/lib/glimmer/dsl/swt/font_expression.rb +3 -1
  14. data/lib/glimmer/dsl/swt/image_expression.rb +21 -0
  15. data/lib/glimmer/dsl/swt/message_box_expression.rb +9 -1
  16. data/lib/glimmer/dsl/swt/widget_expression.rb +7 -7
  17. data/lib/glimmer/launcher.rb +59 -20
  18. data/lib/glimmer/package.rb +26 -9
  19. data/lib/glimmer/rake_task.rb +115 -5
  20. data/lib/glimmer/scaffold.rb +65 -32
  21. data/lib/glimmer/swt/display_proxy.rb +13 -2
  22. data/lib/glimmer/swt/image_proxy.rb +16 -23
  23. data/lib/glimmer/swt/layout_proxy.rb +2 -0
  24. data/lib/glimmer/swt/message_box_proxy.rb +23 -5
  25. data/lib/glimmer/swt/scrolled_composite_proxy.rb +6 -11
  26. data/lib/glimmer/swt/shell_proxy.rb +0 -1
  27. data/lib/glimmer/swt/table_proxy.rb +60 -2
  28. data/lib/glimmer/swt/widget_proxy.rb +72 -18
  29. data/samples/elaborate/contact_manager.rb +121 -0
  30. data/samples/elaborate/contact_manager/contact.rb +11 -0
  31. data/samples/elaborate/contact_manager/contact_manager_presenter.rb +26 -0
  32. data/samples/elaborate/contact_manager/contact_repository.rb +244 -0
  33. data/samples/elaborate/login.rb +108 -0
  34. data/samples/elaborate/tic_tac_toe.rb +55 -0
  35. data/samples/elaborate/tic_tac_toe/board.rb +124 -0
  36. data/samples/elaborate/tic_tac_toe/cell.rb +27 -0
  37. data/samples/elaborate/user_profile.rb +55 -0
  38. data/samples/hello/hello_browser.rb +8 -0
  39. data/samples/hello/hello_combo.rb +38 -0
  40. data/samples/hello/hello_computed.rb +69 -0
  41. data/samples/hello/hello_computed/contact.rb +21 -0
  42. data/samples/hello/hello_drag_and_drop.rb +29 -0
  43. data/samples/hello/hello_list_multi_selection.rb +48 -0
  44. data/samples/hello/hello_list_single_selection.rb +37 -0
  45. data/samples/hello/hello_menu_bar.rb +64 -0
  46. data/samples/hello/hello_message_box.rb +15 -0
  47. data/samples/hello/hello_pop_up_context_menu.rb +36 -0
  48. data/samples/hello/hello_tab.rb +24 -0
  49. data/samples/hello/hello_world.rb +8 -0
  50. metadata +66 -8
@@ -4,6 +4,8 @@ require 'facets'
4
4
 
5
5
  # TODO refactor to nest under RakeTask namespace
6
6
 
7
+ MAIN_OBJECT = self
8
+
7
9
  class Scaffold
8
10
  class << self
9
11
  include FileUtils
@@ -73,7 +75,8 @@ class Scaffold
73
75
 
74
76
  # Glimmer
75
77
  dist
76
- packages
78
+ packages
79
+ vendor/jars
77
80
  MULTI_LINE_STRING
78
81
 
79
82
  GEMFILE = <<~MULTI_LINE_STRING
@@ -109,7 +112,6 @@ class Scaffold
109
112
  MULTI_LINE_STRING
110
113
 
111
114
  def app(app_name)
112
- return puts('Namespace is required! Usage: glimmer scaffold:custom_shell_gem[custom_shell_name,namespace]') unless `git config --get github.user`.to_s.strip == 'AndyObtiva'
113
115
  gem_name = file_name(app_name)
114
116
  gem_summary = human_name(app_name)
115
117
  system "jruby -r git-glimmer -S jeweler --rspec --summary '#{gem_summary}' --description '#{gem_summary}' #{gem_name}"
@@ -127,17 +129,22 @@ class Scaffold
127
129
  mkdir 'app/models'
128
130
  mkdir 'app/views'
129
131
  custom_shell('AppView', current_dir_name, :app)
130
- if OS::Underlying.windows?
131
- mkdir_p 'package/windows'
132
- icon_file = "package/windows/#{human_name(app_name)}.ico"
133
- cp File.expand_path('../../../icons/scaffold_app.ico', __FILE__), icon_file
134
- puts "Created #{current_dir_name}/#{icon_file}"
135
- elsif OS.mac?
136
- mkdir_p 'package/macosx'
137
- icon_file = "package/macosx/#{human_name(app_name)}.icns"
138
- cp File.expand_path('../../../icons/scaffold_app.icns', __FILE__), icon_file
139
- puts "Created #{current_dir_name}/#{icon_file}"
140
- end
132
+
133
+ mkdir_p 'package/windows'
134
+ icon_file = "package/windows/#{human_name(app_name)}.ico"
135
+ cp File.expand_path('../../../icons/scaffold_app.ico', __FILE__), icon_file
136
+ puts "Created #{current_dir_name}/#{icon_file}"
137
+
138
+ mkdir_p 'package/macosx'
139
+ icon_file = "package/macosx/#{human_name(app_name)}.icns"
140
+ cp File.expand_path('../../../icons/scaffold_app.icns', __FILE__), icon_file
141
+ puts "Created #{current_dir_name}/#{icon_file}"
142
+
143
+ mkdir_p 'package/linux'
144
+ icon_file = "package/linux/#{human_name(app_name)}.png"
145
+ cp File.expand_path('../../../icons/scaffold_app.png', __FILE__), icon_file
146
+ puts "Created #{current_dir_name}/#{icon_file}"
147
+
141
148
  mkdir 'bin'
142
149
  write "bin/#{file_name(app_name)}", app_bin_file(app_name)
143
150
  write 'spec/spec_helper.rb', spec_helper_file
@@ -147,9 +154,12 @@ class Scaffold
147
154
  system "\"packages/bundles/#{human_name(app_name)}/#{human_name(app_name)}.exe\""
148
155
  else
149
156
  system "bash -c '#{RVM_FUNCTION}\n cd .\n bundle\n glimmer package\n'"
150
- system "open packages/bundles/#{human_name(app_name).gsub(' ', '\ ')}.app" if OS.mac?
157
+ if OS.mac?
158
+ system "open packages/bundles/#{human_name(app_name).gsub(' ', '\ ')}.app"
159
+ else
160
+ system "glimmer bin/#{file_name(app_name)}"
161
+ end
151
162
  end
152
- # TODO generate rspec test suite
153
163
  end
154
164
 
155
165
  def custom_shell(custom_shell_name, namespace, shell_type = nil)
@@ -169,13 +179,20 @@ class Scaffold
169
179
  end
170
180
 
171
181
  def custom_shell_gem(custom_shell_name, namespace)
172
- return puts('Namespace is required! Usage: glimmer scaffold:custom_shell_gem[custom_shell_name,namespace]') unless `git config --get github.user`.to_s.strip == 'AndyObtiva'
173
182
  gem_name = "glimmer-cs-#{compact_name(custom_shell_name)}"
174
183
  gem_summary = "#{human_name(custom_shell_name)} - Glimmer Custom Shell"
184
+ begin
185
+ custom_shell_keyword = dsl_widget_name(custom_shell_name)
186
+ MAIN_OBJECT.method(custom_shell_keyword)
187
+ return puts("CustomShell keyword `#{custom_shell_keyword}` is unavailable (occupied by a built-in Ruby method)! Please pick a different name.")
188
+ rescue NameError
189
+ # No Op (keyword is not taken by a built in Ruby method)
190
+ end
175
191
  if namespace
176
192
  gem_name += "-#{compact_name(namespace)}"
177
193
  gem_summary += " (#{human_name(namespace)})"
178
194
  else
195
+ return puts('Namespace is required! Usage: glimmer scaffold:gem:customshell[name,namespace]') unless `git config --get github.user`.to_s.strip == 'AndyObtiva'
179
196
  namespace = 'glimmer'
180
197
  end
181
198
  system "jruby -r git-glimmer -S jeweler --rspec --summary '#{gem_summary}' --description '#{gem_summary}' #{gem_name}"
@@ -194,24 +211,33 @@ class Scaffold
194
211
  write "bin/#{file_name(custom_shell_name)}", gem_bin_command_file(gem_name)
195
212
  FileUtils.chmod 0755, "bin/#{file_name(custom_shell_name)}"
196
213
  write 'spec/spec_helper.rb', spec_helper_file
197
- if OS::Underlying.windows?
198
- mkdir_p 'package/windows'
199
- icon_file = "package/windows/#{human_name(custom_shell_name)}.ico"
200
- cp File.expand_path('../../../icons/scaffold_app.ico', __FILE__), icon_file
201
- puts "Created #{current_dir_name}/#{icon_file}"
202
- elsif OS.mac?
203
- mkdir_p 'package/macosx'
204
- icon_file = "package/macosx/#{human_name(custom_shell_name)}.icns"
205
- cp File.expand_path('../../../icons/scaffold_app.icns', __FILE__), icon_file
206
- puts "Created #{current_dir_name}/#{icon_file}"
207
- end
214
+
215
+ mkdir_p 'package/windows'
216
+ icon_file = "package/windows/#{human_name(custom_shell_name)}.ico"
217
+ cp File.expand_path('../../../icons/scaffold_app.ico', __FILE__), icon_file
218
+ puts "Created #{current_dir_name}/#{icon_file}"
219
+
220
+ mkdir_p 'package/macosx'
221
+ icon_file = "package/macosx/#{human_name(custom_shell_name)}.icns"
222
+ cp File.expand_path('../../../icons/scaffold_app.icns', __FILE__), icon_file
223
+ puts "Created #{current_dir_name}/#{icon_file}"
224
+
225
+ mkdir_p 'package/linux'
226
+ icon_file = "package/linux/#{human_name(custom_shell_name)}.png"
227
+ cp File.expand_path('../../../icons/scaffold_app.png', __FILE__), icon_file
228
+ puts "Created #{current_dir_name}/#{icon_file}"
229
+
208
230
  if OS.windows?
209
231
  system "bundle"
210
232
  system "glimmer package[image]"
211
233
  system "\"packages/bundles/#{human_name(custom_shell_name)}/#{human_name(custom_shell_name)}.exe\""
212
234
  else
213
235
  system "bash -c '#{RVM_FUNCTION}\n cd .\n bundle\n glimmer package\n'"
214
- system "open packages/bundles/#{human_name(custom_shell_name).gsub(' ', '\ ')}.app" if OS.mac?
236
+ if OS.mac?
237
+ system "open packages/bundles/#{human_name(custom_shell_name).gsub(' ', '\ ')}.app" if OS.mac?
238
+ else
239
+ system "bin/#{file_name(custom_shell_name)}"
240
+ end
215
241
  end
216
242
  puts "Finished creating #{gem_name} Ruby gem."
217
243
  puts 'Edit Rakefile to configure gem details.'
@@ -333,18 +359,25 @@ class Scaffold
333
359
  end
334
360
 
335
361
  def gem_bin_file(gem_name, custom_shell_name, namespace)
362
+ # TODO change this so that it does not mix Glimmer unto the main object
336
363
  <<~MULTI_LINE_STRING
337
364
  require_relative '../lib/#{gem_name}'
338
365
 
339
- include Glimmer
366
+ class #{class_name(custom_shell_name)}App
367
+ include Glimmer
368
+
369
+ def open
370
+ #{dsl_widget_name(custom_shell_name)}.open
371
+ end
372
+ end
340
373
 
341
- #{dsl_widget_name(custom_shell_name)}.open
374
+ #{class_name(custom_shell_name)}App.new.open
342
375
  MULTI_LINE_STRING
343
376
  end
344
377
 
345
378
  def gem_bin_command_file(gem_name)
346
379
  <<~MULTI_LINE_STRING
347
- #!/usr/bin/env ruby
380
+ #!/usr/bin/env jruby
348
381
 
349
382
  require 'glimmer/launcher'
350
383
 
@@ -489,7 +522,7 @@ class Scaffold
489
522
  menu {
490
523
  text '&File'
491
524
  menu_item {
492
- text 'Preferences...'
525
+ text '&Preferences...'
493
526
  on_widget_selected {
494
527
  display_preferences_dialog
495
528
  }
@@ -35,16 +35,26 @@ module Glimmer
35
35
  @swt_display = Display.new(*args)
36
36
  @swt_display.set_data('proxy', self)
37
37
  end
38
+
39
+ def content(&block)
40
+ Glimmer::DSL::Engine.add_content(self, Glimmer::DSL::SWT::DisplayExpression.new, &block)
41
+ end
38
42
 
39
43
  def method_missing(method, *args, &block)
40
- swt_display.send(method, *args, &block)
44
+ if can_handle_observation_request?(method)
45
+ handle_observation_request(method, &block)
46
+ else
47
+ swt_display.send(method, *args, &block)
48
+ end
41
49
  rescue => e
42
50
  Glimmer::Config.logger.debug {"Neither DisplayProxy nor #{swt_display.class.name} can handle the method ##{method}"}
43
51
  super
44
52
  end
45
53
 
46
54
  def respond_to?(method, *args, &block)
47
- super || swt_display.respond_to?(method, *args, &block)
55
+ super ||
56
+ can_handle_observation_request?(method) ||
57
+ swt_display.respond_to?(method, *args, &block)
48
58
  end
49
59
 
50
60
  def can_handle_observation_request?(observation_request)
@@ -61,6 +71,7 @@ module Glimmer
61
71
  end
62
72
 
63
73
  def handle_observation_request(observation_request, &block)
74
+ observation_request = observation_request.to_s
64
75
  if observation_request.start_with?('on_swt_')
65
76
  constant_name = observation_request.sub(/^on_swt_/, '')
66
77
  add_swt_event_listener(constant_name, &block)
@@ -8,7 +8,7 @@ module Glimmer
8
8
  class ImageProxy
9
9
  include_package 'org.eclipse.swt.graphics'
10
10
 
11
- attr_reader :jar_file_path, :image_data
11
+ attr_reader :file_path, :jar_file_path, :image_data, :swt_image
12
12
 
13
13
  # Initializes a proxy for an SWT Image object
14
14
  #
@@ -17,31 +17,24 @@ module Glimmer
17
17
  # and returns an image object.
18
18
  def initialize(*args)
19
19
  @args = args
20
- @jar_file_path = @args.first if @args.first.is_a?(String) && @args.size == 1
21
-
22
- end
23
-
24
- def swt_image
25
- unless @swt_image
26
- if @jar_file_path
27
- file_path = @jar_file_path
28
- if file_path.start_with?('uri:classloader')
29
- file_path = file_path.sub(/^uri\:classloader\:/, '').sub('//', '/') # the latter sub is needed for Mac
30
- object = java.lang.Object.new
31
- file_input_stream = object.java_class.resource_as_stream(file_path)
32
- buffered_file_input_stream = java.io.BufferedInputStream.new(file_input_stream)
33
- end
34
- @image_data = ImageData.new(buffered_file_input_stream || file_path)
35
- @swt_image = Image.new(DisplayProxy.instance.swt_display, @image_data)
36
- else
37
- @swt_image = Image.new(*@args)
20
+ @file_path = @args.first if @args.first.is_a?(String) && @args.size == 1
21
+ if @file_path
22
+ if @file_path.start_with?('uri:classloader')
23
+ @jar_file_path = @file_path
24
+ @file_path = @jar_file_path.sub(/^uri\:classloader\:/, '').sub('//', '/') # the latter sub is needed for Mac
25
+ object = java.lang.Object.new
26
+ file_input_stream = object.java_class.resource_as_stream(file_path)
27
+ buffered_file_input_stream = java.io.BufferedInputStream.new(file_input_stream)
38
28
  end
39
- end
40
- @swt_image
29
+ @image_data = ImageData.new(buffered_file_input_stream || @file_path)
30
+ @swt_image = Image.new(DisplayProxy.instance.swt_display, @image_data)
31
+ else
32
+ @swt_image = Image.new(*@args)
33
+ @image_data = @swt_image.image_data
34
+ end
41
35
  end
42
-
36
+
43
37
  def scale_to(width, height)
44
- return @swt_image if image_data.nil?
45
38
  scaled_image_data = image_data.scaledTo(width, height)
46
39
  device = swt_image.device
47
40
  swt_image.dispose
@@ -45,6 +45,8 @@ module Glimmer
45
45
  @widget_proxy = widget_proxy
46
46
  args = SWTProxy.constantify_args(args)
47
47
  @swt_layout = self.class.swt_layout_class_for(underscored_layout_name).new(*args)
48
+ @swt_layout.marginWidth = 15 if @swt_layout.respond_to?(:marginWidth)
49
+ @swt_layout.marginHeight = 15 if @swt_layout.respond_to?(:marginHeight)
48
50
  @widget_proxy.swt_widget.setLayout(@swt_layout)
49
51
  end
50
52
 
@@ -14,16 +14,22 @@ module Glimmer
14
14
  attr_reader :swt_widget
15
15
 
16
16
  def initialize(parent, style)
17
- parent = parent.swt_widget if parent.respond_to?(:swt_widget) && parent.swt_widget.is_a?(Shell)
18
- @temporary_parent = parent = Glimmer::SWT::ShellProxy.new.swt_widget if parent.nil?
19
- @swt_widget = MessageBox.new(parent, style)
17
+ if parent.nil?
18
+ @temporary_parent = parent = Glimmer::SWT::ShellProxy.new.swt_widget
19
+ end
20
+ @swt_widget = MessageBox.new(parent, style)
20
21
  end
21
22
 
22
23
  def open
23
- @swt_widget.open
24
- @temporary_parent&.dispose
24
+ @swt_widget.open.tap do |result|
25
+ @temporary_parent&.dispose
26
+ end
25
27
  end
26
28
 
29
+ def content(&block)
30
+ Glimmer::DSL::Engine.add_content(self, Glimmer::DSL::SWT::MessageBoxExpression.new, &block)
31
+ end
32
+
27
33
  # TODO refactor the following methods to put in a JavaBean mixin or somethin (perhaps contribute to OSS project too)
28
34
 
29
35
  def attribute_setter(attribute_name)
@@ -44,6 +50,18 @@ module Glimmer
44
50
 
45
51
  def get_attribute(attribute_name)
46
52
  @swt_widget.send(attribute_getter(attribute_name))
53
+ end
54
+
55
+ def method_missing(method, *args, &block)
56
+ swt_widget.send(method, *args, &block)
57
+ rescue => e
58
+ Glimmer::Config.logger.debug {"Neither MessageBoxProxy nor #{swt_widget.class.name} can handle the method ##{method}"}
59
+ super
60
+ end
61
+
62
+ def respond_to?(method, *args, &block)
63
+ super ||
64
+ swt_widget.respond_to?(method, *args, &block)
47
65
  end
48
66
  end
49
67
  end
@@ -1,21 +1,16 @@
1
1
  require 'glimmer/swt/widget_proxy'
2
+ require 'glimmer/swt/swt_proxy'
2
3
 
3
4
  module Glimmer
4
5
  module SWT
5
- class ScrolledCompositeProxy < Glimmer::SWT::WidgetProxy
6
- def initialize(underscored_widget_name, parent, args)
7
- unless args.first.is_a?(Numeric)
8
- args.unshift(:h_scroll)
9
- args.unshift(:v_scroll)
10
- end
11
- super
12
- swt_widget.expand_horizontal = true
13
- swt_widget.expand_vertical = true
14
- end
15
-
6
+ class ScrolledCompositeProxy < Glimmer::SWT::WidgetProxy
16
7
  def post_initialize_child(child)
17
8
  swt_widget.content = child.swt_widget
18
9
  end
10
+
11
+ def post_add_content
12
+ swt_widget.set_min_size(swt_widget.computeSize(SWTProxy[:default], SWTProxy[:default]))
13
+ end
19
14
  end
20
15
  end
21
16
  end
@@ -1,7 +1,6 @@
1
1
  require 'glimmer/swt/swt_proxy'
2
2
  require 'glimmer/swt/widget_proxy'
3
3
  require 'glimmer/swt/display_proxy'
4
- require 'glimmer/swt/swt_proxy'
5
4
 
6
5
  module Glimmer
7
6
  module SWT
@@ -85,7 +85,55 @@ module Glimmer
85
85
  }
86
86
  table_editor_widget_proxy
87
87
  end,
88
- }
88
+ },
89
+ checkbox: {
90
+ widget_value_property: :selection,
91
+ editor_gui: lambda do |args, model, property, table_proxy|
92
+ first_time = true
93
+ table_proxy.table_editor.minimumHeight = 25
94
+ checkbox(*args) {
95
+ selection model.send(property)
96
+ focus true
97
+ on_widget_selected {
98
+ table_proxy.finish_edit!
99
+ }
100
+ on_focus_lost {
101
+ table_proxy.finish_edit!
102
+ }
103
+ on_key_pressed { |key_event|
104
+ if key_event.keyCode == swt(:cr)
105
+ table_proxy.finish_edit!
106
+ elsif key_event.keyCode == swt(:esc)
107
+ table_proxy.cancel_edit!
108
+ end
109
+ }
110
+ }
111
+ end,
112
+ },
113
+ radio: {
114
+ widget_value_property: :selection,
115
+ editor_gui: lambda do |args, model, property, table_proxy|
116
+ first_time = true
117
+ table_proxy.table_editor.minimumHeight = 25
118
+ radio(*args) {
119
+ selection model.send(property)
120
+ focus true
121
+ on_widget_selected {
122
+ table_proxy.finish_edit!
123
+ }
124
+ on_focus_lost {
125
+ table_proxy.finish_edit!
126
+ }
127
+ on_key_pressed { |key_event|
128
+ if key_event.keyCode == swt(:cr)
129
+ table_proxy.finish_edit!
130
+ elsif key_event.keyCode == swt(:esc)
131
+ table_proxy.cancel_edit!
132
+ end
133
+ }
134
+ }
135
+ end,
136
+ }
89
137
  }
90
138
  end
91
139
  end
@@ -161,9 +209,19 @@ module Glimmer
161
209
  @editor = args
162
210
  end
163
211
 
212
+ def cells_for(model)
213
+ column_properties.map {|property| model.send(property)}
214
+ end
215
+
216
+ def cells
217
+ column_count = @table.column_properties.size
218
+ swt_widget.items.map {|item| column_count.times.map {|i| item.get_text(i)} }
219
+ end
220
+
164
221
  def sort
165
222
  return unless sort_property && (sort_type || sort_block || sort_by_block)
166
223
  array = model_binding.evaluate_property
224
+ array = array.sort_by(&:hash) # this ensures consistent subsequent sorting in case there are equivalent sorts to avoid an infinite loop
167
225
  # Converting value to_s first to handle nil cases. Should work with numeric, boolean, and date fields
168
226
  if sort_block
169
227
  sorted_array = array.sort(&sort_block)
@@ -276,7 +334,7 @@ module Glimmer
276
334
  new_value = @table_editor_widget_proxy&.swt_widget&.send(widget_value_property)
277
335
  if table_item.isDisposed
278
336
  @cancel_edit.call
279
- elsif new_value && !action_taken && !@edit_in_progress && !@cancel_in_progress
337
+ elsif !new_value.nil? && !action_taken && !@edit_in_progress && !@cancel_in_progress
280
338
  action_taken = true
281
339
  @edit_in_progress = true
282
340
  if new_value == model.send(model_editing_property)