Merge remote-tracking branch 'origin/bug_453_multiepg_no_more_ask_bouquet'
authorghost <andreas.monzner@multimedia-labs.de>
Tue, 13 Sep 2011 08:50:43 +0000 (10:50 +0200)
committerghost <andreas.monzner@multimedia-labs.de>
Tue, 13 Sep 2011 08:50:43 +0000 (10:50 +0200)
1  2 
data/setup.xml
lib/python/Components/UsageConfig.py
lib/python/Plugins/Extensions/GraphMultiEPG/plugin.py
lib/python/Screens/ChannelSelection.py
lib/python/Screens/InfoBarGenerics.py

diff --combined data/setup.xml
index 5f7cbf6,93549fa..8620709
mode 100755,100644..100755
                        <item level="2" text="Load Length of Movies in Movielist">config.usage.load_length_of_movies_in_moviellist</item>
                        <item level="1" text="Show positioner movement">config.usage.showdish</item>
                        <item level="1" text="Enable multiple bouquets">config.usage.multibouquet</item>
+                       <item level="1" text="Multi-EPG bouquet selection">config.usage.multiepg_ask_bouquet</item>
                        <item level="1" text="Change bouquets in quickzap">config.usage.quickzap_bouquet_change</item>
                        <item level="1" text="Alternative radio mode">config.usage.e1like_radio_mode</item>
                        <item level="1" text="Action on long powerbutton press">config.usage.on_long_powerpress</item>
 +                      <item level="1" text="Action on short powerbutton press">config.usage.on_short_powerpress</item>
 +                      <item level="1" text="Position of finished Timers in Timerlist">config.usage.timerlist_finished_timer_position</item>
                        <item level="0" text="Infobar timeout">config.usage.infobar_timeout</item>
                        <item level="1" text="12V output" requires="12V_Output">config.usage.output_12V</item>
 +                      <item level="0" text="Show event-progress in channel selection">config.usage.show_event_progress_in_servicelist</item>
                        <item level="2" text="Show infobar on channel change">config.usage.show_infobar_on_zap</item>
                        <item level="2" text="Show infobar on skip forward/backward">config.usage.show_infobar_on_skip</item>
                        <item level="2" text="Show infobar on event change">config.usage.show_infobar_on_event_change</item>
                        <item level="2" text="Fast Forward speeds">config.seek.speeds_forward</item>
                        <item level="2" text="Rewind speeds">config.seek.speeds_backward</item>
                        <item level="2" text="Slow Motion speeds">config.seek.speeds_slowmotion</item>
 -<!-- TRANSLATORS: Note that "Enter" in the two strings below should *not*
 -     be interpreted as "Give speed as input". The intended meaning is
 -     instead "Initial speed when starting winding", i.e. the speed at
 -     which "winding mode" is entered when first pressing "rewind" or
 -     "fast forward". -->  
 -                      <item level="2" text="Enter Fast Forward at speed">config.seek.enter_forward</item>
 -                      <item level="2" text="Enter Rewind at speed">config.seek.enter_backward</item>
 -<!-- TRANSLATORS: The effect of "Non-smooth winding" is that rather
 -     than using ordinary "continuous" or "smooth" winding, a fast
 -     sequence of stills is shown when winding at high speeds. This
 -     makes it much easier too follow when almost each frame comes from
 -     a new scene. The effect is achieved by repeating each shown frame
 -     a couple of times. The settings control both at which speed this
 -     winding mode sets in, and how many times each frame should be
 -     repeated. This was previously called "Discontinuous playback"
 -     which was incomprehensible. "Non-smooth winding" may be a better
 -     term, but note that there is nothing irregular about it. Synonyms
 -     better suited for translation to other languages may be "stepwise
 -     winding/playback", or "winding/playback using stills". -->
 -                      <item level="2" text="Use non-smooth winding at speeds above">config.seek.stepwise_minspeed</item>
 -                      <item level="2" text="Frame repeat count during non-smooth winding">config.seek.stepwise_repeat</item>
 +<!-- TRANSLATORS: The following is the speed you get on the first press on fast-forward.
 +     It was previously called "enter fast forward at speed" which was easily misunderstood. -->  
 +                      <item level="2" text="Initial Fast Forward speed">config.seek.enter_forward</item>
 +                      <item level="2" text="Initial Rewind speed">config.seek.enter_backward</item>
                        <item level="2" text="Behavior of 'pause' when paused">config.seek.on_pause</item>
                        <item level="2" text="Behavior of 0 key in PiP-mode">config.usage.pip_zero_button</item>
                        <item level="2" text="Alternative services tuner priority">config.usage.alternatives_priority</item>
                        <item level="2" text="Limited character set for recording filenames">config.recording.ascii_filenames</item>
 +                      <item level="2" text="Composition of the recording filenames">config.recording.filename_composition</item>
                </setup>
                <setup key="harddisk" title="Harddisk setup" >
                        <item level="0" text="Harddisk standby after">config.usage.hdd_standby</item>
@@@ -1,7 -1,7 +1,7 @@@
  from Components.Harddisk import harddiskmanager
  from config import ConfigSubsection, ConfigYesNo, config, ConfigSelection, ConfigText, ConfigNumber, ConfigSet, ConfigLocations
  from Tools.Directories import resolveFilename, SCOPE_HDD
 -from enigma import Misc_Options, setTunerTypePriorityOrder;
 +from enigma import Misc_Options, setTunerTypePriorityOrder, eEnv;
  from SystemInfo import SystemInfo
  import os
  
@@@ -9,6 -9,8 +9,8 @@@ def InitUsageConfig()
        config.usage = ConfigSubsection();
        config.usage.showdish = ConfigYesNo(default = True)
        config.usage.multibouquet = ConfigYesNo(default = False)
+       config.usage.multiepg_ask_bouquet = ConfigYesNo(default = False)
        config.usage.quickzap_bouquet_change = ConfigYesNo(default = False)
        config.usage.e1like_radio_mode = ConfigYesNo(default = False)
        config.usage.infobar_timeout = ConfigSelection(default = "5", choices = [
  
        config.usage.on_long_powerpress = ConfigSelection(default = "show_menu", choices = [
                ("show_menu", _("show shutdown menu")),
 -              ("shutdown", _("immediate shutdown")) ] )
 +              ("shutdown", _("immediate shutdown")),
 +              ("standby", _("Standby")) ] )
 +      
 +      config.usage.on_short_powerpress = ConfigSelection(default = "standby", choices = [
 +              ("show_menu", _("show shutdown menu")),
 +              ("shutdown", _("immediate shutdown")),
 +              ("standby", _("Standby")) ] )
 +
  
        config.usage.alternatives_priority = ConfigSelection(default = "0", choices = [
                ("0", "DVB-S/-C/-T"),
@@@ -68,8 -63,6 +70,8 @@@
                ("4", "DVB-T/-C/-S"),
                ("5", "DVB-T/-S/-C") ])
  
 +      config.usage.show_event_progress_in_servicelist = ConfigYesNo(default = False)
 +
        config.usage.blinking_display_clock_during_recording = ConfigYesNo(default = False)
  
        config.usage.show_message_when_recording_starts = ConfigYesNo(default = True)
@@@ -94,7 -87,7 +96,7 @@@
  
        SystemInfo["12V_Output"] = Misc_Options.getInstance().detected_12V_output()
  
 -      config.usage.keymap = ConfigText(default = "/usr/share/enigma2/keymap.xml")
 +      config.usage.keymap = ConfigText(default = eEnv.resolve("${datadir}/enigma2/keymap.xml"))
  
        config.seek = ConfigSubsection()
        config.seek.selfdefined_13 = ConfigNumber(default=15)
        config.seek.selfdefined_79 = ConfigNumber(default=300)
  
        config.seek.speeds_forward = ConfigSet(default=[2, 4, 8, 16, 32, 64, 128], choices=[2, 4, 6, 8, 12, 16, 24, 32, 48, 64, 96, 128])
 -      config.seek.speeds_backward = ConfigSet(default=[8, 16, 32, 64, 128], choices=[1, 2, 4, 6, 8, 12, 16, 24, 32, 48, 64, 96, 128])
 +      config.seek.speeds_backward = ConfigSet(default=[2, 4, 8, 16, 32, 64, 128], choices=[1, 2, 4, 6, 8, 12, 16, 24, 32, 48, 64, 96, 128])
        config.seek.speeds_slowmotion = ConfigSet(default=[2, 4, 8], choices=[2, 4, 6, 8, 12, 16, 25])
  
        config.seek.enter_forward = ConfigSelection(default = "2", choices = ["2", "4", "6", "8", "12", "16", "24", "32", "48", "64", "96", "128"])
        config.seek.enter_backward = ConfigSelection(default = "1", choices = ["1", "2", "4", "6", "8", "12", "16", "24", "32", "48", "64", "96", "128"])
 -      config.seek.stepwise_minspeed = ConfigSelection(default = "16", choices = ["Never", "2", "4", "6", "8", "12", "16", "24", "32", "48", "64", "96", "128"])
 -      config.seek.stepwise_repeat = ConfigSelection(default = "3", choices = ["2", "3", "4", "5", "6"])
  
        config.seek.on_pause = ConfigSelection(default = "play", choices = [
                ("play", _("Play")),
                ("step", _("Singlestep (GOP)")),
                ("last", _("Last speed")) ])
  
 +      config.usage.timerlist_finished_timer_position = ConfigSelection(default = "beginning", choices = [("beginning", _("at beginning")), ("end", _("at end"))])
 +
        def updateEnterForward(configElement):
                if not configElement.value:
                        configElement.value = [2]
@@@ -1,8 -1,9 +1,9 @@@
  from Plugins.Plugin import PluginDescriptor
  from GraphMultiEpg import GraphMultiEPG
- from Screens.ChannelSelection import BouquetSelector
+ from Screens.ChannelSelection import BouquetSelector, SilentBouquetSelector
  from enigma import eServiceCenter, eServiceReference
  from ServiceReference import ServiceReference
+ from Components.config import config
  
  Session = None
  Servicelist = None
@@@ -73,6 -74,32 +74,32 @@@ def changeBouquetCB(direction, epg)
                        epg_bouquet = bouquet
                        epg.setServices(services)
  
+ def openAskBouquet(Session, bouquets, cnt):
+       if cnt > 1: # show bouquet list
+               global bouquetSel
+               bouquetSel = Session.openWithCallback(closed, BouquetSelector, bouquets, openBouquetEPG, enableWrapAround=True)
+               dlg_stack.append(bouquetSel)
+       elif cnt == 1:
+               if not openBouquetEPG(bouquets[0][1]):
+                       cleanup()
+ def openSilent(Servicelist, bouquets, cnt):
+       root = Servicelist.getRoot()
+       if cnt > 1: # create bouquet list
+               global bouquetSel
+               current = 0
+               rootstr = root.toCompareString()
+               for bouquet in bouquets:
+                       if bouquet[1].toCompareString() == rootstr:
+                               break
+                       current += 1
+               if current >= cnt:
+                       current = 0
+               bouquetSel = SilentBouquetSelector(bouquets, True, current)
+       if cnt >= 1: # open current bouquet
+               if not openBouquetEPG(root):
+                       cleanup()
  def main(session, servicelist, **kwargs):
        global Session
        Session = session
                cnt = 0
        else:
                cnt = len(bouquets)
-       if cnt > 1: # show bouquet list
-               global bouquetSel
-               bouquetSel = Session.openWithCallback(closed, BouquetSelector, bouquets, openBouquetEPG, enableWrapAround=True)
-               dlg_stack.append(bouquetSel)
-       elif cnt == 1:
-               if not openBouquetEPG(bouquets[0][1]):
-                       cleanup()
+       if config.usage.multiepg_ask_bouquet.value:
+               openAskBouquet(session, bouquets, cnt)
+       else:
+               openSilent(servicelist, bouquets, cnt)
  
  def Plugins(**kwargs):
        name = _("Graphical Multi EPG")
        descr = _("A graphical EPG for all services of an specific bouquet")
 -      return [ PluginDescriptor(name=name, description=descr, where = PluginDescriptor.WHERE_EVENTINFO, fnc=main),
 -        PluginDescriptor(name=name, description=descr, where = PluginDescriptor.WHERE_EXTENSIONSMENU, fnc=main) ]
 +      return [PluginDescriptor(name=name, description=descr, where = PluginDescriptor.WHERE_EVENTINFO, needsRestart = False, fnc=main),
 +              PluginDescriptor(name=name, description=descr, where = PluginDescriptor.WHERE_EXTENSIONSMENU, needsRestart = False, fnc=main)]
@@@ -8,7 -8,7 +8,7 @@@ from Components.MenuList import MenuLis
  from Components.ServiceEventTracker import ServiceEventTracker, InfoBarBase
  profile("ChannelSelection.py 1")
  from EpgSelection import EPGSelection
 -from enigma import eServiceReference, eEPGCache, eServiceCenter, eRCInput, eTimer, eDVBDB, iPlayableService, iServiceInformation, getPrevAsciiCode
 +from enigma import eServiceReference, eEPGCache, eServiceCenter, eRCInput, eTimer, eDVBDB, iPlayableService, iServiceInformation, getPrevAsciiCode, eEnv
  from Components.config import config, ConfigSubsection, ConfigText
  from Tools.NumericalTextInput import NumericalTextInput
  profile("ChannelSelection.py 2")
@@@ -20,6 -20,7 +20,6 @@@ from Components.Sources.ServiceEvent im
  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
@@@ -65,6 -66,24 +65,24 @@@ class BouquetSelector(Screen)
        def cancelClick(self):
                self.close(False)
  
+ class SilentBouquetSelector:
+       def __init__(self, bouquets, enableWrapAround=False, current=0):
+               self.bouquets = [b[1] for b in bouquets]
+               self.pos = current
+               self.count = len(bouquets)
+               self.enableWrapAround = enableWrapAround
+       def up(self):
+               if self.pos > 0 or self.enableWrapAround:
+                       self.pos = (self.pos - 1) % self.count
+       def down(self):
+               if self.pos < (self.count - 1) or self.enableWrapAround:
+                       self.pos = (self.pos + 1) % self.count
+       def getCurrent(self):
+               return self.bouquets[self.pos]
  # csel.bouquet_mark_edit values
  OFF = 0
  EDIT_BOUQUET = 1
@@@ -76,7 -95,6 +94,7 @@@ def append_when_current_valid(current, 
  
  class ChannelContextMenu(Screen):
        def __init__(self, session, csel):
 +
                Screen.__init__(self, session)
                #raise Exception("we need a better summary screen here")
                self.csel = csel
                                isPlayable = not (current_sel_flags & (eServiceReference.isMarker|eServiceReference.isDirectory))
                                if isPlayable:
                                        if config.ParentalControl.configured.value:
 +                                              from Components.ParentalControl import parentalControl
                                                if parentalControl.getProtectionLevel(csel.getCurrentSelection().toCompareString()) == -1:
                                                        append_when_current_valid(current, menu, (_("add to parental protection"), boundFunction(self.addParentalProtection, csel.getCurrentSelection())), level = 0)
                                                else:
                                                        append_when_current_valid(current, menu, (_("remove from parental protection"), boundFunction(self.removeParentalProtection, csel.getCurrentSelection())), level = 0)
                                        if haveBouquets:
 -                                              append_when_current_valid(current, menu, (_("add service to bouquet"), self.addServiceToBouquetSelected), level = 0)
 +                                              bouquets = self.csel.getBouquetList()
 +                                              if bouquets is None:
 +                                                      bouquetCnt = 0
 +                                              else:
 +                                                      bouquetCnt = len(bouquets)
 +                                              if not inBouquet or bouquetCnt > 1:
 +                                                      append_when_current_valid(current, menu, (_("add service to bouquet"), self.addServiceToBouquetSelected), level = 0)
                                        else:
 -                                              append_when_current_valid(current, menu, (_("add service to favourites"), self.addServiceToBouquetSelected), level = 0)
 +                                              if not inBouquet:
 +                                                      append_when_current_valid(current, menu, (_("add service to favourites"), self.addServiceToBouquetSelected), level = 0)
                                else:
                                        if current_root.getPath().find('FROM SATELLITES') != -1:
                                                append_when_current_valid(current, menu, (_("remove selected satellite"), self.removeSatelliteServices), level = 0)
                self.close()
  
        def addParentalProtection(self, service):
 +              from Components.ParentalControl import parentalControl
                parentalControl.protectService(service.toCompareString())
                self.close()
  
  
        def pinEntered(self, service, result):
                if result:
 +                      from Components.ParentalControl import parentalControl
                        parentalControl.unProtectService(service)
                        self.close()
                else:
                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])
 +                      self.addCurrentServiceToBouquet(bouquets[0][1], closeBouquetSelection = False)
  
        def bouquetSelClosed(self, recursive):
                self.bsel = None
                        self.csel.addMarker(marker)
                self.close()
  
 -      def addCurrentServiceToBouquet(self, dest):
 +      def addCurrentServiceToBouquet(self, dest, closeBouquetSelection = True):
                self.csel.addServiceToBouquet(dest)
                if self.bsel is not None:
                        self.bsel.close(True)
                else:
 -                      self.close(True) # close bouquet selection
 +                      self.close(closeBouquetSelection) # close bouquet selection
  
        def removeCurrentService(self):
                self.csel.removeCurrentService()
@@@ -459,7 -467,7 +477,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()
                        refstr = refstr[pos+14:]
                        pos = refstr.find('"')
                        if pos != -1:
 -                              filename = '/etc/enigma2/' + refstr[:pos] # FIXMEEE !!! HARDCODED /etc/enigma2
 +                              filename = eEnv.resolve('${sysconfdir}/enigma2/') + refstr[:pos]
                self.removeCurrentService()
                try:
                        if filename is not None:
@@@ -1410,9 -1418,9 +1428,9 @@@ class ChannelSelectionRadio(ChannelSele
  
                self["actions"] = ActionMap(["OkCancelActions", "TvRadioActions"],
                        {
 -                              "keyTV": self.closeRadio,
 -                              "keyRadio": self.closeRadio,
 -                              "cancel": self.closeRadio,
 +                              "keyTV": self.cancel,
 +                              "keyRadio": self.cancel,
 +                              "cancel": self.cancel,
                                "ok": self.channelSelected,
                        })
  
                self["RdsActions"].setEnabled(state)
  ########## RDS Radiotext / Rass Support END
  
 -      def closeRadio(self):
 +      def cancel(self):
                self.infobar.rds_display.onRassInteractivePossibilityChanged.remove(self.RassInteractivePossibilityChanged)
                self.info.hide()
                #set previous tv service
@@@ -1,4 -1,4 +1,4 @@@
- from ChannelSelection import ChannelSelection, BouquetSelector
+ from ChannelSelection import ChannelSelection, BouquetSelector, SilentBouquetSelector
  
  from Components.ActionMap import ActionMap, HelpableActionMap
  from Components.ActionMap import NumberActionMap
@@@ -487,7 -487,7 +487,7 @@@ class InfoBarEPG
                self["EPGActions"] = HelpableActionMap(self, "InfobarEPGActions",
                        {
                                "showEventInfo": (self.openEventView, _("show EPG...")),
 -                              "showEventInfoPlugin": (self.showEventInfoPlugins, _("show single service EPG...")),
 +                              "showEventInfoPlugin": (self.showEventInfoPlugins, _("list of EPG views...")),
                                "showInfobarOrEpgWhenInfobarAlreadyVisible": self.showEventInfoWhenNotVisible,
                        })
  
                        cnt = 0
                else:
                        cnt = len(bouquets)
+               if config.usage.multiepg_ask_bouquet.value:
+                       self.openMultiServiceEPGAskBouquet(bouquets, cnt, withCallback)
+               else:
+                       self.openMultiServiceEPGSilent(bouquets, cnt, withCallback)
+       def openMultiServiceEPGAskBouquet(self, bouquets, cnt, withCallback):
                if cnt > 1: # show bouquet list
                        if withCallback:
                                self.bouquetSel = self.session.openWithCallback(self.closed, BouquetSelector, bouquets, self.openBouquetEPG, enableWrapAround=True)
                elif cnt == 1:
                        self.openBouquetEPG(bouquets[0][1], withCallback)
  
+       def openMultiServiceEPGSilent(self, bouquets, cnt, withCallback):
+               root = self.servicelist.getRoot()
+               rootstr = root.toCompareString()
+               current = 0
+               for bouquet in bouquets:
+                       if bouquet[1].toCompareString() == rootstr:
+                               break
+                       current += 1
+               if current >= cnt:
+                       current = 0
+               if cnt > 1: # create bouquet list for bouq+/-
+                       self.bouquetSel = SilentBouquetSelector(bouquets, True, self.servicelist.getBouquetNumOffset(root))
+               if cnt >= 1:
+                       self.openBouquetEPG(root, withCallback)
        def changeServiceCB(self, direction, epg):
                if self.serviceSel:
                        if direction > 0:
  
                if list:
                        list.append((_("show single service EPG..."), self.openSingleServiceEPG))
 +                      list.append((_("Multi EPG"), self.openMultiServiceEPG))
                        self.session.openWithCallback(self.EventInfoPluginChosen, ChoiceBox, title=_("Please choose an extension..."), list = list, skin_name = "EPGExtensionsList")
                else:
                        self.openSingleServiceEPG()
@@@ -717,7 -737,7 +738,7 @@@ class InfoBarSeek
        SEEK_STATE_PAUSE = (1, 0, 0, "||")
        SEEK_STATE_EOF = (1, 0, 0, "END")
  
 -      def __init__(self, actionmap = "InfobarSeekActions", useSeekBackHack=True):
 +      def __init__(self, actionmap = "InfobarSeekActions"):
                self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
                        {
                                iPlayableService.evSeekableStatusChanged: self.__seekableStatusChanged,
                self.__seekableStatusChanged()
  
        def makeStateForward(self, n):
 -#             minspeed = config.seek.stepwise_minspeed.value
 -#             repeat = int(config.seek.stepwise_repeat.value)
 -#             if minspeed != "Never" and n >= int(minspeed) and repeat > 1:
 -#                     return (0, n * repeat, repeat, ">> %dx" % n)
 -#             else:
 -                      return (0, n, 0, ">> %dx" % n)
 +              return (0, n, 0, ">> %dx" % n)
  
        def makeStateBackward(self, n):
 -#             minspeed = config.seek.stepwise_minspeed.value
 -#             repeat = int(config.seek.stepwise_repeat.value)
 -#             if minspeed != "Never" and n >= int(minspeed) and repeat > 1:
 -#                     return (0, -n * repeat, repeat, "<< %dx" % n)
 -#             else:
 -                      return (0, -n, 0, "<< %dx" % n)
 +              return (0, -n, 0, "<< %dx" % n)
  
        def makeStateSlowMotion(self, n):
                return (0, 0, n, "/%d" % n)
@@@ -1101,21 -1131,15 +1122,21 @@@ class InfoBarPVRState
                        self.pvrStateDialog.hide()
                else:
                        self._mayShow()
 -                      
  
  class InfoBarTimeshiftState(InfoBarPVRState):
        def __init__(self):
                InfoBarPVRState.__init__(self, screen=TimeshiftState, force_show = True)
 +              self.__hideTimer = eTimer()
 +              self.__hideTimer.callback.append(self.__hideTimeshiftState)
  
        def _mayShow(self):
 -              if self.execing and self.timeshift_enabled and self.seekstate != self.SEEK_STATE_PLAY:
 +              if self.execing and self.timeshift_enabled:
                        self.pvrStateDialog.show()
 +                      if self.seekstate == self.SEEK_STATE_PLAY and not self.shown:
 +                              self.__hideTimer.start(5*1000, True)
 +
 +      def __hideTimeshiftState(self):
 +              self.pvrStateDialog.hide()
  
  class InfoBarShowMovies:
  
@@@ -1353,7 -1377,6 +1374,7 @@@ class InfoBarExtensions
                        answer[1][1]()
  
  from Tools.BoundFunction import boundFunction
 +import inspect
  
  # depends on InfoBarExtensions
  
@@@ -1365,13 -1388,9 +1386,13 @@@ class InfoBarPlugins
                return name
  
        def getPluginList(self):
 -              list = [((boundFunction(self.getPluginName, p.name), boundFunction(self.runPlugin, p), lambda: True), None, p.name) for p in plugins.getPlugins(where = PluginDescriptor.WHERE_EXTENSIONSMENU)]
 -              list.sort(key = lambda e: e[2]) # sort by name
 -              return list
 +              l = []
 +              for p in plugins.getPlugins(where = PluginDescriptor.WHERE_EXTENSIONSMENU):
 +                args = inspect.getargspec(p.__call__)[0]
 +                if len(args) == 1 or len(args) == 2 and isinstance(self, InfoBarChannelSelection):
 +                        l.append(((boundFunction(self.getPluginName, p.name), boundFunction(self.runPlugin, p), lambda: True), None, p.name))
 +              l.sort(key = lambda e: e[2]) # sort by name
 +              return l
  
        def runPlugin(self, plugin):
                if isinstance(self, InfoBarChannelSelection):
@@@ -1529,30 -1548,28 +1550,30 @@@ class InfoBarInstantRecord
  
                recording = RecordTimerEntry(serviceref, begin, end, name, description, eventid, dirname = preferredInstantRecordPath())
                recording.dontSave = True
 -              
 +
                if event is None or limitEvent == False:
                        recording.autoincrease = True
 -                      if recording.setAutoincreaseEnd():
 -                              self.session.nav.RecordTimer.record(recording)
 -                              self.recording.append(recording)
 +                      recording.setAutoincreaseEnd()
 +
 +              simulTimerList = self.session.nav.RecordTimer.record(recording)
 +
 +              if simulTimerList is None:      # no conflict
 +                      self.recording.append(recording)
                else:
 -                              simulTimerList = self.session.nav.RecordTimer.record(recording)
 -                              if simulTimerList is not None:  # conflict with other recording
 -                                      name = simulTimerList[1].name
 -                                      name_date = ' '.join((name, strftime('%c', localtime(simulTimerList[1].begin))))
 -                                      print "[TIMER] conflicts with", name_date
 -                                      recording.autoincrease = True   # start with max available length, then increment
 -                                      if recording.setAutoincreaseEnd():
 -                                              self.session.nav.RecordTimer.record(recording)
 -                                              self.recording.append(recording)
 -                                              self.session.open(MessageBox, _("Record time limited due to conflicting timer %s") % name_date, MessageBox.TYPE_INFO)
 -                                      else:
 -                                              self.session.open(MessageBox, _("Couldn't record due to conflicting timer %s") % name, MessageBox.TYPE_INFO)
 -                                      recording.autoincrease = False
 -                              else:
 +                      if len(simulTimerList) > 1: # with other recording
 +                              name = simulTimerList[1].name
 +                              name_date = ' '.join((name, strftime('%c', localtime(simulTimerList[1].begin))))
 +                              print "[TIMER] conflicts with", name_date
 +                              recording.autoincrease = True   # start with max available length, then increment
 +                              if recording.setAutoincreaseEnd():
 +                                      self.session.nav.RecordTimer.record(recording)
                                        self.recording.append(recording)
 +                                      self.session.open(MessageBox, _("Record time limited due to conflicting timer %s") % name_date, MessageBox.TYPE_INFO)
 +                              else:
 +                                      self.session.open(MessageBox, _("Couldn't record due to conflicting timer %s") % name, MessageBox.TYPE_INFO)
 +                      else:
 +                              self.session.open(MessageBox, _("Couldn't record due to invalid service %s") % serviceref, MessageBox.TYPE_INFO)
 +                      recording.autoincrease = False
  
        def isInstantRecordRunning(self):
                print "self.recording:", self.recording
@@@ -1670,11 -1687,126 +1691,11 @@@ class InfoBarAudioSelection
                        })
  
        def audioSelection(self):
 -              service = self.session.nav.getCurrentService()
 -              self.audioTracks = audio = service and service.audioTracks()
 -              n = audio and audio.getNumberOfTracks() or 0
 -              tlist = []
 -              if n > 0:
 -                      self.audioChannel = service.audioChannel()
 -
 -                      idx = 0
 -                      while idx < n:
 -                              cnt = 0
 -                              i = audio.getTrackInfo(idx)
 -                              languages = i.getLanguage().split('/')
 -                              description = i.getDescription()
 -                              language = ""
 -
 -                              for lang in languages:
 -                                      if cnt:
 -                                              language += ' / '
 -                                      if LanguageCodes.has_key(lang):
 -                                              language += LanguageCodes[lang][0]
 -                                      else:
 -                                              language += lang
 -                                      cnt += 1
 -
 -                              if len(description):
 -                                      description += " (" + language + ")"
 -                              else:
 -                                      description = language
 -
 -                              tlist.append((description, idx))
 -                              idx += 1
 -
 -                      tlist.sort(key=lambda x: x[0])
 -
 -                      selectedAudio = self.audioTracks.getCurrentTrack()
 -
 -                      selection = 0
 -
 -                      for x in tlist:
 -                              if x[1] != selectedAudio:
 -                                      selection += 1
 -                              else:
 -                                      break
 -
 -                      availableKeys = []
 -                      usedKeys = []
 -
 -                      if SystemInfo["CanDownmixAC3"]:
 -                              flist = [(_("AC3 downmix") + " - " +(_("Off"), _("On"))[config.av.downmix_ac3.value and 1 or 0], "CALLFUNC", self.changeAC3Downmix),
 -                                      ((_("Left"), _("Stereo"), _("Right"))[self.audioChannel.getCurrentChannel()], "mode")]
 -                              usedKeys.extend(["red", "green"])
 -                              availableKeys.extend(["yellow", "blue"])
 -                              selection += 2
 -                      else:
 -                              flist = [((_("Left"), _("Stereo"), _("Right"))[self.audioChannel.getCurrentChannel()], "mode")]
 -                              usedKeys.extend(["red"])
 -                              availableKeys.extend(["green", "yellow", "blue"])
 -                              selection += 1
 -
 -                      if hasattr(self, "runPlugin"):
 -                              class PluginCaller:
 -                                      def __init__(self, fnc, *args):
 -                                              self.fnc = fnc
 -                                              self.args = args
 -                                      def __call__(self, *args, **kwargs):
 -                                              self.fnc(*self.args)
 -
 -                              Plugins = [ (p.name, PluginCaller(self.runPlugin, p)) for p in plugins.getPlugins(where = PluginDescriptor.WHERE_AUDIOMENU) ]
 -
 -                              for p in Plugins:
 -                                      selection += 1
 -                                      flist.append((p[0], "CALLFUNC", p[1]))
 -                                      if availableKeys:
 -                                              usedKeys.append(availableKeys[0])
 -                                              del availableKeys[0]
 -                                      else:
 -                                              usedKeys.append("")
 -
 -                      flist.append(("--", ""))
 -                      usedKeys.append("")
 -                      selection += 1
 -
 -                      keys = usedKeys + [ "1", "2", "3", "4", "5", "6", "7", "8", "9", "0" ] + [""] * n
 -                      self.session.openWithCallback(self.audioSelected, ChoiceBox, title=_("Select audio track"), list = flist + tlist, selection = selection, keys = keys, skin_name = "AudioTrackSelection")
 -              else:
 -                      del self.audioTracks
 -
 -      def changeAC3Downmix(self, arg):
 -              choicelist = self.session.current_dialog["list"]
 -              list = choicelist.list
 -              t = list[0][1]
 -              list[0][1]=(t[0], t[1], t[2], t[3], t[4], t[5], t[6],
 -                      _("AC3 downmix") + " - " + (_("On"), _("Off"))[config.av.downmix_ac3.value and 1 or 0])
 -              choicelist.setList(list)
 -              if config.av.downmix_ac3.value:
 -                      config.av.downmix_ac3.value = False
 -              else:
 -                      config.av.downmix_ac3.value = True
 -              config.av.downmix_ac3.save()
 -
 -      def audioSelected(self, audio):
 -              if audio is not None:
 -                      if isinstance(audio[1], str):
 -                              if audio[1] == "mode":
 -                                      keys = ["red", "green", "yellow"]
 -                                      selection = self.audioChannel.getCurrentChannel()
 -                                      tlist = ((_("left"), 0), (_("stereo"), 1), (_("right"), 2))
 -                                      self.session.openWithCallback(self.modeSelected, ChoiceBox, title=_("Select audio mode"), list = tlist, selection = selection, keys = keys, skin_name ="AudioModeSelection")
 -                      else:
 -                              del self.audioChannel
 -                              if self.session.nav.getCurrentService().audioTracks().getNumberOfTracks() > audio[1]:
 -                                      self.audioTracks.selectTrack(audio[1])
 -              else:
 -                      del self.audioChannel
 -              del self.audioTracks
 -
 -      def modeSelected(self, mode):
 -              if mode is not None:
 -                      self.audioChannel.selectChannel(mode[1])
 -              del self.audioChannel
 +              from Screens.AudioSelection import AudioSelection
 +              self.session.openWithCallback(self.audioSelected, AudioSelection, infobar=self)
 +              
 +      def audioSelected(self, ret=None):
 +              print "[infobar::audioSelected]", ret
  
  class InfoBarSubserviceSelection:
        def __init__(self):
@@@ -1967,21 -2099,20 +1988,21 @@@ class InfoBarCueSheetSupport
                return True
  
        def jumpPreviousMark(self):
 -              # we add 2 seconds, so if the play position is <2s after
 +              # we add 5 seconds, so if the play position is <5s after
                # the mark, the mark before will be used
                self.jumpPreviousNextMark(lambda x: -x-5*90000, start=True)
  
        def jumpNextMark(self):
 -              if not self.jumpPreviousNextMark(lambda x: x):
 +              if not self.jumpPreviousNextMark(lambda x: x-90000):
                        self.doSeek(-1)
  
        def getNearestCutPoint(self, pts, cmp=abs, start=False):
                # can be optimized
 -              beforecut = False
 +              beforecut = True
                nearest = None
 +              bestdiff = -1
 +              instate = True
                if start:
 -                      beforecut = True
                        bestdiff = cmp(0 - pts)
                        if bestdiff >= 0:
                                nearest = [0, False]
                                beforecut = False
                                if cp[1] == self.CUT_TYPE_IN:  # Start is here, disregard previous marks
                                        diff = cmp(cp[0] - pts)
 -                                      if diff >= 0:
 +                                      if start and diff >= 0:
                                                nearest = cp
                                                bestdiff = diff
                                        else:
                                                nearest = None
 -                      if cp[1] in (self.CUT_TYPE_MARK, self.CUT_TYPE_LAST):
 +                                              bestdiff = -1
 +                      if cp[1] == self.CUT_TYPE_IN:
 +                              instate = True
 +                      elif cp[1] == self.CUT_TYPE_OUT:
 +                              instate = False
 +                      elif cp[1] in (self.CUT_TYPE_MARK, self.CUT_TYPE_LAST):
                                diff = cmp(cp[0] - pts)
 -                              if diff >= 0 and (nearest is None or bestdiff > diff):
 +                              if instate and diff >= 0 and (nearest is None or bestdiff > diff):
                                        nearest = cp
                                        bestdiff = diff
                return nearest