rugui 1.3.0 → 1.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.
- data/Changelog +9 -0
- data/lib/packing/release.rb +2 -2
- data/lib/rugui/base_controller.rb +101 -42
- data/lib/rugui/base_model.rb +1 -1
- data/lib/rugui/base_view.rb +2 -2
- data/lib/rugui/configuration.rb +8 -0
- data/lib/rugui/entity_registration_support.rb +94 -0
- data/lib/rugui/framework_adapters/GTK.rb +5 -1
- data/lib/rugui/framework_adapters/Qt4.rb +5 -0
- data/lib/rugui/framework_adapters/base_framework_adapter.rb +7 -0
- data/lib/rugui/log_support.rb +5 -3
- data/lib/rugui/observable_property_support.rb +4 -1
- data/lib/rugui/property_changed_support.rb +119 -0
- data/lib/rugui/property_observer.rb +12 -5
- data/lib/rugui/version.rb +1 -1
- data/lib/rugui.rb +3 -1
- data/spec/framework/base_controller_spec.rb +85 -0
- data/spec/framework/observable_property_support_spec.rb +6 -0
- data/spec/helpers/controllers.rb +10 -5
- data/spec/helpers/models.rb +3 -0
- data/spec/helpers/views.rb +6 -0
- data/spec/resource_files/my_other_view.glade +1 -1
- data/spec/resource_files/my_view.glade +1 -1
- data/spec/spec.opts +1 -0
- metadata +4 -2
data/Changelog
CHANGED
@@ -1,3 +1,12 @@
|
|
1
|
+
1.3.1
|
2
|
+
- Added a DSL to detect when observable properties were changed.
|
3
|
+
- Silencing logs when running in test environment unless a level is defined in test environment configuration file.
|
4
|
+
- Added refresh method to be used when testing GUI parts (views) of applications.
|
5
|
+
- Conventionally named views are now registered automatically (i.e., for a controller named MyController, a view named MyView will be registered automatically)
|
6
|
+
- Added a new style registering of controllers, views and models, with option for registering main models (models which are already registered in the main controller)
|
7
|
+
- Connecting signals for widget types only if the widget isn't destroyed
|
8
|
+
- Fixed a bug which happened when copying properties from a observable when the destination observable property value was nil
|
9
|
+
|
1
10
|
1.3.0
|
2
11
|
- Added support to upload RuGUI to rubyforge.
|
3
12
|
- Updated README docs with new instructions for installation.
|
data/lib/packing/release.rb
CHANGED
@@ -9,8 +9,8 @@ begin
|
|
9
9
|
gemspec.authors = ["Vicente Mundim", "Felipe Mesquita", "Claudio Escudero"]
|
10
10
|
gemspec.add_dependency(%q<activesupport>, [">= 2.1.1"])
|
11
11
|
gemspec.add_dependency(%q<rubigen>, [">= 1.5.1"])
|
12
|
-
gemspec.version = "1.3.
|
13
|
-
gemspec.date = %q{2009-
|
12
|
+
gemspec.version = "1.3.1"
|
13
|
+
gemspec.date = %q{2009-06-16}
|
14
14
|
gemspec.rubyforge_project = "rugui"
|
15
15
|
gemspec.executables = ['rugui']
|
16
16
|
gemspec.files = FileList["bin/*", "lib/**/*", "rugui_generators/**/*", "script/*", "spec/**/*", "Changelog", "LICENSE", "Rakefile", "README"].to_a
|
@@ -6,14 +6,17 @@ module RuGUI
|
|
6
6
|
include RuGUI::PropertyObserver
|
7
7
|
include RuGUI::LogSupport
|
8
8
|
include RuGUI::SignalSupport
|
9
|
+
include RuGUI::EntityRegistrationSupport
|
9
10
|
|
10
11
|
attr_accessor :models
|
12
|
+
attr_accessor :main_models
|
11
13
|
attr_accessor :views
|
12
14
|
attr_accessor :controllers
|
13
15
|
attr_accessor :parent_controller
|
14
16
|
|
15
17
|
def initialize(parent_controller = nil)
|
16
18
|
@models = {}
|
19
|
+
@main_models = {}
|
17
20
|
@views = {}
|
18
21
|
@controllers = {}
|
19
22
|
|
@@ -23,9 +26,18 @@ module RuGUI
|
|
23
26
|
@parent_controller = parent_controller
|
24
27
|
end
|
25
28
|
|
29
|
+
register_all :model
|
26
30
|
setup_models
|
31
|
+
|
32
|
+
register_default_view if should_register_default_view?
|
33
|
+
register_all :view
|
27
34
|
setup_views
|
35
|
+
|
36
|
+
register_all :controller
|
28
37
|
setup_controllers
|
38
|
+
|
39
|
+
register_all :main_model
|
40
|
+
setup_main_models
|
29
41
|
end
|
30
42
|
|
31
43
|
# This is included here so that the initialize method is properly updated.
|
@@ -43,13 +55,19 @@ module RuGUI
|
|
43
55
|
# a new instance of the model class will be created.
|
44
56
|
#
|
45
57
|
def register_model(model, name = nil)
|
46
|
-
|
47
|
-
|
48
|
-
model.register_observer(self, name)
|
49
|
-
@models[name.to_sym] = model
|
50
|
-
create_model_attribute_reader(name)
|
58
|
+
register(:model, model, name)
|
59
|
+
end
|
51
60
|
|
52
|
-
|
61
|
+
#
|
62
|
+
# Registers a main model for this controller.
|
63
|
+
#
|
64
|
+
# Only model names (as string or symbol) should be passed. Optionally a
|
65
|
+
# different name may be given. If the main controller doesn't have a model
|
66
|
+
# registered or if this is the main controller a NoMethodError exception
|
67
|
+
# will be raised.
|
68
|
+
#
|
69
|
+
def register_main_model(model_name, name = nil)
|
70
|
+
register(:main_model, model_name, name)
|
53
71
|
end
|
54
72
|
|
55
73
|
#
|
@@ -59,13 +77,7 @@ module RuGUI
|
|
59
77
|
# instance of the view class will be created.
|
60
78
|
#
|
61
79
|
def register_view(view, name = nil)
|
62
|
-
|
63
|
-
name ||= view.class.to_s.underscore
|
64
|
-
view.register_controller(self)
|
65
|
-
@views[name.to_sym] = view
|
66
|
-
create_view_attribute_reader(name)
|
67
|
-
|
68
|
-
view.post_registration(self)
|
80
|
+
register(:view, view, name)
|
69
81
|
end
|
70
82
|
|
71
83
|
#
|
@@ -75,13 +87,7 @@ module RuGUI
|
|
75
87
|
# a new instance of the controller class will be created.
|
76
88
|
#
|
77
89
|
def register_controller(controller, name = nil)
|
78
|
-
|
79
|
-
name ||= controller.class.to_s.underscore
|
80
|
-
controller.parent_controller = self
|
81
|
-
@controllers[name.to_sym] = controller
|
82
|
-
create_controller_attribute_reader(name)
|
83
|
-
|
84
|
-
controller.post_registration
|
90
|
+
register(:controller, controller, name)
|
85
91
|
end
|
86
92
|
|
87
93
|
#
|
@@ -102,54 +108,97 @@ module RuGUI
|
|
102
108
|
@main_controller ||= find_main_controller
|
103
109
|
end
|
104
110
|
|
111
|
+
class << self
|
112
|
+
def models(*names)
|
113
|
+
register(:model, *names)
|
114
|
+
end
|
115
|
+
|
116
|
+
def main_models(*names)
|
117
|
+
register(:main_model, *names)
|
118
|
+
end
|
119
|
+
|
120
|
+
def views(*names)
|
121
|
+
register(:view, *names)
|
122
|
+
end
|
123
|
+
|
124
|
+
def controllers(*names)
|
125
|
+
register(:controller, *names)
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
105
129
|
protected
|
106
130
|
#
|
107
|
-
# Subclasses should reimplement this to register models.
|
131
|
+
# Subclasses should reimplement this to register or initialize models.
|
108
132
|
#
|
109
133
|
def setup_models
|
110
134
|
end
|
111
135
|
|
112
136
|
#
|
113
|
-
# Subclasses should reimplement this to register
|
137
|
+
# Subclasses should reimplement this to register or initialize main models.
|
138
|
+
#
|
139
|
+
def setup_main_models
|
140
|
+
end
|
141
|
+
|
142
|
+
#
|
143
|
+
# Subclasses should reimplement this to register or initialize views.
|
114
144
|
#
|
115
145
|
def setup_views
|
116
146
|
end
|
117
147
|
|
118
148
|
#
|
119
|
-
# Subclasses should reimplement this to register controllers.
|
149
|
+
# Subclasses should reimplement this to register or initialize controllers.
|
120
150
|
#
|
121
151
|
def setup_controllers
|
122
152
|
end
|
123
153
|
|
124
154
|
private
|
125
|
-
def
|
126
|
-
|
155
|
+
def after_register_model(model, name)
|
156
|
+
model.register_observer(self, name)
|
157
|
+
model.post_registration(self)
|
158
|
+
end
|
159
|
+
|
160
|
+
def after_register_main_model(model, name)
|
161
|
+
after_register_model(model, name)
|
127
162
|
end
|
128
163
|
|
129
|
-
|
130
|
-
|
131
|
-
|
164
|
+
def after_register_view(view, name)
|
165
|
+
view.register_controller(self)
|
166
|
+
view.post_registration(self)
|
132
167
|
end
|
133
168
|
|
134
|
-
|
135
|
-
|
136
|
-
|
169
|
+
def after_register_controller(controller, name)
|
170
|
+
controller.parent_controller = self
|
171
|
+
controller.post_registration
|
137
172
|
end
|
138
173
|
|
139
|
-
|
140
|
-
|
141
|
-
create_attribute_reader(:controllers, name)
|
174
|
+
def create_instance_arguments_for_controller
|
175
|
+
[self]
|
142
176
|
end
|
143
177
|
|
144
|
-
|
145
|
-
|
146
|
-
self.class.class_eval <<-class_eval
|
147
|
-
def #{name}
|
148
|
-
@#{entity}[:#{name}]
|
149
|
-
end
|
150
|
-
class_eval
|
178
|
+
def get_instance_for_main_model(name)
|
179
|
+
main_controller.send(name) # should raise an error if main_controller doesn't have that main model.
|
151
180
|
end
|
152
|
-
|
181
|
+
|
182
|
+
def register_default_view
|
183
|
+
default_view_name.camelize.constantize # Check if we can constantize view name, if this fails a NameError exception is thrown.
|
184
|
+
register_view default_view_name
|
185
|
+
rescue NameError
|
186
|
+
# No default view for this controller, nothing to do.
|
187
|
+
end
|
188
|
+
|
189
|
+
def default_view_name
|
190
|
+
"#{controller_name}_view"
|
191
|
+
end
|
192
|
+
|
193
|
+
def controller_name
|
194
|
+
match = self.class.name.underscore.match(/([\w_]*)_controller/)
|
195
|
+
match ? match[1] : self.class.name
|
196
|
+
end
|
197
|
+
|
198
|
+
def should_register_default_view?
|
199
|
+
RuGUI.configuration.automatically_register_conventionally_named_views
|
200
|
+
end
|
201
|
+
|
153
202
|
# Navigates through the controllers hierarchy trying to find the main
|
154
203
|
# controller (i.e., a class that extends RuGUI::BaseMainController).
|
155
204
|
def find_main_controller
|
@@ -182,6 +231,16 @@ module RuGUI
|
|
182
231
|
self.framework_adapter.run
|
183
232
|
end
|
184
233
|
|
234
|
+
#
|
235
|
+
# Refreshes the GUI application, running just one event loop.
|
236
|
+
#
|
237
|
+
# This method is mostly useful when writing tests. It shouldn't be used
|
238
|
+
# in normal applications.
|
239
|
+
#
|
240
|
+
def refresh
|
241
|
+
self.framework_adapter.refresh
|
242
|
+
end
|
243
|
+
|
185
244
|
#
|
186
245
|
# Exits from the application.
|
187
246
|
#
|
data/lib/rugui/base_model.rb
CHANGED
data/lib/rugui/base_view.rb
CHANGED
@@ -36,7 +36,7 @@ module RuGUI
|
|
36
36
|
attr_accessor :controllers
|
37
37
|
attr_reader :widgets
|
38
38
|
attr_reader :unnamed_widgets
|
39
|
-
|
39
|
+
|
40
40
|
class_inheritable_accessor :configured_builder_file
|
41
41
|
class_inheritable_accessor :configured_builder_file_usage
|
42
42
|
class_inheritable_accessor :configured_builder_file_extension
|
@@ -67,7 +67,7 @@ module RuGUI
|
|
67
67
|
# Reimplement this method to create widgets by hand.
|
68
68
|
def setup_widgets
|
69
69
|
end
|
70
|
-
|
70
|
+
|
71
71
|
# Reimplement this method to setup view helpers.
|
72
72
|
def setup_view_helpers
|
73
73
|
end
|
data/lib/rugui/configuration.rb
CHANGED
@@ -41,6 +41,9 @@ module RuGUI
|
|
41
41
|
# The timeout for queued calls. Useful when performing long tasks.
|
42
42
|
attr_accessor :queue_timeout
|
43
43
|
|
44
|
+
# Automatically register conventionally named views. Defaults to true.
|
45
|
+
attr_accessor :automatically_register_conventionally_named_views
|
46
|
+
|
44
47
|
# A hash of application specific configurations.
|
45
48
|
attr_accessor :application
|
46
49
|
|
@@ -61,6 +64,7 @@ module RuGUI
|
|
61
64
|
self.builder_files_paths = default_builder_files_paths
|
62
65
|
self.styles_paths = default_styles_paths
|
63
66
|
self.queue_timeout = default_queue_timeout
|
67
|
+
self.automatically_register_conventionally_named_views = default_automatically_register_conventionally_named_views
|
64
68
|
self.gems = default_gems
|
65
69
|
self.logger = {}
|
66
70
|
self.application = {}
|
@@ -129,6 +133,10 @@ module RuGUI
|
|
129
133
|
50
|
130
134
|
end
|
131
135
|
|
136
|
+
def default_automatically_register_conventionally_named_views
|
137
|
+
true
|
138
|
+
end
|
139
|
+
|
132
140
|
def default_gems
|
133
141
|
[]
|
134
142
|
end
|
@@ -0,0 +1,94 @@
|
|
1
|
+
module RuGUI
|
2
|
+
module EntityRegistrationSupport
|
3
|
+
module ClassMethods
|
4
|
+
def register(entity, *names)
|
5
|
+
names.each do |name|
|
6
|
+
register_entity entity, name
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
private
|
11
|
+
def register_entity(entity, name)
|
12
|
+
self.entity_registrations[entity] ||= []
|
13
|
+
self.entity_registrations[entity] << name
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.included(base)
|
18
|
+
base.class_inheritable_accessor :entity_registrations
|
19
|
+
base.entity_registrations = {}
|
20
|
+
base.extend(ClassMethods)
|
21
|
+
end
|
22
|
+
|
23
|
+
protected
|
24
|
+
def register_all(entity)
|
25
|
+
if self.entity_registrations.has_key?(entity)
|
26
|
+
self.entity_registrations[entity].each do |name|
|
27
|
+
register(entity, name)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def register(entity, object_or_name, name = nil)
|
33
|
+
name = register_name_for(object_or_name, name)
|
34
|
+
if should_register?(name)
|
35
|
+
object = create_or_get_instance_for(entity, object_or_name)
|
36
|
+
setup_instance(entity, name, object)
|
37
|
+
call_after_register_for(entity, object, name)
|
38
|
+
object
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
private
|
43
|
+
def register_name_for(object_or_name, name)
|
44
|
+
if object_or_name.is_a?(String) or object_or_name.is_a?(Symbol)
|
45
|
+
name || object_or_name.to_s.underscore
|
46
|
+
else
|
47
|
+
name || object_or_name.class.to_s.underscore
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def should_register?(name)
|
52
|
+
not respond_to?(name) or send(name).nil?
|
53
|
+
end
|
54
|
+
|
55
|
+
def create_or_get_instance_for(entity, object_or_name)
|
56
|
+
if object_or_name.is_a?(String) or object_or_name.is_a?(Symbol)
|
57
|
+
args = create_instance_arguments_for(entity) || []
|
58
|
+
get_instance_for(entity, object_or_name) or create_instance(object_or_name, *args)
|
59
|
+
else
|
60
|
+
object_or_name
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def create_instance_arguments_for(entity)
|
65
|
+
send("create_instance_arguments_for_#{entity}") if respond_to?("create_instance_arguments_for_#{entity}", true)
|
66
|
+
end
|
67
|
+
|
68
|
+
def get_instance_for(entity, name)
|
69
|
+
send("get_instance_for_#{entity}", name) if respond_to?("get_instance_for_#{entity}", true)
|
70
|
+
end
|
71
|
+
|
72
|
+
def create_instance(klass_name, *args)
|
73
|
+
klass_name.to_s.camelize.constantize.new(*args)
|
74
|
+
end
|
75
|
+
|
76
|
+
def setup_instance(entity, name, object)
|
77
|
+
send("#{entity}s")[name.to_sym] = object
|
78
|
+
create_attribute_reader(entity, name)
|
79
|
+
end
|
80
|
+
|
81
|
+
def call_after_register_for(entity, object, name)
|
82
|
+
send("after_register_#{entity}", object, name) if respond_to?("after_register_#{entity}", true)
|
83
|
+
end
|
84
|
+
|
85
|
+
# Creates an attribute reader for the some entity.
|
86
|
+
def create_attribute_reader(type, name)
|
87
|
+
self.class.class_eval <<-class_eval
|
88
|
+
def #{name}
|
89
|
+
@#{type}s[:#{name}]
|
90
|
+
end
|
91
|
+
class_eval
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
@@ -85,6 +85,10 @@ module RuGUI
|
|
85
85
|
Gtk.main
|
86
86
|
end
|
87
87
|
|
88
|
+
def refresh
|
89
|
+
Gtk.main_iteration_do(false) while Gtk.events_pending?
|
90
|
+
end
|
91
|
+
|
88
92
|
def quit
|
89
93
|
Gtk.main_quit
|
90
94
|
end
|
@@ -188,7 +192,7 @@ module RuGUI
|
|
188
192
|
widgets.concat(@unnamed_widgets.select { |widget| widget.kind_of?(widget_type) }) unless @unnamed_widgets.empty?
|
189
193
|
|
190
194
|
widgets.each do |widget|
|
191
|
-
widget.signal_connect(signal, &block)
|
195
|
+
widget.signal_connect(signal, &block) unless widget.destroyed?
|
192
196
|
end
|
193
197
|
end
|
194
198
|
|
@@ -27,6 +27,11 @@ module RuGUI
|
|
27
27
|
Qt.application.exec
|
28
28
|
end
|
29
29
|
|
30
|
+
def refresh
|
31
|
+
# TODO: Vicente Mundim - 03/06/2009 - Implement this method for Qt.
|
32
|
+
raise NotImplementedError.new("Sorry, refresh is not implemented for Qt yet!")
|
33
|
+
end
|
34
|
+
|
30
35
|
def quit
|
31
36
|
Qt.application.exit
|
32
37
|
end
|
@@ -22,6 +22,13 @@ module RuGUI
|
|
22
22
|
def run
|
23
23
|
end
|
24
24
|
|
25
|
+
# Refreshes the GUI application, running just one event loop.
|
26
|
+
#
|
27
|
+
# This method is mostly useful when writing tests. It shouldn't be used
|
28
|
+
# in normal applications.
|
29
|
+
def refresh
|
30
|
+
end
|
31
|
+
|
25
32
|
# Exits the application, freeing any resources used by the framework.
|
26
33
|
def quit
|
27
34
|
end
|
data/lib/rugui/log_support.rb
CHANGED
@@ -89,10 +89,12 @@ module RuGUI
|
|
89
89
|
#
|
90
90
|
def defined_level
|
91
91
|
level = RuGUI.configuration.logger[:level]
|
92
|
-
|
93
|
-
level = DEFAULT_LEVEL
|
94
|
-
else
|
92
|
+
if level
|
95
93
|
level = LEVELS[level]
|
94
|
+
elsif ENV["RUGUI_ENV"] == 'test'
|
95
|
+
level = LEVELS[:fatal] # log nothing at all
|
96
|
+
else
|
97
|
+
level = DEFAULT_LEVEL
|
96
98
|
end
|
97
99
|
level
|
98
100
|
end
|
@@ -95,7 +95,10 @@ module RuGUI
|
|
95
95
|
if other_observable.respond_to?(property)
|
96
96
|
other_property_value = other_observable.send(property)
|
97
97
|
if other_property_value.class.include?(ObservablePropertySupport)
|
98
|
-
|
98
|
+
if deep
|
99
|
+
send("#{property}=", other_property_value.class.new) if send(property).nil? # Creates an instance of the same class
|
100
|
+
send(property).copy_observable_properties_from(other_property_value)
|
101
|
+
end
|
99
102
|
else
|
100
103
|
send("#{property}=", other_property_value)
|
101
104
|
end
|
@@ -0,0 +1,119 @@
|
|
1
|
+
module RuGUI
|
2
|
+
module PropertyChangedSupport
|
3
|
+
module ClassMethods
|
4
|
+
# Invoked when a property was changed.
|
5
|
+
#
|
6
|
+
# Example:
|
7
|
+
# <tt>
|
8
|
+
# when_property_changed :name do |observable, new_value, old_value|
|
9
|
+
# puts "Hey! The property 'name' of the #{observable.class.name} was changed from #{old_value} to #{new_value}."
|
10
|
+
# end
|
11
|
+
# </tt>
|
12
|
+
#
|
13
|
+
# Or you can inform the observable:
|
14
|
+
# <tt>
|
15
|
+
# when_property_changed :name, :observable => :rabbit do |observable, new_value, old_value|
|
16
|
+
# puts "Hey! The property 'name' of the 'rabbit' was changed from #{old_value} to #{new_value}."
|
17
|
+
# end
|
18
|
+
# </tt>
|
19
|
+
#
|
20
|
+
# If you can inform a method to be called:
|
21
|
+
# <tt>
|
22
|
+
# when_property_changed :name, :puts_anything
|
23
|
+
#
|
24
|
+
# def puts_anything(observable, new_value, old_value)
|
25
|
+
# puts "Hey! The property 'name' of the #{observable.class.name} was changed from #{old_value} to #{new_value}."
|
26
|
+
# end
|
27
|
+
# </tt>
|
28
|
+
#
|
29
|
+
# Or you can inform the observable and a method to be called.
|
30
|
+
# <tt>
|
31
|
+
# when_property_changed :name, :observable => :rabbit, :call => :puts_anything
|
32
|
+
#
|
33
|
+
# def puts_anything(observable, new_value, old_value)
|
34
|
+
# puts "Hey! The property 'name' of the 'rabbit' was changed from #{old_value} to #{new_value}."
|
35
|
+
# end
|
36
|
+
# </tt>
|
37
|
+
# </tt>
|
38
|
+
#
|
39
|
+
def when_property_changed(property, method_or_options = {}, &block)
|
40
|
+
property_changed_block = RuGUI::PropertyChangedSupport::PropertyChangedBlock.new
|
41
|
+
property_changed_block.property = property
|
42
|
+
property_changed_block.set_options(method_or_options)
|
43
|
+
property_changed_block.block = block if block_given?
|
44
|
+
self.property_changed_blocks << property_changed_block
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def self.included(base)
|
49
|
+
base.class_inheritable_accessor :property_changed_blocks
|
50
|
+
base.property_changed_blocks = []
|
51
|
+
base.extend(ClassMethods)
|
52
|
+
end
|
53
|
+
|
54
|
+
class PropertyChangedBlock
|
55
|
+
attr_accessor :property
|
56
|
+
attr_accessor :options
|
57
|
+
attr_accessor :block
|
58
|
+
attr_accessor :observer
|
59
|
+
|
60
|
+
# Call the block configurated for the property changed if a block exists for the one.
|
61
|
+
def call_property_changed_block_if_exists(observer, observable, property, new_value, old_value)
|
62
|
+
self.observer = observer
|
63
|
+
call_property_changed_block(observable, new_value, old_value) if block_exists?(observable, property, new_value, old_value)
|
64
|
+
end
|
65
|
+
|
66
|
+
# Set the options given the args.
|
67
|
+
def set_options(method_or_options)
|
68
|
+
case method_or_options
|
69
|
+
when String, Symbol
|
70
|
+
self.options = { :call => prepared(method_or_options) }
|
71
|
+
when Hash
|
72
|
+
self.options = method_or_options
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
protected
|
77
|
+
# Check if a block exists for the property changed
|
78
|
+
def block_exists?(observable, property, new_value, old_value)
|
79
|
+
if self.options.has_key?(:observable)
|
80
|
+
return same_observable_and_property?(observable, property)
|
81
|
+
else
|
82
|
+
return same_property?(property)
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
# Call the block configurated for the property changed.
|
87
|
+
def call_property_changed_block(observable, new_value, old_value)
|
88
|
+
return if not self.options.has_key?(:call) and self.block.blank?
|
89
|
+
if self.options.has_key?(:call)
|
90
|
+
method = self.options[:call]
|
91
|
+
self.observer.send(method, observable, new_value, old_value) if self.observer.respond_to?(method)
|
92
|
+
else
|
93
|
+
self.block.call(observable, new_value, old_value) unless self.block.blank?
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
private
|
98
|
+
def same_property?(property)
|
99
|
+
prepared(self.property) == prepared(property)
|
100
|
+
end
|
101
|
+
|
102
|
+
def same_observable?(observable)
|
103
|
+
prepared(self.options[:observable]) == prepared(observable.class.name)
|
104
|
+
end
|
105
|
+
|
106
|
+
def same_observable_and_property?(observable, property)
|
107
|
+
same_observable?(observable) and same_property?(property)
|
108
|
+
end
|
109
|
+
|
110
|
+
def prepared(param)
|
111
|
+
param.to_s.downcase.underscore
|
112
|
+
end
|
113
|
+
|
114
|
+
def logger
|
115
|
+
@logger ||= RuGUILogger.logger
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
@@ -1,13 +1,13 @@
|
|
1
1
|
module RuGUI
|
2
2
|
# Adds observer functionality for any class which has support for observable
|
3
3
|
# properties.
|
4
|
-
#
|
4
|
+
#
|
5
5
|
# The observer class should implement a method name
|
6
6
|
# 'property_property_name_changed', where 'property_name' is
|
7
7
|
# the name of the observable property, that will be called whenever that
|
8
8
|
# property value has changed. If it does not declare a method with this
|
9
9
|
# name, it will be silently ignored.
|
10
|
-
#
|
10
|
+
#
|
11
11
|
# The method signature is:
|
12
12
|
#
|
13
13
|
# property_foo_changed(model, new_value, old_value)
|
@@ -33,15 +33,22 @@ module RuGUI
|
|
33
33
|
module PropertyObserver
|
34
34
|
include RuGUI::FrameworkAdapters::FrameworkAdapterSupport
|
35
35
|
|
36
|
+
def self.included(base)
|
37
|
+
base.send(:include, RuGUI::PropertyChangedSupport)
|
38
|
+
end
|
39
|
+
|
36
40
|
def property_updated(observable, property, new_value, old_value)
|
37
41
|
queue_method_call_if_exists("property_#{property}_changed", observable, new_value, old_value)
|
38
42
|
queue_method_call_if_exists("property_#{observable.class.name.underscore}_#{property}_changed", observable, new_value, old_value)
|
43
|
+
self.property_changed_blocks.each do |property_changed_block|
|
44
|
+
property_changed_block.call_property_changed_block_if_exists(self, observable, property, new_value, old_value)
|
45
|
+
end
|
39
46
|
end
|
40
|
-
|
47
|
+
|
41
48
|
def named_observable_property_updated(observable_name, observable, property, new_value, old_value)
|
42
49
|
queue_method_call_if_exists("property_#{observable_name}_#{property}_changed", observable, new_value, old_value) unless named_observable_collides_with_class_name?(observable_name, observable)
|
43
50
|
end
|
44
|
-
|
51
|
+
|
45
52
|
private
|
46
53
|
def queue_method_call_if_exists(method_name, *args)
|
47
54
|
if respond_to?(method_name)
|
@@ -50,7 +57,7 @@ module RuGUI
|
|
50
57
|
end
|
51
58
|
end
|
52
59
|
end
|
53
|
-
|
60
|
+
|
54
61
|
def named_observable_collides_with_class_name?(observable_name, observable)
|
55
62
|
observable_name == observable.class.name.underscore
|
56
63
|
end
|
data/lib/rugui/version.rb
CHANGED
data/lib/rugui.rb
CHANGED
@@ -27,11 +27,13 @@ require 'rugui/log_support'
|
|
27
27
|
require 'rugui/plugin/loader'
|
28
28
|
require 'rugui/framework_adapters/framework_adapter_support'
|
29
29
|
require 'rugui/base_object'
|
30
|
+
require 'rugui/property_changed_support'
|
30
31
|
require 'rugui/observable_property_support'
|
31
32
|
require 'rugui/property_observer'
|
32
33
|
require 'rugui/initialize_hooks'
|
33
34
|
require 'rugui/signal_support'
|
35
|
+
require 'rugui/entity_registration_support'
|
34
36
|
require 'rugui/base_controller'
|
35
37
|
require 'rugui/base_model'
|
36
38
|
require 'rugui/base_view_helper'
|
37
|
-
require 'rugui/base_view'
|
39
|
+
require 'rugui/base_view'
|
@@ -15,6 +15,14 @@ describe RuGUI::BaseController do
|
|
15
15
|
@controller.my_view.should be_an_instance_of(MyView)
|
16
16
|
@controller.views[:my_view].should == @controller.my_view
|
17
17
|
end
|
18
|
+
|
19
|
+
describe "with conventionally named controllers and views" do
|
20
|
+
it "should automatically register a conventionally named view if it exists" do
|
21
|
+
@conventionally_named_controller = ConventionallyNamedController.new
|
22
|
+
@conventionally_named_controller.respond_to?(:conventionally_named_view).should be_true
|
23
|
+
@conventionally_named_controller.conventionally_named_view.should be_an_instance_of(ConventionallyNamedView)
|
24
|
+
end
|
25
|
+
end
|
18
26
|
end
|
19
27
|
|
20
28
|
describe "with model registering" do
|
@@ -38,6 +46,83 @@ describe RuGUI::BaseController do
|
|
38
46
|
end
|
39
47
|
end
|
40
48
|
|
49
|
+
describe "with new style registering" do
|
50
|
+
before :all do
|
51
|
+
RuGUI.configuration.automatically_register_conventionally_named_views = false
|
52
|
+
end
|
53
|
+
|
54
|
+
after :all do
|
55
|
+
RuGUI.configuration.automatically_register_conventionally_named_views = true
|
56
|
+
end
|
57
|
+
|
58
|
+
describe "of views" do
|
59
|
+
before :each do
|
60
|
+
NewStyleController.views :new_style_view
|
61
|
+
@controller = NewStyleController.new
|
62
|
+
end
|
63
|
+
|
64
|
+
it "should have the new_style_view registered when instantiated" do
|
65
|
+
@controller.views[:new_style_view].should be_an_instance_of(NewStyleView)
|
66
|
+
@controller.new_style_view.should be_an_instance_of(NewStyleView)
|
67
|
+
@controller.views[:new_style_view].should == @controller.new_style_view
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
describe "of models" do
|
72
|
+
before :each do
|
73
|
+
NewStyleController.models :new_style_model
|
74
|
+
@controller = NewStyleController.new
|
75
|
+
end
|
76
|
+
|
77
|
+
it "should have the new_style_model registered when instantiated" do
|
78
|
+
@controller.models[:new_style_model].should be_an_instance_of(NewStyleModel)
|
79
|
+
@controller.new_style_model.should be_an_instance_of(NewStyleModel)
|
80
|
+
@controller.models[:new_style_model].should == @controller.new_style_model
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
describe "of main models" do
|
85
|
+
before :each do
|
86
|
+
NewStyleController.main_models :new_style_model
|
87
|
+
|
88
|
+
@main_controller = RuGUI::BaseMainController.new
|
89
|
+
@main_controller.register_model :new_style_model
|
90
|
+
@main_controller.register_controller :new_style_controller
|
91
|
+
|
92
|
+
@controller = @main_controller.new_style_controller
|
93
|
+
end
|
94
|
+
|
95
|
+
it "should have the new_style_model registered when instantiated" do
|
96
|
+
@controller.main_models[:new_style_model].should be_an_instance_of(NewStyleModel)
|
97
|
+
@controller.new_style_model.should be_an_instance_of(NewStyleModel)
|
98
|
+
@controller.main_models[:new_style_model].should == @controller.new_style_model
|
99
|
+
end
|
100
|
+
|
101
|
+
it "should use the same instance that was registered in the main controller" do
|
102
|
+
@controller.new_style_model.object_id.should == @main_controller.new_style_model.object_id # object ids should be equals here
|
103
|
+
end
|
104
|
+
|
105
|
+
it "should raise an error if we register a main model which aren't register in the main controller" do
|
106
|
+
lambda {
|
107
|
+
@controller.register_main_model(:some_inexistent_model)
|
108
|
+
}.should raise_error(NoMethodError)
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
describe "of controllers" do
|
113
|
+
before :each do
|
114
|
+
NewStyleController.controllers :new_style_child_controller
|
115
|
+
@controller = NewStyleController.new
|
116
|
+
end
|
117
|
+
|
118
|
+
it "should have the new_style_child_controller registered when instantiated" do
|
119
|
+
@controller.controllers[:new_style_child_controller].should be_an_instance_of(NewStyleChildController)
|
120
|
+
@controller.new_style_child_controller.should be_an_instance_of(NewStyleChildController)
|
121
|
+
@controller.controllers[:new_style_child_controller].should == @controller.new_style_child_controller
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
41
126
|
describe "with initialization hooks" do
|
42
127
|
it "should call before initialize and after initialize methods" do
|
43
128
|
controller = MyController.new
|
@@ -210,6 +210,12 @@ describe RuGUI::ObservablePropertySupport do
|
|
210
210
|
@parent.my_own_observable_property.should == @another_parent.my_own_observable_property
|
211
211
|
@parent.child_observable_property.should_not == @another_parent.child_observable_property
|
212
212
|
end
|
213
|
+
|
214
|
+
it "should create an instance of the same class and copy observable properties to it if destination object has a nil observable property while source object doesn't" do
|
215
|
+
@parent.child_observable_property = nil
|
216
|
+
@parent.copy_observable_properties_from(@another_parent)
|
217
|
+
@parent.child_observable_property.should == @another_parent.child_observable_property
|
218
|
+
end
|
213
219
|
end
|
214
220
|
|
215
221
|
describe "with observable properties mapped for an instance" do
|
data/spec/helpers/controllers.rb
CHANGED
@@ -7,10 +7,6 @@ class MyController < RuGUI::BaseController
|
|
7
7
|
|
8
8
|
attr_accessor :message
|
9
9
|
|
10
|
-
def setup_views
|
11
|
-
register_view :my_view
|
12
|
-
end
|
13
|
-
|
14
10
|
def setup_models
|
15
11
|
register_model :my_model
|
16
12
|
register_model :my_model, :my_other_model_instance
|
@@ -26,4 +22,13 @@ class MyController < RuGUI::BaseController
|
|
26
22
|
end
|
27
23
|
|
28
24
|
class MyChildController < RuGUI::BaseController
|
29
|
-
end
|
25
|
+
end
|
26
|
+
|
27
|
+
class ConventionallyNamedController < RuGUI::BaseController
|
28
|
+
end
|
29
|
+
|
30
|
+
class NewStyleController < RuGUI::BaseController
|
31
|
+
end
|
32
|
+
|
33
|
+
class NewStyleChildController < RuGUI::BaseController
|
34
|
+
end
|
data/spec/helpers/models.rb
CHANGED
data/spec/helpers/views.rb
CHANGED
@@ -3,7 +3,7 @@
|
|
3
3
|
<!--Generated with glade3 3.4.5 on Thu Aug 28 14:02:01 2008 -->
|
4
4
|
<glade-interface>
|
5
5
|
<widget class="GtkWindow" id="top_window">
|
6
|
-
<property name="visible">
|
6
|
+
<property name="visible">False</property>
|
7
7
|
<signal name="delete_event" handler="on_top_window_delete_event"/>
|
8
8
|
<child>
|
9
9
|
<widget class="GtkHBox" id="horizontal_container">
|
@@ -3,7 +3,7 @@
|
|
3
3
|
<!--Generated with glade3 3.4.5 on Thu Aug 28 14:02:07 2008 -->
|
4
4
|
<glade-interface>
|
5
5
|
<widget class="GtkWindow" id="top_window">
|
6
|
-
<property name="visible">
|
6
|
+
<property name="visible">False</property>
|
7
7
|
<signal name="delete_event" handler="on_top_window_delete_event"/>
|
8
8
|
<child>
|
9
9
|
<widget class="GtkVBox" id="vertical_container">
|
data/spec/spec.opts
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rugui
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.3.
|
4
|
+
version: 1.3.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Vicente Mundim
|
@@ -11,7 +11,7 @@ autorequire:
|
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
13
|
|
14
|
-
date: 2009-
|
14
|
+
date: 2009-07-08 00:00:00 -03:00
|
15
15
|
default_executable: rugui
|
16
16
|
dependencies:
|
17
17
|
- !ruby/object:Gem::Dependency
|
@@ -61,6 +61,7 @@ files:
|
|
61
61
|
- lib/rugui/base_view.rb
|
62
62
|
- lib/rugui/base_view_helper.rb
|
63
63
|
- lib/rugui/configuration.rb
|
64
|
+
- lib/rugui/entity_registration_support.rb
|
64
65
|
- lib/rugui/framework_adapters/GTK.rb
|
65
66
|
- lib/rugui/framework_adapters/Qt4.rb
|
66
67
|
- lib/rugui/framework_adapters/base_framework_adapter.rb
|
@@ -73,6 +74,7 @@ files:
|
|
73
74
|
- lib/rugui/observable_property_proxy.rb
|
74
75
|
- lib/rugui/observable_property_support.rb
|
75
76
|
- lib/rugui/plugin/loader.rb
|
77
|
+
- lib/rugui/property_changed_support.rb
|
76
78
|
- lib/rugui/property_observer.rb
|
77
79
|
- lib/rugui/signal_support.rb
|
78
80
|
- lib/rugui/tasks/gems_application.rake
|