zik 0.16.1

Sign up to get free protection for your applications and to get access to all the features.
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