Adjust NoteIndexList._index in .index() if it falls off the end of the list.
[hooke.git] / hooke / playlist.py
index 69442da74fa63033980b942431ca04a3a8b84ae5..52d8df1352e6077ae77651512a8eab1305ba3718 100644 (file)
@@ -1,4 +1,4 @@
-# Copyright (C) 2010 W. Trevor King <wking@drexel.edu>
+# Copyright (C) 2010-2011 W. Trevor King <wking@drexel.edu>
 #
 # This file is part of Hooke.
 #
@@ -88,14 +88,17 @@ class NoteIndexList (list):
         is `None`.
         """
         if value == None:
+            if self._index >= len(self):  # perhaps items have been popped
+                self._index = len(self) - 1
             return self._index
         return super(NoteIndexList, self).index(value, *args, **kwargs)
 
-    def current(self):
+    def current(self, load=True):
         if len(self) == 0:
             return None
         item = self[self._index]
-        self._setup_item(item)
+        if load == True:
+            self._setup_item(item)
         return item
 
     def jump(self, index):
@@ -126,6 +129,9 @@ class NoteIndexList (list):
         index = self._index
         items = self
         if reverse == True:
+            # could iterate through `c` if current_curve_callback()
+            # would work, but `c` is not bound to the local `hooke`,
+            # so curent_playlist_callback cannot point to it.
             items = reverse_enumerate(self)
         else:
             items = enumerate(self)
@@ -137,11 +143,11 @@ class NoteIndexList (list):
 
     def filter(self, keeper_fn=lambda item:True, load_curves=True,
                *args, **kwargs):
-        c = copy.deepcopy(self)
+        c = copy.copy(self)
         if load_curves == True:
-            items = c.items(reverse=True)
+            items = self.items(reverse=True)
         else:
-            items = reversed(c)
+            items = reversed(self)
         for item in items: 
             if keeper_fn(item, *args, **kwargs) != True:
                 c.remove(item)
@@ -193,7 +199,7 @@ class Playlist (NoteIndexList):
                 self.append(curve)
             if curve.driver == None:
                 c.identify(self.drivers)
-            if curve.data == None:
+            if curve.data == None or max([d.size for d in curve.data]) == 0:
                 curve.load()
             self._loaded.append(curve)
             if len(self._loaded) > self._max_loaded:
@@ -201,12 +207,15 @@ class Playlist (NoteIndexList):
                 oldest.unload()
 
     def unload(self, curve):
-        "Inverse of .`_setup_item`."
+        "Inverse of `._setup_item`."
         curve.unload()
-        self._loaded.remove(curve)
+        try:
+            self._loaded.remove(curve)
+        except ValueError:
+            pass
 
 
-def playlist_path(path):
+def playlist_path(path, expand=False):
     """Normalize playlist path extensions.
 
     Examples
@@ -222,6 +231,8 @@ def playlist_path(path):
         return None
     if not path.endswith('.hkp'):
         path += '.hkp'
+    if expand:
+        path = os.path.abspath(os.path.expanduser(path))
     return path
 
 
@@ -295,10 +306,9 @@ class FilePlaylist (Playlist):
             if self._base_path == None:
                 self._base_path = os.getcwd()
         else:
-            path = playlist_path(path)
+            path = playlist_path(path, expand=True)
             self.path = path
-            self._base_path = os.path.dirname(os.path.abspath(
-                os.path.expanduser(self.path)))
+            self._base_path = os.path.dirname(self.path)
             if self.name == None:
                 self.name = os.path.basename(path)
         if self._base_path != orig_base_path:
@@ -400,11 +410,13 @@ class FilePlaylist (Playlist):
             - !!python/object:hooke.engine.CommandMessage
               arguments: {arg 0: 0, arg 1: X}
               command: command A
+              explicit_user_call: true
             - !!python/object:hooke.engine.CommandMessage
               arguments:
                 arg 0: 1
                 curve: *id001
               command: command B
+              explicit_user_call: true
           info: {attr with spaces: 'The second curve
         <BLANKLINE>
               with endlines'}
@@ -432,11 +444,13 @@ class FilePlaylist (Playlist):
             - !!python/object:hooke.engine.CommandMessage
               arguments: {arg 0: 0, arg 1: X}
               command: command A
+              explicit_user_call: true
             - !!python/object:hooke.engine.CommandMessage
               arguments:
                 arg 0: 1
                 curve: *id001
               command: command B
+              explicit_user_call: true
           info: {attr with spaces: 'The second curve
         <BLANKLINE>
               with endlines'}
@@ -455,8 +469,10 @@ class FilePlaylist (Playlist):
         self._relative_curve_paths = self.relative_curve_paths
         self.update_curve_paths()
         self._relative_curve_paths = rcp
-
+        digest = self._digest
+        self._digest = None  # don't save the digest (recursive file).
         yaml_string = yaml.dump(self, allow_unicode=True)
+        self._digest = digest
         self.update_curve_paths()
         return ('# Hooke playlist version %s\n' % self.version) + yaml_string
 
@@ -562,7 +578,7 @@ def from_string(string):
 def load(path=None, drivers=None, identify=True, hooke=None):
     """Load a playlist from a file.
     """
-    path = playlist_path(path)
+    path = playlist_path(path, expand=True)
     with open(path, 'r') as f:
         text = f.read()
     playlist = from_string(text)