Moved Playlist and FilePlaylist definitions back to hooke.playlist
[hooke.git] / hooke / plugin / playlist.py
index 58832d3537e39891b28a9c8981e62fc6aada887d..4dc83e3177fde634abb449f2e41f9b907a6e86d5 100644 (file)
@@ -2,17 +2,11 @@
 :class:`hooke.plugin.Command`\s.
 """
 
-import copy
-import hashlib
-import os
-import os.path
-import xml.dom.minidom
+from ..playlist import FilePlaylist
+from ..plugin import Builtin, Command, Argument
 
 
-from .. import curve as curve
-from ..plugin import Plugin, Command, Argument
-
-class PlaylistPlugin (Plugin):
+class PlaylistPlugin (Builtin):
     def __init__(self):
         super(PlaylistPlugin, self).__init__(name='playlist')
 
@@ -21,225 +15,6 @@ class PlaylistPlugin (Plugin):
                 SaveCommand(), LoadCommand(),
                 AddCommand(), RemoveCommand(), FilterCommand()]
 
-class Playlist (list):
-    """A list of :class:`hooke.curve.Curve`\s.
-
-    Keeps a list of :attr:`drivers` for loading curves, the
-    :attr:`index` (i.e. "bookmark") of the currently active curve, and
-    a :class:`dict` of additional informtion (:attr:`info`).
-    """
-    def __init__(self, drivers, name=None):
-        super(Playlist, self).__init__()
-        self.drivers = drivers
-        self.name = name
-        self.info = {}
-        self._index = 0
-
-    def append_curve_by_path(self, path, info=None, identify=True):
-        if self.path != None:
-            path = os.path.join(self.path, path)
-        path = os.path.normpath(path)
-        c = curve.Curve(path, info=info)
-        if identify == True:
-            c.identify(self.drivers)
-        self.append(c)
-        return c
-
-    def active_curve(self):
-        return self[self._index]
-
-    def has_curves(self):
-        return len(self) > 0
-
-    def jump(self, index):
-        if len(self) == 0:
-            self._index = 0
-        else:
-            self._index = index % len(self)
-
-    def next(self):
-        self.jump(self._index + 1)
-
-    def previous(self):
-        self.jump(self._index - 1)
-
-    def filter(self, keeper_fn=lambda curve:True):
-        playlist = copy.deepcopy(self)
-        for curve in reversed(playlist.curves):
-            if keeper_fn(curve) != True:
-                playlist.curves.remove(curve)
-        try: # attempt to maintain the same active curve
-            playlist._index = playlist.index(self.active_curve())
-        except ValueError:
-            playlist._index = 0
-        return playlist
-
-class FilePlaylist (Playlist):
-    version = '0.1'
-
-    def __init__(self, drivers, name=None, path=None):
-        if name == None and path != None:
-            name = os.path.basename(path)
-        super(FilePlaylist, self).__init__(drivers, name)
-        self.path = path
-        self._digest = None
-
-    def is_saved(self):
-        return self.digest() == self._digest
-
-    def digest(self):
-        r"""Compute the sha1 digest of the flattened playlist
-        representation.
-
-        Examples
-        --------
-
-        >>> root_path = os.path.sep + 'path'
-        >>> p = FilePlaylist(drivers=[],
-        ...                  path=os.path.join(root_path, 'to','playlist'))
-        >>> p.info['note'] = 'An example playlist'
-        >>> c = curve.Curve(os.path.join(root_path, 'to', 'curve', 'one'))
-        >>> c.info['note'] = 'The first curve'
-        >>> p.append(c)
-        >>> c = curve.Curve(os.path.join(root_path, 'to', 'curve', 'two'))
-        >>> c.info['note'] = 'The second curve'
-        >>> p.append(c)
-        >>> p.digest()
-        "\xa1\x99\x8a\x99\xed\xad\x13'\xa7w\x12\x00\x07Z\xb3\xd0zN\xa2\xe1"
-        """
-        string = self.flatten()
-        return hashlib.sha1(string).digest()
-
-    def flatten(self, absolute_paths=False):
-        """Create a string representation of the playlist.
-
-        A playlist is an XML document with the following syntax::
-
-            <?xml version="1.0" encoding="utf-8"?>
-            <playlist attribute="value">
-              <curve path="/my/file/path/"/ attribute="value" ...>
-              <curve path="...">
-            </playlist>
-
-        Relative paths are interpreted relative to the location of the
-        playlist file.
-        
-        Examples
-        --------
-
-        >>> root_path = os.path.sep + 'path'
-        >>> p = FilePlaylist(drivers=[],
-        ...                  path=os.path.join(root_path, 'to','playlist'))
-        >>> p.info['note'] = 'An example playlist'
-        >>> c = curve.Curve(os.path.join(root_path, 'to', 'curve', 'one'))
-        >>> c.info['note'] = 'The first curve'
-        >>> p.append(c)
-        >>> c = curve.Curve(os.path.join(root_path, 'to', 'curve', 'two'))
-        >>> c.info['note'] = 'The second curve'
-        >>> p.append(c)
-        >>> print p.flatten() # doctest: +NORMALIZE_WHITESPACE +REPORT_UDIFF
-        <?xml version="1.0" encoding="utf-8"?>
-        <playlist index="0" note="An example playlist" version="0.1">
-            <curve note="The first curve" path="../curve/one"/>
-            <curve note="The second curve" path="../curve/two"/>
-        </playlist>
-        <BLANKLINE>
-        >>> print p.flatten(absolute_paths=True) # doctest: +NORMALIZE_WHITESPACE +REPORT_UDIFF
-        <?xml version="1.0" encoding="utf-8"?>
-        <playlist index="0" note="An example playlist" version="0.1">
-            <curve note="The first curve" path="/path/to/curve/one"/>
-            <curve note="The second curve" path="/path/to/curve/two"/>
-        </playlist>
-        <BLANKLINE>
-        """
-        implementation = xml.dom.minidom.getDOMImplementation()
-        # create the document DOM object and the root element
-        doc = implementation.createDocument(None, 'playlist', None)
-        root = doc.documentElement
-        root.setAttribute('version', self.version) # store playlist version
-        root.setAttribute('index', str(self._index))
-        for key,value in self.info.items(): # save info variables
-            root.setAttribute(key, str(value))
-        for curve in self: # save curves and their attributes
-            curve_element = doc.createElement('curve')
-            root.appendChild(curve_element)
-            path = os.path.abspath(os.path.expanduser(curve.path))
-            if absolute_paths == False:
-                path = os.path.relpath(
-                    path,
-                    os.path.abspath(os.path.expanduser(self.path)))
-            curve_element.setAttribute('path', path)
-            for key,value in curve.info.items():
-                curve_element.setAttribute(key, str(value))
-        string = doc.toprettyxml(encoding='utf-8')
-        root.unlink() # break circular references for garbage collection
-        return string
-
-    def _from_xml_doc(self, doc):
-        """Load a playlist from an :class:`xml.dom.minidom.Document`
-        instance.
-        """
-        root = doc.documentElement
-        for attribute,value in root.attributes.items():
-            if attribute == 'version':
-                assert value == self.version, \
-                    'Cannot read v%s playlist with a v%s reader' \
-                    % (value, self.version)
-            elif attribute == 'index':
-                self._index = int(value)
-            else:
-                self.info[attribute] = value
-        for curve_element in doc.getElementsByTagName('curve'):
-            path = curve_element.getAttribute('path')
-            info = dict(curve_element.attributes.items())
-            info.pop('path')
-            self.append_curve_by_path(path, info, identify=False)
-        self.jump(self._index) # ensure valid index
-
-    def from_string(self, string):
-        """Load a playlist from a string.
-
-        Examples
-        --------
-
-        >>> string = '''<?xml version="1.0" encoding="utf-8"?>
-        ... <playlist index="1" note="An example playlist" version="0.1">
-        ...     <curve note="The first curve" path="../curve/one"/>
-        ...     <curve note="The second curve" path="../curve/two"/>
-        ... </playlist>
-        ... '''
-        >>> p = FilePlaylist(drivers=[],
-        ...                  path=os.path.join('path', 'to','playlist'))
-        >>> p.from_string(string)
-        >>> p._index
-        1
-        >>> p.info
-        {u'note': u'An example playlist'}
-        >>> for curve in p:
-        ...     print curve.path
-        path/to/curve/one
-        path/to/curve/two
-        """
-        doc = xml.dom.minidom.parseString(string)
-        return self._from_xml_doc(doc)
-
-    def load(self, path=None):
-        """Load a playlist from a file.
-        """
-        if path != None:
-            self.path = path
-        if self.name == None:
-            self.name = os.path.basename(self.path)
-        doc = xml.dom.minidom.parse(path)
-        return self._from_xml_doc(doc)
-
-    def save(self, path):
-        """Saves the playlist in a XML file.
-        """
-        f = file(path, 'w')
-        f.write(self.flatten())
-        f.close()
-
 class NextCommand (Command):
     """Move playlist to the next curve.
     """