glimmer-dsl-swt 0.2.4 → 0.5.0

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.
@@ -33,26 +33,24 @@ module Glimmer
33
33
 
34
34
  def initialize(*args)
35
35
  @swt_display = Display.new(*args)
36
+ @swt_display.set_data('proxy', self)
36
37
  end
37
38
 
38
- def dispose
39
- @swt_display.dispose
39
+ def method_missing(method, *args, &block)
40
+ swt_display.send(method, *args, &block)
41
+ rescue => e
42
+ Glimmer::Config.logger.debug {"Neither DisplayProxy nor #{swt_display.class.name} can handle the method ##{method}"}
43
+ super
40
44
  end
41
-
42
- # Executes code block asynchronously with respect to SWT UI thread
43
- def async_exec(&block)
44
- @swt_display.asyncExec(&block)
45
- end
46
-
47
- # Executes code block synchronously with respect to SWT UI thread
48
- def sync_exec(&block)
49
- @swt_display.syncExec(&block)
45
+
46
+ def respond_to?(method, *args, &block)
47
+ super || swt_display.respond_to?(method, *args, &block)
50
48
  end
51
49
 
52
50
  def can_handle_observation_request?(observation_request)
53
51
  observation_request = observation_request.to_s
54
- if observation_request.start_with?('on_event_')
55
- constant_name = observation_request.sub(/^on_event_/, '')
52
+ if observation_request.start_with?('on_swt_')
53
+ constant_name = observation_request.sub(/^on_swt_/, '')
56
54
  SWTProxy.has_constant?(constant_name)
57
55
  elsif observation_request.start_with?('on_')
58
56
  event_name = observation_request.sub(/^on_/, '')
@@ -63,8 +61,8 @@ module Glimmer
63
61
  end
64
62
 
65
63
  def handle_observation_request(observation_request, &block)
66
- if observation_request.start_with?('on_event_')
67
- constant_name = observation_request.sub(/^on_event_/, '')
64
+ if observation_request.start_with?('on_swt_')
65
+ constant_name = observation_request.sub(/^on_swt_/, '')
68
66
  add_swt_event_listener(constant_name, &block)
69
67
  elsif observation_request.start_with?('on_')
70
68
  event_name = observation_request.sub(/^on_/, '')
@@ -31,7 +31,7 @@ module Glimmer
31
31
  begin
32
32
  @swt_layout_data = swt_layout_data_class.new(*args)
33
33
  rescue => e
34
- Glimmer::Config.logger&.debug "#{e.message}\n#{e.backtrace.join("\n")}"
34
+ Glimmer::Config.logger.debug {"#{e.message}\n#{e.backtrace.join("\n")}"}
35
35
  @swt_layout_data = args.first if args.count == 1
36
36
  end
37
37
  @widget_proxy.swt_widget.setLayoutData(@swt_layout_data)
@@ -34,8 +34,8 @@ module Glimmer
34
34
  end
35
35
  swt_layout_class
36
36
  rescue => e
37
- Glimmer::Config.logger&.debug e.message
38
- # Glimmer::Config.logger&.debug "#{e.message}\n#{e.backtrace.join("\n")}"
37
+ Glimmer::Config.logger.debug {e.message}
38
+ # Glimmer::Config.logger.debug {"#{e.message}\n#{e.backtrace.join("\n")}"}
39
39
  raise e
40
40
  end
41
41
  end
@@ -15,11 +15,13 @@ module Glimmer
15
15
 
16
16
  def initialize(parent, style)
17
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?
18
19
  @swt_widget = MessageBox.new(parent, style)
19
20
  end
20
21
 
21
22
  def open
22
23
  @swt_widget.open
24
+ @temporary_parent&.dispose
23
25
  end
24
26
 
25
27
  # TODO refactor the following methods to put in a JavaBean mixin or somethin (perhaps contribute to OSS project too)
@@ -40,9 +40,10 @@ module Glimmer
40
40
  end
41
41
  args = args.compact
42
42
  @swt_widget = Shell.new(*args)
43
+ @swt_widget.set_data('proxy', self)
43
44
  @swt_widget.setLayout(FillLayout.new)
44
45
  @swt_widget.setMinimumSize(WIDTH_MIN, HEIGHT_MIN)
45
- on_event_show do
46
+ on_swt_show do
46
47
  Thread.new do
47
48
  sleep(0.25)
48
49
  async_exec do
@@ -83,10 +84,6 @@ module Glimmer
83
84
  @swt_widget.setVisible(false)
84
85
  end
85
86
 
86
- def close
87
- @swt_widget.close
88
- end
89
-
90
87
  def visible?
91
88
  @swt_widget.isDisposed ? false : @swt_widget.isVisible
92
89
  end
@@ -130,7 +127,11 @@ module Glimmer
130
127
  # This method is not needed except in rare circumstances where there is a need to start the SWT Event Loop before opening the shell.
131
128
  def start_event_loop
132
129
  until @swt_widget.isDisposed
133
- @display.sleep unless @display.readAndDispatch
130
+ begin
131
+ @display.sleep unless @display.readAndDispatch
132
+ rescue => e
133
+ Glimmer::Config.logger.debug {e.full_message}
134
+ end
134
135
  end
135
136
  end
136
137
 
@@ -140,9 +141,9 @@ module Glimmer
140
141
  visibility_notifier = proc do
141
142
  observer.call(visible?)
142
143
  end
143
- on_event_show(&visibility_notifier)
144
- on_event_hide(&visibility_notifier)
145
- on_event_close(&visibility_notifier)
144
+ on_swt_show(&visibility_notifier)
145
+ on_swt_hide(&visibility_notifier)
146
+ on_swt_close(&visibility_notifier)
146
147
  else
147
148
  super
148
149
  end
@@ -61,12 +61,12 @@ module Glimmer
61
61
  negative ? ~bit_value : bit_value
62
62
  rescue => e
63
63
  begin
64
- # Glimmer::Config.logger&.debug(e.full_message)
64
+ # Glimmer::Config.logger.debug {e.full_message}
65
65
  alternative_swt_constant_symbol = constant_source_class.constants.find {|c| c.to_s.upcase == swt_constant_symbol.to_s.upcase}
66
66
  bit_value = constant_source_class.const_get(alternative_swt_constant_symbol)
67
67
  negative ? ~bit_value : bit_value
68
68
  rescue => e
69
- # Glimmer::Config.logger&.debug(e.full_message)
69
+ # Glimmer::Config.logger.debug {e.full_message}
70
70
  bit_value = extra_styles[swt_constant_symbol]
71
71
  if bit_value
72
72
  negative ? ~bit_value : bit_value
@@ -3,7 +3,7 @@ require 'glimmer/swt/widget_proxy'
3
3
  module Glimmer
4
4
  module SWT
5
5
  class TableColumnProxy < Glimmer::SWT::WidgetProxy
6
- attr_reader :no_sort, :sort_property
6
+ attr_reader :no_sort, :sort_property, :editor
7
7
  alias no_sort? no_sort
8
8
  attr_accessor :sort_block, :sort_by_block
9
9
 
@@ -16,7 +16,11 @@ module Glimmer
16
16
  end
17
17
 
18
18
  def sort_property=(args)
19
- @sort_property = args.to_a.first
19
+ @sort_property = args unless args.empty?
20
+ end
21
+
22
+ def editor=(args)
23
+ @editor = args
20
24
  end
21
25
 
22
26
  end
@@ -23,8 +23,8 @@ module Glimmer
23
23
  def find_table_item_and_column_index
24
24
  {}.tap do |result|
25
25
  if respond_to?(:x) && respond_to?(:y)
26
- result[:table_item] = widget.getItems.detect do |ti|
27
- result[:column_index] = widget.getColumnCount.times.to_a.detect do |ci|
26
+ result[:table_item] = widget.items.detect do |ti|
27
+ result[:column_index] = widget.column_count.times.to_a.detect do |ci|
28
28
  ti.getBounds(ci).contains(x, y)
29
29
  end
30
30
  end
@@ -33,7 +33,61 @@ module Glimmer
33
33
  end
34
34
  end
35
35
 
36
- attr_reader :table_editor, :table_editor_text_proxy, :sort_property, :sort_direction, :sort_block, :sort_type, :sort_by_block
36
+ class << self
37
+ def editors
38
+ @editors ||= {
39
+ text: {
40
+ widget_value_property: :text,
41
+ editor_gui: lambda do |args, model, property, table_proxy|
42
+ table_proxy.table_editor.minimumHeight = 20
43
+ table_editor_widget_proxy = text(*args) {
44
+ text model.send(property)
45
+ focus true
46
+ on_focus_lost {
47
+ table_proxy.finish_edit!
48
+ }
49
+ on_key_pressed { |key_event|
50
+ if key_event.keyCode == swt(:cr)
51
+ table_proxy.finish_edit!
52
+ elsif key_event.keyCode == swt(:esc)
53
+ table_proxy.cancel_edit!
54
+ end
55
+ }
56
+ }
57
+ table_editor_widget_proxy.swt_widget.selectAll
58
+ table_editor_widget_proxy
59
+ end,
60
+ },
61
+ combo: {
62
+ widget_value_property: :text,
63
+ editor_gui: lambda do |args, model, property, table_proxy|
64
+ table_proxy.table_editor.minimumHeight = 25
65
+ table_editor_widget_proxy = combo(*args) {
66
+ items model.send("#{property}_options")
67
+ text model.send(property)
68
+ focus true
69
+ on_focus_lost {
70
+ table_proxy.finish_edit!
71
+ }
72
+ on_key_pressed { |key_event|
73
+ if key_event.keyCode == swt(:cr)
74
+ table_proxy.finish_edit!
75
+ elsif key_event.keyCode == swt(:esc)
76
+ table_proxy.cancel_edit!
77
+ end
78
+ }
79
+ on_widget_selected {
80
+ table_proxy.finish_edit!
81
+ }
82
+ }
83
+ table_editor_widget_proxy
84
+ end,
85
+ }
86
+ }
87
+ end
88
+ end
89
+
90
+ attr_reader :table_editor, :table_editor_widget_proxy, :sort_property, :sort_direction, :sort_block, :sort_type, :sort_by_block, :additional_sort_properties, :editor
37
91
  attr_accessor :column_properties
38
92
 
39
93
  def initialize(underscored_widget_name, parent, args)
@@ -46,13 +100,30 @@ module Glimmer
46
100
 
47
101
  def model_binding
48
102
  swt_widget.data
49
- end
103
+ end
50
104
 
51
105
  def sort_by_column(table_column_proxy)
52
106
  index = swt_widget.columns.to_a.index(table_column_proxy.swt_widget)
53
- new_sort_property = table_column_proxy.sort_property || column_properties[index]
54
- @sort_direction = @sort_direction.nil? || @sort_property != new_sort_property || @sort_direction == :descending ? :ascending : :descending
107
+ new_sort_property = table_column_proxy.sort_property || [column_properties[index]]
108
+ if new_sort_property.size == 1 && !additional_sort_properties.to_a.empty?
109
+ selected_additional_sort_properties = additional_sort_properties.clone
110
+ if selected_additional_sort_properties.include?(new_sort_property.first)
111
+ selected_additional_sort_properties.delete(new_sort_property.first)
112
+ new_sort_property += selected_additional_sort_properties
113
+ else
114
+ new_sort_property += additional_sort_properties
115
+ end
116
+ end
117
+
118
+ @sort_direction = @sort_direction.nil? || @sort_property != new_sort_property || @sort_direction == :descending ? :ascending : :descending
119
+ swt_widget.sort_direction = @sort_direction == :ascending ? SWTProxy[:up] : SWTProxy[:down]
120
+
55
121
  @sort_property = new_sort_property
122
+ swt_widget.sort_column = table_column_proxy.swt_widget
123
+
124
+ @sort_by_block = nil
125
+ @sort_block = nil
126
+ @sort_type = nil
56
127
  if table_column_proxy.sort_by_block
57
128
  @sort_by_block = table_column_proxy.sort_by_block
58
129
  elsif table_column_proxy.sort_block
@@ -64,43 +135,51 @@ module Glimmer
64
135
  end
65
136
 
66
137
  def detect_sort_type
67
- @sort_type = String
138
+ @sort_type = sort_property.size.times.map { String }
68
139
  array = model_binding.evaluate_property
69
- values = array.map { |object| object.send(sort_property) }
70
- value_classes = values.map(&:class).uniq
71
- if value_classes.size == 1
72
- @sort_type = value_classes.first
73
- elsif value_classes.include?(Integer)
74
- @sort_type = Integer
75
- elsif value_classes.include?(Float)
76
- @sort_type = Float
140
+ sort_property.each_with_index do |a_sort_property, i|
141
+ values = array.map { |object| object.send(a_sort_property) }
142
+ value_classes = values.map(&:class).uniq
143
+ if value_classes.size == 1
144
+ @sort_type[i] = value_classes.first
145
+ elsif value_classes.include?(Integer)
146
+ @sort_type[i] = Integer
147
+ elsif value_classes.include?(Float)
148
+ @sort_type[i] = Float
149
+ end
77
150
  end
78
151
  end
79
152
 
153
+ def additional_sort_properties=(args)
154
+ @additional_sort_properties = args unless args.empty?
155
+ end
156
+
157
+ def editor=(args)
158
+ @editor = args
159
+ end
160
+
80
161
  def sort
81
162
  return unless sort_property && (sort_type || sort_block || sort_by_block)
82
163
  array = model_binding.evaluate_property
83
164
  # Converting value to_s first to handle nil cases. Should work with numeric, boolean, and date fields
84
165
  if sort_block
85
- sorted_array = array.sort do |object1, object2|
86
- value1 = object1.send(sort_property)
87
- value2 = object2.send(sort_property)
88
- sort_block.call(value1, value2)
89
- end
166
+ sorted_array = array.sort(&sort_block)
167
+ elsif sort_by_block
168
+ sorted_array = array.sort_by(&sort_by_block)
90
169
  else
91
170
  sorted_array = array.sort_by do |object|
92
- value = object.send(sort_property)
93
- # handle nil and difficult to compare types gracefully
94
- if sort_by_block
95
- value = sort_by_block.call(value)
96
- elsif sort_type == Integer
97
- value = value.to_i
98
- elsif sort_type == Float
99
- value = value.to_f
100
- elsif sort_type == String
101
- value = value.to_s
171
+ sort_property.each_with_index.map do |a_sort_property, i|
172
+ value = object.send(a_sort_property)
173
+ # handle nil and difficult to compare types gracefully
174
+ if sort_type[i] == Integer
175
+ value = value.to_i
176
+ elsif sort_type[i] == Float
177
+ value = value.to_f
178
+ elsif sort_type[i] == String
179
+ value = value.to_s
180
+ end
181
+ value
102
182
  end
103
- value
104
183
  end
105
184
  end
106
185
  sorted_array = sorted_array.reverse if sort_direction == :descending
@@ -131,6 +210,14 @@ module Glimmer
131
210
  })
132
211
  end
133
212
 
213
+ def post_initialize_child(table_column_proxy)
214
+ table_column_proxies << table_column_proxy
215
+ end
216
+
217
+ def table_column_proxies
218
+ @table_column_proxies ||= []
219
+ end
220
+
134
221
  # Indicates if table is in edit mode, thus displaying a text widget for a table item cell
135
222
  def edit_mode?
136
223
  !!@edit_mode
@@ -156,58 +243,62 @@ module Glimmer
156
243
 
157
244
  def edit_table_item(table_item, column_index, before_write: nil, after_write: nil, after_cancel: nil)
158
245
  return if table_item.nil?
246
+ model = table_item.data
247
+ property = column_properties[column_index]
159
248
  @cancel_edit&.call if @edit_mode
249
+ action_taken = false
160
250
  @edit_mode = true
161
- content {
162
- @table_editor_text_proxy = text {
163
- focus true
164
- text table_item.getText(column_index)
165
- action_taken = false
166
- @cancel_edit = lambda do
167
- @cancel_in_progress = true
168
- @table_editor_text_proxy&.swt_widget&.dispose
169
- @table_editor_text_proxy = nil
170
- after_cancel&.call
251
+
252
+ editor_config = table_column_proxies[column_index].editor || editor
253
+ editor_config = editor_config.to_a
254
+ editor_widget_options = editor_config.last.is_a?(Hash) ? editor_config.last : {}
255
+ editor_widget_arg_last_index = editor_config.last.is_a?(Hash) ? -2 : -1
256
+ editor_widget = editor_config[0] || :text
257
+ editor_widget_args = editor_config[1..editor_widget_arg_last_index]
258
+ model_editing_property = editor_widget_options[:property] || property
259
+ widget_value_property = TableProxy::editors[editor_widget][:widget_value_property]
260
+
261
+ @cancel_edit = lambda do |event=nil|
262
+ @cancel_in_progress = true
263
+ @table_editor_widget_proxy&.swt_widget&.dispose
264
+ @table_editor_widget_proxy = nil
265
+ after_cancel&.call
266
+ @edit_in_progress = false
267
+ @cancel_in_progress = false
268
+ @cancel_edit = nil
269
+ @edit_mode = false
270
+ end
271
+
272
+ @finish_edit = lambda do |event=nil|
273
+ new_value = @table_editor_widget_proxy&.swt_widget&.send(widget_value_property)
274
+ if table_item.isDisposed
275
+ @cancel_edit.call
276
+ elsif new_value && !action_taken && !@edit_in_progress && !@cancel_in_progress
277
+ action_taken = true
278
+ @edit_in_progress = true
279
+ if new_value == model.send(model_editing_property)
280
+ @cancel_edit.call
281
+ else
282
+ before_write&.call
283
+ model.send("#{model_editing_property}=", new_value) # makes table update itself, so must search for selected table item again
284
+ # Table refresh happens here because of model update triggering observers, so must retrieve table item again
285
+ edited_table_item = search { |ti| ti.getData == model }.first
286
+ swt_widget.showItem(edited_table_item)
287
+ @table_editor_widget_proxy&.swt_widget&.dispose
288
+ @table_editor_widget_proxy = nil
289
+ after_write&.call(edited_table_item)
171
290
  @edit_in_progress = false
172
- @cancel_in_progress = false
173
- @cancel_edit = nil
174
- @edit_mode = false
175
291
  end
176
- @finish_edit = lambda do |event=nil|
177
- if table_item.isDisposed
178
- @cancel_edit.call
179
- elsif !action_taken && !@edit_in_progress && !@cancel_in_progress
180
- action_taken = true
181
- @edit_in_progress = true
182
- new_text = @table_editor_text_proxy.swt_widget.getText
183
- if new_text == table_item.getText(column_index)
184
- @cancel_edit.call
185
- else
186
- before_write&.call
187
- table_item.setText(column_index, new_text)
188
- model = table_item.getData
189
- model.send("#{column_properties[column_index]}=", new_text) # makes table update itself, so must search for selected table item again
190
- edited_table_item = search { |ti| ti.getData == model }.first
191
- swt_widget.showItem(edited_table_item)
192
- @table_editor_text_proxy&.swt_widget&.dispose
193
- @table_editor_text_proxy = nil
194
- after_write&.call(edited_table_item)
195
- @edit_in_progress = false
196
- end
197
- end
198
- end
199
- on_focus_lost(&@finish_edit)
200
- on_key_pressed { |key_event|
201
- if key_event.keyCode == swt(:cr)
202
- @finish_edit.call(key_event)
203
- elsif key_event.keyCode == swt(:esc)
204
- @cancel_edit.call
205
- end
206
- }
207
- }
208
- @table_editor_text_proxy.swt_widget.selectAll
292
+ end
293
+ end
294
+
295
+ content {
296
+ @table_editor_widget_proxy = TableProxy::editors[editor_widget][:editor_gui].call(editor_widget_args, model, model_editing_property, self)
209
297
  }
210
- @table_editor.setEditor(@table_editor_text_proxy.swt_widget, table_item, column_index)
298
+ @table_editor.setEditor(@table_editor_widget_proxy.swt_widget, table_item, column_index)
299
+ rescue => e
300
+ Glimmer::Config.logger.error {e.full_message}
301
+ raise e
211
302
  end
212
303
 
213
304
  def add_listener(underscored_listener_name, &block)