zik 0.16.1

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 (84) hide show
  1. data.tar.gz.sig +0 -0
  2. data/ChangeLog +222 -0
  3. data/INSTALL +34 -0
  4. data/Makefile.in +199 -0
  5. data/README +53 -0
  6. data/ZiK.desktop +11 -0
  7. data/ZiK.rb +377 -0
  8. data/configure +269 -0
  9. data/dependencies +142 -0
  10. data/doc/COPYING +340 -0
  11. data/doc/ChangeLog +222 -0
  12. data/doc/html/fr/index.html +128 -0
  13. data/doc/html/index.html +126 -0
  14. data/doc/html/pix/ZiK3.png +0 -0
  15. data/doc/html/pix/capture.png +0 -0
  16. data/doc/html/pix/capture_cd.png +0 -0
  17. data/doc/html/pix/capture_compact.png +0 -0
  18. data/doc/html/pix/capture_radio.png +0 -0
  19. data/doc/html/pix/icon.png +0 -0
  20. data/doc/html/pix/logo.png +0 -0
  21. data/doc/html/styles/main.css +47 -0
  22. data/doc/man/manpage.1 +43 -0
  23. data/gui/assistant.rb +133 -0
  24. data/gui/cdgui.rb +54 -0
  25. data/gui/common.rb +56 -0
  26. data/gui/config.rb +120 -0
  27. data/gui/edit.rb +413 -0
  28. data/gui/error.rb +124 -0
  29. data/gui/gui.rb +1383 -0
  30. data/gui/mod.rb +239 -0
  31. data/gui/preference.rb +496 -0
  32. data/gui/progress.rb +50 -0
  33. data/gui/radiogui.rb +404 -0
  34. data/gui/search.rb +249 -0
  35. data/gui/socket.rb +107 -0
  36. data/mod/brainz.rb +76 -0
  37. data/mod/brainz/dialogs.rb +132 -0
  38. data/mod/brainz/functions.rb +55 -0
  39. data/mod/brainz/ofa.rb +76 -0
  40. data/mod/brainz/song.rb +139 -0
  41. data/mod/brainz/widget.rb +34 -0
  42. data/mod/cover.rb +90 -0
  43. data/mod/cover/application-x-cd-image.svg +666 -0
  44. data/mod/cover/config.rb +79 -0
  45. data/mod/cover/configwidget.rb +35 -0
  46. data/mod/cover/widget.rb +147 -0
  47. data/mod/hotkeys.rb +137 -0
  48. data/mod/hotkeys/config.rb +84 -0
  49. data/mod/hotkeys/configwidget.rb +93 -0
  50. data/mod/interact.rb +131 -0
  51. data/mod/interact/configwidget.rb +107 -0
  52. data/mod/interact/interaction.rb +79 -0
  53. data/mod/notify.rb +128 -0
  54. data/mod/notify/config.rb +96 -0
  55. data/mod/notify/configwidget.rb +76 -0
  56. data/mod/notify/window.rb +56 -0
  57. data/mod/trayicon.rb +83 -0
  58. data/mod/trayicon/config.rb +79 -0
  59. data/mod/trayicon/configwidget.rb +35 -0
  60. data/mod/trayicon/icon.rb +99 -0
  61. data/pix/ZiK.svg +78 -0
  62. data/pix/ZiK3.png +0 -0
  63. data/pix/assistant/capture.png +0 -0
  64. data/pix/gtk-directory.svg +287 -0
  65. data/pix/media-cdrom.svg +292 -0
  66. data/pix/network-wireless.svg +429 -0
  67. data/pix/player_play.svg +286 -0
  68. data/pix/sound.svg +244 -0
  69. data/pix/sound_directory.svg +464 -0
  70. data/player/cdplayer.rb +108 -0
  71. data/player/player.rb +132 -0
  72. data/player/radioplayer.rb +124 -0
  73. data/playlist/cdlist.rb +140 -0
  74. data/playlist/common.rb +343 -0
  75. data/playlist/editlist.rb +50 -0
  76. data/playlist/export.rb +108 -0
  77. data/playlist/playlist.rb +143 -0
  78. data/playlist/radiolist.rb +148 -0
  79. data/playlist/song.rb +122 -0
  80. data/po/ZiK.pot +622 -0
  81. data/po/fr/ZiK.po +658 -0
  82. data/zik +2 -0
  83. metadata +265 -0
  84. metadata.gz.sig +0 -0
data/gui/mod.rb ADDED
@@ -0,0 +1,239 @@
1
+ # encoding: UTF-8
2
+ =begin
3
+ Copyright 2007-2011 Vincent Carmona
4
+ vinc4mai@gmail.com
5
+
6
+ This file is part of ZiK.
7
+
8
+ ZiK is free software; you can redistribute it and/or modify
9
+ it under the terms of the GNU General Public License as published by
10
+ the Free Software Foundation; either version 2 of the License, or
11
+ (at your option) any later version.
12
+
13
+ ZiK is distributed in the hope that it will be useful,
14
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
15
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16
+ GNU General Public License for more details.
17
+
18
+ You should have received a copy of the GNU General Public License
19
+ along with ZiK; if not, write to the Free Software
20
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
21
+ =end
22
+
23
+ class ModNotUniqueId < Exception
24
+ end
25
+
26
+ class ModError < Error
27
+ #Error superclass for module not to be directly used.
28
+ def initialize(mod, type, message, user, description)
29
+ super(type, message, user, "#{mod.title}\n"+(description||message))
30
+ end
31
+ end
32
+
33
+ class ModErrorInfo < ModError
34
+ def initialize(mod, message, user=false, description=nil)
35
+ print "[#{mod.id}]: "
36
+ super(mod, ModErrorINFO, message, user, description)
37
+ end
38
+ end
39
+
40
+ class ModErrorWarning < ModError
41
+ def initialize(mod, message, user=false, description=nil)
42
+ $stderr.print "[#{mod.id}]: "
43
+ super(mod, ModErrorWARNING, message, user, description)
44
+ end
45
+ end
46
+
47
+ class ModErrorError < ModError
48
+ def initialize(mod, message, user=false, description=nil)
49
+ $stderr.print "[#{mod.id}]: "
50
+ super(mod, ModErrorERROR, message, user, description)
51
+ end
52
+ end
53
+
54
+ class ModErrorLoadError < ModError
55
+ @@stock=[]
56
+ attr_reader :mod, :message
57
+
58
+ def ModErrorLoadError.show_all
59
+ if $show_errors
60
+ unless @@stock.empty?
61
+ message=_("Some module cannot be loaded.")
62
+ @@stock.each{|error| message+="\n\n#{error.mod.title}\n#{error.message}"}
63
+ dialog=Gtk::MessageDialog.new(@@zik, Gtk::Dialog::MODAL|Gtk::Dialog::DESTROY_WITH_PARENT,
64
+ Gtk::MessageDialog::ERROR, Gtk::MessageDialog::BUTTONS_CLOSE, message)
65
+ dialog.run; dialog.destroy
66
+ @@stock=[]
67
+ end
68
+ end
69
+ end
70
+
71
+ def initialize(mod, type, message)
72
+ @mod=mod; @message=message
73
+ @@stock.push(self)
74
+ $stderr.print "[#{mod.id}]: "
75
+ super(mod, ModErrorLOAD_ERROR, message, false)
76
+ end
77
+ end
78
+
79
+ class Mod
80
+ #Class used to implement a ZiK module (plugin).
81
+
82
+ ###Internal use
83
+ @@ids=[]; @@global=true
84
+ @@all=[]; @@own=[]; @@user=[]
85
+
86
+ def Mod.global=(tf)
87
+ @@global=tf
88
+ end
89
+
90
+ def Mod.all
91
+ @@all
92
+ end
93
+
94
+ def Mod.own
95
+ @@own
96
+ end
97
+
98
+ def Mod.user
99
+ @@user
100
+ end
101
+
102
+ def Mod.zik=(zik)
103
+ @@zik=zik
104
+ end
105
+
106
+ ###External use
107
+ attr_reader :id, :title, :description, :author, :license
108
+
109
+ def initialize(id, title, description, author, license)
110
+ @id=id#Internal id. Must be unique.
111
+ raise ModNotUniqueId if @@ids.include?(@id)
112
+ @@ids.push(@id)
113
+ @loaded=false
114
+ @title=title#Name of the module
115
+ @description=description#Short description of the module
116
+ @author=author#A string used in credits (name1 <contact email>, name2)
117
+ @license=license#A short string ('GPL-2', 'BSD'...)
118
+ @@all.push(self)
119
+ @@global ? @@own.push(self) : @@user.push(self)
120
+ end
121
+
122
+ def pack(widget, start=true, expand=true, fill=true, padding=0)
123
+ #Use this method to show a widget in the main interface.
124
+ unless defined?(@@hbox)
125
+ @@expander=Gtk::Expander.new(_('Modules'))
126
+ @@expander.spacing=$border
127
+ @@expander.signal_connect('notify::expanded'){|widget, foo|
128
+ if widget.expanded?
129
+ @@hbox.show
130
+ else
131
+ @@hbox.hide
132
+ @@zik.resize(@@zik.size[0], 1) if @@zik.selectview.active==View::COMPACT
133
+ end
134
+ }
135
+ @@hbox=Gtk::HBox.new
136
+ zik.vbox.pack_start(@@expander, false, false)
137
+ zik.vbox.pack_start(@@hbox, false, false)
138
+ position=2; position+=1 if $cd; position+=1 if $radio
139
+ zik.vbox.reorder_child(@@expander, position)
140
+ zik.vbox.reorder_child(@@hbox, position+1)
141
+ @@expander.show
142
+ end
143
+
144
+ if start
145
+ @@hbox.pack_start(widget, expand, fill, padding)
146
+ else
147
+ @@hbox.pack_end(widget, expand, fill, padding)
148
+ end
149
+ @@expander.activate
150
+ end
151
+
152
+ def menu_add(widget)
153
+ #Use this method to show a widget under ZiK module menu.
154
+ unless defined?(@@menu)
155
+ @@menu=Gtk::Menu.new
156
+ item=Gtk::MenuItem.new(_('Modules')).show
157
+ item.set_submenu(@@menu)
158
+ @@zik.menu_bar.append(item)
159
+ end
160
+ @@menu.show
161
+ @@menu.append(widget)
162
+ end
163
+
164
+ def menu_hide
165
+ #Destroy module menu if it is empty
166
+ if defined?(@@menu)
167
+ @@menu.hide if @@menu.children.empty?
168
+ end
169
+ end
170
+
171
+ def list_cmenu_add(widget)
172
+ #Use this method to show a widget in the playlist context menu.
173
+ unless defined?(@@cmenu_list)
174
+ @@cmenu_list=Gtk::Menu.new
175
+ it=Gtk::MenuItem.new(_("Modules"))
176
+ @@zik.cm_list.append(Gtk::SeparatorMenuItem.new)
177
+ @@zik.cm_list.append(it)
178
+ it.set_submenu(@@cmenu_list)
179
+ it.show
180
+ @@cmenu_list.show
181
+ end
182
+ @@cmenu_list.append(widget)
183
+ end
184
+
185
+ def expander
186
+ #Use this method to get the expander. Can return nil.
187
+ defined?(@@expander) ? @@expander : nil
188
+ end
189
+
190
+ def zik
191
+ @@zik
192
+ end
193
+
194
+ def loaded?
195
+ @loaded
196
+ end
197
+
198
+ ###Methods you may want to redefine.
199
+
200
+ def init(input)
201
+ #Called when ZiK starts
202
+ #input is a hash containing objects potentially needed. See modinput in ZiK.rb (main.rb) file.
203
+ end
204
+
205
+ def load
206
+ #Call when ZiK need to activate the module. Do not forget to set @loaded to true if module activation goes ok.
207
+ unless @loaded
208
+ ModErrorInfo.new(self, "Module loaded.")
209
+ @loaded=true
210
+ else
211
+ false
212
+ end
213
+ end
214
+
215
+ def unload
216
+ #Call when ZiK need to deactivate the module. Do not forget to set @loaded to false.
217
+ if @loaded
218
+ ModErrorInfo.new(self, "Module unloaded.")
219
+ @loaded=false
220
+ true
221
+ else
222
+ false
223
+ end
224
+ end
225
+
226
+ def configwidget
227
+ #Return a Gtk::Widget used in ZiK preferences windows in order to configure module (or nil).
228
+ nil
229
+ end
230
+
231
+ def saveconfig
232
+ #Called when configuration should be modified.
233
+ #If you writes a configuration file check first for the $write_config variable.
234
+ end
235
+
236
+ def quit
237
+ #Called when ZiK exits.
238
+ end
239
+ end
data/gui/preference.rb ADDED
@@ -0,0 +1,496 @@
1
+ # encoding: UTF-8
2
+ =begin
3
+ Copyright 2007-2011 Vincent Carmona
4
+ vinc4mai@gmail.com
5
+
6
+ This file is part of ZiK.
7
+
8
+ ZiK is free software; you can redistribute it and/or modify
9
+ it under the terms of the GNU General Public License as published by
10
+ the Free Software Foundation; either version 2 of the License, or
11
+ (at your option) any later version.
12
+
13
+ ZiK is distributed in the hope that it will be useful,
14
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
15
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16
+ GNU General Public License for more details.
17
+
18
+ You should have received a copy of the GNU General Public License
19
+ along with ZiK; if not, write to the Free Software
20
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
21
+ =end
22
+
23
+ class DirBox < Gtk::Frame
24
+ include Pack
25
+
26
+ def initialize(parent)
27
+ @parent=parent
28
+ @label=Gtk::Label.new
29
+ @label.wrap=true
30
+ @vbox=Gtk::VBox.new
31
+ @badd=Gtk::Button.new
32
+ @badd.image=Gtk::Image.new(Gtk::Stock::ADD,Gtk::IconSize::BUTTON)
33
+ @badd.tooltip_text=_('Add a directory.')
34
+ @badd.signal_connect('clicked'){add_directory_dialog}
35
+ super(_("Directories"))
36
+ border_width=$border
37
+ add(vpack([@label, @vbox, @badd]))
38
+ end
39
+
40
+ def ilabel=(str)
41
+ @label.label=str
42
+ end
43
+
44
+ def add_directory(dir)
45
+ entry=Gtk::Entry.new
46
+ entry.text=dir
47
+ entry.editable=false
48
+ brm=Gtk::Button.new
49
+ brm.image=Gtk::Image.new(Gtk::Stock::REMOVE,Gtk::IconSize::BUTTON)
50
+ brm.tooltip_text=_('Delete this directory.')
51
+ pack=hpack([entry, brm])
52
+ @vbox.pack_start(pack, false)
53
+ pack.show_all
54
+ brm.signal_connect('clicked'){entry.destroy; brm.destroy; pack.destroy}
55
+ end
56
+
57
+ def add_directory_dialog
58
+ dialog=Gtk::FileChooserDialog.new(_("Add a directory"), @parent,
59
+ Gtk::FileChooser::ACTION_SELECT_FOLDER, nil,
60
+ [Gtk::Stock::CANCEL, Gtk::Dialog::RESPONSE_CANCEL],
61
+ [Gtk::Stock::OPEN, Gtk::Dialog::RESPONSE_ACCEPT])
62
+ dialog.show_hidden=false
63
+ dialog.current_folder=ENV['HOME']
64
+ add_directory(dialog.filename) if dialog.run == Gtk::Dialog::RESPONSE_ACCEPT
65
+ dialog.destroy
66
+ end
67
+
68
+ def sdirectory
69
+ res=''
70
+ @vbox.children.each{|child| res+=child.children[0].text+','}
71
+ res
72
+ end
73
+ end
74
+
75
+ class ExtBox < Gtk::Frame
76
+ include Pack
77
+
78
+ def initialize(config)
79
+ @nb=0
80
+ @label=Gtk::Label.new
81
+ @label.wrap=true
82
+ @table=Gtk::Table.new(1,3)
83
+ @table.column_spacings=$border
84
+ @table.row_spacings=$border
85
+ @bdefault=Gtk::Button.new(_('Default'))
86
+ @bdefault.tooltip_text=_('Reset to default.')
87
+ @bdefault.signal_connect('clicked'){
88
+ @table.children.each{|child| child.destroy}
89
+ @nb=0
90
+ config.default['extension'].split(',').each{|ext| add_ext(ext)}
91
+ }
92
+ @badd=Gtk::Button.new
93
+ @badd.image=Gtk::Image.new(Gtk::Stock::ADD,Gtk::IconSize::BUTTON)
94
+ @badd.tooltip_text=_('Add an extension.')
95
+ @badd.signal_connect('clicked'){add_ext}
96
+ super(_("Extensions"))
97
+ border_width=$border
98
+ add(vpack([@label, @table, hpack([@bdefault, @badd])]))
99
+ end
100
+
101
+ def ilabel=(str)
102
+ @label.label=str
103
+ end
104
+
105
+ def add_ext(ext='')
106
+ entry=Gtk::Entry.new
107
+ entry.text=ext
108
+ entry.show
109
+ brm=Gtk::Button.new
110
+ brm.image=Gtk::Image.new(Gtk::Stock::REMOVE,Gtk::IconSize::BUTTON)
111
+ brm.tooltip_text=_('Delete this directory.')
112
+ brm.show
113
+ brm.signal_connect('clicked'){entry.destroy; brm.destroy; @nb-=1; refresh}
114
+ @table.attach(entry, @nb.modulo(3)*3, @nb.modulo(3)*3+1, @nb/3, @nb/3+1, Gtk::SHRINK, Gtk::SHRINK)
115
+ @table.attach(brm, @nb.modulo(3)*3+1, @nb.modulo(3)*3+2, @nb/3, @nb/3+1, Gtk::SHRINK, Gtk::SHRINK)
116
+ @nb+=1
117
+ end
118
+
119
+ def refresh
120
+ exts=[]
121
+ @table.children.reverse.each{|child|
122
+ exts.push(child.text) if child.is_a?(Gtk::Entry)
123
+ child.destroy
124
+ }
125
+ @nb=0
126
+ exts.each{|ext| add_ext(ext) unless ext.empty?}
127
+ end
128
+
129
+ def sext
130
+ res=''
131
+ @table.children.reverse_each{|child| res+=child.text+',' if child.is_a?(Gtk::Entry)}
132
+ res
133
+ end
134
+ end
135
+
136
+ class FormatCombo < Gtk::ComboBox
137
+ def initialize
138
+ super()
139
+ self.append_text(_('None'))
140
+ self.append_text(_('Title'))
141
+ self.append_text(_('Artist'))
142
+ self.append_text(_('Album'))
143
+ self.append_text(_('Track'))
144
+ end
145
+ end
146
+
147
+ class FormatSelector < Gtk::HBox
148
+ def initialize(format)
149
+ @c1=FormatCombo.new
150
+ @c2=FormatCombo.new
151
+ @c3=FormatCombo.new
152
+ @c4=FormatCombo.new
153
+ self.format=format
154
+ super()
155
+ self.spacing=$border
156
+ [@c1, @c2, @c3, @c4].each{|c| self.pack_start(c, false)}
157
+ end
158
+
159
+ def format
160
+ retrieve(@c1)+' - '+retrieve(@c2)+' - '+retrieve(@c3)+' - '+retrieve(@c4)
161
+ end
162
+
163
+ def format=(format)
164
+ f=format.split(' - ')
165
+ select(@c1, f[0]);select(@c2, f[1]);select(@c3, f[2]);select(@c4, f[3])
166
+ end
167
+
168
+ private
169
+
170
+ def retrieve(combo)
171
+ case combo.active
172
+ when 0 then 'None'
173
+ when 1 then 'Title'
174
+ when 2 then 'Artist'
175
+ when 3 then 'Album'
176
+ when 4 then 'Track'
177
+ end
178
+ end
179
+
180
+ def select(combo, string)
181
+ case string
182
+ when 'None' then combo.active=0
183
+ when 'Title' then combo.active=1
184
+ when 'Artist' then combo.active=2
185
+ when 'Album' then combo.active=3
186
+ when 'Track' then combo.active=4
187
+ else
188
+ ErrorError.new("Parsing format (FomatSelector::select).")
189
+ combo.active=0
190
+ end
191
+ end
192
+ end
193
+
194
+ class Preference_window < Gtk::Window
195
+ include Pack
196
+ @@exist=false
197
+
198
+ def Preference_window.show(parent, playlist, config, page=:default, cdlist=nil, cdplayer=nil, cdgui=nil)
199
+ pages={:default=>0, :browse=>0, :playlist=>1, :player=>2, :cd=>3}
200
+ if @@exist
201
+ @@window.hide; @@window.show
202
+ else
203
+ @@window=Preference_window.new(parent,playlist,config, cdlist, cdplayer, cdgui)
204
+ end
205
+ @@window.page=pages[page]
206
+ end
207
+
208
+ def page=(n)
209
+ begin
210
+ @notebook.page=n
211
+ rescue
212
+ @notebook.page=0
213
+ end
214
+ end
215
+
216
+ private
217
+
218
+ def initialize(parent, playlist, config, cdlist, cdplayer, cdgui)
219
+ @@exist=true
220
+
221
+ #*********************Browser page******************************
222
+ #Directories
223
+ @dirbox=DirBox.new(self)
224
+ @dirbox.ilabel=_('List of directories displayed in the browser view.')
225
+ config['directory'].split(',').each{|dir| @dirbox.add_directory(dir)}
226
+
227
+ #Extensions
228
+ @extbox=ExtBox.new(config)
229
+ @extbox.ilabel=_('Only files with the given extension are displayed in the browser view. Extensions must be separate by a comma (,).')
230
+ config['extension'].split(',').each{|ext| @extbox.add_ext(ext)}
231
+
232
+ #Refresh on start
233
+ @brefresh=Gtk::CheckButton.new(_('Refresh browser view on start'))
234
+ @brefresh.active=config['refresh_on_start']
235
+ @refresh_label=Gtk::Label.new(_('Uncheck to use previous view (faster).'))
236
+ @refresh_label.wrap=true
237
+ @refresh_frame=Gtk::Frame.new
238
+ @refresh_frame.border_width=$border
239
+ @refresh_frame.add(vpack([@brefresh, @refresh_label]))
240
+
241
+ #Sort
242
+ @bsortdir=Gtk::CheckButton.new(_('Directories before files'))
243
+ @bsortdir.active=config['sort_directories_first']
244
+ @bsortcase=Gtk::CheckButton.new(_('Case sensitive'))
245
+ @bsortcase.active=config['sort_case_sensitive']
246
+ @sort_frame=Gtk::Frame.new(_('Sort options'))
247
+ @sort_frame.border_width=$border
248
+ @sort_frame.add(vpack([@bsortdir, @bsortcase]))
249
+
250
+ #Search
251
+ @bpath=Gtk::CheckButton.new(_('Path'))
252
+ @bpath.active=config['search_in_path']
253
+ @btitle=Gtk::CheckButton.new(_('Title'))
254
+ @btitle.active=config['search_in_title']
255
+ @bartist=Gtk::CheckButton.new(_('Artist'))
256
+ @bartist.active=config['search_in_artist']
257
+ @balbum=Gtk::CheckButton.new(_('Album'))
258
+ @balbum.active=config['search_in_album']
259
+ @bgenre=Gtk::CheckButton.new(_('Genre'))
260
+ @bgenre.active=config['search_in_genre']
261
+ @search_label=Gtk::Label.new(_('Check entries used for search. Use only path for speed.'))
262
+ @search_label.wrap=true
263
+ @search_table=Gtk::Table.new(4, 2)
264
+ @search_table.border_width=$border
265
+ @search_table.column_spacings=$border
266
+ @search_table.row_spacings=$border
267
+ @search_table.attach(@bpath, 0, 1, 0, 1, Gtk::FILL, Gtk::FILL)
268
+ @search_table.attach(@btitle, 0, 1, 1, 2, Gtk::FILL, Gtk::FILL)
269
+ @search_table.attach(@bartist, 1, 2, 1, 2, Gtk::FILL, Gtk::FILL)
270
+ @search_table.attach(@balbum, 0, 1, 2, 3, Gtk::FILL, Gtk::FILL)
271
+ @search_table.attach(@bgenre, 1, 2, 2, 3, Gtk::FILL, Gtk::FILL)
272
+ @search_table.attach(@search_label, 0, 2, 3, 4, Gtk::FILL, Gtk::FILL)
273
+ @search_frame=Gtk::Frame.new(_('Search'))
274
+ @search_frame.add(@search_table)
275
+
276
+ #Main box
277
+ @browser_box=vpack([@dirbox, @extbox, @refresh_frame, @sort_frame, @search_frame])
278
+ @wbrowser=Gtk::ScrolledWindow.new
279
+ @wbrowser.set_policy(Gtk::POLICY_AUTOMATIC,Gtk::POLICY_AUTOMATIC)
280
+ @wbrowser.add_with_viewport(@browser_box)
281
+
282
+ #*********************Playlist page*****************************
283
+ #session
284
+ @bsocket1=Gtk::RadioButton.new(_("Single"))
285
+ @bsocket2=Gtk::RadioButton.new(@bsocket1, _("Multi"))
286
+ config['socket'] ? @bsocket2.active=true : @bsocket1.active=true
287
+
288
+ @socket_frame=Gtk::Frame.new(_("Session"))
289
+ @socket_frame.border_width=$border
290
+ @socket_frame.add(hpack([@bsocket1, @bsocket2]))
291
+ #format
292
+ @format_selector=FormatSelector.new(config['name_format'])
293
+ @format_label=Gtk::Label.new(_('Format used to display songs\' name. Set all to None if you want to use file name.'))
294
+ @format_label.wrap=true
295
+ @format_frame=Gtk::Frame.new(_('Format'))
296
+ @format_frame.border_width=$border
297
+ @format_frame.add(vpack([@format_selector, @format_label]))
298
+ #color
299
+ @color_default=Gtk::Button.new(_('Default'))
300
+ @color_default.tooltip_text=_('Reset to default.')
301
+ @color_default.signal_connect('clicked'){@color_entry.text=config.default['playing_color']}
302
+ @color_entry=Gtk::Entry.new
303
+ @color_entry.text=config['playing_color']
304
+ @bcolor=Gtk::ColorButton.new(Gdk::Color.parse(config['playing_color']))
305
+ @bcolor.tooltip_text=_('Select a color.')
306
+ @bcolor.signal_connect('color-set'){@color_entry.text=@bcolor.color.to_s}
307
+ @color_label=Gtk::Label.new(_('Color used to highlight the current song.'))
308
+ @color_label.wrap=true
309
+ @color_frame=Gtk::Frame.new(_('Color'))
310
+ @color_frame.border_width=$border
311
+ @color_frame.add(vpack([hpack([@color_default, @color_entry, @bcolor]), @color_label]))
312
+ #compact
313
+ @bcompact=Gtk::CheckButton.new(_('Compact view'))
314
+ @bcompact.active=config['compact']
315
+ @compact_label=Gtk::Label.new(_('Show more tracks in playlist.'))
316
+ @compact_label.wrap=true
317
+ @compact_frame=Gtk::Frame.new(_('Compact view'))
318
+ @compact_frame.border_width=$border
319
+ @compact_frame.add(vpack([@bcompact, @compact_label]))
320
+ #sort
321
+ @bsorttrack=Gtk::CheckButton.new(_('Sort by track'))
322
+ @bsorttrack.active=config['sort_by_track']
323
+ @sort2_label=Gtk::Label.new(_('Try to sort files by track numbers when adding a directory.'))
324
+ @sort2_label.wrap=true
325
+ @sort2_frame=Gtk::Frame.new(_('Sort options'))
326
+ @sort2_frame.border_width=$border
327
+ @sort2_frame.add(vpack([@bsorttrack, @sort2_label]))
328
+ #relative
329
+ @brelative=Gtk::CheckButton.new(_('Relative paths'))
330
+ @brelative.active=config['relative_playlist']
331
+ @relative_label=Gtk::Label.new(_('Use relative paths when saving playlist.'))
332
+ @relative_label.wrap=true
333
+ @relative_frame=Gtk::Frame.new(_('Relative path'))
334
+ @relative_frame.border_width=$border
335
+ @relative_frame.add(vpack([@brelative, @relative_label]))
336
+
337
+ #main
338
+ @playlist_box=vpack([@socket_frame, @format_frame, @color_frame, @compact_frame,
339
+ @sort2_frame, @relative_frame])
340
+
341
+ #*********************Player page*******************************
342
+ @bplay=Gtk::CheckButton.new(_('Play on start'))
343
+ @bplay.image=Gtk::Image.new(Gtk::Stock::MEDIA_PLAY, Gtk::IconSize::BUTTON)
344
+ @bplay.active=config['play_on_start']
345
+
346
+ @bshuffle=Gtk::CheckButton.new(_('Shuffle'))
347
+ @bshuffle.image=Gtk::Image.new('media-playlist-shuffle', Gtk::IconSize::BUTTON)
348
+ @bshuffle.active=config['shuffle']
349
+
350
+ @brepeat=Gtk::CheckButton.new(_('Repeat'))
351
+ @brepeat.image=Gtk::Image.new('media-playlist-repeat', Gtk::IconSize::BUTTON)
352
+ @brepeat.active=config['repeat']
353
+
354
+ @player_box=vpack([@bplay, @bshuffle, @brepeat])
355
+
356
+ #*********************cd page***********************************
357
+ @device_default=Gtk::Button.new(_('Default'))
358
+ @device_default.tooltip_text=_('Reset to default.')
359
+ @device_default.signal_connect('clicked'){@device_entry.text=config.default['cd_device']}
360
+ @device_entry=Gtk::Entry.new
361
+ @device_entry.text=config['cd_device']
362
+ @device_frame=Gtk::Frame.new(_('Device'))
363
+ @device_frame.border_width=$border
364
+ @device_frame.add(vpack([hpack([@device_default, @device_entry])]))
365
+
366
+ @bweb=Gtk::CheckButton.new(_('Search for the songs'' title on the web.'))
367
+ @bweb.image=Gtk::Image.new(Gtk::Stock::NETWORK, Gtk::IconSize::BUTTON)
368
+ @bweb.active=config['cd_web']
369
+
370
+ @cd_box=vpack([@device_frame, @bweb])
371
+
372
+ #*********************Module page******************************
373
+ if $module
374
+ @module_frames=[]
375
+ @module_hbuttons={}
376
+ Mod.all.each{|m|
377
+ button=Gtk::CheckButton.new(m.title)
378
+ button.active=m.loaded?
379
+ @module_hbuttons[m.id]=button#Store check button
380
+ label=Gtk::Label.new(m.description)
381
+ label.wrap=true
382
+ widget=m.configwidget
383
+ frame=Gtk::Frame.new
384
+ frame.border_width=$border
385
+ @module_frames.push(frame)
386
+ if widget
387
+ expander=Gtk::Expander.new(_("Configuration"))
388
+ expander.spacing=$border
389
+ expander.add(widget)
390
+ frame.add(vpack([button, label, expander]))
391
+ else
392
+ frame.add(vpack([button, label]))
393
+ end
394
+ }
395
+ @module_box=vpack(@module_frames)
396
+ @wmodule=Gtk::ScrolledWindow.new
397
+ @wmodule.set_policy(Gtk::POLICY_AUTOMATIC,Gtk::POLICY_AUTOMATIC)
398
+ @wmodule.add_with_viewport(@module_box)
399
+ end
400
+
401
+ #*********************Main window*******************************
402
+ @notebook=Gtk::Notebook.new
403
+ @notebook.tab_pos=Gtk::POS_LEFT
404
+ @notebook.append_page(@wbrowser, Gtk::Label.new(_('Browser')))
405
+ @notebook.append_page(@playlist_box, Gtk::Label.new(_('Playlist')))
406
+ @notebook.append_page(@player_box, Gtk::Label.new(_('Player')))
407
+ @notebook.append_page(@cd_box, Gtk::Label.new(_('Cd')))
408
+ @notebook.append_page(@wmodule, Gtk::Label.new(_('Modules'))) if $module
409
+
410
+ @bcancel=Gtk::Button.new(Gtk::Stock::CANCEL)
411
+ @bcancel.signal_connect('clicked'){quit}
412
+ @bok=Gtk::Button.new(Gtk::Stock::OK)
413
+ @bok.signal_connect('clicked'){
414
+ oldconfig={}; oldconfig.merge!(config)
415
+ config.merge!({'directory'=>@dirbox.sdirectory, 'extension'=>@extbox.sext,
416
+ 'sort_directories_first'=>@bsortdir.active?, 'sort_case_sensitive'=>@bsortcase.active?, 'refresh_on_start'=>@brefresh.active?,
417
+ 'search_in_path'=>@bpath.active?, 'search_in_title'=>@btitle.active?,
418
+ 'search_in_artist'=>@bartist.active?, 'search_in_album'=>@balbum.active?, 'search_in_genre'=>@bgenre.active?,
419
+ 'socket'=>@bsocket2.active?,
420
+ 'name_format'=>@format_selector.format, 'relative_playlist'=>@brelative.active?,
421
+ 'compact'=>@bcompact.active?,
422
+ 'sort_by_track'=>@bsorttrack.active?, 'playing_color'=>@color_entry.text,
423
+ 'play_on_start'=>@bplay.active?, 'shuffle'=>@bshuffle.active?, 'repeat'=>@brepeat.active?,
424
+ 'cd_device'=>@device_entry.text, 'cd_web'=>@bweb.active?})
425
+ if $module
426
+ config['module']=''
427
+ @module_hbuttons.each_pair{|key, value| config['module']+=key+',' if value.active?}
428
+ end
429
+ begin
430
+ Gdk::Color.parse(config['playing_color'])
431
+ rescue
432
+ ErrorError.new("#{config['playing_color']} is not a color. Restore previous color.")
433
+ config['playing_color']=oldconfig['playing_color']
434
+ end
435
+ unless oldconfig['name_format']==config['name_format']
436
+ playlist.songs.each{|song| song.refresh_name(config['name_format'])}
437
+ parent.refresh_liststore
438
+ end
439
+ parent.compact(config['compact']) unless oldconfig['compact']==config['compact']
440
+ playlist.sort_by_track=config['sort_by_track']
441
+ noc=(oldconfig['directory']==config['directory'] and oldconfig['extension']==config['extension'] and
442
+ oldconfig['sort_directories_first']==config['sort_directories_first'] and
443
+ oldconfig['sort_case_sensitive']==config['sort_case_sensitive'])
444
+ unless noc
445
+ parent.refresh_treestore(config['directory'],config['extension'])
446
+ end
447
+ unless config['playing_color']==oldconfig['playing_color']
448
+ parent.renderer2.background=config['playing_color']
449
+ cdgui.renderer.background=config['playing_color'] if $cd
450
+ end
451
+ parent.shuffle=config['shuffle']
452
+ parent.repeat=config['repeat']
453
+ if $cd
454
+ cdlist.web=config['cd_web']
455
+ unless oldconfig['cd_device']==config['cd_device']
456
+ cdplayer.device=config['cd_device']
457
+ cdlist.device=config['cd_device']
458
+ cdlist.refresh
459
+ cdgui.refresh_store
460
+ end
461
+ end
462
+ if $module
463
+ Mod.all.each{|mod| mod.saveconfig}
464
+ Mod.all.each{|mod|
465
+ config['module'].split(',').include?(mod.id) ? mod.load : mod.unload
466
+ ModErrorLoadError.show_all
467
+ } unless config['module']==oldconfig['module']
468
+ end
469
+ quit
470
+ }
471
+ @hbox=Gtk::HBox.new
472
+ [@bcancel, @bok].reverse.each{|button| @hbox.pack_end(button,false)}
473
+
474
+ @vbox=Gtk::VBox.new
475
+ @vbox.pack_start(@notebook)
476
+ @vbox.pack_start(@hbox,false)
477
+
478
+ super(Gtk::Window::TOPLEVEL)
479
+ self.transient_for=parent
480
+ self.skip_taskbar_hint=true
481
+ self.skip_pager_hint=true
482
+ self.title=_('Preferences')
483
+ self.icon=Gdk::Pixbuf.new(File.join(Pix_dir,'ZiK.svg'))
484
+
485
+ self.signal_connect("delete_event") {quit;true}
486
+
487
+ self.add(@vbox)
488
+
489
+ self.show_all
490
+ end
491
+
492
+ def quit
493
+ @@exist=false
494
+ self.destroy
495
+ end
496
+ end