allow burning DVDs with multiple titles where playback automatically jumps to the...
[enigma2.git] / lib / python / Screens / LocationBox.py
index b15fece5112dca1c1ade6849998295eeb4b50a54..e41601a94147e5b23e04bfe7e14c533ea37e4f65 100644 (file)
@@ -6,40 +6,53 @@
 from Screens.Screen import Screen
 from Screens.MessageBox import MessageBox
 from Screens.InputBox import InputBox
 from Screens.Screen import Screen
 from Screens.MessageBox import MessageBox
 from Screens.InputBox import InputBox
+from Screens.HelpMenu import HelpableScreen
+from Screens.ChoiceBox import ChoiceBox
 
 # Generic
 from Tools.BoundFunction import boundFunction
 
 # Generic
 from Tools.BoundFunction import boundFunction
+from Tools.Directories import *
+from Components.config import config
+import os
 
 # Quickselect
 from Tools.NumericalTextInput import NumericalTextInput
 
 # GUI (Components)
 
 # Quickselect
 from Tools.NumericalTextInput import NumericalTextInput
 
 # GUI (Components)
-from Components.ActionMap import NumberActionMap
+from Components.ActionMap import NumberActionMap, HelpableActionMap
 from Components.Label import Label
 from Components.Pixmap import Pixmap
 from Components.Button import Button
 from Components.FileList import FileList
 from Components.Label import Label
 from Components.Pixmap import Pixmap
 from Components.Button import Button
 from Components.FileList import FileList
+from Components.MenuList import MenuList
 
 # Timer
 from enigma import eTimer
 
 
 # Timer
 from enigma import eTimer
 
-class LocationBox(Screen, NumericalTextInput):
+class LocationBox(Screen, NumericalTextInput, HelpableScreen):
        """Simple Class similar to MessageBox / ChoiceBox but used to choose a folder/pathname combination"""
 
        """Simple Class similar to MessageBox / ChoiceBox but used to choose a folder/pathname combination"""
 
-       skin = """<screen name="LocationBox" position="100,130" size="540,340" >
+       skin = """<screen name="LocationBox" position="100,75" size="540,460" >
                        <widget name="text" position="0,2" size="540,22" font="Regular;22" />
                        <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" />
+                       <widget name="target" position="0,23" size="540,22" valign="center" font="Regular;22" />
+                       <widget name="filelist" position="0,55" zPosition="1" size="540,210" scrollbarMode="showOnDemand" selectionDisabled="1" />
+                       <widget name="textbook" position="0,272" size="540,22" font="Regular;22" />
+                       <widget name="booklist" position="5,302" zPosition="2" size="535,100" scrollbarMode="showOnDemand" />
+                       <widget name="red" position="0,415" zPosition="1" size="135,40" pixmap="skin_default/buttons/red.png" transparent="1" alphatest="on" />
+                       <widget name="key_red" position="0,415" zPosition="2" size="135,40" halign="center" valign="center" font="Regular;22" transparent="1" shadowColor="black" shadowOffset="-1,-1" />   
+                       <widget name="green" position="135,415" zPosition="1" size="135,40" pixmap="skin_default/buttons/green.png" transparent="1" alphatest="on" />
+                       <widget name="key_green" position="135,415" zPosition="2" size="135,40" halign="center" valign="center" font="Regular;22" transparent="1" shadowColor="black" shadowOffset="-1,-1" />
+                       <widget name="yellow" position="270,415" zPosition="1" size="135,40" pixmap="skin_default/buttons/yellow.png" transparent="1" alphatest="on" />
+                       <widget name="key_yellow" position="270,415" zPosition="2" size="135,40" halign="center" valign="center" font="Regular;22" transparent="1" shadowColor="black" shadowOffset="-1,-1" />
+                       <widget name="blue" position="405,415" zPosition="1" size="135,40" pixmap="skin_default/buttons/blue.png" transparent="1" alphatest="on" />
+                       <widget name="key_blue" position="405,415" zPosition="2" size="135,40" halign="center" valign="center" font="Regular;22" transparent="1" shadowColor="black" shadowOffset="-1,-1" />            
                </screen>"""
 
                </screen>"""
 
-       def __init__(self, session, text = "", filename = "", currDir = None, windowTitle = _("Select Location"), minFree = None):
+       def __init__(self, session, text = "", filename = "", currDir = None, bookmarks = None, userMode = False, windowTitle = _("Select Location"), minFree = None, autoAdd = False, editDir = False, inhibitDirs = [], inhibitMounts = []):
                # Init parents
                Screen.__init__(self, session)
                NumericalTextInput.__init__(self, handleTimeout = False)
                # Init parents
                Screen.__init__(self, session)
                NumericalTextInput.__init__(self, handleTimeout = False)
+               HelpableScreen.__init__(self)
 
                # Set useable chars
                self.setUseableChars(u'1234567890abcdefghijklmnopqrstuvwxyz')
 
                # Set useable chars
                self.setUseableChars(u'1234567890abcdefghijklmnopqrstuvwxyz')
@@ -55,50 +68,84 @@ class LocationBox(Screen, NumericalTextInput):
 
                # Set Text
                self["text"] = Label(text)
 
                # Set Text
                self["text"] = Label(text)
+               self["textbook"] = Label(_("Bookmarks"))
 
                # Save parameters locally
                self.text = text
                self.filename = filename
                self.minFree = minFree
 
                # Save parameters locally
                self.text = text
                self.filename = filename
                self.minFree = minFree
+               self.realBookmarks = bookmarks
+               self.bookmarks = bookmarks and bookmarks.value[:] or []
+               self.userMode = userMode
+               self.autoAdd = autoAdd
+               self.editDir = editDir
+               self.inhibitDirs = inhibitDirs
 
                # Initialize FileList
 
                # Initialize FileList
-               self["filelist"] = FileList(currDir, showDirectories = True, showFiles = False)
+               self["filelist"] = FileList(currDir, showDirectories = True, showFiles = False, inhibitMounts = inhibitMounts, inhibitDirs = inhibitDirs)
+
+               # Initialize BookList
+               self["booklist"] = MenuList(self.bookmarks)
 
                # Buttons
 
                # Buttons
-               self["key_green"] = Button(_("Confirm"))
+               self["key_green"] = Button(_("OK"))
                self["key_yellow"] = Button(_("Rename"))
                self["key_yellow"] = Button(_("Rename"))
+               self["key_blue"] = Button(_("Remove Bookmark"))
+               self["key_red"] = Button(_("Cancel"))
 
                # Background for Buttons
                self["green"] = Pixmap()
                self["yellow"] = Pixmap()
 
                # Background for Buttons
                self["green"] = Pixmap()
                self["yellow"] = Pixmap()
+               self["blue"] = Pixmap()
+               self["red"] = Pixmap()
 
                # Initialize Target
                self["target"] = Label()
 
 
                # Initialize Target
                self["target"] = Label()
 
+               if self.userMode:
+                       self.usermodeOn()
+
                # Custom Action Handler
                # Custom Action Handler
-               class LocationBoxActionMap(NumberActionMap):
-                       def __init__(self, box, contexts = [ ], actions = { }, prio=0):                                                                                                                                                                                                                                    
-                               NumberActionMap.__init__(self, contexts, actions, prio)
-                               self.box = box
+               class LocationBoxActionMap(HelpableActionMap):
+                       def __init__(self, parent, context, actions = { }, prio=0):
+                               HelpableActionMap.__init__(self, parent, context, actions, prio)
+                               self.box = parent
 
                        def action(self, contexts, action):
                                # Reset Quickselect
                                self.box.timeout(force = True)
 
 
                        def action(self, contexts, action):
                                # Reset Quickselect
                                self.box.timeout(force = True)
 
-                               return NumberActionMap.action(self, contexts, action)
+                               return HelpableActionMap.action(self, contexts, action)
 
                # Actions that will reset quickselect
 
                # 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)
+               self["WizardActions"] = LocationBoxActionMap(self, "WizardActions",
+                       {
+                               "left": self.left,
+                               "right": self.right,
+                               "up": self.up,
+                               "down": self.down,
+                               "ok": (self.ok, _("select")),
+                               "back": (self.cancel, _("cancel")),
+                       }, -2)
+
+               self["ColorActions"] = LocationBoxActionMap(self, "ColorActions",
+                       {
+                               "red": self.cancel,
+                               "green": self.select,
+                               "yellow": self.changeName,
+                               "blue": self.addRemoveBookmark,
+                       }, -2)
+
+               self["EPGSelectActions"] = LocationBoxActionMap(self, "EPGSelectActions",
+                       {
+                               "prevBouquet": (self.switchToBookList, _("switch to bookmarks")),
+                               "nextBouquet": (self.switchToFileList, _("switch to filelist")),
+                       }, -2)
+
+               self["MenuActions"] = LocationBoxActionMap(self, "MenuActions",
+                       {
+                               "menu": (self.showMenu, _("menu")),
+                       }, -2)
 
                # Actions used by quickselect
                self["NumberActions"] = NumberActionMap(["NumberActions"],
 
                # Actions used by quickselect
                self["NumberActions"] = NumberActionMap(["NumberActions"],
@@ -119,55 +166,186 @@ class LocationBox(Screen, NumericalTextInput):
                self.onShown.extend([
                        boundFunction(self.setTitle, windowTitle),
                        self.updateTarget,
                self.onShown.extend([
                        boundFunction(self.setTitle, windowTitle),
                        self.updateTarget,
-                       self.showHideRename
+                       self.showHideRename,
                ])
                ])
+
+               self.onLayoutFinish.append(self.switchToFileListOnStart)
  
                # Make sure we remove our callback
                self.onClose.append(self.disableTimer)
 
  
                # Make sure we remove our callback
                self.onClose.append(self.disableTimer)
 
+       def switchToFileListOnStart(self):
+               if self.realBookmarks and self.realBookmarks.value:
+                       self.currList = "booklist"
+                       currDir = self["filelist"].current_directory
+                       if currDir in self.bookmarks:
+                               self["booklist"].moveToIndex(self.bookmarks.index(currDir))
+               else:
+                       self.switchToFileList()
+
        def disableTimer(self):
                self.qs_timer.callback.remove(self.timeout)
 
        def showHideRename(self):
                # Don't allow renaming when filename is empty
                if self.filename == "":
        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()
 
                        self["key_yellow"].hide()
 
+       def switchToFileList(self):
+               if not self.userMode:
+                       self.currList = "filelist"
+                       self["filelist"].selectionEnabled(1)
+                       self["booklist"].selectionEnabled(0)
+                       self["key_blue"].text = _("Add Bookmark")
+                       self.updateTarget()
+
+       def switchToBookList(self):
+               self.currList = "booklist"
+               self["filelist"].selectionEnabled(0)
+               self["booklist"].selectionEnabled(1)
+               self["key_blue"].text = _("Remove Bookmark")
+               self.updateTarget()
+
+       def addRemoveBookmark(self):
+               if self.currList == "filelist":
+                       # add bookmark
+                       folder = self["filelist"].getSelection()[0]
+                       if folder is not None and not folder in self.bookmarks:
+                               self.bookmarks.append(folder)
+                               self.bookmarks.sort()
+                               self["booklist"].setList(self.bookmarks)
+               else:
+                       # remove bookmark
+                       if not self.userMode:
+                               name = self["booklist"].getCurrent()
+                               self.session.openWithCallback(
+                                       boundFunction(self.removeBookmark, name),
+                                       MessageBox,
+                                       _("Do you really want to remove your bookmark of %s?") % (name),
+                               )
+
+       def removeBookmark(self, name, ret):
+               if not ret:
+                       return
+               if name in self.bookmarks:
+                       self.bookmarks.remove(name)
+                       self["booklist"].setList(self.bookmarks)
+
+       def createDir(self):
+               if self["filelist"].current_directory != None:
+                       self.session.openWithCallback(
+                               self.createDirCallback,
+                               InputBox,
+                               title = _("Please enter name of the new directory"),
+                               text = ""
+                       )
+
+       def createDirCallback(self, res):
+               if res is not None and len(res):
+                       path = os.path.join(self["filelist"].current_directory, res)
+                       if not pathExists(path):
+                               if not createDir(path):
+                                       self.session.open(
+                                               MessageBox,
+                                               _("Creating directory %s failed.") % (path),
+                                               type = MessageBox.TYPE_ERROR,
+                                               timeout = 5
+                                       )
+                               self["filelist"].refresh()
+                       else:
+                               self.session.open(
+                                       MessageBox,
+                                       _("The path %s already exists.") % (path),
+                                       type = MessageBox.TYPE_ERROR,
+                                       timeout = 5
+                               )
+
+       def removeDir(self):
+               sel = self["filelist"].getSelection()
+               if sel and pathExists(sel[0]):
+                       self.session.openWithCallback(
+                               boundFunction(self.removeDirCallback, sel[0]),
+                               MessageBox,
+                               _("Do you really want to remove directory %s from the disk?") % (sel[0]),
+                               type = MessageBox.TYPE_YESNO
+                       )
+               else:
+                       self.session.open(
+                               MessageBox,
+                               _("Invalid directory selected: %s") % (sel[0]),
+                               type = MessageBox.TYPE_ERROR,
+                               timeout = 5
+                       )
+
+       def removeDirCallback(self, name, res):
+               if res:
+                       if not removeDir(name):
+                               self.session.open(
+                                       MessageBox,
+                                       _("Removing directory %s failed. (Maybe not empty.)") % (name),
+                                       type = MessageBox.TYPE_ERROR,
+                                       timeout = 5
+                               )
+                       else:
+                               self["filelist"].refresh()
+                               self.removeBookmark(name, True)
+
        def up(self):
        def up(self):
-               self["filelist"].up()
+               self[self.currList].up()
+               self.updateTarget()
 
        def down(self):
 
        def down(self):
-               self["filelist"].down()
+               self[self.currList].down()
+               self.updateTarget()
 
        def left(self):
 
        def left(self):
-               self["filelist"].pageUp()
+               self[self.currList].pageUp()
+               self.updateTarget()
 
        def right(self):
 
        def right(self):
-               self["filelist"].pageDown()
+               self[self.currList].pageDown()
+               self.updateTarget()
 
        def ok(self):
 
        def ok(self):
-               if self["filelist"].canDescent():
-                       self["filelist"].descent()
-                       self.updateTarget()
+               if self.currList == "filelist":
+                       if self["filelist"].canDescent():
+                               self["filelist"].descent()
+                               self.updateTarget()
+               else:
+                       self.select()
 
        def cancel(self):
                self.close(None)
 
 
        def cancel(self):
                self.close(None)
 
-       def selectConfirmed(self, res):
-               if res: 
-                       self.close(''.join([self["filelist"].getCurrentDirectory(), self.filename]))
+       def getPreferredFolder(self):
+               if self.currList == "filelist":
+                       # XXX: We might want to change this for parent folder...
+                       return self["filelist"].getSelection()[0]
+               else:
+                       return self["booklist"].getCurrent()
+
+       def selectConfirmed(self, ret):
+               if ret:
+                       ret = ''.join([self.getPreferredFolder(), self.filename])
+                       if self.realBookmarks:
+                               if self.autoAdd and not ret in self.bookmarks:
+                                       self.bookmarks.append(self.getPreferredFolder())
+                                       self.bookmarks.sort()
+
+                               if self.bookmarks != self.realBookmarks.value:
+                                       self.realBookmarks.value = self.bookmarks
+                                       self.realBookmarks.save()
+                       self.close(ret)
 
        def select(self):
 
        def select(self):
+               currentFolder = self.getPreferredFolder()
                # Do nothing unless current Directory is valid
                # Do nothing unless current Directory is valid
-               if self["filelist"].getCurrentDirectory() is not None:
+               if currentFolder 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:
                        # 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())
+                                       s = os.statvfs(currentFolder)
                                        if (s.f_bavail * s.f_bsize) / 1000000 > self.minFree:
                                                # Automatically confirm if we have enough free disk Space available
                                                return self.selectConfirmed(True)
                                        if (s.f_bavail * s.f_bsize) / 1000000 > self.minFree:
                                                # Automatically confirm if we have enough free disk Space available
                                                return self.selectConfirmed(True)
@@ -182,13 +360,12 @@ class LocationBox(Screen, NumericalTextInput):
                                        type = MessageBox.TYPE_YESNO
                                )
                        # No minimum free Space means we can safely close
                                        type = MessageBox.TYPE_YESNO
                                )
                        # No minimum free Space means we can safely close
-                       else:   
+                       else:
                                self.selectConfirmed(True)
 
        def changeName(self):
                if self.filename != "":
                        # TODO: Add Information that changing extension is bad? disallow?
                                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,
                        self.session.openWithCallback(
                                self.nameChanged,
                                InputBox,
@@ -211,12 +388,42 @@ class LocationBox(Screen, NumericalTextInput):
 
        def updateTarget(self):
                # Write Combination of Folder & Filename when Folder is valid
 
        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
+               currFolder = self.getPreferredFolder()
+               if currFolder is not None:
+                       self["target"].setText(''.join([currFolder, self.filename]))
+               # Display a Warning otherwise
                else:
                        self["target"].setText(_("Invalid Location"))
 
                else:
                        self["target"].setText(_("Invalid Location"))
 
+       def showMenu(self):
+               if not self.userMode and self.realBookmarks:
+                       menu = []
+                       if self.currList == "filelist":
+                               menu.append((_("switch to bookmarks"), self.switchToBookList))
+                               menu.append((_("add bookmark"), self.addRemoveBookmark))
+                               if self.editDir:
+                                       menu.append((_("create directory"), self.createDir))
+                                       menu.append((_("remove directory"), self.removeDir))
+                       else:
+                               menu.append((_("switch to filelist"), self.switchToFileList))
+                               menu.append((_("remove bookmark"), self.addRemoveBookmark))
+
+                       self.session.openWithCallback(
+                               self.menuCallback,
+                               ChoiceBox,
+                               title = "",
+                               list = menu
+                       )
+
+       def menuCallback(self, choice):
+               if choice:
+                       choice[1]()
+                       
+       def usermodeOn(self):
+               self.switchToBookList()
+               self["filelist"].hide()
+               self["key_blue"].hide()
+
        def keyNumberGlobal(self, number):
                # Cancel Timeout
                self.qs_timer.stop()
        def keyNumberGlobal(self, number):
                # Cancel Timeout
                self.qs_timer.stop()
@@ -290,3 +497,7 @@ class LocationBox(Screen, NumericalTextInput):
        def __repr__(self):
                return str(type(self)) + "(" + self.text + ")"
 
        def __repr__(self):
                return str(type(self)) + "(" + self.text + ")"
 
+class MovieLocationBox(LocationBox):
+       def __init__(self, session, text, dir, minFree = None):
+               inhibitDirs = ["/bin", "/boot", "/dev", "/etc", "/lib", "/proc", "/sbin", "/sys", "/usr", "/var"]
+               LocationBox.__init__(self, session, text = text, currDir = dir, bookmarks = config.movielist.videodirs, autoAdd = True, editDir = True, inhibitDirs = inhibitDirs, minFree = minFree)