conduit r1882 - in trunk: . conduit po tools/eog-plugin tools/nautilus-extension tools/totem-plugin



Author: jstowers
Date: Fri Feb 20 06:23:38 2009
New Revision: 1882
URL: http://svn.gnome.org/viewvc/conduit?rev=1882&view=rev

Log:
2009-02-20  John Stowers  <john stowers gmail com>

	* conduit/Makefile.am:
	* conduit/libconduit.py: Create a common python
	library which handles a remote conduit instance
	via DBus.

	* tools/eog-plugin/conduit.py:
	* tools/nautilus-extension/conduit.py:
	* tools/totem-plugin/conduit.py: Use this new common
	library for considerable code savings.

	* tools/eog-plugin/config.glade:
	* tools/eog-plugin/Makefile.am: Delete config.glade, it
	was not used.



Added:
   trunk/conduit/libconduit.py
Removed:
   trunk/tools/eog-plugin/config.glade
Modified:
   trunk/ChangeLog
   trunk/conduit/Makefile.am
   trunk/po/POTFILES.skip
   trunk/tools/eog-plugin/Makefile.am
   trunk/tools/eog-plugin/conduit.py
   trunk/tools/nautilus-extension/conduit.py
   trunk/tools/totem-plugin/conduit.py

Modified: trunk/conduit/Makefile.am
==============================================================================
--- trunk/conduit/Makefile.am	(original)
+++ trunk/conduit/Makefile.am	Fri Feb 20 06:23:38 2009
@@ -19,6 +19,7 @@
 	__init__.py \
 	Knowledge.py \
 	Logging.py \
+	libconduit.py \
 	Main.py \
 	MappingDB.py \
 	Module.py \

Added: trunk/conduit/libconduit.py
==============================================================================
--- (empty file)
+++ trunk/conduit/libconduit.py	Fri Feb 20 06:23:38 2009
@@ -0,0 +1,306 @@
+import os
+import gobject
+import gtk
+import dbus, dbus.glib
+
+APPLICATION_DBUS_IFACE="org.conduit.Application"
+CONDUIT_DBUS_IFACE="org.conduit.Conduit"
+EXPORTER_DBUS_IFACE="org.conduit.Exporter"
+DATAPROVIDER_DBUS_IFACE="org.conduit.DataProvider"
+SYNCSET_DBUS_IFACE="org.conduit.SyncSet"
+
+SYNCSET_GUI_PATH = '/syncset/gui'
+SYNCSET_NOGUI_PATH = '/syncset/dbus'
+
+class ConduitWrapper:
+
+    CONFIG_PATH='~/.conduit/test-plugin'
+    NAME_IDX=0
+    URI_IDX=1
+    STATUS_IDX=2
+    PB_IDX=3
+
+    def __init__(self, conduit, name, store):
+        self.conduit = conduit
+        self.name = name
+        self.store = store
+        self.rowref = None
+        self.configured = False
+        self.pendingSync = False
+
+        self.conduit.connect_to_signal(
+                        "SyncProgress",
+                        self._on_sync_progress,
+                        dbus_interface=CONDUIT_DBUS_IFACE
+                        )
+        self.conduit.connect_to_signal(
+                        "SyncCompleted",
+                        self._on_sync_completed,
+                        dbus_interface=CONDUIT_DBUS_IFACE
+                        )
+        self.conduit.connect_to_signal(
+                        "SyncStarted",
+                        self._on_sync_started,
+                        dbus_interface=CONDUIT_DBUS_IFACE
+                        )
+
+    def _get_configuration(self):
+        """
+        Gets the latest configuration for a given
+        dataprovider
+        """
+        config_path = os.path.expanduser(self.CONFIG_PATH)
+
+        if not os.path.exists(os.path.join(config_path, self.name)):
+            return
+
+        f = open(os.path.join(config_path, self.name), 'r')
+        xml = f.read()
+        f.close()
+
+        return xml
+
+    def _save_configuration(self, xml):
+        """
+        Saves the configuration XML from a given dataprovider again
+        """
+        config_path = os.path.expanduser(self.CONFIG_PATH)
+
+        if not os.path.exists(config_path):
+            os.mkdir(config_path)
+
+        f = open(os.path.join(config_path, self.name), 'w')
+        f.write(xml)
+        f.close()
+
+    def _get_rowref(self):
+        if self.rowref == None:
+            self.add_rowref()
+        return self.rowref
+
+    def _configure_reply_handler(self):
+        #save the configuration
+        xml = self.conduit.SinkGetConfigurationXml()
+        self._save_configuration(xml)
+        self.configured = True
+
+        #check if a sync was waiting for the conduit (sink) to be configured
+        if self.pendingSync == True:
+            self.pendingSync = False
+            self.conduit.Sync(dbus_interface=CONDUIT_DBUS_IFACE)
+
+    def _configure_error_handler(self, error):
+        pass
+
+    def _on_sync_started(self):
+        self.store.set_value(self._get_rowref(), self.STATUS_IDX, "uploading")
+
+    def _on_sync_progress(self, progress, uids):
+        uris = [str(i) for i in uids]
+        delete = []
+
+        treeiter = self.store.iter_children(self._get_rowref())
+        while treeiter:
+            if self.store.get_value(treeiter, self.URI_IDX) in uris:
+                delete.append(treeiter)
+            treeiter = self.store.iter_next(treeiter)
+
+        for d in delete:
+            self.store.remove(d)
+
+        #for uri in uids:
+        #    rowref = self._get_rowref_for_photo(str(uri))
+        #    print "\t%s - %s" % (uri, rowref)
+        #    print "\t",self.photoRefs
+        
+    def _on_sync_completed(self, abort, error, conflict):
+        rowref = self._get_rowref()
+        if abort == False and error == False:
+            self.clear()
+            #update the status
+            self.store.set_value(rowref, self.STATUS_IDX, "finished")
+        else:
+            #show the error message in the conduit gui
+            self.store.set_value(rowref, self.STATUS_IDX, "error")
+
+    def _add_uri(self, uri):
+        return self.conduit.AddData(uri, dbus_interface=EXPORTER_DBUS_IFACE)
+
+    def _add_item(self, filename, uri, status, pixbuf):
+        rowref = self._get_rowref()
+        self.store.append(rowref,(
+                    filename,       #ConduitWrapper.NAME_IDX
+                    uri,            #ConduitWrapper.URI_IDX
+                    status,         #ConduitWrapper.STATUS_IDX
+                    pixbuf)         #ConduitWrapper.PB_IDX
+        )
+
+    def _add_rowref(self, name, uri, status, pixbuf):
+        self.rowref = self.store.append(None,(
+                            name,   #ConduitWrapper.NAME_IDX
+                            uri,    #ConduitWrapper.URI_IDX
+                            status, #ConduitWrapper.STATUS_IDX
+                            pixbuf) #ConduitWrapper.PB_IDX
+        )
+
+    def clear(self):
+        rowref = self._get_rowref()
+        #delete all the items from the list of items to upload
+        delete = []
+        child = self.store.iter_children(rowref)
+        while child != None:
+            delete.append(child)
+            child = self.store.iter_next(child)
+        #need to do in two steps so we dont modify the store while iterating
+        for d in delete:
+            self.store.remove(d)
+
+    def sync(self):
+        if self.configured == True:
+            self.conduit.Sync(dbus_interface=CONDUIT_DBUS_IFACE)
+        else:
+            #defer the sync until the conduit has been configured
+            self.pendingSync = True
+            #configure the sink and perform the actual synchronisation
+            #when the configuration is finished, this way the GUI doesnt
+            #block on the call
+            self.conduit.SinkConfigure(
+                                reply_handler=self._configure_reply_handler,
+                                error_handler=self._configure_error_handler,
+                                dbus_interface=EXPORTER_DBUS_IFACE
+                                )
+
+    def add_item(self, pixbuf, uri):
+        if self._add_uri(uri):
+            #add to the store
+            self._add_item(
+                    filename=uri.split("/")[-1],
+                    uri=uri,
+                    status="",
+                    pixbuf=pixbuf
+            )
+
+    def add_rowref(self):
+        raise NotImplementedError
+
+class ConduitApplicationWrapper(gobject.GObject):
+
+    __gsignals__ = {
+        "conduit-started" : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, [gobject.TYPE_BOOLEAN]),
+        }
+       
+    def __init__(self, conduitWrapperKlass, store=True, debug=False):
+        gobject.GObject.__init__(self)
+        self.conduitWrapperKlass = conduitWrapperKlass
+        self.debug = debug
+        self.app = None
+        self.conduits = {}
+        self.dps = []
+
+        if store:
+            #the liststore with icons of the images to be uploaded        
+            self.store = gtk.TreeStore(
+                                str,                #ConduitWrapper.NAME_IDX
+                                str,                #ConduitWrapper.URI_IDX
+                                str,                #ConduitWrapper.STATUS_IDX
+                                gtk.gdk.Pixbuf      #ConduitWrapper.PB_IDX
+                                )
+
+        self.dbus_iface = dbus.Interface(
+            dbus.SessionBus().get_object('org.freedesktop.DBus', '/org/freedesktop/DBus'), 
+            'org.freedesktop.DBus'
+        )
+        self.dbus_iface.connect_to_signal("NameOwnerChanged", self._on_name_owner_changed)
+
+    def _debug(self, msg):
+        if self.debug:
+            print "CON: ", msg
+
+    def _get_conduit_app(self):
+        try:
+            self.app = dbus.Interface(
+                        dbus.SessionBus().get_object(APPLICATION_DBUS_IFACE,"/"),
+                        APPLICATION_DBUS_IFACE
+            )
+        except dbus.exceptions.DBusException:
+            self._debug("Could not connect to conduit")
+            self.app = None
+        return self.app
+
+    def _get_available_dps(self):
+        if self.app != None:
+            self.dps = self.app.GetAllDataProviders()
+
+    def _on_name_owner_changed(self, name, oldOwner, newOwner):
+        if name == APPLICATION_DBUS_IFACE:
+            if self.dbus_iface.NameHasOwner(APPLICATION_DBUS_IFACE):
+                self._get_conduit_app()
+                self._get_available_dps()
+                self._debug("Conduit started")
+            else:
+                self._debug("Conduit stopped")
+                self.app = None
+                self.dps = []
+            self.emit("conduit-started", self.connected())
+
+    def build_conduit(self, sinkName):
+        a = self.get_dataproviders()
+        if sinkName in a:
+            realName = a[sinkName]
+            self._debug("Building exporter conduit %s (%s)" % (sinkName, realName))
+            path = self.app.BuildExporter(realName)
+            exporter = dbus.SessionBus().get_object(CONDUIT_DBUS_IFACE,path)
+            self.conduits[sinkName] = self.conduitWrapperKlass(
+                                                conduit=exporter,
+                                                name=sinkName,
+                                                store=self.store
+            )
+        else:
+            self._debug("Could not build Conduit %s" % sinkName)
+
+    def get_application(self):
+        return self.app
+
+    def get_dataproviders(self):
+        #Split of the key part of the name
+        a = {}
+        for n in self.dps:
+            a[n.split(":")[0]] = str(n)
+        return a
+
+    def upload(self, name, uri, pixbuf):
+        if self.connected():
+            if name not in self.conduits:
+                self.build_conduit(name)
+
+            if uri != None:
+                self.conduits[name].add_item(
+                                    pixbuf=pixbuf,
+                                    uri=uri
+                                    )
+
+    def connect_to_conduit(self, startConduit):
+        #check if conduit is running
+        if self.dbus_iface.NameHasOwner(APPLICATION_DBUS_IFACE):
+            self._debug("Conduit already running")
+            self._get_conduit_app()
+            self._get_available_dps()
+            return True
+        elif startConduit:
+            self._debug("Starting conduit via DBus activation")
+            self.dbus_iface.StartServiceByName(APPLICATION_DBUS_IFACE, 0)
+            return False
+
+    def sync(self):
+        if self.connected():
+            for c in self.conduits:
+                self.conduits[c].sync()
+
+    def clear(self):
+        if self.connected():
+            for c in self.conduits:
+                self.conduits[c].clear()
+
+    def connected(self):
+        return self.app != None
+

Modified: trunk/po/POTFILES.skip
==============================================================================
--- trunk/po/POTFILES.skip	(original)
+++ trunk/po/POTFILES.skip	Fri Feb 20 06:23:38 2009
@@ -1,9 +1,9 @@
 conduit/Main.py
+conduit/libconduit.py
 data/conduit.desktop.in
-tools/eog-plugin/config.glade
+tools/eog-plugin/conduit.py
 tools/totem-plugin/conduit.py
 tools/test-db-wrapper/main.glade
-tools/test-db-wrapper/main.glade
 conduit/modules/GoogleModule/contacts-config.glade
 conduit/modules/SynceModule.py
 conduit/modules/SettingsModule/GConfUtils.py

Modified: trunk/tools/eog-plugin/Makefile.am
==============================================================================
--- trunk/tools/eog-plugin/Makefile.am	(original)
+++ trunk/tools/eog-plugin/Makefile.am	Fri Feb 20 06:23:38 2009
@@ -1,10 +1,9 @@
 if ENABLE_EOG_PLUGIN
 nautextdir = $(EOG_PLUGIN_DIR)
-	nautext_DATA = conduit.py conduit.eog-plugin config.glade
+	nautext_DATA = conduit.py conduit.eog-plugin
 endif
 
 EXTRA_DIST = \
 	conduit.py \
 	conduit.eog-plugin \
-	config.glade \
 	README

Modified: trunk/tools/eog-plugin/conduit.py
==============================================================================
--- trunk/tools/eog-plugin/conduit.py	(original)
+++ trunk/tools/eog-plugin/conduit.py	Fri Feb 20 06:23:38 2009
@@ -1,19 +1,16 @@
 import os
 import eog
-import gtk, gtk.glade
+import gtk
 import dbus, dbus.glib
 
-#if this code is a bit convoluted and jumps around a lot
-#it is because I lazy initialize everything to minimise 
-#the work that occurs at startup time
-
-APPLICATION_DBUS_IFACE="org.conduit.Application"
-CONDUIT_DBUS_IFACE="org.conduit.Conduit"
-EXPORTER_DBUS_IFACE="org.conduit.Exporter"
-DATAPROVIDER_DBUS_IFACE="org.conduit.DataProvider"
+try:
+    import libconduit
+except ImportError:
+    import conduit.libconduit as libconduit
 
+DEBUG = True
+ICON_SIZE = 24
 MENU_PATH="/MainMenu/ToolsMenu/ToolsOps_2"
-
 SUPPORTED_SINKS = {
     "FlickrTwoWay"      :   "Upload to Flickr",
     "PicasaTwoWay"      :   "Upload to Picasa",
@@ -21,263 +18,56 @@
     "ShutterflySink"    :   "Upload to Shutterfly",
     "BoxDotNetTwoWay"   :   "Upload to Box.net",
     "FacebookSink"      :   "Upload to Facebook",
-    "IPodPhotoSink"     :   "Add to iPod",
-#    "TestImageSink"     :   "Test"
+    "IPodPhotoSink"     :   "Add to iPod"
 }
+if DEBUG:
+    SUPPORTED_SINKS["TestImageSink"] = "Test"
 
-ICON_SIZE = 24
-
-CONFIG_PATH='~/.conduit/eog-plugin'
-
-PB_IDX=0
-NAME_IDX=1
-URI_IDX=2
-STATUS_IDX=3
-
-class ConduitWrapper:
-    def __init__(self, conduit, name, store):
-        self.conduit = conduit
-        self.name = name
-        self.store = store
-        self.rowref = None
-        self.configured = False
-        self.pendingSync = False
-
-        self.conduit.connect_to_signal(
-                        "SyncProgress",
-                        self._on_sync_progress,
-                        dbus_interface=CONDUIT_DBUS_IFACE
-                        )
-        self.conduit.connect_to_signal(
-                        "SyncCompleted",
-                        self._on_sync_completed,
-                        dbus_interface=CONDUIT_DBUS_IFACE
-                        )
-        self.conduit.connect_to_signal(
-                        "SyncStarted",
-                        self._on_sync_started,
-                        dbus_interface=CONDUIT_DBUS_IFACE
-                        )
-
-    def _get_configuration(self):
-        """
-        Gets the latest configuration for a given
-        dataprovider
-        """
-        config_path = os.path.expanduser(CONFIG_PATH)
-
-        if not os.path.exists(os.path.join(config_path, self.name)):
-           return
-
-        f = open(os.path.join(config_path, self.name), 'r')
-        xml = f.read ()
-        f.close()
-
-        return xml
-           
-    def _save_configuration(self, xml):
-        """
-        Saves the configuration xml from a given dataprovider again
-        """
-        config_path = os.path.expanduser(CONFIG_PATH)
-
-        if not os.path.exists(config_path):
-           os.mkdir(config_path)
-
-        f = open(os.path.join(config_path, self.name), 'w')
-        f.write(xml)
-        f.close()
-
-    def _get_rowref(self):
-        if self.rowref == None:
-            #store the rowref in the store with the icon conduit gave us
-            info = self.conduit.SinkGetInformation(dbus_interface=EXPORTER_DBUS_IFACE)
-            pb = gtk.gdk.pixbuf_new_from_file_at_size(info['icon_path'], ICON_SIZE, ICON_SIZE)
-            desc = SUPPORTED_SINKS[self.name]
-            self.rowref = self.store.append(None,(
-                                pb,         #PB_IDX
-                                desc,       #NAME_IDX
-                                "",         #URI_IDX
-                                "ready")    #STATUS_IDX
-                                )
-        return self.rowref
-
-    def _configure_reply_handler(self):            
-        #save the configuration
-        xml = self.conduit.SinkGetConfigurationXml()
-        self._save_configuration(xml)
-        self.configured = True
-
-        #check if a sync was waiting for the conduit (sink) to be configured
-        if self.pendingSync == True:
-            self.pendingSync = False
-            self.conduit.Sync(dbus_interface=CONDUIT_DBUS_IFACE)
-
-    def _configure_error_handler(self, error):
-        pass
-
-    def _on_sync_started(self):
-        self.store.set_value(self._get_rowref(), STATUS_IDX, "uploading")
-
-    def _on_sync_progress(self, progress, uids):
-        uris = [str(i) for i in uids]
-        delete = []
-
-        treeiter = self.store.iter_children(self._get_rowref())
-        while treeiter:
-            if self.store.get_value(treeiter, URI_IDX) in uris:
-                delete.append(treeiter)
-            treeiter = self.store.iter_next(treeiter)
-
-        for d in delete:
-            self.store.remove(d)
-
-        #for uri in uids:
-        #    rowref = self._get_rowref_for_photo(str(uri))
-        #    print "\t%s - %s" % (uri, rowref)
-        #    print "\t",self.photoRefs
-        
-    def _on_sync_completed(self, abort, error, conflict):
-        rowref = self._get_rowref()
-        if abort == False and error == False:
-            self.clear()
-            #update the status
-            self.store.set_value(rowref, STATUS_IDX, "finished")
-        else:
-            #show the error message in the conduit gui
-            self.store.set_value(rowref, STATUS_IDX, "error")
-
-    def clear(self):
-        rowref = self._get_rowref()
-        #Delete all the images from the list of images to upload
-        delete = []
-        child = self.store.iter_children(rowref)
-        while child != None:
-            delete.append(child)
-            child = self.store.iter_next(child)
-        #need to do in two steps so we dont modify the store while 
-        #iterating
-        for d in delete:
-            self.store.remove(d)
-
-    def add_photo(self, pixbuf, uri):
-        ok = self.conduit.AddData(uri,dbus_interface=EXPORTER_DBUS_IFACE)
-        if ok == True:
-            #add to the store
-            rowref = self._get_rowref()
-            filename = uri.split("/")[-1]
-            self.store.append(rowref,(
-                        pixbuf,         #PB_IDX
-                        filename,       #NAME_IDX
-                        uri,            #URI_IDX
-                        "")             #STATUS_IDX
-                        )
-
-    def sync(self):
-        if self.configured == True:
-            self.conduit.Sync(dbus_interface=CONDUIT_DBUS_IFACE)
-        else:
-            #defer the sync until the conduit has been configured
-            self.pendingSync = True
-            # configure the sink; and perform the actual synchronisation
-            # when the configuration is finished, this way the eog gui doesnt
-            # block on the call
-            self.conduit.SinkConfigure(
-                                reply_handler=self._configure_reply_handler,
-                                error_handler=self._configure_error_handler,
-                                dbus_interface=EXPORTER_DBUS_IFACE
-                                )
-
-class ConduitApplicationWrapper:
-    def __init__(self, startConduit, addToGui):
-        self.addToGui = addToGui
-        self.app = None
-        self.conduits = {}
-        #the liststore with icons of the images to be uploaded        
-        self.store = gtk.TreeStore(
-                            gtk.gdk.Pixbuf,     #PB_IDX
-                            str,                #NAME_IDX
-                            str,                #URI_IDX
-                            str                 #STATUS_IDX
-                            )
-
-        if startConduit:
-            self.start()
-        else:
-            obj = self.bus.get_object('org.freedesktop.DBus', '/org/freedesktop/DBus') 
-            dbus_iface = dbus.Interface(obj, 'org.freedesktop.DBus')
-            if dbus_iface.NameHasOwner(APPLICATION_DBUS_IFACE):
-                self.start()
-            else:
-                raise Exception("Could not connect to conduit")
-        
-    def _build_conduit(self, sinkName):
-        #Split of the key part of the name
-        a = {}
-        for n in self.dps:
-            a[n.split(":")[0]] = str(n)
-
-        if sinkName in a:
-            realName = a[sinkName]
-            print "Building exporter conduit %s (%s)" % (sinkName, realName)
-            path = self.app.BuildExporter(realName)
-            exporter = dbus.SessionBus().get_object(CONDUIT_DBUS_IFACE,path)
-            self.conduits[sinkName] = ConduitWrapper(conduit=exporter, name=sinkName, store=self.store)
-
-    def upload(self, name, eogImage):
-        if self.connected():
-            if name not in self.conduits:
-                self._build_conduit(name)
-
-            if eogImage != None:
-                #proportionally scale the pixbuf            
-                thumb = eogImage.get_thumbnail()
-                pb = thumb.scale_simple(ICON_SIZE,ICON_SIZE,gtk.gdk.INTERP_BILINEAR)
-
-                #add the photo to the remote condui and the liststore
-                self.conduits[name].add_photo(
-                                        pixbuf=pb,
-                                        uri=eogImage.get_uri_for_display()
-                                        )
+class EogConduitWrapper(libconduit.ConduitWrapper):
 
+    CONFIG_PATH='~/.conduit/eog-plugin'
 
-    def start(self):
-        if not self.connected():
-            try:
-                remote_object = dbus.SessionBus().get_object(APPLICATION_DBUS_IFACE,"/")
-                self.app = dbus.Interface(remote_object, APPLICATION_DBUS_IFACE)
-                self.dps = self.app.GetAllDataProviders()
-            except dbus.exceptions.DBusException:
-                self.app = None
-                print "Conduit unavailable"
-
-    def sync(self):
-        if self.connected():
-            for c in self.conduits:
-                self.conduits[c].sync()
-
-    def clear(self):
-        if self.connected():
-            for c in self.conduits:
-                self.conduits[c].clear()
-
-    def connected(self):
-        return self.app != None
+    def add_rowref(self):
+        #store the rowref in the store with the icon conduit gave us
+        info = self.conduit.SinkGetInformation(dbus_interface=libconduit.EXPORTER_DBUS_IFACE)
+        desc = SUPPORTED_SINKS[self.name]
+        self._add_rowref(
+                name=desc,
+                uri="",
+                status="ready",
+                pixbuf=gtk.gdk.pixbuf_new_from_file_at_size(info['icon_path'], ICON_SIZE, ICON_SIZE)
+        )
 
 class ConduitPlugin(eog.Plugin):
     def __init__(self):
-        self.dir = os.path.abspath(os.path.join(__file__, ".."))
-        self.gladefile = os.path.join(self.dir, "config.glade")
-
-        self.conduit = ConduitApplicationWrapper(
-                                        startConduit=True,
-                                        addToGui=False
+        self.debug = DEBUG
+        self.conduit = libconduit.ConduitApplicationWrapper(
+                                        conduitWrapperKlass=EogConduitWrapper,
+                                        store=True,
+                                        debug=self.debug
                                         )
+        self.conduit.connect("conduit-started", self._on_conduit_started)
+        self.running = self.conduit.connect_to_conduit(startConduit=True)
+    
+    def _debug(self, msg):
+        if self.debug:
+            print "EOG: ", msg
+
+    def _on_conduit_started(self, sender, started):
+        self._debug("Conduit started: %s" % started)
+        self.running = started
+        self.box.set_sensitive(self.running)
 
     def _on_upload_clicked(self, sender, window):
-        currentImage = window.get_image()
+        eogImage = window.get_image()
         name = sender.get_property("name")
-        self.conduit.upload(name, currentImage)
+
+        if eogImage != None:
+            thumb = eogImage.get_thumbnail()
+            pb = thumb.scale_simple(ICON_SIZE,ICON_SIZE,gtk.gdk.INTERP_BILINEAR)
+            uri = eogImage.get_uri_for_display()
+
+            self.conduit.upload(name, uri, pb)
 
     def _on_sync_clicked(self, *args):
         self.conduit.sync()
@@ -300,19 +90,20 @@
         #the sidebar is a treeview where 
         #photos to upload are grouped by the
         #upload service, with a clear button and
-        #a upload button below
+        #an upload button below
 
-        box = gtk.VBox()
+        self.box = gtk.VBox()
+        self.box.set_sensitive(self.running)
         view = gtk.TreeView(self.conduit.store)
         view.connect("row-activated", self._on_row_activated)
         view.set_headers_visible(False)
 
-        box.pack_start(view,expand=True,fill=True)
+        self.box.pack_start(view,expand=True,fill=True)
         bbox = gtk.HButtonBox()
-        box.pack_start(bbox,expand=False)
+        self.box.pack_start(bbox,expand=False)
         
         #two colums, an icon and a description/name
-        col0 = gtk.TreeViewColumn("Pic", gtk.CellRendererPixbuf(), pixbuf=0)
+        col0 = gtk.TreeViewColumn("Pic", gtk.CellRendererPixbuf(), pixbuf=libconduit.ConduitWrapper.PB_IDX)
         view.append_column(col0)
         #second colum is the dataprovider name + status, or the filename 
         nameRenderer = gtk.CellRendererText()
@@ -332,7 +123,7 @@
         bbox.pack_start(clearbtn,expand=True)
 
         sidebar = window.get_sidebar()
-        sidebar.add_page("Photo Uploads", box)
+        sidebar.add_page("Photo Uploads", self.box)
         sidebar.show_all()
 
     def _prepare_tools_menu(self, window):
@@ -365,29 +156,25 @@
     			    top=False)
     			    
     def _name_data_func(self, column, cell_renderer, tree_model, rowref):
-        name = tree_model.get_value(rowref, NAME_IDX)
+        name = tree_model.get_value(rowref, libconduit.ConduitWrapper.NAME_IDX)
         #render the headers different to the data
         if tree_model.iter_depth(rowref) == 0:
-            status = tree_model.get_value(rowref, STATUS_IDX)
+            status = tree_model.get_value(rowref, libconduit.ConduitWrapper.STATUS_IDX)
             name = '%s <span foreground="grey" style="italic">(%s)</span>' % (name,status)
         cell_renderer.set_property("markup", name)
 
     def activate(self, window):
+        self._debug("Activate")
         #the sidebar and menu integration must be done once per eog window instance
-        if self.conduit.connected() == True:
-            self._prepare_sidebar(window) 
-            self._prepare_tools_menu(window)
+        self._prepare_sidebar(window) 
+        self._prepare_tools_menu(window)
 
     def deactivate(self, window):
-        pass
+        self._debug("Deactivate")
 
     def update_ui(self, window):
-        pass
+        self._debug("Update UI")
 
     def is_configurable(self):
         return False
 
-    def create_configure_dialog(self):
-        xml = gtk.glade.XML(self.gladefile, "ConfigDialog")
-        dlg = xml.get_widget("ConfigDialog")
-        return dlg

Modified: trunk/tools/nautilus-extension/conduit.py
==============================================================================
--- trunk/tools/nautilus-extension/conduit.py	(original)
+++ trunk/tools/nautilus-extension/conduit.py	Fri Feb 20 06:23:38 2009
@@ -27,37 +27,27 @@
 """
 
 import os
-
 import nautilus
 import dbus, dbus.glib
 
-# we only operate on directories
-SUPPORTED_FORMAT = 'x-directory/normal'
-
-#dbus interfaces
-APPLICATION_DBUS_IFACE='org.conduit.Application'
-DATAPROVIDER_DBUS_IFACE="org.conduit.DataProvider"
-CONDUIT_DBUS_IFACE="org.conduit.Conduit"
-SYNCSET_DBUS_IFACE="org.conduit.SyncSet"
-
-# supported sinks
+try:
+    import libconduit
+except ImportError:
+    import conduit.libconduit as libconduit
+
+DEBUG = True
+FOLDER_TWOWAY = "FolderTwoWay"
+FOLDER_TWOWAY_CONFIG = "<configuration><folder type='string'>%s</folder><folderGroupName type='string'>Home</folderGroupName><includeHidden type='bool'>False</includeHidden></configuration>"
+CONFIG_PATH = '~/.conduit/nautilus-extension'
 SUPPORTED_SINKS = {
     "FlickrTwoWay"      :   "Upload to Flickr",
     "PicasaTwoWay"      :   "Upload to Picasa",
     "SmugMugTwoWay"     :   "Upload to SmugMug",
     "BoxDotNetTwoWay"   :   "Upload to Box.net",
-#    "FolderTwoWay"      :   "Synchronize with Another Folder"
+    "FolderTwoWay"      :   "Synchronize with Another Folder"
 }
-
-# source dataprovider
-FOLDER_TWOWAY="FolderTwoWay"
-
-# configuration stuff
-FOLDER_TWOWAY_CONFIG ="<configuration><folder type='string'>%s</folder><folderGroupName type='string'>Home</folderGroupName><includeHidden type='bool'>False</includeHidden></configuration>"
-CONFIG_PATH='~/.conduit/nautilus-extension'
-
-# add to gui or dbus
-SYNCSET_PATH = '/syncset/gui'
+if DEBUG:
+    SUPPORTED_SINKS["TestFileSink"] = "Test"
 
 class ItemCallbackHandler:
     """
@@ -66,7 +56,7 @@
     """
     def __init__ (self, sink_name, conduitApplication):
         self.sink_name = sink_name
-        self.app = conduitApplication
+        self.conduitApp = conduitApplication
         self.conduit = None
 
     def activate_cb(self, menu, folder):
@@ -74,7 +64,9 @@
         This is the callback method that can be attached to the
         activate signal of a nautilus menu
         """
-        if not self.app:
+        if self.conduitApp.connected():
+            app = self.conduitApp.get_application()
+        else:
             return
 
         # it has got to be there
@@ -85,28 +77,28 @@
         uri = folder.get_uri()
         
         # check if they needed providers are available
-        dps = self.app.GetAllDataProviders()
+        dps = self.conduitApp.get_dataproviders()
 
         if not FOLDER_TWOWAY in dps and not self.sink_name in dps:
             return
 
         # create dataproviders
-        folder_twoway_path = self.app.GetDataProvider(FOLDER_TWOWAY)
-        sink_path = self.app.GetDataProvider(self.sink_name)
+        folder_twoway_path = app.GetDataProvider(dps[FOLDER_TWOWAY])
+        sink_path = app.GetDataProvider(dps[self.sink_name])
 
         bus = dbus.SessionBus()
 
         # set up folder config
-        folder_twoway = bus.get_object(DATAPROVIDER_DBUS_IFACE, folder_twoway_path)
+        folder_twoway = bus.get_object(libconduit.DATAPROVIDER_DBUS_IFACE, folder_twoway_path)
         folder_twoway.SetConfigurationXml(FOLDER_TWOWAY_CONFIG % uri)
         
         # get flickr dbus object
-        self.sink = bus.get_object(DATAPROVIDER_DBUS_IFACE, sink_path)
+        self.sink = bus.get_object(libconduit.DATAPROVIDER_DBUS_IFACE, sink_path)
         
         # now create conduit
-        conduit_path = self.app.BuildConduit (folder_twoway_path, sink_path)
-        self.conduit = bus.get_object(CONDUIT_DBUS_IFACE, conduit_path)
-        self.conduit.connect_to_signal("SyncCompleted", self.on_sync_completed, dbus_interface=CONDUIT_DBUS_IFACE)
+        conduit_path = app.BuildConduit (folder_twoway_path, sink_path)
+        self.conduit = bus.get_object(libconduit.CONDUIT_DBUS_IFACE, conduit_path)
+        self.conduit.connect_to_signal("SyncCompleted", self.on_sync_completed, dbus_interface=libconduit.CONDUIT_DBUS_IFACE)
 
         # check if we have configuration on disk; set it on dataprovider
         xml = self.get_configuration(self.sink_name)
@@ -115,8 +107,8 @@
             self.sink.SetConfigurationXml(xml)
             
         #Get the syncset
-        self.ss = bus.get_object(SYNCSET_DBUS_IFACE, SYNCSET_PATH)
-        self.ss.AddConduit(self.conduit, dbus_interface=SYNCSET_DBUS_IFACE)
+        self.ss = bus.get_object(libconduit.SYNCSET_DBUS_IFACE, libconduit.SYNCSET_GUI_PATH)
+        self.ss.AddConduit(self.conduit, dbus_interface=libconduit.SYNCSET_DBUS_IFACE)
 
         # configure the sink; and perform the actual synchronisation
         # when the configuration is finished
@@ -153,7 +145,7 @@
         f.close()
         
     def on_sync_completed(self, abort, error, conflict):
-        self.ss.DeleteConduit(self.conduit, dbus_interface=SYNCSET_DBUS_IFACE)
+        self.ss.DeleteConduit(self.conduit, dbus_interface=libconduit.SYNCSET_DBUS_IFACE)
         print "Finished"
 
     def _configure_reply_handler(self):
@@ -168,7 +160,7 @@
         self.save_configuration(self.sink_name, xml)
 
         # do it to me, baby, real good!
-        self.conduit.Sync(dbus_interface=CONDUIT_DBUS_IFACE)
+        self.conduit.Sync(dbus_interface=libconduit.CONDUIT_DBUS_IFACE)
 
     def _configure_error_handler(self, error):
         """
@@ -181,72 +173,53 @@
     This is the actual extension
     """
     def __init__(self):
-        obj = dbus.SessionBus().get_object('org.freedesktop.DBus', '/org/freedesktop/DBus') 
-        self.dbus_iface = dbus.Interface(obj, 'org.freedesktop.DBus')
-        self.dbus_iface.connect_to_signal("NameOwnerChanged", self._on_name_owner_changed)
-
-        self.conduitApp = None
-        self.dps = []
-        
-        #check if conduit is running
-        self._on_name_owner_changed(APPLICATION_DBUS_IFACE,'','')
-        
-    def _get_conduit_app (self):
-        bus = dbus.SessionBus()
-        try:
-            remote_object = bus.get_object(APPLICATION_DBUS_IFACE,"/")
-            return dbus.Interface(remote_object, APPLICATION_DBUS_IFACE)
-        except dbus.exceptions.DBusException:
-            print "COULD NOT CONNECT TO CONDUIT"
-            return None
-
-    def _populate_available_dps(self):
-        if self.conduitApp != None and self.dps == []:
-            for dp in self.conduitApp.GetAllDataProviders():
-                if dp in SUPPORTED_SINKS:
-                    self.dps.append(dp)
-
-    def _on_name_owner_changed(self, name, oldOwner, newOwner):
-        if name == APPLICATION_DBUS_IFACE:
-            if self.dbus_iface.NameHasOwner(APPLICATION_DBUS_IFACE):
-                self.conduitApp = self._get_conduit_app()
-                print "Conduit Started"
-            else:
-                print "Conduit Stopped"
-                self.conduitApp = None
-        
-    def get_file_items(self, window, files):
-        if self.conduitApp == None:
-            return
+        self.debug = DEBUG
+        self.conduit = libconduit.ConduitApplicationWrapper(
+                                        conduitWrapperKlass=None,
+                                        store=False,
+                                        debug=self.debug
+                                        )
+        self.conduit.connect("conduit-started", self._on_conduit_started)
+        self.conduit.connect_to_conduit(startConduit=False)
+        self.dps = self._get_dataproviders()
+
+    def _get_dataproviders(self):
+        #restrict dps to those we know about
+        return [dp for dp in self.conduit.get_dataproviders() if dp in SUPPORTED_SINKS]
 
-        # more than one selected?
-        if len(files) != 1:
-            return
+    def _on_conduit_started(self, sender, started):
+        self.dps = self._get_dataproviders()
 
-        file = files[0]
-
-        # must be a folder
-        if not file.get_mime_type () == SUPPORTED_FORMAT:
-            return
-
-        # add available items
-        self._populate_available_dps()
-        items = []
-        for dp in self.dps:
-            name = dp
-            desc = SUPPORTED_SINKS[dp]
-
-            #make the menu item
-            item = nautilus.MenuItem(
-                                'Conduit::synchronizeTo%s' % name,
-                                desc,
-                                '',
-                                'image-x-generic')
-
-            cb = ItemCallbackHandler(name, self.conduitApp)
-            item.connect('activate', cb.activate_cb, file)
-            items.append(item)
+    def get_file_items(self, window, files):
+        if self.conduit.connected():
+            if len(files) == 1:
+                file_ = files[0]
+                if file_.is_directory():
+                    submenu = nautilus.Menu()
+                    for dp in self.dps:
+                        name = dp
+                        desc = SUPPORTED_SINKS[dp]
+
+                        #make the menu item
+                        item = nautilus.MenuItem(
+                                            'Conduit::SynchronizeTo%s' % name,
+                                            desc,
+                                            '',
+                                            'image-x-generic'
+                        )
+                        cb = ItemCallbackHandler(name, self.conduit)
+                        item.connect('activate', cb.activate_cb, file_)
+
+                        submenu.append_item(item)
+
+                    menuitem = nautilus.MenuItem(
+                                            'Conduit::',
+                                            'Conduit',
+                                            '',
+                                            'conduit'
+                    )
+                    menuitem.set_submenu(submenu)
+                    return menuitem,
 
-        # return all items
-        return items
+        return None
        

Modified: trunk/tools/totem-plugin/conduit.py
==============================================================================
--- trunk/tools/totem-plugin/conduit.py	(original)
+++ trunk/tools/totem-plugin/conduit.py	Fri Feb 20 06:23:38 2009
@@ -3,296 +3,118 @@
 import gtk
 import dbus, dbus.glib
 
-"""Based on John Stowers' plugin for EOG to upload images to Flickr via Conduit."""
-
-APPLICATION_DBUS_IFACE="org.conduit.Application"
-CONDUIT_DBUS_IFACE="org.conduit.Conduit"
-EXPORTER_DBUS_IFACE="org.conduit.Exporter"
-DATAPROVIDER_DBUS_IFACE="org.conduit.DataProvider"
+try:
+    import libconduit
+except ImportError:
+    import conduit.libconduit as libconduit
 
+DEBUG = True
 MENU_PATH="/tmw-menubar/movie/properties"
-
 SUPPORTED_SINKS = {
-	"YouTubeTwoWay" : "Upload to YouTube",
-#	"TestVideoSink" : "Test"
+    "YouTubeTwoWay" : "Upload to YouTube",
 }
+if DEBUG:
+    SUPPORTED_SINKS["TestVideoSink"] = "Test"
 
-ICON_SIZE = 24
+class TotemConduitWrapper(libconduit.ConduitWrapper):
 
-CONFIG_PATH='~/.conduit/totem-plugin'
+    CONFIG_PATH='~/.conduit/totem-plugin'
 
-NAME_IDX=0
-URI_IDX=1
-STATUS_IDX=2
-
-class ConduitWrapper:
-	def __init__ (self, conduit, name, store):
-		self.conduit = conduit
-		self.name = name
-		self.store = store
-		self.rowref = None
-		self.configured = False
-		self.pendingSync = False
-
-		self.conduit.connect_to_signal ("SyncProgress",
-						self._on_sync_progress,
-						dbus_interface = CONDUIT_DBUS_IFACE)
-		self.conduit.connect_to_signal ("SyncCompleted",
-						self._on_sync_completed,
-						dbus_interface = CONDUIT_DBUS_IFACE)
-		self.conduit.connect_to_signal ("SyncStarted",
-						self._on_sync_started,
-						dbus_interface = CONDUIT_DBUS_IFACE)
-
-	def _get_configuration (self):
-		"""Gets the latest configuration for a given
-		dataprovider"""
-		config_path = os.path.expanduser (CONFIG_PATH)
-
-		if not os.path.exists (os.path.join (config_path, self.name)):
-			return
-
-		f = open (os.path.join (config_path, self.name), 'r')
-		xml = f.read ()
-		f.close()
-
-		return xml
-
-	def _save_configuration (self, xml):
-		"""Saves the configuration XML from a given dataprovider again"""
-		config_path = os.path.expanduser (CONFIG_PATH)
-
-		if not os.path.exists (config_path):
-			os.mkdir (config_path)
-
-		f = open (os.path.join (config_path, self.name), 'w')
-		f.write (xml)
-		f.close()
-
-	def _get_rowref (self):
-		if self.rowref == None:
-			# Store the rowref in the store with the icon Conduit gave us
-			info = self.conduit.SinkGetInformation (dbus_interface = EXPORTER_DBUS_IFACE)
-			desc = SUPPORTED_SINKS[self.name]
-			self.rowref = self.store.append (None,
-							 (desc,		#NAME_IDX
-							  "",		#URI_IDX
-							  "ready"))	#STATUS_IDX
-		return self.rowref
-
-	def _configure_reply_handler (self):			
-		# Save the configuration
-		xml = self.conduit.SinkGetConfigurationXml ()
-		self._save_configuration (xml)
-		self.configured = True
-
-		# Check if a sync was waiting for the Conduit (sink) to be configured
-		if self.pendingSync == True:
-			self.pendingSync = False
-			self.conduit.Sync (dbus_interface = CONDUIT_DBUS_IFACE)
-
-	def _configure_error_handler (self, error):
-		pass
-
-	def _on_sync_started (self):
-		self.store.set_value (self._get_rowref(), STATUS_IDX, "uploading")
-
-	def _on_sync_progress (self, progress, uids):
-		uris = [str(i) for i in uids]
-		delete = []
-
-		treeiter = self.store.iter_children (self._get_rowref ())
-		while treeiter:
-			if self.store.get_value (treeiter, URI_IDX) in uris:
-				delete.append (treeiter)
-			treeiter = self.store.iter_next (treeiter)
-
-		for d in delete:
-			self.store.remove (d)
-
-		#for uri in uids:
-		#	rowref = self._get_rowref_for_photo(str(uri))
-		#	print "\t%s - %s" % (uri, rowref)
-		#	print "\t",self.photoRefs
-		
-	def _on_sync_completed (self, abort, error, conflict):
-		rowref = self._get_rowref ()
-		if abort == False and error == False:
-			self.clear ()
-			# Update the status
-			self.store.set_value (rowref, STATUS_IDX, "finished")
-		else:
-			# Show the error message in the Conduit GUI
-			self.store.set_value (rowref, STATUS_IDX, "error")
-
-	def clear (self):
-		rowref = self._get_rowref ()
-		# Delete all the videos from the list of videos to upload
-		delete = []
-		child = self.store.iter_children (rowref)
-		while child != None:
-			delete.append (child)
-			child = self.store.iter_next (child)
-		# Need to do in two steps so we don't modify the store while iterating
-		for d in delete:
-			self.store.remove (d)
-
-	def add_video (self, uri):
-		ok = self.conduit.AddData (uri, dbus_interface = EXPORTER_DBUS_IFACE)
-		if ok == True:
-			# Add to the store
-			rowref = self._get_rowref ()
-			filename = uri.split ("/")[-1]
-			self.store.append (rowref,
-					   (filename,	# NAME_IDX
-					    uri,	# URI_IDX
-					    ""))	# STATUS_IDX
-
-	def sync (self):
-		if self.configured == True:
-			self.conduit.Sync (dbus_interface = CONDUIT_DBUS_IFACE)
-		else:
-			# Defer the sync until the Conduit has been configured
-			self.pendingSync = True
-			# Configure the sink and perform the actual synchronisation
-			# when the configuration is finished, this way the Totem GUI doesn't
-			# block on the call
-			self.conduit.SinkConfigure (reply_handler = self._configure_reply_handler,
-						    error_handler = self._configure_error_handler,
-						    dbus_interface = EXPORTER_DBUS_IFACE)
-
-class ConduitApplicationWrapper:
-	def __init__ (self, startConduit, addToGui):
-		self.addToGui = addToGui
-		self.app = None
-		self.conduits = {}
-		# The liststore of videos to be uploaded
-		self.store = gtk.TreeStore (str,		#NAME_IDX
-					    str,		#URI_IDX
-					    str)		#STATUS_IDX
-
-		if startConduit:
-			self.start ()
-		else:
-			obj = self.bus.get_object ('org.freedesktop.DBus', '/org/freedesktop/DBus') 
-			dbus_iface = dbus.Interface (obj, 'org.freedesktop.DBus')
-			if dbus_iface.NameHasOwner (APPLICATION_DBUS_IFACE):
-				self.start ()
-			else:
-				raise Exception ("Could not connect to Conduit.")
-		
-	def _build_conduit (self, sinkName):
-		if sinkName in self.dps:
-			print "Building exporter Conduit %s" % sinkName
-			path = self.app.BuildExporter (sinkName)
-			exporter = dbus.SessionBus ().get_object (CONDUIT_DBUS_IFACE, path)
-			self.conduits[sinkName] = ConduitWrapper (conduit = exporter, name = sinkName, store = self.store)
-		else:
-			print "Could not build Conduit %s" % sinkName
-
-	def upload (self, name, uri):
-		if self.connected ():
-			if name not in self.conduits:
-				self._build_conduit (name)
-
-			if uri != None:
-				# Add the video to the remote Conduit and the liststore
-				self.conduits[name].add_video (uri)
-
-	def start (self):
-		if not self.connected ():
-			try:
-				remote_object = dbus.SessionBus ().get_object (APPLICATION_DBUS_IFACE, "/")
-				self.app = dbus.Interface (remote_object, APPLICATION_DBUS_IFACE)
-				self.dps = self.app.GetAllDataProviders () 
-			except dbus.exceptions.DBusException:
-				self.app = None
-				print "Conduit unavailable"
-
-	def sync (self):
-		if self.connected ():
-			for c in self.conduits:
-				self.conduits[c].sync ()
-
-	def clear (self):
-		if self.connected ():
-			for c in self.conduits:
-				self.conduits[c].clear ()
-
-	def connected (self):
-		return self.app != None
-
-class ConduitPlugin (totem.Plugin):
-	def __init__ (self):
-		self.conduit = ConduitApplicationWrapper (startConduit = True,
-							  addToGui = False)
-
-	def _on_upload_clicked (self, action, totem_object):
-		current_uri = totem_object.get_current_mrl ()
-		name = action.get_property ("name")
-
-		# Add the file to the list and sync it immediately
-		self.conduit.upload (name, current_uri)
-		self.conduit.sync ()
-
-	def _on_file_opened (self, totem_object, mrl):
-		self.top_level_action.set_sensitive (True)
-
-	def _on_file_closed (self, totem_object):
-		self.top_level_action.set_sensitive (False)
-
-	def activate (self, totem_object):
-		totem_object.connect ("file-opened", self._on_file_opened)
-		totem_object.connect ("file-closed", self._on_file_closed)
-
-		ui_action_group = gtk.ActionGroup ("ConduitPluginActions")
-		manager = totem_object.get_ui_manager ()
-
-		# Make an action for each sink
-		for sink_name in SUPPORTED_SINKS:
-			desc = SUPPORTED_SINKS[sink_name]
-			action = gtk.Action (name = sink_name,
-					     stock_id = "internet",
-					     label = desc,
-					     tooltip = "")
-			action.connect ("activate", self._on_upload_clicked, totem_object)
-			ui_action_group.add_action (action)
-
-		# Create a top-level menu
-		self.top_level_action = gtk.Action (name = "sync",
-						stock_id = "internet",
-						label = _("_Share"),
-						tooltip = "")
-		ui_action_group.add_action (self.top_level_action)
-
-		manager.insert_action_group (ui_action_group, -1)
-
-		mid = manager.new_merge_id ()
-		manager.add_ui (merge_id = mid,
-				path = MENU_PATH,
-				name = "sync",
-				action = "sync",
-				type = gtk.UI_MANAGER_MENU,
-				top = False)
-
-		# Add each action to the menu
-		for sink_name in SUPPORTED_SINKS:
-			mid = manager.new_merge_id ()
-			manager.add_ui (merge_id = mid,
-					path = "/tmw-menubar/movie/sync/",
-					name = sink_name, 
-					action = sink_name,
-					type = gtk.UI_MANAGER_MENUITEM, 
-					top = False)
-
-		# Make sure the menu starts disabled
-		self.top_level_action.set_sensitive (False)
+    def add_rowref(self):
+        #store the rowref in the store with the icon conduit gave us
+        info = self.conduit.SinkGetInformation(dbus_interface=libconduit.EXPORTER_DBUS_IFACE)
+        desc = SUPPORTED_SINKS[self.name]
+        self._add_rowref(
+                name=desc,
+                uri="",
+                status="ready",
+                pixbuf=None
+        )
+
+class ConduitPlugin(totem.Plugin):
+    def __init__(self):
+        self.debug = DEBUG
+        self.conduit = libconduit.ConduitApplicationWrapper(
+                                        conduitWrapperKlass=TotemConduitWrapper,
+                                        store=True,
+                                        debug=self.debug
+                                        )
+        self.conduit.connect("conduit-started", self._on_conduit_started)
+        self.running = self.conduit.connect_to_conduit(startConduit=True)
+        self.opened = False
+
+    def _on_conduit_started(self, sender, started):
+        self.running = started
+        self.top_level_action.set_sensitive(self.opened and self.running)
+
+    def _on_upload_clicked(self, action, totem_object):
+        current_uri = totem_object.get_current_mrl()
+        name = action.get_property("name")
+
+        # Add the file to the list and sync it immediately
+        self.conduit.upload(name, current_uri, None)
+        self.conduit.sync()
+
+    def _on_file_opened(self, totem_object, mrl):
+        self.opened = True
+        self.top_level_action.set_sensitive(self.running)
+
+    def _on_file_closed(self, totem_object):
+        self.opened = False
+        self.top_level_action.set_sensitive(False)
+
+    def activate(self, totem_object):
+        totem_object.connect("file-opened", self._on_file_opened)
+        totem_object.connect("file-closed", self._on_file_closed)
+
+        ui_action_group = gtk.ActionGroup("ConduitPluginActions")
+        manager = totem_object.get_ui_manager()
+
+        # Make an action for each sink
+        for sink_name in SUPPORTED_SINKS:
+            desc = SUPPORTED_SINKS[sink_name]
+            action = gtk.Action(name = sink_name,
+                         stock_id = "internet",
+                         label = desc,
+                         tooltip = "")
+            action.connect("activate", self._on_upload_clicked, totem_object)
+            ui_action_group.add_action(action)
+
+        # Create a top-level menu
+        self.top_level_action = gtk.Action(name = "sync",
+                        stock_id = "internet",
+                        label = _("_Share"),
+                        tooltip = "")
+        ui_action_group.add_action(self.top_level_action)
+
+        manager.insert_action_group(ui_action_group, -1)
+
+        mid = manager.new_merge_id()
+        manager.add_ui(merge_id = mid,
+                path = MENU_PATH,
+                name = "sync",
+                action = "sync",
+                type = gtk.UI_MANAGER_MENU,
+                top = False)
+
+        # Add each action to the menu
+        for sink_name in SUPPORTED_SINKS:
+            mid = manager.new_merge_id()
+            manager.add_ui(merge_id = mid,
+                    path = "/tmw-menubar/movie/sync/",
+                    name = sink_name, 
+                    action = sink_name,
+                    type = gtk.UI_MANAGER_MENUITEM, 
+                    top = False)
+
+        # Make sure the menu starts disabled
+        self.top_level_action.set_sensitive(False)
 
-	def deactivate (self, window):
-		pass
+    def deactivate(self, window):
+        pass
 
-	def update_ui (self, window):
-		pass
+    def update_ui(self, window):
+        pass
 
-	def is_configurable (self):
-		return False
+    def is_configurable(self):
+        return False



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]