[SystemInfo] Add PVRSupport.
[vuplus_dvbapp] / lib / python / Screens / InfoBarGenerics.py
1 from ChannelSelection import ChannelSelection, BouquetSelector, SilentBouquetSelector
2
3 from Components.ActionMap import ActionMap, HelpableActionMap
4 from Components.ActionMap import NumberActionMap
5 from Components.Harddisk import harddiskmanager
6 from Components.Input import Input
7 from Components.Label import Label
8 from Components.PluginComponent import plugins
9 from Components.ServiceEventTracker import ServiceEventTracker
10 from Components.Sources.Boolean import Boolean
11 from Components.config import config, ConfigBoolean, ConfigClock
12 from Components.SystemInfo import SystemInfo
13 from Components.UsageConfig import preferredInstantRecordPath, defaultMoviePath
14 from EpgSelection import EPGSelection
15 from Plugins.Plugin import PluginDescriptor
16
17 from Screen import Screen
18 from Screens.ChoiceBox import ChoiceBox
19 from Screens.Dish import Dish
20 from Screens.EventView import EventViewEPGSelect, EventViewSimple
21 from Screens.InputBox import InputBox
22 from Screens.MessageBox import MessageBox
23 from Screens.MinuteInput import MinuteInput
24 from Screens.TimerSelection import TimerSelection
25 from Screens.PictureInPicture import PictureInPicture
26 from Screens.SubtitleDisplay import SubtitleDisplay
27 from Screens.RdsDisplay import RdsInfoDisplay, RassInteractive
28 from Screens.TimeDateInput import TimeDateInput
29 from Screens.UnhandledKey import UnhandledKey
30 from ServiceReference import ServiceReference
31
32 from Tools import Notifications
33 from Tools.Directories import fileExists
34
35 from enigma import eTimer, eServiceCenter, eDVBServicePMTHandler, iServiceInformation, \
36         iPlayableService, eServiceReference, eEPGCache, eActionMap
37
38 from time import time, localtime, strftime
39 from os import stat as os_stat, system as os_system
40 from bisect import insort
41
42 from RecordTimer import RecordTimerEntry, RecordTimer, findSafeRecordPath
43
44 # hack alert!
45 from Menu import MainMenu, mdom
46
47 class InfoBarDish:
48         def __init__(self):
49                 self.dishDialog = self.session.instantiateDialog(Dish)
50                 self.dishDialog.setAnimationMode(0)
51
52 class InfoBarUnhandledKey:
53         def __init__(self):
54                 self.unhandledKeyDialog = self.session.instantiateDialog(UnhandledKey)
55                 self.unhandledKeyDialog.setAnimationMode(0)
56                 self.hideUnhandledKeySymbolTimer = eTimer()
57                 self.hideUnhandledKeySymbolTimer.callback.append(self.unhandledKeyDialog.hide)
58                 self.checkUnusedTimer = eTimer()
59                 self.checkUnusedTimer.callback.append(self.checkUnused)
60                 self.onLayoutFinish.append(self.unhandledKeyDialog.hide)
61                 eActionMap.getInstance().bindAction('', -0x7FFFFFFF, self.actionA) #highest prio
62                 eActionMap.getInstance().bindAction('', 0x7FFFFFFF, self.actionB) #lowest prio
63                 self.flags = (1<<1);
64                 self.uflags = 0;
65
66         #this function is called on every keypress!
67         def actionA(self, key, flag):
68                 if flag != 4:
69                         if self.flags & (1<<1):
70                                 self.flags = self.uflags = 0
71                         self.flags |= (1<<flag)
72                         if flag == 1: # break
73                                 self.checkUnusedTimer.start(0, True)
74                 return 0
75
76         #this function is only called when no other action has handled this key
77         def actionB(self, key, flag):
78                 if flag != 4:
79                         self.uflags |= (1<<flag)
80
81         def checkUnused(self):
82                 if self.flags == self.uflags:
83                         self.unhandledKeyDialog.show()
84                         self.hideUnhandledKeySymbolTimer.start(2000, True)
85
86 class InfoBarShowHide:
87         """ InfoBar show/hide control, accepts toggleShow and hide actions, might start
88         fancy animations. """
89         STATE_HIDDEN = 0
90         STATE_HIDING = 1
91         STATE_SHOWING = 2
92         STATE_SHOWN = 3
93
94         def __init__(self):
95                 self["ShowHideActions"] = ActionMap( ["InfobarShowHideActions"] ,
96                         {
97                                 "toggleShow": self.toggleShow,
98                                 "hide": self.hide,
99                         }, 1) # lower prio to make it possible to override ok and cancel..
100
101                 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
102                         {
103                                 iPlayableService.evStart: self.serviceStarted,
104                         })
105
106                 self.__state = self.STATE_SHOWN
107                 self.__locked = 0
108
109                 self.hideTimer = eTimer()
110                 self.hideTimer.callback.append(self.doTimerHide)
111                 self.hideTimer.start(5000, True)
112
113                 self.onShow.append(self.__onShow)
114                 self.onHide.append(self.__onHide)
115
116         def serviceStarted(self):
117                 if self.execing:
118                         if config.usage.show_infobar_on_zap.value:
119                                 self.doShow()
120
121         def __onShow(self):
122                 self.__state = self.STATE_SHOWN
123                 self.startHideTimer()
124
125         def startHideTimer(self):
126                 if self.__state == self.STATE_SHOWN and not self.__locked:
127                         idx = config.usage.infobar_timeout.index
128                         if idx:
129                                 self.hideTimer.start(idx*1000, True)
130
131         def __onHide(self):
132                 self.__state = self.STATE_HIDDEN
133
134         def doShow(self):
135                 self.show()
136                 self.startHideTimer()
137
138         def doTimerHide(self):
139                 self.hideTimer.stop()
140                 if self.__state == self.STATE_SHOWN:
141                         self.hide()
142
143         def toggleShow(self):
144                 if self.__state == self.STATE_SHOWN:
145                         self.hide()
146                         self.hideTimer.stop()
147                 elif self.__state == self.STATE_HIDDEN:
148                         self.show()
149
150         def lockShow(self):
151                 self.__locked = self.__locked + 1
152                 if self.execing:
153                         self.show()
154                         self.hideTimer.stop()
155
156         def unlockShow(self):
157                 self.__locked = self.__locked - 1
158                 if self.execing:
159                         self.startHideTimer()
160
161 #       def startShow(self):
162 #               self.instance.m_animation.startMoveAnimation(ePoint(0, 600), ePoint(0, 380), 100)
163 #               self.__state = self.STATE_SHOWN
164 #
165 #       def startHide(self):
166 #               self.instance.m_animation.startMoveAnimation(ePoint(0, 380), ePoint(0, 600), 100)
167 #               self.__state = self.STATE_HIDDEN
168
169 class NumberZap(Screen):
170         def quit(self):
171                 self.Timer.stop()
172                 self.close(0)
173
174         def keyOK(self):
175                 self.Timer.stop()
176                 self.close(int(self["number"].getText()))
177
178         def keyNumberGlobal(self, number):
179                 self.Timer.start(3000, True)            #reset timer
180                 self.field = self.field + str(number)
181                 self["number"].setText(self.field)
182                 if len(self.field) >= 4:
183                         self.keyOK()
184
185         def __init__(self, session, number):
186                 Screen.__init__(self, session)
187                 self.field = str(number)
188
189                 self["channel"] = Label(_("Channel:"))
190
191                 self["number"] = Label(self.field)
192
193                 self["actions"] = NumberActionMap( [ "SetupActions" ],
194                         {
195                                 "cancel": self.quit,
196                                 "ok": self.keyOK,
197                                 "1": self.keyNumberGlobal,
198                                 "2": self.keyNumberGlobal,
199                                 "3": self.keyNumberGlobal,
200                                 "4": self.keyNumberGlobal,
201                                 "5": self.keyNumberGlobal,
202                                 "6": self.keyNumberGlobal,
203                                 "7": self.keyNumberGlobal,
204                                 "8": self.keyNumberGlobal,
205                                 "9": self.keyNumberGlobal,
206                                 "0": self.keyNumberGlobal
207                         })
208
209                 self.Timer = eTimer()
210                 self.Timer.callback.append(self.keyOK)
211                 self.Timer.start(3000, True)
212
213 class InfoBarNumberZap:
214         """ Handles an initial number for NumberZapping """
215         def __init__(self):
216                 self["NumberActions"] = NumberActionMap( [ "NumberActions"],
217                         {
218                                 "1": self.keyNumberGlobal,
219                                 "2": self.keyNumberGlobal,
220                                 "3": self.keyNumberGlobal,
221                                 "4": self.keyNumberGlobal,
222                                 "5": self.keyNumberGlobal,
223                                 "6": self.keyNumberGlobal,
224                                 "7": self.keyNumberGlobal,
225                                 "8": self.keyNumberGlobal,
226                                 "9": self.keyNumberGlobal,
227                                 "0": self.keyNumberGlobal,
228                         })
229
230         def keyNumberGlobal(self, number):
231 #               print "You pressed number " + str(number)
232                 if number == 0:
233                         if isinstance(self, InfoBarPiP) and self.pipHandles0Action():
234                                 self.pipDoHandle0Action()
235                         else:
236                                 self.servicelist.recallPrevService()
237                 else:
238                         if not (self.has_key("TimeshiftActions") and self.timeshift_enabled):
239                                 self.session.openWithCallback(self.numberEntered, NumberZap, number)
240
241         def numberEntered(self, retval):
242 #               print self.servicelist
243                 if retval > 0:
244                         self.zapToNumber(retval)
245
246         def searchNumberHelper(self, serviceHandler, num, bouquet):
247                 servicelist = serviceHandler.list(bouquet)
248                 if not servicelist is None:
249                         while num:
250                                 serviceIterator = servicelist.getNext()
251                                 if not serviceIterator.valid(): #check end of list
252                                         break
253                                 playable = not (serviceIterator.flags & (eServiceReference.isMarker|eServiceReference.isDirectory))
254                                 if playable:
255                                         num -= 1;
256                         if not num: #found service with searched number ?
257                                 return serviceIterator, 0
258                 return None, num
259
260         def zapToNumber(self, number):
261                 bouquet = self.servicelist.bouquet_root
262                 service = None
263                 serviceHandler = eServiceCenter.getInstance()
264                 if not config.usage.multibouquet.value:
265                         service, number = self.searchNumberHelper(serviceHandler, number, bouquet)
266                 else:
267                         bouquetlist = serviceHandler.list(bouquet)
268                         if not bouquetlist is None:
269                                 while number:
270                                         bouquet = bouquetlist.getNext()
271                                         if not bouquet.valid(): #check end of list
272                                                 break
273                                         if bouquet.flags & eServiceReference.isDirectory:
274                                                 service, number = self.searchNumberHelper(serviceHandler, number, bouquet)
275                 if not service is None:
276                         if self.servicelist.getRoot() != bouquet: #already in correct bouquet?
277                                 self.servicelist.clearPath()
278                                 if self.servicelist.bouquet_root != bouquet:
279                                         self.servicelist.enterPath(self.servicelist.bouquet_root)
280                                 self.servicelist.enterPath(bouquet)
281                         self.servicelist.setCurrentSelection(service) #select the service in servicelist
282                         self.servicelist.zap()
283
284 config.misc.initialchannelselection = ConfigBoolean(default = True)
285
286 class InfoBarChannelSelection:
287         """ ChannelSelection - handles the channelSelection dialog and the initial
288         channelChange actions which open the channelSelection dialog """
289         def __init__(self):
290                 #instantiate forever
291                 self.servicelist = self.session.instantiateDialog(ChannelSelection)
292
293                 if config.misc.initialchannelselection.value:
294                         self.onShown.append(self.firstRun)
295
296                 self["ChannelSelectActions"] = HelpableActionMap(self, "InfobarChannelSelection",
297                         {
298                                 "switchChannelUp": (self.switchChannelUp, _("open servicelist(up)")),
299                                 "switchChannelDown": (self.switchChannelDown, _("open servicelist(down)")),
300                                 "zapUp": (self.zapUp, _("previous channel")),
301                                 "zapDown": (self.zapDown, _("next channel")),
302                                 "historyBack": (self.historyBack, _("previous channel in history")),
303                                 "historyNext": (self.historyNext, _("next channel in history")),
304                                 "openServiceList": (self.openServiceList, _("open servicelist")),
305                         })
306
307         def showTvChannelList(self, zap=False):
308                 self.servicelist.setModeTv()
309                 if zap:
310                         self.servicelist.zap()
311                 self.session.execDialog(self.servicelist)
312
313         def showRadioChannelList(self, zap=False):
314                 self.servicelist.setModeRadio()
315                 if zap:
316                         self.servicelist.zap()
317                 self.session.execDialog(self.servicelist)
318
319         def firstRun(self):
320                 self.onShown.remove(self.firstRun)
321                 config.misc.initialchannelselection.value = False
322                 config.misc.initialchannelselection.save()
323                 self.switchChannelDown()
324
325         def historyBack(self):
326                 self.servicelist.historyBack()
327
328         def historyNext(self):
329                 self.servicelist.historyNext()
330
331         def switchChannelUp(self):
332                 self.servicelist.moveUp()
333                 self.session.execDialog(self.servicelist)
334
335         def switchChannelDown(self):
336                 self.servicelist.moveDown()
337                 self.session.execDialog(self.servicelist)
338
339         def openServiceList(self):
340                 self.session.execDialog(self.servicelist)
341
342         def zapUp(self):
343                 if self.servicelist.inBouquet():
344                         prev = self.servicelist.getCurrentSelection()
345                         if prev:
346                                 prev = prev.toString()
347                                 while True:
348                                         if config.usage.quickzap_bouquet_change.value:
349                                                 if self.servicelist.atBegin():
350                                                         self.servicelist.prevBouquet()
351                                         self.servicelist.moveUp()
352                                         cur = self.servicelist.getCurrentSelection()
353                                         if not cur or (not (cur.flags & 64)) or cur.toString() == prev:
354                                                 break
355                 else:
356                         self.servicelist.moveUp()
357                 self.servicelist.zap()
358
359         def zapDown(self):
360                 if self.servicelist.inBouquet():
361                         prev = self.servicelist.getCurrentSelection()
362                         if prev:
363                                 prev = prev.toString()
364                                 while True:
365                                         if config.usage.quickzap_bouquet_change.value and self.servicelist.atEnd():
366                                                 self.servicelist.nextBouquet()
367                                         else:
368                                                 self.servicelist.moveDown()
369                                         cur = self.servicelist.getCurrentSelection()
370                                         if not cur or (not (cur.flags & 64)) or cur.toString() == prev:
371                                                 break
372                 else:
373                         self.servicelist.moveDown()
374                 self.servicelist.zap()
375
376 class InfoBarMenu:
377         """ Handles a menu action, to open the (main) menu """
378         def __init__(self):
379                 self["MenuActions"] = HelpableActionMap(self, "InfobarMenuActions",
380                         {
381                                 "mainMenu": (self.mainMenu, _("Enter main menu...")),
382                         })
383                 self.session.infobar = None
384
385         def mainMenu(self):
386                 print "loading mainmenu XML..."
387                 menu = mdom.getroot()
388                 assert menu.tag == "menu", "root element in menu must be 'menu'!"
389
390                 self.session.infobar = self
391                 # so we can access the currently active infobar from screens opened from within the mainmenu
392                 # at the moment used from the SubserviceSelection
393
394                 self.session.openWithCallback(self.mainMenuClosed, MainMenu, menu)
395
396         def mainMenuClosed(self, *val):
397                 self.session.infobar = None
398
399 class InfoBarSimpleEventView:
400         """ Opens the Eventview for now/next """
401         def __init__(self):
402                 self["EPGActions"] = HelpableActionMap(self, "InfobarEPGActions",
403                         {
404                                 "showEventInfo": (self.openEventView, _("show event details")),
405                                 "showInfobarOrEpgWhenInfobarAlreadyVisible": self.showEventInfoWhenNotVisible,
406                         })
407
408         def showEventInfoWhenNotVisible(self):
409                 if self.shown:
410                         self.openEventView()
411                 else:
412                         self.toggleShow()
413                         return 1
414
415         def openEventView(self):
416                 epglist = [ ]
417                 self.epglist = epglist
418                 service = self.session.nav.getCurrentService()
419                 ref = self.session.nav.getCurrentlyPlayingServiceReference()
420                 info = service.info()
421                 ptr=info.getEvent(0)
422                 if ptr:
423                         epglist.append(ptr)
424                 ptr=info.getEvent(1)
425                 if ptr:
426                         epglist.append(ptr)
427                 if epglist:
428                         self.session.open(EventViewSimple, epglist[0], ServiceReference(ref), self.eventViewCallback)
429
430         def eventViewCallback(self, setEvent, setService, val): #used for now/next displaying
431                 epglist = self.epglist
432                 if len(epglist) > 1:
433                         tmp = epglist[0]
434                         epglist[0] = epglist[1]
435                         epglist[1] = tmp
436                         setEvent(epglist[0])
437
438 class SimpleServicelist:
439         def __init__(self, services):
440                 self.services = services
441                 self.length = len(services)
442                 self.current = 0
443
444         def selectService(self, service):
445                 if not self.length:
446                         self.current = -1
447                         return False
448                 else:
449                         self.current = 0
450                         while self.services[self.current].ref != service:
451                                 self.current += 1
452                                 if self.current >= self.length:
453                                         return False
454                 return True
455
456         def nextService(self):
457                 if not self.length:
458                         return
459                 if self.current+1 < self.length:
460                         self.current += 1
461                 else:
462                         self.current = 0
463
464         def prevService(self):
465                 if not self.length:
466                         return
467                 if self.current-1 > -1:
468                         self.current -= 1
469                 else:
470                         self.current = self.length - 1
471
472         def currentService(self):
473                 if not self.length or self.current >= self.length:
474                         return None
475                 return self.services[self.current]
476
477 class InfoBarEPG:
478         """ EPG - Opens an EPG list when the showEPGList action fires """
479         def __init__(self):
480                 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
481                         {
482                                 iPlayableService.evUpdatedEventInfo: self.__evEventInfoChanged,
483                         })
484
485                 self.is_now_next = False
486                 self.dlg_stack = [ ]
487                 self.bouquetSel = None
488                 self.eventView = None
489                 self["EPGActions"] = HelpableActionMap(self, "InfobarEPGActions",
490                         {
491                                 "showEventInfo": (self.openEventView, _("show EPG...")),
492                                 "showEventInfoPlugin": (self.showEventInfoPlugins, _("list of EPG views...")),
493                                 "showInfobarOrEpgWhenInfobarAlreadyVisible": self.showEventInfoWhenNotVisible,
494                         })
495
496         def showEventInfoWhenNotVisible(self):
497                 if self.shown:
498                         self.openEventView()
499                 else:
500                         self.toggleShow()
501                         return 1
502
503         def zapToService(self, service):
504                 if not service is None:
505                         if self.servicelist.getRoot() != self.epg_bouquet: #already in correct bouquet?
506                                 self.servicelist.clearPath()
507                                 if self.servicelist.bouquet_root != self.epg_bouquet:
508                                         self.servicelist.enterPath(self.servicelist.bouquet_root)
509                                 self.servicelist.enterPath(self.epg_bouquet)
510                         self.servicelist.setCurrentSelection(service) #select the service in servicelist
511                         self.servicelist.zap()
512
513         def getBouquetServices(self, bouquet):
514                 services = [ ]
515                 servicelist = eServiceCenter.getInstance().list(bouquet)
516                 if not servicelist is None:
517                         while True:
518                                 service = servicelist.getNext()
519                                 if not service.valid(): #check if end of list
520                                         break
521                                 if service.flags & (eServiceReference.isDirectory | eServiceReference.isMarker): #ignore non playable services
522                                         continue
523                                 services.append(ServiceReference(service))
524                 return services
525
526         def openBouquetEPG(self, bouquet, withCallback=True):
527                 services = self.getBouquetServices(bouquet)
528                 if services:
529                         self.epg_bouquet = bouquet
530                         if withCallback:
531                                 self.dlg_stack.append(self.session.openWithCallback(self.closed, EPGSelection, services, self.zapToService, None, self.changeBouquetCB))
532                         else:
533                                 self.session.open(EPGSelection, services, self.zapToService, None, self.changeBouquetCB)
534
535         def changeBouquetCB(self, direction, epg):
536                 if self.bouquetSel:
537                         if direction > 0:
538                                 self.bouquetSel.down()
539                         else:
540                                 self.bouquetSel.up()
541                         bouquet = self.bouquetSel.getCurrent()
542                         services = self.getBouquetServices(bouquet)
543                         if services:
544                                 self.epg_bouquet = bouquet
545                                 epg.setServices(services)
546
547         def closed(self, ret=False):
548                 closedScreen = self.dlg_stack.pop()
549                 if self.bouquetSel and closedScreen == self.bouquetSel:
550                         self.bouquetSel = None
551                 elif self.eventView and closedScreen == self.eventView:
552                         self.eventView = None
553                 if ret:
554                         dlgs=len(self.dlg_stack)
555                         if dlgs > 0:
556                                 self.dlg_stack[dlgs-1].close(dlgs > 1)
557
558         def openMultiServiceEPG(self, withCallback=True):
559                 bouquets = self.servicelist.getBouquetList()
560                 if bouquets is None:
561                         cnt = 0
562                 else:
563                         cnt = len(bouquets)
564                 if config.usage.multiepg_ask_bouquet.value:
565                         self.openMultiServiceEPGAskBouquet(bouquets, cnt, withCallback)
566                 else:
567                         self.openMultiServiceEPGSilent(bouquets, cnt, withCallback)
568
569         def openMultiServiceEPGAskBouquet(self, bouquets, cnt, withCallback):
570                 if cnt > 1: # show bouquet list
571                         if withCallback:
572                                 self.bouquetSel = self.session.openWithCallback(self.closed, BouquetSelector, bouquets, self.openBouquetEPG, enableWrapAround=True)
573                                 self.dlg_stack.append(self.bouquetSel)
574                         else:
575                                 self.bouquetSel = self.session.open(BouquetSelector, bouquets, self.openBouquetEPG, enableWrapAround=True)
576                 elif cnt == 1:
577                         self.openBouquetEPG(bouquets[0][1], withCallback)
578
579         def openMultiServiceEPGSilent(self, bouquets, cnt, withCallback):
580                 root = self.servicelist.getRoot()
581                 rootstr = root.toCompareString()
582                 current = 0
583                 for bouquet in bouquets:
584                         if bouquet[1].toCompareString() == rootstr:
585                                 break
586                         current += 1
587                 if current >= cnt:
588                         current = 0
589                 if cnt > 1: # create bouquet list for bouq+/-
590                         self.bouquetSel = SilentBouquetSelector(bouquets, True, self.servicelist.getBouquetNumOffset(root))
591                 if cnt >= 1:
592                         self.openBouquetEPG(root, withCallback)
593
594         def changeServiceCB(self, direction, epg):
595                 if self.serviceSel:
596                         if direction > 0:
597                                 self.serviceSel.nextService()
598                         else:
599                                 self.serviceSel.prevService()
600                         epg.setService(self.serviceSel.currentService())
601
602         def SingleServiceEPGClosed(self, ret=False):
603                 self.serviceSel = None
604
605         def openSingleServiceEPG(self):
606                 ref=self.session.nav.getCurrentlyPlayingServiceReference()
607                 if ref:
608                         if self.servicelist.getMutableList() is not None: # bouquet in channellist
609                                 current_path = self.servicelist.getRoot()
610                                 services = self.getBouquetServices(current_path)
611                                 self.serviceSel = SimpleServicelist(services)
612                                 if self.serviceSel.selectService(ref):
613                                         self.session.openWithCallback(self.SingleServiceEPGClosed, EPGSelection, ref, serviceChangeCB = self.changeServiceCB)
614                                 else:
615                                         self.session.openWithCallback(self.SingleServiceEPGClosed, EPGSelection, ref)
616                         else:
617                                 self.session.open(EPGSelection, ref)
618
619         def showEventInfoPlugins(self):
620                 list = [(p.name, boundFunction(self.runPlugin, p)) for p in plugins.getPlugins(where = PluginDescriptor.WHERE_EVENTINFO)]
621
622                 if list:
623                         list.append((_("show single service EPG..."), self.openSingleServiceEPG))
624                         list.append((_("Multi EPG"), self.openMultiServiceEPG))
625                         self.session.openWithCallback(self.EventInfoPluginChosen, ChoiceBox, title=_("Please choose an extension..."), list = list, skin_name = "EPGExtensionsList")
626                 else:
627                         self.openSingleServiceEPG()
628
629         def runPlugin(self, plugin):
630                 plugin(session = self.session, servicelist = self.servicelist)
631                 
632         def EventInfoPluginChosen(self, answer):
633                 if answer is not None:
634                         answer[1]()
635
636         def openSimilarList(self, eventid, refstr):
637                 self.session.open(EPGSelection, refstr, None, eventid)
638
639         def getNowNext(self):
640                 epglist = [ ]
641                 service = self.session.nav.getCurrentService()
642                 info = service and service.info()
643                 ptr = info and info.getEvent(0)
644                 if ptr:
645                         epglist.append(ptr)
646                 ptr = info and info.getEvent(1)
647                 if ptr:
648                         epglist.append(ptr)
649                 self.epglist = epglist
650
651         def __evEventInfoChanged(self):
652                 if self.is_now_next and len(self.dlg_stack) == 1:
653                         self.getNowNext()
654                         assert self.eventView
655                         if self.epglist:
656                                 self.eventView.setEvent(self.epglist[0])
657
658         def openEventView(self):
659                 ref = self.session.nav.getCurrentlyPlayingServiceReference()
660                 self.getNowNext()
661                 epglist = self.epglist
662                 if not epglist:
663                         self.is_now_next = False
664                         epg = eEPGCache.getInstance()
665                         ptr = ref and ref.valid() and epg.lookupEventTime(ref, -1)
666                         if ptr:
667                                 epglist.append(ptr)
668                                 ptr = epg.lookupEventTime(ref, ptr.getBeginTime(), +1)
669                                 if ptr:
670                                         epglist.append(ptr)
671                 else:
672                         self.is_now_next = True
673                 if epglist:
674                         self.eventView = self.session.openWithCallback(self.closed, EventViewEPGSelect, self.epglist[0], ServiceReference(ref), self.eventViewCallback, self.openSingleServiceEPG, self.openMultiServiceEPG, self.openSimilarList)
675                         self.dlg_stack.append(self.eventView)
676                 else:
677                         print "no epg for the service avail.. so we show multiepg instead of eventinfo"
678                         self.openMultiServiceEPG(False)
679
680         def eventViewCallback(self, setEvent, setService, val): #used for now/next displaying
681                 epglist = self.epglist
682                 if len(epglist) > 1:
683                         tmp = epglist[0]
684                         epglist[0]=epglist[1]
685                         epglist[1]=tmp
686                         setEvent(epglist[0])
687
688 class InfoBarRdsDecoder:
689         """provides RDS and Rass support/display"""
690         def __init__(self):
691                 self.rds_display = self.session.instantiateDialog(RdsInfoDisplay)
692                 self.rds_display.setAnimationMode(0)
693                 self.rass_interactive = None
694
695                 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
696                         {
697                                 iPlayableService.evEnd: self.__serviceStopped,
698                                 iPlayableService.evUpdatedRassSlidePic: self.RassSlidePicChanged
699                         })
700
701                 self["RdsActions"] = ActionMap(["InfobarRdsActions"],
702                 {
703                         "startRassInteractive": self.startRassInteractive
704                 },-1)
705
706                 self["RdsActions"].setEnabled(False)
707
708                 self.onLayoutFinish.append(self.rds_display.show)
709                 self.rds_display.onRassInteractivePossibilityChanged.append(self.RassInteractivePossibilityChanged)
710
711         def RassInteractivePossibilityChanged(self, state):
712                 self["RdsActions"].setEnabled(state)
713
714         def RassSlidePicChanged(self):
715                 if not self.rass_interactive:
716                         service = self.session.nav.getCurrentService()
717                         decoder = service and service.rdsDecoder()
718                         if decoder:
719                                 decoder.showRassSlidePicture()
720
721         def __serviceStopped(self):
722                 if self.rass_interactive is not None:
723                         rass_interactive = self.rass_interactive
724                         self.rass_interactive = None
725                         rass_interactive.close()
726
727         def startRassInteractive(self):
728                 self.rds_display.hide()
729                 self.rass_interactive = self.session.openWithCallback(self.RassInteractiveClosed, RassInteractive)
730
731         def RassInteractiveClosed(self, *val):
732                 if self.rass_interactive is not None:
733                         self.rass_interactive = None
734                         self.RassSlidePicChanged()
735                 self.rds_display.show()
736
737 class InfoBarSeek:
738         """handles actions like seeking, pause"""
739
740         SEEK_STATE_PLAY = (0, 0, 0, ">")
741         SEEK_STATE_PAUSE = (1, 0, 0, "||")
742         SEEK_STATE_EOF = (1, 0, 0, "END")
743
744         def __init__(self, actionmap = "InfobarSeekActions"):
745                 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
746                         {
747                                 iPlayableService.evSeekableStatusChanged: self.__seekableStatusChanged,
748                                 iPlayableService.evStart: self.__serviceStarted,
749
750                                 iPlayableService.evEOF: self.__evEOF,
751                                 iPlayableService.evSOF: self.__evSOF,
752                         })
753                 self.fast_winding_hint_message_showed = False
754
755                 class InfoBarSeekActionMap(HelpableActionMap):
756                         def __init__(self, screen, *args, **kwargs):
757                                 HelpableActionMap.__init__(self, screen, *args, **kwargs)
758                                 self.screen = screen
759
760                         def action(self, contexts, action):
761                                 print "action:", action
762                                 if action[:5] == "seek:":
763                                         time = int(action[5:])
764                                         self.screen.doSeekRelative(time * 90000)
765                                         return 1
766                                 elif action[:8] == "seekdef:":
767                                         key = int(action[8:])
768                                         time = (-config.seek.selfdefined_13.value, False, config.seek.selfdefined_13.value,
769                                                 -config.seek.selfdefined_46.value, False, config.seek.selfdefined_46.value,
770                                                 -config.seek.selfdefined_79.value, False, config.seek.selfdefined_79.value)[key-1]
771                                         self.screen.doSeekRelative(time * 90000)
772                                         return 1                                        
773                                 else:
774                                         return HelpableActionMap.action(self, contexts, action)
775
776                 self["SeekActions"] = InfoBarSeekActionMap(self, actionmap,
777                         {
778                                 "playpauseService": (self.playpauseService, _("Pause/Continue")),
779                                 "pauseService": (self.pauseService, _("pause")),
780                                 "unPauseService": (self.unPauseService, _("continue")),
781
782                                 "seekFwd": (self.seekFwd, _("skip forward")),
783                                 "seekFwdManual": (self.seekFwdManual, _("skip forward (enter time)")),
784                                 "seekBack": (self.seekBack, _("skip backward")),
785                                 "seekBackManual": (self.seekBackManual, _("skip backward (enter time)"))
786                         }, prio=-1)
787                         # give them a little more priority to win over color buttons
788
789                 self["SeekActions"].setEnabled(False)
790
791                 self.seekstate = self.SEEK_STATE_PLAY
792                 self.lastseekstate = self.SEEK_STATE_PLAY
793
794                 self.onPlayStateChanged = [ ]
795
796                 self.lockedBecauseOfSkipping = False
797
798                 self.__seekableStatusChanged()
799
800         def makeStateForward(self, n):
801                 return (0, n, 0, ">> %dx" % n)
802
803         def makeStateBackward(self, n):
804                 return (0, -n, 0, "<< %dx" % n)
805
806         def makeStateSlowMotion(self, n):
807                 return (0, 0, n, "/%d" % n)
808
809         def isStateForward(self, state):
810                 return state[1] > 1
811
812         def isStateBackward(self, state):
813                 return state[1] < 0
814
815         def isStateSlowMotion(self, state):
816                 return state[1] == 0 and state[2] > 1
817
818         def getHigher(self, n, lst):
819                 for x in lst:
820                         if x > n:
821                                 return x
822                 return False
823
824         def getLower(self, n, lst):
825                 lst = lst[:]
826                 lst.reverse()
827                 for x in lst:
828                         if x < n:
829                                 return x
830                 return False
831
832         def showAfterSeek(self):
833                 if isinstance(self, InfoBarShowHide):
834                         self.doShow()
835
836         def up(self):
837                 pass
838
839         def down(self):
840                 pass
841
842         def getSeek(self):
843                 service = self.session.nav.getCurrentService()
844                 if service is None:
845                         return None
846
847                 seek = service.seek()
848
849                 if seek is None or not seek.isCurrentlySeekable():
850                         return None
851
852                 return seek
853
854         def isSeekable(self):
855                 if self.getSeek() is None:
856                         return False
857                 return True
858
859         def __seekableStatusChanged(self):
860 #               print "seekable status changed!"
861                 if not self.isSeekable():
862                         self["SeekActions"].setEnabled(False)
863 #                       print "not seekable, return to play"
864                         self.setSeekState(self.SEEK_STATE_PLAY)
865                 else:
866                         self["SeekActions"].setEnabled(True)
867 #                       print "seekable"
868
869         def __serviceStarted(self):
870                 self.fast_winding_hint_message_showed = False
871                 self.seekstate = self.SEEK_STATE_PLAY
872                 self.__seekableStatusChanged()
873
874         def setSeekState(self, state):
875                 service = self.session.nav.getCurrentService()
876
877                 if service is None:
878                         return False
879
880                 if not self.isSeekable():
881                         if state not in (self.SEEK_STATE_PLAY, self.SEEK_STATE_PAUSE):
882                                 state = self.SEEK_STATE_PLAY
883
884                 pauseable = service.pause()
885
886                 if pauseable is None:
887                         print "not pauseable."
888                         state = self.SEEK_STATE_PLAY
889
890                 self.seekstate = state
891
892                 if pauseable is not None:
893                         if self.seekstate[0]:
894                                 print "resolved to PAUSE"
895                                 pauseable.pause()
896                         elif self.seekstate[1]:
897                                 print "resolved to FAST FORWARD"
898                                 pauseable.setFastForward(self.seekstate[1])
899                         elif self.seekstate[2]:
900                                 print "resolved to SLOW MOTION"
901                                 pauseable.setSlowMotion(self.seekstate[2])
902                         else:
903                                 print "resolved to PLAY"
904                                 pauseable.unpause()
905
906                 for c in self.onPlayStateChanged:
907                         c(self.seekstate)
908
909                 self.checkSkipShowHideLock()
910
911                 return True
912
913         def playpauseService(self):
914                 if self.seekstate != self.SEEK_STATE_PLAY:
915                         self.unPauseService()
916                 else:
917                         self.pauseService()
918
919         def pauseService(self):
920                 if self.seekstate == self.SEEK_STATE_PAUSE:
921                         if config.seek.on_pause.value == "play":
922                                 self.unPauseService()
923                         elif config.seek.on_pause.value == "step":
924                                 self.doSeekRelative(1)
925                         elif config.seek.on_pause.value == "last":
926                                 self.setSeekState(self.lastseekstate)
927                                 self.lastseekstate = self.SEEK_STATE_PLAY
928                 else:
929                         if self.seekstate != self.SEEK_STATE_EOF:
930                                 self.lastseekstate = self.seekstate
931                         self.setSeekState(self.SEEK_STATE_PAUSE);
932
933         def unPauseService(self):
934                 print "unpause"
935                 if self.seekstate == self.SEEK_STATE_PLAY:
936                         return 0
937                 self.setSeekState(self.SEEK_STATE_PLAY)
938
939         def doSeek(self, pts):
940                 seekable = self.getSeek()
941                 if seekable is None:
942                         return
943                 seekable.seekTo(pts)
944
945         def doSeekRelative(self, pts):
946                 seekable = self.getSeek()
947                 if seekable is None:
948                         return
949                 prevstate = self.seekstate
950
951                 if self.seekstate == self.SEEK_STATE_EOF:
952                         if prevstate == self.SEEK_STATE_PAUSE:
953                                 self.setSeekState(self.SEEK_STATE_PAUSE)
954                         else:
955                                 self.setSeekState(self.SEEK_STATE_PLAY)
956                 seekable.seekRelative(pts<0 and -1 or 1, abs(pts))
957                 if abs(pts) > 100 and config.usage.show_infobar_on_skip.value:
958                         self.showAfterSeek()
959
960         def seekFwd(self):
961                 seek = self.getSeek()
962                 if seek and not (seek.isCurrentlySeekable() & 2):
963                         if not self.fast_winding_hint_message_showed and (seek.isCurrentlySeekable() & 1):
964                                 self.session.open(MessageBox, _("No fast winding possible yet.. but you can use the number buttons to skip forward/backward!"), MessageBox.TYPE_INFO, timeout=10)
965                                 self.fast_winding_hint_message_showed = True
966                                 return
967                         return 0 # trade as unhandled action
968                 if self.seekstate == self.SEEK_STATE_PLAY:
969                         self.setSeekState(self.makeStateForward(int(config.seek.enter_forward.value)))
970                 elif self.seekstate == self.SEEK_STATE_PAUSE:
971                         if len(config.seek.speeds_slowmotion.value):
972                                 self.setSeekState(self.makeStateSlowMotion(config.seek.speeds_slowmotion.value[-1]))
973                         else:
974                                 self.setSeekState(self.makeStateForward(int(config.seek.enter_forward.value)))
975                 elif self.seekstate == self.SEEK_STATE_EOF:
976                         pass
977                 elif self.isStateForward(self.seekstate):
978                         speed = self.seekstate[1]
979                         if self.seekstate[2]:
980                                 speed /= self.seekstate[2]
981                         speed = self.getHigher(speed, config.seek.speeds_forward.value) or config.seek.speeds_forward.value[-1]
982                         self.setSeekState(self.makeStateForward(speed))
983                 elif self.isStateBackward(self.seekstate):
984                         speed = -self.seekstate[1]
985                         if self.seekstate[2]:
986                                 speed /= self.seekstate[2]
987                         speed = self.getLower(speed, config.seek.speeds_backward.value)
988                         if speed:
989                                 self.setSeekState(self.makeStateBackward(speed))
990                         else:
991                                 self.setSeekState(self.SEEK_STATE_PLAY)
992                 elif self.isStateSlowMotion(self.seekstate):
993                         speed = self.getLower(self.seekstate[2], config.seek.speeds_slowmotion.value) or config.seek.speeds_slowmotion.value[0]
994                         self.setSeekState(self.makeStateSlowMotion(speed))
995
996         def seekBack(self):
997                 seek = self.getSeek()
998                 if seek and not (seek.isCurrentlySeekable() & 2):
999                         if not self.fast_winding_hint_message_showed and (seek.isCurrentlySeekable() & 1):
1000                                 self.session.open(MessageBox, _("No fast winding possible yet.. but you can use the number buttons to skip forward/backward!"), MessageBox.TYPE_INFO, timeout=10)
1001                                 self.fast_winding_hint_message_showed = True
1002                                 return
1003                         return 0 # trade as unhandled action
1004                 seekstate = self.seekstate
1005                 if seekstate == self.SEEK_STATE_PLAY:
1006                         self.setSeekState(self.makeStateBackward(int(config.seek.enter_backward.value)))
1007                 elif seekstate == self.SEEK_STATE_EOF:
1008                         self.setSeekState(self.makeStateBackward(int(config.seek.enter_backward.value)))
1009                         self.doSeekRelative(-6)
1010                 elif seekstate == self.SEEK_STATE_PAUSE:
1011                         self.doSeekRelative(-1)
1012                 elif self.isStateForward(seekstate):
1013                         speed = seekstate[1]
1014                         if seekstate[2]:
1015                                 speed /= seekstate[2]
1016                         speed = self.getLower(speed, config.seek.speeds_forward.value)
1017                         if speed:
1018                                 self.setSeekState(self.makeStateForward(speed))
1019                         else:
1020                                 self.setSeekState(self.SEEK_STATE_PLAY)
1021                 elif self.isStateBackward(seekstate):
1022                         speed = -seekstate[1]
1023                         if seekstate[2]:
1024                                 speed /= seekstate[2]
1025                         speed = self.getHigher(speed, config.seek.speeds_backward.value) or config.seek.speeds_backward.value[-1]
1026                         self.setSeekState(self.makeStateBackward(speed))
1027                 elif self.isStateSlowMotion(seekstate):
1028                         speed = self.getHigher(seekstate[2], config.seek.speeds_slowmotion.value)
1029                         if speed:
1030                                 self.setSeekState(self.makeStateSlowMotion(speed))
1031                         else:
1032                                 self.setSeekState(self.SEEK_STATE_PAUSE)
1033
1034         def seekFwdManual(self):
1035                 self.session.openWithCallback(self.fwdSeekTo, MinuteInput)
1036
1037         def fwdSeekTo(self, minutes):
1038                 print "Seek", minutes, "minutes forward"
1039                 self.doSeekRelative(minutes * 60 * 90000)
1040
1041         def seekBackManual(self):
1042                 self.session.openWithCallback(self.rwdSeekTo, MinuteInput)
1043
1044         def rwdSeekTo(self, minutes):
1045                 print "rwdSeekTo"
1046                 self.doSeekRelative(-minutes * 60 * 90000)
1047
1048         def checkSkipShowHideLock(self):
1049                 wantlock = self.seekstate != self.SEEK_STATE_PLAY
1050
1051                 if config.usage.show_infobar_on_skip.value:
1052                         if self.lockedBecauseOfSkipping and not wantlock:
1053                                 self.unlockShow()
1054                                 self.lockedBecauseOfSkipping = False
1055
1056                         if wantlock and not self.lockedBecauseOfSkipping:
1057                                 self.lockShow()
1058                                 self.lockedBecauseOfSkipping = True
1059
1060         def calcRemainingTime(self):
1061                 seekable = self.getSeek()
1062                 if seekable is not None:
1063                         len = seekable.getLength()
1064                         try:
1065                                 tmp = self.cueGetEndCutPosition()
1066                                 if tmp:
1067                                         len = [False, tmp]
1068                         except:
1069                                 pass
1070                         pos = seekable.getPlayPosition()
1071                         speednom = self.seekstate[1] or 1
1072                         speedden = self.seekstate[2] or 1
1073                         if not len[0] and not pos[0]:
1074                                 if len[1] <= pos[1]:
1075                                         return 0
1076                                 time = (len[1] - pos[1])*speedden/(90*speednom)
1077                                 return time
1078                 return False
1079                 
1080         def __evEOF(self):
1081                 if self.seekstate == self.SEEK_STATE_EOF:
1082                         return
1083
1084                 # if we are seeking forward, we try to end up ~1s before the end, and pause there.
1085                 seekstate = self.seekstate
1086                 if self.seekstate != self.SEEK_STATE_PAUSE:
1087                         self.setSeekState(self.SEEK_STATE_EOF)
1088
1089                 if seekstate not in (self.SEEK_STATE_PLAY, self.SEEK_STATE_PAUSE): # if we are seeking
1090                         seekable = self.getSeek()
1091                         if seekable is not None:
1092                                 seekable.seekTo(-1)
1093                 if seekstate == self.SEEK_STATE_PLAY: # regular EOF
1094                         self.doEofInternal(True)
1095                 else:
1096                         self.doEofInternal(False)
1097
1098         def doEofInternal(self, playing):
1099                 pass            # Defined in subclasses
1100
1101         def __evSOF(self):
1102                 self.setSeekState(self.SEEK_STATE_PLAY)
1103                 self.doSeek(0)
1104
1105 from Screens.PVRState import PVRState, TimeshiftState
1106
1107 class InfoBarPVRState:
1108         def __init__(self, screen=PVRState, force_show = False):
1109                 self.onPlayStateChanged.append(self.__playStateChanged)
1110                 self.pvrStateDialog = self.session.instantiateDialog(screen)
1111                 self.pvrStateDialog.setAnimationMode(0)
1112                 self.onShow.append(self._mayShow)
1113                 self.onHide.append(self.pvrStateDialog.hide)
1114                 self.force_show = force_show
1115
1116         def _mayShow(self):
1117                 if self.execing and self.seekstate != self.SEEK_STATE_PLAY:
1118                         self.pvrStateDialog.show()
1119
1120         def __playStateChanged(self, state):
1121                 playstateString = state[3]
1122                 self.pvrStateDialog["state"].setText(playstateString)
1123                 
1124                 # if we return into "PLAY" state, ensure that the dialog gets hidden if there will be no infobar displayed
1125                 if not config.usage.show_infobar_on_skip.value and self.seekstate == self.SEEK_STATE_PLAY and not self.force_show:
1126                         self.pvrStateDialog.hide()
1127                 else:
1128                         self._mayShow()
1129
1130 class InfoBarTimeshiftState(InfoBarPVRState):
1131         def __init__(self):
1132                 InfoBarPVRState.__init__(self, screen=TimeshiftState, force_show = True)
1133                 self.__hideTimer = eTimer()
1134                 self.__hideTimer.callback.append(self.__hideTimeshiftState)
1135
1136         def _mayShow(self):
1137                 if self.execing and self.timeshift_enabled:
1138                         self.pvrStateDialog.show()
1139                         if self.seekstate == self.SEEK_STATE_PLAY and not self.shown:
1140                                 self.__hideTimer.start(5*1000, True)
1141
1142         def __hideTimeshiftState(self):
1143                 self.pvrStateDialog.hide()
1144
1145 class InfoBarShowMovies:
1146
1147         # i don't really like this class.
1148         # it calls a not further specified "movie list" on up/down/movieList,
1149         # so this is not more than an action map
1150         def __init__(self):
1151                 self["MovieListActions"] = HelpableActionMap(self, "InfobarMovieListActions",
1152                         {
1153                                 "movieList": (self.showMovies, _("movie list")),
1154                                 "up": (self.showMovies, _("movie list")),
1155                                 "down": (self.showMovies, _("movie list"))
1156                         })
1157
1158 # InfoBarTimeshift requires InfoBarSeek, instantiated BEFORE!
1159
1160 # Hrmf.
1161 #
1162 # Timeshift works the following way:
1163 #                                         demux0   demux1                    "TimeshiftActions" "TimeshiftActivateActions" "SeekActions"
1164 # - normal playback                       TUNER    unused      PLAY               enable                disable              disable
1165 # - user presses "yellow" button.         FILE     record      PAUSE              enable                disable              enable
1166 # - user presess pause again              FILE     record      PLAY               enable                disable              enable
1167 # - user fast forwards                    FILE     record      FF                 enable                disable              enable
1168 # - end of timeshift buffer reached       TUNER    record      PLAY               enable                enable               disable
1169 # - user backwards                        FILE     record      BACK  # !!         enable                disable              enable
1170 #
1171
1172 # in other words:
1173 # - when a service is playing, pressing the "timeshiftStart" button ("yellow") enables recording ("enables timeshift"),
1174 # freezes the picture (to indicate timeshift), sets timeshiftMode ("activates timeshift")
1175 # now, the service becomes seekable, so "SeekActions" are enabled, "TimeshiftEnableActions" are disabled.
1176 # - the user can now PVR around
1177 # - if it hits the end, the service goes into live mode ("deactivates timeshift", it's of course still "enabled")
1178 # the service looses it's "seekable" state. It can still be paused, but just to activate timeshift right
1179 # after!
1180 # the seek actions will be disabled, but the timeshiftActivateActions will be enabled
1181 # - if the user rewinds, or press pause, timeshift will be activated again
1182
1183 # note that a timeshift can be enabled ("recording") and
1184 # activated (currently time-shifting).
1185
1186 class InfoBarTimeshift:
1187         def __init__(self):
1188                 if SystemInfo["PVRSupport"]:
1189                         self["TimeshiftActions"] = HelpableActionMap(self, "InfobarTimeshiftActions",
1190                                 {
1191                                         "timeshiftStart": (self.startTimeshift, _("start timeshift")),  # the "yellow key"
1192                                         "timeshiftStop": (self.stopTimeshift, _("stop timeshift"))      # currently undefined :), probably 'TV'
1193                                 }, prio=1)
1194                 self["TimeshiftActivateActions"] = ActionMap(["InfobarTimeshiftActivateActions"],
1195                         {
1196                                 "timeshiftActivateEnd": self.activateTimeshiftEnd, # something like "rewind key"
1197                                 "timeshiftActivateEndAndPause": self.activateTimeshiftEndAndPause  # something like "pause key"
1198                         }, prio=-1) # priority over record
1199
1200                 self.timeshift_enabled = 0
1201                 self.timeshift_state = 0
1202                 self.ts_rewind_timer = eTimer()
1203                 self.ts_rewind_timer.callback.append(self.rewindService)
1204
1205                 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1206                         {
1207                                 iPlayableService.evStart: self.__serviceStarted,
1208                                 iPlayableService.evSeekableStatusChanged: self.__seekableStatusChanged,
1209                                 iPlayableService.evUser+3: self.__lowDiskspaceMessage
1210                         })
1211
1212         def getTimeshift(self):
1213                 service = self.session.nav.getCurrentService()
1214                 return service and service.timeshift()
1215
1216         def startTimeshift(self):
1217                 print "enable timeshift"
1218                 ts = self.getTimeshift()
1219                 if ts is None:
1220                         self.session.open(MessageBox, _("Timeshift not possible!"), MessageBox.TYPE_ERROR)
1221                         print "no ts interface"
1222                         return 0
1223
1224                 if self.timeshift_enabled:
1225                         print "hu, timeshift already enabled?"
1226                 else:
1227                         from Components import Harddisk
1228                         if Harddisk.getMountPath(config.usage.timeshift_path.value) != '/' and \
1229                                 SystemInfo.get("DisableUsbRecord", True) and \
1230                                 Harddisk.isUsbStorage(config.usage.timeshift_path.value):
1231                                 self.session.open(MessageBox, _("Timeshift not possible on a USB storage."), MessageBox.TYPE_ERROR)
1232                                 return 0
1233
1234                         if not ts.startTimeshift():
1235                                 self.timeshift_enabled = 1
1236
1237                                 # we remove the "relative time" for now.
1238                                 #self.pvrStateDialog["timeshift"].setRelative(time.time())
1239
1240                                 # PAUSE.
1241                                 #self.setSeekState(self.SEEK_STATE_PAUSE)
1242                                 self.activateTimeshiftEnd(False)
1243
1244                                 # enable the "TimeshiftEnableActions", which will override
1245                                 # the startTimeshift actions
1246                                 self.__seekableStatusChanged()
1247                         else:
1248                                 print "timeshift failed"
1249
1250         def stopTimeshift(self):
1251                 if not self.timeshift_enabled:
1252                         return 0
1253                 print "disable timeshift"
1254                 ts = self.getTimeshift()
1255                 if ts is None:
1256                         return 0
1257                 self.session.openWithCallback(self.stopTimeshiftConfirmed, MessageBox, _("Stop Timeshift?"), MessageBox.TYPE_YESNO)
1258
1259         def stopTimeshiftConfirmed(self, confirmed):
1260                 if not confirmed:
1261                         return
1262
1263                 ts = self.getTimeshift()
1264                 if ts is None:
1265                         return
1266
1267                 ts.stopTimeshift()
1268                 self.timeshift_enabled = 0
1269
1270                 # disable actions
1271                 self.__seekableStatusChanged()
1272
1273         # activates timeshift, and seeks to (almost) the end
1274         def activateTimeshiftEnd(self, back = True):
1275                 ts = self.getTimeshift()
1276                 print "activateTimeshiftEnd"
1277
1278                 if ts is None:
1279                         return
1280
1281                 if ts.isTimeshiftActive():
1282                         print "!! activate timeshift called - but shouldn't this be a normal pause?"
1283                         self.pauseService()
1284                 else:
1285                         print "play, ..."
1286                         ts.activateTimeshift() # activate timeshift will automatically pause
1287                         self.setSeekState(self.SEEK_STATE_PAUSE)
1288
1289                 if back:
1290                         self.ts_rewind_timer.start(200, 1)
1291
1292         def rewindService(self):
1293                 self.setSeekState(self.makeStateBackward(int(config.seek.enter_backward.value)))
1294
1295         # same as activateTimeshiftEnd, but pauses afterwards.
1296         def activateTimeshiftEndAndPause(self):
1297                 print "activateTimeshiftEndAndPause"
1298                 #state = self.seekstate
1299                 self.activateTimeshiftEnd(False)
1300
1301         def __seekableStatusChanged(self):
1302                 enabled = False
1303
1304 #               print "self.isSeekable", self.isSeekable()
1305 #               print "self.timeshift_enabled", self.timeshift_enabled
1306
1307                 # when this service is not seekable, but timeshift
1308                 # is enabled, this means we can activate
1309                 # the timeshift
1310                 if not self.isSeekable() and self.timeshift_enabled:
1311                         enabled = True
1312
1313 #               print "timeshift activate:", enabled
1314                 self["TimeshiftActivateActions"].setEnabled(enabled)
1315
1316         def __serviceStarted(self):
1317                 self.timeshift_enabled = False
1318                 self.__seekableStatusChanged()
1319
1320         def __lowDiskspaceMessage(self):
1321                 Notifications.AddPopup(text = _("Write error. Not enough space for writing.\n"), type = MessageBox.TYPE_ERROR, timeout = 0, id = "DiskFullMessage")
1322
1323 from Screens.PiPSetup import PiPSetup
1324
1325 class InfoBarExtensions:
1326         EXTENSION_SINGLE = 0
1327         EXTENSION_LIST = 1
1328
1329         def __init__(self):
1330                 self.list = []
1331
1332                 self["InstantExtensionsActions"] = HelpableActionMap(self, "InfobarExtensions",
1333                         {
1334                                 "extensions": (self.showExtensionSelection, _("view extensions...")),
1335                         }, 1) # lower priority
1336
1337                 for p in plugins.getPlugins(PluginDescriptor.WHERE_EXTENSIONSINGLE):
1338                         p(self)
1339
1340         def addExtension(self, extension, key = None, type = EXTENSION_SINGLE):
1341                 self.list.append((type, extension, key))
1342
1343         def updateExtension(self, extension, key = None):
1344                 self.extensionsList.append(extension)
1345                 if key is not None:
1346                         if self.extensionKeys.has_key(key):
1347                                 key = None
1348
1349                 if key is None:
1350                         for x in self.availableKeys:
1351                                 if not self.extensionKeys.has_key(x):
1352                                         key = x
1353                                         break
1354
1355                 if key is not None:
1356                         self.extensionKeys[key] = len(self.extensionsList) - 1
1357
1358         def updateExtensions(self):
1359                 self.extensionsList = []
1360                 self.availableKeys = [ "1", "2", "3", "4", "5", "6", "7", "8", "9", "0", "red", "green", "yellow", "blue" ]
1361                 self.extensionKeys = {}
1362                 for x in self.list:
1363                         if x[0] == self.EXTENSION_SINGLE:
1364                                 self.updateExtension(x[1], x[2])
1365                         else:
1366                                 for y in x[1]():
1367                                         self.updateExtension(y[0], y[1])
1368
1369
1370         def showExtensionSelection(self):
1371                 self.updateExtensions()
1372                 extensionsList = self.extensionsList[:]
1373                 keys = []
1374                 list = []
1375                 for x in self.availableKeys:
1376                         if self.extensionKeys.has_key(x):
1377                                 entry = self.extensionKeys[x]
1378                                 extension = self.extensionsList[entry]
1379                                 if extension[2]():
1380                                         name = str(extension[0]())
1381                                         list.append((extension[0](), extension))
1382                                         keys.append(x)
1383                                         extensionsList.remove(extension)
1384                                 else:
1385                                         extensionsList.remove(extension)
1386                 list.extend([(x[0](), x) for x in extensionsList])
1387
1388                 keys += [""] * len(extensionsList)
1389                 self.session.openWithCallback(self.extensionCallback, ChoiceBox, title=_("Please choose an extension..."), list = list, keys = keys, skin_name = "ExtensionsList")
1390
1391         def extensionCallback(self, answer):
1392                 if answer is not None:
1393                         answer[1][1]()
1394
1395 from Tools.BoundFunction import boundFunction
1396 import inspect
1397
1398 # depends on InfoBarExtensions
1399
1400 class InfoBarPlugins:
1401         def __init__(self):
1402                 self.addExtension(extension = self.getPluginList, type = InfoBarExtensions.EXTENSION_LIST)
1403
1404         def getPluginName(self, name):
1405                 return name
1406
1407         def getPluginList(self):
1408                 l = []
1409                 for p in plugins.getPlugins(where = PluginDescriptor.WHERE_EXTENSIONSMENU):
1410                   args = inspect.getargspec(p.__call__)[0]
1411                   if len(args) == 1 or len(args) == 2 and isinstance(self, InfoBarChannelSelection):
1412                           l.append(((boundFunction(self.getPluginName, p.name), boundFunction(self.runPlugin, p), lambda: True), None, p.name))
1413                 l.sort(key = lambda e: e[2]) # sort by name
1414                 return l
1415
1416         def runPlugin(self, plugin):
1417                 if isinstance(self, InfoBarChannelSelection):
1418                         plugin(session = self.session, servicelist = self.servicelist)
1419                 else:
1420                         plugin(session = self.session)
1421
1422 from Components.Task import job_manager
1423 class InfoBarJobman:
1424         def __init__(self):
1425                 self.addExtension(extension = self.getJobList, type = InfoBarExtensions.EXTENSION_LIST)
1426
1427         def getJobList(self):
1428                 return [((boundFunction(self.getJobName, job), boundFunction(self.showJobView, job), lambda: True), None) for job in job_manager.getPendingJobs()]
1429
1430         def getJobName(self, job):
1431                 return "%s: %s (%d%%)" % (job.getStatustext(), job.name, int(100*job.progress/float(job.end)))
1432
1433         def showJobView(self, job):
1434                 from Screens.TaskView import JobView
1435                 job_manager.in_background = False
1436                 self.session.openWithCallback(self.JobViewCB, JobView, job)
1437         
1438         def JobViewCB(self, in_background):
1439                 job_manager.in_background = in_background
1440
1441 # depends on InfoBarExtensions
1442 class InfoBarPiP:
1443         def __init__(self):
1444                 try:
1445                         self.session.pipshown
1446                 except:
1447                         self.session.pipshown = False
1448                 if SystemInfo.get("NumVideoDecoders", 1) > 1:
1449                         if (self.allowPiP):
1450                                 self.addExtension((self.getShowHideName, self.showPiP, lambda: True), "blue")
1451                                 self.addExtension((self.getMoveName, self.movePiP, self.pipShown), "green")
1452                                 self.addExtension((self.getSwapName, self.swapPiP, self.pipShown), "yellow")
1453                         else:
1454                                 self.addExtension((self.getShowHideName, self.showPiP, self.pipShown), "blue")
1455                                 self.addExtension((self.getMoveName, self.movePiP, self.pipShown), "green")
1456
1457         def pipShown(self):
1458                 return self.session.pipshown
1459
1460         def pipHandles0Action(self):
1461                 return self.pipShown() and config.usage.pip_zero_button.value != "standard"
1462
1463         def getShowHideName(self):
1464                 if self.session.pipshown:
1465                         return _("Disable Picture in Picture")
1466                 else:
1467                         return _("Activate Picture in Picture")
1468
1469         def getSwapName(self):
1470                 return _("Swap Services")
1471
1472         def getMoveName(self):
1473                 return _("Move Picture in Picture")
1474
1475         def showPiP(self):
1476                 if self.session.pipshown:
1477                         del self.session.pip
1478                         self.session.pipshown = False
1479                 else:
1480                         self.session.pip = self.session.instantiateDialog(PictureInPicture)
1481                         self.session.pip.setAnimationMode(0)
1482                         self.session.pip.show()
1483                         newservice = self.session.nav.getCurrentlyPlayingServiceReference()
1484                         if self.session.pip.playService(newservice):
1485                                 self.session.pipshown = True
1486                                 self.session.pip.servicePath = self.servicelist.getCurrentServicePath()
1487                         else:
1488                                 self.session.pipshown = False
1489                                 del self.session.pip
1490                         self.session.nav.playService(newservice)
1491
1492         def swapPiP(self):
1493                 swapservice = self.session.nav.getCurrentlyPlayingServiceReference()
1494                 if self.session.pip.servicePath:
1495                         servicepath = self.servicelist.getCurrentServicePath()
1496                         ref=servicepath[len(servicepath)-1]
1497                         pipref=self.session.pip.getCurrentService()
1498                         self.session.pip.playService(swapservice)
1499                         self.servicelist.setCurrentServicePath(self.session.pip.servicePath)
1500                         if pipref.toString() != ref.toString(): # is a subservice ?
1501                                 self.session.nav.stopService() # stop portal
1502                                 self.session.nav.playService(pipref) # start subservice
1503                         self.session.pip.servicePath=servicepath
1504
1505         def movePiP(self):
1506                 self.session.open(PiPSetup, pip = self.session.pip)
1507
1508         def pipDoHandle0Action(self):
1509                 use = config.usage.pip_zero_button.value
1510                 if "swap" == use:
1511                         self.swapPiP()
1512                 elif "swapstop" == use:
1513                         self.swapPiP()
1514                         self.showPiP()
1515                 elif "stop" == use:
1516                         self.showPiP()
1517
1518 from RecordTimer import parseEvent, RecordTimerEntry
1519
1520 class InfoBarInstantRecord:
1521         """Instant Record - handles the instantRecord action in order to
1522         start/stop instant records"""
1523         def __init__(self):
1524                 if SystemInfo["PVRSupport"]:
1525                         self["InstantRecordActions"] = HelpableActionMap(self, "InfobarInstantRecord",
1526                                 {
1527                                         "instantRecord": (self.instantRecord, _("Instant Record...")),
1528                                 })
1529                 self.recording = []
1530
1531         def stopCurrentRecording(self, entry = -1):
1532                 if entry is not None and entry != -1:
1533                         self.session.nav.RecordTimer.removeEntry(self.recording[entry])
1534                         self.recording.remove(self.recording[entry])
1535
1536         def startInstantRecording(self, limitEvent = False):
1537                 serviceref = self.session.nav.getCurrentlyPlayingServiceReference()
1538
1539                 # try to get event info
1540                 event = None
1541                 try:
1542                         service = self.session.nav.getCurrentService()
1543                         epg = eEPGCache.getInstance()
1544                         event = epg.lookupEventTime(serviceref, -1, 0)
1545                         if event is None:
1546                                 info = service.info()
1547                                 ev = info.getEvent(0)
1548                                 event = ev
1549                 except:
1550                         pass
1551
1552                 begin = int(time())
1553                 end = begin + 3600      # dummy
1554                 name = "instant record"
1555                 description = ""
1556                 eventid = None
1557
1558                 if event is not None:
1559                         curEvent = parseEvent(event)
1560                         name = curEvent[2]
1561                         description = curEvent[3]
1562                         eventid = curEvent[4]
1563                         if limitEvent:
1564                                 end = curEvent[1]
1565                 else:
1566                         if limitEvent:
1567                                 self.session.open(MessageBox, _("No event info found, recording indefinitely."), MessageBox.TYPE_INFO)
1568
1569                 if isinstance(serviceref, eServiceReference):
1570                         serviceref = ServiceReference(serviceref)
1571
1572                 recording = RecordTimerEntry(serviceref, begin, end, name, description, eventid, dirname = preferredInstantRecordPath())
1573                 recording.dontSave = True
1574
1575                 if event is None or limitEvent == False:
1576                         recording.autoincrease = True
1577                         recording.setAutoincreaseEnd()
1578
1579                 simulTimerList = self.session.nav.RecordTimer.record(recording)
1580
1581                 if simulTimerList is None:      # no conflict
1582                         self.recording.append(recording)
1583                 else:
1584                         if len(simulTimerList) > 1: # with other recording
1585                                 name = simulTimerList[1].name
1586                                 name_date = ' '.join((name, strftime('%c', localtime(simulTimerList[1].begin))))
1587                                 print "[TIMER] conflicts with", name_date
1588                                 recording.autoincrease = True   # start with max available length, then increment
1589                                 if recording.setAutoincreaseEnd():
1590                                         self.session.nav.RecordTimer.record(recording)
1591                                         self.recording.append(recording)
1592                                         self.session.open(MessageBox, _("Record time limited due to conflicting timer %s") % name_date, MessageBox.TYPE_INFO)
1593                                 else:
1594                                         self.session.open(MessageBox, _("Couldn't record due to conflicting timer %s") % name, MessageBox.TYPE_INFO)
1595                         else:
1596                                 self.session.open(MessageBox, _("Couldn't record due to invalid service %s") % serviceref, MessageBox.TYPE_INFO)
1597                         recording.autoincrease = False
1598
1599         def isInstantRecordRunning(self):
1600                 print "self.recording:", self.recording
1601                 if self.recording:
1602                         for x in self.recording:
1603                                 if x.isRunning():
1604                                         return True
1605                 return False
1606
1607         def recordQuestionCallback(self, answer):
1608                 print "pre:\n", self.recording
1609
1610                 if answer is None or answer[1] == "no":
1611                         return
1612                 list = []
1613                 recording = self.recording[:]
1614                 for x in recording:
1615                         if not x in self.session.nav.RecordTimer.timer_list:
1616                                 self.recording.remove(x)
1617                         elif x.dontSave and x.isRunning():
1618                                 list.append((x, False))
1619
1620                 if answer[1] == "changeduration":
1621                         if len(self.recording) == 1:
1622                                 self.changeDuration(0)
1623                         else:
1624                                 self.session.openWithCallback(self.changeDuration, TimerSelection, list)
1625                 elif answer[1] == "changeendtime":
1626                         if len(self.recording) == 1:
1627                                 self.setEndtime(0)
1628                         else:
1629                                 self.session.openWithCallback(self.setEndtime, TimerSelection, list)
1630                 elif answer[1] == "stop":
1631                         if len(self.recording) == 1:
1632                                 self.stopCurrentRecording(0)
1633                         else:
1634                                 self.session.openWithCallback(self.stopCurrentRecording, TimerSelection, list)
1635                 elif answer[1] in ( "indefinitely" , "manualduration", "manualendtime", "event"):
1636                         self.startInstantRecording(limitEvent = answer[1] in ("event", "manualendtime") or False)
1637                         if answer[1] == "manualduration":
1638                                 self.changeDuration(len(self.recording)-1)
1639                         elif answer[1] == "manualendtime":
1640                                 self.setEndtime(len(self.recording)-1)
1641                 print "after:\n", self.recording
1642
1643         def setEndtime(self, entry):
1644                 if entry is not None and entry >= 0:
1645                         self.selectedEntry = entry
1646                         self.endtime=ConfigClock(default = self.recording[self.selectedEntry].end)
1647                         dlg = self.session.openWithCallback(self.TimeDateInputClosed, TimeDateInput, self.endtime)
1648                         dlg.setTitle(_("Please change recording endtime"))
1649
1650         def TimeDateInputClosed(self, ret):
1651                 if len(ret) > 1:
1652                         if ret[0]:
1653                                 localendtime = localtime(ret[1])
1654                                 print "stopping recording at", strftime("%c", localendtime)
1655                                 if self.recording[self.selectedEntry].end != ret[1]:
1656                                         self.recording[self.selectedEntry].autoincrease = False
1657                                 self.recording[self.selectedEntry].end = ret[1]
1658                                 self.session.nav.RecordTimer.timeChanged(self.recording[self.selectedEntry])
1659
1660         def changeDuration(self, entry):
1661                 if entry is not None and entry >= 0:
1662                         self.selectedEntry = entry
1663                         self.session.openWithCallback(self.inputCallback, InputBox, title=_("How many minutes do you want to record?"), text="5", maxSize=False, type=Input.NUMBER)
1664
1665         def inputCallback(self, value):
1666                 if value is not None:
1667                         print "stopping recording after", int(value), "minutes."
1668                         entry = self.recording[self.selectedEntry]
1669                         if int(value) != 0:
1670                                 entry.autoincrease = False
1671                         entry.end = int(time()) + 60 * int(value)
1672                         self.session.nav.RecordTimer.timeChanged(entry)
1673
1674         def instantRecord(self):
1675                 if not fileExists("/hdd", 0):
1676                         print "not found /hdd"
1677                         os_system("ln -s /media/hdd /hdd")
1678
1679                 recPath = preferredInstantRecordPath()
1680                 if not findSafeRecordPath(recPath) and not findSafeRecordPath(defaultMoviePath()):
1681                         if not recPath:
1682                                 recPath = ""
1683                         self.session.open(MessageBox, _("No HDD found or HDD not initialized!"), MessageBox.TYPE_ERROR)
1684                         return
1685
1686                 if self.isInstantRecordRunning():
1687                         self.session.openWithCallback(self.recordQuestionCallback, ChoiceBox, \
1688                                 title=_("A recording is currently running.\nWhat do you want to do?"), \
1689                                 list=((_("stop recording"), "stop"), \
1690                                 (_("add recording (stop after current event)"), "event"), \
1691                                 (_("add recording (indefinitely)"), "indefinitely"), \
1692                                 (_("add recording (enter recording duration)"), "manualduration"), \
1693                                 (_("add recording (enter recording endtime)"), "manualendtime"), \
1694                                 (_("change recording (duration)"), "changeduration"), \
1695                                 (_("change recording (endtime)"), "changeendtime"), \
1696                                 (_("do nothing"), "no")))
1697                 else:
1698                         self.session.openWithCallback(self.recordQuestionCallback, ChoiceBox, \
1699                                 title=_("Start recording?"), \
1700                                 list=((_("add recording (stop after current event)"), "event"), \
1701                                 (_("add recording (indefinitely)"), "indefinitely"), \
1702                                 (_("add recording (enter recording duration)"), "manualduration"), \
1703                                 (_("add recording (enter recording endtime)"), "manualendtime"), \
1704                                 (_("don't record"), "no")))
1705
1706 from Tools.ISO639 import LanguageCodes
1707
1708 class InfoBarAudioSelection:
1709         def __init__(self):
1710                 self["AudioSelectionAction"] = HelpableActionMap(self, "InfobarAudioSelectionActions",
1711                         {
1712                                 "audioSelection": (self.audioSelection, _("Audio Options...")),
1713                         })
1714
1715         def audioSelection(self):
1716                 from Screens.AudioSelection import AudioSelection
1717                 self.session.openWithCallback(self.audioSelected, AudioSelection, infobar=self)
1718                 
1719         def audioSelected(self, ret=None):
1720                 print "[infobar::audioSelected]", ret
1721
1722 class InfoBarSubserviceSelection:
1723         def __init__(self):
1724                 self["SubserviceSelectionAction"] = HelpableActionMap(self, "InfobarSubserviceSelectionActions",
1725                         {
1726                                 "subserviceSelection": (self.subserviceSelection, _("Subservice list...")),
1727                         })
1728
1729                 self["SubserviceQuickzapAction"] = HelpableActionMap(self, "InfobarSubserviceQuickzapActions",
1730                         {
1731                                 "nextSubservice": (self.nextSubservice, _("Switch to next subservice")),
1732                                 "prevSubservice": (self.prevSubservice, _("Switch to previous subservice"))
1733                         }, -1)
1734                 self["SubserviceQuickzapAction"].setEnabled(False)
1735
1736                 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1737                         {
1738                                 iPlayableService.evUpdatedEventInfo: self.checkSubservicesAvail
1739                         })
1740
1741                 self.bsel = None
1742
1743         def checkSubservicesAvail(self):
1744                 service = self.session.nav.getCurrentService()
1745                 subservices = service and service.subServices()
1746                 if not subservices or subservices.getNumberOfSubservices() == 0:
1747                         self["SubserviceQuickzapAction"].setEnabled(False)
1748
1749         def nextSubservice(self):
1750                 self.changeSubservice(+1)
1751
1752         def prevSubservice(self):
1753                 self.changeSubservice(-1)
1754
1755         def changeSubservice(self, direction):
1756                 service = self.session.nav.getCurrentService()
1757                 subservices = service and service.subServices()
1758                 n = subservices and subservices.getNumberOfSubservices()
1759                 if n and n > 0:
1760                         selection = -1
1761                         ref = self.session.nav.getCurrentlyPlayingServiceReference()
1762                         idx = 0
1763                         while idx < n:
1764                                 if subservices.getSubservice(idx).toString() == ref.toString():
1765                                         selection = idx
1766                                         break
1767                                 idx += 1
1768                         if selection != -1:
1769                                 selection += direction
1770                                 if selection >= n:
1771                                         selection=0
1772                                 elif selection < 0:
1773                                         selection=n-1
1774                                 newservice = subservices.getSubservice(selection)
1775                                 if newservice.valid():
1776                                         del subservices
1777                                         del service
1778                                         self.session.nav.playService(newservice, False)
1779
1780         def subserviceSelection(self):
1781                 service = self.session.nav.getCurrentService()
1782                 subservices = service and service.subServices()
1783                 self.bouquets = self.servicelist.getBouquetList()
1784                 n = subservices and subservices.getNumberOfSubservices()
1785                 selection = 0
1786                 if n and n > 0:
1787                         ref = self.session.nav.getCurrentlyPlayingServiceReference()
1788                         tlist = []
1789                         idx = 0
1790                         while idx < n:
1791                                 i = subservices.getSubservice(idx)
1792                                 if i.toString() == ref.toString():
1793                                         selection = idx
1794                                 tlist.append((i.getName(), i))
1795                                 idx += 1
1796
1797                         if self.bouquets and len(self.bouquets):
1798                                 keys = ["red", "blue", "",  "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" ] + [""] * n
1799                                 if config.usage.multibouquet.value:
1800                                         tlist = [(_("Quickzap"), "quickzap", service.subServices()), (_("Add to bouquet"), "CALLFUNC", self.addSubserviceToBouquetCallback), ("--", "")] + tlist
1801                                 else:
1802                                         tlist = [(_("Quickzap"), "quickzap", service.subServices()), (_("Add to favourites"), "CALLFUNC", self.addSubserviceToBouquetCallback), ("--", "")] + tlist
1803                                 selection += 3
1804                         else:
1805                                 tlist = [(_("Quickzap"), "quickzap", service.subServices()), ("--", "")] + tlist
1806                                 keys = ["red", "",  "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" ] + [""] * n
1807                                 selection += 2
1808
1809                         self.session.openWithCallback(self.subserviceSelected, ChoiceBox, title=_("Please select a subservice..."), list = tlist, selection = selection, keys = keys, skin_name = "SubserviceSelection")
1810
1811         def subserviceSelected(self, service):
1812                 del self.bouquets
1813                 if not service is None:
1814                         if isinstance(service[1], str):
1815                                 if service[1] == "quickzap":
1816                                         from Screens.SubservicesQuickzap import SubservicesQuickzap
1817                                         self.session.open(SubservicesQuickzap, service[2])
1818                         else:
1819                                 self["SubserviceQuickzapAction"].setEnabled(True)
1820                                 self.session.nav.playService(service[1], False)
1821
1822         def addSubserviceToBouquetCallback(self, service):
1823                 if len(service) > 1 and isinstance(service[1], eServiceReference):
1824                         self.selectedSubservice = service
1825                         if self.bouquets is None:
1826                                 cnt = 0
1827                         else:
1828                                 cnt = len(self.bouquets)
1829                         if cnt > 1: # show bouquet list
1830                                 self.bsel = self.session.openWithCallback(self.bouquetSelClosed, BouquetSelector, self.bouquets, self.addSubserviceToBouquet)
1831                         elif cnt == 1: # add to only one existing bouquet
1832                                 self.addSubserviceToBouquet(self.bouquets[0][1])
1833                                 self.session.open(MessageBox, _("Service has been added to the favourites."), MessageBox.TYPE_INFO)
1834
1835         def bouquetSelClosed(self, confirmed):
1836                 self.bsel = None
1837                 del self.selectedSubservice
1838                 if confirmed:
1839                         self.session.open(MessageBox, _("Service has been added to the selected bouquet."), MessageBox.TYPE_INFO)
1840
1841         def addSubserviceToBouquet(self, dest):
1842                 self.servicelist.addServiceToBouquet(dest, self.selectedSubservice[1])
1843                 if self.bsel:
1844                         self.bsel.close(True)
1845                 else:
1846                         del self.selectedSubservice
1847
1848 from Components.Sources.HbbtvApplication import HbbtvApplication
1849 gHbbtvApplication = HbbtvApplication()
1850 class InfoBarRedButton:
1851         def __init__(self):
1852                 if not (config.misc.rcused.value == 1):
1853                         self["RedButtonActions"] = HelpableActionMap(self, "InfobarRedButtonActions",
1854                                 {
1855                                         "activateRedButton": (self.activateRedButton, _("Red button...")),
1856                                 })
1857                         self["HbbtvApplication"] = gHbbtvApplication
1858                 else:
1859                         self["HbbtvApplication"] = Boolean(fixed=0)
1860                         self["HbbtvApplication"].name = "" #is this a hack?
1861                         
1862                 self.onHBBTVActivation = [ ]
1863                 self.onRedButtonActivation = [ ]
1864                 self.onReadyForAIT = [ ]
1865                 self.__et = ServiceEventTracker(screen=self, eventmap=
1866                         {
1867                                 iPlayableService.evHBBTVInfo: self.detectedHbbtvApplication,
1868                                 iPlayableService.evUpdatedInfo: self.updateInfomation
1869                         })
1870
1871         def updateAIT(self, orgId=0):
1872                 for x in self.onReadyForAIT:
1873                         try:
1874                                 x(orgId)
1875                         except Exception, ErrMsg: 
1876                                 print ErrMsg
1877                                 #self.onReadyForAIT.remove(x)
1878
1879         def updateInfomation(self):
1880                 try:
1881                         self["HbbtvApplication"].setApplicationName("")
1882                         self.updateAIT()
1883                 except Exception, ErrMsg:
1884                         pass
1885                 
1886         def detectedHbbtvApplication(self):
1887                 service = self.session.nav.getCurrentService()
1888                 info = service and service.info()
1889                 try:
1890                         for x in info.getInfoObject(iServiceInformation.sHBBTVUrl):
1891                                 print x
1892                                 if x[0] in (-1, 1):
1893                                         self.updateAIT(x[3])
1894                                         self["HbbtvApplication"].setApplicationName(x[1])
1895                                         break
1896                 except Exception, ErrMsg:
1897                         pass
1898
1899         def activateRedButton(self):
1900                 service = self.session.nav.getCurrentService()
1901                 info = service and service.info()
1902                 if info and info.getInfoString(iServiceInformation.sHBBTVUrl) != "":
1903                         for x in self.onHBBTVActivation:
1904                                 x()
1905                 elif False: # TODO: other red button services
1906                         for x in self.onRedButtonActivation:
1907                                 x()
1908
1909 class InfoBarAdditionalInfo:
1910         def __init__(self):
1911
1912                 self["RecordingPossible"] = Boolean(fixed=harddiskmanager.HDDCount() > 0 and config.misc.rcused.value == 1)
1913                 self["TimeshiftPossible"] = self["RecordingPossible"]
1914                 self["ShowTimeshiftOnYellow"] = Boolean(fixed=(config.misc.rcused.value == 1))
1915                 self["ShowAudioOnYellow"] = Boolean(fixed=config.misc.rcused.value != 1)
1916                 self["ShowRecordOnRed"] = Boolean(fixed=config.misc.rcused.value == 1)
1917                 self["ExtensionsAvailable"] = Boolean(fixed=1)
1918
1919 class InfoBarNotifications:
1920         def __init__(self):
1921                 self.onExecBegin.append(self.checkNotifications)
1922                 Notifications.notificationAdded.append(self.checkNotificationsIfExecing)
1923                 self.onClose.append(self.__removeNotification)
1924
1925         def __removeNotification(self):
1926                 Notifications.notificationAdded.remove(self.checkNotificationsIfExecing)
1927
1928         def checkNotificationsIfExecing(self):
1929                 if self.execing:
1930                         self.checkNotifications()
1931
1932         def checkNotifications(self):
1933                 notifications = Notifications.notifications
1934                 if notifications:
1935                         n = notifications[0]
1936
1937                         del notifications[0]
1938                         cb = n[0]
1939
1940                         if n[3].has_key("onSessionOpenCallback"):
1941                                 n[3]["onSessionOpenCallback"]()
1942                                 del n[3]["onSessionOpenCallback"]
1943
1944                         if cb is not None:
1945                                 dlg = self.session.openWithCallback(cb, n[1], *n[2], **n[3])
1946                         else:
1947                                 dlg = self.session.open(n[1], *n[2], **n[3])
1948
1949                         # remember that this notification is currently active
1950                         d = (n[4], dlg)
1951                         Notifications.current_notifications.append(d)
1952                         dlg.onClose.append(boundFunction(self.__notificationClosed, d))
1953
1954         def __notificationClosed(self, d):
1955                 Notifications.current_notifications.remove(d)
1956
1957 class InfoBarServiceNotifications:
1958         def __init__(self):
1959                 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1960                         {
1961                                 iPlayableService.evEnd: self.serviceHasEnded
1962                         })
1963
1964         def serviceHasEnded(self):
1965                 print "service end!"
1966
1967                 try:
1968                         self.setSeekState(self.SEEK_STATE_PLAY)
1969                 except:
1970                         pass
1971
1972 class InfoBarCueSheetSupport:
1973         CUT_TYPE_IN = 0
1974         CUT_TYPE_OUT = 1
1975         CUT_TYPE_MARK = 2
1976         CUT_TYPE_LAST = 3
1977
1978         ENABLE_RESUME_SUPPORT = False
1979
1980         def __init__(self, actionmap = "InfobarCueSheetActions"):
1981                 self["CueSheetActions"] = HelpableActionMap(self, actionmap,
1982                         {
1983                                 "jumpPreviousMark": (self.jumpPreviousMark, _("jump to previous marked position")),
1984                                 "jumpNextMark": (self.jumpNextMark, _("jump to next marked position")),
1985                                 "toggleMark": (self.toggleMark, _("toggle a cut mark at the current position"))
1986                         }, prio=1)
1987
1988                 self.cut_list = [ ]
1989                 self.is_closing = False
1990                 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1991                         {
1992                                 iPlayableService.evStart: self.__serviceStarted,
1993                         })
1994
1995         def __serviceStarted(self):
1996                 if self.is_closing:
1997                         return
1998                 print "new service started! trying to download cuts!"
1999                 self.downloadCuesheet()
2000
2001                 if self.ENABLE_RESUME_SUPPORT:
2002                         last = None
2003
2004                         for (pts, what) in self.cut_list:
2005                                 if what == self.CUT_TYPE_LAST:
2006                                         last = pts
2007
2008                         if last is not None:
2009                                 self.resume_point = last
2010                                 
2011                                 l = last / 90000
2012                                 if config.usage.on_movie_start.value == "ask":
2013                                         Notifications.AddNotificationWithCallback(self.playLastCB, MessageBox, _("Do you want to resume this playback?") + "\n" + (_("Resume position at %s") % ("%d:%02d:%02d" % (l/3600, l%3600/60, l%60))), timeout=10)
2014                                 elif config.usage.on_movie_start.value == "resume":
2015 # TRANSLATORS: The string "Resuming playback" flashes for a moment
2016 # TRANSLATORS: at the start of a movie, when the user has selected
2017 # TRANSLATORS: "Resume from last position" as start behavior.
2018 # TRANSLATORS: The purpose is to notify the user that the movie starts
2019 # TRANSLATORS: in the middle somewhere and not from the beginning.
2020 # TRANSLATORS: (Some translators seem to have interpreted it as a
2021 # TRANSLATORS: question or a choice, but it is a statement.)
2022                                         Notifications.AddNotificationWithCallback(self.playLastCB, MessageBox, _("Resuming playback"), timeout=2, type=MessageBox.TYPE_INFO)
2023
2024         def playLastCB(self, answer):
2025                 if answer == True:
2026                         self.doSeek(self.resume_point)
2027                 self.hideAfterResume()
2028
2029         def hideAfterResume(self):
2030                 if isinstance(self, InfoBarShowHide):
2031                         self.hide()
2032
2033         def __getSeekable(self):
2034                 service = self.session.nav.getCurrentService()
2035                 if service is None:
2036                         return None
2037                 return service.seek()
2038
2039         def cueGetCurrentPosition(self):
2040                 seek = self.__getSeekable()
2041                 if seek is None:
2042                         return None
2043                 r = seek.getPlayPosition()
2044                 if r[0]:
2045                         return None
2046                 return long(r[1])
2047
2048         def cueGetEndCutPosition(self):
2049                 ret = False
2050                 isin = True
2051                 for cp in self.cut_list:
2052                         if cp[1] == self.CUT_TYPE_OUT:
2053                                 if isin:
2054                                         isin = False
2055                                         ret = cp[0]
2056                         elif cp[1] == self.CUT_TYPE_IN:
2057                                 isin = True
2058                 return ret
2059                 
2060         def jumpPreviousNextMark(self, cmp, start=False):
2061                 current_pos = self.cueGetCurrentPosition()
2062                 if current_pos is None:
2063                         return False
2064                 mark = self.getNearestCutPoint(current_pos, cmp=cmp, start=start)
2065                 if mark is not None:
2066                         pts = mark[0]
2067                 else:
2068                         return False
2069
2070                 self.doSeek(pts)
2071                 return True
2072
2073         def jumpPreviousMark(self):
2074                 # we add 5 seconds, so if the play position is <5s after
2075                 # the mark, the mark before will be used
2076                 self.jumpPreviousNextMark(lambda x: -x-5*90000, start=True)
2077
2078         def jumpNextMark(self):
2079                 if not self.jumpPreviousNextMark(lambda x: x-90000):
2080                         self.doSeek(-1)
2081
2082         def getNearestCutPoint(self, pts, cmp=abs, start=False):
2083                 # can be optimized
2084                 beforecut = True
2085                 nearest = None
2086                 bestdiff = -1
2087                 instate = True
2088                 if start:
2089                         bestdiff = cmp(0 - pts)
2090                         if bestdiff >= 0:
2091                                 nearest = [0, False]
2092                 for cp in self.cut_list:
2093                         if beforecut and cp[1] in (self.CUT_TYPE_IN, self.CUT_TYPE_OUT):
2094                                 beforecut = False
2095                                 if cp[1] == self.CUT_TYPE_IN:  # Start is here, disregard previous marks
2096                                         diff = cmp(cp[0] - pts)
2097                                         if start and diff >= 0:
2098                                                 nearest = cp
2099                                                 bestdiff = diff
2100                                         else:
2101                                                 nearest = None
2102                                                 bestdiff = -1
2103                         if cp[1] == self.CUT_TYPE_IN:
2104                                 instate = True
2105                         elif cp[1] == self.CUT_TYPE_OUT:
2106                                 instate = False
2107                         elif cp[1] in (self.CUT_TYPE_MARK, self.CUT_TYPE_LAST):
2108                                 diff = cmp(cp[0] - pts)
2109                                 if instate and diff >= 0 and (nearest is None or bestdiff > diff):
2110                                         nearest = cp
2111                                         bestdiff = diff
2112                 return nearest
2113
2114         def toggleMark(self, onlyremove=False, onlyadd=False, tolerance=5*90000, onlyreturn=False):
2115                 current_pos = self.cueGetCurrentPosition()
2116                 if current_pos is None:
2117                         print "not seekable"
2118                         return
2119
2120                 nearest_cutpoint = self.getNearestCutPoint(current_pos)
2121
2122                 if nearest_cutpoint is not None and abs(nearest_cutpoint[0] - current_pos) < tolerance:
2123                         if onlyreturn:
2124                                 return nearest_cutpoint
2125                         if not onlyadd:
2126                                 self.removeMark(nearest_cutpoint)
2127                 elif not onlyremove and not onlyreturn:
2128                         self.addMark((current_pos, self.CUT_TYPE_MARK))
2129
2130                 if onlyreturn:
2131                         return None
2132
2133         def addMark(self, point):
2134                 insort(self.cut_list, point)
2135                 self.uploadCuesheet()
2136                 self.showAfterCuesheetOperation()
2137
2138         def removeMark(self, point):
2139                 self.cut_list.remove(point)
2140                 self.uploadCuesheet()
2141                 self.showAfterCuesheetOperation()
2142
2143         def showAfterCuesheetOperation(self):
2144                 if isinstance(self, InfoBarShowHide):
2145                         self.doShow()
2146
2147         def __getCuesheet(self):
2148                 service = self.session.nav.getCurrentService()
2149                 if service is None:
2150                         return None
2151                 return service.cueSheet()
2152
2153         def uploadCuesheet(self):
2154                 cue = self.__getCuesheet()
2155
2156                 if cue is None:
2157                         print "upload failed, no cuesheet interface"
2158                         return
2159                 cue.setCutList(self.cut_list)
2160
2161         def downloadCuesheet(self):
2162                 cue = self.__getCuesheet()
2163
2164                 if cue is None:
2165                         print "download failed, no cuesheet interface"
2166                         self.cut_list = [ ]
2167                 else:
2168                         self.cut_list = cue.getCutList()
2169
2170 class InfoBarSummary(Screen):
2171         skin = """
2172         <screen position="0,0" size="132,64">
2173                 <widget source="global.CurrentTime" render="Label" position="62,46" size="82,18" font="Regular;16" >
2174                         <convert type="ClockToText">WithSeconds</convert>
2175                 </widget>
2176                 <widget source="session.RecordState" render="FixedLabel" text=" " position="62,46" size="82,18" zPosition="1" >
2177                         <convert type="ConfigEntryTest">config.usage.blinking_display_clock_during_recording,True,CheckSourceBoolean</convert>
2178                         <convert type="ConditionalShowHide">Blink</convert>
2179                 </widget>
2180                 <widget source="session.CurrentService" render="Label" position="6,4" size="120,42" font="Regular;18" >
2181                         <convert type="ServiceName">Name</convert>
2182                 </widget>
2183                 <widget source="session.Event_Now" render="Progress" position="6,46" size="46,18" borderWidth="1" >
2184                         <convert type="EventTime">Progress</convert>
2185                 </widget>
2186         </screen>"""
2187
2188 # for picon:  (path="piconlcd" will use LCD picons)
2189 #               <widget source="session.CurrentService" render="Picon" position="6,0" size="120,64" path="piconlcd" >
2190 #                       <convert type="ServiceName">Reference</convert>
2191 #               </widget>
2192
2193 class InfoBarSummarySupport:
2194         def __init__(self):
2195                 pass
2196
2197         def createSummary(self):
2198                 return InfoBarSummary
2199
2200 class InfoBarMoviePlayerSummary(Screen):
2201         skin = """
2202         <screen position="0,0" size="132,64">
2203                 <widget source="global.CurrentTime" render="Label" position="62,46" size="64,18" font="Regular;16" halign="right" >
2204                         <convert type="ClockToText">WithSeconds</convert>
2205                 </widget>
2206                 <widget source="session.RecordState" render="FixedLabel" text=" " position="62,46" size="64,18" zPosition="1" >
2207                         <convert type="ConfigEntryTest">config.usage.blinking_display_clock_during_recording,True,CheckSourceBoolean</convert>
2208                         <convert type="ConditionalShowHide">Blink</convert>
2209                 </widget>
2210                 <widget source="session.CurrentService" render="Label" position="6,4" size="120,42" font="Regular;18" >
2211                         <convert type="ServiceName">Name</convert>
2212                 </widget>
2213                 <widget source="session.CurrentService" render="Progress" position="6,46" size="56,18" borderWidth="1" >
2214                         <convert type="ServicePosition">Position</convert>
2215                 </widget>
2216         </screen>"""
2217
2218 class InfoBarMoviePlayerSummarySupport:
2219         def __init__(self):
2220                 pass
2221
2222         def createSummary(self):
2223                 return InfoBarMoviePlayerSummary
2224
2225 class InfoBarTeletextPlugin:
2226         def __init__(self):
2227                 self.teletext_plugin = None
2228
2229                 for p in plugins.getPlugins(PluginDescriptor.WHERE_TELETEXT):
2230                         self.teletext_plugin = p
2231
2232                 if self.teletext_plugin is not None:
2233                         self["TeletextActions"] = HelpableActionMap(self, "InfobarTeletextActions",
2234                                 {
2235                                         "startTeletext": (self.startTeletext, _("View teletext..."))
2236                                 })
2237                 else:
2238                         print "no teletext plugin found!"
2239
2240         def startTeletext(self):
2241                 self.teletext_plugin(session=self.session, service=self.session.nav.getCurrentService())
2242
2243 class InfoBarSubtitleSupport(object):
2244         def __init__(self):
2245                 object.__init__(self)
2246                 self.subtitle_window = self.session.instantiateDialog(SubtitleDisplay)
2247                 self.subtitle_window.setAnimationMode(0)
2248                 self.__subtitles_enabled = False
2249
2250                 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
2251                         {
2252                                 iPlayableService.evEnd: self.__serviceStopped,
2253                                 iPlayableService.evUpdatedInfo: self.__updatedInfo
2254                         })
2255                 self.cached_subtitle_checked = False
2256                 self.__selected_subtitle = None
2257
2258         def __serviceStopped(self):
2259                 self.cached_subtitle_checked = False
2260                 if self.__subtitles_enabled:
2261                         self.subtitle_window.hide()
2262                         self.__subtitles_enabled = False
2263                         self.__selected_subtitle = None
2264
2265         def __updatedInfo(self):
2266                 if not self.__selected_subtitle:
2267                         subtitle = self.getCurrentServiceSubtitle()
2268                         self.setSelectedSubtitle(subtitle and subtitle.getCachedSubtitle())
2269                         if self.__selected_subtitle:
2270                                 self.setSubtitlesEnable(True)
2271
2272         def getCurrentServiceSubtitle(self):
2273                 service = self.session.nav.getCurrentService()
2274                 return service and service.subtitle()
2275
2276         def setSubtitlesEnable(self, enable=True):
2277                 subtitle = self.getCurrentServiceSubtitle()
2278                 if enable:
2279                         if self.__selected_subtitle:
2280                                 if subtitle and not self.__subtitles_enabled:
2281                                         subtitle.enableSubtitles(self.subtitle_window.instance, self.selected_subtitle)
2282                                         self.subtitle_window.show()
2283                                         self.__subtitles_enabled = True
2284                 else:
2285                         if subtitle:
2286                                 subtitle.disableSubtitles(self.subtitle_window.instance)
2287                         self.__selected_subtitle = None
2288                         self.__subtitles_enabled = False
2289                         self.subtitle_window.hide()
2290
2291         def setSelectedSubtitle(self, subtitle):
2292                 self.__selected_subtitle = subtitle
2293
2294         subtitles_enabled = property(lambda self: self.__subtitles_enabled, setSubtitlesEnable)
2295         selected_subtitle = property(lambda self: self.__selected_subtitle, setSelectedSubtitle)
2296
2297 class InfoBarServiceErrorPopupSupport:
2298         def __init__(self):
2299                 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
2300                         {
2301                                 iPlayableService.evTuneFailed: self.__tuneFailed,
2302                                 iPlayableService.evStart: self.__serviceStarted
2303                         })
2304                 self.__serviceStarted()
2305
2306         def __serviceStarted(self):
2307                 self.last_error = None
2308                 Notifications.RemovePopup(id = "ZapError")
2309
2310         def __tuneFailed(self):
2311                 service = self.session.nav.getCurrentService()
2312                 info = service and service.info()
2313                 error = info and info.getInfo(iServiceInformation.sDVBState)
2314
2315                 if error == self.last_error:
2316                         error = None
2317                 else:
2318                         self.last_error = error
2319
2320                 error = {
2321                         eDVBServicePMTHandler.eventNoResources: _("No free tuner!"),
2322                         eDVBServicePMTHandler.eventTuneFailed: _("Tune failed!"),
2323                         eDVBServicePMTHandler.eventNoPAT: _("No data on transponder!\n(Timeout reading PAT)"),
2324                         eDVBServicePMTHandler.eventNoPATEntry: _("Service not found!\n(SID not found in PAT)"),
2325                         eDVBServicePMTHandler.eventNoPMT: _("Service invalid!\n(Timeout reading PMT)"),
2326                         eDVBServicePMTHandler.eventNewProgramInfo: None,
2327                         eDVBServicePMTHandler.eventTuned: None,
2328                         eDVBServicePMTHandler.eventSOF: None,
2329                         eDVBServicePMTHandler.eventEOF: None,
2330                         eDVBServicePMTHandler.eventMisconfiguration: _("Service unavailable!\nCheck tuner configuration!"),
2331                 }.get(error) #this returns None when the key not exist in the dict
2332
2333                 if error is not None:
2334                         Notifications.AddPopup(text = error, type = MessageBox.TYPE_ERROR, timeout = 5, id = "ZapError")
2335                 else:
2336                         Notifications.RemovePopup(id = "ZapError")
2337
2338 class InfoBarHDMI:
2339         def __init__(self):
2340                 self.hdmiInServiceRef = eServiceReference('8192:0:1:0:0:0:0:0:0:0:')
2341
2342                 if SystemInfo.get("HdmiInSupport", False):
2343                         self.addExtension((self.getShowHdmiInName, self.HDMIIn, lambda: True), None)
2344                         self.addExtension((self.getShowHdmiInPIPName, self.HDMIInPIP, self.showHDMIPIPMenu), None)
2345
2346         def getShowHdmiInName(self):
2347                 curref = self.session.nav.getCurrentlyPlayingServiceReference()
2348                 if curref and curref.type == 8192:
2349                         name = _("Disable HDMI-IN on Main Screen")
2350                 else:
2351                         name = _("Enable HDMI-IN on Main Screen")
2352
2353                 return name
2354
2355         def getShowHdmiInPIPName(self):
2356                 return _("Enable HDMI-IN on PIP")
2357
2358         def showHDMIPIPMenu(self):
2359                 _pipAvailable = SystemInfo.get("NumVideoDecoders", 1) > 1
2360
2361                 hdmiin_enabled = False
2362                 curref = self.session.nav.getCurrentlyPlayingServiceReference()
2363                 if curref and curref.type == 8192:
2364                         hdmiin_enabled = True
2365
2366                 hdmiin_pip_shown = False
2367                 if self.session.pipshown:
2368                         pipref=self.session.pip.getCurrentService()
2369                         if pipref and pipref.type == 8192:
2370                                 hdmiin_pip_shown = True
2371
2372                 return _pipAvailable and not hdmiin_enabled and not hdmiin_pip_shown
2373
2374         def getCurrentServiceRef(self):
2375                 slist = self.servicelist
2376                 currentServiceSref = slist.servicelist.getCurrent()
2377                 return currentServiceSref
2378
2379         def HDMIIn(self):
2380                 curref = self.session.nav.getCurrentlyPlayingServiceReference()
2381                 if curref and curref.type == 8192:
2382                         self.session.nav.playService(self.getCurrentServiceRef())
2383                 else:
2384                         self.session.nav.playService(self.hdmiInServiceRef)
2385
2386         def HDMIInPIP(self):
2387                 if self.session.pipshown:
2388                         del self.session.pip
2389
2390                 self.session.pip = self.session.instantiateDialog(PictureInPicture)
2391                 self.session.pip.setAnimationMode(0)
2392                 self.session.pip.show()
2393                 newservice = self.hdmiInServiceRef
2394                 if self.session.pip.playService(newservice):
2395                         self.session.pipshown = True
2396                         self.session.pip.servicePath = self.servicelist.getCurrentServicePath()
2397                 else:
2398                         self.session.pipshown = False
2399                         del self.session.pip
2400                         self.session.openWithCallback(self.close, MessageBox, _("Could not open Picture in Picture"), MessageBox.TYPE_ERROR)