1 # -*- coding: utf-8 -*-
3 # gPodder - A media aggregator and podcast client
4 # Copyright (c) 2005-2011 Thomas Perl and the gPodder Team
6 # gPodder is free software; you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License as published by
8 # the Free Software Foundation; either version 3 of the License, or
9 # (at your option) any later version.
11 # gPodder is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 # GNU General Public License for more details.
16 # You should have received a copy of the GNU General Public License
17 # along with this program. If not, see <http://www.gnu.org/licenses/>.
30 logger
= logging
.getLogger(__name__
)
32 from gpodder
.gtkui
.interface
.common
import BuilderWidget
35 class ExtensionTextItem(gtk
.VBox
):
36 def __init__(self
, key
, settings
, value
):
37 gtk
.VBox
.__init
__(self
, spacing
=6)
38 self
.set_border_width(6)
41 self
.__label
= gtk
.Label(settings
['desc'])
42 self
.__label
.set_alignment(0, 0)
44 self
.__entry
= gtk
.Entry(max=0)
45 self
.__entry
.set_visibility(True)
46 self
.__entry
.set_editable(True)
47 self
.__entry
.set_text(value
)
48 self
.pack_start(self
.__label
, False, False, 0)
49 self
.pack_start(self
.__entry
, False, False, 0)
55 return self
.__entry
.get_text()
57 def set_value(self
, settings
, value
):
58 self
.__entry
.set_text(value
)
61 class ExtensionCheckBox(gtk
.CheckButton
):
62 def __init__(self
, key
, settings
, value
):
63 gtk
.CheckButton
.__init
__(self
)
64 self
.set_border_width(6)
67 self
.set_label(settings
['desc'])
68 self
.set_active(value
)
74 return self
.get_active()
76 def set_value(self
, settings
, value
):
77 self
.set_active(value
)
80 class ExtensionSpinButton(gtk
.VBox
):
81 def __init__(self
, key
, settings
, value
):
82 gtk
.VBox
.__init
__(self
, spacing
=6)
83 self
.set_border_width(6)
86 self
.__label
= gtk
.Label(settings
['desc'])
87 self
.__label
.set_alignment(0, 0)
89 self
.__spin
= gtk
.SpinButton(
90 adjustment
=gtk
.Adjustment(value
, 0, 1000, 1),
91 climb_rate
=1, digits
=2
94 self
.pack_start(self
.__label
, False, False, 0)
95 self
.pack_start(self
.__spin
, False, False, 0)
101 return self
.__spin
.get_value()
103 def set_value(self
, settings
, value
):
104 self
.__spin
.set_value(value
)
107 class ExtensionMultiChoice(gtk
.VBox
):
108 def __init__(self
, key
, settings
, value
):
109 gtk
.VBox
.__init
__(self
, spacing
=6)
110 self
.set_border_width(6)
113 self
.__label
= gtk
.Label(settings
['desc'])
114 self
.__label
.set_alignment(0, 0)
116 self
.__treeView
= gtk
.TreeView(self
._get
_model
(settings
, value
))
118 toggle_cell
= gtk
.CellRendererToggle()
119 toggle_cell
.connect('toggled', self
.value_changed
, self
.__treeView
)
120 toggle_column
= gtk
.TreeViewColumn('', toggle_cell
, active
=0)
121 toggle_column
.set_clickable(True)
122 self
.__treeView
.append_column(toggle_column
)
124 renderer
= gtk
.CellRendererText()
125 renderer
.set_property('ellipsize', pango
.ELLIPSIZE_END
)
126 column
= gtk
.TreeViewColumn(_('Podcast'), renderer
, markup
=1)
127 column
.set_clickable(False)
128 column
.set_resizable(True)
129 column
.set_expand(True)
130 self
.__treeView
.append_column(column
)
131 self
.__treeView
.columns_autosize()
133 self
.pack_start(self
.__label
, False, False, 0)
134 self
.pack_start(self
.__treeView
, False, False, 0)
136 def _get_model(self
, settings
, value
):
137 model
= gtk
.ListStore(bool, str, int)
138 multichoice_list
= zip(value
, settings
['list'])
139 for index
, (state
, text
) in enumerate(multichoice_list
):
140 model
.append(row
=(state
, text
, index
))
143 def value_changed(self
, cell
, path
, treeview
):
144 model
= treeview
.get_model()
145 iter = model
.get_iter(path
)
146 value
= model
.get_value(iter, 0)
147 model
.set_value(iter, 0, not value
)
153 model
= self
.__treeView
.get_model()
155 iter = model
.get_iter_first()
156 while iter is not None:
157 value
= model
.get_value(iter, 0)
159 iter = model
.iter_next(iter)
162 def set_value(self
, settings
, value
):
163 model
= self
._get
_model
(settings
, value
)
164 self
.__treeView
.set_model(model
)
167 class ExtensionRadioGroup(gtk
.VBox
):
168 def __init__(self
, key
, settings
, value
):
169 gtk
.VBox
.__init
__(self
, spacing
=6)
170 self
.set_border_width(6)
173 self
.__label
= gtk
.Label(settings
['desc'])
174 self
.__label
.set_alignment(0, 0)
176 self
.__radioButtons
= []
177 choices
= zip(value
, settings
['list'])
179 for state
, label
in choices
:
180 rb
= gtk
.RadioButton(group
, label
, False)
183 self
.__radioButtons
.append(rb
)
185 self
.pack_start(self
.__label
, False, False, 0)
186 for rb
in self
.__radioButtons
:
187 self
.pack_start(rb
, False, False, 0)
194 for rb
in self
.__radioButtons
:
195 values
.append(rb
.get_active())
198 def set_value(self
, settings
, value
):
199 choices
= zip(value
, self
.__radioButtons
)
200 for state
, rb
in choices
:
204 #TODO: Replace this implementation with a ComboBoxEntry or expandable TreeView
205 class ExtensionComboBoxEntry(ExtensionTextItem
):
206 def __init__(self
, key
, settings
, value
):
207 value
= ';'.join(value
)
208 ExtensionTextItem
.__init
__(self
, key
, settings
, value
)
211 value
= super(ExtensionComboBoxEntry
, self
).get_value()
212 return value
.split(';')
214 def set_value(self
, settings
, value
):
215 value
= ';'.join(value
)
216 super(ExtensionComboBoxEntry
, self
).set_value(settings
, value
)
219 class gPodderExtensionPreference(BuilderWidget
):
220 widgets
= { 'textitem': ExtensionTextItem
,
221 'checkbox': ExtensionCheckBox
,
222 'spinbutton': ExtensionSpinButton
,
223 'multichoice-list': ExtensionMultiChoice
,
224 'combobox': ExtensionComboBoxEntry
,
225 'radiogroup': ExtensionRadioGroup
,
229 """Extension Preference Dialog
231 Optional keyword arguments that modify the behaviour of this dialog:
233 - _extenstion_container: ExtensionContainer class for which the preferences should be displayed
236 'desc': 'Defines the command line bittorrent program'}
239 self
.params
= self
._extension
_container
.params
240 self
.config
= self
._extension
_container
.config
242 self
.vbox
= gtk
.VBox()
243 self
.viewport_extensionpref
.add(self
.vbox
)
244 for key
, settings
in self
.params
.items():
245 value
= getattr(self
._extension
_container
.config
, key
)
246 widget
= self
.widgets
[settings
['type']](key
, settings
, value
)
247 self
.vbox
.pack_start(widget
, False, False, 0)
249 self
.gPodderExtensionPreference
.show_all()
251 def on_btnRevert_clicked(self
, widget
):
252 self
._extension
_container
.revert_settings()
253 self
.config
= self
._extension
_container
.config
255 for w
in self
.vbox
.get_children():
257 value
= getattr(self
._extension
_container
.config
, key
)
258 w
.set_value(self
.params
[key
], value
)
260 def on_btnClose_clicked(self
, widget
):
261 for w
in self
.vbox
.get_children():
263 value
= w
.get_value()
264 setattr(self
._extension
_container
.config
, key
, value
)
266 self
.main_window
.destroy()
269 class gPodderExtensionManager(BuilderWidget
):
270 C_INDEX
, C_TOOLTIP
, C_TOGGLE
, C_NAME
, C_ID
, C_EXTENSIONCONTAINER
= range(6)
273 toggle_cell
= gtk
.CellRendererToggle()
274 toggle_cell
.connect('toggled', self
.toggle_cell_handler
)
275 toggle_column
= gtk
.TreeViewColumn('', toggle_cell
, active
=self
.C_TOGGLE
)
276 toggle_column
.set_clickable(True)
277 self
.treeviewExtensions
.append_column(toggle_column
)
279 renderer
= gtk
.CellRendererText()
280 renderer
.set_property('ellipsize', pango
.ELLIPSIZE_END
)
281 column
= gtk
.TreeViewColumn(_('Name'), renderer
, markup
=self
.C_NAME
)
282 column
.set_clickable(False)
283 column
.set_resizable(True)
284 column
.set_expand(True)
285 self
.treeviewExtensions
.append_column(column
)
287 renderer
= gtk
.CellRendererText()
288 column
= gtk
.TreeViewColumn(_('Extension-ID'), renderer
, markup
=self
.C_ID
)
289 column
.set_clickable(False)
290 column
.set_resizable(True)
291 column
.set_expand(False)
292 self
.treeviewExtensions
.append_column(column
)
294 self
.treeviewExtensions
.set_property('has-tooltip', True)
295 self
.treeviewExtensions
.connect('query-tooltip', self
.treeview_show_tooltip
)
297 column_types
= [ int, str, bool, str, str, object ]
298 self
.model
= gtk
.ListStore(*column_types
)
300 for index
, (extension_container
, state
) in enumerate( gpodder
.user_extensions
.get_extensions() ):
301 if extension_container
.metadata
:
302 tooltip
= extension_container
.metadata
['desc']
303 name
= extension_container
.metadata
['name']
304 row
= [ index
, tooltip
, state
, name
,
305 extension_container
.metadata
['id'], extension_container
307 self
.model
.append(row
)
309 self
.model
.set_sort_column_id(self
.C_NAME
, gtk
.SORT_ASCENDING
)
310 self
.treeviewExtensions
.set_model(self
.model
)
311 self
.treeviewExtensions
.columns_autosize()
313 self
.context_id
= self
.extension_statusbar
.get_context_id('Extension messages')
315 def _set_enabled_extension_in_config(self
, model
, path
):
316 iter = model
.get_iter(path
)
317 value
= model
.get_value(iter, self
.C_TOGGLE
)
318 name
= model
.get_value(iter, self
.C_NAME
)
319 extension_id
= model
.get_value(iter, self
.C_ID
)
320 extension_container
= model
.get_value(iter, self
.C_EXTENSIONCONTAINER
)
321 new_value
= not value
323 if new_value
and extension_id
not in self
._config
.extensions
.enabled
:
325 extension_container
.load_extension()
327 self
.extension_statusbar
.push(self
.context_id
, "Error %s: %s" % (name
, e
))
330 self
._config
.extensions
.enabled
.append(extension_id
)
331 self
.extension_statusbar
.remove_all(self
.context_id
)
333 if not new_value
and extension_id
in self
._config
.extensions
.enabled
:
334 self
._config
.extensions
.enabled
.remove(extension_id
)
336 self
._config
.schedule_save()
337 self
._set
_preferences
_button
(not value
)
338 model
.set_value(iter, self
.C_TOGGLE
, not value
)
340 def _get_selected_extension_container(self
):
341 selection
= self
.treeviewExtensions
.get_selection()
342 model
, iter = selection
.get_selected()
346 return model
.get_value(iter, self
.C_EXTENSIONCONTAINER
)
348 def _set_preferences_button(self
, value
):
349 extension
= self
._get
_selected
_extension
_container
()
351 if extension
and extension
.params
is not None and value
:
352 self
.btnExtensionPrefs
.set_sensitive(True)
354 self
.btnExtensionPrefs
.set_sensitive(False)
356 def on_button_close_clicked(self
, widget
):
357 # sync enabled/disabled extensions
358 gpodder
.user_extensions
.get_extensions()
360 # close extension preference window
361 self
.main_window
.destroy()
363 def on_btnOK_clicked(self
, widget
):
364 self
.on_button_close_clicked(widget
)
366 def on_btnExtensionPrefs_clicked(self
, widget
):
367 gPodderExtensionPreference(self
.main_window
,
368 _extension_container
= self
._get
_selected
_extension
_container
()
371 def toggle_cell_handler(self
, cell
, path
):
372 model
= self
.treeviewExtensions
.get_model()
373 self
._set
_enabled
_extension
_in
_config
(model
, path
)
375 def on_row_activated(self
, treeview
, path
, view_column
):
376 model
= treeview
.get_model()
377 self
._set
_enabled
_extension
_in
_config
(model
, path
)
379 def on_selection_changed(self
, treeselection
):
380 model
, iter = treeselection
.get_selected()
384 value
= model
.get_value(iter, self
.C_TOGGLE
)
386 self
._set
_preferences
_button
(value
)
388 def treeview_show_tooltip(self
, treeview
, x
, y
, keyboard_tooltip
, tooltip
):
389 # TODO: Copied some of the code from src/gpodder/gtkui/desktop/episodeselector.py (gPodderEpisodeSelector.treeview_episodes_query_tooltip)
390 # maybe we should don't duplicate the code and implement this as a function globaly?!
392 # With get_bin_window, we get the window that contains the rows without
393 # the header. The Y coordinate of this window will be the height of the
394 # treeview header. This is the amount we have to subtract from the
395 # event's Y coordinate to get the coordinate to pass to get_path_at_pos
396 (x_bin
, y_bin
) = treeview
.get_bin_window().get_position()
399 (path
, column
, rx
, ry
) = treeview
.get_path_at_pos(x
, y
) or (None,)*4
401 if column
!= treeview
.get_columns()[1]:
404 model
= treeview
.get_model()
405 iter = model
.get_iter(path
)
406 description
= model
.get_value(iter, self
.C_TOOLTIP
)
408 tooltip
.set_text(description
)