timer_select.patch by Moritz Venn, with minor fixes
authorFelix Domke <tmbinc@elitedvb.net>
Wed, 20 Feb 2008 00:36:00 +0000 (00:36 +0000)
committerFelix Domke <tmbinc@elitedvb.net>
Wed, 20 Feb 2008 00:36:00 +0000 (00:36 +0000)
data/skin_default.xml
lib/python/Screens/LocationBox.py [new file with mode: 0644]
lib/python/Screens/Makefile.am
lib/python/Screens/TimerEntry.py
lib/python/Tools/Directories.py

index 0288337ebd049f0cea2541ad58c0c413886f61ae..d0eabca083a5b3eeadd8dbd42b61d5add175ceba 100644 (file)
@@ -769,9 +769,11 @@ self.instance.move(ePoint(orgpos.x() + (orgwidth - newwidth)/2, orgpos.y()))
        <screen name="TimerEntry" position="90,95" size="560,430" title="Timer entry">
                <widget name="config" position="10,10" size="540,350" scrollbarMode="showOnDemand" />
                <widget name="cancel" pixmap="skin_default/key-red.png" position="10,380" zPosition="1" size="140,40" transparent="1" alphatest="on" />
        <screen name="TimerEntry" position="90,95" size="560,430" title="Timer entry">
                <widget name="config" position="10,10" size="540,350" scrollbarMode="showOnDemand" />
                <widget name="cancel" pixmap="skin_default/key-red.png" position="10,380" zPosition="1" size="140,40" transparent="1" alphatest="on" />
+               <widget name="location" pixmap="skin_default/key-yellow.png" position="260,380" zPosition="1" size="140,40" transparent="1" alphatest="on" />
                <widget name="ok" pixmap="skin_default/key-green.png" position="410,380" zPosition="1" size="140,40" transparent="1" alphatest="on" />
                <widget name="ok" pixmap="skin_default/key-green.png" position="410,380" zPosition="1" size="140,40" transparent="1" alphatest="on" />
-               <widget name="canceltext" position="10,380" zPosition="2" size="140,40" valign="center" halign="center" font="Regular;21" transparent="1" />
-               <widget name="oktext" position="410,380" zPosition="2" size="140,40" valign="center" halign="center" font="Regular;21" transparent="1" />
+               <widget name="canceltext" position="10,380" zPosition="2" size="140,40" valign="center" halign="center" font="Regular;21" backgroundColor="#9f1313" transparent="1" />
+               <widget name="locationtext" position="260,380" zPosition="2" size="140,40" valign="center" halign="center" font="Regular;21" backgroundColor="#a08500" transparent="1" />
+               <widget name="oktext" position="410,380" zPosition="2" size="140,40" valign="center" halign="center" font="Regular;21" backgroundColor="#1f771f" transparent="1" />
        </screen>
        <!-- Timer log -->
        <screen name="TimerLog" position="70,100" size="560,400" title="Timer log">
        </screen>
        <!-- Timer log -->
        <screen name="TimerLog" position="70,100" size="560,400" title="Timer log">
diff --git a/lib/python/Screens/LocationBox.py b/lib/python/Screens/LocationBox.py
new file mode 100644 (file)
index 0000000..b15fece
--- /dev/null
@@ -0,0 +1,292 @@
+#
+# Generic Screen to select a path/filename combination
+#
+
+# GUI (Screens)
+from Screens.Screen import Screen
+from Screens.MessageBox import MessageBox
+from Screens.InputBox import InputBox
+
+# Generic
+from Tools.BoundFunction import boundFunction
+
+# Quickselect
+from Tools.NumericalTextInput import NumericalTextInput
+
+# GUI (Components)
+from Components.ActionMap import NumberActionMap
+from Components.Label import Label
+from Components.Pixmap import Pixmap
+from Components.Button import Button
+from Components.FileList import FileList
+
+# Timer
+from enigma import eTimer
+
+class LocationBox(Screen, NumericalTextInput):
+       """Simple Class similar to MessageBox / ChoiceBox but used to choose a folder/pathname combination"""
+
+       skin = """<screen name="LocationBox" position="100,130" size="540,340" >
+                       <widget name="text" position="0,2" size="540,22" font="Regular;22" />
+                       <widget name="filelist" position="0,25" size="540,235" />
+                       <widget name="target" position="0,260" size="540,40" valign="center" font="Regular;22" />
+                       <widget name="yellow" position="260,300" zPosition="1" size="140,40" pixmap="skin_default/key-yellow.png" transparent="1" alphatest="on" />
+                       <widget name="key_yellow" position="260,300" zPosition="2" size="140,40" halign="center" valign="center" font="Regular;22" transparent="1" shadowColor="black" shadowOffset="-1,-1" />
+                       <widget name="green" position="400,300" zPosition="1" size="140,40" pixmap="skin_default/key-green.png" transparent="1" alphatest="on" />
+                       <widget name="key_green" position="400,300" zPosition="2" size="140,40" halign="center" valign="center" font="Regular;22" transparent="1" shadowColor="black" shadowOffset="-1,-1" />
+               </screen>"""
+
+       def __init__(self, session, text = "", filename = "", currDir = None, windowTitle = _("Select Location"), minFree = None):
+               # Init parents
+               Screen.__init__(self, session)
+               NumericalTextInput.__init__(self, handleTimeout = False)
+
+               # Set useable chars
+               self.setUseableChars(u'1234567890abcdefghijklmnopqrstuvwxyz')
+
+               # Quickselect Timer
+               self.qs_timer = eTimer()
+               self.qs_timer.callback.append(self.timeout)
+               self.qs_timer_type = 0
+
+               # Initialize Quickselect
+               self.curr_pos = -1
+               self.quickselect = ""
+
+               # Set Text
+               self["text"] = Label(text)
+
+               # Save parameters locally
+               self.text = text
+               self.filename = filename
+               self.minFree = minFree
+
+               # Initialize FileList
+               self["filelist"] = FileList(currDir, showDirectories = True, showFiles = False)
+
+               # Buttons
+               self["key_green"] = Button(_("Confirm"))
+               self["key_yellow"] = Button(_("Rename"))
+
+               # Background for Buttons
+               self["green"] = Pixmap()
+               self["yellow"] = Pixmap()
+
+               # Initialize Target
+               self["target"] = Label()
+
+               # Custom Action Handler
+               class LocationBoxActionMap(NumberActionMap):
+                       def __init__(self, box, contexts = [ ], actions = { }, prio=0):                                                                                                                                                                                                                                    
+                               NumberActionMap.__init__(self, contexts, actions, prio)
+                               self.box = box
+
+                       def action(self, contexts, action):
+                               # Reset Quickselect
+                               self.box.timeout(force = True)
+
+                               return NumberActionMap.action(self, contexts, action)
+
+               # Actions that will reset quickselect
+               self["actions"] = LocationBoxActionMap(self, ["WizardActions", "ColorActions"],
+               {
+                       "ok": self.ok,
+                       "back": self.cancel,
+                       "green": self.select,
+                       "yellow": self.changeName,
+                       "left": self.left,
+                       "right": self.right,
+                       "up": self.up,
+                       "down": self.down,
+               }, -2)
+
+               # Actions used by quickselect
+               self["NumberActions"] = NumberActionMap(["NumberActions"],
+               {
+                       "1": self.keyNumberGlobal,
+                       "2": self.keyNumberGlobal,
+                       "3": self.keyNumberGlobal,
+                       "4": self.keyNumberGlobal,
+                       "5": self.keyNumberGlobal,
+                       "6": self.keyNumberGlobal,
+                       "7": self.keyNumberGlobal,
+                       "8": self.keyNumberGlobal,
+                       "9": self.keyNumberGlobal,
+                       "0": self.keyNumberGlobal
+               })
+
+               # Run some functions when shown
+               self.onShown.extend([
+                       boundFunction(self.setTitle, windowTitle),
+                       self.updateTarget,
+                       self.showHideRename
+               ])
+               # Make sure we remove our callback
+               self.onClose.append(self.disableTimer)
+
+       def disableTimer(self):
+               self.qs_timer.callback.remove(self.timeout)
+
+       def showHideRename(self):
+               # Don't allow renaming when filename is empty
+               if self.filename == "":
+                       self["yellow"].hide()
+                       self["key_yellow"].hide()
+
+       def up(self):
+               self["filelist"].up()
+
+       def down(self):
+               self["filelist"].down()
+
+       def left(self):
+               self["filelist"].pageUp()
+
+       def right(self):
+               self["filelist"].pageDown()
+
+       def ok(self):
+               if self["filelist"].canDescent():
+                       self["filelist"].descent()
+                       self.updateTarget()
+
+       def cancel(self):
+               self.close(None)
+
+       def selectConfirmed(self, res):
+               if res: 
+                       self.close(''.join([self["filelist"].getCurrentDirectory(), self.filename]))
+
+       def select(self):
+               # Do nothing unless current Directory is valid
+               if self["filelist"].getCurrentDirectory() is not None:
+                       # Check if we need to have a minimum of free Space available
+                       if self.minFree is not None:
+                               # Try to read fs stats
+                               try:
+                                       from os import statvfs
+
+                                       s = statvfs(self["filelist"].getCurrentDirectory())
+                                       if (s.f_bavail * s.f_bsize) / 1000000 > self.minFree:
+                                               # Automatically confirm if we have enough free disk Space available
+                                               return self.selectConfirmed(True)
+                               except OSError:
+                                       pass
+
+                               # Ask User if he really wants to select this folder
+                               self.session.openWithCallback(
+                                       self.selectConfirmed,
+                                       MessageBox,
+                                       _("There might not be enough Space on the selected Partition.\nDo you really want to continue?"),
+                                       type = MessageBox.TYPE_YESNO
+                               )
+                       # No minimum free Space means we can safely close
+                       else:   
+                               self.selectConfirmed(True)
+
+       def changeName(self):
+               if self.filename != "":
+                       # TODO: Add Information that changing extension is bad? disallow?
+                       # TODO: decide if using an inputbox is ok - we could also keep this in here
+                       self.session.openWithCallback(
+                               self.nameChanged,
+                               InputBox,
+                               title = _("Please enter a new filename"),
+                               text = self.filename
+                       )
+
+       def nameChanged(self, res):
+               if res is not None:
+                       if len(res):
+                               self.filename = res
+                               self.updateTarget()
+                       else:
+                               self.session.open(
+                                       MessageBox,
+                                       _("An empty filename is illegal."),
+                                       type = MessageBox.TYPE_ERROR,
+                                       timeout = 5
+                               )
+
+       def updateTarget(self):
+               # Write Combination of Folder & Filename when Folder is valid
+               if self["filelist"].getCurrentDirectory() is not None:
+                       self["target"].setText(''.join([self["filelist"].getCurrentDirectory(), self.filename]))
+               # Warning else
+               else:
+                       self["target"].setText(_("Invalid Location"))
+
+       def keyNumberGlobal(self, number):
+               # Cancel Timeout
+               self.qs_timer.stop()
+
+               # See if another key was pressed before
+               if number != self.lastKey:
+                       # Reset lastKey again so NumericalTextInput triggers its keychange
+                       self.nextKey()
+
+                       # Try to select what was typed
+                       self.selectByStart()
+
+                       # Increment position
+                       self.curr_pos += 1
+
+               # Get char and append to text
+               char = self.getKey(number)
+               self.quickselect = self.quickselect[:self.curr_pos] + unicode(char)
+
+               # Start Timeout
+               self.qs_timer_type = 0
+               self.qs_timer.start(1000, 1)
+
+       def selectByStart(self):
+               # Don't do anything on initial call
+               if not len(self.quickselect):
+                       return
+
+               # Don't select if no dir
+               if self["filelist"].getCurrentDirectory():
+                       # TODO: implement proper method in Components.FileList
+                       files = self["filelist"].getFileList()
+
+                       # Initialize index
+                       idx = 0
+
+                       # We select by filename which is absolute
+                       lookfor = self["filelist"].getCurrentDirectory() + self.quickselect
+
+                       # Select file starting with generated text
+                       for file in files:
+                               if file[0][0] and file[0][0].lower().startswith(lookfor):
+                                       self["filelist"].instance.moveSelectionTo(idx)
+                                       break
+                               idx += 1
+
+       def timeout(self, force = False):
+               # Timeout Key
+               if not force and self.qs_timer_type == 0:
+                       # Try to select what was typed
+                       self.selectByStart()
+
+                       # Reset Key
+                       self.lastKey = -1
+
+                       # Change type
+                       self.qs_timer_type = 1
+
+                       # Start timeout again
+                       self.qs_timer.start(1000, 1)
+               # Timeout Quickselect
+               else:
+                       # Eventually stop Timer
+                       self.qs_timer.stop()
+
+                       # Invalidate
+                       self.lastKey = -1
+                       self.curr_pos = -1
+                       self.quickselect = ""
+
+       def __repr__(self):
+               return str(type(self)) + "(" + self.text + ")"
+
index aeff31513936ccd710e61826b8ed364e3b5d40df..068ce4427fb799ccdc57681c43625fe440ffb6b4 100644 (file)
@@ -12,4 +12,4 @@ install_PYTHON = \
        Console.py InputBox.py ChoiceBox.py SimpleSummary.py ImageWizard.py \
        TimerSelection.py PictureInPicture.py TimeDateInput.py \
        SubtitleDisplay.py SubservicesQuickzap.py ParentalControlSetup.py NumericalTextInputHelpDialog.py \
        Console.py InputBox.py ChoiceBox.py SimpleSummary.py ImageWizard.py \
        TimerSelection.py PictureInPicture.py TimeDateInput.py \
        SubtitleDisplay.py SubservicesQuickzap.py ParentalControlSetup.py NumericalTextInputHelpDialog.py \
-       SleepTimerEdit.py Ipkg.py RdsDisplay.py Globals.py SessionGlobals.py
+       SleepTimerEdit.py Ipkg.py RdsDisplay.py Globals.py SessionGlobals.py LocationBox.py
index 3541d36d07fa3196cc1dae08f29bc9890a519f50..d11c5c2a766228ce855d851c5bc1269c76f6af87 100644 (file)
@@ -1,7 +1,8 @@
 from Screen import Screen
 from Screen import Screen
+from LocationBox import LocationBox
 import ChannelSelection
 from ServiceReference import ServiceReference
 import ChannelSelection
 from ServiceReference import ServiceReference
-from Components.config import ConfigSelection, ConfigText, ConfigSubList, ConfigDateTime, ConfigClock, ConfigYesNo, getConfigListEntry
+from Components.config import config, ConfigSelection, ConfigText, ConfigSubList, ConfigDateTime, ConfigClock, ConfigYesNo, getConfigListEntry
 from Components.ActionMap import NumberActionMap
 from Components.ConfigList import ConfigListScreen
 from Components.MenuList import MenuList
 from Components.ActionMap import NumberActionMap
 from Components.ConfigList import ConfigListScreen
 from Components.MenuList import MenuList
@@ -25,22 +26,32 @@ class TimerEntry(Screen, ConfigListScreen):
                
                self["oktext"] = Label(_("OK"))
                self["canceltext"] = Label(_("Cancel"))
                
                self["oktext"] = Label(_("OK"))
                self["canceltext"] = Label(_("Cancel"))
+               self["locationtext"] = Label(_("Choose Location"))
                self["ok"] = Pixmap()
                self["cancel"] = Pixmap()
                self["ok"] = Pixmap()
                self["cancel"] = Pixmap()
+               self["location"] = Pixmap()
 
                self.createConfig()
 
 
                self.createConfig()
 
-               self["actions"] = NumberActionMap(["SetupActions"],
+               self["actions"] = NumberActionMap(["SetupActions", "ColorActions"],
                {
                        "ok": self.keySelect,
                        "save": self.keyGo,
                        "cancel": self.keyCancel,
                {
                        "ok": self.keySelect,
                        "save": self.keyGo,
                        "cancel": self.keyCancel,
+                       "yellow": self.selectPath,
                }, -2)
 
                self.list = []
                ConfigListScreen.__init__(self, self.list, session = session)
                self.createSetup("config")
 
                }, -2)
 
                self.list = []
                ConfigListScreen.__init__(self, self.list, session = session)
                self.createSetup("config")
 
+               self.onLayoutFinish.append(self.handleLocation)
+
+       def handleLocation(self):
+               if config.usage.setup_level.index < 2: # -expert
+                       self["locationtext"].hide()
+                       self["location"].hide()
+
        def createConfig(self):
                        justplay = self.timer.justplay
                                
        def createConfig(self):
                        justplay = self.timer.justplay
                                
@@ -95,6 +106,8 @@ class TimerEntry(Screen, ConfigListScreen):
                        self.timerentry_enddate = ConfigDateTime(default = self.timer.end, formatstring =  _("%d.%B %Y"), increment = 86400)
                        self.timerentry_endtime = ConfigClock(default = self.timer.end)
 
                        self.timerentry_enddate = ConfigDateTime(default = self.timer.end, formatstring =  _("%d.%B %Y"), increment = 86400)
                        self.timerentry_endtime = ConfigClock(default = self.timer.end)
 
+                       self.timerentry_dirname = ConfigSelection(choices = [self.timer.dirname or "/hdd/movie/"])
+
                        self.timerentry_repeatedbegindate = ConfigDateTime(default = self.timer.repeatedbegindate, formatstring = _("%d.%B %Y"), increment = 86400)
 
                        self.timerentry_weekday = ConfigSelection(default = weekday_table[weekday], choices = [("mon",_("Monday")), ("tue", _("Tuesday")), ("wed",_("Wednesday")), ("thu", _("Thursday")), ("fri", _("Friday")), ("sat", _("Saturday")), ("sun", _("Sunday"))])
                        self.timerentry_repeatedbegindate = ConfigDateTime(default = self.timer.repeatedbegindate, formatstring = _("%d.%B %Y"), increment = 86400)
 
                        self.timerentry_weekday = ConfigSelection(default = weekday_table[weekday], choices = [("mon",_("Monday")), ("tue", _("Tuesday")), ("wed",_("Wednesday")), ("thu", _("Thursday")), ("fri", _("Friday")), ("sat", _("Saturday")), ("sun", _("Sunday"))])
@@ -177,6 +190,8 @@ class TimerEntry(Screen, ConfigListScreen):
                                self.list.append(getConfigListEntry(_("EndTime"), self.timerentry_endtime))
 
                if self.timerentry_justplay.value != "zap":
                                self.list.append(getConfigListEntry(_("EndTime"), self.timerentry_endtime))
 
                if self.timerentry_justplay.value != "zap":
+                       if config.usage.setup_level.index >= 2: # expert+
+                               self.list.append(getConfigListEntry(_("Location"), self.timerentry_dirname))
                        self.list.append(getConfigListEntry(_("After event"), self.timerentry_afterevent))
 
                self.channelEntry = getConfigListEntry(_("Channel"), self.timerentry_service)
                        self.list.append(getConfigListEntry(_("After event"), self.timerentry_afterevent))
 
                self.channelEntry = getConfigListEntry(_("Channel"), self.timerentry_service)
@@ -255,6 +270,12 @@ class TimerEntry(Screen, ConfigListScreen):
                self.timer.afterEvent = {"nothing": AFTEREVENT.NONE, "deepstandby": AFTEREVENT.DEEPSTANDBY, "standby": AFTEREVENT.STANDBY}[self.timerentry_afterevent.value]
                self.timer.service_ref = self.timerentry_service_ref
 
                self.timer.afterEvent = {"nothing": AFTEREVENT.NONE, "deepstandby": AFTEREVENT.DEEPSTANDBY, "standby": AFTEREVENT.STANDBY}[self.timerentry_afterevent.value]
                self.timer.service_ref = self.timerentry_service_ref
 
+               # TODO: fix that thing with none (this might as well just be ignored)
+               if self.timerentry_dirname.value == "/hdd/movie/":
+                       self.timer.dirname = None
+               else:
+                       self.timer.dirname = self.timerentry_dirname.value
+
                if self.timerentry_type.value == "once":
                        self.timer.begin, self.timer.end = self.getBeginEnd()
                if self.timerentry_type.value == "repeated":
                if self.timerentry_type.value == "once":
                        self.timer.begin, self.timer.end = self.getBeginEnd()
                if self.timerentry_type.value == "repeated":
@@ -313,7 +334,25 @@ class TimerEntry(Screen, ConfigListScreen):
 
        def keyCancel(self):
                self.close((False,))
 
        def keyCancel(self):
                self.close((False,))
-               
+
+       def selectPath(self):
+               if config.usage.setup_level.index < 2: #-expert
+                       return
+               self.session.openWithCallback(
+                       self.pathSelected,
+                       LocationBox,
+                       text = _("Choose target folder"),
+                       filename = "",
+                       currDir = None, # TODO: fix FileList to correctly determine mountpoint
+                       minFree = 100
+               )
+
+       def pathSelected(self, res):
+               if res is not None:
+                       self.timerentry_dirname.choices.append(res)
+                       self.timerentry_dirname.description[res] = res
+                       self.timerentry_dirname.value = res
+
 class TimerLog(Screen):
        def __init__(self, session, timer):
                Screen.__init__(self, session)
 class TimerLog(Screen):
        def __init__(self, session, timer):
                Screen.__init__(self, session)
index 975d3ade64f1f746a8c9fc976b42771f4d14d2ea..0096f3f4426d90f29eb12c78dcc00571967fddbd 100644 (file)
@@ -114,8 +114,8 @@ def fileExists(f):
                exists = 1
        return exists
 
                exists = 1
        return exists
 
-def getRecordingFilename(basename):
-               # filter out non-allowed characters
+def getRecordingFilename(basename, dirname = None):
+       # filter out non-allowed characters
        non_allowed_characters = "/.\\:*?<>|\""
        filename = ""
        
        non_allowed_characters = "/.\\:*?<>|\""
        filename = ""
        
@@ -125,7 +125,10 @@ def getRecordingFilename(basename):
                if c in non_allowed_characters:
                        c = "_"
                filename += c
                if c in non_allowed_characters:
                        c = "_"
                filename += c
-       
+
+       if dirname is not None:
+               filename = ''.join([dirname, filename])
+
        i = 0
        while True:
                path = resolveFilename(SCOPE_HDD, filename)
        i = 0
        while True:
                path = resolveFilename(SCOPE_HDD, filename)