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