virtual zap plugin - initial checkin
authorDr.Best <dr_best@users.schwerkraft.elitedvb.net>
Sat, 6 Feb 2010 21:01:45 +0000 (21:01 +0000)
committerDr.Best <dr_best@users.schwerkraft.elitedvb.net>
Sat, 6 Feb 2010 21:01:45 +0000 (21:01 +0000)
16 files changed:
Makefile.am
configure.ac
virtualzap/CONTROL/control [new file with mode: 0644]
virtualzap/Makefile.am [new file with mode: 0755]
virtualzap/meta/Makefile.am [new file with mode: 0755]
virtualzap/meta/plugin_virtualzap.xml [new file with mode: 0755]
virtualzap/meta/virtualzap.jpg [new file with mode: 0644]
virtualzap/po/Makefile.am [new file with mode: 0644]
virtualzap/po/VirtualZap.pot [new file with mode: 0644]
virtualzap/po/de.po [new file with mode: 0644]
virtualzap/src/Makefile.am [new file with mode: 0755]
virtualzap/src/__init__.py [new file with mode: 0644]
virtualzap/src/keymap.xml [new file with mode: 0644]
virtualzap/src/maintainer.info [new file with mode: 0644]
virtualzap/src/plugin.png [new file with mode: 0644]
virtualzap/src/plugin.py [new file with mode: 0644]

index 2cc31cf..f75c671 100644 (file)
@@ -57,6 +57,7 @@ SUBDIRS = \
        tageditor \
        trafficinfo \
        unwetterzentrale \
+       virtualzap \
        vlcplayer \
        weatherplugin \
        webcamviewer \
index 1710aee..ac18019 100644 (file)
@@ -301,6 +301,11 @@ unwetterzentrale/Makefile
 unwetterzentrale/meta/Makefile
 unwetterzentrale/src/Makefile
 
+virtualzap/Makefile
+virtualzap/meta/Makefile
+virtualzap/po/Makefile
+virtualzap/src/Makefile
+
 vlcplayer/Makefile
 vlcplayer/meta/Makefile
 vlcplayer/po/Makefile
diff --git a/virtualzap/CONTROL/control b/virtualzap/CONTROL/control
new file mode 100644 (file)
index 0000000..50d8e12
--- /dev/null
@@ -0,0 +1,10 @@
+Package: enigma2-plugin-extensions-virtualzap
+Version: 1.0
+Description: E2 Virtual Zap Plugin
+Architecture: mipsel
+Section: extra
+Priority: optional
+Maintainer: Dr. Best <dr.best@dreambox-tools.info>
+Homepage: http://www.dreambox-tools.info
+Depends: enigma2(>2.6git20091201), twisted-web, streamripper
+Source: http://enigma2-plugins.schwerkraft.elitedvb.net/
diff --git a/virtualzap/Makefile.am b/virtualzap/Makefile.am
new file mode 100755 (executable)
index 0000000..1442b1d
--- /dev/null
@@ -0,0 +1 @@
+SUBDIRS = src meta po
diff --git a/virtualzap/meta/Makefile.am b/virtualzap/meta/Makefile.am
new file mode 100755 (executable)
index 0000000..5ab0c1f
--- /dev/null
@@ -0,0 +1,5 @@
+installdir = $(datadir)/meta/
+
+dist_install_DATA = plugin_virtualzap.xml
+
+EXTRA_DIST = virtualzap.jpg
diff --git a/virtualzap/meta/plugin_virtualzap.xml b/virtualzap/meta/plugin_virtualzap.xml
new file mode 100755 (executable)
index 0000000..a335135
--- /dev/null
@@ -0,0 +1,24 @@
+<default>
+         <prerequisites>
+                    <tag type="Multimedia" />
+         </prerequisites>
+          <info language="en">
+                    <author>Dr.Best</author>
+                    <name>Virtual Zap</name>
+                    <packagename>enigma2-plugin-extensions-virtualzap</packagename>
+                    <shortdescription>see service-epg (and PiP) from channels in an infobar</shortdescription>
+                    <description>see service-epg (and PiP) from other channels in an infobar</description>
+                    <screenshot src="http://www.dreamboxupdate.com/preview/virtualzap.jpg" />              
+          </info>
+          <info language="de">
+                    <author>Dr.Best</author>
+                    <name>Virtual Zap</name>
+                    <packagename>enigma2-plugin-extensions-shoutcast</packagename>
+                   <shortdescription>EPG Daten und PiP von Kanälen in Infobar anzeigen</shortdescription>
+                    <description>EPG Daten und PiP von Kanälen in Infobar anzeigen</description>
+                    <screenshot src="http://www.dreamboxupdate.com/preview/virtualzap.jpg" />           
+          </info>
+         <files type="package"> <!-- without version, without .ipk -->
+               <file type="package" name="enigma2-plugin-extensions-virtualzap" />
+         </files>
+</default>
diff --git a/virtualzap/meta/virtualzap.jpg b/virtualzap/meta/virtualzap.jpg
new file mode 100644 (file)
index 0000000..eb67ca0
Binary files /dev/null and b/virtualzap/meta/virtualzap.jpg differ
diff --git a/virtualzap/po/Makefile.am b/virtualzap/po/Makefile.am
new file mode 100644 (file)
index 0000000..f3ab24c
--- /dev/null
@@ -0,0 +1,57 @@
+#
+# to use this for the localisation of other plugins,
+# just change the DOMAIN to the name of the Plugin.
+# It is assumed, that the domain ist the same as
+# the directory name of the plugin.
+#
+
+DOMAIN=VirtualZap
+installdir = /usr/lib/enigma2/python/Plugins/Extensions/$(DOMAIN)
+#GETTEXT=./pygettext.py
+GETTEXT=xgettext
+
+#MSGFMT = ./msgfmt.py
+MSGFMT = msgfmt
+
+LANGS := de
+LANGPO := $(foreach LANG, $(LANGS),$(LANG).po)
+LANGMO := $(foreach LANG, $(LANGS),$(LANG).mo)
+
+default: $(DOMAIN).pot $(LANGPO) merge $(LANGMO)
+       for lang in $(LANGS); do \
+               mkdir -p $$lang/LC_MESSAGES; \
+               cp $$lang.mo $$lang/LC_MESSAGES/$(DOMAIN).mo; \
+       done
+
+merge:
+       for lang in $(LANGS); do \
+               msgmerge --no-location -s -N -U $$lang.po $(DOMAIN).pot; \
+       done
+
+
+# the TRANSLATORS: allows putting translation comments before the to-be-translated line.
+$(DOMAIN).pot:
+       $(GETTEXT) -L python --add-comments="TRANSLATORS:" -d $(DOMAIN) -s -o $(DOMAIN).pot ../src/*.py
+       msguniq -o $(DOMAIN)uniq.pot $(DOMAIN).pot
+       $(RM) $(DOMAIN).pot
+       mv $(DOMAIN)uniq.pot $(DOMAIN).pot
+
+.PHONY: $(DOMAIN).pot
+
+
+%.mo: %.po
+       $(MSGFMT) -o $@ $<
+
+%.po:
+       msginit -l $@ -o $@ -i $(DOMAIN).pot --no-translator
+
+CLEANFILES = $(foreach LANG, $(LANGS),$(LANG).mo)
+
+clean-local:
+       $(RM) -r $(LANGS)
+
+install-data-am: default
+       for lang in $(LANGS); do \
+               mkdir -p $(DESTDIR)$(installdir)/locale/$$lang/LC_MESSAGES; \
+               cp $$lang.mo $(DESTDIR)$(installdir)/locale/$$lang/LC_MESSAGES/$(DOMAIN).mo; \
+       done
diff --git a/virtualzap/po/VirtualZap.pot b/virtualzap/po/VirtualZap.pot
new file mode 100644 (file)
index 0000000..9c9dc75
--- /dev/null
@@ -0,0 +1,63 @@
+msgid ""
+msgstr ""
+"Project-Id-Version: \n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2010-02-05 19:05+0100\n"
+"PO-Revision-Date: \n"
+"Last-Translator: Dr. Best <dr.best@dreambox-tools.info>\n"
+"Language-Team: \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#: ../src/plugin.py:48
+msgid "as plugin in extended bar"
+msgstr ""
+
+#: ../src/plugin.py:48
+msgid "with long OK press"
+msgstr ""
+
+#: ../src/plugin.py:48
+msgid "with exit button"
+msgstr ""
+
+#: ../src/plugin.py:48
+msgid "as plugin in pluginmenu"
+msgstr ""
+
+#: ../src/plugin.py:106
+msgid "Virtual Zap Setup"
+msgstr ""
+
+#: ../src/plugin.py:108
+#: ../src/plugin.py:112
+msgid "Virtual (PiP) Zap"
+msgstr ""
+
+#: ../src/plugin.py:413
+msgid "Cancel"
+msgstr ""
+
+#: ../src/plugin.py:414
+msgid "OK"
+msgstr ""
+
+#: ../src/plugin.py:416
+msgid "Usage"
+msgstr ""
+
+#: ../src/plugin.py:418
+msgid "Show with PiP"
+msgstr ""
+
+#: ../src/plugin.py:430
+msgid ""
+"GUI needs a restart to apply the new settings.\n"
+"Do you want to Restart the GUI now?"
+msgstr ""
+
+#: ../src/plugin.py:431
+msgid "Restart GUI now?"
+msgstr ""
+
diff --git a/virtualzap/po/de.po b/virtualzap/po/de.po
new file mode 100644 (file)
index 0000000..25b6019
--- /dev/null
@@ -0,0 +1,65 @@
+msgid ""
+msgstr ""
+"Project-Id-Version: \n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2010-02-05 19:05+0100\n"
+"PO-Revision-Date: \n"
+"Last-Translator: Dr. Best <dr.best@dreambox-tools.info>\n"
+"Language-Team: \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#: ../src/plugin.py:48
+msgid "as plugin in extended bar"
+msgstr "als Plugin in Extended Bar"
+
+#: #: ../src/plugin.py:48
+msgid "with long OK press"
+msgstr "mit langen Druck auf \"OK\""
+
+#: #: ../src/plugin.py:48
+msgid "with exit button"
+msgstr "mit \"Exit\" auf Fernbedienung"
+
+#: ../src/plugin.py:48
+msgid "as plugin in pluginmenu"
+msgstr "als Plugin im Pluginbrowser"
+
+#: ../src/plugin.py:106
+msgid "Virtual Zap Setup"
+msgstr "Virtual Zap Einstellungen"
+
+#: ../src/plugin.py:108
+#: ../src/plugin.py:112
+msgid "Virtual (PiP) Zap"
+msgstr "Virtual (PiP) Zap"
+
+#: ../src/plugin.py:413
+msgid "Cancel"
+msgstr "Abbruch"
+
+#: ../src/plugin.py:414
+msgid "OK"
+msgstr "OK"
+
+#: ../src/plugin.py:416
+msgid "Usage"
+msgstr "Benutzung"
+
+#: ../src/plugin.py:418
+msgid "Show with PiP"
+msgstr "PiP in Infobar anzeigen"
+
+#: ../src/plugin.py:430
+msgid ""
+"GUI needs a restart to apply the new settings.\n"
+"Do you want to Restart the GUI now?"
+msgstr ""
+"Die GUI benötigt einen Neustart, damit die Änderungen wirksam werden.\n"
+"Soll die GUI jezt neu gestartet werden?"
+
+#: ../src/plugin.py:431
+msgid "Restart GUI now?"
+msgstr "GUI Neustart?"
+
diff --git a/virtualzap/src/Makefile.am b/virtualzap/src/Makefile.am
new file mode 100755 (executable)
index 0000000..e7fed98
--- /dev/null
@@ -0,0 +1,5 @@
+installdir = /usr/lib/enigma2/python/Plugins/Extensions/VirtualZap
+
+install_PYTHON = *.py
+
+install_DATA = maintainer.info plugin.png keymap.xml
diff --git a/virtualzap/src/__init__.py b/virtualzap/src/__init__.py
new file mode 100644 (file)
index 0000000..f80c119
--- /dev/null
@@ -0,0 +1,21 @@
+# -*- coding: utf-8 -*-
+from Components.Language import language
+from Tools.Directories import resolveFilename, SCOPE_PLUGINS, SCOPE_LANGUAGE
+from os import environ as os_environ
+import gettext
+
+def localeInit():
+       lang = language.getLanguage()[:2] # getLanguage returns e.g. "fi_FI" for "language_country"
+       os_environ["LANGUAGE"] = lang # Enigma doesn't set this (or LC_ALL, LC_MESSAGES, LANG). gettext needs it!
+       gettext.bindtextdomain("VirtualZap", resolveFilename(SCOPE_PLUGINS, "Extensions/VirtualZap/locale"))
+
+def _(txt):
+       t = gettext.dgettext("VirtualZap", txt)
+       if t == txt:
+               print "[VirtualZap] fallback to default translation for", txt
+               t = gettext.gettext(txt)
+       return t
+
+localeInit()
+language.addCallback(localeInit)
+
diff --git a/virtualzap/src/keymap.xml b/virtualzap/src/keymap.xml
new file mode 100644 (file)
index 0000000..7a784cc
--- /dev/null
@@ -0,0 +1,10 @@
+<keymap>
+       <map context="myShowHideActions">
+               <key id="KEY_OK" mapto="toggleShow" flags="b" />
+               <key id="KEY_ENTER" mapto="toggleShow" flags="b" />
+               <key id="KEY_OK" mapto="longOK" flags="l" />
+               <key id="KEY_ENTER" mapto="longOK" flags="l" />
+               <key id="KEY_EXIT" mapto="hide" flags="m" />
+               <key id="KEY_ESC" mapto="hide" flags="m" />
+       </map>
+</keymap>
diff --git a/virtualzap/src/maintainer.info b/virtualzap/src/maintainer.info
new file mode 100644 (file)
index 0000000..0481203
--- /dev/null
@@ -0,0 +1,2 @@
+dr.best@dreambox-tools.info
+VirtualZap
diff --git a/virtualzap/src/plugin.png b/virtualzap/src/plugin.png
new file mode 100644 (file)
index 0000000..43ee907
Binary files /dev/null and b/virtualzap/src/plugin.png differ
diff --git a/virtualzap/src/plugin.py b/virtualzap/src/plugin.py
new file mode 100644 (file)
index 0000000..aff553c
--- /dev/null
@@ -0,0 +1,448 @@
+#
+#  VirtualZap E2
+#
+#  $Id$
+#
+#  Coded by Dr.Best (c) 2010
+#  Coding idea by vali
+#  Support: www.dreambox-tools.info
+#
+#  This plugin is licensed under the Creative Commons 
+#  Attribution-NonCommercial-ShareAlike 3.0 Unported 
+#  License. To view a copy of this license, visit
+#  http://creativecommons.org/licenses/by-nc-sa/3.0/ or send a letter to Creative
+#  Commons, 559 Nathan Abbott Way, Stanford, California 94305, USA.
+#
+#  Alternatively, this plugin may be distributed and executed on hardware which
+#  is licensed by Dream Multimedia GmbH.
+
+#  This plugin is NOT free software. It is open source, you are allowed to
+#  modify it (if you keep the license), but it may not be commercially 
+#  distributed other than under the conditions noted above.
+#
+\r
+from Plugins.Plugin import PluginDescriptor\r
+from Screens.Screen import Screen\r
+from Components.ActionMap import ActionMap, NumberActionMap\r
+from Components.Label import Label\r
+from enigma import eServiceReference,  eTimer, getDesktop\r
+from ServiceReference import ServiceReference\r
+from Components.SystemInfo import SystemInfo
+from enigma import eServiceCenter, getBestPlayableServiceReference
+from Components.VideoWindow import VideoWindow
+from enigma import ePoint, eEPGCache
+from time import localtime, time
+from Screens.InfoBarGenerics import InfoBarShowHide, NumberZap
+from Screens.InfoBar import InfoBar
+
+from Components.Sources.StaticText import StaticText
+from Screens.MessageBox import MessageBox
+from Screens.Standby import TryQuitMainloop
+
+InfoBarShowHideINIT = None
+
+from Components.config import config, ConfigSubsection, ConfigSelection, ConfigYesNo, getConfigListEntry, configfile
+from Components.ConfigList import ConfigList, ConfigListScreen
+
+# for localized messages
+from . import _
+
+config.plugins.virtualzap = ConfigSubsection()
+config.plugins.virtualzap.mode = ConfigSelection(default="0", choices = [("0", _("as plugin in extended bar")),("1", _("with long OK press")), ("2", _("with exit button")),("3", _("as plugin in pluginmenu"))])
+config.plugins.virtualzap.usepip = ConfigYesNo(default = True)
+
+def autostart(reason, **kwargs):
+       if config.plugins.virtualzap.mode.value != "0":
+               # overide InfoBarShowHide
+               global InfoBarShowHideINIT
+               if InfoBarShowHideINIT is None:
+                       InfoBarShowHideINIT = InfoBarShowHide.__init__
+               InfoBarShowHide.__init__ = InfoBarShowHide__init__
+               # new method
+               InfoBarShowHide.showVZ = showVZ
+               if config.plugins.virtualzap.mode.value == "2":
+                       InfoBarShowHide.newHide = newHide
+
+def InfoBarShowHide__init__(self):
+       # initialize InfoBarShowHide with original __init__
+       InfoBarShowHideINIT(self)
+       if config.plugins.virtualzap.mode.value == "1":
+               # delete current key map --> we have to use "ok" with b-flag
+               del self["ShowHideActions"]
+               # initialize own actionmap with ok = b and longOK = l
+               self["myactions"] = ActionMap( ["myShowHideActions"] ,
+               {
+                       "toggleShow": self.toggleShow,
+                       "longOK": self.showVZ,
+                       "hide": self.hide,
+               }, 1)
+       elif config.plugins.virtualzap.mode.value == "2":
+               # overide hide 
+               self["ShowHideActions"] = ActionMap( ["InfobarShowHideActions"] ,
+               {
+                       "toggleShow": self.toggleShow,
+                       "hide": self.newHide,
+               }, 1)
+
+
+def showVZ(self):
+       from  Screens.InfoBarGenerics import InfoBarEPG, InfoBarPiP
+       # check for InfoBarEPG --> only start if true
+       if isinstance(self, InfoBarEPG):
+               # check for PiP
+               if isinstance(self, InfoBarPiP):
+                       # check if PiP is already shown
+                       if self.pipShown():
+                               # it is... close it!
+                               self.showPiP()
+               if InfoBar and InfoBar.instance:
+                       InfoBar.instance.session.open(VirtualZap, InfoBar.instance.servicelist)
+
+def newHide(self):
+       # remember if infobar is shown
+       visible = self.shown
+       self.hide()
+       if not visible:
+               # infobar was not shown, start VZ
+               self.showVZ()
+
+def Plugins(**kwargs):
+       plist =  [PluginDescriptor(name="Virtual Zap Setup", description=_("Virtual Zap Setup"), where = [PluginDescriptor.WHERE_PLUGINMENU], icon = "plugin.png", fnc = setup)]
+       if config.plugins.virtualzap.mode.value == "0":
+               plist.append(PluginDescriptor(name="Virtual Zap", description=_("Virtual (PiP) Zap"), where = [PluginDescriptor.WHERE_EXTENSIONSMENU],icon = "plugin.png", fnc = main))
+       elif config.plugins.virtualzap.mode.value == "1" or config.plugins.virtualzap.mode.value == "2":
+               plist.append(PluginDescriptor(where = [PluginDescriptor.WHERE_SESSIONSTART],fnc = autostart))
+       elif config.plugins.virtualzap.mode.value == "3":
+               plist.append(PluginDescriptor(name="Virtual Zap", description=_("Virtual (PiP) Zap"), where = [PluginDescriptor.WHERE_PLUGINMENU],icon = "plugin.png", fnc = main))
+       return plist
+
+def setup(session,**kwargs):
+       session.open(VirtualZapConfig)
+
+def main(session,**kwargs):
+       if InfoBar and InfoBar.instance:
+               session.open(VirtualZap, InfoBar.instance.servicelist)
+
+class VirtualZap(Screen):\r
+       sz_w = getDesktop(0).size().width()
+
+       #
+       # VirtualZap or VirtualZapNoPiP
+       #
+
+       if SystemInfo.get("NumVideoDecoders", 1) > 1 and config.plugins.virtualzap.usepip.value:
+               # the video widget position is odd for 1280 and 1024... but it seems that the video position is calculated wrong with res <> 720
+               if sz_w == 1280:
+                       skin = """
+                               <screen name="VirtualZap" position="0,0" size="1280,720" flags="wfNoBorder" backgroundColor="transparent">
+                                       <widget name="NowChannel" position="350,555" size="740,25" zPosition="2" font="Regular;22" />
+                                       <widget name="NowEPG" position="350,580" size="620,25" zPosition="2" font="Regular;22" foregroundColor="#fcc000" />
+                                       <widget name="NextEPG" position="350,605" size="620,25" zPosition="2" font="Regular;22" />
+                                       <widget name="NowTime" position="970,580" size="120,25" zPosition="2" font="Regular;22" halign="right" foregroundColor="#fcc000"/>
+                                       <widget name="NextTime" position="970,605" size="120,25" zPosition="2" font="Regular;22" halign="right"/>
+                                       <widget name="video" position="70,420" size="120,96" backgroundColor="transparent" />
+                               </screen>"""
+
+               elif sz_w == 1024:
+
+                       skin = """
+                               <screen name="VirtualZap" position="0,440" size="1024,96" flags="wfNoBorder" backgroundColor="transparent">
+                                       <widget name="NowChannel" position="280,10" size="675,25" zPosition="2" font="Regular;22" />
+                                       <widget name="NowEPG" position="280,35" size="555,25" zPosition="2" font="Regular;22" foregroundColor="#fcc000" />
+                                       <widget name="NextEPG" position="280,60" size="555,25" zPosition="2" font="Regular;22" />
+                                       <widget name="NowTime" position="835,35" size="120,25" zPosition="2" font="Regular;22" halign="right" foregroundColor="#fcc000"/>
+                                       <widget name="NextTime" position="835,60" size="120,25" zPosition="2" font="Regular;22" halign="right"/>
+                                       <widget name="video" position="70,0" size="120,96" backgroundColor="transparent" />
+                               </screen>"""
+
+               else:
+
+                       skin = """
+                               <screen name="VirtualZap" position="0,0" size="720,576" flags="wfNoBorder" backgroundColor="transparent">
+                                       <widget name="NowChannel" position="170,450" size="510,25" zPosition="2" font="Regular;22" />
+                                       <widget name="NowEPG" position="170,475" size="390,25" zPosition="2" font="Regular;22" foregroundColor="#fcc000"/>
+                                       <widget name="NextEPG" position="170,500" size="390,25" zPosition="2" font="Regular;22" />
+                                       <widget name="NowTime" position="560,475" size="120,25" zPosition="2" font="Regular;22" halign="right" foregroundColor="#fcc000"/>
+                                       <widget name="NextTime" position="560,500" size="120,25" zPosition="2" font="Regular;22" halign="right"/>
+                                       <widget name="video" position="40,440" size="120,96" backgroundColor="transparent" />
+                               </screen>"""
+       else:
+               if sz_w == 1280:
+                       skin = """
+                               <screen name="VirtualZapNoPiP" position="0,0" size="1280,720" flags="wfNoBorder" backgroundColor="transparent">
+                                       <widget name="NowChannel" position="270,555" size="740,25" zPosition="2" font="Regular;22" />
+                                       <widget name="NowEPG" position="270,580" size="620,25" zPosition="2" font="Regular;22" foregroundColor="#fcc000" />
+                                       <widget name="NextEPG" position="270,605" size="620,25" zPosition="2" font="Regular;22" />
+                                       <widget name="NowTime" position="890,580" size="120,25" zPosition="2" font="Regular;22" halign="right" foregroundColor="#fcc000"/>
+                                       <widget name="NextTime" position="890,605" size="120,25" zPosition="2" font="Regular;22" halign="right"/>
+                               </screen>"""
+
+               elif sz_w == 1024:
+
+                       skin = """
+                               <screen name="VirtualZapNoPiP" position="0,440" size="1024,96" flags="wfNoBorder" backgroundColor="transparent">
+                                       <widget name="NowChannel" position="167,10" size="690,25" zPosition="2" font="Regular;22" />
+                                       <widget name="NowEPG" position="167,35" size="570,25" zPosition="2" font="Regular;22" foregroundColor="#fcc000" />
+                                       <widget name="NextEPG" position="167,60" size="570,25" zPosition="2" font="Regular;22" />
+                                       <widget name="NowTime" position="737,35" size="120,25" zPosition="2" font="Regular;22" halign="right" foregroundColor="#fcc000"/>
+                                       <widget name="NextTime" position="737,60" size="120,25" zPosition="2" font="Regular;22" halign="right"/>
+                               </screen>"""
+
+               else:
+
+                       skin = """
+                               <screen name="VirtualZapNoPiP" position="0,0" size="720,576" flags="wfNoBorder" backgroundColor="transparent">
+                                       <widget name="NowChannel" position="80,450" size="560,25" zPosition="2" font="Regular;22" />
+                                       <widget name="NowEPG" position="80,475" size="440,25" zPosition="2" font="Regular;22" foregroundColor="#fcc000"/>
+                                       <widget name="NextEPG" position="80,500" size="440,25" zPosition="2" font="Regular;22" />
+                                       <widget name="NowTime" position="520,475" size="120,25" zPosition="2" font="Regular;22" halign="right" foregroundColor="#fcc000"/>
+                                       <widget name="NextTime" position="520,500" size="120,25" zPosition="2" font="Regular;22" halign="right"/>
+                               </screen>"""
+
+\r
+       def __init__(self, session, servicelist = None):\r
+               Screen.__init__(self, session)\r
+               self.session = session
+               self.pipAvailable = False
+               if SystemInfo.get("NumVideoDecoders", 1) > 1 and config.plugins.virtualzap.usepip.value:
+                       self.skinName = "VirtualZap"
+                       self.pipAvailable = True
+               else:
+                       self.skinName = "VirtualZapNoPiP"
+               self.epgcache = eEPGCache.getInstance()\r
+               self.CheckForEPG = eTimer()\r
+               self.CheckForEPG.callback.append(self.CheckItNow)\r
+               self["NowChannel"] = Label()\r
+               self["NowEPG"] = Label()\r
+               self["NextEPG"] = Label()
+               self["NowTime"] = Label()\r
+               self["NextTime"] = Label()\r
+               self["actions"] = ActionMap(["OkCancelActions", "DirectionActions"], 
+               {\r
+                       "ok": self.ok, \r
+                       "cancel": self.closing,\r
+                       "right": self.prgPlus,\r
+                       "left": self.prgMinus,
+               },-2)
+               self["actions2"] = NumberActionMap(["NumberActions"],
+               {
+                       "1": self.keyNumberGlobal,
+                       "2": self.keyNumberGlobal,
+                       "3": self.keyNumberGlobal,
+                       "4": self.keyNumberGlobal,
+                       "5": self.keyNumberGlobal,
+                       "6": self.keyNumberGlobal,
+                       "7": self.keyNumberGlobal,
+                       "8": self.keyNumberGlobal,
+                       "9": self.keyNumberGlobal,
+               }, -1)
+               self.onLayoutFinish.append(self.onLayoutReady)
+               # PiP
+               if self.pipAvailable:
+                       # activate PiP support
+                       self["video"] = VideoWindow()
+                       self.pip = None
+                       self.currentPiP = ""
+               # this is the servicelist from ChannelSelectionBase
+               self.servicelist = servicelist
+               self.newServicePlayed  =  False
+               # needed, because if we won't zap, we habe to go back to the current bouquet and service
+               self.curRef = ServiceReference(self.servicelist.getCurrentSelection())
+               self.curBouquet = self.servicelist.getRoot()
+
+       def onLayoutReady(self):
+               self.updateInfos()\r
+\r
+       def prgPlus(self):
+               # get next service
+               self.servicelist.moveDown()
+               if self.isPlayable():
+                       self.updateInfos()
+               else:
+                       # service is not playable, try next one
+                       self.prgPlus()
+\r
+       def prgMinus(self):
+               # get previous service
+               self.servicelist.moveUp()
+               if self.isPlayable():
+                       self.updateInfos()
+               else:
+                       # service is not playable, try next one
+                       self.prgMinus()
+
+       def isPlayable(self):
+               # check if service is playable
+               current = ServiceReference(self.servicelist.getCurrentSelection())
+               return not (current.ref.flags & (eServiceReference.isMarker|eServiceReference.isDirectory))\r
+\r
+       def updateInfos(self):
+               # update data\r
+               current = ServiceReference(self.servicelist.getCurrentSelection())
+               self["NowChannel"].setText(current.getServiceName())
+               nowepg, nowtimedisplay = self.getEPGNowNext(current.ref,0)
+               nextepg, nexttimedisplay = self.getEPGNowNext(current.ref,1)
+               self["NowEPG"].setText(nowepg)
+               self["NextEPG"].setText(nextepg)
+               self["NowTime"].setText(nowtimedisplay)
+               self["NextTime"].setText(nexttimedisplay)
+               if not nowepg:
+                       # no epg found --> let's try it again, but only if PiP is activated
+                       if self.pipAvailable:
+                               self.CheckForEPG.start(3000, True)
+               if self.pipAvailable:
+                       # play in videowindow
+                       self.playService(current.ref)
+
+       def getEPGNowNext(self,ref, modus):
+               # get now || next event
+               if self.epgcache is not None:
+                       event = self.epgcache.lookupEvent(['IBDCTSERNX', (ref.toString(), modus, -1)])
+                       if event:
+                               if event[0][4]:
+                                       t = localtime(event[0][1])
+                                       duration = event[0][2]
+                                       if modus == 0:
+                                               timedisplay = "+%d min" % (((event[0][1] + duration) - time()) / 60)
+                                       elif modus == 1:
+                                               timedisplay = "%d min" %  (duration / 60)
+                                       return "%02d:%02d %s" % (t[3],t[4], event[0][4]), timedisplay
+                               else:
+                                       return "", ""
+               return "", ""
+
+       def closing(self):
+               if self.pipAvailable:
+                       self.pipservice = None
+               if not self.newServicePlayed:
+                       # we need to select the old service with bouquet
+                       if self.curBouquet != self.servicelist.getRoot():
+                               self.servicelist.clearPath()
+                               if self.servicelist.bouquet_root != self.curBouquet:
+                                       self.servicelist.enterPath(self.servicelist.bouquet_root)
+                               self.servicelist.enterPath(self.curBouquet)
+                       self.servicelist.setCurrentSelection(self.curRef.ref)
+               self.close()\r
+                       \r
+       def ok(self):
+               # we have to close PiP first, otherwise the service-display is freezed
+               if self.pipAvailable:
+                       self.pipservice = None
+               # play selected service and close virtualzap
+               self.newServicePlayed = True\r
+               self.servicelist.zap()\r
+               self.close()\r
+\r
+       def CheckItNow(self):\r
+               self.CheckForEPG.stop()\r
+               self.updateInfos()
+
+       # if available play service in PiP 
+       def playService(self, service):
+               if service and (service.flags & eServiceReference.isGroup):
+                       ref = getBestPlayableServiceReference(service, eServiceReference())
+               else:
+                       ref = service
+               if ref and ref.toString() != self.currentPiP:
+                       self.pipservice = eServiceCenter.getInstance().play(ref)
+                       if self.pipservice and not self.pipservice.setTarget(1):
+                               self.pipservice.start()
+                               self.currentPiP = ref.toString()
+                       else:
+                               self.pipservice = None
+                               self.currentPiP = ""
+
+
+       # switch with numbers
+       def keyNumberGlobal(self, number):
+               self.session.openWithCallback(self.numberEntered, NumberZap, number)
+
+       def numberEntered(self, retval):
+               if retval > 0:
+                       self.zapToNumber(retval)
+
+       def searchNumberHelper(self, serviceHandler, num, bouquet):
+               servicelist = serviceHandler.list(bouquet)
+               if not servicelist is None:
+                       while num:
+                               serviceIterator = servicelist.getNext()
+                               if not serviceIterator.valid(): #check end of list
+                                       break
+                               playable = not (serviceIterator.flags & (eServiceReference.isMarker|eServiceReference.isDirectory))
+                               if playable:
+                                       num -= 1;
+                       if not num: #found service with searched number ?
+                               return serviceIterator, 0
+               return None, num
+
+       def zapToNumber(self, number):
+               bouquet = self.servicelist.bouquet_root
+               service = None
+               serviceHandler = eServiceCenter.getInstance()
+               bouquetlist = serviceHandler.list(bouquet)
+               if not bouquetlist is None:
+                       while number:
+                               bouquet = bouquetlist.getNext()
+                               if not bouquet.valid(): #check end of list
+                                       break
+                               if bouquet.flags & eServiceReference.isDirectory:
+                                       service, number = self.searchNumberHelper(serviceHandler, number, bouquet)
+               if not service is None:
+                       if self.servicelist.getRoot() != bouquet: #already in correct bouquet?
+                               self.servicelist.clearPath()
+                               if self.servicelist.bouquet_root != bouquet:
+                                       self.servicelist.enterPath(self.servicelist.bouquet_root)
+                               self.servicelist.enterPath(bouquet)
+                       self.servicelist.setCurrentSelection(service) #select the service in servicelist
+               # update infos, no matter if service is none or not
+               self.updateInfos()\r
+
+
+
+class VirtualZapConfig(Screen, ConfigListScreen):
+
+       skin = """
+               <screen position="center,center" size="560,110" title="Virtual Zap Config" >
+                       <ePixmap pixmap="skin_default/buttons/red.png" position="0,0" zPosition="0" size="140,40" transparent="1" alphatest="on" />
+                       <ePixmap pixmap="skin_default/buttons/green.png" position="140,0" zPosition="0" size="140,40" transparent="1" alphatest="on" />
+                       <ePixmap pixmap="skin_default/buttons/yellow.png" position="280,0" zPosition="0" size="140,40" transparent="1" alphatest="on" />
+                       <ePixmap pixmap="skin_default/buttons/blue.png" position="420,0" zPosition="0" size="140,40" transparent="1" alphatest="on" />
+                       <widget render="Label" source="key_red" position="0,0" size="140,40" zPosition="5" valign="center" halign="center" backgroundColor="red" font="Regular;21" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
+                       <widget render="Label" source="key_green" position="140,0" size="140,40" zPosition="5" valign="center" halign="center" backgroundColor="red" font="Regular;21" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
+                       <widget name="config" position="20,50" size="520,330" scrollbarMode="showOnDemand" />
+               </screen>"""
+
+       def __init__(self, session):
+               Screen.__init__(self, session)
+               self["key_red"] = StaticText(_("Cancel"))
+               self["key_green"] = StaticText(_("OK"))
+               self.list = [ ]
+               self.list.append(getConfigListEntry(_("Usage"), config.plugins.virtualzap.mode))
+               if SystemInfo.get("NumVideoDecoders", 1) > 1:
+                       self.list.append(getConfigListEntry(_("Show with PiP"), config.plugins.virtualzap.usepip))
+               ConfigListScreen.__init__(self, self.list, session)
+               self["setupActions"] = ActionMap(["SetupActions", "ColorActions"],
+               {
+                       "green": self.keySave,
+                       "cancel": self.keyClose,
+               }, -2)
+
+       def keySave(self):
+               for x in self["config"].list:
+                       x[1].save()
+               configfile.save()
+               restartbox = self.session.openWithCallback(self.restartGUI,MessageBox,_("GUI needs a restart to apply the new settings.\nDo you want to Restart the GUI now?"), MessageBox.TYPE_YESNO)
+               restartbox.setTitle(_("Restart GUI now?"))
+               
+
+       def keyClose(self):
+               for x in self["config"].list:
+                       x[1].cancel()
+               self.close()
+
+       def restartGUI(self, answer):
+               if answer is True:
+                       self.session.open(TryQuitMainloop, 3)
+               else:
+                       self.close()
+