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