InfoBar: Do not open MoviePlayer when parental locked recording is blocked
[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
186         def __onClose(self):
187                 from Screens.MovieSelection import playlist
188                 del playlist[:]
189                 if not config.movielist.stop_service.value:
190                         Screens.InfoBar.InfoBar.instance.callServiceStarted()
191                 self.session.nav.playService(self.lastservice)
192                 config.usage.last_movie_played.value = self.cur_service.toString()
193                 config.usage.last_movie_played.save()
194
195         def handleLeave(self, how):
196                 self.is_closing = True
197                 if how == "ask":
198                         if config.usage.setup_level.index < 2: # -expert
199                                 list = (
200                                         (_("Yes"), "quit"),
201                                         (_("No"), "continue")
202                                 )
203                         else:
204                                 list = (
205                                         (_("Yes"), "quit"),
206                                         (_("Yes, returning to movie list"), "movielist"),
207                                         (_("Yes, and delete this movie"), "quitanddelete"),
208                                         (_("Yes, delete this movie and return to movie list"), "deleteandmovielist"),
209                                         (_("No"), "continue"),
210                                         (_("No, but restart from begin"), "restart")
211                                 )
212
213                         from Screens.ChoiceBox import ChoiceBox
214                         self.session.openWithCallback(self.leavePlayerConfirmed, ChoiceBox, title=_("Stop playing this movie?"), list = list)
215                 else:
216                         self.leavePlayerConfirmed([True, how])
217
218         def leavePlayer(self):
219                 setResumePoint(self.session)
220                 self.handleLeave(config.usage.on_movie_stop.value)
221
222         def leavePlayerOnExit(self):
223                 if self.shown:
224                         self.hide()
225                 elif self.session.pipshown and "popup" in config.usage.pip_hideOnExit.value:
226                         if config.usage.pip_hideOnExit.value == "popup":
227                                 self.session.openWithCallback(self.hidePipOnExitCallback, MessageBox, _("Disable Picture in Picture"), simple=True)
228                         else:
229                                 self.hidePipOnExitCallback(True)
230                 elif config.usage.leave_movieplayer_onExit.value == "popup":
231                         self.session.openWithCallback(self.leavePlayerOnExitCallback, MessageBox, _("Exit movie player?"), simple=True)
232                 elif config.usage.leave_movieplayer_onExit.value == "without popup":
233                         self.leavePlayerOnExitCallback(True)
234
235         def leavePlayerOnExitCallback(self, answer):
236                 if answer == True:
237                         setResumePoint(self.session)
238                         self.handleLeave("quit")
239
240         def hidePipOnExitCallback(self, answer):
241                 if answer == True:
242                         self.showPiP()
243
244         def deleteConfirmed(self, answer):
245                 if answer:
246                         self.leavePlayerConfirmed((True, "quitanddeleteconfirmed"))
247
248         def deleteAndMovielistConfirmed(self, answer):
249                 if answer:
250                         self.leavePlayerConfirmed((True, "deleteandmovielistconfirmed"))
251
252         def movielistAgain(self):
253                 from Screens.MovieSelection import playlist
254                 del playlist[:]
255                 self.leavePlayerConfirmed((True, "movielist"))
256
257         def leavePlayerConfirmed(self, answer):
258                 answer = answer and answer[1]
259                 if answer is None:
260                         return
261                 if answer in ("quitanddelete", "quitanddeleteconfirmed", "deleteandmovielist", "deleteandmovielistconfirmed"):
262                         ref = self.session.nav.getCurrentlyPlayingServiceOrGroup()
263                         serviceHandler = enigma.eServiceCenter.getInstance()
264                         if answer in ("quitanddelete", "deleteandmovielist"):
265                                 msg = ''
266                                 if config.usage.movielist_trashcan.value:
267                                         import Tools.Trashcan
268                                         try:
269                                                 trash = Tools.Trashcan.createTrashFolder(ref.getPath())
270                                                 Screens.MovieSelection.moveServiceFiles(ref, trash)
271                                                 # Moved to trash, okay
272                                                 if answer == "quitanddelete":
273                                                         self.close()
274                                                 else:
275                                                         self.movielistAgain()
276                                                 return
277                                         except Exception, e:
278                                                 print "[InfoBar] Failed to move to .Trash folder:", e
279                                                 msg = _("Cannot move to trash can") + "\n" + str(e) + "\n"
280                                 info = serviceHandler.info(ref)
281                                 name = info and info.getName(ref) or _("this recording")
282                                 msg += _("Do you really want to delete %s?") % name
283                                 if answer == "quitanddelete":
284                                         self.session.openWithCallback(self.deleteConfirmed, MessageBox, msg)
285                                 elif answer == "deleteandmovielist":
286                                         self.session.openWithCallback(self.deleteAndMovielistConfirmed, MessageBox, msg)
287                                 return
288
289                         elif answer in ("quitanddeleteconfirmed", "deleteandmovielistconfirmed"):
290                                 offline = serviceHandler.offlineOperations(ref)
291                                 if offline.deleteFromDisk(0):
292                                         self.session.openWithCallback(self.close, MessageBox, _("You cannot delete this!"), MessageBox.TYPE_ERROR)
293                                         if answer == "deleteandmovielistconfirmed":
294                                                 self.movielistAgain()
295                                         return
296
297                 if answer in ("quit", "quitanddeleteconfirmed"):
298                         self.close()
299                 elif answer in ("movielist", "deleteandmovielistconfirmed"):
300                         ref = self.session.nav.getCurrentlyPlayingServiceOrGroup()
301                         self.returning = True
302                         self.session.openWithCallback(self.movieSelected, Screens.MovieSelection.MovieSelection, ref)
303                         self.session.nav.stopService()
304                         if not config.movielist.stop_service.value:
305                                 self.session.nav.playService(self.lastservice)
306                 elif answer == "restart":
307                         self.doSeek(0)
308                         self.setSeekState(self.SEEK_STATE_PLAY)
309                 elif answer in ("playlist","playlistquit","loop"):
310                         ( next_service, item , lenght ) = self.getPlaylistServiceInfo(self.cur_service)
311                         if next_service is not None:
312                                 if config.usage.next_movie_msg.value:
313                                         self.displayPlayedName(next_service, item, lenght)
314                                 self.session.nav.playService(next_service)
315                                 self.cur_service = next_service
316                         else:
317                                 if answer == "playlist":
318                                         self.leavePlayerConfirmed([True,"movielist"])
319                                 elif answer == "loop" and lenght > 0:
320                                         self.leavePlayerConfirmed([True,"loop"])
321                                 else:
322                                         self.leavePlayerConfirmed([True,"quit"])
323                 elif answer in ("repeatcurrent"):
324                         if config.usage.next_movie_msg.value:
325                                 (item, lenght) = self.getPlaylistServiceInfo(self.cur_service)
326                                 self.displayPlayedName(self.cur_service, item, lenght)
327                         self.session.nav.stopService()
328                         self.session.nav.playService(self.cur_service)
329
330         def doEofInternal(self, playing):
331                 if not self.execing:
332                         return
333                 if not playing :
334                         return
335                 ref = self.session.nav.getCurrentlyPlayingServiceOrGroup()
336                 if ref:
337                         delResumePoint(ref)
338                 self.handleLeave(config.usage.on_movie_eof.value)
339
340         def up(self):
341                 slist = self.servicelist
342                 if self.servicelist and self.servicelist.dopipzap:
343                         if config.usage.oldstyle_zap_controls.value:
344                                 self.zapDown()
345                         else:
346                                 self.switchChannelUp()
347                 else:
348                         self.showMovies()
349
350         def down(self):
351                 if self.servicelist and self.servicelist.dopipzap:
352                         if config.usage.oldstyle_zap_controls.value:
353                                 self.zapUp()
354                         else:
355                                 self.switchChannelDown()
356                 else:
357                         self.showMovies()
358
359         def right(self):
360                 if self.servicelist and self.servicelist.dopipzap:
361                         if config.usage.oldstyle_zap_controls.value:
362                                 self.switchChannelDown()
363                         else:
364                                 self.zapDown()
365                 else:
366                         InfoBarSeek.seekFwd(self)
367
368         def left(self):
369                 if self.servicelist and self.servicelist.dopipzap:
370                         if config.usage.oldstyle_zap_controls.value:
371                                 self.switchChannelUp()
372                         else:
373                                 self.zapUp()
374                 else:
375                         InfoBarSeek.seekBack(self)
376
377         def channelUp(self):
378                 if config.usage.zap_with_ch_buttons.value and self.servicelist.dopipzap:
379                         self.zapDown()
380                 else:
381                         return 0
382
383         def channelDown(self):
384                 if config.usage.zap_with_ch_buttons.value and self.servicelist.dopipzap:
385                         self.zapUp()
386                 else:
387                         return 0
388
389         def switchChannelDown(self):
390                 if "keep" not in config.usage.servicelist_cursor_behavior.value:
391                         self.servicelist.moveDown()
392                 self.session.execDialog(self.servicelist)
393
394         def switchChannelUp(self):
395                 if "keep" not in config.usage.servicelist_cursor_behavior.value:
396                         self.servicelist.moveUp()
397                 self.session.execDialog(self.servicelist)
398
399         def zapUp(self):
400                 slist = self.servicelist
401                 if slist.inBouquet():
402                         prev = slist.getCurrentSelection()
403                         if prev:
404                                 prev = prev.toString()
405                                 while True:
406                                         if config.usage.quickzap_bouquet_change.value:
407                                                 if slist.atBegin():
408                                                         slist.prevBouquet()
409                                         slist.moveUp()
410                                         cur = slist.getCurrentSelection()
411                                         if cur:
412                                                 playable = not (cur.flags & (64|8)) and hasattr(self.session, "pip") and self.session.pip.isPlayableForPipService(cur)
413                                                 if cur.toString() == prev or playable:
414                                                         break
415                 else:
416                         slist.moveUp()
417                 slist.zap(enable_pipzap = True)
418
419         def zapDown(self):
420                 slist = self.servicelist
421                 if slist.inBouquet():
422                         prev = slist.getCurrentSelection()
423                         if prev:
424                                 prev = prev.toString()
425                                 while True:
426                                         if config.usage.quickzap_bouquet_change.value and slist.atEnd():
427                                                 slist.nextBouquet()
428                                         else:
429                                                 slist.moveDown()
430                                         cur = slist.getCurrentSelection()
431                                         if cur:
432                                                 playable = not (cur.flags & (64|8)) and hasattr(self.session, "pip") and self.session.pip.isPlayableForPipService(cur)
433                                                 if cur.toString() == prev or playable:
434                                                         break
435                 else:
436                         slist.moveDown()
437                 slist.zap(enable_pipzap = True)
438
439         def showPiP(self):
440                 slist = self.servicelist
441                 if self.session.pipshown:
442                         if slist and slist.dopipzap:
443                                 slist.togglePipzap()
444                         if self.session.pipshown:
445                                 del self.session.pip
446                                 self.session.pipshown = False
447                 else:
448                         from Screens.PictureInPicture import PictureInPicture
449                         self.session.pip = self.session.instantiateDialog(PictureInPicture)
450                         self.session.pip.show()
451                         if self.session.pip.playService(slist.getCurrentSelection()):
452                                 self.session.pipshown = True
453                                 self.session.pip.servicePath = slist.getCurrentServicePath()
454                         else:
455                                 self.session.pipshown = False
456                                 del self.session.pip
457
458         def movePiP(self):
459                 if self.session.pipshown:
460                         InfoBarPiP.movePiP(self)
461
462         def swapPiP(self):
463                 pass
464
465         def showDefaultEPG(self):
466                 self.infobar and self.infobar.showMultiEPG()
467
468         def openEventView(self):
469                 self.infobar and self.infobar.showDefaultEPG()
470
471         def showEventInfoPlugins(self):
472                 self.infobar and self.infobar.showEventInfoPlugins()
473
474         def showEventGuidePlugins(self):
475                 self.infobar and self.infobar.showEventGuidePlugins()
476
477         def openSingleServiceEPG(self):
478                 self.infobar and self.infobar.openSingleServiceEPG()
479
480         def openMultiServiceEPG(self):
481                 self.infobar and self.infobar.openMultiServiceEPG()
482
483         def showMovies(self):
484                 ref = self.session.nav.getCurrentlyPlayingServiceOrGroup()
485                 self.playingservice = ref # movie list may change the currently playing
486                 self.session.openWithCallback(self.movieSelected, Screens.MovieSelection.MovieSelection, ref)
487
488         def movieSelected(self, service):
489                 if service is not None:
490                         self.cur_service = service
491                         self.is_closing = False
492                         self.session.nav.playService(service)
493                         self.returning = False
494                 elif self.returning:
495                         self.close()
496                 else:
497                         self.is_closing = False
498                         ref = self.playingservice
499                         del self.playingservice
500                         # no selection? Continue where we left off
501                         if ref and not self.session.nav.getCurrentlyPlayingServiceOrGroup():
502                                 self.session.nav.playService(ref)
503
504         def getPlaylistServiceInfo(self, service):
505                 from MovieSelection import playlist
506                 for i, item in enumerate(playlist):
507                         if item == service:
508                                 if config.usage.on_movie_eof.value == "repeatcurrent":
509                                         return (i+1, len(playlist))
510                                 i += 1
511                                 if i < len(playlist):
512                                         return (playlist[i], i+1, len(playlist))
513                                 elif config.usage.on_movie_eof.value == "loop":
514                                         return (playlist[0], 1, len(playlist))
515                 return ( None, 0, 0 )
516
517         def displayPlayedName(self, ref, index, n):
518                 from Tools import Notifications
519                 Notifications.AddPopup(text = _("%s/%s: %s") % (index, n, self.ref2HumanName(ref)), type = MessageBox.TYPE_INFO, timeout = 5)
520
521         def ref2HumanName(self, ref):
522                 return enigma.eServiceCenter.getInstance().info(ref).getName(ref)