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