glimmer 0.7.4 → 0.8.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -16,6 +16,8 @@ module Glimmer
16
16
  class DisplayProxy
17
17
  include_package 'org.eclipse.swt.widgets'
18
18
 
19
+ OBSERVED_MENU_ITEMS = ['about', 'preferences']
20
+
19
21
  class << self
20
22
  # Returns singleton instance
21
23
  def instance(*args)
@@ -52,6 +54,9 @@ module Glimmer
52
54
  if observation_request.start_with?('on_event_')
53
55
  constant_name = observation_request.sub(/^on_event_/, '')
54
56
  SWTProxy.has_constant?(constant_name)
57
+ elsif observation_request.start_with?('on_')
58
+ event_name = observation_request.sub(/^on_/, '')
59
+ OBSERVED_MENU_ITEMS.include?(event_name)
55
60
  else
56
61
  false
57
62
  end
@@ -61,6 +66,15 @@ module Glimmer
61
66
  if observation_request.start_with?('on_event_')
62
67
  constant_name = observation_request.sub(/^on_event_/, '')
63
68
  add_swt_event_listener(constant_name, &block)
69
+ elsif observation_request.start_with?('on_')
70
+ event_name = observation_request.sub(/^on_/, '')
71
+ if OBSERVED_MENU_ITEMS.include?(event_name)
72
+ if OS.mac?
73
+ system_menu = swt_display.getSystemMenu
74
+ menu_item = system_menu.getItems.find {|menu_item| menu_item.getID == SWTProxy["ID_#{event_name.upcase}"]}
75
+ menu_item.addListener(SWTProxy[:Selection], &block)
76
+ end
77
+ end
64
78
  end
65
79
  end
66
80
 
@@ -79,6 +79,23 @@ module Glimmer
79
79
  super(attribute_name)
80
80
  end
81
81
  end
82
+
83
+ def can_handle_observation_request?(observation_request, super_only: false)
84
+ super_result = super(observation_request)
85
+ if observation_request.start_with?('on_') && !super_result && !super_only
86
+ return menu_item_proxy.can_handle_observation_request?(observation_request)
87
+ else
88
+ super_result
89
+ end
90
+ end
91
+
92
+ def handle_observation_request(observation_request, &block)
93
+ if can_handle_observation_request?(observation_request, super_only: true)
94
+ super
95
+ else
96
+ menu_item_proxy.handle_observation_request(observation_request, &block)
97
+ end
98
+ end
82
99
  end
83
100
  end
84
101
  end
@@ -14,7 +14,6 @@ module Glimmer
14
14
 
15
15
  WIDTH_MIN = 130
16
16
  HEIGHT_MIN = 0
17
- OBSERVED_MENU_ITEMS = ['about', 'preferences']
18
17
 
19
18
  attr_reader :opened_before
20
19
  alias opened_before? opened_before
@@ -47,7 +46,7 @@ module Glimmer
47
46
  Thread.new do
48
47
  sleep(0.25)
49
48
  async_exec do
50
- @swt_widget.setActive
49
+ @swt_widget.setActive unless @swt_widget.isDisposed
51
50
  end
52
51
  end
53
52
  end
@@ -128,30 +127,6 @@ module Glimmer
128
127
  end
129
128
  end
130
129
 
131
- def can_handle_observation_request?(observation_request)
132
- result = false
133
- if observation_request.start_with?('on_')
134
- event_name = observation_request.sub(/^on_/, '')
135
- result = OBSERVED_MENU_ITEMS.include?(event_name)
136
- end
137
- result || super
138
- end
139
-
140
- def handle_observation_request(observation_request, &block)
141
- if observation_request.start_with?('on_')
142
- event_name = observation_request.sub(/^on_/, '')
143
- if OBSERVED_MENU_ITEMS.include?(event_name)
144
- if OS.mac?
145
- system_menu = DisplayProxy.instance.swt_display.getSystemMenu
146
- menu_item = system_menu.getItems.find {|menu_item| menu_item.getID == SWTProxy["ID_#{event_name.upcase}"]}
147
- menu_item.addListener(SWTProxy[:Selection], &block)
148
- end
149
- else
150
- super
151
- end
152
- end
153
- end
154
-
155
130
  def add_observer(observer, property_name)
156
131
  case property_name.to_s
157
132
  when 'visible?' #TODO see if you must handle non-? version and/or move elsewhere
@@ -54,6 +54,12 @@ module Glimmer
54
54
  super(attribute_name)
55
55
  end
56
56
  end
57
+
58
+ def dispose
59
+ swt_tab_item.setControl(nil)
60
+ swt_widget.dispose
61
+ swt_tab_item.dispose
62
+ end
57
63
  end
58
64
  end
59
65
  end
@@ -3,22 +3,118 @@ require 'glimmer/swt/widget_proxy'
3
3
  module Glimmer
4
4
  module SWT
5
5
  class TreeProxy < Glimmer::SWT::WidgetProxy
6
+ include Glimmer
7
+
8
+ attr_reader :tree_editor, :tree_editor_text_proxy
9
+ attr_accessor :tree_properties
10
+
11
+ def initialize(underscored_widget_name, parent, args)
12
+ super
13
+ @tree_editor = TreeEditor.new(swt_widget)
14
+ @tree_editor.horizontalAlignment = SWTProxy[:left]
15
+ @tree_editor.grabHorizontal = true
16
+ @tree_editor.minimumHeight = 20
17
+ end
18
+
6
19
  # Performs depth first search for tree items matching block condition
7
- # Returns a Java TreeItem array to easily set as selection on org.eclipse.swt.Tree when needed
20
+ # If no condition block is passed, returns all tree items
21
+ # Returns a Java TreeItem array to easily set as selection on org.eclipse.swt.Tree if needed
8
22
  def depth_first_search(&condition)
9
23
  found = []
10
24
  recursive_depth_first_search(swt_widget.getItems.first, found, &condition)
11
25
  found.to_java(TreeItem)
12
26
  end
27
+
28
+ # Returns all tree items including descendants
29
+ def all_tree_items
30
+ depth_first_search
31
+ end
13
32
 
33
+ def widget_property_listener_installers
34
+ super.merge({
35
+ Java::OrgEclipseSwtWidgets::Tree => {
36
+ selection: lambda do |observer|
37
+ on_widget_selected { |selection_event|
38
+ observer.call(@swt_widget.getSelection)
39
+ }
40
+ end
41
+ },
42
+ })
43
+ end
44
+
45
+ def edit_in_progress?
46
+ !!@edit_in_progress
47
+ end
48
+
49
+ def edit_selected_tree_item(before_write: nil, after_write: nil, after_cancel: nil)
50
+ edit_tree_item(swt_widget.getSelection.first, before_write: before_write, after_write: after_write, after_cancel: after_cancel)
51
+ end
52
+
53
+ def edit_tree_item(tree_item, before_write: nil, after_write: nil, after_cancel: nil)
54
+ return if tree_item.nil?
55
+ content {
56
+ @tree_editor_text_proxy = text {
57
+ focus true
58
+ text tree_item.getText
59
+ action_taken = false
60
+ cancel = lambda {
61
+ @tree_editor_text_proxy.swt_widget.dispose
62
+ @tree_editor_text_proxy = nil
63
+ after_cancel&.call
64
+ @edit_in_progress = false
65
+ }
66
+ action = lambda { |event|
67
+ if !action_taken && !@edit_in_progress
68
+ action_taken = true
69
+ @edit_in_progress = true
70
+ new_text = @tree_editor_text_proxy.swt_widget.getText
71
+ if new_text == tree_item.getText
72
+ cancel.call
73
+ else
74
+ before_write&.call
75
+ tree_item.setText(new_text)
76
+ model = tree_item.getData
77
+ model.send("#{tree_properties[:text]}=", new_text) # makes tree update itself, so must search for selected tree item again
78
+ edited_tree_item = depth_first_search { |ti| ti.getData == model }.first
79
+ swt_widget.showItem(edited_tree_item)
80
+ @tree_editor_text_proxy.swt_widget.dispose
81
+ @tree_editor_text_proxy = nil
82
+ after_write&.call(edited_tree_item)
83
+ @edit_in_progress = false
84
+ end
85
+ end
86
+ }
87
+ on_focus_lost(&action)
88
+ on_key_pressed { |key_event|
89
+ if key_event.keyCode == swt(:cr)
90
+ action.call(key_event)
91
+ elsif key_event.keyCode == swt(:esc)
92
+ cancel.call
93
+ end
94
+ }
95
+ }
96
+ @tree_editor_text_proxy.swt_widget.selectAll
97
+ }
98
+ @tree_editor.setEditor(@tree_editor_text_proxy.swt_widget, tree_item);
99
+ end
100
+
14
101
  private
15
102
 
16
103
  def recursive_depth_first_search(tree_item, found, &condition)
104
+ return if tree_item.nil?
17
105
  found << tree_item if condition.nil? || condition.call(tree_item)
18
106
  tree_item.getItems.each do |child_tree_item|
19
107
  recursive_depth_first_search(child_tree_item, found, &condition)
20
108
  end
21
109
  end
110
+
111
+ def property_type_converters
112
+ super.merge({
113
+ selection: lambda do |value|
114
+ depth_first_search {|ti| ti.getData == value}
115
+ end,
116
+ })
117
+ end
22
118
  end
23
119
  end
24
120
  end
@@ -5,12 +5,29 @@ module Glimmer
5
5
  # Follows the Proxy Design Pattern
6
6
  class WidgetListenerProxy
7
7
 
8
- attr_reader :swt_listener
8
+ attr_reader :swt_widget, :swt_listener, :widget_add_listener_method, :swt_listener_class, :swt_listener_method, :event_type, :swt_constant
9
9
 
10
- # TODO capture its widget and support unregistering
11
-
12
- def initialize(swt_listener)
10
+ def initialize(swt_widget:, swt_listener:, widget_add_listener_method: nil, swt_listener_class: nil, swt_listener_method: nil, event_type: nil, swt_constant: nil)
11
+ @swt_widget = swt_widget
13
12
  @swt_listener = swt_listener
13
+ @widget_add_listener_method = widget_add_listener_method
14
+ @swt_listener_class = swt_listener_class
15
+ @swt_listener_method = swt_listener_method
16
+ @event_type = event_type
17
+ @swt_constant = swt_constant
18
+ end
19
+
20
+ def widget_remove_listener_method
21
+ @widget_add_listener_method.sub('add', 'remove')
22
+ end
23
+
24
+ def unregister
25
+ # TODO consider renaming to deregister (and in Observer too)
26
+ if @event_type
27
+ @swt_widget.removeListener(@event_type, @swt_listener)
28
+ else
29
+ @swt_widget.send(widget_remove_listener_method, @swt_listener)
30
+ end
14
31
  end
15
32
  end
16
33
  end
@@ -5,6 +5,8 @@ require 'glimmer/swt/font_proxy'
5
5
  require 'glimmer/swt/swt_proxy'
6
6
  require 'glimmer/data_binding/observable_widget'
7
7
 
8
+ # TODO refactor to make file smaller and extract sub-widget-proxies out of this
9
+
8
10
  module Glimmer
9
11
  module SWT
10
12
  # Proxy for SWT Widget objects
@@ -23,6 +25,7 @@ module Glimmer
23
25
  DEFAULT_STYLES = {
24
26
  "text" => [:border],
25
27
  "table" => [:border],
28
+ "tree" => [:virtual, :border, :h_scroll, :v_scroll],
26
29
  "spinner" => [:border],
27
30
  "styled_text" => [:border],
28
31
  "list" => [:border, :v_scroll],
@@ -31,17 +34,17 @@ module Glimmer
31
34
  }
32
35
 
33
36
  DEFAULT_INITIALIZERS = {
34
- "composite" => proc do |composite|
37
+ "composite" => lambda do |composite|
35
38
  composite.setLayout(GridLayout.new)
36
39
  end,
37
- "table" => proc do |table|
40
+ "table" => lambda do |table|
38
41
  table.setHeaderVisible(true)
39
42
  table.setLinesVisible(true)
40
43
  end,
41
- "table_column" => proc do |table_column|
44
+ "table_column" => lambda do |table_column|
42
45
  table_column.setWidth(80)
43
46
  end,
44
- "group" => proc do |group|
47
+ "group" => lambda do |group|
45
48
  group.setLayout(GridLayout.new)
46
49
  end,
47
50
  }
@@ -119,7 +122,7 @@ module Glimmer
119
122
  def widget_property_listener_installers
120
123
  @swt_widget_property_listener_installers ||= {
121
124
  Java::OrgEclipseSwtWidgets::Control => {
122
- :focus => proc do |observer|
125
+ :focus => lambda do |observer|
123
126
  on_focus_gained { |focus_event|
124
127
  observer.call(true)
125
128
  }
@@ -129,12 +132,12 @@ module Glimmer
129
132
  end,
130
133
  },
131
134
  Java::OrgEclipseSwtWidgets::Text => {
132
- :text => proc do |observer|
135
+ :text => lambda do |observer|
133
136
  on_modify_text { |modify_event|
134
137
  observer.call(@swt_widget.getText)
135
138
  }
136
139
  end,
137
- :caret_position => proc do |observer|
140
+ :caret_position => lambda do |observer|
138
141
  on_event_keydown { |event|
139
142
  observer.call(@swt_widget.getCaretPosition)
140
143
  }
@@ -148,7 +151,21 @@ module Glimmer
148
151
  observer.call(@swt_widget.getCaretPosition)
149
152
  }
150
153
  end,
151
- :selection_count => proc do |observer|
154
+ :selection => lambda do |observer|
155
+ on_event_keydown { |event|
156
+ observer.call(@swt_widget.getSelection)
157
+ }
158
+ on_event_keyup { |event|
159
+ observer.call(@swt_widget.getSelection)
160
+ }
161
+ on_event_mousedown { |event|
162
+ observer.call(@swt_widget.getSelection)
163
+ }
164
+ on_event_mouseup { |event|
165
+ observer.call(@swt_widget.getSelection)
166
+ }
167
+ end,
168
+ :selection_count => lambda do |observer|
152
169
  on_event_keydown { |event|
153
170
  observer.call(@swt_widget.getSelectionCount)
154
171
  }
@@ -162,7 +179,7 @@ module Glimmer
162
179
  observer.call(@swt_widget.getSelectionCount)
163
180
  }
164
181
  end,
165
- :top_index => proc do |observer|
182
+ :top_index => lambda do |observer|
166
183
  @last_top_index = @swt_widget.getTopIndex
167
184
  on_paint_control { |event|
168
185
  if @swt_widget.getTopIndex != @last_top_index
@@ -173,33 +190,33 @@ module Glimmer
173
190
  end,
174
191
  },
175
192
  Java::OrgEclipseSwtCustom::StyledText => {
176
- :text => proc do |observer|
193
+ :text => lambda do |observer|
177
194
  on_modify_text { |modify_event|
178
195
  observer.call(@swt_widget.getText)
179
196
  }
180
197
  end,
181
198
  },
182
199
  Java::OrgEclipseSwtWidgets::Button => {
183
- :selection => proc do |observer|
200
+ :selection => lambda do |observer|
184
201
  on_widget_selected { |selection_event|
185
202
  observer.call(@swt_widget.getSelection)
186
203
  }
187
204
  end
188
205
  },
189
206
  Java::OrgEclipseSwtWidgets::MenuItem => {
190
- :selection => proc do |observer|
207
+ :selection => lambda do |observer|
191
208
  on_widget_selected { |selection_event|
192
209
  observer.call(@swt_widget.getSelection)
193
210
  }
194
211
  end
195
212
  },
196
213
  Java::OrgEclipseSwtWidgets::Spinner => {
197
- :selection => proc do |observer|
214
+ :selection => lambda do |observer|
198
215
  on_widget_selected { |selection_event|
199
216
  observer.call(@swt_widget.getSelection)
200
217
  }
201
218
  end
202
- }
219
+ },
203
220
  }
204
221
  end
205
222
 
@@ -321,10 +338,12 @@ module Glimmer
321
338
  end
322
339
 
323
340
  def add_listener(underscored_listener_name, &block)
324
- widget_add_listener_method, listener_class, listener_method = self.class.find_listener(@swt_widget.getClass, underscored_listener_name)
325
- listener = listener_class.new(listener_method => block)
341
+ widget_add_listener_method, listener_class, listener_method = self.class.find_listener(@swt_widget.getClass, underscored_listener_name)
342
+ widget_listener_proxy = nil
343
+ safe_block = lambda { |event| block.call(event) unless @swt_widget.isDisposed }
344
+ listener = listener_class.new(listener_method => safe_block)
326
345
  @swt_widget.send(widget_add_listener_method, listener)
327
- WidgetListenerProxy.new(listener)
346
+ widget_listener_proxy = WidgetListenerProxy.new(swt_widget: @swt_widget, swt_listener: listener, widget_add_listener_method: widget_add_listener_method, swt_listener_class: listener_class, swt_listener_method: listener_method)
328
347
  end
329
348
 
330
349
  # Looks through SWT class add***Listener methods till it finds one for which
@@ -375,8 +394,10 @@ module Glimmer
375
394
 
376
395
  def add_swt_event_listener(swt_constant, &block)
377
396
  event_type = SWTProxy[swt_constant]
378
- @swt_widget.addListener(event_type, &block)
379
- WidgetListenerProxy.new(@swt_widget.getListeners(event_type).last)
397
+ widget_listener_proxy = nil
398
+ safe_block = lambda { |event| block.call(event) unless @swt_widget.isDisposed }
399
+ @swt_widget.addListener(event_type, &safe_block)
400
+ widget_listener_proxy = WidgetListenerProxy.new(swt_widget: @swt_widget, swt_listener: @swt_widget.getListeners(event_type).last, event_type: event_type, swt_constant: swt_constant)
380
401
  end
381
402
 
382
403
  def widget_custom_attribute_mapping
@@ -409,7 +430,7 @@ module Glimmer
409
430
  end
410
431
 
411
432
  def property_type_converters
412
- color_converter = proc do |value|
433
+ color_converter = lambda do |value|
413
434
  if value.is_a?(Symbol) || value.is_a?(String)
414
435
  ColorProxy.new(value).swt_color
415
436
  else
@@ -419,7 +440,7 @@ module Glimmer
419
440
  # TODO consider detecting type on widget method and automatically invoking right converter (e.g. :to_s for String, :to_i for Integer)
420
441
  @property_type_converters ||= {
421
442
  :background => color_converter,
422
- :background_image => proc do |value|
443
+ :background_image => lambda do |value|
423
444
  if value.is_a?(String)
424
445
  if value.start_with?('uri:classloader')
425
446
  value = value.sub(/^uri\:classloader\:\//, '')
@@ -440,7 +461,7 @@ module Glimmer
440
461
  end
441
462
  end,
442
463
  :foreground => color_converter,
443
- :font => proc do |value|
464
+ :font => lambda do |value|
444
465
  if value.is_a?(Hash)
445
466
  font_properties = value
446
467
  FontProxy.new(self, font_properties).swt_font
@@ -448,17 +469,17 @@ module Glimmer
448
469
  value
449
470
  end
450
471
  end,
451
- :items => proc do |value|
472
+ :items => lambda do |value|
452
473
  value.to_java :string
453
474
  end,
454
- :text => proc do |value|
475
+ :text => lambda do |value|
455
476
  if swt_widget.is_a?(Browser)
456
477
  value.to_s
457
478
  else
458
479
  value.to_s
459
480
  end
460
481
  end,
461
- :visible => proc do |value|
482
+ :visible => lambda do |value|
462
483
  !!value
463
484
  end,
464
485
  }