dont show the infobar when close the last open screen
[vuplus_dvbapp] / lib / python / Screens / InfoBarGenerics.py
1 from ChannelSelection import ChannelSelection, BouquetSelector
2
3 from Components.ActionMap import ActionMap, HelpableActionMap
4 from Components.ActionMap import NumberActionMap
5 from Components.BlinkingPixmap import BlinkingPixmapConditional
6 from Components.Harddisk import harddiskmanager
7 from Components.Input import Input
8 from Components.Label import *
9 from Components.Pixmap import Pixmap, PixmapConditional
10 from Components.PluginComponent import plugins
11 from Components.ProgressBar import *
12 from Components.ServiceEventTracker import ServiceEventTracker
13 from Components.Sources.CurrentService import CurrentService
14 from Components.Sources.EventInfo import EventInfo
15 from Components.Sources.RadioText import RadioText
16 from Components.Sources.FrontendStatus import FrontendStatus
17 from Components.Sources.Boolean import Boolean
18 from Components.Sources.Clock import Clock
19 from Components.TimerList import TimerEntryComponent
20 from Components.config import config, ConfigBoolean
21
22 from EpgSelection import EPGSelection
23 from Plugins.Plugin import PluginDescriptor
24
25 from Screen import Screen
26 from Screens.ChoiceBox import ChoiceBox
27 from Screens.Dish import Dish
28 from Screens.EventView import EventViewEPGSelect, EventViewSimple
29 from Screens.InputBox import InputBox
30 from Screens.MessageBox import MessageBox
31 from Screens.MinuteInput import MinuteInput
32 from Screens.TimerSelection import TimerSelection
33 from Screens.PictureInPicture import PictureInPicture
34 from Screens.SubtitleDisplay import SubtitleDisplay
35 from Screens.SleepTimerEdit import SleepTimerEdit
36 from ServiceReference import ServiceReference
37
38 from Tools import Notifications
39 from Tools.Directories import SCOPE_HDD, resolveFilename
40
41 from enigma import eTimer, eServiceCenter, eDVBServicePMTHandler, iServiceInformation, \
42         iPlayableService, eServiceReference, eDVBResourceManager, iFrontendInformation, eEPGCache
43
44 from time import time
45 from os import stat as os_stat
46 from bisect import insort
47
48 # hack alert!
49 from Menu import MainMenu, mdom
50
51 class InfoBarDish:
52         def __init__(self):
53                 self.dishDialog = self.session.instantiateDialog(Dish)
54                 self.onLayoutFinish.append(self.dishDialog.show)
55
56 class InfoBarShowHide:
57         """ InfoBar show/hide control, accepts toggleShow and hide actions, might start
58         fancy animations. """
59         STATE_HIDDEN = 0
60         STATE_HIDING = 1
61         STATE_SHOWING = 2
62         STATE_SHOWN = 3
63         
64         def __init__(self):
65                 self["ShowHideActions"] = ActionMap( ["InfobarShowHideActions"] ,
66                         {
67                                 "toggleShow": self.toggleShow,
68                                 "hide": self.hide,
69                         }, 1) # lower prio to make it possible to override ok and cancel..
70
71                 self.__state = self.STATE_SHOWN
72                 self.__locked = 0
73                 
74                 self.hideTimer = eTimer()
75                 self.hideTimer.timeout.get().append(self.doTimerHide)
76                 self.hideTimer.start(5000, True)
77                 
78                 self.onShow.append(self.__onShow)
79                 self.onHide.append(self.__onHide)
80
81         def __onShow(self):
82                 self.__state = self.STATE_SHOWN
83                 self.startHideTimer()
84         
85         def startHideTimer(self):
86                 if self.__state == self.STATE_SHOWN and not self.__locked:
87                         idx = config.usage.infobar_timeout.index
88                         if idx:
89                                 self.hideTimer.start(idx*1000, True)
90
91         def __onHide(self):
92                 self.__state = self.STATE_HIDDEN
93
94         def doShow(self):
95                 self.show()
96                 self.startHideTimer()
97
98         def doTimerHide(self):
99                 self.hideTimer.stop()
100                 if self.__state == self.STATE_SHOWN:
101                         self.hide()
102
103         def toggleShow(self):
104                 if self.__state == self.STATE_SHOWN:
105                         self.hide()
106                         self.hideTimer.stop()
107                 elif self.__state == self.STATE_HIDDEN:
108                         self.show()
109
110         def lockShow(self):
111                 self.__locked = self.__locked + 1
112                 if self.execing:
113                         self.show()
114                         self.hideTimer.stop()
115         
116         def unlockShow(self):
117                 self.__locked = self.__locked - 1
118                 if self.execing:
119                         self.startHideTimer()
120
121 #       def startShow(self):
122 #               self.instance.m_animation.startMoveAnimation(ePoint(0, 600), ePoint(0, 380), 100)
123 #               self.__state = self.STATE_SHOWN
124 #       
125 #       def startHide(self):
126 #               self.instance.m_animation.startMoveAnimation(ePoint(0, 380), ePoint(0, 600), 100)
127 #               self.__state = self.STATE_HIDDEN
128
129 class NumberZap(Screen):
130         def quit(self):
131                 self.Timer.stop()
132                 self.close(0)
133
134         def keyOK(self):
135                 self.Timer.stop()
136                 self.close(int(self["number"].getText()))
137
138         def keyNumberGlobal(self, number):
139                 self.Timer.start(3000, True)            #reset timer
140                 self.field = self.field + str(number)
141                 self["number"].setText(self.field)
142                 if len(self.field) >= 4:
143                         self.keyOK()
144
145         def __init__(self, session, number):
146                 Screen.__init__(self, session)
147                 self.field = str(number)
148
149                 self["channel"] = Label(_("Channel:"))
150
151                 self["number"] = Label(self.field)
152
153                 self["actions"] = NumberActionMap( [ "SetupActions" ], 
154                         {
155                                 "cancel": self.quit,
156                                 "ok": self.keyOK,
157                                 "1": self.keyNumberGlobal,
158                                 "2": self.keyNumberGlobal,
159                                 "3": self.keyNumberGlobal,
160                                 "4": self.keyNumberGlobal,
161                                 "5": self.keyNumberGlobal,
162                                 "6": self.keyNumberGlobal,
163                                 "7": self.keyNumberGlobal,
164                                 "8": self.keyNumberGlobal,
165                                 "9": self.keyNumberGlobal,
166                                 "0": self.keyNumberGlobal
167                         })
168
169                 self.Timer = eTimer()
170                 self.Timer.timeout.get().append(self.keyOK)
171                 self.Timer.start(3000, True)
172
173 class InfoBarNumberZap:
174         """ Handles an initial number for NumberZapping """
175         def __init__(self):
176                 self["NumberActions"] = NumberActionMap( [ "NumberActions"],
177                         {
178                                 "1": self.keyNumberGlobal,
179                                 "2": self.keyNumberGlobal,
180                                 "3": self.keyNumberGlobal,
181                                 "4": self.keyNumberGlobal,
182                                 "5": self.keyNumberGlobal,
183                                 "6": self.keyNumberGlobal,
184                                 "7": self.keyNumberGlobal,
185                                 "8": self.keyNumberGlobal,
186                                 "9": self.keyNumberGlobal,
187                                 "0": self.keyNumberGlobal,
188                         })
189
190         def keyNumberGlobal(self, number):
191 #               print "You pressed number " + str(number)
192                 if number == 0:
193                         self.servicelist.recallPrevService()
194                         if config.usage.show_infobar_on_zap.value:
195                                 self.doShow()
196                 else:
197                         self.session.openWithCallback(self.numberEntered, NumberZap, number)
198
199         def numberEntered(self, retval):
200 #               print self.servicelist
201                 if retval > 0:
202                         self.zapToNumber(retval)
203
204         def searchNumberHelper(self, serviceHandler, num, bouquet):
205                 servicelist = serviceHandler.list(bouquet)
206                 if not servicelist is None:
207                         while num:
208                                 serviceIterator = servicelist.getNext()
209                                 if not serviceIterator.valid(): #check end of list
210                                         break
211                                 playable = not (serviceIterator.flags & (eServiceReference.isMarker|eServiceReference.isDirectory))
212                                 if playable:
213                                         num -= 1;
214                         if not num: #found service with searched number ?
215                                 return serviceIterator, 0
216                 return None, num
217
218         def zapToNumber(self, number):
219                 bouquet = self.servicelist.bouquet_root
220                 service = None
221                 serviceHandler = eServiceCenter.getInstance()
222                 if not config.usage.multibouquet.value:
223                         service, number = self.searchNumberHelper(serviceHandler, number, bouquet)
224                 else:
225                         bouquetlist = serviceHandler.list(bouquet)
226                         if not bouquetlist is None:
227                                 while number:
228                                         bouquet = bouquetlist.getNext()
229                                         if not bouquet.valid(): #check end of list
230                                                 break
231                                         if bouquet.flags & eServiceReference.isDirectory:
232                                                 service, number = self.searchNumberHelper(serviceHandler, number, bouquet)
233                 if not service is None:
234                         if self.servicelist.getRoot() != bouquet: #already in correct bouquet?
235                                 self.servicelist.clearPath()
236                                 if self.servicelist.bouquet_root != bouquet:
237                                         self.servicelist.enterPath(self.servicelist.bouquet_root)
238                                 self.servicelist.enterPath(bouquet)
239                         self.servicelist.setCurrentSelection(service) #select the service in servicelist
240                         self.servicelist.zap()
241
242 config.misc.initialchannelselection = ConfigBoolean(default = True)
243
244 class InfoBarChannelSelection:
245         """ ChannelSelection - handles the channelSelection dialog and the initial 
246         channelChange actions which open the channelSelection dialog """
247         def __init__(self):
248                 #instantiate forever
249                 self.servicelist = self.session.instantiateDialog(ChannelSelection)
250                 
251                 if config.misc.initialchannelselection.value:
252                         self.onShown.append(self.firstRun)
253
254                 self["ChannelSelectActions"] = HelpableActionMap(self, "InfobarChannelSelection",
255                         {
256                                 "switchChannelUp": (self.switchChannelUp, _("open servicelist(up)")),
257                                 "switchChannelDown": (self.switchChannelDown, _("open servicelist(down)")),
258                                 "zapUp": (self.zapUp, _("previous channel")),
259                                 "zapDown": (self.zapDown, _("next channel")),
260                                 "historyBack": (self.historyBack, _("previous channel in history")),
261                                 "historyNext": (self.historyNext, _("next channel in history")),
262                                 "openServiceList": (self.openServiceList, _("open servicelist")),
263                         })
264
265         def showTvChannelList(self, zap=False):
266                 self.servicelist.setModeTv()
267                 if zap:
268                         self.servicelist.zap()
269                 self.session.execDialog(self.servicelist)
270
271         def showRadioChannelList(self, zap=False):
272                 self.servicelist.setModeRadio()
273                 if zap:
274                         self.servicelist.zap()
275                 self.session.execDialog(self.servicelist)
276
277         def firstRun(self):
278                 self.onShown.remove(self.firstRun)
279                 config.misc.initialchannelselection.value = False
280                 config.misc.initialchannelselection.save()
281                 self.switchChannelDown()
282
283         def historyBack(self):
284                 self.servicelist.historyBack()
285
286         def historyNext(self):
287                 self.servicelist.historyNext()
288
289         def switchChannelUp(self):
290                 self.servicelist.moveUp()
291                 self.session.execDialog(self.servicelist)
292
293         def switchChannelDown(self):
294                 self.servicelist.moveDown()
295                 self.session.execDialog(self.servicelist)
296         
297         def openServiceList(self):
298                 self.session.execDialog(self.servicelist)
299
300         def zapUp(self):
301                 if self.servicelist.inBouquet():
302                         prev = self.servicelist.getCurrentSelection()
303                         if prev:
304                                 prev = prev.toString()
305                                 while True:
306                                         if config.usage.quickzap_bouquet_change.value:
307                                                 if self.servicelist.atBegin():
308                                                         self.servicelist.prevBouquet()
309                                         self.servicelist.moveUp()
310                                         cur = self.servicelist.getCurrentSelection()
311                                         if not cur or (not (cur.flags & 64)) or cur.toString() == prev:
312                                                 break
313                 else:
314                         self.servicelist.moveUp()
315                 self.servicelist.zap()
316                 if config.usage.show_infobar_on_zap.value:
317                         self.doShow()
318
319         def zapDown(self):
320                 if self.servicelist.inBouquet():
321                         prev = self.servicelist.getCurrentSelection()
322                         if prev:
323                                 prev = prev.toString()
324                                 while True:
325                                         if config.usage.quickzap_bouquet_change.value and self.servicelist.atEnd():
326                                                 self.servicelist.nextBouquet()
327                                         else:
328                                                 self.servicelist.moveDown()
329                                         cur = self.servicelist.getCurrentSelection()
330                                         if not cur or (not (cur.flags & 64)) or cur.toString() == prev:
331                                                 break
332                 else:
333                         self.servicelist.moveDown()
334                 self.servicelist.zap()
335                 if config.usage.show_infobar_on_zap.value:
336                         self.doShow()
337
338 class InfoBarMenu:
339         """ Handles a menu action, to open the (main) menu """
340         def __init__(self):
341                 self["MenuActions"] = HelpableActionMap(self, "InfobarMenuActions", 
342                         {
343                                 "mainMenu": (self.mainMenu, _("Enter main menu...")),
344                         })
345                 self.session.infobar = None
346
347         def mainMenu(self):
348                 print "loading mainmenu XML..."
349                 menu = mdom.childNodes[0]
350                 assert menu.tagName == "menu", "root element in menu must be 'menu'!"
351
352                 self.session.infobar = self
353                 # so we can access the currently active infobar from screens opened from within the mainmenu
354                 # at the moment used from the SubserviceSelection
355
356                 self.session.openWithCallback(self.mainMenuClosed, MainMenu, menu, menu.childNodes)
357
358         def mainMenuClosed(self, *val):
359                 self.session.infobar = None
360
361 class InfoBarSimpleEventView:
362         """ Opens the Eventview for now/next """
363         def __init__(self):
364                 self["EPGActions"] = HelpableActionMap(self, "InfobarEPGActions",
365                         {
366                                 "showEventInfo": (self.openEventView, _("show event details")),
367                         })
368
369         def openEventView(self):
370                 self.epglist = [ ]
371                 service = self.session.nav.getCurrentService()
372                 ref = self.session.nav.getCurrentlyPlayingServiceReference()
373                 info = service.info()
374                 ptr=info.getEvent(0)
375                 if ptr:
376                         self.epglist.append(ptr)
377                 ptr=info.getEvent(1)
378                 if ptr:
379                         self.epglist.append(ptr)
380                 if len(self.epglist) > 0:
381                         self.session.open(EventViewSimple, self.epglist[0], ServiceReference(ref), self.eventViewCallback)
382
383         def eventViewCallback(self, setEvent, setService, val): #used for now/next displaying
384                 if len(self.epglist) > 1:
385                         tmp = self.epglist[0]
386                         self.epglist[0]=self.epglist[1]
387                         self.epglist[1]=tmp
388                         setEvent(self.epglist[0])
389
390 class InfoBarEPG:
391         """ EPG - Opens an EPG list when the showEPGList action fires """
392         def __init__(self):
393                 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
394                         {
395                                 iPlayableService.evUpdatedEventInfo: self.__evEventInfoChanged,
396                         })
397
398                 self.is_now_next = False
399                 self.dlg_stack = [ ]
400                 self.bouquetSel = None
401                 self.eventView = None
402                 self["EPGActions"] = HelpableActionMap(self, "InfobarEPGActions", 
403                         {
404                                 "showEventInfo": (self.openEventView, _("show EPG...")),
405                         })
406
407         def zapToService(self, service):
408                 if not service is None:
409                         if self.servicelist.getRoot() != self.epg_bouquet: #already in correct bouquet?
410                                 self.servicelist.clearPath()
411                                 if self.servicelist.bouquet_root != self.epg_bouquet:
412                                         self.servicelist.enterPath(self.servicelist.bouquet_root)
413                                 self.servicelist.enterPath(self.epg_bouquet)
414                         self.servicelist.setCurrentSelection(service) #select the service in servicelist
415                         self.servicelist.zap()
416
417         def getBouquetServices(self, bouquet):
418                 services = [ ]
419                 servicelist = eServiceCenter.getInstance().list(bouquet)
420                 if not servicelist is None:
421                         while True:
422                                 service = servicelist.getNext()
423                                 if not service.valid(): #check if end of list
424                                         break
425                                 if service.flags & (eServiceReference.isDirectory | eServiceReference.isMarker): #ignore non playable services
426                                         continue
427                                 services.append(ServiceReference(service))
428                 return services
429
430         def openBouquetEPG(self, bouquet, withCallback=True):
431                 services = self.getBouquetServices(bouquet)
432                 if len(services):
433                         self.epg_bouquet = bouquet
434                         if withCallback:
435                                 self.dlg_stack.append(self.session.openWithCallback(self.closed, EPGSelection, services, self.zapToService, None, self.changeBouquetCB))
436                         else:
437                                 self.session.open(EPGSelection, services, self.zapToService, None, self.changeBouquetCB)
438
439         def changeBouquetCB(self, direction, epg):
440                 if self.bouquetSel:
441                         if direction > 0:
442                                 self.bouquetSel.down()
443                         else:
444                                 self.bouquetSel.up()
445                         bouquet = self.bouquetSel.getCurrent()
446                         services = self.getBouquetServices(bouquet)
447                         if len(services):
448                                 self.epg_bouquet = bouquet
449                                 epg.setServices(services)
450
451         def closed(self, ret=False):
452                 closedScreen = self.dlg_stack.pop()
453                 if self.bouquetSel and closedScreen == self.bouquetSel:
454                         self.bouquetSel = None
455                 elif self.eventView and closedScreen == self.eventView:
456                         self.eventView = None
457                 if ret:
458                         dlgs=len(self.dlg_stack)
459                         if dlgs > 0:
460                                 self.dlg_stack[dlgs-1].close(dlgs > 1)
461
462         def openMultiServiceEPG(self, withCallback=True):
463                 bouquets = self.servicelist.getBouquetList()
464                 if bouquets is None:
465                         cnt = 0
466                 else:
467                         cnt = len(bouquets)
468                 if cnt > 1: # show bouquet list
469                         if withCallback:
470                                 self.bouquetSel = self.session.openWithCallback(self.closed, BouquetSelector, bouquets, self.openBouquetEPG, enableWrapAround=True)
471                                 self.dlg_stack.append(self.bouquetSel)
472                         else:
473                                 self.bouquetSel = self.session.open(BouquetSelector, bouquets, self.openBouquetEPG, enableWrapAround=True)
474                 elif cnt == 1: 
475                         self.openBouquetEPG(bouquets[0][1], withCallback)
476
477         def openSingleServiceEPG(self):
478                 ref=self.session.nav.getCurrentlyPlayingServiceReference()
479                 self.session.open(EPGSelection, ref)
480
481         def openSimilarList(self, eventid, refstr):
482                 self.session.open(EPGSelection, refstr, None, eventid)
483
484         def getNowNext(self):
485                 self.epglist = [ ]
486                 service = self.session.nav.getCurrentService()
487                 info = service and service.info()
488                 ptr = info and info.getEvent(0)
489                 if ptr:
490                         self.epglist.append(ptr)
491                 ptr = info and info.getEvent(1)
492                 if ptr:
493                         self.epglist.append(ptr)
494
495         def __evEventInfoChanged(self):
496                 if self.is_now_next and len(self.dlg_stack) == 1:
497                         self.getNowNext()
498                         assert self.eventView
499                         if len(self.epglist):
500                                 self.eventView.setEvent(self.epglist[0])
501
502         def openEventView(self):
503                 ref = self.session.nav.getCurrentlyPlayingServiceReference()
504                 self.getNowNext()
505                 if len(self.epglist) == 0:
506                         self.is_now_next = False
507                         epg = eEPGCache.getInstance()
508                         ptr = ref and ref.valid() and epg.lookupEventTime(ref, -1)
509                         if ptr:
510                                 self.epglist.append(ptr)
511                                 ptr = epg.lookupEventTime(ref, ptr.getBeginTime(), +1)
512                                 if ptr:
513                                         self.epglist.append(ptr)
514                 else:
515                         self.is_now_next = True
516                 if len(self.epglist) > 0:
517                         self.eventView = self.session.openWithCallback(self.closed, EventViewEPGSelect, self.epglist[0], ServiceReference(ref), self.eventViewCallback, self.openSingleServiceEPG, self.openMultiServiceEPG, self.openSimilarList)
518                         self.dlg_stack.append(self.eventView)
519                 else:
520                         print "no epg for the service avail.. so we show multiepg instead of eventinfo"
521                         self.openMultiServiceEPG(False)
522
523         def eventViewCallback(self, setEvent, setService, val): #used for now/next displaying
524                 if len(self.epglist) > 1:
525                         tmp = self.epglist[0]
526                         self.epglist[0]=self.epglist[1]
527                         self.epglist[1]=tmp
528                         setEvent(self.epglist[0])
529
530 class InfoBarTuner:
531         """provides a snr/agc/ber display"""
532         def __init__(self):
533                 self["FrontendStatus"] = FrontendStatus(service_source = self.session.nav.getCurrentService)
534
535 class InfoBarEvent:
536         """provides a current/next event info display"""
537         def __init__(self):
538                 self["Event_Now"] = EventInfo(self.session.nav, EventInfo.NOW)
539                 self["Event_Next"] = EventInfo(self.session.nav, EventInfo.NEXT)
540
541 class InfoBarRadioText:
542         """provides radio (RDS) text info display"""
543         def __init__(self):
544                 self["RadioText"] = RadioText(self.session.nav)
545
546 class InfoBarServiceName:
547         def __init__(self):
548                 self["CurrentService"] = CurrentService(self.session.nav)
549
550 class InfoBarSeek:
551         """handles actions like seeking, pause"""
552         
553         # ispause, isff, issm
554         SEEK_STATE_PLAY = (0, 0, 0, ">")
555         SEEK_STATE_PAUSE = (1, 0, 0, "||")
556         SEEK_STATE_FF_2X = (0, 2, 0, ">> 2x")
557         SEEK_STATE_FF_4X = (0, 4, 0, ">> 4x")
558         SEEK_STATE_FF_8X = (0, 8, 0, ">> 8x")
559         SEEK_STATE_FF_32X = (0, 32, 0, ">> 32x")
560         SEEK_STATE_FF_64X = (0, 64, 0, ">> 64x")
561         SEEK_STATE_FF_128X = (0, 128, 0, ">> 128x")
562         
563         SEEK_STATE_BACK_16X = (0, -16, 0, "<< 16x")
564         SEEK_STATE_BACK_32X = (0, -32, 0, "<< 32x")
565         SEEK_STATE_BACK_64X = (0, -64, 0, "<< 64x")
566         SEEK_STATE_BACK_128X = (0, -128, 0, "<< 128x")
567         
568         SEEK_STATE_SM_HALF = (0, 0, 2, "/2")
569         SEEK_STATE_SM_QUARTER = (0, 0, 4, "/4")
570         SEEK_STATE_SM_EIGHTH = (0, 0, 8, "/8")
571         
572         def __init__(self):
573                 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
574                         {
575                                 iPlayableService.evSeekableStatusChanged: self.__seekableStatusChanged,
576                                 iPlayableService.evStart: self.__serviceStarted,
577                                 
578                                 iPlayableService.evEOF: self.__evEOF,
579                                 iPlayableService.evSOF: self.__evSOF,
580                         })
581
582                 class InfoBarSeekActionMap(HelpableActionMap):
583                         def __init__(self, screen, *args, **kwargs):
584                                 HelpableActionMap.__init__(self, screen, *args, **kwargs)
585                                 self.screen = screen
586                                 
587                         def action(self, contexts, action):
588                                 if action[:5] == "seek:":
589                                         time = int(action[5:])
590                                         self.screen.seekRelative(time * 90000)
591                                         return 1
592                                 else:
593                                         return HelpableActionMap.action(self, contexts, action)
594
595                 self["SeekActions"] = InfoBarSeekActionMap(self, "InfobarSeekActions", 
596                         {
597                                 "playpauseService": (self.playpauseService, _("pause")),
598                                 "pauseService": (self.pauseService, _("pause")),
599                                 "unPauseService": (self.unPauseService, _("continue")),
600                                 
601                                 "seekFwd": (self.seekFwd, _("skip forward")),
602                                 "seekFwdDown": self.seekFwdDown,
603                                 "seekFwdUp": self.seekFwdUp,
604                                 "seekBack": (self.seekBack, _("skip backward")),
605                                 "seekBackDown": self.seekBackDown,
606                                 "seekBackUp": self.seekBackUp,
607                         }, prio=-1)
608                         # give them a little more priority to win over color buttons
609
610                 self["SeekActions"].setEnabled(False)
611
612                 self.seekstate = self.SEEK_STATE_PLAY
613                 self.onClose.append(self.delTimer)
614                 
615                 self.fwdtimer = False
616                 self.fwdKeyTimer = eTimer()
617                 self.fwdKeyTimer.timeout.get().append(self.fwdTimerFire)
618
619                 self.rwdtimer = False
620                 self.rwdKeyTimer = eTimer()
621                 self.rwdKeyTimer.timeout.get().append(self.rwdTimerFire)
622                 
623                 self.onPlayStateChanged = [ ]
624                 
625                 self.lockedBecauseOfSkipping = False
626         
627         def up(self):
628                 pass
629         
630         def down(self):
631                 pass
632         
633         def delTimer(self):
634                 del self.fwdKeyTimer
635                 del self.rwdKeyTimer
636         
637         def getSeek(self):
638                 service = self.session.nav.getCurrentService()
639                 if service is None:
640                         return None
641
642                 seek = service.seek()
643
644                 if seek is None or not seek.isCurrentlySeekable():
645                         return None
646                 
647                 return seek
648         
649         def isSeekable(self):
650                 if self.getSeek() is None:
651                         return False
652                 return True
653
654         def __seekableStatusChanged(self):
655                 print "seekable status changed!"
656                 if not self.isSeekable():
657                         self["SeekActions"].setEnabled(False)
658                         print "not seekable, return to play"
659                         self.setSeekState(self.SEEK_STATE_PLAY)
660                 else:
661                         self["SeekActions"].setEnabled(True)
662                         print "seekable"
663
664         def __serviceStarted(self):
665                 self.seekstate = self.SEEK_STATE_PLAY
666
667         def setSeekState(self, state):
668                 service = self.session.nav.getCurrentService()
669                 
670                 if service is None:
671                         return False
672                 
673                 if not self.isSeekable():
674                         if state not in [self.SEEK_STATE_PLAY, self.SEEK_STATE_PAUSE]:
675                                 state = self.SEEK_STATE_PLAY
676                 
677                 pauseable = service.pause()
678
679                 if pauseable is None:
680                         print "not pauseable."
681                         state = self.SEEK_STATE_PLAY
682                 
683                 oldstate = self.seekstate
684                 self.seekstate = state
685                 
686                 for i in range(3):
687                         if oldstate[i] != self.seekstate[i]:
688                                 (self.session.nav.pause, pauseable.setFastForward, pauseable.setSlowMotion)[i](self.seekstate[i])
689
690                 for c in self.onPlayStateChanged:
691                         c(self.seekstate)
692                 
693                 self.checkSkipShowHideLock()
694
695                 return True
696         
697         def playpauseService(self):
698                 if self.seekstate != self.SEEK_STATE_PLAY:
699                         self.unPauseService()
700                 else:
701                         self.pauseService()
702
703         def pauseService(self):
704                 if self.seekstate == self.SEEK_STATE_PAUSE:
705                         print "pause, but in fact unpause"
706                         self.unPauseService()
707                 else:
708                         if self.seekstate == self.SEEK_STATE_PLAY:
709                                 print "yes, playing."
710                         else:
711                                 print "no", self.seekstate
712                         print "pause"
713                         self.setSeekState(self.SEEK_STATE_PAUSE);
714                 
715         def unPauseService(self):
716                 print "unpause"
717                 if self.seekstate == self.SEEK_STATE_PLAY:
718                         return 0
719                 self.setSeekState(self.SEEK_STATE_PLAY)
720         
721         def doSeek(self, seektime):
722                 print "doseek", seektime
723                 service = self.session.nav.getCurrentService()
724                 if service is None:
725                         return
726                 
727                 seekable = self.getSeek()
728                 if seekable is None:
729                         return
730                 
731                 seekable.seekTo(90 * seektime)
732
733         def seekFwdDown(self):
734                 print "start fwd timer"
735                 self.fwdtimer = True
736                 self.fwdKeyTimer.start(1000)
737
738         def seekBackDown(self):
739                 print "start rewind timer"
740                 self.rwdtimer = True
741                 self.rwdKeyTimer.start(1000)
742
743         def seekFwdUp(self):
744                 print "seekFwdUp"
745                 if self.fwdtimer:
746                         self.fwdKeyTimer.stop()
747                         self.fwdtimer = False
748                         self.seekFwd()
749
750         def seekFwd(self):
751                 lookup = {
752                                 self.SEEK_STATE_PLAY: self.SEEK_STATE_FF_2X,
753                                 self.SEEK_STATE_PAUSE: self.SEEK_STATE_SM_EIGHTH,
754                                 self.SEEK_STATE_FF_2X: self.SEEK_STATE_FF_4X,
755                                 self.SEEK_STATE_FF_4X: self.SEEK_STATE_FF_8X,
756                                 self.SEEK_STATE_FF_8X: self.SEEK_STATE_FF_32X,
757                                 self.SEEK_STATE_FF_32X: self.SEEK_STATE_FF_64X,
758                                 self.SEEK_STATE_FF_64X: self.SEEK_STATE_FF_128X,
759                                 self.SEEK_STATE_FF_128X: self.SEEK_STATE_FF_128X,
760                                 self.SEEK_STATE_BACK_16X: self.SEEK_STATE_PLAY,
761                                 self.SEEK_STATE_BACK_32X: self.SEEK_STATE_BACK_16X,
762                                 self.SEEK_STATE_BACK_64X: self.SEEK_STATE_BACK_32X,
763                                 self.SEEK_STATE_BACK_128X: self.SEEK_STATE_BACK_64X,
764                                 self.SEEK_STATE_SM_HALF: self.SEEK_STATE_SM_HALF,
765                                 self.SEEK_STATE_SM_QUARTER: self.SEEK_STATE_SM_HALF,
766                                 self.SEEK_STATE_SM_EIGHTH: self.SEEK_STATE_SM_QUARTER
767                         }
768                 self.setSeekState(lookup[self.seekstate])
769         
770         def seekBackUp(self):
771                 print "seekBackUp"
772                 if self.rwdtimer:
773                         self.rwdKeyTimer.stop()
774                         self.rwdtimer = False
775                         self.seekBack()
776                 
777         def seekBack(self):
778                 lookup = {
779                                 self.SEEK_STATE_PLAY: self.SEEK_STATE_BACK_16X,
780                                 self.SEEK_STATE_PAUSE: self.SEEK_STATE_PAUSE,
781                                 self.SEEK_STATE_FF_2X: self.SEEK_STATE_PLAY,
782                                 self.SEEK_STATE_FF_4X: self.SEEK_STATE_FF_2X,
783                                 self.SEEK_STATE_FF_8X: self.SEEK_STATE_FF_4X,
784                                 self.SEEK_STATE_FF_32X: self.SEEK_STATE_FF_8X,
785                                 self.SEEK_STATE_FF_64X: self.SEEK_STATE_FF_32X,
786                                 self.SEEK_STATE_FF_128X: self.SEEK_STATE_FF_64X,
787                                 self.SEEK_STATE_BACK_16X: self.SEEK_STATE_BACK_32X,
788                                 self.SEEK_STATE_BACK_32X: self.SEEK_STATE_BACK_64X,
789                                 self.SEEK_STATE_BACK_64X: self.SEEK_STATE_BACK_128X,
790                                 self.SEEK_STATE_BACK_128X: self.SEEK_STATE_BACK_128X,
791                                 self.SEEK_STATE_SM_HALF: self.SEEK_STATE_SM_QUARTER,
792                                 self.SEEK_STATE_SM_QUARTER: self.SEEK_STATE_SM_EIGHTH,
793                                 self.SEEK_STATE_SM_EIGHTH: self.SEEK_STATE_PAUSE
794                         }
795                 self.setSeekState(lookup[self.seekstate])
796                 
797                 if self.seekstate == self.SEEK_STATE_PAUSE:
798                         seekable = self.getSeek()
799                         if seekable is not None:
800                                 seekable.seekRelative(-1, 3)
801
802         def fwdTimerFire(self):
803                 print "Display seek fwd"
804                 self.fwdKeyTimer.stop()
805                 self.fwdtimer = False
806                 self.session.openWithCallback(self.fwdSeekTo, MinuteInput)
807                 
808         def fwdSeekTo(self, minutes):
809                 print "Seek", minutes, "minutes forward"
810                 if minutes != 0:
811                         seekable = self.getSeek()
812                         if seekable is not None:
813                                 seekable.seekRelative(1, minutes * 60 * 90000)
814         
815         def rwdTimerFire(self):
816                 print "rwdTimerFire"
817                 self.rwdKeyTimer.stop()
818                 self.rwdtimer = False
819                 self.session.openWithCallback(self.rwdSeekTo, MinuteInput)
820         
821         def rwdSeekTo(self, minutes):
822                 print "rwdSeekTo"
823                 self.fwdSeekTo(0 - minutes)
824         
825         def checkSkipShowHideLock(self):
826                 wantlock = self.seekstate != self.SEEK_STATE_PLAY
827                 
828                 if config.usage.show_infobar_on_zap.value:
829                         if self.lockedBecauseOfSkipping and not wantlock:
830                                 self.unlockShow()
831                                 self.lockedBecauseOfSkipping = False
832                 
833                         if wantlock and not self.lockedBecauseOfSkipping:
834                                 self.lockShow()
835                                 self.lockedBecauseOfSkipping = True
836
837         def __evEOF(self):
838                 if self.seekstate != self.SEEK_STATE_PLAY:
839                         self.setSeekState(self.SEEK_STATE_PAUSE)
840                         # HACK
841                         #self.getSeek().seekRelative(1, -90000)
842                         self.setSeekState(self.SEEK_STATE_PLAY)
843                 else:
844                         self.setSeekState(self.SEEK_STATE_PAUSE)
845         
846         def __evSOF(self):
847                 self.setSeekState(self.SEEK_STATE_PLAY)
848                 self.doSeek(0)
849
850         def seekRelative(self, diff):
851                 seekable = self.getSeek()
852                 if seekable is not None:
853                         seekable.seekRelative(1, diff)
854
855         def seekAbsolute(self, abs):
856                 seekable = self.getSeek()
857                 if seekable is not None:
858                         seekable.seekTo(abs)
859
860 from Screens.PVRState import PVRState, TimeshiftState
861
862 class InfoBarPVRState:
863         def __init__(self, screen=PVRState):
864                 self.onPlayStateChanged.append(self.__playStateChanged)
865                 self.pvrStateDialog = self.session.instantiateDialog(screen)
866                 self.onShow.append(self._mayShow)
867                 self.onHide.append(self.pvrStateDialog.hide)
868
869         def _mayShow(self):
870                 if self.execing and self.seekstate != self.SEEK_STATE_PLAY:
871                         self.pvrStateDialog.show()
872
873         def __playStateChanged(self, state):
874                 playstateString = state[3]
875                 self.pvrStateDialog["state"].setText(playstateString)
876                 self._mayShow()
877
878 class InfoBarTimeshiftState(InfoBarPVRState):
879         def __init__(self):
880                 InfoBarPVRState.__init__(self, screen=TimeshiftState)
881
882         def _mayShow(self):
883                 if self.execing and self.timeshift_enabled:
884                         self.pvrStateDialog.show()
885
886 class InfoBarShowMovies:
887
888         # i don't really like this class. 
889         # it calls a not further specified "movie list" on up/down/movieList,
890         # so this is not more than an action map
891         def __init__(self):
892                 self["MovieListActions"] = HelpableActionMap(self, "InfobarMovieListActions", 
893                         {
894                                 "movieList": (self.showMovies, "movie list"),
895                                 "up": (self.showMovies, "movie list"),
896                                 "down": (self.showMovies, "movie list")
897                         })
898
899 # InfoBarTimeshift requires InfoBarSeek, instantiated BEFORE!
900
901 # Hrmf.
902 #
903 # Timeshift works the following way:
904 #                                         demux0   demux1                    "TimeshiftActions" "TimeshiftActivateActions" "SeekActions"
905 # - normal playback                       TUNER    unused      PLAY               enable                disable              disable
906 # - user presses "yellow" button.         TUNER    record      PAUSE              enable                disable              enable
907 # - user presess pause again              FILE     record      PLAY               enable                disable              enable
908 # - user fast forwards                    FILE     record      FF                 enable                disable              enable
909 # - end of timeshift buffer reached       TUNER    record      PLAY               enable                enable               disable
910 # - user backwards                        FILE     record      BACK  # !!         enable                disable              enable
911 #
912
913 # in other words:
914 # - when a service is playing, pressing the "timeshiftStart" button ("yellow") enables recording ("enables timeshift"),
915 # freezes the picture (to indicate timeshift), sets timeshiftMode ("activates timeshift")
916 # now, the service becomes seekable, so "SeekActions" are enabled, "TimeshiftEnableActions" are disabled.
917 # - the user can now PVR around
918 # - if it hits the end, the service goes into live mode ("deactivates timeshift", it's of course still "enabled")
919 # the service looses it's "seekable" state. It can still be paused, but just to activate timeshift right
920 # after!
921 # the seek actions will be disabled, but the timeshiftActivateActions will be enabled
922 # - if the user rewinds, or press pause, timeshift will be activated again
923
924 # note that a timeshift can be enabled ("recording") and
925 # activated (currently time-shifting).
926
927 class InfoBarTimeshift:
928         def __init__(self):
929                 self["TimeshiftActions"] = HelpableActionMap(self, "InfobarTimeshiftActions", 
930                         {
931                                 "timeshiftStart": (self.startTimeshift, _("start timeshift")),  # the "yellow key"
932                                 "timeshiftStop": (self.stopTimeshift, _("stop timeshift"))      # currently undefined :), probably 'TV'
933                         }, prio=1)
934                 self["TimeshiftActivateActions"] = ActionMap(["InfobarTimeshiftActivateActions"],
935                         {
936                                 "timeshiftActivateEnd": self.activateTimeshiftEnd, # something like "pause key"
937                                 "timeshiftActivateEndAndPause": self.activateTimeshiftEndAndPause  # something like "backward key"
938                         }, prio=-1) # priority over record
939
940                 self.timeshift_enabled = 0
941                 self.timeshift_state = 0
942                 self.ts_pause_timer = eTimer()
943                 self.ts_pause_timer.timeout.get().append(self.pauseService)
944
945                 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
946                         {
947                                 iPlayableService.evStart: self.__serviceStarted,
948                                 iPlayableService.evSeekableStatusChanged: self.__seekableStatusChanged
949                         })
950         
951         def getTimeshift(self):
952                 service = self.session.nav.getCurrentService()
953                 return service and service.timeshift()
954
955         def startTimeshift(self):
956                 print "enable timeshift"
957                 ts = self.getTimeshift()
958                 if ts is None:
959                         self.session.open(MessageBox, _("Timeshift not possible!"), MessageBox.TYPE_ERROR)
960                         print "no ts interface"
961                         return 0;
962                 
963                 if self.timeshift_enabled:
964                         print "hu, timeshift already enabled?"
965                 else:
966                         if not ts.startTimeshift():
967                                 self.timeshift_enabled = 1
968
969                                 # we remove the "relative time" for now.
970                                 #self.pvrStateDialog["timeshift"].setRelative(time.time())
971                                         
972                                 # PAUSE.
973                                 self.setSeekState(self.SEEK_STATE_PAUSE)
974                                 
975                                 # enable the "TimeshiftEnableActions", which will override
976                                 # the startTimeshift actions
977                                 self.__seekableStatusChanged()
978                         else:
979                                 print "timeshift failed"
980
981         def stopTimeshift(self):
982                 if not self.timeshift_enabled:
983                         return 0
984                 print "disable timeshift"
985                 ts = self.getTimeshift()
986                 if ts is None:
987                         return 0
988                 self.session.openWithCallback(self.stopTimeshiftConfirmed, MessageBox, _("Stop Timeshift?"), MessageBox.TYPE_YESNO)
989
990         def stopTimeshiftConfirmed(self, confirmed):
991                 if not confirmed:
992                         return
993
994                 ts = self.getTimeshift()
995                 if ts is None:
996                         return
997
998                 ts.stopTimeshift()
999                 self.timeshift_enabled = 0
1000
1001                 # disable actions
1002                 self.__seekableStatusChanged()
1003         
1004         # activates timeshift, and seeks to (almost) the end
1005         def activateTimeshiftEnd(self):
1006                 ts = self.getTimeshift()
1007                 
1008                 if ts is None:
1009                         return
1010                 
1011                 if ts.isTimeshiftActive():
1012                         print "!! activate timeshift called - but shouldn't this be a normal pause?"
1013                         self.pauseService()
1014                 else:
1015                         self.setSeekState(self.SEEK_STATE_PLAY)
1016                         ts.activateTimeshift()
1017                         self.seekRelative(0)
1018         
1019         # same as activateTimeshiftEnd, but pauses afterwards.
1020         def activateTimeshiftEndAndPause(self):
1021                 state = self.seekstate
1022                 self.activateTimeshiftEnd()
1023                 
1024                 # well, this is "andPause", but it could be pressed from pause,
1025                 # when pausing on the (fake-)"live" picture, so an un-pause
1026                 # is perfectly ok.
1027                 
1028                 print "now, pauseService"
1029                 if state == self.SEEK_STATE_PLAY:
1030                         print "is PLAYING, start pause timer"
1031                         self.ts_pause_timer.start(200, 1)
1032                 else:
1033                         print "unpause"
1034                         self.unPauseService()
1035         
1036         def __seekableStatusChanged(self):
1037                 enabled = False
1038                 
1039                 print "self.isSeekable", self.isSeekable()
1040                 print "self.timeshift_enabled", self.timeshift_enabled
1041                 
1042                 # when this service is not seekable, but timeshift
1043                 # is enabled, this means we can activate
1044                 # the timeshift
1045                 if not self.isSeekable() and self.timeshift_enabled:
1046                         enabled = True
1047
1048                 print "timeshift activate:", enabled
1049                 self["TimeshiftActivateActions"].setEnabled(enabled)
1050
1051         def __serviceStarted(self):
1052                 self.timeshift_enabled = False
1053                 self.__seekableStatusChanged()
1054
1055 from Screens.PiPSetup import PiPSetup
1056
1057 class InfoBarExtensions:
1058         EXTENSION_SINGLE = 0
1059         EXTENSION_LIST = 1
1060         
1061         def __init__(self):
1062                 self.list = []
1063                 
1064                 self["InstantExtensionsActions"] = HelpableActionMap(self, "InfobarExtensions",
1065                         {
1066                                 "extensions": (self.showExtensionSelection, _("view extensions...")),
1067                         })
1068
1069         def addExtension(self, extension, key = None, type = EXTENSION_SINGLE):
1070                 self.list.append((type, extension, key))
1071                 
1072         def updateExtension(self, extension, key = None):
1073                 self.extensionsList.append(extension)
1074                 if key is not None:
1075                         if self.extensionKeys.has_key(key):
1076                                 key = None
1077                 
1078                 if key is None:
1079                         for x in self.availableKeys:
1080                                 if not self.extensionKeys.has_key(x):
1081                                         key = x
1082                                         break
1083
1084                 if key is not None:
1085                         self.extensionKeys[key] = len(self.extensionsList) - 1
1086                         
1087         def updateExtensions(self):
1088                 self.extensionsList = []
1089                 self.availableKeys = [ "1", "2", "3", "4", "5", "6", "7", "8", "9", "0", "red", "green", "yellow", "blue" ]
1090                 self.extensionKeys = {}
1091                 for x in self.list:
1092                         if x[0] == self.EXTENSION_SINGLE:
1093                                 self.updateExtension(x[1], x[2])
1094                         else:
1095                                 for y in x[1]():
1096                                         self.updateExtension(y[0], y[1])
1097
1098
1099         def showExtensionSelection(self):
1100                 self.updateExtensions()
1101                 extensionsList = self.extensionsList[:]
1102                 keys = []
1103                 list = []
1104                 for x in self.availableKeys:
1105                         if self.extensionKeys.has_key(x):
1106                                 entry = self.extensionKeys[x]
1107                                 extension = self.extensionsList[entry]
1108                                 if extension[2]():
1109                                         name = str(extension[0]())
1110                                         list.append((extension[0](), extension))
1111                                         keys.append(x)
1112                                         extensionsList.remove(extension)
1113                                 else:
1114                                         extensionsList.remove(extension)
1115                 for x in extensionsList:
1116                         list.append((x[0](), x))
1117                 keys += [""] * len(extensionsList)
1118                 self.session.openWithCallback(self.extensionCallback, ChoiceBox, title=_("Please choose an extension..."), list = list, keys = keys)
1119
1120         def extensionCallback(self, answer):
1121                 if answer is not None:
1122                         answer[1][1]()
1123
1124 from Tools.BoundFunction import boundFunction
1125
1126 # depends on InfoBarExtensions
1127 from Components.PluginComponent import plugins
1128
1129 class InfoBarPlugins:
1130         def __init__(self):
1131                 self.addExtension(extension = self.getPluginList, type = InfoBarExtensions.EXTENSION_LIST)
1132                 
1133         def getPluginName(self, name):
1134                 return name
1135                 
1136         def getPluginList(self):
1137                 list = []
1138                 for p in plugins.getPlugins(where = PluginDescriptor.WHERE_EXTENSIONSMENU):
1139                         list.append(((boundFunction(self.getPluginName, p.name), boundFunction(self.runPlugin, p), lambda: True), None))
1140                 return list
1141
1142         def runPlugin(self, plugin):
1143                 plugin(session = self.session)
1144
1145 # depends on InfoBarExtensions
1146 class InfoBarSleepTimer:
1147         def __init__(self):
1148                 self.addExtension((self.getSleepTimerName, self.showSleepTimerSetup, self.available), "1")      
1149                 
1150         def available(self):
1151                 return True
1152
1153         def getSleepTimerName(self):
1154                 return _("Sleep Timer")
1155
1156         def showSleepTimerSetup(self):
1157                 self.session.open(SleepTimerEdit)
1158
1159 # depends on InfoBarExtensions
1160 class InfoBarPiP:
1161         def __init__(self):
1162                 self.session.pipshown = False
1163
1164                 self.addExtension((self.getShowHideName, self.showPiP, self.available), "blue")
1165                 self.addExtension((self.getMoveName, self.movePiP, self.pipShown), "green")
1166                 self.addExtension((self.getSwapName, self.swapPiP, self.pipShown), "yellow")
1167         
1168         def available(self):
1169                 return True
1170         
1171         def pipShown(self):
1172                 return self.session.pipshown
1173         
1174         def getShowHideName(self):
1175                 if self.session.pipshown:
1176                         return _("Disable Picture in Picture")
1177                 else:
1178                         return _("Activate Picture in Picture")
1179                 
1180         def getSwapName(self):
1181                 return _("Swap Services")
1182                 
1183         def getMoveName(self):
1184                 return _("Move Picture in Picture")
1185         
1186         def showPiP(self):
1187                 if self.session.pipshown:
1188                         del self.session.pip
1189                         self.session.pipshown = False
1190                 else:
1191                         self.session.pip = self.session.instantiateDialog(PictureInPicture)
1192                         newservice = self.session.nav.getCurrentlyPlayingServiceReference()
1193                         if self.session.pip.playService(newservice):
1194                                 self.session.pipshown = True
1195                                 self.session.pip.servicePath = self.servicelist.getCurrentServicePath()
1196                         else:
1197                                 self.session.pipshown = False
1198                                 del self.session.pip
1199                         self.session.nav.playService(newservice)
1200         
1201         def swapPiP(self):
1202                 swapservice = self.session.nav.getCurrentlyPlayingServiceReference()
1203                 if self.session.pip.servicePath:
1204                         servicepath = self.servicelist.getCurrentServicePath()
1205                         ref=servicepath[len(servicepath)-1]
1206                         pipref=self.session.pip.getCurrentService()
1207                         self.session.pip.playService(swapservice)
1208                         self.servicelist.setCurrentServicePath(self.session.pip.servicePath)
1209                         if pipref.toString() != ref.toString(): # is a subservice ?
1210                                 self.session.nav.stopService() # stop portal
1211                                 self.session.nav.playService(pipref) # start subservice
1212                         self.session.pip.servicePath=servicepath
1213         
1214         def movePiP(self):
1215                 self.session.open(PiPSetup, pip = self.session.pip)
1216
1217 from RecordTimer import parseEvent
1218
1219 class InfoBarInstantRecord:
1220         """Instant Record - handles the instantRecord action in order to 
1221         start/stop instant records"""
1222         def __init__(self):
1223                 self["InstantRecordActions"] = HelpableActionMap(self, "InfobarInstantRecord",
1224                         {
1225                                 "instantRecord": (self.instantRecord, _("Instant Record...")),
1226                         })
1227                 self.recording = []
1228                 self["BlinkingPoint"] = BlinkingPixmapConditional()
1229                 self["BlinkingPoint"].hide()
1230                 self["BlinkingPoint"].setConnect(self.session.nav.RecordTimer.isRecording)
1231
1232         def stopCurrentRecording(self, entry = -1):     
1233                 if entry is not None and entry != -1:
1234                         self.session.nav.RecordTimer.removeEntry(self.recording[entry])
1235                         self.recording.remove(self.recording[entry])
1236
1237         def startInstantRecording(self, limitEvent = False):
1238                 serviceref = self.session.nav.getCurrentlyPlayingServiceReference()
1239                 
1240                 # try to get event info
1241                 event = None
1242                 try:
1243                         service = self.session.nav.getCurrentService()
1244                         epg = eEPGCache.getInstance()
1245                         event = epg.lookupEventTime(serviceref, -1, 0)
1246                         if event is None:
1247                                 info = service.info()
1248                                 ev = info.getEvent(0)
1249                                 event = ev
1250                 except:
1251                         pass
1252
1253                 begin = time()
1254                 end = time() + 3600 * 10
1255                 name = "instant record"
1256                 description = ""
1257                 eventid = None
1258                 
1259                 if event is not None:
1260                         curEvent = parseEvent(event)
1261                         name = curEvent[2]
1262                         description = curEvent[3]
1263                         eventid = curEvent[4]
1264                         if limitEvent:
1265                                 end = curEvent[1]
1266                 else:
1267                         if limitEvent:
1268                                 self.session.open(MessageBox, _("No event info found, recording indefinitely."), MessageBox.TYPE_INFO)
1269                                 
1270                 data = (begin, end, name, description, eventid)
1271                 
1272                 recording = self.session.nav.recordWithTimer(serviceref, *data)
1273                 recording.dontSave = True
1274                 self.recording.append(recording)
1275                 
1276                 #self["BlinkingPoint"].setConnect(lambda: self.recording.isRunning())
1277                 
1278         def isInstantRecordRunning(self):
1279                 print "self.recording:", self.recording
1280                 if len(self.recording) > 0:
1281                         for x in self.recording:
1282                                 if x.isRunning():
1283                                         return True
1284                 return False
1285
1286         def recordQuestionCallback(self, answer):
1287                 print "pre:\n", self.recording
1288                 
1289                 if answer is None or answer[1] == "no":
1290                         return
1291                 list = []
1292                 recording = self.recording[:]
1293                 for x in recording:
1294                         if not x in self.session.nav.RecordTimer.timer_list:
1295                                 self.recording.remove(x)
1296                         elif x.dontSave and x.isRunning():
1297                                 list.append(TimerEntryComponent(x, False))              
1298
1299                 if answer[1] == "changeduration":
1300                         if len(self.recording) == 1:
1301                                 self.changeDuration(0)
1302                         else:
1303                                 self.session.openWithCallback(self.changeDuration, TimerSelection, list)
1304                 elif answer[1] == "stop":
1305                         if len(self.recording) == 1:
1306                                 self.stopCurrentRecording(0)
1307                         else:
1308                                 self.session.openWithCallback(self.stopCurrentRecording, TimerSelection, list)
1309                 if answer[1] == "indefinitely" or answer[1] == "manualduration" or answer[1] == "event":
1310                         limitEvent = False
1311                         if answer[1] == "event":
1312                                 limitEvent = True
1313                         if answer[1] == "manualduration":
1314                                 self.selectedEntry = len(self.recording)
1315                                 self.session.openWithCallback(self.inputCallback, InputBox, title=_("How many minutes do you want to record?"), text="5", maxSize=False, type=Input.NUMBER)
1316                         self.startInstantRecording(limitEvent = limitEvent)
1317                         
1318                 print "after:\n", self.recording
1319
1320         def changeDuration(self, entry):
1321                 if entry is not None:
1322                         self.selectedEntry = entry
1323                         self.session.openWithCallback(self.inputCallback, InputBox, title=_("How many minutes do you want to record?"), text="5", maxSize=False, type=Input.NUMBER)
1324
1325         def inputCallback(self, value):
1326                 if value is not None:
1327                         print "stopping recording after", int(value), "minutes."
1328                         self.recording[self.selectedEntry].end = time() + 60 * int(value)
1329                         self.session.nav.RecordTimer.timeChanged(self.recording[self.selectedEntry])
1330
1331         def instantRecord(self):
1332                 try:
1333                         stat = os_stat(resolveFilename(SCOPE_HDD))
1334                 except:
1335                         self.session.open(MessageBox, _("No HDD found or HDD not initialized!"), MessageBox.TYPE_ERROR)
1336                         return
1337
1338                 if self.isInstantRecordRunning():
1339                         self.session.openWithCallback(self.recordQuestionCallback, ChoiceBox, \
1340                                 title=_("A recording is currently running.\nWhat do you want to do?"), \
1341                                 list=[(_("stop recording"), "stop"), \
1342                                 (_("change recording (duration)"), "changeduration"), \
1343                                 (_("add recording (indefinitely)"), "indefinitely"), \
1344                                 (_("add recording (stop after current event)"), "event"), \
1345                                 (_("add recording (enter recording duration)"), "manualduration"), \
1346                                 (_("do nothing"), "no")])
1347                 else:
1348                         self.session.openWithCallback(self.recordQuestionCallback, ChoiceBox, \
1349                                 title=_("Start recording?"), \
1350                                 list=[(_("add recording (indefinitely)"), "indefinitely"), \
1351                                 (_("add recording (stop after current event)"), "event"), \
1352                                 (_("add recording (enter recording duration)"), "manualduration"), \
1353                                 (_("don't record"), "no")])
1354
1355 from Tools.ISO639 import LanguageCodes
1356
1357 class InfoBarAudioSelection:
1358         def __init__(self):
1359                 self["AudioSelectionAction"] = HelpableActionMap(self, "InfobarAudioSelectionActions", 
1360                         {
1361                                 "audioSelection": (self.audioSelection, _("Audio Options...")),
1362                         })
1363
1364         def audioSelection(self):
1365                 service = self.session.nav.getCurrentService()
1366                 audio = service and service.audioTracks()
1367                 self.audioTracks = audio
1368                 n = audio and audio.getNumberOfTracks() or 0
1369                 keys = [ "red", "", "1", "2", "3", "4", "5", "6", "7", "8", "9", "0"] + [""]*n
1370                 tlist = []
1371                 print "tlist:", tlist
1372                 if n > 0:
1373                         self.audioChannel = service.audioChannel()
1374
1375                         for x in range(n):
1376                                 i = audio.getTrackInfo(x)
1377                                 language = i.getLanguage()
1378                                 description = i.getDescription()
1379         
1380                                 if LanguageCodes.has_key(language):
1381                                         language = LanguageCodes[language][0]
1382         
1383                                 if len(description):
1384                                         description += " (" + language + ")"
1385                                 else:
1386                                         description = language
1387         
1388                                 tlist.append((description, x))
1389                         
1390                         selectedAudio = tlist[0][1]
1391                         tlist.sort(lambda x,y : cmp(x[0], y[0]))
1392
1393                         selection = 2
1394                         for x in tlist:
1395                                 if x[1] != selectedAudio:
1396                                         selection += 1
1397                                 else:
1398                                         break
1399
1400                         tlist = [([_("Left"), _("Stereo"), _("Right")][self.audioChannel.getCurrentChannel()], "mode"), ("--", "")] + tlist
1401                         self.session.openWithCallback(self.audioSelected, ChoiceBox, title=_("Select audio track"), list = tlist, selection = selection, keys = keys)
1402                 else:
1403                         del self.audioTracks
1404
1405         def audioSelected(self, audio):
1406                 if audio is not None:
1407                         if isinstance(audio[1], str):
1408                                 if audio[1] == "mode":
1409                                         keys = ["red", "green", "yellow"]
1410                                         selection = self.audioChannel.getCurrentChannel()
1411                                         tlist = [(_("left"), 0), (_("stereo"), 1), (_("right"), 2)]
1412                                         self.session.openWithCallback(self.modeSelected, ChoiceBox, title=_("Select audio mode"), list = tlist, selection = selection, keys = keys)
1413                         else:
1414                                 del self.audioChannel
1415                                 if self.session.nav.getCurrentService().audioTracks().getNumberOfTracks() > audio[1]:
1416                                         self.audioTracks.selectTrack(audio[1])
1417                 else:
1418                         del self.audioChannel
1419                 del self.audioTracks
1420
1421         def modeSelected(self, mode):
1422                 if mode is not None:
1423                         self.audioChannel.selectChannel(mode[1])
1424                 del self.audioChannel
1425
1426 class InfoBarSubserviceSelection:
1427         def __init__(self):
1428                 self["SubserviceSelectionAction"] = HelpableActionMap(self, "InfobarSubserviceSelectionActions",
1429                         {
1430                                 "subserviceSelection": (self.subserviceSelection, _("Subservice list...")),
1431                         })
1432
1433                 self["SubserviceQuickzapAction"] = HelpableActionMap(self, "InfobarSubserviceQuickzapActions",
1434                         {
1435                                 "nextSubservice": (self.nextSubservice, _("Switch to next subservice")),
1436                                 "prevSubservice": (self.prevSubservice, _("Switch to previous subservice"))
1437                         }, -1)
1438                 self["SubserviceQuickzapAction"].setEnabled(False)
1439
1440                 self.session.nav.event.append(self.checkSubservicesAvail) # we like to get service events
1441
1442                 self.bsel = None
1443
1444         def checkSubservicesAvail(self, ev):
1445                 if ev == iPlayableService.evUpdatedEventInfo:
1446                         service = self.session.nav.getCurrentService()
1447                         subservices = service and service.subServices()
1448                         if not subservices or subservices.getNumberOfSubservices() == 0:
1449                                 self["SubserviceQuickzapAction"].setEnabled(False)
1450
1451         def nextSubservice(self):
1452                 self.changeSubservice(+1)
1453
1454         def prevSubservice(self):
1455                 self.changeSubservice(-1)
1456
1457         def changeSubservice(self, direction):
1458                 service = self.session.nav.getCurrentService()
1459                 subservices = service and service.subServices()
1460                 n = subservices and subservices.getNumberOfSubservices()
1461                 if n and n > 0:
1462                         selection = -1
1463                         ref = self.session.nav.getCurrentlyPlayingServiceReference()
1464                         for x in range(n):
1465                                 if subservices.getSubservice(x).toString() == ref.toString():
1466                                         selection = x
1467                         if selection != -1:
1468                                 selection += direction
1469                                 if selection >= n:
1470                                         selection=0
1471                                 elif selection < 0:
1472                                         selection=n-1
1473                                 newservice = subservices.getSubservice(selection)
1474                                 if newservice.valid():
1475                                         del subservices
1476                                         del service
1477                                         if config.usage.show_infobar_on_zap.value:
1478                                                 self.doShow()
1479                                         self.session.nav.playService(newservice)
1480
1481         def subserviceSelection(self):
1482                 service = self.session.nav.getCurrentService()
1483                 subservices = service and service.subServices()
1484                 self.bouquets = self.servicelist.getBouquetList()
1485                 n = subservices and subservices.getNumberOfSubservices()
1486                 selection = 0
1487                 if n and n > 0:
1488                         ref = self.session.nav.getCurrentlyPlayingServiceReference()
1489                         tlist = []
1490                         for x in range(n):
1491                                 i = subservices.getSubservice(x)
1492                                 if i.toString() == ref.toString():
1493                                         selection = x
1494                                 tlist.append((i.getName(), i))
1495
1496                         if self.bouquets and len(self.bouquets):
1497                                 keys = ["red", "green", "",  "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" ] + [""] * n
1498                                 if config.usage.multibouquet.value:
1499                                         tlist = [(_("Quickzap"), "quickzap", service.subServices()), (_("Add to bouquet"), "CALLFUNC", self.addSubserviceToBouquetCallback), ("--", "")] + tlist
1500                                 else:
1501                                         tlist = [(_("Quickzap"), "quickzap", service.subServices()), (_("Add to favourites"), "CALLFUNC", self.addSubserviceToBouquetCallback), ("--", "")] + tlist
1502                                 selection += 3
1503                         else:
1504                                 tlist = [(_("Quickzap"), "quickzap", service.subServices()), ("--", "")] + tlist
1505                                 keys = ["red", "",  "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" ] + [""] * n
1506                                 selection += 2
1507
1508                         self.session.openWithCallback(self.subserviceSelected, ChoiceBox, title=_("Please select a subservice..."), list = tlist, selection = selection, keys = keys)
1509
1510         def subserviceSelected(self, service):
1511                 del self.bouquets
1512                 if not service is None:
1513                         if isinstance(service[1], str):
1514                                 if service[1] == "quickzap":
1515                                         from Screens.SubservicesQuickzap import SubservicesQuickzap
1516                                         self.session.open(SubservicesQuickzap, service[2])
1517                         else:
1518                                 self["SubserviceQuickzapAction"].setEnabled(True)
1519                                 if config.usage.show_infobar_on_zap.value:
1520                                         self.doShow()
1521                                 self.session.nav.playService(service[1])
1522
1523         def addSubserviceToBouquetCallback(self, service):
1524                 if len(service) > 1 and isinstance(service[1], eServiceReference):
1525                         self.selectedSubservice = service
1526                         if self.bouquets is None:
1527                                 cnt = 0
1528                         else:
1529                                 cnt = len(self.bouquets)
1530                         if cnt > 1: # show bouquet list
1531                                 self.bsel = self.session.openWithCallback(self.bouquetSelClosed, BouquetSelector, self.bouquets, self.addSubserviceToBouquet)
1532                         elif cnt == 1: # add to only one existing bouquet
1533                                 self.addSubserviceToBouquet(self.bouquets[0][1])
1534                                 self.session.open(MessageBox, _("Service has been added to the favourites."), MessageBox.TYPE_INFO)
1535
1536         def bouquetSelClosed(self, confirmed):
1537                 self.bsel = None
1538                 del self.selectedSubservice
1539                 if confirmed:
1540                         self.session.open(MessageBox, _("Service has been added to the selected bouquet."), MessageBox.TYPE_INFO)
1541
1542         def addSubserviceToBouquet(self, dest):
1543                 self.servicelist.addServiceToBouquet(dest, self.selectedSubservice[1])
1544                 if self.bsel:
1545                         self.bsel.close(True)
1546                 else:
1547                         del self.selectedSubservice
1548
1549 class InfoBarAdditionalInfo:
1550         def __init__(self):
1551                 self["NimA"] = Pixmap()
1552                 self["NimB"] = Pixmap()
1553                 self["NimA_Active"] = Pixmap()
1554                 self["NimB_Active"] = Pixmap()
1555
1556                 self["RecordingPossible"] = Boolean(fixed=harddiskmanager.HDDCount() > 0)
1557                 self["TimeshiftPossible"] = self["RecordingPossible"]
1558                 self["ExtensionsAvailable"] = Boolean(fixed=1)
1559
1560                 self.session.nav.event.append(self.gotServiceEvent) # we like to get service events
1561                 res_mgr = eDVBResourceManager.getInstance()
1562                 if res_mgr:
1563                         res_mgr.frontendUseMaskChanged.get().append(self.tunerUseMaskChanged)
1564
1565         def tunerUseMaskChanged(self, mask):
1566                 if mask&1:
1567                         self["NimA_Active"].show()
1568                 else:
1569                         self["NimA_Active"].hide()
1570                 if mask&2:
1571                         self["NimB_Active"].show()
1572                 else:
1573                         self["NimB_Active"].hide()
1574
1575         def checkTunerState(self, service):
1576                 info = service and service.frontendInfo()
1577                 feNumber = info and info.getFrontendInfo(iFrontendInformation.frontendNumber)
1578                 if feNumber is None:
1579                         self["NimA"].hide()
1580                         self["NimB"].hide()
1581                 elif feNumber == 0:
1582                         self["NimB"].hide()
1583                         self["NimA"].show()
1584                 elif feNumber == 1:
1585                         self["NimA"].hide()
1586                         self["NimB"].show()
1587
1588         def gotServiceEvent(self, ev):
1589                 service = self.session.nav.getCurrentService()
1590                 if ev == iPlayableService.evUpdatedInfo or ev == iPlayableService.evEnd:
1591                         self.checkTunerState(service)
1592
1593 class InfoBarNotifications:
1594         def __init__(self):
1595                 self.onExecBegin.append(self.checkNotifications)
1596                 Notifications.notificationAdded.append(self.checkNotificationsIfExecing)
1597                 self.onClose.append(self.__removeNotification)
1598         
1599         def __removeNotification(self):
1600                 Notifications.notificationAdded.remove(self.checkNotificationsIfExecing)
1601         
1602         def checkNotificationsIfExecing(self):
1603                 if self.execing:
1604                         self.checkNotifications()
1605
1606         def checkNotifications(self):
1607                 if len(Notifications.notifications):
1608                         n = Notifications.notifications[0]
1609                         
1610                         Notifications.notifications = Notifications.notifications[1:]
1611                         cb = n[0]
1612
1613                         if n[3].has_key("onSessionOpenCallback"):
1614                                 n[3]["onSessionOpenCallback"]()
1615                                 del n[3]["onSessionOpenCallback"]
1616
1617                         if cb is not None:
1618                                 dlg = self.session.openWithCallback(cb, n[1], *n[2], **n[3])
1619                         else:
1620                                 dlg = self.session.open(n[1], *n[2], **n[3])
1621                         
1622                         # remember that this notification is currently active
1623                         d = (n[4], dlg)
1624                         Notifications.current_notifications.append(d)
1625                         dlg.onClose.append(boundFunction(self.__notificationClosed, d))
1626
1627         def __notificationClosed(self, d):
1628                 Notifications.current_notifications.remove(d)
1629
1630 class InfoBarServiceNotifications:
1631         def __init__(self):
1632                 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1633                         {
1634                                 iPlayableService.evEnd: self.serviceHasEnded
1635                         })
1636
1637         def serviceHasEnded(self):
1638                 print "service end!"
1639
1640                 try:
1641                         self.setSeekState(self.SEEK_STATE_PLAY)
1642                 except:
1643                         pass
1644
1645 class InfoBarCueSheetSupport:
1646         CUT_TYPE_IN = 0
1647         CUT_TYPE_OUT = 1
1648         CUT_TYPE_MARK = 2
1649         CUT_TYPE_LAST = 3
1650         
1651         ENABLE_RESUME_SUPPORT = False
1652         
1653         def __init__(self):
1654                 self["CueSheetActions"] = HelpableActionMap(self, "InfobarCueSheetActions", 
1655                         {
1656                                 "jumpPreviousMark": (self.jumpPreviousMark, "jump to next marked position"),
1657                                 "jumpNextMark": (self.jumpNextMark, "jump to previous marked position"),
1658                                 "toggleMark": (self.toggleMark, "toggle a cut mark at the current position")
1659                         }, prio=1) 
1660                 
1661                 self.cut_list = [ ]
1662                 self.is_closing = False
1663                 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1664                         {
1665                                 iPlayableService.evStart: self.__serviceStarted,
1666                         })
1667
1668         def __serviceStarted(self):
1669                 if self.is_closing:
1670                         return
1671                 print "new service started! trying to download cuts!"
1672                 self.downloadCuesheet()
1673                 
1674                 if self.ENABLE_RESUME_SUPPORT:
1675                         last = None
1676                         
1677                         for (pts, what) in self.cut_list:
1678                                 if what == self.CUT_TYPE_LAST:
1679                                         last = pts
1680                         
1681                         if last is not None:
1682                                 self.resume_point = last
1683                                 Notifications.AddNotificationWithCallback(self.playLastCB, MessageBox, _("Do you want to resume this playback?"), timeout=10)
1684
1685         def playLastCB(self, answer):
1686                 if answer == True:
1687                         seekable = self.__getSeekable()
1688                         if seekable is not None:
1689                                 seekable.seekTo(self.resume_point)
1690
1691         def __getSeekable(self):
1692                 service = self.session.nav.getCurrentService()
1693                 if service is None:
1694                         return None
1695                 return service.seek()
1696
1697         def cueGetCurrentPosition(self):
1698                 seek = self.__getSeekable()
1699                 if seek is None:
1700                         return None
1701                 r = seek.getPlayPosition()
1702                 if r[0]:
1703                         return None
1704                 return long(r[1])
1705
1706         def jumpPreviousNextMark(self, cmp, alternative=None):
1707                 current_pos = self.cueGetCurrentPosition()
1708                 if current_pos is None:
1709                         return
1710                 mark = self.getNearestCutPoint(current_pos, cmp=cmp)
1711                 if mark is not None:
1712                         pts = mark[0]
1713                 elif alternative is not None:
1714                         pts = alternative
1715                 else:
1716                         return
1717
1718                 seekable = self.__getSeekable()
1719                 if seekable is not None:
1720                         seekable.seekTo(pts)
1721
1722         def jumpPreviousMark(self):
1723                 # we add 2 seconds, so if the play position is <2s after
1724                 # the mark, the mark before will be used
1725                 self.jumpPreviousNextMark(lambda x: -x-5*90000, alternative=0)
1726
1727         def jumpNextMark(self):
1728                 self.jumpPreviousNextMark(lambda x: x)
1729
1730         def getNearestCutPoint(self, pts, cmp=abs):
1731                 # can be optimized
1732                 nearest = None
1733                 for cp in self.cut_list:
1734                         diff = cmp(cp[0] - pts)
1735                         if diff >= 0 and (nearest is None or cmp(nearest[0] - pts) > diff):
1736                                 nearest = cp
1737                 return nearest
1738
1739         def toggleMark(self, onlyremove=False, onlyadd=False, tolerance=5*90000, onlyreturn=False):
1740                 current_pos = self.cueGetCurrentPosition()
1741                 if current_pos is None:
1742                         print "not seekable"
1743                         return
1744                 
1745                 nearest_cutpoint = self.getNearestCutPoint(current_pos)
1746                 
1747                 if nearest_cutpoint is not None and abs(nearest_cutpoint[0] - current_pos) < tolerance:
1748                         if onlyreturn:
1749                                 return nearest_cutpoint
1750                         if not onlyadd:
1751                                 self.removeMark(nearest_cutpoint)
1752                 elif not onlyremove and not onlyreturn:
1753                         self.addMark((current_pos, self.CUT_TYPE_MARK))
1754                 
1755                 if onlyreturn:
1756                         return None
1757
1758         def addMark(self, point):
1759                 insort(self.cut_list, point)
1760                 self.uploadCuesheet()
1761
1762         def removeMark(self, point):
1763                 self.cut_list.remove(point)
1764                 self.uploadCuesheet()
1765
1766         def __getCuesheet(self):
1767                 service = self.session.nav.getCurrentService()
1768                 if service is None:
1769                         return None
1770                 return service.cueSheet()
1771
1772         def uploadCuesheet(self):
1773                 cue = self.__getCuesheet()
1774
1775                 if cue is None:
1776                         print "upload failed, no cuesheet interface"
1777                         return
1778                 cue.setCutList(self.cut_list)
1779
1780         def downloadCuesheet(self):
1781                 cue = self.__getCuesheet()
1782
1783                 if cue is None:
1784                         print "upload failed, no cuesheet interface"
1785                         return
1786                 self.cut_list = cue.getCutList()
1787
1788 class InfoBarSummary(Screen):
1789         skin = """
1790         <screen position="0,0" size="132,64">
1791                 <widget source="CurrentTime" render="Label" position="56,46" size="82,18" font="Regular;16" >
1792                         <convert type="ClockToText">WithSeconds</convert>
1793                 </widget>
1794                 <widget source="CurrentService" render="Label" position="6,4" size="120,42" font="Regular;18" >
1795                         <convert type="ServiceName">Name</convert>
1796                 </widget>
1797         </screen>"""
1798
1799         def __init__(self, session, parent):
1800                 Screen.__init__(self, session)
1801                 self["CurrentService"] = CurrentService(self.session.nav)
1802                 self["CurrentTime"] = Clock()
1803
1804 class InfoBarSummarySupport:
1805         def __init__(self):
1806                 pass
1807         
1808         def createSummary(self):
1809                 return InfoBarSummary
1810
1811 class InfoBarTeletextPlugin:
1812         def __init__(self):
1813                 self.teletext_plugin = None
1814                 
1815                 for p in plugins.getPlugins(PluginDescriptor.WHERE_TELETEXT):
1816                         self.teletext_plugin = p
1817                 
1818                 if self.teletext_plugin is not None:
1819                         self["TeletextActions"] = HelpableActionMap(self, "InfobarTeletextActions",
1820                                 {
1821                                         "startTeletext": (self.startTeletext, _("View teletext..."))
1822                                 })
1823                 else:
1824                         print "no teletext plugin found!"
1825
1826         def startTeletext(self):
1827                 self.teletext_plugin(session=self.session, service=self.session.nav.getCurrentService())
1828
1829 class InfoBarSubtitleSupport(object):
1830         def __init__(self):
1831                 object.__init__(self)
1832                 self.subtitle_window = self.session.instantiateDialog(SubtitleDisplay)
1833                 self.__subtitles_enabled = False
1834
1835                 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1836                         {
1837                                 iPlayableService.evEnd: self.__serviceStopped,
1838                                 iPlayableService.evUpdatedInfo: self.__updatedInfo
1839                         })
1840                 self.cached_subtitle_checked = False
1841
1842         def __serviceStopped(self):
1843                 self.subtitle_window.hide()
1844                 self.__subtitles_enabled = False
1845                 self.cached_subtitle_checked = False
1846
1847         def __updatedInfo(self):
1848                 if not self.cached_subtitle_checked:
1849                         subtitle = self.getCurrentServiceSubtitle()
1850                         self.cached_subtitle_checked = True
1851                         if subtitle:
1852                                 self.__selected_subtitle = subtitle.getCachedSubtitle()
1853                         if self.__selected_subtitle:
1854                                 subtitle.enableSubtitles(self.subtitle_window.instance, self.selected_subtitle)
1855                                 self.subtitle_window.show()
1856                                 self.__subtitles_enabled = True
1857
1858         def getCurrentServiceSubtitle(self):
1859                 service = self.session.nav.getCurrentService()
1860                 return service and service.subtitle()
1861         
1862         def setSubtitlesEnable(self, enable=True):
1863                 subtitle = self.getCurrentServiceSubtitle()
1864                 if enable and self.__selected_subtitle is not None:
1865                         if subtitle and not self.__subtitles_enabled:
1866                                 subtitle.enableSubtitles(self.subtitle_window.instance, self.selected_subtitle)
1867                                 self.subtitle_window.show()
1868                                 self.__subtitles_enabled = True
1869                 else:
1870                         if subtitle:
1871                                 subtitle.disableSubtitles(self.subtitle_window.instance)
1872                         self.__subtitles_enabled = False
1873                         self.subtitle_window.hide()
1874
1875         def setSelectedSubtitle(self, subtitle):
1876                 self.__selected_subtitle = subtitle
1877
1878         subtitles_enabled = property(lambda self: self.__subtitles_enabled, setSubtitlesEnable)
1879         selected_subtitle = property(lambda self: self.__selected_subtitle, setSelectedSubtitle)
1880
1881 class InfoBarServiceErrorPopupSupport:
1882         def __init__(self):
1883                 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1884                         {
1885                                 iPlayableService.evTuneFailed: self.__tuneFailed,
1886                                 iPlayableService.evStart: self.__serviceStarted
1887                         })
1888                 self.__serviceStarted()
1889
1890         def __serviceStarted(self):
1891                 self.last_error = None
1892                 Notifications.RemovePopup(id = "ZapError")
1893
1894         def __tuneFailed(self):
1895                 service = self.session.nav.getCurrentService()
1896                 info = service and service.info()
1897                 error = info and info.getInfo(iServiceInformation.sDVBState)
1898                 
1899                 if error == self.last_error:
1900                         error = None
1901                 else:
1902                         self.last_error = error
1903
1904                 errors = {
1905                         eDVBServicePMTHandler.eventNoResources: _("No free tuner!"),
1906                         eDVBServicePMTHandler.eventTuneFailed: _("Tune failed!"),
1907                         eDVBServicePMTHandler.eventNoPAT: _("No data on transponder!\n(Timeout reading PAT)"),
1908                         eDVBServicePMTHandler.eventNoPATEntry: _("Service not found!\n(SID not found in PAT)"),
1909                         eDVBServicePMTHandler.eventNoPMT: _("Service invalid!\n(Timeout reading PMT)"),
1910                         eDVBServicePMTHandler.eventNewProgramInfo: None,
1911                         eDVBServicePMTHandler.eventTuned: None,
1912                         eDVBServicePMTHandler.eventSOF: None,
1913                         eDVBServicePMTHandler.eventEOF: None
1914                 }
1915
1916                 error = errors.get(error) #this returns None when the key not exist in the dict
1917
1918                 if error is not None:
1919                         Notifications.AddPopup(text = error, type = MessageBox.TYPE_ERROR, timeout = 5, id = "ZapError")
1920                 else:
1921                         Notifications.RemovePopup(id = "ZapError")