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