just one bouquet (favourites)
[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
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 Components.Harddisk import harddiskmanager
25
26 from Tools import Notifications
27
28 #from enigma import eTimer, eDVBVolumecontrol, quitMainloop
29 from enigma import *
30
31 import time
32 import os
33
34 # hack alert!
35 from Menu import MainMenu, mdom
36
37 class InfoBarVolumeControl:
38         """Volume control, handles volUp, volDown, volMute actions and display 
39         a corresponding dialog"""
40         def __init__(self):
41                 config.audio = ConfigSubsection()
42                 config.audio.volume = configElement("config.audio.volume", configSequence, [5], configsequencearg.get("INTEGER", (0, 100)))
43
44                 self["VolumeActions"] = ActionMap( ["InfobarVolumeActions"] ,
45                         {
46                                 "volumeUp": self.volUp,
47                                 "volumeDown": self.volDown,
48                                 "volumeMute": self.volMute,
49                         })
50
51                 self.volumeDialog = self.session.instantiateDialog(Volume)
52                 self.muteDialog = self.session.instantiateDialog(Mute)
53
54                 self.hideVolTimer = eTimer()
55                 self.hideVolTimer.timeout.get().append(self.volHide)
56
57                 vol = config.audio.volume.value[0]
58                 self.volumeDialog.setValue(vol)
59                 eDVBVolumecontrol.getInstance().setVolume(vol, vol)
60         
61         def volSave(self):
62                 config.audio.volume.value = eDVBVolumecontrol.getInstance().getVolume()
63                 config.audio.volume.save()
64                 
65         def     volUp(self):
66                 if (eDVBVolumecontrol.getInstance().isMuted()):
67                         self.volMute()
68                 eDVBVolumecontrol.getInstance().volumeUp()
69                 self.volumeDialog.instance.show()
70                 self.volumeDialog.setValue(eDVBVolumecontrol.getInstance().getVolume())
71                 self.volSave()
72                 self.hideVolTimer.start(3000)
73
74         def     volDown(self):
75                 if (eDVBVolumecontrol.getInstance().isMuted()):
76                         self.volMute()
77                 eDVBVolumecontrol.getInstance().volumeDown()
78                 self.volumeDialog.instance.show()
79                 self.volumeDialog.setValue(eDVBVolumecontrol.getInstance().getVolume())
80                 self.volSave()
81                 self.hideVolTimer.start(3000)
82                 
83         def volHide(self):
84                 self.volumeDialog.instance.hide()
85
86         def     volMute(self):
87                 eDVBVolumecontrol.getInstance().volumeToggleMute()
88                 self.volumeDialog.setValue(eDVBVolumecontrol.getInstance().getVolume())
89                 
90                 if (eDVBVolumecontrol.getInstance().isMuted()):
91                         self.muteDialog.instance.show()
92                 else:
93                         self.muteDialog.instance.hide()
94
95 class InfoBarDish:
96         def __init__(self):
97                 self.dishDialog = self.session.instantiateDialog(Dish)
98                 self.onShown.append(self.dishDialog.instance.hide)
99
100 class InfoBarShowHide:
101         """ InfoBar show/hide control, accepts toggleShow and hide actions, might start
102         fancy animations. """
103         STATE_HIDDEN = 0
104         STATE_HIDING = 1
105         STATE_SHOWING = 2
106         STATE_SHOWN = 3
107         
108         def __init__(self):
109                 self["ShowHideActions"] = ActionMap( ["InfobarShowHideActions"] ,
110                         {
111                                 "toggleShow": self.toggleShow,
112                                 "hide": self.hide,
113                         })
114
115                 self.state = self.STATE_SHOWN
116                 
117                 self.onExecBegin.append(self.show)
118                 self.onClose.append(self.delHideTimer)
119                 
120                 self.hideTimer = eTimer()
121                 self.hideTimer.timeout.get().append(self.doTimerHide)
122                 self.hideTimer.start(5000)
123
124         def delHideTimer(self):
125                 del self.hideTimer
126
127         def hide(self): 
128                 self.instance.hide()
129                 
130         def show(self):
131                 self.state = self.STATE_SHOWN
132                 self.hideTimer.stop()
133                 self.hideTimer.start(5000)
134
135         def doTimerHide(self):
136                 self.hideTimer.stop()
137                 if self.state == self.STATE_SHOWN:
138                         self.instance.hide()
139                         self.state = self.STATE_HIDDEN
140
141         def toggleShow(self):
142                 if self.state == self.STATE_SHOWN:
143                         self.instance.hide()
144                         #pls check animation support, sorry
145 #                       self.startHide()
146                         self.hideTimer.stop()
147                         self.state = self.STATE_HIDDEN
148                 elif self.state == self.STATE_HIDDEN:
149                         self.instance.show()
150                         self.show()
151                         
152         def startShow(self):
153                 self.instance.m_animation.startMoveAnimation(ePoint(0, 600), ePoint(0, 380), 100)
154                 self.state = self.STATE_SHOWN
155         
156         def startHide(self):
157                 self.instance.m_animation.startMoveAnimation(ePoint(0, 380), ePoint(0, 600), 100)
158                 self.state = self.STATE_HIDDEN
159
160 class NumberZap(Screen):
161         def quit(self):
162                 self.Timer.stop()
163                 self.close(0)
164
165         def keyOK(self):
166                 self.Timer.stop()
167                 self.close(int(self["number"].getText()))
168
169         def keyNumberGlobal(self, number):
170                 self.Timer.start(3000)          #reset timer
171                 self.field = self.field + str(number)
172                 self["number"].setText(self.field)
173                 if len(self.field) >= 4:
174                         self.keyOK()
175
176         def __init__(self, session, number):
177                 Screen.__init__(self, session)
178                 self.field = str(number)
179
180                 self["channel"] = Label(_("Channel:"))
181
182                 self["number"] = Label(self.field)
183
184                 self["actions"] = NumberActionMap( [ "SetupActions" ], 
185                         {
186                                 "cancel": self.quit,
187                                 "ok": self.keyOK,
188                                 "1": self.keyNumberGlobal,
189                                 "2": self.keyNumberGlobal,
190                                 "3": self.keyNumberGlobal,
191                                 "4": self.keyNumberGlobal,
192                                 "5": self.keyNumberGlobal,
193                                 "6": self.keyNumberGlobal,
194                                 "7": self.keyNumberGlobal,
195                                 "8": self.keyNumberGlobal,
196                                 "9": self.keyNumberGlobal,
197                                 "0": self.keyNumberGlobal
198                         })
199
200                 self.Timer = eTimer()
201                 self.Timer.timeout.get().append(self.keyOK)
202                 self.Timer.start(3000)
203
204 class InfoBarPowerKey:
205         """ PowerKey stuff - handles the powerkey press and powerkey release actions"""
206         
207         def __init__(self):
208                 self.powerKeyTimer = eTimer()
209                 self.powerKeyTimer.timeout.get().append(self.powertimer)
210                 self["PowerKeyActions"] = HelpableActionMap(self, "PowerKeyActions",
211                         {
212                                 "powerdown": self.powerdown,
213                                 "powerup": self.powerup,
214                                 "discreteStandby": (self.standby, "Go standby"),
215                                 "discretePowerOff": (self.quit, "Go to deep standby"),
216                         })
217
218         def powertimer(self):   
219                 print "PowerOff - Now!"
220                 self.quit()
221         
222         def powerdown(self):
223                 self.standbyblocked = 0
224                 self.powerKeyTimer.start(3000)
225
226         def powerup(self):
227                 self.powerKeyTimer.stop()
228                 if self.standbyblocked == 0:
229                         self.standbyblocked = 1
230                         self.standby()
231
232         def standby(self):
233                 self.session.open(Standby, self)
234
235         def quit(self):
236                 # halt
237                 quitMainloop(1)
238
239 class InfoBarNumberZap:
240         """ Handles an initial number for NumberZapping """
241         def __init__(self):
242                 self["NumberZapActions"] = NumberActionMap( [ "NumberZapActions"],
243                         {
244                                 "1": self.keyNumberGlobal,
245                                 "2": self.keyNumberGlobal,
246                                 "3": self.keyNumberGlobal,
247                                 "4": self.keyNumberGlobal,
248                                 "5": self.keyNumberGlobal,
249                                 "6": self.keyNumberGlobal,
250                                 "7": self.keyNumberGlobal,
251                                 "8": self.keyNumberGlobal,
252                                 "9": self.keyNumberGlobal,
253                                 "0": self.keyNumberGlobal,
254                         })
255
256         def keyNumberGlobal(self, number):
257 #               print "You pressed number " + str(number)
258                 self.session.openWithCallback(self.numberEntered, NumberZap, number)
259
260         def numberEntered(self, retval):
261 #               print self.servicelist
262                 if retval > 0:
263                         self.zapToNumber(retval)
264
265         def searchNumberHelper(self, serviceHandler, num, bouquet):
266                 servicelist = serviceHandler.list(bouquet)
267                 if not servicelist is None:
268                         while num:
269                                 serviceIterator = servicelist.getNext()
270                                 if not serviceIterator.valid(): #check end of list
271                                         break
272                                 if serviceIterator.flags: #assume normal dvb service have no flags set
273                                         continue
274                                 num -= 1;
275                         if not num: #found service with searched number ?
276                                 return serviceIterator, 0
277                 return None, num
278
279         def zapToNumber(self, number):
280                 bouquet = self.servicelist.bouquet_root
281                 service = None
282                 serviceHandler = eServiceCenter.getInstance()
283                 if bouquet.toString().find('FROM BOUQUET "bouquets.') == -1: #FIXME HACK
284                         service, number = self.searchNumberHelper(serviceHandler, number, bouquet)
285                 else:
286                         bouquetlist = serviceHandler.list(bouquet)
287                         if not bouquetlist is None:
288                                 while number:
289                                         bouquet = bouquetlist.getNext()
290                                         if not bouquet.valid(): #check end of list
291                                                 break
292                                         if ((bouquet.flags & eServiceReference.flagDirectory) != eServiceReference.flagDirectory):
293                                                 continue
294                                         service, number = self.searchNumberHelper(serviceHandler, number, bouquet)
295                 if not service is None:
296                         self.session.nav.playService(service) #play service
297                         if self.servicelist.getRoot() != bouquet: #already in correct bouquet?
298                                 self.servicelist.setRoot(bouquet)
299                         self.servicelist.setCurrentSelection(service) #select the service in servicelist
300
301 class InfoBarChannelSelection:
302         """ ChannelSelection - handles the channelSelection dialog and the initial 
303         channelChange actions which open the channelSelection dialog """
304         def __init__(self):
305                 #instantiate forever
306                 self.servicelist = self.session.instantiateDialog(ChannelSelection)
307
308                 self["ChannelSelectActions"] = HelpableActionMap(self, "InfobarChannelSelection",
309                         {
310                                 "switchChannelUp": self.switchChannelUp,
311                                 "switchChannelDown": self.switchChannelDown,
312                                 "zapUp": (self.zapUp, _("next channel")),
313                                 "zapDown": (self.zapDown, _("previous channel")),
314                         })
315                         
316         def switchChannelUp(self):      
317                 self.servicelist.moveUp()
318                 self.session.execDialog(self.servicelist)
319
320         def switchChannelDown(self):    
321                 self.servicelist.moveDown()
322                 self.session.execDialog(self.servicelist)
323
324         def     zapUp(self):
325                 self.servicelist.moveUp()
326                 self.servicelist.zap()
327                 self.instance.show()
328                 self.show()
329
330         def     zapDown(self):
331                 self.servicelist.moveDown()
332                 self.servicelist.zap()
333                 self.instance.show()
334                 self.show()
335                 
336 class InfoBarMenu:
337         """ Handles a menu action, to open the (main) menu """
338         def __init__(self):
339                 self["MenuActions"] = HelpableActionMap(self, "InfobarMenuActions", 
340                         {
341                                 "mainMenu": (self.mainMenu, "Enter main menu..."),
342                         })
343
344         def mainMenu(self):
345                 print "loading mainmenu XML..."
346                 menu = mdom.childNodes[0]
347                 assert menu.tagName == "menu", "root element in menu must be 'menu'!"
348                 self.session.open(MainMenu, menu, menu.childNodes)
349
350 class InfoBarEPG:
351         """ EPG - Opens an EPG list when the showEPGList action fires """
352         def __init__(self):
353                 self["EPGActions"] = HelpableActionMap(self, "InfobarEPGActions", 
354                         {
355                                 "showEPGList": (self.showEPGList, _("show EPG...")),
356                         })
357
358         def showEPGList(self):
359                 ref=self.session.nav.getCurrentlyPlayingServiceReference()
360                 ptr=eEPGCache.getInstance()
361                 if ptr.startTimeQuery(ref) != -1:
362                         self.session.open(EPGSelection, ref)
363                 else: # try to show now/next
364                         print 'no epg for service', ref.toString()
365                         try:
366                                 self.epglist = [ ]
367                                 service = self.session.nav.getCurrentService()
368                                 info = service.info()
369                                 ptr=info.getEvent(0)
370                                 if ptr:
371                                         self.epglist.append(ptr)
372                                 ptr=info.getEvent(1)
373                                 if ptr:
374                                         self.epglist.append(ptr)
375                                 if len(self.epglist) > 0:
376                                         self.session.open(EventView, self.epglist[0], ServiceReference(ref), self.eventViewCallback)
377                         except:
378                                 pass
379
380         def eventViewCallback(self, setEvent, val): #used for now/next displaying
381                 if len(self.epglist) > 1:
382                         tmp = self.epglist[0]
383                         self.epglist[0]=self.epglist[1]
384                         self.epglist[1]=tmp
385                         setEvent(self.epglist[0])
386
387 from math import log
388
389 class InfoBarTuner:
390         """provides a snr/agc/ber display"""
391         def __init__(self):
392                 self["snr"] = Label()
393                 self["agc"] = Label()
394                 self["ber"] = Label()
395                 self["snr_percent"] = Label()
396                 self["agc_percent"] = Label()
397                 self["ber_count"] = Label()
398                 self["snr_progress"] = ProgressBar()
399                 self["agc_progress"] = ProgressBar()
400                 self["ber_progress"] = ProgressBar()
401                 self.timer = eTimer()
402                 self.timer.timeout.get().append(self.updateTunerInfo)
403                 self.timer.start(500)
404
405         def calc(self,val):
406                 if not val:
407                         return 0
408                 if val < 2500:
409                         return (long)(log(val)/log(2))
410                 return val*100/65535
411
412         def updateTunerInfo(self):
413                 if self.instance.isVisible():
414                         service = self.session.nav.getCurrentService()
415                         snr=0
416                         agc=0
417                         ber=0
418                         if service is not None:
419                                 feinfo = service.frontendStatusInfo()
420                                 if feinfo is not None:
421                                         ber=feinfo.getFrontendInfo(iFrontendStatusInformation.bitErrorRate)
422                                         snr=feinfo.getFrontendInfo(iFrontendStatusInformation.signalPower)*100/65536
423                                         agc=feinfo.getFrontendInfo(iFrontendStatusInformation.signalQuality)*100/65536
424                         self["snr_percent"].setText("%d%%"%(snr))
425                         self["agc_percent"].setText("%d%%"%(agc))
426                         self["ber_count"].setText("%d"%(ber))
427                         self["snr_progress"].setValue(snr)
428                         self["agc_progress"].setValue(agc)
429                         self["ber_progress"].setValue(self.calc(ber))
430
431 class InfoBarEvent:
432         """provides a current/next event info display"""
433         def __init__(self):
434                 self["Event_Now_StartTime"] = EventInfo(self.session.nav, EventInfo.Now_StartTime)
435                 self["Event_Next_StartTime"] = EventInfo(self.session.nav, EventInfo.Next_StartTime)
436                                 
437                 self["Event_Now"] = EventInfo(self.session.nav, EventInfo.Now)
438                 self["Event_Next"] = EventInfo(self.session.nav, EventInfo.Next)
439
440                 self["Event_Now_Duration"] = EventInfo(self.session.nav, EventInfo.Now_Duration)
441                 self["Event_Next_Duration"] = EventInfo(self.session.nav, EventInfo.Next_Duration)
442
443 class InfoBarServiceName:
444         def __init__(self):
445                 self["ServiceName"] = ServiceName(self.session.nav)
446
447 class InfoBarPVR:
448         """handles PVR specific actions like seeking, pause"""
449         def __init__(self):
450                 self["PVRActions"] = HelpableActionMap(self, "InfobarPVRActions", 
451                         {
452                                 "pauseService": (self.pauseService, "pause"),
453                                 "unPauseService": (self.unPauseService, "continue"),
454                                 
455                                 "seekFwd": (self.seekFwd, "skip forward"),
456                                 "seekBack": (self.seekBack, "skip backward"),
457                         })
458                 
459         def pauseService(self):
460                 self.session.nav.pause(1)
461                 
462         def unPauseService(self):
463                 self.session.nav.pause(0)
464         
465         def doSeek(self, dir, seektime):
466                 service = self.session.nav.getCurrentService()
467                 if service is None:
468                         return
469                 
470                 seekable = service.seek()
471                 if seekable is None:
472                         return
473                 seekable.seekRelative(dir, 90 * seektime)
474
475         def seekFwd(self):
476                 self.doSeek(+1, 60000)
477         
478         def seekBack(self):
479                 self.doSeek(-1, 60000)
480
481 class InfoBarInstantRecord:
482         """Instant Record - handles the instantRecord action in order to 
483         start/stop instant records"""
484         def __init__(self):
485                 self["InstantRecordActions"] = HelpableActionMap(self, "InfobarInstantRecord",
486                         {
487                                 "instantRecord": (self.instantRecord, "Instant Record..."),
488                         })
489                 self.recording = None
490                 
491                 self["BlinkingPoint"] = BlinkingPixmapConditional()
492                 self.onShown.append(self["BlinkingPoint"].hideWidget)
493                 self["BlinkingPoint"].setConnect(self.session.nav.RecordTimer.isRecording)
494                 
495         def stopCurrentRecording(self): 
496                 self.session.nav.RecordTimer.removeEntry(self.recording)
497                 self.recording = None
498                         
499         def startInstantRecording(self):
500                 serviceref = self.session.nav.getCurrentlyPlayingServiceReference()
501                         
502                 # try to get event info
503                 epg = None
504                 try:
505                         service = self.session.nav.getCurrentService()
506                         info = service.info()
507                         ev = info.getEvent(0)
508                         epg = ev
509                 except:
510                         pass
511                 
512                 # fix me, description. 
513                 self.recording = self.session.nav.recordWithTimer(time.time(), time.time() + 3600, serviceref, epg, "instant record")
514                 self.recording.dontSave = True
515                 
516                 #self["BlinkingPoint"].setConnect(lambda: self.recording.isRunning())
517                 
518         def isInstantRecordRunning(self):
519                 if self.recording != None:
520                         if self.recording.isRunning():
521                                 return True
522                 return False
523
524         def recordQuestionCallback(self, answer):
525                 if answer == False:
526                         return
527                 
528                 if self.isInstantRecordRunning():
529                         self.stopCurrentRecording()
530                 else:
531                         self.startInstantRecording()
532
533         def instantRecord(self):
534                 try:
535                         stat = os.stat("/hdd/movies")
536                 except:
537                         self.session.open(MessageBox, "No HDD found!")
538                         return
539         
540                 if self.isInstantRecordRunning():
541                         self.session.openWithCallback(self.recordQuestionCallback, MessageBox, _("Do you want to stop the current\n(instant) recording?"))
542                 else:
543                         self.session.openWithCallback(self.recordQuestionCallback, MessageBox, _("Start recording?"))
544
545 from Screens.AudioSelection import AudioSelection
546
547 class InfoBarAudioSelection:
548         def __init__(self):
549                 self["AudioSelectionAction"] = HelpableActionMap(self, "InfobarAudioSelectionActions", 
550                         {
551                                 "audioSelection": (self.audioSelection, "Audio Options..."),
552                         })
553
554         def audioSelection(self):
555                 service = self.session.nav.getCurrentService()
556                 audio = service.audioTracks()
557                 n = audio.getNumberOfTracks()
558                 if n > 0:
559                         self.session.open(AudioSelection, audio)
560
561 from Screens.SubserviceSelection import SubserviceSelection
562
563 class InfoBarSubserviceSelection:
564         def __init__(self):
565                 self["SubserviceSelectionAction"] = HelpableActionMap(self, "InfobarSubserviceSelectionActions",
566                         {
567                                 "subserviceSelection": (self.subserviceSelection, "Subservice list..."),
568                         })
569
570         def subserviceSelection(self):
571                 service = self.session.nav.getCurrentService()
572                 subservices = service.subServices()
573                 n = subservices.getNumberOfSubservices()
574                 if n > 0:
575                         self.session.openWithCallback(self.subserviceSelected, SubserviceSelection, subservices)
576
577         def subserviceSelected(self, service):
578                 if not service is None:
579                         self.session.nav.playService(service)
580
581 class InfoBarAdditionalInfo:
582         def __init__(self):
583                 self["DolbyActive"] = PixmapConditional()
584                 # TODO: get the info from c++ somehow
585                 self["DolbyActive"].setConnect(lambda: False)
586                 
587                 self["CryptActive"] = PixmapConditional()
588                 # TODO: get the info from c++ somehow
589                 self["CryptActive"].setConnect(lambda: False)
590                 
591                 self["FormatActive"] = PixmapConditional()
592                 # TODO: get the info from c++ somehow
593                 self["FormatActive"].setConnect(lambda: False)
594                 
595                 self["ButtonRed"] = PixmapConditional(withTimer = False)
596                 self["ButtonRed"].setConnect(lambda: harddiskmanager.HDDCount() > 0)
597                 self.onShown.append(self["ButtonRed"].update)
598                 self["ButtonRedText"] = LabelConditional(text = _("Record"), withTimer = False)
599                 self["ButtonRedText"].setConnect(lambda: harddiskmanager.HDDCount() > 0)
600                 self.onShown.append(self["ButtonRedText"].update)
601                                 
602                 self["ButtonGreen"] = PixmapConditional()
603                 self["ButtonGreen"].setConnect(lambda: self.session.nav.getCurrentService().subServices().getNumberOfSubservices() > 0)
604                 self["ButtonGreenText"] = LabelConditional(text = _("Subservices"))
605                 self["ButtonGreenText"].setConnect(lambda: self.session.nav.getCurrentService().subServices().getNumberOfSubservices() > 0)
606
607                 self["ButtonYellow"] = PixmapConditional()
608                 self["ButtonYellow"].setConnect(lambda: False)
609
610                 self["ButtonBlue"] = PixmapConditional()
611                 self["ButtonBlue"].setConnect(lambda: False)
612
613 class InfoBarNotifications:
614         def __init__(self):
615                 self.onExecBegin.append(self.checkNotifications)
616                 Notifications.notificationAdded.append(self.checkNotificationsIfExecing)
617         
618         def checkNotificationsIfExecing(self):
619                 if self.execing:
620                         self.checkNotifications()
621
622         def checkNotifications(self):
623                 if len(Notifications.notifications):
624                         n = Notifications.notifications[0]
625                         Notifications.notifications = Notifications.notifications[1:]
626                         print "open",n
627                         cb = n[0]
628                         if cb is not None:
629                                 self.session.openWithCallback(cb, *n[1:])
630                         else:
631                                 self.session.open(*n[1:])