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