remove VolumeControl from infobar
[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 class InfoBarServiceName:
458         def __init__(self):
459                 self["ServiceName"] = ServiceName(self.session.nav)
460
461 class InfoBarSeek:
462         """handles actions like seeking, pause"""
463         
464         # ispause, isff, issm, skip
465         SEEK_STATE_PLAY = (0, 0, 0, 0)
466         SEEK_STATE_PAUSE = (1, 0, 0, 0)
467         SEEK_STATE_FF_2X = (0, 2, 0, 0)
468         SEEK_STATE_FF_4X = (0, 4, 0, 0)
469         SEEK_STATE_FF_8X = (0, 8, 0, 0)
470         SEEK_STATE_FF_32X = (0, 4, 0, 32)
471         SEEK_STATE_FF_64X = (0, 4, 0, 64)
472         SEEK_STATE_FF_128X = (0, 4, 0, 128)
473         
474         SEEK_STATE_BACK_4X = (0, 0, 0, -4)
475         SEEK_STATE_BACK_32X = (0, 0, 0, -32)
476         SEEK_STATE_BACK_64X = (0, 0, 0, -64)
477         SEEK_STATE_BACK_128X = (0, 0, 0, -128)
478         
479         SEEK_STATE_SM_HALF = (0, 0, 2, 0)
480         SEEK_STATE_SM_QUARTER = (0, 0, 4, 0)
481         SEEK_STATE_SM_EIGHTH = (0, 0, 8, 0)
482         
483         def __init__(self):
484                 self["SeekActions"] = HelpableActionMap(self, "InfobarSeekActions", 
485                         {
486                                 "pauseService": (self.pauseService, "pause"),
487                                 "unPauseService": (self.unPauseService, "continue"),
488                                 
489                                 "seekFwd": (self.seekFwd, "skip forward"),
490                                 "seekFwdUp": (self.seekFwdUp, "skip forward"),
491                                 "seekBack": (self.seekBack, "skip backward"),
492                                 "seekBackUp": (self.seekBackUp, "skip backward"),
493                         })
494
495                 self.seekstate = self.SEEK_STATE_PLAY
496                 self.seekTimer = eTimer()
497                 self.seekTimer.timeout.get().append(self.seekTimerFired)
498                 self.skipinterval = 500 # 500ms skip interval
499                 self.onClose.append(self.delSeekTimer)
500                 
501                 self.fwdtimer = False
502                 self.fwdKeyTimer = eTimer()
503                 self.fwdKeyTimer.timeout.get().append(self.fwdTimerFire)
504
505                 self.rwdtimer = False
506                 self.rwdKeyTimer = eTimer()
507                 self.rwdKeyTimer.timeout.get().append(self.rwdTimerFire)
508         
509         def up(self):
510                 pass
511         
512         def down(self):
513                 pass
514         
515         def delSeekTimer(self):
516                 del self.seekTimer
517         
518         def seekTimerFired(self):
519                 self.seekbase += self.skipmode * self.skipinterval
520                 
521                 # check if we bounced against the beginning of the file
522                 if self.seekbase < 0:
523                         self.seekbase = 0;
524                         self.setSeekState(self.SEEK_STATE_PLAY)
525                         
526                 self.doSeek(self.seekbase)
527
528         def setSeekState(self, state):
529                 oldstate = self.seekstate
530                 
531                 self.seekstate = state
532
533                 service = self.session.nav.getCurrentService()
534                 if service is None:
535                         return
536                 
537                 pauseable = service.pause()
538                 
539                 for i in range(4):
540                         if oldstate[i] != self.seekstate[i]:
541                                 (self.session.nav.pause, pauseable.setFastForward, pauseable.setSlowMotion, self.setSkipMode)[i](self.seekstate[i])
542                 
543         def setSkipMode(self, skipmode):
544                 self.skipmode = skipmode
545                 if skipmode == 0:
546                         self.seekTimer.stop()
547                 else:
548                         self.seekTimer.start(500)
549                 
550                 service = self.session.nav.getCurrentService()
551                 if service is None:
552                         return
553                 
554                 seekable = service.seek()
555                 if seekable is None:
556                         return
557
558                 if skipmode:
559                         seekable.setTrickmode(1)
560                 else:
561                         seekable.setTrickmode(0)
562                 
563                 self.seekbase = seekable.getPlayPosition()[1] / 90
564         
565         def pauseService(self):
566                 if (self.seekstate == self.SEEK_STATE_PAUSE):
567                         self.unPauseService()
568                 else:
569                         self.setSeekState(self.SEEK_STATE_PAUSE);
570                 
571         def unPauseService(self):
572                 self.setSeekState(self.SEEK_STATE_PLAY);
573         
574         def doSeek(self, seektime):
575                 service = self.session.nav.getCurrentService()
576                 if service is None:
577                         return
578                 
579                 seekable = service.seek()
580                 if seekable is None:
581                         return
582                 seekable.seekTo(90 * seektime)
583
584         def seekFwd(self):
585                 print "start fwd timer"
586                 self.fwdtimer = True
587                 self.fwdKeyTimer.start(500)
588
589         def seekBack(self):
590                 print "start rewind timer"
591                 self.rwdtimer = True
592                 self.rwdKeyTimer.start(500)
593
594         def seekFwdUp(self):
595                 if self.fwdtimer:
596                         self.fwdKeyTimer.stop()
597                         self.fwdtimer = False
598                         lookup = {
599                                         self.SEEK_STATE_PLAY: self.SEEK_STATE_FF_2X,
600                                         self.SEEK_STATE_PAUSE: self.SEEK_STATE_SM_EIGHTH,
601                                         self.SEEK_STATE_FF_2X: self.SEEK_STATE_FF_4X,
602                                         self.SEEK_STATE_FF_4X: self.SEEK_STATE_FF_8X,
603                                         self.SEEK_STATE_FF_8X: self.SEEK_STATE_FF_32X,
604                                         self.SEEK_STATE_FF_32X: self.SEEK_STATE_FF_64X,
605                                         self.SEEK_STATE_FF_64X: self.SEEK_STATE_FF_128X,
606                                         self.SEEK_STATE_FF_128X: self.SEEK_STATE_FF_128X,
607                                         self.SEEK_STATE_BACK_4X: self.SEEK_STATE_PLAY,
608                                         self.SEEK_STATE_BACK_32X: self.SEEK_STATE_BACK_4X,
609                                         self.SEEK_STATE_BACK_64X: self.SEEK_STATE_BACK_32X,
610                                         self.SEEK_STATE_BACK_128X: self.SEEK_STATE_BACK_64X,
611                                         self.SEEK_STATE_SM_HALF: self.SEEK_STATE_SM_HALF,
612                                         self.SEEK_STATE_SM_QUARTER: self.SEEK_STATE_SM_HALF,
613                                         self.SEEK_STATE_SM_EIGHTH: self.SEEK_STATE_SM_QUARTER
614                                 }
615                         self.setSeekState(lookup[self.seekstate]);
616         
617         def seekBackUp(self):
618                 if self.rwdtimer:
619                         self.rwdKeyTimer.stop()
620                         self.rwdtimer = False
621                 
622                         lookup = {
623                                         self.SEEK_STATE_PLAY: self.SEEK_STATE_BACK_4X,
624                                         self.SEEK_STATE_PAUSE: self.SEEK_STATE_PAUSE,
625                                         self.SEEK_STATE_FF_2X: self.SEEK_STATE_PLAY,
626                                         self.SEEK_STATE_FF_4X: self.SEEK_STATE_FF_2X,
627                                         self.SEEK_STATE_FF_8X: self.SEEK_STATE_FF_4X,
628                                         self.SEEK_STATE_FF_32X: self.SEEK_STATE_FF_8X,
629                                         self.SEEK_STATE_FF_64X: self.SEEK_STATE_FF_32X,
630                                         self.SEEK_STATE_FF_128X: self.SEEK_STATE_FF_64X,
631                                         self.SEEK_STATE_BACK_4X: self.SEEK_STATE_BACK_32X,
632                                         self.SEEK_STATE_BACK_32X: self.SEEK_STATE_BACK_64X,
633                                         self.SEEK_STATE_BACK_64X: self.SEEK_STATE_BACK_128X,
634                                         self.SEEK_STATE_BACK_128X: self.SEEK_STATE_BACK_128X,
635                                         self.SEEK_STATE_SM_HALF: self.SEEK_STATE_SM_QUARTER,
636                                         self.SEEK_STATE_SM_QUARTER: self.SEEK_STATE_SM_EIGHTH,
637                                         self.SEEK_STATE_SM_EIGHTH: self.SEEK_STATE_PAUSE
638                                 }
639                         self.setSeekState(lookup[self.seekstate]);
640                 
641         def fwdTimerFire(self):
642                 print "Display seek fwd"
643                 self.fwdKeyTimer.stop()
644                 self.fwdtimer = False
645                 self.session.openWithCallback(self.fwdSeekTo, MinuteInput)
646                 
647         def fwdSeekTo(self, minutes):
648                 print "Seek", minutes, "minutes forward"
649                 if minutes != 0:
650                         service = self.session.nav.getCurrentService()
651                         if service is None:
652                                 return
653                         seekable = service.seek()
654                         if seekable is None:
655                                 return
656                         seekable.seekRelative(1, minutes * 60 * 90000)
657         
658         def rwdTimerFire(self):
659                 self.rwdKeyTimer.stop()
660                 self.rwdtimer = False
661                 self.session.openWithCallback(self.rwdSeekTo, MinuteInput)
662         
663         def rwdSeekTo(self, minutes):
664                 self.fwdSeekTo(0 - minutes)
665
666 class InfoBarShowMovies:
667
668         # i don't really like this class. 
669         # it calls a not further specified "movie list" on up/down/movieList,
670         # so this is not moe than an action map
671         def __init__(self):
672                 self["MovieListActions"] = HelpableActionMap(self, "InfobarMovieListActions", 
673                         {
674                                 "movieList": (self.showMovies, "movie list"),
675                                 "up": (self.showMovies, "movie list"),
676                                 "down": (self.showMovies, "movie list")
677                         })
678
679 class InfoBarTimeshift:
680         def __init__(self):
681                 self["TimeshiftActions"] = HelpableActionMap(self, "InfobarTimeshiftActions", 
682                         {
683                                 "timeshiftStart": (self.startTimeshift, "start timeshift "),
684                                 "timeshiftStop": (self.stopTimeshift, "stop timeshift")
685                         })
686                 self.tshack = 0
687         
688         def getTimeshift(self):
689                 service = self.session.nav.getCurrentService()
690                 return service.timeshift()
691
692         def startTimeshift(self):
693                 # TODO: check for harddisk! (or do this in the interface? would make
694                 # more sense... for example radio could be timeshifted in memory,
695                 # and the decision can't be made here)
696                 print "enable timeshift"
697                 ts = self.getTimeshift()
698                 if ts is None:
699                         self.session.open(MessageBox, _("Timeshift not possible!"), MessageBox.TYPE_ERROR)
700                         print "no ts interface"
701                         return
702                 print "ok, timeshift enabled"
703                 if self.tshack == 0:
704                         ts.startTimeshift()
705                         self.tshack = 1
706                 else:
707                         pauseable = self.session.nav.getCurrentService().pause()
708                         pauseable.pause() # switch to record
709
710         def stopTimeshift(self):
711                 print "disable timeshift"
712                 ts = self.getTimeshift()
713                 if ts is None:
714                         return
715                 ts.stopTimeshift()
716                 self.tshack = 0
717                 
718
719 from RecordTimer import parseEvent
720
721 class InfoBarInstantRecord:
722         """Instant Record - handles the instantRecord action in order to 
723         start/stop instant records"""
724         def __init__(self):
725                 self["InstantRecordActions"] = HelpableActionMap(self, "InfobarInstantRecord",
726                         {
727                                 "instantRecord": (self.instantRecord, "Instant Record..."),
728                         })
729                 self.recording = None
730                 
731                 self["BlinkingPoint"] = BlinkingPixmapConditional()
732                 self.onShown.append(self["BlinkingPoint"].hideWidget)
733                 self["BlinkingPoint"].setConnect(self.session.nav.RecordTimer.isRecording)
734                 
735         def stopCurrentRecording(self): 
736                 self.session.nav.RecordTimer.removeEntry(self.recording)
737                 self.recording = None
738                         
739         def startInstantRecording(self):
740                 serviceref = self.session.nav.getCurrentlyPlayingServiceReference()
741                 
742                 # try to get event info
743                 event = None
744                 try:
745                         service = self.session.nav.getCurrentService()
746                         info = service.info()
747                         ev = info.getEvent(0)
748                         event = ev
749                 except:
750                         pass
751                 
752                 if event is not None:
753                         data = parseEvent(event)
754                         begin = data[0]
755                         if begin < time.time():
756                                 begin = time.time()
757                         
758                         end = data[1]
759                         if end < begin:
760                                 end = begin
761                         
762                         end += 3600 * 10
763                         
764                         data = (begin, end, data[2], data[3], data[4])
765                 else:
766                         data = (time.time(), time.time() + 3600 * 10, "instant record", "", None)
767                 
768                 # fix me, description. 
769                 self.recording = self.session.nav.recordWithTimer(serviceref, *data)
770                 self.recording.dontSave = True
771                 
772                 #self["BlinkingPoint"].setConnect(lambda: self.recording.isRunning())
773                 
774         def isInstantRecordRunning(self):
775                 if self.recording != None:
776                         if self.recording.isRunning():
777                                 return True
778                 return False
779
780         def recordQuestionCallback(self, answer):
781                 if answer == False:
782                         return
783                 
784                 if self.isInstantRecordRunning():
785                         self.stopCurrentRecording()
786                 else:
787                         self.startInstantRecording()
788
789         def instantRecord(self):
790                 try:
791                         stat = os.stat(resolveFilename(SCOPE_HDD))
792                 except:
793                         self.session.open(MessageBox, _("No HDD found or HDD not initialized!"), MessageBox.TYPE_ERROR)
794                         return
795         
796                 if self.isInstantRecordRunning():
797                         self.session.openWithCallback(self.recordQuestionCallback, MessageBox, _("Do you want to stop the current\n(instant) recording?"))
798                 else:
799                         self.session.openWithCallback(self.recordQuestionCallback, MessageBox, _("Start recording?"))
800
801 from Screens.AudioSelection import AudioSelection
802
803 class InfoBarAudioSelection:
804         def __init__(self):
805                 self["AudioSelectionAction"] = HelpableActionMap(self, "InfobarAudioSelectionActions", 
806                         {
807                                 "audioSelection": (self.audioSelection, "Audio Options..."),
808                         })
809
810         def audioSelection(self):
811                 service = self.session.nav.getCurrentService()
812                 audio = service.audioTracks()
813                 n = audio.getNumberOfTracks()
814                 if n > 0:
815                         self.session.open(AudioSelection, audio)
816
817 from Screens.SubserviceSelection import SubserviceSelection
818
819 class InfoBarSubserviceSelection:
820         def __init__(self):
821                 self["SubserviceSelectionAction"] = HelpableActionMap(self, "InfobarSubserviceSelectionActions",
822                         {
823                                 "subserviceSelection": (self.subserviceSelection, "Subservice list..."),
824                         })
825
826         def subserviceSelection(self):
827                 service = self.session.nav.getCurrentService()
828                 subservices = service.subServices()
829                 n = subservices.getNumberOfSubservices()
830                 if n > 0:
831                         self.session.openWithCallback(self.subserviceSelected, SubserviceSelection, subservices)
832
833         def subserviceSelected(self, service):
834                 if not service is None:
835                         self.session.nav.playService(service)
836
837 class InfoBarAdditionalInfo:
838         def __init__(self):
839                 self["DolbyActive"] = Pixmap()
840                 self["CryptActive"] = Pixmap()
841                 self["FormatActive"] = Pixmap()
842                 
843                 self["ButtonRed"] = PixmapConditional(withTimer = False)
844                 self["ButtonRed"].setConnect(lambda: harddiskmanager.HDDCount() > 0)
845                 self.onShown.append(self["ButtonRed"].update)
846                 self["ButtonRedText"] = LabelConditional(text = _("Record"), withTimer = False)
847                 self["ButtonRedText"].setConnect(lambda: harddiskmanager.HDDCount() > 0)
848                 self.onShown.append(self["ButtonRedText"].update)
849
850                 self["ButtonGreen"] = Pixmap()
851                 self["ButtonGreenText"] = Label(_("Subservices"))
852
853                 self["ButtonYellow"] = PixmapConditional(withTimer = False)
854                 self["ButtonYellow"].setConnect(lambda: False)
855
856                 self["ButtonBlue"] = PixmapConditional(withTimer = False)
857                 self["ButtonBlue"].setConnect(lambda: False)
858
859                 self.session.nav.event.append(self.gotServiceEvent) # we like to get service events
860
861         def hideSubServiceIndication(self):
862                 self["ButtonGreen"].hideWidget()
863                 self["ButtonGreenText"].hide()
864
865         def showSubServiceIndication(self):
866                 self["ButtonGreen"].showWidget()
867                 self["ButtonGreenText"].show()
868
869         def checkFormat(self, service):
870                 info = service.info()
871                 if info is not None:
872                         aspect = info.getInfo(iServiceInformation.sAspect)
873                         if aspect in [ 3, 4, 7, 8, 0xB, 0xC, 0xF, 0x10 ]:
874                                 self["FormatActive"].showWidget()
875                         else:
876                                 self["FormatActive"].hideWidget()
877
878         def checkSubservices(self, service):
879                 if service.subServices().getNumberOfSubservices() > 0:
880                         self.showSubServiceIndication()
881                 else:
882                         self.hideSubServiceIndication()
883
884         def checkDolby(self, service):
885                 # FIXME
886                 dolby = False
887                 audio = service.audioTracks()
888                 if audio is not None:
889                         n = audio.getNumberOfTracks()
890                         for x in range(n):
891                                 i = audio.getTrackInfo(x)
892                                 description = i.getDescription();
893                                 if description.find("AC3") != -1 or description.find("DTS") != -1:
894                                         dolby = True
895                                         break
896                 if dolby:
897                         self["DolbyActive"].showWidget()
898                 else:
899                         self["DolbyActive"].hideWidget()
900
901         def checkCrypted(self, service):
902                 info = service.info()
903                 if info is not None:
904                         if info.getInfo(iServiceInformation.sIsCrypted) > 0:
905                                 self["CryptActive"].showWidget()
906                         else:
907                                 self["CryptActive"].hideWidget()
908
909         def gotServiceEvent(self, ev):
910                 service = self.session.nav.getCurrentService()
911                 if ev == pNavigation.evUpdatedEventInfo:
912                         self.checkSubservices(service)
913                         self.checkFormat(service)
914                 elif ev == pNavigation.evUpdatedInfo:
915                         self.checkCrypted(service)
916                         self.checkDolby(service)
917                 elif ev == pNavigation.evStopService:
918                         self.hideSubServiceIndication()
919                         self["CryptActive"].hideWidget()
920                         self["DolbyActive"].hideWidget()
921                         self["FormatActive"].hideWidget()
922
923 class InfoBarNotifications:
924         def __init__(self):
925                 self.onExecBegin.append(self.checkNotifications)
926                 Notifications.notificationAdded.append(self.checkNotificationsIfExecing)
927         
928         def checkNotificationsIfExecing(self):
929                 if self.execing:
930                         self.checkNotifications()
931
932         def checkNotifications(self):
933                 if len(Notifications.notifications):
934                         n = Notifications.notifications[0]
935                         Notifications.notifications = Notifications.notifications[1:]
936                         print "open",n
937                         cb = n[0]
938                         if cb is not None:
939                                 self.session.openWithCallback(cb, *n[1:])
940                         else:
941                                 self.session.open(*n[1:])