rugui 1.3.0 → 1.3.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|