rui 0.1.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.
@@ -0,0 +1,178 @@
1
+ # Copyright (c) 2009-2010 Paolo Capriotti <p.capriotti@gmail.com>
2
+ #
3
+ # This library is free software; you can redistribute it and/or modify
4
+ # it under the terms of the GNU Lesser General Public License as
5
+ # published by the Free Software Foundation; either version 3 of the
6
+ # License, or (at your option) any later version.
7
+
8
+ require 'observer'
9
+ require 'rui/utils'
10
+
11
+ #
12
+ # A mixin to make it easier to implement observers using the standard observer
13
+ # library.
14
+ #
15
+ # Mixing <tt>Observer</tt> into a class generates a default update method,
16
+ # which reacts to notification in the form of a hash, and calls appropriate
17
+ # event handlers, obtained by prepending "on_" to each key, and passing it the
18
+ # corresponding value.
19
+ #
20
+ # For example, an event containing the following data
21
+ #
22
+ # { :pressed => { :x => 34, :y => 11 },
23
+ # :released => { :x => 10, :y => 76 } }
24
+ #
25
+ # would result in the following method calls:
26
+ #
27
+ # on_pressed(:x => 34, :y => 11)
28
+ # on_released(:x => 10, :y => 76)
29
+ #
30
+ # As a special case, if an event takes more than 1 parameter, the corresponding
31
+ # value is assumed to be an array, and its elements are passed as arguments to
32
+ # the event.
33
+ #
34
+ module Observer
35
+ #
36
+ # A default implementation for the <tt>update</tt> function.
37
+ #
38
+ # Parses notification data and dispatches to the corresponding events.
39
+ #
40
+ def update(data)
41
+ data.each_key do |key|
42
+ m = begin
43
+ method("on_#{key}")
44
+ rescue NameError
45
+ end
46
+
47
+ if m
48
+ case m.arity
49
+ when 0
50
+ m[]
51
+ when 1
52
+ m[data[key]]
53
+ else
54
+ m[*data[key]]
55
+ end
56
+ end
57
+ end
58
+ end
59
+ end
60
+
61
+ #
62
+ # Extensions to the standard Observable module of the observer library.
63
+ #
64
+ # This mixin allows to define event handlers dynamically, without having to
65
+ # create an Observer class for each handler.
66
+ #
67
+ # For example, assuming <tt>button</tt> is an instance of some observable class:
68
+ #
69
+ # count = 0
70
+ # button.on(:clicked) do
71
+ # count += 1
72
+ # puts "I have been clicked #{count} times"
73
+ # end
74
+ #
75
+ # Events can be fired with the <tt>fire</tt> method, and support arbitrary
76
+ # arguments.
77
+ #
78
+ module Observable
79
+ #
80
+ # Alias to observe.
81
+ #
82
+ def on(event, &blk)
83
+ observe(event, &blk)
84
+ end
85
+
86
+ #
87
+ # Create a dynamic observer handling a given event.
88
+ #
89
+ # @param event [Symbol] the event to handle
90
+ # @param &blk [Block] event handler
91
+ # @return an observer object, which can be later used to remove
92
+ # the event handler.
93
+ #
94
+ def observe(event, &blk)
95
+ obs = SimpleObserver.new(event, &blk)
96
+ add_observer obs
97
+ # return observer so that we can remove it later
98
+ obs
99
+ end
100
+
101
+ # Create a limited observer handling a given event.
102
+ #
103
+ # A limited observer behaves similarly to a normal dynamic observer, but in
104
+ # addition, it keeps track of the return valur of the handler. When the
105
+ # handler returns true, the observer is destroyed.
106
+ #
107
+ # @param event [Symbol] the event to handle
108
+ # @param &blk [Block] event handler
109
+ # @return an observer object, which can be later used to remove
110
+ # the event handler.
111
+ #
112
+ def observe_limited(event, &blk)
113
+ obs = LimitedObserver.new(self, event, &blk)
114
+ add_observer obs
115
+ obs
116
+ end
117
+
118
+ #
119
+ # Fire an event.
120
+ #
121
+ # @param e [Symbol, Hash] event and arguments. This needs to be either
122
+ # a Symbol, or a Hash with a single key corresponding to the event, and the
123
+ # value being the event data to pass to the handler.
124
+ #
125
+ def fire(e)
126
+ changed
127
+ notify_observers any_to_event(e)
128
+ end
129
+
130
+ private
131
+
132
+ def any_to_event(e)
133
+ if e.is_a? Symbol
134
+ { e => nil }
135
+ else
136
+ e
137
+ end
138
+ end
139
+ end
140
+
141
+ class Proc
142
+ def generic_call(args)
143
+ case arity
144
+ when 0
145
+ call
146
+ when 1
147
+ call(args)
148
+ else
149
+ call(*args)
150
+ end
151
+ end
152
+ end
153
+
154
+ class SimpleObserver
155
+ def initialize(event, &blk)
156
+ @event = event
157
+ @blk = blk
158
+ end
159
+
160
+ def update(data)
161
+ if data.has_key?(@event)
162
+ @blk.generic_call(data[@event])
163
+ end
164
+ end
165
+ end
166
+
167
+ class LimitedObserver < SimpleObserver
168
+ def initialize(observed, event, &blk)
169
+ super(event, &blk)
170
+ @observed = observed
171
+ end
172
+
173
+ def update(data)
174
+ remove = super(data)
175
+ @observed.delete_observer(self) if remove
176
+ remove
177
+ end
178
+ end
@@ -0,0 +1,276 @@
1
+ # Copyright (c) 2009-2010 Paolo Capriotti <p.capriotti@gmail.com>
2
+ #
3
+ # This library is free software; you can redistribute it and/or modify
4
+ # it under the terms of the GNU Lesser General Public License as
5
+ # published by the Free Software Foundation; either version 3 of the
6
+ # License, or (at your option) any later version.
7
+
8
+ require 'rui/toolkits/qtbase/qt'
9
+ require 'builder'
10
+ begin
11
+ require 'kio'
12
+ rescue LoadError
13
+ end
14
+
15
+ class KDE::Dialog
16
+ include Layoutable
17
+
18
+ def setGUI(gui)
19
+ self.caption = gui.opts[:caption]
20
+ widget = Qt::Widget.new(self)
21
+ widget.owner = self
22
+ widget.setGUI(gui)
23
+ self.main_widget = widget
24
+ end
25
+ end
26
+
27
+ class KDE::Application
28
+ #
29
+ # Initialize an application.
30
+ #
31
+ def self.init(data)
32
+ data = { :id => data } unless data.is_a?(Hash)
33
+ about = KDE::AboutData.new(
34
+ data[:id],
35
+ data[:id],
36
+ data[:name] || KDE::LocalizedString.new,
37
+ data[:version] || '0.0',
38
+ data[:description] || KDE::LocalizedString.new,
39
+ KDE::AboutData::License_GPL,
40
+ data[:copyright] || KDE::LocalizedString.new)
41
+ (data[:authors] || []).each do |name, email|
42
+ about.addAuthor(name, KDE::LocalizedString.new, email)
43
+ end
44
+ (data[:contributors] || []).each do |name, contribution|
45
+ about.addCredit(name, contribution)
46
+ end
47
+ about.bug_address = Qt::ByteArray.new(data[:bug_tracker] || "")
48
+
49
+ KDE::CmdLineArgs.init(ARGV, about)
50
+ opts = KDE::CmdLineOptions.new
51
+ (data[:options] || []).each do |args|
52
+ case args.size
53
+ when 2
54
+ opts.add(args[0], args[1])
55
+ when 3
56
+ opts.add(args[0], args[1], args[2])
57
+ end
58
+ end
59
+ KDE::CmdLineArgs.add_cmd_line_options opts
60
+ opts
61
+
62
+ app = KDE::Application.new
63
+ if block_given?
64
+ yield app
65
+ app.exec
66
+ end
67
+ app
68
+ end
69
+ end
70
+
71
+ class KDE::CmdLineArgs
72
+ def [](i)
73
+ arg(i)
74
+ end
75
+
76
+ def is_set(name)
77
+ isSet(Qt::ByteArray.new(name))
78
+ end
79
+ end
80
+
81
+ class KDE::ActionCollection
82
+ def []=(name, action)
83
+ unless action.is_a? KDE::Action
84
+ orig_action = action
85
+ action = KDE::Action.new(action.text, action.parent)
86
+ action.icon = orig_action.icon
87
+ action.checkable = orig_action.checkable
88
+ action.checked = orig_action.checked
89
+ action.on(:triggered) { orig_action.trigger }
90
+ orig_action.on(:changed) { action.checked = orig_action.checked }
91
+ end
92
+ add_action(name.to_s, action)
93
+ end
94
+ end
95
+
96
+ class KDE::XmlGuiWindow
97
+ def setGUI(gui)
98
+ RUI::with_xml_gui(gui) do |file|
99
+ setupGUI(KDE::XmlGuiWindow::Default, file)
100
+ end
101
+ end
102
+
103
+ def saveGUI
104
+ end
105
+ end
106
+
107
+ class KDE::XMLGUIClient
108
+ def setGUI(gui)
109
+ RUI::with_xml_gui(gui) do |file|
110
+ setXMLFile(file)
111
+ end
112
+ end
113
+ end
114
+
115
+ module ActionHandler
116
+ def std_action(action, opts = {}, &blk)
117
+ target, slot = get_slot(opts[:slot], &blk)
118
+ KDE::StandardAction.method_missing(action, target, slot, action_collection)
119
+ end
120
+
121
+ def get_slot(s = nil, &blk)
122
+ target, slot = if block_given?
123
+ [Qt::SignalBlockInvocation.new(action_parent, blk, 'invoke()'), SLOT('invoke()')]
124
+ else
125
+ [action_parent, SLOT(s)]
126
+ end
127
+ end
128
+
129
+ def regular_action(name, opts, &blk)
130
+ a = KDE::Action.new(KDE::Icon.from_theme(opts[:icon]),
131
+ opts[:text], action_parent)
132
+ action_collection.add_action(name.to_s, a)
133
+ a.connect(SIGNAL('triggered(bool)'), &blk)
134
+ a.tool_tip = opts[:tooltip] if opts[:tooltip]
135
+ a.shortcut = opts[:shortcut] if opts[:shortcut]
136
+ a
137
+ end
138
+
139
+ def action_parent
140
+ self
141
+ end
142
+
143
+ def plug_action_list(name, actions)
144
+ plugActionList(name.to_s, actions)
145
+ end
146
+
147
+ def unplug_action_list(name)
148
+ unplugActionList(name.to_s)
149
+ end
150
+ end
151
+
152
+ class KDE::Icon
153
+ def self.from_theme(name)
154
+ if name
155
+ new(name.to_s)
156
+ else
157
+ new
158
+ end
159
+ end
160
+ end
161
+
162
+ class KDE::ConfigGroup
163
+ def each_group
164
+ group_list.each do |g|
165
+ yield group(g)
166
+ end
167
+ end
168
+ end
169
+
170
+ class KDE::TabWidget
171
+ include Layoutable
172
+ end
173
+
174
+ class KDE::Process
175
+ def output_channel_mode=(value)
176
+ c = self.class.const_get("#{value.to_s.capitalize.camelize}Channel")
177
+ setOutputChannelMode(c)
178
+ end
179
+
180
+ def self.split_args(str)
181
+ KDE::Shell.split_args(str)
182
+ end
183
+
184
+ def run(path, args)
185
+ set_program(path, args)
186
+ start
187
+ end
188
+ end
189
+
190
+ def KDE.download_tempfile(url, parent)
191
+ result = ""
192
+ if KIO::NetAccess.download(url, result, parent)
193
+ result
194
+ end
195
+ end
196
+
197
+ module RUI
198
+ def self.gui(name, &blk)
199
+ "<!DOCTYPE kpartgui SYSTEM \"kpartgui.dtd\">\n" +
200
+ XmlGuiBuilder.new.gui({ :version => 2, :name => name }, &blk)
201
+ end
202
+
203
+ def self.with_xml_gui(xml, &blk)
204
+ tmp = TemporaryFile.new
205
+ tmp.open
206
+
207
+ ::File.open(tmp.file_name, 'w') do |f|
208
+ f.write(xml)
209
+ end
210
+ blk[tmp.file_name]
211
+ ensure
212
+ tmp.close
213
+ ::File.unlink(tmp.file_name)
214
+ end
215
+
216
+ class XmlGuiBuilder < Builder::XmlMarkup
217
+ def initialize
218
+ super
219
+ @action_opts = { }
220
+ end
221
+
222
+ def menu_bar(&blk)
223
+ MenuBar(&blk)
224
+ end
225
+
226
+ def menu(name, opts = {}, &blk)
227
+ Menu(:name => name) do |m|
228
+ m.text(opts[:text]) if opts[:text]
229
+ blk[m] if block_given?
230
+ end
231
+ end
232
+
233
+ def action(name, opts = {})
234
+ Action(opts.merge(@action_opts).merge(:name => name))
235
+ end
236
+
237
+ def separator
238
+ self.Separator
239
+ end
240
+
241
+ def tool_bar(name, opts = { }, &blk)
242
+ ToolBar(:name => name) do |tb|
243
+ tb.text(opts[:text]) if opts[:text]
244
+ blk[tb] if block_given?
245
+ end
246
+ end
247
+
248
+ def action_list(name)
249
+ ActionList(:name => name)
250
+ end
251
+
252
+ def group(name, &blk)
253
+ if block_given?
254
+ @action_opts = { :group => name }
255
+ blk[self]
256
+ @action_opts = { }
257
+ else
258
+ DefineGroup(:name => name)
259
+ end
260
+ end
261
+ end
262
+
263
+ def self.active_color
264
+ scheme = KDE::ColorScheme.new(Qt::Palette::Active, KDE::ColorScheme::Window)
265
+ color = scheme.foreground(KDE::ColorScheme::PositiveText).color
266
+ end
267
+
268
+ def self.std_shortcut(name)
269
+ code = KDE::StandardShortcut.send(name.to_s.capitalize)
270
+ StandardShortcut::shortcut(code)
271
+ end
272
+
273
+ def self.i18n(*args)
274
+ KDE.i18n(*args)
275
+ end
276
+ end