2009-08-24 19:31:58 +02:00
|
|
|
# -*- coding: utf-8 -*-
|
|
|
|
#
|
|
|
|
# gPodder - A media aggregator and podcast client
|
2010-01-02 17:35:42 +01:00
|
|
|
# Copyright (c) 2005-2010 Thomas Perl and the gPodder Team
|
2009-08-24 19:31:58 +02:00
|
|
|
#
|
|
|
|
# gPodder is free software; you can redistribute it and/or modify
|
|
|
|
# it under the terms of the GNU General Public License as published by
|
|
|
|
# the Free Software Foundation; either version 3 of the License, or
|
|
|
|
# (at your option) any later version.
|
|
|
|
#
|
|
|
|
# gPodder is distributed in the hope that it will be useful,
|
|
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
# GNU General Public License for more details.
|
|
|
|
#
|
|
|
|
# You should have received a copy of the GNU General Public License
|
|
|
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
#
|
|
|
|
|
|
|
|
import gtk
|
2010-03-02 01:36:23 +01:00
|
|
|
import pango
|
2010-05-03 21:16:13 +02:00
|
|
|
import threading
|
2009-08-24 19:31:58 +02:00
|
|
|
|
|
|
|
import gpodder
|
|
|
|
|
|
|
|
_ = gpodder.gettext
|
2010-03-02 01:36:23 +01:00
|
|
|
N_ = gpodder.ngettext
|
|
|
|
|
|
|
|
from gpodder import util
|
2009-08-24 19:31:58 +02:00
|
|
|
|
|
|
|
from gpodder.gtkui.interface.common import BuilderWidget
|
|
|
|
from gpodder.gtkui.interface.configeditor import gPodderConfigEditor
|
|
|
|
|
2010-03-02 01:36:23 +01:00
|
|
|
from gpodder.gtkui.desktopfile import PlayerListModel
|
|
|
|
|
|
|
|
class NewEpisodeActionList(gtk.ListStore):
|
|
|
|
C_CAPTION, C_AUTO_DOWNLOAD, C_HIDE_DIALOG = range(3)
|
|
|
|
|
|
|
|
ACTION_NONE, ACTION_ASK, ACTION_MINIMIZED, ACTION_ALWAYS = range(4)
|
|
|
|
|
|
|
|
def __init__(self, config):
|
|
|
|
gtk.ListStore.__init__(self, str, str, bool)
|
|
|
|
self._config = config
|
|
|
|
self.append((_('Do nothing'), 'never', True))
|
|
|
|
self.append((_('Show episode list'), 'never', False))
|
|
|
|
self.append((_('Add to download list'), 'queue', False))
|
|
|
|
self.append((_('Download if minimized'), 'minimized', False))
|
|
|
|
self.append((_('Download immediately'), 'always', False))
|
|
|
|
|
|
|
|
def get_index(self):
|
|
|
|
if self._config.do_not_show_new_episodes_dialog:
|
|
|
|
return 0
|
|
|
|
else:
|
|
|
|
for index, row in enumerate(self):
|
|
|
|
if row[self.C_HIDE_DIALOG]:
|
|
|
|
continue
|
|
|
|
|
|
|
|
if self._config.auto_download == \
|
|
|
|
row[self.C_AUTO_DOWNLOAD]:
|
|
|
|
return index
|
|
|
|
|
|
|
|
return 1 # Some sane default
|
|
|
|
|
|
|
|
def set_index(self, index):
|
|
|
|
self._config.do_not_show_new_episodes_dialog = self[index][self.C_HIDE_DIALOG]
|
|
|
|
self._config.auto_download = self[index][self.C_AUTO_DOWNLOAD]
|
|
|
|
|
|
|
|
|
2010-06-05 15:57:28 +02:00
|
|
|
class DeviceTypeActionList(gtk.ListStore):
|
|
|
|
C_CAPTION, C_DEVICE_TYPE = range(2)
|
|
|
|
ACTION_NONE, ACTION_ASK, ACTION_MINIMIZED, ACTION_ALWAYS = range(4)
|
|
|
|
|
|
|
|
def __init__(self, config):
|
|
|
|
gtk.ListStore.__init__(self, str, str)
|
|
|
|
self._config = config
|
|
|
|
self.append((_('None'), 'none'))
|
2010-06-30 03:31:49 +02:00
|
|
|
self.append((_('iPod'), 'ipod'))
|
|
|
|
self.append((_('Filesystem-based'), 'filesystem'))
|
|
|
|
self.append((_('MTP'), 'mtp'))
|
2010-06-05 15:57:28 +02:00
|
|
|
|
|
|
|
def get_index(self):
|
|
|
|
for index, row in enumerate(self):
|
|
|
|
if self._config.device_type == row[self.C_DEVICE_TYPE]:
|
|
|
|
return index
|
|
|
|
return 0 # Some sane default
|
|
|
|
|
|
|
|
def set_index(self, index):
|
|
|
|
self._config.device_type = self[index][self.C_DEVICE_TYPE]
|
|
|
|
|
|
|
|
class OnSyncActionList(gtk.ListStore):
|
|
|
|
C_CAPTION, C_ON_SYNC_DELETE, C_ON_SYNC_MARK_PLAYED = range(3)
|
|
|
|
ACTION_NONE, ACTION_ASK, ACTION_MINIMIZED, ACTION_ALWAYS = range(4)
|
|
|
|
|
|
|
|
def __init__(self, config):
|
|
|
|
gtk.ListStore.__init__(self, str, bool, bool)
|
|
|
|
self._config = config
|
|
|
|
self.append((_('Do nothing'), False, False))
|
|
|
|
self.append((_('Mark it as played'), False, True))
|
|
|
|
self.append((_('Delete it from gPodder'), True, False))
|
|
|
|
|
|
|
|
def get_index(self):
|
|
|
|
for index, row in enumerate(self):
|
|
|
|
if self._config.on_sync_delete and row[self.C_ON_SYNC_DELETE]:
|
|
|
|
return index
|
|
|
|
if self._config.on_sync_mark_played and row[self.C_ON_SYNC_MARK_PLAYED] \
|
|
|
|
and not self._config.on_sync_delete:
|
|
|
|
return index
|
|
|
|
return 0 # Some sane default
|
|
|
|
|
|
|
|
def set_index(self, index):
|
|
|
|
self._config.on_sync_delete = self[index][self.C_ON_SYNC_DELETE]
|
|
|
|
self._config.on_sync_mark_played = self[index][self.C_ON_SYNC_MARK_PLAYED]
|
|
|
|
|
|
|
|
|
2009-08-24 19:31:58 +02:00
|
|
|
class gPodderPreferences(BuilderWidget):
|
|
|
|
def new(self):
|
2010-03-02 01:36:23 +01:00
|
|
|
if not hasattr(self, 'callback_finished'):
|
2009-08-24 19:31:58 +02:00
|
|
|
self.callback_finished = None
|
|
|
|
|
2010-03-02 01:36:23 +01:00
|
|
|
for cb in (self.combo_audio_player_app, self.combo_video_player_app):
|
|
|
|
cellrenderer = gtk.CellRendererPixbuf()
|
|
|
|
cb.pack_start(cellrenderer, False)
|
|
|
|
cb.add_attribute(cellrenderer, 'pixbuf', PlayerListModel.C_ICON)
|
|
|
|
cellrenderer = gtk.CellRendererText()
|
|
|
|
cellrenderer.set_property('ellipsize', pango.ELLIPSIZE_END)
|
|
|
|
cb.pack_start(cellrenderer, True)
|
|
|
|
cb.add_attribute(cellrenderer, 'markup', PlayerListModel.C_NAME)
|
|
|
|
cb.set_row_separator_func(PlayerListModel.is_separator)
|
|
|
|
|
|
|
|
self.audio_player_model = self.user_apps_reader.get_model('audio')
|
|
|
|
self.combo_audio_player_app.set_model(self.audio_player_model)
|
|
|
|
index = self.audio_player_model.get_index(self._config.player)
|
|
|
|
self.combo_audio_player_app.set_active(index)
|
|
|
|
|
|
|
|
self.video_player_model = self.user_apps_reader.get_model('video')
|
|
|
|
self.combo_video_player_app.set_model(self.video_player_model)
|
|
|
|
index = self.video_player_model.get_index(self._config.videoplayer)
|
|
|
|
self.combo_video_player_app.set_active(index)
|
|
|
|
|
|
|
|
self._config.connect_gtk_togglebutton('enable_notifications', self.checkbutton_enable_notifications)
|
|
|
|
self._config.connect_gtk_togglebutton('display_tray_icon', self.checkbutton_show_tray_icon)
|
|
|
|
|
|
|
|
self.update_interval_presets = [0, 10, 30, 60, 2*60, 6*60, 12*60]
|
|
|
|
adjustment_update_interval = self.hscale_update_interval.get_adjustment()
|
2010-09-27 00:27:01 +02:00
|
|
|
adjustment_update_interval.upper = len(self.update_interval_presets)-1
|
2010-03-02 01:36:23 +01:00
|
|
|
if self._config.auto_update_frequency in self.update_interval_presets:
|
|
|
|
index = self.update_interval_presets.index(self._config.auto_update_frequency)
|
|
|
|
self.hscale_update_interval.set_value(index)
|
|
|
|
else:
|
|
|
|
# Patch in the current "custom" value into the mix
|
|
|
|
self.update_interval_presets.append(self._config.auto_update_frequency)
|
|
|
|
self.update_interval_presets.sort()
|
2009-08-24 19:31:58 +02:00
|
|
|
|
2010-09-27 00:27:01 +02:00
|
|
|
adjustment_update_interval.upper = len(self.update_interval_presets)-1
|
2010-03-02 01:36:23 +01:00
|
|
|
index = self.update_interval_presets.index(self._config.auto_update_frequency)
|
|
|
|
self.hscale_update_interval.set_value(index)
|
2009-08-24 19:31:58 +02:00
|
|
|
|
2010-03-02 01:36:23 +01:00
|
|
|
self._config.connect_gtk_togglebutton('update_on_startup', self.checkbutton_update_on_startup)
|
|
|
|
self._config.connect_gtk_spinbutton('max_episodes_per_feed', self.spinbutton_episode_limit)
|
2009-08-24 19:31:58 +02:00
|
|
|
|
2010-03-02 01:36:23 +01:00
|
|
|
self.auto_download_model = NewEpisodeActionList(self._config)
|
|
|
|
self.combo_auto_download.set_model(self.auto_download_model)
|
|
|
|
cellrenderer = gtk.CellRendererText()
|
|
|
|
self.combo_auto_download.pack_start(cellrenderer, True)
|
|
|
|
self.combo_auto_download.add_attribute(cellrenderer, 'text', NewEpisodeActionList.C_CAPTION)
|
|
|
|
self.combo_auto_download.set_active(self.auto_download_model.get_index())
|
2009-08-24 19:31:58 +02:00
|
|
|
|
2010-03-02 01:36:23 +01:00
|
|
|
if self._config.auto_remove_played_episodes:
|
|
|
|
adjustment_expiration = self.hscale_expiration.get_adjustment()
|
|
|
|
if self._config.episode_old_age > adjustment_expiration.get_upper():
|
|
|
|
# Patch the adjustment to include the higher current value
|
2010-09-27 00:27:01 +02:00
|
|
|
adjustment_expiration.upper = self._config.episode_old_age
|
2009-08-24 19:31:58 +02:00
|
|
|
|
2010-03-02 01:36:23 +01:00
|
|
|
self.hscale_expiration.set_value(self._config.episode_old_age)
|
|
|
|
else:
|
|
|
|
self.hscale_expiration.set_value(0)
|
2009-08-24 19:31:58 +02:00
|
|
|
|
2010-03-02 01:36:23 +01:00
|
|
|
self._config.connect_gtk_togglebutton('auto_remove_unplayed_episodes', self.checkbutton_expiration_unplayed)
|
2010-03-23 13:51:08 +01:00
|
|
|
self._config.connect_gtk_togglebutton('auto_cleanup_downloads', self.checkbutton_auto_cleanup_downloads)
|
2009-08-24 19:31:58 +02:00
|
|
|
|
2010-06-05 15:57:28 +02:00
|
|
|
self.device_type_model = DeviceTypeActionList(self._config)
|
|
|
|
self.combobox_device_type.set_model(self.device_type_model)
|
|
|
|
cellrenderer = gtk.CellRendererText()
|
|
|
|
self.combobox_device_type.pack_start(cellrenderer, True)
|
|
|
|
self.combobox_device_type.add_attribute(cellrenderer, 'text', DeviceTypeActionList.C_CAPTION)
|
|
|
|
self.combobox_device_type.set_active(self.device_type_model.get_index())
|
|
|
|
|
|
|
|
self.on_sync_model = OnSyncActionList(self._config)
|
|
|
|
self.combobox_on_sync.set_model(self.on_sync_model)
|
|
|
|
cellrenderer = gtk.CellRendererText()
|
|
|
|
self.combobox_on_sync.pack_start(cellrenderer, True)
|
|
|
|
self.combobox_on_sync.add_attribute(cellrenderer, 'text', OnSyncActionList.C_CAPTION)
|
|
|
|
self.combobox_on_sync.set_active(self.on_sync_model.get_index())
|
|
|
|
|
|
|
|
self._config.connect_gtk_togglebutton('only_sync_not_played', self.checkbutton_only_sync_not_played)
|
|
|
|
|
2010-11-23 12:26:40 +01:00
|
|
|
# Have to do this before calling set_active on checkbutton_enable
|
|
|
|
self._enable_mygpo = self._config.mygpo_enabled
|
|
|
|
|
2010-05-03 21:16:13 +02:00
|
|
|
# Initialize the UI state with configuration settings
|
|
|
|
self.checkbutton_enable.set_active(self._config.mygpo_enabled)
|
|
|
|
self.entry_username.set_text(self._config.mygpo_username)
|
|
|
|
self.entry_password.set_text(self._config.mygpo_password)
|
|
|
|
self.entry_caption.set_text(self._config.mygpo_device_caption)
|
|
|
|
|
|
|
|
# Disable mygpo sync while the dialog is open
|
|
|
|
self._config.mygpo_enabled = False
|
|
|
|
|
2010-03-02 01:36:23 +01:00
|
|
|
def on_dialog_destroy(self, widget):
|
2010-05-03 21:16:13 +02:00
|
|
|
# Re-enable mygpo sync if the user has selected it
|
|
|
|
self._config.mygpo_enabled = self._enable_mygpo
|
|
|
|
# Make sure the device is successfully created/updated
|
|
|
|
self.mygpo_client.create_device()
|
|
|
|
# Flush settings for mygpo client now
|
|
|
|
self.mygpo_client.flush(now=True)
|
|
|
|
|
2010-03-02 01:36:23 +01:00
|
|
|
if self.callback_finished:
|
|
|
|
self.callback_finished()
|
2009-08-24 19:31:58 +02:00
|
|
|
|
2010-03-02 01:36:23 +01:00
|
|
|
def on_button_close_clicked(self, widget):
|
|
|
|
self.main_window.destroy()
|
|
|
|
|
|
|
|
def on_button_advanced_clicked(self, widget):
|
|
|
|
self.main_window.destroy()
|
|
|
|
gPodderConfigEditor(self.parent_window, _config=self._config)
|
|
|
|
|
|
|
|
def on_combo_audio_player_app_changed(self, widget):
|
|
|
|
index = self.combo_audio_player_app.get_active()
|
|
|
|
self._config.player = self.audio_player_model.get_command(index)
|
|
|
|
|
|
|
|
def on_combo_video_player_app_changed(self, widget):
|
|
|
|
index = self.combo_video_player_app.get_active()
|
|
|
|
self._config.videoplayer = self.video_player_model.get_command(index)
|
|
|
|
|
|
|
|
def on_button_audio_player_clicked(self, widget):
|
|
|
|
result = self.show_text_edit_dialog(_('Configure audio player'), \
|
|
|
|
_('Command:'), \
|
|
|
|
self._config.player)
|
|
|
|
|
|
|
|
if result:
|
|
|
|
self._config.player = result
|
|
|
|
index = self.audio_player_model.get_index(self._config.player)
|
|
|
|
self.combo_audio_player_app.set_active(index)
|
|
|
|
|
|
|
|
def on_button_video_player_clicked(self, widget):
|
|
|
|
result = self.show_text_edit_dialog(_('Configure video player'), \
|
|
|
|
_('Command:'), \
|
|
|
|
self._config.videoplayer)
|
|
|
|
|
|
|
|
if result:
|
|
|
|
self._config.videoplayer = result
|
|
|
|
index = self.video_player_model.get_index(self._config.videoplayer)
|
|
|
|
self.combo_video_player_app.set_active(index)
|
|
|
|
|
|
|
|
def format_update_interval_value(self, scale, value):
|
|
|
|
value = int(value)
|
|
|
|
if value == 0:
|
|
|
|
return _('manual only')
|
2010-11-23 12:26:40 +01:00
|
|
|
elif value > 0 and len(self.update_interval_presets) < value:
|
|
|
|
return util.format_seconds_to_hour_min_sec(self.update_interval_presets[value]*60)
|
2009-08-24 19:31:58 +02:00
|
|
|
else:
|
2010-11-23 12:26:40 +01:00
|
|
|
return str(value)
|
2010-03-02 01:36:23 +01:00
|
|
|
|
|
|
|
def on_update_interval_value_changed(self, range):
|
|
|
|
value = int(range.get_value())
|
|
|
|
self._config.auto_update_feeds = (value > 0)
|
|
|
|
self._config.auto_update_frequency = self.update_interval_presets[value]
|
|
|
|
|
|
|
|
def on_combo_auto_download_changed(self, widget):
|
|
|
|
index = self.combo_auto_download.get_active()
|
|
|
|
self.auto_download_model.set_index(index)
|
|
|
|
|
2010-06-05 15:57:28 +02:00
|
|
|
def on_combobox_on_sync_changed(self, widget):
|
|
|
|
index = self.combobox_on_sync.get_active()
|
|
|
|
self.on_sync_model.set_index(index)
|
|
|
|
|
|
|
|
def on_combobox_device_type_changed(self, widget):
|
|
|
|
index = self.combobox_device_type.get_active()
|
|
|
|
self.device_type_model.set_index(index)
|
|
|
|
if index == 0:
|
|
|
|
self.btn_filesystemMountpoint.set_label('')
|
|
|
|
self.btn_filesystemMountpoint.set_sensitive(False)
|
|
|
|
if index == 1:
|
|
|
|
self.btn_filesystemMountpoint.set_label(self._config.ipod_mount)
|
|
|
|
self.btn_filesystemMountpoint.set_sensitive(True)
|
|
|
|
self._config.connect_gtk_togglebutton('ipod_purge_old_episodes', self.checkbutton_delete_played)
|
|
|
|
if index == 2:
|
|
|
|
self.btn_filesystemMountpoint.set_label(self._config.mp3_player_folder)
|
|
|
|
self.btn_filesystemMountpoint.set_sensitive(True)
|
|
|
|
self._config.connect_gtk_togglebutton('mp3_player_delete_played', self.checkbutton_delete_played)
|
|
|
|
if index == 3:
|
|
|
|
self.btn_filesystemMountpoint.set_label('')
|
|
|
|
self.btn_filesystemMountpoint.set_sensitive(False)
|
|
|
|
|
2010-06-30 03:31:49 +02:00
|
|
|
children = self.btn_filesystemMountpoint.get_children()
|
|
|
|
if children:
|
|
|
|
label = children.pop()
|
|
|
|
label.set_alignment(0., .5)
|
2010-06-05 15:57:28 +02:00
|
|
|
|
|
|
|
def on_btn_device_mountpoint_clicked(self, widget):
|
|
|
|
fs = gtk.FileChooserDialog( title = _('Select folder for mount point'), action = gtk.FILE_CHOOSER_ACTION_SELECT_FOLDER)
|
|
|
|
fs.add_button( gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL)
|
|
|
|
fs.add_button( gtk.STOCK_OPEN, gtk.RESPONSE_OK)
|
|
|
|
fs.set_current_folder(self.btn_filesystemMountpoint.get_label())
|
|
|
|
if fs.run() == gtk.RESPONSE_OK:
|
2010-06-30 03:31:49 +02:00
|
|
|
filename = fs.get_filename()
|
|
|
|
if self._config.device_type == 'filesystem':
|
|
|
|
self._config.mp3_player_folder = filename
|
|
|
|
elif self._config.device_type == 'ipod':
|
|
|
|
self._config.ipod_mount = filename
|
|
|
|
|
|
|
|
# Request an update of the mountpoint button
|
|
|
|
self.on_combobox_device_type_changed(None)
|
|
|
|
|
2010-06-05 15:57:28 +02:00
|
|
|
fs.destroy()
|
|
|
|
|
2010-03-02 01:36:23 +01:00
|
|
|
def format_expiration_value(self, scale, value):
|
|
|
|
value = int(value)
|
|
|
|
if value == 0:
|
|
|
|
return _('manually')
|
2009-08-24 19:31:58 +02:00
|
|
|
else:
|
2010-11-22 21:52:58 +01:00
|
|
|
return N_('after %(count)d day', 'after %(count)d days', value) % {'count':value}
|
2010-03-02 01:36:23 +01:00
|
|
|
|
|
|
|
def on_expiration_value_changed(self, range):
|
|
|
|
value = int(range.get_value())
|
|
|
|
|
|
|
|
if value == 0:
|
|
|
|
self.checkbutton_expiration_unplayed.set_active(False)
|
|
|
|
self._config.auto_remove_played_episodes = False
|
|
|
|
self._config.auto_remove_unplayed_episodes = False
|
2009-08-24 19:31:58 +02:00
|
|
|
else:
|
2010-03-02 01:36:23 +01:00
|
|
|
self._config.auto_remove_played_episodes = True
|
|
|
|
self._config.episode_old_age = value
|
|
|
|
|
|
|
|
self.checkbutton_expiration_unplayed.set_sensitive(value > 0)
|
2009-08-24 19:31:58 +02:00
|
|
|
|
2010-05-03 21:16:13 +02:00
|
|
|
def on_enabled_toggled(self, widget):
|
|
|
|
# Only update indirectly (see on_dialog_destroy)
|
|
|
|
self._enable_mygpo = widget.get_active()
|
|
|
|
|
|
|
|
def on_username_changed(self, widget):
|
|
|
|
self._config.mygpo_username = widget.get_text()
|
|
|
|
|
|
|
|
def on_password_changed(self, widget):
|
|
|
|
self._config.mygpo_password = widget.get_text()
|
|
|
|
|
|
|
|
def on_device_caption_changed(self, widget):
|
|
|
|
self._config.mygpo_device_caption = widget.get_text()
|
|
|
|
|
|
|
|
def on_button_overwrite_clicked(self, button):
|
|
|
|
title = _('Replace subscription list on server')
|
|
|
|
message = _('Remote podcasts that have not been added locally will be removed on the server. Continue?')
|
|
|
|
if self.show_confirmation(message, title):
|
|
|
|
def thread_proc():
|
|
|
|
self._config.mygpo_enabled = True
|
|
|
|
self.on_send_full_subscriptions()
|
|
|
|
self._config.mygpo_enabled = False
|
|
|
|
threading.Thread(target=thread_proc).start()
|
|
|
|
|