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