rugui 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (56) hide show
  1. data/LICENSE +165 -0
  2. data/README +67 -0
  3. data/README.rdoc +67 -0
  4. data/Rakefile +56 -0
  5. data/VERSION.yml +4 -0
  6. data/bin/rugui +16 -0
  7. data/lib/rugui/base_controller.rb +194 -0
  8. data/lib/rugui/base_model.rb +22 -0
  9. data/lib/rugui/base_object.rb +73 -0
  10. data/lib/rugui/base_view.rb +302 -0
  11. data/lib/rugui/base_view_helper.rb +23 -0
  12. data/lib/rugui/configuration.rb +136 -0
  13. data/lib/rugui/framework_adapters/GTK.rb +233 -0
  14. data/lib/rugui/framework_adapters/Qt4.rb +171 -0
  15. data/lib/rugui/framework_adapters/base_framework_adapter.rb +90 -0
  16. data/lib/rugui/framework_adapters/framework_adapter_support.rb +35 -0
  17. data/lib/rugui/gem_builder.rb +21 -0
  18. data/lib/rugui/gem_dependency.rb +282 -0
  19. data/lib/rugui/initialize_hooks.rb +36 -0
  20. data/lib/rugui/initializer.rb +162 -0
  21. data/lib/rugui/log_support.rb +118 -0
  22. data/lib/rugui/observable_property_proxy.rb +73 -0
  23. data/lib/rugui/observable_property_support.rb +251 -0
  24. data/lib/rugui/plugin/loader.rb +77 -0
  25. data/lib/rugui/property_observer.rb +58 -0
  26. data/lib/rugui/signal_support.rb +57 -0
  27. data/lib/rugui/tasks/gems_application.rake +71 -0
  28. data/lib/rugui/tasks/rugui.rb +8 -0
  29. data/lib/rugui/tasks/rugui_framework.rb +4 -0
  30. data/lib/rugui/tasks/runner_application.rake +4 -0
  31. data/lib/rugui/tasks/spec_application.rake +64 -0
  32. data/lib/rugui/tasks/spec_framework.rake +27 -0
  33. data/lib/rugui/tasks/test_application.rake +77 -0
  34. data/lib/rugui/vendor_gem_source_index.rb +140 -0
  35. data/lib/rugui/version.rb +9 -0
  36. data/lib/rugui.rb +37 -0
  37. data/spec/framework/base_controller_spec.rb +48 -0
  38. data/spec/framework/base_model_spec.rb +13 -0
  39. data/spec/framework/base_view_helper_spec.rb +13 -0
  40. data/spec/framework/base_view_spec.rb +92 -0
  41. data/spec/framework/log_support_spec.rb +16 -0
  42. data/spec/framework/observable_property_proxy_spec.rb +67 -0
  43. data/spec/framework/observable_property_support_spec.rb +283 -0
  44. data/spec/framework/property_observer_spec.rb +88 -0
  45. data/spec/helpers/controllers.rb +29 -0
  46. data/spec/helpers/initialize_hooks_helper.rb +18 -0
  47. data/spec/helpers/models.rb +9 -0
  48. data/spec/helpers/observables.rb +210 -0
  49. data/spec/helpers/view_helpers.rb +9 -0
  50. data/spec/helpers/views.rb +72 -0
  51. data/spec/rcov.opts +1 -0
  52. data/spec/resource_files/my_other_view.glade +46 -0
  53. data/spec/resource_files/my_view.glade +46 -0
  54. data/spec/spec.opts +4 -0
  55. data/spec/spec_helper.rb +15 -0
  56. metadata +149 -0
@@ -0,0 +1,302 @@
1
+ module RuGUI
2
+ # A base class for views.
3
+ #
4
+ # To use this class create a subclass and reimplement #setup_widgets, if you
5
+ # want to create your interface by hand. If you want to use a builder file
6
+ # just call #use_builder and, optionally, call #builder_file passing the
7
+ # filename to use.
8
+ #
9
+ # Each adapter may implement additional features, extending this class, look
10
+ # for it in adapter classes.
11
+ #
12
+ # The view may have ViewHelpers, which works as 'models' for views, i.e., they
13
+ # have observable properties that can be observed by the view. A default
14
+ # helper, named as <code>{view_name}Helper</code> is registered if it exists.
15
+ # For example, for a view named *MyView*, the default view helper should be
16
+ # named *MyViewHelper*. This helper can be accessed as a <code>helper</code>
17
+ # attribute. Other helpers may be registered if needed.
18
+ #
19
+ # Example (using GTK framework adapter):
20
+ # class MyGladeView < RuGUI::BaseView
21
+ # builder_file 'my_file.glade' # this is optional, if the glade file was called my_glade_view.glade this wouldn't be needed.
22
+ # root :top_window
23
+ # use_builder
24
+ # end
25
+ #
26
+ # class MyHandView < RuGUI::BaseView
27
+ # def setup_widgets
28
+ # # do your hand-made code here...
29
+ # end
30
+ # end
31
+ class BaseView < BaseObject
32
+ include RuGUI::LogSupport
33
+ include RuGUI::PropertyObserver
34
+ include RuGUI::SignalSupport
35
+
36
+ attr_accessor :controllers
37
+ attr_reader :widgets
38
+ attr_reader :unnamed_widgets
39
+
40
+ class_inheritable_accessor :configured_builder_file
41
+ class_inheritable_accessor :configured_builder_file_usage
42
+ class_inheritable_accessor :configured_builder_file_extension
43
+ class_inheritable_accessor :configured_root
44
+ class_inheritable_accessor :configured_display_root
45
+
46
+ def initialize
47
+ @controllers = {}
48
+ @helpers = {}
49
+ @unnamed_widgets = []
50
+ @widgets = {}
51
+
52
+ register_default_helper
53
+ setup_view_helpers
54
+ build_from_builder_file if use_builder?
55
+ setup_widgets
56
+ autoconnect_signals(self)
57
+ end
58
+
59
+ # This is included here so that the initialize method is properly updated.
60
+ include RuGUI::InitializeHooks
61
+
62
+ # Returns the framework_adapter for this class.
63
+ def framework_adapter
64
+ framework_adapter_for('BaseView')
65
+ end
66
+
67
+ # Reimplement this method to create widgets by hand.
68
+ def setup_widgets
69
+ end
70
+
71
+ # Reimplement this method to setup view helpers.
72
+ def setup_view_helpers
73
+ end
74
+
75
+ # Adds the given widget to a container widget.
76
+ def add_widget_to_container(widget, container_widget_or_name)
77
+ self.framework_adapter.add_widget_to_container(widget, from_widget_or_name(container_widget_or_name))
78
+ end
79
+
80
+ # Adds the given widget to a container widget.
81
+ def remove_widget_from_container(widget, container_widget_or_name)
82
+ self.framework_adapter.remove_widget_from_container(widget, from_widget_or_name(container_widget_or_name))
83
+ end
84
+
85
+ # Includes a view root widget inside the given container widget.
86
+ def include_view(container_widget_name, view)
87
+ raise RootWidgetNotSetForIncludedView, "You must set a root for views to be included." if view.root_widget.nil?
88
+ add_widget_to_container(view.root_widget, container_widget_name)
89
+ end
90
+
91
+ # Removes a view root widget from the given container widget.
92
+ def remove_view(container_widget_name, view)
93
+ raise RootWidgetNotSetForIncludedView, "You must set a root for views to be removed." if view.root_widget.nil?
94
+ remove_widget_from_container(view.root_widget, container_widget_name)
95
+ end
96
+
97
+ # Removes all children from the given container widget
98
+ def remove_all_children(container_widget)
99
+ self.framework_adapter.remove_all_children(container_widget)
100
+ end
101
+
102
+ # Registers a controller as receiver of signals from the view widgets.
103
+ def register_controller(controller, name = nil)
104
+ name ||= controller.class.to_s.underscore
105
+ autoconnect_signals(controller)
106
+ @controllers[name.to_sym] = controller
107
+ end
108
+
109
+ # Registers a view helper for the view.
110
+ def register_helper(helper, name = nil)
111
+ helper = create_instance_if_possible(helper) if helper.is_a?(String) or helper.is_a?(Symbol)
112
+ unless helper.nil?()
113
+ name ||= helper.class.to_s.underscore
114
+ helper.register_observer(self, name)
115
+ @helpers[name.to_sym] = helper
116
+ create_attribute_reader(:helpers, name)
117
+ helper.post_registration(self)
118
+ end
119
+ end
120
+
121
+ # Called after the view is registered in a controller.
122
+ def post_registration(controller)
123
+ end
124
+
125
+ # Returns the root widget if one is set.
126
+ def root_widget
127
+ send(root.to_sym) if not root.nil?
128
+ end
129
+
130
+ # Returns the builder file.
131
+ def builder_file
132
+ self.configured_builder_file
133
+ end
134
+
135
+ # Returns the builder file extension.
136
+ def builder_file_extension
137
+ self.configured_builder_file_extension
138
+ end
139
+
140
+ # Returns true if builder file is being used for this view.
141
+ def use_builder?
142
+ self.configured_builder_file_usage
143
+ end
144
+
145
+ # Framework adapters should implement this if they support builder files.
146
+ def build_from_builder_file
147
+ filename = get_builder_file
148
+ raise BuilderFileNotFoundError, "Could not find builder file for view #{self.class.name}. UI file paths: #{RuGUI.configuration.builder_files_paths.join(', ')}." if filename.nil?
149
+
150
+ self.framework_adapter.build_widgets_from(filename)
151
+ self.framework_adapter.register_widgets
152
+ end
153
+
154
+ # Returns the name of the root widget for this view.
155
+ def root
156
+ self.configured_root.to_s unless self.configured_root.nil?
157
+ end
158
+
159
+ def display_root?
160
+ !!self.configured_display_root
161
+ end
162
+
163
+ class << self
164
+ # Sets the name of the root widget for this view.
165
+ #
166
+ # This is specially useful when more than one view uses the same glade
167
+ # file, but each one uses a diferent widget tree inside that glade file.
168
+ #
169
+ # Other use for this is when building a reusable widget, composed of the
170
+ # contents of a glade file. One could create a window, place a vertical
171
+ # box, and then place elements inside this vertical box. Later, this glade
172
+ # file is used to insert the contents of the vertical box inside another
173
+ # vertical box in other glade file.
174
+ def root(root_widget_name)
175
+ self.configured_root = root_widget_name
176
+ end
177
+
178
+ # Sets the builder file to use when creating this view.
179
+ def builder_file(file)
180
+ self.configured_builder_file = file
181
+ end
182
+
183
+ # Tells whether we should use a builder file when creating this view.
184
+ #
185
+ # By default the root widget will be displayed, but you can pass false to
186
+ # this method to prevent it for being displayed.
187
+ def use_builder(display_root = true)
188
+ self.configured_builder_file_usage = true
189
+ self.configured_display_root = display_root
190
+
191
+ self.configured_builder_file_extension = self.framework_adapter_class.builder_file_extension
192
+ default_builder_file_path = RuGUI.root.join('app', 'resources', "#{self.configured_builder_file_extension}")
193
+ RuGUI.configuration.builder_files_paths << default_builder_file_path unless RuGUI.configuration.builder_files_paths.include?(default_builder_file_path)
194
+ end
195
+
196
+ def framework_adapter_class
197
+ class_adapter_for('BaseView')
198
+ end
199
+ end
200
+
201
+ protected
202
+ # Builds a widget of the given type, possibly adding it to a parent
203
+ # widget, and display it.
204
+ #
205
+ # The *args are passed to the widget constructor.
206
+ def build_widget(widget_type, widget_name = nil, parent = nil, *args)
207
+ widget = widget_type.new(*args)
208
+ self.framework_adapter.set_widget_name(widget, widget_name)
209
+ add_widget(widget, widget_name)
210
+ add_widget_to_container(widget, parent) unless parent.nil?
211
+ widget.show
212
+ end
213
+
214
+ # Adds the widget to the view.
215
+ #
216
+ # If +widget_name+ is not given one is assumed the widget`s name will be
217
+ # used instead. If the widget doesn't have a name it will be added as an
218
+ # unnamed widget (accessible through #unnamed_widgets property.
219
+ def add_widget(widget, widget_name = nil)
220
+ widget_name ||= widget.name
221
+ widget_name = widget_name.to_s
222
+
223
+ unless widget_name.nil? || widget_name.empty?
224
+ create_attribute_for_widget(widget_name)
225
+ send("#{widget_name}=", widget)
226
+ @widgets[widget_name] = widget
227
+ else
228
+ @unnamed_widgets << widget
229
+ end
230
+ end
231
+
232
+ def from_widget_or_name(widget_or_name)
233
+ if widget_or_name.is_a?(String) || widget_or_name.is_a?(Symbol)
234
+ send(widget_or_name)
235
+ else
236
+ widget_or_name
237
+ end
238
+ end
239
+
240
+ def autoconnect_signals(receiver)
241
+ receiver.autoconnect_declared_signals(self)
242
+ self.framework_adapter.autoconnect_signals(receiver)
243
+ end
244
+
245
+ private
246
+ def get_builder_file
247
+ filename = (not self.builder_file.nil?) ? self.builder_file : "#{self.class.to_s.underscore}.#{builder_file_extension}"
248
+
249
+ # The builder file given may already contain a full path to a glade file.
250
+ return filename if File.file?(filename)
251
+
252
+ filename = "#{filename}.#{builder_file_extension}" unless File.extname(filename) == ".#{builder_file_extension}"
253
+
254
+ paths = RuGUI.configuration.builder_files_paths.select do |path|
255
+ File.file?(File.join(path, filename))
256
+ end
257
+ File.join(paths.first, filename) unless paths.empty?
258
+ end
259
+
260
+ # Attempts to register the default helper for the view
261
+ def register_default_helper
262
+ register_helper("#{self.class.name}Helper", :helper)
263
+ end
264
+
265
+ def create_attribute_for_widget(widget_name)
266
+ self.instance_eval <<-instance_eval
267
+ def #{widget_name}
268
+ @#{widget_name}
269
+ end
270
+
271
+ def #{widget_name}=(widget)
272
+ @#{widget_name} = widget
273
+ end
274
+ instance_eval
275
+ end
276
+
277
+ # Creates an attribute reader for the some entity.
278
+ def create_attribute_reader(entity, name)
279
+ self.class.class_eval <<-class_eval
280
+ def #{name}
281
+ @#{entity}[:#{name}]
282
+ end
283
+ class_eval
284
+ end
285
+
286
+ # Creates an instance of the given class.
287
+ def create_instance_if_possible(klass_name, *args)
288
+ klass_name.to_s.camelize.constantize.new(*args)
289
+ rescue NameError
290
+ # Couldn't create instance.
291
+ end
292
+ end
293
+
294
+ # Exception thrown when the builder file for this view could not be found.
295
+ class BuilderFileNotFoundError < Exception
296
+ end
297
+
298
+ # Exception thrown when attempting to include a view which don't have a root
299
+ # set.
300
+ class RootWidgetNotSetForIncludedView < Exception
301
+ end
302
+ end
@@ -0,0 +1,23 @@
1
+ module RuGUI
2
+ # A base class for view helpers.
3
+ class BaseViewHelper < BaseObject
4
+ include RuGUI::ObservablePropertySupport
5
+ include RuGUI::LogSupport
6
+
7
+ def initialize(observable_properties_values = {})
8
+ initialize_observable_property_support(observable_properties_values)
9
+ end
10
+
11
+ # This is included here so that the initialize method is properly updated.
12
+ include RuGUI::InitializeHooks
13
+
14
+ # Returns the framework_adapter for this class.
15
+ def framework_adapter
16
+ framework_adapter_for('BaseViewHelper')
17
+ end
18
+
19
+ # Called after the view helper is registered in a view.
20
+ def post_registration(view)
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,136 @@
1
+ # Defines the environment to be used by the application.
2
+ RUGUI_ENV = (ENV['RUGUI_ENV'] || 'development').dup unless defined?(RUGUI_ENV)
3
+
4
+ module RuGUI
5
+ # Defines configurations for a RuGUI application.
6
+ class Configuration
7
+ # The application root path, defined by ::APPLICATION_ROOT
8
+ attr_reader :root_path
9
+
10
+ # The environment for this application.
11
+ attr_accessor :environment
12
+
13
+ # The framework adapter to be used for this application. Defaults to GTK.
14
+ # For now it can only be GTK.
15
+ attr_accessor :framework_adapter
16
+
17
+ # The specific logger to use. By default, a logger will be created and
18
+ # initialized using #log_path and #log_level, but a programmer may
19
+ # specifically set the logger to use via this accessor and it will be
20
+ # used directly.
21
+ attr_accessor :logger
22
+
23
+ # An array of paths for builder files.
24
+ attr_accessor :builder_files_paths
25
+
26
+ # An array of paths which should be automaticaly loaded.
27
+ attr_accessor :load_paths
28
+
29
+ # An array of paths which should be searched for gtkrc styles files.
30
+ #
31
+ # It searchs for files which have the '.rc' extension or files which have
32
+ # the string 'gtkrc' in its filename.
33
+ #
34
+ # The order in which the files are loaded is random, so do not rely on it.
35
+ #
36
+ # If you need to use absolute paths in a gtkrc file, such as set the pixmap
37
+ # path, you can use "{ROOT_PATH}", which will be substituted by the
38
+ # application root path when the file is read.
39
+ attr_accessor :styles_paths
40
+
41
+ # The timeout for queued calls. Useful when performing long tasks.
42
+ attr_accessor :queue_timeout
43
+
44
+ # A hash of application specific configurations.
45
+ attr_accessor :application
46
+
47
+ # An array of gems that this RuGUI application depends on. RuGUI will automatically load
48
+ # these gems during installation, and allow you to install any missing gems with:
49
+ #
50
+ # rake gems:install
51
+ #
52
+ # You can add gems with the #gem method.
53
+ attr_accessor :gems
54
+
55
+ def initialize
56
+ set_root_path!
57
+
58
+ self.environment = default_environment
59
+ self.framework_adapter = default_framework_adapter
60
+ self.load_paths = default_load_paths
61
+ self.builder_files_paths = default_builder_files_paths
62
+ self.styles_paths = default_styles_paths
63
+ self.queue_timeout = default_queue_timeout
64
+ self.gems = default_gems
65
+ self.logger = {}
66
+ self.application = {}
67
+ end
68
+
69
+ # The path to the current environment's file (<tt>development.rb</tt>, etc.). By
70
+ # default the file is at <tt>config/environments/#{environment}.rb</tt>.
71
+ def environment_path
72
+ root_path.join('config', 'environments', "#{environment}.rb")
73
+ end
74
+
75
+ def set_root_path!
76
+ raise 'APPLICATION_ROOT is not set' unless defined?(::APPLICATION_ROOT)
77
+ raise 'APPLICATION_ROOT is not a directory' unless File.directory?(::APPLICATION_ROOT)
78
+
79
+ @root_path = Pathname.new(File.expand_path(::APPLICATION_ROOT))
80
+ end
81
+
82
+ # Adds a single Gem dependency to the RuGUI application. By default, it will require
83
+ # the library with the same name as the gem. Use :lib to specify a different name.
84
+ #
85
+ # # gem 'aws-s3', '>= 0.4.0'
86
+ # # require 'aws/s3'
87
+ # config.gem 'aws-s3', :lib => 'aws/s3', :version => '>= 0.4.0', \
88
+ # :source => "http://code.whytheluckystiff.net"
89
+ #
90
+ # To require a library be installed, but not attempt to load it, pass :lib => false
91
+ #
92
+ # config.gem 'qrp', :version => '0.4.1', :lib => false
93
+ def gem(name, options = {})
94
+ @gems << RuGUI::GemDependency.new(name, options)
95
+ end
96
+
97
+ private
98
+ def default_environment
99
+ ::RUGUI_ENV
100
+ end
101
+
102
+ def default_framework_adapter
103
+ 'GTK'
104
+ end
105
+
106
+ def default_load_paths
107
+ paths = []
108
+
109
+ paths.concat %w(
110
+ app
111
+ app/models
112
+ app/controllers
113
+ app/views
114
+ app/views/helpers
115
+ config
116
+ lib
117
+ ).map { |dir| root_path.join(dir) }.select { |dir| File.directory?(dir) }
118
+ end
119
+
120
+ def default_builder_files_paths
121
+ []
122
+ end
123
+
124
+ def default_styles_paths
125
+ [root_path.join('app', 'resources', 'styles')]
126
+ end
127
+
128
+ def default_queue_timeout
129
+ 50
130
+ end
131
+
132
+ def default_gems
133
+ []
134
+ end
135
+ end
136
+ end
@@ -0,0 +1,233 @@
1
+ require 'gtk2'
2
+ require 'libglade2'
3
+
4
+ # See the discussion here: http://eigenclass.org/hiki.rb?instance_exec
5
+ class Object
6
+ module InstanceExecHelper; end
7
+ include InstanceExecHelper
8
+ def instance_exec(*args, &block)
9
+ begin
10
+ old_critical, Thread.critical = Thread.critical, true
11
+ n = 0
12
+ n += 1 while respond_to?(mname="__instance_exec#{n}")
13
+ InstanceExecHelper.module_eval{ define_method(mname, &block) }
14
+ ensure
15
+ Thread.critical = old_critical
16
+ end
17
+ begin
18
+ ret = send(mname, *args)
19
+ ensure
20
+ InstanceExecHelper.module_eval{ remove_method(mname) } rescue nil
21
+ end
22
+ ret
23
+ end
24
+ end
25
+
26
+ module Gtk
27
+ GTK_PENDING_BLOCKS = []
28
+ GTK_PENDING_BLOCKS_LOCK = Monitor.new
29
+
30
+ def Gtk.queue(&block)
31
+ if Thread.current == Thread.main
32
+ block.call
33
+ else
34
+ GTK_PENDING_BLOCKS_LOCK.synchronize do
35
+ GTK_PENDING_BLOCKS << block
36
+ end
37
+ end
38
+ end
39
+
40
+ # Adds a timeout to execute pending blocks in a queue.
41
+ def Gtk.queue_timeout(timeout)
42
+ Gtk.timeout_add timeout do
43
+ GTK_PENDING_BLOCKS_LOCK.synchronize do
44
+ GTK_PENDING_BLOCKS.each do |block|
45
+ block.call
46
+ end
47
+ GTK_PENDING_BLOCKS.clear
48
+ end
49
+ true
50
+ end
51
+ end
52
+
53
+ def Gtk.load_style_paths
54
+ styles_paths = RuGUI.configuration.styles_paths.select { |path| File.directory?(path) }
55
+ styles_paths.each do |path|
56
+ Dir.new(path).each do |entry|
57
+ Gtk::RC.parse_string(get_style_file_contents(path, entry)) if is_style_file?(path, entry)
58
+ end
59
+ end
60
+ end
61
+
62
+ def Gtk.is_style_file?(path, filename)
63
+ File.extname(filename) == '.rc' or /gtkrc/.match(filename) if File.file?(File.join(path, filename))
64
+ end
65
+
66
+ def Gtk.get_style_file_contents(path, filename)
67
+ IO.read(File.join(path, filename)).sub('{ROOT_PATH}', RuGUI.configuration.root_path)
68
+ end
69
+ end
70
+
71
+ Gtk.load_style_paths
72
+
73
+ module RuGUI
74
+ module FrameworkAdapters
75
+ module GTK
76
+ class BaseController < RuGUI::FrameworkAdapters::BaseFrameworkAdapter::BaseController
77
+ def queue(&block)
78
+ Gtk.queue(&block)
79
+ end
80
+ end
81
+
82
+ class BaseMainController < RuGUI::FrameworkAdapters::GTK::BaseController
83
+ def run
84
+ Gtk.queue_timeout(RuGUI.configuration.queue_timeout)
85
+ Gtk.main
86
+ end
87
+
88
+ def quit
89
+ Gtk.main_quit
90
+ end
91
+ end
92
+
93
+ class BaseView < RuGUI::FrameworkAdapters::BaseFrameworkAdapter::BaseView
94
+ # Queues the block call, so that it is only gets executed in the main thread.
95
+ def queue(&block)
96
+ Gtk.queue(&block)
97
+ end
98
+
99
+ # Adds a widget to the given container widget.
100
+ def add_widget_to_container(widget, container_widget)
101
+ container_widget.add(widget)
102
+ end
103
+
104
+ # Removes a widget from the given container widget.
105
+ def remove_widget_from_container(widget, container_widget)
106
+ container_widget.remove(widget)
107
+ end
108
+
109
+ # Removes all children from the given container widget.
110
+ def remove_all_children(container_widget)
111
+ container_widget.children.each do |child|
112
+ container_widget.remove(child)
113
+ end
114
+ end
115
+
116
+ # Sets the widget name for the given widget if given.
117
+ def set_widget_name(widget, widget_name)
118
+ widget.name = widget_name.to_s unless widget_name.nil?
119
+ end
120
+
121
+ # Autoconnects signals handlers for the view. If +other_target+ is given
122
+ # it is used instead of the view itself.
123
+ def autoconnect_signals(other_target = nil)
124
+ if self.adapted_object.use_builder?
125
+ self.adapted_object.glade.signal_autoconnect_full do |source, target, signal_name, handler_name, signal_data, after|
126
+ target ||= other_target
127
+ self.adapted_object.glade.connect(source, target, signal_name, handler_name, signal_data) if target.respond_to?(handler_name)
128
+ end
129
+ end
130
+ end
131
+
132
+ # Connects the signal from the widget to the given receiver block.
133
+ # The block is executed in the context of the receiver.
134
+ def connect_declared_signal_block(widget, signal, receiver, block)
135
+ widget.signal_connect(signal) do |*args|
136
+ receiver.instance_exec(*args, &block)
137
+ end
138
+ end
139
+
140
+ # Connects the signal from the widget to the given receiver method.
141
+ def connect_declared_signal(widget, signal, receiver, method)
142
+ widget.signal_connect(signal) do |*args|
143
+ receiver.send(method, *args)
144
+ end
145
+ end
146
+
147
+ # Builds widgets from the given filename, using the proper builder.
148
+ def build_widgets_from(filename)
149
+ self.adapted_object.glade = GladeXML.new(filename, self.adapted_object.root, nil, nil, GladeXML::FILE)
150
+
151
+ self.adapted_object.glade.widget_names.each do |widget_name|
152
+ self.adapted_object.send(:create_attribute_for_widget, widget_name) unless self.adapted_object.glade[widget_name].nil?
153
+ end
154
+ self.adapted_object.root_widget.show if self.adapted_object.display_root? and not self.adapted_object.root_widget.nil?
155
+ end
156
+
157
+ # Registers widgets as attributes of the view class.
158
+ def register_widgets
159
+ self.adapted_object.glade.widget_names.each do |widget_name|
160
+ unless self.adapted_object.glade[widget_name].nil?
161
+ self.adapted_object.send("#{widget_name}=".to_sym, self.adapted_object.glade[widget_name])
162
+ self.adapted_object.widgets[widget_name] = self.adapted_object.glade[widget_name]
163
+ end
164
+ end
165
+ end
166
+
167
+ class << self
168
+ # Returns the builder file extension to be used for this view class.
169
+ def builder_file_extension
170
+ 'glade'
171
+ end
172
+ end
173
+ end
174
+ end
175
+ end
176
+ end
177
+
178
+ module RuGUI
179
+ class BaseView < BaseObject
180
+ class_inheritable_accessor :configured_glade_usage
181
+
182
+ attr_accessor :glade
183
+
184
+ # Adds a signal handler for all widgets of the given type.
185
+ def add_signal_handler_for_widget_type(widget_type, signal, &block)
186
+ widgets = []
187
+ widgets.concat(@widgets.values.select { |widget| widget.kind_of?(widget_type) }) unless @widgets.empty?
188
+ widgets.concat(@unnamed_widgets.select { |widget| widget.kind_of?(widget_type) }) unless @unnamed_widgets.empty?
189
+
190
+ widgets.each do |widget|
191
+ widget.signal_connect(signal, &block)
192
+ end
193
+ end
194
+
195
+ # Changes the widget style to use the given widget style.
196
+ #
197
+ # This widget style should be declared in a gtkrc file, by specifying a
198
+ # style using a widget path, such as:
199
+ #
200
+ # widget "main_window" style "main_window_style"
201
+ # widget "main_window_other" style "main_window_other_style"
202
+ #
203
+ # In this example, if you called this method like this:
204
+ #
205
+ # change_widget_style(:main_window, 'main_window_other')
206
+ # change_widget_style(self.main_window, 'main_window_other') # or, passing the widget instance directly
207
+ #
208
+ # The widget style would be set to "main_window_other_style".
209
+ #
210
+ # NOTE: Unfortunately, gtk doesn't offer an API to get declared styles, so
211
+ # you must set a style to a widget. Since the widget name set in the style
212
+ # definition doesn't need to point to an existing widget we can use this
213
+ # to simplify the widget styling here.
214
+ def change_widget_style(widget_or_name, widget_path_style)
215
+ if widget_or_name.is_a?(Gtk::Widget)
216
+ widget = widget_or_name
217
+ else
218
+ widget = @glade[widget_or_name.to_s]
219
+ end
220
+ style = Gtk::RC.get_style_by_paths(Gtk::Settings.default, widget_path_style.to_s, nil, nil)
221
+ widget.style = style
222
+ end
223
+
224
+ class << self
225
+ # Call this method at class level if the view should be built from a glade
226
+ # file.
227
+ def use_glade
228
+ self.logger.warn('DEPRECATED - Call use_builder class method instead in your view.')
229
+ use_builder
230
+ end
231
+ end
232
+ end
233
+ end