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