conduit r1262 - in trunk: . conduit conduit/modules/NetworkModule tools/eog-plugin



Author: jstowers
Date: Wed Jan 23 11:43:35 2008
New Revision: 1262
URL: http://svn.gnome.org/viewvc/conduit?rev=1262&view=rev

Log:
2008-01-23  John Stowers  <john stowers gmail com>

	* conduit/Main.py: Improve help message

	* conduit/modules/NetworkModule/Client.py:
	* conduit/modules/NetworkModule/Server.py:
	* conduit/modules/NetworkModule/XMLRPCUtils.py: Dont create a new Peerlister
	every time. Small improvements to hopefully improve cancellation.

	* tools/eog-plugin/conduit.py:
	* tools/eog-plugin/config.glade: Add Facebook and ShutterFly support. Clear
	the sidebar when sync finishes



Modified:
   trunk/ChangeLog
   trunk/conduit/Main.py
   trunk/conduit/modules/NetworkModule/Client.py
   trunk/conduit/modules/NetworkModule/Server.py
   trunk/conduit/modules/NetworkModule/XMLRPCUtils.py
   trunk/tools/eog-plugin/conduit.py
   trunk/tools/eog-plugin/config.glade

Modified: trunk/conduit/Main.py
==============================================================================
--- trunk/conduit/Main.py	(original)
+++ trunk/conduit/Main.py	Wed Jan 23 11:43:35 2008
@@ -53,13 +53,16 @@
         iconify = False
         self.ui = "gtk"
         try:
-            opts, args = getopt.getopt(sys.argv[1:], "hs:ciu:", 
-                ["help", "settings=", "console", "iconify", "ui="])
+            opts, args = getopt.getopt(sys.argv[1:], "hvs:ciu:", 
+                ["help", "version", "settings=", "console", "iconify", "ui="])
             #parse args
             for o, a in opts:
                 if o in ("-h", "--help"):
                     self._usage()
                     sys.exit(0)
+                if o in ("-v", "--version"):
+                    print "%s %s" % (conduit.APPNAME, conduit.APPVERSION)
+                    sys.exit(0)
                 if o in ("-s", "--settings"):
                      self.settingsFile = os.path.join(os.getcwd(), a)
                 if o in ("-c", "--console"):
@@ -161,14 +164,18 @@
             self.Quit()
 
     def _usage(self):
-        print """Conduit: Usage
-$ %s [OPTIONS]
-
+        print """Usage: conduit [OPTIONS] - Synchronize things
 OPTIONS:
-    -h, --help          Print this help notice.
-    -c, --console       Launch Conduit with no GUI) (default=no).
-    -s, --settings=FILE Override saving conduit settings to FILE
-    -i, --iconify       Iconify on startup (default=no)""" % sys.argv[0]
+    -h, --help          Show this message.
+    -c, --console       Launch with no GUI.
+                        (default=no)
+    -s, --settings=FILE Save settings to FILE.
+                        (default=~/.conduit/settings.xml)
+    -i, --iconify       Iconify on startup.
+                        (default=no)
+    -u, --ui=NAME       Run with the specified UI
+                        (default=gtk)
+    -v, --version       Show version information"""
 
     @dbus.service.method(APPLICATION_DBUS_IFACE, in_signature='', out_signature='b')
     def HasGUI(self):

Modified: trunk/conduit/modules/NetworkModule/Client.py
==============================================================================
--- trunk/conduit/modules/NetworkModule/Client.py	(original)
+++ trunk/conduit/modules/NetworkModule/Client.py	Wed Jan 23 11:43:35 2008
@@ -30,14 +30,14 @@
 
         self.categories = {}
         self.dataproviders = {}
-        self.peers = []
+        self.peers = {}
         try:
             self.monitor = Peers.AvahiMonitor(self.host_available, self.host_removed)
         except:
             log.warn("Error starting client")
 
     def quit(self):
-        for p in self.peers:
+        for p in self.peers.values():
             p.stop()
 
     def host_available(self, name, host, address, port, extra_info):
@@ -45,40 +45,34 @@
         Callback which is triggered when a dataprovider is advertised on 
         a remote conduit instance
         """
-        log.debug("Remote host '%s' detected" % host)
-
-        # Path to remote data services
         url = "http://%s"; % host
+        log.debug("Remote host '%s' detected" % url)
 
-        # Create a categories group for this host?
-        if not self.categories.has_key(url):
+        if not self.peers.has_key(url):
+            #Create a category group for this host
             self.categories[url] = DataProviderCategory.DataProviderCategory("On %s" % host, "computer", host)
-        
-        # Create a dataproviders list for this host
-        self.dataproviders[url] = {}
-
-        # Request all dp's for this host. Because there is no
-        # avahi signal when the text entry in a avahi publish group
-        # is changed, we must poll detected peers....
-        request = _PeerLister(url, port)
-        request.connect("complete", self.dataprovider_process)
-        request.start()
-        self.peers.append(request)
+            # Create a dataproviders list for this host
+            self.dataproviders[url] = {}
+            # Request all dp's for this host. Because there is no
+            # avahi signal when the text entry in a avahi publish group
+            # is changed, we must poll detected peers....
+            request = _PeerLister(url, port)
+            request.connect("complete", self.dataprovider_process)
+            request.start()
+            self.peers[url] = request
 
     def host_removed(self, url):
         """
         Callback which is triggered when a host is no longer available
         """
         log.debug("Remote host '%s' removed" % url)
-
-        if self.categories.has_key(url):
+        if self.peers.has_key(url):
             self.categories.remove(url)
-        
-        if self.dataproviders.has_key(url):
-            for uid, dp in self.dataproviders[url].iteritems():
+            for uid, dp in self.dataproviders[url].items():
                 self.dataprovider_removed(dp)
             self.dataproviders.remove(url)
-                    
+            self.peers.remove(url)
+
     def dataprovider_process(self, peerLister):
         """
         """
@@ -170,15 +164,14 @@
         server = xmlrpclib.Server("%s:%s/" % (self.url,self.port))
         #Gross cancellable spinning loop...
         while not self.stopped:
-            while self._ticks > (self.FREQ / self.SLEEP):
+            if self._ticks > (self.FREQ / self.SLEEP):
                 try:
                     self.data_out = server.list_shared_dataproviders()
                     gobject.idle_add(self.emit, "complete")
-                    self._ticks = 0
-                except socket.error:
+                except:
                     #If the server has died or not started yet
                     pass
-                                   
+                self._ticks = 0
             else:
                 time.sleep(self.SLEEP)
                 self._ticks += 1

Modified: trunk/conduit/modules/NetworkModule/Server.py
==============================================================================
--- trunk/conduit/modules/NetworkModule/Server.py	(original)
+++ trunk/conduit/modules/NetworkModule/Server.py	Wed Jan 23 11:43:35 2008
@@ -114,11 +114,11 @@
 
     def quit(self):
         #stop all the xmlrpc servers
+        for server in self.shared.values():
+            server.stop()
+
         if self.peerAnnouncer != None:
             self.peerAnnouncer.stop()
-    
-        for server in self.shared.values():
-            server.stop()           
 
     def share_dataprovider(self, dpw):
         """

Modified: trunk/conduit/modules/NetworkModule/XMLRPCUtils.py
==============================================================================
--- trunk/conduit/modules/NetworkModule/XMLRPCUtils.py	(original)
+++ trunk/conduit/modules/NetworkModule/XMLRPCUtils.py	Wed Jan 23 11:43:35 2008
@@ -77,13 +77,18 @@
         while not inputObjects and not self.closed:
             try:
                 inputObjects, outputObjects, errorObjects = select.select([self.socket], [], [], 0.2)
-                return self.socket.accept()
+                sock, addr = self.socket.accept()
+                return (sock, addr)
+            except socket.timeout:
+                if self.closed:
+                    raise
+            except socket.error:
+                #Occurs at shutdown, raise to stop serving
+                if self.closed:
+                    raise
             except select.error:
                 #Occurs sometimes at start up, race condition, ignore
                 pass
-            except socket.error:
-                #Occurs at shutdown, raise to stop serving
-                raise
                 
     def start(self):
         threading.Thread(target=self.serve).start()

Modified: trunk/tools/eog-plugin/conduit.py
==============================================================================
--- trunk/tools/eog-plugin/conduit.py	(original)
+++ trunk/tools/eog-plugin/conduit.py	Wed Jan 23 11:43:35 2008
@@ -18,7 +18,9 @@
     "FlickrTwoWay"      :   "Upload to Flickr",
     "PicasaTwoWay"      :   "Upload to Picasa",
     "SmugMugTwoWay"     :   "Upload to SmugMug",
+    "ShutterflySink"    :   "Upload to Shutterfly",
     "BoxDotNetTwoWay"   :   "Upload to Box.net",
+    "FacebookSink"      :   "Upload to Facebook",
     "TestImageSink"     :   "Test"
 }
 
@@ -113,18 +115,28 @@
         self.store.set_value(rowref, STATUS_IDX, "finished")
         
     def _on_sync_completed(self, abort, error, conflict):
-        #FIXME:
-        #on error or abort, add to the conduit gui syncset to allow
-        #the user to debug it. 
         rowref = self._get_rowref()
-        #update the status
-        self.store.set_value(rowref, STATUS_IDX, "finished")
-        #tell the view to redraw
-        self.store.row_changed(
-                    self.store.get_path(rowref),
-                    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:
@@ -154,10 +166,9 @@
                                 )
 
 class ConduitApplicationWrapper:
-    def __init__(self):
-        #conduit dbus application
+    def __init__(self, startConduit, addToGui):
+        self.addToGui = addToGui
         self.app = None
-        #the conduit dbus objects
         self.conduits = {}
         #the liststore with icons of the images to be uploaded        
         self.store = gtk.TreeStore(
@@ -167,18 +178,16 @@
                             str                 #STATUS_IDX
                             )
 
-        #setup the DBus connection
-        self._connect_to_conduit_application()
-
-    def _connect_to_conduit_application(self):
-            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"
-
+        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
@@ -191,31 +200,50 @@
             if name not in self.conduits:
                 self._build_conduit(name)
 
-            imageuri = eogImage.get_uri_for_display()
-            
-            #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
-            print "Upload ", name, eogImage
-            self.conduits[name].add_photo(pixbuf=pb,uri=imageuri)
+            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()
+                                        )
+
+
+    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):
-        for c in self.conduits:
-            self.conduits[c].sync()
+        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):
-        #are we connected to conduit dbus interface
         return self.app != None
 
 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.window = None
-        self.conduit = ConduitApplicationWrapper()
+
+        self.conduit = ConduitApplicationWrapper(
+                                        startConduit=True,
+                                        addToGui=False
+                                        )
 
     def _on_upload_clicked(self, sender, window):
         currentImage = window.get_image()
@@ -225,6 +253,9 @@
     def _on_sync_clicked(self, *args):
         self.conduit.sync()
 
+    def _on_clear_clicked(self, *args):
+        self.conduit.clear()
+
     def _on_row_activated(self, treeview, path, view_column):
         #check the user didnt click a header row
         rowref = treeview.get_model().get_iter(path)
@@ -261,11 +292,15 @@
         view.append_column(col1)
         
         #upload and clear button
-        okbtn = gtk.Button(stock=gtk.STOCK_OK)
+        okbtn = gtk.Button(label="Synchronize")
+        okbtn.set_image(
+                gtk.image_new_from_stock(gtk.STOCK_REFRESH,gtk.ICON_SIZE_BUTTON)
+                )
         okbtn.connect("clicked",self._on_sync_clicked)
         clearbtn = gtk.Button(stock=gtk.STOCK_CLEAR)
-        bbox.pack_start(okbtn)
-        bbox.pack_start(clearbtn)
+        clearbtn.connect("clicked",self._on_clear_clicked)        
+        bbox.pack_start(okbtn,expand=True)
+        bbox.pack_start(clearbtn,expand=True)
 
         sidebar = window.get_sidebar()
         sidebar.add_page("Photo Uploads", box)
@@ -305,24 +340,20 @@
         #render the headers different to the data
         if tree_model.iter_depth(rowref) == 0:
             status = tree_model.get_value(rowref, STATUS_IDX)
-            name = "%s <i>(%s)</i>" % (name,status)
-
+            name = '%s <span foreground="grey" style="italic">(%s)</span>' % (name,status)
         cell_renderer.set_property("markup", name)
 
     def activate(self, window):
         #the sidebar and menu integration must be done once per eog window instance
-        print "ACTIVATE"
-        self.window = window
         if self.conduit.connected() == True:
             self._prepare_sidebar(window) 
             self._prepare_tools_menu(window)
 
-
     def deactivate(self, window):
-        print "DEACTIVATE"
+        pass
 
     def update_ui(self, window):
-        print "UPDATE"
+        pass
 
     def is_configurable(self):
         return False

Modified: trunk/tools/eog-plugin/config.glade
==============================================================================
--- trunk/tools/eog-plugin/config.glade	(original)
+++ trunk/tools/eog-plugin/config.glade	Wed Jan 23 11:43:35 2008
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8" standalone="no"?>
 <!DOCTYPE glade-interface SYSTEM "glade-2.0.dtd">
-<!--Generated with glade3 3.3.3 on Wed Aug 15 10:24:52 2007 -->
+<!--Generated with glade3 3.4.0 on Wed Jan 23 16:51:51 2008 -->
 <glade-interface>
   <widget class="GtkDialog" id="ConfigDialog">
     <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
@@ -18,129 +18,32 @@
             <property name="visible">True</property>
             <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
             <child>
-              <widget class="GtkLabel" id="label1">
-                <property name="visible">True</property>
-                <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
-                <property name="label" translatable="yes">Enable Synchronizing Photos with the Following Locations</property>
-              </widget>
-              <packing>
-                <property name="expand">False</property>
-              </packing>
-            </child>
-            <child>
-              <widget class="GtkExpander" id="expander1">
+              <widget class="GtkCheckButton" id="checkbutton1">
                 <property name="visible">True</property>
                 <property name="can_focus">True</property>
                 <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
-                <child>
-                  <widget class="GtkVBox" id="vbox2">
-                    <property name="visible">True</property>
-                    <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
-                    <child>
-                      <widget class="GtkCheckButton" id="checkbutton1">
-                        <property name="visible">True</property>
-                        <property name="can_focus">True</property>
-                        <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
-                        <property name="label" translatable="yes">Enabled</property>
-                        <property name="response_id">0</property>
-                        <property name="draw_indicator">True</property>
-                      </widget>
-                    </child>
-                    <child>
-                      <widget class="GtkHBox" id="hbox1">
-                        <property name="visible">True</property>
-                        <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
-                        <child>
-                          <widget class="GtkLabel" id="label5">
-                            <property name="visible">True</property>
-                            <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
-                            <property name="xalign">0</property>
-                            <property name="label" translatable="yes">Username: </property>
-                          </widget>
-                          <packing>
-                            <property name="expand">False</property>
-                            <property name="padding">5</property>
-                          </packing>
-                        </child>
-                        <child>
-                          <widget class="GtkEntry" id="entry1">
-                            <property name="visible">True</property>
-                            <property name="can_focus">True</property>
-                            <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
-                          </widget>
-                          <packing>
-                            <property name="position">1</property>
-                          </packing>
-                        </child>
-                      </widget>
-                      <packing>
-                        <property name="position">1</property>
-                      </packing>
-                    </child>
-                  </widget>
-                </child>
-                <child>
-                  <widget class="GtkLabel" id="label2">
-                    <property name="visible">True</property>
-                    <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
-                    <property name="label" translatable="yes">Flickr</property>
-                  </widget>
-                  <packing>
-                    <property name="type">label_item</property>
-                  </packing>
-                </child>
-              </widget>
-              <packing>
-                <property name="expand">False</property>
-                <property name="position">1</property>
-              </packing>
-            </child>
-            <child>
-              <widget class="GtkExpander" id="expander3">
-                <property name="visible">True</property>
-                <property name="can_focus">True</property>
-                <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
-                <child>
-                  <placeholder/>
-                </child>
-                <child>
-                  <widget class="GtkLabel" id="label4">
-                    <property name="visible">True</property>
-                    <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
-                    <property name="label" translatable="yes">SmugMug</property>
-                  </widget>
-                  <packing>
-                    <property name="type">label_item</property>
-                  </packing>
-                </child>
+                <property name="label" translatable="yes">Start Conduit if it is not running.</property>
+                <property name="response_id">0</property>
+                <property name="draw_indicator">True</property>
               </widget>
               <packing>
                 <property name="expand">False</property>
-                <property name="position">2</property>
+                <property name="fill">False</property>
               </packing>
             </child>
             <child>
-              <widget class="GtkExpander" id="expander2">
+              <widget class="GtkCheckButton" id="checkbutton2">
                 <property name="visible">True</property>
                 <property name="can_focus">True</property>
                 <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
-                <child>
-                  <placeholder/>
-                </child>
-                <child>
-                  <widget class="GtkLabel" id="label3">
-                    <property name="visible">True</property>
-                    <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
-                    <property name="label" translatable="yes">iPod Photos</property>
-                  </widget>
-                  <packing>
-                    <property name="type">label_item</property>
-                  </packing>
-                </child>
+                <property name="label" translatable="yes">Show synchronization process in Conduit.</property>
+                <property name="response_id">0</property>
+                <property name="draw_indicator">True</property>
               </widget>
               <packing>
                 <property name="expand">False</property>
-                <property name="position">3</property>
+                <property name="fill">False</property>
+                <property name="position">1</property>
               </packing>
             </child>
           </widget>



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