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