]> rtime.felk.cvut.cz Git - CanFestival-3.git/blob - objdictgen/nodemanager.py
Bug on map variable type changing and on comments with special characters corrected
[CanFestival-3.git] / objdictgen / nodemanager.py
1 #!/usr/bin/env python
2 # -*- coding: utf-8 -*-
3
4 #This file is part of CanFestival, a library implementing CanOpen Stack. 
5 #
6 #Copyright (C): Edouard TISSERANT, Francis DUPIN and Laurent BESSARD
7 #
8 #See COPYING file for copyrights details.
9 #
10 #This library is free software; you can redistribute it and/or
11 #modify it under the terms of the GNU Lesser General Public
12 #License as published by the Free Software Foundation; either
13 #version 2.1 of the License, or (at your option) any later version.
14 #
15 #This library is distributed in the hope that it will be useful,
16 #but WITHOUT ANY WARRANTY; without even the implied warranty of
17 #MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18 #Lesser General Public License for more details.
19 #
20 #You should have received a copy of the GNU Lesser General Public
21 #License along with this library; if not, write to the Free Software
22 #Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
23
24 from gnosis.xml.pickle import *
25 from gnosis.xml.pickle.util import setParanoia
26 setParanoia(0)
27
28 from node import *
29 import xml_in, gen_cfile
30
31 from types import *
32 import os, re
33
34 UndoBufferLength = 20
35
36 type_model = re.compile('([\_A-Z]*)([0-9]*)')
37 range_model = re.compile('([\_A-Z]*)([0-9]*)\[([\-0-9]*)-([\-0-9]*)\]')
38 name_model = re.compile('(.*)\[(.*)\]')
39
40 def IsOfType(object, typedef):
41     return type(object) == typedef
42
43 #-------------------------------------------------------------------------------
44 #                           Formating Name of an Entry
45 #-------------------------------------------------------------------------------
46
47 """
48 Format the text given with the index and subindex defined
49 """
50
51 def StringFormat(text, idx, sub):
52     result = name_model.match(text)
53     if result:
54         format = result.groups()
55         return format[0]%eval(format[1])
56     else:
57         return text
58
59 #-------------------------------------------------------------------------------
60 #                         Search in a Mapping Dictionary
61 #-------------------------------------------------------------------------------
62
63 """
64 Return the index of the informations in the Object Dictionary in case of identical
65 indexes
66 """
67 def FindIndex(index, mappingdictionary):
68     if index in mappingdictionary:
69         return index
70     else:
71         listpluri = [idx for idx in mappingdictionary.keys() if mappingdictionary[idx]["struct"] & OD_IdenticalIndexes]
72         listpluri.sort()
73         for idx in listpluri:
74             nb_max = mappingdictionary[idx]["nbmax"]
75             incr = mappingdictionary[idx]["incr"]
76             if idx < index < idx + incr * nb_max and (index - idx)%incr == 0:
77                 return idx
78     return None
79
80 """
81 Return the index of the typename given by searching in mappingdictionary 
82 """
83 def FindTypeIndex(typename, mappingdictionary):
84     testdic = {}
85     for index, values in mappingdictionary.iteritems():
86         if index < 0x1000:
87             testdic[values["name"]] = index
88     if typename in testdic:
89         return testdic[typename]
90     return None
91
92 """
93 Return the name of the type by searching in mappingdictionary 
94 """
95 def FindTypeName(typeindex, mappingdictionary):
96     if typeindex < 0x1000 and typeindex in mappingdictionary:
97         return mappingdictionary[typeindex]["name"]
98     return None
99
100 """
101 Return the default value of the type by searching in mappingdictionary 
102 """
103 def FindTypeDefaultValue(typeindex, mappingdictionary):
104     if typeindex < 0x1000 and typeindex in mappingdictionary:
105         return mappingdictionary[typeindex]["default"]
106     return None
107
108 """
109 Return the list of types defined in mappingdictionary 
110 """
111 def FindTypeList(mappingdictionary):
112     list = []
113     for index in mappingdictionary.keys():
114         if index < 0x1000:
115             list.append((index, mappingdictionary[index]["name"]))
116     return list
117
118 """
119 Return the name of an entry by searching in mappingdictionary 
120 """
121 def FindEntryName(index, mappingdictionary):
122     base_index = FindIndex(index, mappingdictionary)
123     if base_index:
124         infos = mappingdictionary[base_index]
125         if infos["struct"] & OD_IdenticalIndexes:
126             return StringFormat(infos["name"], (index - base_index) / infos["incr"] + 1, 0)
127         else:
128             return infos["name"]
129     return None
130
131 """
132 Return the informations of one entry by searching in mappingdictionary 
133 """
134 def FindEntryInfos(index, mappingdictionary):
135     base_index = FindIndex(index, mappingdictionary)
136     if base_index:
137         copy = mappingdictionary[base_index].copy()
138         if copy["struct"] & OD_IdenticalIndexes:
139             copy["name"] = StringFormat(copy["name"], (index - base_index) / copy["incr"] + 1, 0)
140         copy.pop("values")
141         return copy
142     return None
143
144 """
145 Return the informations of one subentry of an entry by searching in mappingdictionary 
146 """
147 def FindSubentryInfos(index, subIndex, mappingdictionary):
148     base_index = FindIndex(index, mappingdictionary)
149     if base_index:
150         struct = mappingdictionary[base_index]["struct"]
151         if struct & OD_Subindex:
152             if struct & OD_IdenticalSubindexes:
153                 if struct & OD_IdenticalIndexes:
154                     incr = mappingdictionary[base_index]["incr"]
155                 else:
156                     incr = 1
157                 if subIndex == 0:
158                     return mappingdictionary[base_index]["values"][0].copy()
159                 elif 0 < subIndex <= mappingdictionary[base_index]["values"][1]["nbmax"]:
160                     copy = mappingdictionary[base_index]["values"][1].copy()
161                     copy["name"] = StringFormat(copy["name"], (index - base_index) / incr + 1, subIndex)
162                     return copy
163             elif struct & OD_MultipleSubindexes and 0 <= subIndex < len(mappingdictionary[base_index]["values"]):
164                 return mappingdictionary[base_index]["values"][subIndex].copy()
165             elif subIndex == 0:
166                 return mappingdictionary[base_index]["values"][0].copy()
167     return None
168
169 """
170 Return the list of variables that can be mapped defined in mappingdictionary 
171 """
172 def FindMapVariableList(mappingdictionary, Manager):
173     list = []
174     for index in mappingdictionary.iterkeys():
175         if Manager.IsCurrentEntry(index):
176             for subIndex, values in enumerate(mappingdictionary[index]["values"]):
177                 if mappingdictionary[index]["values"][subIndex]["pdo"]:
178                     infos = Manager.GetEntryInfos(mappingdictionary[index]["values"][subIndex]["type"])
179                     if mappingdictionary[index]["struct"] & OD_IdenticalSubindexes:
180                         values = Manager.GetCurrentEntry(index)
181                         for i in xrange(len(values) - 1):
182                             list.append((index, i + 1, infos["size"], StringFormat(mappingdictionary[index]["values"][subIndex]["name"],1,i+1)))
183                     else:
184                         list.append((index, subIndex, infos["size"], mappingdictionary[index]["values"][subIndex]["name"]))
185     return list
186
187 """
188 Return the list of mandatory indexes defined in mappingdictionary 
189 """
190 def FindMandatoryIndexes(mappingdictionary):
191     list = []
192     for index in mappingdictionary.iterkeys():
193         if index >= 0x1000 and mappingdictionary[index]["need"]:
194             list.append(index)
195     return list
196
197
198 """
199 Class implementing a buffer of changes made on the current editing Object Dictionary
200 """
201
202 class UndoBuffer:
203
204     """
205     Constructor initialising buffer
206     """
207     def __init__(self, currentstate, issaved = False):
208         self.Buffer = []
209         self.CurrentIndex = -1
210         self.MinIndex = -1
211         self.MaxIndex = -1
212         # if current state is defined
213         if currentstate:
214             self.CurrentIndex = 0
215             self.MinIndex = 0
216             self.MaxIndex = 0
217         # Initialising buffer with currentstate at the first place
218         for i in xrange(UndoBufferLength):
219             if i == 0:
220                 self.Buffer.append(currentstate)
221             else:
222                 self.Buffer.append(None)
223         # Initialising index of state saved
224         if issaved:
225             self.LastSave = 0
226         else:
227             self.LastSave = -1
228     
229     """
230     Add a new state in buffer
231     """
232     def Buffering(self, currentstate):
233         self.CurrentIndex = (self.CurrentIndex + 1) % UndoBufferLength
234         self.Buffer[self.CurrentIndex] = currentstate
235         # Actualising buffer limits
236         self.MaxIndex = self.CurrentIndex
237         if self.MinIndex == self.CurrentIndex:
238             # If the removed state was the state saved, there is no state saved in the buffer
239             if self.LastSave == self.MinIndex:
240                 self.LastSave = -1
241             self.MinIndex = (self.MinIndex + 1) % UndoBufferLength
242         self.MinIndex = max(self.MinIndex, 0)
243     
244     """
245     Return current state of buffer
246     """
247     def Current(self):
248         return self.Buffer[self.CurrentIndex]
249     
250     """
251     Change current state to previous in buffer and return new current state
252     """
253     def Previous(self):
254         if self.CurrentIndex != self.MinIndex:
255             self.CurrentIndex = (self.CurrentIndex - 1) % UndoBufferLength
256             return self.Buffer[self.CurrentIndex]
257         return None
258     
259     """
260     Change current state to next in buffer and return new current state
261     """
262     def Next(self):
263         if self.CurrentIndex != self.MaxIndex:
264             self.CurrentIndex = (self.CurrentIndex + 1) % UndoBufferLength
265             return self.Buffer[self.CurrentIndex]
266         return None
267     
268     """
269     Return True if current state is the first in buffer
270     """
271     def IsFirst(self):
272         return self.CurrentIndex == self.MinIndex
273     
274     """
275     Return True if current state is the last in buffer
276     """
277     def IsLast(self):
278         return self.CurrentIndex == self.MaxIndex
279
280     """
281     Note that current state is saved
282     """
283     def CurrentSaved(self):
284         self.LastSave = self.CurrentIndex
285         
286     """
287     Return True if current state is saved
288     """
289     def IsCurrentSaved(self):
290         return self.LastSave == self.CurrentIndex
291
292
293
294 """
295 Class which control the operations made on the node and answer to view requests
296 """
297
298 class NodeManager:
299
300     """
301     Constructor
302     """
303     def __init__(self):
304         self.LastNewIndex = 0
305         self.FilePaths = []
306         self.FileNames = []
307         self.NodeIndex = -1
308         self.CurrentNode = None
309         self.UndoBuffers = []
310
311 #-------------------------------------------------------------------------------
312 #                         Type and Map Variable Lists
313 #-------------------------------------------------------------------------------
314
315     """
316     Generate the list of types defined for the current node
317     """
318     def GenerateTypeList(self):
319         self.TypeList = ""
320         self.TypeTranslation = {}
321         list = self.GetTypeList()
322         sep = ""
323         for index, name in list:
324             self.TypeList += "%s%s"%(sep,name)
325             self.TypeTranslation[name] = index
326             sep = ","
327     
328     """
329     Generate the list of variables that can be mapped for the current node
330     """
331     def GenerateMapList(self):
332         self.MapList = "None"
333         self.NameTranslation = {"None" : "00000000"}
334         self.MapTranslation = {"00000000" : "None"}
335         list = self.GetMapVariableList()
336         for index, subIndex, size, name in list:
337             self.MapList += ",%s"%name
338             map = "%04X%02X%02X"%(index,subIndex,size)
339             self.NameTranslation[name] = map
340             self.MapTranslation[map] = name
341     
342     """
343     Return the list of types defined for the current node
344     """
345     def GetCurrentTypeList(self):
346         return self.TypeList
347
348     """
349     Return the list of variables that can be mapped for the current node
350     """
351     def GetCurrentMapList(self):
352         return self.MapList
353
354 #-------------------------------------------------------------------------------
355 #                        Create Load and Save Functions
356 #-------------------------------------------------------------------------------
357
358     """
359     Create a new node and add a new buffer for storing it
360     """
361     def CreateNewNode(self, name, id, type, profile, filepath, NMT, options):
362         # Create a new node
363         node = Node()
364         # Try to load profile given
365         result = self.LoadProfile(profile, filepath, node)
366         if not IsOfType(result, StringType):
367             # if success, initialising node
368             self.CurrentNode = node
369             self.CurrentNode.SetNodeName(name)
370             self.CurrentNode.SetNodeID(id)
371             self.CurrentNode.SetNodeType(type)
372             AddIndexList = self.GetMandatoryIndexes()
373             if NMT == "NodeGuarding":
374                 AddIndexList.extend([0x100C, 0x100D])
375             elif NMT == "Heartbeat":
376                 AddIndexList.append(0x1017)
377             for option in options:
378                 if option == "DS302":
379                     # Charging DS-302 profile if choosen by user
380                     if os.path.isfile("config/DS-302.prf"):
381                         try:
382                             Mapping = {}
383                             AddMenuEntries = []
384                             execfile("config/DS-302.prf")
385                             self.CurrentNode.SetDS302Profile(Mapping)
386                             self.CurrentNode.ExtendSpecificMenu(AddMenuEntries)
387                         except:
388                             return "Problem with DS-302! Syntax Error."
389                     else:
390                         return "Couldn't find DS-302 in 'config' folder!"
391                 elif option == "GenSYNC":
392                     AddIndexList.extend([0x1005, 0x1006])
393                 elif option == "Emergency":
394                     AddIndexList.append(0x1014)
395                 elif option == "SaveConfig":
396                     AddIndexList.extend([0x1010, 0x1011, 0x1020])
397                 elif option == "StoreEDS":
398                     AddIndexList.extend([0x1021, 0x1022])
399             # Add a new buffer 
400             self.AddNodeBuffer()
401             self.SetCurrentFilePath("")
402             # Add Mandatory indexes
403             self.ManageEntriesOfCurrent(AddIndexList, [])
404             # Regenerate lists
405             self.GenerateTypeList()
406             self.GenerateMapList()
407             return True
408         else:
409             return result
410     
411     """
412     Load a profile in node
413     """
414     def LoadProfile(self, profile, filepath, node):
415         if profile != "None":
416             # Try to charge the profile given
417             try:
418                 execfile(filepath)
419                 node.SetProfileName(profile)
420                 node.SetProfile(Mapping)
421                 node.SetSpecificMenu(AddMenuEntries)
422                 return True
423             except:
424                 return "Bad OD Profile file!\nSyntax Error."
425         else:
426             # Default profile
427             node.SetProfileName("None")
428             node.SetProfile({})
429             node.SetSpecificMenu([])
430             return True
431
432     """
433     Open a file and store it in a new buffer
434     """
435     def OpenFileInCurrent(self, filepath):
436         # Open and load file
437         file = open(filepath, "r")
438         node = load(file)
439         file.close()
440         self.CurrentNode = node
441         # Add a new buffer and defining current state
442         self.AddNodeBuffer(self.CurrentNode.Copy(), True)
443         self.SetCurrentFilePath(filepath)
444         # Regenerate lists
445         self.GenerateTypeList()
446         self.GenerateMapList()
447         return True
448
449     """
450     Save current node in  a file
451     """
452     def SaveCurrentInFile(self, filepath = None):
453         # if no filepath given, verify if current node has a filepath defined
454         if not filepath:
455             filepath = self.GetCurrentFilePath()
456             if filepath == "":
457                 return False
458         # Save node in file
459         file = open(filepath, "w")
460         dump(self.CurrentNode, file)
461         file.close()
462         self.SetCurrentFilePath(filepath)
463         # Update saved state in buffer
464         self.UndoBuffers[self.NodeIndex].CurrentSaved()
465         return True
466
467     """
468     Close current state
469     """
470     def CloseCurrent(self, ignore = False):
471         # Verify if it's not forced that the current node is saved before closing it
472         if self.UndoBuffers[self.NodeIndex].IsCurrentSaved() or ignore:
473             self.RemoveNodeBuffer(self.NodeIndex)
474             return True
475         return False
476
477     """
478     Import a xml file and store it in a new buffer if no node edited
479     """
480     def ImportCurrentFromFile(self, filepath):
481         # Generate node from definition in a xml file
482         node = xml_in.GenerateNode(filepath, self)
483         if node:
484             self.CurrentNode = node
485             self.GenerateTypeList()
486             self.GenerateMapList()
487             if len(self.UndoBuffers) == 0:
488                 self.AddNodeBuffer()
489                 self.SetCurrentFilePath("")
490             self.BufferCurrentNode()
491         return result
492     
493     """
494     Build the C definition of Object Dictionary for current node 
495     """
496     def ExportCurrentToFile(self, filepath):
497         return gen_cfile.GenerateFile(filepath, self)
498
499 #-------------------------------------------------------------------------------
500 #                        Add Entries to Current Functions
501 #-------------------------------------------------------------------------------
502
503     """
504     Add the specified number of subentry for the given entry. Verify that total
505     number of subentry (except 0) doesn't exceed nbmax defined
506     """
507     def AddSubentriesToCurrent(self, index, number):
508         # Informations about entry
509         length = self.CurrentNode.GetEntry(index, 0)
510         infos = self.GetEntryInfos(index)
511         subentry_infos = self.GetSubentryInfos(index, 1)
512         # Get default value for subindex
513         if "default" in subentry_infos:
514             default = subentry_infos["default"]
515         else:
516             default = self.GetTypeDefaultValue(subentry_infos["type"])   
517         # First case entry is record
518         if infos["struct"] & OD_IdenticalSubindexes:
519             for i in xrange(1, min(number,subentry_infos["nbmax"]-length) + 1):
520                 self.CurrentNode.AddEntry(index, length + i, default)
521             self.BufferCurrentNode()
522         # Second case entry is array, only possible for manufacturer specific
523         elif infos["struct"] & OD_MultipleSubindexes and 0x2000 <= index <= 0x5FFF:
524             values = {"name" : "Undefined", "type" : 5, "access" : "rw", "pdo" : True}
525             for i in xrange(1, min(number,0xFE-length) + 1):
526                 self.CurrentNode.AddMappingEntry(index, length + i, values = values.copy())
527                 self.CurrentNode.AddEntry(index, length + i, 0)
528             self.BufferCurrentNode()
529
530     """
531     Remove the specified number of subentry for the given entry. Verify that total
532     number of subentry (except 0) isn't less than 1
533     """
534     def RemoveSubentriesFromCurrent(self, index, number):
535         # Informations about entry
536         infos = self.GetEntryInfos(index)
537         length = self.CurrentNode.GetEntry(index, 0)
538         # Entry is a record, or is an array of manufacturer specific
539         if infos["struct"] & OD_IdenticalSubindexes or 0x2000 <= index <= 0x5FFF and infos["struct"] & OD_IdenticalSubindexes:
540             for i in xrange(min(number, length - 1)):
541                 self.RemoveCurrentVariable(index, length - i)
542             self.BufferCurrentNode()
543
544     """
545     Add a SDO Server to current node
546     """
547     def AddSDOServerToCurrent(self):
548         # An SDO Server is already defined at index 0x1200
549         if self.CurrentNode.IsEntry(0x1200):
550             indexlist = [self.GetLineFromIndex(0x1201)]
551             if None not in indexlist:
552                 self.ManageEntriesOfCurrent(indexlist, [])
553         # Add an SDO Server at index 0x1200
554         else:
555             self.ManageEntriesOfCurrent([0x1200], [])
556         
557     """
558     Add a SDO Server to current node
559     """
560     def AddSDOClientToCurrent(self):
561         indexlist = [self.GetLineFromIndex(0x1280)]
562         if None not in indexlist:
563             self.ManageEntriesOfCurrent(indexlist, [])
564
565     """
566     Add a Transmit PDO to current node
567     """
568     def AddPDOTransmitToCurrent(self):
569         indexlist = [self.GetLineFromIndex(0x1800),self.GetLineFromIndex(0x1A00)]
570         if None not in indexlist:
571             self.ManageEntriesOfCurrent(indexlist, [])
572         
573     """
574     Add a Receive PDO to current node
575     """
576     def AddPDOReceiveToCurrent(self):
577         indexlist = [self.GetLineFromIndex(0x1400),self.GetLineFromIndex(0x1600)]
578         if None not in indexlist:
579             self.ManageEntriesOfCurrent(indexlist, [])
580
581     """
582     Add a list of entries defined in profile for menu item selected to current node
583     """
584     def AddSpecificEntryToCurrent(self, menuitem):
585         indexlist = []
586         for menu, indexes in self.CurrentNode.GetSpecificMenu():
587             if menuitem == menu:
588                 for index in indexes:
589                     indexlist.append(self.GetLineFromIndex(index))
590         if None not in indexlist:
591             self.ManageEntriesOfCurrent(indexlist, [])
592
593     """
594     Search the first index available for a pluri entry from base_index
595     """
596     def GetLineFromIndex(self, base_index):
597         found = False
598         index = base_index
599         infos = self.GetEntryInfos(base_index)
600         while index < base_index + infos["incr"]*infos["nbmax"] and not found:
601             if not self.CurrentNode.IsEntry(index):
602                 found = True
603             else:
604                 index += infos["incr"]
605         if found:
606             return index
607         return None
608     
609     """
610     Add entries specified in addinglist and remove entries specified in removinglist
611     """
612     def ManageEntriesOfCurrent(self, addinglist, removinglist):
613         # Add all the entries in addinglist
614         for index in addinglist:
615             infos = self.GetEntryInfos(index)
616             if infos["struct"] & OD_MultipleSubindexes:
617                 # First case entry is a record
618                 if infos["struct"] & OD_IdenticalSubindexes:
619                     subentry_infos = self.GetSubentryInfos(index, 1)
620                     if "default" in subentry_infos:
621                         default = subentry_infos["default"]
622                     else:
623                         default = self.GetTypeDefaultValue(subentry_infos["type"])
624                     self.CurrentNode.AddEntry(index, 1, default)
625                 # Second case entry is a record
626                 else:
627                     i = 1
628                     subentry_infos = self.GetSubentryInfos(index, i)
629                     while subentry_infos:
630                         if "default" in subentry_infos:
631                             default = subentry_infos["default"]
632                         else:
633                             default = self.GetTypeDefaultValue(subentry_infos["type"])
634                         self.CurrentNode.AddEntry(index, i, default)
635                         i += 1
636                         subentry_infos = self.GetSubentryInfos(index, i)
637             # Third case entry is a record
638             else:
639                 subentry_infos = self.GetSubentryInfos(index, 0)
640                 if "default" in subentry_infos:
641                     default = subentry_infos["default"]
642                 else:
643                     default = self.GetTypeDefaultValue(subentry_infos["type"])
644                 self.CurrentNode.AddEntry(index, 0, default)
645         # Remove all the entries in removinglist
646         for index in removinglist:
647             self.RemoveCurrentVariable(index)
648         self.BufferCurrentNode()
649
650     """
651     Remove an entry from current node. Analize the index to perform the correct
652     method
653     """
654     def RemoveCurrentVariable(self, index, subIndex = None):
655         Mappings = self.CurrentNode.GetMappings()
656         if index < 0x1000 and subIndex == None:
657             type = self.CurrentNode.GetEntry(index, 1)
658             for i in Mappings[-1]:
659                 for value in Mappings[-1][i]["values"]:
660                     if value["type"] == index:
661                         value["type"] = type
662             self.CurrentNode.RemoveMappingEntry(index)
663             self.CurrentNode.RemoveEntry(index)
664         elif index == 0x1200 and subIndex == None:
665             self.CurrentNode.RemoveEntry(0x1200)
666         elif 0x1201 <= index <= 0x127F and subIndex == None:
667             self.CurrentNode.RemoveLine(index, 0x127F)
668         elif 0x1280 <= index <= 0x12FF and subIndex == None:
669             self.CurrentNode.RemoveLine(index, 0x12FF)
670         elif 0x1400 <= index <= 0x15FF or 0x1600 <= index <= 0x17FF and subIndex == None:
671             if 0x1600 <= index <= 0x17FF and subIndex == None:
672                 index -= 0x200
673             self.CurrentNode.RemoveLine(index, 0x15FF)
674             self.CurrentNode.RemoveLine(index + 0x200, 0x17FF)
675         elif 0x1800 <= index <= 0x19FF or 0x1A00 <= index <= 0x1BFF and subIndex == None:
676             if 0x1A00 <= index <= 0x1BFF:
677                 index -= 0x200
678             self.CurrentNode.RemoveLine(index, 0x19FF)
679             self.CurrentNode.RemoveLine(index + 0x200, 0x1BFF)
680         else:
681             found = False
682             for menu,list in self.CurrentNode.GetSpecificMenu():
683                 for i in list:
684                     iinfos = self.GetEntryInfos(i)
685                     indexes = [i + incr * iinfos["incr"] for incr in xrange(iinfos["nbmax"])] 
686                     if index in indexes:
687                         found = True
688                         diff = index - i
689                         for j in list:
690                             jinfos = self.GetEntryInfos(j)
691                             self.CurrentNode.RemoveLine(j + diff, j + jinfos["incr"]*jinfos["nbmax"], jinfos["incr"])
692             self.CurrentNode.RemoveMapVariable(index, subIndex)
693             if not found:
694                 infos = self.GetEntryInfos(index)
695                 if not infos["need"]:
696                     self.CurrentNode.RemoveEntry(index, subIndex)
697             if index in Mappings[-1]:
698                 self.CurrentNode.RemoveMappingEntry(index, subIndex)
699             self.GenerateMapList()
700
701     def AddMapVariableToCurrent(self, index, name, struct, number):
702         if 0x2000 <= index <= 0x5FFF:
703             if not self.CurrentNode.IsEntry(index):
704                 self.CurrentNode.AddMappingEntry(index, name = name, struct = struct)
705                 if struct == var:
706                     values = {"name" : name, "type" : 5, "access" : "rw", "pdo" : True}
707                     self.CurrentNode.AddMappingEntry(index, 0, values = values)
708                     self.CurrentNode.AddEntry(index, 0, 0)
709                 else:
710                     values = {"name" : "Number of Entries", "type" : 2, "access" : "ro", "pdo" : False}
711                     self.CurrentNode.AddMappingEntry(index, 0, values = values)
712                     if struct == rec:
713                         values = {"name" : name + " %d[(sub)]", "type" : 5, "access" : "rw", "pdo" : True, "nbmax" : 0xFE}
714                         self.CurrentNode.AddMappingEntry(index, 1, values = values)
715                         for i in xrange(number):
716                             self.CurrentNode.AddEntry(index, i + 1, 0)
717                     else:
718                         for i in xrange(number):
719                             values = {"name" : "Undefined", "type" : 5, "access" : "rw", "pdo" : True}
720                             self.CurrentNode.AddMappingEntry(index, i + 1, values = values)
721                             self.CurrentNode.AddEntry(index, i + 1, 0)
722                 self.GenerateMapList()
723                 self.BufferCurrentNode()
724                 return None
725             else:
726                 return "Index 0x%04X already defined!"%index
727         else:
728             return "Index 0x%04X isn't a valid index for Map Variable!"%index
729
730     def AddUserTypeToCurrent(self, type, min, max, length):
731         index = 0xA0
732         while index < 0x100 and self.CurrentNode.IsEntry(index):
733             index += 1
734         if index < 0x100:
735             customisabletypes = self.GetCustomisableTypes()
736             name, valuetype = customisabletypes[type]
737             size = self.GetEntryInfos(type)["size"]
738             default = self.GetTypeDefaultValue(type)
739             if valuetype == 0:
740                 self.CurrentNode.AddMappingEntry(index, name = "%s[%d-%d]"%(name, min, max), struct = 3, size = size, default = default)
741                 self.CurrentNode.AddMappingEntry(index, 0, values = {"name" : "Number of Entries", "type" : 0x02, "access" : "ro", "pdo" : False})
742                 self.CurrentNode.AddMappingEntry(index, 1, values = {"name" : "Type", "type" : 0x02, "access" : "ro", "pdo" : False})
743                 self.CurrentNode.AddMappingEntry(index, 2, values = {"name" : "Minimum Value", "type" : type, "access" : "ro", "pdo" : False})
744                 self.CurrentNode.AddMappingEntry(index, 3, values = {"name" : "Maximum Value", "type" : type, "access" : "ro", "pdo" : False})
745                 self.CurrentNode.AddEntry(index, 1, type)
746                 self.CurrentNode.AddEntry(index, 2, min)
747                 self.CurrentNode.AddEntry(index, 3, max)
748             elif valuetype == 1:
749                 self.CurrentNode.AddMappingEntry(index, name = "%s%d"%(name, length), struct = 3, size = length * size, default = default)
750                 self.CurrentNode.AddMappingEntry(index, 0, values = {"name" : "Number of Entries", "type" : 0x02, "access" : "ro", "pdo" : False})
751                 self.CurrentNode.AddMappingEntry(index, 1, values = {"name" : "Type", "type" : 0x02, "access" : "ro", "pdo" : False})
752                 self.CurrentNode.AddMappingEntry(index, 2, values = {"name" : "Length", "type" : 0x02, "access" : "ro", "pdo" : False})
753                 self.CurrentNode.AddEntry(index, 1, type)
754                 self.CurrentNode.AddEntry(index, 2, length)
755             self.GenerateTypeList()
756             self.BufferCurrentNode()
757             return None
758         else:
759             return "Too many User Types have already been defined!"
760
761 #-------------------------------------------------------------------------------
762 #                      Modify Entry and Mapping Functions
763 #-------------------------------------------------------------------------------
764
765     def SetCurrentEntryCallbacks(self, index, value):
766         if self.CurrentNode and self.CurrentNode.IsEntry(index):
767             entry_infos = self.GetEntryInfos(index)
768             if "callback" not in entry_infos:
769                 self.CurrentNode.SetParamsEntry(index, None, callback = value)
770                 self.BufferCurrentNode()
771
772     def SetCurrentEntry(self, index, subIndex, value, name, editor):
773         if self.CurrentNode and self.CurrentNode.IsEntry(index):
774             if name == "value":
775                 if editor == "map":
776                     value = eval("0x%s"%self.NameTranslation[value])
777                     self.CurrentNode.SetEntry(index, subIndex, value)
778                 elif editor == "bool":
779                     value = value == "True"
780                     self.CurrentNode.SetEntry(index, subIndex, value)
781                 else:
782                     subentry_infos = self.GetSubentryInfos(index, subIndex)
783                     type = subentry_infos["type"]
784                     dic = {}
785                     for typeindex, typevalue in CustomisableTypes:
786                         dic[typeindex] = typevalue
787                     if type not in dic:
788                         type = self.CurrentNode.GetEntry(type)[1]
789                     if dic[type] == 0:
790                         try:
791                             value = eval(value, {})
792                             self.CurrentNode.SetEntry(index, subIndex, value)
793                         except:
794                             pass
795                     else:
796                         self.CurrentNode.SetEntry(index, subIndex, value)
797             elif name in ["comment", "save"]:
798                 if editor == "option":
799                     value = value == "Yes"
800                 if name == "save":
801                     self.CurrentNode.SetParamsEntry(index, subIndex, save = value)
802                 elif name == "comment":
803                     self.CurrentNode.SetParamsEntry(index, subIndex, comment = value)
804             else:
805                 if editor == "type":
806                     value = self.TypeTranslation[value]
807                     size = self.GetEntryInfos(value)["size"]
808                     self.CurrentNode.UpdateMapVariable(index, subIndex, size)
809                 elif editor == "access":
810                     dic = {}
811                     for abbrev,access in AccessType.iteritems():
812                         dic[access] = abbrev
813                     value = dic[value]
814                 self.CurrentNode.SetMappingEntry(index, subIndex, values = {name : value})
815                 if name == "name" or editor == "type":
816                     self.GenerateMapList()
817             self.BufferCurrentNode()
818
819     def SetCurrentEntryName(self, index, name):
820         self.CurrentNode.SetMappingEntry(index, name=name)
821         self.BufferCurrentNode()
822
823     def SetCurrentUserType(self, index, type, min, max, length):
824         customisabletypes = self.GetCustomisableTypes()
825         values, valuetype = self.GetCustomisedTypeValues(index)
826         name, new_valuetype = customisabletypes[type]
827         size = self.GetEntryInfos(type)["size"]
828         default = self.GetTypeDefaultValue(type)
829         if new_valuetype == 0:
830             self.CurrentNode.SetMappingEntry(index, name = "%s[%d-%d]"%(name, min, max), struct = 3, size = size, default = default) 
831             if valuetype == 1:
832                 self.CurrentNode.SetMappingEntry(index, 2, values = {"name" : "Minimum Value", "type" : type, "access" : "ro", "pdo" : False})
833                 self.CurrentNode.AddMappingEntry(index, 3, values = {"name" : "Maximum Value", "type" : type, "access" : "ro", "pdo" : False})
834             self.CurrentNode.SetEntry(index, 1, type)
835             self.CurrentNode.SetEntry(index, 2, min)
836             if valuetype == 1:
837                 self.CurrentNode.AddEntry(index, 3, max)
838             else:
839                 self.CurrentNode.SetEntry(index, 3, max)
840         elif new_valuetype == 1:
841             self.CurrentNode.SetMappingEntry(index, name = "%s%d"%(name, length), struct = 3, size = size, default = default)
842             if valuetype == 0:
843                 self.CurrentNode.SetMappingEntry(index, 2, values = {"name" : "Length", "type" : 0x02, "access" : "ro", "pdo" : False})
844                 self.CurrentNode.RemoveMappingEntry(index, 3)
845             self.CurrentNode.SetEntry(index, 1, type)
846             self.CurrentNode.SetEntry(index, 2, length)
847             if valuetype == 0:
848                 self.CurrentNode.RemoveEntry(index, 3)
849         self.BufferCurrentNode()
850
851 #-------------------------------------------------------------------------------
852 #                      Current Buffering Management Functions
853 #-------------------------------------------------------------------------------
854
855     def BufferCurrentNode(self):
856         self.UndoBuffers[self.NodeIndex].Buffering(self.CurrentNode.Copy())
857
858     def CurrentIsSaved(self):
859         return self.UndoBuffers[self.NodeIndex].IsCurrentSaved()
860
861     def OneFileHasChanged(self):
862         result = False
863         for buffer in self.UndoBuffers:
864             result |= not buffer.IsCurrentSaved()
865         return result
866
867     def GetBufferNumber(self):
868         return len(self.UndoBuffers)
869
870     def LoadCurrentPrevious(self):
871         self.CurrentNode = self.UndoBuffers[self.NodeIndex].Previous().Copy()
872     
873     def LoadCurrentNext(self):
874         self.CurrentNode = self.UndoBuffers[self.NodeIndex].Next().Copy()
875
876     def AddNodeBuffer(self, currentstate = None, issaved = False):
877         self.NodeIndex = len(self.UndoBuffers)
878         self.UndoBuffers.append(UndoBuffer(currentstate, issaved))
879         self.FilePaths.append("")
880         self.FileNames.append("")
881
882     def ChangeCurrentNode(self, index):
883         if index < len(self.UndoBuffers):
884             self.NodeIndex = index
885             self.CurrentNode = self.UndoBuffers[self.NodeIndex].Current().Copy()
886             self.GenerateTypeList()
887             self.GenerateMapList()
888     
889     def RemoveNodeBuffer(self, index):
890         self.UndoBuffers.pop(index)
891         self.FilePaths.pop(index)
892         self.FileNames.pop(index)
893         self.NodeIndex = min(self.NodeIndex, len(self.UndoBuffers) - 1)
894         if len(self.UndoBuffers) > 0:
895             self.CurrentNode = self.UndoBuffers[self.NodeIndex].Current().Copy()
896             self.GenerateTypeList()
897             self.GenerateMapList()
898         else:
899             self.CurrentNode = None
900     
901     def GetCurrentNodeIndex(self):
902         return self.NodeIndex
903     
904     def GetCurrentFilename(self):
905         return self.GetFilename(self.NodeIndex)
906     
907     def GetAllFilenames(self):
908         filenames = []
909         for i in xrange(len(self.UndoBuffers)):
910             filenames.append(self.GetFilename(i))
911         return filenames
912     
913     def GetFilename(self, index):
914         if self.UndoBuffers[index].IsCurrentSaved():
915             return self.FileNames[index]
916         else:
917             return "~%s~"%self.FileNames[index]
918     
919     def SetCurrentFilePath(self, filepath):
920         self.FilePaths[self.NodeIndex] = filepath
921         if filepath == "":
922             self.LastNewIndex += 1
923             self.FileNames[self.NodeIndex] = "Unnamed%d"%self.LastNewIndex
924         else:
925             self.FileNames[self.NodeIndex] = os.path.splitext(os.path.basename(filepath))[0]
926                 
927     def GetCurrentFilePath(self):
928         if len(self.FilePaths) > 0:
929             return self.FilePaths[self.NodeIndex]
930         else:
931             return ""
932     
933     def GetCurrentBufferState(self):
934         first = self.UndoBuffers[self.NodeIndex].IsFirst()
935         last = self.UndoBuffers[self.NodeIndex].IsLast()
936         return not first, not last
937
938 #-------------------------------------------------------------------------------
939 #                         Profiles Management Functions
940 #-------------------------------------------------------------------------------
941
942     def GetCurrentCommunicationLists(self):
943         list = []
944         for index in MappingDictionary.iterkeys():
945             if 0x1000 <= index < 0x1200:
946                 list.append(index)
947         return self.GetProfileLists(MappingDictionary, list)
948     
949     def GetCurrentDS302Lists(self):
950         return self.GetSpecificProfileLists(self.CurrentNode.GetDS302Profile())
951     
952     def GetCurrentProfileLists(self):
953         return self.GetSpecificProfileLists(self.CurrentNode.GetProfile())
954     
955     def GetSpecificProfileLists(self, mappingdictionary):
956         validlist = []
957         exclusionlist = []
958         for name, list in self.CurrentNode.GetSpecificMenu():
959             exclusionlist.extend(list)
960         for index in mappingdictionary.iterkeys():
961             if index not in exclusionlist:
962                 validlist.append(index)
963         return self.GetProfileLists(mappingdictionary, validlist)
964     
965     def GetProfileLists(self, mappingdictionary, list):
966         dictionary = {}
967         current = []
968         for index in list:
969             dictionary[index] = (mappingdictionary[index]["name"], mappingdictionary[index]["need"])
970             if self.CurrentNode.IsEntry(index):
971                 current.append(index)
972         return dictionary, current
973
974     def GetCurrentNextMapIndex(self):
975         if self.CurrentNode:
976             index = 0x2000
977             while self.CurrentNode.IsEntry(index) and index < 0x5FFF:
978                 index += 1
979             if index < 0x6000:
980                 return index
981             else:
982                 return None
983
984     def CurrentDS302Defined(self):
985         if self.CurrentNode:
986             return len(self.CurrentNode.GetDS302Profile()) > 0
987         return False
988
989 #-------------------------------------------------------------------------------
990 #                         Node State and Values Functions
991 #-------------------------------------------------------------------------------
992
993     def GetCurrentNodeInfos(self):
994         name = self.CurrentNode.GetNodeName()
995         id = self.CurrentNode.GetNodeID()
996         type = self.CurrentNode.GetNodeType()
997         return name, id, type
998         
999     def SetCurrentNodeInfos(self, name, id, type):
1000         self.CurrentNode.SetNodeName(name)
1001         self.CurrentNode.SetNodeID(id)
1002         self.CurrentNode.SetNodeType(type)
1003         self.BufferCurrentNode()
1004
1005     def GetCurrentProfileName(self):
1006         if self.CurrentNode:
1007             return self.CurrentNode.GetProfileName()
1008         return ""
1009
1010     def IsCurrentEntry(self, index):
1011         if self.CurrentNode:
1012             return self.CurrentNode.IsEntry(index)
1013         return False
1014     
1015     def GetCurrentEntry(self, index, subIndex = None):
1016         if self.CurrentNode:
1017             return self.CurrentNode.GetEntry(index, subIndex)
1018         return None
1019     
1020     def GetCurrentParamsEntry(self, index, subIndex = None):
1021         if self.CurrentNode:
1022             return self.CurrentNode.GetParamsEntry(index, subIndex)
1023         return None
1024     
1025     def GetCurrentValidIndexes(self, min, max):
1026         validindexes = []
1027         for index in self.CurrentNode.GetIndexes():
1028             if min <= index <= max:
1029                 validindexes.append((self.GetEntryName(index), index))
1030         return validindexes
1031         
1032     def GetCurrentValidChoices(self, min, max):
1033         validchoices = []
1034         exclusionlist = []
1035         for menu, indexes in self.CurrentNode.GetSpecificMenu():
1036             exclusionlist.extend(indexes)
1037             good = True
1038             for index in indexes:
1039                 good &= min <= index <= max
1040             if good:
1041                 validchoices.append((menu, None))
1042         list = [index for index in MappingDictionary.keys() if index >= 0x1000]
1043         profiles = self.CurrentNode.GetMappings(False)
1044         for profile in profiles:
1045             list.extend(profile.keys())
1046         list.sort()
1047         for index in list:
1048             if min <= index <= max and not self.CurrentNode.IsEntry(index) and index not in exclusionlist:
1049                 validchoices.append((self.GetEntryName(index), index))
1050         return validchoices
1051     
1052     def HasCurrentEntryCallbacks(self, index):
1053         if self.CurrentNode and self.CurrentNode.IsEntry(index):
1054             entry_infos = self.GetEntryInfos(index)
1055             if "callback" in entry_infos:
1056                 return entry_infos["callback"]
1057             return self.CurrentNode.HasEntryCallbacks(index)
1058         return False
1059     
1060     def GetCurrentEntryValues(self, index):
1061         if self.CurrentNode and self.CurrentNode.IsEntry(index):
1062             entry_infos = self.GetEntryInfos(index)
1063             data = []
1064             editors = []
1065             values = self.CurrentNode.GetEntry(index)
1066             params = self.CurrentNode.GetParamsEntry(index)
1067             if type(values) == ListType:
1068                 for i, value in enumerate(values):
1069                     data.append({"value" : value})
1070                     data[-1].update(params[i])
1071             else:
1072                 data.append({"value" : values})
1073                 data[-1].update(params)
1074             for i, dic in enumerate(data):
1075                 infos = self.GetSubentryInfos(index, i)
1076                 dic["subindex"] = "0x%02X"%i
1077                 dic["name"] = infos["name"]
1078                 dic["type"] = self.GetTypeName(infos["type"])
1079                 dic["access"] = AccessType[infos["access"]]
1080                 dic["save"] = OptionType[dic["save"]]
1081                 editor = {"subindex" : None, "save" : "option", "callback" : "option", "comment" : "string"}
1082                 if type(values) == ListType and i == 0:
1083                     editor["name"] = None
1084                     editor["type"] = None
1085                     editor["access"] = None
1086                     editor["value"] = None
1087                 else:
1088                     if infos["user_defined"]:
1089                         if entry_infos["struct"] & OD_IdenticalSubindexes:
1090                             editor["name"] = None
1091                             if i > 1:
1092                                 editor["type"] = None
1093                                 editor["access"] = None
1094                             else:
1095                                 editor["type"] = "type"
1096                                 editor["access"] = "access"
1097                         else:
1098                             if entry_infos["struct"] & OD_MultipleSubindexes:
1099                                 editor["name"] = "string"
1100                             else:
1101                                 editor["name"] = None
1102                             editor["type"] = "type"
1103                             editor["access"] = "access"
1104                     else:
1105                         editor["name"] = None
1106                         editor["type"] = None
1107                         editor["access"] = None
1108                     if index < 0x260:
1109                         editor["value"] = None
1110                         if i == 1:
1111                             dic["value"] = self.GetTypeName(dic["value"])
1112                     elif 0x1600 <= index <= 0x17FF or 0x1A00 <= index <= 0x1C00:
1113                         editor["value"] = "map"
1114                         dic["value"] = self.MapTranslation["%08X"%dic["value"]]
1115                     else:
1116                         if dic["type"].startswith("VISIBLE_STRING"):
1117                             editor["value"] = "string"
1118                         elif dic["type"] == "BOOLEAN":
1119                             editor["value"] = "bool"
1120                             dic["value"] = BoolType[dic["value"]]
1121                         result = type_model.match(dic["type"])
1122                         if result:
1123                             values = result.groups()
1124                             if values[0] in ["INTEGER", "UNSIGNED"]:
1125                                 format = "0x%0" + str(int(values[1])/4) + "X"
1126                                 dic["value"] = format%dic["value"]
1127                                 editor["value"] = "string"
1128                             elif values[0] == "REAL":
1129                                 editor["value"] = "float"
1130                             elif values[0] == "VISIBLE_STRING":
1131                                 editor["length"] = values[0]
1132                         result = range_model.match(dic["type"])
1133                         if result:
1134                             values = result.groups()
1135                             if values[0] in ("UNSIGNED", "REAL"):
1136                                 editor["min"] = values[2]
1137                                 editor["max"] = values[3]
1138                 editors.append(editor)
1139             return data, editors
1140         else:
1141             return None
1142     
1143 #-------------------------------------------------------------------------------
1144 #                         Node Informations Functions
1145 #-------------------------------------------------------------------------------
1146
1147     def GetCustomisedTypeValues(self, index):
1148         values = self.CurrentNode.GetEntry(index)
1149         customisabletypes = self.GetCustomisableTypes()
1150         return values, customisabletypes[values[1]][1]
1151
1152     def GetEntryName(self, index, node = True):
1153         result = FindEntryName(index, MappingDictionary)
1154         if result == None and node:
1155             NodeMappings = self.CurrentNode.GetMappings()
1156             i = 0
1157             while not result and i < len(NodeMappings):
1158                 result = FindEntryName(index, NodeMappings[i])
1159                 i += 1
1160         return result
1161     
1162     def GetEntryInfos(self, index, node = True):
1163         result = FindEntryInfos(index, MappingDictionary)
1164         if result == None and node:
1165             NodeMappings = self.CurrentNode.GetMappings()
1166             i = 0
1167             while not result and i < len(NodeMappings):
1168                 result = FindEntryInfos(index, NodeMappings[i])
1169                 i += 1
1170         return result
1171     
1172     def GetSubentryInfos(self, index, subIndex, node = True):
1173         result = FindSubentryInfos(index, subIndex, MappingDictionary)
1174         if result == None and node:
1175             NodeMappings = self.CurrentNode.GetMappings()
1176             i = 0
1177             while not result and i < len(NodeMappings):
1178                 result = FindSubentryInfos(index, subIndex, NodeMappings[i])
1179                 if result:
1180                     result["user_defined"] = i == len(NodeMappings) - 1 and index >= 0x1000
1181                 i += 1
1182         else :
1183             result["user_defined"] = False
1184         return result
1185     
1186     def GetTypeIndex(self, typename, node = True):
1187         result = FindTypeIndex(typename, MappingDictionary)
1188         if result == None and node:
1189             NodeMappings = self.CurrentNode.GetMappings()
1190             i = 0
1191             while not result and i < len(NodeMappings):
1192                 result = FindTypeIndex(typename, NodeMappings[i])
1193                 i += 1
1194         return result
1195     
1196     def GetTypeName(self, typeindex, node = True):
1197         result = FindTypeName(typeindex, MappingDictionary)
1198         if result == None and node:
1199             NodeMappings = self.CurrentNode.GetMappings()
1200             i = 0
1201             while not result and i < len(NodeMappings):
1202                 result = FindTypeName(typeindex, NodeMappings[i])
1203                 i += 1
1204         return result
1205     
1206     def GetTypeDefaultValue(self, typeindex, node = True):
1207         result = FindTypeDefaultValue(typeindex, MappingDictionary)
1208         if result == None and node:
1209             NodeMappings = self.CurrentNode.GetMappings()
1210             i = 0
1211             while not result and i < len(NodeMappings):
1212                 result = FindTypeDefaultValue(typeindex, NodeMappings[i])
1213                 i += 1
1214         return result
1215     
1216     def GetTypeList(self, node = True):
1217         list = FindTypeList(MappingDictionary)
1218         if node:
1219             for NodeMapping in self.CurrentNode.GetMappings():
1220                 list.extend(FindTypeList(NodeMapping))
1221         list.sort()
1222         return list
1223     
1224     def GetMapVariableList(self):
1225         list = FindMapVariableList(MappingDictionary, self)
1226         for NodeMapping in self.CurrentNode.GetMappings():
1227             list.extend(FindMapVariableList(NodeMapping, self))
1228         list.sort()
1229         return list
1230     
1231     def GetMandatoryIndexes(self, node = True):
1232         list = FindMandatoryIndexes(MappingDictionary)
1233         if node:
1234             for NodeMapping in self.CurrentNode.GetMappings():
1235                 list.extend(FindMandatoryIndexes(NodeMapping))
1236         return list
1237     
1238     def GetCustomisableTypes(self):
1239         dic = {}
1240         for index, valuetype in CustomisableTypes:
1241             name = self.GetTypeName(index)
1242             dic[index] = [name, valuetype]
1243         return dic
1244     
1245     def GetCurrentSpecificMenu(self):
1246         if self.CurrentNode:
1247             return self.CurrentNode.GetSpecificMenu()
1248         return []
1249
1250