1 # Copyright (C) 2010 W. Trevor King <wking@drexel.edu>
3 # This file is part of Hooke.
5 # Hooke is free software: you can redistribute it and/or
6 # modify it under the terms of the GNU Lesser General Public
7 # License as published by the Free Software Foundation, either
8 # version 3 of the License, or (at your option) any later version.
10 # Hooke is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # GNU Lesser General Public License for more details.
15 # You should have received a copy of the GNU Lesser General Public
16 # License along with Hooke. If not, see
17 # <http://www.gnu.org/licenses/>.
19 """The ``playlist`` module provides :class:`PlaylistPlugin` and
20 several associated :class:`hooke.command.Command`\s for handling
21 :mod:`hooke.playlist` classes.
27 from ..command import Command, Argument, Failure
28 from ..playlist import FilePlaylist
29 from ..plugin import Builtin
32 class PlaylistPlugin (Builtin):
34 super(PlaylistPlugin, self).__init__(name='playlist')
36 NextCommand(self), PreviousCommand(self), JumpCommand(self),
37 IndexCommand(self), CurveListCommand(self),
38 SaveCommand(self), LoadCommand(self),
39 AddCommand(self), AddGlobCommand(self),
40 RemoveCommand(self), FilterCommand(self), NoteFilterCommand(self)]
43 # Define common or complicated arguments
45 def current_playlist_callback(hooke, command, argument, value):
48 playlist = hooke.playlists.current()
50 raise Failure('No playlists loaded')
53 PlaylistArgument = Argument(
54 name='playlist', type='playlist', callback=current_playlist_callback,
56 :class:`hooke.playlist.Playlist` to act on. Defaults to the current
60 def playlist_name_callback(hooke, command, argument, value):
62 names = [p.name for p in hooke.playlists]
64 name = 'playlist-%d' % i
69 PlaylistNameArgument = Argument(
70 name='name', type='string', optional=True, callback=playlist_name_callback,
72 Name of the new playlist (defaults to an auto-generated name).
75 def all_drivers_callback(hooke, command, argument, value):
81 class NextCommand (Command):
82 """Move playlist to the next curve.
84 def __init__(self, plugin):
85 super(NextCommand, self).__init__(
87 arguments=[PlaylistArgument],
88 help=self.__doc__, plugin=plugin)
90 def _run(self, hooke, inqueue, outqueue, params):
91 params['playlist'].next()
93 class PreviousCommand (Command):
94 """Move playlist to the previous curve.
96 def __init__(self, plugin):
97 super(PreviousCommand, self).__init__(
98 name='previous curve',
99 arguments=[PlaylistArgument],
100 help=self.__doc__, plugin=plugin)
102 def _run(self, hooke, inqueue, outqueue, params):
103 params['playlist'].previous()
105 class JumpCommand (Command):
106 """Move playlist to a given curve.
108 def __init__(self, plugin):
109 super(JumpCommand, self).__init__(
110 name='jump to curve',
113 Argument(name='index', type='int', optional=False, help="""
114 Index of target curve.
117 help=self.__doc__, plugin=plugin)
119 def _run(self, hooke, inqueue, outqueue, params):
120 params['playlist'].jump(int(params['index'])) # HACK, int() should be handled by ui
122 class IndexCommand (Command):
123 """Print the index of the current curve.
125 The first curve has index 0.
127 def __init__(self, plugin):
128 super(IndexCommand, self).__init__(
133 help=self.__doc__, plugin=plugin)
135 def _run(self, hooke, inqueue, outqueue, params):
136 outqueue.put(params['playlist']._index)
138 class CurveListCommand (Command):
139 """Get the curves in a playlist.
141 def __init__(self, plugin):
142 super(CurveListCommand, self).__init__(
143 name='playlist curves',
147 help=self.__doc__, plugin=plugin)
149 def _run(self, hooke, inqueue, outqueue, params):
150 outqueue.put([c for c in params['playlist']])
152 class SaveCommand (Command):
155 def __init__(self, plugin):
156 super(SaveCommand, self).__init__(
157 name='save playlist',
160 Argument(name='output', type='file',
162 File name for the output playlist. Defaults to overwriting the input
166 help=self.__doc__, plugin=plugin)
168 def _run(self, hooke, inqueue, outqueue, params):
169 params['playlist'].save(params['output'])
171 class LoadCommand (Command):
174 def __init__(self, plugin):
175 super(LoadCommand, self).__init__(
176 name='load playlist',
178 Argument(name='input', type='file', optional=False,
180 File name for the input playlist.
182 Argument(name='drivers', type='driver', optional=True,
183 count=-1, callback=all_drivers_callback,
185 Drivers for loading curves.
188 help=self.__doc__, plugin=plugin)
190 def _run(self, hooke, inqueue, outqueue, params):
191 p = FilePlaylist(drivers=params['drivers'], path=params['input'])
193 hooke.playlists.append(p)
196 class AddCommand (Command):
197 """Add a curve to a playlist.
199 def __init__(self, plugin):
200 super(AddCommand, self).__init__(
201 name='add curve to playlist',
204 Argument(name='input', type='file', optional=False,
206 File name for the input :class:`hooke.curve.Curve`.
208 Argument(name='info', type='dict', optional=True,
210 Additional information for the input :class:`hooke.curve.Curve`.
213 help=self.__doc__, plugin=plugin)
215 def _run(self, hooke, inqueue, outqueue, params):
216 params['playlist'].append_curve_by_path(params['input'],
219 class AddGlobCommand (Command):
220 """Add curves to a playlist with file globbing.
222 Adding lots of files one at a time can be tedious. With this
223 command you can use globs (`data/curves/*.dat`) to add curves
224 for all matching files at once.
226 def __init__(self, plugin):
227 super(AddGlobCommand, self).__init__(
228 name='glob curves to playlist',
231 Argument(name='input', type='glob', optional=False,
233 File name glob for the input :class:`hooke.curve.Curve`.
235 Argument(name='info', type='dict', optional=True,
237 Additional information for the input :class:`hooke.curve.Curve`.
240 help=self.__doc__, plugin=plugin)
242 def _run(self, hooke, inqueue, outqueue, params):
243 for path in sorted(glob.glob(params['input'])):
244 params['playlist'].append_curve_by_path(path, params['info'])
246 class RemoveCommand (Command):
247 """Remove a curve from a playlist.
249 def __init__(self, plugin):
250 super(RemoveCommand, self).__init__(
251 name='remove curve from playlist',
254 Argument(name='index', type='int', optional=False, help="""
255 Index of target curve.
258 help=self.__doc__, plugin=plugin)
260 def _run(self, hooke, inqueue, outqueue, params):
261 params['playlist'].pop(params['index'])
262 params['playlist'].jump(params._index)
264 class FilterCommand (Command):
265 """Create a subset playlist via a selection function.
267 Removing lots of curves one at a time can be tedious. With this
268 command you can use a function `filter` to select the curves you
273 There are issues with pickling functions bound to class
274 attributes, because the pickle module doesn't know where those
275 functions were originally defined (where it should point the
276 loader). Because of this, subclasses with hard-coded filter
277 functions are encouraged to define their filter function as a
278 method of their subclass. See, for example,
279 :meth:`NoteFilterCommand.filter`.
281 def __init__(self, plugin, name='filter playlist'):
282 super(FilterCommand, self).__init__(
286 PlaylistNameArgument,
288 help=self.__doc__, plugin=plugin)
289 if not hasattr(self, 'filter'):
290 self.arguments.append(
291 Argument(name='filter', type='function', optional=False,
293 Function returning `True` for "good" curves.
294 `filter(curve, hooke, inqueue, outqueue, params) -> True/False`.
297 def _run(self, hooke, inqueue, outqueue, params):
298 if not hasattr(self, 'filter'):
299 filter_fn = params['filter']
301 filter_fn = self.filter
302 p = params['playlist'].filter(filter_fn,
303 hooke=hooke, inqueue=inqueue, outqueue=outqueue, params=params)
304 p.name = params['name']
305 if hasattr(p, 'path') and p.path != None:
306 p.set_path(os.path.join(os.path.dirname(p.path), p.name))
307 hooke.playlists.append(p)
310 class NoteFilterCommand (FilterCommand):
311 """Create a subset playlist of curves with `.info['note'] != None`.
313 def __init__(self, plugin):
314 super(NoteFilterCommand, self).__init__(
315 plugin, name='note filter playlist')
317 def filter(self, curve, hooke, inqueue, outqueue, params):
318 return 'note' in curve.info and curve.info['note'] != None