|
1 """ |
|
2 Config Tree Node base class. |
|
3 |
|
4 - A Beremiz project is organized in a tree each node derivate from ConfigTreeNode |
|
5 - Project tree organization match filesystem organization of project directory. |
|
6 - Each node of the tree have its own xml configuration, whose grammar is defined for each node type, as XSD |
|
7 - ... TODO : document |
|
8 """ |
|
9 |
|
10 import os,traceback,types |
|
11 import shutil |
|
12 from xml.dom import minidom |
|
13 |
|
14 from xmlclass import GenerateClassesFromXSDstring |
|
15 from util import opjimg, GetClassImporter |
|
16 |
|
17 from PLCControler import PLCControler, LOCATION_CONFNODE |
|
18 |
|
19 _BaseParamsClass = GenerateClassesFromXSDstring("""<?xml version="1.0" encoding="ISO-8859-1" ?> |
|
20 <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"> |
|
21 <xsd:element name="BaseParams"> |
|
22 <xsd:complexType> |
|
23 <xsd:attribute name="Name" type="xsd:string" use="optional" default="__unnamed__"/> |
|
24 <xsd:attribute name="IEC_Channel" type="xsd:integer" use="required"/> |
|
25 <xsd:attribute name="Enabled" type="xsd:boolean" use="optional" default="true"/> |
|
26 </xsd:complexType> |
|
27 </xsd:element> |
|
28 </xsd:schema>""")["BaseParams"] |
|
29 |
|
30 NameTypeSeparator = '@' |
|
31 |
|
32 class ConfigTreeNode: |
|
33 """ |
|
34 This class is the one that define confnodes. |
|
35 """ |
|
36 |
|
37 XSD = None |
|
38 CTNChildrenTypes = [] |
|
39 CTNMaxCount = None |
|
40 ConfNodeMethods = [] |
|
41 LibraryControler = None |
|
42 EditorType = None |
|
43 |
|
44 def _AddParamsMembers(self): |
|
45 self.CTNParams = None |
|
46 if self.XSD: |
|
47 self.Classes = GenerateClassesFromXSDstring(self.XSD) |
|
48 Classes = [(name, XSDclass) for name, XSDclass in self.Classes.items() if XSDclass.IsBaseClass] |
|
49 if len(Classes) == 1: |
|
50 name, XSDclass = Classes[0] |
|
51 obj = XSDclass() |
|
52 self.CTNParams = (name, obj) |
|
53 setattr(self, name, obj) |
|
54 |
|
55 def __init__(self): |
|
56 # Create BaseParam |
|
57 self.BaseParams = _BaseParamsClass() |
|
58 self.MandatoryParams = ("BaseParams", self.BaseParams) |
|
59 self._AddParamsMembers() |
|
60 self.Children = {} |
|
61 self._View = None |
|
62 # copy ConfNodeMethods so that it can be later customized |
|
63 self.ConfNodeMethods = [dic.copy() for dic in self.ConfNodeMethods] |
|
64 self.LoadSTLibrary() |
|
65 |
|
66 def ConfNodeBaseXmlFilePath(self, CTNName=None): |
|
67 return os.path.join(self.CTNPath(CTNName), "baseconfnode.xml") |
|
68 |
|
69 def ConfNodeXmlFilePath(self, CTNName=None): |
|
70 return os.path.join(self.CTNPath(CTNName), "confnode.xml") |
|
71 |
|
72 def ConfNodeLibraryFilePath(self): |
|
73 return os.path.join(self.ConfNodePath(), "pous.xml") |
|
74 |
|
75 def ConfNodePath(self): |
|
76 return os.path.join(self.CTNParent.ConfNodePath(), self.CTNType) |
|
77 |
|
78 def CTNPath(self,CTNName=None): |
|
79 if not CTNName: |
|
80 CTNName = self.CTNName() |
|
81 return os.path.join(self.CTNParent.CTNPath(), |
|
82 CTNName + NameTypeSeparator + self.CTNType) |
|
83 |
|
84 def CTNName(self): |
|
85 return self.BaseParams.getName() |
|
86 |
|
87 def CTNEnabled(self): |
|
88 return self.BaseParams.getEnabled() |
|
89 |
|
90 def CTNFullName(self): |
|
91 parent = self.CTNParent.CTNFullName() |
|
92 if parent != "": |
|
93 return parent + "." + self.CTNName() |
|
94 return self.BaseParams.getName() |
|
95 |
|
96 def GetIconPath(self, name): |
|
97 return opjimg(name) |
|
98 |
|
99 def CTNTestModified(self): |
|
100 return self.ChangesToSave |
|
101 |
|
102 def ProjectTestModified(self): |
|
103 """ |
|
104 recursively check modified status |
|
105 """ |
|
106 if self.CTNTestModified(): |
|
107 return True |
|
108 |
|
109 for CTNChild in self.IterChildren(): |
|
110 if CTNChild.ProjectTestModified(): |
|
111 return True |
|
112 |
|
113 return False |
|
114 |
|
115 def RemoteExec(self, script, **kwargs): |
|
116 return self.CTNParent.RemoteExec(script, **kwargs) |
|
117 |
|
118 def OnCTNSave(self): |
|
119 #Default, do nothing and return success |
|
120 return True |
|
121 |
|
122 def GetParamsAttributes(self, path = None): |
|
123 if path: |
|
124 parts = path.split(".", 1) |
|
125 if self.MandatoryParams and parts[0] == self.MandatoryParams[0]: |
|
126 return self.MandatoryParams[1].getElementInfos(parts[0], parts[1]) |
|
127 elif self.CTNParams and parts[0] == self.CTNParams[0]: |
|
128 return self.CTNParams[1].getElementInfos(parts[0], parts[1]) |
|
129 else: |
|
130 params = [] |
|
131 if self.CTNParams: |
|
132 params.append(self.CTNParams[1].getElementInfos(self.CTNParams[0])) |
|
133 return params |
|
134 |
|
135 def SetParamsAttribute(self, path, value): |
|
136 self.ChangesToSave = True |
|
137 # Filter IEC_Channel and Name, that have specific behavior |
|
138 if path == "BaseParams.IEC_Channel": |
|
139 old_leading = ".".join(map(str, self.GetCurrentLocation())) |
|
140 new_value = self.FindNewIEC_Channel(value) |
|
141 new_leading = ".".join(map(str, self.CTNParent.GetCurrentLocation() + (new_value,))) |
|
142 self.GetCTRoot().UpdateProjectVariableLocation(old_leading, new_leading) |
|
143 return new_value, True |
|
144 elif path == "BaseParams.Name": |
|
145 res = self.FindNewName(value) |
|
146 self.CTNRequestSave() |
|
147 return res, True |
|
148 |
|
149 parts = path.split(".", 1) |
|
150 if self.MandatoryParams and parts[0] == self.MandatoryParams[0]: |
|
151 self.MandatoryParams[1].setElementValue(parts[1], value) |
|
152 elif self.CTNParams and parts[0] == self.CTNParams[0]: |
|
153 self.CTNParams[1].setElementValue(parts[1], value) |
|
154 return value, False |
|
155 |
|
156 def CTNMakeDir(self): |
|
157 os.mkdir(self.CTNPath()) |
|
158 |
|
159 def CTNRequestSave(self): |
|
160 if self.GetCTRoot().CheckProjectPathPerm(False): |
|
161 # If confnode do not have corresponding directory |
|
162 ctnpath = self.CTNPath() |
|
163 if not os.path.isdir(ctnpath): |
|
164 # Create it |
|
165 os.mkdir(ctnpath) |
|
166 |
|
167 # generate XML for base XML parameters controller of the confnode |
|
168 if self.MandatoryParams: |
|
169 BaseXMLFile = open(self.ConfNodeBaseXmlFilePath(),'w') |
|
170 BaseXMLFile.write("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n") |
|
171 BaseXMLFile.write(self.MandatoryParams[1].generateXMLText(self.MandatoryParams[0], 0).encode("utf-8")) |
|
172 BaseXMLFile.close() |
|
173 |
|
174 # generate XML for XML parameters controller of the confnode |
|
175 if self.CTNParams: |
|
176 XMLFile = open(self.ConfNodeXmlFilePath(),'w') |
|
177 XMLFile.write("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n") |
|
178 XMLFile.write(self.CTNParams[1].generateXMLText(self.CTNParams[0], 0).encode("utf-8")) |
|
179 XMLFile.close() |
|
180 |
|
181 # Call the confnode specific OnCTNSave method |
|
182 result = self.OnCTNSave() |
|
183 if not result: |
|
184 return _("Error while saving \"%s\"\n")%self.CTNPath() |
|
185 |
|
186 # mark confnode as saved |
|
187 self.ChangesToSave = False |
|
188 # go through all children and do the same |
|
189 for CTNChild in self.IterChildren(): |
|
190 result = CTNChild.CTNRequestSave() |
|
191 if result: |
|
192 return result |
|
193 return None |
|
194 |
|
195 def CTNImport(self, src_CTNPath): |
|
196 shutil.copytree(src_CTNPath, self.CTNPath) |
|
197 return True |
|
198 |
|
199 def CTNGenerate_C(self, buildpath, locations): |
|
200 """ |
|
201 Generate C code |
|
202 @param locations: List of complete variables locations \ |
|
203 [{"IEC_TYPE" : the IEC type (i.e. "INT", "STRING", ...) |
|
204 "NAME" : name of the variable (generally "__IW0_1_2" style) |
|
205 "DIR" : direction "Q","I" or "M" |
|
206 "SIZE" : size "X", "B", "W", "D", "L" |
|
207 "LOC" : tuple of interger for IEC location (0,1,2,...) |
|
208 }, ...] |
|
209 @return: [(C_file_name, CFLAGS),...] , LDFLAGS_TO_APPEND |
|
210 """ |
|
211 self.GetCTRoot().logger.write_warning(".".join(map(lambda x:str(x), self.GetCurrentLocation())) + " -> Nothing to do\n") |
|
212 return [],"",False |
|
213 |
|
214 def _Generate_C(self, buildpath, locations): |
|
215 # Generate confnodes [(Cfiles, CFLAGS)], LDFLAGS, DoCalls, extra_files |
|
216 # extra_files = [(fname,fobject), ...] |
|
217 gen_result = self.CTNGenerate_C(buildpath, locations) |
|
218 CTNCFilesAndCFLAGS, CTNLDFLAGS, DoCalls = gen_result[:3] |
|
219 extra_files = gen_result[3:] |
|
220 # if some files have been generated put them in the list with their location |
|
221 if CTNCFilesAndCFLAGS: |
|
222 LocationCFilesAndCFLAGS = [(self.GetCurrentLocation(), CTNCFilesAndCFLAGS, DoCalls)] |
|
223 else: |
|
224 LocationCFilesAndCFLAGS = [] |
|
225 |
|
226 # confnode asks for some LDFLAGS |
|
227 if CTNLDFLAGS: |
|
228 # LDFLAGS can be either string |
|
229 if type(CTNLDFLAGS)==type(str()): |
|
230 LDFLAGS=[CTNLDFLAGS] |
|
231 #or list of strings |
|
232 elif type(CTNLDFLAGS)==type(list()): |
|
233 LDFLAGS=CTNLDFLAGS[:] |
|
234 else: |
|
235 LDFLAGS=[] |
|
236 |
|
237 # recurse through all children, and stack their results |
|
238 for CTNChild in self.IECSortedChildren(): |
|
239 new_location = CTNChild.GetCurrentLocation() |
|
240 # How deep are we in the tree ? |
|
241 depth=len(new_location) |
|
242 _LocationCFilesAndCFLAGS, _LDFLAGS, _extra_files = \ |
|
243 CTNChild._Generate_C( |
|
244 #keep the same path |
|
245 buildpath, |
|
246 # filter locations that start with current IEC location |
|
247 [loc for loc in locations if loc["LOC"][0:depth] == new_location ]) |
|
248 # stack the result |
|
249 LocationCFilesAndCFLAGS += _LocationCFilesAndCFLAGS |
|
250 LDFLAGS += _LDFLAGS |
|
251 extra_files += _extra_files |
|
252 |
|
253 return LocationCFilesAndCFLAGS, LDFLAGS, extra_files |
|
254 |
|
255 def ConfNodeTypesFactory(self): |
|
256 if self.LibraryControler is not None: |
|
257 return [{"name" : self.CTNType, "types": self.LibraryControler.Project}] |
|
258 return [] |
|
259 |
|
260 def ParentsTypesFactory(self): |
|
261 return self.CTNParent.ParentsTypesFactory() + self.ConfNodeTypesFactory() |
|
262 |
|
263 def ConfNodesTypesFactory(self): |
|
264 list = self.ConfNodeTypesFactory() |
|
265 for CTNChild in self.IterChildren(): |
|
266 list += CTNChild.ConfNodesTypesFactory() |
|
267 return list |
|
268 |
|
269 def STLibraryFactory(self): |
|
270 if self.LibraryControler is not None: |
|
271 program, errors, warnings = self.LibraryControler.GenerateProgram() |
|
272 return program + "\n" |
|
273 return "" |
|
274 |
|
275 def ConfNodesSTLibraryFactory(self): |
|
276 program = self.STLibraryFactory() |
|
277 for CTNChild in self.IECSortedChildren(): |
|
278 program += CTNChild.ConfNodesSTLibraryFactory() |
|
279 return program |
|
280 |
|
281 def IterChildren(self): |
|
282 for CTNType, Children in self.Children.items(): |
|
283 for CTNInstance in Children: |
|
284 yield CTNInstance |
|
285 |
|
286 def IECSortedChildren(self): |
|
287 # reorder children by IEC_channels |
|
288 ordered = [(chld.BaseParams.getIEC_Channel(),chld) for chld in self.IterChildren()] |
|
289 if ordered: |
|
290 ordered.sort() |
|
291 return zip(*ordered)[1] |
|
292 else: |
|
293 return [] |
|
294 |
|
295 def _GetChildBySomething(self, something, toks): |
|
296 for CTNInstance in self.IterChildren(): |
|
297 # if match component of the name |
|
298 if getattr(CTNInstance.BaseParams, something) == toks[0]: |
|
299 # if Name have other components |
|
300 if len(toks) >= 2: |
|
301 # Recurse in order to find the latest object |
|
302 return CTNInstance._GetChildBySomething( something, toks[1:]) |
|
303 # No sub name -> found |
|
304 return CTNInstance |
|
305 # Not found |
|
306 return None |
|
307 |
|
308 def GetChildByName(self, Name): |
|
309 if Name: |
|
310 toks = Name.split('.') |
|
311 return self._GetChildBySomething("Name", toks) |
|
312 else: |
|
313 return self |
|
314 |
|
315 def GetChildByIECLocation(self, Location): |
|
316 if Location: |
|
317 return self._GetChildBySomething("IEC_Channel", Location) |
|
318 else: |
|
319 return self |
|
320 |
|
321 def GetCurrentLocation(self): |
|
322 """ |
|
323 @return: Tupple containing confnode IEC location of current confnode : %I0.0.4.5 => (0,0,4,5) |
|
324 """ |
|
325 return self.CTNParent.GetCurrentLocation() + (self.BaseParams.getIEC_Channel(),) |
|
326 |
|
327 def GetCurrentName(self): |
|
328 """ |
|
329 @return: String "ParentParentName.ParentName.Name" |
|
330 """ |
|
331 return self.CTNParent._GetCurrentName() + self.BaseParams.getName() |
|
332 |
|
333 def _GetCurrentName(self): |
|
334 """ |
|
335 @return: String "ParentParentName.ParentName.Name." |
|
336 """ |
|
337 return self.CTNParent._GetCurrentName() + self.BaseParams.getName() + "." |
|
338 |
|
339 def GetCTRoot(self): |
|
340 return self.CTNParent.GetCTRoot() |
|
341 |
|
342 def GetFullIEC_Channel(self): |
|
343 return ".".join([str(i) for i in self.GetCurrentLocation()]) + ".x" |
|
344 |
|
345 def GetLocations(self): |
|
346 location = self.GetCurrentLocation() |
|
347 return [loc for loc in self.CTNParent.GetLocations() if loc["LOC"][0:len(location)] == location] |
|
348 |
|
349 def GetVariableLocationTree(self): |
|
350 ''' |
|
351 This function is meant to be overridden by confnodes. |
|
352 |
|
353 It should returns an list of dictionaries |
|
354 |
|
355 - IEC_type is an IEC type like BOOL/BYTE/SINT/... |
|
356 - location is a string of this variable's location, like "%IX0.0.0" |
|
357 ''' |
|
358 children = [] |
|
359 for child in self.IECSortedChildren(): |
|
360 children.append(child.GetVariableLocationTree()) |
|
361 return {"name": self.BaseParams.getName(), |
|
362 "type": LOCATION_CONFNODE, |
|
363 "location": self.GetFullIEC_Channel(), |
|
364 "children": children} |
|
365 |
|
366 def FindNewName(self, DesiredName): |
|
367 """ |
|
368 Changes Name to DesiredName if available, Name-N if not. |
|
369 @param DesiredName: The desired Name (string) |
|
370 """ |
|
371 # Get Current Name |
|
372 CurrentName = self.BaseParams.getName() |
|
373 # Do nothing if no change |
|
374 #if CurrentName == DesiredName: return CurrentName |
|
375 # Build a list of used Name out of parent's Children |
|
376 AllNames=[] |
|
377 for CTNInstance in self.CTNParent.IterChildren(): |
|
378 if CTNInstance != self: |
|
379 AllNames.append(CTNInstance.BaseParams.getName()) |
|
380 |
|
381 # Find a free name, eventually appending digit |
|
382 res = DesiredName |
|
383 suffix = 1 |
|
384 while res in AllNames: |
|
385 res = "%s-%d"%(DesiredName, suffix) |
|
386 suffix += 1 |
|
387 |
|
388 # Get old path |
|
389 oldname = self.CTNPath() |
|
390 # Check previous confnode existance |
|
391 dontexist = self.BaseParams.getName() == "__unnamed__" |
|
392 # Set the new name |
|
393 self.BaseParams.setName(res) |
|
394 # Rename confnode dir if exist |
|
395 if not dontexist: |
|
396 shutil.move(oldname, self.CTNPath()) |
|
397 # warn user he has two left hands |
|
398 if DesiredName != res: |
|
399 self.GetCTRoot().logger.write_warning(_("A child names \"%s\" already exist -> \"%s\"\n")%(DesiredName,res)) |
|
400 return res |
|
401 |
|
402 def GetAllChannels(self): |
|
403 AllChannels=[] |
|
404 for CTNInstance in self.CTNParent.IterChildren(): |
|
405 if CTNInstance != self: |
|
406 AllChannels.append(CTNInstance.BaseParams.getIEC_Channel()) |
|
407 AllChannels.sort() |
|
408 return AllChannels |
|
409 |
|
410 def FindNewIEC_Channel(self, DesiredChannel): |
|
411 """ |
|
412 Changes IEC Channel number to DesiredChannel if available, nearest available if not. |
|
413 @param DesiredChannel: The desired IEC channel (int) |
|
414 """ |
|
415 # Get Current IEC channel |
|
416 CurrentChannel = self.BaseParams.getIEC_Channel() |
|
417 # Do nothing if no change |
|
418 #if CurrentChannel == DesiredChannel: return CurrentChannel |
|
419 # Build a list of used Channels out of parent's Children |
|
420 AllChannels = self.GetAllChannels() |
|
421 |
|
422 # Now, try to guess the nearest available channel |
|
423 res = DesiredChannel |
|
424 while res in AllChannels: # While channel not free |
|
425 if res < CurrentChannel: # Want to go down ? |
|
426 res -= 1 # Test for n-1 |
|
427 if res < 0 : |
|
428 self.GetCTRoot().logger.write_warning(_("Cannot find lower free IEC channel than %d\n")%CurrentChannel) |
|
429 return CurrentChannel # Can't go bellow 0, do nothing |
|
430 else : # Want to go up ? |
|
431 res += 1 # Test for n-1 |
|
432 # Finally set IEC Channel |
|
433 self.BaseParams.setIEC_Channel(res) |
|
434 return res |
|
435 |
|
436 def _OpenView(self, name=None): |
|
437 if self.EditorType is not None and self._View is None: |
|
438 app_frame = self.GetCTRoot().AppFrame |
|
439 |
|
440 self._View = self.EditorType(app_frame.TabsOpened, self, app_frame) |
|
441 |
|
442 app_frame.EditProjectElement(self._View, self.CTNName()) |
|
443 |
|
444 return self._View |
|
445 return None |
|
446 |
|
447 def OnCloseEditor(self, view): |
|
448 if self._View == view: |
|
449 self._View = None |
|
450 |
|
451 def OnCTNClose(self): |
|
452 if self._View is not None: |
|
453 app_frame = self.GetCTRoot().AppFrame |
|
454 if app_frame is not None: |
|
455 app_frame.DeletePage(self._View) |
|
456 return True |
|
457 |
|
458 def _doRemoveChild(self, CTNInstance): |
|
459 # Remove all children of child |
|
460 for SubCTNInstance in CTNInstance.IterChildren(): |
|
461 CTNInstance._doRemoveChild(SubCTNInstance) |
|
462 # Call the OnCloseMethod |
|
463 CTNInstance.OnCTNClose() |
|
464 # Delete confnode dir |
|
465 shutil.rmtree(CTNInstance.CTNPath()) |
|
466 # Remove child of Children |
|
467 self.Children[CTNInstance.CTNType].remove(CTNInstance) |
|
468 # Forget it... (View have to refresh) |
|
469 |
|
470 def CTNRemove(self): |
|
471 # Fetch the confnode |
|
472 #CTNInstance = self.GetChildByName(CTNName) |
|
473 # Ask to his parent to remove it |
|
474 self.CTNParent._doRemoveChild(self) |
|
475 |
|
476 def CTNAddChild(self, CTNName, CTNType, IEC_Channel=0): |
|
477 """ |
|
478 Create the confnodes that may be added as child to this node self |
|
479 @param CTNType: string desining the confnode class name (get name from CTNChildrenTypes) |
|
480 @param CTNName: string for the name of the confnode instance |
|
481 """ |
|
482 # reorganize self.CTNChildrenTypes tuples from (name, CTNClass, Help) |
|
483 # to ( name, (CTNClass, Help)), an make a dict |
|
484 transpose = zip(*self.CTNChildrenTypes) |
|
485 CTNChildrenTypes = dict(zip(transpose[0],zip(transpose[1],transpose[2]))) |
|
486 # Check that adding this confnode is allowed |
|
487 try: |
|
488 CTNClass, CTNHelp = CTNChildrenTypes[CTNType] |
|
489 except KeyError: |
|
490 raise Exception, _("Cannot create child %s of type %s ")%(CTNName, CTNType) |
|
491 |
|
492 # if CTNClass is a class factory, call it. (prevent unneeded imports) |
|
493 if type(CTNClass) == types.FunctionType: |
|
494 CTNClass = CTNClass() |
|
495 |
|
496 # Eventualy Initialize child instance list for this class of confnode |
|
497 ChildrenWithSameClass = self.Children.setdefault(CTNType, list()) |
|
498 # Check count |
|
499 if getattr(CTNClass, "CTNMaxCount", None) and len(ChildrenWithSameClass) >= CTNClass.CTNMaxCount: |
|
500 raise Exception, _("Max count (%d) reached for this confnode of type %s ")%(CTNClass.CTNMaxCount, CTNType) |
|
501 |
|
502 # create the final class, derived of provided confnode and template |
|
503 class FinalCTNClass(CTNClass, ConfigTreeNode): |
|
504 """ |
|
505 ConfNode class is derivated into FinalCTNClass before being instanciated |
|
506 This way __init__ is overloaded to ensure ConfigTreeNode.__init__ is called |
|
507 before CTNClass.__init__, and to do the file related stuff. |
|
508 """ |
|
509 def __init__(_self): |
|
510 # self is the parent |
|
511 _self.CTNParent = self |
|
512 # Keep track of the confnode type name |
|
513 _self.CTNType = CTNType |
|
514 # remind the help string, for more fancy display |
|
515 _self.CTNHelp = CTNHelp |
|
516 # Call the base confnode template init - change XSD into class members |
|
517 ConfigTreeNode.__init__(_self) |
|
518 # check name is unique |
|
519 NewCTNName = _self.FindNewName(CTNName) |
|
520 # If dir have already be made, and file exist |
|
521 if os.path.isdir(_self.CTNPath(NewCTNName)): #and os.path.isfile(_self.ConfNodeXmlFilePath(CTNName)): |
|
522 #Load the confnode.xml file into parameters members |
|
523 _self.LoadXMLParams(NewCTNName) |
|
524 # Basic check. Better to fail immediately. |
|
525 if (_self.BaseParams.getName() != NewCTNName): |
|
526 raise Exception, _("Project tree layout do not match confnode.xml %s!=%s ")%(NewCTNName, _self.BaseParams.getName()) |
|
527 |
|
528 # Now, self.CTNPath() should be OK |
|
529 |
|
530 # Check that IEC_Channel is not already in use. |
|
531 _self.FindNewIEC_Channel(_self.BaseParams.getIEC_Channel()) |
|
532 # Call the confnode real __init__ |
|
533 if getattr(CTNClass, "__init__", None): |
|
534 CTNClass.__init__(_self) |
|
535 #Load and init all the children |
|
536 _self.LoadChildren() |
|
537 #just loaded, nothing to saved |
|
538 _self.ChangesToSave = False |
|
539 else: |
|
540 # If confnode do not have corresponding file/dirs - they will be created on Save |
|
541 _self.CTNMakeDir() |
|
542 # Find an IEC number |
|
543 _self.FindNewIEC_Channel(IEC_Channel) |
|
544 # Call the confnode real __init__ |
|
545 if getattr(CTNClass, "__init__", None): |
|
546 CTNClass.__init__(_self) |
|
547 _self.CTNRequestSave() |
|
548 #just created, must be saved |
|
549 _self.ChangesToSave = True |
|
550 |
|
551 def _getBuildPath(_self): |
|
552 return self._getBuildPath() |
|
553 |
|
554 # Create the object out of the resulting class |
|
555 newConfNodeOpj = FinalCTNClass() |
|
556 # Store it in CTNgedChils |
|
557 ChildrenWithSameClass.append(newConfNodeOpj) |
|
558 |
|
559 return newConfNodeOpj |
|
560 |
|
561 def ClearChildren(self): |
|
562 for child in self.IterChildren(): |
|
563 child.ClearChildren() |
|
564 self.Children = {} |
|
565 |
|
566 def LoadSTLibrary(self): |
|
567 # Get library blocks if plcopen library exist |
|
568 library_path = self.ConfNodeLibraryFilePath() |
|
569 if os.path.isfile(library_path): |
|
570 self.LibraryControler = PLCControler() |
|
571 self.LibraryControler.OpenXMLFile(library_path) |
|
572 self.LibraryControler.ClearConfNodeTypes() |
|
573 self.LibraryControler.AddConfNodeTypesList(self.ParentsTypesFactory()) |
|
574 |
|
575 def LoadXMLParams(self, CTNName = None): |
|
576 methode_name = os.path.join(self.CTNPath(CTNName), "methods.py") |
|
577 if os.path.isfile(methode_name): |
|
578 execfile(methode_name) |
|
579 |
|
580 # Get the base xml tree |
|
581 if self.MandatoryParams: |
|
582 try: |
|
583 basexmlfile = open(self.ConfNodeBaseXmlFilePath(CTNName), 'r') |
|
584 basetree = minidom.parse(basexmlfile) |
|
585 self.MandatoryParams[1].loadXMLTree(basetree.childNodes[0]) |
|
586 basexmlfile.close() |
|
587 except Exception, exc: |
|
588 self.GetCTRoot().logger.write_error(_("Couldn't load confnode base parameters %s :\n %s") % (CTNName, str(exc))) |
|
589 self.GetCTRoot().logger.write_error(traceback.format_exc()) |
|
590 |
|
591 # Get the xml tree |
|
592 if self.CTNParams: |
|
593 try: |
|
594 xmlfile = open(self.ConfNodeXmlFilePath(CTNName), 'r') |
|
595 tree = minidom.parse(xmlfile) |
|
596 self.CTNParams[1].loadXMLTree(tree.childNodes[0]) |
|
597 xmlfile.close() |
|
598 except Exception, exc: |
|
599 self.GetCTRoot().logger.write_error(_("Couldn't load confnode parameters %s :\n %s") % (CTNName, str(exc))) |
|
600 self.GetCTRoot().logger.write_error(traceback.format_exc()) |
|
601 |
|
602 def LoadChildren(self): |
|
603 # Iterate over all CTNName@CTNType in confnode directory, and try to open them |
|
604 for CTNDir in os.listdir(self.CTNPath()): |
|
605 if os.path.isdir(os.path.join(self.CTNPath(), CTNDir)) and \ |
|
606 CTNDir.count(NameTypeSeparator) == 1: |
|
607 pname, ptype = CTNDir.split(NameTypeSeparator) |
|
608 try: |
|
609 self.CTNAddChild(pname, ptype) |
|
610 except Exception, exc: |
|
611 self.GetCTRoot().logger.write_error(_("Could not add child \"%s\", type %s :\n%s\n")%(pname, ptype, str(exc))) |
|
612 self.GetCTRoot().logger.write_error(traceback.format_exc()) |
|
613 |
|
614 def EnableMethod(self, method, value): |
|
615 for d in self.ConfNodeMethods: |
|
616 if d["method"]==method: |
|
617 d["enabled"]=value |
|
618 return True |
|
619 return False |
|
620 |
|
621 def ShowMethod(self, method, value): |
|
622 for d in self.ConfNodeMethods: |
|
623 if d["method"]==method: |
|
624 d["shown"]=value |
|
625 return True |
|
626 return False |
|
627 |
|
628 def CallMethod(self, method): |
|
629 for d in self.ConfNodeMethods: |
|
630 if d["method"]==method and d.get("enabled", True) and d.get("shown", True): |
|
631 getattr(self, method)() |
|
632 |