New, separate episode selector for Maemo 4
This commit is contained in:
parent
2951544a77
commit
c73db9e587
|
@ -0,0 +1,176 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--*- mode: xml -*-->
|
||||
<interface>
|
||||
<object class="HildonWindow" id="gPodderEpisodeSelector">
|
||||
<property name="visible">False</property>
|
||||
<property name="title" translatable="yes">Select episodes</property>
|
||||
<property name="window_position">GTK_WIN_POS_CENTER_ON_PARENT</property>
|
||||
<property name="modal">True</property>
|
||||
<property name="default_width">600</property>
|
||||
<property name="default_height">400</property>
|
||||
<property name="destroy_with_parent">False</property>
|
||||
<property name="skip_taskbar_hint">False</property>
|
||||
<property name="skip_pager_hint">False</property>
|
||||
<property name="type_hint">GDK_WINDOW_TYPE_HINT_NORMAL</property>
|
||||
<property name="focus_on_map">True</property>
|
||||
<property name="urgency_hint">False</property>
|
||||
<signal name="destroy" handler="on_close_button_clicked"/>
|
||||
<child>
|
||||
<object class="GtkVBox" id="vbox10">
|
||||
<property name="border_width">6</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="homogeneous">False</property>
|
||||
<property name="spacing">6</property>
|
||||
<child>
|
||||
<object class="GtkVBox" id="vbox_for_episode_selector">
|
||||
<property name="visible">True</property>
|
||||
<property name="spacing">6</property>
|
||||
<child>
|
||||
<object class="GtkLabel" id="labelInstructions">
|
||||
<property name="use_underline">False</property>
|
||||
<property name="use_markup">False</property>
|
||||
<property name="wrap">False</property>
|
||||
<property name="selectable">False</property>
|
||||
<property name="xalign">0</property>
|
||||
<property name="width_chars">-1</property>
|
||||
<property name="single_line_mode">False</property>
|
||||
<property name="visible">False</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="padding">0</property>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkScrolledWindow" id="scrolledwindow7">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
|
||||
<property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
|
||||
<property name="shadow_type">GTK_SHADOW_IN</property>
|
||||
<property name="window_placement">GTK_CORNER_TOP_LEFT</property>
|
||||
<child>
|
||||
<object class="GtkTreeView" id="treeviewEpisodes">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="headers_visible">False</property>
|
||||
<property name="rules_hint">False</property>
|
||||
<property name="reorderable">False</property>
|
||||
<property name="enable_search">True</property>
|
||||
<property name="fixed_height_mode">False</property>
|
||||
<property name="hover_selection">False</property>
|
||||
<property name="hover_expand">False</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="padding">0</property>
|
||||
<property name="expand">True</property>
|
||||
<property name="fill">True</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel" id="labelTotalSize">
|
||||
<property name="visible">True</property>
|
||||
<property name="use_underline">False</property>
|
||||
<property name="use_markup">False</property>
|
||||
<property name="justify">GTK_JUSTIFY_RIGHT</property>
|
||||
<property name="wrap">False</property>
|
||||
<property name="selectable">False</property>
|
||||
<property name="xalign">1</property>
|
||||
<property name="width_chars">-1</property>
|
||||
<property name="single_line_mode">False</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="padding">0</property>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkHButtonBox" id="hbox35">
|
||||
<property name="visible">True</property>
|
||||
<property name="homogeneous">False</property>
|
||||
<property name="spacing">12</property>
|
||||
<property name="border-width">0</property>
|
||||
<property name="layout-style">end</property>
|
||||
<child>
|
||||
<object class="GtkButton" id="btnRemoveAction">
|
||||
<property name="visible">False</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="label">gtk-delete</property>
|
||||
<property name="use_stock">True</property>
|
||||
<property name="focus_on_click">True</property>
|
||||
<signal handler="on_remove_action_activate" name="clicked"/>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="padding">0</property>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
<property name="secondary">True</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkButton" id="btnCancel">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="label">gtk-cancel</property>
|
||||
<property name="use_stock">True</property>
|
||||
<property name="focus_on_click">True</property>
|
||||
<signal handler="on_btnCancel_clicked" name="clicked"/>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="padding">0</property>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkButton" id="btnOK">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_default">True</property>
|
||||
<property name="has_default">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="has_focus">True</property>
|
||||
<property name="label">gtk-ok</property>
|
||||
<property name="use_stock">True</property>
|
||||
<property name="focus_on_click">True</property>
|
||||
<signal handler="on_btnOK_clicked" name="clicked"/>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="padding">0</property>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="padding">0</property>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<object class="GtkAction" id="action_select_all">
|
||||
<property name="label" translatable="yes">Select all</property>
|
||||
<signal name="activate" handler="on_select_all_button_clicked"/>
|
||||
</object>
|
||||
<object class="GtkAction" id="action_select_none">
|
||||
<property name="label" translatable="yes">Select none</property>
|
||||
<signal name="activate" handler="on_select_none_button_clicked"/>
|
||||
</object>
|
||||
<object class="GtkAction" id="action_invert_selection">
|
||||
<property name="label" translatable="yes">Invert selection</property>
|
||||
<property name="stock_id">gtk-refresh</property>
|
||||
<signal name="activate" handler="on_invert_selection_button_clicked"/>
|
||||
</object>
|
||||
<object class="GtkAction" id="action_close">
|
||||
<property name="stock_id">gtk-close</property>
|
||||
<signal name="activate" handler="on_close_button_clicked"/>
|
||||
</object>
|
||||
</interface>
|
|
@ -136,9 +136,6 @@ class gPodderEpisodeSelector(BuilderWidget):
|
|||
self.gPodderEpisodeSelector.set_title( self.title)
|
||||
self.labelHeading.set_markup( '<b><big>%s</big></b>' % saxutils.escape( self.title))
|
||||
|
||||
if gpodder.interface == gpodder.MAEMO:
|
||||
self.labelHeading.hide()
|
||||
|
||||
if hasattr( self, 'instructions'):
|
||||
self.labelInstructions.set_text( self.instructions)
|
||||
self.labelInstructions.show_all()
|
|
@ -0,0 +1,362 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# gPodder - A media aggregator and podcast client
|
||||
# Copyright (c) 2005-2009 Thomas Perl and the gPodder Team
|
||||
#
|
||||
# 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
|
||||
import pango
|
||||
from xml.sax import saxutils
|
||||
|
||||
import gpodder
|
||||
|
||||
_ = gpodder.gettext
|
||||
|
||||
from gpodder import util
|
||||
from gpodder.liblogger import log
|
||||
|
||||
from gpodder.gtkui.interface.common import BuilderWidget
|
||||
|
||||
class gPodderEpisodeSelector(BuilderWidget):
|
||||
"""Episode selection dialog
|
||||
|
||||
Optional keyword arguments that modify the behaviour of this dialog:
|
||||
|
||||
- callback: Function that takes 1 parameter which is a list of
|
||||
the selected episodes (or empty list when none selected)
|
||||
- remove_callback: Function that takes 1 parameter which is a list
|
||||
of episodes that should be "removed" (see below)
|
||||
(default is None, which means remove not possible)
|
||||
- remove_action: Label for the "remove" action (default is "Remove")
|
||||
- remove_finished: Callback after all remove callbacks have finished
|
||||
(default is None, also depends on remove_callback)
|
||||
It will get a list of episode URLs that have been
|
||||
removed, so the main UI can update those
|
||||
- episodes: List of episodes that are presented for selection
|
||||
- selected: (optional) List of boolean variables that define the
|
||||
default checked state for the given episodes
|
||||
- selected_default: (optional) The default boolean value for the
|
||||
checked state if no other value is set
|
||||
(default is False)
|
||||
- columns: List of (name, sort_name, sort_type, caption) pairs for the
|
||||
columns, the name is the attribute name of the episode to be
|
||||
read from each episode object. The sort name is the
|
||||
attribute name of the episode to be used to sort this column.
|
||||
If the sort_name is None it will use the attribute name for
|
||||
sorting. The sort type is the type of the sort column.
|
||||
The caption attribute is the text that appear as column caption
|
||||
(default is [('title_markup', None, None, 'Episode'),])
|
||||
- title: (optional) The title of the window + heading
|
||||
- instructions: (optional) A one-line text describing what the
|
||||
user should select / what the selection is for
|
||||
- stock_ok_button: (optional) Will replace the "OK" button with
|
||||
another GTK+ stock item to be used for the
|
||||
affirmative button of the dialog (e.g. can
|
||||
be gtk.STOCK_DELETE when the episodes to be
|
||||
selected will be deleted after closing the
|
||||
dialog)
|
||||
- selection_buttons: (optional) A dictionary with labels as
|
||||
keys and callbacks as values; for each
|
||||
key a button will be generated, and when
|
||||
the button is clicked, the callback will
|
||||
be called for each episode and the return
|
||||
value of the callback (True or False) will
|
||||
be the new selected state of the episode
|
||||
- size_attribute: (optional) The name of an attribute of the
|
||||
supplied episode objects that can be used to
|
||||
calculate the size of an episode; set this to
|
||||
None if no total size calculation should be
|
||||
done (in cases where total size is useless)
|
||||
(default is 'length')
|
||||
- tooltip_attribute: (optional) The name of an attribute of
|
||||
the supplied episode objects that holds
|
||||
the text for the tooltips when hovering
|
||||
over an episode (default is 'description')
|
||||
|
||||
"""
|
||||
finger_friendly_widgets = ['btnRemoveAction', 'btnCancel', 'btnOK']
|
||||
|
||||
COLUMN_INDEX = 0
|
||||
COLUMN_TOOLTIP = 1
|
||||
COLUMN_TOGGLE = 2
|
||||
COLUMN_ADDITIONAL = 3
|
||||
|
||||
def new( self):
|
||||
self._config.connect_gtk_window(self.gPodderEpisodeSelector, 'episode_selector', True)
|
||||
if not hasattr( self, 'callback'):
|
||||
self.callback = None
|
||||
|
||||
if not hasattr(self, 'remove_callback'):
|
||||
self.remove_callback = None
|
||||
|
||||
if not hasattr(self, 'remove_action'):
|
||||
self.remove_action = _('Remove')
|
||||
|
||||
if not hasattr(self, 'remove_finished'):
|
||||
self.remove_finished = None
|
||||
|
||||
if not hasattr( self, 'episodes'):
|
||||
self.episodes = []
|
||||
|
||||
if not hasattr( self, 'size_attribute'):
|
||||
self.size_attribute = 'length'
|
||||
|
||||
if not hasattr(self, 'tooltip_attribute'):
|
||||
self.tooltip_attribute = 'description'
|
||||
|
||||
if not hasattr( self, 'selection_buttons'):
|
||||
self.selection_buttons = {}
|
||||
|
||||
if not hasattr( self, 'selected_default'):
|
||||
self.selected_default = False
|
||||
|
||||
if not hasattr( self, 'selected'):
|
||||
self.selected = [self.selected_default]*len(self.episodes)
|
||||
|
||||
if len(self.selected) < len(self.episodes):
|
||||
self.selected += [self.selected_default]*(len(self.episodes)-len(self.selected))
|
||||
|
||||
if not hasattr( self, 'columns'):
|
||||
self.columns = (('title_markup', None, None, _('Episode')),)
|
||||
|
||||
if hasattr( self, 'title'):
|
||||
self.gPodderEpisodeSelector.set_title( self.title)
|
||||
|
||||
if hasattr( self, 'instructions'):
|
||||
self.labelInstructions.set_text( self.instructions)
|
||||
self.labelInstructions.show_all()
|
||||
|
||||
if self.remove_callback is not None:
|
||||
self.btnRemoveAction.show()
|
||||
self.btnRemoveAction.set_label(self.remove_action)
|
||||
|
||||
if hasattr(self, 'stock_ok_button'):
|
||||
if self.stock_ok_button == 'gpodder-download':
|
||||
self.btnOK.set_image(gtk.image_new_from_stock(gtk.STOCK_GO_DOWN, gtk.ICON_SIZE_BUTTON))
|
||||
self.btnOK.set_label(_('Download'))
|
||||
else:
|
||||
self.btnOK.set_label(self.stock_ok_button)
|
||||
self.btnOK.set_use_stock(True)
|
||||
|
||||
# Make sure the window comes up quick
|
||||
self.main_window.show()
|
||||
self.main_window.present()
|
||||
while gtk.events_pending():
|
||||
gtk.main_iteration(False)
|
||||
|
||||
# check/uncheck column
|
||||
toggle_cell = gtk.CellRendererToggle()
|
||||
toggle_cell.set_fixed_size(50, -1)
|
||||
self.treeviewEpisodes.append_column( gtk.TreeViewColumn( '', toggle_cell, active=self.COLUMN_TOGGLE))
|
||||
|
||||
next_column = self.COLUMN_ADDITIONAL
|
||||
for name, sort_name, sort_type, caption in self.columns:
|
||||
renderer = gtk.CellRendererText()
|
||||
if next_column < self.COLUMN_ADDITIONAL + 2:
|
||||
renderer.set_property('ellipsize', pango.ELLIPSIZE_END)
|
||||
column = gtk.TreeViewColumn(caption, renderer, markup=next_column)
|
||||
column.set_resizable( True)
|
||||
# Only set "expand" on the first column
|
||||
if next_column < self.COLUMN_ADDITIONAL + 1:
|
||||
column.set_expand(True)
|
||||
if sort_name is not None:
|
||||
column.set_sort_column_id(next_column+1)
|
||||
else:
|
||||
column.set_sort_column_id(next_column)
|
||||
self.treeviewEpisodes.append_column( column)
|
||||
next_column += 1
|
||||
|
||||
if sort_name is not None:
|
||||
# add the sort column
|
||||
column = gtk.TreeViewColumn()
|
||||
column.set_visible(False)
|
||||
self.treeviewEpisodes.append_column( column)
|
||||
next_column += 1
|
||||
|
||||
column_types = [ int, str, bool ]
|
||||
# add string column type plus sort column type if it exists
|
||||
for name, sort_name, sort_type, caption in self.columns:
|
||||
column_types.append(str)
|
||||
if sort_name is not None:
|
||||
column_types.append(sort_type)
|
||||
self.model = gtk.ListStore( *column_types)
|
||||
|
||||
tooltip = None
|
||||
for index, episode in enumerate( self.episodes):
|
||||
if self.tooltip_attribute is not None:
|
||||
try:
|
||||
tooltip = getattr(episode, self.tooltip_attribute)
|
||||
except:
|
||||
log('Episode object %s does not have tooltip attribute: "%s"', episode, self.tooltip_attribute, sender=self)
|
||||
tooltip = None
|
||||
row = [ index, tooltip, self.selected[index] ]
|
||||
for name, sort_name, sort_type, caption in self.columns:
|
||||
if not hasattr(episode, name):
|
||||
log('Warning: Missing attribute "%s"', name, sender=self)
|
||||
row.append(None)
|
||||
else:
|
||||
row.append(getattr( episode, name))
|
||||
|
||||
if sort_name is not None:
|
||||
if not hasattr(episode, sort_name):
|
||||
log('Warning: Missing attribute "%s"', sort_name, sender=self)
|
||||
row.append(None)
|
||||
else:
|
||||
row.append(getattr( episode, sort_name))
|
||||
self.model.append( row)
|
||||
|
||||
self.treeviewEpisodes.set_rules_hint( True)
|
||||
self.treeviewEpisodes.set_model( self.model)
|
||||
self.treeviewEpisodes.columns_autosize()
|
||||
self.calculate_total_size()
|
||||
|
||||
menu = gtk.Menu()
|
||||
menu.append(self.action_select_all.create_menu_item())
|
||||
menu.append(self.action_select_none.create_menu_item())
|
||||
menu.append(gtk.SeparatorMenuItem())
|
||||
menu.append(self.action_invert_selection.create_menu_item())
|
||||
menu.append(gtk.SeparatorMenuItem())
|
||||
|
||||
selection = self.treeviewEpisodes.get_selection()
|
||||
#selection.connect('changed', self.on_selection_changed)
|
||||
self.treeviewEpisodes.connect('button-release-event', \
|
||||
self.on_treeview_button_release)
|
||||
|
||||
if self.selection_buttons:
|
||||
for label in self.selection_buttons:
|
||||
item = gtk.MenuItem(label)
|
||||
item.connect('activate', self.custom_selection_button_clicked, label)
|
||||
menu.append(item)
|
||||
menu.append(gtk.SeparatorMenuItem())
|
||||
|
||||
menu.append(self.action_close.create_menu_item())
|
||||
self.main_window.set_menu(self.set_finger_friendly(menu))
|
||||
|
||||
def on_selection_changed(self, selection):
|
||||
model, iter = selection.get_selected()
|
||||
if iter is not None:
|
||||
model.set_value(iter, self.COLUMN_TOGGLE, \
|
||||
not model.get_value(iter, self.COLUMN_TOGGLE))
|
||||
self.calculate_total_size()
|
||||
|
||||
def on_treeview_button_release(self, widget, event):
|
||||
selection = widget.get_selection()
|
||||
self.on_selection_changed(widget.get_selection())
|
||||
|
||||
def on_select_all_button_clicked(self, widget):
|
||||
for row in self.model:
|
||||
row[self.COLUMN_TOGGLE] = True
|
||||
self.calculate_total_size()
|
||||
|
||||
def on_select_none_button_clicked(self, widget):
|
||||
for row in self.model:
|
||||
row[self.COLUMN_TOGGLE] = False
|
||||
self.calculate_total_size()
|
||||
|
||||
def on_invert_selection_button_clicked(self, widget):
|
||||
for row in self.model:
|
||||
row[self.COLUMN_TOGGLE] = not row[self.COLUMN_TOGGLE]
|
||||
self.calculate_total_size()
|
||||
|
||||
def on_close_button_clicked(self, widget):
|
||||
self.on_btnCancel_clicked(widget)
|
||||
|
||||
def calculate_total_size( self):
|
||||
if self.size_attribute is not None:
|
||||
(total_size, count) = (0, 0)
|
||||
for episode in self.get_selected_episodes():
|
||||
try:
|
||||
total_size += int(getattr( episode, self.size_attribute))
|
||||
count += 1
|
||||
except:
|
||||
log( 'Cannot get size for %s', episode.title, sender = self)
|
||||
|
||||
text = []
|
||||
if count == 0:
|
||||
text.append(_('Nothing selected'))
|
||||
elif count == 1:
|
||||
text.append(_('One episode'))
|
||||
else:
|
||||
text.append(_('%d episodes') % count)
|
||||
if total_size > 0:
|
||||
text.append(_('size: %s') % util.format_filesize(total_size))
|
||||
self.labelTotalSize.set_text(', '.join(text))
|
||||
self.btnOK.set_sensitive(count>0)
|
||||
self.btnRemoveAction.set_sensitive(count>0)
|
||||
if count > 0:
|
||||
self.btnCancel.set_label(gtk.STOCK_CANCEL)
|
||||
else:
|
||||
self.btnCancel.set_label(gtk.STOCK_CLOSE)
|
||||
else:
|
||||
self.btnOK.set_sensitive(False)
|
||||
self.btnRemoveAction.set_sensitive(False)
|
||||
for index, row in enumerate(self.model):
|
||||
if self.model.get_value(row.iter, self.COLUMN_TOGGLE) == True:
|
||||
self.btnOK.set_sensitive(True)
|
||||
self.btnRemoveAction.set_sensitive(True)
|
||||
break
|
||||
self.labelTotalSize.set_text('')
|
||||
|
||||
def custom_selection_button_clicked(self, button, label):
|
||||
callback = self.selection_buttons[label]
|
||||
|
||||
for index, row in enumerate( self.model):
|
||||
new_value = callback( self.episodes[index])
|
||||
self.model.set_value( row.iter, self.COLUMN_TOGGLE, new_value)
|
||||
|
||||
self.calculate_total_size()
|
||||
|
||||
def on_remove_action_activate(self, widget):
|
||||
episodes = self.get_selected_episodes(remove_episodes=True)
|
||||
|
||||
urls = []
|
||||
for episode in episodes:
|
||||
urls.append(episode.url)
|
||||
self.remove_callback(episode)
|
||||
|
||||
if self.remove_finished is not None:
|
||||
self.remove_finished(urls)
|
||||
self.calculate_total_size()
|
||||
|
||||
def get_selected_episodes( self, remove_episodes=False):
|
||||
selected_episodes = []
|
||||
|
||||
for index, row in enumerate( self.model):
|
||||
if self.model.get_value( row.iter, self.COLUMN_TOGGLE) == True:
|
||||
selected_episodes.append( self.episodes[self.model.get_value( row.iter, self.COLUMN_INDEX)])
|
||||
|
||||
if remove_episodes:
|
||||
for episode in selected_episodes:
|
||||
index = self.episodes.index(episode)
|
||||
iter = self.model.get_iter_first()
|
||||
while iter is not None:
|
||||
if self.model.get_value(iter, self.COLUMN_INDEX) == index:
|
||||
self.model.remove(iter)
|
||||
break
|
||||
iter = self.model.iter_next(iter)
|
||||
|
||||
return selected_episodes
|
||||
|
||||
def on_btnOK_clicked( self, widget):
|
||||
self.gPodderEpisodeSelector.destroy()
|
||||
if self.callback is not None:
|
||||
self.callback( self.get_selected_episodes())
|
||||
|
||||
def on_btnCancel_clicked(self, widget):
|
||||
self.gPodderEpisodeSelector.destroy()
|
||||
if self.callback is not None:
|
||||
self.callback([])
|
||||
|
|
@ -95,6 +95,7 @@ if gpodder.interface == gpodder.GUI:
|
|||
from gpodder.gtkui.desktop.channel import gPodderChannel
|
||||
from gpodder.gtkui.desktop.preferences import gPodderPreferences
|
||||
from gpodder.gtkui.desktop.shownotes import gPodderShownotes
|
||||
from gpodder.gtkui.desktop.episodeselector import gPodderEpisodeSelector
|
||||
try:
|
||||
from gpodder.gtkui.desktop.trayicon import GPodderStatusIcon
|
||||
have_trayicon = True
|
||||
|
@ -107,10 +108,10 @@ else:
|
|||
from gpodder.gtkui.maemo.channel import gPodderChannel
|
||||
from gpodder.gtkui.maemo.preferences import gPodderPreferences
|
||||
from gpodder.gtkui.maemo.shownotes import gPodderShownotes
|
||||
from gpodder.gtkui.maemo.episodeselector import gPodderEpisodeSelector
|
||||
have_trayicon = False
|
||||
|
||||
from gpodder.gtkui.interface.podcastdirectory import gPodderPodcastDirectory
|
||||
from gpodder.gtkui.interface.episodeselector import gPodderEpisodeSelector
|
||||
from gpodder.gtkui.interface.welcome import gPodderWelcome
|
||||
|
||||
if gpodder.interface == gpodder.MAEMO:
|
||||
|
@ -2016,21 +2017,26 @@ class gPodder(BuilderWidget, dbus.service.Object):
|
|||
self.play_or_download()
|
||||
|
||||
def on_itemRemoveOldEpisodes_activate( self, widget):
|
||||
columns = (
|
||||
if gpodder.interface == gpodder.MAEMO:
|
||||
columns = (
|
||||
('maemo_remove_markup', None, None, _('Episode')),
|
||||
)
|
||||
else:
|
||||
columns = (
|
||||
('title_markup', None, None, _('Episode')),
|
||||
('channel_prop', None, None, _('Podcast')),
|
||||
('filesize_prop', 'length', gobject.TYPE_INT, _('Size')),
|
||||
('pubdate_prop', 'pubDate', gobject.TYPE_INT, _('Released')),
|
||||
('played_prop', None, None, _('Status')),
|
||||
('age_prop', None, None, _('Downloaded')),
|
||||
)
|
||||
)
|
||||
|
||||
selection_buttons = {
|
||||
_('Select played'): lambda episode: episode.is_played,
|
||||
_('Select older than %d days') % self.config.episode_old_age: lambda episode: episode.age_in_days() > self.config.episode_old_age,
|
||||
}
|
||||
|
||||
instructions = _('Select the episodes you want to delete from your hard disk.')
|
||||
instructions = _('Select the episodes you want to delete:')
|
||||
|
||||
episodes = []
|
||||
selected = []
|
||||
|
@ -2171,14 +2177,19 @@ class gPodder(BuilderWidget, dbus.service.Object):
|
|||
self.update_downloads_list()
|
||||
|
||||
def new_episodes_show(self, episodes):
|
||||
columns = (
|
||||
if gpodder.interface == gpodder.MAEMO:
|
||||
columns = (
|
||||
('maemo_markup', None, None, _('Episode')),
|
||||
)
|
||||
else:
|
||||
columns = (
|
||||
('title_markup', None, None, _('Episode')),
|
||||
('channel_prop', None, None, _('Podcast')),
|
||||
('filesize_prop', 'length', gobject.TYPE_INT, _('Size')),
|
||||
('pubdate_prop', 'pubDate', gobject.TYPE_INT, _('Released')),
|
||||
)
|
||||
)
|
||||
|
||||
instructions = _('Select the episodes you want to download now.')
|
||||
instructions = _('Select the episodes you want to download:')
|
||||
|
||||
gPodderEpisodeSelector(self.gPodder, title=_('New episodes available'), instructions=instructions, \
|
||||
episodes=episodes, columns=columns, selected_default=True, \
|
||||
|
|
|
@ -718,6 +718,32 @@ class PodcastEpisode(PodcastModelObject):
|
|||
def title_markup(self):
|
||||
return self.format_episode_row_markup(False)
|
||||
|
||||
@property
|
||||
def maemo_markup(self):
|
||||
return ('<b>%s</b>\n<small>%s; '+_('released %s')+ \
|
||||
'; '+_('from %s')+'</small>') % (\
|
||||
xml.sax.saxutils.escape(self.title), \
|
||||
xml.sax.saxutils.escape(self.filesize_prop), \
|
||||
xml.sax.saxutils.escape(self.pubdate_prop), \
|
||||
xml.sax.saxutils.escape(self.channel.title))
|
||||
|
||||
@property
|
||||
def maemo_remove_markup(self):
|
||||
if self.is_played:
|
||||
played_string = _('played')
|
||||
else:
|
||||
played_string = _('unplayed')
|
||||
downloaded_string = self.get_age_string()
|
||||
if not downloaded_string:
|
||||
downloaded_string = _('today')
|
||||
return ('<b>%s</b>\n<small>%s; %s; '+_('downloaded %s')+ \
|
||||
'; '+_('from %s')+'</small>') % (\
|
||||
xml.sax.saxutils.escape(self.title), \
|
||||
xml.sax.saxutils.escape(self.filesize_prop), \
|
||||
xml.sax.saxutils.escape(played_string), \
|
||||
xml.sax.saxutils.escape(downloaded_string), \
|
||||
xml.sax.saxutils.escape(self.channel.title))
|
||||
|
||||
def age_in_days(self):
|
||||
return util.file_age_in_days(self.local_filename(create=False))
|
||||
|
||||
|
|
Loading…
Reference in New Issue