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