+import xml.dom.minidom
+
+class BouquetSelector(Screen):
+ def __init__(self, session, bouquets, selectedFunc, enableWrapAround=False):
+ Screen.__init__(self, session)
+
+ self.selectedFunc=selectedFunc
+
+ self["actions"] = ActionMap(["OkCancelActions"],
+ {
+ "ok": self.okbuttonClick,
+ "cancel": self.cancelClick
+ })
+ entrys = [ (x[0], x[1]) for x in bouquets ]
+ self["menu"] = MenuList(entrys, enableWrapAround)
+
+ def getCurrent(self):
+ cur = self["menu"].getCurrent()
+ return cur and cur[1]
+
+ def okbuttonClick(self):
+ self.selectedFunc(self.getCurrent())
+
+ def up(self):
+ self["menu"].up()
+
+ def down(self):
+ self["menu"].down()
+
+ def cancelClick(self):
+ self.close(False)
+
+# csel.bouquet_mark_edit values
+OFF = 0
+EDIT_BOUQUET = 1
+EDIT_ALTERNATIVES = 2
+
+def apend_when_current_valid(current, menu, args):
+ if current and current.valid():
+ menu.append(args)
+
+class ChannelContextMenu(Screen):
+ def __init__(self, session, csel):
+ Screen.__init__(self, session)
+ self.csel = csel
+ self.bsel = None
+
+ self["actions"] = ActionMap(["OkCancelActions"],
+ {
+ "ok": self.okbuttonClick,
+ "cancel": self.cancelClick
+ })
+ menu = [ ]
+
+ current = csel.getCurrentSelection()
+ current_root = csel.getRoot()
+ current_sel_path = current.getPath()
+ current_sel_flags = current.flags
+ inBouquetRootList = current_root and current_root.getPath().find('FROM BOUQUET "bouquets.') != -1 #FIXME HACK
+ 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)):
+ apend_when_current_valid(current, menu, (_("show transponder info"), self.showServiceInformations))
+ if csel.bouquet_mark_edit == OFF and not csel.movemode:
+ if not inBouquetRootList:
+ isPlayable = not (current_sel_flags & (eServiceReference.isMarker|eServiceReference.isDirectory))
+ if isPlayable:
+ if config.ParentalControl.configured.value:
+ if parentalControl.getProtectionLevel(csel.getCurrentSelection().toCompareString()) == -1:
+ apend_when_current_valid(current, menu, (_("add to parental protection"), boundFunction(self.addParentalProtection, csel.getCurrentSelection())))
+ else:
+ apend_when_current_valid(current, menu, (_("remove from parental protection"), boundFunction(self.removeParentalProtection, csel.getCurrentSelection())))
+ if haveBouquets:
+ apend_when_current_valid(current, menu, (_("add service to bouquet"), self.addServiceToBouquetSelected))
+ else:
+ apend_when_current_valid(current, menu, (_("add service to favourites"), self.addServiceToBouquetSelected))
+ else:
+ if haveBouquets:
+ if not inBouquet and current_sel_path.find("PROVIDERS") == -1:
+ apend_when_current_valid(current, menu, (_("copy to bouquets"), self.copyCurrentToBouquetList))
+ if current_sel_path.find("flags == %d" %(FLAG_SERVICE_NEW_FOUND)) != -1:
+ apend_when_current_valid(current, menu, (_("remove all new found flags"), self.removeAllNewFoundFlags))
+ if inBouquet:
+ apend_when_current_valid(current, menu, (_("remove entry"), self.removeCurrentService))
+ if current_root and current_root.getPath().find("flags == %d" %(FLAG_SERVICE_NEW_FOUND)) != -1:
+ apend_when_current_valid(current, menu, (_("remove new found flag"), self.removeNewFoundFlag))
+ else:
+ menu.append((_("add bouquet"), self.showBouquetInputBox))
+ apend_when_current_valid(current, menu, (_("remove entry"), self.removeBouquet))
+
+ if inBouquet: # current list is editable?
+ if csel.bouquet_mark_edit == OFF:
+ if not csel.movemode:
+ apend_when_current_valid(current, menu, (_("enable move mode"), self.toggleMoveMode))
+ if not inBouquetRootList and current_root and not (current_root.flags & eServiceReference.isGroup):
+ menu.append((_("add marker"), self.showMarkerInputBox))
+ if haveBouquets:
+ apend_when_current_valid(current, menu, (_("enable bouquet edit"), self.bouquetMarkStart))
+ else:
+ apend_when_current_valid(current, menu, (_("enable favourite edit"), self.bouquetMarkStart))
+ if current_sel_flags & eServiceReference.isGroup:
+ apend_when_current_valid(current, menu, (_("edit alternatives"), self.editAlternativeServices))
+ apend_when_current_valid(current, menu, (_("show alternatives"), self.showAlternativeServices))
+ apend_when_current_valid(current, menu, (_("remove all alternatives"), self.removeAlternativeServices))
+ elif not current_sel_flags & eServiceReference.isMarker:
+ apend_when_current_valid(current, menu, (_("add alternatives"), self.addAlternativeServices))
+ else:
+ apend_when_current_valid(current, menu, (_("disable move mode"), self.toggleMoveMode))
+ else:
+ if csel.bouquet_mark_edit == EDIT_BOUQUET:
+ if haveBouquets:
+ apend_when_current_valid(current, menu, (_("end bouquet edit"), self.bouquetMarkEnd))
+ apend_when_current_valid(current, menu, (_("abort bouquet edit"), self.bouquetMarkAbort))
+ else:
+ apend_when_current_valid(current, menu, (_("end favourites edit"), self.bouquetMarkEnd))
+ apend_when_current_valid(current, menu, (_("abort favourites edit"), self.bouquetMarkAbort))
+ else:
+ apend_when_current_valid(current, menu, (_("end alternatives edit"), self.bouquetMarkEnd))
+ apend_when_current_valid(current, menu, (_("abort alternatives edit"), self.bouquetMarkAbort))
+
+ menu.append((_("back"), self.cancelClick))
+ self["menu"] = MenuList(menu)
+
+ def okbuttonClick(self):
+ self["menu"].getCurrent()[1]()
+
+ def cancelClick(self):
+ self.close(False)
+
+ def showServiceInformations(self):
+ self.session.open( ServiceInfo, self.csel.getCurrentSelection() )
+
+ def showBouquetInputBox(self):
+ self.session.openWithCallback(self.bouquetInputCallback, InputBox, title=_("Please enter a name for the new bouquet"), text="bouquetname", maxSize=False, type=Input.TEXT)
+
+ def bouquetInputCallback(self, bouquet):
+ if bouquet is not None:
+ self.csel.addBouquet(bouquet, None)
+ self.close()
+
+ def addParentalProtection(self, service):
+ parentalControl.protectService(service.toCompareString())
+ self.close()
+
+ def removeParentalProtection(self, service):
+ self.session.openWithCallback(boundFunction(self.pinEntered, service.toCompareString()), PinInput, pinList = [config.ParentalControl.servicepin[0].value], triesEntry = config.ParentalControl.retries.servicepin, title = _("Enter the service pin"), windowTitle = _("Change pin code"))
+
+ def pinEntered(self, service, result):
+ if result:
+ parentalControl.unProtectService(service)
+ self.close()
+ else:
+ self.session.openWithCallback(self.close, MessageBox, _("The pin code you entered is wrong."), MessageBox.TYPE_ERROR)
+
+ def addServiceToBouquetSelected(self):
+ bouquets = self.csel.getBouquetList()
+ if bouquets is None:
+ cnt = 0
+ else:
+ cnt = len(bouquets)
+ if cnt > 1: # show bouquet list
+ self.bsel = self.session.openWithCallback(self.bouquetSelClosed, BouquetSelector, bouquets, self.addCurrentServiceToBouquet)
+ elif cnt == 1: # add to only one existing bouquet
+ self.addCurrentServiceToBouquet(bouquets[0][1])
+
+ def bouquetSelClosed(self, recursive):
+ self.bsel = None
+ if recursive:
+ self.close(False)
+
+ def copyCurrentToBouquetList(self):
+ self.csel.copyCurrentToBouquetList()
+ self.close()
+
+ def removeBouquet(self):
+ self.csel.removeBouquet()
+ self.close()
+
+ def showMarkerInputBox(self):
+ self.session.openWithCallback(self.markerInputCallback, InputBox, title=_("Please enter a name for the new marker"), text="markername", maxSize=False, type=Input.TEXT)
+
+ def markerInputCallback(self, marker):
+ if marker is not None:
+ self.csel.addMarker(marker)
+ self.close()
+
+ def addCurrentServiceToBouquet(self, dest):
+ self.csel.addServiceToBouquet(dest)
+ if self.bsel is not None:
+ self.bsel.close(True)
+ else:
+ self.close(True) # close bouquet selection
+
+ def removeCurrentService(self):
+ self.csel.removeCurrentService()
+ self.close()
+
+ def toggleMoveMode(self):
+ self.csel.toggleMoveMode()
+ self.close()
+
+ def bouquetMarkStart(self):
+ self.csel.startMarkedEdit(EDIT_BOUQUET)
+ self.close()
+
+ def bouquetMarkEnd(self):
+ self.csel.endMarkedEdit(abort=False)
+ self.close()
+
+ def bouquetMarkAbort(self):
+ self.csel.endMarkedEdit(abort=True)
+ self.close()
+
+ def removeNewFoundFlag(self):
+ eDVBDB.getInstance().removeFlag(self.csel.getCurrentSelection(), FLAG_SERVICE_NEW_FOUND)
+ self.close()
+
+ def removeAllNewFoundFlags(self):
+ curpath = self.csel.getCurrentSelection().getPath()
+ idx = curpath.find("satellitePosition == ")
+ if idx != -1:
+ tmp = curpath[idx+21:]
+ idx = tmp.find(')')
+ if idx != -1:
+ satpos = int(tmp[:idx])
+ eDVBDB.getInstance().removeFlags(FLAG_SERVICE_NEW_FOUND, -1, -1, -1, satpos)
+ self.close()
+
+ def editAlternativeServices(self):
+ self.csel.startMarkedEdit(EDIT_ALTERNATIVES)
+ self.close()
+
+ def showAlternativeServices(self):
+ self.csel.enterPath(self.csel.getCurrentSelection())
+ self.close()
+
+ def removeAlternativeServices(self):
+ self.csel.removeAlternativeServices()
+ self.close()
+
+ def addAlternativeServices(self):
+ self.csel.addAlternativeServices()
+ self.csel.startMarkedEdit(EDIT_ALTERNATIVES)
+ self.close()
+
+class ChannelSelectionEPG:
+ def __init__(self):
+ self["ChannelSelectEPGActions"] = ActionMap(["ChannelSelectEPGActions"],
+ {
+ "showEPGList": self.showEPGList,
+ })
+
+ 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()
+
+class ChannelSelectionEdit:
+ def __init__(self):
+ self.entry_marked = False
+ self.movemode = False
+ self.bouquet_mark_edit = OFF
+ self.mutableList = None
+ self.__marked = [ ]
+ self.saved_title = None
+ self.saved_root = None
+
+ class ChannelSelectionEditActionMap(ActionMap):
+ def __init__(self, csel, contexts = [ ], actions = { }, prio=0):
+ ActionMap.__init__(self, contexts, actions, prio)
+ self.csel = csel
+
+ def action(self, contexts, action):
+ if action == "cancel":
+ self.csel.handleEditCancel()
+ return 0 # fall-trough
+ elif action == "ok":
+ return 0 # fall-trough
+ else:
+ return ActionMap.action(self, contexts, action)
+
+ self["ChannelSelectEditActions"] = ChannelSelectionEditActionMap(self, ["ChannelSelectEditActions", "OkCancelActions"],
+ {
+ "contextMenu": self.doContext,
+ })
+
+ def getMutableList(self, root=eServiceReference()):
+ if not self.mutableList is None:
+ return self.mutableList
+ serviceHandler = eServiceCenter.getInstance()
+ if not root.valid():
+ root=self.getRoot()
+ list = root and serviceHandler.list(root)
+ if list is not None:
+ return list.startEdit()
+ return None
+
+ def buildBouquetID(self, str):
+ tmp = str.lower()
+ name = ''
+ for c in tmp:
+ if (c >= 'a' and c <= 'z') or (c >= '0' and c <= '9'):
+ name += c
+ else:
+ name += '_'
+ return name
+
+ def addMarker(self, name):
+ current = self.servicelist.getCurrent()
+ mutableList = self.getMutableList()
+ cnt = 0
+ while mutableList:
+ str = '1:64:%d:0:0:0:0:0:0:0::%s'%(cnt, name)
+ ref = eServiceReference(str)
+ if current and current.valid():
+ if not mutableList.addService(ref, current):
+ self.servicelist.addService(ref, True)
+ mutableList.flushChanges()
+ break
+ elif not mutableList.addService(ref):
+ self.servicelist.addService(ref, True)
+ mutableList.flushChanges()
+ break
+ cnt+=1
+
+ def addAlternativeServices(self):
+ cur_service = ServiceReference(self.getCurrentSelection())
+ root = self.getRoot()
+ cur_root = root and ServiceReference(root)
+ mutableBouquet = cur_root.list().startEdit()
+ if mutableBouquet:
+ name = cur_service.getServiceName()
+ print "NAME", name
+ if self.mode == MODE_TV:
+ str = '1:134:1:0:0:0:0:0:0:0:FROM BOUQUET \"alternatives.%s.tv\" ORDER BY bouquet'%(self.buildBouquetID(name))
+ else:
+ str = '1:134:2:0:0:0:0:0:0:0:FROM BOUQUET \"alternatives.%s.radio\" ORDER BY bouquet'%(self.buildBouquetID(name))
+ new_ref = ServiceReference(str)
+ if not mutableBouquet.addService(new_ref.ref, cur_service.ref):
+ mutableBouquet.removeService(cur_service.ref)
+ mutableBouquet.flushChanges()
+ eDVBDB.getInstance().reloadBouquets()
+ mutableAlternatives = new_ref.list().startEdit()
+ if mutableAlternatives:
+ mutableAlternatives.setListName(name)
+ if mutableAlternatives.addService(cur_service.ref):
+ print "add", cur_service.toString(), "to new alternatives failed"
+ mutableAlternatives.flushChanges()
+ self.servicelist.addService(new_ref.ref, True)
+ self.servicelist.removeCurrent()
+ self.servicelist.moveUp()
+ else:
+ print "get mutable list for new created alternatives failed"
+ else:
+ print "add", str, "to", cur_root.getServiceName(), "failed"
+ else:
+ print "bouquetlist is not editable"
+
+ def addBouquet(self, bName, services):
+ serviceHandler = eServiceCenter.getInstance()
+ mutableBouquetList = serviceHandler.list(self.bouquet_root).startEdit()
+ if mutableBouquetList:
+ if self.mode == MODE_TV:
+ bName += " (TV)"
+ str = '1:7:1:0:0:0:0:0:0:0:(type == 1) FROM BOUQUET \"userbouquet.%s.tv\" ORDER BY bouquet'%(self.buildBouquetID(bName))
+ else:
+ bName += " (Radio)"
+ str = '1:7:2:0:0:0:0:0:0:0:(type == 2) FROM BOUQUET \"userbouquet.%s.radio\" ORDER BY bouquet'%(self.buildBouquetID(bName))
+ new_bouquet_ref = eServiceReference(str)
+ if not mutableBouquetList.addService(new_bouquet_ref):
+ mutableBouquetList.flushChanges()
+ eDVBDB.getInstance().reloadBouquets()
+ mutableBouquet = serviceHandler.list(new_bouquet_ref).startEdit()
+ if mutableBouquet:
+ mutableBouquet.setListName(bName)
+ if services is not None:
+ for service in services:
+ if mutableBouquet.addService(service):
+ print "add", service.toString(), "to new bouquet failed"
+ mutableBouquet.flushChanges()
+ else:
+ print "get mutable list for new created bouquet failed"
+ # do some voodoo to check if current_root is equal to bouquet_root
+ cur_root = self.getRoot();
+ str1 = cur_root and cur_root.toString()
+ pos1 = str1 and str1.find("FROM BOUQUET") or -1
+ pos2 = self.bouquet_rootstr.find("FROM BOUQUET")
+ if pos1 != -1 and pos2 != -1 and str1[pos1:] == self.bouquet_rootstr[pos2:]:
+ self.servicelist.addService(new_bouquet_ref)
+ else:
+ print "add", str, "to bouquets failed"
+ else:
+ print "bouquetlist is not editable"
+
+ def copyCurrentToBouquetList(self):
+ provider = ServiceReference(self.getCurrentSelection())
+ providerName = provider.getServiceName()
+ serviceHandler = eServiceCenter.getInstance()
+ services = serviceHandler.list(provider.ref)
+ self.addBouquet(providerName, services and services.getContent('R', True))
+
+ def removeAlternativeServices(self):
+ cur_service = ServiceReference(self.getCurrentSelection())
+ root = self.getRoot()
+ cur_root = root and ServiceReference(root)
+ list = cur_service.list()
+ first_in_alternative = list and list.getNext()
+ if first_in_alternative:
+ edit_root = cur_root and cur_root.list().startEdit()
+ if edit_root:
+ if not edit_root.addService(first_in_alternative, cur_service.ref):
+ self.servicelist.addService(first_in_alternative, True)
+ else:
+ print "couldn't add first alternative service to current root"
+ else:
+ print "couldn't edit current root!!"
+ else:
+ print "remove empty alternative list !!"
+ self.removeBouquet()
+ self.servicelist.moveUp()
+
+ def removeBouquet(self):
+ refstr = self.getCurrentSelection().toString()
+ print "removeBouquet", refstr
+ self.bouquetNumOffsetCache = { }
+ pos = refstr.find('FROM BOUQUET "')
+ filename = None
+ if pos != -1:
+ refstr = refstr[pos+14:]
+ pos = refstr.find('"')
+ if pos != -1:
+ filename = '/etc/enigma2/' + refstr[:pos] # FIXMEEE !!! HARDCODED /etc/enigma2
+ self.removeCurrentService()
+ try:
+ if filename is not None:
+ remove(filename)
+ except OSError:
+ print "error during remove of", filename
+
+# multiple marked entry stuff ( edit mode, later multiepg selection )
+ def startMarkedEdit(self, type):
+ self.savedPath = self.servicePath[:]
+ if type == EDIT_ALTERNATIVES:
+ self.enterPath(self.getCurrentSelection())
+ 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()
+ pos = self.saved_title.find(')')
+ new_title = self.saved_title[:pos+1]
+ if type == EDIT_ALTERNATIVES:
+ self.bouquet_mark_edit = EDIT_ALTERNATIVES
+ new_title += ' ' + _("[alternative edit]")
+ else:
+ self.bouquet_mark_edit = EDIT_BOUQUET
+ if config.usage.multibouquet.value:
+ new_title += ' ' + _("[bouquet edit]")
+ else:
+ new_title += ' ' + _("[favourite edit]")
+ self.setTitle(new_title)
+ self.__marked = self.servicelist.getRootServices()
+ for x in self.__marked:
+ self.servicelist.addMarked(eServiceReference(x))
+ self.showAllServices()
+
+ def endMarkedEdit(self, abort):
+ if not abort and self.mutableList is not None:
+ self.bouquetNumOffsetCache = { }
+ new_marked = set(self.servicelist.getMarked())
+ old_marked = set(self.__marked)
+ removed = old_marked - new_marked
+ added = new_marked - old_marked
+ changed = False
+ for x in removed:
+ changed = True
+ self.mutableList.removeService(eServiceReference(x))
+ for x in added:
+ changed = True
+ self.mutableList.addService(eServiceReference(x))
+ if changed:
+ self.mutableList.flushChanges()
+ self.__marked = []
+ self.clearMarks()
+ self.bouquet_mark_edit = OFF
+ self.mutableList = None
+ self.setTitle(self.saved_title)
+ self.saved_title = None
+ # self.servicePath is just a reference to servicePathTv or Radio...
+ # so we never ever do use the asignment operator in self.servicePath
+ del self.servicePath[:] # remove all elements
+ self.servicePath += self.savedPath # add saved elements
+ del self.savedPath
+ self.setRoot(self.servicePath[len(self.servicePath)-1])
+
+ def clearMarks(self):
+ self.servicelist.clearMarks()
+
+ def doMark(self):
+ ref = self.servicelist.getCurrent()
+ if self.servicelist.isMarked(ref):
+ self.servicelist.removeMarked(ref)
+ else:
+ self.servicelist.addMarked(ref)
+
+ def removeCurrentService(self):
+ ref = self.servicelist.getCurrent()
+ mutableList = self.getMutableList()
+ if ref.valid() and mutableList is not None:
+ if not mutableList.removeService(ref):
+ self.bouquetNumOffsetCache = { }
+ mutableList.flushChanges() #FIXME dont flush on each single removed service
+ self.servicelist.removeCurrent()
+
+ def addServiceToBouquet(self, dest, service=None):
+ mutableList = self.getMutableList(dest)
+ if not mutableList is None:
+ if service is None: #use current selected service
+ service = self.servicelist.getCurrent()
+ if not mutableList.addService(service):
+ self.bouquetNumOffsetCache = { }
+ mutableList.flushChanges()
+ # do some voodoo to check if current_root is equal to dest
+ cur_root = self.getRoot();
+ str1 = cur_root and cur_root.toString() or -1
+ str2 = dest.toString()
+ pos1 = str1.find("FROM BOUQUET")
+ pos2 = str2.find("FROM BOUQUET")
+ if pos1 != -1 and pos2 != -1 and str1[pos1:] == str2[pos2:]:
+ self.servicelist.addService(service)
+
+ def toggleMoveMode(self):
+ if self.movemode:
+ if self.entry_marked:
+ self.toggleMoveMarked() # unmark current entry
+ self.movemode = False
+ self.pathChangeDisabled = False # re-enable path change
+ self.mutableList.flushChanges() # FIXME add check if changes was made
+ self.mutableList = None
+ self.setTitle(self.saved_title)
+ self.saved_title = None
+ cur_root = self.getRoot()
+ if cur_root and cur_root == self.bouquet_root:
+ self.bouquetNumOffsetCache = { }
+ else:
+ self.mutableList = self.getMutableList()
+ self.movemode = True
+ self.pathChangeDisabled = True # no path change allowed in movemode
+ self.saved_title = self.instance.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:]
+ self.setTitle(new_title);
+
+ def handleEditCancel(self):
+ if self.movemode: #movemode active?
+ self.channelSelected() # unmark
+ self.toggleMoveMode() # disable move mode
+ elif self.bouquet_mark_edit != OFF:
+ self.endMarkedEdit(True) # abort edit mode
+
+ def toggleMoveMarked(self):
+ if self.entry_marked:
+ self.servicelist.setCurrentMarked(False)
+ self.entry_marked = False
+ else:
+ self.servicelist.setCurrentMarked(True)
+ self.entry_marked = True
+
+ def doContext(self):
+ self.session.open(ChannelContextMenu, self)
+
+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)'
+service_types_radio = '1:7:2:0:0:0:0:0:0:0:(type == 2)'
+
+class ChannelSelectionBase(Screen):