Index: test/python-tests/common.py
===================================================================
--- test/python-tests/common.py	(revision 1369)
+++ test/python-tests/common.py	(working copy)
@@ -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):
Index: conduit/gtkui/Tree.py
===================================================================
--- conduit/gtkui/Tree.py	(revision 1369)
+++ conduit/gtkui/Tree.py	(working copy)
@@ -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):
Index: conduit/TypeConverter.py
===================================================================
--- conduit/TypeConverter.py	(revision 1369)
+++ conduit/TypeConverter.py	(working copy)
@@ -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
Index: conduit/dataproviders/VolumeFactory.py
===================================================================
--- conduit/dataproviders/VolumeFactory.py	(revision 1369)
+++ conduit/dataproviders/VolumeFactory.py	(working copy)
@@ -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 """
Index: conduit/dataproviders/DataProvider.py
===================================================================
--- conduit/dataproviders/DataProvider.py	(revision 1369)
+++ conduit/dataproviders/DataProvider.py	(working copy)
@@ -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
Index: conduit/modules/FileModule/FileModule.py
===================================================================
--- conduit/modules/FileModule/FileModule.py	(revision 1369)
+++ conduit/modules/FileModule/FileModule.py	(working copy)
@@ -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):
+class RemovableDeviceFactory(VolumeFactory.VolumeFactory):
+
     def __init__(self, **kwargs):
-        DataProvider.DataProviderFactory.__init__(self, **kwargs)
+        VolumeFactory.VolumeFactory.__init__(self, **kwargs)
+        self.foo = {}
 
-        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)
+    def _make_class(self, folder, name):
+        klass = type(
+                "FolderTwoWay",
+                (FolderTwoWay,),
+                {"DEFAULT_FOLDER":folder,"DEFAULT_GROUP":name}
+                )
+        return klass
 
-        self.usb = {}
-
-    def probe(self):
+    def emit_added(self, klass, initargs, category):
         """
-        Probe for USB Keys that are already attached
+        Override emit_added to allow duplictes.
         """
-        for device_type, udi, mount, name in self.hal.get_all_usb_keys():
-            self._usb_added(None, udi, mount, name)
+        VolumeFactory.VolumeFactory.emit_added(self, klass, initargs, category, customKey="12345")
 
-    def _usb_added(self, hal, udi, mount, name):
-        """
-        New USB key has been discovered
-        """
-        cat = DataProvider.DataProviderCategory(
-                    name,
-                    "drive-removable-media",
-                    mount)
+    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)
 
-        keys = []
-        for klass in [FileSource]:
-            key = self.emit_added(
-                           klass,            # Dataprovider class
-                           (mount,udi,),     # Init args
-                           cat)              # Category..
-            keys.append(key)
+    def get_dataproviders(self, udi, **kwargs):
+         return self.foo[udi]
+         
+    def get_args(self, udi, **kwargs):
+        return ()
 
-        self.usb[udi] = keys
-
-    def _usb_removed(self, hal, udi, mount, name):
-        for key in self.usb[udi]:
-            self.emit_removed(key)
-
-        del self.usb[udi]
-
Index: conduit/modules/NetworkModule/Client.py
===================================================================
--- conduit/modules/NetworkModule/Client.py	(revision 1369)
+++ conduit/modules/NetworkModule/Client.py	(working copy)
@@ -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
Index: conduit/modules/ConverterModule.py
===================================================================
--- conduit/modules/ConverterModule.py	(revision 1369)
+++ conduit/modules/ConverterModule.py	(working copy)
@@ -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,
Index: conduit/modules/TomboyModule.py
===================================================================
--- conduit/modules/TomboyModule.py	(revision 1369)
+++ conduit/modules/TomboyModule.py	(working copy)
@@ -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 =  {
Index: conduit/modules/TestModule.py
===================================================================
--- conduit/modules/TestModule.py	(revision 1369)
+++ conduit/modules/TestModule.py	(working copy)
@@ -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
 
Index: conduit/modules/AudioVideoConverterModule.py
===================================================================
--- conduit/modules/AudioVideoConverterModule.py	(revision 1369)
+++ conduit/modules/AudioVideoConverterModule.py	(working copy)
@@ -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
Index: conduit/modules/PhotoConverterModule.py
===================================================================
--- conduit/modules/PhotoConverterModule.py	(revision 1369)
+++ conduit/modules/PhotoConverterModule.py	(working copy)
@@ -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,    
Index: conduit/Module.py
===================================================================
--- conduit/Module.py	(revision 1369)
+++ conduit/Module.py	(working copy)
@@ -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:
Index: conduit/ModuleWrapper.py
===================================================================
--- conduit/ModuleWrapper.py	(revision 1369)
+++ conduit/ModuleWrapper.py	(working copy)
@@ -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
         
-        @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 
+        @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
         """
-        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)
+        if type(initargs) != tuple:
+            raise Exception("Module init args must be a tuple")
+        
+        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__
 
-        #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.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-missing"
+        self.module_type="twoway"
+        self.classname=key.split(':')[0]
+        self.enabled=False
+
         self.key = key
         self.xmltext = ""
 
