fdf6becee6a4d73d3503a712da3e88920d52d511
[openblackhole/openblackhole-enigma2.git] / lib / python / Screens / InfoBar.py
1 from Tools.Profile import profile
2 from Tools.BoundFunction import boundFunction
3 from enigma import eServiceReference
4
5 # workaround for required config entry dependencies.
6 import Screens.MovieSelection
7
8 from Screen import Screen
9 from Screens.MessageBox import MessageBox
10
11 profile("LOAD:enigma")
12 import enigma
13
14 profile("LOAD:InfoBarGenerics")
15 from Screens.InfoBarGenerics import InfoBarShowHide, \
16         InfoBarNumberZap, InfoBarChannelSelection, InfoBarMenu, InfoBarRdsDecoder, \
17         InfoBarEPG, InfoBarSeek, InfoBarInstantRecord, InfoBarRedButton, InfoBarTimerButton, InfoBarVmodeButton, \
18         InfoBarAudioSelection, InfoBarAdditionalInfo, InfoBarNotifications, InfoBarDish, InfoBarUnhandledKey, \
19         InfoBarSubserviceSelection, InfoBarShowMovies, InfoBarTimeshift,  \
20         InfoBarServiceNotifications, InfoBarPVRState, InfoBarCueSheetSupport, InfoBarBuffer, \
21         InfoBarSummarySupport, InfoBarMoviePlayerSummarySupport, InfoBarTimeshiftState, InfoBarTeletextPlugin, InfoBarExtensions, \
22         InfoBarSubtitleSupport, InfoBarPiP, InfoBarPlugins, InfoBarServiceErrorPopupSupport, InfoBarJobman, InfoBarPowersaver, \
23         InfoBarHDMI, setResumePoint, delResumePoint
24 from Screens.Hotkey import InfoBarHotkey
25
26 profile("LOAD:InitBar_Components")
27 from Components.ActionMap import HelpableActionMap
28 from Components.config import config
29 from Components.ServiceEventTracker import ServiceEventTracker, InfoBarBase
30
31 profile("LOAD:HelpableScreen")
32 from Screens.HelpMenu import HelpableScreen
33
34 class InfoBar(InfoBarBase, InfoBarShowHide,
35         InfoBarNumberZap, InfoBarChannelSelection, InfoBarMenu, InfoBarEPG, InfoBarRdsDecoder,
36         InfoBarInstantRecord, InfoBarAudioSelection, InfoBarRedButton, InfoBarTimerButton, InfoBarVmodeButton,
37         HelpableScreen, InfoBarAdditionalInfo, InfoBarNotifications, InfoBarDish, InfoBarUnhandledKey,
38         InfoBarSubserviceSelection, InfoBarTimeshift, InfoBarSeek, InfoBarCueSheetSupport, InfoBarBuffer,
39         InfoBarSummarySupport, InfoBarTimeshiftState, InfoBarTeletextPlugin, InfoBarExtensions,
40         InfoBarPiP, InfoBarPlugins, InfoBarSubtitleSupport, InfoBarServiceErrorPopupSupport, InfoBarJobman, InfoBarPowersaver,
41         InfoBarHDMI, InfoBarHotkey, Screen):
42
43         ALLOW_SUSPEND = True
44         instance = None
45
46         def __init__(self, session):
47                 Screen.__init__(self, session)
48                 self["actions"] = HelpableActionMap(self, "InfobarActions",
49                         {
50                                 "showMovies": (self.showMovies, _("Play recorded movies...")),
51                                 "showRadio": (self.showRadio, _("Show the radio player...")),
52                                 "showTv": (self.showTv, _("Show the tv player...")),
53                         }, prio=2)
54
55                 self.allowPiP = True
56
57                 for x in HelpableScreen, \
58                                 InfoBarBase, InfoBarShowHide, \
59                                 InfoBarNumberZap, InfoBarChannelSelection, InfoBarMenu, InfoBarEPG, InfoBarRdsDecoder, \
60                                 InfoBarInstantRecord, InfoBarAudioSelection, InfoBarRedButton, InfoBarTimerButton, InfoBarUnhandledKey, InfoBarVmodeButton,\
61                                 InfoBarAdditionalInfo, InfoBarNotifications, InfoBarDish, InfoBarSubserviceSelection, InfoBarBuffer, \
62                                 InfoBarTimeshift, InfoBarSeek, InfoBarCueSheetSupport, InfoBarSummarySupport, InfoBarTimeshiftState, \
63                                 InfoBarTeletextPlugin, InfoBarExtensions, InfoBarPiP, InfoBarSubtitleSupport, InfoBarJobman, InfoBarPowersaver, \
64                                 InfoBarPlugins, InfoBarServiceErrorPopupSupport, InfoBarHotkey:
65                         x.__init__(self)
66
67                 self.helpList.append((self["actions"], "InfobarActions", [("showMovies", _("Watch recordings..."))]))
68                 self.helpList.append((self["actions"], "InfobarActions", [("showRadio", _("Listen to the radio..."))]))
69
70                 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
71                         {
72                                 enigma.iPlayableService.evUpdatedEventInfo: self.__eventInfoChanged
73                         })
74
75                 self.current_begin_time=0
76                 assert InfoBar.instance is None, "class InfoBar is a singleton class and just one instance of this class is allowed!"
77                 InfoBar.instance = self
78
79         def __onClose(self):
80                 InfoBar.instance = None
81
82         def __eventInfoChanged(self):
83                 if self.execing:
84                         service = self.session.nav.getCurrentService()
85                         old_begin_time = self.current_begin_time
86                         info = service and service.info()
87                         ptr = info and info.getEvent(0)
88                         self.current_begin_time = ptr and ptr.getBeginTime() or 0
89                         if config.usage.show_infobar_on_event_change.value:
90                                 if old_begin_time and old_begin_time != self.current_begin_time:
91                                         self.doShow()
92
93         def __checkServiceStarted(self):
94                 self.__serviceStarted(True)
95                 self.onExecBegin.remove(self.__checkServiceStarted)
96
97         def serviceStarted(self):  #override from InfoBarShowHide
98                 new = self.servicelist.newServicePlayed()
99                 if self.execing:
100                         InfoBarShowHide.serviceStarted(self)
101                         self.current_begin_time=0
102                 elif not self.__checkServiceStarted in self.onShown and new:
103                         self.onShown.append(self.__checkServiceStarted)
104
105         def __checkServiceStarted(self):
106                 self.serviceStarted()
107                 self.onShown.remove(self.__checkServiceStarted)
108
109         def showTv(self):
110                 self.showTvChannelList(True)
111
112         def showRadio(self):
113                 if config.usage.e1like_radio_mode.value:
114                         self.showRadioChannelList(True)
115                 else:
116                         self.rds_display.hide() # in InfoBarRdsDecoder
117                         from Screens.ChannelSelection import ChannelSelectionRadio
118                         self.session.openWithCallback(self.ChannelSelectionRadioClosed, ChannelSelectionRadio, self)
119
120         def ChannelSelectionRadioClosed(self, *arg):
121                 self.rds_display.show()  # in InfoBarRdsDecoder
122                 self.servicelist.correctChannelNumber()
123
124         def showMovies(self, defaultRef=None):
125                 self.lastservice = self.session.nav.getCurrentlyPlayingServiceOrGroup()
126                 self.session.openWithCallback(self.movieSelected, Screens.MovieSelection.MovieSelection, defaultRef or eServiceReference(config.usage.last_movie_played.value), timeshiftEnabled = self.timeshiftEnabled())
127
128         def movieSelected(self, service):
129                 ref = self.lastservice
130                 del self.lastservice
131                 if service is None:
132                         if ref and not self.session.nav.getCurrentlyPlayingServiceOrGroup():
133                                 self.session.nav.playService(ref)
134                 else:
135                         from Components.ParentalControl import parentalControl
136                         if parentalControl.isServicePlayable(service, self.openMoviePlayer):
137                                 self.openMoviePlayer(service)
138
139         def openMoviePlayer(self, ref):
140                 self.session.open(MoviePlayer, ref, slist=self.servicelist, lastservice=self.session.nav.getCurrentlyPlayingServiceOrGroup(), infobar=self)
141
142 class MoviePlayer(InfoBarBase, InfoBarShowHide, InfoBarMenu, InfoBarSeek, InfoBarShowMovies, InfoBarInstantRecord,
143                 InfoBarAudioSelection, HelpableScreen, InfoBarNotifications, InfoBarServiceNotifications, InfoBarPVRState,
144                 InfoBarCueSheetSupport, InfoBarMoviePlayerSummarySupport, InfoBarSubtitleSupport, Screen, InfoBarTeletextPlugin,
145                 InfoBarServiceErrorPopupSupport, InfoBarExtensions, InfoBarPlugins, InfoBarPiP, InfoBarHDMI, InfoBarHotkey):
146
147         ENABLE_RESUME_SUPPORT = True
148         ALLOW_SUSPEND = True
149
150         def __init__(self, session, service, slist=None, lastservice=None, infobar=None):
151                 Screen.__init__(self, session)
152
153                 self["actions"] = HelpableActionMap(self, "MoviePlayerActions",
154                         {
155                                 "leavePlayer": (self.leavePlayer, _("leave movie player...")),
156                                 "leavePlayerOnExit": (self.leavePlayerOnExit, _("leave movie player...")),
157                                 "channelUp": (self.channelUp, _("when PiPzap enabled zap channel up...")),
158                                 "channelDown": (self.channelDown, _("when PiPzap enabled zap channel down...")),
159                         })
160
161                 self["DirectionActions"] = HelpableActionMap(self, "DirectionActions",
162                         {
163                                 "left": self.left,
164                                 "right": self.right
165                         }, prio = -2)
166
167                 self.allowPiP = True
168
169                 for x in HelpableScreen, InfoBarShowHide, InfoBarMenu, \
170                                 InfoBarBase, InfoBarSeek, InfoBarShowMovies, InfoBarInstantRecord, \
171                                 InfoBarAudioSelection, InfoBarNotifications, \
172                                 InfoBarServiceNotifications, InfoBarPVRState, InfoBarCueSheetSupport, \
173                                 InfoBarMoviePlayerSummarySupport, InfoBarSubtitleSupport, \
174                                 InfoBarTeletextPlugin, InfoBarServiceErrorPopupSupport, InfoBarExtensions, \
175                                 InfoBarPlugins, InfoBarPiP, InfoBarHotkey:
176                         x.__init__(self)
177
178                 self.servicelist = slist
179                 self.infobar = infobar
180                 self.lastservice = lastservice or session.nav.getCurrentlyPlayingServiceOrGroup()
181                 session.nav.playService(service)
182                 self.cur_service = service
183                 self.returning = False
184                 self.onClose.append(self.__onClose)
185                 config.misc.standbyCounter.addNotifier(self.standbyCountChanged, initial_call=False)
186
187         def __onClose(self):
188                 config.misc.standbyCounter.removeNotifier(self.standbyCountChanged)
189                 from Screens.MovieSelection import playlist
190                 del playlist[:]
191                 if not config.movielist.stop_service.value:
192                         Screens.InfoBar.InfoBar.instance.callServiceStarted()
193                 self.session.nav.playService(self.lastservice)
194                 config.usage.last_movie_played.value = self.cur_service.toString()
195                 config.usage.last_movie_played.save()
196
197         def standbyCountChanged(self, value):
198                 if config.ParentalControl.servicepinactive.value:
199                         from Components.ParentalControl import parentalControl
200                         if parentalControl.isProtected(self.cur_service):
201                                 self.close()
202
203         def handleLeave(self, how):
204                 self.is_closing = True
205                 if how == "ask":
206                         if config.usage.setup_level.index < 2: # -expert
207                                 list = (
208                                         (_("Yes"), "quit"),
209                                         (_("No"), "continue")
210                                 )
211                         else:
212                                 list = (
213                                         (_("Yes"), "quit"),
214                                         (_("Yes, returning to movie list"), "movielist"),
215                                         (_("Yes, and delete this movie"), "quitanddelete"),
216                                         (_("Yes, delete this movie and return to movie list"), "deleteandmovielist"),
217                                         (_("No"), "continue"),
218                                         (_("No, but restart from begin"), "restart")
219                                 )
220
221                         from Screens.ChoiceBox import ChoiceBox
222                         self.session.openWithCallback(self.leavePlayerConfirmed, ChoiceBox, title=_("Stop playing this movie?"), list = list)
223                 else:
224                         self.leavePlayerConfirmed([True, how])
225
226         def leavePlayer(self):
227                 setResumePoint(self.session)
228                 self.handleLeave(config.usage.on_movie_stop.value)
229
230         def leavePlayerOnExit(self):
231                 if self.shown:
232                         self.hide()
233                 elif self.session.pipshown and "popup" in config.usage.pip_hideOnExit.value:
234                         if config.usage.pip_hideOnExit.value == "popup":
235                                 self.session.openWithCallback(self.hidePipOnExitCallback, MessageBox, _("Disable Picture in Picture"), simple=True)
236                         else:
237                                 self.hidePipOnExitCallback(True)
238                 elif config.usage.leave_movieplayer_onExit.value == "movielist":
239                         self.leavePlayer()
240                 elif config.usage.leave_movieplayer_onExit.value == "popup":
241                         self.session.openWithCallback(self.leavePlayerOnExitCallback, MessageBox, _("Exit movie player?"), simple=True)
242                 elif config.usage.leave_movieplayer_onExit.value == "without popup":
243                         self.leavePlayerOnExitCallback(True)
244
245         def leavePlayerOnExitCallback(self, answer):
246                 if answer == True:
247                         setResumePoint(self.session)
248                         self.handleLeave("quit")
249
250         def hidePipOnExitCallback(self, answer):
251                 if answer == True:
252                         self.showPiP()
253
254         def deleteConfirmed(self, answer):
255                 if answer:
256                         self.leavePlayerConfirmed((True, "quitanddeleteconfirmed"))
257
258         def deleteAndMovielistConfirmed(self, answer):
259                 if answer:
260                         self.leavePlayerConfirmed((True, "deleteandmovielistconfirmed"))
261
262         def movielistAgain(self):
263                 from Screens.MovieSelection import playlist
264                 del playlist[:]
265                 self.leavePlayerConfirmed((True, "movielist"))
266
267         def leavePlayerConfirmed(self, answer):
268                 answer = answer and answer[1]
269                 if answer is None:
270                         return
271                 if answer in ("quitanddelete", "quitanddeleteconfirmed", "deleteandmovielist", "deleteandmovielistconfirmed"):
272                         ref = self.session.nav.getCurrentlyPlayingServiceOrGroup()
273                         serviceHandler = enigma.eServiceCenter.getInstance()
274                         if answer in ("quitanddelete", "deleteandmovielist"):
275                                 msg = ''
276                                 if config.usage.movielist_trashcan.value:
277                                         import Tools.Trashcan
278                                         try:
279                                                 trash = Tools.Trashcan.createTrashFolder(ref.getPath())
280                                                 Screens.MovieSelection.moveServiceFiles(ref, trash)
281                                                 # Moved to trash, okay
282                                                 if answer == "quitanddelete":
283                                                         self.close()
284                                                 else:
285                                                         self.movielistAgain()
286                                                 return
287                                         except Exception, e:
288                                                 print "[InfoBar] Failed to move to .Trash folder:", e
289                                                 msg = _("Cannot move to trash can") + "\n" + str(e) + "\n"
290                                 info = serviceHandler.info(ref)
291                                 name = info and info.getName(ref) or _("this recording")
292                                 msg += _("Do you really want to delete %s?") % name
293                                 if answer == "quitanddelete":
294                                         self.session.openWithCallback(self.deleteConfirmed, MessageBox, msg)
295                                 elif answer == "deleteandmovielist":
296                                         self.session.openWithCallback(self.deleteAndMovielistConfirmed, MessageBox, msg)
297                                 return
298
299                         elif answer in ("quitanddeleteconfirmed", "deleteandmovielistconfirmed"):
300                                 offline = serviceHandler.offlineOperations(ref)
301                                 if offline.deleteFromDisk(0):
302                                         self.session.openWithCallback(self.close, MessageBox, _("You cannot delete this!"), MessageBox.TYPE_ERROR)
303                                         if answer == "deleteandmovielistconfirmed":
304                                                 self.movielistAgain()
305                                         return
306
307                 if answer in ("quit", "quitanddeleteconfirmed"):
308                         self.close()
309                 elif answer in ("movielist", "deleteandmovielistconfirmed"):
310                         ref = self.session.nav.getCurrentlyPlayingServiceOrGroup()
311                         self.returning = True
312                         self.session.openWithCallback(self.movieSelected, Screens.MovieSelection.MovieSelection, ref)
313                         self.session.nav.stopService()
314                         if not config.movielist.stop_service.value:
315                                 self.session.nav.playService(self.lastservice)
316                 elif answer == "restart":
317                         self.doSeek(0)
318                         self.setSeekState(self.SEEK_STATE_PLAY)
319                 elif answer in ("playlist","playlistquit","loop"):
320                         ( next_service, item , lenght ) = self.getPlaylistServiceInfo(self.cur_service)
321                         if next_service is not None:
322                                 if config.usage.next_movie_msg.value:
323                                         self.displayPlayedName(next_service, item, lenght)
324                                 self.session.nav.playService(next_service)
325                                 self.cur_service = next_service
326                         else:
327                                 if answer == "playlist":
328                                         self.leavePlayerConfirmed([True,"movielist"])
329                                 elif answer == "loop" and lenght > 0:
330                                         self.leavePlayerConfirmed([True,"loop"])
331                                 else:
332                                         self.leavePlayerConfirmed([True,"quit"])
333                 elif answer in ("repeatcurrent"):
334                         if config.usage.next_movie_msg.value:
335                                 (item, lenght) = self.getPlaylistServiceInfo(self.cur_service)
336                                 self.displayPlayedName(self.cur_service, item, lenght)
337                         self.session.nav.stopService()
338                         self.session.nav.playService(self.cur_service)
339
340         def doEofInternal(self, playing):
341                 if not self.execing:
342                         return
343                 if not playing :
344                         return
345                 ref = self.session.nav.getCurrentlyPlayingServiceOrGroup()
346                 if ref:
347                         delResumePoint(ref)
348                 self.handleLeave(config.usage.on_movie_eof.value)
349
350         def up(self):
351                 slist = self.servicelist
352                 if self.servicelist and self.servicelist.dopipzap:
353                         if config.usage.oldstyle_zap_controls.value:
354                                 self.zapDown()
355                         else:
356                                 self.switchChannelUp()
357                 else:
358                         self.showMovies()
359
360         def down(self):
361                 if self.servicelist and self.servicelist.dopipzap:
362                         if config.usage.oldstyle_zap_controls.value:
363                                 self.zapUp()
364                         else:
365                                 self.switchChannelDown()
366                 else:
367                         self.showMovies()
368
369         def right(self):
370                 if self.servicelist and self.servicelist.dopipzap:
371                         if config.usage.oldstyle_zap_controls.value:
372                                 self.switchChannelDown()
373                         else:
374                                 self.zapDown()
375                 else:
376                         InfoBarSeek.seekFwd(self)
377
378         def left(self):
379                 if self.servicelist and self.servicelist.dopipzap:
380                         if config.usage.oldstyle_zap_controls.value:
381                                 self.switchChannelUp()
382                         else:
383                                 self.zapUp()
384                 else:
385                         InfoBarSeek.seekBack(self)
386
387         def channelUp(self):
388                 if config.usage.zap_with_ch_buttons.value and self.servicelist.dopipzap:
389                         self.zapDown()
390                 else:
391                         return 0
392
393         def channelDown(self):
394                 if config.usage.zap_with_ch_buttons.value and self.servicelist.dopipzap:
395                         self.zapUp()
396                 else:
397                         return 0
398
399         def switchChannelDown(self):
400                 if "keep" not in config.usage.servicelist_cursor_behavior.value:
401                         self.servicelist.moveDown()
402                 self.session.execDialog(self.servicelist)
403
404         def switchChannelUp(self):
405                 if "keep" not in config.usage.servicelist_cursor_behavior.value:
406                         self.servicelist.moveUp()
407                 self.session.execDialog(self.servicelist)
408
409         def zapUp(self):
410                 slist = self.servicelist
411                 if slist.inBouquet():
412                         prev = slist.getCurrentSelection()
413                         if prev:
414                                 prev = prev.toString()
415                                 while True:
416                                         if config.usage.quickzap_bouquet_change.value:
417                                                 if slist.atBegin():
418                                                         slist.prevBouquet()
419                                         slist.moveUp()
420                                         cur = slist.getCurrentSelection()
421                                         if cur:
422                                                 playable = not (cur.flags & (64|8)) and hasattr(self.session, "pip") and self.session.pip.isPlayableForPipService(cur)
423                                                 if cur.toString() == prev or playable:
424                                                         break
425                 else:
426                         slist.moveUp()
427                 slist.zap(enable_pipzap = True)
428
429         def zapDown(self):
430                 slist = self.servicelist
431                 if slist.inBouquet():
432                         prev = slist.getCurrentSelection()
433                         if prev:
434                                 prev = prev.toString()
435                                 while True:
436                                         if config.usage.quickzap_bouquet_change.value and slist.atEnd():
437                                                 slist.nextBouquet()
438                                         else:
439                                                 slist.moveDown()
440                                         cur = slist.getCurrentSelection()
441                                         if cur:
442                                                 playable = not (cur.flags & (64|8)) and hasattr(self.session, "pip") and self.session.pip.isPlayableForPipService(cur)
443                                                 if cur.toString() == prev or playable:
444                                                         break
445                 else:
446                         slist.moveDown()
447                 slist.zap(enable_pipzap = True)
448
449         def showPiP(self):
450                 slist = self.servicelist
451                 if self.session.pipshown:
452                         if slist and slist.dopipzap:
453                                 slist.togglePipzap()
454                         if self.session.pipshown:
455                                 del self.session.pip
456                                 self.session.pipshown = False
457                 else:
458                         from Screens.PictureInPicture import PictureInPicture
459                         self.session.pip = self.session.instantiateDialog(PictureInPicture)
460                         self.session.pip.show()
461                         if self.session.pip.playService(slist.getCurrentSelection()):
462                                 self.session.pipshown = True
463                                 self.session.pip.servicePath = slist.getCurrentServicePath()
464                         else:
465                                 self.session.pipshown = False
466                                 del self.session.pip
467
468         def movePiP(self):
469                 if self.session.pipshown:
470                         InfoBarPiP.movePiP(self)
471
472         def swapPiP(self):
473                 pass
474
475         def showDefaultEPG(self):
476                 self.infobar and self.infobar.showMultiEPG()
477
478         def openEventView(self):
479                 self.infobar and self.infobar.showDefaultEPG()
480
481         def showEventInfoPlugins(self):
482                 self.infobar and self.infobar.showEventInfoPlugins()
483
484         def showEventGuidePlugins(self):
485                 self.infobar and self.infobar.showEventGuidePlugins()
486
487         def openSingleServiceEPG(self):
488                 self.infobar and self.infobar.openSingleServiceEPG()
489
490         def openMultiServiceEPG(self):
491                 self.infobar and self.infobar.openMultiServiceEPG()
492
493         def showMovies(self):
494                 ref = self.session.nav.getCurrentlyPlayingServiceOrGroup()
495                 self.playingservice = ref # movie list may change the currently playing
496                 self.session.openWithCallback(self.movieSelected, Screens.MovieSelection.MovieSelection, ref)
497
498         def movieSelected(self, service):
499                 if service is not None:
500                         self.cur_service = service
501                         self.is_closing = False
502                         self.session.nav.playService(service)
503                         self.returning = False
504                 elif self.returning:
505                         self.close()
506                 else:
507                         self.is_closing = False
508                         ref = self.playingservice
509                         del self.playingservice
510                         # no selection? Continue where we left off
511                         if ref and not self.session.nav.getCurrentlyPlayingServiceOrGroup():
512                                 self.session.nav.playService(ref)
513
514         def getPlaylistServiceInfo(self, service):
515                 from MovieSelection import playlist
516                 for i, item in enumerate(playlist):
517                         if item == service:
518                                 if config.usage.on_movie_eof.value == "repeatcurrent":
519                                         return (i+1, len(playlist))
520                                 i += 1
521                                 if i < len(playlist):
522                                         return (playlist[i], i+1, len(playlist))
523                                 elif config.usage.on_movie_eof.value == "loop":
524                                         return (playlist[0], 1, len(playlist))
525                 return ( None, 0, 0 )
526
527         def displayPlayedName(self, ref, index, n):
528                 from Tools import Notifications
529                 Notifications.AddPopup(text = _("%s/%s: %s") % (index, n, self.ref2HumanName(ref)), type = MessageBox.TYPE_INFO, timeout = 5)
530
531         def ref2HumanName(self, ref):
532                 return enigma.eServiceCenter.getInstance().info(ref).getName(ref)