conduit r1371 - in trunk: . conduit conduit/dataproviders conduit/gtkui conduit/modules conduit/modules/FileModule conduit/modules/NetworkModule test/python-tests



Author: jstowers
Date: Thu Mar 13 12:41:11 2008
New Revision: 1371
URL: http://svn.gnome.org/viewvc/conduit?rev=1371&view=rev

Log:
2008-03-14  John Stowers  <john stowers gmail com>

	* conduit/Module.py:
	* conduit/ModuleWrapper.py:
	* conduit/TypeConverter.py:
	* conduit/dataproviders/DataProvider.py:
	* conduit/dataproviders/VolumeFactory.py:
	* conduit/gtkui/Tree.py:
	* conduit/modules/AudioVideoConverterModule.py:
	* conduit/modules/ConverterModule.py:
	* conduit/modules/FileModule/FileModule.py:
	* conduit/modules/NetworkModule/Client.py:
	* conduit/modules/PhotoConverterModule.py:
	* conduit/modules/TestModule.py:
	* conduit/modules/TomboyModule.py:
	* test/python-tests/common.py: Add the plumbing needed for better removable
	volume support. This involves being able to specify your own keys (to
	be used in DND from tree to canvas), while leaving the actual instantiating
	key unchanged. I also cleaned up a number of other warts, such as making
	ModuleWrapper have a much saner API.



Modified:
   trunk/ChangeLog
   trunk/conduit/Module.py
   trunk/conduit/ModuleWrapper.py
   trunk/conduit/TypeConverter.py
   trunk/conduit/dataproviders/DataProvider.py
   trunk/conduit/dataproviders/VolumeFactory.py
   trunk/conduit/gtkui/Tree.py
   trunk/conduit/modules/AudioVideoConverterModule.py
   trunk/conduit/modules/ConverterModule.py
   trunk/conduit/modules/FileModule/FileModule.py
   trunk/conduit/modules/NetworkModule/Client.py
   trunk/conduit/modules/PhotoConverterModule.py
   trunk/conduit/modules/TestModule.py
   trunk/conduit/modules/TomboyModule.py
   trunk/test/python-tests/common.py

Modified: trunk/conduit/Module.py
==============================================================================
--- trunk/conduit/Module.py	(original)
+++ trunk/conduit/Module.py	Thu Mar 13 12:41:11 2008
@@ -46,8 +46,6 @@
         @type dirs: C{string[]}
         """
         gobject.GObject.__init__(self)
-        #Dict of loaded classes, key is classname, value is class
-        self.classRegistry = {}
         #Dict of loaded modulewrappers. key is wrapper.get_key()
         #Stored seperate to the classes because dynamic dataproviders may
         #use the same class but with different initargs (diff keys)
@@ -59,7 +57,7 @@
         #scan all dirs for files in the right format (*Module/*Module.py)
         self.filelist = self._build_filelist_from_directories(dirs)
 
-    def _on_dynamic_dataprovider_available(self, monitor, dpw, klass):
+    def _on_dynamic_dataprovider_added(self, monitor, dpw, klass):
         """
         Store the ipod so it can be retrieved later by the treeview/model
         emit a signal so it is added to the GUI
@@ -67,17 +65,13 @@
         log.info("Dynamic dataprovider (%s) available by %s" % (dpw, monitor))
         self._append_module(dpw, klass)
 
-    def _on_dynamic_dataprovider_unavailable(self, monitor, key):
+    def _on_dynamic_dataprovider_removed(self, monitor, key):
         log.info("Dynamic dataprovider (%s) unavailable by %s" % (key, monitor))
         self._remove_module(key)
 
     def _emit_available(self, dataproviderWrapper):
         if dataproviderWrapper.module_type in ["source", "sink", "twoway"]:
             self.emit("dataprovider-available", dataproviderWrapper)
-        else:
-            #Dont emit a signal when a datatype of converter is loaded as I dont
-            #think signal emission is useful in that case
-            pass
 
     def _emit_unavailable(self, dataproviderWrapper):
         if dataproviderWrapper.module_type in ["source", "sink", "twoway"]:
@@ -116,34 +110,14 @@
         return res            
        
     def _is_module(self, filename):
-        """
-        Tests whether the filename has the appropriate extension.
-        """
-        endswith = "Module.py"
-        isModule = filename[-len(endswith):] == endswith
-        return isModule
+        return filename.endswith("Module.py")
 
     def _is_module_dir(self, dirname):
-        endswith = "Module"
-        isModuleDir = dirname[-len(endswith):] == endswith
-        return isModuleDir
+        return dirname.endswith("Module")
         
     def _append_module(self, wrapper, klass):
-        """
-        Checks if the given module (checks by classname) is already loaded
-        into the modulelist array, if not it is added to that array
-        
-        @param module: The module to append.
-        @type module: L{conduit.ModuleManager.ModuleWrapper}
-        """
-        #Check if the class is unique
-        classname = klass.__name__
-        if classname not in self.classRegistry:
-            self.classRegistry[classname] = klass
-        else:
-            log.warn("Class named %s allready loaded" % (classname))
         #Check if the wrapper is unique
-        key = wrapper.get_key()
+        key = wrapper.get_dnd_key()
         if key not in self.moduleWrappers:
             self.moduleWrappers[key] = wrapper
             #Emit a signal because this wrapper is new
@@ -189,7 +163,7 @@
                     log.warn("Class %s in file %s does define a %s attribute. Skipping." % (modules, filename, i))
                     raise Exception
         return mods
-        
+
     def _load_modules_in_file(self, filename):
         """
         Loads all modules in the given file
@@ -200,21 +174,16 @@
                 try:
                     klass = getattr(mod, modules)
                     if infos["type"] == "dataprovider" or infos["type"] == "converter":
-                        mod_wrapper = ModuleWrapper(   
-                                            name=getattr(klass, "_name_", ""),
-                                            description=getattr(klass, "_description_", ""),
-                                            icon_name=getattr(klass, "_icon_", ""),
-                                            module_type=getattr(klass, "_module_type_", infos["type"]),
-                                            category=getattr(klass, "_category_", CATEGORY_TEST),
-                                            in_type=getattr(klass, "_in_type_", ""),
-                                            out_type=getattr(klass, "_out_type_", ""),
-                                            filename=filename,
-                                            classname=klass.__name__,
-                                            initargs=(),
-                                            enabled=True
-                                            )
-                        #Save the module (signal is emitted _append_module
-                        self._append_module(mod_wrapper, klass)
+                        mod_wrapper = ModuleWrapper(
+                                        klass=klass,
+                                        initargs=(),
+                                        category=getattr(klass, "_category_", CATEGORY_TEST)
+                                        )
+                        #Save the module (signal is emitted in _append_module)
+                        self._append_module(
+                                mod_wrapper,
+                                klass
+                                )
                     elif infos["type"] == "dataprovider-factory":
                         # build a dict of kwargs to pass to factories
                         kwargs = {
@@ -224,23 +193,13 @@
                         instance = klass(**kwargs)
                         self.dataproviderFactories.append(instance)
                     else:
-                        log.warn("Class %s is an unknown type: %s" % (klass.__name__, infos["type"]))
+                        log.warn("Class is an unknown type: %s" % klass)
                 except AttributeError:
                     log.warn("Could not find module %s in %s\n%s" % (modules,filename,traceback.format_exc()))
         except Exception, e:
-            log.warn("Error loading the file: %s.\n%s" % (filename, traceback.format_exc()))
+            log.warn("Error loading the file: %s\n%s" % (filename, traceback.format_exc()))
             self.invalidFiles.append(os.path.basename(filename))
 
-    def _instantiate_class(self, classname, initargs):
-        if type(initargs) != tuple:
-            log.warn("Could not make class %s. Initargs must be a tuple" % classname)
-            return None
-        if classname in self.classRegistry:
-            log.debug("Returning new instance: Classname=%s Initargs=%s" % (classname,initargs))
-            return self.classRegistry[classname](*initargs)
-        else:
-            log.warn("Could not find class named %s" % classname)
-
     def load_all(self):
         """
         Loads all classes in the configured paths
@@ -249,8 +208,8 @@
             self._load_modules_in_file(f)
 
         for i in self.dataproviderFactories:
-            i.connect("dataprovider-unavailable", self._on_dynamic_dataprovider_unavailable)
-            i.connect("dataprovider-available", self._on_dynamic_dataprovider_available)
+            i.connect("dataprovider-removed", self._on_dynamic_dataprovider_removed)
+            i.connect("dataprovider-added", self._on_dynamic_dataprovider_added)
             i.probe()
 
         self.emit('all-modules-loaded')
@@ -280,23 +239,13 @@
         if wrapperKey in self.moduleWrappers:
             #Get the existing wrapper
             m = self.moduleWrappers[wrapperKey]
-            #Get its construction args
-            classname = m.classname
-            initargs = m.initargs
-            mod_wrapper = ModuleWrapper(  
-                                name=m.name, 
-                                description=m.description,
-                                icon_name=m.icon_name, 
-                                module_type=m.module_type, 
-                                category=m.category, 
-                                in_type=m.in_type,
-                                out_type=m.out_type,
-                                filename=m.filename,
-                                classname=classname,
-                                initargs=initargs,
-                                module=self._instantiate_class(classname, initargs),
-                                enabled=True
-                                )
+            #Make a copy of it, containing an instantiated module
+            mod_wrapper = ModuleWrapper(
+                            klass=m.klass,
+                            initargs=m.initargs,
+                            category=m.category
+                            )
+            mod_wrapper.instantiate_module()
         else:
             log.warn("Could not find module wrapper: %s" % (wrapperKey))
             mod_wrapper = PendingDataproviderWrapper(wrapperKey)
@@ -310,7 +259,7 @@
         """
         for i in self.moduleWrappers.values():
             if i.module_type == type_filter:
-                i.module = self._instantiate_class(i.classname, i.initargs)
+                i.instantiate_module()
 
     def quit(self):
         for dpf in self.dataproviderFactories:

Modified: trunk/conduit/ModuleWrapper.py
==============================================================================
--- trunk/conduit/ModuleWrapper.py	(original)
+++ trunk/conduit/ModuleWrapper.py	Thu Mar 13 12:41:11 2008
@@ -15,42 +15,45 @@
                             "type"
                             ]
     	
-    def __init__ (self, **kwargs):
+    def __init__ (self, klass, initargs, category):
         """
-        Constructor for ModuleWrapper. A convenient wrapper around a dynamically
-        loaded module.
+        Initializes the ModuleWrapper with an uninstantiated class
+       
+        @param klass: The klass this wrapper wraps
+        @param initargs: The arguments used to instantiate klass
+        @param category: The category
+        
+        @ivar name: The name of the contained module
+        @ivar description: The description of the contained module
+        @ivar icon_name: The name of an icon representing the contained module
+        @ivar module_type: The type of the contained module (e.g. sink, source)
+        @ivar category: The category of the contained module
+        @ivar in_type: The name of the datatype that the module accepts (put())
+        @ivar out_type: The name of the datatype that the module produces (get())
+        @ivar classname: The classname used to instanciate another module instance
+        @ivar initargs: The arguments passed to the new module if created
+        @ivar module: An instance of the described module
+        """
+        if type(initargs) != tuple:
+            raise Exception("Module init args must be a tuple")
         
-        @keyword name: The name of the contained module
-        @keyword description: The description of the contained module
-        @keyword icon_name: The name of an icon representing the contained module
-        @keyword module_type: The type of the contained module (e.g. sink, source)
-        @keyword category: The category of the contained module
-        @keyword in_type: The name of the datatype that the module accepts (put())
-        @keyword out_type: The name of the datatype that the module produces (get())
-        @keyword filename: The filename from which the module was loaded
-        @keyword classname: The classname used to instanciate another module instance
-        @keyword initargs: The arguments passed to the new module if created
-        @keyword module: An instance of the described module
-        @keyword loaded: Whether the module was loaded corectly 
-        """
-        self.name =                 kwargs.get("name","")
-        self.description =          kwargs.get("description","")
-        self.icon_name =            kwargs.get("icon_name","image-missing")
-        self.module_type =          kwargs.get('module_type',"twoway")
-        self.category =             kwargs.get('category',"")
-        self.in_type =              kwargs.get('in_type',"")
-        self.out_type =             kwargs.get('out_type',"")
-        self.filename =             kwargs.get('filename',"")
-        self.classname =            kwargs.get('classname',"")
-        self.initargs =             kwargs.get('initargs',())
-        self.module =               kwargs.get('module',None)
-        self.enabled =              kwargs.get('enabled',True)
-
-        #Initargs must be a tuple or a list for get_key() to work
-        if type(self.initargs) != tuple:
-            log.warn("init args must be a tuple (was:%s type:%s)" % (self.initargs,type(self.initargs)))
-            raise Exception
+        self.klass =                klass
+        self.initargs =             initargs
+        self.category =             category
         
+        #extract class parameters
+        if klass:
+            self.name =             getattr(klass, "_name_", "")
+            self.description =      getattr(klass, "_description_", "")
+            self.icon_name =        getattr(klass, "_icon_", "")
+            self.module_type =      getattr(klass, "_module_type_", "")
+            self.in_type =          getattr(klass, "_in_type_", "")
+            self.out_type =         getattr(klass, "_out_type_", "")
+            self.classname =        klass.__name__
+
+        self.dndKey = None
+        self.enabled = True
+        self.module = None
         self.icon_path = ""
         self.icon = {}
         self.descriptiveIcon = None
@@ -58,6 +61,23 @@
     def __str__(self):
         return "Wrapper: %s %s (UID: %s)" % (self.get_name(), self.module_type, self.get_UID())
 
+    # Keys serve two goals in conduit, nominally related to dataprovider factories.
+    # and instantiating dataproviders
+    #
+    # 1. Keys act as a match pattern for instantiating the same class multiple times
+    # with different configurations, such as when the user has multiple iPods connected.
+    # This matching is tested when conduit restores saved dataproviders, if the key
+    # is not known to Conduit, then a pending dataprovider is inserted in its place
+    #
+    # 2. They are also serve a way to show the same class in multiple categories
+    def get_dnd_key(self):
+        if self.dndKey:
+            return self.dndKey
+        return self.get_key()
+        
+    def set_dnd_key(self, dndKey):
+        self.dndKey = dndKey
+
     def get_key(self):
         """
         Returns a string in the form of classname:initarg0:initarg1:...
@@ -224,16 +244,23 @@
 
     def configure(self, window):
         self.module.configure(window)
+        
+    def instantiate_module(self):
+        self.module = self.klass(*self.initargs)
 
 class PendingDataproviderWrapper(ModuleWrapper):
     def __init__(self, key):
         ModuleWrapper.__init__(
                     self,
-                    module_type="twoway",
-                    classname=key.split(':')[0],
-                    module=None,
-                    enabled=False
+                    klass=None,
+                    initargs=(),
+                    category=None
                     )
+        self.icon_name="image-loading"
+        self.module_type="twoway"
+        self.classname=key.split(':')[0]
+        self.enabled=False
+
         self.key = key
         self.xmltext = ""
 

Modified: trunk/conduit/TypeConverter.py
==============================================================================
--- trunk/conduit/TypeConverter.py	(original)
+++ trunk/conduit/TypeConverter.py	Thu Mar 13 12:41:11 2008
@@ -11,6 +11,9 @@
 import conduit.Exceptions as Exceptions
 import conduit.Utils as Utils
 
+class Converter:
+    _module_type_ = "converter"
+
 class TypeConverter: 
     """
     Maintains a dictionary of dictionaries, indexed by the type converted FROM which

Modified: trunk/conduit/dataproviders/DataProvider.py
==============================================================================
--- trunk/conduit/dataproviders/DataProvider.py	(original)
+++ trunk/conduit/dataproviders/DataProvider.py	Thu Mar 13 12:41:11 2008
@@ -49,7 +49,7 @@
     _out_type_ = ""
     _in_type_ = ""
     
-    def __init__(self):
+    def __init__(self, *args):
         """
         All sync functionality should be provided by derived classes
         """
@@ -209,10 +209,7 @@
     def configure(self, window):
         """
         Show a configuration box for configuring the dataprovider instance.
-        This call may block
-        
-        @param window: The parent window (to show a modal diaconduit.log)
-        @type window: {gtk.Window}
+        @param window: The parent gtk.Window (to show a modal dialog)
         """
         log.debug("configure() not overridden by derived class %s" % self._name_)
 
@@ -485,40 +482,32 @@
     dynamic dataproviders become available at runtime.
     """
     __gsignals__ = {
-        "dataprovider-available" : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, [
+        "dataprovider-added" : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, [
             gobject.TYPE_PYOBJECT,      #Wrapper
             gobject.TYPE_PYOBJECT]),    #Class
-        "dataprovider-unavailable" : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, [
-            gobject.TYPE_STRING])     #Unique key
+        "dataprovider-removed" : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, [
+            gobject.TYPE_STRING])       #Unique key
     }
 
+    _module_type_ = "dataprovider-factory"
+
     def __init__(self, **kwargs):
         gobject.GObject.__init__(self)
 
-    def emit_added(self, klass, initargs=(), category=None):
-        if category == None:
-            category = getattr(klass, "_category_", conduit.dataproviders.CATEGORY_TEST)
+    def emit_added(self, klass, initargs, category, customKey=None):
         dpw = ModuleWrapper.ModuleWrapper(   
-                    name=getattr(klass, "_name_", ""),
-                    description=getattr(klass, "_description_", ""),
-                    icon_name=getattr(klass, "_icon_", ""),
-                    module_type=getattr(klass, "_module_type_", ""),
-                    category=category,
-                    in_type=getattr(klass, "_in_type_", ""),
-                    out_type=getattr(klass, "_out_type_", ""),
-                    filename=__file__,
-                    classname=klass.__name__,
+                    klass=klass,
                     initargs=initargs,
-                    module=None,
-                    enabled=True
+                    category=category
                     )
-        log.debug("DataProviderFactory %s: Emitting dataprovider-available for %s" % (self, dpw.get_key()))
-        self.emit("dataprovider-available", dpw, klass)
-        return dpw.get_key()
+        dpw.set_dnd_key(customKey)
+        log.debug("DataProviderFactory %s: Emitting dataprovider-added for %s" % (self, dpw.get_dnd_key()))
+        self.emit("dataprovider-added", dpw, klass)
+        return dpw.get_dnd_key()
 
     def emit_removed(self, key):
-        log.debug("DataProviderFactory %s: Emitting dataprovider-unavailable for %s" % (self, key))
-        self.emit("dataprovider-unavailable", key)
+        log.debug("DataProviderFactory %s: Emitting dataprovider-removed for %s" % (self, key))
+        self.emit("dataprovider-removed", key)
 
     def probe(self):
         pass

Modified: trunk/conduit/dataproviders/VolumeFactory.py
==============================================================================
--- trunk/conduit/dataproviders/VolumeFactory.py	(original)
+++ trunk/conduit/dataproviders/VolumeFactory.py	Thu Mar 13 12:41:11 2008
@@ -47,20 +47,6 @@
                 self.item_removed(device_udi)
         return False
 
-    def probe(self):
-        """
-        Called after VolumeFactory is initialised to detect already connected volumes
-        """
-        for volume in self.vol_monitor.get_mounted_volumes():
-            device_udi = volume.get_hal_udi()
-            if device_udi != None:
-                props = self._get_properties(device_udi)
-                if self.is_interesting(device_udi, props):
-                    mount, label = self._get_device_info(props)
-                    kwargs = { "mount": mount, "label": label }
-                    print device_udi, kwargs
-                    self.item_added(device_udi, **kwargs)
-
     def _get_properties(self, device_udi):
         try:
             device_dbus_obj = self.bus.get_object("org.freedesktop.Hal" ,device_udi)
@@ -82,6 +68,19 @@
             label = ""
 
         return (mount, label)
+        
+    def probe(self):
+        """
+        Called after VolumeFactory is initialised to detect already connected volumes
+        """
+        for volume in self.vol_monitor.get_mounted_volumes():
+            device_udi = volume.get_hal_udi()
+            if device_udi != None:
+                props = self._get_properties(device_udi)
+                if self.is_interesting(device_udi, props):
+                    mount, label = self._get_device_info(props)
+                    kwargs = { "mount": mount, "label": label }
+                    self.item_added(device_udi, **kwargs)
 
     def get_args(self, udi, **kwargs):
         """ VolumeFactory passes mount point and udi to dataproviders """

Modified: trunk/conduit/gtkui/Tree.py
==============================================================================
--- trunk/conduit/gtkui/Tree.py	(original)
+++ trunk/conduit/gtkui/Tree.py	Thu Mar 13 12:41:11 2008
@@ -27,18 +27,22 @@
     def __init__(self, category):
         ModuleWrapper.__init__(
                             self,
-                            name=category.name,
-                            icon_name=category.icon,
-                            module_type="category",
+                            klass=None,
+                            initargs=(),
                             category=category
                             )
+        self.name=category.name
+        self.classname=category.name
+        self.icon_name=category.icon
+        self.module_type="category"
+
     def get_UID(self):
         return self.name
 
 IDX_ICON = 0
 IDX_NAME = 1
 IDX_DESCRIPTION = 2
-IDX_KEY = 3
+IDX_DND_KEY = 3
 COLUMN_TYPES = (gtk.gdk.Pixbuf, str, str, str)
        
 class DataProviderTreeModel(gtk.GenericTreeModel):
@@ -241,11 +245,11 @@
             return rowref.description
         #Used internally from the TreeView to get the key used by the canvas to 
         #reinstantiate new dataproviders
-        elif column is IDX_KEY:
+        elif column is IDX_DND_KEY:
             if self._is_category_heading(rowref):
                 return ""
             else:
-                return rowref.get_key()
+                return rowref.get_dnd_key()
         #Used internally from the TreeView to see if this is a category heading
         #and subsequently cancel the drag and drop
         elif column is IDX_IS_CATEGORY:        
@@ -407,7 +411,7 @@
         treeselection = treeview.get_selection()
         model, iter = treeselection.get_selected()
         #get the classname
-        data = model.get_value(iter, IDX_KEY)
+        data = model.get_value(iter, IDX_DND_KEY)
         selection.set(selection.target, 8, data)
         
     def on_drag_data_delete (self, context, etime):

Modified: trunk/conduit/modules/AudioVideoConverterModule.py
==============================================================================
--- trunk/conduit/modules/AudioVideoConverterModule.py	(original)
+++ trunk/conduit/modules/AudioVideoConverterModule.py	Thu Mar 13 12:41:11 2008
@@ -4,6 +4,7 @@
 
 import conduit
 import conduit.Utils as Utils
+import conduit.TypeConverter as TypeConverter
 import conduit.datatypes.File as File
 import conduit.datatypes.Audio as Audio
 import conduit.datatypes.Video as Video
@@ -88,7 +89,7 @@
     def check_cancelled(self):
         return conduit.GLOBALS.cancelled
             
-class AudioVideoConverter:
+class AudioVideoConverter(TypeConverter.Converter):
 
     #These commands are run to determine attributes about the file 
     #(such as size and duration) prior to transcode. They should be

Modified: trunk/conduit/modules/ConverterModule.py
==============================================================================
--- trunk/conduit/modules/ConverterModule.py	(original)
+++ trunk/conduit/modules/ConverterModule.py	Thu Mar 13 12:41:11 2008
@@ -2,8 +2,8 @@
 import logging
 log = logging.getLogger("modules.Converter")
 
-import conduit
 import conduit.Utils as Utils
+import conduit.TypeConverter as TypeConverter
 import conduit.datatypes.Contact as Contact
 import conduit.datatypes.Event as Event
 import conduit.datatypes.Text as Text
@@ -21,7 +21,7 @@
         "SettingConverter" :    { "type": "converter" }
 }
 
-class EmailConverter:
+class EmailConverter(TypeConverter.Converter):
     def __init__(self):
         self.conversions =  {    
                             "email,text"    : self.email_to_text,
@@ -72,7 +72,7 @@
         return email
 
 
-class NoteConverter:
+class NoteConverter(TypeConverter.Converter):
     def __init__(self):
         self.conversions =  {  
                             "text,note"     : self.text_to_note,  
@@ -99,7 +99,7 @@
         f.force_new_file_extension(".txt")
         return f
 
-class ContactConverter:
+class ContactConverter(TypeConverter.Converter):
     def __init__(self):
         self.conversions =  {
                             "contact,file"    : self.contact_to_file,
@@ -124,7 +124,7 @@
         c. set_from_vcard_string(f.get_contents_as_text())
         return c
 
-class EventConverter:
+class EventConverter(TypeConverter.Converter):
     def __init__(self):
         self.conversions =  {    
                             "event,file"    : self.event_to_file,
@@ -154,7 +154,7 @@
         e.set_from_ical_string(text.get_string())
         return e
 
-class FileConverter:
+class FileConverter(TypeConverter.Converter):
     def __init__(self):
         self.conversions =  {    
                             "text,file" : self.text_to_file,
@@ -184,7 +184,7 @@
                     )
         return note
        
-class SettingConverter(object):
+class SettingConverter(TypeConverter.Converter):
     def __init__(self):
         self.conversions =  {    
                             "setting,text"    : self.setting_to_text,

Modified: trunk/conduit/modules/FileModule/FileModule.py
==============================================================================
--- trunk/conduit/modules/FileModule/FileModule.py	(original)
+++ trunk/conduit/modules/FileModule/FileModule.py	Thu Mar 13 12:41:11 2008
@@ -5,15 +5,17 @@
 
 import conduit
 import conduit.dataproviders.DataProvider as DataProvider
+import conduit.dataproviders.DataProviderCategory as DataProviderCategory
 import conduit.dataproviders.File as FileDataProvider
+import conduit.dataproviders.VolumeFactory as VolumeFactory
 import conduit.dataproviders.AutoSync as AutoSync
 import conduit.Utils as Utils
 import conduit.Vfs as Vfs
 
 MODULES = {
-	"FileSource" :      { "type": "dataprovider" },
-	"FolderTwoWay" :    { "type": "dataprovider" },
-#    "USBFactory" :      { "type": "dataprovider-factory" }
+	"FileSource" :              { "type": "dataprovider" },
+	"FolderTwoWay" :            { "type": "dataprovider" },
+#    "RemovableDeviceFactory" :  { "type": "dataprovider-factory" }
 }
 
 class FileSource(FileDataProvider.FileSource):
@@ -66,11 +68,12 @@
     DEFAULT_COMPARE_IGNORE_MTIME = False
 
     def __init__(self, *args):
+        print "#"*100,self.DEFAULT_FOLDER
         FileDataProvider.FolderTwoWay.__init__(self,
-                FolderTwoWay.DEFAULT_FOLDER,
-                FolderTwoWay.DEFAULT_GROUP,
-                FolderTwoWay.DEFAULT_HIDDEN,
-                FolderTwoWay.DEFAULT_COMPARE_IGNORE_MTIME
+                self.DEFAULT_FOLDER,
+                self.DEFAULT_GROUP,
+                self.DEFAULT_HIDDEN,
+                self.DEFAULT_COMPARE_IGNORE_MTIME
                 )
         AutoSync.AutoSync.__init__(self)
         self._monitor_folder_id = None
@@ -79,7 +82,7 @@
         if self._monitor_folder_id != None:
             Vfs.monitor_cancel(self._monitor_folder_id)
             self._monitor_folder_id = None
-
+            
     def configure(self, window):
         Utils.dataprovider_add_dir_to_path(__file__, "")
         import FileConfiguration
@@ -88,10 +91,10 @@
         self._monitor_folder()
         
     def set_configuration(self, config):
-        self.folder = config.get("folder", FolderTwoWay.DEFAULT_FOLDER)
-        self.folderGroupName = config.get("folderGroupName", FolderTwoWay.DEFAULT_GROUP)
-        self.includeHidden = config.get("includeHidden", FolderTwoWay.DEFAULT_HIDDEN)
-        self.compareIgnoreMtime = config.get("compareIgnoreMtime", FolderTwoWay.DEFAULT_COMPARE_IGNORE_MTIME)
+        self.folder = config.get("folder", self.DEFAULT_FOLDER)
+        self.folderGroupName = config.get("folderGroupName", self.DEFAULT_GROUP)
+        self.includeHidden = config.get("includeHidden", self.DEFAULT_HIDDEN)
+        self.compareIgnoreMtime = config.get("compareIgnoreMtime", self.DEFAULT_COMPARE_IGNORE_MTIME)
         self._monitor_folder()
 
     def get_configuration(self):
@@ -128,46 +131,53 @@
         elif event == Vfs.MONITOR_EVENT_DELETED:
             self.handle_deleted(event_uri)
 
-class USBFactory(DataProvider.DataProviderFactory):
-    def __init__(self, **kwargs):
-        DataProvider.DataProviderFactory.__init__(self, **kwargs)
-
-        if kwargs.has_key("hal"):
-            self.hal = kwargs["hal"]
-            self.hal.connect("usb-added", self._usb_added)
-            self.hal.connect("usb-removed", self._usb_removed)
+class RemovableDeviceFactory(VolumeFactory.VolumeFactory):
 
-        self.usb = {}
+    def __init__(self, **kwargs):
+        VolumeFactory.VolumeFactory.__init__(self, **kwargs)
+        self.foo = {}
 
-    def probe(self):
-        """
-        Probe for USB Keys that are already attached
-        """
-        for device_type, udi, mount, name in self.hal.get_all_usb_keys():
-            self._usb_added(None, udi, mount, name)
+    def _make_class(self, folder, name):
+        klass = type(
+                "FolderTwoWay",
+                (FolderTwoWay,),
+                {"DEFAULT_FOLDER":folder,"DEFAULT_GROUP":name}
+                )
+        return klass
 
-    def _usb_added(self, hal, udi, mount, name):
+    def emit_added(self, klass, initargs, category):
         """
-        New USB key has been discovered
+        Override emit_added to allow duplictes.
         """
-        cat = DataProvider.DataProviderCategory(
-                    name,
-                    "drive-removable-media",
-                    mount)
-
-        keys = []
-        for klass in [FileSource]:
-            key = self.emit_added(
-                           klass,            # Dataprovider class
-                           (mount,udi,),     # Init args
-                           cat)              # Category..
-            keys.append(key)
-
-        self.usb[udi] = keys
-
-    def _usb_removed(self, hal, udi, mount, name):
-        for key in self.usb[udi]:
-            self.emit_removed(key)
+        VolumeFactory.VolumeFactory.emit_added(self, klass, initargs, category, customKey="12345")
 
-        del self.usb[udi]
+    def is_interesting(self, udi, props):
+        if props.has_key("info.parent") and props.has_key("info.parent") != "":
+            prop2 = self._get_properties(props["info.parent"])
+            if prop2.has_key("storage.removable") and prop2["storage.removable"] == True:
+                mount,label = self._get_device_info(props)
+                #check for the presence of a mount/.conduit file
+                #which describe the folder sync groups, and their names, 
+                #on this volume
+                #
+                #The format of this file is n lines in the form
+                # group_name|path
+                # group_name|path
+                path = Vfs.uri_join(mount,".conduit")
+                if Vfs.uri_exists(path):
+                    self.foo[udi] = [self._make_class("/tmp",i) for i in range(2)]
+                return True
+        return False
+    
+    def get_category(self, udi, **kwargs):
+        return DataProviderCategory.DataProviderCategory(
+                    kwargs['label'],
+                    "multimedia-player-ipod-video-white",
+                    udi)
+
+    def get_dataproviders(self, udi, **kwargs):
+         return self.foo[udi]
+         
+    def get_args(self, udi, **kwargs):
+        return ()
 

Modified: trunk/conduit/modules/NetworkModule/Client.py
==============================================================================
--- trunk/conduit/modules/NetworkModule/Client.py	(original)
+++ trunk/conduit/modules/NetworkModule/Client.py	Thu Mar 13 12:41:11 2008
@@ -121,10 +121,10 @@
 
         # Register the new dataprovider with Conduit
         key = self.emit_added(
-                                  newdp, 
-                                  (), #No init args, these are encoded as class params
-                                  self.categories[newdp.hostUrl]
-                             )
+                          klass=newdp, 
+                          initargs=(), #No init args, these are encoded as class params
+                          category=self.categories[newdp.hostUrl]
+                         )
 
         # Record the key so we can unregister the dp later (if needed)
         self.dataproviders[hostUrl][newdp.uid] = key

Modified: trunk/conduit/modules/PhotoConverterModule.py
==============================================================================
--- trunk/conduit/modules/PhotoConverterModule.py	(original)
+++ trunk/conduit/modules/PhotoConverterModule.py	Thu Mar 13 12:41:11 2008
@@ -3,6 +3,7 @@
 
 import conduit
 import conduit.Utils as Utils
+import conduit.TypeConverter as TypeConverter
 import conduit.datatypes.File as File
 import conduit.datatypes.Photo as Photo
 
@@ -12,7 +13,7 @@
 
 NO_RESIZE = "None"
 
-class PixbufPhotoConverter:
+class PixbufPhotoConverter(TypeConverter.Converter):
     def __init__(self):
         self.conversions =  {
                             "file/photo,file/photo"     :   self.transcode,    

Modified: trunk/conduit/modules/TestModule.py
==============================================================================
--- trunk/conduit/modules/TestModule.py	(original)
+++ trunk/conduit/modules/TestModule.py	Thu Mar 13 12:41:11 2008
@@ -9,6 +9,7 @@
 
 import conduit
 import conduit.Utils as Utils
+import conduit.TypeConverter as TypeConverter
 import conduit.dataproviders.DataProvider as DataProvider
 import conduit.dataproviders.DataProviderCategory as DataProviderCategory
 import conduit.dataproviders.SimpleFactory as SimpleFactory
@@ -32,7 +33,7 @@
     "TestConflict" :            { "type": "dataprovider" },
     "TestConversionArgs" :      { "type": "dataprovider" },
     "TestTwoWay" :              { "type": "dataprovider" },
-    "TestFailRefresh" :     { "type": "dataprovider" },
+    "TestFailRefresh" :         { "type": "dataprovider" },
     "TestSinkNeedConfigure" :   { "type": "dataprovider" },
     "TestFactory" :             { "type": "dataprovider-factory" },
 #    "TestFactoryRemoval" :      { "type": "dataprovider-factory" },
@@ -255,12 +256,14 @@
     _in_type_ = "test_type"
     _out_type_ = "test_type"
     _icon_ = "go-next"
+    
+    DEFAULT_NUM_DATA = 10
 
     def __init__(self, *args):
         _TestBase.__init__(self)
         DataProvider.DataSource.__init__(self)
         self.data = []
-        self.numData = 10
+        self.numData = self.DEFAULT_NUM_DATA
         
     def refresh(self):
         DataProvider.DataSource.refresh(self)
@@ -674,7 +677,7 @@
     def get_UID(self):
         return Utils.random_string()
 
-class TestConverter:
+class TestConverter(TypeConverter.Converter):
     def __init__(self):
         self.conversions =  {
                 "test_type,test_type"   : self.transcode,
@@ -726,9 +729,10 @@
 
     def make_three(self, *args):
         self.key3 = self.emit_added(
-                             klass=type("DynamicTestSource3", (TestSource, ), {"_name_":"Dynamic Source 3"}),
-                             initargs=("Baz","Foo"), 
-                             category=conduit.dataproviders.CATEGORY_TEST)
+                             klass=type("TestSource", (TestSource, ), {"_name_":"Preconfigured Test Source", "DEFAULT_NUM_DATA":20}),
+                             initargs=(), 
+                             category=conduit.dataproviders.CATEGORY_TEST,
+                             customKey="CustomKey")
         #run once
         return False
 

Modified: trunk/conduit/modules/TomboyModule.py
==============================================================================
--- trunk/conduit/modules/TomboyModule.py	(original)
+++ trunk/conduit/modules/TomboyModule.py	Thu Mar 13 12:41:11 2008
@@ -4,6 +4,7 @@
 log = logging.getLogger("modules.Tomboy")
 
 import conduit
+import conduit.TypeConverter as TypeConverter
 import conduit.dataproviders.DataProvider as DataProvider
 import conduit.dataproviders.AutoSync as AutoSync
 import conduit.Exceptions as Exceptions
@@ -36,7 +37,7 @@
         self.xml = data["xml"]
         Note.Note.__setstate__(self, data)
 
-class TomboyNoteConverter(object):
+class TomboyNoteConverter(TypeConverter.Converter):
     NOTE_EXTENSION = ".xml"
     def __init__(self):
         self.conversions =  {

Modified: trunk/test/python-tests/common.py
==============================================================================
--- trunk/test/python-tests/common.py	(original)
+++ trunk/test/python-tests/common.py	Thu Mar 13 12:41:11 2008
@@ -315,10 +315,11 @@
 
     def wrap_dataprovider(self, dp):
         wrapper = ModuleWrapper.ModuleWrapper(   
-                        classname=dp.__class__.__name__,
-                        module=dp,
-                        enabled=True
+                        klass=dp.__class__,
+                        initargs=(),
+                        category=None
                         )
+        wrapper.module = dp
         return wrapper
 
     def networked_dataprovider(self, dp):



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