2007-04-01 19:53:04 +02:00
# -*- coding: utf-8 -*-
2005-11-21 19:21:25 +01:00
#
2007-08-29 20:30:26 +02:00
# gPodder - A media aggregator and podcast client
Sat, 29 Mar 2008 17:13:26 +0100 <thp@perli.net>
Project management updates (authors, contributors and copyright)
* AUTHORS: Removed (was outdated); content now in gui.py (AboutDialog)
* bin/gpodder, data/po/Makefile, doc/dev/copyright_notice,
doc/dev/win32/setup-win32.py, INSTALL, Makefile, README,
setup.py: Updated Copyright and old website URL to include 2008, the
gPodder team and www.gpodder.org
* src/gpodder/*.py: Updated Copyright years
* src/gpodder/gui.py: Add list of contributors from AUTHORS file and
from the content on the website's news page (please mail me if I
forgot to mention you as a contributor, I surely have missed a few);
make the AboutDialog's application name "gPodder" (from gpodder) and
add an URL hook function to the AboutDialog, so the website is opened
in the user's default web browser
git-svn-id: svn://svn.berlios.de/gpodder/trunk@648 b0d088ad-0a06-0410-aad2-9ed5178a7e87
2008-03-29 17:16:55 +01:00
# Copyright (c) 2005-2008 Thomas Perl and the gPodder Team
2006-04-07 22:22:30 +02:00
#
2007-08-29 20:30:26 +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.
2006-04-07 22:22:30 +02:00
#
2007-08-29 20:30:26 +02:00
# gPodder is distributed in the hope that it will be useful,
2006-04-07 22:22:30 +02:00
# 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
2007-08-29 20:30:26 +02:00
# along with this program. If not, see <http://www.gnu.org/licenses/>.
2005-11-21 19:21:25 +01:00
#
import os
import gtk
2007-01-28 10:21:39 +01:00
import gtk . gdk
2005-11-21 19:21:25 +01:00
import gobject
2006-11-20 12:51:20 +01:00
import pango
2005-11-21 19:21:25 +01:00
import sys
2007-04-23 17:18:31 +02:00
import shutil
2008-01-21 10:52:09 +01:00
import subprocess
2008-03-03 23:09:34 +01:00
import glob
2008-03-20 11:24:26 +01:00
import time
2006-03-04 21:45:01 +01:00
2007-07-05 23:07:16 +02:00
from xml . sax import saxutils
2005-11-21 19:21:25 +01:00
from threading import Event
2006-04-07 03:43:06 +02:00
from threading import Thread
2006-03-04 21:45:01 +01:00
from string import strip
2005-11-21 19:21:25 +01:00
2008-04-06 02:19:03 +02:00
import gpodder
2007-08-07 20:11:31 +02:00
from gpodder import util
2007-08-19 16:28:24 +02:00
from gpodder import opml
2007-08-24 16:49:41 +02:00
from gpodder import services
2008-01-28 12:38:53 +01:00
from gpodder import sync
2007-09-18 20:25:25 +02:00
from gpodder import download
2007-08-28 00:18:01 +02:00
from gpodder import SimpleGladeApp
2008-03-11 18:45:52 +01:00
from gpodder . liblogger import log
try :
from gpodder import trayicon
have_trayicon = True
except Exception , exc :
2008-04-22 22:24:19 +02:00
log ( ' Warning: Could not import gpodder.trayicon. ' , traceback = True )
2008-03-11 18:45:52 +01:00
log ( ' Warning: This probably means your PyGTK installation is too old! ' )
have_trayicon = False
2005-11-21 19:21:25 +01:00
from libpodcasts import podcastChannel
2007-11-27 23:04:15 +01:00
from libpodcasts import channels_to_model
2007-08-20 15:45:46 +02:00
from libpodcasts import load_channels
from libpodcasts import save_channels
2005-11-21 19:21:25 +01:00
2008-03-02 14:22:29 +01:00
from gpodder . libgpodder import gl
2005-11-21 19:21:25 +01:00
2006-03-30 00:07:27 +02:00
from libplayers import UserAppsReader
2007-03-17 13:11:13 +01:00
from libtagupdate import tagging_supported
2008-04-06 02:19:03 +02:00
if gpodder . interface == gpodder . GUI :
WEB_BROWSER_ICON = ' web-browser '
elif gpodder . interface == gpodder . MAEMO :
import hildon
WEB_BROWSER_ICON = ' qgn_toolb_browser_web '
2005-11-21 19:21:25 +01:00
app_name = " gpodder "
app_version = " unknown " # will be set in main() call
Sat, 29 Mar 2008 17:13:26 +0100 <thp@perli.net>
Project management updates (authors, contributors and copyright)
* AUTHORS: Removed (was outdated); content now in gui.py (AboutDialog)
* bin/gpodder, data/po/Makefile, doc/dev/copyright_notice,
doc/dev/win32/setup-win32.py, INSTALL, Makefile, README,
setup.py: Updated Copyright and old website URL to include 2008, the
gPodder team and www.gpodder.org
* src/gpodder/*.py: Updated Copyright years
* src/gpodder/gui.py: Add list of contributors from AUTHORS file and
from the content on the website's news page (please mail me if I
forgot to mention you as a contributor, I surely have missed a few);
make the AboutDialog's application name "gPodder" (from gpodder) and
add an URL hook function to the AboutDialog, so the website is opened
in the user's default web browser
git-svn-id: svn://svn.berlios.de/gpodder/trunk@648 b0d088ad-0a06-0410-aad2-9ed5178a7e87
2008-03-29 17:16:55 +01:00
app_authors = [
_ ( ' Current maintainer: ' ) , ' Thomas Perl <thpinfo.com> ' ,
' ' ,
_ ( ' Patches, bug reports and donations by: ' ) , ' Adrien Beaucreux ' ,
' Alain Tauch ' , ' Alistair Sutton ' , ' Anders Kvist ' , ' Andy Busch ' ,
' Antonio Roversi ' , ' Aravind Seshadri ' , ' Atte André Jensen ' ,
' Bernd Schlapsi ' , ' Bill Barnard ' , ' Bjørn Rasmussen ' , ' Camille Moncelier ' ,
2008-04-22 21:57:02 +02:00
' Carlos Moffat ' , ' Chris ' , ' Chris Arnold ' , ' Clark Burbidge ' ,
2008-06-05 18:11:25 +02:00
' David Spreen ' , ' Doug Hellmann ' , ' FFranci72 ' , ' Florian Richter ' , ' Frank Harper ' ,
2008-05-02 17:36:43 +02:00
' FriedBunny ' , ' Gerrit Sangel ' , ' Götz Waschk ' ,
Sat, 29 Mar 2008 17:13:26 +0100 <thp@perli.net>
Project management updates (authors, contributors and copyright)
* AUTHORS: Removed (was outdated); content now in gui.py (AboutDialog)
* bin/gpodder, data/po/Makefile, doc/dev/copyright_notice,
doc/dev/win32/setup-win32.py, INSTALL, Makefile, README,
setup.py: Updated Copyright and old website URL to include 2008, the
gPodder team and www.gpodder.org
* src/gpodder/*.py: Updated Copyright years
* src/gpodder/gui.py: Add list of contributors from AUTHORS file and
from the content on the website's news page (please mail me if I
forgot to mention you as a contributor, I surely have missed a few);
make the AboutDialog's application name "gPodder" (from gpodder) and
add an URL hook function to the AboutDialog, so the website is opened
in the user's default web browser
git-svn-id: svn://svn.berlios.de/gpodder/trunk@648 b0d088ad-0a06-0410-aad2-9ed5178a7e87
2008-03-29 17:16:55 +01:00
' Haim Roitgrund ' , ' Hex ' , ' Holger Bauer ' , ' Holger Leskien ' , ' Jens Thiele ' ,
2008-05-05 15:55:27 +02:00
' Jérôme Chabod ' , ' Jerry Moss ' ,
' Jessica Henline ' , ' João Trindade ' , ' Joel Calado ' , ' John Ferguson ' ,
2008-04-23 22:33:27 +02:00
' José Luis Fustel ' , ' Joseph Bleau ' , ' Julio Acuña ' , ' Junio C Hamano ' ,
2008-06-13 14:30:42 +02:00
' Jürgen Schinker ' , ' Justin Forest ' ,
2008-05-25 17:11:49 +02:00
' Konstantin Ryabitsev ' , ' Leonid Ponomarev ' , ' Marcos Hernández ' , ' Mark Alford ' , ' Michael Salim ' ,
Sat, 29 Mar 2008 17:13:26 +0100 <thp@perli.net>
Project management updates (authors, contributors and copyright)
* AUTHORS: Removed (was outdated); content now in gui.py (AboutDialog)
* bin/gpodder, data/po/Makefile, doc/dev/copyright_notice,
doc/dev/win32/setup-win32.py, INSTALL, Makefile, README,
setup.py: Updated Copyright and old website URL to include 2008, the
gPodder team and www.gpodder.org
* src/gpodder/*.py: Updated Copyright years
* src/gpodder/gui.py: Add list of contributors from AUTHORS file and
from the content on the website's news page (please mail me if I
forgot to mention you as a contributor, I surely have missed a few);
make the AboutDialog's application name "gPodder" (from gpodder) and
add an URL hook function to the AboutDialog, so the website is opened
in the user's default web browser
git-svn-id: svn://svn.berlios.de/gpodder/trunk@648 b0d088ad-0a06-0410-aad2-9ed5178a7e87
2008-03-29 17:16:55 +01:00
' Mika Leppinen ' , ' Mike Coulson ' , ' Mykola Nikishov ' , ' narf at inode.at ' ,
2008-03-30 10:50:34 +02:00
' Nick L. ' , ' Nicolas Quienot ' , ' Ondrej Vesely ' ,
Sat, 29 Mar 2008 17:13:26 +0100 <thp@perli.net>
Project management updates (authors, contributors and copyright)
* AUTHORS: Removed (was outdated); content now in gui.py (AboutDialog)
* bin/gpodder, data/po/Makefile, doc/dev/copyright_notice,
doc/dev/win32/setup-win32.py, INSTALL, Makefile, README,
setup.py: Updated Copyright and old website URL to include 2008, the
gPodder team and www.gpodder.org
* src/gpodder/*.py: Updated Copyright years
* src/gpodder/gui.py: Add list of contributors from AUTHORS file and
from the content on the website's news page (please mail me if I
forgot to mention you as a contributor, I surely have missed a few);
make the AboutDialog's application name "gPodder" (from gpodder) and
add an URL hook function to the AboutDialog, so the website is opened
in the user's default web browser
git-svn-id: svn://svn.berlios.de/gpodder/trunk@648 b0d088ad-0a06-0410-aad2-9ed5178a7e87
2008-03-29 17:16:55 +01:00
' Ortwin Forster ' , ' Paul Elliot ' , ' Paul Rudkin ' ,
2008-04-13 08:04:51 +02:00
' Pavel Mlčoch ' , ' Peter Hoffmann ' , ' Philippe Gouaillier ' , ' Pieter de Decker ' ,
Sat, 29 Mar 2008 17:13:26 +0100 <thp@perli.net>
Project management updates (authors, contributors and copyright)
* AUTHORS: Removed (was outdated); content now in gui.py (AboutDialog)
* bin/gpodder, data/po/Makefile, doc/dev/copyright_notice,
doc/dev/win32/setup-win32.py, INSTALL, Makefile, README,
setup.py: Updated Copyright and old website URL to include 2008, the
gPodder team and www.gpodder.org
* src/gpodder/*.py: Updated Copyright years
* src/gpodder/gui.py: Add list of contributors from AUTHORS file and
from the content on the website's news page (please mail me if I
forgot to mention you as a contributor, I surely have missed a few);
make the AboutDialog's application name "gPodder" (from gpodder) and
add an URL hook function to the AboutDialog, so the website is opened
in the user's default web browser
git-svn-id: svn://svn.berlios.de/gpodder/trunk@648 b0d088ad-0a06-0410-aad2-9ed5178a7e87
2008-03-29 17:16:55 +01:00
' Preben Randhol ' , ' Rafael Proença ' , ' red26wings ' , ' Richard Voigt ' ,
2008-05-12 11:07:05 +02:00
' Robert Young ' , ' Roel Groeneveld ' ,
2008-05-12 11:29:05 +02:00
' Scott Wegner ' , ' Seth Remington ' , ' Shane Donohoe ' , ' SPGoetze ' ,
2008-05-10 16:47:29 +02:00
' Stefan Lohmaier ' , ' Stephan Buys ' , ' Stylianos Papanastasiou ' , ' Teo Ramirez ' ,
Sat, 29 Mar 2008 17:13:26 +0100 <thp@perli.net>
Project management updates (authors, contributors and copyright)
* AUTHORS: Removed (was outdated); content now in gui.py (AboutDialog)
* bin/gpodder, data/po/Makefile, doc/dev/copyright_notice,
doc/dev/win32/setup-win32.py, INSTALL, Makefile, README,
setup.py: Updated Copyright and old website URL to include 2008, the
gPodder team and www.gpodder.org
* src/gpodder/*.py: Updated Copyright years
* src/gpodder/gui.py: Add list of contributors from AUTHORS file and
from the content on the website's news page (please mail me if I
forgot to mention you as a contributor, I surely have missed a few);
make the AboutDialog's application name "gPodder" (from gpodder) and
add an URL hook function to the AboutDialog, so the website is opened
in the user's default web browser
git-svn-id: svn://svn.berlios.de/gpodder/trunk@648 b0d088ad-0a06-0410-aad2-9ed5178a7e87
2008-03-29 17:16:55 +01:00
' Thomas Matthijs ' , ' Thomas Mills Hinkle ' , ' Thomas Nilsson ' ,
2008-04-13 08:14:01 +02:00
' Tim Michelsen ' , ' Tim Preetz ' , ' Todd Zullinger ' , ' Tomas Matheson ' , ' VladDrac ' ,
Sat, 29 Mar 2008 17:13:26 +0100 <thp@perli.net>
Project management updates (authors, contributors and copyright)
* AUTHORS: Removed (was outdated); content now in gui.py (AboutDialog)
* bin/gpodder, data/po/Makefile, doc/dev/copyright_notice,
doc/dev/win32/setup-win32.py, INSTALL, Makefile, README,
setup.py: Updated Copyright and old website URL to include 2008, the
gPodder team and www.gpodder.org
* src/gpodder/*.py: Updated Copyright years
* src/gpodder/gui.py: Add list of contributors from AUTHORS file and
from the content on the website's news page (please mail me if I
forgot to mention you as a contributor, I surely have missed a few);
make the AboutDialog's application name "gPodder" (from gpodder) and
add an URL hook function to the AboutDialog, so the website is opened
in the user's default web browser
git-svn-id: svn://svn.berlios.de/gpodder/trunk@648 b0d088ad-0a06-0410-aad2-9ed5178a7e87
2008-03-29 17:16:55 +01:00
' Vladimir Zemlyakov ' , ' Wilfred van Rooijen ' ,
' ' ,
' List may be incomplete - please contact me. '
]
app_copyright = ' © 2005-2008 Thomas Perl and the gPodder Team '
2008-03-03 20:38:22 +01:00
app_website = ' http://www.gpodder.org/ '
2005-11-21 19:21:25 +01:00
2007-03-18 17:11:34 +01:00
# these will be filled with pathnames in bin/gpodder
glade_dir = [ ' share ' , ' gpodder ' ]
icon_dir = [ ' share ' , ' pixmaps ' , ' gpodder.png ' ]
2007-03-25 21:55:28 +02:00
scalable_dir = [ ' share ' , ' icons ' , ' hicolor ' , ' scalable ' , ' apps ' , ' gpodder.svg ' ]
2005-11-21 19:21:25 +01:00
2006-03-29 13:33:56 +02:00
2007-08-28 00:18:01 +02:00
class GladeWidget ( SimpleGladeApp . SimpleGladeApp ) :
gpodder_main_window = None
2008-04-24 18:28:39 +02:00
finger_friendly_widgets = [ ]
2007-08-28 00:18:01 +02:00
def __init__ ( self , * * kwargs ) :
path = os . path . join ( glade_dir , ' %s .glade ' % app_name )
root = self . __class__ . __name__
domain = app_name
SimpleGladeApp . SimpleGladeApp . __init__ ( self , path , root , domain , * * kwargs )
2008-04-24 18:28:39 +02:00
# Set widgets to finger-friendly mode if on Maemo
for widget_name in self . finger_friendly_widgets :
self . set_finger_friendly ( getattr ( self , widget_name ) )
2007-08-28 00:18:01 +02:00
if root == ' gPodder ' :
GladeWidget . gpodder_main_window = self . gPodder
else :
# If we have a child window, set it transient for our main window
getattr ( self , root ) . set_transient_for ( GladeWidget . gpodder_main_window )
2007-11-08 20:11:57 +01:00
2008-04-06 02:19:03 +02:00
if gpodder . interface == gpodder . GUI :
if hasattr ( self , ' center_on_widget ' ) :
( x , y ) = self . gpodder_main_window . get_position ( )
a = self . center_on_widget . allocation
( x , y ) = ( x + a . x , y + a . y )
( w , h ) = ( a . width , a . height )
( pw , ph ) = getattr ( self , root ) . get_size ( )
getattr ( self , root ) . move ( x + w / 2 - pw / 2 , y + h / 2 - ph / 2 )
else :
getattr ( self , root ) . set_position ( gtk . WIN_POS_CENTER_ON_PARENT )
2007-08-28 00:18:01 +02:00
2008-01-15 14:54:22 +01:00
def notification ( self , message , title = None ) :
util . idle_add ( self . show_message , message , title )
2007-11-05 13:55:36 +01:00
2007-08-28 00:18:01 +02:00
def show_message ( self , message , title = None ) :
2008-01-24 14:52:37 +01:00
if hasattr ( self , ' tray_icon ' ) and hasattr ( self , ' minimized ' ) and self . tray_icon and self . minimized :
2008-01-23 09:08:13 +01:00
if title is None :
title = ' gPodder '
2008-02-04 11:29:41 +01:00
self . tray_icon . send_notification ( message , title )
2008-01-23 09:08:13 +01:00
return
2008-04-06 02:19:03 +02:00
if gpodder . interface == gpodder . GUI :
dlg = gtk . MessageDialog ( GladeWidget . gpodder_main_window , gtk . DIALOG_MODAL , gtk . MESSAGE_INFO , gtk . BUTTONS_OK )
if title :
dlg . set_title ( str ( title ) )
dlg . set_markup ( ' <span weight= " bold " size= " larger " > %s </span> \n \n %s ' % ( title , message ) )
else :
dlg . set_markup ( ' <span weight= " bold " size= " larger " > %s </span> ' % ( message ) )
elif gpodder . interface == gpodder . MAEMO :
dlg = hildon . Note ( ' information ' , ( GladeWidget . gpodder_main_window , message ) )
2007-08-28 00:18:01 +02:00
dlg . run ( )
dlg . destroy ( )
2008-04-24 18:28:39 +02:00
def set_finger_friendly ( self , widget ) :
"""
If we are on Maemo , we carry out the necessary
operations to turn a widget into a finger - friendly
one , depending on which type of widget it is ( i . e .
buttons will have more padding , TreeViews a thick
scrollbar , etc . . )
"""
if gpodder . interface == gpodder . MAEMO :
if isinstance ( widget , gtk . Misc ) :
widget . set_padding ( 0 , 5 )
elif isinstance ( widget , gtk . Button ) :
for child in widget . get_children ( ) :
if isinstance ( child , gtk . Alignment ) :
child . set_padding ( 10 , 10 , 5 , 5 )
else :
child . set_padding ( 10 , 10 )
elif isinstance ( widget , gtk . TreeView ) or isinstance ( widget , gtk . TextView ) :
parent = widget . get_parent ( )
if isinstance ( parent , gtk . ScrolledWindow ) :
hildon . hildon_helper_set_thumb_scrollbar ( parent , True )
elif isinstance ( widget , gtk . MenuItem ) :
for child in widget . get_children ( ) :
self . set_finger_friendly ( child )
else :
log ( ' Cannot set widget finger-friendly: %s ' , widget , sender = self )
return widget
2007-08-28 00:18:01 +02:00
def show_confirmation ( self , message , title = None ) :
2008-04-06 02:19:03 +02:00
if gpodder . interface == gpodder . GUI :
affirmative = gtk . RESPONSE_YES
dlg = gtk . MessageDialog ( GladeWidget . gpodder_main_window , gtk . DIALOG_MODAL , gtk . MESSAGE_QUESTION , gtk . BUTTONS_YES_NO )
if title :
dlg . set_title ( str ( title ) )
dlg . set_markup ( ' <span weight= " bold " size= " larger " > %s </span> \n \n %s ' % ( title , message ) )
else :
dlg . set_markup ( ' <span weight= " bold " size= " larger " > %s </span> ' % ( message ) )
elif gpodder . interface == gpodder . MAEMO :
affirmative = gtk . RESPONSE_OK
dlg = hildon . Note ( ' confirmation ' , ( GladeWidget . gpodder_main_window , message ) )
2007-08-28 00:18:01 +02:00
response = dlg . run ( )
dlg . destroy ( )
2008-04-06 02:19:03 +02:00
return response == affirmative
2007-08-28 00:18:01 +02:00
2007-10-28 15:30:11 +01:00
def show_copy_dialog ( self , src_filename , dst_filename = None , dst_directory = None , title = _ ( ' Select destination ' ) ) :
2008-02-26 16:49:59 +01:00
if dst_filename is None :
2007-10-28 15:30:11 +01:00
dst_filename = src_filename
2008-02-26 16:49:59 +01:00
if dst_directory is None :
2007-10-28 15:30:11 +01:00
dst_directory = os . path . expanduser ( ' ~ ' )
( base , extension ) = os . path . splitext ( src_filename )
if not dst_filename . endswith ( extension ) :
dst_filename + = extension
2008-05-02 17:36:43 +02:00
if gpodder . interface == gpodder . GUI :
dlg = gtk . FileChooserDialog ( title = title , parent = GladeWidget . gpodder_main_window , action = gtk . FILE_CHOOSER_ACTION_SAVE )
dlg . add_button ( gtk . STOCK_CANCEL , gtk . RESPONSE_CANCEL )
dlg . add_button ( gtk . STOCK_SAVE , gtk . RESPONSE_OK )
elif gpodder . interface == gpodder . MAEMO :
dlg = hildon . FileChooserDialog ( GladeWidget . gpodder_main_window , gtk . FILE_CHOOSER_ACTION_SAVE )
2007-10-28 15:30:11 +01:00
2008-05-02 17:36:43 +02:00
dlg . set_do_overwrite_confirmation ( True )
2007-10-28 15:30:11 +01:00
dlg . set_current_name ( os . path . basename ( dst_filename ) )
dlg . set_current_folder ( dst_directory )
if dlg . run ( ) == gtk . RESPONSE_OK :
dst_filename = dlg . get_filename ( )
if not dst_filename . endswith ( extension ) :
dst_filename + = extension
log ( ' Copying %s => %s ' , src_filename , dst_filename , sender = self )
try :
shutil . copyfile ( src_filename , dst_filename )
except :
2008-04-22 22:24:19 +02:00
log ( ' Error copying file. ' , sender = self , traceback = True )
2007-10-28 15:30:11 +01:00
dlg . destroy ( )
2006-03-31 18:20:18 +02:00
2005-11-21 19:21:25 +01:00
2007-08-28 00:18:01 +02:00
class gPodder ( GladeWidget ) :
2008-04-24 18:28:39 +02:00
finger_friendly_widgets = [ ' btnUpdateFeeds ' , ' btnCancelFeedUpdate ' , ' treeAvailable ' , ' label2 ' , ' labelDownloads ' ]
2008-05-02 17:36:43 +02:00
ENTER_URL_TEXT = _ ( ' Enter podcast URL... ' )
2008-04-24 18:28:39 +02:00
2005-11-21 19:21:25 +01:00
def new ( self ) :
2008-04-06 02:19:03 +02:00
if gpodder . interface == gpodder . MAEMO :
# Maemo-specific changes to the UI
global scalable_dir
scalable_dir = scalable_dir . replace ( ' .svg ' , ' .png ' )
self . app = hildon . Program ( )
gtk . set_application_name ( ' gPodder ' )
self . window = hildon . Window ( )
self . window . connect ( ' delete-event ' , self . on_gPodder_delete_event )
self . window . connect ( ' window-state-event ' , self . window_state_event )
self . window . connect ( ' key-press-event ' , self . on_key_press )
# Give toolbar to the hildon window
self . toolbar . parent . remove ( self . toolbar )
self . toolbar . set_style ( gtk . TOOLBAR_ICONS )
self . window . add_toolbar ( self . toolbar )
self . app . add_window ( self . window )
self . vMain . reparent ( self . window )
self . gPodder = self . window
# Reparent the main menu
menu = gtk . Menu ( )
for child in self . mainMenu . get_children ( ) :
child . reparent ( menu )
2008-04-11 10:29:13 +02:00
self . itemQuit . reparent ( menu )
2008-04-06 02:19:03 +02:00
self . window . set_menu ( menu )
self . mainMenu . destroy ( )
2008-04-22 20:34:41 +02:00
self . window . show ( )
2008-04-06 02:19:03 +02:00
# do some widget hiding
self . toolbar . remove ( self . toolTransfer )
self . itemTransferSelected . hide_all ( )
2008-05-02 17:36:43 +02:00
self . item_show_url_entry . hide_all ( )
2008-05-02 17:45:45 +02:00
self . item_email_subscriptions . hide_all ( )
2008-04-22 20:34:41 +02:00
# Feed cache update button
2008-04-24 19:42:57 +02:00
self . label120 . set_text ( _ ( ' Update ' ) )
2008-04-24 18:28:39 +02:00
# get screen real estate
self . hboxContainer . set_border_width ( 0 )
2008-05-02 17:36:43 +02:00
self . treeChannels . connect ( ' size-allocate ' , self . on_tree_channels_resize )
if gpodder . interface == gpodder . MAEMO or not gl . config . show_podcast_url_entry :
self . hboxAddChannel . hide_all ( )
if not gl . config . show_toolbar :
self . toolbar . hide_all ( )
gl . config . add_observer ( self . on_config_changed )
self . default_entry_text_color = self . entryAddChannel . get_style ( ) . text [ gtk . STATE_NORMAL ]
self . entryAddChannel . connect ( ' focus-in-event ' , self . entry_add_channel_focus )
self . entryAddChannel . connect ( ' focus-out-event ' , self . entry_add_channel_unfocus )
self . entry_add_channel_unfocus ( self . entryAddChannel , None )
2008-04-06 02:19:03 +02:00
2007-08-28 00:18:01 +02:00
self . uar = None
2008-03-20 11:24:26 +01:00
self . tray_icon = None
2007-08-28 00:18:01 +02:00
2008-04-06 02:19:03 +02:00
self . fullscreen = False
2008-01-09 23:46:17 +01:00
self . minimized = False
self . gPodder . connect ( ' window-state-event ' , self . window_state_event )
2008-02-04 11:29:41 +01:00
self . already_notified_new_episodes = [ ]
2008-04-15 20:59:22 +02:00
self . show_hide_tray_icon ( )
2008-05-02 17:36:43 +02:00
self . no_episode_selected . set_sensitive ( False )
2008-02-06 10:29:56 +01:00
self . itemShowToolbar . set_active ( gl . config . show_toolbar )
self . itemShowDescription . set_active ( gl . config . episode_list_descriptions )
2008-05-02 17:36:43 +02:00
self . item_show_url_entry . set_active ( gl . config . show_podcast_url_entry )
2008-01-09 23:46:17 +01:00
2007-11-02 17:37:14 +01:00
gl . config . connect_gtk_window ( self . gPodder )
gl . config . connect_gtk_paned ( ' paned_position ' , self . channelPaned )
2008-04-17 17:45:29 +02:00
gl . config . connect_gtk_spinbutton ( ' max_downloads ' , self . spinMaxDownloads )
gl . config . connect_gtk_togglebutton ( ' max_downloads_enabled ' , self . cbMaxDownloads )
gl . config . connect_gtk_spinbutton ( ' limit_rate_value ' , self . spinLimitDownloads )
gl . config . connect_gtk_togglebutton ( ' limit_rate ' , self . cbLimitDownloads )
# Make sure we free/close the download queue when we
# update the "max downloads" spin button
changed_cb = lambda spinbutton : services . download_status_manager . update_max_downloads ( )
self . spinMaxDownloads . connect ( ' value-changed ' , changed_cb )
2008-04-06 02:19:03 +02:00
self . default_title = None
if app_version . rfind ( ' svn ' ) != - 1 :
self . set_title ( ' gPodder %s ' % app_version )
else :
self . set_title ( self . gPodder . get_title ( ) )
2007-09-02 15:02:28 +02:00
Sat, 29 Mar 2008 17:13:26 +0100 <thp@perli.net>
Project management updates (authors, contributors and copyright)
* AUTHORS: Removed (was outdated); content now in gui.py (AboutDialog)
* bin/gpodder, data/po/Makefile, doc/dev/copyright_notice,
doc/dev/win32/setup-win32.py, INSTALL, Makefile, README,
setup.py: Updated Copyright and old website URL to include 2008, the
gPodder team and www.gpodder.org
* src/gpodder/*.py: Updated Copyright years
* src/gpodder/gui.py: Add list of contributors from AUTHORS file and
from the content on the website's news page (please mail me if I
forgot to mention you as a contributor, I surely have missed a few);
make the AboutDialog's application name "gPodder" (from gpodder) and
add an URL hook function to the AboutDialog, so the website is opened
in the user's default web browser
git-svn-id: svn://svn.berlios.de/gpodder/trunk@648 b0d088ad-0a06-0410-aad2-9ed5178a7e87
2008-03-29 17:16:55 +01:00
gtk . about_dialog_set_url_hook ( lambda dlg , link , data : util . open_website ( link ) , None )
2007-03-07 15:53:05 +01:00
2007-07-05 23:07:16 +02:00
# cell renderers for channel tree
2008-05-02 17:36:43 +02:00
namecolumn = gtk . TreeViewColumn ( _ ( ' Podcast ' ) )
2007-07-05 23:07:16 +02:00
iconcell = gtk . CellRendererPixbuf ( )
namecolumn . pack_start ( iconcell , False )
2007-11-27 23:04:15 +01:00
namecolumn . add_attribute ( iconcell , ' pixbuf ' , 5 )
2008-04-24 19:42:57 +02:00
self . cell_channel_icon = iconcell
2007-07-05 23:07:16 +02:00
namecell = gtk . CellRendererText ( )
namecell . set_property ( ' ellipsize ' , pango . ELLIPSIZE_END )
namecolumn . pack_start ( namecell , True )
2007-11-27 23:04:15 +01:00
namecolumn . add_attribute ( namecell , ' markup ' , 2 )
2007-07-05 23:07:16 +02:00
namecolumn . add_attribute ( namecell , ' weight ' , 4 )
2007-11-27 23:04:15 +01:00
iconcell = gtk . CellRendererPixbuf ( )
namecolumn . pack_start ( iconcell , False )
namecolumn . add_attribute ( iconcell , ' pixbuf ' , 3 )
2008-04-24 19:42:57 +02:00
self . cell_channel_pill = iconcell
2007-07-05 23:07:16 +02:00
self . treeChannels . append_column ( namecolumn )
2008-04-06 02:19:03 +02:00
self . treeChannels . set_headers_visible ( False )
2005-11-21 19:21:25 +01:00
2007-04-03 08:27:46 +02:00
# enable alternating colors hint
self . treeAvailable . set_rules_hint ( True )
2007-09-19 17:04:42 +02:00
self . treeChannels . set_rules_hint ( True )
2007-04-03 08:27:46 +02:00
2007-11-14 21:57:31 +01:00
# connect to tooltip signals
2007-11-17 18:43:23 +01:00
try :
self . treeChannels . set_property ( ' has-tooltip ' , True )
self . treeChannels . connect ( ' query-tooltip ' , self . treeview_channels_query_tooltip )
except :
log ( ' No tooltips for channel navigator (need at least PyGTK 2.12) ' , sender = self )
2007-11-14 21:57:31 +01:00
self . last_tooltip_channel = None
2007-08-26 17:20:46 +02:00
# Add our context menu to treeAvailable
2008-04-06 02:19:03 +02:00
if gpodder . interface == gpodder . MAEMO :
self . treeAvailable . connect ( ' button-release-event ' , self . treeview_button_pressed )
else :
self . treeAvailable . connect ( ' button-press-event ' , self . treeview_button_pressed )
2007-09-15 16:29:37 +02:00
self . treeChannels . connect ( ' button-press-event ' , self . treeview_channels_button_pressed )
2007-08-26 17:20:46 +02:00
2007-04-03 08:27:46 +02:00
iconcell = gtk . CellRendererPixbuf ( )
2008-04-06 02:19:03 +02:00
if gpodder . interface == gpodder . MAEMO :
status_column_label = ' '
else :
status_column_label = _ ( ' Status ' )
iconcolumn = gtk . TreeViewColumn ( status_column_label , iconcell , pixbuf = 4 )
2007-04-03 13:21:12 +02:00
2005-11-22 14:30:28 +01:00
namecell = gtk . CellRendererText ( )
2008-02-06 10:29:56 +01:00
namecell . set_property ( ' ellipsize ' , pango . ELLIPSIZE_END )
namecolumn = gtk . TreeViewColumn ( _ ( " Episode " ) , namecell , markup = 6 )
namecolumn . set_sizing ( gtk . TREE_VIEW_COLUMN_AUTOSIZE )
namecolumn . set_expand ( True )
2005-11-22 14:30:28 +01:00
sizecell = gtk . CellRendererText ( )
2006-03-31 15:00:54 +02:00
sizecolumn = gtk . TreeViewColumn ( _ ( " Size " ) , sizecell , text = 2 )
2006-04-10 18:46:50 +02:00
releasecell = gtk . CellRendererText ( )
releasecolumn = gtk . TreeViewColumn ( _ ( " Released " ) , releasecell , text = 5 )
2005-11-22 14:30:28 +01:00
2008-02-06 10:29:56 +01:00
for itemcolumn in ( iconcolumn , namecolumn , sizecolumn , releasecolumn ) :
itemcolumn . set_reorderable ( True )
self . treeAvailable . append_column ( itemcolumn )
2006-06-22 23:41:32 +02:00
2008-04-06 02:19:03 +02:00
if gpodder . interface == gpodder . MAEMO :
# Due to screen space contraints, we
# hide these columns here by default
self . column_size = sizecolumn
self . column_released = releasecolumn
self . column_released . set_visible ( False )
self . column_size . set_visible ( False )
2007-04-03 08:27:46 +02:00
# enable search in treeavailable
self . treeAvailable . set_search_equal_func ( self . treeAvailable_search_equal )
2006-06-22 23:41:32 +02:00
# enable multiple selection support
self . treeAvailable . get_selection ( ) . set_mode ( gtk . SELECTION_MULTIPLE )
2006-07-06 20:56:43 +02:00
self . treeDownloads . get_selection ( ) . set_mode ( gtk . SELECTION_MULTIPLE )
2006-02-04 18:29:17 +01:00
2005-11-22 23:26:51 +01:00
# columns and renderers for "download progress" tab
2005-11-22 23:04:58 +01:00
episodecell = gtk . CellRendererText ( )
2008-04-06 02:19:03 +02:00
episodecell . set_property ( ' ellipsize ' , pango . ELLIPSIZE_END )
2006-03-31 15:00:54 +02:00
episodecolumn = gtk . TreeViewColumn ( _ ( " Episode " ) , episodecell , text = 0 )
2008-04-06 02:19:03 +02:00
episodecolumn . set_sizing ( gtk . TREE_VIEW_COLUMN_AUTOSIZE )
episodecolumn . set_expand ( True )
2005-11-22 23:26:51 +01:00
2005-11-22 23:04:58 +01:00
speedcell = gtk . CellRendererText ( )
2006-03-31 15:00:54 +02:00
speedcolumn = gtk . TreeViewColumn ( _ ( " Speed " ) , speedcell , text = 1 )
2005-11-22 23:26:51 +01:00
progresscell = gtk . CellRendererProgress ( )
2006-03-31 15:00:54 +02:00
progresscolumn = gtk . TreeViewColumn ( _ ( " Progress " ) , progresscell , value = 2 )
2008-04-06 02:19:03 +02:00
progresscolumn . set_expand ( True )
2005-11-22 23:26:51 +01:00
for itemcolumn in ( episodecolumn , speedcolumn , progresscolumn ) :
2005-11-22 23:04:58 +01:00
self . treeDownloads . append_column ( itemcolumn )
2007-08-24 16:49:41 +02:00
2008-05-10 13:35:06 +02:00
# After we've set up most of the window, show it :)
if not gpodder . interface == gpodder . MAEMO :
self . gPodder . show ( )
2008-06-08 20:10:09 +02:00
if self . tray_icon :
if gl . config . start_iconified :
self . iconify_main_window ( )
elif gl . config . minimize_to_tray :
self . tray_icon . set_visible ( False )
2007-08-24 16:49:41 +02:00
services . download_status_manager . register ( ' list-changed ' , self . download_status_updated )
services . download_status_manager . register ( ' progress-changed ' , self . download_progress_updated )
self . treeDownloads . set_model ( services . download_status_manager . tree_model )
2005-11-22 23:26:51 +01:00
2005-11-22 14:23:50 +01:00
#Add Drag and Drop Support
2007-09-19 17:04:42 +02:00
flags = gtk . DEST_DEFAULT_ALL
targets = [ ( ' text/plain ' , 0 , 2 ) , ( ' STRING ' , 0 , 3 ) , ( ' TEXT ' , 0 , 4 ) ]
actions = gtk . gdk . ACTION_DEFAULT | gtk . gdk . ACTION_COPY
self . treeChannels . drag_dest_set ( flags , targets , actions )
self . treeChannels . connect ( ' drag_data_received ' , self . drag_data_received )
2006-04-04 00:27:57 +02:00
2007-03-10 16:57:56 +01:00
# Subscribed channels
self . active_channel = None
2007-09-18 02:17:44 +02:00
self . channels = load_channels ( load_items = False , offline = True )
2006-12-03 19:11:14 +01:00
2008-01-21 09:57:03 +01:00
# load list of user applications for audio playback
2008-03-20 11:24:26 +01:00
self . user_apps_reader = UserAppsReader ( [ ' audio ' , ' video ' ] )
Thread ( target = self . read_apps ) . start ( )
2006-12-09 03:04:32 +01:00
2006-12-03 19:11:14 +01:00
# Clean up old, orphaned download files
2007-02-03 11:48:32 +01:00
gl . clean_up_downloads ( delete_partial = True )
2007-05-25 12:06:43 +02:00
2007-11-08 20:11:57 +01:00
# Set the "Device" menu item for the first time
self . update_item_device ( )
2007-05-25 12:06:43 +02:00
# Now, update the feed cache, when everything's in place
2008-04-22 20:34:41 +02:00
self . feed_cache_update_cancelled = False
2008-01-09 23:46:17 +01:00
self . update_feed_cache ( force_update = gl . config . update_on_startup )
# Start the auto-update procedure
self . auto_update_procedure ( first_run = True )
2005-11-21 19:21:25 +01:00
2007-12-12 20:57:50 +01:00
# Delete old episodes if the user wishes to
if gl . config . auto_remove_old_episodes :
old_episodes = self . get_old_episodes ( )
if len ( old_episodes ) > 0 :
self . delete_episode_list ( old_episodes , confirm = False )
self . updateComboBox ( )
2008-05-02 17:36:43 +02:00
# First-time users should be asked if they want to see the OPML
if len ( self . channels ) == 0 :
util . idle_add ( self . on_itemUpdate_activate , None )
2008-04-24 19:42:57 +02:00
def on_tree_channels_resize ( self , widget , allocation ) :
2008-05-16 10:03:13 +02:00
if not gl . config . podcast_sidebar_save_space :
return
2008-04-24 19:42:57 +02:00
window_allocation = self . gPodder . get_allocation ( )
percentage = 100. * float ( allocation . width ) / float ( window_allocation . width )
2008-04-29 20:22:55 +02:00
if hasattr ( self , ' cell_channel_icon ' ) :
2008-05-02 17:36:43 +02:00
self . cell_channel_icon . set_property ( ' visible ' , bool ( percentage > 22. ) )
2008-04-29 20:22:55 +02:00
if hasattr ( self , ' cell_channel_pill ' ) :
2008-05-02 17:36:43 +02:00
self . cell_channel_pill . set_property ( ' visible ' , bool ( percentage > 25. ) )
def entry_add_channel_focus ( self , widget , event ) :
widget . modify_text ( gtk . STATE_NORMAL , self . default_entry_text_color )
if widget . get_text ( ) == self . ENTER_URL_TEXT :
widget . set_text ( ' ' )
def entry_add_channel_unfocus ( self , widget , event ) :
if widget . get_text ( ) == ' ' :
widget . set_text ( self . ENTER_URL_TEXT )
widget . modify_text ( gtk . STATE_NORMAL , gtk . gdk . color_parse ( ' #aaaaaa ' ) )
def on_config_changed ( self , name , old_value , new_value ) :
if name == ' show_toolbar ' :
if new_value :
self . toolbar . show_all ( )
else :
self . toolbar . hide_all ( )
elif name == ' episode_list_descriptions ' :
for channel in self . channels :
channel . force_update_tree_model ( )
self . updateTreeView ( )
elif name == ' show_podcast_url_entry ' and gpodder . interface != gpodder . MAEMO :
if new_value :
self . hboxAddChannel . show_all ( )
else :
self . hboxAddChannel . hide_all ( )
2008-04-24 19:42:57 +02:00
2008-03-20 11:24:26 +01:00
def read_apps ( self ) :
time . sleep ( 3 ) # give other parts of gpodder a chance to start up
self . user_apps_reader . read ( )
util . idle_add ( self . user_apps_reader . get_applications_as_model , ' audio ' , False )
util . idle_add ( self . user_apps_reader . get_applications_as_model , ' video ' , False )
2007-12-12 20:57:50 +01:00
2007-11-14 21:57:31 +01:00
def treeview_channels_query_tooltip ( self , treeview , x , y , keyboard_tooltip , tooltip ) :
2008-04-06 17:25:17 +02:00
( path , column , rx , ry ) = treeview . get_path_at_pos ( x , y ) or ( None , ) * 4
2007-11-14 21:57:31 +01:00
if path is not None :
model = treeview . get_model ( )
iter = model . get_iter ( path )
url = model . get_value ( iter , 0 )
for channel in self . channels :
if channel . url == url :
if self . last_tooltip_channel is not None and self . last_tooltip_channel != channel :
self . last_tooltip_channel = None
return False
self . last_tooltip_channel = channel
2008-06-05 18:17:09 +02:00
channel . request_save_dir_size ( )
diskspace_str = gl . format_filesize ( channel . save_dir_size , 0 )
2008-03-29 16:33:18 +01:00
error_str = model . get_value ( iter , 6 )
if error_str :
error_str = _ ( ' Feedparser error: %s ' ) % saxutils . escape ( error_str . strip ( ) )
2008-06-05 18:17:09 +02:00
error_str = ' <span foreground= " #ff0000 " > %s </span> ' % error_str
table = gtk . Table ( rows = 3 , columns = 3 )
table . set_row_spacings ( 5 )
table . set_col_spacings ( 5 )
table . set_border_width ( 5 )
heading = gtk . Label ( )
heading . set_alignment ( 0 , 1 )
heading . set_markup ( ' <b><big> %s </big></b> \n <small> %s </small> ' % ( saxutils . escape ( channel . title ) , saxutils . escape ( channel . url ) ) )
table . attach ( heading , 0 , 1 , 0 , 1 )
size_info = gtk . Label ( )
size_info . set_alignment ( 1 , 1 )
size_info . set_justify ( gtk . JUSTIFY_RIGHT )
size_info . set_markup ( ' <b> %s </b> \n <small> %s </small> ' % ( diskspace_str , _ ( ' disk usage ' ) ) )
table . attach ( size_info , 2 , 3 , 0 , 1 )
table . attach ( gtk . HSeparator ( ) , 0 , 3 , 1 , 2 )
if len ( channel . description ) < 500 :
description = channel . description
else :
pos = channel . description . find ( ' \n \n ' )
if pos == - 1 or pos > 500 :
description = channel . description [ : 498 ] + ' [...] '
else :
description = channel . description [ : pos ]
description = gtk . Label ( description )
if error_str :
description . set_markup ( error_str )
description . set_alignment ( 0 , 0 )
description . set_line_wrap ( True )
table . attach ( description , 0 , 3 , 2 , 3 )
table . show_all ( )
tooltip . set_custom ( table )
2008-05-14 15:38:06 +02:00
2007-11-14 21:57:31 +01:00
return True
self . last_tooltip_channel = None
return False
2008-03-10 16:50:12 +01:00
def update_m3u_playlist_clicked ( self , widget ) :
self . active_channel . update_m3u_playlist ( )
self . show_message ( _ ( ' Updated M3U playlist in download folder. ' ) , _ ( ' Updated playlist ' ) )
2007-09-15 16:29:37 +02:00
def treeview_channels_button_pressed ( self , treeview , event ) :
2008-04-06 02:19:03 +02:00
global WEB_BROWSER_ICON
2007-09-15 16:29:37 +02:00
if event . button == 3 :
( x , y ) = ( int ( event . x ) , int ( event . y ) )
( path , column , rx , ry ) = treeview . get_path_at_pos ( x , y ) or ( None , ) * 4
paths = [ ]
# Did the user right-click into a selection?
selection = treeview . get_selection ( )
if selection . count_selected_rows ( ) and path :
( model , paths ) = selection . get_selected_rows ( )
if path not in paths :
# We have right-clicked, but not into the
# selection, assume we don't want to operate
# on the selection
paths = [ ]
# No selection or right click not in selection:
# Select the single item where we clicked
if not len ( paths ) and path :
treeview . grab_focus ( )
treeview . set_cursor ( path , column , 0 )
( model , paths ) = ( treeview . get_model ( ) , [ path ] )
# We did not find a selection, and the user didn't
# click on an item to select -- don't show the menu
if not len ( paths ) :
return True
menu = gtk . Menu ( )
2007-11-02 07:53:30 +01:00
item = gtk . ImageMenuItem ( _ ( ' Open download folder ' ) )
item . set_image ( gtk . image_new_from_icon_name ( ' folder-open ' , gtk . ICON_SIZE_MENU ) )
2008-03-02 14:04:37 +01:00
item . connect ( ' activate ' , lambda x : util . gui_open ( self . active_channel . save_dir ) )
2007-11-02 07:53:30 +01:00
menu . append ( item )
2008-03-10 16:50:12 +01:00
if gl . config . create_m3u_playlists :
item = gtk . ImageMenuItem ( _ ( ' Update M3U playlist ' ) )
item . set_image ( gtk . image_new_from_stock ( gtk . STOCK_REFRESH , gtk . ICON_SIZE_MENU ) )
item . connect ( ' activate ' , self . update_m3u_playlist_clicked )
menu . append ( item )
2008-03-22 20:43:20 +01:00
if self . active_channel . link :
item = gtk . ImageMenuItem ( _ ( ' Visit website ' ) )
2008-04-06 02:19:03 +02:00
item . set_image ( gtk . image_new_from_icon_name ( WEB_BROWSER_ICON , gtk . ICON_SIZE_MENU ) )
2008-03-22 20:43:20 +01:00
item . connect ( ' activate ' , lambda w : util . open_website ( self . active_channel . link ) )
menu . append ( item )
2007-11-02 07:53:30 +01:00
menu . append ( gtk . SeparatorMenuItem ( ) )
2008-03-22 20:43:20 +01:00
item = gtk . ImageMenuItem ( gtk . STOCK_EDIT )
2007-09-15 16:29:37 +02:00
item . connect ( ' activate ' , self . on_itemEditChannel_activate )
menu . append ( item )
2008-03-22 20:43:20 +01:00
item = gtk . ImageMenuItem ( gtk . STOCK_DELETE )
2007-09-15 16:29:37 +02:00
item . connect ( ' activate ' , self . on_itemRemoveChannel_activate )
menu . append ( item )
menu . show_all ( )
menu . popup ( None , None , None , event . button , event . time )
return True
2008-04-11 10:29:13 +02:00
def on_itemClose_activate ( self , widget ) :
if self . tray_icon is not None :
2008-05-02 17:36:43 +02:00
if gpodder . interface == gpodder . MAEMO :
self . gPodder . set_property ( ' visible ' , False )
else :
self . iconify_main_window ( )
2008-04-11 10:29:13 +02:00
else :
self . on_gPodder_delete_event ( widget )
2007-10-28 15:30:11 +01:00
def save_episode_as_file ( self , url , * args ) :
episode = self . active_channel . find_episode ( url )
self . show_copy_dialog ( src_filename = episode . local_filename ( ) , dst_filename = episode . sync_filename ( ) )
2008-01-21 10:52:09 +01:00
def copy_episode_bluetooth ( self , url , * args ) :
episode = self . active_channel . find_episode ( url )
filename = episode . local_filename ( )
if gl . config . bluetooth_ask_always :
device = None
else :
device = gl . config . bluetooth_device_address
2008-02-27 09:42:38 +01:00
destfile = os . path . join ( gl . tempdir , episode . sync_filename ( ) )
( base , ext ) = os . path . splitext ( filename )
if not destfile . endswith ( ext ) :
destfile + = ext
2008-01-21 10:52:09 +01:00
2008-02-27 09:42:38 +01:00
if gl . config . bluetooth_use_converter :
2008-01-21 10:52:09 +01:00
title = _ ( ' Converting file ' )
message = _ ( ' Please wait while gPodder converts your media file for bluetooth file transfer. ' )
dlg = gtk . MessageDialog ( self . gPodder , gtk . DIALOG_MODAL , gtk . MESSAGE_INFO , gtk . BUTTONS_NONE )
dlg . set_title ( title )
dlg . set_markup ( ' <span weight= " bold " size= " larger " > %s </span> \n \n %s ' % ( title , message ) )
dlg . show_all ( )
2008-02-27 09:42:38 +01:00
else :
dlg = None
2008-01-21 10:52:09 +01:00
2008-02-27 09:42:38 +01:00
def convert_and_send_thread ( filename , destfile , device , dialog , notify ) :
if gl . config . bluetooth_use_converter :
2008-01-21 10:52:09 +01:00
p = subprocess . Popen ( [ gl . config . bluetooth_converter , filename , destfile ] , stdout = sys . stdout , stderr = sys . stderr )
result = p . wait ( )
2008-02-27 09:42:38 +01:00
if dialog is not None :
dialog . destroy ( )
else :
try :
shutil . copyfile ( filename , destfile )
result = 0
except :
2008-03-19 15:43:22 +01:00
log ( ' Cannot copy " %s " to " %s " . ' , filename , destfile , sender = self )
2008-02-27 09:42:38 +01:00
result = 1
if result == 0 or not os . path . exists ( destfile ) :
util . bluetooth_send_file ( destfile , device )
else :
notify ( _ ( ' Error converting file. ' ) , _ ( ' Bluetooth file transfer ' ) )
util . delete_file ( destfile )
Thread ( target = convert_and_send_thread , args = [ filename , destfile , device , dlg , self . notification ] ) . start ( )
2008-01-21 10:52:09 +01:00
2007-08-26 17:20:46 +02:00
def treeview_button_pressed ( self , treeview , event ) :
2008-04-06 02:19:03 +02:00
global WEB_BROWSER_ICON
# Use right-click for the Desktop version and left-click for Maemo
if ( event . button == 1 and gpodder . interface == gpodder . MAEMO ) or \
( event . button == 3 and gpodder . interface == gpodder . GUI ) :
2007-08-26 17:20:46 +02:00
( x , y ) = ( int ( event . x ) , int ( event . y ) )
( path , column , rx , ry ) = treeview . get_path_at_pos ( x , y ) or ( None , ) * 4
paths = [ ]
# Did the user right-click into a selection?
selection = self . treeAvailable . get_selection ( )
if selection . count_selected_rows ( ) and path :
( model , paths ) = selection . get_selected_rows ( )
if path not in paths :
# We have right-clicked, but not into the
# selection, assume we don't want to operate
# on the selection
paths = [ ]
# No selection or right click not in selection:
# Select the single item where we clicked
if not len ( paths ) and path :
treeview . grab_focus ( )
treeview . set_cursor ( path , column , 0 )
( model , paths ) = ( treeview . get_model ( ) , [ path ] )
# We did not find a selection, and the user didn't
# click on an item to select -- don't show the menu
if not len ( paths ) :
return True
2007-08-30 20:54:18 +02:00
first_url = model . get_value ( model . get_iter ( paths [ 0 ] ) , 0 )
2007-08-26 17:20:46 +02:00
menu = gtk . Menu ( )
( can_play , can_download , can_transfer , can_cancel ) = self . play_or_download ( )
if can_play :
2008-03-19 18:07:59 +01:00
item = gtk . ImageMenuItem ( gtk . STOCK_MEDIA_PLAY )
2007-08-26 17:20:46 +02:00
item . connect ( ' activate ' , lambda w : self . on_treeAvailable_row_activated ( self . toolPlay ) )
2008-04-24 18:28:39 +02:00
menu . append ( self . set_finger_friendly ( item ) )
2007-12-12 19:50:52 +01:00
2008-03-02 14:22:29 +01:00
is_locked = gl . history_is_locked ( first_url )
2007-12-12 19:50:52 +01:00
if not is_locked :
2008-03-19 18:07:59 +01:00
item = gtk . ImageMenuItem ( gtk . STOCK_DELETE )
2007-12-12 19:50:52 +01:00
item . connect ( ' activate ' , self . on_btnDownloadedDelete_clicked )
2008-04-24 18:28:39 +02:00
menu . append ( self . set_finger_friendly ( item ) )
2008-03-19 18:07:59 +01:00
if can_cancel :
item = gtk . ImageMenuItem ( _ ( ' Cancel download ' ) )
item . set_image ( gtk . image_new_from_stock ( gtk . STOCK_STOP , gtk . ICON_SIZE_MENU ) )
item . connect ( ' activate ' , lambda w : self . on_treeDownloads_row_activated ( self . toolCancel ) )
2008-04-24 18:28:39 +02:00
menu . append ( self . set_finger_friendly ( item ) )
2007-08-26 17:20:46 +02:00
if can_download :
2008-03-19 18:07:59 +01:00
item = gtk . ImageMenuItem ( _ ( ' Download ' ) )
2007-08-26 17:20:46 +02:00
item . set_image ( gtk . image_new_from_stock ( gtk . STOCK_GO_DOWN , gtk . ICON_SIZE_MENU ) )
item . connect ( ' activate ' , lambda w : self . on_treeAvailable_row_activated ( self . toolDownload ) )
2008-04-24 18:28:39 +02:00
menu . append ( self . set_finger_friendly ( item ) )
2007-08-26 17:20:46 +02:00
2008-03-02 14:22:29 +01:00
is_downloaded = gl . history_is_downloaded ( first_url )
2007-08-30 20:54:18 +02:00
if is_downloaded :
2008-03-19 18:07:59 +01:00
item = gtk . ImageMenuItem ( _ ( ' Mark as not downloaded ' ) )
2007-08-30 20:54:18 +02:00
item . set_image ( gtk . image_new_from_stock ( gtk . STOCK_UNDELETE , gtk . ICON_SIZE_MENU ) )
item . connect ( ' activate ' , lambda w : self . on_item_toggle_downloaded_activate ( w , False , False ) )
2008-04-24 18:28:39 +02:00
menu . append ( self . set_finger_friendly ( item ) )
2007-08-30 20:54:18 +02:00
else :
2008-03-19 18:07:59 +01:00
# FIXME: foreach episode go and delete/toggle downloaded episode
# ++ unify into a single menu item (with "Delete" from above)
item = gtk . ImageMenuItem ( gtk . STOCK_DELETE )
2007-08-30 20:54:18 +02:00
item . connect ( ' activate ' , lambda w : self . on_item_toggle_downloaded_activate ( w , False , True ) )
2008-04-24 18:28:39 +02:00
menu . append ( self . set_finger_friendly ( item ) )
2007-08-30 20:54:18 +02:00
2008-03-19 18:07:59 +01:00
if can_play :
menu . append ( gtk . SeparatorMenuItem ( ) )
item = gtk . ImageMenuItem ( _ ( ' Save to disk ' ) )
item . set_image ( gtk . image_new_from_stock ( gtk . STOCK_SAVE_AS , gtk . ICON_SIZE_MENU ) )
item . connect ( ' activate ' , lambda w : self . save_episode_as_file ( episode_url ) )
2008-04-24 18:28:39 +02:00
menu . append ( self . set_finger_friendly ( item ) )
2008-03-19 18:07:59 +01:00
if gl . config . bluetooth_enabled :
item = gtk . ImageMenuItem ( _ ( ' Send via bluetooth ' ) )
item . set_image ( gtk . image_new_from_icon_name ( ' bluetooth ' , gtk . ICON_SIZE_MENU ) )
item . connect ( ' activate ' , lambda w : self . copy_episode_bluetooth ( episode_url ) )
2008-04-24 18:28:39 +02:00
menu . append ( self . set_finger_friendly ( item ) )
2008-03-19 18:07:59 +01:00
if can_transfer :
item = gtk . ImageMenuItem ( _ ( ' Transfer to %s ' ) % gl . get_device_name ( ) )
item . set_image ( gtk . image_new_from_icon_name ( ' multimedia-player ' , gtk . ICON_SIZE_MENU ) )
item . connect ( ' activate ' , lambda w : self . on_treeAvailable_row_activated ( self . toolTransfer ) )
2008-04-24 18:28:39 +02:00
menu . append ( self . set_finger_friendly ( item ) )
2007-08-26 17:20:46 +02:00
2007-08-30 20:54:18 +02:00
if can_play :
menu . append ( gtk . SeparatorMenuItem ( ) )
2008-03-02 14:22:29 +01:00
is_played = gl . history_is_played ( first_url )
2007-08-30 20:54:18 +02:00
if is_played :
2008-03-19 18:07:59 +01:00
item = gtk . ImageMenuItem ( _ ( ' Mark as unplayed ' ) )
2007-08-30 20:54:18 +02:00
item . set_image ( gtk . image_new_from_stock ( gtk . STOCK_CANCEL , gtk . ICON_SIZE_MENU ) )
item . connect ( ' activate ' , lambda w : self . on_item_toggle_played_activate ( w , False , False ) )
2008-04-24 18:28:39 +02:00
menu . append ( self . set_finger_friendly ( item ) )
2007-08-30 20:54:18 +02:00
else :
2008-03-19 18:07:59 +01:00
item = gtk . ImageMenuItem ( _ ( ' Mark as played ' ) )
2007-08-30 20:54:18 +02:00
item . set_image ( gtk . image_new_from_stock ( gtk . STOCK_APPLY , gtk . ICON_SIZE_MENU ) )
item . connect ( ' activate ' , lambda w : self . on_item_toggle_played_activate ( w , False , True ) )
2008-04-24 18:28:39 +02:00
menu . append ( self . set_finger_friendly ( item ) )
2007-08-30 20:54:18 +02:00
2008-03-02 14:22:29 +01:00
is_locked = gl . history_is_locked ( first_url )
2007-12-12 19:50:52 +01:00
if is_locked :
2008-03-19 18:07:59 +01:00
item = gtk . ImageMenuItem ( _ ( ' Allow deletion ' ) )
2007-12-12 19:50:52 +01:00
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 )
2008-04-24 18:28:39 +02:00
menu . append ( self . set_finger_friendly ( item ) )
2007-12-12 19:50:52 +01:00
else :
2008-03-19 18:07:59 +01:00
item = gtk . ImageMenuItem ( _ ( ' Prohibit deletion ' ) )
2007-12-12 19:50:52 +01:00
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 )
2008-04-24 18:28:39 +02:00
menu . append ( self . set_finger_friendly ( item ) )
2008-03-19 18:07:59 +01:00
if len ( paths ) == 1 :
menu . append ( gtk . SeparatorMenuItem ( ) )
# Single item, add episode information menu item
episode_url = model . get_value ( model . get_iter ( paths [ 0 ] ) , 0 )
item = gtk . ImageMenuItem ( _ ( ' Episode details ' ) )
item . set_image ( gtk . image_new_from_stock ( gtk . STOCK_INFO , gtk . ICON_SIZE_MENU ) )
item . connect ( ' activate ' , lambda w : self . on_treeAvailable_row_activated ( self . treeAvailable ) )
2008-04-24 18:28:39 +02:00
menu . append ( self . set_finger_friendly ( item ) )
2008-03-22 20:43:20 +01:00
episode = self . active_channel . find_episode ( episode_url )
# If we have it, also add episode website link
if episode and episode . link and episode . link != episode . url :
item = gtk . ImageMenuItem ( _ ( ' Visit website ' ) )
2008-04-06 02:19:03 +02:00
item . set_image ( gtk . image_new_from_icon_name ( WEB_BROWSER_ICON , gtk . ICON_SIZE_MENU ) )
2008-03-22 20:43:20 +01:00
item . connect ( ' activate ' , lambda w : util . open_website ( episode . link ) )
2008-04-24 18:28:39 +02:00
menu . append ( self . set_finger_friendly ( item ) )
2008-04-06 02:19:03 +02:00
if gpodder . interface == gpodder . MAEMO :
# Because we open the popup on left-click for Maemo,
# we also include a non-action to close the menu
menu . append ( gtk . SeparatorMenuItem ( ) )
item = gtk . ImageMenuItem ( _ ( ' Close this menu ' ) )
item . set_image ( gtk . image_new_from_stock ( gtk . STOCK_CLOSE , gtk . ICON_SIZE_MENU ) )
2008-04-24 18:28:39 +02:00
menu . append ( self . set_finger_friendly ( item ) )
2007-08-26 17:20:46 +02:00
menu . show_all ( )
menu . popup ( None , None , None , event . button , event . time )
return True
2008-04-06 02:19:03 +02:00
def set_title ( self , new_title ) :
self . default_title = new_title
self . gPodder . set_title ( new_title )
2007-08-24 16:49:41 +02:00
def download_progress_updated ( self , count , percentage ) :
title = [ self . default_title ]
if count == 1 :
title . append ( _ ( ' downloading one file ' ) )
elif count > 1 :
title . append ( _ ( ' downloading %d files ' ) % count )
if len ( title ) == 2 :
title [ 1 ] = ' ' . join ( [ title [ 1 ] , ' ( %d %% ) ' % ( percentage , ) ] )
self . gPodder . set_title ( ' - ' . join ( title ) )
2007-04-03 13:21:12 +02:00
def playback_episode ( self , current_channel , current_podcast ) :
2008-03-02 14:22:29 +01:00
( success , application ) = gl . playback_episode ( current_channel , current_podcast )
2007-08-13 23:53:26 +02:00
if not success :
self . show_message ( _ ( ' The selected player application cannot be found. Please check your media player settings in the preferences dialog. ' ) , _ ( ' Error opening player: %s ' ) % ( saxutils . escape ( application ) , ) )
2007-08-20 15:45:46 +02:00
self . download_status_updated ( )
2007-04-03 13:21:12 +02:00
2007-04-03 08:27:46 +02:00
def treeAvailable_search_equal ( self , model , column , key , iter , data = None ) :
2008-02-26 16:49:59 +01:00
if model is None :
2007-04-03 08:27:46 +02:00
return True
key = key . lower ( )
# columns, as defined in libpodcasts' get model method
# 1 = episode title, 7 = description
columns = ( 1 , 7 )
for column in columns :
value = model . get_value ( iter , column ) . lower ( )
if value . find ( key ) != - 1 :
return False
return True
2008-05-02 17:36:43 +02:00
def change_menu_item ( self , menuitem , icon = None , label = None ) :
( label_widget , icon_widget ) = menuitem . get_children ( )
if icon is not None :
icon_widget . set_from_icon_name ( icon , gtk . ICON_SIZE_MENU )
if label is not None :
label_widget . set_text ( label )
2007-04-03 08:27:46 +02:00
2006-12-13 00:11:34 +01:00
def play_or_download ( self ) :
2007-03-31 04:00:30 +02:00
if self . wNotebook . get_current_page ( ) > 0 :
return
2007-08-26 17:20:46 +02:00
( can_play , can_download , can_transfer , can_cancel ) = ( False , ) * 4
2008-05-02 17:36:43 +02:00
( is_played , is_locked ) = ( False , ) * 2
2006-12-13 00:11:34 +01:00
2007-08-26 17:20:46 +02:00
selection = self . treeAvailable . get_selection ( )
if selection . count_selected_rows ( ) > 0 :
( model , paths ) = selection . get_selected_rows ( )
for path in paths :
url = model . get_value ( model . get_iter ( path ) , 0 )
local_filename = model . get_value ( model . get_iter ( path ) , 8 )
2006-12-13 00:11:34 +01:00
2007-08-26 17:20:46 +02:00
if os . path . exists ( local_filename ) :
can_play = True
2008-05-02 17:36:43 +02:00
is_played = gl . history_is_played ( url )
is_locked = gl . history_is_locked ( url )
2007-08-26 17:20:46 +02:00
else :
2007-08-25 18:05:03 +02:00
if services . download_status_manager . is_download_in_progress ( url ) :
2007-08-26 17:20:46 +02:00
can_cancel = True
else :
can_download = True
2006-12-13 00:11:34 +01:00
2007-08-26 17:20:46 +02:00
if util . file_type_by_extension ( util . file_extension_from_url ( url ) ) == ' torrent ' :
2008-03-02 14:22:29 +01:00
can_download = can_download or gl . config . use_gnome_bittorrent
2007-08-26 17:20:46 +02:00
can_download = can_download and not can_cancel
can_play = can_play and not can_cancel and not can_download
2008-03-02 14:22:29 +01:00
can_transfer = can_play and gl . config . device_type != ' none '
2007-08-26 17:20:46 +02:00
self . toolPlay . set_sensitive ( can_play )
self . toolDownload . set_sensitive ( can_download )
self . toolTransfer . set_sensitive ( can_transfer )
self . toolCancel . set_sensitive ( can_cancel )
2008-05-02 17:36:43 +02:00
if can_cancel :
self . item_cancel_download . show_all ( )
else :
self . item_cancel_download . hide_all ( )
if can_download :
self . itemDownloadSelected . show_all ( )
else :
self . itemDownloadSelected . hide_all ( )
if can_play :
self . itemPlaySelected . show_all ( )
self . itemDeleteSelected . show_all ( )
self . item_toggle_played . show_all ( )
self . item_toggle_lock . show_all ( )
self . separator9 . show_all ( )
if is_played :
self . change_menu_item ( self . item_toggle_played , gtk . STOCK_CANCEL , _ ( ' Mark as unplayed ' ) )
else :
self . change_menu_item ( self . item_toggle_played , gtk . STOCK_APPLY , _ ( ' Mark as played ' ) )
if is_locked :
self . change_menu_item ( self . item_toggle_lock , gtk . STOCK_DIALOG_AUTHENTICATION , _ ( ' Allow deletion ' ) )
else :
self . change_menu_item ( self . item_toggle_lock , gtk . STOCK_DIALOG_AUTHENTICATION , _ ( ' Prohibit deletion ' ) )
else :
self . itemPlaySelected . hide_all ( )
self . itemDeleteSelected . hide_all ( )
self . item_toggle_played . hide_all ( )
self . item_toggle_lock . hide_all ( )
self . separator9 . hide_all ( )
if can_play or can_download or can_cancel :
self . item_episode_details . show_all ( )
self . separator16 . show_all ( )
self . no_episode_selected . hide_all ( )
else :
self . item_episode_details . hide_all ( )
self . separator16 . hide_all ( )
self . no_episode_selected . show_all ( )
2007-08-26 17:20:46 +02:00
return ( can_play , can_download , can_transfer , can_cancel )
2006-12-13 00:11:34 +01:00
2007-07-24 20:42:04 +02:00
def download_status_updated ( self ) :
2007-08-24 16:49:41 +02:00
count = services . download_status_manager . count ( )
2007-07-24 20:42:04 +02:00
if count :
self . labelDownloads . set_text ( _ ( ' Downloads ( %d ) ' ) % count )
else :
self . labelDownloads . set_text ( _ ( ' Downloads ' ) )
2007-08-20 15:45:46 +02:00
for channel in self . channels :
2007-08-24 16:49:41 +02:00
channel . update_model ( )
2007-08-20 15:45:46 +02:00
2007-07-24 20:42:04 +02:00
self . updateComboBox ( )
2008-04-17 17:45:29 +02:00
def on_cbMaxDownloads_toggled ( self , widget , * args ) :
self . spinMaxDownloads . set_sensitive ( self . cbMaxDownloads . get_active ( ) )
def on_cbLimitDownloads_toggled ( self , widget , * args ) :
self . spinLimitDownloads . set_sensitive ( self . cbLimitDownloads . get_active ( ) )
2008-05-14 15:38:06 +02:00
def updateComboBox ( self , selected_url = None ) :
( model , iter ) = self . treeChannels . get_selection ( ) . get_selected ( )
2007-09-19 17:04:42 +02:00
2008-05-14 15:38:06 +02:00
if model and iter and selected_url is None :
# Get the URL of the currently-selected podcast
selected_url = model . get_value ( iter , 0 )
2007-09-19 17:04:42 +02:00
rect = self . treeChannels . get_visible_rect ( )
2007-11-27 23:04:15 +01:00
self . treeChannels . set_model ( channels_to_model ( self . channels ) )
2008-05-14 15:38:06 +02:00
util . idle_add ( self . treeChannels . scroll_to_point , rect . x , rect . y )
2007-09-19 17:04:42 +02:00
2005-11-21 19:21:25 +01:00
try :
2008-05-14 15:38:06 +02:00
selected_path = ( 0 , )
# Find the previously-selected URL in the new
# model if we have an URL (else select first)
if selected_url is not None :
model = self . treeChannels . get_model ( )
pos = model . get_iter_first ( )
while pos is not None :
url = model . get_value ( pos , 0 )
if url == selected_url :
selected_path = model . get_path ( pos )
break
pos = model . iter_next ( pos )
self . treeChannels . get_selection ( ) . select_path ( selected_path )
2005-11-21 19:21:25 +01:00
except :
2007-09-19 17:04:42 +02:00
log ( ' Cannot set selection on treeChannels ' , sender = self )
2007-09-19 17:22:14 +02:00
self . on_treeChannels_cursor_changed ( self . treeChannels )
2005-11-21 19:21:25 +01:00
def updateTreeView ( self ) :
2008-03-04 12:06:55 +01:00
if self . channels and self . active_channel is not None :
self . treeAvailable . set_model ( self . active_channel . tree_model )
2007-04-01 19:53:04 +02:00
self . treeAvailable . columns_autosize ( )
2007-03-18 19:28:17 +01:00
self . play_or_download ( )
2006-12-06 21:25:26 +01:00
else :
if self . treeAvailable . get_model ( ) :
self . treeAvailable . get_model ( ) . clear ( )
2005-11-21 19:21:25 +01:00
2005-11-22 14:23:50 +01:00
def drag_data_received ( self , widget , context , x , y , sel , ttype , time ) :
result = sel . data
2006-03-31 18:20:18 +02:00
self . add_new_channel ( result )
2008-05-14 15:38:06 +02:00
def add_new_channel ( self , result = None , ask_download_new = True ) :
2007-08-07 20:11:31 +02:00
result = util . normalize_feed_url ( result )
2007-07-19 14:44:12 +02:00
2007-03-07 15:53:05 +01:00
if result :
2006-06-13 23:00:31 +02:00
for old_channel in self . channels :
if old_channel . url == result :
2006-11-17 15:26:10 +01:00
log ( ' Channel already exists: %s ' , result )
2006-12-06 21:25:26 +01:00
# Select the existing channel in combo box
for i in range ( len ( self . channels ) ) :
if self . channels [ i ] == old_channel :
2007-09-21 01:47:47 +02:00
self . treeChannels . get_selection ( ) . select_path ( ( i , ) )
2008-05-14 15:38:06 +02:00
self . on_treeChannels_cursor_changed ( self . treeChannels )
break
self . show_message ( _ ( ' You have already subscribed to this podcast: %s ' ) % ( saxutils . escape ( old_channel . title ) , ) , _ ( ' Already added ' ) )
2006-06-13 23:00:31 +02:00
return
2006-11-17 15:26:10 +01:00
log ( ' Adding new channel: %s ' , result )
2007-08-20 15:45:46 +02:00
try :
channel = podcastChannel . get_by_url ( url = result , force_update = True )
except :
2007-12-12 19:50:52 +01:00
log ( ' Error in podcastChannel.get_by_url( %s ) ' , result , sender = self )
2007-08-20 15:45:46 +02:00
channel = None
if channel :
self . channels . append ( channel )
save_channels ( self . channels )
2008-05-14 15:38:06 +02:00
# download changed channels and select the new episode in the UI afterwards
self . update_feed_cache ( force_update = False , select_url_afterwards = channel . url )
2007-08-20 15:45:46 +02:00
2007-08-07 20:11:31 +02:00
( username , password ) = util . username_password_from_url ( result )
2007-07-19 14:44:12 +02:00
if username and self . show_confirmation ( _ ( ' You have supplied <b> %s </b> as username and a password for this feed. Would you like to use the same authentication data for downloading episodes? ' ) % ( saxutils . escape ( username ) , ) , _ ( ' Password authentication ' ) ) :
channel . username = username
channel . password = password
log ( ' Saving authentication data for episode downloads.. ' , sender = self )
2007-08-20 15:45:46 +02:00
channel . save_settings ( )
2007-07-19 14:44:12 +02:00
2007-07-11 20:12:02 +02:00
if ask_download_new :
2008-05-14 15:38:06 +02:00
new_episodes = channel . get_new_episodes ( )
if len ( new_episodes ) :
self . new_episodes_show ( new_episodes )
2007-08-20 15:45:46 +02:00
else :
2008-05-02 17:36:43 +02:00
title = _ ( ' Error adding podcast ' )
message = _ ( ' The podcast could not be added. Please check the spelling of the URL or try again later. ' )
2007-08-20 15:45:46 +02:00
self . show_message ( message , title )
2005-11-22 14:23:50 +01:00
else :
2006-12-09 02:59:53 +01:00
if result :
2007-03-10 18:42:32 +01:00
title = _ ( ' URL scheme not supported ' )
message = _ ( ' gPodder currently only supports URLs starting with <b>http://</b>, <b>feed://</b> or <b>ftp://</b>. ' )
self . show_message ( message , title )
2008-05-12 11:40:55 +02:00
else :
self . show_message ( _ ( ' There has been an error adding this podcast. Please see the log output for more information. ' ) , _ ( ' Error adding podcast ' ) )
2006-03-31 18:20:18 +02:00
2008-04-24 18:28:39 +02:00
def update_feed_cache_callback ( self , progressbar , position , count , force_update ) :
2008-01-09 23:46:17 +01:00
title = self . channels [ position ] . title
2008-04-24 18:28:39 +02:00
if force_update :
progression = _ ( ' Updating %s ( %d / %d ) ' ) % ( title , position + 1 , count )
else :
progression = _ ( ' Loading %s ( %d / %d ) ' ) % ( title , position + 1 , count )
2008-02-20 13:46:51 +01:00
progressbar . set_text ( progression )
if self . tray_icon :
self . tray_icon . set_status ( self . tray_icon . STATUS_UPDATING_FEED_CACHE , progression )
2006-12-09 02:59:53 +01:00
2008-01-09 23:46:17 +01:00
if count > 0 :
progressbar . set_fraction ( float ( position ) / float ( count ) )
2007-08-20 15:45:46 +02:00
2008-05-14 15:38:06 +02:00
def update_feed_cache_finish_callback ( self , force_update = False , notify_no_new_episodes = False , select_url_afterwards = None ) :
2008-04-22 20:34:41 +02:00
self . hboxUpdateFeeds . hide_all ( )
self . btnUpdateFeeds . show_all ( )
2008-01-09 23:46:17 +01:00
2008-05-14 15:38:06 +02:00
# If we want to select a specific podcast (via its URL)
# after the update, we give it to updateComboBox here to
# select exactly this podcast after updating the view
self . updateComboBox ( selected_url = select_url_afterwards )
2008-01-09 23:46:17 +01:00
if self . tray_icon :
self . tray_icon . set_status ( None )
2008-02-04 11:29:41 +01:00
if self . minimized and force_update :
2008-01-09 23:46:17 +01:00
new_episodes = [ ]
2008-02-04 11:29:41 +01:00
# look for new episodes to notify
2008-01-09 23:46:17 +01:00
for channel in self . channels :
for episode in channel . get_new_episodes ( ) :
2008-04-15 20:59:22 +02:00
if not episode in self . already_notified_new_episodes :
2008-02-04 11:29:41 +01:00
new_episodes . append ( episode )
2008-04-15 20:59:22 +02:00
self . already_notified_new_episodes . append ( episode )
2008-02-04 11:29:41 +01:00
# notify new episodes
2008-02-27 10:46:32 +01:00
if len ( new_episodes ) == 0 :
if notify_no_new_episodes and self . tray_icon is not None :
msg = _ ( ' No new episodes available for download ' )
self . tray_icon . send_notification ( msg )
return
elif len ( new_episodes ) == 1 :
title = _ ( ' gPodder has found %s ' ) % ( _ ( ' one new episode: ' ) , )
else :
title = _ ( ' gPodder has found %s ' ) % ( _ ( ' %i new episodes: ' ) % len ( new_episodes ) )
message = self . tray_icon . format_episode_list ( new_episodes )
#auto download new episodes
if gl . config . auto_download_when_minimized :
message + = ' \n <i>( %s ...)</i> ' % _ ( ' downloading ' )
self . download_episode_list ( new_episodes )
self . tray_icon . send_notification ( message , title )
2008-01-23 09:08:13 +01:00
return
2008-01-09 23:46:17 +01:00
2008-02-04 11:29:41 +01:00
# open the episodes selection dialog
if force_update :
2008-01-09 23:46:17 +01:00
self . on_itemDownloadAllNew_activate ( self . gPodder )
2006-07-14 22:09:00 +02:00
2007-08-20 15:45:46 +02:00
def update_feed_cache_proc ( self , force_update , callback_proc = None , callback_error = None , finish_proc = None ) :
2008-04-22 20:34:41 +02:00
is_cancelled_cb = lambda : self . feed_cache_update_cancelled
2008-05-10 13:43:43 +02:00
self . channels = load_channels ( force_update = force_update , callback_proc = callback_proc , callback_error = callback_error , offline = not force_update , is_cancelled_cb = is_cancelled_cb , old_channels = self . channels )
2007-08-20 15:45:46 +02:00
if finish_proc :
finish_proc ( )
2007-03-10 16:57:56 +01:00
2008-04-22 20:34:41 +02:00
def on_btnCancelFeedUpdate_clicked ( self , widget ) :
self . pbFeedUpdate . set_text ( _ ( ' Cancelling... ' ) )
self . feed_cache_update_cancelled = True
2008-05-14 15:38:06 +02:00
def update_feed_cache ( self , force_update = True , notify_no_new_episodes = False , select_url_afterwards = None ) :
2008-01-09 23:46:17 +01:00
if self . tray_icon :
self . tray_icon . set_status ( self . tray_icon . STATUS_UPDATING_FEED_CACHE )
2006-07-14 22:09:00 +02:00
# let's get down to business..
2008-04-24 18:28:39 +02:00
callback_proc = lambda pos , count : util . idle_add ( self . update_feed_cache_callback , self . pbFeedUpdate , pos , count , force_update )
2008-05-14 15:38:06 +02:00
finish_proc = lambda : util . idle_add ( self . update_feed_cache_finish_callback , force_update , notify_no_new_episodes , select_url_afterwards )
2008-04-22 20:34:41 +02:00
self . feed_cache_update_cancelled = False
self . btnUpdateFeeds . hide_all ( )
self . hboxUpdateFeeds . show_all ( )
2007-03-10 16:57:56 +01:00
2008-01-15 14:54:22 +01:00
args = ( force_update , callback_proc , self . notification , finish_proc )
2007-03-10 16:57:56 +01:00
thread = Thread ( target = self . update_feed_cache_proc , args = args )
thread . start ( )
2008-04-22 20:34:41 +02:00
2006-06-22 23:41:32 +02:00
def download_podcast_by_url ( self , url , want_message_dialog = True , widget = None ) :
2008-02-26 16:49:59 +01:00
if self . active_channel is None :
2007-08-26 17:20:46 +02:00
return
2006-12-09 02:59:53 +01:00
current_channel = self . active_channel
2006-12-09 01:41:58 +01:00
current_podcast = current_channel . find_episode ( url )
2007-08-22 01:00:49 +02:00
filename = current_podcast . local_filename ( )
2006-12-09 02:59:53 +01:00
2006-12-13 00:11:34 +01:00
if widget :
2007-03-31 04:00:30 +02:00
if ( widget . get_name ( ) == ' itemPlaySelected ' or widget . get_name ( ) == ' toolPlay ' ) and os . path . exists ( filename ) :
2007-03-14 20:35:15 +01:00
# addDownloadedItem just to make sure the episode is marked correctly in localdb
2007-09-15 16:29:37 +02:00
current_channel . addDownloadedItem ( current_podcast )
2007-03-14 20:35:15 +01:00
# open the file now
2007-08-22 01:00:49 +02:00
if current_podcast . file_type ( ) != ' torrent ' :
2007-04-09 21:40:36 +02:00
self . playback_episode ( current_channel , current_podcast )
2006-12-13 00:11:34 +01:00
return
2008-05-02 17:36:43 +02:00
if widget . get_name ( ) == ' treeAvailable ' or widget . get_name ( ) == ' item_episode_details ' :
2007-08-27 22:28:00 +02:00
play_callback = lambda : self . playback_episode ( current_channel , current_podcast )
download_callback = lambda : self . download_podcast_by_url ( url , want_message_dialog , None )
2008-04-22 21:57:02 +02:00
gpe = gPodderEpisode ( episode = current_podcast , channel = current_channel , download_callback = download_callback , play_callback = play_callback )
2006-12-13 00:11:34 +01:00
return
2006-06-22 23:41:32 +02:00
2007-08-24 16:49:41 +02:00
if not os . path . exists ( filename ) and not services . download_status_manager . is_download_in_progress ( current_podcast . url ) :
2007-11-05 13:55:36 +01:00
download . DownloadThread ( current_channel , current_podcast , self . notification ) . start ( )
2006-06-22 23:41:32 +02:00
else :
2007-08-22 01:00:49 +02:00
if want_message_dialog and os . path . exists ( filename ) and not current_podcast . file_type ( ) == ' torrent ' :
2007-03-10 18:42:32 +01:00
title = _ ( ' Episode already downloaded ' )
message = _ ( ' You have already downloaded this episode. Click on the episode to play it. ' )
self . show_message ( message , title )
2007-08-22 01:00:49 +02:00
elif want_message_dialog and not current_podcast . file_type ( ) == ' torrent ' :
2007-03-10 18:42:32 +01:00
title = _ ( ' Download in progress ' )
message = _ ( ' You are currently downloading this episode. Please check the download status tab to check when the download is finished. ' )
self . show_message ( message , title )
2006-12-09 02:59:53 +01:00
if os . path . exists ( filename ) :
2006-11-17 15:26:10 +01:00
log ( ' Episode has already been downloaded. ' )
2007-09-15 16:29:37 +02:00
current_channel . addDownloadedItem ( current_podcast )
2007-09-19 17:04:42 +02:00
self . updateComboBox ( )
2008-01-09 23:46:17 +01:00
def on_gPodder_delete_event ( self , widget , * args ) :
""" Called when the GUI wants to close the window
Displays a confirmation dialog ( and closes / hides gPodder )
"""
2005-11-21 19:21:25 +01:00
2008-01-09 23:46:17 +01:00
downloading = services . download_status_manager . has_items ( )
2008-03-30 10:50:34 +02:00
# Only iconify if we are using the window's "X" button,
# but not when we are using "Quit" in the menu or toolbar
2008-04-11 10:29:13 +02:00
if not gl . config . on_quit_ask and gl . config . on_quit_systray and self . tray_icon and widget . name not in ( ' toolQuit ' , ' itemQuit ' ) :
2008-02-06 10:45:40 +01:00
self . iconify_main_window ( )
elif gl . config . on_quit_ask or downloading :
2008-04-06 02:19:03 +02:00
if gpodder . interface == gpodder . MAEMO :
result = self . show_confirmation ( _ ( ' Do you really want to quit gPodder now? ' ) )
if result :
self . close_gpodder ( )
else :
return True
2008-01-09 23:46:17 +01:00
dialog = gtk . MessageDialog ( self . gPodder , gtk . DIALOG_MODAL , gtk . MESSAGE_QUESTION , gtk . BUTTONS_NONE )
dialog . add_button ( gtk . STOCK_CANCEL , gtk . RESPONSE_CANCEL )
dialog . add_button ( gtk . STOCK_QUIT , gtk . RESPONSE_CLOSE )
title = _ ( ' Quit gPodder ' )
if downloading :
message = _ ( ' You are downloading episodes. If you close gPodder now, the downloads will be aborted. ' )
else :
message = _ ( ' Do you really want to quit gPodder now? ' )
dialog . set_title ( title )
dialog . set_markup ( ' <span weight= " bold " size= " larger " > %s </span> \n \n %s ' % ( title , message ) )
if not downloading :
cb_ask = gtk . CheckButton ( _ ( " Don ' t ask me again " ) )
dialog . vbox . pack_start ( cb_ask )
cb_ask . show_all ( )
result = dialog . run ( )
dialog . destroy ( )
if result == gtk . RESPONSE_CLOSE :
if not downloading and cb_ask . get_active ( ) == True :
gl . config . on_quit_ask = False
self . close_gpodder ( )
else :
self . close_gpodder ( )
return True
def close_gpodder ( self ) :
""" clean everything and exit properly
"""
2006-12-09 02:59:53 +01:00
if self . channels :
2007-11-25 11:55:12 +01:00
if not save_channels ( self . channels ) :
2008-05-02 17:36:43 +02:00
self . show_message ( _ ( ' Please check your permissions and free disk space. ' ) , _ ( ' Error saving podcast list ' ) )
2005-11-21 19:21:25 +01:00
2007-08-24 16:49:41 +02:00
services . download_status_manager . cancel_all ( )
2005-11-23 20:53:18 +01:00
2005-11-21 19:21:25 +01:00
self . gtk_main_quit ( )
2007-05-05 10:10:10 +02:00
sys . exit ( 0 )
2005-11-21 19:21:25 +01:00
2007-12-12 20:57:50 +01:00
def get_old_episodes ( self ) :
episodes = [ ]
for channel in self . channels :
2007-12-22 11:45:59 +01:00
for episode in channel . get_all_episodes ( ) :
2007-12-12 20:57:50 +01:00
if episode . is_downloaded ( ) and episode . is_old ( ) and not episode . is_locked ( ) and episode . is_played ( ) :
episodes . append ( episode )
return episodes
2007-08-30 20:54:18 +02:00
def for_each_selected_episode_url ( self , callback ) :
( model , paths ) = self . treeAvailable . get_selection ( ) . get_selected_rows ( )
for path in paths :
url = model . get_value ( model . get_iter ( path ) , 0 )
try :
callback ( url )
except :
log ( ' Warning: Error in for_each_selected_episode_url for URL %s ' , url , sender = self )
self . active_channel . update_model ( )
self . updateComboBox ( )
2007-11-08 20:11:57 +01:00
def delete_episode_list ( self , episodes , confirm = True ) :
if len ( episodes ) == 0 :
return
if len ( episodes ) == 1 :
message = _ ( ' Do you really want to delete this episode? ' )
else :
message = _ ( ' Do you really want to delete %d episodes? ' ) % len ( episodes )
if confirm and self . show_confirmation ( message , _ ( ' Delete episodes ' ) ) == False :
return
for episode in episodes :
log ( ' Deleting episode: %s ' , episode . title , sender = self )
episode . delete_from_disk ( )
self . download_status_updated ( )
def on_itemRemoveOldEpisodes_activate ( self , widget ) :
columns = (
( ' title ' , _ ( ' Episode ' ) ) ,
2008-05-02 17:36:43 +02:00
( ' channel_prop ' , _ ( ' Podcast ' ) ) ,
2007-11-08 20:11:57 +01:00
( ' filesize_prop ' , _ ( ' Size ' ) ) ,
( ' pubdate_prop ' , _ ( ' Released ' ) ) ,
( ' played_prop ' , _ ( ' Status ' ) ) ,
2007-12-10 09:41:17 +01:00
( ' age_prop ' , _ ( ' Downloaded ' ) ) ,
2007-11-08 20:11:57 +01:00
)
selection_buttons = {
2007-12-10 09:41:17 +01:00
_ ( ' Select played ' ) : lambda episode : episode . is_played ( ) ,
_ ( ' Select older than %d days ' ) % gl . config . episode_old_age : lambda episode : episode . is_old ( ) ,
2007-11-08 20:11:57 +01:00
}
instructions = _ ( ' Select the episodes you want to delete from your hard disk. ' )
episodes = [ ]
selected = [ ]
for channel in self . channels :
for episode in channel :
2007-12-12 19:50:52 +01:00
if episode . is_downloaded ( ) and not episode . is_locked ( ) :
2007-11-08 20:11:57 +01:00
episodes . append ( episode )
2007-12-10 09:41:17 +01:00
selected . append ( episode . is_played ( ) )
2007-11-08 20:11:57 +01:00
gPodderEpisodeSelector ( title = _ ( ' Remove old episodes ' ) , instructions = instructions , \
episodes = episodes , selected = selected , columns = columns , \
stock_ok_button = gtk . STOCK_DELETE , callback = self . delete_episode_list , \
selection_buttons = selection_buttons )
2007-08-30 20:54:18 +02:00
def on_item_toggle_downloaded_activate ( self , widget , toggle = True , new_value = False ) :
if toggle :
2008-03-02 14:22:29 +01:00
callback = lambda url : gl . history_mark_downloaded ( url , not gl . history_is_downloaded ( url ) )
2007-08-30 20:54:18 +02:00
else :
2008-03-02 14:22:29 +01:00
callback = lambda url : gl . history_mark_downloaded ( url , new_value )
2007-08-30 20:54:18 +02:00
self . for_each_selected_episode_url ( callback )
2008-06-13 14:30:42 +02:00
if self . active_channel :
# Reset the cache for newest_pubdate_downloaded
self . active_channel . reset_pubdate_cache ( )
2007-08-30 20:54:18 +02:00
def on_item_toggle_played_activate ( self , widget , toggle = True , new_value = False ) :
if toggle :
2008-03-02 14:22:29 +01:00
callback = lambda url : gl . history_mark_played ( url , not gl . history_is_played ( url ) )
2007-08-30 20:54:18 +02:00
else :
2008-03-02 14:22:29 +01:00
callback = lambda url : gl . history_mark_played ( url , new_value )
2007-08-30 20:54:18 +02:00
self . for_each_selected_episode_url ( callback )
2007-12-12 19:50:52 +01:00
def on_item_toggle_lock_activate ( self , widget , toggle = True , new_value = False ) :
if toggle :
2008-03-02 14:22:29 +01:00
callback = lambda url : gl . history_mark_locked ( url , not gl . history_is_locked ( url ) )
2007-12-12 19:50:52 +01:00
else :
2008-03-02 14:22:29 +01:00
callback = lambda url : gl . history_mark_locked ( url , new_value )
2007-12-12 19:50:52 +01:00
self . for_each_selected_episode_url ( callback )
2008-05-02 17:36:43 +02:00
def on_item_email_subscriptions_activate ( self , widget ) :
if not self . channels :
self . show_message ( _ ( ' Your subscription list is empty. ' ) , _ ( ' Could not send list ' ) )
elif not gl . send_subscriptions ( ) :
self . show_message ( _ ( ' There was an error sending your subscription list via e-mail. ' ) , _ ( ' Could not send list ' ) )
def on_item_show_url_entry_activate ( self , widget ) :
gl . config . show_podcast_url_entry = self . item_show_url_entry . get_active ( )
2008-02-27 10:46:32 +01:00
def on_itemUpdate_activate ( self , widget , notify_no_new_episodes = False ) :
2006-12-06 21:25:26 +01:00
if self . channels :
2008-02-27 10:46:32 +01:00
self . update_feed_cache ( notify_no_new_episodes = notify_no_new_episodes )
2006-12-06 21:25:26 +01:00
else :
2008-05-02 17:36:43 +02:00
title = _ ( ' Import podcasts from the web ' )
message = _ ( ' Your podcast list is empty. Do you want to see a list of example podcasts you can subscribe to? ' )
if self . show_confirmation ( message , title ) :
self . on_itemImportChannels_activate ( self , widget )
2005-11-21 19:21:25 +01:00
2007-11-08 20:11:57 +01:00
def download_episode_list ( self , episodes ) :
2008-05-14 15:38:06 +02:00
services . download_status_manager . start_batch_mode ( )
2007-11-08 20:11:57 +01:00
for episode in episodes :
log ( ' Downloading episode: %s ' , episode . title , sender = self )
filename = episode . local_filename ( )
if not os . path . exists ( filename ) and not services . download_status_manager . is_download_in_progress ( episode . url ) :
download . DownloadThread ( episode . channel , episode , self . notification ) . start ( )
2008-05-14 15:38:06 +02:00
services . download_status_manager . end_batch_mode ( )
2006-12-20 20:44:29 +01:00
2008-01-22 10:10:08 +01:00
def new_episodes_show ( self , episodes ) :
2007-11-08 20:11:57 +01:00
columns = (
( ' title ' , _ ( ' Episode ' ) ) ,
2008-05-02 17:36:43 +02:00
( ' channel_prop ' , _ ( ' Podcast ' ) ) ,
2007-11-08 20:11:57 +01:00
( ' filesize_prop ' , _ ( ' Size ' ) ) ,
( ' pubdate_prop ' , _ ( ' Released ' ) ) ,
)
if len ( episodes ) > 0 :
instructions = _ ( ' Select the episodes you want to download now. ' )
2007-03-10 18:42:32 +01:00
2008-01-22 10:10:08 +01:00
gPodderEpisodeSelector ( title = _ ( ' New episodes available ' ) , instructions = instructions , \
episodes = episodes , columns = columns , selected_default = True , \
callback = self . download_episode_list )
2006-12-20 20:44:29 +01:00
else :
2007-03-10 18:42:32 +01:00
title = _ ( ' No new episodes ' )
2008-04-06 02:19:03 +02:00
message = _ ( ' No new episodes to download. \n Please check for new episodes later. ' )
2008-01-22 10:10:08 +01:00
self . show_message ( message , title )
def on_itemDownloadAllNew_activate ( self , widget , * args ) :
episodes = [ ]
for channel in self . channels :
for episode in channel . get_new_episodes ( ) :
episodes . append ( episode )
self . new_episodes_show ( episodes )
2006-12-20 20:44:29 +01:00
2008-06-13 09:41:36 +02:00
def get_all_episodes ( self , exclude_nonsignificant = True ) :
""" ' exclude_nonsignificant ' will exclude non-downloaded episodes
and all episodes from channels that are set to skip when syncing """
episode_list = [ ]
for channel in self . channels :
if not channel . sync_to_devices and exclude_nonsignificant :
log ( ' Skipping channel: %s ' , channel . title , sender = self )
continue
for episode in channel . get_all_episodes ( ) :
if episode . is_downloaded ( ) or not exclude_nonsignificant :
episode_list . append ( episode )
return episode_list
def ipod_delete_played ( self , device ) :
all_episodes = self . get_all_episodes ( exclude_nonsignificant = False )
episodes_on_device = device . get_all_tracks ( )
for local_episode in all_episodes :
if local_episode . is_played ( ) and not local_episode . is_locked ( ) or local_episode . is_deleted ( ) :
if gl . config . device_type == ' filesystem ' :
local_episode_name = util . sanitize_filename ( local_episode . sync_filename ( ) , gl . config . mp3_player_max_filename_length )
else :
local_episode_name = local_episode . sync_filename ( )
for device_episode in episodes_on_device :
if device_episode . title == local_episode_name :
log ( " mp3_player_delete_played: removing %s " % device_episode . title )
device . remove_track ( device_episode )
break
2008-01-28 12:38:53 +01:00
def on_sync_to_ipod_activate ( self , widget , episodes = None ) :
Thread ( target = self . sync_to_ipod_thread , args = ( widget , episodes ) ) . start ( )
def sync_to_ipod_thread ( self , widget , episodes = None ) :
device = sync . open_device ( )
if device is None :
2007-03-10 18:42:32 +01:00
title = _ ( ' No device configured ' )
message = _ ( ' To use the synchronization feature, please configure your device in the preferences dialog first. ' )
2008-01-28 12:38:53 +01:00
self . notification ( message , title )
2007-03-18 19:28:17 +01:00
return
2008-01-28 12:38:53 +01:00
if not device . open ( ) :
title = _ ( ' Cannot open device ' )
message = _ ( ' There has been an error opening your device. ' )
self . notification ( message , title )
2008-01-09 23:56:03 +01:00
return
2007-03-18 19:28:17 +01:00
2008-02-20 13:46:51 +01:00
gPodderSync ( device = device , gPodder = self )
if self . tray_icon :
self . tray_icon . set_synchronisation_device ( device )
2007-03-18 19:28:17 +01:00
2008-01-28 12:38:53 +01:00
if episodes is None :
2008-06-13 09:41:36 +02:00
episodes_to_sync = self . get_all_episodes ( )
2008-01-28 12:38:53 +01:00
device . add_tracks ( episodes_to_sync )
2008-06-13 09:41:36 +02:00
# 'only_sync_not_played' must be used or else all the played
# tracks will be copied then immediately deleted
if gl . config . mp3_player_delete_played and gl . config . only_sync_not_played :
self . ipod_delete_played ( device )
2008-01-28 12:38:53 +01:00
else :
device . add_tracks ( episodes , force_played = True )
if not device . close ( ) :
title = _ ( ' Error closing device ' )
message = _ ( ' There has been an error closing your device. ' )
self . notification ( message , title )
return
2008-02-20 13:46:51 +01:00
if self . tray_icon :
self . tray_icon . release_synchronisation_device ( )
2007-03-18 19:28:17 +01:00
2008-01-28 12:38:53 +01:00
# update model for played state updates after sync
for channel in self . channels :
util . idle_add ( channel . update_model )
util . idle_add ( self . updateComboBox )
def ipod_cleanup_callback ( self , device , tracks ) :
title = _ ( ' Delete podcasts from device? ' )
message = _ ( ' Do you really want to completely remove the selected episodes? ' )
if len ( tracks ) > 0 and self . show_confirmation ( message , title ) :
device . remove_tracks ( tracks )
if not device . close ( ) :
title = _ ( ' Error closing device ' )
message = _ ( ' There has been an error closing your device. ' )
self . show_message ( message , title )
return
2006-04-07 03:43:06 +02:00
2006-04-06 16:11:03 +02:00
def on_cleanup_ipod_activate ( self , widget , * args ) :
2008-01-28 12:38:53 +01:00
columns = (
( ' title ' , _ ( ' Episode ' ) ) ,
2008-04-19 19:01:09 +02:00
( ' podcast ' , _ ( ' Podcast ' ) ) ,
2008-01-28 12:38:53 +01:00
( ' filesize ' , _ ( ' Size ' ) ) ,
( ' modified ' , _ ( ' Copied ' ) ) ,
2008-03-27 13:11:33 +01:00
( ' playcount ' , _ ( ' Play count ' ) ) ,
2008-04-19 19:01:09 +02:00
( ' released ' , _ ( ' Released ' ) ) ,
2008-01-28 12:38:53 +01:00
)
device = sync . open_device ( )
if device is None :
2007-03-10 18:42:32 +01:00
title = _ ( ' No device configured ' )
message = _ ( ' To use the synchronization feature, please configure your device in the preferences dialog first. ' )
2008-01-28 12:38:53 +01:00
self . show_message ( message , title )
2007-03-18 19:28:17 +01:00
return
2008-01-28 12:38:53 +01:00
if not device . open ( ) :
title = _ ( ' Cannot open device ' )
message = _ ( ' There has been an error opening your device. ' )
self . show_message ( message , title )
2007-03-18 19:28:17 +01:00
return
2008-01-28 12:38:53 +01:00
2008-02-20 13:46:51 +01:00
gPodderSync ( device = device , gPodder = self )
2008-01-28 12:38:53 +01:00
tracks = device . get_all_tracks ( )
if len ( tracks ) > 0 :
remove_tracks_callback = lambda tracks : self . ipod_cleanup_callback ( device , tracks )
2008-04-19 19:01:09 +02:00
wanted_columns = [ ]
for key , caption in columns :
want_this_column = False
for track in tracks :
if getattr ( track , key ) is not None :
want_this_column = True
break
if want_this_column :
wanted_columns . append ( ( key , caption ) )
2008-01-28 12:38:53 +01:00
title = _ ( ' Remove podcasts from device ' )
instructions = _ ( ' Select the podcast episodes you want to remove from your device. ' )
2008-04-19 19:01:09 +02:00
gPodderEpisodeSelector ( title = title , instructions = instructions , episodes = tracks , columns = wanted_columns , \
2008-01-28 12:38:53 +01:00
stock_ok_button = gtk . STOCK_DELETE , callback = remove_tracks_callback )
else :
title = _ ( ' No files on device ' )
message = _ ( ' The devices contains no files to be removed. ' )
self . show_message ( message , title )
2006-04-06 16:11:03 +02:00
2008-01-09 23:46:17 +01:00
def show_hide_tray_icon ( self ) :
2008-03-11 18:45:52 +01:00
if gl . config . display_tray_icon and have_trayicon and self . tray_icon is None :
2008-01-09 23:46:17 +01:00
self . tray_icon = trayicon . GPodderStatusIcon ( self , scalable_dir )
elif not gl . config . display_tray_icon and self . tray_icon is not None :
self . tray_icon . set_visible ( False )
del self . tray_icon
self . tray_icon = None
if gl . config . minimize_to_tray and self . tray_icon :
self . tray_icon . set_visible ( self . minimized )
elif self . tray_icon :
self . tray_icon . set_visible ( True )
2008-02-06 10:29:56 +01:00
def on_itemShowToolbar_activate ( self , widget ) :
gl . config . show_toolbar = self . itemShowToolbar . get_active ( )
def on_itemShowDescription_activate ( self , widget ) :
gl . config . episode_list_descriptions = self . itemShowDescription . get_active ( )
2007-11-08 20:11:57 +01:00
def update_item_device ( self ) :
if gl . config . device_type != ' none ' :
self . itemDevice . show_all ( )
2008-05-02 17:36:43 +02:00
( label , ) = self . itemDevice . get_children ( )
label . set_text ( gl . get_device_name ( ) )
2007-11-08 20:11:57 +01:00
else :
self . itemDevice . hide_all ( )
def properties_closed ( self ) :
2008-01-09 23:46:17 +01:00
self . show_hide_tray_icon ( )
2007-11-08 20:11:57 +01:00
self . update_item_device ( )
self . updateComboBox ( )
2005-11-21 19:21:25 +01:00
def on_itemPreferences_activate ( self , widget , * args ) :
2008-04-24 19:42:57 +02:00
if gpodder . interface == gpodder . GUI :
gPodderProperties ( callback_finished = self . properties_closed , user_apps_reader = self . user_apps_reader )
else :
gPodderMaemoPreferences ( )
2005-11-21 19:21:25 +01:00
def on_itemAddChannel_activate ( self , widget , * args ) :
2008-05-02 17:36:43 +02:00
if gpodder . interface == gpodder . MAEMO or not gl . config . show_podcast_url_entry :
2008-04-24 19:42:57 +02:00
gPodderAddPodcastDialog ( url_callback = self . add_new_channel )
else :
if self . channelPaned . get_position ( ) < 200 :
self . channelPaned . set_position ( 200 )
self . entryAddChannel . grab_focus ( )
2005-11-21 19:21:25 +01:00
def on_itemEditChannel_activate ( self , widget , * args ) :
2008-02-26 16:49:59 +01:00
if self . active_channel is None :
2008-05-02 17:36:43 +02:00
title = _ ( ' No podcast selected ' )
message = _ ( ' Please select a podcast in the podcasts list to edit. ' )
2007-03-10 18:42:32 +01:00
self . show_message ( message , title )
2006-04-06 16:11:03 +02:00
return
2007-07-11 20:28:09 +02:00
2008-03-03 23:09:34 +01:00
gPodderChannel ( channel = self . active_channel , callback_closed = self . updateComboBox , callback_change_url = self . change_channel_url )
def change_channel_url ( self , old_url , new_url ) :
channel = None
try :
channel = podcastChannel . get_by_url ( url = new_url , force_update = True )
except :
channel = None
if channel is None :
self . show_message ( _ ( ' The specified URL is invalid. The old URL has been used instead. ' ) , _ ( ' Invalid URL ' ) )
return
for channel in self . channels :
if channel . url == old_url :
log ( ' => change channel url from %s to %s ' , old_url , new_url )
old_save_dir = channel . save_dir
channel . url = new_url
new_save_dir = channel . save_dir
log ( ' old save dir= %s ' , old_save_dir , sender = self )
log ( ' new save dir= %s ' , new_save_dir , sender = self )
files = glob . glob ( os . path . join ( old_save_dir , ' * ' ) )
log ( ' moving %d files to %s ' , len ( files ) , new_save_dir , sender = self )
for file in files :
log ( ' moving %s ' , file , sender = self )
shutil . move ( file , new_save_dir )
try :
os . rmdir ( old_save_dir )
except :
log ( ' Warning: cannot delete %s ' , old_save_dir , sender = self )
save_channels ( self . channels )
2008-05-14 15:38:06 +02:00
# update feed cache and select the podcast with the new URL afterwards
self . update_feed_cache ( force_update = False , select_url_afterwards = new_url )
2007-07-11 13:05:02 +02:00
2005-11-21 19:21:25 +01:00
def on_itemRemoveChannel_activate ( self , widget , * args ) :
try :
2008-04-06 02:19:03 +02:00
if gpodder . interface == gpodder . GUI :
dialog = gtk . MessageDialog ( self . gPodder , gtk . DIALOG_MODAL , gtk . MESSAGE_QUESTION , gtk . BUTTONS_NONE )
dialog . add_button ( gtk . STOCK_NO , gtk . RESPONSE_NO )
dialog . add_button ( gtk . STOCK_YES , gtk . RESPONSE_YES )
2008-05-02 17:36:43 +02:00
title = _ ( ' Remove podcast and episodes? ' )
2008-04-06 02:19:03 +02:00
message = _ ( ' Do you really want to remove <b> %s </b> and all downloaded episodes? ' ) % saxutils . escape ( self . active_channel . title )
dialog . set_title ( title )
dialog . set_markup ( ' <span weight= " bold " size= " larger " > %s </span> \n \n %s ' % ( title , message ) )
cb_ask = gtk . CheckButton ( _ ( ' Do not delete my downloaded episodes ' ) )
dialog . vbox . pack_start ( cb_ask )
cb_ask . show_all ( )
affirmative = gtk . RESPONSE_YES
elif gpodder . interface == gpodder . MAEMO :
cb_ask = gtk . CheckButton ( ' ' ) # dummy check button
2008-05-02 17:36:43 +02:00
dialog = hildon . Note ( ' confirmation ' , ( self . gPodder , _ ( ' Do you really want to remove this podcast and all downloaded episodes? ' ) ) )
2008-04-06 02:19:03 +02:00
affirmative = gtk . RESPONSE_OK
2008-01-14 20:06:26 +01:00
result = dialog . run ( )
dialog . destroy ( )
2008-04-06 02:19:03 +02:00
if result == affirmative :
2008-01-14 20:06:26 +01:00
# delete downloaded episodes only if checkbox is unchecked
if cb_ask . get_active ( ) == False :
self . active_channel . remove_downloaded ( )
else :
log ( ' Not removing downloaded episodes ' , sender = self )
2007-02-03 11:48:32 +01:00
# only delete partial files if we do not have any downloads in progress
2007-08-24 16:49:41 +02:00
delete_partial = not services . download_status_manager . has_items ( )
2008-03-02 14:22:29 +01:00
gl . clean_up_downloads ( delete_partial )
2008-05-14 15:38:06 +02:00
# get the URL of the podcast we want to select next
position = self . channels . index ( self . active_channel )
if position == len ( self . channels ) - 1 :
# this is the last podcast, so select the URL
# of the item before this one (i.e. the "new last")
select_url = self . channels [ position - 1 ] . url
else :
# there is a podcast after the deleted one, so
# we simply select the one that comes after it
select_url = self . channels [ position + 1 ] . url
# Remove the channel
2008-01-14 20:06:26 +01:00
self . channels . remove ( self . active_channel )
save_channels ( self . channels )
2008-05-14 15:38:06 +02:00
# Re-load the channels and select the desired new channel
self . update_feed_cache ( force_update = False , select_url_afterwards = select_url )
2005-11-21 19:21:25 +01:00
except :
2008-04-22 22:24:19 +02:00
log ( ' There has been an error removing the channel. ' , traceback = True , sender = self )
2005-11-21 19:21:25 +01:00
2008-05-02 17:36:43 +02:00
def get_opml_filter ( self ) :
filter = gtk . FileFilter ( )
filter . add_pattern ( ' *.opml ' )
filter . add_pattern ( ' *.xml ' )
filter . set_name ( _ ( ' OPML files ' ) + ' (*.opml, *.xml) ' )
return filter
def on_item_import_from_file_activate ( self , widget ) :
if gpodder . interface == gpodder . GUI :
dlg = gtk . FileChooserDialog ( title = _ ( ' Import from OPML ' ) , parent = None , action = gtk . FILE_CHOOSER_ACTION_OPEN )
dlg . add_button ( gtk . STOCK_CANCEL , gtk . RESPONSE_CANCEL )
dlg . add_button ( gtk . STOCK_OPEN , gtk . RESPONSE_OK )
elif gpodder . interface == gpodder . MAEMO :
dlg = hildon . FileChooserDialog ( self . gPodder , gtk . FILE_CHOOSER_ACTION_OPEN )
dlg . set_filter ( self . get_opml_filter ( ) )
response = dlg . run ( )
filename = None
if response == gtk . RESPONSE_OK :
filename = dlg . get_filename ( )
dlg . destroy ( )
if filename is not None :
gPodderOpmlLister ( custom_title = _ ( ' Import podcasts from OPML file ' ) , hide_url_entry = True ) . get_channels_from_url ( filename , lambda url : self . add_new_channel ( url , False ) , lambda : self . on_itemDownloadAllNew_activate ( self . gPodder ) )
2005-11-21 19:21:25 +01:00
def on_itemExportChannels_activate ( self , widget , * args ) :
2006-12-09 02:59:53 +01:00
if not self . channels :
2007-03-10 18:42:32 +01:00
title = _ ( ' Nothing to export ' )
2008-05-02 17:36:43 +02:00
message = _ ( ' Your list of podcast subscriptions is empty. Please subscribe to some podcasts first before trying to export your subscription list. ' )
2007-03-10 18:42:32 +01:00
self . show_message ( message , title )
2006-12-09 02:59:53 +01:00
return
2008-05-02 17:36:43 +02:00
if gpodder . interface == gpodder . GUI :
dlg = gtk . FileChooserDialog ( title = _ ( ' Export to OPML ' ) , parent = self . gPodder , action = gtk . FILE_CHOOSER_ACTION_SAVE )
dlg . add_button ( gtk . STOCK_CANCEL , gtk . RESPONSE_CANCEL )
dlg . add_button ( gtk . STOCK_SAVE , gtk . RESPONSE_OK )
elif gpodder . interface == gpodder . MAEMO :
dlg = hildon . FileChooserDialog ( self . gPodder , gtk . FILE_CHOOSER_ACTION_SAVE )
dlg . set_filter ( self . get_opml_filter ( ) )
2005-12-08 20:47:35 +01:00
response = dlg . run ( )
if response == gtk . RESPONSE_OK :
2007-08-19 16:28:24 +02:00
filename = dlg . get_filename ( )
exporter = opml . Exporter ( filename )
if not exporter . write ( self . channels ) :
self . show_message ( _ ( ' Could not export OPML to file. Please check your permissions. ' ) , _ ( ' OPML export failed ' ) )
2006-12-09 02:59:53 +01:00
2005-12-08 20:47:35 +01:00
dlg . destroy ( )
2005-11-21 19:21:25 +01:00
2006-06-13 23:00:31 +02:00
def on_itemImportChannels_activate ( self , widget , * args ) :
2008-03-02 14:22:29 +01:00
gPodderOpmlLister ( ) . get_channels_from_url ( gl . config . opml_url , lambda url : self . add_new_channel ( url , False ) , lambda : self . on_itemDownloadAllNew_activate ( self . gPodder ) )
2006-06-13 23:00:31 +02:00
2007-03-18 19:28:17 +01:00
def on_btnTransfer_clicked ( self , widget , * args ) :
self . on_treeAvailable_row_activated ( widget , args )
2006-12-04 14:06:42 +01:00
def on_homepage_activate ( self , widget , * args ) :
2008-03-03 20:38:22 +01:00
util . open_website ( app_website )
2006-12-04 14:06:42 +01:00
2007-12-13 08:05:25 +01:00
def on_wiki_activate ( self , widget , * args ) :
2008-03-03 20:38:22 +01:00
util . open_website ( ' http://wiki.gpodder.org/ ' )
2006-12-04 14:06:42 +01:00
2008-01-14 20:23:49 +01:00
def on_bug_tracker_activate ( self , widget , * args ) :
2008-03-03 20:38:22 +01:00
util . open_website ( ' http://bugs.gpodder.org/ ' )
2008-01-14 20:23:49 +01:00
2005-11-21 19:21:25 +01:00
def on_itemAbout_activate ( self , widget , * args ) :
dlg = gtk . AboutDialog ( )
Sat, 29 Mar 2008 17:13:26 +0100 <thp@perli.net>
Project management updates (authors, contributors and copyright)
* AUTHORS: Removed (was outdated); content now in gui.py (AboutDialog)
* bin/gpodder, data/po/Makefile, doc/dev/copyright_notice,
doc/dev/win32/setup-win32.py, INSTALL, Makefile, README,
setup.py: Updated Copyright and old website URL to include 2008, the
gPodder team and www.gpodder.org
* src/gpodder/*.py: Updated Copyright years
* src/gpodder/gui.py: Add list of contributors from AUTHORS file and
from the content on the website's news page (please mail me if I
forgot to mention you as a contributor, I surely have missed a few);
make the AboutDialog's application name "gPodder" (from gpodder) and
add an URL hook function to the AboutDialog, so the website is opened
in the user's default web browser
git-svn-id: svn://svn.berlios.de/gpodder/trunk@648 b0d088ad-0a06-0410-aad2-9ed5178a7e87
2008-03-29 17:16:55 +01:00
dlg . set_name ( app_name . replace ( ' p ' , ' P ' ) ) # gpodder->gPodder
2005-11-21 19:21:25 +01:00
dlg . set_version ( app_version )
dlg . set_copyright ( app_copyright )
dlg . set_website ( app_website )
2006-04-06 16:11:03 +02:00
dlg . set_translator_credits ( _ ( ' translator-credits ' ) )
2007-08-28 00:18:01 +02:00
dlg . connect ( ' response ' , lambda dlg , response : dlg . destroy ( ) )
2006-12-04 14:06:42 +01:00
2008-04-06 02:19:03 +02:00
if gpodder . interface == gpodder . GUI :
# For the "GUI" version, we add some more
# items to the about dialog (credits and logo)
dlg . set_authors ( app_authors )
try :
dlg . set_logo ( gtk . gdk . pixbuf_new_from_file_at_size ( scalable_dir , 200 , 200 ) )
except :
pass
2006-12-04 14:06:42 +01:00
2005-11-21 19:21:25 +01:00
dlg . run ( )
2006-11-29 00:23:16 +01:00
2006-02-04 18:29:17 +01:00
def on_wNotebook_switch_page ( self , widget , * args ) :
2007-03-31 04:00:30 +02:00
page_num = args [ 1 ]
2008-04-06 02:19:03 +02:00
if gpodder . interface == gpodder . MAEMO :
page = self . wNotebook . get_nth_page ( page_num )
2008-04-24 18:28:39 +02:00
tab_label = self . wNotebook . get_tab_label ( page ) . get_text ( )
if page_num == 0 and self . active_channel is not None :
self . set_title ( self . active_channel . title )
else :
self . set_title ( tab_label )
2007-03-31 04:00:30 +02:00
if page_num == 0 :
self . play_or_download ( )
else :
self . toolDownload . set_sensitive ( False )
self . toolPlay . set_sensitive ( False )
self . toolTransfer . set_sensitive ( False )
2007-08-24 16:49:41 +02:00
self . toolCancel . set_sensitive ( services . download_status_manager . has_items ( ) )
2006-02-04 18:29:17 +01:00
2007-07-05 23:07:16 +02:00
def on_treeChannels_row_activated ( self , widget , * args ) :
self . on_itemEditChannel_activate ( self . treeChannels )
def on_treeChannels_cursor_changed ( self , widget , * args ) :
2007-09-19 17:04:42 +02:00
( model , iter ) = self . treeChannels . get_selection ( ) . get_selected ( )
2007-07-11 13:05:02 +02:00
2008-04-22 21:16:30 +02:00
if model is not None and iter != None :
2007-09-19 17:04:42 +02:00
id = model . get_path ( iter ) [ 0 ]
self . active_channel = self . channels [ id ]
2006-12-09 02:59:53 +01:00
2008-04-06 02:19:03 +02:00
if gpodder . interface == gpodder . MAEMO :
self . set_title ( self . active_channel . title )
2006-12-16 18:44:13 +01:00
self . itemEditChannel . show_all ( )
self . itemRemoveChannel . show_all ( )
else :
2007-09-19 17:04:42 +02:00
self . active_channel = None
2006-12-16 18:44:13 +01:00
self . itemEditChannel . hide_all ( )
self . itemRemoveChannel . hide_all ( )
2005-11-21 19:21:25 +01:00
self . updateTreeView ( )
2007-09-19 17:04:42 +02:00
def on_entryAddChannel_changed ( self , widget , * args ) :
2008-05-02 17:36:43 +02:00
active = self . entryAddChannel . get_text ( ) not in ( ' ' , self . ENTER_URL_TEXT )
2007-09-19 17:04:42 +02:00
self . btnAddChannel . set_sensitive ( active )
def on_btnAddChannel_clicked ( self , widget , * args ) :
url = self . entryAddChannel . get_text ( )
self . entryAddChannel . set_text ( ' ' )
self . add_new_channel ( url )
2006-03-04 21:45:01 +01:00
def on_btnEditChannel_clicked ( self , widget , * args ) :
self . on_itemEditChannel_activate ( widget , args )
2005-11-21 19:21:25 +01:00
def on_treeAvailable_row_activated ( self , widget , * args ) :
2006-03-29 16:40:08 +02:00
try :
2006-06-22 23:41:32 +02:00
selection = self . treeAvailable . get_selection ( )
selection_tuple = selection . get_selected_rows ( )
2007-03-18 19:28:17 +01:00
transfer_files = False
episodes = [ ]
2006-12-09 02:59:53 +01:00
2006-06-22 23:41:32 +02:00
if selection . count_selected_rows ( ) > 1 :
widget_to_send = None
show_message_dialog = False
else :
widget_to_send = widget
show_message_dialog = True
2006-12-09 02:59:53 +01:00
2007-03-31 04:00:30 +02:00
if widget . get_name ( ) == ' itemTransferSelected ' or widget . get_name ( ) == ' toolTransfer ' :
2007-03-18 19:28:17 +01:00
transfer_files = True
2008-05-14 15:38:06 +02:00
services . download_status_manager . start_batch_mode ( )
2006-06-22 23:41:32 +02:00
for apath in selection_tuple [ 1 ] :
2006-12-09 02:59:53 +01:00
selection_iter = self . treeAvailable . get_model ( ) . get_iter ( apath )
url = self . treeAvailable . get_model ( ) . get_value ( selection_iter , 0 )
2007-03-18 19:28:17 +01:00
if transfer_files :
episodes . append ( self . active_channel . find_episode ( url ) )
else :
self . download_podcast_by_url ( url , show_message_dialog , widget_to_send )
2008-05-14 15:38:06 +02:00
services . download_status_manager . end_batch_mode ( )
2007-03-18 19:28:17 +01:00
if transfer_files and len ( episodes ) :
2008-01-28 12:38:53 +01:00
self . on_sync_to_ipod_activate ( None , episodes )
2006-03-29 16:40:08 +02:00
except :
2007-03-10 18:42:32 +01:00
title = _ ( ' Nothing selected ' )
message = _ ( ' Please select an episode that you want to download and then click on the download button to start downloading the selected episode. ' )
self . show_message ( message , title )
2005-11-21 19:21:25 +01:00
def on_btnDownload_clicked ( self , widget , * args ) :
self . on_treeAvailable_row_activated ( widget , args )
2006-12-13 00:11:34 +01:00
def on_treeAvailable_button_release_event ( self , widget , * args ) :
self . play_or_download ( )
2008-01-09 23:46:17 +01:00
def auto_update_procedure ( self , first_run = False ) :
log ( ' auto_update_procedure() got called ' , sender = self )
2008-02-02 11:38:34 +01:00
if not first_run and gl . config . auto_update_feeds and self . minimized :
2008-01-09 23:46:17 +01:00
self . update_feed_cache ( )
next_update = 60 * 1000 * gl . config . auto_update_frequency
gobject . timeout_add ( next_update , self . auto_update_procedure )
2006-07-20 15:19:19 +02:00
2005-11-23 20:53:18 +01:00
def on_treeDownloads_row_activated ( self , widget , * args ) :
2007-08-25 18:05:03 +02:00
cancel_urls = [ ]
if self . wNotebook . get_current_page ( ) > 0 :
# Use the download list treeview + model
( tree , column ) = ( self . treeDownloads , 3 )
else :
# Use the available podcasts treeview + model
( tree , column ) = ( self . treeAvailable , 0 )
2006-07-14 22:09:00 +02:00
2007-08-26 17:20:46 +02:00
selection = tree . get_selection ( )
( model , paths ) = selection . get_selected_rows ( )
2007-08-25 18:05:03 +02:00
for path in paths :
url = model . get_value ( model . get_iter ( path ) , column )
cancel_urls . append ( url )
2007-03-10 18:42:32 +01:00
2007-08-25 18:05:03 +02:00
if len ( cancel_urls ) == 0 :
log ( ' Nothing selected. ' , sender = self )
return
if len ( cancel_urls ) == 1 :
2007-03-10 18:42:32 +01:00
title = _ ( ' Cancel download? ' )
message = _ ( " Cancelling this download will remove the partially downloaded file and stop the download. " )
2007-08-25 18:05:03 +02:00
else :
title = _ ( ' Cancel downloads? ' )
message = _ ( " Cancelling the download will stop the %d selected downloads and remove partially downloaded files. " ) % selection . count_selected_rows ( )
2007-03-10 18:42:32 +01:00
if self . show_confirmation ( message , title ) :
2008-05-14 15:38:06 +02:00
services . download_status_manager . start_batch_mode ( )
2007-08-25 18:05:03 +02:00
for url in cancel_urls :
services . download_status_manager . cancel_by_url ( url )
2008-05-14 15:38:06 +02:00
services . download_status_manager . end_batch_mode ( )
2005-11-23 20:53:18 +01:00
def on_btnCancelDownloadStatus_clicked ( self , widget , * args ) :
self . on_treeDownloads_row_activated ( widget , None )
2006-07-20 15:19:19 +02:00
def on_btnCancelAll_clicked ( self , widget , * args ) :
self . treeDownloads . get_selection ( ) . select_all ( )
2007-03-31 04:00:30 +02:00
self . on_treeDownloads_row_activated ( self . toolCancel , None )
2006-07-20 15:19:19 +02:00
self . treeDownloads . get_selection ( ) . unselect_all ( )
2006-02-04 18:29:17 +01:00
def on_btnDownloadedExecute_clicked ( self , widget , * args ) :
2006-12-09 02:59:53 +01:00
self . on_treeAvailable_row_activated ( widget , args )
2006-02-04 18:29:17 +01:00
2006-03-24 20:08:59 +01:00
def on_btnDownloadedDelete_clicked ( self , widget , * args ) :
2008-02-26 16:49:59 +01:00
if self . active_channel is None :
2007-08-26 17:20:46 +02:00
return
2006-12-09 02:59:53 +01:00
channel_url = self . active_channel . url
selection = self . treeAvailable . get_selection ( )
2007-09-09 18:49:56 +02:00
( model , paths ) = selection . get_selected_rows ( )
2006-07-14 22:09:00 +02:00
if selection . count_selected_rows ( ) == 0 :
2006-11-17 15:26:10 +01:00
log ( ' Nothing selected - will not remove any downloaded episode. ' )
2006-07-14 22:09:00 +02:00
return
2006-07-14 21:10:47 +02:00
if selection . count_selected_rows ( ) == 1 :
2007-12-12 19:50:52 +01:00
episode_title = saxutils . escape ( model . get_value ( model . get_iter ( paths [ 0 ] ) , 1 ) )
2008-03-02 14:22:29 +01:00
locked = gl . history_is_locked ( model . get_value ( model . get_iter ( paths [ 0 ] ) , 0 ) )
2007-12-12 19:50:52 +01:00
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
2007-03-10 18:42:32 +01:00
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. " )
2007-09-09 18:49:56 +02:00
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. ' )
2007-12-12 19:50:52 +01:00
locked_count = 0
for path in paths :
url = model . get_value ( model . get_iter ( path ) , 0 )
2008-03-02 14:22:29 +01:00
if gl . history_is_locked ( url ) :
2007-12-12 19:50:52 +01:00
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. ' )
2006-07-14 21:10:47 +02:00
# if user confirms deletion, let's remove some stuff ;)
2007-03-10 18:42:32 +01:00
if self . show_confirmation ( message , title ) :
2007-02-03 11:48:32 +01:00
try :
2006-07-14 21:10:47 +02:00
# iterate over the selection, see also on_treeDownloads_row_activated
2007-09-09 18:49:56 +02:00
for path in paths :
url = model . get_value ( model . get_iter ( path ) , 0 )
2007-03-14 20:35:15 +01:00
self . active_channel . delete_episode_by_url ( url )
2008-03-02 14:22:29 +01:00
gl . history_mark_downloaded ( url )
2006-07-14 21:10:47 +02:00
# now, clear local db cache so we can re-read it
2006-03-29 14:41:34 +02:00
self . updateComboBox ( )
2007-02-03 11:48:32 +01:00
except :
log ( ' Error while deleting (some) downloads. ' )
2007-09-09 18:49:56 +02:00
2007-02-03 11:48:32 +01:00
# only delete partial files if we do not have any downloads in progress
2007-08-24 16:49:41 +02:00
delete_partial = not services . download_status_manager . has_items ( )
2008-03-02 14:22:29 +01:00
gl . clean_up_downloads ( delete_partial )
2007-08-20 15:45:46 +02:00
self . active_channel . force_update_tree_model ( )
self . updateTreeView ( )
2006-03-24 20:08:59 +01:00
2008-04-06 02:19:03 +02:00
def on_key_press ( self , widget , event ) :
# Currently, we only handle Maemo hardware keys here,
# so if we are not a Maemo app, we don't do anything!
if gpodder . interface != gpodder . MAEMO :
return
if event . keyval == gtk . keysyms . F6 :
if self . fullscreen :
self . window . unfullscreen ( )
else :
self . window . fullscreen ( )
if event . keyval == gtk . keysyms . Escape :
new_visibility = not self . vboxChannelNavigator . get_property ( ' visible ' )
self . vboxChannelNavigator . set_property ( ' visible ' , new_visibility )
self . column_size . set_visible ( not new_visibility )
self . column_released . set_visible ( not new_visibility )
diff = 0
if event . keyval == gtk . keysyms . F7 : #plus
diff = 1
elif event . keyval == gtk . keysyms . F8 : #minus
diff = - 1
if diff != 0 :
selection = self . treeChannels . get_selection ( )
( model , iter ) = selection . get_selected ( )
selection . select_path ( ( ( model . get_path ( iter ) [ 0 ] + diff ) % len ( model ) , ) )
self . on_treeChannels_cursor_changed ( self . treeChannels )
2008-01-09 23:46:17 +01:00
def window_state_event ( self , widget , event ) :
2008-04-06 02:19:03 +02:00
if event . new_window_state & gtk . gdk . WINDOW_STATE_FULLSCREEN :
self . fullscreen = True
else :
self . fullscreen = False
2008-01-09 23:46:17 +01:00
old_minimized = self . minimized
if event . new_window_state & gtk . gdk . WINDOW_STATE_ICONIFIED :
self . minimized = True
else :
self . minimized = False
2007-07-11 13:05:02 +02:00
2008-01-09 23:46:17 +01:00
if old_minimized != self . minimized and self . tray_icon :
self . gPodder . set_skip_taskbar_hint ( self . minimized )
elif not self . tray_icon :
self . gPodder . set_skip_taskbar_hint ( False )
if gl . config . minimize_to_tray and self . tray_icon :
self . tray_icon . set_visible ( self . minimized )
def uniconify_main_window ( self ) :
if self . minimized :
self . gPodder . present ( )
def iconify_main_window ( self ) :
if not self . minimized :
self . gPodder . iconify ( )
2007-07-11 13:05:02 +02:00
2007-08-28 00:18:01 +02:00
class gPodderChannel ( GladeWidget ) :
2008-04-24 18:28:39 +02:00
finger_friendly_widgets = [ ' btn_website ' , ' btnOK ' , ' channel_description ' ]
2005-11-21 19:21:25 +01:00
def new ( self ) :
2008-04-06 02:19:03 +02:00
global WEB_BROWSER_ICON
self . image3167 . set_property ( ' icon-name ' , WEB_BROWSER_ICON )
2007-08-28 00:18:01 +02:00
self . gPodderChannel . set_title ( self . channel . title )
self . entryTitle . set_text ( self . channel . title )
self . entryURL . set_text ( self . channel . url )
self . LabelDownloadTo . set_text ( self . channel . save_dir )
self . LabelWebsite . set_text ( self . channel . link )
self . channel . load_settings ( )
self . cbNoSync . set_active ( not self . channel . sync_to_devices )
2008-01-28 12:38:53 +01:00
self . musicPlaylist . set_text ( self . channel . device_playlist_name )
2007-08-28 00:18:01 +02:00
if self . channel . username :
self . FeedUsername . set_text ( self . channel . username )
if self . channel . password :
self . FeedPassword . set_text ( self . channel . password )
2007-09-19 17:04:42 +02:00
self . on_btnClearCover_clicked ( self . btnClearCover , delete_file = False )
self . on_btnDownloadCover_clicked ( self . btnDownloadCover , url = False )
2008-03-03 20:54:42 +01:00
# Hide the website button if we don't have a valid URL
if not self . channel . link :
self . btn_website . hide_all ( )
2006-03-31 18:20:18 +02:00
2006-03-04 21:45:01 +01:00
b = gtk . TextBuffer ( )
2007-08-28 00:18:01 +02:00
b . set_text ( self . channel . description )
2006-03-04 21:45:01 +01:00
self . channel_description . set_buffer ( b )
2007-07-11 13:05:02 +02:00
2007-09-19 17:04:42 +02:00
#Add Drag and Drop Support
flags = gtk . DEST_DEFAULT_ALL
targets = [ ( ' text/uri-list ' , 0 , 2 ) , ( ' text/plain ' , 0 , 4 ) ]
actions = gtk . gdk . ACTION_DEFAULT | gtk . gdk . ACTION_COPY
self . vboxCoverEditor . drag_dest_set ( flags , targets , actions )
self . vboxCoverEditor . connect ( ' drag_data_received ' , self . drag_data_received )
2008-03-03 20:54:42 +01:00
def on_btn_website_clicked ( self , widget ) :
util . open_website ( self . channel . link )
2007-09-19 17:04:42 +02:00
def on_btnClearCover_clicked ( self , widget , delete_file = True ) :
self . imgCover . clear ( )
if delete_file :
util . delete_file ( self . channel . cover_file )
self . btnClearCover . set_sensitive ( os . path . exists ( self . channel . cover_file ) )
self . btnDownloadCover . set_sensitive ( not os . path . exists ( self . channel . cover_file ) and bool ( self . channel . image ) )
self . labelCoverStatus . set_text ( _ ( ' You can drag a cover file here. ' ) )
self . labelCoverStatus . show ( )
def on_btnDownloadCover_clicked ( self , widget , url = None ) :
2008-02-26 16:49:59 +01:00
if url is None :
2007-09-19 17:04:42 +02:00
url = self . channel . image
if url != False :
self . btnDownloadCover . set_sensitive ( False )
self . labelCoverStatus . show ( )
2008-03-02 14:22:29 +01:00
gl . get_image_from_url ( url , self . imgCover . set_from_pixbuf , self . labelCoverStatus . set_text , self . cover_download_finished , self . channel . cover_file )
2007-09-19 17:04:42 +02:00
def cover_download_finished ( self ) :
self . labelCoverStatus . hide ( )
self . btnClearCover . set_sensitive ( os . path . exists ( self . channel . cover_file ) )
self . btnDownloadCover . set_sensitive ( not os . path . exists ( self . channel . cover_file ) and bool ( self . channel . image ) )
def drag_data_received ( self , widget , content , x , y , sel , ttype , time ) :
files = sel . data . strip ( ) . split ( ' \n ' )
if len ( files ) != 1 :
self . show_message ( _ ( ' You can only drop a single image or URL here. ' ) , _ ( ' Drag and drop ' ) )
return
file = files [ 0 ]
if file . startswith ( ' file:// ' ) or file . startswith ( ' http:// ' ) :
self . on_btnClearCover_clicked ( self . btnClearCover )
if file . startswith ( ' file:// ' ) :
filename = file [ len ( ' file:// ' ) : ]
shutil . copyfile ( filename , self . channel . cover_file )
self . on_btnDownloadCover_clicked ( self . btnDownloadCover , url = file )
return
self . show_message ( _ ( ' You can only drop local files and http:// URLs here. ' ) , _ ( ' Drag and drop ' ) )
2005-11-21 19:21:25 +01:00
def on_gPodderChannel_destroy ( self , widget , * args ) :
2007-08-28 00:18:01 +02:00
self . callback_closed ( )
2005-11-21 19:21:25 +01:00
def on_btnOK_clicked ( self , widget , * args ) :
2008-03-03 23:09:34 +01:00
entered_url = self . entryURL . get_text ( )
channel_url = self . channel . url
if entered_url != channel_url :
2008-05-02 17:36:43 +02:00
if self . show_confirmation ( _ ( ' Do you really want to move this podcast to <b> %s </b>? ' ) % ( saxutils . escape ( entered_url ) , ) , _ ( ' Really change URL? ' ) ) :
2008-03-03 23:09:34 +01:00
if hasattr ( self , ' callback_change_url ' ) :
self . gPodderChannel . hide_all ( )
self . callback_change_url ( channel_url , entered_url )
2007-07-11 13:05:02 +02:00
self . channel . sync_to_devices = not self . cbNoSync . get_active ( )
self . channel . device_playlist_name = self . musicPlaylist . get_text ( )
self . channel . set_custom_title ( self . entryTitle . get_text ( ) )
2007-07-19 14:44:12 +02:00
self . channel . username = self . FeedUsername . get_text ( ) . strip ( )
self . channel . password = self . FeedPassword . get_text ( )
2007-08-20 15:45:46 +02:00
self . channel . save_settings ( )
2005-11-21 19:21:25 +01:00
2007-07-11 13:05:02 +02:00
self . gPodderChannel . destroy ( )
2005-11-21 19:21:25 +01:00
2008-04-24 19:42:57 +02:00
class gPodderAddPodcastDialog ( GladeWidget ) :
finger_friendly_widgets = [ ' btn_close ' , ' btn_add ' ]
def new ( self ) :
if not hasattr ( self , ' url_callback ' ) :
log ( ' No url callback set ' , sender = self )
self . url_callback = None
def on_btn_close_clicked ( self , widget ) :
self . gPodderAddPodcastDialog . destroy ( )
def on_entry_url_changed ( self , widget ) :
self . btn_add . set_sensitive ( self . entry_url . get_text ( ) . strip ( ) != ' ' )
def on_btn_add_clicked ( self , widget ) :
url = self . entry_url . get_text ( )
self . on_btn_close_clicked ( widget )
if self . url_callback is not None :
self . url_callback ( url )
class gPodderMaemoPreferences ( GladeWidget ) :
finger_friendly_widgets = [ ' btn_close ' , ' label128 ' , ' label129 ' , ' btn_advanced ' ]
def new ( self ) :
gl . config . connect_gtk_togglebutton ( ' update_on_startup ' , self . update_on_startup )
gl . config . connect_gtk_togglebutton ( ' display_tray_icon ' , self . show_tray_icon )
gl . config . connect_gtk_togglebutton ( ' enable_notifications ' , self . show_notifications )
2008-05-02 17:45:45 +02:00
gl . config . connect_gtk_togglebutton ( ' on_quit_ask ' , self . on_quit_ask )
2008-04-24 19:42:57 +02:00
self . restart_required = False
self . show_tray_icon . connect ( ' clicked ' , self . on_restart_required )
self . show_notifications . connect ( ' clicked ' , self . on_restart_required )
def on_restart_required ( self , widget ) :
self . restart_required = True
def on_btn_advanced_clicked ( self , widget ) :
self . gPodderMaemoPreferences . destroy ( )
gPodderConfigEditor ( )
def on_btn_close_clicked ( self , widget ) :
self . gPodderMaemoPreferences . destroy ( )
if self . restart_required :
self . show_message ( _ ( ' Please restart gPodder for the changes to take effect. ' ) )
2005-11-21 19:21:25 +01:00
2007-08-28 00:18:01 +02:00
class gPodderProperties ( GladeWidget ) :
2006-01-09 00:52:40 +01:00
def new ( self ) :
2007-11-08 20:11:57 +01:00
if not hasattr ( self , ' callback_finished ' ) :
self . callback_finished = None
2008-04-06 02:19:03 +02:00
if gpodder . interface == gpodder . MAEMO :
self . table13 . hide_all ( ) # bluetooth
self . table5 . hide_all ( ) # player
self . table6 . hide_all ( ) # bittorrent
self . gPodderProperties . fullscreen ( )
2007-11-02 17:37:14 +01:00
gl . config . connect_gtk_editable ( ' http_proxy ' , self . httpProxy )
gl . config . connect_gtk_editable ( ' ftp_proxy ' , self . ftpProxy )
gl . config . connect_gtk_editable ( ' player ' , self . openApp )
2008-01-21 09:57:03 +01:00
gl . config . connect_gtk_editable ( ' videoplayer ' , self . openVideoApp )
2007-11-02 17:37:14 +01:00
gl . config . connect_gtk_editable ( ' custom_sync_name ' , self . entryCustomSyncName )
gl . config . connect_gtk_togglebutton ( ' custom_sync_name_enabled ' , self . cbCustomSyncName )
2008-02-04 11:29:41 +01:00
gl . config . connect_gtk_togglebutton ( ' auto_download_when_minimized ' , self . downloadnew )
2007-11-02 17:37:14 +01:00
gl . config . connect_gtk_togglebutton ( ' use_gnome_bittorrent ' , self . radio_gnome_bittorrent )
gl . config . connect_gtk_togglebutton ( ' update_on_startup ' , self . updateonstartup )
gl . config . connect_gtk_togglebutton ( ' only_sync_not_played ' , self . only_sync_not_played )
2007-12-03 21:26:18 +01:00
gl . config . connect_gtk_togglebutton ( ' fssync_channel_subfolders ' , self . cbChannelSubfolder )
gl . config . connect_gtk_togglebutton ( ' on_sync_mark_played ' , self . on_sync_mark_played )
2007-12-18 10:18:33 +01:00
gl . config . connect_gtk_togglebutton ( ' on_sync_delete ' , self . on_sync_delete )
2007-11-02 17:37:14 +01:00
gl . config . connect_gtk_togglebutton ( ' proxy_use_environment ' , self . cbEnvironmentVariables )
gl . config . connect_gtk_filechooser ( ' bittorrent_dir ' , self . chooserBitTorrentTo )
2007-12-12 20:57:50 +01:00
gl . config . connect_gtk_spinbutton ( ' episode_old_age ' , self . episode_old_age )
gl . config . connect_gtk_togglebutton ( ' auto_remove_old_episodes ' , self . auto_remove_old_episodes )
2008-01-09 23:46:17 +01:00
gl . config . connect_gtk_togglebutton ( ' auto_update_feeds ' , self . auto_update_feeds )
gl . config . connect_gtk_spinbutton ( ' auto_update_frequency ' , self . auto_update_frequency )
gl . config . connect_gtk_togglebutton ( ' display_tray_icon ' , self . display_tray_icon )
gl . config . connect_gtk_togglebutton ( ' minimize_to_tray ' , self . minimize_to_tray )
2008-02-04 11:29:41 +01:00
gl . config . connect_gtk_togglebutton ( ' enable_notifications ' , self . enable_notifications )
2008-01-09 23:46:17 +01:00
gl . config . connect_gtk_togglebutton ( ' start_iconified ' , self . start_iconified )
2008-01-21 10:52:09 +01:00
gl . config . connect_gtk_togglebutton ( ' bluetooth_enabled ' , self . bluetooth_enabled )
gl . config . connect_gtk_togglebutton ( ' bluetooth_ask_always ' , self . bluetooth_ask_always )
gl . config . connect_gtk_togglebutton ( ' bluetooth_ask_never ' , self . bluetooth_ask_never )
gl . config . connect_gtk_togglebutton ( ' bluetooth_use_converter ' , self . bluetooth_use_converter )
gl . config . connect_gtk_filechooser ( ' bluetooth_converter ' , self . bluetooth_converter , is_for_files = True )
2008-03-11 18:55:53 +01:00
gl . config . connect_gtk_togglebutton ( ' ipod_write_gtkpod_extended ' , self . ipod_write_gtkpod_extended )
2008-06-13 09:41:36 +02:00
gl . config . connect_gtk_togglebutton ( ' mp3_player_delete_played ' , self . delete_episodes_marked_played )
2008-01-09 23:46:17 +01:00
2008-02-04 11:29:41 +01:00
self . enable_notifications . set_sensitive ( self . display_tray_icon . get_active ( ) )
self . minimize_to_tray . set_sensitive ( self . display_tray_icon . get_active ( ) )
2007-09-08 16:49:54 +02:00
self . entryCustomSyncName . set_sensitive ( self . cbCustomSyncName . get_active ( ) )
2008-05-25 17:17:48 +02:00
self . radio_gnome_bittorrent . set_active ( gl . config . use_gnome_bittorrent )
self . radio_copy_torrents . set_active ( not gl . config . use_gnome_bittorrent )
2007-11-02 17:37:14 +01:00
self . iPodMountpoint . set_label ( gl . config . ipod_mount )
self . filesystemMountpoint . set_label ( gl . config . mp3_player_folder )
2008-01-21 10:52:09 +01:00
self . bluetooth_device_name . set_markup ( ' <b> %s </b> ' % gl . config . bluetooth_device_name )
2007-12-09 13:22:50 +01:00
self . chooserDownloadTo . set_current_folder ( gl . downloaddir )
2007-11-02 17:37:14 +01:00
2008-06-13 09:41:36 +02:00
self . on_sync_delete . set_sensitive ( not self . delete_episodes_marked_played . get_active ( ) )
self . on_sync_mark_played . set_sensitive ( not self . delete_episodes_marked_played . get_active ( ) )
2007-03-17 13:11:13 +01:00
if tagging_supported ( ) :
2007-11-02 17:37:14 +01:00
gl . config . connect_gtk_togglebutton ( ' update_tags ' , self . updatetags )
2007-03-17 13:11:13 +01:00
else :
self . updatetags . set_sensitive ( False )
new_label = ' %s ( %s ) ' % ( self . updatetags . get_label ( ) , _ ( ' needs python-eyed3 ' ) )
self . updatetags . set_label ( new_label )
2007-11-02 17:37:14 +01:00
2006-12-06 21:25:26 +01:00
# device type
self . comboboxDeviceType . set_active ( 0 )
2007-11-02 17:37:14 +01:00
if gl . config . device_type == ' ipod ' :
2006-12-06 21:25:26 +01:00
self . comboboxDeviceType . set_active ( 1 )
2007-11-02 17:37:14 +01:00
elif gl . config . device_type == ' filesystem ' :
2006-12-06 21:25:26 +01:00
self . comboboxDeviceType . set_active ( 2 )
2007-11-02 17:37:14 +01:00
2006-03-30 00:07:27 +02:00
# setup cell renderers
cellrenderer = gtk . CellRendererPixbuf ( )
2008-01-21 09:57:03 +01:00
self . comboAudioPlayerApp . pack_start ( cellrenderer , False )
self . comboAudioPlayerApp . add_attribute ( cellrenderer , ' pixbuf ' , 2 )
cellrenderer = gtk . CellRendererText ( )
self . comboAudioPlayerApp . pack_start ( cellrenderer , True )
self . comboAudioPlayerApp . add_attribute ( cellrenderer , ' markup ' , 0 )
cellrenderer = gtk . CellRendererPixbuf ( )
self . comboVideoPlayerApp . pack_start ( cellrenderer , False )
self . comboVideoPlayerApp . add_attribute ( cellrenderer , ' pixbuf ' , 2 )
2006-03-30 00:07:27 +02:00
cellrenderer = gtk . CellRendererText ( )
2008-01-21 09:57:03 +01:00
self . comboVideoPlayerApp . pack_start ( cellrenderer , True )
self . comboVideoPlayerApp . add_attribute ( cellrenderer , ' markup ' , 0 )
2006-03-31 18:20:18 +02:00
2008-03-20 11:24:26 +01:00
if not hasattr ( self , ' user_apps_reader ' ) :
self . user_apps_reader = UserAppsReader ( [ ' audio ' , ' video ' ] )
2008-04-06 02:19:03 +02:00
if gpodder . interface == gpodder . GUI :
self . user_apps_reader . read ( )
2008-03-20 11:24:26 +01:00
self . comboAudioPlayerApp . set_model ( self . user_apps_reader . get_applications_as_model ( ' audio ' ) )
index = self . find_active_audio_app ( )
self . comboAudioPlayerApp . set_active ( index )
self . comboVideoPlayerApp . set_model ( self . user_apps_reader . get_applications_as_model ( ' video ' ) )
index = self . find_active_video_app ( )
self . comboVideoPlayerApp . set_active ( index )
2007-11-02 17:37:14 +01:00
self . ipodIcon . set_from_icon_name ( ' gnome-dev-ipod ' , gtk . ICON_SIZE_BUTTON )
2006-04-09 18:18:47 +02:00
def update_mountpoint ( self , ipod ) :
2008-02-26 16:49:59 +01:00
if ipod is None or ipod . mount_point is None :
2006-12-06 21:25:26 +01:00
self . iPodMountpoint . set_label ( ' ' )
2006-04-09 18:18:47 +02:00
else :
2006-12-06 21:25:26 +01:00
self . iPodMountpoint . set_label ( ipod . mount_point )
2008-01-21 10:52:09 +01:00
def on_bluetooth_select_device_clicked ( self , widget ) :
2008-03-22 21:08:54 +01:00
# Stupid GTK doesn't provide us with a method to directly
# edit the text of a gtk.Button without "destroying" the
# image on it, so we dig into the button's widget tree and
# get the gtk.Image and gtk.Label and edit the label directly.
alignment = self . bluetooth_select_device . get_child ( )
hbox = alignment . get_child ( )
( image , label ) = hbox . get_children ( )
old_text = label . get_text ( )
label . set_text ( _ ( ' Searching... ' ) )
2008-01-21 10:52:09 +01:00
self . bluetooth_select_device . set_sensitive ( False )
2008-03-22 21:08:54 +01:00
while gtk . events_pending ( ) :
gtk . main_iteration ( False )
# FIXME: Make bluetooth device discovery threaded, so
# the GUI doesn't freeze while we are searching for devices
2008-03-19 15:43:22 +01:00
found = False
2008-01-21 10:52:09 +01:00
for name , address in util . discover_bluetooth_devices ( ) :
if self . show_confirmation ( ' Use this device as your bluetooth device? ' , name ) :
gl . config . bluetooth_device_name = name
gl . config . bluetooth_device_address = address
self . bluetooth_device_name . set_markup ( ' <b> %s </b> ' % gl . config . bluetooth_device_name )
2008-03-19 15:43:22 +01:00
found = True
break
if not found :
self . show_message ( ' No more devices found ' , ' Scan finished ' )
2008-01-21 10:52:09 +01:00
self . bluetooth_select_device . set_sensitive ( True )
2008-03-22 21:08:54 +01:00
label . set_text ( old_text )
2006-04-09 18:18:47 +02:00
2008-01-21 09:57:03 +01:00
def find_active_audio_app ( self ) :
model = self . comboAudioPlayerApp . get_model ( )
2006-03-30 00:07:27 +02:00
iter = model . get_iter_first ( )
index = 0
2008-01-21 09:57:03 +01:00
while iter is not None :
command = model . get_value ( iter , 1 )
2006-03-30 00:07:27 +02:00
if command == self . openApp . get_text ( ) :
return index
2008-01-21 09:57:03 +01:00
iter = model . iter_next ( iter )
index + = 1
# return last item = custom command
return index - 1
def find_active_video_app ( self ) :
model = self . comboVideoPlayerApp . get_model ( )
iter = model . get_iter_first ( )
index = 0
while iter is not None :
command = model . get_value ( iter , 1 )
if command == self . openVideoApp . get_text ( ) :
return index
iter = model . iter_next ( iter )
index + = 1
2006-03-30 00:07:27 +02:00
# return last item = custom command
return index - 1
2006-12-20 17:38:36 +01:00
def set_download_dir ( self , new_download_dir , event = None ) :
gl . downloaddir = self . chooserDownloadTo . get_filename ( )
2007-08-28 00:18:01 +02:00
if gl . downloaddir != self . chooserDownloadTo . get_filename ( ) :
2008-01-15 14:54:22 +01:00
self . notification ( _ ( ' There has been an error moving your downloads to the specified location. The old download directory will be used instead. ' ) , _ ( ' Error moving downloads ' ) )
2006-12-20 17:38:36 +01:00
if event :
event . set ( )
2008-01-09 23:46:17 +01:00
def on_auto_update_feeds_toggled ( self , widget , * args ) :
self . auto_update_frequency . set_sensitive ( widget . get_active ( ) )
2008-02-04 11:29:41 +01:00
def on_display_tray_icon_toggled ( self , widget , * args ) :
self . enable_notifications . set_sensitive ( widget . get_active ( ) )
self . minimize_to_tray . set_sensitive ( widget . get_active ( ) )
2007-09-08 16:49:54 +02:00
def on_cbCustomSyncName_toggled ( self , widget , * args ) :
self . entryCustomSyncName . set_sensitive ( widget . get_active ( ) )
2008-06-13 09:41:36 +02:00
def on_only_sync_not_played_toggled ( self , widget , * args ) :
self . delete_episodes_marked_played . set_sensitive ( widget . get_active ( ) )
if not widget . get_active ( ) :
self . delete_episodes_marked_played . set_active ( False )
def on_delete_episodes_marked_played_toggled ( self , widget , * args ) :
if widget . get_active ( ) and self . only_sync_not_played . get_active ( ) :
self . on_sync_leave . set_active ( True )
self . on_sync_delete . set_sensitive ( not widget . get_active ( ) )
self . on_sync_mark_played . set_sensitive ( not widget . get_active ( ) )
2007-09-08 16:49:54 +02:00
def on_btnCustomSyncNameHelp_clicked ( self , widget ) :
examples = [
2007-09-21 00:18:57 +02:00
' <i> {episode.title} </i> -> <b>Interview with RMS</b> ' ,
' <i> {episode.basename} </i> -> <b>70908-interview-rms</b> ' ,
' <i> {episode.published} </i> -> <b>20070908</b> '
2007-09-08 16:49:54 +02:00
]
info = [
_ ( ' You can specify a custom format string for the file names on your MP3 player here. ' ) ,
_ ( ' The format string will be used to generate a file name on your device. The file extension (e.g. " .mp3 " ) will be added automatically. ' ) ,
' \n ' . join ( [ ' %s ' % s for s in examples ] )
]
self . show_message ( ' \n \n ' . join ( info ) , _ ( ' Custom format strings ' ) )
2006-01-09 00:52:40 +01:00
def on_gPodderProperties_destroy ( self , widget , * args ) :
2007-03-17 13:31:37 +01:00
self . on_btnOK_clicked ( widget , * args )
2006-01-09 00:52:40 +01:00
2008-02-07 22:19:03 +01:00
def on_btnConfigEditor_clicked ( self , widget , * args ) :
self . on_btnOK_clicked ( widget , * args )
gPodderConfigEditor ( )
2008-01-21 09:57:03 +01:00
def on_comboAudioPlayerApp_changed ( self , widget , * args ) :
2006-03-30 00:07:27 +02:00
# find out which one
2008-01-21 09:57:03 +01:00
iter = self . comboAudioPlayerApp . get_active_iter ( )
model = self . comboAudioPlayerApp . get_model ( )
2006-03-30 00:07:27 +02:00
command = model . get_value ( iter , 1 )
if command == ' ' :
self . openApp . set_sensitive ( True )
self . openApp . show ( )
self . labelCustomCommand . show ( )
else :
self . openApp . set_text ( command )
self . openApp . set_sensitive ( False )
self . openApp . hide ( )
self . labelCustomCommand . hide ( )
2008-01-21 09:57:03 +01:00
def on_comboVideoPlayerApp_changed ( self , widget , * args ) :
# find out which one
iter = self . comboVideoPlayerApp . get_active_iter ( )
model = self . comboVideoPlayerApp . get_model ( )
command = model . get_value ( iter , 1 )
if command == ' ' :
self . openVideoApp . set_sensitive ( True )
self . openVideoApp . show ( )
2008-04-17 17:45:29 +02:00
self . label115 . show ( )
2008-01-21 09:57:03 +01:00
else :
self . openVideoApp . set_text ( command )
self . openVideoApp . set_sensitive ( False )
self . openVideoApp . hide ( )
2008-04-17 17:45:29 +02:00
self . label115 . hide ( )
2007-05-05 10:10:10 +02:00
def on_cbEnvironmentVariables_toggled ( self , widget , * args ) :
sens = not self . cbEnvironmentVariables . get_active ( )
self . httpProxy . set_sensitive ( sens )
self . ftpProxy . set_sensitive ( sens )
2006-12-06 21:25:26 +01:00
def on_comboboxDeviceType_changed ( self , widget , * args ) :
active_item = self . comboboxDeviceType . get_active ( )
2007-11-08 12:12:06 +01:00
# None
sync_widgets = ( self . only_sync_not_played , self . labelSyncOptions ,
2007-12-03 21:26:18 +01:00
self . imageSyncOptions , self . separatorSyncOptions ,
2007-12-18 10:18:33 +01:00
self . on_sync_mark_played , self . on_sync_delete ,
2008-06-13 09:41:36 +02:00
self . on_sync_leave , self . label_after_sync , self . delete_episodes_marked_played )
2007-11-08 12:12:06 +01:00
for widget in sync_widgets :
if active_item == 0 :
widget . hide_all ( )
else :
widget . show_all ( )
2006-12-06 21:25:26 +01:00
# iPod
2008-03-11 18:55:53 +01:00
ipod_widgets = ( self . ipodLabel , self . btn_iPodMountpoint ,
self . ipod_write_gtkpod_extended )
2007-11-08 12:12:06 +01:00
for widget in ipod_widgets :
if active_item == 1 :
widget . show_all ( )
else :
widget . hide_all ( )
2006-12-06 21:25:26 +01:00
# filesystem-based MP3 player
2007-11-08 12:12:06 +01:00
fs_widgets = ( self . filesystemLabel , self . btn_filesystemMountpoint ,
self . cbChannelSubfolder , self . cbCustomSyncName ,
self . entryCustomSyncName , self . btnCustomSyncNameHelp )
for widget in fs_widgets :
if active_item == 2 :
widget . show_all ( )
else :
widget . hide_all ( )
2006-12-06 21:25:26 +01:00
def on_btn_iPodMountpoint_clicked ( self , widget , * args ) :
fs = gtk . FileChooserDialog ( title = _ ( ' Select iPod mountpoint ' ) , 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 )
2007-12-09 13:22:50 +01:00
fs . set_current_folder ( self . iPodMountpoint . get_label ( ) )
2006-12-06 21:25:26 +01:00
if fs . run ( ) == gtk . RESPONSE_OK :
self . iPodMountpoint . set_label ( fs . get_filename ( ) )
fs . destroy ( )
def on_btn_FilesystemMountpoint_clicked ( self , widget , * args ) :
fs = gtk . FileChooserDialog ( title = _ ( ' Select folder for MP3 player ' ) , 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 )
2007-12-09 13:22:50 +01:00
fs . set_current_folder ( self . filesystemMountpoint . get_label ( ) )
2006-12-06 21:25:26 +01:00
if fs . run ( ) == gtk . RESPONSE_OK :
self . filesystemMountpoint . set_label ( fs . get_filename ( ) )
fs . destroy ( )
2006-01-09 00:52:40 +01:00
def on_btnOK_clicked ( self , widget , * args ) :
2007-11-02 17:37:14 +01:00
gl . config . ipod_mount = self . iPodMountpoint . get_label ( )
gl . config . mp3_player_folder = self . filesystemMountpoint . get_label ( )
2006-12-20 17:38:36 +01:00
if gl . downloaddir != self . chooserDownloadTo . get_filename ( ) :
new_download_dir = self . chooserDownloadTo . get_filename ( )
2007-08-07 20:11:31 +02:00
download_dir_size = util . calculate_size ( gl . downloaddir )
2007-11-03 14:18:59 +01:00
download_dir_size_string = gl . format_filesize ( download_dir_size )
2006-12-20 17:38:36 +01:00
event = Event ( )
dlg = gtk . Dialog ( _ ( ' Moving downloads folder ' ) , self . gPodderProperties )
dlg . vbox . set_spacing ( 5 )
dlg . set_border_width ( 5 )
label = gtk . Label ( )
label . set_line_wrap ( True )
2007-10-31 15:25:16 +01:00
label . set_markup ( _ ( ' Moving downloads from <b> %s </b> to <b> %s </b>... ' ) % ( saxutils . escape ( gl . downloaddir ) , saxutils . escape ( new_download_dir ) , ) )
2006-12-20 17:38:36 +01:00
myprogressbar = gtk . ProgressBar ( )
# put it all together
dlg . vbox . pack_start ( label )
dlg . vbox . pack_end ( myprogressbar )
# switch windows
dlg . show_all ( )
self . gPodderProperties . hide_all ( )
# hide action area and separator line
dlg . action_area . hide ( )
dlg . set_has_separator ( False )
args = ( new_download_dir , event , )
thread = Thread ( target = self . set_download_dir , args = args )
thread . start ( )
while not event . isSet ( ) :
2008-03-03 23:09:34 +01:00
try :
new_download_dir_size = util . calculate_size ( new_download_dir )
except :
new_download_dir_size = 0
2007-09-25 22:06:48 +02:00
if download_dir_size > 0 :
fract = ( 1.00 * new_download_dir_size ) / ( 1.00 * download_dir_size )
else :
fract = 0.0
2006-12-20 17:38:36 +01:00
if fract < 0.99 :
2007-11-03 14:18:59 +01:00
myprogressbar . set_text ( _ ( ' %s of %s ' ) % ( gl . format_filesize ( new_download_dir_size ) , download_dir_size_string , ) )
2006-12-20 17:38:36 +01:00
else :
myprogressbar . set_text ( _ ( ' Finishing... please wait. ' ) )
2008-03-03 21:15:36 +01:00
myprogressbar . set_fraction ( max ( 0.0 , min ( 1.0 , fract ) ) )
2006-12-20 17:38:36 +01:00
event . wait ( 0.1 )
while gtk . events_pending ( ) :
gtk . main_iteration ( False )
dlg . destroy ( )
2006-12-06 21:25:26 +01:00
device_type = self . comboboxDeviceType . get_active ( )
if device_type == 0 :
2007-11-02 17:37:14 +01:00
gl . config . device_type = ' none '
2006-12-06 21:25:26 +01:00
elif device_type == 1 :
2007-11-02 17:37:14 +01:00
gl . config . device_type = ' ipod '
2006-12-06 21:25:26 +01:00
elif device_type == 2 :
2007-11-02 17:37:14 +01:00
gl . config . device_type = ' filesystem '
2006-01-09 00:52:40 +01:00
self . gPodderProperties . destroy ( )
2007-01-28 10:21:39 +01:00
if self . callback_finished :
self . callback_finished ( )
2007-08-28 00:18:01 +02:00
class gPodderEpisode ( GladeWidget ) :
2008-04-24 18:28:39 +02:00
finger_friendly_widgets = [ ' episode_description ' , ' btnCloseWindow ' , ' btnDownload ' ,
' btnCancel ' , ' btnSaveFile ' , ' btnPlay ' , ' btn_website ' ]
2006-03-31 18:20:18 +02:00
def new ( self ) :
2008-04-06 02:19:03 +02:00
global WEB_BROWSER_ICON
self . image3166 . set_property ( ' icon-name ' , WEB_BROWSER_ICON )
2007-08-28 00:18:01 +02:00
services . download_status_manager . register ( ' list-changed ' , self . on_download_status_changed )
services . download_status_manager . register ( ' progress-detail ' , self . on_download_status_progress )
self . episode_title . set_markup ( ' <span weight= " bold " size= " larger " > %s </span> ' % saxutils . escape ( self . episode . title ) )
2008-04-06 02:19:03 +02:00
if gpodder . interface == gpodder . MAEMO :
# Hide the advanced prefs expander
self . expander1 . hide_all ( )
2007-08-28 00:18:01 +02:00
b = gtk . TextBuffer ( )
b . set_text ( strip ( self . episode . description ) )
self . episode_description . set_buffer ( b )
self . gPodderEpisode . set_title ( self . episode . title )
self . LabelDownloadLink . set_text ( self . episode . url )
self . LabelWebsiteLink . set_text ( self . episode . link )
2007-10-31 15:25:16 +01:00
self . labelPubDate . set_text ( self . episode . pubDate )
2007-08-28 00:18:01 +02:00
2008-03-03 20:54:42 +01:00
# Hide the "Go to website" button if we don't have a valid URL
if self . episode . link == self . episode . url or not self . episode . link :
self . btn_website . hide_all ( )
2007-10-31 15:25:16 +01:00
self . channel_title . set_markup ( _ ( ' <i>from %s </i> ' ) % saxutils . escape ( self . channel . title ) )
2007-08-28 00:18:01 +02:00
self . hide_show_widgets ( )
services . download_status_manager . request_progress_detail ( self . episode . url )
2006-03-04 21:45:01 +01:00
2007-08-27 22:28:00 +02:00
def on_btnCancel_clicked ( self , widget ) :
services . download_status_manager . cancel_by_url ( self . episode . url )
def on_gPodderEpisode_destroy ( self , widget ) :
services . download_status_manager . unregister ( ' list-changed ' , self . on_download_status_changed )
services . download_status_manager . unregister ( ' progress-detail ' , self . on_download_status_progress )
def on_download_status_changed ( self ) :
self . hide_show_widgets ( )
2008-03-03 20:54:42 +01:00
def on_btn_website_clicked ( self , widget ) :
util . open_website ( self . episode . link )
2007-08-27 22:28:00 +02:00
def on_download_status_progress ( self , url , progress , speed ) :
if url == self . episode . url :
2008-01-09 23:46:17 +01:00
progress = float ( min ( 100.0 , max ( 0.0 , progress ) ) )
self . progress_bar . set_fraction ( progress / 100.0 )
2007-08-27 22:28:00 +02:00
self . progress_bar . set_text ( ' Downloading: %d %% ( %s ) ' % ( progress , speed , ) )
def hide_show_widgets ( self ) :
is_downloading = services . download_status_manager . is_download_in_progress ( self . episode . url )
if is_downloading :
self . progress_bar . show_all ( )
self . btnCancel . show_all ( )
self . btnPlay . hide_all ( )
2007-08-28 00:18:01 +02:00
self . btnSaveFile . hide_all ( )
2007-08-27 22:28:00 +02:00
self . btnDownload . hide_all ( )
else :
self . progress_bar . hide_all ( )
self . btnCancel . hide_all ( )
if os . path . exists ( self . episode . local_filename ( ) ) :
self . btnPlay . show_all ( )
2007-08-28 00:18:01 +02:00
self . btnSaveFile . show_all ( )
self . btnDownload . hide_all ( )
2007-08-27 22:28:00 +02:00
else :
2007-08-28 00:18:01 +02:00
self . btnPlay . hide_all ( )
self . btnSaveFile . hide_all ( )
2007-08-27 22:28:00 +02:00
self . btnDownload . show_all ( )
2006-03-04 21:45:01 +01:00
def on_btnCloseWindow_clicked ( self , widget , * args ) :
self . gPodderEpisode . destroy ( )
2006-07-14 22:30:30 +02:00
def on_btnDownload_clicked ( self , widget , * args ) :
2006-12-09 02:59:53 +01:00
if self . download_callback :
2006-07-14 22:30:30 +02:00
self . download_callback ( )
2006-12-09 02:59:53 +01:00
def on_btnPlay_clicked ( self , widget , * args ) :
if self . play_callback :
self . play_callback ( )
self . gPodderEpisode . destroy ( )
2007-04-23 17:18:31 +02:00
def on_btnSaveFile_clicked ( self , widget , * args ) :
2007-10-28 15:30:11 +01:00
self . show_copy_dialog ( src_filename = self . episode . local_filename ( ) , dst_filename = self . episode . sync_filename ( ) )
2007-04-23 17:18:31 +02:00
2006-03-04 21:45:01 +01:00
2007-08-28 00:18:01 +02:00
class gPodderSync ( GladeWidget ) :
def new ( self ) :
2008-01-28 12:38:53 +01:00
util . idle_add ( self . imageSync . set_from_icon_name , ' gnome-dev-ipod ' , gtk . ICON_SIZE_DIALOG )
2006-04-07 03:43:06 +02:00
2008-01-28 12:38:53 +01:00
self . device . register ( ' progress ' , self . on_progress )
self . device . register ( ' sub-progress ' , self . on_sub_progress )
self . device . register ( ' status ' , self . on_status )
self . device . register ( ' done ' , self . on_done )
def on_progress ( self , pos , max ) :
util . idle_add ( self . progressbar . set_fraction , float ( pos ) / float ( max ) )
util . idle_add ( self . progressbar . set_text , _ ( ' %d of %d done ' ) % ( pos , max ) )
2006-04-07 03:43:06 +02:00
2008-01-28 12:38:53 +01:00
def on_sub_progress ( self , percentage ) :
util . idle_add ( self . progressbar . set_text , _ ( ' Processing ( %d %% ) ' ) % ( percentage ) )
2007-03-22 17:35:51 +01:00
2008-01-28 12:38:53 +01:00
def on_status ( self , status ) :
util . idle_add ( self . status_label . set_markup , ' <i> %s </i> ' % saxutils . escape ( status ) )
2007-03-22 17:35:51 +01:00
2008-01-28 12:38:53 +01:00
def on_done ( self ) :
util . idle_add ( self . gPodderSync . destroy )
2008-02-20 13:46:51 +01:00
if not self . gPodder . minimized :
util . idle_add ( self . notification , _ ( ' Your device has been updated by gPodder. ' ) , _ ( ' Operation finished ' ) )
2006-04-07 03:43:06 +02:00
def on_gPodderSync_destroy ( self , widget , * args ) :
2008-01-28 12:38:53 +01:00
self . device . unregister ( ' progress ' , self . on_progress )
self . device . unregister ( ' sub-progress ' , self . on_sub_progress )
self . device . unregister ( ' status ' , self . on_status )
self . device . unregister ( ' done ' , self . on_done )
self . device . cancel ( )
2006-04-07 03:43:06 +02:00
2007-03-22 17:35:51 +01:00
def on_cancel_button_clicked ( self , widget , * args ) :
2008-01-28 12:38:53 +01:00
self . device . cancel ( )
2007-03-22 17:35:51 +01:00
2006-04-07 03:43:06 +02:00
2007-08-28 00:18:01 +02:00
class gPodderOpmlLister ( GladeWidget ) :
2008-04-24 18:28:39 +02:00
finger_friendly_widgets = [ ' btnDownloadOpml ' , ' btnCancel ' , ' btnOK ' , ' treeviewChannelChooser ' ]
2006-06-13 23:00:31 +02:00
def new ( self ) :
# initiate channels list
self . channels = [ ]
self . callback_for_channel = None
2007-07-11 20:12:02 +02:00
self . callback_finished = None
2006-06-13 23:00:31 +02:00
2008-05-02 17:36:43 +02:00
if hasattr ( self , ' custom_title ' ) :
self . gPodderOpmlLister . set_title ( self . custom_title )
if hasattr ( self , ' hide_url_entry ' ) :
self . hbox25 . hide_all ( )
2006-06-13 23:00:31 +02:00
togglecell = gtk . CellRendererToggle ( )
togglecell . set_property ( ' activatable ' , True )
togglecell . connect ( ' toggled ' , self . callback_edited )
2007-07-11 20:12:02 +02:00
togglecolumn = gtk . TreeViewColumn ( ' ' , togglecell , active = 0 )
2006-06-13 23:00:31 +02:00
titlecell = gtk . CellRendererText ( )
2008-05-02 17:45:45 +02:00
titlecell . set_property ( ' ellipsize ' , pango . ELLIPSIZE_END )
2008-05-02 17:36:43 +02:00
titlecolumn = gtk . TreeViewColumn ( _ ( ' Podcast ' ) , titlecell , markup = 1 )
2006-06-13 23:00:31 +02:00
for itemcolumn in ( togglecolumn , titlecolumn ) :
self . treeviewChannelChooser . append_column ( itemcolumn )
def callback_edited ( self , cell , path ) :
model = self . treeviewChannelChooser . get_model ( )
2007-07-11 20:12:02 +02:00
url = model [ path ] [ 2 ]
2006-06-13 23:00:31 +02:00
2007-07-11 20:12:02 +02:00
model [ path ] [ 0 ] = not model [ path ] [ 0 ]
if model [ path ] [ 0 ] :
2006-06-13 23:00:31 +02:00
self . channels . append ( url )
else :
self . channels . remove ( url )
2007-07-11 20:12:02 +02:00
self . btnOK . set_sensitive ( bool ( len ( self . channels ) ) )
2008-01-15 14:54:22 +01:00
def thread_finished ( self , model ) :
self . treeviewChannelChooser . set_model ( model )
self . labelStatus . set_label ( ' ' )
self . btnDownloadOpml . set_sensitive ( True )
self . entryURL . set_sensitive ( True )
self . treeviewChannelChooser . set_sensitive ( True )
self . channels = [ ]
def thread_func ( self ) :
2007-08-19 16:28:24 +02:00
url = self . entryURL . get_text ( )
2008-01-15 14:54:22 +01:00
importer = opml . Importer ( url )
2007-08-19 16:28:24 +02:00
model = importer . get_model ( )
2008-02-07 20:23:12 +01:00
if len ( model ) == 0 :
self . notification ( _ ( ' The specified URL does not provide any valid OPML podcast items. ' ) , _ ( ' No feeds found ' ) )
2008-01-15 14:54:22 +01:00
util . idle_add ( self . thread_finished , model )
2007-07-11 20:12:02 +02:00
def get_channels_from_url ( self , url , callback_for_channel = None , callback_finished = None ) :
if callback_for_channel :
self . callback_for_channel = callback_for_channel
if callback_finished :
self . callback_finished = callback_finished
self . labelStatus . set_label ( _ ( ' Downloading, please wait... ' ) )
self . entryURL . set_text ( url )
self . btnDownloadOpml . set_sensitive ( False )
self . entryURL . set_sensitive ( False )
self . btnOK . set_sensitive ( False )
self . treeviewChannelChooser . set_sensitive ( False )
Thread ( target = self . thread_func ) . start ( )
2006-06-13 23:00:31 +02:00
def on_gPodderOpmlLister_destroy ( self , widget , * args ) :
2006-11-17 15:26:10 +01:00
pass
2006-06-13 23:00:31 +02:00
2007-07-11 20:12:02 +02:00
def on_btnDownloadOpml_clicked ( self , widget , * args ) :
self . get_channels_from_url ( self . entryURL . get_text ( ) )
2006-06-13 23:00:31 +02:00
def on_btnOK_clicked ( self , widget , * args ) :
self . gPodderOpmlLister . destroy ( )
2007-07-11 20:12:02 +02:00
2006-06-13 23:00:31 +02:00
# add channels that have been selected
for url in self . channels :
2007-07-11 20:12:02 +02:00
if self . callback_for_channel :
self . callback_for_channel ( url )
if self . callback_finished :
self . callback_finished ( )
2006-06-13 23:00:31 +02:00
def on_btnCancel_clicked ( self , widget , * args ) :
self . gPodderOpmlLister . destroy ( )
2005-11-21 19:21:25 +01:00
2007-11-08 20:11:57 +01:00
class gPodderEpisodeSelector ( GladeWidget ) :
""" 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 )
- 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 , caption ) pairs for the columns , the name
is the attribute name of the episode to be read from
each episode object and the caption attribute is the
text that appear as column caption
( default is [ ( ' title ' , ' 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 ' )
"""
2008-04-24 18:28:39 +02:00
finger_friendly_widgets = [ ' btnCancel ' , ' btnOK ' , ' btnCheckAll ' , ' btnCheckNone ' , ' treeviewEpisodes ' ]
2007-11-08 20:11:57 +01:00
COLUMN_TOGGLE = 0
COLUMN_ADDITIONAL = 1
def new ( self ) :
if not hasattr ( self , ' callback ' ) :
self . callback = None
if not hasattr ( self , ' episodes ' ) :
self . episodes = [ ]
if not hasattr ( self , ' size_attribute ' ) :
self . size_attribute = ' length '
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 ' , _ ( ' Episode ' ) ) , )
if hasattr ( self , ' title ' ) :
self . gPodderEpisodeSelector . set_title ( self . title )
self . labelHeading . set_markup ( ' <b><big> %s </big></b> ' % saxutils . escape ( self . title ) )
2008-04-24 18:28:39 +02:00
if gpodder . interface == gpodder . MAEMO :
self . labelHeading . hide ( )
2007-11-08 20:11:57 +01:00
if hasattr ( self , ' instructions ' ) :
self . labelInstructions . set_text ( self . instructions )
self . labelInstructions . show_all ( )
if hasattr ( self , ' stock_ok_button ' ) :
self . btnOK . set_label ( self . stock_ok_button )
self . btnOK . set_use_stock ( True )
toggle_cell = gtk . CellRendererToggle ( )
toggle_cell . connect ( ' toggled ' , self . toggle_cell_handler )
self . treeviewEpisodes . append_column ( gtk . TreeViewColumn ( ' ' , toggle_cell , active = self . COLUMN_TOGGLE ) )
next_column = self . COLUMN_ADDITIONAL
for name , caption in self . columns :
renderer = gtk . CellRendererText ( )
2008-04-19 19:01:09 +02:00
renderer . set_property ( ' ellipsize ' , pango . ELLIPSIZE_END )
2007-11-08 20:11:57 +01:00
column = gtk . TreeViewColumn ( caption , renderer , text = next_column )
column . set_resizable ( True )
2008-04-19 19:01:09 +02:00
# Only set "expand" on the first column (so more text is displayed there)
column . set_expand ( next_column == self . COLUMN_ADDITIONAL )
2007-11-08 20:11:57 +01:00
self . treeviewEpisodes . append_column ( column )
next_column + = 1
column_types = [ gobject . TYPE_BOOLEAN ] + [ gobject . TYPE_STRING ] * len ( self . columns )
self . model = gtk . ListStore ( * column_types )
for index , episode in enumerate ( self . episodes ) :
row = [ self . selected [ index ] ]
for name , caption in self . columns :
2008-04-13 08:04:51 +02:00
if not hasattr ( episode , name ) :
log ( ' Warning: Missing attribute " %s " ' , name , sender = self )
row . append ( None )
else :
row . append ( getattr ( episode , name ) )
2007-11-08 20:11:57 +01:00
self . model . append ( row )
for label in self . selection_buttons :
button = gtk . Button ( label )
2008-03-04 12:17:29 +01:00
button . connect ( ' clicked ' , self . custom_selection_button_clicked , label )
2007-11-08 20:11:57 +01:00
self . hboxButtons . pack_start ( button , expand = False )
button . show_all ( )
self . treeviewEpisodes . set_rules_hint ( True )
self . treeviewEpisodes . set_model ( self . model )
self . treeviewEpisodes . columns_autosize ( )
self . calculate_total_size ( )
def calculate_total_size ( self ) :
if self . size_attribute is not None :
total_size = 0
for index , row in enumerate ( self . model ) :
if self . model . get_value ( row . iter , self . COLUMN_TOGGLE ) == True :
try :
total_size + = int ( getattr ( self . episodes [ index ] , self . size_attribute ) )
except :
log ( ' Cannot get size for %s ' , self . episodes [ index ] . title , sender = self )
if total_size > 0 :
2007-11-09 10:09:05 +01:00
self . labelTotalSize . set_text ( _ ( ' Total size: %s ' ) % gl . format_filesize ( total_size ) )
2007-11-08 20:11:57 +01:00
else :
self . labelTotalSize . set_text ( ' ' )
self . labelTotalSize . show_all ( )
else :
self . labelTotalSize . hide_all ( )
def toggle_cell_handler ( self , cell , path ) :
model = self . treeviewEpisodes . get_model ( )
model [ path ] [ self . COLUMN_TOGGLE ] = not model [ path ] [ self . COLUMN_TOGGLE ]
if self . size_attribute is not None :
self . calculate_total_size ( )
2008-03-04 12:17:29 +01:00
def custom_selection_button_clicked ( self , button , label ) :
2007-11-08 20:11:57 +01:00
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_btnCheckAll_clicked ( self , widget ) :
for row in self . model :
self . model . set_value ( row . iter , self . COLUMN_TOGGLE , True )
self . calculate_total_size ( )
def on_btnCheckNone_clicked ( self , widget ) :
for row in self . model :
self . model . set_value ( row . iter , self . COLUMN_TOGGLE , False )
self . calculate_total_size ( )
def get_selected_episodes ( self ) :
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 [ index ] )
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 ( )
2007-12-10 09:41:17 +01:00
if self . callback is not None :
self . callback ( [ ] )
2008-02-07 22:19:03 +01:00
class gPodderConfigEditor ( GladeWidget ) :
2008-04-24 18:28:39 +02:00
finger_friendly_widgets = [ ' btnShowAll ' , ' btnClose ' , ' configeditor ' ]
2008-02-07 22:19:03 +01:00
def new ( self ) :
name_column = gtk . TreeViewColumn ( _ ( ' Variable ' ) )
name_renderer = gtk . CellRendererText ( )
name_column . pack_start ( name_renderer )
name_column . add_attribute ( name_renderer , ' text ' , 0 )
name_column . add_attribute ( name_renderer , ' weight ' , 5 )
self . configeditor . append_column ( name_column )
type_column = gtk . TreeViewColumn ( _ ( ' Type ' ) )
type_renderer = gtk . CellRendererText ( )
type_column . pack_start ( type_renderer )
type_column . add_attribute ( type_renderer , ' text ' , 1 )
type_column . add_attribute ( type_renderer , ' weight ' , 5 )
self . configeditor . append_column ( type_column )
value_column = gtk . TreeViewColumn ( _ ( ' Value ' ) )
value_renderer = gtk . CellRendererText ( )
value_column . pack_start ( value_renderer )
value_column . add_attribute ( value_renderer , ' text ' , 2 )
value_column . add_attribute ( value_renderer , ' editable ' , 4 )
value_column . add_attribute ( value_renderer , ' weight ' , 5 )
value_renderer . connect ( ' edited ' , self . value_edited )
self . configeditor . append_column ( value_column )
self . model = gl . config . model ( )
self . filter = self . model . filter_new ( )
self . filter . set_visible_func ( self . visible_func )
self . configeditor . set_model ( self . filter )
self . configeditor . set_rules_hint ( True )
def visible_func ( self , model , iter , user_data = None ) :
text = self . entryFilter . get_text ( ) . lower ( )
if text == ' ' :
return True
else :
# either the variable name or its value
return ( text in model . get_value ( iter , 0 ) . lower ( ) or
text in model . get_value ( iter , 2 ) . lower ( ) )
def value_edited ( self , renderer , path , new_text ) :
model = self . configeditor . get_model ( )
iter = model . get_iter ( path )
name = model . get_value ( iter , 0 )
type_cute = model . get_value ( iter , 1 )
if not gl . config . update_field ( name , new_text ) :
self . notification ( _ ( ' Cannot set value of <b> %s </b> to <i> %s </i>. \n \n Needed data type: %s ' ) % ( saxutils . escape ( name ) , saxutils . escape ( new_text ) , saxutils . escape ( type_cute ) ) , _ ( ' Error updating %s ' ) % saxutils . escape ( name ) )
def on_entryFilter_changed ( self , widget ) :
self . filter . refilter ( )
def on_btnShowAll_clicked ( self , widget ) :
self . entryFilter . set_text ( ' ' )
self . entryFilter . grab_focus ( )
def on_configeditor_row_activated ( self , treeview , path , view_column ) :
model = treeview . get_model ( )
it = model . get_iter ( path )
field_name = model . get_value ( it , 0 )
field_type = model . get_value ( it , 3 )
# Flip the boolean config flag
if field_type == bool :
gl . config . toggle_flag ( field_name )
def on_btnClose_clicked ( self , widget ) :
self . gPodderConfigEditor . destroy ( )
2007-11-08 20:11:57 +01:00
2007-08-28 00:18:01 +02:00
def main ( ) :
2006-04-03 22:59:10 +02:00
gobject . threads_init ( )
2007-03-25 21:55:28 +02:00
gtk . window_set_default_icon_name ( ' gpodder ' )
2005-11-21 19:21:25 +01:00
2007-08-28 00:18:01 +02:00
gPodder ( ) . run ( )
2005-11-21 19:21:25 +01:00
2008-02-20 13:46:51 +01:00