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.
- data/.document +4 -0
- data/COPYING +165 -0
- data/Gemfile +15 -0
- data/Gemfile.lock +24 -0
- data/README.md +8 -0
- data/Rakefile +43 -0
- data/VERSION +1 -0
- data/examples/autogui/main.rb +12 -0
- data/examples/hello/main.rb +13 -0
- data/examples/kderun.rb +4 -0
- data/examples/qtrun.rb +4 -0
- data/examples/signals/main.rb +15 -0
- data/lib/rui/descriptor.rb +241 -0
- data/lib/rui/factory.rb +84 -0
- data/lib/rui/observer_utils.rb +178 -0
- data/lib/rui/toolkits/kde/kde.rb +276 -0
- data/lib/rui/toolkits/qt/qt.rb +350 -0
- data/lib/rui/toolkits/qtbase/gui_builder.rb +344 -0
- data/lib/rui/toolkits/qtbase/qt.rb +555 -0
- data/lib/rui/utils.rb +42 -0
- data/lib/rui.rb +54 -0
- data/rui.gemspec +92 -0
- data/test/helper.rb +17 -0
- data/test/test_descriptor.rb +237 -0
- data/test/test_factory.rb +38 -0
- data/test/test_observer_utils.rb +67 -0
- metadata +189 -0
|
@@ -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
|