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
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
15 from ServiceReference import ServiceReference
16 from EpgSelection import EPGSelection
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
25 from Components.ServiceEventTracker import ServiceEventTracker
27 from Tools import Notifications
28 from Tools.Directories import *
30 #from enigma import eTimer, eDVBVolumecontrol, quitMainloop
36 from Components.config import config, currentConfigSelectionElement
39 from Menu import MainMenu, mdom
43 self.dishDialog = self.session.instantiateDialog(Dish)
44 self.onShown.append(self.dishDialog.instance.show)
46 class InfoBarShowHide:
47 """ InfoBar show/hide control, accepts toggleShow and hide actions, might start
55 self["ShowHideActions"] = ActionMap( ["InfobarShowHideActions"] ,
57 "toggleShow": self.toggleShow,
61 self.state = self.STATE_SHOWN
63 self.onExecBegin.append(self.show)
64 self.onClose.append(self.delHideTimer)
66 self.hideTimer = eTimer()
67 self.hideTimer.timeout.get().append(self.doTimerHide)
68 self.hideTimer.start(5000, True)
70 def delHideTimer(self):
77 self.state = self.STATE_SHOWN
78 self.hideTimer.start(5000, True)
80 def doTimerHide(self):
82 if self.state == self.STATE_SHOWN:
84 self.state = self.STATE_HIDDEN
87 if self.state == self.STATE_SHOWN:
89 #pls check animation support, sorry
92 self.state = self.STATE_HIDDEN
93 elif self.state == self.STATE_HIDDEN:
98 self.instance.m_animation.startMoveAnimation(ePoint(0, 600), ePoint(0, 380), 100)
99 self.state = self.STATE_SHOWN
102 self.instance.m_animation.startMoveAnimation(ePoint(0, 380), ePoint(0, 600), 100)
103 self.state = self.STATE_HIDDEN
105 class NumberZap(Screen):
112 self.close(int(self["number"].getText()))
114 def keyNumberGlobal(self, number):
115 self.Timer.start(3000, True) #reset timer
116 self.field = self.field + str(number)
117 self["number"].setText(self.field)
118 if len(self.field) >= 4:
121 def __init__(self, session, number):
122 Screen.__init__(self, session)
123 self.field = str(number)
125 self["channel"] = Label(_("Channel:"))
127 self["number"] = Label(self.field)
129 self["actions"] = NumberActionMap( [ "SetupActions" ],
133 "1": self.keyNumberGlobal,
134 "2": self.keyNumberGlobal,
135 "3": self.keyNumberGlobal,
136 "4": self.keyNumberGlobal,
137 "5": self.keyNumberGlobal,
138 "6": self.keyNumberGlobal,
139 "7": self.keyNumberGlobal,
140 "8": self.keyNumberGlobal,
141 "9": self.keyNumberGlobal,
142 "0": self.keyNumberGlobal
145 self.Timer = eTimer()
146 self.Timer.timeout.get().append(self.keyOK)
147 self.Timer.start(3000, True)
149 class InfoBarPowerKey:
150 """ PowerKey stuff - handles the powerkey press and powerkey release actions"""
153 self.powerKeyTimer = eTimer()
154 self.powerKeyTimer.timeout.get().append(self.powertimer)
155 self["PowerKeyActions"] = HelpableActionMap(self, "PowerKeyActions",
157 "powerdown": self.powerdown,
158 "powerup": self.powerup,
159 "discreteStandby": (self.standby, "Go standby"),
160 "discretePowerOff": (self.quit, "Go to deep standby"),
163 def powertimer(self):
164 print "PowerOff - Now!"
168 self.standbyblocked = 0
169 self.powerKeyTimer.start(3000, True)
172 self.powerKeyTimer.stop()
173 if self.standbyblocked == 0:
174 self.standbyblocked = 1
178 self.session.open(Standby, self)
184 class InfoBarNumberZap:
185 """ Handles an initial number for NumberZapping """
187 self["NumberActions"] = NumberActionMap( [ "NumberActions"],
189 "1": self.keyNumberGlobal,
190 "2": self.keyNumberGlobal,
191 "3": self.keyNumberGlobal,
192 "4": self.keyNumberGlobal,
193 "5": self.keyNumberGlobal,
194 "6": self.keyNumberGlobal,
195 "7": self.keyNumberGlobal,
196 "8": self.keyNumberGlobal,
197 "9": self.keyNumberGlobal,
198 "0": self.keyNumberGlobal,
201 def keyNumberGlobal(self, number):
202 # print "You pressed number " + str(number)
204 self.servicelist.recallPrevService()
208 self.session.openWithCallback(self.numberEntered, NumberZap, number)
210 def numberEntered(self, retval):
211 # print self.servicelist
213 self.zapToNumber(retval)
215 def searchNumberHelper(self, serviceHandler, num, bouquet):
216 servicelist = serviceHandler.list(bouquet)
217 if not servicelist is None:
219 serviceIterator = servicelist.getNext()
220 if not serviceIterator.valid(): #check end of list
222 if serviceIterator.flags: #assume normal dvb service have no flags set
225 if not num: #found service with searched number ?
226 return serviceIterator, 0
229 def zapToNumber(self, number):
230 bouquet = self.servicelist.bouquet_root
232 serviceHandler = eServiceCenter.getInstance()
233 if bouquet.toString().find('FROM BOUQUET "bouquets.') == -1: #FIXME HACK
234 service, number = self.searchNumberHelper(serviceHandler, number, bouquet)
236 bouquetlist = serviceHandler.list(bouquet)
237 if not bouquetlist is None:
239 bouquet = self.servicelist.appendDVBTypes(bouquetlist.getNext())
240 if not bouquet.valid(): #check end of list
242 if (bouquet.flags & eServiceReference.flagDirectory) != eServiceReference.flagDirectory:
244 service, number = self.searchNumberHelper(serviceHandler, number, bouquet)
245 if not service is None:
246 if self.servicelist.getRoot() != bouquet: #already in correct bouquet?
247 self.servicelist.clearPath()
248 if self.servicelist.bouquet_root != bouquet:
249 self.servicelist.enterPath(self.servicelist.bouquet_root)
250 self.servicelist.enterPath(bouquet)
251 self.servicelist.setCurrentSelection(service) #select the service in servicelist
252 self.servicelist.zap()
254 class InfoBarChannelSelection:
255 """ ChannelSelection - handles the channelSelection dialog and the initial
256 channelChange actions which open the channelSelection dialog """
259 self.servicelist = self.session.instantiateDialog(ChannelSelection)
261 self["ChannelSelectActions"] = HelpableActionMap(self, "InfobarChannelSelection",
263 "switchChannelUp": self.switchChannelUp,
264 "switchChannelDown": self.switchChannelDown,
265 "zapUp": (self.zapUp, _("next channel")),
266 "zapDown": (self.zapDown, _("previous channel")),
269 def switchChannelUp(self):
270 self.servicelist.moveUp()
271 self.session.execDialog(self.servicelist)
273 def switchChannelDown(self):
274 self.servicelist.moveDown()
275 self.session.execDialog(self.servicelist)
278 self.servicelist.moveUp()
279 self.servicelist.zap()
284 self.servicelist.moveDown()
285 self.servicelist.zap()
290 """ Handles a menu action, to open the (main) menu """
292 self["MenuActions"] = HelpableActionMap(self, "InfobarMenuActions",
294 "mainMenu": (self.mainMenu, "Enter main menu..."),
298 print "loading mainmenu XML..."
299 menu = mdom.childNodes[0]
300 assert menu.tagName == "menu", "root element in menu must be 'menu'!"
301 self.session.open(MainMenu, menu, menu.childNodes)
304 """ EPG - Opens an EPG list when the showEPGList action fires """
306 self["EPGActions"] = HelpableActionMap(self, "InfobarEPGActions",
308 "showEPGList": (self.showEPG, _("show EPG...")),
312 if currentConfigSelectionElement(config.usage.epgtoggle) == "yes":
313 self.openSingleServiceEPG()
317 def showEPGList(self):
318 bouquets = self.servicelist.getBouquetList()
323 if cnt > 1: # show bouquet list
324 self.session.open(BouquetSelector, bouquets, self.openBouquetEPG)
325 elif cnt == 1: # add to only one existing bouquet
326 self.openBouquetEPG(bouquets[0][1])
327 else: #no bouquets so we open single epg
328 self.openSingleEPGSelector(self.session.nav.getCurrentlyPlayingServiceReference())
330 def bouquetEPGCallback(self, info):
332 self.openSingleServiceEPG()
334 def singleEPGCallback(self, info):
338 def openEventView(self):
341 service = self.session.nav.getCurrentService()
342 info = service.info()
345 self.epglist.append(ptr)
348 self.epglist.append(ptr)
349 if len(self.epglist) > 0:
350 self.session.open(EventView, self.epglist[0], ServiceReference(ref), self.eventViewCallback)
354 def openSingleServiceEPG(self):
355 ref=self.session.nav.getCurrentlyPlayingServiceReference()
356 ptr=eEPGCache.getInstance()
357 if ptr.startTimeQuery(ref) != -1:
358 self.session.openWithCallback(self.singleEPGCallback, EPGSelection, ref)
359 else: # try to show now/next
360 print 'no epg for service', ref.toString()
362 def openBouquetEPG(self, bouquet):
363 ptr=eEPGCache.getInstance()
365 servicelist = eServiceCenter.getInstance().list(bouquet)
366 if not servicelist is None:
368 service = servicelist.getNext()
369 if not service.valid(): #check if end of list
371 if service.flags: #ignore non playable services
373 services.append(ServiceReference(service))
375 self.session.openWithCallback(self.bouquetEPGCallback, EPGSelection, services)
377 def openSingleEPGSelector(self, ref):
378 ptr=eEPGCache.getInstance()
379 if ptr.startTimeQuery(ref) != -1:
380 self.session.open(EPGSelection, ref)
381 else: # try to show now/next
382 print 'no epg for service', ref.toString()
385 service = self.session.nav.getCurrentService()
386 info = service.info()
389 self.epglist.append(ptr)
392 self.epglist.append(ptr)
393 if len(self.epglist) > 0:
394 self.session.open(EventView, self.epglist[0], ServiceReference(ref), self.eventViewCallback)
398 def eventViewCallback(self, setEvent, setService, val): #used for now/next displaying
399 if len(self.epglist) > 1:
400 tmp = self.epglist[0]
401 self.epglist[0]=self.epglist[1]
403 setEvent(self.epglist[0])
408 """provides a snr/agc/ber display"""
410 self["snr"] = Label()
411 self["agc"] = Label()
412 self["ber"] = Label()
413 self["snr_percent"] = Label()
414 self["agc_percent"] = Label()
415 self["ber_count"] = Label()
416 self["snr_progress"] = ProgressBar()
417 self["agc_progress"] = ProgressBar()
418 self["ber_progress"] = ProgressBar()
419 self.timer = eTimer()
420 self.timer.timeout.get().append(self.updateTunerInfo)
421 self.timer.start(1000)
427 return (long)(log(val)/log(2))
430 def updateTunerInfo(self):
431 if self.instance.isVisible():
432 service = self.session.nav.getCurrentService()
436 if service is not None:
437 feinfo = service.frontendStatusInfo()
438 if feinfo is not None:
439 ber=feinfo.getFrontendInfo(iFrontendStatusInformation.bitErrorRate)
440 snr=feinfo.getFrontendInfo(iFrontendStatusInformation.signalPower)*100/65536
441 agc=feinfo.getFrontendInfo(iFrontendStatusInformation.signalQuality)*100/65536
442 self["snr_percent"].setText("%d%%"%(snr))
443 self["agc_percent"].setText("%d%%"%(agc))
444 self["ber_count"].setText("%d"%(ber))
445 self["snr_progress"].setValue(snr)
446 self["agc_progress"].setValue(agc)
447 self["ber_progress"].setValue(self.calc(ber))
450 """provides a current/next event info display"""
452 self["Event_Now_StartTime"] = EventInfo(self.session.nav, EventInfo.Now_StartTime)
453 self["Event_Next_StartTime"] = EventInfo(self.session.nav, EventInfo.Next_StartTime)
455 self["Event_Now"] = EventInfo(self.session.nav, EventInfo.Now)
456 self["Event_Next"] = EventInfo(self.session.nav, EventInfo.Next)
458 self["Event_Now_Duration"] = EventInfo(self.session.nav, EventInfo.Now_Duration)
459 self["Event_Next_Duration"] = EventInfo(self.session.nav, EventInfo.Next_Duration)
461 self["Now_ProgressBar"] = EventInfoProgress(self.session.nav, EventInfo.Now)
463 class InfoBarServiceName:
465 self["ServiceName"] = ServiceName(self.session.nav)
468 """handles actions like seeking, pause"""
470 # ispause, isff, issm, skip
471 SEEK_STATE_PLAY = (0, 0, 0, 0)
472 SEEK_STATE_PAUSE = (1, 0, 0, 0)
473 SEEK_STATE_FF_2X = (0, 2, 0, 0)
474 SEEK_STATE_FF_4X = (0, 4, 0, 0)
475 SEEK_STATE_FF_8X = (0, 8, 0, 0)
476 SEEK_STATE_FF_32X = (0, 4, 0, 32)
477 SEEK_STATE_FF_64X = (0, 4, 0, 64)
478 SEEK_STATE_FF_128X = (0, 4, 0, 128)
480 SEEK_STATE_BACK_4X = (0, 0, 0, -4)
481 SEEK_STATE_BACK_32X = (0, 0, 0, -32)
482 SEEK_STATE_BACK_64X = (0, 0, 0, -64)
483 SEEK_STATE_BACK_128X = (0, 0, 0, -128)
485 SEEK_STATE_SM_HALF = (0, 0, 2, 0)
486 SEEK_STATE_SM_QUARTER = (0, 0, 4, 0)
487 SEEK_STATE_SM_EIGHTH = (0, 0, 8, 0)
490 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
492 pNavigation.evSeekableStatusChanged: self.__seekableStatusChanged,
493 pNavigation.evNewService: self.__serviceStarted
495 self["SeekActions"] = HelpableActionMap(self, "InfobarSeekActions",
497 "pauseService": (self.pauseService, "pause"),
498 "unPauseService": (self.unPauseService, "continue"),
500 "seekFwd": (self.seekFwd, "skip forward"),
501 "seekFwdUp": (self.seekFwdUp, "skip forward"),
502 "seekBack": (self.seekBack, "skip backward"),
503 "seekBackUp": (self.seekBackUp, "skip backward"),
505 # give them a little more priority to win over color buttons
507 self.seekstate = self.SEEK_STATE_PLAY
508 self.seekTimer = eTimer()
509 self.seekTimer.timeout.get().append(self.seekTimerFired)
510 self.skipinterval = 500 # 500ms skip interval
511 self.onClose.append(self.delSeekTimer)
513 self.fwdtimer = False
514 self.fwdKeyTimer = eTimer()
515 self.fwdKeyTimer.timeout.get().append(self.fwdTimerFire)
517 self.rwdtimer = False
518 self.rwdKeyTimer = eTimer()
519 self.rwdKeyTimer.timeout.get().append(self.rwdTimerFire)
527 def delSeekTimer(self):
532 def seekTimerFired(self):
533 self.seekbase += self.skipmode * self.skipinterval
535 # check if we bounced against the beginning of the file
536 if self.seekbase < 0:
538 self.setSeekState(self.SEEK_STATE_PLAY)
540 self.doSeek(self.seekbase)
542 def isSeekable(self):
543 service = self.session.nav.getCurrentService()
546 if service.seek() is None:
551 def __seekableStatusChanged(self):
552 print "seekable status changed!"
553 if not self.isSeekable():
554 self["SeekActions"].setEnabled(False)
555 print "not seekable, return to play"
556 self.setSeekState(self.SEEK_STATE_PLAY)
558 self["SeekActions"].setEnabled(True)
561 def __serviceStarted(self):
562 self.seekstate = self.SEEK_STATE_PLAY
564 def setSeekState(self, state):
565 service = self.session.nav.getCurrentService()
566 self.seekTimer.stop()
571 if service.seek() is None:
572 if state not in [self.SEEK_STATE_PLAY, self.SEEK_STATE_PAUSE]:
573 state = self.SEEK_STATE_PLAY
575 pauseable = service.pause()
577 if pauseable is None:
578 print "not pauseable."
579 state = self.SEEK_STATE_PLAY
581 oldstate = self.seekstate
582 self.seekstate = state
585 if oldstate[i] != self.seekstate[i]:
586 (self.session.nav.pause, pauseable.setFastForward, pauseable.setSlowMotion, self.setSkipMode)[i](self.seekstate[i])
590 def setSkipMode(self, skipmode):
591 print "setskipmode", skipmode
592 self.skipmode = skipmode
594 self.seekTimer.stop()
596 self.seekTimer.start(500)
598 service = self.session.nav.getCurrentService()
602 seekable = service.seek()
607 seekable.setTrickmode(1)
609 seekable.setTrickmode(0)
611 self.seekbase = seekable.getPlayPosition()[1] / 90
613 def pauseService(self):
614 if self.seekstate == self.SEEK_STATE_PAUSE:
615 print "pause, but in fact unpause"
616 self.unPauseService()
618 if self.seekstate == self.SEEK_STATE_PLAY:
619 print "yes, playing."
621 print "no", self.seekstate
623 self.setSeekState(self.SEEK_STATE_PAUSE);
625 def unPauseService(self):
627 self.setSeekState(self.SEEK_STATE_PLAY);
629 def doSeek(self, seektime):
630 print "doseek", seektime
631 service = self.session.nav.getCurrentService()
635 seekable = service.seek()
638 seekable.seekTo(90 * seektime)
641 print "start fwd timer"
643 self.fwdKeyTimer.start(500)
646 print "start rewind timer"
648 self.rwdKeyTimer.start(500)
653 self.fwdKeyTimer.stop()
654 self.fwdtimer = False
656 self.SEEK_STATE_PLAY: self.SEEK_STATE_FF_2X,
657 self.SEEK_STATE_PAUSE: self.SEEK_STATE_SM_EIGHTH,
658 self.SEEK_STATE_FF_2X: self.SEEK_STATE_FF_4X,
659 self.SEEK_STATE_FF_4X: self.SEEK_STATE_FF_8X,
660 self.SEEK_STATE_FF_8X: self.SEEK_STATE_FF_32X,
661 self.SEEK_STATE_FF_32X: self.SEEK_STATE_FF_64X,
662 self.SEEK_STATE_FF_64X: self.SEEK_STATE_FF_128X,
663 self.SEEK_STATE_FF_128X: self.SEEK_STATE_FF_128X,
664 self.SEEK_STATE_BACK_4X: self.SEEK_STATE_PLAY,
665 self.SEEK_STATE_BACK_32X: self.SEEK_STATE_BACK_4X,
666 self.SEEK_STATE_BACK_64X: self.SEEK_STATE_BACK_32X,
667 self.SEEK_STATE_BACK_128X: self.SEEK_STATE_BACK_64X,
668 self.SEEK_STATE_SM_HALF: self.SEEK_STATE_SM_HALF,
669 self.SEEK_STATE_SM_QUARTER: self.SEEK_STATE_SM_HALF,
670 self.SEEK_STATE_SM_EIGHTH: self.SEEK_STATE_SM_QUARTER
672 self.setSeekState(lookup[self.seekstate]);
674 def seekBackUp(self):
677 self.rwdKeyTimer.stop()
678 self.rwdtimer = False
681 self.SEEK_STATE_PLAY: self.SEEK_STATE_BACK_4X,
682 self.SEEK_STATE_PAUSE: self.SEEK_STATE_PAUSE,
683 self.SEEK_STATE_FF_2X: self.SEEK_STATE_PLAY,
684 self.SEEK_STATE_FF_4X: self.SEEK_STATE_FF_2X,
685 self.SEEK_STATE_FF_8X: self.SEEK_STATE_FF_4X,
686 self.SEEK_STATE_FF_32X: self.SEEK_STATE_FF_8X,
687 self.SEEK_STATE_FF_64X: self.SEEK_STATE_FF_32X,
688 self.SEEK_STATE_FF_128X: self.SEEK_STATE_FF_64X,
689 self.SEEK_STATE_BACK_4X: self.SEEK_STATE_BACK_32X,
690 self.SEEK_STATE_BACK_32X: self.SEEK_STATE_BACK_64X,
691 self.SEEK_STATE_BACK_64X: self.SEEK_STATE_BACK_128X,
692 self.SEEK_STATE_BACK_128X: self.SEEK_STATE_BACK_128X,
693 self.SEEK_STATE_SM_HALF: self.SEEK_STATE_SM_QUARTER,
694 self.SEEK_STATE_SM_QUARTER: self.SEEK_STATE_SM_EIGHTH,
695 self.SEEK_STATE_SM_EIGHTH: self.SEEK_STATE_PAUSE
697 self.setSeekState(lookup[self.seekstate]);
699 def fwdTimerFire(self):
700 print "Display seek fwd"
701 self.fwdKeyTimer.stop()
702 self.fwdtimer = False
703 self.session.openWithCallback(self.fwdSeekTo, MinuteInput)
705 def fwdSeekTo(self, minutes):
706 print "Seek", minutes, "minutes forward"
708 service = self.session.nav.getCurrentService()
711 seekable = service.seek()
714 seekable.seekRelative(1, minutes * 60 * 90000)
716 def rwdTimerFire(self):
718 self.rwdKeyTimer.stop()
719 self.rwdtimer = False
720 self.session.openWithCallback(self.rwdSeekTo, MinuteInput)
722 def rwdSeekTo(self, minutes):
724 self.fwdSeekTo(0 - minutes)
726 class InfoBarShowMovies:
728 # i don't really like this class.
729 # it calls a not further specified "movie list" on up/down/movieList,
730 # so this is not more than an action map
732 self["MovieListActions"] = HelpableActionMap(self, "InfobarMovieListActions",
734 "movieList": (self.showMovies, "movie list"),
735 "up": (self.showMovies, "movie list"),
736 "down": (self.showMovies, "movie list")
739 # InfoBarTimeshift requires InfoBarSeek, instantiated BEFORE!
743 # Timeshift works the following way:
744 # demux0 demux1 "TimeshiftActions" "TimeshiftActivateActions" "SeekActions"
745 # - normal playback TUNER unused PLAY enable disable disable
746 # - user presses "yellow" button. TUNER record PAUSE enable disable enable
747 # - user presess pause again FILE record PLAY enable disable enable
748 # - user fast forwards FILE record FF enable disable enable
749 # - end of timeshift buffer reached TUNER record PLAY enable enable disable
750 # - user backwards FILE record BACK # !! enable disable enable
754 # - when a service is playing, pressing the "timeshiftStart" button ("yellow") enables recording ("enables timeshift"),
755 # freezes the picture (to indicate timeshift), sets timeshiftMode ("activates timeshift")
756 # now, the service becomes seekable, so "SeekActions" are enabled, "TimeshiftEnableActions" are disabled.
757 # - the user can now PVR around
758 # - if it hits the end, the service goes into live mode ("deactivates timeshift", it's of course still "enabled")
759 # the service looses it's "seekable" state. It can still be paused, but just to activate timeshift right
761 # the seek actions will be disabled, but the timeshiftActivateActions will be enabled
762 # - if the user rewinds, or press pause, timeshift will be activated again
764 # note that a timeshift can be enabled ("recording") and
765 # activated (currently time-shifting).
767 class InfoBarTimeshift:
769 self["TimeshiftActions"] = HelpableActionMap(self, "InfobarTimeshiftActions",
771 "timeshiftStart": (self.startTimeshift, "start timeshift"), # the "yellow key"
772 "timeshiftStop": (self.stopTimeshift, "stop timeshift") # currently undefined :), probably 'TV'
774 self["TimeshiftActivateActions"] = ActionMap(["InfobarTimeshiftActivateActions"],
776 "timeshiftActivateEnd": self.activateTimeshiftEnd, # something like "pause key"
777 "timeshiftActivateEndAndPause": self.activateTimeshiftEndAndPause # something like "backward key"
780 self.timeshift_enabled = 0
781 self.timeshift_state = 0
782 self.ts_pause_timer = eTimer()
783 self.ts_pause_timer.timeout.get().append(self.pauseService)
785 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
787 pNavigation.evSeekableStatusChanged: self.__seekableStatusChanged
790 def getTimeshift(self):
791 service = self.session.nav.getCurrentService()
792 return service.timeshift()
794 def startTimeshift(self):
795 # TODO: check for harddisk! (or do this in the interface? would make
796 # more sense... for example radio could be timeshifted in memory,
797 # and the decision can't be made here)
798 print "enable timeshift"
799 ts = self.getTimeshift()
801 self.session.open(MessageBox, _("Timeshift not possible!"), MessageBox.TYPE_ERROR)
802 print "no ts interface"
805 if self.timeshift_enabled:
806 print "hu, timeshift already enabled?"
808 if not ts.startTimeshift():
809 self.timeshift_enabled = 1
812 self.setSeekState(self.SEEK_STATE_PAUSE)
814 # enable the "TimeshiftEnableActions", which will override
815 # the startTimeshift actions
816 self.__seekableStatusChanged()
818 print "timeshift failed"
821 def stopTimeshift(self):
822 print "disable timeshift"
823 ts = self.getTimeshift()
827 self.timeshift_enabled = 0
830 self.__seekableStatusChanged()
832 # activates timeshift, and seeks to (almost) the end
833 def activateTimeshiftEnd(self):
834 ts = self.getTimeshift()
839 if ts.isTimeshiftActive():
840 print "!! activate timeshift called - but shouldn't this be a normal pause?"
843 self.setSeekState(self.SEEK_STATE_PLAY)
844 ts.activateTimeshift()
846 # same as activateTimeshiftEnd, but pauses afterwards.
847 def activateTimeshiftEndAndPause(self):
848 state = self.seekstate
849 self.activateTimeshiftEnd()
851 # well, this is "andPause", but it could be pressed from pause,
852 # when pausing on the (fake-)"live" picture, so an un-pause
855 print "now, pauseService"
856 if state == self.SEEK_STATE_PLAY:
857 print "is PLAYING, start pause timer"
858 self.ts_pause_timer.start(200, 1)
861 self.unPauseService()
863 def __seekableStatusChanged(self):
866 print "self.isSeekable", self.isSeekable()
867 print "self.timeshift_enabled", self.timeshift_enabled
869 # when this service is not seekable, but timeshift
870 # is enabled, this means we can activate
872 if not self.isSeekable() and self.timeshift_enabled:
875 print "timeshift activate:", enabled
876 self["TimeshiftActivateActions"].setEnabled(enabled)
878 from RecordTimer import parseEvent
880 class InfoBarInstantRecord:
881 """Instant Record - handles the instantRecord action in order to
882 start/stop instant records"""
884 self["InstantRecordActions"] = HelpableActionMap(self, "InfobarInstantRecord",
886 "instantRecord": (self.instantRecord, "Instant Record..."),
888 self.recording = None
890 self["BlinkingPoint"] = BlinkingPixmapConditional()
891 self.onShown.append(self["BlinkingPoint"].hideWidget)
892 self["BlinkingPoint"].setConnect(self.session.nav.RecordTimer.isRecording)
894 def stopCurrentRecording(self):
895 self.session.nav.RecordTimer.removeEntry(self.recording)
896 self.recording = None
898 def startInstantRecording(self):
899 serviceref = self.session.nav.getCurrentlyPlayingServiceReference()
901 # try to get event info
904 service = self.session.nav.getCurrentService()
905 info = service.info()
906 ev = info.getEvent(0)
911 if event is not None:
912 data = parseEvent(event)
914 if begin < time.time():
923 data = (begin, end, data[2], data[3], data[4])
925 data = (time.time(), time.time() + 3600 * 10, "instant record", "", None)
927 # fix me, description.
928 self.recording = self.session.nav.recordWithTimer(serviceref, *data)
929 self.recording.dontSave = True
931 #self["BlinkingPoint"].setConnect(lambda: self.recording.isRunning())
933 def isInstantRecordRunning(self):
934 if self.recording != None:
935 if self.recording.isRunning():
939 def recordQuestionCallback(self, answer):
943 if self.isInstantRecordRunning():
944 self.stopCurrentRecording()
946 self.startInstantRecording()
948 def instantRecord(self):
950 stat = os.stat(resolveFilename(SCOPE_HDD))
952 self.session.open(MessageBox, _("No HDD found or HDD not initialized!"), MessageBox.TYPE_ERROR)
955 if self.isInstantRecordRunning():
956 self.session.openWithCallback(self.recordQuestionCallback, MessageBox, _("Do you want to stop the current\n(instant) recording?"))
958 self.session.openWithCallback(self.recordQuestionCallback, MessageBox, _("Start recording?"))
960 from Screens.AudioSelection import AudioSelection
962 class InfoBarAudioSelection:
964 self["AudioSelectionAction"] = HelpableActionMap(self, "InfobarAudioSelectionActions",
966 "audioSelection": (self.audioSelection, "Audio Options..."),
969 def audioSelection(self):
970 service = self.session.nav.getCurrentService()
971 audio = service.audioTracks()
972 n = audio.getNumberOfTracks()
974 self.session.open(AudioSelection, audio)
976 from Screens.SubserviceSelection import SubserviceSelection
978 class InfoBarSubserviceSelection:
980 self["SubserviceSelectionAction"] = HelpableActionMap(self, "InfobarSubserviceSelectionActions",
982 "subserviceSelection": (self.subserviceSelection, "Subservice list..."),
985 def subserviceSelection(self):
986 service = self.session.nav.getCurrentService()
987 subservices = service.subServices()
988 n = subservices.getNumberOfSubservices()
990 self.session.openWithCallback(self.subserviceSelected, SubserviceSelection, subservices)
992 def subserviceSelected(self, service):
993 if not service is None:
994 self.session.nav.playService(service)
996 class InfoBarAdditionalInfo:
998 self["DolbyActive"] = Pixmap()
999 self["CryptActive"] = Pixmap()
1000 self["FormatActive"] = Pixmap()
1002 self["ButtonRed"] = PixmapConditional(withTimer = False)
1003 self["ButtonRed"].setConnect(lambda: harddiskmanager.HDDCount() > 0)
1004 self.onShown.append(self["ButtonRed"].update)
1005 self["ButtonRedText"] = LabelConditional(text = _("Record"), withTimer = False)
1006 self["ButtonRedText"].setConnect(lambda: harddiskmanager.HDDCount() > 0)
1007 self.onShown.append(self["ButtonRedText"].update)
1009 self["ButtonGreen"] = Pixmap()
1010 self["ButtonGreenText"] = Label(_("Subservices"))
1012 self["ButtonYellow"] = PixmapConditional(withTimer = False)
1013 self["ButtonYellow"].setConnect(lambda: False)
1015 self["ButtonBlue"] = PixmapConditional(withTimer = False)
1016 self["ButtonBlue"].setConnect(lambda: False)
1018 self.session.nav.event.append(self.gotServiceEvent) # we like to get service events
1020 def hideSubServiceIndication(self):
1021 self["ButtonGreen"].hideWidget()
1022 self["ButtonGreenText"].hide()
1024 def showSubServiceIndication(self):
1025 self["ButtonGreen"].showWidget()
1026 self["ButtonGreenText"].show()
1028 def checkFormat(self, service):
1029 info = service.info()
1030 if info is not None:
1031 aspect = info.getInfo(iServiceInformation.sAspect)
1032 if aspect in [ 3, 4, 7, 8, 0xB, 0xC, 0xF, 0x10 ]:
1033 self["FormatActive"].showWidget()
1035 self["FormatActive"].hideWidget()
1037 def checkSubservices(self, service):
1038 if service.subServices().getNumberOfSubservices() > 0:
1039 self.showSubServiceIndication()
1041 self.hideSubServiceIndication()
1043 def checkDolby(self, service):
1046 audio = service.audioTracks()
1047 if audio is not None:
1048 n = audio.getNumberOfTracks()
1050 i = audio.getTrackInfo(x)
1051 description = i.getDescription();
1052 if description.find("AC3") != -1 or description.find("DTS") != -1:
1056 self["DolbyActive"].showWidget()
1058 self["DolbyActive"].hideWidget()
1060 def checkCrypted(self, service):
1061 info = service.info()
1062 if info is not None:
1063 if info.getInfo(iServiceInformation.sIsCrypted) > 0:
1064 self["CryptActive"].showWidget()
1066 self["CryptActive"].hideWidget()
1068 def gotServiceEvent(self, ev):
1069 service = self.session.nav.getCurrentService()
1070 if ev == pNavigation.evUpdatedEventInfo:
1071 self.checkSubservices(service)
1072 self.checkFormat(service)
1073 elif ev == pNavigation.evUpdatedInfo:
1074 self.checkCrypted(service)
1075 self.checkDolby(service)
1076 elif ev == pNavigation.evStopService:
1077 self.hideSubServiceIndication()
1078 self["CryptActive"].hideWidget()
1079 self["DolbyActive"].hideWidget()
1080 self["FormatActive"].hideWidget()
1082 class InfoBarNotifications:
1084 self.onExecBegin.append(self.checkNotifications)
1085 Notifications.notificationAdded.append(self.checkNotificationsIfExecing)
1087 def checkNotificationsIfExecing(self):
1089 self.checkNotifications()
1091 def checkNotifications(self):
1092 if len(Notifications.notifications):
1093 n = Notifications.notifications[0]
1094 Notifications.notifications = Notifications.notifications[1:]
1098 self.session.openWithCallback(cb, *n[1:])
1100 self.session.open(*n[1:])
1102 class InfoBarServiceNotifications:
1104 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1106 pNavigation.evEnd: self.serviceHasEnded
1109 def serviceHasEnded(self):
1110 print "service end!"
1113 self.setSeekState(self.SEEK_STATE_PLAY)