glimmer 0.2.5 → 0.3.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.
- checksums.yaml +4 -4
- data/README.markdown +2 -2
- data/lib/command_handlers/combo_selection_data_binding_command_handler.rb +3 -3
- data/lib/command_handlers/data_binding_command_handler.rb +1 -1
- data/lib/command_handlers/list_selection_data_binding_command_handler.rb +5 -3
- data/lib/command_handlers/models/block_observer.rb +2 -1
- data/lib/command_handlers/models/list_selection_binding.rb +6 -0
- data/lib/command_handlers/models/model_binding.rb +60 -22
- data/lib/command_handlers/models/observable.rb +9 -0
- data/lib/command_handlers/models/observable_array.rb +61 -23
- data/lib/command_handlers/models/observable_model.rb +65 -36
- data/lib/command_handlers/models/observer.rb +72 -1
- data/lib/command_handlers/models/r_widget.rb +16 -16
- data/lib/command_handlers/models/table_items_binding.rb +8 -2
- data/lib/command_handlers/models/tree_items_binding.rb +10 -4
- data/lib/command_handlers/models/widget_binding.rb +6 -0
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: cc35b055fcf86d7c93b264b409424039c63c0361f0a7b587e9db0f2071e7809e
|
4
|
+
data.tar.gz: 3ab0eec08e13367c717ee74a984fea0ee49bbd309fd2fd3348fb40e70b156b2c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: '059e99839505e645cc41cd13d0adc2f04680643dd7d45d6b6ecb0e9e2fec7823f330f0962756f745ba9ca564c945fb97480e988d21efd732fb3ec36185c8dc89'
|
7
|
+
data.tar.gz: eb9f191f5aa31e9d716b787bb1b54d0792fb2aaaf080f8f37b7dd17e0ada300192986910b8fe3bcf777a1da7382cf5bd8dd3c6d59bccf63703fbcb95b3fa7bc9
|
data/README.markdown
CHANGED
@@ -66,14 +66,14 @@ Please follow these instructions to make the `glimmer` command available on your
|
|
66
66
|
|
67
67
|
Run this command to install directly:
|
68
68
|
```
|
69
|
-
jgem install glimmer -v 0.
|
69
|
+
jgem install glimmer -v 0.3.1
|
70
70
|
```
|
71
71
|
|
72
72
|
### Option 2: Bundler
|
73
73
|
|
74
74
|
Add the following to `Gemfile`:
|
75
75
|
```
|
76
|
-
gem 'glimmer', '~> 0.
|
76
|
+
gem 'glimmer', '~> 0.3.1'
|
77
77
|
```
|
78
78
|
|
79
79
|
And, then run:
|
@@ -22,12 +22,12 @@ class ComboSelectionDataBindingCommandHandler
|
|
22
22
|
widget_binding = WidgetBinding.new(parent, "items")
|
23
23
|
widget_binding.update(model_binding.evaluate_options_property)
|
24
24
|
model = model_binding.base_model
|
25
|
-
model.extend
|
26
|
-
|
25
|
+
model.extend(ObservableModel) unless model.is_a?(ObservableModel)
|
26
|
+
widget_binding.observe(model, model_binding.options_property_name)
|
27
27
|
|
28
28
|
widget_binding = WidgetBinding.new(parent, "text")
|
29
29
|
widget_binding.update(model_binding.evaluate_property)
|
30
|
-
|
30
|
+
widget_binding.observe(model, model_binding.property_name_expression)
|
31
31
|
|
32
32
|
add_contents(parent) {
|
33
33
|
on_widget_selected {
|
@@ -58,7 +58,7 @@ class DataBindingCommandHandler
|
|
58
58
|
widget_binding_parameters = [parent, command_symbol.to_s]
|
59
59
|
widget_binding = WidgetBinding.new(*widget_binding_parameters)
|
60
60
|
widget_binding.update(model_binding.evaluate_property)
|
61
|
-
|
61
|
+
widget_binding.observe(model_binding)
|
62
62
|
widget_data_binder_map = @@widget_data_binders[parent.widget.class]
|
63
63
|
widget_data_binder = widget_data_binder_map[command_symbol.to_s.to_sym] if widget_data_binder_map
|
64
64
|
widget_data_binder.call(parent, model_binding) if widget_data_binder
|
@@ -23,14 +23,16 @@ class ListSelectionDataBindingCommandHandler
|
|
23
23
|
widget_binding = WidgetBinding.new(parent, "items")
|
24
24
|
widget_binding.update(model_binding.evaluate_options_property)
|
25
25
|
model = model_binding.base_model
|
26
|
-
model.extend
|
27
|
-
|
26
|
+
model.extend(ObservableModel) unless model.is_a?(ObservableModel)
|
27
|
+
#TODO make this options observer dependent and all similar observers in widget specific data binding handlers
|
28
|
+
widget_binding.observe(model, model_binding.options_property_name)
|
28
29
|
|
29
30
|
property_type = :string
|
30
31
|
property_type = :array if parent.has_style?(:multi)
|
31
32
|
list_selection_binding = ListSelectionBinding.new(parent, property_type)
|
32
33
|
list_selection_binding.update(model_binding.evaluate_property)
|
33
|
-
|
34
|
+
#TODO check if nested data binding works for list widget and other widgets that need custom data binding
|
35
|
+
list_selection_binding.observe(model, model_binding.property_name_expression)
|
34
36
|
|
35
37
|
add_contents(parent) {
|
36
38
|
on_widget_selected {
|
@@ -2,6 +2,7 @@ require File.dirname(__FILE__) + "/observer"
|
|
2
2
|
|
3
3
|
# SWT List widget selection binding
|
4
4
|
class ListSelectionBinding
|
5
|
+
include Glimmer
|
5
6
|
include Observer
|
6
7
|
|
7
8
|
attr_reader :widget
|
@@ -25,6 +26,11 @@ class ListSelectionBinding
|
|
25
26
|
property_type = :string if property_type.nil? or property_type == :undefined
|
26
27
|
@widget = widget
|
27
28
|
@property_type = property_type
|
29
|
+
add_contents(@widget) {
|
30
|
+
on_widget_disposed { |dispose_event|
|
31
|
+
unregister_all_observables
|
32
|
+
}
|
33
|
+
}
|
28
34
|
end
|
29
35
|
def update(value)
|
30
36
|
@@property_type_updaters[@property_type].call(@widget, value) unless evaluate_property == value
|
@@ -1,4 +1,5 @@
|
|
1
|
-
|
1
|
+
require_relative 'observer'
|
2
|
+
require_relative 'block_observer'
|
2
3
|
|
3
4
|
class ModelBinding
|
4
5
|
include Observer
|
@@ -92,40 +93,77 @@ class ModelBinding
|
|
92
93
|
)
|
93
94
|
end
|
94
95
|
end
|
96
|
+
# @nested_property_observers_collection[observer].keys.each_with_index do |property_name, i|
|
97
|
+
# previous_property_name = nested_property_names[i-1]
|
98
|
+
# previous_observer = @nested_property_observers_collection[observer][previous_property_name]
|
99
|
+
# nested_property_observer = @nested_property_observers_collection[observer][property_name]
|
100
|
+
# previous_observer.add_dependent(nested_property_observer) unless previous_observer.nil?
|
101
|
+
# end
|
102
|
+
# TODO remove this brainstorming
|
103
|
+
# person.addresses[1].streets[2].number
|
104
|
+
# person.addresses[1] = ...
|
95
105
|
@nested_property_observers_collection[observer]
|
96
106
|
end
|
97
107
|
def add_observer(observer)
|
98
108
|
if computed?
|
99
109
|
add_computed_observers(observer)
|
110
|
+
elsif nested_property?
|
111
|
+
add_nested_observers(observer)
|
100
112
|
else
|
101
|
-
|
113
|
+
model.extend(ObservableModel) unless model.is_a?(ObservableModel)
|
114
|
+
observer.observe(model, property_name)
|
115
|
+
observer.add_dependent([self, nil] => [observer, model, property_name])
|
102
116
|
end
|
103
117
|
end
|
104
|
-
def
|
105
|
-
|
106
|
-
|
118
|
+
def remove_observer(observer)
|
119
|
+
if computed?
|
120
|
+
@computed_model_bindings.each do |computed_model_binding|
|
121
|
+
computed_observer_for(observer).unobserve(computed_model_binding)
|
122
|
+
end
|
123
|
+
@computed_observer_collection[observer] = nil
|
124
|
+
elsif nested_property?
|
125
|
+
nested_property_observers_for(observer).clear
|
126
|
+
else
|
127
|
+
model.extend(ObservableModel) unless model.is_a?(ObservableModel)
|
128
|
+
observer.unobserve(model, property_name)
|
107
129
|
end
|
130
|
+
end
|
131
|
+
def computed_observer_for(observer)
|
132
|
+
@computed_observer_collection ||= {}
|
133
|
+
unless @computed_observer_collection.has_key?(observer)
|
134
|
+
@computed_observer_collection[observer] = BlockObserver.new do |changed_value|
|
135
|
+
observer.update(evaluate_property)
|
136
|
+
end
|
137
|
+
end
|
138
|
+
@computed_observer_collection[observer]
|
139
|
+
end
|
140
|
+
def add_computed_observers(observer)
|
108
141
|
@computed_model_bindings.each do |computed_model_binding|
|
109
|
-
|
142
|
+
computed_observer_for(observer).observe(computed_model_binding)
|
143
|
+
observer.add_dependent([self, nil] => [computed_observer_for(observer), computed_model_binding, nil])
|
110
144
|
end
|
111
145
|
end
|
112
|
-
def
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
146
|
+
def add_nested_observers(observer)
|
147
|
+
nested_property_observers = nested_property_observers_for(observer)
|
148
|
+
nested_models.zip(nested_property_names).each_with_index do |zip, i|
|
149
|
+
model, property_name = zip
|
150
|
+
nested_property_observer = nested_property_observers[property_name]
|
151
|
+
previous_index = i - 1
|
152
|
+
parent_model = previous_index.negative? ? self : nested_models[previous_index]
|
153
|
+
parent_property_name = previous_index.negative? ? nil : nested_property_names[previous_index]
|
154
|
+
parent_observer = previous_index.negative? ? observer : nested_property_observers[parent_property_name]
|
155
|
+
parent_property_name = nil if parent_property_name.to_s.start_with?('[')
|
156
|
+
unless model.nil?
|
157
|
+
if property_indexed?(property_name)
|
158
|
+
model.extend(ObservableArray) unless model.is_a?(ObservableArray)
|
159
|
+
nested_property_observer.observe(model) unless model.has_observer?(nested_property_observer)
|
160
|
+
parent_observer.add_dependent([parent_model, parent_property_name] => [nested_property_observer, model, nil])
|
161
|
+
else
|
162
|
+
model.extend(ObservableModel) unless model.is_a?(ObservableModel)
|
163
|
+
nested_property_observer.observe(model, property_name) unless model.has_observer?(nested_property_observer, property_name)
|
164
|
+
parent_observer.add_dependent([parent_model, parent_property_name] => [nested_property_observer, model, property_name])
|
124
165
|
end
|
125
166
|
end
|
126
|
-
else
|
127
|
-
model.extend ObservableModel unless model.is_a?(ObservableModel)
|
128
|
-
model.add_observer(property_name, observer)
|
129
167
|
end
|
130
168
|
end
|
131
169
|
def update(value)
|
@@ -137,7 +175,7 @@ class ModelBinding
|
|
137
175
|
invoke_property_reader(model, property_name) unless model.nil?
|
138
176
|
end
|
139
177
|
def evaluate_options_property
|
140
|
-
model.send(
|
178
|
+
model.send(options_property_name) unless model.nil?
|
141
179
|
end
|
142
180
|
def options_property_name
|
143
181
|
self.property_name + "_options"
|
@@ -1,27 +1,39 @@
|
|
1
1
|
require 'set'
|
2
|
+
|
3
|
+
require_relative 'observable'
|
4
|
+
|
5
|
+
# TODO prefix utility methods with double-underscore
|
2
6
|
module ObservableArray
|
7
|
+
include Observable
|
3
8
|
|
4
|
-
def add_observer(
|
9
|
+
def add_observer(observer, element_properties=nil)
|
5
10
|
property_observer_list << observer
|
6
|
-
each do |
|
7
|
-
|
11
|
+
[element_properties].flatten.compact.each do |property|
|
12
|
+
each do |element|
|
8
13
|
element.extend(ObservableModel) unless element.is_a?(ObservableModel)
|
9
|
-
|
14
|
+
observer.observe(element, property)
|
10
15
|
end
|
11
16
|
end
|
17
|
+
observer
|
12
18
|
end
|
13
19
|
|
14
|
-
def
|
15
|
-
property_observer_list
|
20
|
+
def remove_observer(observer, element_properties=nil)
|
21
|
+
property_observer_list.delete(observer)
|
22
|
+
[element_properties].flatten.compact.each do |property|
|
23
|
+
each do |element|
|
24
|
+
element.extend(ObservableModel) unless element.is_a?(ObservableModel)
|
25
|
+
observer.unobserve(element, property)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
observer
|
16
29
|
end
|
17
30
|
|
18
|
-
def
|
31
|
+
def has_observer?(observer)
|
19
32
|
property_observer_list.include?(observer)
|
20
33
|
end
|
21
34
|
|
22
35
|
def property_observer_list
|
23
|
-
@property_observer_list
|
24
|
-
@property_observer_list
|
36
|
+
@property_observer_list ||= Set.new
|
25
37
|
end
|
26
38
|
|
27
39
|
def notify_observers
|
@@ -29,37 +41,63 @@ module ObservableArray
|
|
29
41
|
end
|
30
42
|
|
31
43
|
def self.extend_object(array)
|
32
|
-
array.instance_eval("alias
|
44
|
+
array.instance_eval("alias __original_add <<")
|
33
45
|
array.instance_eval <<-end_eval, __FILE__, __LINE__
|
34
46
|
def <<(value)
|
35
|
-
self.
|
47
|
+
self.__original_add(value)
|
36
48
|
notify_observers
|
37
49
|
end
|
38
50
|
end_eval
|
39
51
|
|
40
|
-
array.instance_eval("alias
|
52
|
+
array.instance_eval("alias __original_set_value []=")
|
41
53
|
array.instance_eval <<-end_eval, __FILE__, __LINE__
|
42
54
|
def []=(index, value)
|
43
|
-
self
|
55
|
+
old_value = self[index]
|
56
|
+
unregister_dependent_observers(old_value)
|
57
|
+
self.__original_set_value(index, value)
|
44
58
|
notify_observers
|
45
59
|
end
|
46
60
|
end_eval
|
47
61
|
|
48
|
-
|
49
|
-
|
50
|
-
|
62
|
+
array.instance_eval("alias __original_delete delete")
|
63
|
+
array.instance_eval <<-end_eval, __FILE__, __LINE__
|
64
|
+
def delete(value)
|
65
|
+
unregister_dependent_observers(value)
|
66
|
+
self.__original_delete(value)
|
67
|
+
notify_observers
|
68
|
+
end
|
69
|
+
end_eval
|
51
70
|
|
52
|
-
|
53
|
-
|
71
|
+
array.instance_eval("alias __original_delete_at delete_at")
|
72
|
+
array.instance_eval <<-end_eval, __FILE__, __LINE__
|
73
|
+
def delete_at(index)
|
74
|
+
old_value = self[index]
|
75
|
+
unregister_dependent_observers(old_value)
|
76
|
+
self.__original_delete_at(index)
|
77
|
+
notify_observers
|
78
|
+
end
|
79
|
+
end_eval
|
54
80
|
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
81
|
+
array.instance_eval("alias __original_clear clear")
|
82
|
+
array.instance_eval <<-end_eval, __FILE__, __LINE__
|
83
|
+
def clear
|
84
|
+
each do |old_value|
|
85
|
+
unregister_dependent_observers(old_value)
|
86
|
+
end
|
87
|
+
self.__original_clear
|
60
88
|
notify_observers
|
61
89
|
end
|
62
90
|
end_eval
|
91
|
+
|
92
|
+
super
|
93
|
+
end
|
94
|
+
|
95
|
+
def unregister_dependent_observers(old_value)
|
96
|
+
# TODO look into optimizing this
|
97
|
+
return unless old_value.is_a?(ObservableModel) || old_value.is_a?(ObservableArray)
|
98
|
+
property_observer_list.each do |observer|
|
99
|
+
observer.unregister_dependents_with_observable([self, nil], old_value)
|
100
|
+
end
|
63
101
|
end
|
64
102
|
|
65
103
|
end
|
@@ -1,19 +1,42 @@
|
|
1
1
|
require 'set'
|
2
2
|
|
3
|
-
|
3
|
+
require_relative 'observable'
|
4
|
+
require_relative 'observer'
|
4
5
|
|
6
|
+
# TODO prefix utility methods with double-underscore
|
5
7
|
module ObservableModel
|
8
|
+
include Observable
|
6
9
|
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
+
class Updater
|
11
|
+
include Observer
|
12
|
+
def initialize(observable_model, property_name)
|
13
|
+
@observable_model = observable_model
|
14
|
+
@property_name = property_name
|
15
|
+
end
|
16
|
+
def update(changed_value=nil)
|
17
|
+
@observable_model.notify_observers(@property_name)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def add_observer(observer, property_name)
|
22
|
+
return observer if has_observer?(observer, property_name)
|
10
23
|
property_observer_list(property_name) << observer
|
24
|
+
add_property_writer_observers(property_name)
|
25
|
+
observer
|
11
26
|
end
|
12
27
|
|
13
|
-
def
|
28
|
+
def remove_observer(observer, property_name)
|
29
|
+
property_observer_list(property_name).delete(observer)
|
30
|
+
end
|
31
|
+
|
32
|
+
def has_observer?(observer, property_name)
|
14
33
|
property_observer_list(property_name).include?(observer)
|
15
34
|
end
|
16
35
|
|
36
|
+
def has_observer_for_any_property?(observer)
|
37
|
+
property_observer_hash.values.map(&:to_a).sum.include?(observer)
|
38
|
+
end
|
39
|
+
|
17
40
|
def property_observer_hash
|
18
41
|
@property_observers = Hash.new unless @property_observers
|
19
42
|
@property_observers
|
@@ -27,45 +50,51 @@ module ObservableModel
|
|
27
50
|
def notify_observers(property_name)
|
28
51
|
property_observer_list(property_name).each {|observer| observer.update(send(property_name))}
|
29
52
|
end
|
53
|
+
#TODO upon updating values, make sure dependent observers are cleared (not added as dependents here)
|
30
54
|
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
55
|
+
def add_property_writer_observers(property_name)
|
56
|
+
property_writer_name = "#{property_name}="
|
57
|
+
ensure_array_object_observer(property_name, send(property_name))
|
58
|
+
begin
|
59
|
+
method("__original_#{property_writer_name}")
|
60
|
+
rescue
|
61
|
+
instance_eval "alias __original_#{property_writer_name} #{property_writer_name}"
|
62
|
+
instance_eval <<-end_eval, __FILE__, __LINE__
|
63
|
+
def #{property_writer_name}(value)
|
64
|
+
old_value = self.#{property_name}
|
65
|
+
unregister_dependent_observers('#{property_name}', old_value)
|
66
|
+
self.__original_#{property_writer_name}(value)
|
67
|
+
notify_observers('#{property_name}')
|
68
|
+
ensure_array_object_observer('#{property_name}', value, old_value)
|
69
|
+
end
|
70
|
+
end_eval
|
35
71
|
end
|
36
|
-
|
37
|
-
|
72
|
+
end
|
73
|
+
|
74
|
+
def unregister_dependent_observers(property_name, old_value)
|
75
|
+
# TODO look into optimizing this
|
76
|
+
return unless old_value.is_a?(ObservableModel) || old_value.is_a?(ObservableArray)
|
77
|
+
property_observer_list(property_name).each do |observer|
|
78
|
+
observer.unregister_dependents_with_observable([self, property_name], old_value)
|
38
79
|
end
|
39
80
|
end
|
40
81
|
|
41
|
-
def
|
42
|
-
|
43
|
-
|
44
|
-
|
82
|
+
def ensure_array_object_observer(property_name, object, old_object = nil)
|
83
|
+
return unless object.is_a?(Array)
|
84
|
+
object.extend(ObservableArray) unless object.is_a?(ObservableArray)
|
85
|
+
array_object_observer = array_object_observer_for(property_name)
|
86
|
+
array_object_observer.observe(object)
|
87
|
+
property_observer_list(property_name).each do |observer|
|
88
|
+
observer.add_dependent([self, property_name] => [array_object_observer, object, nil])
|
45
89
|
end
|
90
|
+
array_object_observer_for(property_name).unregister(old_object) if old_object.is_a?(ObservableArray)
|
46
91
|
end
|
47
92
|
|
48
|
-
def
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
getter_value = model.send(getter_method)
|
53
|
-
if (getter_value.is_a?(Array) and
|
54
|
-
!getter_value.is_a?(ObservableArray))
|
55
|
-
getter_value.extend(ObservableArray)
|
56
|
-
getter_value.add_observer([], Updater.new(getter_method, model))
|
57
|
-
end
|
58
|
-
model.instance_eval "alias original_#{method} #{method}\n"
|
59
|
-
model.instance_eval <<-end_eval, __FILE__, __LINE__
|
60
|
-
def #{method}(value)
|
61
|
-
self.original_#{method}(value)
|
62
|
-
notify_observers('#{getter_method}')
|
63
|
-
if (value.is_a?(Array) and !value.is_a?(ObservableArray))
|
64
|
-
value.extend(ObservableArray)
|
65
|
-
value.add_observer([], ObservableModel::Updater.new('#{getter_method}', self))
|
66
|
-
end
|
67
|
-
end
|
68
|
-
end_eval
|
93
|
+
def array_object_observer_for(property_name)
|
94
|
+
@array_object_observers ||= {}
|
95
|
+
unless @array_object_observers.has_key?(property_name)
|
96
|
+
@array_object_observers[property_name] = ObservableModel::Updater.new(self, property_name)
|
69
97
|
end
|
98
|
+
@array_object_observers[property_name]
|
70
99
|
end
|
71
100
|
end
|
@@ -1,8 +1,79 @@
|
|
1
|
+
require 'set'
|
2
|
+
|
1
3
|
# Mixin representing Observer trait from Observer Design Pattern
|
2
4
|
# Allows classes to include without interfering with their
|
3
5
|
# inheritance hierarchy.
|
4
|
-
|
5
6
|
module Observer
|
7
|
+
def registrations
|
8
|
+
@registrations ||= Set.new
|
9
|
+
end
|
10
|
+
|
11
|
+
def registrations_for(observable, property = nil)
|
12
|
+
registrations.select {|o, p| o == observable && p == property}
|
13
|
+
end
|
14
|
+
|
15
|
+
# mapping of registrations to dependents
|
16
|
+
# {[observable, property] => [[dependent, dependent_observable, dependent_property], ...]}
|
17
|
+
def dependents
|
18
|
+
@dependents ||= Hash.new
|
19
|
+
end
|
20
|
+
|
21
|
+
def dependents_for(registration)
|
22
|
+
dependents[registration] ||= Set.new
|
23
|
+
end
|
24
|
+
|
25
|
+
# registers observer in an observable on a property (optional)
|
26
|
+
# observer maintains registration list to unregister later
|
27
|
+
def register(observable, property = nil)
|
28
|
+
observable.add_observer(*[self, property].compact)
|
29
|
+
[observable, property].tap do |registration|
|
30
|
+
self.registrations << registration
|
31
|
+
end
|
32
|
+
end
|
33
|
+
alias observe register
|
34
|
+
|
35
|
+
def unregister(observable, property = nil)
|
36
|
+
observable.remove_observer(*[self, property].compact)
|
37
|
+
registration = [observable, property]
|
38
|
+
dependents_for(registration).each do |dependent|
|
39
|
+
dependent_observer, dependent_observable, dependent_property = dependent
|
40
|
+
dependent_observer.unregister(dependent_observable, dependent_property)
|
41
|
+
remove_dependent(registration => dependent)
|
42
|
+
end
|
43
|
+
registrations.delete(registration)
|
44
|
+
end
|
45
|
+
alias unobserve unregister
|
46
|
+
|
47
|
+
def unregister_dependents_with_observable(registration, dependent_observable)
|
48
|
+
thedependents = dependents_for(registration).select do |d_observer, d_observable, d_property|
|
49
|
+
d_observable == dependent_observable
|
50
|
+
end
|
51
|
+
thedependents.each do |d_observer, d_observable, d_property|
|
52
|
+
d_observer.unregister(d_observable, d_property)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
# cleans up all registrations in observables
|
57
|
+
def unregister_all_observables
|
58
|
+
registrations.each do |observable, property|
|
59
|
+
unregister(observable, property)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
alias unobserve_all_observables unregister_all_observables
|
63
|
+
|
64
|
+
# add dependent observer to unregister when unregistering observer
|
65
|
+
def add_dependent(parent_to_dependent_hash)
|
66
|
+
observable, property = registration = parent_to_dependent_hash.keys.first
|
67
|
+
dependent_observer, dependent_observable, dependent_property = dependent = parent_to_dependent_hash.values.first
|
68
|
+
dependents_for(registration) << dependent
|
69
|
+
end
|
70
|
+
|
71
|
+
def remove_dependent(parent_to_dependent_hash)
|
72
|
+
observable, property = registration = parent_to_dependent_hash.keys.first
|
73
|
+
dependent_observer, dependent_observable, dependent_property = dependent = parent_to_dependent_hash.values.first
|
74
|
+
dependents_for(registration).delete(dependent)
|
75
|
+
end
|
76
|
+
|
6
77
|
def update(changed_value)
|
7
78
|
raise 'Not implemented!'
|
8
79
|
end
|
@@ -5,9 +5,9 @@ class RWidget
|
|
5
5
|
require File.dirname(__FILE__) + "/r_widget_packages"
|
6
6
|
|
7
7
|
include Parent
|
8
|
-
|
8
|
+
|
9
9
|
attr_reader :widget
|
10
|
-
|
10
|
+
|
11
11
|
#TODO externalize
|
12
12
|
@@default_styles = {
|
13
13
|
"text" => SWT::BORDER,
|
@@ -16,11 +16,11 @@ class RWidget
|
|
16
16
|
"list" => SWT::BORDER | SWT::V_SCROLL,
|
17
17
|
"button" => SWT::PUSH,
|
18
18
|
}
|
19
|
-
|
19
|
+
|
20
20
|
#TODO externalize
|
21
21
|
@@default_initializers = {
|
22
22
|
"composite" => Proc.new {|composite| composite.setLayout(GridLayout.new) },
|
23
|
-
"table" => Proc.new do |table|
|
23
|
+
"table" => Proc.new do |table|
|
24
24
|
table.setHeaderVisible(true)
|
25
25
|
table.setLinesVisible(true)
|
26
26
|
end,
|
@@ -33,7 +33,7 @@ class RWidget
|
|
33
33
|
@widget = underscored_widget_name.swt_widget.new(parent, style(underscored_widget_name, styles))
|
34
34
|
@@default_initializers[underscored_widget_name].call(@widget) if @@default_initializers[underscored_widget_name]
|
35
35
|
end
|
36
|
-
|
36
|
+
|
37
37
|
def has_attribute?(attribute_name, *args)
|
38
38
|
@widget.respond_to?(attribute_setter(attribute_name), args)
|
39
39
|
end
|
@@ -66,10 +66,10 @@ class RWidget
|
|
66
66
|
end
|
67
67
|
return false
|
68
68
|
end
|
69
|
-
|
69
|
+
|
70
70
|
def can_add_listener?(underscored_listener_name)
|
71
71
|
listener_method_name = underscored_listener_name.camelcase(:lower)
|
72
|
-
@widget.getClass.getMethods.each do |widget_method|
|
72
|
+
@widget.getClass.getMethods.each do |widget_method|
|
73
73
|
if widget_method.getName.match(/add.*Listener/)
|
74
74
|
widget_method.getParameterTypes.each do |listener_type|
|
75
75
|
listener_type.getMethods.each do |listener_method|
|
@@ -82,10 +82,10 @@ class RWidget
|
|
82
82
|
end
|
83
83
|
return false
|
84
84
|
end
|
85
|
-
|
86
|
-
def add_listener(underscored_listener_name, &block)
|
85
|
+
|
86
|
+
def add_listener(underscored_listener_name, &block)
|
87
87
|
listener_method_name = underscored_listener_name.camelcase(:lower)
|
88
|
-
@widget.getClass.getMethods.each do |widget_method|
|
88
|
+
@widget.getClass.getMethods.each do |widget_method|
|
89
89
|
if widget_method.getName.match(/add.*Listener/)
|
90
90
|
widget_method.getParameterTypes.each do |listener_type|
|
91
91
|
listener_type.getMethods.each do |listener_method|
|
@@ -109,11 +109,11 @@ class RWidget
|
|
109
109
|
end
|
110
110
|
end
|
111
111
|
end
|
112
|
-
|
112
|
+
|
113
113
|
def process_block(block)
|
114
114
|
block.call(@widget)
|
115
115
|
end
|
116
|
-
|
116
|
+
|
117
117
|
def async_exec(&block)
|
118
118
|
@widget.getDisplay.asyncExec(RRunnable.new(&block))
|
119
119
|
end
|
@@ -121,7 +121,7 @@ class RWidget
|
|
121
121
|
def sync_exec(&block)
|
122
122
|
@widget.getDisplay.syncExec(RRunnable.new(&block))
|
123
123
|
end
|
124
|
-
|
124
|
+
|
125
125
|
def has_style?(style)
|
126
126
|
(widget.style & style.swt_constant) == style.swt_constant
|
127
127
|
end
|
@@ -144,10 +144,10 @@ class RWidget
|
|
144
144
|
|
145
145
|
def swt_styles(styles)
|
146
146
|
styles.map(&:swt_constant)
|
147
|
-
end
|
148
|
-
|
147
|
+
end
|
148
|
+
|
149
149
|
def attribute_setter(attribute_name)
|
150
150
|
"set#{attribute_name.to_s.camelcase(:upper)}"
|
151
151
|
end
|
152
152
|
|
153
|
-
end
|
153
|
+
end
|
@@ -3,6 +3,7 @@ require File.dirname(__FILE__) + "/observable_model"
|
|
3
3
|
require File.dirname(__FILE__) + "/observer"
|
4
4
|
|
5
5
|
class TableItemsBinding
|
6
|
+
include Glimmer
|
6
7
|
include Observer
|
7
8
|
include_package 'org.eclipse.swt'
|
8
9
|
include_package 'org.eclipse.swt.widgets'
|
@@ -14,12 +15,17 @@ class TableItemsBinding
|
|
14
15
|
update(@model_binding.evaluate_property)
|
15
16
|
model = model_binding.base_model
|
16
17
|
model.extend(ObservableModel) unless model.is_a?(ObservableModel)
|
17
|
-
model
|
18
|
+
observe(model, model_binding.property_name_expression)
|
19
|
+
add_contents(@table) {
|
20
|
+
on_widget_disposed { |dispose_event|
|
21
|
+
unregister_all_observables
|
22
|
+
}
|
23
|
+
}
|
18
24
|
end
|
19
25
|
def update(model_collection=nil)
|
20
26
|
if model_collection and model_collection.is_a?(Array)
|
21
27
|
model_collection.extend(ObservableArray) unless model_collection.is_a?(ObservableArray)
|
22
|
-
model_collection
|
28
|
+
observe(model_collection, @column_properties)
|
23
29
|
@model_collection = model_collection
|
24
30
|
end
|
25
31
|
populate_table(@model_collection, @table, @column_properties)
|
@@ -3,6 +3,7 @@ require File.dirname(__FILE__) + "/observable_model"
|
|
3
3
|
require File.dirname(__FILE__) + "/observer"
|
4
4
|
|
5
5
|
class TreeItemsBinding
|
6
|
+
include Glimmer
|
6
7
|
include Observer
|
7
8
|
include_package 'org.eclipse.swt'
|
8
9
|
include_package 'org.eclipse.swt.widgets'
|
@@ -14,13 +15,18 @@ class TreeItemsBinding
|
|
14
15
|
update(@model_binding.evaluate_property)
|
15
16
|
model = model_binding.base_model
|
16
17
|
model.extend(ObservableModel) unless model.is_a?(ObservableModel)
|
17
|
-
model
|
18
|
+
observe(model, model_binding.property_name_expression)
|
19
|
+
add_contents(@tree) {
|
20
|
+
on_widget_disposed { |dispose_event|
|
21
|
+
unregister_all_observables
|
22
|
+
}
|
23
|
+
}
|
18
24
|
end
|
19
25
|
def update(model_tree_root_node=nil)
|
20
26
|
if model_tree_root_node and model_tree_root_node.respond_to?(@tree_properties[:children])
|
21
27
|
model_tree_root_node.extend(ObservableModel) unless model_tree_root_node.is_a?(ObservableModel)
|
22
|
-
model_tree_root_node
|
23
|
-
model_tree_root_node
|
28
|
+
observe(model_tree_root_node, @tree_properties[:text])
|
29
|
+
observe(model_tree_root_node, @tree_properties[:children])
|
24
30
|
@model_tree_root_node = model_tree_root_node
|
25
31
|
end
|
26
32
|
populate_tree(@model_tree_root_node, @tree, @tree_properties)
|
@@ -34,7 +40,7 @@ class TreeItemsBinding
|
|
34
40
|
table_item.setText((model_tree_node && model_tree_node.send(tree_properties[:text])).to_s)
|
35
41
|
[model_tree_node && model_tree_node.send(tree_properties[:children])].flatten.to_a.compact.each do |child|
|
36
42
|
child.extend(ObservableModel) unless child.is_a?(ObservableModel)
|
37
|
-
child
|
43
|
+
observe(child, @tree_properties[:text])
|
38
44
|
populate_tree_node(child, table_item, tree_properties)
|
39
45
|
end
|
40
46
|
end
|
@@ -1,6 +1,7 @@
|
|
1
1
|
require File.dirname(__FILE__) + "/observer"
|
2
2
|
|
3
3
|
class WidgetBinding
|
4
|
+
include Glimmer
|
4
5
|
include Observer
|
5
6
|
|
6
7
|
attr_reader :widget, :property
|
@@ -13,6 +14,11 @@ class WidgetBinding
|
|
13
14
|
@widget = model
|
14
15
|
@property = property
|
15
16
|
@translator = translator || proc {|value| value}
|
17
|
+
add_contents(@widget) {
|
18
|
+
on_widget_disposed { |dispose_event|
|
19
|
+
unregister_all_observables
|
20
|
+
}
|
21
|
+
}
|
16
22
|
end
|
17
23
|
def update(value)
|
18
24
|
converted_value = translated_value = @translator.call(value)
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: glimmer
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- AndyMaleh
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-03-
|
11
|
+
date: 2020-03-11 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
requirement: !ruby/object:Gem::Requirement
|
@@ -162,6 +162,7 @@ files:
|
|
162
162
|
- lib/command_handlers/models/block_observer.rb
|
163
163
|
- lib/command_handlers/models/list_selection_binding.rb
|
164
164
|
- lib/command_handlers/models/model_binding.rb
|
165
|
+
- lib/command_handlers/models/observable.rb
|
165
166
|
- lib/command_handlers/models/observable_array.rb
|
166
167
|
- lib/command_handlers/models/observable_model.rb
|
167
168
|
- lib/command_handlers/models/observer.rb
|