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:
parent
213ab6f932
commit
afe3df8384
39
ChangeLog
39
ChangeLog
|
@ -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)
|
||||
|
||||
|
|
23
Makefile
23
Makefile
|
@ -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
|
||||
|
||||
|
|
13
bin/gpodder
13
bin/gpodder
|
@ -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
|
||||
|
|
|
@ -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>
|
||||
|
|
Binary file not shown.
After Width: | Height: | Size: 1.6 KiB |
Binary file not shown.
After Width: | Height: | Size: 3.1 KiB |
|
@ -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;
|
40
setup.py
40
setup.py
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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))
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue