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,350 @@
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
+
10
+ module KDE
11
+ def self.ki18n(str)
12
+ str
13
+ end
14
+
15
+ def self.i18n(str)
16
+ str
17
+ end
18
+
19
+ def self.i18nc(context, str)
20
+ str
21
+ end
22
+
23
+ def self.active_color
24
+ $qApp.palette.color(Qt::Palette::Highlight)
25
+ end
26
+
27
+ def self.std_shortcut(name)
28
+ code = Qt::KeySequence.send(name.to_s.capitalize)
29
+ Qt::KeySequence.new(code)
30
+ end
31
+ end
32
+
33
+ class Qt::UrlRequester < Qt::LineEdit
34
+ def url=(val)
35
+ self.text = val.to_string
36
+ end
37
+
38
+ def url
39
+ Qt::Url.new(text)
40
+ end
41
+ end
42
+
43
+ class Qt::MainWindow
44
+ attr_reader :guis
45
+
46
+ def initialize(parent)
47
+ super(parent)
48
+
49
+ setToolButtonStyle(Qt::ToolButtonFollowStyle)
50
+
51
+ # create basic GUI
52
+ @guis = []
53
+ @gui = Qt::gui(:qt_base) do |g|
54
+ g.menu_bar do |mb|
55
+ mb.merge_point
56
+ mb.menu(:settings, :text => KDE::i18n("&Settings"))
57
+ mb.menu(:help, :text => KDE::i18n("&Help")) do |m|
58
+ m.action :about
59
+ m.action :about_qt
60
+ end
61
+ end
62
+ end
63
+ end
64
+
65
+ def setGUI(gui)
66
+ regular_action(:about, :text => KDE::i18n("&About")) do
67
+ Qt::MessageBox.about(nil,
68
+ $qApp.data[:name],
69
+ [$qApp.data[:description],
70
+ $qApp.data[:copyright]].join("\n"))
71
+ end
72
+ regular_action(:about_qt, :text => KDE::i18n("About &Qt")) { $qApp.about_qt }
73
+
74
+ @gui.merge!(gui)
75
+ @guis.each {|g| @gui.merge! g }
76
+ RUI::GuiBuilder.build(self, @gui)
77
+
78
+ # restore state
79
+ settings = Qt::Settings.new
80
+ state = nil
81
+ geometry = nil
82
+ if settings.contains("mainwindow/state")
83
+ state = settings.value("mainwindow/state").toByteArray
84
+ geometry = settings.value("mainwindow/geometry").toByteArray
85
+ restore_geometry(geometry)
86
+ restore_state(state)
87
+ end
88
+ end
89
+
90
+ def saveGUI
91
+ settings = Qt::Settings.new
92
+ settings.begin_group("mainwindow")
93
+ settings.set_value("geometry", Qt::Variant.new(save_geometry))
94
+ settings.set_value("state", Qt::Variant.new(save_state))
95
+ settings.end_group
96
+ settings.sync
97
+ end
98
+
99
+ def caption=(title)
100
+ self.window_title = $qApp.application_name.capitalize +
101
+ " - " + title
102
+ end
103
+ end
104
+
105
+ class Qt::Dialog
106
+ include Layoutable
107
+
108
+ def setGUI(gui)
109
+ self.window_title = gui.opts[:caption]
110
+ layout = Qt::VBoxLayout.new(self)
111
+ widget = Qt::Widget.new(self)
112
+ widget.owner = self
113
+ widget.setGUI(gui)
114
+ buttons = Qt::DialogButtonBox.new
115
+ buttons.add_button(Qt::DialogButtonBox::Ok)
116
+ buttons.add_button(Qt::DialogButtonBox::Cancel)
117
+ layout.add_widget(widget)
118
+ layout.add_widget(buttons)
119
+
120
+ buttons.on(:accepted) { fire :ok_clicked; accept }
121
+ buttons.on(:rejected) { reject }
122
+ end
123
+ end
124
+
125
+ class Qt::XMLGUIClient < Qt::Object
126
+ def setGUI(gui)
127
+ parent.guis << gui
128
+ end
129
+ end
130
+
131
+ module ActionHandler
132
+ def action_collection
133
+ @action_collection ||= { }
134
+ end
135
+
136
+ def action_list_entries
137
+ @action_list_entries ||= Hash.new {|h, x| h[x] = [] }
138
+ end
139
+
140
+ def plug_action_list(name, actions)
141
+ action_list_entries[name].each do |entry|
142
+ actions.each do |action|
143
+ puts "adding action to #{entry.parent}: #{action.text}"
144
+ entry.add_action(action)
145
+ end
146
+ end
147
+ end
148
+
149
+ def unplug_action_list(name)
150
+ action_list_entries[name].each do |entry|
151
+ entry.clear
152
+ end
153
+ end
154
+
155
+ def add_action(name, a)
156
+ action_parent.action_collection[name] = a
157
+ end
158
+
159
+ def std_action(name, &blk)
160
+ text, icon_name = Qt::STD_ACTIONS[name]
161
+ if text
162
+ icon = Qt::Icon.from_theme(icon_name)
163
+ a = Qt::Action.new(icon, text, action_parent)
164
+ add_action(name, a)
165
+ a.on(:triggered, &blk)
166
+ a
167
+ end
168
+ end
169
+
170
+ def regular_action(name, opts = { }, &blk)
171
+ a = Qt::Action.new(opts[:text], action_parent)
172
+ add_action(name, a)
173
+ a.on(:triggered, &blk)
174
+ if (opts[:icon])
175
+ a.icon = Qt::Icon.from_theme(opts[:icon])
176
+ end
177
+ a.shortcut = opts[:shortcut] if opts[:shortcut]
178
+ a.tool_tip = opts[:tooltip] if opts[:tooltip]
179
+ a
180
+ end
181
+
182
+ def action_parent
183
+ self
184
+ end
185
+ end
186
+
187
+ module Qt
188
+ STD_ACTIONS = {
189
+ :undo => [KDE::i18n("&Undo"), 'edit-undo'],
190
+ :redo => [KDE::i18n("&Redo"), 'edit-redo']
191
+ }
192
+
193
+ def self.gui(name, opts = { }, &blk)
194
+ self.autogui(name, opts, &blk)
195
+ end
196
+ end
197
+
198
+ class Qt::Application
199
+ attr_accessor :data
200
+
201
+ def self.init(data)
202
+ app = new(ARGV)
203
+ app.application_name = data[:id]
204
+ app.organization_name = data[:id]
205
+ app.data = data
206
+
207
+ if block_given?
208
+ yield app
209
+ app.exec
210
+ end
211
+ app
212
+ end
213
+ end
214
+
215
+ class KDE::CmdLineArgs
216
+ def self.parsed_args
217
+ new(ARGV)
218
+ end
219
+
220
+ def initialize(args)
221
+ @args = args
222
+ end
223
+
224
+ def [](i)
225
+ @args[i]
226
+ end
227
+
228
+ def count
229
+ @args.size
230
+ end
231
+
232
+ def is_set(name)
233
+ false
234
+ end
235
+ end
236
+
237
+ class KDE::Global
238
+ def self.config
239
+ Qt::Settings::Group.new(Qt::Settings.new, "")
240
+ end
241
+ end
242
+
243
+ class Qt::Settings
244
+ class Group
245
+ def initialize(settings, prefix)
246
+ @settings = settings
247
+ @prefix = prefix
248
+ end
249
+
250
+ def exists
251
+ in_group do
252
+ not @settings.all_keys.empty?
253
+ end
254
+ end
255
+
256
+ def delete_group
257
+ @settings.remove(@prefix)
258
+ end
259
+
260
+ def group(name)
261
+ Group.new(@settings, prefixed(name))
262
+ end
263
+
264
+ def write_entry(key, value)
265
+ @settings.set_value(prefixed(key),
266
+ Qt::Variant.new(value))
267
+ end
268
+
269
+ def read_entry(key, default_value = nil)
270
+ @settings.value(prefixed(key)).toString || default_value
271
+ end
272
+
273
+ def sync
274
+ @settings.sync
275
+ end
276
+
277
+ def group_list
278
+ in_group do
279
+ @settings.child_groups
280
+ end
281
+ end
282
+
283
+ def entry_map
284
+ in_group do
285
+ @settings.child_keys.inject({}) do |res, key|
286
+ res[key] = @settings.value(key).toString
287
+ res
288
+ end
289
+ end
290
+ end
291
+
292
+ def each_group
293
+ names = in_group do
294
+ @settings.child_groups
295
+ end
296
+ names.each do |name|
297
+ yield group(name)
298
+ end
299
+ end
300
+
301
+ def name
302
+ if @prefix =~ /\/([^\/]+)$/
303
+ $1
304
+ else
305
+ @prefix
306
+ end
307
+ end
308
+
309
+ private
310
+
311
+ def prefixed(key)
312
+ if @prefix.empty?
313
+ key
314
+ else
315
+ [@prefix, key].join('/')
316
+ end
317
+ end
318
+
319
+ def in_group
320
+ @settings.begin_group(@prefix)
321
+ result = yield
322
+ @settings.end_group
323
+ result
324
+ end
325
+ end
326
+ end
327
+
328
+ class Qt::TabWidget
329
+ include Layoutable
330
+ end
331
+
332
+ class Qt::Process
333
+ def output_channel_mode=(val)
334
+ case val
335
+ when :only_stdout
336
+ setProcessChannelMode(Qt::Process::SeparateChannels)
337
+ setReadChannel(Qt::Process::StandardOutput)
338
+ else
339
+ raise "Unsupported output mode #{val}"
340
+ end
341
+ end
342
+
343
+ def self.split_args(str)
344
+ str.split(/\s+/)
345
+ end
346
+
347
+ def run(path, args)
348
+ start(path, args)
349
+ end
350
+ end
@@ -0,0 +1,344 @@
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/factory'
9
+
10
+ module RUI
11
+ #
12
+ # Helper module used to interpret a GUI descriptor and build a Qt GUI.
13
+ #
14
+ # Classes in this module correspond to valid descriptor tags.
15
+ #
16
+ module GuiBuilder
17
+ def self.build(window, gui)
18
+ Gui.new.build(window, nil, gui)
19
+ end
20
+
21
+ def build(window, parent, desc)
22
+ element = create_element(window, parent, desc)
23
+ desc.children.each do |child|
24
+ b = builder(child.tag).new
25
+ b.build(window, element, child)
26
+ end
27
+ element
28
+ end
29
+
30
+ def setup_widget(widget, parent, layout, desc)
31
+ layout.add_widget(widget)
32
+ if desc.opts[:name]
33
+ parent.add_accessor(desc.opts[:name], widget)
34
+ end
35
+ end
36
+
37
+ def builder(name)
38
+ GuiBuilder.const_get(name.to_s.capitalize.camelize)
39
+ end
40
+
41
+ #
42
+ # Root tag for a GUI descriptor.
43
+ #
44
+ # Created automatically by {RUI.autogui}.
45
+ #
46
+ class Gui
47
+ include GuiBuilder
48
+ def create_element(window, parent, desc)
49
+ window
50
+ end
51
+ end
52
+
53
+ #
54
+ # Menu bar.
55
+ #
56
+ # This tag must be a child of a gui descriptor.
57
+ #
58
+ class MenuBar
59
+ include GuiBuilder
60
+
61
+ def create_element(window, parent, desc)
62
+ window.menu_bar
63
+ end
64
+ end
65
+
66
+ #
67
+ # A menu.
68
+ #
69
+ # This tag must be a child of a menu_bar descriptor.
70
+ #
71
+ class Menu
72
+ include GuiBuilder
73
+
74
+ def create_element(window, parent, desc)
75
+ menu = Qt::Menu.new(desc.opts[:text].to_s, window)
76
+ parent.add_menu(menu)
77
+ menu
78
+ end
79
+ end
80
+
81
+ #
82
+ # Menu or toolbar action.
83
+ #
84
+ # This tag must be a child of a menu or toolbar descriptor.
85
+ #
86
+ class Action
87
+ include GuiBuilder
88
+
89
+ def create_element(window, parent, desc)
90
+ action = window.action_collection[desc.opts[:name]]
91
+ if action
92
+ parent.add_action(action)
93
+ end
94
+ action
95
+ end
96
+ end
97
+
98
+ #
99
+ # Menu or toolbar separator.
100
+ #
101
+ # This tag must be a child of a menu or toolbar descriptor.
102
+ #
103
+ class Separator
104
+ include GuiBuilder
105
+
106
+ def create_element(window, parent, desc)
107
+ parent.add_separator
108
+ end
109
+ end
110
+
111
+ #
112
+ # A descriptor group.
113
+ #
114
+ # This can be used to affect how merging of descriptor is performed
115
+ # (together with merge points).
116
+ #
117
+ # @see Descriptor
118
+ #
119
+ class Group
120
+ include GuiBuilder
121
+
122
+ def create_element(window, parent, desc)
123
+ parent
124
+ end
125
+ end
126
+
127
+ #
128
+ # An action list is a placeholder for dynamically pluggable actions.
129
+ #
130
+ # Action lists can be plugged by using {ActionHandler#plug_action_list} and
131
+ # removed with {ActionHandler#unplug_action_list}.
132
+ #
133
+ class ActionList
134
+ include GuiBuilder
135
+
136
+ def create_element(window, parent, desc)
137
+ parent
138
+ end
139
+ end
140
+
141
+ #
142
+ # A toolbar.
143
+ #
144
+ # This tag must be a child of a gui descriptor.
145
+ #
146
+ class ToolBar
147
+ include GuiBuilder
148
+
149
+ def create_element(window, parent, desc)
150
+ tb = Qt::ToolBar.new(desc.opts[:text].to_s, parent)
151
+ tb.object_name = desc.opts[:name].to_s
152
+ parent.add_tool_bar(Qt::TopToolBarArea, tb)
153
+ tb
154
+ end
155
+ end
156
+
157
+ #
158
+ # A widget layout.
159
+ #
160
+ # Two orientations are supported: horizontal and vertical. The orientation
161
+ # is controlled by the <tt>type</tt> attribute of this descriptor.
162
+ #
163
+ # A margin can also be specified using the <tt>margin</tt> attribute.
164
+ #
165
+ class Layout
166
+ include GuiBuilder
167
+
168
+ def create_element(window, parent, desc)
169
+ factory = if desc.opts[:type] == :horizontal
170
+ Qt::HBoxLayout
171
+ else
172
+ Qt::VBoxLayout
173
+ end
174
+ layout = factory.new
175
+ layout.margin = desc.opts[:margin] if desc.opts[:margin]
176
+ parent.add_layout(layout)
177
+ layout
178
+ end
179
+ end
180
+
181
+ #
182
+ # A stretch element.
183
+ #
184
+ # Used to separate consecutive elements of a layout.
185
+ #
186
+ class Stretch
187
+ include GuiBuilder
188
+
189
+ def create_element(window, parent, desc)
190
+ parent.add_stretch
191
+ end
192
+ end
193
+
194
+ #
195
+ # A label.
196
+ #
197
+ # The label text is specified by the <tt>text</tt> attribute.
198
+ #
199
+ # A <tt>buddy</tt> attribute can also be specified as a widget id. The widget with
200
+ # the given id will be set as the buddy of this label as GUI construction
201
+ # time.
202
+ #
203
+ class Label
204
+ include GuiBuilder
205
+
206
+ def create_element(window, parent, desc)
207
+ label = Qt::Label.new(desc.opts[:text].to_s, window)
208
+ setup_widget(label, window, parent, desc)
209
+ if desc.opts[:buddy]
210
+ window.buddies[label] = desc.opts[:buddy]
211
+ end
212
+ label
213
+ end
214
+ end
215
+
216
+ #
217
+ # A TabWidget.
218
+ #
219
+ class TabWidget
220
+ include GuiBuilder
221
+
222
+ def create_element(window, parent, desc)
223
+ widget = KDE::TabWidget.new(window)
224
+ setup_widget(widget, window, parent, desc)
225
+ widget.owner = window.owner
226
+ widget
227
+ end
228
+ end
229
+
230
+ #
231
+ # A generic widget.
232
+ #
233
+ # To use this tag, the <tt>factory</tt> descriptor property must be set to
234
+ # the Factory to use to create the widget. The {Factory} class can be
235
+ # useful when the widget to create needs special initialization. Note that
236
+ # the given factory will be invoked passing only the parent widget as a
237
+ # parameter, so any extra parameters must be preset by the factory itself.
238
+ #
239
+ class Widget
240
+ include GuiBuilder
241
+
242
+ def create_element(window, parent, desc)
243
+ widget = factory(desc).new(window)
244
+ setup_widget(widget, window, parent, desc)
245
+ widget
246
+ end
247
+
248
+ def factory(desc)
249
+ desc.opts[:factory]
250
+ end
251
+ end
252
+
253
+ #
254
+ # An individual tab in a tab_widget.
255
+ #
256
+ # This tag must be a child of tab_widget descriptor.
257
+ #
258
+ class Tab
259
+ include GuiBuilder
260
+
261
+ class Helper
262
+ def initialize(parent, text)
263
+ @parent = parent
264
+ @text = text
265
+ end
266
+
267
+ def add_widget(widget)
268
+ @parent.add_tab(widget, @text)
269
+ end
270
+ end
271
+
272
+ def build(window, parent, desc)
273
+ desc.children.each do |child|
274
+ b = builder(child.tag).new
275
+ b.build(parent, Helper.new(parent, desc.opts[:text]), child)
276
+ end
277
+ end
278
+ end
279
+
280
+ #
281
+ # A url requester widget.
282
+ #
283
+ class UrlRequester < Widget
284
+ def factory(desc)
285
+ KDE::UrlRequester
286
+ end
287
+ end
288
+
289
+ #
290
+ # A line edit widget.
291
+ #
292
+ class LineEdit < Widget
293
+ def factory(desc)
294
+ Qt::LineEdit
295
+ end
296
+ end
297
+
298
+ #
299
+ # A combobox.
300
+ #
301
+ class ComboBox < Widget
302
+ def factory(desc)
303
+ KDE::ComboBox
304
+ end
305
+ end
306
+
307
+ #
308
+ # A list widget.
309
+ #
310
+ class List < Widget
311
+ def factory(desc)
312
+ Qt::ListView
313
+ end
314
+ end
315
+
316
+ #
317
+ # A checkbox.
318
+ #
319
+ # The <tt>checked</tt> property specifies whether the checkbox is checked.
320
+ #
321
+ class CheckBox < Widget
322
+ def factory(desc)
323
+ Factory.new do |parent|
324
+ check = Qt::CheckBox.new(parent)
325
+ check.text = desc.opts[:text].to_s
326
+ check.checked = desc.opts[:checked]
327
+ check
328
+ end
329
+ end
330
+ end
331
+
332
+ #
333
+ # A push button.
334
+ #
335
+ class Button < Widget
336
+ def factory(desc)
337
+ Factory.new do |parent|
338
+ KDE::PushButton.new(KDE::Icon.from_theme(desc.opts[:icon]),
339
+ desc.opts[:text], parent)
340
+ end
341
+ end
342
+ end
343
+ end
344
+ end