Sun, 06 Apr 2008 02:05:34 +0200 <thp@perli.net>

Initial upstream support for the Maemo platform (Nokia Internet Tablets)

	* bin/gpodder: Add "--maemo/-m" option to enable running as a Maemo
	application (this is only useful on Nokia Internet Tablets or in the
	Maemo SDK environment); determine interface type and set the correct
	variables on startup (gpodder.interface)
	* data/gpodder.glade: Increase the default size of some widgets to
	better fit the screens on Maemo (it won't do any harm on the "big"
	Desktop screen
	* data/icons/26/gpodder.png: Added
	* data/icons/40/gpodder.png: Added
	* data/maemo/gpodder.desktop: Added
	* Makefile: Help2man variable; new "make mtest" target that runs
	gPodder in Maemo scratchbox (probably useless for all other things);
	update the command descriptions; don't run the "generators" target
	from the "install" target; don't run "gen_graphics" from the
	"generators" target, but make it depend on the 24-pixel logo, which
	itself depends on the 22-pixel logo; this way, all should work out
	well when trying to install on systems without ImageMagick installed;
	remove *.pyo files on "make clean"
	* setup.py: Support for build targets; use "TARGET=maemo" to enable
	Maemo-specific installation options and files
	* src/gpodder/config.py: Increase the WRITE_TO_DISK_TIMEOUT to 60
	seconds, so we don't unnecessarily stress memory cards (on ITs);
	modify default path variables on Maemo (/media/mmc2)
	* src/gpodder/gui.py: Maemo-specific changes; clean-up the main window
	a bit and make message and confirmation dialogs Hildon-compatible
	* src/gpodder/__init__.py: Add enums for interface types: CLI, GUI and
	MAEMO; remove the "interface_is_gui" variable and replace with
	"interface", which is now used to determine where we are running
	* src/gpodder/libgpodder.py: Use /media/mmc2/gpodder/ as configuration
	folder on Maemo; use Nokia's Media player to playback files on Maemo
	* src/gpodder/libpodcasts.py: Icon name changes (Maemo-specific)
	* src/gpodder/trayicon.py: Maemo support; swap popup menu on Maemo;
	Add support for hildon banners instead of pynotify on Maemo
	* src/gpodder/util.py: Icon name changes (Maemo-specific); use new
	gpodder.interface variable in idle_add



git-svn-id: svn://svn.berlios.de/gpodder/trunk@654 b0d088ad-0a06-0410-aad2-9ed5178a7e87
This commit is contained in:
Thomas Perl 2008-04-06 00:19:03 +00:00
parent 213ab6f932
commit afe3df8384
15 changed files with 480 additions and 104 deletions

View File

@ -1,3 +1,42 @@
Sun, 06 Apr 2008 02:05:34 +0200 <thp@perli.net>
Initial upstream support for the Maemo platform (Nokia Internet Tablets)
* bin/gpodder: Add "--maemo/-m" option to enable running as a Maemo
application (this is only useful on Nokia Internet Tablets or in the
Maemo SDK environment); determine interface type and set the correct
variables on startup (gpodder.interface)
* data/gpodder.glade: Increase the default size of some widgets to
better fit the screens on Maemo (it won't do any harm on the "big"
Desktop screen
* data/icons/26/gpodder.png: Added
* data/icons/40/gpodder.png: Added
* data/maemo/gpodder.desktop: Added
* Makefile: Help2man variable; new "make mtest" target that runs
gPodder in Maemo scratchbox (probably useless for all other things);
update the command descriptions; don't run the "generators" target
from the "install" target; don't run "gen_graphics" from the
"generators" target, but make it depend on the 24-pixel logo, which
itself depends on the 22-pixel logo; this way, all should work out
well when trying to install on systems without ImageMagick installed;
remove *.pyo files on "make clean"
* setup.py: Support for build targets; use "TARGET=maemo" to enable
Maemo-specific installation options and files
* src/gpodder/config.py: Increase the WRITE_TO_DISK_TIMEOUT to 60
seconds, so we don't unnecessarily stress memory cards (on ITs);
modify default path variables on Maemo (/media/mmc2)
* src/gpodder/gui.py: Maemo-specific changes; clean-up the main window
a bit and make message and confirmation dialogs Hildon-compatible
* src/gpodder/__init__.py: Add enums for interface types: CLI, GUI and
MAEMO; remove the "interface_is_gui" variable and replace with
"interface", which is now used to determine where we are running
* src/gpodder/libgpodder.py: Use /media/mmc2/gpodder/ as configuration
folder on Maemo; use Nokia's Media player to playback files on Maemo
* src/gpodder/libpodcasts.py: Icon name changes (Maemo-specific)
* src/gpodder/trayicon.py: Maemo support; swap popup menu on Maemo;
Add support for hildon banners instead of pynotify on Maemo
* src/gpodder/util.py: Icon name changes (Maemo-specific); use new
gpodder.interface variable in idle_add
Sat, 05 Apr 2008 21:06:14 +0200 <thp@perli.net>
Make i18n help text work in the console help (gpodder --help)

View File

@ -26,6 +26,7 @@ MESSAGESPOT=data/messages.pot
GUIFILE=src/gpodder/gui.py
LOGO_22=data/icons/22/gpodder.png
LOGO_24=data/icons/24/gpodder.png
HELP2MAN=help2man
MANPAGE=doc/man/gpodder.1
GPODDERVERSION=`cat $(BINFILE) |grep ^__version__.*=|cut -d\" -f2`
@ -50,16 +51,17 @@ all: help
help:
@echo 'make test run gpodder in local directory'
@echo 'make mtest run gpodder (for maemo scratchbox)'
@echo 'make cl make new changelog entry (1)'
@echo 'make ci format a commit message from the changelog'
@echo 'make release create source tarball in "dist/"'
@echo 'make releasetest run some tests before the release'
@echo 'make install install gpodder into "$(PREFIX)"'
@echo 'make uninstall uninstall gpodder from "$(PREFIX)"'
@echo 'make generators generate manpage, run tepache and resize logo'
@echo 'make generators generate manpage and icons (if needed)'
@echo 'make messages rebuild messages.pot from new source'
@echo 'make rosetta-upload generate a tarball of all translation files'
@echo 'make clean remove generated+temp+*.pyc files'
@echo 'make clean remove generated+temp+*.py{c,o} files'
@echo 'make distclean do a "make clean" + remove "dist/"'
@echo ''
@echo '(1) Please set environment variable "EMAIL" to your e-mail address'
@ -86,6 +88,10 @@ test:
@echo -ne '\033]0;gPodder console (make test)\007'
$(BINFILE) --local --verbose
mtest:
@# in maemo scratchbox, we need this for osso/hildon
run-standalone.sh $(BINFILE) --local --maemo --verbose
deb:
debuild
@ -96,7 +102,7 @@ releasetest:
if grep -q '^__version__.*=.*+svn' $(BINFILE); then echo "Version is still '+svn'."; exit 1; fi
desktop-file-validate data/gpodder.desktop
install: generators
install:
python setup.py install --root=$(DESTDIR) --prefix=$(PREFIX)
update-icons:
@ -112,19 +118,22 @@ uninstall:
##########################################################################
generators: $(MANPAGE) gen_graphics
generators: $(MANPAGE) $(LOGO_24)
make -C data/po update
messages: gen_gettext
$(MANPAGE): $(BINFILE)
help2man --name="A Media aggregator and Podcast catcher" -N $(BINFILE) >$(MANPAGE)
$(HELP2MAN) --name="A Media aggregator and Podcast catcher" -N $(BINFILE) >$(MANPAGE)
data/maemo/gpodder.desktop: data/gpodder.desktop
sed -e 's/^Exec=gpodder$$/Exec=gpodder --maemo/g' <data/gpodder.desktop >data/maemo/gpodder.desktop
gen_gettext: $(MESSAGESPOT)
make -C data/po generators
make -C data/po update
gen_graphics:
$(LOGO_24): $(LOGO_22)
convert -bordercolor Transparent -border 1x1 $(LOGO_22) $(LOGO_24)
$(GLADEGETTEXT): $(GLADEFILE)
@ -144,7 +153,7 @@ $(ROSETTA_ARCHIVE):
clean:
python setup.py clean
rm -f src/gpodder/*.pyc src/gpodder/*.bak MANIFEST PKG-INFO data/gpodder.gladep{,.bak} data/gpodder.glade.bak $(GLADEGETTEXT) data/messages.pot~ data/gpodder-??x??.png $(ROSETTA_ARCHIVE)
rm -f src/gpodder/*.pyc src/gpodder/*.pyo src/gpodder/*.bak MANIFEST PKG-INFO data/gpodder.gladep{,.bak} data/gpodder.glade.bak $(GLADEGETTEXT) data/messages.pot~ data/gpodder-??x??.png $(ROSETTA_ARCHIVE)
rm -rf build
make -C data/po clean

View File

@ -75,6 +75,10 @@ def main( argv = sys.argv):
action="store_true", dest="local", default=False,
help=_("Run local version in current directory"))
parser.add_option("-m", "--maemo",
action="store_true", dest="maemo", default=False,
help=_("Start the Maemo user interface of gPodder"))
parser.add_option("-l", "--list",
action="store_true", dest="list", default=False,
help=_("List all channel subscriptions"))
@ -105,6 +109,14 @@ def main( argv = sys.argv):
import gpodder
gpodder.user_agent = 'gPodder/%s (+http://gpodder.berlios.de/)' % __version__
if options.maemo:
gpodder.interface = gpodder.MAEMO
elif options.list or options.run or options.update or \
options.sync or options.add or options.delete:
gpodder.interface = gpodder.CLI
else:
gpodder.interface = gpodder.GUI
if options.verbose:
from gpodder.liblogger import enable_verbose
@ -125,7 +137,6 @@ def main( argv = sys.argv):
console.del_channel( options.delete)
else:
#default run gui
gpodder.interface_is_gui = True
from gpodder import gui
from gpodder.SimpleGladeApp import bindtextdomain
import gtk.glade

View File

@ -5452,7 +5452,7 @@ Filesystem-based MP3 player</property>
<property name="type">GTK_WINDOW_TOPLEVEL</property>
<property name="window_position">GTK_WIN_POS_CENTER_ON_PARENT</property>
<property name="modal">True</property>
<property name="default_width">400</property>
<property name="default_width">600</property>
<property name="resizable">True</property>
<property name="destroy_with_parent">False</property>
<property name="decorated">True</property>
@ -5560,7 +5560,7 @@ Filesystem-based MP3 player</property>
<property name="top_attach">0</property>
<property name="bottom_attach">2</property>
<property name="x_options">fill</property>
<property name="y_options"></property>
<property name="y_options">fill</property>
</packing>
</child>
</widget>
@ -6273,8 +6273,8 @@ Filesystem-based MP3 player</property>
<property name="type">GTK_WINDOW_TOPLEVEL</property>
<property name="window_position">GTK_WIN_POS_CENTER_ON_PARENT</property>
<property name="modal">False</property>
<property name="default_width">500</property>
<property name="default_height">300</property>
<property name="default_width">600</property>
<property name="default_height">400</property>
<property name="resizable">True</property>
<property name="destroy_with_parent">False</property>
<property name="decorated">True</property>
@ -6907,7 +6907,7 @@ Filesystem-based MP3 player</property>
<property name="type">GTK_WINDOW_TOPLEVEL</property>
<property name="window_position">GTK_WIN_POS_CENTER</property>
<property name="modal">False</property>
<property name="default_width">600</property>
<property name="default_width">800</property>
<property name="default_height">500</property>
<property name="resizable">True</property>
<property name="destroy_with_parent">False</property>

BIN
data/icons/26/gpodder.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

BIN
data/icons/40/gpodder.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

View File

@ -0,0 +1,27 @@
[Desktop Entry]
Name=gPodder Podcast Client
Name[de]=gPodder Podcast-Client
Name[es]=Cliente Podcast gPodder
Name[gl]=Cliente Podcast gPodder
Name[ru]=gPodder Подкаст-Клиент
Name[uk]=gPodder Подкаст-Клієнт
Name[cs]=gPodder podcast čtečka
GenericName=Media Aggregator
GenericName[de]=Medien-Aggregator
GenericName[es]=Agregador de medios
GenericName[gl]=Agregador de medios
GenericName[ru]=Загрузка, прослушивание подкастов
GenericName[uk]=Завантаження та прослуховування подкастів
GenericName[cs]=Agregátor zpráv
Comment=Download audio and video content from podcasts
Comment[de]=Laden Sie Audio- und Video-Inhalte von Podcasts herunter
Comment[es]=Descargue contenidos audio/vídeo desde podcasts.
Comment[gl]=Descargue contidos audio/vídeo desde podcasts.
Comment[ru]=Загрузка и воспроизведение аудио и видео подкастов, синхронизация с iPod
Comment[uk]=Завантаження та прослуховування аудіо та відео подкастів, синхронізація з iPod
Comment[cs]=Umožňuje stahování audio/video podcastu a synchornizaci s MP3 přehrávačem
Exec=gpodder --maemo
Icon=gpodder
Terminal=false
Type=Application
Categories=AudioVideo;Audio;FileTransfer;News;GTK;

View File

@ -22,6 +22,8 @@ import glob
import os
from distutils.core import setup
# build targets
(DEFAULT, MAEMO) = range(2)
# read the version from the gpodder main program
gpodder_version = os.popen( "cat bin/gpodder |grep ^__version__.*=|cut -d\\\" -f2").read().strip()
@ -30,6 +32,13 @@ gpodder_version = os.popen( "cat bin/gpodder |grep ^__version__.*=|cut -d\\\" -f
languages = [ "de", "fr", "sv", "it", "pt", "es", "nl", "ru", "uk", "gl", "cs" ]
translation_files = []
# build target
if 'TARGET' in os.environ:
if os.environ['TARGET'].strip().lower() == 'maemo':
target = MAEMO
else:
target = DEFAULT
# add translated files to translations dictionary
for l in languages:
translation_files.append( ("share/locale/%s/LC_MESSAGES" % l, [ "data/locale/%s/LC_MESSAGES/gpodder.mo" % l ]) )
@ -38,8 +47,11 @@ for l in languages:
inst_manpages = glob.glob( 'doc/man/*.1')
inst_share = [ 'data/gpodder.glade' ]
inst_desktop = [ 'data/gpodder.desktop' ]
inst_desktop_maemo = [ 'data/maemo/gpodder.desktop' ]
inst_icons = [ 'data/gpodder.png' ]
inst_icons_40 = [ 'data/icons/40/gpodder.png' ]
inst_icons_26 = [ 'data/icons/26/gpodder.png' ]
inst_icons_24 = [ 'data/icons/24/gpodder.png' ]
inst_icons_22 = [ 'data/icons/22/gpodder.png' ]
inst_icons_16 = [ 'data/icons/16/gpodder.png' ]
@ -48,16 +60,28 @@ inst_icons_svg = [ 'data/gpodder.svg' ]
data_files = [
('share/man/man1', inst_manpages),
('share/gpodder', inst_share),
('share/applications', inst_desktop),
('share/pixmaps', inst_icons),
('share/icons/hicolor/scalable/apps', inst_icons_svg),
('share/icons/hicolor/48x48/apps', inst_icons),
('share/icons/hicolor/24x24/apps', inst_icons_24),
('share/icons/hicolor/22x22/apps', inst_icons_22),
('share/icons/hicolor/16x16/apps', inst_icons_16),
]
# target-specific installation data files
if target == DEFAULT:
data_files += [
('share/applications', inst_desktop),
('share/icons/hicolor/scalable/apps', inst_icons_svg),
('share/icons/hicolor/48x48/apps', inst_icons),
('share/icons/hicolor/24x24/apps', inst_icons_24),
('share/icons/hicolor/22x22/apps', inst_icons_22),
('share/icons/hicolor/16x16/apps', inst_icons_16),
('share/pixmaps', inst_icons),
]
elif target == MAEMO:
data_files += [
('share/applications/hildon', inst_desktop_maemo),
('share/icons/hicolor/scalable/apps', inst_icons),
('share/icons/hicolor/40x40/apps', inst_icons_40),
('share/icons/hicolor/26x26/apps', inst_icons_26),
]
setup(
name = 'gpodder',
version = gpodder_version,

View File

@ -20,6 +20,9 @@
# The User-Agent string for downloads
user_agent = 'gPodder'
# Are we running in GUI or console mode?
interface_is_gui = False
# Interface type enums
(CLI, GUI, MAEMO) = range(3)
# Are we running in GUI, Maemo or console mode?
interface = CLI

View File

@ -27,6 +27,7 @@
import gtk
import pango
import gpodder
from gpodder import util
from gpodder.liblogger import log
@ -36,6 +37,13 @@ import time
import threading
import ConfigParser
if gpodder.interface == gpodder.GUI:
default_bittorrent_dir = os.path.expanduser('~/gpodder-downloads/torrents')
default_download_dir = os.path.expanduser('~/gpodder-downloads')
elif gpodder.interface == gpodder.MAEMO:
default_bittorrent_dir = '/media/mmc2/gpodder/torrents'
default_download_dir = '/media/mmc2/gpodder/downloads'
gPodderSettings = {
# General settings
'player': ( str, 'xdg-open' ),
@ -49,7 +57,7 @@ gPodderSettings = {
'max_downloads_enabled': ( bool, False ),
'limit_rate': ( bool, False ),
'limit_rate_value': ( float, 500.0 ),
'bittorrent_dir': ( str, os.path.expanduser( '~/gpodder-downloads/torrents') ),
'bittorrent_dir': (str, default_bittorrent_dir),
'episode_old_age': ( int, 7 ),
# Boolean config flags
@ -89,7 +97,7 @@ gPodderSettings = {
'ipod_mount': ( str, '/media/ipod' ),
'mp3_player_folder': ( str, '/media/usbdisk' ),
'device_type': ( str, 'none' ),
'download_dir': ( str, os.path.expanduser( '~/gpodder-downloads') ),
'download_dir': (str, default_download_dir),
# Special settings (not in preferences)
'default_new': ( int, 1 ),
@ -109,6 +117,9 @@ gPodderSettings = {
class Config(dict):
Settings = gPodderSettings
# Number of seconds after which settings are auto-saved
WRITE_TO_DISK_TIMEOUT = 60
def __init__( self, filename = 'gpodder.conf'):
dict.__init__( self)
@ -210,7 +221,7 @@ class Config(dict):
self.__save_thread.start()
def save_thread_proc( self):
for i in range( 100):
for i in range(self.WRITE_TO_DISK_TIMEOUT*10):
if self.__save_thread != None:
time.sleep( .1)
if self.__save_thread != None:

View File

@ -34,6 +34,7 @@ from threading import Event
from threading import Thread
from string import strip
import gpodder
from gpodder import util
from gpodder import opml
from gpodder import services
@ -61,6 +62,12 @@ from libplayers import UserAppsReader
from libtagupdate import tagging_supported
if gpodder.interface == gpodder.GUI:
WEB_BROWSER_ICON = 'web-browser'
elif gpodder.interface == gpodder.MAEMO:
import hildon
WEB_BROWSER_ICON = 'qgn_toolb_browser_web'
app_name = "gpodder"
app_version = "unknown" # will be set in main() call
app_authors = [
@ -114,15 +121,16 @@ class GladeWidget(SimpleGladeApp.SimpleGladeApp):
# If we have a child window, set it transient for our main window
getattr( self, root).set_transient_for( GladeWidget.gpodder_main_window)
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)
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)
def notification(self, message, title=None):
util.idle_add(self.show_message, message, title)
@ -133,31 +141,37 @@ class GladeWidget(SimpleGladeApp.SimpleGladeApp):
title = 'gPodder'
self.tray_icon.send_notification(message, title)
return
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 ))
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))
dlg.run()
dlg.destroy()
def show_confirmation( self, message, title = None):
dlg = gtk.MessageDialog( GladeWidget.gpodder_main_window, gtk.DIALOG_MODAL, gtk.MESSAGE_QUESTION, gtk.BUTTONS_YES_NO)
if title:
dlg.set_title( 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)
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))
response = dlg.run()
dlg.destroy()
return response == gtk.RESPONSE_YES
return response == affirmative
def show_copy_dialog( self, src_filename, dst_filename = None, dst_directory = None, title = _('Select destination')):
if dst_filename is None:
@ -198,9 +212,52 @@ class GladeWidget(SimpleGladeApp.SimpleGladeApp):
class gPodder(GladeWidget):
def new(self):
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.destroy()
self.gPodder = self.window
self.set_title(_('Podcasts'))
# Reparent the main menu
menu = gtk.Menu()
for child in self.mainMenu.get_children():
child.reparent(menu)
self.itemClose.reparent(menu)
self.trennlinie3.parent.remove(self.trennlinie3)
self.window.set_menu(menu)
self.mainMenu.destroy()
self.window.show_all()
# do some widget hiding
self.toolbar.remove(self.toolTransfer)
self.itemTransferSelected.hide_all()
self.separator11.hide_all()
self.label120.set_text(_('Update feeds'))
self.label120.set_padding(0, 10)
self.uar = None
self.tray_icon = None
self.fullscreen = False
self.minimized = False
self.gPodder.connect('window-state-event', self.window_state_event)
@ -224,10 +281,12 @@ class gPodder(GladeWidget):
while gtk.events_pending():
gtk.main_iteration( False)
if app_version.rfind( "svn") != -1:
self.gPodder.set_title( 'gPodder %s' % app_version)
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())
self.default_title = self.gPodder.get_title()
gtk.about_dialog_set_url_hook(lambda dlg, link, data: util.open_website(link), None)
# cell renderers for channel tree
@ -248,6 +307,7 @@ class gPodder(GladeWidget):
namecolumn.add_attribute( iconcell, 'pixbuf', 3)
self.treeChannels.append_column( namecolumn)
self.treeChannels.set_headers_visible(False)
# enable alternating colors hint
self.treeAvailable.set_rules_hint( True)
@ -262,11 +322,18 @@ class gPodder(GladeWidget):
self.last_tooltip_channel = None
# Add our context menu to treeAvailable
self.treeAvailable.connect('button-press-event', self.treeview_button_pressed)
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)
self.treeChannels.connect('button-press-event', self.treeview_channels_button_pressed)
iconcell = gtk.CellRendererPixbuf()
iconcolumn = gtk.TreeViewColumn( _("Status"), iconcell, pixbuf = 4)
if gpodder.interface == gpodder.MAEMO:
status_column_label = ''
else:
status_column_label = _('Status')
iconcolumn = gtk.TreeViewColumn(status_column_label, iconcell, pixbuf=4)
namecell = gtk.CellRendererText()
namecell.set_property('ellipsize', pango.ELLIPSIZE_END)
@ -284,6 +351,14 @@ class gPodder(GladeWidget):
itemcolumn.set_reorderable(True)
self.treeAvailable.append_column(itemcolumn)
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)
# enable search in treeavailable
self.treeAvailable.set_search_equal_func( self.treeAvailable_search_equal)
@ -293,13 +368,17 @@ class gPodder(GladeWidget):
# columns and renderers for "download progress" tab
episodecell = gtk.CellRendererText()
episodecell.set_property('ellipsize', pango.ELLIPSIZE_END)
episodecolumn = gtk.TreeViewColumn( _("Episode"), episodecell, text=0)
episodecolumn.set_sizing(gtk.TREE_VIEW_COLUMN_AUTOSIZE)
episodecolumn.set_expand(True)
speedcell = gtk.CellRendererText()
speedcolumn = gtk.TreeViewColumn( _("Speed"), speedcell, text=1)
progresscell = gtk.CellRendererProgress()
progresscolumn = gtk.TreeViewColumn( _("Progress"), progresscell, value=2)
progresscolumn.set_expand(True)
for itemcolumn in ( episodecolumn, speedcolumn, progresscolumn ):
self.treeDownloads.append_column( itemcolumn)
@ -381,6 +460,8 @@ class gPodder(GladeWidget):
self.show_message(_('Updated M3U playlist in download folder.'), _('Updated playlist'))
def treeview_channels_button_pressed( self, treeview, event):
global WEB_BROWSER_ICON
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
@ -425,7 +506,7 @@ class gPodder(GladeWidget):
if self.active_channel.link:
item = gtk.ImageMenuItem(_('Visit website'))
item.set_image(gtk.image_new_from_icon_name('web-browser', gtk.ICON_SIZE_MENU))
item.set_image(gtk.image_new_from_icon_name(WEB_BROWSER_ICON, gtk.ICON_SIZE_MENU))
item.connect('activate', lambda w: util.open_website(self.active_channel.link))
menu.append(item)
@ -496,7 +577,11 @@ class gPodder(GladeWidget):
Thread(target=convert_and_send_thread, args=[filename, destfile, device, dlg, self.notification]).start()
def treeview_button_pressed( self, treeview, event):
if event.button == 3:
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):
( x, y ) = ( int(event.x), int(event.y) )
( path, column, rx, ry ) = treeview.get_path_at_pos( x, y) or (None,)*4
@ -622,15 +707,27 @@ class gPodder(GladeWidget):
# If we have it, also add episode website link
if episode and episode.link and episode.link != episode.url:
item = gtk.ImageMenuItem(_('Visit website'))
item.set_image(gtk.image_new_from_icon_name('web-browser', gtk.ICON_SIZE_MENU))
item.set_image(gtk.image_new_from_icon_name(WEB_BROWSER_ICON, gtk.ICON_SIZE_MENU))
item.connect('activate', lambda w: util.open_website(episode.link))
menu.append(item)
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))
menu.append(item)
menu.show_all()
menu.popup( None, None, None, event.button, event.time)
return True
def set_title(self, new_title):
self.default_title = new_title
self.gPodder.set_title(new_title)
def download_progress_updated( self, count, percentage):
title = [ self.default_title ]
@ -973,6 +1070,12 @@ class gPodder(GladeWidget):
if not gl.config.on_quit_ask and gl.config.on_quit_systray and self.tray_icon and widget.name not in ('toolQuit', 'itemClose'):
self.iconify_main_window()
elif gl.config.on_quit_ask or downloading:
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
dialog = gtk.MessageDialog(self.gPodder, gtk.DIALOG_MODAL, gtk.MESSAGE_QUESTION, gtk.BUTTONS_NONE)
dialog.add_button(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL)
if self.tray_icon:
@ -1146,7 +1249,7 @@ class gPodder(GladeWidget):
callback=self.download_episode_list)
else:
title = _('No new episodes')
message = _('There are no new episodes to download from your podcast subscriptions. Please check for new episodes later.')
message = _('No new episodes to download.\nPlease check for new episodes later.')
self.show_message(message, title)
def on_itemDownloadAllNew_activate(self, widget, *args):
@ -1352,24 +1455,30 @@ class gPodder(GladeWidget):
def on_itemRemoveChannel_activate(self, widget, *args):
try:
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)
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)
title = _('Remove channel and episodes?')
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()
title = _('Remove channel and episodes?')
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
dialog = hildon.Note('confirmation', (self.gPodder, _('Do you really want to remove this channel and all downloaded episodes?')))
affirmative = gtk.RESPONSE_OK
result = dialog.run()
dialog.destroy()
if result == gtk.RESPONSE_YES:
if result == affirmative:
# delete downloaded episodes only if checkbox is unchecked
if cb_ask.get_active() == False:
self.active_channel.remove_downloaded()
@ -1429,21 +1538,27 @@ class gPodder(GladeWidget):
dlg = gtk.AboutDialog()
dlg.set_name(app_name.replace('p', 'P')) # gpodder->gPodder
dlg.set_version( app_version)
dlg.set_authors( app_authors)
dlg.set_copyright( app_copyright)
dlg.set_website( app_website)
dlg.set_translator_credits( _('translator-credits'))
dlg.connect( 'response', lambda dlg, response: dlg.destroy())
try:
dlg.set_logo( gtk.gdk.pixbuf_new_from_file_at_size( scalable_dir, 200, 200))
except:
pass
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
dlg.run()
def on_wNotebook_switch_page(self, widget, *args):
page_num = args[1]
if gpodder.interface == gpodder.MAEMO:
page = self.wNotebook.get_nth_page(page_num)
self.set_title(self.wNotebook.get_tab_label(page).get_text())
if page_num == 0:
self.play_or_download()
else:
@ -1464,6 +1579,9 @@ class gPodder(GladeWidget):
self.itemEditChannel.get_child().set_text( _('Edit "%s"') % ( self.active_channel.title,))
self.itemRemoveChannel.get_child().set_text( _('Remove "%s"') % ( self.active_channel.title,))
if gpodder.interface == gpodder.MAEMO:
self.label2.set_text(self.active_channel.title)
self.set_title(self.active_channel.title)
self.itemEditChannel.show_all()
self.itemRemoveChannel.show_all()
else:
@ -1649,8 +1767,42 @@ class gPodder(GladeWidget):
self.treeAvailable.get_selection().select_all()
self.on_btnDownloadedDelete_clicked( widget, args)
self.treeAvailable.get_selection().unselect_all()
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)
def window_state_event(self, widget, event):
if event.new_window_state & gtk.gdk.WINDOW_STATE_FULLSCREEN:
self.fullscreen = True
else:
self.fullscreen = False
old_minimized = self.minimized
if event.new_window_state & gtk.gdk.WINDOW_STATE_ICONIFIED:
@ -1676,6 +1828,8 @@ class gPodder(GladeWidget):
class gPodderChannel(GladeWidget):
def new(self):
global WEB_BROWSER_ICON
self.image3167.set_property('icon-name', WEB_BROWSER_ICON)
self.gPodderChannel.set_title( self.channel.title)
self.entryTitle.set_text( self.channel.title)
self.entryURL.set_text( self.channel.url)
@ -1782,6 +1936,18 @@ class gPodderProperties(GladeWidget):
if not hasattr( self, 'callback_finished'):
self.callback_finished = None
if gpodder.interface == gpodder.MAEMO:
self.table13.hide_all() # bluetooth
self.table5.hide_all() # player
self.table6.hide_all() # bittorrent
# start from web importer
self.hseparator3.hide_all()
self.label87.hide_all()
self.image2423.hide_all()
self.opmlURL.hide_all()
# end from web importer
self.gPodderProperties.fullscreen()
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)
@ -1861,7 +2027,9 @@ class gPodderProperties(GladeWidget):
if not hasattr(self, 'user_apps_reader'):
self.user_apps_reader = UserAppsReader(['audio', 'video'])
self.user_apps_reader.read()
if gpodder.interface == gpodder.GUI:
self.user_apps_reader.read()
self.comboAudioPlayerApp.set_model(self.user_apps_reader.get_applications_as_model('audio'))
index = self.find_active_audio_app()
self.comboAudioPlayerApp.set_active(index)
@ -2135,11 +2303,17 @@ class gPodderProperties(GladeWidget):
class gPodderEpisode(GladeWidget):
def new(self):
global WEB_BROWSER_ICON
self.image3166.set_property('icon-name', WEB_BROWSER_ICON)
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))
if gpodder.interface == gpodder.MAEMO:
# Hide the advanced prefs expander
self.expander1.hide_all()
b = gtk.TextBuffer()
b.set_text( strip( self.episode.description))
self.episode_description.set_buffer( b)

View File

@ -31,6 +31,7 @@ import urllib
import shutil
import xml.dom.minidom
import gpodder
from gpodder import util
from gpodder import opml
from gpodder import config
@ -45,10 +46,17 @@ from liblogger import log
import shlex
if gpodder.interface == gpodder.MAEMO:
import osso
class gPodderLib(object):
def __init__( self):
log('Creating gPodderLib()', sender=self)
gpodder_dir = os.path.expanduser( '~/.config/gpodder/')
if gpodder.interface == gpodder.MAEMO:
gpodder_dir = '/media/mmc2/gpodder/'
self.osso_c = osso.Context('gpodder_osso_sender', '1.0', False)
else:
gpodder_dir = os.path.expanduser('~/.config/gpodder/')
util.make_directory( gpodder_dir)
self.tempdir = gpodder_dir
@ -196,6 +204,15 @@ class gPodderLib(object):
self.history_mark_played( episode.url)
filename = episode.local_filename()
if gpodder.interface == gpodder.MAEMO:
# Use the built-in Nokia Mediaplayer here
filename = filename.encode('utf-8')
osso_rpc = osso.Rpc(self.osso_c)
service = 'com.nokia.mediaplayer'
path = '/com/nokia/mediaplayer'
osso_rpc.rpc_run(service, path, service, 'mime_open', ('file://'+filename,))
return (True, service)
# Determine the file type and set the player accordingly.
file_type = util.file_type_by_extension(util.file_extension_from_url(episode.url))

View File

@ -37,6 +37,7 @@ from gpodder import cache
from gpodder import services
from gpodder import draw
import gpodder
from gpodder.liblogger import log
from gpodder.libgpodder import gl
@ -76,6 +77,23 @@ from gpodder import dumbshelve
global_lock = threading.RLock()
if gpodder.interface == gpodder.GUI:
ICON_AUDIO_FILE = 'audio-x-generic'
ICON_VIDEO_FILE = 'video-x-generic'
ICON_BITTORRENT = 'applications-internet'
ICON_DOWNLOADING = gtk.STOCK_GO_DOWN
ICON_DELETED = gtk.STOCK_DELETE
ICON_NEW = gtk.STOCK_NEW
elif gpodder.interface == gpodder.MAEMO:
ICON_AUDIO_FILE = 'gnome-mime-audio-mp3'
ICON_VIDEO_FILE = 'gnome-mime-video-mp4'
ICON_BITTORRENT = 'qgn_toolb_browser_web'
ICON_DOWNLOADING = 'qgn_toolb_messagin_moveto'
ICON_DELETED = 'qgn_toolb_gene_deletebutton'
ICON_NEW = 'qgn_list_gene_favor'
class ChannelSettings(object):
storage = dumbshelve.open_shelve(gl.channel_settings_file)
@ -448,6 +466,9 @@ class podcastChannel(ListType):
return self.__tree_model
def iter_set_downloading_columns( self, model, iter, new_episodes = []):
global ICON_AUDIO_FILE, ICON_VIDEO_FILE, ICON_BITTORRENT
global ICON_DOWNLOADING, ICON_DELETED, ICON_NEW
url = model.get_value( iter, 0)
local_filename = model.get_value( iter, 8)
played = not gl.history_is_played(url)
@ -461,20 +482,20 @@ class podcastChannel(ListType):
if os.path.exists( local_filename):
file_type = util.file_type_by_extension( util.file_extension_from_url(url))
if file_type == 'audio':
status_icon = util.get_tree_icon('audio-x-generic', played, locked, self.icon_cache, icon_size)
status_icon = util.get_tree_icon(ICON_AUDIO_FILE, played, locked, self.icon_cache, icon_size)
elif file_type == 'video':
status_icon = util.get_tree_icon('video-x-generic', played, locked, self.icon_cache, icon_size)
status_icon = util.get_tree_icon(ICON_VIDEO_FILE, played, locked, self.icon_cache, icon_size)
elif file_type == 'torrent':
status_icon = util.get_tree_icon('applications-internet', played, locked, self.icon_cache, icon_size)
status_icon = util.get_tree_icon(ICON_BITTORRENT, played, locked, self.icon_cache, icon_size)
else:
status_icon = util.get_tree_icon('unknown', played, locked, self.icon_cache, icon_size)
elif services.download_status_manager.is_download_in_progress(url):
status_icon = util.get_tree_icon(gtk.STOCK_GO_DOWN, icon_cache=self.icon_cache, icon_size=icon_size)
status_icon = util.get_tree_icon(ICON_DOWNLOADING, icon_cache=self.icon_cache, icon_size=icon_size)
elif gl.history_is_downloaded(url):
status_icon = util.get_tree_icon(gtk.STOCK_DELETE, icon_cache=self.icon_cache, icon_size=icon_size)
status_icon = util.get_tree_icon(ICON_DELETED, icon_cache=self.icon_cache, icon_size=icon_size)
elif url in [e.url for e in new_episodes]:
status_icon = util.get_tree_icon(gtk.STOCK_NEW, icon_cache=self.icon_cache, icon_size=icon_size)
status_icon = util.get_tree_icon(ICON_NEW, icon_cache=self.icon_cache, icon_size=icon_size)
else:
status_icon = None

View File

@ -25,6 +25,7 @@
import gtk
import datetime
import gpodder
from gpodder.liblogger import log
from gpodder.libgpodder import gl
from gpodder.libpodcasts import podcastItem
@ -41,6 +42,9 @@ from gpodder import services
from gpodder import util
from gpodder import draw
if gpodder.interface == gpodder.MAEMO:
import hildon
class GPodderStatusIcon(gtk.StatusIcon):
""" this class display a status icon in the system tray
this icon serves to show or hide gPodder, notify dowload status
@ -65,11 +69,11 @@ class GPodderStatusIcon(gtk.StatusIcon):
ACTION_KEEP_DOWLOADING = ('keep_dowloading', _('Keep dowloading'))
ACTION_START_DOWNLOAD = ('download', _('Download'))
def __init__(self, gpodder, icon_filename):
def __init__(self, gp, icon_filename):
gtk.StatusIcon.__init__(self)
log('Creating tray icon', sender=self)
self.__gpodder = gpodder
self.__gpodder = gp
self.__finished_downloads = []
self.__icon_cache = {}
self.__icon_filename = icon_filename
@ -82,7 +86,10 @@ class GPodderStatusIcon(gtk.StatusIcon):
# try getting the icon
try:
self.__icon = gtk.gdk.pixbuf_new_from_file(self.__icon_filename)
if gpodder.interface == gpodder.GUI:
self.__icon = gtk.gdk.pixbuf_new_from_file(self.__icon_filename)
elif gpodder.interface == gpodder.MAEMO:
self.__icon = gtk.gdk.pixbuf_new_from_file_at_size(self.__icon_filename, 36, 36)
except Exception, exc:
log('Warning: Cannot load gPodder icon, will use the default icon (%s)', exc, sender=self)
self.__icon = gtk.icon_theme_get_default().load_icon(gtk.STOCK_DIALOG_QUESTION, 30, 30)
@ -91,10 +98,15 @@ class GPodderStatusIcon(gtk.StatusIcon):
self.__current_pixbuf = None
self.__last_ratio = 1.0
self.set_status()
self.connect('activate', self.__on_left_click)
menu = self.__create_context_menu()
self.connect('popup-menu', self.__on_right_click, menu)
if gpodder.interface == gpodder.GUI:
self.connect('activate', self.__on_left_click)
self.connect('popup-menu', self.__on_right_click, menu)
elif gpodder.interface == gpodder.MAEMO:
# On Maemo, we show the popup menu on left-click
self.connect('activate', self.__on_right_click, menu)
self.set_visible(True)
# initialise pynotify
@ -148,6 +160,14 @@ class GPodderStatusIcon(gtk.StatusIcon):
menu.append(menuItem)
menu.append( gtk.SeparatorMenuItem())
if gpodder.interface == gpodder.MAEMO:
# On Maemo, we map the left-click to the popup-menu,
# so add a menu item to do the left-click action
menuItem = gtk.ImageMenuItem(_('Show gPodder'))
menuItem.set_image(gtk.image_new_from_stock(gtk.STOCK_GO_UP, gtk.ICON_SIZE_MENU))
menuItem.connect('activate', self.__on_left_click)
menu.append(menuItem)
menuItem = gtk.ImageMenuItem(gtk.STOCK_QUIT)
menuItem.connect('activate', self.__on_exit_callback)
menu.append(menuItem)
@ -165,9 +185,13 @@ class GPodderStatusIcon(gtk.StatusIcon):
if p != []:
self.send_notification(p[0], p[1], p[2], p[3])
def __on_right_click(self, widget, button, time, data=None):
def __on_right_click(self, widget, button=None, time=0, data=None):
"""Open popup menu on right-click
"""
if gpodder.interface == gpodder.MAEMO and data is None and button is not None:
# The left-click action has a different function
# signature, so we have to swap parameters here
data = button
if data is not None:
data.show_all()
data.popup(None, None, None, 3, time)
@ -282,7 +306,10 @@ class GPodderStatusIcon(gtk.StatusIcon):
message = message.strip()
log('Notification: %s', message, sender=self)
if have_pynotify:
if gpodder.interface == gpodder.MAEMO:
pango_markup = '<b>%s</b>\n<small>%s</small>' % (title, message)
hildon.hildon_banner_show_information_with_markup(gtk.Label(''), None, pango_markup)
elif gpodder.interface == gpodder.GUI and have_pynotify:
notification = pynotify.Notification(title, message, self.__icon_filename)
if is_error: notification.set_urgency(pynotify.URGENCY_CRITICAL)
try:
@ -293,8 +320,12 @@ class GPodderStatusIcon(gtk.StatusIcon):
notification.add_action(action[0], action[1], self.__action_callback)
if not notification.show():
log("Error: enable to send notification %s", message)
self.__previous_notification=[message, title, actions, is_error]
self.menuItem_previous_msg.set_sensitive(True)
else:
return
# If we showed any kind of notification, remember it for next time
self.__previous_notification=[message, title, actions, is_error]
self.menuItem_previous_msg.set_sensitive(True)
def set_status(self, status=None, tooltip=None):
if status is None:

View File

@ -61,6 +61,13 @@ import StringIO
import xml.dom.minidom
if gpodder.interface == gpodder.GUI:
ICON_UNPLAYED = gtk.STOCK_YES
ICON_LOCKED = 'emblem-nowrite'
elif gpodder.interface == gpodder.MAEMO:
ICON_UNPLAYED = 'qgn_list_gene_favor'
ICON_LOCKED = 'qgn_indi_KeypadLk_lock'
def make_directory( path):
"""
Tries to create a directory if it does not exist already.
@ -427,6 +434,7 @@ def get_tree_icon(icon_name, add_bullet=False, add_padlock=False, icon_cache=Non
the cache is supplied again and the icon is found in
the cache.
"""
global ICON_UNPLAYED, ICON_LOCKED
if icon_cache != None and (icon_name,add_bullet,add_padlock,icon_size) in icon_cache:
return icon_cache[(icon_name,add_bullet,add_padlock,icon_size)]
@ -444,18 +452,19 @@ def get_tree_icon(icon_name, add_bullet=False, add_padlock=False, icon_cache=Non
if add_bullet:
try:
icon = icon.copy()
emblem = icon_theme.load_icon(gtk.STOCK_YES, int(float(icon_size)*1.2/3.0), 0)
size = emblem.get_width()
pos = icon.get_width() - size
emblem.composite(icon, pos, pos, size, size, pos, pos, 1, 1, gtk.gdk.INTERP_BILINEAR, 255)
emblem = icon_theme.load_icon(ICON_UNPLAYED, int(float(icon_size)*1.2/3.0), 0)
(width, height) = (emblem.get_width(), emblem.get_height())
xpos = icon.get_width() - width
ypos = icon.get_height() - height
emblem.composite(icon, xpos, ypos, width, height, xpos, ypos, 1, 1, gtk.gdk.INTERP_BILINEAR, 255)
except:
log('(get_tree_icon) Error adding emblem to icon "%s".', icon_name)
if add_padlock:
try:
icon = icon.copy()
emblem = icon_theme.load_icon('emblem-nowrite', int(float(icon_size)/2.0), 0)
size = emblem.get_width()
emblem.composite(icon, 0, 0, size, size, 0, 0, 1, 1, gtk.gdk.INTERP_BILINEAR, 255)
emblem = icon_theme.load_icon(ICON_LOCKED, int(float(icon_size)/2.0), 0)
(width, height) = (emblem.get_width(), emblem.get_height())
emblem.composite(icon, 0, 0, width, height, 0, 0, 1, 1, gtk.gdk.INTERP_BILINEAR, 255)
except:
log('(get_tree_icon) Error adding emblem to icon "%s".', icon_name)
@ -650,7 +659,7 @@ def idle_add(func, *args):
call the function later - this is needed for
threads to be able to modify GTK+ widget data.
"""
if gpodder.interface_is_gui:
if gpodder.interface in (gpodder.GUI, gpodder.MAEMO):
def x(f, *a):
f(*a)
return False