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