use default service types for filtering in bouquets
[enigma2.git] / lib / python / Screens / InfoBarGenerics.py
1 from Screen import Screen
2 from Components.ActionMap import ActionMap, HelpableActionMap
3 from Components.ActionMap import NumberActionMap
4 from Components.Label import *
5 from Components.ProgressBar import *
6 from Components.config import configfile, configsequencearg
7 from Components.config import config, configElement, ConfigSubsection, configSequence
8 from ChannelSelection import ChannelSelection, BouquetSelector
9
10 from Components.Pixmap import Pixmap, PixmapConditional
11 from Components.BlinkingPixmap import BlinkingPixmapConditional
12 from Components.ServiceName import ServiceName
13 from Components.EventInfo import EventInfo
14
15 from ServiceReference import ServiceReference
16 from EpgSelection import EPGSelection
17
18 from Screens.MessageBox import MessageBox
19 from Screens.Volume import Volume
20 from Screens.Mute import Mute
21 from Screens.Dish import Dish
22 from Screens.Standby import Standby
23 from Screens.EventView import EventView
24 from Screens.MinuteInput import MinuteInput
25 from Components.Harddisk import harddiskmanager
26
27 from Tools import Notifications
28 from Tools.Directories import *
29
30 #from enigma import eTimer, eDVBVolumecontrol, quitMainloop
31 from enigma import *
32
33 import time
34 import os
35
36 # hack alert!
37 from Menu import MainMenu, mdom
38
39 class InfoBarVolumeControl:
40         """Volume control, handles volUp, volDown, volMute actions and display 
41         a corresponding dialog"""
42         def __init__(self):
43                 config.audio = ConfigSubsection()
44                 config.audio.volume = configElement("config.audio.volume", configSequence, [100], configsequencearg.get("INTEGER", (0, 100)))
45
46                 self["VolumeActions"] = ActionMap( ["InfobarVolumeActions"] ,
47                         {
48                                 "volumeUp": self.volUp,
49                                 "volumeDown": self.volDown,
50                                 "volumeMute": self.volMute,
51                         })
52
53                 self.volumeDialog = self.session.instantiateDialog(Volume)
54                 self.muteDialog = self.session.instantiateDialog(Mute)
55
56                 self.hideVolTimer = eTimer()
57                 self.hideVolTimer.timeout.get().append(self.volHide)
58
59                 vol = config.audio.volume.value[0]
60                 self.volumeDialog.setValue(vol)
61                 eDVBVolumecontrol.getInstance().setVolume(vol, vol)
62         
63         def volSave(self):
64                 config.audio.volume.value = eDVBVolumecontrol.getInstance().getVolume()
65                 config.audio.volume.save()
66                 
67         def     volUp(self):
68                 if (eDVBVolumecontrol.getInstance().isMuted()):
69                         self.volMute()
70                 eDVBVolumecontrol.getInstance().volumeUp()
71                 self.volumeDialog.instance.show()
72                 self.volumeDialog.setValue(eDVBVolumecontrol.getInstance().getVolume())
73                 self.volSave()
74                 self.hideVolTimer.start(3000, True)
75
76         def     volDown(self):
77                 if (eDVBVolumecontrol.getInstance().isMuted()):
78                         self.volMute()
79                 eDVBVolumecontrol.getInstance().volumeDown()
80                 self.volumeDialog.instance.show()
81                 self.volumeDialog.setValue(eDVBVolumecontrol.getInstance().getVolume())
82                 self.volSave()
83                 self.hideVolTimer.start(3000, True)
84                 
85         def volHide(self):
86                 self.volumeDialog.instance.hide()
87
88         def     volMute(self):
89                 eDVBVolumecontrol.getInstance().volumeToggleMute()
90                 self.volumeDialog.setValue(eDVBVolumecontrol.getInstance().getVolume())
91                 
92                 if (eDVBVolumecontrol.getInstance().isMuted()):
93                         self.muteDialog.instance.show()
94                 else:
95                         self.muteDialog.instance.hide()
96
97 class InfoBarDish:
98         def __init__(self):
99                 self.dishDialog = self.session.instantiateDialog(Dish)
100                 self.onShown.append(self.dishDialog.instance.hide)
101
102 class InfoBarShowHide:
103         """ InfoBar show/hide control, accepts toggleShow and hide actions, might start
104         fancy animations. """
105         STATE_HIDDEN = 0
106         STATE_HIDING = 1
107         STATE_SHOWING = 2
108         STATE_SHOWN = 3
109         
110         def __init__(self):
111                 self["ShowHideActions"] = ActionMap( ["InfobarShowHideActions"] ,
112                         {
113                                 "toggleShow": self.toggleShow,
114                                 "hide": self.hide,
115                         })
116
117                 self.state = self.STATE_SHOWN
118                 
119                 self.onExecBegin.append(self.show)
120                 self.onClose.append(self.delHideTimer)
121                 
122                 self.hideTimer = eTimer()
123                 self.hideTimer.timeout.get().append(self.doTimerHide)
124                 self.hideTimer.start(5000, True)
125
126         def delHideTimer(self):
127                 del self.hideTimer
128
129         def hide(self): 
130                 self.instance.hide()
131                 
132         def show(self):
133                 self.state = self.STATE_SHOWN
134                 self.hideTimer.start(5000, True)
135
136         def doTimerHide(self):
137                 self.hideTimer.stop()
138                 if self.state == self.STATE_SHOWN:
139                         self.instance.hide()
140                         self.state = self.STATE_HIDDEN
141
142         def toggleShow(self):
143                 if self.state == self.STATE_SHOWN:
144                         self.instance.hide()
145                         #pls check animation support, sorry
146 #                       self.startHide()
147                         self.hideTimer.stop()
148                         self.state = self.STATE_HIDDEN
149                 elif self.state == self.STATE_HIDDEN:
150                         self.instance.show()
151                         self.show()
152                         
153         def startShow(self):
154                 self.instance.m_animation.startMoveAnimation(ePoint(0, 600), ePoint(0, 380), 100)
155                 self.state = self.STATE_SHOWN
156         
157         def startHide(self):
158                 self.instance.m_animation.startMoveAnimation(ePoint(0, 380), ePoint(0, 600), 100)
159                 self.state = self.STATE_HIDDEN
160
161 class NumberZap(Screen):
162         def quit(self):
163                 self.Timer.stop()
164                 self.close(0)
165
166         def keyOK(self):
167                 self.Timer.stop()
168                 self.close(int(self["number"].getText()))
169
170         def keyNumberGlobal(self, number):
171                 self.Timer.start(3000, True)            #reset timer
172                 self.field = self.field + str(number)
173                 self["number"].setText(self.field)
174                 if len(self.field) >= 4:
175                         self.keyOK()
176
177         def __init__(self, session, number):
178                 Screen.__init__(self, session)
179                 self.field = str(number)
180
181                 self["channel"] = Label(_("Channel:"))
182
183                 self["number"] = Label(self.field)
184
185                 self["actions"] = NumberActionMap( [ "SetupActions" ], 
186                         {
187                                 "cancel": self.quit,
188                                 "ok": self.keyOK,
189                                 "1": self.keyNumberGlobal,
190                                 "2": self.keyNumberGlobal,
191                                 "3": self.keyNumberGlobal,
192                                 "4": self.keyNumberGlobal,
193                                 "5": self.keyNumberGlobal,
194                                 "6": self.keyNumberGlobal,
195                                 "7": self.keyNumberGlobal,
196                                 "8": self.keyNumberGlobal,
197                                 "9": self.keyNumberGlobal,
198                                 "0": self.keyNumberGlobal
199                         })
200
201                 self.Timer = eTimer()
202                 self.Timer.timeout.get().append(self.keyOK)
203                 self.Timer.start(3000, True)
204
205 class InfoBarPowerKey:
206         """ PowerKey stuff - handles the powerkey press and powerkey release actions"""
207         
208         def __init__(self):
209                 self.powerKeyTimer = eTimer()
210                 self.powerKeyTimer.timeout.get().append(self.powertimer)
211                 self["PowerKeyActions"] = HelpableActionMap(self, "PowerKeyActions",
212                         {
213                                 "powerdown": self.powerdown,
214                                 "powerup": self.powerup,
215                                 "discreteStandby": (self.standby, "Go standby"),
216                                 "discretePowerOff": (self.quit, "Go to deep standby"),
217                         })
218
219         def powertimer(self):   
220                 print "PowerOff - Now!"
221                 self.quit()
222         
223         def powerdown(self):
224                 self.standbyblocked = 0
225                 self.powerKeyTimer.start(3000, True)
226
227         def powerup(self):
228                 self.powerKeyTimer.stop()
229                 if self.standbyblocked == 0:
230                         self.standbyblocked = 1
231                         self.standby()
232
233         def standby(self):
234                 self.session.open(Standby, self)
235
236         def quit(self):
237                 # halt
238                 quitMainloop(1)
239
240 class InfoBarNumberZap:
241         """ Handles an initial number for NumberZapping """
242         def __init__(self):
243                 self["NumberZapActions"] = NumberActionMap( [ "NumberZapActions"],
244                         {
245                                 "1": self.keyNumberGlobal,
246                                 "2": self.keyNumberGlobal,
247                                 "3": self.keyNumberGlobal,
248                                 "4": self.keyNumberGlobal,
249                                 "5": self.keyNumberGlobal,
250                                 "6": self.keyNumberGlobal,
251                                 "7": self.keyNumberGlobal,
252                                 "8": self.keyNumberGlobal,
253                                 "9": self.keyNumberGlobal,
254                                 "0": self.keyNumberGlobal,
255                         })
256
257         def keyNumberGlobal(self, number):
258 #               print "You pressed number " + str(number)
259                 if number == 0:
260                         self.session.nav.zapLast()
261                         self.instance.show()
262                         self.show()
263                 else:
264                         self.session.openWithCallback(self.numberEntered, NumberZap, number)
265
266         def numberEntered(self, retval):
267 #               print self.servicelist
268                 if retval > 0:
269                         self.zapToNumber(retval)
270
271         def searchNumberHelper(self, serviceHandler, num, bouquet):
272                 servicelist = serviceHandler.list(bouquet)
273                 if not servicelist is None:
274                         while num:
275                                 serviceIterator = servicelist.getNext()
276                                 if not serviceIterator.valid(): #check end of list
277                                         break
278                                 if serviceIterator.flags: #assume normal dvb service have no flags set
279                                         continue
280                                 num -= 1;
281                         if not num: #found service with searched number ?
282                                 return serviceIterator, 0
283                 return None, num
284
285         def zapToNumber(self, number):
286                 bouquet = self.servicelist.bouquet_root
287                 service = None
288                 serviceHandler = eServiceCenter.getInstance()
289                 if bouquet.toString().find('FROM BOUQUET "bouquets.') == -1: #FIXME HACK
290                         service, number = self.searchNumberHelper(serviceHandler, number, bouquet)
291                 else:
292                         bouquetlist = serviceHandler.list(bouquet)
293                         if not bouquetlist is None:
294                                 while number:
295                                         bouquet = bouquetlist.getNext()
296                                         if not bouquet.valid(): #check end of list
297                                                 break
298                                         if ((bouquet.flags & eServiceReference.flagDirectory) != eServiceReference.flagDirectory):
299                                                 continue
300                                         service, number = self.searchNumberHelper(serviceHandler, number, bouquet)
301                 if not service is None:
302                         self.session.nav.playService(service) #play service
303                         if self.servicelist.getRoot() != bouquet: #already in correct bouquet?
304                                 self.servicelist.setRoot(bouquet)
305                         self.servicelist.setCurrentSelection(service) #select the service in servicelist
306
307 class InfoBarChannelSelection:
308         """ ChannelSelection - handles the channelSelection dialog and the initial 
309         channelChange actions which open the channelSelection dialog """
310         def __init__(self):
311                 #instantiate forever
312                 self.servicelist = self.session.instantiateDialog(ChannelSelection)
313
314                 self["ChannelSelectActions"] = HelpableActionMap(self, "InfobarChannelSelection",
315                         {
316                                 "switchChannelUp": self.switchChannelUp,
317                                 "switchChannelDown": self.switchChannelDown,
318                                 "zapUp": (self.zapUp, _("next channel")),
319                                 "zapDown": (self.zapDown, _("previous channel")),
320                         })
321                         
322         def switchChannelUp(self):      
323                 self.servicelist.moveUp()
324                 self.session.execDialog(self.servicelist)
325
326         def switchChannelDown(self):    
327                 self.servicelist.moveDown()
328                 self.session.execDialog(self.servicelist)
329
330         def     zapUp(self):
331                 self.servicelist.moveUp()
332                 self.servicelist.zap()
333                 self.instance.show()
334                 self.show()
335
336         def     zapDown(self):
337                 self.servicelist.moveDown()
338                 self.servicelist.zap()
339                 self.instance.show()
340                 self.show()
341                 
342 class InfoBarMenu:
343         """ Handles a menu action, to open the (main) menu """
344         def __init__(self):
345                 self["MenuActions"] = HelpableActionMap(self, "InfobarMenuActions", 
346                         {
347                                 "mainMenu": (self.mainMenu, "Enter main menu..."),
348                         })
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                 self.session.open(MainMenu, menu, menu.childNodes)
355
356 class InfoBarEPG:
357         """ EPG - Opens an EPG list when the showEPGList action fires """
358         def __init__(self):
359                 self["EPGActions"] = HelpableActionMap(self, "InfobarEPGActions", 
360                         {
361                                 "showEPGList": (self.openSingleServiceEPG, _("show EPG...")),
362                         })
363
364         def showEPGList(self):
365                 bouquets = self.servicelist.getBouquetList()
366                 if bouquets is None:
367                         cnt = 0
368                 else:
369                         cnt = len(bouquets)
370                 if cnt > 1: # show bouquet list
371                         self.session.open(BouquetSelector, bouquets, self.openBouquetEPG)
372                 elif cnt == 1: # add to only one existing bouquet
373                         self.openBouquetEPG(bouquets[0][1])
374                 else: #no bouquets so we open single epg
375                         self.openSingleEPGSelector(self.session.nav.getCurrentlyPlayingServiceReference())
376
377         def bouquetEPGCallback(self, info):
378                 if info:
379                         self.openSingleServiceEPG()
380         
381         def singleEPGCallback(self, info):
382                 if info:
383                         self.showEPGList()
384                         
385         def openSingleServiceEPG(self):
386                 ref=self.session.nav.getCurrentlyPlayingServiceReference()
387                 ptr=eEPGCache.getInstance()
388                 if ptr.startTimeQuery(ref) != -1:
389                         self.session.openWithCallback(self.singleEPGCallback, EPGSelection, ref)
390                 else: # try to show now/next
391                         print 'no epg for service', ref.toString()
392                         try:
393                                 self.epglist = [ ]
394                                 service = self.session.nav.getCurrentService()
395                                 info = service.info()
396                                 ptr=info.getEvent(0)
397                                 if ptr:
398                                         self.epglist.append(ptr)
399                                 ptr=info.getEvent(1)
400                                 if ptr:
401                                         self.epglist.append(ptr)
402                                 if len(self.epglist) > 0:
403                                         self.session.open(EventView, self.epglist[0], ServiceReference(ref), self.eventViewCallback)
404                         except:
405                                 pass    
406         
407         def openBouquetEPG(self, bouquet):
408                 ptr=eEPGCache.getInstance()
409                 services = [ ]
410                 servicelist = eServiceCenter.getInstance().list(bouquet)
411                 if not servicelist is None:
412                         while True:
413                                 service = servicelist.getNext()
414                                 if not service.valid(): #check if end of list
415                                         break
416                                 if service.flags: #ignore non playable services
417                                         continue
418                                 services.append(ServiceReference(service))
419                 if len(services):
420                         self.session.openWithCallback(self.bouquetEPGCallback, EPGSelection, services)
421
422         def openSingleEPGSelector(self, ref):
423                 ptr=eEPGCache.getInstance()
424                 if ptr.startTimeQuery(ref) != -1:
425                         self.session.open(EPGSelection, ref)
426                 else: # try to show now/next
427                         print 'no epg for service', ref.toString()
428                         try:
429                                 self.epglist = [ ]
430                                 service = self.session.nav.getCurrentService()
431                                 info = service.info()
432                                 ptr=info.getEvent(0)
433                                 if ptr:
434                                         self.epglist.append(ptr)
435                                 ptr=info.getEvent(1)
436                                 if ptr:
437                                         self.epglist.append(ptr)
438                                 if len(self.epglist) > 0:
439                                         self.session.open(EventView, self.epglist[0], ServiceReference(ref), self.eventViewCallback)
440                         except:
441                                 pass
442
443         def eventViewCallback(self, setEvent, setService, val): #used for now/next displaying
444                 if len(self.epglist) > 1:
445                         tmp = self.epglist[0]
446                         self.epglist[0]=self.epglist[1]
447                         self.epglist[1]=tmp
448                         setEvent(self.epglist[0])
449
450 from math import log
451
452 class InfoBarTuner:
453         """provides a snr/agc/ber display"""
454         def __init__(self):
455                 self["snr"] = Label()
456                 self["agc"] = Label()
457                 self["ber"] = Label()
458                 self["snr_percent"] = Label()
459                 self["agc_percent"] = Label()
460                 self["ber_count"] = Label()
461                 self["snr_progress"] = ProgressBar()
462                 self["agc_progress"] = ProgressBar()
463                 self["ber_progress"] = ProgressBar()
464                 self.timer = eTimer()
465                 self.timer.timeout.get().append(self.updateTunerInfo)
466                 self.timer.start(1000)
467
468         def calc(self,val):
469                 if not val:
470                         return 0
471                 if val < 2500:
472                         return (long)(log(val)/log(2))
473                 return val*100/65535
474
475         def updateTunerInfo(self):
476                 if self.instance.isVisible():
477                         service = self.session.nav.getCurrentService()
478                         snr=0
479                         agc=0
480                         ber=0
481                         if service is not None:
482                                 feinfo = service.frontendStatusInfo()
483                                 if feinfo is not None:
484                                         ber=feinfo.getFrontendInfo(iFrontendStatusInformation.bitErrorRate)
485                                         snr=feinfo.getFrontendInfo(iFrontendStatusInformation.signalPower)*100/65536
486                                         agc=feinfo.getFrontendInfo(iFrontendStatusInformation.signalQuality)*100/65536
487                         self["snr_percent"].setText("%d%%"%(snr))
488                         self["agc_percent"].setText("%d%%"%(agc))
489                         self["ber_count"].setText("%d"%(ber))
490                         self["snr_progress"].setValue(snr)
491                         self["agc_progress"].setValue(agc)
492                         self["ber_progress"].setValue(self.calc(ber))
493
494 class InfoBarEvent:
495         """provides a current/next event info display"""
496         def __init__(self):
497                 self["Event_Now_StartTime"] = EventInfo(self.session.nav, EventInfo.Now_StartTime)
498                 self["Event_Next_StartTime"] = EventInfo(self.session.nav, EventInfo.Next_StartTime)
499                                 
500                 self["Event_Now"] = EventInfo(self.session.nav, EventInfo.Now)
501                 self["Event_Next"] = EventInfo(self.session.nav, EventInfo.Next)
502
503                 self["Event_Now_Duration"] = EventInfo(self.session.nav, EventInfo.Now_Duration)
504                 self["Event_Next_Duration"] = EventInfo(self.session.nav, EventInfo.Next_Duration)
505
506 class InfoBarServiceName:
507         def __init__(self):
508                 self["ServiceName"] = ServiceName(self.session.nav)
509
510 class InfoBarPVR:
511
512         # ispause, isff, issm, skip
513         SEEK_STATE_PLAY = (0, 0, 0, 0)
514         SEEK_STATE_PAUSE = (1, 0, 0, 0)
515         SEEK_STATE_FF_2X = (0, 2, 0, 0)
516         SEEK_STATE_FF_4X = (0, 4, 0, 0)
517         SEEK_STATE_FF_8X = (0, 8, 0, 0)
518         SEEK_STATE_FF_32X = (0, 4, 0, 32)
519         SEEK_STATE_FF_64X = (0, 4, 0, 64)
520         SEEK_STATE_FF_128X = (0, 4, 0, 128)
521         
522         SEEK_STATE_BACK_4X = (0, 0, 0, -4)
523         SEEK_STATE_BACK_32X = (0, 0, 0, -32)
524         SEEK_STATE_BACK_64X = (0, 0, 0, -64)
525         SEEK_STATE_BACK_128X = (0, 0, 0, -128)
526         
527         SEEK_STATE_SM_HALF = (0, 0, 2, 0)
528         SEEK_STATE_SM_QUARTER = (0, 0, 4, 0)
529         SEEK_STATE_SM_EIGHTH = (0, 0, 8, 0)
530         
531         """handles PVR specific actions like seeking, pause"""
532         def __init__(self):
533                 self["PVRActions"] = HelpableActionMap(self, "InfobarPVRActions", 
534                         {
535                                 "pauseService": (self.pauseService, "pause"),
536                                 "unPauseService": (self.unPauseService, "continue"),
537                                 
538                                 "seekFwd": (self.seekFwd, "skip forward"),
539                                 "seekFwdUp": (self.seekFwdUp, "skip forward"),
540                                 "seekBack": (self.seekBack, "skip backward"),
541                                 "seekBackUp": (self.seekBackUp, "skip backward"),
542                                                          
543                                 "up": (self.showMovies, "movie list"),
544                                 "down": (self.showMovies, "movie list")
545                         })
546
547                 self.seekstate = self.SEEK_STATE_PLAY
548                 self.seekTimer = eTimer()
549                 self.seekTimer.timeout.get().append(self.seekTimerFired)
550                 self.skipinterval = 500 # 500ms skip interval
551                 self.onClose.append(self.delSeekTimer)
552                 
553                 self.fwdtimer = False
554                 self.fwdKeyTimer = eTimer()
555                 self.fwdKeyTimer.timeout.get().append(self.fwdTimerFire)
556
557                 self.rwdtimer = False
558                 self.rwdKeyTimer = eTimer()
559                 self.rwdKeyTimer.timeout.get().append(self.rwdTimerFire)
560         
561         def up(self):
562                 pass
563         
564         def down(self):
565                 pass
566         
567         def delSeekTimer(self):
568                 del self.seekTimer
569         
570         def seekTimerFired(self):
571                 self.seekbase += self.skipmode * self.skipinterval
572                 
573                 # check if we bounced against the beginning of the file
574                 if self.seekbase < 0:
575                         self.seekbase = 0;
576                         self.setSeekState(self.SEEK_STATE_PLAY)
577                         
578                 self.doSeek(self.seekbase)
579
580         def setSeekState(self, state):
581                 oldstate = self.seekstate
582                 
583                 self.seekstate = state
584
585                 service = self.session.nav.getCurrentService()
586                 if service is None:
587                         return
588                 
589                 pauseable = service.pause()
590                 
591                 for i in range(4):
592                         if oldstate[i] != self.seekstate[i]:
593                                 (self.session.nav.pause, pauseable.setFastForward, pauseable.setSlowMotion, self.setSkipMode)[i](self.seekstate[i])
594                 
595         def setSkipMode(self, skipmode):
596                 self.skipmode = skipmode
597                 if skipmode == 0:
598                         self.seekTimer.stop()
599                 else:
600                         self.seekTimer.start(500)
601                 
602                 service = self.session.nav.getCurrentService()
603                 if service is None:
604                         return
605                 
606                 seekable = service.seek()
607                 if seekable is None:
608                         return
609
610                 if skipmode:
611                         seekable.setTrickmode(1)
612                 else:
613                         seekable.setTrickmode(0)
614                 
615                 self.seekbase = seekable.getPlayPosition()[1] / 90
616         
617         def pauseService(self):
618                 if (self.seekstate == self.SEEK_STATE_PAUSE):
619                         self.unPauseService()
620                 else:
621                         self.setSeekState(self.SEEK_STATE_PAUSE);
622                 
623         def unPauseService(self):
624                 self.setSeekState(self.SEEK_STATE_PLAY);
625         
626         def doSeek(self, seektime):
627                 service = self.session.nav.getCurrentService()
628                 if service is None:
629                         return
630                 
631                 seekable = service.seek()
632                 if seekable is None:
633                         return
634                 seekable.seekTo(90 * seektime)
635
636         def seekFwd(self):
637                 print "start fwd timer"
638                 self.fwdtimer = True
639                 self.fwdKeyTimer.start(500)
640
641         def seekBack(self):
642                 print "start rewind timer"
643                 self.rwdtimer = True
644                 self.rwdKeyTimer.start(500)
645
646         def seekFwdUp(self):
647                 if self.fwdtimer:
648                         self.fwdKeyTimer.stop()
649                         self.fwdtimer = False
650                         lookup = {
651                                         self.SEEK_STATE_PLAY: self.SEEK_STATE_FF_2X,
652                                         self.SEEK_STATE_PAUSE: self.SEEK_STATE_SM_EIGHTH,
653                                         self.SEEK_STATE_FF_2X: self.SEEK_STATE_FF_4X,
654                                         self.SEEK_STATE_FF_4X: self.SEEK_STATE_FF_8X,
655                                         self.SEEK_STATE_FF_8X: self.SEEK_STATE_FF_32X,
656                                         self.SEEK_STATE_FF_32X: self.SEEK_STATE_FF_64X,
657                                         self.SEEK_STATE_FF_64X: self.SEEK_STATE_FF_128X,
658                                         self.SEEK_STATE_FF_128X: self.SEEK_STATE_FF_128X,
659                                         self.SEEK_STATE_BACK_4X: self.SEEK_STATE_PLAY,
660                                         self.SEEK_STATE_BACK_32X: self.SEEK_STATE_BACK_4X,
661                                         self.SEEK_STATE_BACK_64X: self.SEEK_STATE_BACK_32X,
662                                         self.SEEK_STATE_BACK_128X: self.SEEK_STATE_BACK_64X,
663                                         self.SEEK_STATE_SM_HALF: self.SEEK_STATE_SM_HALF,
664                                         self.SEEK_STATE_SM_QUARTER: self.SEEK_STATE_SM_HALF,
665                                         self.SEEK_STATE_SM_EIGHTH: self.SEEK_STATE_SM_QUARTER
666                                 }
667                         self.setSeekState(lookup[self.seekstate]);
668         
669         def seekBackUp(self):
670                 if self.rwdtimer:
671                         self.rwdKeyTimer.stop()
672                         self.rwdtimer = False
673                 
674                         lookup = {
675                                         self.SEEK_STATE_PLAY: self.SEEK_STATE_BACK_4X,
676                                         self.SEEK_STATE_PAUSE: self.SEEK_STATE_PAUSE,
677                                         self.SEEK_STATE_FF_2X: self.SEEK_STATE_PLAY,
678                                         self.SEEK_STATE_FF_4X: self.SEEK_STATE_FF_2X,
679                                         self.SEEK_STATE_FF_8X: self.SEEK_STATE_FF_4X,
680                                         self.SEEK_STATE_FF_32X: self.SEEK_STATE_FF_8X,
681                                         self.SEEK_STATE_FF_64X: self.SEEK_STATE_FF_32X,
682                                         self.SEEK_STATE_FF_128X: self.SEEK_STATE_FF_64X,
683                                         self.SEEK_STATE_BACK_4X: self.SEEK_STATE_BACK_32X,
684                                         self.SEEK_STATE_BACK_32X: self.SEEK_STATE_BACK_64X,
685                                         self.SEEK_STATE_BACK_64X: self.SEEK_STATE_BACK_128X,
686                                         self.SEEK_STATE_BACK_128X: self.SEEK_STATE_BACK_128X,
687                                         self.SEEK_STATE_SM_HALF: self.SEEK_STATE_SM_QUARTER,
688                                         self.SEEK_STATE_SM_QUARTER: self.SEEK_STATE_SM_EIGHTH,
689                                         self.SEEK_STATE_SM_EIGHTH: self.SEEK_STATE_PAUSE
690                                 }
691                         self.setSeekState(lookup[self.seekstate]);
692                 
693         def fwdTimerFire(self):
694                 print "Display seek fwd"
695                 self.fwdKeyTimer.stop()
696                 self.fwdtimer = False
697                 self.session.openWithCallback(self.fwdSeekTo, MinuteInput)
698                 
699         def fwdSeekTo(self, minutes):
700                 print "Seek", minutes, "minutes forward"
701                 if minutes != 0:
702                         service = self.session.nav.getCurrentService()
703                         if service is None:
704                                 return
705                         seekable = service.seek()
706                         if seekable is None:
707                                 return
708                         seekable.seekRelative(1, minutes * 60 * 90000)
709         
710         def rwdTimerFire(self):
711                 self.rwdKeyTimer.stop()
712                 self.rwdtimer = False
713                 self.session.openWithCallback(self.rwdSeekTo, MinuteInput)
714         
715         def rwdSeekTo(self, minutes):
716                 self.fwdSeekTo(0 - minutes)
717
718 from RecordTimer import parseEvent
719
720 class InfoBarInstantRecord:
721         """Instant Record - handles the instantRecord action in order to 
722         start/stop instant records"""
723         def __init__(self):
724                 self["InstantRecordActions"] = HelpableActionMap(self, "InfobarInstantRecord",
725                         {
726                                 "instantRecord": (self.instantRecord, "Instant Record..."),
727                         })
728                 self.recording = None
729                 
730                 self["BlinkingPoint"] = BlinkingPixmapConditional()
731                 self.onShown.append(self["BlinkingPoint"].hideWidget)
732                 self["BlinkingPoint"].setConnect(self.session.nav.RecordTimer.isRecording)
733                 
734         def stopCurrentRecording(self): 
735                 self.session.nav.RecordTimer.removeEntry(self.recording)
736                 self.recording = None
737                         
738         def startInstantRecording(self):
739                 serviceref = self.session.nav.getCurrentlyPlayingServiceReference()
740                 
741                 # try to get event info
742                 event = None
743                 try:
744                         service = self.session.nav.getCurrentService()
745                         info = service.info()
746                         ev = info.getEvent(0)
747                         event = ev
748                 except:
749                         pass
750                 
751                 if event is not None:
752                         data = parseEvent(event)
753                         data = (data[0], data[1] + 3600 * 10, data[2], data[3], data[4])
754                 else:
755                         data = (time.time(), time.time() + 3600 * 10, "instant record", "", None)
756                 
757                 # fix me, description. 
758                 self.recording = self.session.nav.recordWithTimer(serviceref, *data)
759                 self.recording.dontSave = True
760                 
761                 #self["BlinkingPoint"].setConnect(lambda: self.recording.isRunning())
762                 
763         def isInstantRecordRunning(self):
764                 if self.recording != None:
765                         if self.recording.isRunning():
766                                 return True
767                 return False
768
769         def recordQuestionCallback(self, answer):
770                 if answer == False:
771                         return
772                 
773                 if self.isInstantRecordRunning():
774                         self.stopCurrentRecording()
775                 else:
776                         self.startInstantRecording()
777
778         def instantRecord(self):
779                 try:
780                         stat = os.stat(resolveFilename(SCOPE_HDD))
781                 except:
782                         self.session.open(MessageBox, _("No HDD found or HDD not initialized!"), MessageBox.TYPE_ERROR)
783                         return
784         
785                 if self.isInstantRecordRunning():
786                         self.session.openWithCallback(self.recordQuestionCallback, MessageBox, _("Do you want to stop the current\n(instant) recording?"))
787                 else:
788                         self.session.openWithCallback(self.recordQuestionCallback, MessageBox, _("Start recording?"))
789
790 from Screens.AudioSelection import AudioSelection
791
792 class InfoBarAudioSelection:
793         def __init__(self):
794                 self["AudioSelectionAction"] = HelpableActionMap(self, "InfobarAudioSelectionActions", 
795                         {
796                                 "audioSelection": (self.audioSelection, "Audio Options..."),
797                         })
798
799         def audioSelection(self):
800                 service = self.session.nav.getCurrentService()
801                 audio = service.audioTracks()
802                 n = audio.getNumberOfTracks()
803                 if n > 0:
804                         self.session.open(AudioSelection, audio)
805
806 from Screens.SubserviceSelection import SubserviceSelection
807
808 class InfoBarSubserviceSelection:
809         def __init__(self):
810                 self["SubserviceSelectionAction"] = HelpableActionMap(self, "InfobarSubserviceSelectionActions",
811                         {
812                                 "subserviceSelection": (self.subserviceSelection, "Subservice list..."),
813                         })
814
815         def subserviceSelection(self):
816                 service = self.session.nav.getCurrentService()
817                 subservices = service.subServices()
818                 n = subservices.getNumberOfSubservices()
819                 if n > 0:
820                         self.session.openWithCallback(self.subserviceSelected, SubserviceSelection, subservices)
821
822         def subserviceSelected(self, service):
823                 if not service is None:
824                         self.session.nav.playService(service)
825
826 class InfoBarAdditionalInfo:
827         def __init__(self):
828                 self["DolbyActive"] = Pixmap()
829                 self["CryptActive"] = Pixmap()
830                 self["FormatActive"] = Pixmap()
831                 
832                 self["ButtonRed"] = PixmapConditional(withTimer = False)
833                 self["ButtonRed"].setConnect(lambda: harddiskmanager.HDDCount() > 0)
834                 self.onShown.append(self["ButtonRed"].update)
835                 self["ButtonRedText"] = LabelConditional(text = _("Record"), withTimer = False)
836                 self["ButtonRedText"].setConnect(lambda: harddiskmanager.HDDCount() > 0)
837                 self.onShown.append(self["ButtonRedText"].update)
838
839                 self["ButtonGreen"] = Pixmap()
840                 self["ButtonGreenText"] = Label(_("Subservices"))
841
842                 self["ButtonYellow"] = PixmapConditional(withTimer = False)
843                 self["ButtonYellow"].setConnect(lambda: False)
844
845                 self["ButtonBlue"] = PixmapConditional(withTimer = False)
846                 self["ButtonBlue"].setConnect(lambda: False)
847
848                 self.session.nav.event.append(self.gotServiceEvent) # we like to get service events
849
850         def hideSubServiceIndication(self):
851                 self["ButtonGreen"].hideWidget()
852                 self["ButtonGreenText"].hide()
853
854         def showSubServiceIndication(self):
855                 self["ButtonGreen"].showWidget()
856                 self["ButtonGreenText"].show()
857
858         def checkFormat(self, service):
859                 info = service.info()
860                 if info is not None:
861                         aspect = info.getInfo(iServiceInformation.sAspect)
862                         if aspect in [ 3, 4, 7, 8, 0xB, 0xC, 0xF, 0x10 ]:
863                                 self["FormatActive"].showWidget()
864                         else:
865                                 self["FormatActive"].hideWidget()
866
867         def checkSubservices(self, service):
868                 if service.subServices().getNumberOfSubservices() > 0:
869                         self.showSubServiceIndication()
870                 else:
871                         self.hideSubServiceIndication()
872
873         def checkDolby(self, service):
874                 dolby = False
875                 audio = service.audioTracks()
876                 if audio is not None:
877                         n = audio.getNumberOfTracks()
878                         for x in range(n):
879                                 i = audio.getTrackInfo(x)
880                                 description = i.getDescription();
881                                 if description.find("AC3") != -1 or description.find("DTS") != -1:
882                                         dolby = True
883                                         break
884                 if dolby:
885                         self["DolbyActive"].showWidget()
886                 else:
887                         self["DolbyActive"].hideWidget()
888
889         def checkCrypted(self, service):
890                 info = service.info()
891                 if info is not None:
892                         if info.getInfo(iServiceInformation.sIsCrypted) > 0:
893                                 self["CryptActive"].showWidget()
894                         else:
895                                 self["CryptActive"].hideWidget()
896
897         def gotServiceEvent(self, ev):
898                 service = self.session.nav.getCurrentService()
899                 if ev == pNavigation.evUpdatedEventInfo:
900                         self.checkSubservices(service)
901                         self.checkFormat(service)
902                 elif ev == pNavigation.evUpdatedInfo:
903                         self.checkCrypted(service)
904                         self.checkDolby(service)
905                 elif ev == pNavigation.evStopService:
906                         self.hideSubServiceIndication()
907                         self["CryptActive"].hideWidget()
908                         self["DolbyActive"].hideWidget()
909                         self["FormatActive"].hideWidget()
910
911 class InfoBarNotifications:
912         def __init__(self):
913                 self.onExecBegin.append(self.checkNotifications)
914                 Notifications.notificationAdded.append(self.checkNotificationsIfExecing)
915         
916         def checkNotificationsIfExecing(self):
917                 if self.execing:
918                         self.checkNotifications()
919
920         def checkNotifications(self):
921                 if len(Notifications.notifications):
922                         n = Notifications.notifications[0]
923                         Notifications.notifications = Notifications.notifications[1:]
924                         print "open",n
925                         cb = n[0]
926                         if cb is not None:
927                                 self.session.openWithCallback(cb, *n[1:])
928                         else:
929                                 self.session.open(*n[1:])