Hi all,

currently, if you use multiple library locations, browser state for
additional library sources is lost when rhythmbox is restarted.
I made a patch making additional library sources preserve state across
restarts[1].

Until now, additional library sources can only be added by editing the
gconf key "/apps/rhythmbox/library_locations" using e.g. gconf-editor -
so I am planing to edit the preferences dialog to allow selection of
multiple library locations (see attached python demo).

There are some implementation details that have to be decided upon:

* If you have configured multiple library locations, and you choose to
remove one of them, what should happen to the songs from the removed
location? Should they be removed from the library or should they be
kept? If they are removed, what about the metadata (play counts,
ratings, etc.)?
Currently, if you remove a song from the library (by right-clicking a
song and selecting "Remove"), the removal time is recorded in RhythmDB
and metadata is kept for a certain time (configurable via the gconf key
"/apps/rhythmbox/grace_period"). So if you add the song again to your
library during grace_time, metadata will still be there. Should this
apply to songs from a removed library location as well?

* If you rip a CD using rb, where should the files be saved? Currently,
they are put in the first library location. Should there be some ui to
choose where to put them?

* Should there be drag and drop support, allowing to move files between
different library sources within rb?

Please try the patch from [1] and the attached python demo of the new
preferences dialog I have in mind, and tell me your thoughts.


Regards,

Chris

[1] http://bugzilla.gnome.org/show_bug.cgi?id=523162
#!/usr/bin/python

import gobject
import gtk
import gtk.glade
import urlparse

LIBRARY_PREFS_GLADE = "library-prefs-example.glade"

COL_LIBRARY_LOCATION = 0
COL_NEW_FILES_LOCATION = 1

class UI:

        def __init__ (self):
                self.gladeXML = gtk.glade.XML (LIBRARY_PREFS_GLADE)
                self.gladeXML.signal_autoconnect (self)
                locations_tv = self.gladeXML.get_widget 
("library_locations_treeview")
                self.library_locations_filechooserdialog = 
self.gladeXML.get_widget ("library_locations_filechooserdialog")
                self.remove_library_location_messagedialog = 
self.gladeXML.get_widget ("remove_library_location_messagedialog")
                self.keep_metadata_checkbutton = self.gladeXML.get_widget 
("keep_metadata_checkbutton")
                
                self.locations = gtk.ListStore (gobject.TYPE_STRING, 
gobject.TYPE_BOOLEAN)
                self.locations_tree_selection = locations_tv.get_selection ()
                self.locations_tree_selection.set_mode (gtk.SELECTION_MULTIPLE)
                locations_tv.set_model (self.locations)
                locations_column = gtk.TreeViewColumn ("Library Locations")
                locations_column.set_expand (True)
                locations_tv.append_column (locations_column)
                cr = gtk.CellRendererText ()
                locations_column.pack_start (cr, True)
                locations_column.add_attribute (cr, 'text', 
COL_LIBRARY_LOCATION)

                new_files_column = gtk.TreeViewColumn ("Put new files here")
                new_files_column.set_expand (False)
                locations_tv.append_column (new_files_column)
                cr = gtk.CellRendererToggle ()
                cr.set_radio (True)
                cr.connect ("toggled", self.on_new_files_location_toggled)
                new_files_column.pack_start (cr, True)
                new_files_column.add_attribute (cr, 'active', 
COL_NEW_FILES_LOCATION)

        def run (self):
                gtk.main ()

        def run_library_locations_filechooserdialog (self):
                locations = []
                resp = self.library_locations_filechooserdialog.run ()
                if resp == gtk.RESPONSE_OK:
                        locations = 
self.library_locations_filechooserdialog.get_uris ()
                self.library_locations_filechooserdialog.hide ()
                return locations

        def new_files_location_toggled_foreach_func (self, model, path, it, 
toggled):
                if int (path[0]) == int (toggled):
                        model.set_value (it, COL_NEW_FILES_LOCATION, True)
                else:
                        model.set_value (it, COL_NEW_FILES_LOCATION, False)
                return False

        def on_new_files_location_toggled (self, cr, path):
                self.locations.foreach 
(self.new_files_location_toggled_foreach_func, path)
                return False

        def on_quit (self, *args, **kwargs):
                gtk.main_quit ()
        
        def location_is_valid_foreach_func (self, model, path, it, data):
                loc = urlparse.urlsplit (model.get_value (it, 
COL_LIBRARY_LOCATION))
                new = data[0]
                if new.scheme == loc.scheme:
                        if new.path == loc.path or new.path.startswith 
(loc.path) or loc.path.startswith (new.path):
                                data[1] = False
                                return True
        
        def location_is_valid (self, location):
                data = [urlparse.urlsplit (location), True]
                self.locations.foreach (self.location_is_valid_foreach_func, 
data)
                return data[1]
                
        def update_new_files_location_foreach_func (self, model, path, it, 
found):
                if model.get_value (it, COL_NEW_FILES_LOCATION):
                        found[0] = it
                        return False
        
        def update_new_files_location (self):
                found = [None]
                self.locations.foreach 
(self.update_new_files_location_foreach_func, found)
                if not found[0]:
                        gobject.idle_add (self.on_new_files_location_toggled, 
None, 0)
                return False

        def on_button_add_clicked (self, button):
                locations = self.run_library_locations_filechooserdialog ()
                location_added = False
                invalid_locations = []
                for loc in locations:
                        if self.location_is_valid (loc):
                                self.locations.append ([loc, False])
                                location_added = True
                        else:
                                invalid_locations.append (loc)

                if location_added:
                        gobject.idle_add (self.update_new_files_location)

                if invalid_locations:
                        dlg = gtk.MessageDialog 
(parent=self.gladeXML.get_widget ("window1"),
                                        flags=gtk.DIALOG_MODAL | 
gtk.DIALOG_DESTROY_WITH_PARENT,
                                        type=gtk.MESSAGE_ERROR,
                                        buttons=gtk.BUTTONS_OK,
                                        message_format="Some location(s) could 
not be added")
                        dlg.format_secondary_text ("The following location(s) 
could not be added to the list of library locations:\n\n"
                                        "%s\n\n"
                                        "Possible reasons: either the location 
itself, "
                                        "one of its subfolders, or one of its 
parent folders is already added.\n"
                                        "Nested folders can not be added as 
library locations." % 
                                        "\n".join (invalid_locations))
                        dlg.run ()
                        dlg.destroy ()
        
        def on_button_remove_clicked (self, button):
                resp = self.remove_library_location_messagedialog.run ()
                if resp == gtk.RESPONSE_OK:
                        keep_metadata = 
self.keep_metadata_checkbutton.get_active ()
                        if keep_metadata:
                                print "Would remove songs from library, keeping 
metadata in rhythmdb."
                        else:
                                print "Would remove songs from library, 
removing metadata from rhythmdb."
                        (model, pathlist) = 
self.locations_tree_selection.get_selected_rows ()
                        pathlist.reverse ()
                        new_files_location_removed = False
                        for path in pathlist:
                                it = model.get_iter (path)
                                new_files_location_removed = 
(new_files_location_removed
                                                or model.get_value (it, 
COL_NEW_FILES_LOCATION))
                                model.remove (it)
                        if new_files_location_removed:
                                gobject.idle_add 
(self.update_new_files_location)
                self.remove_library_location_messagedialog.hide ()


if __name__ == '__main__':
        ui = UI ()
        ui.run ()

Attachment: library-prefs-example.glade
Description: application/glade

_______________________________________________
rhythmbox-devel mailing list
rhythmbox-devel@gnome.org
http://mail.gnome.org/mailman/listinfo/rhythmbox-devel

Reply via email to