Merged episode locking patch from Paul Rudkin

git-svn-id: svn://svn.berlios.de/gpodder/trunk@489 b0d088ad-0a06-0410-aad2-9ed5178a7e87
This commit is contained in:
Thomas Perl 2007-12-12 18:50:52 +00:00
parent 9dbc9d5a73
commit fe05092ef6
6 changed files with 120 additions and 26 deletions

View file

@ -1,3 +1,15 @@
Wed, 12 Dec 2007 19:44:15 +0100 <thp@perli.net>
Merged episode locking patch from Paul Rudkin
* src/gpodder/gui.py: Merged "lock episodes" patch to mark episodes as
locked, patch by Paul Rudkin <paul@thegithouse.com>
* data/gpodder.glade: Add menu item for toggle locked status
* src/gpodder/libgpodder.py: Add "locked" history
* src/gpodder/libpodcasts.py: When requesting a status icon, also draw
the "Locked" status; is_locked() in podcastItem
* src/gpodder/util.py: Added code for drawing a padlock icon on top of
another (file type) icon; this is used for the "lock episodes" feature
Tue, 11 Dec 2007 22:10:03 +0100 <thp@perli.net>
Updated TODO list

View file

@ -576,6 +576,15 @@
</widget>
</child>
<child>
<widget class="GtkMenuItem" id="item_toggle_lock">
<property name="visible">True</property>
<property name="label" translatable="yes">Toggle lock status for selection</property>
<property name="use_underline">True</property>
<signal name="activate" handler="on_item_toggle_lock_activate"/>
</widget>
</child>
<child>
<widget class="GtkSeparatorMenuItem" id="separator11">
<property name="visible">True</property>

View file

@ -430,10 +430,13 @@ class gPodder(GladeWidget):
item.set_image( gtk.image_new_from_stock( gtk.STOCK_MEDIA_PLAY, gtk.ICON_SIZE_MENU))
item.connect( 'activate', lambda w: self.on_treeAvailable_row_activated( self.toolPlay))
menu.append( item)
item = gtk.ImageMenuItem( _('Remove %s') % episode_title)
item.set_image( gtk.image_new_from_stock( gtk.STOCK_DELETE, gtk.ICON_SIZE_MENU))
item.connect( 'activate', self.on_btnDownloadedDelete_clicked)
menu.append( item)
is_locked = gPodderLib().history_is_locked(first_url)
if not is_locked:
item = gtk.ImageMenuItem(_('Remove %s') % episode_title)
item.set_image(gtk.image_new_from_stock(gtk.STOCK_DELETE, gtk.ICON_SIZE_MENU))
item.connect('activate', self.on_btnDownloadedDelete_clicked)
menu.append(item)
if can_download:
item = gtk.ImageMenuItem( _('Download %s') % episode_title)
@ -474,6 +477,19 @@ class gPodder(GladeWidget):
item.connect( 'activate', lambda w: self.on_item_toggle_played_activate( w, False, True))
menu.append( item)
menu.append(gtk.SeparatorMenuItem())
is_locked = gPodderLib().history_is_locked(first_url)
if is_locked:
item = gtk.ImageMenuItem(_('Unlock %s') % episode_title)
item.set_image(gtk.image_new_from_stock(gtk.STOCK_DIALOG_AUTHENTICATION, gtk.ICON_SIZE_MENU))
item.connect('activate', self.on_item_toggle_lock_activate)
menu.append(item)
else:
item = gtk.ImageMenuItem(_('Lock %s') % episode_title)
item.set_image(gtk.image_new_from_stock(gtk.STOCK_DIALOG_AUTHENTICATION, gtk.ICON_SIZE_MENU))
item.connect('activate', self.on_item_toggle_lock_activate)
menu.append(item)
if can_cancel:
item = gtk.ImageMenuItem( _('_Cancel download'))
item.set_image( gtk.image_new_from_stock( gtk.STOCK_STOP, gtk.ICON_SIZE_MENU))
@ -622,6 +638,7 @@ class gPodder(GladeWidget):
try:
channel = podcastChannel.get_by_url( url = result, force_update = True)
except:
log('Error in podcastChannel.get_by_url(%s)', result, sender=self)
channel = None
if channel:
@ -892,7 +909,7 @@ class gPodder(GladeWidget):
selected = []
for channel in self.channels:
for episode in channel:
if episode.is_downloaded():
if episode.is_downloaded() and not episode.is_locked():
episodes.append( episode)
selected.append( episode.is_played())
@ -917,6 +934,14 @@ class gPodder(GladeWidget):
self.for_each_selected_episode_url( callback)
def on_item_toggle_lock_activate(self, widget, toggle=True, new_value=False):
if toggle:
callback = lambda url: gPodderLib().history_mark_locked(url, not gPodderLib().history_is_locked(url))
else:
callback = lambda url: gPodderLib().history_mark_locked(url, new_value)
self.for_each_selected_episode_url(callback)
def on_itemUpdate_activate(self, widget, *args):
if self.channels:
self.update_feed_cache()
@ -1290,12 +1315,36 @@ class gPodder(GladeWidget):
return
if selection.count_selected_rows() == 1:
title = _('Remove %s?') % model.get_value( model.get_iter( paths[0]), 1)
episode_title = saxutils.escape(model.get_value(model.get_iter(paths[0]), 1))
locked = gPodderLib().history_is_locked(model.get_value(model.get_iter(paths[0]), 0))
if locked:
title = _('%s is locked') % episode_title
message = _('You cannot delete this locked episode. You must unlock it before you can delete it.')
self.notification(message, title)
return
title = _('Remove %s?') % episode_title
message = _("If you remove this episode, it will be deleted from your computer. If you want to listen to this episode again, you will have to re-download it.")
else:
title = _('Remove %d episodes?') % selection.count_selected_rows()
message = _('If you remove these episodes, they will be deleted from your computer. If you want to listen to any of these episodes again, you will have to re-download the episodes in question.')
locked_count = 0
for path in paths:
url = model.get_value(model.get_iter(path), 0)
if gPodderLib().history_is_locked(url):
locked_count += 1
if selection.count_selected_rows() == locked_count:
title = _('Episodes are locked')
message = _('The selected episodes are locked. Please unlock the episodes that you want to delete before trying to delete them.')
self.notification(message, title)
return
elif locked_count > 0:
title = _('Remove %d out of %d episodes?') % (selection.count_selected_rows() - locked_count, selection.count_selected_rows())
message = _('The selection contains locked episodes. These will not be deleted. If you want to listen to any of these episodes again, then you will have to re-download them.')
# if user confirms deletion, let's remove some stuff ;)
if self.show_confirmation( message, title):
try:

View file

@ -68,7 +68,8 @@ class gPodderLibClass( object):
self.__download_history = HistoryStore( os.path.join( gpodder_dir, 'download-history.txt'))
self.__playback_history = HistoryStore( os.path.join( gpodder_dir, 'playback-history.txt'))
self.__locked_history = HistoryStore( os.path.join( gpodder_dir, 'lock-history.txt'))
def get_device_name( self):
if self.config.device_type == 'ipod':
return _('iPod')
@ -134,12 +135,21 @@ class gPodderLibClass( object):
else:
self.__playback_history.del_item( url)
def history_mark_locked( self, url, add_item = True):
if add_item:
self.__locked_history.add_item( url)
else:
self.__locked_history.del_item( url)
def history_is_downloaded( self, url):
return (url in self.__download_history)
def history_is_played( self, url):
return (url in self.__playback_history)
def history_is_locked( self, url):
return (url in self.__locked_history)
def playback_episode( self, channel, episode):
self.history_mark_played( episode.url)
filename = episode.local_filename()

View file

@ -407,17 +407,19 @@ class podcastChannel(ListType):
url = model.get_value( iter, 0)
local_filename = model.get_value( iter, 8)
played = not libgpodder.gPodderLib().history_is_played( url)
locked = libgpodder.gPodderLib().history_is_locked(url)
if os.path.exists( local_filename):
file_type = util.file_type_by_extension( util.file_extension_from_url( url))
if file_type == 'audio':
status_icon = util.get_tree_icon( 'audio-x-generic', played, self.icon_cache)
status_icon = util.get_tree_icon('audio-x-generic', played, locked, self.icon_cache)
elif file_type == 'video':
status_icon = util.get_tree_icon( 'video-x-generic', played, self.icon_cache)
status_icon = util.get_tree_icon('video-x-generic', played, locked, self.icon_cache)
elif file_type == 'torrent':
status_icon = util.get_tree_icon( 'applications-internet', played, self.icon_cache)
status_icon = util.get_tree_icon('applications-internet', played, locked, self.icon_cache)
else:
status_icon = util.get_tree_icon( 'unknown', played, self.icon_cache)
status_icon = util.get_tree_icon('unknown', played, locked, self.icon_cache)
elif services.download_status_manager.is_download_in_progress( url):
status_icon = util.get_tree_icon( gtk.STOCK_GO_DOWN, icon_cache = self.icon_cache)
elif libgpodder.gPodderLib().history_is_downloaded( url):
@ -592,6 +594,9 @@ class podcastItem(object):
def is_downloaded( self):
return os.path.exists( self.local_filename())
def is_locked(self):
return libgpodder.gPodderLib().history_is_locked(self.url)
def delete_from_disk( self):
self.channel.delete_episode_by_url( self.url)

View file

@ -359,13 +359,13 @@ def file_type_by_extension( extension):
return None
def get_tree_icon( icon_name, add_bullet = False, icon_cache = None):
def get_tree_icon(icon_name, add_bullet=False, add_padlock=False, icon_cache=None):
"""
Loads an icon from the current icon theme at the specified
size, suitable for display in a gtk.TreeView.
Optionally adds a green bullet (the GTK Stock "Yes" icon)
to the Pixbuf returned.
to the Pixbuf returned. Also, a padlock icon can be added.
If an icon_cache parameter is supplied, it has to be a
dictionary and will be used to store generated icons.
@ -375,8 +375,8 @@ def get_tree_icon( icon_name, add_bullet = False, icon_cache = None):
the cache.
"""
if icon_cache != None and (icon_name,add_bullet) in icon_cache:
return icon_cache[(icon_name,add_bullet)]
if icon_cache != None and (icon_name,add_bullet,add_padlock) in icon_cache:
return icon_cache[(icon_name,add_bullet,add_padlock)]
icon_theme = gtk.icon_theme_get_default()
@ -386,19 +386,28 @@ def get_tree_icon( icon_name, add_bullet = False, icon_cache = None):
log( '(get_tree_icon) Warning: Cannot load icon with name "%s", will use default icon.', icon_name)
icon = icon_theme.load_icon( gtk.STOCK_DIALOG_QUESTION, 16, 0)
if add_bullet and icon:
if icon and (add_bullet or add_padlock):
# We'll modify the icon, so use .copy()
try:
icon = icon.copy()
emblem = icon_theme.load_icon( gtk.STOCK_YES, 10, 0)
size = emblem.get_width()
pos = icon.get_width() - size
emblem.composite( icon, pos, pos, size, size, pos, pos, 1, 1, gtk.gdk.INTERP_BILINEAR, 255)
except:
log( '(get_tree_icon) Error adding emblem to icon "%s".', icon_name)
if add_bullet:
try:
icon = icon.copy()
emblem = icon_theme.load_icon(gtk.STOCK_YES, 10, 0)
size = emblem.get_width()
pos = icon.get_width() - size
emblem.composite(icon, pos, pos, size, size, pos, pos, 1, 1, gtk.gdk.INTERP_BILINEAR, 255)
except:
log('(get_tree_icon) Error adding emblem to icon "%s".', icon_name)
if add_padlock:
try:
icon = icon.copy()
emblem = icon_theme.load_icon('emblem-nowrite', 8, 0)
size = emblem.get_width()
emblem.composite(icon, 0, 0, size, size, 0, 0, 1, 1, gtk.gdk.INTERP_BILINEAR, 255)
except:
log('(get_tree_icon) Error adding emblem to icon "%s".', icon_name)
if icon_cache != None:
icon_cache[(icon_name,add_bullet)] = icon
icon_cache[(icon_name,add_bullet,add_padlock)] = icon
return icon