Conduit FSpot improvements
- From: Thomas Van Machelen <thomas vanmachelen gmail com>
- To: Conduit <conduit-list gnome org>
- Cc: Stephane Delcroix <stephane delcroix org>
- Subject: Conduit FSpot improvements
- Date: Thu, 27 Sep 2007 22:00:28 +0200
Hi all,
When you apply this [1] patch from gnome bugzilla to your f-spot
installation, and apply the attached patch to your conduit source code,
then you'll be able to two way sync your f-spot with existing conduit
dataproviders.
To do so, I extended the f-spot dbus interface; and created a new
conduit dataprovider that uses that dbus interface to put data into
f-spot and to query for information.
How it works: the conduit patch contains a fspotfactory that detects
when the patched f-spot is started or closed and creates the actual
dataprovider accordingly. Once the dataprovider is there you're able to
create conduits that sync to or from f-spot.
What needs work:
* currently there is no notification from f-spot when an image is
imported, removed or changed. So you have to manually sync in conduit
* when removing images from f-spot there is no way to tell it to also
delete it from the drive
Regards,
Thomas
[1] http://bugzilla.gnome.org/show_bug.cgi?id=480754
Index: conduit/dataproviders/FspotModule/FspotDbusModule.py
===================================================================
--- conduit/dataproviders/FspotModule/FspotDbusModule.py (revision 0)
+++ conduit/dataproviders/FspotModule/FspotDbusModule.py (revision 0)
@@ -0,0 +1,262 @@
+import os
+import gtk
+import gobject
+import dbus
+
+import conduit
+from conduit import logd
+import conduit.Utils as Utils
+import conduit.Exceptions
+import conduit.DataProvider as DataProvider
+import conduit.datatypes.File as File
+
+MODULES = {
+ "FSpotFactory" : { "type": "dataprovider-factory" }
+}
+
+NAME_IDX = 0
+
+SERVICE_PATH = "org.gnome.FSpot"
+PHOTOREMOTE_IFACE = "org.gnome.FSpot.PhotoRemoteControl"
+PHOTOREMOTE_PATH = "/org/gnome/FSpot/PhotoRemoteControl"
+
+TAGREMOTE_IFACE = "org.gnome.FSpot.TagRemoteControl"
+TAGREMOTE_PATH = "/org/gnome/FSpot/TagRemoteControl"
+
+def _get_photoremote():
+ bus = dbus.SessionBus()
+
+ try:
+ remote_object = bus.get_object(SERVICE_PATH, PHOTOREMOTE_PATH)
+ return dbus.Interface(remote_object, PHOTOREMOTE_IFACE)
+ except dbus.exceptions.DBusException:
+ return None
+
+def _get_tagremote():
+ bus = dbus.SessionBus()
+
+ try:
+ remote_object = bus.get_object(SERVICE_PATH, TAGREMOTE_PATH)
+ return dbus.Interface(remote_object, TAGREMOTE_IFACE)
+ except dbus.exceptions.DBusException:
+ return None
+
+class FSpotDbusTwoWay(DataProvider.TwoWay):
+ _name_ = "F-Spot DBus Photos"
+ _description_ = "Sync your F-Spot photos over DBus"
+ _category_ = DataProvider.CATEGORY_PHOTOS
+ _module_type_ = "twoway"
+ _in_type_ = "file"
+ _out_type_ = "file"
+ _icon_ = "f-spot"
+
+ def __init__(self, *args):
+ DataProvider.TwoWay.__init__(self)
+ self.need_configuration(True)
+
+ try:
+ # get photo remote control
+ self.photo_remote = _get_photoremote()
+
+ # get tag remote control
+ self.tag_remote = _get_tagremote()
+ except:
+ print "Fuckage"
+
+ #Settings
+ self.enabledTags = []
+ self.photos = []
+ self.has_roll = False
+
+ def _get_all_tags(self):
+ return self.tag_remote.GetTagNames ()
+
+ def initialize(self):
+ return True
+
+ def refresh(self):
+ DataProvider.TwoWay.refresh(self)
+
+ # get ids
+ self.photos = self.photo_remote.Query (self.enabledTags)
+
+ def get_all(self):
+ """
+ return the list of photo id's
+ """
+ DataProvider.TwoWay.get_all(self)
+ return self.photos
+
+ def get(self, LUID):
+ """
+ Get the File object for a file with a given id
+ """
+ DataProvider.TwoWay.get(self, LUID)
+
+ properties = self.photo_remote.GetPhotoProperties (LUID)
+
+ photouri = properties['Uri']
+
+ f = File.File(URI=photouri)
+ f.set_UID(LUID)
+ f.set_open_URI(photouri)
+
+ return f
+
+ def put (self, file, overwrite, LUID=None):
+ """
+ Import a file into the f-spot catalog
+ """
+ # Update not supported
+ if LUID != None:
+ return
+
+ # create roll if necessary
+ if not self.has_roll:
+ self.prepare_roll ()
+
+ # import the photo
+ id = self.photo_remote.ImportPhoto (file.get_local_uri(), True, self.enabledTags)
+
+ # check the return value
+ if id == -1:
+ raise SynchroniseError ()
+
+ # return id (cast to string for pickle)
+ return str(id)
+
+ def delete(self, LUID):
+ """
+ Remove the photo from the f-spot catalog
+ TODO: add support for deleting from drive also
+ """
+ self.photo_remote.RemovePhoto (LUID)
+
+ def finish(self):
+ """
+ Round up, and don't forget the finish the import roll
+ """
+ DataProvider.TwoWay.finish(self)
+ self.photos = []
+ self.finish_roll ()
+
+ def prepare_roll (self):
+ self.photo_remote.PrepareRoll ()
+ self.has_roll = True
+
+ def finish_roll (self):
+ if not self.has_roll:
+ return
+
+ self.photo_remote.FinishRoll ()
+ self.has_roll = False
+
+ def configure(self, window):
+ def col1_toggled_cb(cell, path, model ):
+ #not because we get this cb before change state
+ checked = not cell.get_active()
+
+ model[path][1] = checked
+ val = model[path][NAME_IDX]
+
+ if checked and val not in self.enabledTags:
+ self.enabledTags.append(val)
+ elif not checked and val in self.enabledTags:
+ self.enabledTags.remove(val)
+
+ logd("Toggle '%s'(%s) to: %s" % (model[path][NAME_IDX], val, checked))
+ return
+
+ tree = Utils.dataprovider_glade_get_widget(
+ __file__,
+ "config.glade",
+ "FspotConfigDialog"
+ )
+ tagtreeview = tree.get_widget("tagtreeview")
+ #Build a list of all the tags
+ list_store = gtk.ListStore(gobject.TYPE_STRING, #NAME_IDX
+ gobject.TYPE_BOOLEAN, #active
+ )
+ #Fill the list store
+ i = 0
+ for tag in self._get_all_tags():
+ list_store.append((tag,tag in self.enabledTags))
+ i += 1
+ #Set up the treeview
+ tagtreeview.set_model(list_store)
+ #column 1 is the tag name
+ tagtreeview.append_column( gtk.TreeViewColumn('Tag Name',
+ gtk.CellRendererText(),
+ text=NAME_IDX)
+ )
+ #column 2 is a checkbox for selecting the tag to sync
+ renderer1 = gtk.CellRendererToggle()
+ renderer1.set_property('activatable', True)
+ renderer1.connect( 'toggled', col1_toggled_cb, list_store )
+ tagtreeview.append_column( gtk.TreeViewColumn('Enabled',
+ renderer1,
+ active=1)
+ )
+
+ dlg = tree.get_widget("FspotConfigDialog")
+ dlg.set_transient_for(window)
+
+ response = dlg.run()
+ if response == gtk.RESPONSE_OK:
+ self.set_configured(True)
+ dlg.destroy()
+
+ def set_configuration(self, config):
+ self.enabledTags = []
+ for tag in config.get("tags", []):
+ self.enabledTags.append(str(tag))
+
+ self.set_configured(True)
+
+ def get_configuration(self):
+ return {"tags": self.enabledTags}
+
+ def get_UID(self):
+ return Utils.get_user_string()
+
+class FSpotFactory (DataProvider.DataProviderFactory):
+ """
+ This class handles the availability of fspot. If it's not running at startup
+ it will listen to dbus until the photo remote control is created. If that happens
+ the FSpot dataprovider pops. Same way it will go down again when fspot goes
+ down
+ """
+ fspot_key = None
+
+ def __init__ (self, **kwargs):
+ DataProvider.DataProviderFactory.__init__(self, **kwargs)
+
+ # connect to singals
+ bus = dbus.SessionBus()
+ bus.add_signal_receiver(self.handle_photoremote_up, dbus_interface=PHOTOREMOTE_IFACE, signal_name="RemoteUp")
+ bus.add_signal_receiver(self.handle_photoremote_down, dbus_interface=PHOTOREMOTE_IFACE, signal_name="RemoteDown")
+
+ # apparently we can't create dataproviders at init time yet,
+ # so wait a bit to check for fspot
+ gobject.timeout_add(2000, self._check_for_fspot)
+
+ def _check_for_fspot(self):
+ if _get_photoremote():
+ self.handle_photoremote_up()
+
+ def handle_photoremote_up(self):
+ if self.fspot_key:
+ return
+
+ self.fspot_key = self.emit_added (
+ klass = FSpotDbusTwoWay,
+ initargs=(),
+ category=DataProvider.CATEGORY_PHOTOS)
+
+ def handle_photoremote_down(self):
+ if not self.fspot_key:
+ return
+
+ self.emit_removed(self.fspot_key)
+ self.fspot_key = None
+
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]