summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorWojciech Siewierski <wojciech.siewierski@onet.pl>2015-02-22 01:33:57 +0100
committerWojciech Siewierski <wojciech.siewierski@onet.pl>2015-02-22 01:42:15 +0100
commit19ee5a7427059c8f570cc050acca1e1e6305bd8c (patch)
treec72062b9b5f82e2d6a09cbcb47510505fe6fc18b
parenta3cd6b0cf3e6b05e7058544b8503872ff7ac2881 (diff)
downloadranger-19ee5a7427059c8f570cc050acca1e1e6305bd8c.tar.gz
linemode refactoring; custom linemodes possible
-rw-r--r--ranger/config/commands.py6
-rw-r--r--ranger/container/fsobject.py7
-rw-r--r--ranger/core/actions.py4
-rw-r--r--ranger/core/linemode.py91
-rw-r--r--ranger/gui/widgets/browsercolumn.py42
5 files changed, 114 insertions, 36 deletions
diff --git a/ranger/config/commands.py b/ranger/config/commands.py
index 55f6442b..6e2ba26d 100644
--- a/ranger/config/commands.py
+++ b/ranger/config/commands.py
@@ -390,7 +390,7 @@ class setintag(setlocal):
 class default_linemode(Command):
     def execute(self):
         import re
-        from ranger.container.fsobject import POSSIBLE_LINEMODES
+        from ranger.core.linemode import REGISTERED_LINEMODES
 
         if len(self.args) < 2:
             self.fm.notify("Usage: default_linemode [path=<regexp> | tag=<tag(s)>] <linemode>", bad=True)
@@ -410,9 +410,9 @@ class default_linemode(Command):
 
         # Extract and validate the line mode from the command line
         linemode = self.rest(1)
-        if linemode not in POSSIBLE_LINEMODES:
+        if linemode not in REGISTERED_LINEMODES:
             self.fm.notify("Invalid linemode: %s; should be %s" %
-                    (linemode, "/".join(POSSIBLE_LINEMODES)), bad=True)
+                    (linemode, "/".join(REGISTERED_LINEMODES)), bad=True)
 
         # Add the prepared entry to the fm.default_linemodes
         entry = [method, argument, linemode]
diff --git a/ranger/container/fsobject.py b/ranger/container/fsobject.py
index 08161c3c..32b1dc8b 100644
--- a/ranger/container/fsobject.py
+++ b/ranger/container/fsobject.py
@@ -12,14 +12,13 @@ DOCUMENT_BASENAMES = ('bugs', 'bugs', 'changelog', 'copying', 'credits',
 
 BAD_INFO = '?'
 
-POSSIBLE_LINEMODES = ("filename", "metatitle", "permissions")
-DEFAULT_LINEMODE = "filename"
-
 import re
 from grp import getgrgid
 from os import lstat, stat, getcwd
 from os.path import abspath, basename, dirname, realpath, splitext, extsep, relpath
 from pwd import getpwuid
+from ranger.core.linemode import REGISTERED_LINEMODES
+from ranger.core.linemode import DEFAULT_LINEMODE
 from ranger.core.shared import FileManagerAware, SettingsAware
 from ranger.ext.shell_escape import shell_escape
 from ranger.ext.spawn import spawn
@@ -112,7 +111,7 @@ class FileSystemObject(FileManagerAware, SettingsAware):
 
         # Set the line mode from fm.default_linemodes
         for method, argument, linemode in self.fm.default_linemodes:
-            if linemode in POSSIBLE_LINEMODES:
+            if linemode in REGISTERED_LINEMODES:
                 if method == "always":
                     self._linemode = linemode
                     break
diff --git a/ranger/core/actions.py b/ranger/core/actions.py
index 1167dab5..aa10e34f 100644
--- a/ranger/core/actions.py
+++ b/ranger/core/actions.py
@@ -27,7 +27,7 @@ from ranger.core.tab import Tab
 from ranger.container.file import File
 from ranger.core.loader import CommandLoader, CopyLoader
 from ranger.container.settings import ALLOWED_SETTINGS
-from ranger.container.fsobject import POSSIBLE_LINEMODES, DEFAULT_LINEMODE
+from ranger.core.linemode import REGISTERED_LINEMODES, DEFAULT_LINEMODE
 
 MACRO_FAIL = "<\x01\x01MACRO_HAS_NO_VALUE\x01\01>"
 
@@ -167,7 +167,7 @@ class Actions(FileManagerAware, EnvironmentAware, SettingsAware):
         if mode == "normal":
             mode = DEFAULT_LINEMODE
 
-        if mode not in POSSIBLE_LINEMODES:
+        if mode not in REGISTERED_LINEMODES:
             self.notify("Unhandled linemode: `%s'" % mode, bad=True)
             return
 
diff --git a/ranger/core/linemode.py b/ranger/core/linemode.py
new file mode 100644
index 00000000..8b5084b0
--- /dev/null
+++ b/ranger/core/linemode.py
@@ -0,0 +1,91 @@
+# -*- coding: utf-8 -*-
+
+from abc import *
+
+DEFAULT_LINEMODE = "filename"
+REGISTERED_LINEMODES = dict()
+
+def register_linemode(*linemodes):
+    """Register a linemode in a dictionary of available linemodes."""
+    for linemode in linemodes:
+        REGISTERED_LINEMODES[linemode.name] = linemode()
+
+def lookup_linemode(name):
+    """Lookup the linemode instance by its name"""
+    return REGISTERED_LINEMODES[name]
+
+
+class LinemodeBase(object):
+    """Supplies the file line contents for BrowserColumn.
+
+    Attributes:
+        name (required!) - Name by which the linemode is referred to by the user
+
+        uses_metadata - True if metadata should to be loaded for this linemode
+
+        required_metadata -
+            If any of these metadata fields are absent, fall back to
+            the default linemode
+    """
+    __metaclass__ = ABCMeta
+
+    uses_metadata = False
+    required_metadata = []
+
+    name = abstractproperty()
+
+    @abstractmethod
+    def filetitle(self, file, metadata):
+        """The left-aligned part of the line."""
+        raise NotImplementedError
+
+    @abstractmethod
+    def infostring(self, file, metadata):
+        """The right-aligned part of the line."""
+        raise NotImplementedError
+
+
+class DefaultLinemode(LinemodeBase):
+    name = "filename"
+
+    def filetitle(self, file, metadata):
+        return file.drawn_basename
+
+    def infostring(self, file, metadata):
+        # Should never be called for this linemode, implemented in BrowserColumn
+        raise NotImplementedError
+
+
+class TitleLinemode(LinemodeBase):
+    name = "metatitle"
+    uses_metadata = True
+    required_metadata = ["title"]
+
+    def filetitle(self, file, metadata):
+        name = metadata.title or file.basename
+        if metadata.year:
+            return "%s - %s" % (metadata.year, name)
+        else:
+            return name
+
+    def infostring(self, file, metadata):
+        if metadata.authors:
+            authorstring = metadata.authors
+            if ',' in authorstring:
+                authorstring = authorstring[0:authorstring.find(",")]
+            return authorstring
+        return ""
+
+
+class PermissionsLinemode(LinemodeBase):
+    name = "permissions"
+
+    def filetitle(self, file, metadata):
+        return "%s %s %s %s" % (file.get_permission_string(),
+                file.user, file.group, file.drawn_basename)
+
+    def infostring(self, file, metadata):
+        return ""
+
+
+register_linemode(DefaultLinemode, PermissionsLinemode, TitleLinemode)
diff --git a/ranger/gui/widgets/browsercolumn.py b/ranger/gui/widgets/browsercolumn.py
index 564e9a5f..427a323d 100644
--- a/ranger/gui/widgets/browsercolumn.py
+++ b/ranger/gui/widgets/browsercolumn.py
@@ -12,6 +12,8 @@ from . import Widget
 from .pager import Pager
 from ranger.ext.widestring import WideString
 
+from ranger.core import linemode
+
 from ranger.gui.color import *
 
 class BrowserColumn(Pager):
@@ -250,38 +252,25 @@ class BrowserColumn(Pager):
 
             # Extract linemode-related information from the drawn object
             metadata = None
-            use_linemode = drawn._linemode
-            if use_linemode == "metatitle":
+            current_linemode = linemode.lookup_linemode(drawn._linemode)
+            if current_linemode.uses_metadata:
                 metadata = self.fm.metadata.get_metadata(drawn.path)
-                if not metadata.title:
-                    use_linemode = "filename"
+                if not all(getattr(metadata, tag)
+                           for tag in current_linemode.required_metadata):
+                    current_linemode = linemode.lookup_linemode(linemode.DEFAULT_LINEMODE)
 
             metakey = hash(repr(sorted(metadata.items()))) if metadata else 0
             key = (self.wid, selected_i == i, drawn.marked, self.main_column,
                     drawn.path in copied, tagged_marker, drawn.infostring,
                     drawn.vcsfilestatus, drawn.vcsremotestatus, self.fm.do_cut,
-                    use_linemode, metakey)
+                    current_linemode.name, metakey)
 
             if key in drawn.display_data:
                 self.execute_curses_batch(line, drawn.display_data[key])
                 self.color_reset()
                 continue
 
-
-            # Deal with the line mode
-            text = ""
-            if use_linemode == "metatitle":
-                assert metadata.title, "Ensure that metadata.title is set!"
-                if metadata.year:
-                    text = "%s - %s" % (metadata.year, metadata.title)
-                else:
-                    text = metadata.title
-            if use_linemode == "filename":
-                text = drawn.drawn_basename
-            elif use_linemode == "permissions":
-                text = "%s %s %s %s" % (drawn.get_permission_string(),
-                        drawn.user, drawn.group, drawn.drawn_basename)
-
+            text = current_linemode.filetitle(drawn, metadata)
 
             if drawn.marked and (self.main_column or \
                     self.settings.display_tags_in_all_columns):
@@ -312,14 +301,13 @@ class BrowserColumn(Pager):
             # info string
             infostring = []
             infostringlen = 0
-            if use_linemode == "filename":
+            if current_linemode.name == "filename":
                 infostring = self._draw_infostring_display(drawn, space)
-            elif use_linemode == "metatitle":
-                if metadata.authors:
-                    authorstring = metadata.authors
-                    if ',' in authorstring:
-                        authorstring = authorstring[0:authorstring.find(",")]
-                    infostring.append([" " + authorstring + " ", ["infostring"]])
+            else:
+                infostringdata = current_linemode.infostring(drawn, metadata)
+                if infostringdata:
+                    infostring.append([" " + infostringdata + " ",
+                                       ["infostring"]])
             if infostring:
                 infostringlen = self._total_len(infostring)
                 if space - infostringlen > 2: