add two native python epg views
[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.showEPGList, _("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 openBouquetEPG(self, bouquet):
378                 ptr=eEPGCache.getInstance()
379                 services = [ ]
380                 servicelist = eServiceCenter.getInstance().list(bouquet)
381                 if not servicelist is None:
382                         while True:
383                                 service = servicelist.getNext()
384                                 if not service.valid(): #check if end of list
385                                         break
386                                 if service.flags: #ignore non playable services
387                                         continue
388                                 services.append(ServiceReference(service))
389                 if len(services):
390                         self.session.open(EPGSelection, services)
391
392         def openSingleEPGSelector(self, ref):
393                 ptr=eEPGCache.getInstance()
394                 if ptr.startTimeQuery(ref) != -1:
395                         self.session.open(EPGSelection, ref)
396                 else: # try to show now/next
397                         print 'no epg for service', ref.toString()
398                         try:
399                                 self.epglist = [ ]
400                                 service = self.session.nav.getCurrentService()
401                                 info = service.info()
402                                 ptr=info.getEvent(0)
403                                 if ptr:
404                                         self.epglist.append(ptr)
405                                 ptr=info.getEvent(1)
406                                 if ptr:
407                                         self.epglist.append(ptr)
408                                 if len(self.epglist) > 0:
409                                         self.session.open(EventView, self.epglist[0], ServiceReference(ref), self.eventViewCallback)
410                         except:
411                                 pass
412
413         def eventViewCallback(self, setEvent, setService, val): #used for now/next displaying
414                 if len(self.epglist) > 1:
415                         tmp = self.epglist[0]
416                         self.epglist[0]=self.epglist[1]
417                         self.epglist[1]=tmp
418                         setEvent(self.epglist[0])
419
420 from math import log
421
422 class InfoBarTuner:
423         """provides a snr/agc/ber display"""
424         def __init__(self):
425                 self["snr"] = Label()
426                 self["agc"] = Label()
427                 self["ber"] = Label()
428                 self["snr_percent"] = Label()
429                 self["agc_percent"] = Label()
430                 self["ber_count"] = Label()
431                 self["snr_progress"] = ProgressBar()
432                 self["agc_progress"] = ProgressBar()
433                 self["ber_progress"] = ProgressBar()
434                 self.timer = eTimer()
435                 self.timer.timeout.get().append(self.updateTunerInfo)
436                 self.timer.start(1000)
437
438         def calc(self,val):
439                 if not val:
440                         return 0
441                 if val < 2500:
442                         return (long)(log(val)/log(2))
443                 return val*100/65535
444
445         def updateTunerInfo(self):
446                 if self.instance.isVisible():
447                         service = self.session.nav.getCurrentService()
448                         snr=0
449                         agc=0
450                         ber=0
451                         if service is not None:
452                                 feinfo = service.frontendStatusInfo()
453                                 if feinfo is not None:
454                                         ber=feinfo.getFrontendInfo(iFrontendStatusInformation.bitErrorRate)
455                                         snr=feinfo.getFrontendInfo(iFrontendStatusInformation.signalPower)*100/65536
456                                         agc=feinfo.getFrontendInfo(iFrontendStatusInformation.signalQuality)*100/65536
457                         self["snr_percent"].setText("%d%%"%(snr))
458                         self["agc_percent"].setText("%d%%"%(agc))
459                         self["ber_count"].setText("%d"%(ber))
460                         self["snr_progress"].setValue(snr)
461                         self["agc_progress"].setValue(agc)
462                         self["ber_progress"].setValue(self.calc(ber))
463
464 class InfoBarEvent:
465         """provides a current/next event info display"""
466         def __init__(self):
467                 self["Event_Now_StartTime"] = EventInfo(self.session.nav, EventInfo.Now_StartTime)
468                 self["Event_Next_StartTime"] = EventInfo(self.session.nav, EventInfo.Next_StartTime)
469                                 
470                 self["Event_Now"] = EventInfo(self.session.nav, EventInfo.Now)
471                 self["Event_Next"] = EventInfo(self.session.nav, EventInfo.Next)
472
473                 self["Event_Now_Duration"] = EventInfo(self.session.nav, EventInfo.Now_Duration)
474                 self["Event_Next_Duration"] = EventInfo(self.session.nav, EventInfo.Next_Duration)
475
476 class InfoBarServiceName:
477         def __init__(self):
478                 self["ServiceName"] = ServiceName(self.session.nav)
479
480 class InfoBarPVR:
481
482         # ispause, isff, issm, skip
483         SEEK_STATE_PLAY = (0, 0, 0, 0)
484         SEEK_STATE_PAUSE = (1, 0, 0, 0)
485         SEEK_STATE_FF_2X = (0, 2, 0, 0)
486         SEEK_STATE_FF_4X = (0, 4, 0, 0)
487         SEEK_STATE_FF_8X = (0, 8, 0, 0)
488         SEEK_STATE_FF_32X = (0, 4, 0, 32)
489         SEEK_STATE_FF_64X = (0, 4, 0, 64)
490         SEEK_STATE_FF_128X = (0, 4, 0, 128)
491         
492         SEEK_STATE_BACK_4X = (0, 0, 0, -4)
493         SEEK_STATE_BACK_32X = (0, 0, 0, -32)
494         SEEK_STATE_BACK_64X = (0, 0, 0, -64)
495         SEEK_STATE_BACK_128X = (0, 0, 0, -128)
496         
497         SEEK_STATE_SM_HALF = (0, 0, 2, 0)
498         SEEK_STATE_SM_QUARTER = (0, 0, 4, 0)
499         SEEK_STATE_SM_EIGHTH = (0, 0, 8, 0)
500         
501         """handles PVR specific actions like seeking, pause"""
502         def __init__(self):
503                 self["PVRActions"] = HelpableActionMap(self, "InfobarPVRActions", 
504                         {
505                                 "pauseService": (self.pauseService, "pause"),
506                                 "unPauseService": (self.unPauseService, "continue"),
507                                 
508                                 "seekFwd": (self.seekFwd, "skip forward"),
509                                 "seekFwdUp": (self.seekFwdUp, "skip forward"),
510                                 "seekBack": (self.seekBack, "skip backward"),
511                                 "seekBackUp": (self.seekBackUp, "skip backward"),
512                                                          
513                                 "up": (self.showMovies, "movie list"),
514                                 "down": (self.showMovies, "movie list")
515                         })
516
517                 self.seekstate = self.SEEK_STATE_PLAY
518                 self.seekTimer = eTimer()
519                 self.seekTimer.timeout.get().append(self.seekTimerFired)
520                 self.skipinterval = 500 # 500ms skip interval
521                 self.onClose.append(self.delSeekTimer)
522                 
523                 self.fwdtimer = False
524                 self.fwdKeyTimer = eTimer()
525                 self.fwdKeyTimer.timeout.get().append(self.fwdTimerFire)
526
527                 self.rwdtimer = False
528                 self.rwdKeyTimer = eTimer()
529                 self.rwdKeyTimer.timeout.get().append(self.rwdTimerFire)
530         
531         def up(self):
532                 pass
533         
534         def down(self):
535                 pass
536         
537         def delSeekTimer(self):
538                 del self.seekTimer
539         
540         def seekTimerFired(self):
541                 self.seekbase += self.skipmode * self.skipinterval
542                 
543                 # check if we bounced against the beginning of the file
544                 if self.seekbase < 0:
545                         self.seekbase = 0;
546                         self.setSeekState(self.SEEK_STATE_PLAY)
547                         
548                 self.doSeek(self.seekbase)
549
550         def setSeekState(self, state):
551                 oldstate = self.seekstate
552                 
553                 self.seekstate = state
554
555                 service = self.session.nav.getCurrentService()
556                 if service is None:
557                         return
558                 
559                 pauseable = service.pause()
560                 
561                 for i in range(4):
562                         if oldstate[i] != self.seekstate[i]:
563                                 (self.session.nav.pause, pauseable.setFastForward, pauseable.setSlowMotion, self.setSkipMode)[i](self.seekstate[i])
564                 
565         def setSkipMode(self, skipmode):
566                 self.skipmode = skipmode
567                 if skipmode == 0:
568                         self.seekTimer.stop()
569                 else:
570                         self.seekTimer.start(500)
571                 
572                 service = self.session.nav.getCurrentService()
573                 if service is None:
574                         return
575                 
576                 seekable = service.seek()
577                 if seekable is None:
578                         return
579
580                 if skipmode:
581                         seekable.setTrickmode(1)
582                 else:
583                         seekable.setTrickmode(0)
584                 
585                 self.seekbase = seekable.getPlayPosition()[1] / 90
586         
587         def pauseService(self):
588                 if (self.seekstate == self.SEEK_STATE_PAUSE):
589                         self.unPauseService()
590                 else:
591                         self.setSeekState(self.SEEK_STATE_PAUSE);
592                 
593         def unPauseService(self):
594                 self.setSeekState(self.SEEK_STATE_PLAY);
595         
596         def doSeek(self, seektime):
597                 service = self.session.nav.getCurrentService()
598                 if service is None:
599                         return
600                 
601                 seekable = service.seek()
602                 if seekable is None:
603                         return
604                 seekable.seekTo(90 * seektime)
605
606         def seekFwd(self):
607                 print "start fwd timer"
608                 self.fwdtimer = True
609                 self.fwdKeyTimer.start(500)
610
611         def seekBack(self):
612                 print "start rewind timer"
613                 self.rwdtimer = True
614                 self.rwdKeyTimer.start(500)
615
616         def seekFwdUp(self):
617                 if self.fwdtimer:
618                         self.fwdKeyTimer.stop()
619                         self.fwdtimer = False
620                         lookup = {
621                                         self.SEEK_STATE_PLAY: self.SEEK_STATE_FF_2X,
622                                         self.SEEK_STATE_PAUSE: self.SEEK_STATE_SM_EIGHTH,
623                                         self.SEEK_STATE_FF_2X: self.SEEK_STATE_FF_4X,
624                                         self.SEEK_STATE_FF_4X: self.SEEK_STATE_FF_8X,
625                                         self.SEEK_STATE_FF_8X: self.SEEK_STATE_FF_32X,
626                                         self.SEEK_STATE_FF_32X: self.SEEK_STATE_FF_64X,
627                                         self.SEEK_STATE_FF_64X: self.SEEK_STATE_FF_128X,
628                                         self.SEEK_STATE_FF_128X: self.SEEK_STATE_FF_128X,
629                                         self.SEEK_STATE_BACK_4X: self.SEEK_STATE_PLAY,
630                                         self.SEEK_STATE_BACK_32X: self.SEEK_STATE_BACK_4X,
631                                         self.SEEK_STATE_BACK_64X: self.SEEK_STATE_BACK_32X,
632                                         self.SEEK_STATE_BACK_128X: self.SEEK_STATE_BACK_64X,
633                                         self.SEEK_STATE_SM_HALF: self.SEEK_STATE_SM_HALF,
634                                         self.SEEK_STATE_SM_QUARTER: self.SEEK_STATE_SM_HALF,
635                                         self.SEEK_STATE_SM_EIGHTH: self.SEEK_STATE_SM_QUARTER
636                                 }
637                         self.setSeekState(lookup[self.seekstate]);
638         
639         def seekBackUp(self):
640                 if self.rwdtimer:
641                         self.rwdKeyTimer.stop()
642                         self.rwdtimer = False
643                 
644                         lookup = {
645                                         self.SEEK_STATE_PLAY: self.SEEK_STATE_BACK_4X,
646                                         self.SEEK_STATE_PAUSE: self.SEEK_STATE_PAUSE,
647                                         self.SEEK_STATE_FF_2X: self.SEEK_STATE_PLAY,
648                                         self.SEEK_STATE_FF_4X: self.SEEK_STATE_FF_2X,
649                                         self.SEEK_STATE_FF_8X: self.SEEK_STATE_FF_4X,
650                                         self.SEEK_STATE_FF_32X: self.SEEK_STATE_FF_8X,
651                                         self.SEEK_STATE_FF_64X: self.SEEK_STATE_FF_32X,
652                                         self.SEEK_STATE_FF_128X: self.SEEK_STATE_FF_64X,
653                                         self.SEEK_STATE_BACK_4X: self.SEEK_STATE_BACK_32X,
654                                         self.SEEK_STATE_BACK_32X: self.SEEK_STATE_BACK_64X,
655                                         self.SEEK_STATE_BACK_64X: self.SEEK_STATE_BACK_128X,
656                                         self.SEEK_STATE_BACK_128X: self.SEEK_STATE_BACK_128X,
657                                         self.SEEK_STATE_SM_HALF: self.SEEK_STATE_SM_QUARTER,
658                                         self.SEEK_STATE_SM_QUARTER: self.SEEK_STATE_SM_EIGHTH,
659                                         self.SEEK_STATE_SM_EIGHTH: self.SEEK_STATE_PAUSE
660                                 }
661                         self.setSeekState(lookup[self.seekstate]);
662                 
663         def fwdTimerFire(self):
664                 print "Display seek fwd"
665                 self.fwdKeyTimer.stop()
666                 self.fwdtimer = False
667                 self.session.openWithCallback(self.fwdSeekTo, MinuteInput)
668                 
669         def fwdSeekTo(self, minutes):
670                 print "Seek", minutes, "minutes forward"
671                 if minutes != 0:
672                         service = self.session.nav.getCurrentService()
673                         if service is None:
674                                 return
675                         seekable = service.seek()
676                         if seekable is None:
677                                 return
678                         seekable.seekRelative(1, minutes * 60 * 90000)
679         
680         def rwdTimerFire(self):
681                 self.rwdKeyTimer.stop()
682                 self.rwdtimer = False
683                 self.session.openWithCallback(self.rwdSeekTo, MinuteInput)
684         
685         def rwdSeekTo(self, minutes):
686                 self.fwdSeekTo(0 - minutes)
687
688 from RecordTimer import parseEvent
689
690 class InfoBarInstantRecord:
691         """Instant Record - handles the instantRecord action in order to 
692         start/stop instant records"""
693         def __init__(self):
694                 self["InstantRecordActions"] = HelpableActionMap(self, "InfobarInstantRecord",
695                         {
696                                 "instantRecord": (self.instantRecord, "Instant Record..."),
697                         })
698                 self.recording = None
699                 
700                 self["BlinkingPoint"] = BlinkingPixmapConditional()
701                 self.onShown.append(self["BlinkingPoint"].hideWidget)
702                 self["BlinkingPoint"].setConnect(self.session.nav.RecordTimer.isRecording)
703                 
704         def stopCurrentRecording(self): 
705                 self.session.nav.RecordTimer.removeEntry(self.recording)
706                 self.recording = None
707                         
708         def startInstantRecording(self):
709                 serviceref = self.session.nav.getCurrentlyPlayingServiceReference()
710                 
711                 # try to get event info
712                 event = None
713                 try:
714                         service = self.session.nav.getCurrentService()
715                         info = service.info()
716                         ev = info.getEvent(0)
717                         event = ev
718                 except:
719                         pass
720                 
721                 if event is not None:
722                         data = parseEvent(event)
723                         data = (data[0], data[1] + 3600 * 10, data[2], data[3], data[4])
724                 else:
725                         data = (time.time(), time.time() + 3600 * 10, "instant record", "", None)
726                 
727                 # fix me, description. 
728                 self.recording = self.session.nav.recordWithTimer(serviceref, *data)
729                 self.recording.dontSave = True
730                 
731                 #self["BlinkingPoint"].setConnect(lambda: self.recording.isRunning())
732                 
733         def isInstantRecordRunning(self):
734                 if self.recording != None:
735                         if self.recording.isRunning():
736                                 return True
737                 return False
738
739         def recordQuestionCallback(self, answer):
740                 if answer == False:
741                         return
742                 
743                 if self.isInstantRecordRunning():
744                         self.stopCurrentRecording()
745                 else:
746                         self.startInstantRecording()
747
748         def instantRecord(self):
749                 try:
750                         stat = os.stat(resolveFilename(SCOPE_HDD))
751                 except:
752                         self.session.open(MessageBox, _("No HDD found or HDD not initialized!"), MessageBox.TYPE_ERROR)
753                         return
754         
755                 if self.isInstantRecordRunning():
756                         self.session.openWithCallback(self.recordQuestionCallback, MessageBox, _("Do you want to stop the current\n(instant) recording?"))
757                 else:
758                         self.session.openWithCallback(self.recordQuestionCallback, MessageBox, _("Start recording?"))
759
760 from Screens.AudioSelection import AudioSelection
761
762 class InfoBarAudioSelection:
763         def __init__(self):
764                 self["AudioSelectionAction"] = HelpableActionMap(self, "InfobarAudioSelectionActions", 
765                         {
766                                 "audioSelection": (self.audioSelection, "Audio Options..."),
767                         })
768
769         def audioSelection(self):
770                 service = self.session.nav.getCurrentService()
771                 audio = service.audioTracks()
772                 n = audio.getNumberOfTracks()
773                 if n > 0:
774                         self.session.open(AudioSelection, audio)
775
776 from Screens.SubserviceSelection import SubserviceSelection
777
778 class InfoBarSubserviceSelection:
779         def __init__(self):
780                 self["SubserviceSelectionAction"] = HelpableActionMap(self, "InfobarSubserviceSelectionActions",
781                         {
782                                 "subserviceSelection": (self.subserviceSelection, "Subservice list..."),
783                         })
784
785         def subserviceSelection(self):
786                 service = self.session.nav.getCurrentService()
787                 subservices = service.subServices()
788                 n = subservices.getNumberOfSubservices()
789                 if n > 0:
790                         self.session.openWithCallback(self.subserviceSelected, SubserviceSelection, subservices)
791
792         def subserviceSelected(self, service):
793                 if not service is None:
794                         self.session.nav.playService(service)
795
796 class InfoBarAdditionalInfo:
797         def __init__(self):
798                 self["DolbyActive"] = Pixmap()
799                 self["CryptActive"] = Pixmap()
800                 self["FormatActive"] = Pixmap()
801                 
802                 self["ButtonRed"] = PixmapConditional(withTimer = False)
803                 self["ButtonRed"].setConnect(lambda: harddiskmanager.HDDCount() > 0)
804                 self.onShown.append(self["ButtonRed"].update)
805                 self["ButtonRedText"] = LabelConditional(text = _("Record"), withTimer = False)
806                 self["ButtonRedText"].setConnect(lambda: harddiskmanager.HDDCount() > 0)
807                 self.onShown.append(self["ButtonRedText"].update)
808
809                 self["ButtonGreen"] = Pixmap()
810                 self["ButtonGreenText"] = Label(_("Subservices"))
811
812                 self["ButtonYellow"] = PixmapConditional(withTimer = False)
813                 self["ButtonYellow"].setConnect(lambda: False)
814
815                 self["ButtonBlue"] = PixmapConditional(withTimer = False)
816                 self["ButtonBlue"].setConnect(lambda: False)
817
818                 self.session.nav.event.append(self.gotServiceEvent) # we like to get service events
819
820         def hideSubServiceIndication(self):
821                 self["ButtonGreen"].hideWidget()
822                 self["ButtonGreenText"].hide()
823
824         def showSubServiceIndication(self):
825                 self["ButtonGreen"].showWidget()
826                 self["ButtonGreenText"].show()
827
828         def checkFormat(self, service):
829                 info = service.info()
830                 if info is not None:
831                         aspect = info.getInfo(iServiceInformation.sAspect)
832                         if aspect in [ 3, 4, 7, 8, 0xB, 0xC, 0xF, 0x10 ]:
833                                 self["FormatActive"].showWidget()
834                         else:
835                                 self["FormatActive"].hideWidget()
836
837         def checkSubservices(self, service):
838                 if service.subServices().getNumberOfSubservices() > 0:
839                         self.showSubServiceIndication()
840                 else:
841                         self.hideSubServiceIndication()
842
843         def checkDolby(self, service):
844                 dolby = False
845                 audio = service.audioTracks()
846                 if audio is not None:
847                         n = audio.getNumberOfTracks()
848                         for x in range(n):
849                                 i = audio.getTrackInfo(x)
850                                 description = i.getDescription();
851                                 if description.find("AC3") != -1 or description.find("DTS") != -1:
852                                         dolby = True
853                                         break
854                 if dolby:
855                         self["DolbyActive"].showWidget()
856                 else:
857                         self["DolbyActive"].hideWidget()
858
859         def checkCrypted(self, service):
860                 info = service.info()
861                 if info is not None:
862                         if info.getInfo(iServiceInformation.sIsCrypted) > 0:
863                                 self["CryptActive"].showWidget()
864                         else:
865                                 self["CryptActive"].hideWidget()
866
867         def gotServiceEvent(self, ev):
868                 service = self.session.nav.getCurrentService()
869                 if ev == pNavigation.evUpdatedEventInfo:
870                         self.checkSubservices(service)
871                         self.checkFormat(service)
872                 elif ev == pNavigation.evUpdatedInfo:
873                         self.checkCrypted(service)
874                         self.checkDolby(service)
875                 elif ev == pNavigation.evStopService:
876                         self.hideSubServiceIndication()
877                         self["CryptActive"].hideWidget()
878                         self["DolbyActive"].hideWidget()
879                         self["FormatActive"].hideWidget()
880
881 class InfoBarNotifications:
882         def __init__(self):
883                 self.onExecBegin.append(self.checkNotifications)
884                 Notifications.notificationAdded.append(self.checkNotificationsIfExecing)
885         
886         def checkNotificationsIfExecing(self):
887                 if self.execing:
888                         self.checkNotifications()
889
890         def checkNotifications(self):
891                 if len(Notifications.notifications):
892                         n = Notifications.notifications[0]
893                         Notifications.notifications = Notifications.notifications[1:]
894                         print "open",n
895                         cb = n[0]
896                         if cb is not None:
897                                 self.session.openWithCallback(cb, *n[1:])
898                         else:
899                                 self.session.open(*n[1:])