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:
parent
9dbc9d5a73
commit
fe05092ef6
12
ChangeLog
12
ChangeLog
|
@ -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>
|
Tue, 11 Dec 2007 22:10:03 +0100 <thp@perli.net>
|
||||||
Updated TODO list
|
Updated TODO list
|
||||||
|
|
||||||
|
|
|
@ -576,6 +576,15 @@
|
||||||
</widget>
|
</widget>
|
||||||
</child>
|
</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>
|
<child>
|
||||||
<widget class="GtkSeparatorMenuItem" id="separator11">
|
<widget class="GtkSeparatorMenuItem" id="separator11">
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
|
|
|
@ -430,10 +430,13 @@ class gPodder(GladeWidget):
|
||||||
item.set_image( gtk.image_new_from_stock( gtk.STOCK_MEDIA_PLAY, gtk.ICON_SIZE_MENU))
|
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))
|
item.connect( 'activate', lambda w: self.on_treeAvailable_row_activated( self.toolPlay))
|
||||||
menu.append( item)
|
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))
|
is_locked = gPodderLib().history_is_locked(first_url)
|
||||||
item.connect( 'activate', self.on_btnDownloadedDelete_clicked)
|
if not is_locked:
|
||||||
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)
|
||||||
|
|
||||||
if can_download:
|
if can_download:
|
||||||
item = gtk.ImageMenuItem( _('Download %s') % episode_title)
|
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))
|
item.connect( 'activate', lambda w: self.on_item_toggle_played_activate( w, False, True))
|
||||||
menu.append( item)
|
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:
|
if can_cancel:
|
||||||
item = gtk.ImageMenuItem( _('_Cancel download'))
|
item = gtk.ImageMenuItem( _('_Cancel download'))
|
||||||
item.set_image( gtk.image_new_from_stock( gtk.STOCK_STOP, gtk.ICON_SIZE_MENU))
|
item.set_image( gtk.image_new_from_stock( gtk.STOCK_STOP, gtk.ICON_SIZE_MENU))
|
||||||
|
@ -622,6 +638,7 @@ class gPodder(GladeWidget):
|
||||||
try:
|
try:
|
||||||
channel = podcastChannel.get_by_url( url = result, force_update = True)
|
channel = podcastChannel.get_by_url( url = result, force_update = True)
|
||||||
except:
|
except:
|
||||||
|
log('Error in podcastChannel.get_by_url(%s)', result, sender=self)
|
||||||
channel = None
|
channel = None
|
||||||
|
|
||||||
if channel:
|
if channel:
|
||||||
|
@ -892,7 +909,7 @@ class gPodder(GladeWidget):
|
||||||
selected = []
|
selected = []
|
||||||
for channel in self.channels:
|
for channel in self.channels:
|
||||||
for episode in channel:
|
for episode in channel:
|
||||||
if episode.is_downloaded():
|
if episode.is_downloaded() and not episode.is_locked():
|
||||||
episodes.append( episode)
|
episodes.append( episode)
|
||||||
selected.append( episode.is_played())
|
selected.append( episode.is_played())
|
||||||
|
|
||||||
|
@ -917,6 +934,14 @@ class gPodder(GladeWidget):
|
||||||
|
|
||||||
self.for_each_selected_episode_url( callback)
|
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):
|
def on_itemUpdate_activate(self, widget, *args):
|
||||||
if self.channels:
|
if self.channels:
|
||||||
self.update_feed_cache()
|
self.update_feed_cache()
|
||||||
|
@ -1290,12 +1315,36 @@ class gPodder(GladeWidget):
|
||||||
return
|
return
|
||||||
|
|
||||||
if selection.count_selected_rows() == 1:
|
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.")
|
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:
|
else:
|
||||||
title = _('Remove %d episodes?') % selection.count_selected_rows()
|
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.')
|
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 user confirms deletion, let's remove some stuff ;)
|
||||||
if self.show_confirmation( message, title):
|
if self.show_confirmation( message, title):
|
||||||
try:
|
try:
|
||||||
|
|
|
@ -68,7 +68,8 @@ class gPodderLibClass( object):
|
||||||
|
|
||||||
self.__download_history = HistoryStore( os.path.join( gpodder_dir, 'download-history.txt'))
|
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.__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):
|
def get_device_name( self):
|
||||||
if self.config.device_type == 'ipod':
|
if self.config.device_type == 'ipod':
|
||||||
return _('iPod')
|
return _('iPod')
|
||||||
|
@ -134,12 +135,21 @@ class gPodderLibClass( object):
|
||||||
else:
|
else:
|
||||||
self.__playback_history.del_item( url)
|
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):
|
def history_is_downloaded( self, url):
|
||||||
return (url in self.__download_history)
|
return (url in self.__download_history)
|
||||||
|
|
||||||
def history_is_played( self, url):
|
def history_is_played( self, url):
|
||||||
return (url in self.__playback_history)
|
return (url in self.__playback_history)
|
||||||
|
|
||||||
|
def history_is_locked( self, url):
|
||||||
|
return (url in self.__locked_history)
|
||||||
|
|
||||||
def playback_episode( self, channel, episode):
|
def playback_episode( self, channel, episode):
|
||||||
self.history_mark_played( episode.url)
|
self.history_mark_played( episode.url)
|
||||||
filename = episode.local_filename()
|
filename = episode.local_filename()
|
||||||
|
|
|
@ -407,17 +407,19 @@ class podcastChannel(ListType):
|
||||||
url = model.get_value( iter, 0)
|
url = model.get_value( iter, 0)
|
||||||
local_filename = model.get_value( iter, 8)
|
local_filename = model.get_value( iter, 8)
|
||||||
played = not libgpodder.gPodderLib().history_is_played( url)
|
played = not libgpodder.gPodderLib().history_is_played( url)
|
||||||
|
locked = libgpodder.gPodderLib().history_is_locked(url)
|
||||||
|
|
||||||
if os.path.exists( local_filename):
|
if os.path.exists( local_filename):
|
||||||
file_type = util.file_type_by_extension( util.file_extension_from_url( url))
|
file_type = util.file_type_by_extension( util.file_extension_from_url( url))
|
||||||
if file_type == 'audio':
|
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':
|
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':
|
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:
|
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):
|
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)
|
status_icon = util.get_tree_icon( gtk.STOCK_GO_DOWN, icon_cache = self.icon_cache)
|
||||||
elif libgpodder.gPodderLib().history_is_downloaded( url):
|
elif libgpodder.gPodderLib().history_is_downloaded( url):
|
||||||
|
@ -592,6 +594,9 @@ class podcastItem(object):
|
||||||
def is_downloaded( self):
|
def is_downloaded( self):
|
||||||
return os.path.exists( self.local_filename())
|
return os.path.exists( self.local_filename())
|
||||||
|
|
||||||
|
def is_locked(self):
|
||||||
|
return libgpodder.gPodderLib().history_is_locked(self.url)
|
||||||
|
|
||||||
def delete_from_disk( self):
|
def delete_from_disk( self):
|
||||||
self.channel.delete_episode_by_url( self.url)
|
self.channel.delete_episode_by_url( self.url)
|
||||||
|
|
||||||
|
|
|
@ -359,13 +359,13 @@ def file_type_by_extension( extension):
|
||||||
return None
|
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
|
Loads an icon from the current icon theme at the specified
|
||||||
size, suitable for display in a gtk.TreeView.
|
size, suitable for display in a gtk.TreeView.
|
||||||
|
|
||||||
Optionally adds a green bullet (the GTK Stock "Yes" icon)
|
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
|
If an icon_cache parameter is supplied, it has to be a
|
||||||
dictionary and will be used to store generated icons.
|
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.
|
the cache.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
if icon_cache != None and (icon_name,add_bullet) in icon_cache:
|
if icon_cache != None and (icon_name,add_bullet,add_padlock) in icon_cache:
|
||||||
return icon_cache[(icon_name,add_bullet)]
|
return icon_cache[(icon_name,add_bullet,add_padlock)]
|
||||||
|
|
||||||
icon_theme = gtk.icon_theme_get_default()
|
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)
|
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)
|
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()
|
# We'll modify the icon, so use .copy()
|
||||||
try:
|
if add_bullet:
|
||||||
icon = icon.copy()
|
try:
|
||||||
emblem = icon_theme.load_icon( gtk.STOCK_YES, 10, 0)
|
icon = icon.copy()
|
||||||
size = emblem.get_width()
|
emblem = icon_theme.load_icon(gtk.STOCK_YES, 10, 0)
|
||||||
pos = icon.get_width() - size
|
size = emblem.get_width()
|
||||||
emblem.composite( icon, pos, pos, size, size, pos, pos, 1, 1, gtk.gdk.INTERP_BILINEAR, 255)
|
pos = icon.get_width() - size
|
||||||
except:
|
emblem.composite(icon, pos, pos, size, size, pos, pos, 1, 1, gtk.gdk.INTERP_BILINEAR, 255)
|
||||||
log( '(get_tree_icon) Error adding emblem to icon "%s".', icon_name)
|
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:
|
if icon_cache != None:
|
||||||
icon_cache[(icon_name,add_bullet)] = icon
|
icon_cache[(icon_name,add_bullet,add_padlock)] = icon
|
||||||
|
|
||||||
return icon
|
return icon
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue