fixes bug #556
[enigma2.git] / lib / python / Screens / ChannelSelection.py
index ebfbe812fb5e132b04762a0099fc15ed022835d0..0895c9c201398eac4b98723f21d3f7bb2b08d088 100644 (file)
@@ -21,14 +21,16 @@ profile("ChannelSelection.py 2.3")
 from Components.Input import Input
 profile("ChannelSelection.py 3")
 from Components.ParentalControl import parentalControl
+from Components.ChoiceList import ChoiceList, ChoiceEntryComponent
+from Components.SystemInfo import SystemInfo
 from Screens.InputBox import InputBox, PinInput
 from Screens.MessageBox import MessageBox
 from Screens.ServiceInfo import ServiceInfo
 profile("ChannelSelection.py 4")
+from Screens.PictureInPicture import PictureInPicture
 from Screens.RdsDisplay import RassInteractive
 from ServiceReference import ServiceReference
 from Tools.BoundFunction import boundFunction
-from re import compile
 from os import remove
 profile("ChannelSelection.py after imports")
 
@@ -69,9 +71,9 @@ OFF = 0
 EDIT_BOUQUET = 1
 EDIT_ALTERNATIVES = 2
 
-def append_when_current_valid(current, menu, args, level = 0):
+def append_when_current_valid(current, menu, args, level = 0, key = ""):
        if current and current.valid() and level <= config.usage.setup_level.index:
-               menu.append(args)
+               menu.append(ChoiceEntryComponent(key, args))
 
 class ChannelContextMenu(Screen):
        def __init__(self, session, csel):
@@ -80,13 +82,15 @@ class ChannelContextMenu(Screen):
                self.csel = csel
                self.bsel = None
 
-               self["actions"] = ActionMap(["OkCancelActions"],
+               self["actions"] = ActionMap(["OkCancelActions", "ColorActions", "NumberActions"],
                        {
                                "ok": self.okbuttonClick,
-                               "cancel": self.cancelClick
+                               "cancel": self.cancelClick,
+                               "blue": self.showServiceInPiP
                        })
                menu = [ ]
 
+               self.pipAvailable = False
                current = csel.getCurrentSelection()
                current_root = csel.getRoot()
                current_sel_path = current.getPath()
@@ -95,7 +99,7 @@ class ChannelContextMenu(Screen):
                inBouquet = csel.getMutableList() is not None
                haveBouquets = config.usage.multibouquet.value
 
-               if not (len(current_sel_path) or current_sel_flags & (eServiceReference.isDirectory|eServiceReference.isMarker)):
+               if not (current_sel_path or current_sel_flags & (eServiceReference.isDirectory|eServiceReference.isMarker)):
                        append_when_current_valid(current, menu, (_("show transponder info"), self.showServiceInformations), level = 2)
                if csel.bouquet_mark_edit == OFF and not csel.movemode:
                        if not inBouquetRootList:
@@ -122,8 +126,11 @@ class ChannelContextMenu(Screen):
                                        append_when_current_valid(current, menu, (_("remove entry"), self.removeCurrentService), level = 0)
                                if current_root and current_root.getPath().find("flags == %d" %(FLAG_SERVICE_NEW_FOUND)) != -1:
                                        append_when_current_valid(current, menu, (_("remove new found flag"), self.removeNewFoundFlag), level = 0)
+                               if isPlayable and SystemInfo.get("NumVideoDecoders", 1) > 1:
+                                       append_when_current_valid(current, menu, (_("Activate Picture in Picture"), self.showServiceInPiP), level = 0, key = "blue")
+                                       self.pipAvailable = True
                        else:
-                                       menu.append((_("add bouquet"), self.showBouquetInputBox))
+                                       menu.append(ChoiceEntryComponent(text = (_("add bouquet"), self.showBouquetInputBox)))
                                        append_when_current_valid(current, menu, (_("remove entry"), self.removeBouquet), level = 0)
 
                if inBouquet: # current list is editable?
@@ -131,7 +138,7 @@ class ChannelContextMenu(Screen):
                                if not csel.movemode:
                                        append_when_current_valid(current, menu, (_("enable move mode"), self.toggleMoveMode), level = 1)
                                        if not inBouquetRootList and current_root and not (current_root.flags & eServiceReference.isGroup):
-                                               menu.append((_("add marker"), self.showMarkerInputBox))
+                                               menu.append(ChoiceEntryComponent(text = (_("add marker"), self.showMarkerInputBox)))
                                                if haveBouquets:
                                                        append_when_current_valid(current, menu, (_("enable bouquet edit"), self.bouquetMarkStart), level = 0)
                                                else:
@@ -156,11 +163,11 @@ class ChannelContextMenu(Screen):
                                                append_when_current_valid(current, menu, (_("end alternatives edit"), self.bouquetMarkEnd), level = 0)
                                                append_when_current_valid(current, menu, (_("abort alternatives edit"), self.bouquetMarkAbort), level = 0)
 
-               menu.append((_("back"), self.cancelClick))
-               self["menu"] = MenuList(menu)
+               menu.append(ChoiceEntryComponent(text = (_("back"), self.cancelClick)))
+               self["menu"] = ChoiceList(menu)
 
        def okbuttonClick(self):
-               self["menu"].getCurrent()[1]()
+               self["menu"].getCurrent()[0][1]()
 
        def cancelClick(self):
                self.close(False)
@@ -189,6 +196,23 @@ class ChannelContextMenu(Screen):
                        self.close()
                else:
                        self.session.openWithCallback(self.close, MessageBox, _("The pin code you entered is wrong."), MessageBox.TYPE_ERROR)
+                       
+       def showServiceInPiP(self):
+               if not self.pipAvailable:
+                       return
+               if self.session.pipshown:
+                       del self.session.pip
+               self.session.pip = self.session.instantiateDialog(PictureInPicture)
+               self.session.pip.show()
+               newservice = self.csel.servicelist.getCurrent()
+               if self.session.pip.playService(newservice):
+                       self.session.pipshown = True
+                       self.session.pip.servicePath = self.csel.getCurrentServicePath()
+                       self.close(True)
+               else:
+                       self.session.pipshown = False
+                       del self.session.pip
+                       self.session.openWithCallback(self.close, MessageBox, _("Could not open Picture in Picture"), MessageBox.TYPE_ERROR)
 
        def addServiceToBouquetSelected(self):
                bouquets = self.csel.getBouquetList()
@@ -317,11 +341,24 @@ class ChannelSelectionEPG:
 
        def showEPGList(self):
                ref=self.getCurrentSelection()
-               ptr=eEPGCache.getInstance()
-               if ptr.startTimeQuery(ref) != -1:
-                       self.session.open(EPGSelection, ref)
-               else:
-                       print 'no epg for service', ref.toString()
+               if ref:
+                       self.savedService = ref
+                       self.session.openWithCallback(self.SingleServiceEPGClosed, EPGSelection, ref, serviceChangeCB=self.changeServiceCB)
+
+       def SingleServiceEPGClosed(self, ret=False):
+               self.setCurrentSelection(self.savedService)
+
+       def changeServiceCB(self, direction, epg):
+               beg = self.getCurrentSelection()
+               while True:
+                       if direction > 0:
+                               self.moveDown()
+                       else:
+                               self.moveUp()
+                       cur = self.getCurrentSelection()
+                       if cur == beg or not (cur.flags & eServiceReference.isMarker):
+                               break
+               epg.setService(ServiceReference(self.getCurrentSelection()))
 
 class ChannelSelectionEdit:
        def __init__(self):
@@ -412,7 +449,7 @@ class ChannelSelectionEdit:
                                if mutableAlternatives:
                                        mutableAlternatives.setListName(name)
                                        if mutableAlternatives.addService(cur_service.ref):
-                                               print "add", cur_service.toString(), "to new alternatives failed"
+                                               print "add", cur_service.ref.toString(), "to new alternatives failed"
                                        mutableAlternatives.flushChanges()
                                        self.servicelist.addService(new_ref.ref, True)
                                        self.servicelist.removeCurrent()
@@ -513,7 +550,7 @@ class ChannelSelectionEdit:
                self.mutableList = self.getMutableList()
                # add all services from the current list to internal marked set in listboxservicecontent
                self.clearMarks() # this clears the internal marked set in the listboxservicecontent
-               self.saved_title = self.instance.getTitle()
+               self.saved_title = self.getTitle()
                pos = self.saved_title.find(')')
                new_title = self.saved_title[:pos+1]
                if type == EDIT_ALTERNATIVES:
@@ -558,7 +595,7 @@ class ChannelSelectionEdit:
                del self.servicePath[:] # remove all elements
                self.servicePath += self.savedPath # add saved elements
                del self.savedPath
-               self.setRoot(self.servicePath[len(self.servicePath)-1])
+               self.setRoot(self.servicePath[-1])
 
        def clearMarks(self):
                self.servicelist.clearMarks()
@@ -613,7 +650,7 @@ class ChannelSelectionEdit:
                        self.mutableList = self.getMutableList()
                        self.movemode = True
                        self.pathChangeDisabled = True # no path change allowed in movemode
-                       self.saved_title = self.instance.getTitle()
+                       self.saved_title = self.getTitle()
                        new_title = self.saved_title
                        pos = self.saved_title.find(')')
                        new_title = self.saved_title[:pos+1] + ' ' + _("[move mode]") + self.saved_title[pos+1:]
@@ -635,14 +672,27 @@ class ChannelSelectionEdit:
                        self.entry_marked = True
 
        def doContext(self):
-               self.session.open(ChannelContextMenu, self)
+               self.session.openWithCallback(self.exitContext, ChannelContextMenu, self)
+               
+       def exitContext(self, close = False):
+               if close:
+                       self.cancel()
 
 MODE_TV = 0
 MODE_RADIO = 1
 
-# this makes it much simple to implement a selectable radio or tv mode :)
-service_types_tv = '1:7:1:0:0:0:0:0:0:0:(type == 1) || (type == 17) || (type == 195) || (type == 25) || (type == 134)'
-service_types_radio = '1:7:2:0:0:0:0:0:0:0:(type == 2)'
+# type 1 = digital television service
+# type 4 = nvod reference service (NYI)
+# type 17 = MPEG-2 HD digital television service
+# type 22 = advanced codec SD digital television
+# type 24 = advanced codec SD NVOD reference service (NYI)
+# type 25 = advanced codec HD digital television
+# type 27 = advanced codec HD NVOD reference service (NYI)
+# type 2 = digital radio sound service
+# type 10 = advanced codec digital radio sound service
+
+service_types_tv = '1:7:1:0:0:0:0:0:0:0:(type == 1) || (type == 17) || (type == 22) || (type == 25) || (type == 134) || (type == 195)'
+service_types_radio = '1:7:2:0:0:0:0:0:0:0:(type == 2) || (type == 10)'
 
 class ChannelSelectionBase(Screen):
        def __init__(self, session):
@@ -662,6 +712,7 @@ class ChannelSelectionBase(Screen):
                self.servicePathTV = [ ]
                self.servicePathRadio = [ ]
                self.servicePath = [ ]
+               self.rootChanged = False
 
                self.mode = MODE_TV
 
@@ -739,7 +790,7 @@ class ChannelSelectionBase(Screen):
                self.mode = MODE_TV
                self.servicePath = self.servicePathTV
                self.recallBouquetMode()
-               title = self.instance.getTitle()
+               title = self.getTitle()
                pos = title.find(" (")
                if pos != -1:
                        title = title[:pos]
@@ -750,7 +801,7 @@ class ChannelSelectionBase(Screen):
                self.mode = MODE_RADIO
                self.servicePath = self.servicePathRadio
                self.recallBouquetMode()
-               title = self.instance.getTitle()
+               title = self.getTitle()
                pos = title.find(" (")
                if pos != -1:
                        title = title[:pos]
@@ -768,6 +819,7 @@ class ChannelSelectionBase(Screen):
                else:
                        self.servicelist.setMode(ServiceList.MODE_NORMAL)
                self.servicelist.setRoot(root, justSet)
+               self.rootChanged = True
                self.buildTitleString()
 
        def removeModeStr(self, str):
@@ -781,18 +833,18 @@ class ChannelSelectionBase(Screen):
 
        def getServiceName(self, ref):
                str = self.removeModeStr(ServiceReference(ref).getServiceName())
-               if not len(str):
+               if not str:
                        pathstr = ref.getPath()
-                       if pathstr.find('FROM PROVIDERS') != -1:
+                       if 'FROM PROVIDERS' in pathstr:
                                return _("Provider")
-                       if pathstr.find('FROM SATELLITES') != -1:
+                       if 'FROM SATELLITES' in pathstr:
                                return _("Satellites")
-                       if pathstr.find(') ORDER BY name') != -1:
+                       if ') ORDER BY name' in pathstr:
                                return _("All")
                return str
 
        def buildTitleString(self):
-               titleStr = self.instance.getTitle()
+               titleStr = self.getTitle()
                pos = titleStr.find(']')
                if pos == -1:
                        pos = titleStr.find(')')
@@ -831,9 +883,8 @@ class ChannelSelectionBase(Screen):
 
        def pathUp(self, justSet=False):
                prev = self.servicePath.pop()
-               length = len(self.servicePath)
-               if length:
-                       current = self.servicePath[length-1]
+               if self.servicePath:
+                       current = self.servicePath[-1]
                        self.setRoot(current, justSet)
                        if not justSet:
                                self.setCurrentSelection(prev)
@@ -961,7 +1012,7 @@ class ChannelSelectionBase(Screen):
                                self.enterPath(ref)
 
        def inBouquet(self):
-               if len(self.servicePath) > 0 and self.servicePath[0] == self.bouquet_root:
+               if self.servicePath and self.servicePath[0] == self.bouquet_root:
                        return True
                return False
 
@@ -1130,6 +1181,7 @@ class ChannelSelection(ChannelSelectionBase, ChannelSelectionEdit, ChannelSelect
                self.servicelist.setPlayableIgnoreService(eServiceReference())
 
        def setMode(self):
+               self.rootChanged = True
                self.restoreRoot()
                lastservice=eServiceReference(self.lastservice.value)
                if lastservice.valid():
@@ -1235,8 +1287,7 @@ class ChannelSelection(ChannelSelectionBase, ChannelSelectionEdit, ChannelSelect
                del self.servicePath[:]
                self.servicePath += path
                self.saveRoot()
-               plen = len(path)
-               root = path[plen-1]
+               root = path[-1]
                cur_root = self.getRoot()
                if cur_root and cur_root != root:
                        self.setRoot(root)
@@ -1249,27 +1300,29 @@ class ChannelSelection(ChannelSelectionBase, ChannelSelectionEdit, ChannelSelect
                for i in self.servicePath:
                        path += i.toString()
                        path += ';'
-               if len(path) and path != self.lastroot.value:
+               if path and path != self.lastroot.value:
                        self.lastroot.value = path
                        self.lastroot.save()
 
        def restoreRoot(self):
-               self.clearPath()
-               re = compile('.+?;')
-               tmp = re.findall(self.lastroot.value)
-               cnt = 0
-               for i in tmp:
-                       self.servicePath.append(eServiceReference(i[:len(i)-1]))
-                       cnt += 1
-               if cnt:
-                       path = self.servicePath.pop()
-                       self.enterPath(path)
-               else:
-                       self.showFavourites()
-                       self.saveRoot()
+               tmp = [x for x in self.lastroot.value.split(';') if x != '']
+               current = [x.toString() for x in self.servicePath]
+               if tmp != current or self.rootChanged:
+                       self.clearPath()
+                       cnt = 0
+                       for i in tmp:
+                               self.servicePath.append(eServiceReference(i))
+                               cnt += 1
+                       if cnt:
+                               path = self.servicePath.pop()
+                               self.enterPath(path)
+                       else:
+                               self.showFavourites()
+                               self.saveRoot()
+                       self.rootChanged = False
 
        def preEnterPath(self, refstr):
-               if len(self.servicePath) and self.servicePath[0] != eServiceReference(refstr):
+               if self.servicePath and self.servicePath[0] != eServiceReference(refstr):
                        pathstr = self.lastroot.value
                        if pathstr is not None and pathstr.find(refstr) == 0:
                                self.restoreRoot()
@@ -1289,16 +1342,14 @@ class ChannelSelection(ChannelSelectionBase, ChannelSelectionEdit, ChannelSelect
                        self.lastservice.save()
 
        def setCurrentServicePath(self, path):
-               hlen = len(self.history)
-               if hlen > 0:
+               if self.history:
                        self.history[self.history_pos] = path
                else:
                        self.history.append(path)
                self.setHistoryPath()
 
        def getCurrentServicePath(self):
-               hlen = len(self.history)
-               if hlen > 0:
+               if self.history:
                        return self.history[self.history_pos]
                return None
 
@@ -1411,27 +1462,28 @@ class ChannelSelectionRadio(ChannelSelectionBase, ChannelSelectionEdit, ChannelS
                for i in self.servicePathRadio:
                        path += i.toString()
                        path += ';'
-               if len(path) and path != config.radio.lastroot.value:
+               if path and path != config.radio.lastroot.value:
                        config.radio.lastroot.value = path
                        config.radio.lastroot.save()
 
        def restoreRoot(self):
-               self.clearPath()
-               re = compile('.+?;')
-               tmp = re.findall(config.radio.lastroot.value)
-               cnt = 0
-               for i in tmp:
-                       self.servicePathRadio.append(eServiceReference(i[:len(i)-1]))
-                       cnt += 1
-               if cnt:
-                       path = self.servicePathRadio.pop()
-                       self.enterPath(path)
-               else:
-                       self.showFavourites()
-                       self.saveRoot()
+               tmp = [x for x in config.radio.lastroot.value.split(';') if x != '']
+               current = [x.toString() for x in self.servicePath]
+               if tmp != current or self.rootChanged:
+                       cnt = 0
+                       for i in tmp:
+                               self.servicePathRadio.append(eServiceReference(i))
+                               cnt += 1
+                       if cnt:
+                               path = self.servicePathRadio.pop()
+                               self.enterPath(path)
+                       else:
+                               self.showFavourites()
+                               self.saveRoot()
+                       self.rootChanged = False
 
        def preEnterPath(self, refstr):
-               if len(self.servicePathRadio) and self.servicePathRadio[0] != eServiceReference(refstr):
+               if self.servicePathRadio and self.servicePathRadio[0] != eServiceReference(refstr):
                        pathstr = config.radio.lastroot.value
                        if pathstr is not None and pathstr.find(refstr) == 0:
                                self.restoreRoot()
@@ -1474,9 +1526,6 @@ class ChannelSelectionRadio(ChannelSelectionBase, ChannelSelectionEdit, ChannelS
 class SimpleChannelSelection(ChannelSelectionBase):
        def __init__(self, session, title):
                ChannelSelectionBase.__init__(self, session)
-               self.title = title
-               self.onShown.append(self.__onExecCallback)
-
                self["actions"] = ActionMap(["OkCancelActions", "TvRadioActions"],
                        {
                                "cancel": self.close,
@@ -1484,9 +1533,10 @@ class SimpleChannelSelection(ChannelSelectionBase):
                                "keyRadio": self.setModeRadio,
                                "keyTV": self.setModeTv,
                        })
+               self.title = title
+               self.onLayoutFinish.append(self.layoutFinished)
 
-       def __onExecCallback(self):
-               self.setTitle(self.title)
+       def layoutFinished(self):
                self.setModeTv()
 
        def channelSelected(self): # just return selected service