Package conduit :: Module SyncSet
[hide private]

Source Code for Module conduit.SyncSet

  1  """ 
  2  Represents a group of conduits 
  3   
  4  Copyright: John Stowers, 2007 
  5  License: GPLv2 
  6  """ 
  7  import traceback 
  8  import os 
  9  import xml.dom.minidom 
 10  import gobject 
 11  import logging 
 12  log = logging.getLogger("SyncSet") 
 13   
 14  import conduit 
 15  import conduit.Conduit as Conduit 
 16  import conduit.Settings as Settings 
 17   
 18  #Increment this number when the xml settings file 
 19  #changes format 
 20  SETTINGS_VERSION = "1" 
 21   
22 -class SyncSet(gobject.GObject):
23 """ 24 Represents a group of conduits 25 """ 26 __gsignals__ = { 27 #Fired when a new instantiatable DP becomes available. It is described via 28 #a wrapper because we do not actually instantiate it till later - to save memory 29 "conduit-added" : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, [ 30 gobject.TYPE_PYOBJECT]), # The ConduitModel that was added 31 "conduit-removed" : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, [ 32 gobject.TYPE_PYOBJECT]), # The ConduitModel that was removed 33 } 34
35 - def __init__(self, moduleManager, syncManager, xmlSettingFilePath="settings.xml"):
36 gobject.GObject.__init__(self) 37 38 self.moduleManager = moduleManager 39 self.syncManager = syncManager 40 self.xmlSettingFilePath = xmlSettingFilePath 41 self.conduits = [] 42 43 self.moduleManager.connect("dataprovider-available", self.on_dataprovider_available_unavailable) 44 self.moduleManager.connect("dataprovider-unavailable", self.on_dataprovider_available_unavailable) 45 46 47 # FIXME: temporary hack - need to let factories know about this factory :-\! 48 self.moduleManager.emit("syncset-added", self)
49
50 - def _unitialize_dataproviders(self, cond):
51 for dp in cond.get_all_dataproviders(): 52 if dp.module: 53 dp.module.uninitialize()
54
55 - def _restore_dataprovider(self, cond, wrapperKey, dpName, dpxml, trySourceFirst):
56 """ 57 Adds the dataprovider back onto the canvas at the specifed 58 location and configures it with the given settings 59 """ 60 log.debug("Restoring %s to (source=%s)" % (wrapperKey,trySourceFirst)) 61 wrapper = self.moduleManager.get_module_wrapper_with_instance(wrapperKey) 62 wrapper.set_name(dpName) 63 if wrapper is not None: 64 for i in dpxml.childNodes: 65 if i.nodeType == i.ELEMENT_NODE and i.localName == "configuration": 66 wrapper.set_configuration_xml(xmltext=i.toxml()) 67 cond.add_dataprovider(wrapper, trySourceFirst)
68
69 - def on_dataprovider_available_unavailable(self, loader, dpw):
70 """ 71 Removes all PendingWrappers corresponding to dpw and replaces with new dpw instances 72 """ 73 key = dpw.get_key() 74 for c in self.get_all_conduits(): 75 for dp in c.get_dataproviders_by_key(key): 76 new = self.moduleManager.get_module_wrapper_with_instance(key) 77 #retain configuration information 78 new.set_configuration_xml(dp.get_configuration_xml()) 79 new.set_name(dp.get_name()) 80 c.change_dataprovider( 81 oldDpw=dp, 82 newDpw=new 83 )
84
85 - def emit(self, *args):
86 """ 87 Override the gobject signal emission so that all signals are emitted 88 from the main loop on an idle handler 89 """ 90 gobject.idle_add(gobject.GObject.emit,self,*args)
91
92 - def add_conduit(self, cond):
93 self.conduits.append(cond) 94 self.emit("conduit-added", cond)
95
96 - def remove_conduit(self, cond):
97 self.emit("conduit-removed", cond) 98 self._unitialize_dataproviders(cond) 99 self.conduits.remove(cond)
100
101 - def get_all_conduits(self):
102 return self.conduits
103
104 - def get_conduit(self, index):
105 return self.conduits[index]
106
107 - def index (self, conduit):
108 return self.conduits.index(conduit)
109
110 - def num_conduits(self):
111 return len(self.conduits)
112
113 - def clear(self):
114 for c in self.conduits[:]: 115 self.remove_conduit(c)
116
117 - def save_to_xml(self, xmlSettingFilePath=None):
118 """ 119 Saves the synchronisation settings (icluding all dataproviders and how 120 they are connected) to an xml file so that the 'sync set' can 121 be restored later 122 """ 123 if xmlSettingFilePath == None: 124 xmlSettingFilePath = self.xmlSettingFilePath 125 log.info("Saving Sync Set to %s" % self.xmlSettingFilePath) 126 127 #Build the application settings xml document 128 doc = xml.dom.minidom.Document() 129 rootxml = doc.createElement("conduit-application") 130 rootxml.setAttribute("application-version", conduit.VERSION) 131 rootxml.setAttribute("settings-version", SETTINGS_VERSION) 132 doc.appendChild(rootxml) 133 134 #Store the conduits 135 for cond in self.conduits: 136 conduitxml = doc.createElement("conduit") 137 conduitxml.setAttribute("uid",cond.uid) 138 conduitxml.setAttribute("twoway",str(cond.is_two_way())) 139 conduitxml.setAttribute("autosync",str(cond.do_auto_sync())) 140 for policyName in Conduit.CONFLICT_POLICY_NAMES: 141 conduitxml.setAttribute( 142 "%s_policy" % policyName, 143 cond.get_policy(policyName) 144 ) 145 rootxml.appendChild(conduitxml) 146 147 #Store the source 148 source = cond.datasource 149 if source is not None: 150 sourcexml = doc.createElement("datasource") 151 sourcexml.setAttribute("key", source.get_key()) 152 sourcexml.setAttribute("name", source.get_name()) 153 conduitxml.appendChild(sourcexml) 154 #Store source settings 155 configxml = xml.dom.minidom.parseString(source.get_configuration_xml()) 156 sourcexml.appendChild(configxml.documentElement) 157 158 #Store all sinks 159 sinksxml = doc.createElement("datasinks") 160 for sink in cond.datasinks: 161 sinkxml = doc.createElement("datasink") 162 sinkxml.setAttribute("key", sink.get_key()) 163 sinkxml.setAttribute("name", sink.get_name()) 164 sinksxml.appendChild(sinkxml) 165 #Store sink settings 166 configxml = xml.dom.minidom.parseString(sink.get_configuration_xml()) 167 sinkxml.appendChild(configxml.documentElement) 168 conduitxml.appendChild(sinksxml) 169 170 #Save to disk 171 try: 172 file_object = open(xmlSettingFilePath, "w") 173 file_object.write(doc.toxml()) 174 #file_object.write(doc.toprettyxml()) 175 file_object.close() 176 except IOError, err: 177 log.warn("Could not save settings to %s (Error: %s)" % (xmlSettingFilePath, err.strerror))
178
179 - def restore_from_xml(self, xmlSettingFilePath=None):
180 """ 181 Restores sync settings from the xml file 182 """ 183 if xmlSettingFilePath == None: 184 xmlSettingFilePath = self.xmlSettingFilePath 185 log.info("Restoring Sync Set from %s" % xmlSettingFilePath) 186 187 #Check the file exists 188 if not os.path.isfile(xmlSettingFilePath): 189 log.info("%s not present" % xmlSettingFilePath) 190 return 191 192 try: 193 #Open 194 doc = xml.dom.minidom.parse(xmlSettingFilePath) 195 196 #check the xml file is in a version we can read. 197 if doc.documentElement.hasAttribute("settings-version"): 198 if SETTINGS_VERSION != doc.documentElement.getAttribute("settings-version"): 199 log.info("%s xml file is incorrect version" % xmlSettingFilePath) 200 os.remove(xmlSettingFilePath) 201 return 202 203 #Parse... 204 for conds in doc.getElementsByTagName("conduit"): 205 #create a new conduit 206 cond = Conduit.Conduit(self.syncManager, conds.getAttribute("uid")) 207 self.add_conduit(cond) 208 209 #restore conduit specific settings 210 twoway = Settings.string_to_bool(conds.getAttribute("twoway")) 211 if twoway == True: 212 cond.enable_two_way_sync() 213 auto = Settings.string_to_bool(conds.getAttribute("autosync")) 214 if auto == True: 215 cond.enable_auto_sync() 216 for policyName in Conduit.CONFLICT_POLICY_NAMES: 217 cond.set_policy( 218 policyName, 219 conds.getAttribute("%s_policy" % policyName) 220 ) 221 222 #each dataprovider 223 for i in conds.childNodes: 224 #keep a ref to the dataproider was added to so that we 225 #can apply settings to it at the end 226 #one datasource 227 if i.nodeType == i.ELEMENT_NODE and i.localName == "datasource": 228 key = i.getAttribute("key") 229 name = i.getAttribute("name") 230 #add to canvas 231 if len(key) > 0: 232 self._restore_dataprovider(cond, key, name, i, True) 233 #many datasinks 234 elif i.nodeType == i.ELEMENT_NODE and i.localName == "datasinks": 235 #each datasink 236 for sink in i.childNodes: 237 if sink.nodeType == sink.ELEMENT_NODE and sink.localName == "datasink": 238 key = sink.getAttribute("key") 239 name = sink.getAttribute("name") 240 #add to canvas 241 if len(key) > 0: 242 self._restore_dataprovider(cond, key, name, sink, False) 243 244 except: 245 log.warn("Error parsing %s. Exception:\n%s" % (xmlSettingFilePath, traceback.format_exc())) 246 os.remove(xmlSettingFilePath)
247
248 - def quit(self):
249 """ 250 Calls unitialize on all dataproviders 251 """ 252 for c in self.conduits: 253 self._unitialize_dataproviders(c)
254