]> rtime.felk.cvut.cz Git - CanFestival-3.git/blob - objdictgen/nodemanager.py
Adding the possibility for users to choose between Dynamic Mapping and Static Mapping
[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                 elif editor == "time":
782                     self.CurrentNode.SetEntry(index, subIndex, value)
783                 else:
784                     subentry_infos = self.GetSubentryInfos(index, subIndex)
785                     type = subentry_infos["type"]
786                     dic = {}
787                     for typeindex, typevalue in CustomisableTypes:
788                         dic[typeindex] = typevalue
789                     if type not in dic:
790                         type = self.CurrentNode.GetEntry(type)[1]
791                     if dic[type] == 0:
792                         try:
793                             value = eval(value, {})
794                             self.CurrentNode.SetEntry(index, subIndex, value)
795                         except:
796                             pass
797                     else:
798                         self.CurrentNode.SetEntry(index, subIndex, value)
799             elif name in ["comment", "save"]:
800                 if editor == "option":
801                     value = value == "Yes"
802                 if name == "save":
803                     self.CurrentNode.SetParamsEntry(index, subIndex, save = value)
804                 elif name == "comment":
805                     self.CurrentNode.SetParamsEntry(index, subIndex, comment = value)
806             else:
807                 if editor == "type":
808                     value = self.TypeTranslation[value]
809                     size = self.GetEntryInfos(value)["size"]
810                     self.CurrentNode.UpdateMapVariable(index, subIndex, size)
811                 elif editor in ["access","raccess"]:
812                     dic = {}
813                     for abbrev,access in AccessType.iteritems():
814                         dic[access] = abbrev
815                     value = dic[value]
816                     if editor == "raccess" and not self.CurrentNode.IsMappingEntry(index):
817                         entry_infos = self.GetEntryInfos(index)
818                         self.CurrentNode.AddMappingEntry(index, name = entry_infos["name"], struct = 7)
819                         self.CurrentNode.AddMappingEntry(index, 0, values = self.GetSubentryInfos(index, 0, False).copy())
820                         self.CurrentNode.AddMappingEntry(index, 1, values = self.GetSubentryInfos(index, 1, False).copy())
821                 self.CurrentNode.SetMappingEntry(index, subIndex, values = {name : value})
822                 if name == "name" or editor == "type":
823                     self.GenerateMapList()
824             self.BufferCurrentNode()
825
826     def SetCurrentEntryName(self, index, name):
827         self.CurrentNode.SetMappingEntry(index, name=name)
828         self.BufferCurrentNode()
829
830     def SetCurrentUserType(self, index, type, min, max, length):
831         customisabletypes = self.GetCustomisableTypes()
832         values, valuetype = self.GetCustomisedTypeValues(index)
833         name, new_valuetype = customisabletypes[type]
834         size = self.GetEntryInfos(type)["size"]
835         default = self.GetTypeDefaultValue(type)
836         if new_valuetype == 0:
837             self.CurrentNode.SetMappingEntry(index, name = "%s[%d-%d]"%(name, min, max), struct = 3, size = size, default = default) 
838             if valuetype == 1:
839                 self.CurrentNode.SetMappingEntry(index, 2, values = {"name" : "Minimum Value", "type" : type, "access" : "ro", "pdo" : False})
840                 self.CurrentNode.AddMappingEntry(index, 3, values = {"name" : "Maximum Value", "type" : type, "access" : "ro", "pdo" : False})
841             self.CurrentNode.SetEntry(index, 1, type)
842             self.CurrentNode.SetEntry(index, 2, min)
843             if valuetype == 1:
844                 self.CurrentNode.AddEntry(index, 3, max)
845             else:
846                 self.CurrentNode.SetEntry(index, 3, max)
847         elif new_valuetype == 1:
848             self.CurrentNode.SetMappingEntry(index, name = "%s%d"%(name, length), struct = 3, size = size, default = default)
849             if valuetype == 0:
850                 self.CurrentNode.SetMappingEntry(index, 2, values = {"name" : "Length", "type" : 0x02, "access" : "ro", "pdo" : False})
851                 self.CurrentNode.RemoveMappingEntry(index, 3)
852             self.CurrentNode.SetEntry(index, 1, type)
853             self.CurrentNode.SetEntry(index, 2, length)
854             if valuetype == 0:
855                 self.CurrentNode.RemoveEntry(index, 3)
856         self.BufferCurrentNode()
857
858 #-------------------------------------------------------------------------------
859 #                      Current Buffering Management Functions
860 #-------------------------------------------------------------------------------
861
862     def BufferCurrentNode(self):
863         self.UndoBuffers[self.NodeIndex].Buffering(self.CurrentNode.Copy())
864
865     def CurrentIsSaved(self):
866         return self.UndoBuffers[self.NodeIndex].IsCurrentSaved()
867
868     def OneFileHasChanged(self):
869         result = False
870         for buffer in self.UndoBuffers:
871             result |= not buffer.IsCurrentSaved()
872         return result
873
874     def GetBufferNumber(self):
875         return len(self.UndoBuffers)
876
877     def LoadCurrentPrevious(self):
878         self.CurrentNode = self.UndoBuffers[self.NodeIndex].Previous().Copy()
879     
880     def LoadCurrentNext(self):
881         self.CurrentNode = self.UndoBuffers[self.NodeIndex].Next().Copy()
882
883     def AddNodeBuffer(self, currentstate = None, issaved = False):
884         self.NodeIndex = len(self.UndoBuffers)
885         self.UndoBuffers.append(UndoBuffer(currentstate, issaved))
886         self.FilePaths.append("")
887         self.FileNames.append("")
888
889     def ChangeCurrentNode(self, index):
890         if index < len(self.UndoBuffers):
891             self.NodeIndex = index
892             self.CurrentNode = self.UndoBuffers[self.NodeIndex].Current().Copy()
893             self.GenerateTypeList()
894             self.GenerateMapList()
895     
896     def RemoveNodeBuffer(self, index):
897         self.UndoBuffers.pop(index)
898         self.FilePaths.pop(index)
899         self.FileNames.pop(index)
900         self.NodeIndex = min(self.NodeIndex, len(self.UndoBuffers) - 1)
901         if len(self.UndoBuffers) > 0:
902             self.CurrentNode = self.UndoBuffers[self.NodeIndex].Current().Copy()
903             self.GenerateTypeList()
904             self.GenerateMapList()
905         else:
906             self.CurrentNode = None
907     
908     def GetCurrentNodeIndex(self):
909         return self.NodeIndex
910     
911     def GetCurrentFilename(self):
912         return self.GetFilename(self.NodeIndex)
913     
914     def GetAllFilenames(self):
915         filenames = []
916         for i in xrange(len(self.UndoBuffers)):
917             filenames.append(self.GetFilename(i))
918         return filenames
919     
920     def GetFilename(self, index):
921         if self.UndoBuffers[index].IsCurrentSaved():
922             return self.FileNames[index]
923         else:
924             return "~%s~"%self.FileNames[index]
925     
926     def SetCurrentFilePath(self, filepath):
927         self.FilePaths[self.NodeIndex] = filepath
928         if filepath == "":
929             self.LastNewIndex += 1
930             self.FileNames[self.NodeIndex] = "Unnamed%d"%self.LastNewIndex
931         else:
932             self.FileNames[self.NodeIndex] = os.path.splitext(os.path.basename(filepath))[0]
933                 
934     def GetCurrentFilePath(self):
935         if len(self.FilePaths) > 0:
936             return self.FilePaths[self.NodeIndex]
937         else:
938             return ""
939     
940     def GetCurrentBufferState(self):
941         first = self.UndoBuffers[self.NodeIndex].IsFirst()
942         last = self.UndoBuffers[self.NodeIndex].IsLast()
943         return not first, not last
944
945 #-------------------------------------------------------------------------------
946 #                         Profiles Management Functions
947 #-------------------------------------------------------------------------------
948
949     def GetCurrentCommunicationLists(self):
950         list = []
951         for index in MappingDictionary.iterkeys():
952             if 0x1000 <= index < 0x1200:
953                 list.append(index)
954         return self.GetProfileLists(MappingDictionary, list)
955     
956     def GetCurrentDS302Lists(self):
957         return self.GetSpecificProfileLists(self.CurrentNode.GetDS302Profile())
958     
959     def GetCurrentProfileLists(self):
960         return self.GetSpecificProfileLists(self.CurrentNode.GetProfile())
961     
962     def GetSpecificProfileLists(self, mappingdictionary):
963         validlist = []
964         exclusionlist = []
965         for name, list in self.CurrentNode.GetSpecificMenu():
966             exclusionlist.extend(list)
967         for index in mappingdictionary.iterkeys():
968             if index not in exclusionlist:
969                 validlist.append(index)
970         return self.GetProfileLists(mappingdictionary, validlist)
971     
972     def GetProfileLists(self, mappingdictionary, list):
973         dictionary = {}
974         current = []
975         for index in list:
976             dictionary[index] = (mappingdictionary[index]["name"], mappingdictionary[index]["need"])
977             if self.CurrentNode.IsEntry(index):
978                 current.append(index)
979         return dictionary, current
980
981     def GetCurrentNextMapIndex(self):
982         if self.CurrentNode:
983             index = 0x2000
984             while self.CurrentNode.IsEntry(index) and index < 0x5FFF:
985                 index += 1
986             if index < 0x6000:
987                 return index
988             else:
989                 return None
990
991     def CurrentDS302Defined(self):
992         if self.CurrentNode:
993             return len(self.CurrentNode.GetDS302Profile()) > 0
994         return False
995
996 #-------------------------------------------------------------------------------
997 #                         Node State and Values Functions
998 #-------------------------------------------------------------------------------
999
1000     def GetCurrentNodeInfos(self):
1001         name = self.CurrentNode.GetNodeName()
1002         id = self.CurrentNode.GetNodeID()
1003         type = self.CurrentNode.GetNodeType()
1004         return name, id, type
1005         
1006     def SetCurrentNodeInfos(self, name, id, type):
1007         self.CurrentNode.SetNodeName(name)
1008         self.CurrentNode.SetNodeID(id)
1009         self.CurrentNode.SetNodeType(type)
1010         self.BufferCurrentNode()
1011
1012     def GetCurrentProfileName(self):
1013         if self.CurrentNode:
1014             return self.CurrentNode.GetProfileName()
1015         return ""
1016
1017     def IsCurrentEntry(self, index):
1018         if self.CurrentNode:
1019             return self.CurrentNode.IsEntry(index)
1020         return False
1021     
1022     def GetCurrentEntry(self, index, subIndex = None):
1023         if self.CurrentNode:
1024             return self.CurrentNode.GetEntry(index, subIndex)
1025         return None
1026     
1027     def GetCurrentParamsEntry(self, index, subIndex = None):
1028         if self.CurrentNode:
1029             return self.CurrentNode.GetParamsEntry(index, subIndex)
1030         return None
1031     
1032     def GetCurrentValidIndexes(self, min, max):
1033         validindexes = []
1034         for index in self.CurrentNode.GetIndexes():
1035             if min <= index <= max:
1036                 validindexes.append((self.GetEntryName(index), index))
1037         return validindexes
1038         
1039     def GetCurrentValidChoices(self, min, max):
1040         validchoices = []
1041         exclusionlist = []
1042         for menu, indexes in self.CurrentNode.GetSpecificMenu():
1043             exclusionlist.extend(indexes)
1044             good = True
1045             for index in indexes:
1046                 good &= min <= index <= max
1047             if good:
1048                 validchoices.append((menu, None))
1049         list = [index for index in MappingDictionary.keys() if index >= 0x1000]
1050         profiles = self.CurrentNode.GetMappings(False)
1051         for profile in profiles:
1052             list.extend(profile.keys())
1053         list.sort()
1054         for index in list:
1055             if min <= index <= max and not self.CurrentNode.IsEntry(index) and index not in exclusionlist:
1056                 validchoices.append((self.GetEntryName(index), index))
1057         return validchoices
1058     
1059     def HasCurrentEntryCallbacks(self, index):
1060         if self.CurrentNode and self.CurrentNode.IsEntry(index):
1061             entry_infos = self.GetEntryInfos(index)
1062             if "callback" in entry_infos:
1063                 return entry_infos["callback"]
1064             return self.CurrentNode.HasEntryCallbacks(index)
1065         return False
1066     
1067     def GetCurrentEntryValues(self, index):
1068         if self.CurrentNode and self.CurrentNode.IsEntry(index):
1069             entry_infos = self.GetEntryInfos(index)
1070             data = []
1071             editors = []
1072             values = self.CurrentNode.GetEntry(index)
1073             params = self.CurrentNode.GetParamsEntry(index)
1074             if type(values) == ListType:
1075                 for i, value in enumerate(values):
1076                     data.append({"value" : value})
1077                     data[-1].update(params[i])
1078             else:
1079                 data.append({"value" : values})
1080                 data[-1].update(params)
1081             for i, dic in enumerate(data):
1082                 infos = self.GetSubentryInfos(index, i)
1083                 dic["subindex"] = "0x%02X"%i
1084                 dic["name"] = infos["name"]
1085                 dic["type"] = self.GetTypeName(infos["type"])
1086                 dic["access"] = AccessType[infos["access"]]
1087                 dic["save"] = OptionType[dic["save"]]
1088                 editor = {"subindex" : None, "save" : "option", "callback" : "option", "comment" : "string"}
1089                 if type(values) == ListType and i == 0:
1090                     editor["name"] = None
1091                     editor["type"] = None
1092                     if 0x1600 <= index <= 0x17FF or 0x1A00 <= index <= 0x1C00:
1093                         editor["access"] = "raccess"
1094                     else:
1095                         editor["access"] = None
1096                     editor["value"] = None
1097                 else:
1098                     if infos["user_defined"]:
1099                         if entry_infos["struct"] & OD_IdenticalSubindexes:
1100                             editor["name"] = None
1101                             if i > 1:
1102                                 editor["type"] = None
1103                                 editor["access"] = None
1104                             else:
1105                                 editor["type"] = "type"
1106                                 editor["access"] = "access"
1107                         else:
1108                             if entry_infos["struct"] & OD_MultipleSubindexes:
1109                                 editor["name"] = "string"
1110                             else:
1111                                 editor["name"] = None
1112                             editor["type"] = "type"
1113                             editor["access"] = "access"
1114                     else:
1115                         editor["name"] = None
1116                         editor["type"] = None
1117                         editor["access"] = None
1118                     if index < 0x260:
1119                         editor["value"] = None
1120                         if i == 1:
1121                             dic["value"] = self.GetTypeName(dic["value"])
1122                     elif 0x1600 <= index <= 0x17FF or 0x1A00 <= index <= 0x1C00:
1123                         editor["value"] = "map"
1124                         dic["value"] = self.MapTranslation["%08X"%dic["value"]]
1125                     else:
1126                         if dic["type"].startswith("VISIBLE_STRING"):
1127                             editor["value"] = "string"
1128                         if dic["type"] in ["TIME_OF_DAY","TIME_DIFFERENCE"]:
1129                             editor["value"] = "time"
1130                         elif dic["type"] == "BOOLEAN":
1131                             editor["value"] = "bool"
1132                             dic["value"] = BoolType[dic["value"]]
1133                         result = type_model.match(dic["type"])
1134                         if result:
1135                             values = result.groups()
1136                             if values[0] in ["INTEGER", "UNSIGNED"]:
1137                                 format = "0x%0" + str(int(values[1])/4) + "X"
1138                                 dic["value"] = format%dic["value"]
1139                                 editor["value"] = "string"
1140                             elif values[0] == "REAL":
1141                                 editor["value"] = "float"
1142                             elif values[0] == "VISIBLE_STRING":
1143                                 editor["length"] = values[0]
1144                         result = range_model.match(dic["type"])
1145                         if result:
1146                             values = result.groups()
1147                             if values[0] in ("UNSIGNED", "REAL"):
1148                                 editor["min"] = values[2]
1149                                 editor["max"] = values[3]
1150                 editors.append(editor)
1151             return data, editors
1152         else:
1153             return None
1154     
1155 #-------------------------------------------------------------------------------
1156 #                         Node Informations Functions
1157 #-------------------------------------------------------------------------------
1158
1159     def GetCustomisedTypeValues(self, index):
1160         values = self.CurrentNode.GetEntry(index)
1161         customisabletypes = self.GetCustomisableTypes()
1162         return values, customisabletypes[values[1]][1]
1163
1164     def GetEntryName(self, index, node = True):
1165         result = None
1166         if node:
1167             NodeMappings = self.CurrentNode.GetMappings()
1168             i = 0
1169             while not result and i < len(NodeMappings):
1170                 result = FindEntryName(index, NodeMappings[i])
1171                 i += 1
1172         if result == None:
1173             result = FindEntryName(index, MappingDictionary)
1174         return result
1175     
1176     def GetEntryInfos(self, index, node = True):
1177         result = None
1178         if node:
1179             NodeMappings = self.CurrentNode.GetMappings()
1180             i = 0
1181             while not result and i < len(NodeMappings):
1182                 result = FindEntryInfos(index, NodeMappings[i])
1183                 i += 1
1184         if result == None:
1185             result = FindEntryInfos(index, MappingDictionary)
1186         return result
1187     
1188     def GetSubentryInfos(self, index, subIndex, node = True):
1189         result = None
1190         if node:
1191             NodeMappings = self.CurrentNode.GetMappings()
1192             i = 0
1193             while not result and i < len(NodeMappings):
1194                 result = FindSubentryInfos(index, subIndex, NodeMappings[i])
1195                 if result:
1196                     result["user_defined"] = i == len(NodeMappings) - 1 and index >= 0x1000
1197                 i += 1
1198         if result == None:    
1199             result = FindSubentryInfos(index, subIndex, MappingDictionary)
1200             if result:
1201                 result["user_defined"] = False
1202         return result
1203     
1204     def GetTypeIndex(self, typename, node = True):
1205         result = None
1206         if node:
1207             NodeMappings = self.CurrentNode.GetMappings()
1208             i = 0
1209             while not result and i < len(NodeMappings):
1210                 result = FindTypeIndex(typename, NodeMappings[i])
1211                 i += 1
1212         if result == None:
1213             result = FindTypeIndex(typename, MappingDictionary)
1214         return result
1215     
1216     def GetTypeName(self, typeindex, node = True):
1217         result = None
1218         if node:
1219             NodeMappings = self.CurrentNode.GetMappings()
1220             i = 0
1221             while not result and i < len(NodeMappings):
1222                 result = FindTypeName(typeindex, NodeMappings[i])
1223                 i += 1
1224         if result == None:
1225             result = FindTypeName(typeindex, MappingDictionary)
1226         return result
1227     
1228     def GetTypeDefaultValue(self, typeindex, node = True):
1229         result = None
1230         if node:
1231             NodeMappings = self.CurrentNode.GetMappings()
1232             i = 0
1233             while not result and i < len(NodeMappings):
1234                 result = FindTypeDefaultValue(typeindex, NodeMappings[i])
1235                 i += 1
1236         if result == None:
1237             result = FindTypeDefaultValue(typeindex, MappingDictionary)
1238         return result
1239     
1240     def GetTypeList(self, node = True):
1241         list = FindTypeList(MappingDictionary)
1242         if node:
1243             for NodeMapping in self.CurrentNode.GetMappings():
1244                 list.extend(FindTypeList(NodeMapping))
1245         list.sort()
1246         return list
1247     
1248     def GetMapVariableList(self):
1249         list = FindMapVariableList(MappingDictionary, self)
1250         for NodeMapping in self.CurrentNode.GetMappings():
1251             list.extend(FindMapVariableList(NodeMapping, self))
1252         list.sort()
1253         return list
1254     
1255     def GetMandatoryIndexes(self, node = True):
1256         list = FindMandatoryIndexes(MappingDictionary)
1257         if node:
1258             for NodeMapping in self.CurrentNode.GetMappings():
1259                 list.extend(FindMandatoryIndexes(NodeMapping))
1260         return list
1261     
1262     def GetCustomisableTypes(self):
1263         dic = {}
1264         for index, valuetype in CustomisableTypes:
1265             name = self.GetTypeName(index)
1266             dic[index] = [name, valuetype]
1267         return dic
1268     
1269     def GetCurrentSpecificMenu(self):
1270         if self.CurrentNode:
1271             return self.CurrentNode.GetSpecificMenu()
1272         return []
1273
1274