fix for new enigma-version from oe 2.0
[enigma2-plugins.git] / virtualzap / src / plugin.py
1 #
2 #  VirtualZap E2
3 #
4 #  $Id$
5 #
6 #  Coded by Dr.Best (c) 2010
7 #  Coding idea and design by Vali
8 #  Support: www.dreambox-tools.info
9 #
10 #  This plugin is licensed under the Creative Commons 
11 #  Attribution-NonCommercial-ShareAlike 3.0 Unported 
12 #  License. To view a copy of this license, visit
13 #  http://creativecommons.org/licenses/by-nc-sa/3.0/ or send a letter to Creative
14 #  Commons, 559 Nathan Abbott Way, Stanford, California 94305, USA.
15 #
16 #  Alternatively, this plugin may be distributed and executed on hardware which
17 #  is licensed by Dream Multimedia GmbH.
18
19 #  This plugin is NOT free software. It is open source, you are allowed to
20 #  modify it (if you keep the license), but it may not be commercially 
21 #  distributed other than under the conditions noted above.
22 #
23 from Plugins.Plugin import PluginDescriptor
24 from Screens.Screen import Screen
25 from Components.ActionMap import ActionMap, NumberActionMap
26 from Components.Label import Label
27 from enigma import eServiceReference,  eTimer, getDesktop
28 from ServiceReference import ServiceReference
29 from Components.SystemInfo import SystemInfo
30 from Components.ParentalControl import parentalControl
31 from enigma import eServiceCenter, getBestPlayableServiceReference
32 from Components.VideoWindow import VideoWindow
33 from enigma import ePoint, eEPGCache
34 from time import localtime, time
35 from Screens.InfoBarGenerics import InfoBarShowHide, NumberZap, InfoBarPiP
36 from Screens.InfoBar import InfoBar
37
38 from Components.Sources.StaticText import StaticText
39 from Screens.MessageBox import MessageBox
40 from Screens.Standby import TryQuitMainloop
41
42 from Screens.EpgSelection import EPGSelection
43 from Screens.EventView import  EventViewEPGSelect
44 from Screens.PictureInPicture import PictureInPicture
45
46 InfoBarShowHideINIT = None
47
48 from Components.config import config, ConfigSubsection, ConfigSelection, ConfigYesNo, getConfigListEntry, configfile, ConfigPosition, ConfigText, ConfigInteger
49 from Components.ConfigList import ConfigList, ConfigListScreen
50
51 # for localized messages
52 from . import _
53
54 # PiPServiceRelation installed?
55 try:
56         from Plugins.SystemPlugins.PiPServiceRelation.plugin import getRelationDict, CONFIG_FILE
57         plugin_PiPServiceRelation_installed = True
58 except:
59         plugin_PiPServiceRelation_installed = False
60
61 config.plugins.virtualzap = ConfigSubsection()
62 config.plugins.virtualzap.mode = ConfigSelection(default="0", choices = [("0", _("as plugin in extended bar")),("1", _("with long OK press")), ("2", _("with exit button"))])
63 config.plugins.virtualzap.usepip = ConfigYesNo(default = True)
64 config.plugins.virtualzap.showpipininfobar = ConfigYesNo(default = True)
65 config.plugins.virtualzap.saveLastService = ConfigYesNo(default = False)
66 config.plugins.virtualzap.curref = ConfigText()
67 config.plugins.virtualzap.curbouquet = ConfigText()
68 config.plugins.virtualzap.exittimer =  ConfigInteger(0,limits = (0, 20))
69
70 def autostart(reason, **kwargs):
71         if config.plugins.virtualzap.mode.value != "0":
72                 # overide InfoBarShowHide
73                 global InfoBarShowHideINIT
74                 if InfoBarShowHideINIT is None:
75                         InfoBarShowHideINIT = InfoBarShowHide.__init__
76                 InfoBarShowHide.__init__ = InfoBarShowHide__init__
77                 # new method
78                 InfoBarShowHide.showVZ = showVZ
79                 InfoBarShowHide.VirtualZapCallback = VirtualZapCallback
80                 if config.plugins.virtualzap.mode.value == "2":
81                         InfoBarShowHide.newHide = newHide
82
83 def InfoBarShowHide__init__(self):
84         # initialize InfoBarShowHide with original __init__
85         InfoBarShowHideINIT(self)
86         # delete current key map --> we have to use "ok" with b-flag
87         if config.plugins.virtualzap.mode.value == "1":
88                 del self["ShowHideActions"]
89                 # initialize own actionmap with ok = b and longOK = l
90                 self["myactions"] = ActionMap( ["myShowHideActions"] ,
91                 {
92                         "toggleShow": self.toggleShow,
93                         "longOK": self.showVZ,
94                         "hide": self.hide,
95                 }, 1)
96         elif config.plugins.virtualzap.mode.value == "2":
97                 self["ShowHideActions"] = ActionMap( ["InfobarShowHideActions"] ,
98                 {
99                         "toggleShow": self.toggleShow,
100                         "hide": self.newHide,
101                 }, 1)
102
103
104 def showVZ(self):
105         from  Screens.InfoBarGenerics import InfoBarEPG
106         # check for InfoBarEPG --> only start if true
107         if isinstance(self, InfoBarEPG):
108                 # check for PiP
109                 if isinstance(self, InfoBarPiP):
110                         # check if PiP is already shown
111                         if self.pipShown():
112                                 # it is... close it!
113                                 self.showPiP()
114                 if isinstance(self, InfoBar):
115                         self.session.openWithCallback(self.VirtualZapCallback, VirtualZap, self.servicelist)
116
117 def VirtualZapCallback(self, service = None, servicePath = None):
118         if isinstance(self, InfoBarPiP):
119                 if service and servicePath:
120                         self.session.pip = self.session.instantiateDialog(PictureInPicture)
121                         self.session.pip.show()
122                         if self.session.pip.playService(service):
123                                 self.session.pipshown = True
124                                 self.session.pip.servicePath = servicePath
125                         else:
126                                 self.session.pipshown = False
127                                 del self.session.pip
128                                 self.session.openWithCallback(self.close, MessageBox, _("Could not open Picture in Picture"), MessageBox.TYPE_ERROR)
129
130 def newHide(self):
131         # remember if infobar is shown
132         visible = self.shown
133         self.hide()
134         if not visible:
135                 # infobar was not shown, start VZ
136                 self.showVZ()
137
138 def Plugins(**kwargs):
139         plist =  [PluginDescriptor(name="Virtual Zap Setup", description=_("Virtual Zap Setup"), where = [PluginDescriptor.WHERE_PLUGINMENU], icon = "plugin.png", fnc = setup)]
140         if config.plugins.virtualzap.mode.value == "0":
141                 plist.append(PluginDescriptor(name="Virtual Zap", description=_("Virtual (PiP) Zap"), where = [PluginDescriptor.WHERE_EXTENSIONSMENU],icon = "plugin.png", fnc = main))
142         elif config.plugins.virtualzap.mode.value == "1" or config.plugins.virtualzap.mode.value == "2":
143                 plist.append(PluginDescriptor(where = [PluginDescriptor.WHERE_SESSIONSTART],fnc = autostart))
144         return plist
145
146 def setup(session,**kwargs):
147         session.open(VirtualZapConfig)
148
149 def main(session,**kwargs):
150         session.open(VirtualZap, kwargs["servicelist"])
151
152 class VirtualZap(Screen):
153         sz_w = getDesktop(0).size().width()
154
155         #
156         # VirtualZap or VirtualZapNoPiP
157         #
158
159         if SystemInfo.get("NumVideoDecoders", 1) > 1 and config.plugins.virtualzap.usepip.value and config.plugins.virtualzap.showpipininfobar.value:
160                 # use PiP in Infobar
161                 if sz_w == 1280:
162                         skin = """
163                                 <screen backgroundColor="#101214" flags="wfNoBorder" name="VirtualZap" position="0,505" size="1280,220" title="Virtual Zap">
164                                         <ePixmap alphatest="off" pixmap="/usr/lib/enigma2/python/Plugins/Extensions/VirtualZap/hd.png" position="0,0" size="1280,220" zPosition="0"/>
165                                         <widget backgroundColor="transparent" name="video" position="60,50" size="214,120" zPosition="1"/>
166                                         <widget backgroundColor="#101214" font="Regular;26" halign="left" name="NowChannel" position="305,60" size="887,32" transparent="1" zPosition="2"/>
167                                         <widget backgroundColor="#101214" font="Regular;24" foregroundColor="#fcc000" halign="left" name="NowEPG" position="305,105" size="600,28" transparent="1" zPosition="2"/>
168                                         <widget backgroundColor="#101214" font="Regular;24" halign="left" name="NextEPG" position="305,140" size="600,28" transparent="1" zPosition="2"/>
169                                         <widget backgroundColor="#101214" font="Regular;24" foregroundColor="#fcc000" halign="right" name="NowTime" position="1070,105" size="124,28" transparent="1" zPosition="2"/>
170                                         <widget backgroundColor="#101214" font="Regular;24" halign="right" name="NextTime" position="1070,140" size="124,28" transparent="1" zPosition="2"/>
171                                 </screen>"""
172                 elif sz_w == 1024:
173                         skin = """
174                                 <screen backgroundColor="#101214" flags="wfNoBorder" name="VirtualZap" position="0,420" size="1024,176" title="Virtual Zap">
175                                         <ePixmap alphatest="off" pixmap="/usr/lib/enigma2/python/Plugins/Extensions/VirtualZap/sd.png" position="0,0" size="1024,176" zPosition="0"/>
176                                         <widget backgroundColor="transparent" name="video" position="50,20" size="164,92" zPosition="1"/>
177                                         <widget backgroundColor="#101214" font="Regular;22" halign="left" name="NowChannel" position="230,25" size="741,30" transparent="1" zPosition="2"/>
178                                         <widget backgroundColor="#101214" font="Regular;20" foregroundColor="#fcc000" halign="left" name="NowEPG" position="230,55" size="600,25" transparent="1" zPosition="2"/>
179                                         <widget backgroundColor="#101214" font="Regular;20" halign="left" name="NextEPG" position="230,80" size="600,25" transparent="1" zPosition="2"/>
180                                         <widget backgroundColor="#101214" font="Regular;20" foregroundColor="#fcc000" halign="right" name="NowTime" position="850,55" size="124,25" transparent="1" zPosition="2"/>
181                                         <widget backgroundColor="#101214" font="Regular;20" halign="right" name="NextTime" position="850,80" size="124,25" transparent="1" zPosition="2"/>
182                                 </screen>"""
183                 else:
184                         skin = """
185                                 <screen backgroundColor="#101214" flags="wfNoBorder" name="VirtualZap" position="0,420" size="720,176" title="Virtual Zap">
186                                         <ePixmap alphatest="off" pixmap="/usr/lib/enigma2/python/Plugins/Extensions/VirtualZap/sd.png" position="0,0" size="720,176" zPosition="0"/>
187                                         <widget backgroundColor="transparent" name="video" position="50,25" size="130,73" zPosition="1"/>
188                                         <widget backgroundColor="#101214" font="Regular;22" halign="left" name="NowChannel" position="190,25" size="480,30" transparent="1" zPosition="2"/>
189                                         <widget backgroundColor="#101214" font="Regular;20" foregroundColor="#fcc000" halign="left" name="NowEPG" position="190,55" size="360,25" transparent="1" zPosition="2"/>
190                                         <widget backgroundColor="#101214" font="Regular;20" halign="left" name="NextEPG" position="190,80" size="360,25" transparent="1" zPosition="2"/>
191                                         <widget backgroundColor="#101214" font="Regular;20" foregroundColor="#fcc000" halign="right" name="NowTime" position="550,55" size="120,25" transparent="1" zPosition="2"/>
192                                         <widget backgroundColor="#101214" font="Regular;20" halign="right" name="NextTime" position="550,80" size="120,25" transparent="1" zPosition="2"/>
193                                 </screen>"""
194         else:
195                 if SystemInfo.get("NumVideoDecoders", 1) > 1 and config.plugins.virtualzap.usepip.value and not config.plugins.virtualzap.showpipininfobar.value:
196                         # use standard PiP
197                         config.av.pip = ConfigPosition(default=[0, 0, 0, 0], args = (719, 567, 720, 568))
198                         x = config.av.pip.value[0]
199                         y = config.av.pip.value[1]
200                         w = config.av.pip.value[2]
201                         h = config.av.pip.value[3]
202
203                 else:
204                         # no PiP
205                         x = 0
206                         y = 0
207                         w = 0
208                         h = 0
209
210                 if sz_w == 1280:
211                         skin = """
212                                 <screen backgroundColor="transparent" flags="wfNoBorder" name="VirtualZapNoPiP" position="0,0" size="1280,720" title="Virtual Zap">
213                                         <widget backgroundColor="transparent" name="video" position="%d,%d" size="%d,%d" zPosition="1"/>
214                                         <ePixmap alphatest="off" pixmap="/usr/lib/enigma2/python/Plugins/Extensions/VirtualZap/hd.png" position="0,505" size="1280,220" zPosition="0"/>
215                                         <widget backgroundColor="#101214" font="Regular;26" halign="center" name="NowChannel" position="140,565" size="1000,32" transparent="1" zPosition="2"/>
216                                         <widget backgroundColor="#101214" font="Regular;24" foregroundColor="#fcc000" halign="left" name="NowEPG" position="140,610" size="860,28" transparent="1" zPosition="2"/>
217                                         <widget backgroundColor="#101214" font="Regular;24" halign="left" name="NextEPG" position="140,645" size="860,28" transparent="1" zPosition="2"/>
218                                         <widget backgroundColor="#101214" font="Regular;24" foregroundColor="#fcc000" halign="right" name="NowTime" position="1015,610" size="124,28" transparent="1" zPosition="2"/>
219                                         <widget backgroundColor="#101214" font="Regular;24" halign="right" name="NextTime" position="1015,645" size="124,28" transparent="1" zPosition="2"/>
220                                 </screen>""" % (x,y,w,h)
221                 elif sz_w == 1024:
222                         skin = """
223                                 <screen backgroundColor="transparent" flags="wfNoBorder" name="VirtualZapNoPiP" position="0,0" size="1024,576" title="Virtual Zap">
224                                         <widget backgroundColor="transparent" name="video" position="%d,%d" size="%d,%d" zPosition="1"/>
225                                         <ePixmap alphatest="off" pixmap="/usr/lib/enigma2/python/Plugins/Extensions/VirtualZap/sd.png" position="0,420" size="1024,176" zPosition="0"/>
226                                         <widget backgroundColor="#101214" font="Regular;22" halign="center" name="NowChannel" position="100,445" size="824,30" transparent="1" zPosition="2"/>
227                                         <widget backgroundColor="#101214" font="Regular;20" foregroundColor="#fcc000" halign="left" name="NowEPG" position="100,475" size="700,25" transparent="1" zPosition="2"/>
228                                         <widget backgroundColor="#101214" font="Regular;20" halign="left" name="NextEPG" position="100,500" size="700,25" transparent="1" zPosition="2"/>
229                                         <widget backgroundColor="#101214" font="Regular;20" foregroundColor="#fcc000" halign="right" name="NowTime" position="800,475" size="124,25" transparent="1" zPosition="2"/>
230                                         <widget backgroundColor="#101214" font="Regular;20" halign="right" name="NextTime" position="800,500" size="124,25" transparent="1" zPosition="2"/>
231                                 </screen>""" % (x,y,w,h)
232                 else:
233
234                         skin = """
235                                 <screen backgroundColor="transparent" flags="wfNoBorder" name="VirtualZapNoPiP" position="0,0" size="720,576" title="Virtual Zap">
236                                         <widget backgroundColor="transparent" name="video" position="%d,%d" size="%d,%d" zPosition="1"/>
237                                         <ePixmap alphatest="off" pixmap="/usr/lib/enigma2/python/Plugins/Extensions/VirtualZap/sd.png" position="0,420" size="720,176" zPosition="0"/>
238                                         <widget backgroundColor="#101214" font="Regular;22" halign="center" name="NowChannel" position="50,445" size="620,30" transparent="1" zPosition="2"/>
239                                         <widget backgroundColor="#101214" font="Regular;20" foregroundColor="#fcc000" halign="left" name="NowEPG" position="50,475" size="500,25" transparent="1" zPosition="2"/>
240                                         <widget backgroundColor="#101214" font="Regular;20" halign="left" name="NextEPG" position="50,500" size="500,25" transparent="1" zPosition="2"/>
241                                         <widget backgroundColor="#101214" font="Regular;20" foregroundColor="#fcc000" halign="right" name="NowTime" position="550,475" size="120,25" transparent="1" zPosition="2"/>
242                                         <widget backgroundColor="#101214" font="Regular;20" halign="right" name="NextTime" position="550,500" size="120,25" transparent="1" zPosition="2"/>
243                                 </screen>"""  % (x,y,w,h)
244
245         def __init__(self, session, servicelist = None):
246                 Screen.__init__(self, session)
247                 self.session = session
248                 if SystemInfo.get("NumVideoDecoders", 1) > 1 and config.plugins.virtualzap.usepip.value and config.plugins.virtualzap.showpipininfobar.value:
249                         self.skinName = "VirtualZap"
250                         self.pipAvailable = True
251                 else:
252                         self.skinName = "VirtualZapNoPiP"
253                         self.pipAvailable =  (SystemInfo.get("NumVideoDecoders", 1) > 1)  and config.plugins.virtualzap.usepip.value and not config.plugins.virtualzap.showpipininfobar.value
254                 self.epgcache = eEPGCache.getInstance()
255                 self.CheckForEPG = eTimer()
256                 self.CheckForEPG.callback.append(self.CheckItNow)
257                 self["NowChannel"] = Label()
258                 self["NowEPG"] = Label()
259                 self["NextEPG"] = Label()
260                 self["NowTime"] = Label()
261                 self["NextTime"] = Label()
262                 self["actions"] = ActionMap(["OkCancelActions", "DirectionActions", "ChannelSelectBaseActions", "ChannelSelectEPGActions", "ColorActions"], 
263                 {
264                         "ok": self.ok, 
265                         "cancel": self.closing,
266                         "right": self.nextService,
267                         "left": self.prevService,
268                         "nextBouquet": self.showFavourites,
269                         "prevBouquet": self.openServiceList,
270                         "showEPGList": self.openEventView,
271                         "blue": self.standardPiP,
272                         "yellow": self.switchAndStandardPiP,
273                         "down": self.switchChannelDown,
274                         "up": self.switchChannelUp,
275                 },-2)
276                 self["actions2"] = NumberActionMap(["NumberActions"],
277                 {
278                         "0": self.swap,
279                         "1": self.keyNumberGlobal,
280                         "2": self.keyNumberGlobal,
281                         "3": self.keyNumberGlobal,
282                         "4": self.keyNumberGlobal,
283                         "5": self.keyNumberGlobal,
284                         "6": self.keyNumberGlobal,
285                         "7": self.keyNumberGlobal,
286                         "8": self.keyNumberGlobal,
287                         "9": self.keyNumberGlobal,
288                 }, -1)
289                 self.onLayoutFinish.append(self.onLayoutReady)
290                 # PiP
291                 if self.pipAvailable:
292                         # activate PiP support
293                         if config.plugins.virtualzap.usepip.value and not config.plugins.virtualzap.showpipininfobar.value:
294                                 # activate standard PiP
295                                 self["video"] = VideoWindow()
296                         else:
297                                 # show PiP in Infobar
298                                 self["video"] = VideoWindow(fb_width = getDesktop(0).size().width(), fb_height = getDesktop(0).size().height())
299                         self.currentPiP = ""
300                 else:
301                         # no PiP
302                         self["video"] = Label()
303                 # this is the servicelist from ChannelSelectionBase
304                 self.servicelist = servicelist
305                 # save orig. method of zap in servicelist
306                 self.servicelist_orig_zap = self.servicelist.zap 
307                 # when displaying ChannelSelection, do not zap when pressing "ok", so new method is needed      
308                 self.servicelist.zap = self.servicelist_overwrite_zap
309                 # overwrite the actionmap of ChannelSelection
310                 self.servicelist["actions"] = ActionMap(["OkCancelActions"],
311                         {
312                                 "cancel": self.cancelChannelSelection,
313                                 "ok": self.servicelist.channelSelected,
314                         })
315                 # temp. vars, needed when pressing cancel in ChannelSelection
316                 self.curSelectedRef = None
317                 self.curSelectedBouquet = None
318                 # needed, because if we won't zap, we have to go back to the current bouquet and service
319                 self.curRef = ServiceReference(self.servicelist.getCurrentSelection())
320                 self.curBouquet = self.servicelist.getRoot()
321                 # start with last used service
322                 if config.plugins.virtualzap.saveLastService.value:
323                         # get service and bouquet ref
324                         ref = eServiceReference(config.plugins.virtualzap.curref.value)
325                         bouquet = eServiceReference(config.plugins.virtualzap.curbouquet.value)
326                         if ref.valid() and bouquet.valid():
327                                 # select bouquet and ref in servicelist
328                                 self.setServicelistSelection(bouquet, ref)
329                 # prepare exitTimer
330                 self.exitTimer = eTimer()
331                 self.exitTimer.timeout.get().append(self.standardPiP)
332                 # reverse changes of ChannelSelection when closing plugin
333                 self.onClose.append(self.__onClose)
334                 # if PiPServiceRelation is installed, get relation dict
335                 if plugin_PiPServiceRelation_installed:
336                         self.pipServiceRelation = getRelationDict()
337                 else:
338                         self.pipServiceRelation = {}
339
340         def onLayoutReady(self):
341                 self.updateInfos()
342
343         def resetExitTimer(self):
344                 # if enabled, run exit timer
345                 if config.plugins.virtualzap.exittimer.value != 0:
346                         if self.exitTimer.isActive():
347                                 self.exitTimer.stop()
348                         self.exitTimer.start(config.plugins.virtualzap.exittimer.value * 1000)
349
350         def nextService(self):
351                 # get next service
352                 if self.servicelist.inBouquet():
353                         prev = self.servicelist.getCurrentSelection()
354                         if prev:
355                                 prev = prev.toString()
356                                 while True:
357                                         if config.usage.quickzap_bouquet_change.value and self.servicelist.atEnd():
358                                                 self.servicelist.nextBouquet()
359                                         else:
360                                                 self.servicelist.moveDown()
361                                         cur = self.servicelist.getCurrentSelection()
362                                         if not cur or (not (cur.flags & 64)) or cur.toString() == prev:
363                                                 break
364                 else:
365                         self.servicelist.moveDown()
366                 if self.isPlayable():
367                         self.updateInfos()
368                 else:
369                         self.nextService()
370
371         def prevService(self):
372                 # get previous service
373                 if self.servicelist.inBouquet():
374                         prev = self.servicelist.getCurrentSelection()
375                         if prev:
376                                 prev = prev.toString()
377                                 while True:
378                                         if config.usage.quickzap_bouquet_change.value:
379                                                 if self.servicelist.atBegin():
380                                                         self.servicelist.prevBouquet()
381                                         self.servicelist.moveUp()
382                                         cur = self.servicelist.getCurrentSelection()
383                                         if not cur or (not (cur.flags & 64)) or cur.toString() == prev:
384                                                 break
385                 else:
386                         self.servicelist.moveUp()
387                 if self.isPlayable():
388                         self.updateInfos()
389                 else:
390                         self.prevService()
391
392         def isPlayable(self):
393                 # check if service is playable
394                 current = ServiceReference(self.servicelist.getCurrentSelection())
395                 return not (current.ref.flags & (eServiceReference.isMarker|eServiceReference.isDirectory))
396
397
398         def nextBouquet(self):
399                 # next bouquet with first service
400                 if config.usage.multibouquet.value:
401                         self.servicelist.nextBouquet()
402                 self.updateInfos()
403
404         def prevBouquet(self):
405                 # previous bouquet with first service
406                 if config.usage.multibouquet.value:
407                         self.servicelist.prevBouquet()
408                 self.updateInfos()
409
410
411         def updateInfos(self):
412                 self.resetExitTimer()
413                 # update data
414                 current = ServiceReference(self.servicelist.getCurrentSelection())
415                 self["NowChannel"].setText(current.getServiceName())
416                 nowepg, nowtimedisplay = self.getEPGNowNext(current.ref,0)
417                 nextepg, nexttimedisplay = self.getEPGNowNext(current.ref,1)
418                 self["NowEPG"].setText(nowepg)
419                 self["NextEPG"].setText(nextepg)
420                 self["NowTime"].setText(nowtimedisplay)
421                 self["NextTime"].setText(nexttimedisplay)
422                 if not nowepg:
423                         # no epg found --> let's try it again, but only if PiP is activated
424                         if self.pipAvailable:
425                                 self.CheckForEPG.start(3000, True)
426                 if self.pipAvailable:
427                         # play in videowindow
428                         self.playService(current.ref)
429
430         def getEPGNowNext(self,ref, modus):
431                 # get now || next event
432                 if self.epgcache is not None:
433                         event = self.epgcache.lookupEvent(['IBDCTSERNX', (ref.toString(), modus, -1)])
434                         if event:
435                                 if event[0][4]:
436                                         t = localtime(event[0][1])
437                                         duration = event[0][2]
438                                         if modus == 0:
439                                                 timedisplay = "+%d min" % (((event[0][1] + duration) - time()) / 60)
440                                         elif modus == 1:
441                                                 timedisplay = "%d min" %  (duration / 60)
442                                         return "%02d:%02d %s" % (t[3],t[4], event[0][4]), timedisplay
443                                 else:
444                                         return "", ""
445                 return "", ""
446
447         def openSingleServiceEPG(self):
448                 # show EPGList
449                 current = ServiceReference(self.servicelist.getCurrentSelection())
450                 self.session.open(EPGSelection, current.ref)
451
452         def openEventView(self):
453                 # stop exitTimer
454                 if self.exitTimer.isActive():
455                         self.exitTimer.stop()
456                 # show EPG Event
457                 epglist = [ ]
458                 self.epglist = epglist
459                 service = ServiceReference(self.servicelist.getCurrentSelection())
460                 ref = service.ref
461                 evt = self.epgcache.lookupEventTime(ref, -1)
462                 if evt:
463                         epglist.append(evt)
464                 evt = self.epgcache.lookupEventTime(ref, -1, 1)
465                 if evt:
466                         epglist.append(evt)
467                 if epglist:
468                         self.session.openWithCallback(self.EventViewEPGSelectCallBack, EventViewEPGSelect, epglist[0], service, self.eventViewCallback, self.openSingleServiceEPG, self.openMultiServiceEPG, self.openSimilarList)
469
470         def EventViewEPGSelectCallBack(self):
471                 # if enabled, start ExitTimer
472                 self.resetExitTimer()
473
474         def eventViewCallback(self, setEvent, setService, val):
475                 epglist = self.epglist
476                 if len(epglist) > 1:
477                         tmp = epglist[0]
478                         epglist[0] = epglist[1]
479                         epglist[1] = tmp
480                         setEvent(epglist[0])
481
482         def openMultiServiceEPG(self):
483                 # not supported
484                 pass
485
486         def openSimilarList(self, eventid, refstr):
487                 self.session.open(EPGSelection, refstr, None, eventid)
488
489         def setServicelistSelection(self, bouquet, service):
490                 # we need to select the old service with bouquet
491                 if self.servicelist.getRoot() != bouquet: #already in correct bouquet?
492                         self.servicelist.clearPath()
493                         self.servicelist.enterPath(self.servicelist.bouquet_root)
494                         self.servicelist.enterPath(bouquet)
495                 self.servicelist.setCurrentSelection(service) #select the service in servicelist
496
497         def closing(self):
498                 if self.pipAvailable:
499                         self.pipservice = None
500                 # save last used service and bouqet ref
501                 self.saveLastService(self.servicelist.getCurrentSelection().toString(), self.servicelist.getRoot().toString())
502                 # select running service in servicelist again
503                 self.setServicelistSelection(self.curBouquet, self.curRef.ref)
504                 self.close()
505                         
506         def ok(self):
507                 # we have to close PiP first, otherwise the service-display is freezed
508                 if self.pipAvailable:
509                         self.pipservice = None
510                 # play selected service and close virtualzap
511                 self.servicelist_orig_zap()
512                 # save last used service and bouqet ref
513                 self.saveLastService(self.curRef.ref.toString(), self.curBouquet.toString())
514                 self.close()
515
516         def standardPiP(self):
517                 if not self.pipAvailable:
518                         return
519                 # close PiP
520                 self.pipservice = None
521                 # save current selected service for standard PiP
522                 service = ServiceReference(self.servicelist.getCurrentSelection()).ref
523                 servicePath = self.servicelist.getCurrentServicePath() # same bug as in channelselection
524                 # save last used service and bouqet ref
525                 self.saveLastService(self.servicelist.getCurrentSelection().toString(), self.servicelist.getRoot().toString())
526                 # select running service in servicelist
527                 self.setServicelistSelection(self.curBouquet, self.curRef.ref)
528                 # close VZ and start standard PiP
529                 self.close(service, servicePath)
530
531         def switchAndStandardPiP(self):
532                 if not self.pipAvailable:
533                         return
534                 self.pipservice = None
535                 # save current selected servicePath for standard PiP
536                 servicePath = self.servicelist.getCurrentServicePath()
537                 # save last used service and bouqet ref
538                 self.saveLastService(self.curRef.ref.toString(), self.curBouquet.toString())
539                 # play selected service
540                 self.servicelist_orig_zap()
541                 # close VZ and start standard PiP
542                 self.close(self.curRef.ref, servicePath)
543
544         def saveLastService(self, ref, bouquet):
545                 if config.plugins.virtualzap.saveLastService.value:
546                         # save last VZ service
547                         config.plugins.virtualzap.curref.value = ref
548                         config.plugins.virtualzap.curbouquet.value = bouquet
549                         config.plugins.virtualzap.save()
550                 # stop exitTimer
551                 if self.exitTimer.isActive():
552                         self.exitTimer.stop()
553
554         def CheckItNow(self):
555                 self.CheckForEPG.stop()
556                 self.updateInfos()
557
558         # if available play service in PiP 
559         def playService(self, service):
560                 if parentalControl.getProtectionLevel(service.toCompareString()) == -1 or (parentalControl.configInitialized and parentalControl.sessionPinCached and parentalControl.sessionPinCachedValue): # check parentalControl, only play a protected service when Pin-Cache is activated and still valid
561                         current_service = service
562                         n_service = self.pipServiceRelation.get(service.toString(),None) # PiPServiceRelation
563                         if n_service is not None:
564                                 service = eServiceReference(n_service)
565                         if service and (service.flags & eServiceReference.isGroup):
566                                 ref = getBestPlayableServiceReference(service, eServiceReference())
567                         else:
568                                 ref = service
569                         if ref and ref.toString() != self.currentPiP:
570                                 self.pipservice = eServiceCenter.getInstance().play(ref)
571                                 if self.pipservice and not self.pipservice.setTarget(1):
572                                         self.pipservice.start()
573                                         self.currentPiP = current_service.toString()
574                                 else:
575                                         self.pipservice = None
576                                         self.currentPiP = ""
577                 else:
578                         self.pipservice = None
579                         self.currentPiP = ""
580
581
582         # switch with numbers
583         def keyNumberGlobal(self, number):
584                 self.session.openWithCallback(self.numberEntered, NumberZap, number)
585
586         def numberEntered(self, retval):
587                 if retval > 0:
588                         self.zapToNumber(retval)
589
590         def searchNumberHelper(self, serviceHandler, num, bouquet):
591                 servicelist = serviceHandler.list(bouquet)
592                 if not servicelist is None:
593                         while num:
594                                 serviceIterator = servicelist.getNext()
595                                 if not serviceIterator.valid(): #check end of list
596                                         break
597                                 playable = not (serviceIterator.flags & (eServiceReference.isMarker|eServiceReference.isDirectory))
598                                 if playable:
599                                         num -= 1;
600                         if not num: #found service with searched number ?
601                                 return serviceIterator, 0
602                 return None, num
603
604         def zapToNumber(self, number):
605                 bouquet = self.servicelist.bouquet_root
606                 service = None
607                 serviceHandler = eServiceCenter.getInstance()
608                 bouquetlist = serviceHandler.list(bouquet)
609                 if not bouquetlist is None:
610                         while number:
611                                 bouquet = bouquetlist.getNext()
612                                 if not bouquet.valid(): #check end of list
613                                         break
614                                 if bouquet.flags & eServiceReference.isDirectory:
615                                         service, number = self.searchNumberHelper(serviceHandler, number, bouquet)
616                 if not service is None:
617                         self.setServicelistSelection(bouquet, service)
618                 # update infos, no matter if service is none or not
619                 self.updateInfos()
620
621         def swap(self, number):
622                 # save old values for selecting it in servicelist after zapping
623                 currentRef = self.curRef
624                 currentBouquet = self.curBouquet
625                 # we have to close PiP first, otherwise the service-display is freezed
626                 if self.pipAvailable:
627                         self.pipservice = None
628                 # zap and set new values for the new reference and bouquet
629                 self.servicelist_orig_zap()
630                 self.curRef = ServiceReference(self.servicelist.getCurrentSelection())
631                 self.curBouquet = self.servicelist.getRoot()
632                 # select old values in servicelist
633                 self.setServicelistSelection(currentBouquet, currentRef.ref)
634                 # play old service in PiP
635                 self.updateInfos()
636
637         # ChannelSelection Support
638         def prepareChannelSelectionDisplay(self):
639                 # stop exitTimer
640                 if self.exitTimer.isActive():
641                         self.exitTimer.stop()
642                 # turn off PiP
643                 if self.pipAvailable:
644                         self.pipservice = None
645                 # save current ref and bouquet ( for cancel )
646                 self.curSelectedRef = eServiceReference(self.servicelist.getCurrentSelection().toString())
647                 self.curSelectedBouquet = self.servicelist.getRoot()
648
649         def cancelChannelSelection(self):
650                 # select service and bouquet selected before started ChannelSelection
651                 if self.servicelist.revertMode is None:
652                         ref = self.curSelectedRef
653                         bouquet = self.curSelectedBouquet
654                         if ref.valid() and bouquet.valid():
655                                 # select bouquet and ref in servicelist
656                                 self.setServicelistSelection(bouquet, ref)
657                 # close ChannelSelection
658                 self.servicelist.revertMode = None
659                 self.servicelist.close(None)
660
661                 # clean up
662                 self.curSelectedRef = None
663                 self.curSelectedBouquet = None
664                 # display VZ data
665                 self.servicelist_overwrite_zap()
666
667         def switchChannelDown(self):
668                 self.prepareChannelSelectionDisplay()
669                 self.servicelist.moveDown()
670                 # show ChannelSelection
671                 self.session.execDialog(self.servicelist)
672
673         def switchChannelUp(self):
674                 self.prepareChannelSelectionDisplay()
675                 self.servicelist.moveUp()
676                 # show ChannelSelection
677                 self.session.execDialog(self.servicelist)
678
679         def showFavourites(self):
680                 self.prepareChannelSelectionDisplay()
681                 self.servicelist.showFavourites()
682                 # show ChannelSelection
683                 self.session.execDialog(self.servicelist)
684
685         def openServiceList(self):
686                 self.prepareChannelSelectionDisplay()
687                 # show ChannelSelection
688                 self.session.execDialog(self.servicelist)
689
690         def servicelist_overwrite_zap(self, *args, **kwargs):
691                 # we do not really want to zap to the service, just display data for VZ
692                 self.currentPiP = ""
693                 if self.isPlayable():
694                         self.updateInfos()
695
696         def __onClose(self):
697                 # reverse changes of ChannelSelection 
698                 self.servicelist.zap = self.servicelist_orig_zap
699                 self.servicelist["actions"] = ActionMap(["OkCancelActions", "TvRadioActions"],
700                         {
701                                 "cancel": self.servicelist.cancel,
702                                 "ok": self.servicelist.channelSelected,
703                                 "keyRadio": self.servicelist.setModeRadio,
704                                 "keyTV": self.servicelist.setModeTv,
705                         })
706
707 class VirtualZapConfig(Screen, ConfigListScreen):
708
709         skin = """
710                 <screen position="center,center" size="560,180" title="Virtual Zap Config" >
711                         <ePixmap pixmap="skin_default/buttons/red.png" position="0,0" zPosition="0" size="140,40" transparent="1" alphatest="on" />
712                         <ePixmap pixmap="skin_default/buttons/green.png" position="140,0" zPosition="0" size="140,40" transparent="1" alphatest="on" />
713                         <ePixmap pixmap="skin_default/buttons/yellow.png" position="280,0" zPosition="0" size="140,40" transparent="1" alphatest="on" />
714                         <ePixmap pixmap="skin_default/buttons/blue.png" position="420,0" zPosition="0" size="140,40" transparent="1" alphatest="on" />
715                         <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" />
716                         <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" />
717                         <widget name="config" position="20,50" size="520,330" scrollbarMode="showOnDemand" />
718                 </screen>"""
719
720         def __init__(self, session):
721                 Screen.__init__(self, session)
722                 self["key_red"] = StaticText(_("Cancel"))
723                 self["key_green"] = StaticText(_("OK"))
724                 self.list = [ ]
725                 self.list.append(getConfigListEntry(_("Usage"), config.plugins.virtualzap.mode))
726                 if SystemInfo.get("NumVideoDecoders", 1) > 1:
727                         self.list.append(getConfigListEntry(_("Use PiP"), config.plugins.virtualzap.usepip))
728                         self.list.append(getConfigListEntry(_("Show PiP in Infobar"), config.plugins.virtualzap.showpipininfobar))
729                         self.list.append(getConfigListEntry(_("Start standard PiP after x secs (0 = disabled)"), config.plugins.virtualzap.exittimer))
730                 self.list.append(getConfigListEntry(_("Remember last service"), config.plugins.virtualzap.saveLastService))
731                 ConfigListScreen.__init__(self, self.list, session)
732                 self["setupActions"] = ActionMap(["SetupActions", "ColorActions"],
733                 {
734                         "green": self.keySave,
735                         "cancel": self.keyClose,
736                 }, -2)
737
738         def keySave(self):
739                 for x in self["config"].list:
740                         x[1].save()
741                 configfile.save()
742                 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)
743                 restartbox.setTitle(_("Restart GUI now?"))
744                 
745
746         def keyClose(self):
747                 for x in self["config"].list:
748                         x[1].cancel()
749                 self.close()
750
751         def restartGUI(self, answer):
752                 if answer is True:
753                         self.session.open(TryQuitMainloop, 3)
754                 else:
755                         self.close()
756