home *** CD-ROM | disk | FTP | other *** search
/ PC Welt 2006 November (DVD) / PCWELT_11_2006.ISO / casper / filesystem.squashfs / usr / lib / python2.4 / site-packages / serpentine / mastering.pyc (.txt) < prev    next >
Encoding:
Python Compiled Bytecode  |  2006-08-31  |  27.7 KB  |  811 lines

  1. # Source Generated with Decompyle++
  2. # File: in.pyc (Python 2.4)
  3.  
  4. import gtk
  5. import gobject
  6. import sys
  7. import weakref
  8. from gtk import glade
  9. from os import path
  10. from types import IntType, TupleType
  11. from gettext import gettext as _
  12. from gettext import ngettext as N_
  13. import operations
  14. import audio
  15. import xspf
  16. import gtkutil
  17. import urlutil
  18. from gtkutil import DictStore
  19. from operations import OperationsQueue
  20. from gdkpiechart import SerpentineUsage
  21.  
  22. class ErrorTrapper(operations.Operation, operations.OperationListener):
  23.     
  24.     def __init__(self, parent = None):
  25.         operations.Operation.__init__(self)
  26.         self._ErrorTrapper__errors = []
  27.         self._parent = parent
  28.  
  29.     errors = property((lambda self: self._ErrorTrapper__errors))
  30.     parent = property((lambda self: self._parent))
  31.     
  32.     def on_finished(self, event):
  33.         if event.id == operations.ERROR:
  34.             self.errors.append(event.source)
  35.         
  36.  
  37.     
  38.     def start(self):
  39.         if len(self.errors) == 0:
  40.             e = operations.FinishedEvent(self, operations.SUCCESSFUL)
  41.             for l in self.listeners:
  42.                 l.on_finished(e)
  43.             
  44.             return None
  45.         
  46.         filenames = []
  47.         for e in self.errors:
  48.             filenames.append(urlutil.basename(e.hints['location']))
  49.         
  50.         del self._ErrorTrapper__errors
  51.         title = N_('Unsupported file type', 'Unsupported file types', len(filenames))
  52.         msg = N_('The following file was not added:', 'The following files were not added:', len(filenames))
  53.         gtkutil.list_dialog(title, _("If you're having problems opening certain files make sure you have the GStreamer plugins needed to decode them."), list_title = msg, parent = self.parent, items = filenames, stock = gtk.STOCK_DIALOG_ERROR, buttons = (gtk.STOCK_CLOSE, gtk.RESPONSE_OK))
  54.         e = operations.FinishedEvent(self, operations.SUCCESSFUL)
  55.         for l in self.listeners:
  56.             l.on_finished(e)
  57.         
  58.  
  59.  
  60.  
  61. class AddFile(audio.AudioMetadataListener, operations.Operation):
  62.     running = property((lambda self: False))
  63.     
  64.     def __init__(self, music_list, hints, insert = None, app = None):
  65.         operations.Operation.__init__(self)
  66.         self.hints = hints
  67.         self.music_list = music_list
  68.         self.insert = insert
  69.         hints['location'] = urlutil.normalize(hints['location'])
  70.         self.app = app
  71.  
  72.     
  73.     def start(self):
  74.         if self.app.preferences.useGnomeVfs:
  75.             oper = audio.get_metadata(audio.GVFS_SRC, self.hints['location'])
  76.         else:
  77.             url = urlutil.UrlParse(self.hints['location'])
  78.             if not url.is_local:
  79.                 self._send_finished_error(operations.ERROR, error = StandardError(self.hints['location']))
  80.                 return None
  81.             
  82.             filename = url.path
  83.             oper = audio.get_metadata('filesrc', filename)
  84.         oper.listeners.append(self)
  85.         
  86.         try:
  87.             oper.start()
  88.         except audio.GstPlayingFailledError:
  89.             self._send_finished_event(operations.ERROR, error = StandardError(self.hints['location']))
  90.  
  91.  
  92.     
  93.     def on_metadata(self, event, metadata):
  94.         title = urlutil.basename(self.hints['location'])
  95.         title = path.splitext(title)[0]
  96.         if not title:
  97.             pass
  98.         row = {
  99.             'location': self.hints['location'],
  100.             'cache_location': '',
  101.             'title': _('Unknown'),
  102.             'artist': _('Unknown Artist'),
  103.             'duration': int(metadata['duration']) }
  104.         if metadata.has_key('title'):
  105.             row['title'] = metadata['title']
  106.         
  107.         if metadata.has_key('artist'):
  108.             row['artist'] = metadata['artist']
  109.         
  110.         if self.hints.has_key('title'):
  111.             row['title'] = self.hints['title']
  112.         
  113.         if self.hints.has_key('artist'):
  114.             row['artist'] = self.hints['artist']
  115.         
  116.         if self.insert is not None:
  117.             self.music_list.insert(self.insert, row)
  118.         else:
  119.             self.music_list.append(row)
  120.  
  121.     
  122.     def on_finished(self, evt):
  123.         e = operations.FinishedEvent(self, evt.id)
  124.         for l in self.listeners:
  125.             l.on_finished(e)
  126.         
  127.  
  128.  
  129.  
  130. class UpdateDiscUsage(operations.Operation):
  131.     
  132.     def __init__(self, masterer, update):
  133.         operations.Operation.__init__(self)
  134.         self._UpdateDiscUsage__update = update
  135.         self._UpdateDiscUsage__masterer = masterer
  136.  
  137.     running = property((lambda self: False))
  138.     can_run = property((lambda self: True))
  139.     
  140.     def start(self):
  141.         self._UpdateDiscUsage__masterer.update = self._UpdateDiscUsage__update
  142.         if self._UpdateDiscUsage__update:
  143.             self._UpdateDiscUsage__masterer.update_disc_usage()
  144.         
  145.         e = operations.FinishedEvent(self, operations.SUCCESSFUL)
  146.         for l in self.listeners:
  147.             l.on_finished(e)
  148.         
  149.  
  150.  
  151.  
  152. class MusicListListener:
  153.     
  154.     def on_musics_added(self, event, rows):
  155.         pass
  156.  
  157.     
  158.     def on_musics_removed(self, event, rows):
  159.         pass
  160.  
  161.  
  162.  
  163. class MusicList(operations.Listenable):
  164.     
  165.     def __getitem__(self):
  166.         pass
  167.  
  168.     
  169.     def append_many(self, rows):
  170.         pass
  171.  
  172.     
  173.     def append(self, row):
  174.         pass
  175.  
  176.     
  177.     def insert(self, index, row):
  178.         pass
  179.  
  180.     
  181.     def insert_many(self, index, rows):
  182.         pass
  183.  
  184.     
  185.     def __len__(self):
  186.         pass
  187.  
  188.     
  189.     def __delitem__(self, index):
  190.         pass
  191.  
  192.     
  193.     def delete_many(self, indexes):
  194.         pass
  195.  
  196.     
  197.     def clear(self):
  198.         pass
  199.  
  200.     
  201.     def has_key(self, key):
  202.         pass
  203.  
  204.     
  205.     def from_playlist(self, playlist):
  206.         rows = []
  207.         for t in playlist.tracks:
  208.             rows.append({
  209.                 'location': t.location,
  210.                 'duration': t.duration,
  211.                 'title': t.title,
  212.                 'artist': t.creator })
  213.         
  214.         self.append_many(rows)
  215.  
  216.     
  217.     def to_playlist(self, playlist):
  218.         for r in self:
  219.             t = xspf.Track()
  220.             t.location = r['location']
  221.             t.duration = r['duration']
  222.             t.title = r['title']
  223.             t.creator = r['artist']
  224.             playlist.tracks.append(t)
  225.         
  226.  
  227.  
  228.  
  229. class GtkMusicList(MusicList):
  230.     '''The GtkMusicList uses a ListStore as a backend, it is not visual and
  231.     depends only on glib.
  232.     
  233.     Takes care of the data source. Supports events and listeners.
  234.     '''
  235.     SPEC = ({
  236.         'name': 'location',
  237.         'type': gobject.TYPE_STRING }, {
  238.         'name': 'cache_location',
  239.         'type': gobject.TYPE_STRING }, {
  240.         'name': 'duration',
  241.         'type': gobject.TYPE_INT }, {
  242.         'name': 'title',
  243.         'type': gobject.TYPE_STRING }, {
  244.         'name': 'artist',
  245.         'type': gobject.TYPE_STRING }, {
  246.         'name': 'time',
  247.         'type': gobject.TYPE_STRING })
  248.     
  249.     def __init__(self):
  250.         operations.Listenable.__init__(self)
  251.         self._GtkMusicList__model = DictStore(*self.SPEC)
  252.         self._GtkMusicList__total_duration = 0
  253.         self._GtkMusicList__freezed = False
  254.  
  255.     model = property(fget = (lambda self: self._GtkMusicList__model), doc = 'Associated ListStore.')
  256.     total_duration = property(fget = (lambda self: self._GtkMusicList__total_duration), doc = 'Total disc duration, in seconds.')
  257.     
  258.     def __getitem__(self, index):
  259.         return self.model.get(index)
  260.  
  261.     
  262.     def append_many(self, rows):
  263.         self._GtkMusicList__freezed = True
  264.         for row in rows:
  265.             self.append(row)
  266.         
  267.         self._GtkMusicList__freezed = False
  268.         rows = tuple(rows)
  269.         e = operations.Event(self)
  270.         for l in self.listeners:
  271.             l.on_musics_added(e, rows)
  272.         
  273.  
  274.     
  275.     def __correct_row(self, row):
  276.         if not row.has_key('time'):
  277.             row['time'] = '%.2d:%.2d' % (row['duration'] / 60, row['duration'] % 60)
  278.         
  279.         if not row.has_key('cache_location'):
  280.             row['cache_location'] = ''
  281.         
  282.         return row
  283.  
  284.     
  285.     def append(self, row):
  286.         row = self._GtkMusicList__correct_row(row)
  287.         self.model.append(row)
  288.         self._GtkMusicList__total_duration += int(row['duration'])
  289.         if not self._GtkMusicList__freezed:
  290.             e = operations.Event(self)
  291.             rows = (row,)
  292.             for l in self.listeners:
  293.                 l.on_musics_added(e, rows)
  294.             
  295.         
  296.  
  297.     
  298.     def insert(self, index, row):
  299.         row = self._GtkMusicList__correct_row(row)
  300.         self.model.insert_before(self.model.get_iter(index), row)
  301.         self._GtkMusicList__total_duration += int(row['duration'])
  302.         if not self._GtkMusicList__freezed:
  303.             e = operations.Event(self)
  304.             rows = (row,)
  305.             for l in self.listeners:
  306.                 l.on_musics_added(e, rows)
  307.             
  308.         
  309.  
  310.     
  311.     def __len__(self):
  312.         return len(self.model)
  313.  
  314.     
  315.     def __delitem__(self, index):
  316.         row = dict(self[index])
  317.         del self.model[index]
  318.         self._GtkMusicList__total_duration -= row['duration']
  319.         rows = (row,)
  320.         if not self._GtkMusicList__freezed:
  321.             e = operations.Event(self)
  322.             for l in self.listeners:
  323.                 l.on_musics_removed(e, rows)
  324.             
  325.         
  326.  
  327.     
  328.     def delete_many(self, indexes):
  329.         if not isinstance(indexes, list):
  330.             raise AssertionError
  331.         rows = []
  332.         indexes.sort()
  333.         low = indexes[0] - 1
  334.         for i in indexes:
  335.             if low == i:
  336.                 indexes.remove(i)
  337.             
  338.             low = i
  339.         
  340.         for i in range(len(indexes)):
  341.             indexes[i] -= i
  342.         
  343.         for i in indexes:
  344.             r = dict(self.model.get(i))
  345.             rows.append(r)
  346.             self._GtkMusicList__total_duration -= r['duration']
  347.             del self.model[i]
  348.         
  349.         rows = tuple(rows)
  350.         e = operations.Event(self)
  351.         for l in self.listeners:
  352.             l.on_musics_removed(e, rows)
  353.         
  354.  
  355.     
  356.     def clear(self):
  357.         rows = []
  358.         for row in iter(self.model):
  359.             rows.append(dict(row))
  360.         
  361.         self.model.clear()
  362.         self._GtkMusicList__total_duration = 0
  363.         rows = tuple(rows)
  364.         e = operations.Event(self)
  365.         for l in self.listeners:
  366.             l.on_musics_removed(e, rows)
  367.         
  368.  
  369.  
  370.  
  371. class AudioMasteringMusicListener(MusicListListener):
  372.     
  373.     def __init__(self, audio_mastering):
  374.         self._AudioMasteringMusicListener__master = audio_mastering
  375.  
  376.     
  377.     def on_musics_added(self, e, rows):
  378.         self._AudioMasteringMusicListener__master.update_disc_usage()
  379.  
  380.     
  381.     def on_musics_removed(self, e, rows):
  382.         self._AudioMasteringMusicListener__master.update_disc_usage()
  383.  
  384.  
  385.  
  386. class HintsFilter(object):
  387.     __priority = 0
  388.     
  389.     def priority(self, value):
  390.         if not isinstance(value, int):
  391.             raise AssertionError
  392.         self._HintsFilter__priority = value
  393.  
  394.     priority = property((lambda self: self._HintsFilter__priority), priority, doc = 'Represents the parser priority, a higher value will give it precedence over filters lower filters.')
  395.     
  396.     def filter_location(self, location):
  397.         """Returns a list of dictionaries of hints of a given location.
  398.         The 'location' field is obligatory.
  399.         
  400.         For example if your filter parses a directory it should return a list
  401.         of hints of each encountered file.
  402.         """
  403.         raise NotImplementedError
  404.  
  405.     
  406.     def __cmp__(self, value):
  407.         if not isinstance(value, HintsFilter):
  408.             raise AssertionError
  409.         return self.priority - value.priority
  410.  
  411.  
  412.  
  413. def normalize_hints(hints):
  414.     hints['location'] = urlutil.normalize(hints['location'])
  415.  
  416.  
  417. class MusicListGateway:
  418.     '''This class wraps the MusicList interface in a friendlier one with a
  419.     method `add_files` easier to use then the `insert` method which expects
  420.     a hints `dict`. It also serves as a hints filter which is a list of client
  421.     objects which must provide the `filter_location` method.
  422.     '''
  423.     
  424.     class Handler:
  425.         '''A handler is created each time a method is created, it must
  426.         return objects with this class signature.'''
  427.         
  428.         def prepare_queue(self, gateway, queue):
  429.             '''Method called before the AddFile operations are added to the queue'''
  430.             pass
  431.  
  432.         
  433.         def finish_queue(self, gateway, queue):
  434.             '''Method called after the AddFile operations are added to the queue'''
  435.             pass
  436.  
  437.         
  438.         def prepare_add_file(self, gateway, add_file):
  439.             '''Method called before add_file object is added to queue'''
  440.             pass
  441.  
  442.  
  443.     
  444.     def __init__(self, app):
  445.         self._MusicListGateway__filters = []
  446.         self._app = weakref.ref(app)
  447.  
  448.     music_list = None
  449.     
  450.     def __filter_location(self, location):
  451.         for loc_filter in self._MusicListGateway__filters:
  452.             hints = loc_filter.filter_location(location)
  453.             if hints is not None:
  454.                 return hints
  455.                 continue
  456.         
  457.  
  458.     
  459.     def add_files(self, filenames):
  460.         
  461.         to_hint = lambda filename: {
  462. 'location': urlutil.normalize(filename) }
  463.         return self.add_hints(map(to_hint, filenames))
  464.  
  465.     
  466.     def add_hints(self, hints_list, insert = None):
  467.         if not insert is None and isinstance(insert, IntType):
  468.             raise AssertionError
  469.         queue = OperationsQueue()
  470.         queue.abort_on_failure = False
  471.         handler = self.Handler()
  472.         handler.prepare_queue(self, queue)
  473.         i = 0
  474.         for h in hints_list:
  475.             pls = self._MusicListGateway__filter_location(h['location'])
  476.             if pls is not None and len(pls) > 0:
  477.                 map(normalize_hints, pls)
  478.                 queue.append(self.add_hints(pls, insert))
  479.                 continue
  480.             
  481.             ins = insert
  482.             if insert != None:
  483.                 ins += i
  484.             
  485.             a = AddFile(self.music_list, h, ins, self._app())
  486.             handler.prepare_add_file(self, a)
  487.             queue.append(a)
  488.             i += 1
  489.         
  490.         handler.finish_queue(self, queue)
  491.         return queue
  492.  
  493.     
  494.     def add_hints_filter(self, location_filter):
  495.         self._MusicListGateway__filters.append(location_filter)
  496.         self._MusicListGateway__filters.sort()
  497.  
  498.     
  499.     def remove_hints_filter(self, location_filter):
  500.         self._MusicListGateway__filters.remove(location_filter)
  501.  
  502.  
  503.  
  504. class AudioMastering(gtk.VBox, operations.Listenable):
  505.     SIZE_21 = 0
  506.     SIZE_74 = 1
  507.     SIZE_80 = 2
  508.     SIZE_90 = 3
  509.     
  510.     class MusicListGateway(MusicListGateway):
  511.         
  512.         def __init__(self, parent):
  513.             MusicListGateway.__init__(self, parent._application())
  514.             self.parent = parent
  515.  
  516.         
  517.         def music_list(self):
  518.             return self.parent.music_list
  519.  
  520.         music_list = property(music_list)
  521.         
  522.         def window(self):
  523.             return gtkutil.get_root_parent(self.parent)
  524.  
  525.         window = property(window)
  526.         
  527.         class Handler:
  528.             
  529.             def prepare_queue(self, gateway, queue):
  530.                 queue.append(UpdateDiscUsage(gateway.parent, False))
  531.                 self.trapper = ErrorTrapper(gateway.window)
  532.  
  533.             
  534.             def finish_queue(self, gateway, queue):
  535.                 queue.append(UpdateDiscUsage(gateway.parent, True))
  536.                 queue.append(self.trapper)
  537.                 del self.trapper
  538.  
  539.             
  540.             def prepare_add_file(self, gateway, add_file):
  541.                 add_file.listeners.append(self.trapper)
  542.  
  543.  
  544.  
  545.     disc_sizes = [
  546.         21 * 60,
  547.         74 * 60,
  548.         80 * 60,
  549.         90 * 60]
  550.     DND_TARGETS = [
  551.         ('SERPENTINE_ROW', gtk.TARGET_SAME_WIDGET, 0),
  552.         ('text/uri-list', 0, 1),
  553.         ('text/plain', 0, 2),
  554.         ('STRING', 0, 3)]
  555.     
  556.     def __init__(self, application):
  557.         gtk.VBox.__init__(self)
  558.         self._application = weakref.ref(application)
  559.         operations.Listenable.__init__(self)
  560.         self._AudioMastering__disc_size = 74 * 60
  561.         self.update = True
  562.         self.source = GtkMusicList()
  563.         self.source.listeners.append(AudioMasteringMusicListener(self))
  564.         self._AudioMastering__gateway = AudioMastering.MusicListGateway(self)
  565.         gtk.VBox.__init__(self)
  566.         filename = application.locations.get_data_file('serpentine.glade')
  567.         g = glade.XML(filename, 'audio_container')
  568.         self.add(g.get_widget('audio_container'))
  569.         self._AudioMastering__setup_track_list(g)
  570.         self._AudioMastering__setup_container_misc(g)
  571.  
  572.     
  573.     def __set_disc_size(self, size):
  574.         if not size in AudioMastering.disc_sizes:
  575.             raise AssertionError
  576.         self._AudioMastering__disc_size = size
  577.         self._AudioMastering__size_list.set_active(AudioMastering.disc_sizes.index(size))
  578.         self.update_disc_usage()
  579.         e = operations.Event(self)
  580.         for l in self.listeners:
  581.             if hasattr(l, 'on_disc_size_changed'):
  582.                 l.on_disc_size_changed(e)
  583.                 continue
  584.         
  585.  
  586.     music_list_gateway = property((lambda self: self._AudioMastering__gateway))
  587.     music_list = property((lambda self: self.source))
  588.     disc_size = property((lambda self: self._AudioMastering__disc_size), __set_disc_size, doc = 'Represents the disc size, in seconds.')
  589.     disc_size_widget = property((lambda self: self._AudioMastering__size_list))
  590.     
  591.     def __setup_container_misc(self, g):
  592.         self._AudioMastering__size_list = g.get_widget('size_list')
  593.         self._AudioMastering__usage_label = g.get_widget('usage_label')
  594.         self._AudioMastering__usage_gauge = SerpentineUsage(self)
  595.         self._AudioMastering__usage_gauge.widget.show()
  596.         self._AudioMastering__usage_gauge.widget.set_size_request(92, 92)
  597.         hbox = g.get_widget('disc_details')
  598.         hbox.pack_start(self._AudioMastering__usage_gauge.widget, expand = False, fill = False)
  599.         self._AudioMastering__capacity_exceeded = g.get_widget('capacity_exceeded')
  600.         self._AudioMastering__size_list.connect('changed', self._AudioMastering__on_size_changed)
  601.         self._AudioMastering__size_list.set_active(AudioMastering.SIZE_74)
  602.  
  603.     
  604.     def __setup_track_list(self, g):
  605.         lst = g.get_widget('track_list')
  606.         lst.set_model(self.source.model)
  607.         r = gtk.CellRendererText()
  608.         col = gtk.TreeViewColumn(_('Track'), r)
  609.         col.set_cell_data_func(r, self._AudioMastering__generate_track)
  610.         r = gtk.CellRendererText()
  611.         r.set_property('editable', True)
  612.         r.connect('edited', self._AudioMastering__on_title_edited)
  613.         lst.append_column(col)
  614.         col = gtk.TreeViewColumn('Title', r, text = self.source.model.index_of('title'))
  615.         lst.append_column(col)
  616.         r = gtk.CellRendererText()
  617.         r.set_property('editable', True)
  618.         r.connect('edited', self._AudioMastering__on_artist_edited)
  619.         col = gtk.TreeViewColumn(_('Artist'), r, text = self.source.model.index_of('artist'))
  620.         lst.append_column(col)
  621.         r = gtk.CellRendererText()
  622.         col = gtk.TreeViewColumn(_('Duration'), r, text = self.source.model.index_of('time'))
  623.         lst.append_column(col)
  624.         self._AudioMastering__selection = lst.get_selection()
  625.         self._AudioMastering__selection.connect('changed', self._AudioMastering__selection_changed)
  626.         self._AudioMastering__selection.set_mode(gtk.SELECTION_MULTIPLE)
  627.         lst.set_reorderable(True)
  628.         lst.enable_model_drag_source(gtk.gdk.BUTTON1_MASK, AudioMastering.DND_TARGETS, gtk.gdk.ACTION_DEFAULT | gtk.gdk.ACTION_MOVE)
  629.         lst.enable_model_drag_dest(AudioMastering.DND_TARGETS, gtk.gdk.ACTION_DEFAULT | gtk.gdk.ACTION_MOVE)
  630.         lst.connect('drag_data_received', self._AudioMastering__on_dnd_drop)
  631.         lst.connect('drag_data_get', self._AudioMastering__on_dnd_send)
  632.  
  633.     
  634.     def __generate_track(self, col, renderer, tree_model, treeiter, user_data = None):
  635.         index = tree_model.get_path(treeiter)[0]
  636.         renderer.set_property('text', index + 1)
  637.  
  638.     
  639.     def __on_size_changed(self, *args):
  640.         self.disc_size = AudioMastering.disc_sizes[self._AudioMastering__size_list.get_active()]
  641.  
  642.     
  643.     def __on_title_edited(self, cell, path, new_text, user_data = None):
  644.         self.source[path]['title'] = new_text
  645.  
  646.     
  647.     def __on_artist_edited(self, cell, path, new_text, user_data = None):
  648.         self.source[path]['artist'] = new_text
  649.  
  650.     
  651.     def __on_dnd_drop(self, treeview, context, x, y, selection, info, timestamp, user_data = None):
  652.         data = selection.data
  653.         hints_list = []
  654.         insert = None
  655.         drop_info = treeview.get_dest_row_at_pos(x, y)
  656.         if drop_info:
  657.             (insert, insert_before) = drop_info
  658.             if not isinstance(insert, TupleType):
  659.                 raise AssertionError, len(insert) == 1
  660.             (insert,) = insert
  661.             if insert_before != gtk.TREE_VIEW_DROP_BEFORE and insert_before != gtk.TREE_VIEW_DROP_INTO_OR_BEFORE:
  662.                 insert += 1
  663.                 if insert == len(self.source):
  664.                     insert = None
  665.                 
  666.             
  667.             del insert_before
  668.         
  669.         del drop_info
  670.         if selection.type == 'application/x-rhythmbox-source':
  671.             return None
  672.         elif selection.type == 'SERPENTINE_ROW':
  673.             (store, path_list) = self._AudioMastering__selection.get_selected_rows()
  674.             if not path_list or len(path_list) != 1:
  675.                 return None
  676.             
  677.             (path,) = path_list
  678.             row = dict(self.source[path])
  679.             del self.source[path]
  680.             if len(self.source) == insert:
  681.                 insert = None
  682.             
  683.             if insert is not None:
  684.                 self.source.insert(insert, row)
  685.             else:
  686.                 self.source.append(row)
  687.             return None
  688.         
  689.         for line in data.split('\n'):
  690.             line = line.strip()
  691.             if len(line) < 1 or line == '\x00':
  692.                 continue
  693.             
  694.             if not '\x00' not in line:
  695.                 raise AssertionError, 'Malformed DnD string: %s' % line
  696.             hint = {
  697.                 'location': line }
  698.             hints_list.append(hint)
  699.         
  700.         self.music_list_gateway.add_hints(hints_list, insert).start()
  701.  
  702.     
  703.     def __on_dnd_send(self, widget, context, selection, target_type, timestamp):
  704.         (store, path_list) = self._AudioMastering__selection.get_selected_rows()
  705.         if not path_list or len(path_list) == 1:
  706.             raise AssertionError
  707.         (path,) = path_list
  708.         selection.set(selection.target, 8, self.source[path]['location'])
  709.  
  710.     
  711.     def __hig_duration(self, duration):
  712.         hig_duration = ''
  713.         minutes = duration / 60
  714.         if minutes:
  715.             if not minutes == 1 or _('minute'):
  716.                 pass
  717.             hig_duration = '%s %s' % (minutes, _('minutes'))
  718.         
  719.         seconds = duration % 60
  720.         if seconds:
  721.             if not seconds == 1 or _('second'):
  722.                 pass
  723.             hig_secs = '%s %s' % (seconds, _('seconds'))
  724.             if len(hig_duration):
  725.                 hig_duration += _(' and ')
  726.             
  727.             hig_duration += hig_secs
  728.         
  729.         return hig_duration
  730.  
  731.     
  732.     def get_preferences(self):
  733.         return self._application().preferences
  734.  
  735.     
  736.     def get_media_duration(self):
  737.         total = self.source.total_duration
  738.         num_tracks = len(self.source)
  739.         if num_tracks > 0 and self.get_preferences().useGap:
  740.             total += (num_tracks - 1) * 2
  741.         
  742.         return total
  743.  
  744.     
  745.     def update_disc_usage(self):
  746.         if not self.update:
  747.             return None
  748.         
  749.         if self.source.total_duration > self.disc_size:
  750.             self._AudioMastering__capacity_exceeded.show()
  751.         else:
  752.             self._AudioMastering__capacity_exceeded.hide()
  753.         while gtk.events_pending():
  754.             gtk.main_iteration(True)
  755.         if self.source.total_duration > 0:
  756.             duration = self._AudioMastering__disc_size - self.source.total_duration
  757.             if duration > 0:
  758.                 dur = _('%s remaining') % self._AudioMastering__hig_duration(duration)
  759.             else:
  760.                 dur = _('%s overlaping') % self._AudioMastering__hig_duration(abs(duration))
  761.         else:
  762.             dur = _('Empty')
  763.         self._AudioMastering__usage_label.set_text(dur)
  764.         e = operations.Event(self)
  765.         for l in self.listeners:
  766.             l.on_contents_changed(e)
  767.         
  768.  
  769.     
  770.     def __selection_changed(self, treeselection):
  771.         e = operations.Event(self)
  772.         for l in self.listeners:
  773.             l.on_selection_changed(e)
  774.         
  775.  
  776.     
  777.     def get_selected(self):
  778.         '''Returns the selected indexes'''
  779.         (store, path_list) = self._AudioMastering__selection.get_selected_rows()
  780.         if path_list is None:
  781.             return []
  782.         
  783.         indexes = []
  784.         for p in path_list:
  785.             if not len(p) == 1:
  786.                 raise AssertionError
  787.             indexes.append(*p)
  788.         
  789.         return indexes
  790.  
  791.     
  792.     def remove_selected(self):
  793.         self.source.delete_many(self.get_selected())
  794.  
  795.     
  796.     def count_selected(self):
  797.         return self._AudioMastering__selection.count_selected_rows()
  798.  
  799.  
  800. if __name__ == '__main__':
  801.     win = gtk.Window()
  802.     win.connect('delete-event', gtk.main_quit)
  803.     w = AudioMastering()
  804.     w.show()
  805.     win.add(w)
  806.     win.show()
  807.     w.add_file(sys.argv[1])
  808.     w.source.clear()
  809.     gtk.main()
  810.  
  811.