]> rtime.felk.cvut.cz Git - CanFestival-3.git/blob - objdictgen/nodemanager.py
Bug on NodeManager corrected :
[CanFestival-3.git] / objdictgen / nodemanager.py
1 #!/usr/bin/env python
2 # -*- coding: utf-8 -*-
3
4 #This file is part of CanFestival, a library implementing CanOpen Stack. 
5 #
6 #Copyright (C): Edouard TISSERANT, Francis DUPIN and Laurent BESSARD
7 #
8 #See COPYING file for copyrights details.
9 #
10 #This library is free software; you can redistribute it and/or
11 #modify it under the terms of the GNU Lesser General Public
12 #License as published by the Free Software Foundation; either
13 #version 2.1 of the License, or (at your option) any later version.
14 #
15 #This library is distributed in the hope that it will be useful,
16 #but WITHOUT ANY WARRANTY; without even the implied warranty of
17 #MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18 #Lesser General Public License for more details.
19 #
20 #You should have received a copy of the GNU Lesser General Public
21 #License along with this library; if not, write to the Free Software
22 #Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
23
24 from gnosis.xml.pickle import *
25 from gnosis.xml.pickle.util import setParanoia
26 setParanoia(0)
27
28 from node import *
29 import 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()
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             if len(self.UndoBuffers) == 0:
310                 index = self.AddNodeBuffer()
311                 self.SetCurrentFilePath("")
312             self.BufferCurrentNode()
313             return index
314         else:
315             return result
316     
317     """
318     Export to an eds file and store it in a new buffer if no node edited
319     """
320     def ExportCurrentToEDSFile(self, filepath):
321         return eds_utils.GenerateEDSFile(filepath, self)
322     
323     """
324     Build the C definition of Object Dictionary for current node 
325     """
326     def ExportCurrentToCFile(self, filepath):
327         return gen_cfile.GenerateFile(filepath, self)
328
329 #-------------------------------------------------------------------------------
330 #                        Add Entries to Current Functions
331 #-------------------------------------------------------------------------------
332
333     """
334     Add the specified number of subentry for the given entry. Verify that total
335     number of subentry (except 0) doesn't exceed nbmax defined
336     """
337     def AddSubentriesToCurrent(self, index, number):
338         # Informations about entry
339         length = self.CurrentNode.GetEntry(index, 0)
340         infos = self.GetEntryInfos(index)
341         subentry_infos = self.GetSubentryInfos(index, 1)
342         # Get default value for subindex
343         if "default" in subentry_infos:
344             default = subentry_infos["default"]
345         else:
346             default = self.GetTypeDefaultValue(subentry_infos["type"])   
347         # First case entry is record
348         if infos["struct"] & OD_IdenticalSubindexes:
349             for i in xrange(1, min(number,subentry_infos["nbmax"]-length) + 1):
350                 self.CurrentNode.AddEntry(index, length + i, default)
351             self.BufferCurrentNode()
352         # Second case entry is array, only possible for manufacturer specific
353         elif infos["struct"] & OD_MultipleSubindexes and 0x2000 <= index <= 0x5FFF:
354             values = {"name" : "Undefined", "type" : 5, "access" : "rw", "pdo" : True}
355             for i in xrange(1, min(number,0xFE-length) + 1):
356                 self.CurrentNode.AddMappingEntry(index, length + i, values = values.copy())
357                 self.CurrentNode.AddEntry(index, length + i, 0)
358             self.BufferCurrentNode()
359
360     """
361     Remove the specified number of subentry for the given entry. Verify that total
362     number of subentry (except 0) isn't less than 1
363     """
364     def RemoveSubentriesFromCurrent(self, index, number):
365         # Informations about entry
366         infos = self.GetEntryInfos(index)
367         length = self.CurrentNode.GetEntry(index, 0)
368         # Entry is a record, or is an array of manufacturer specific
369         if infos["struct"] & OD_IdenticalSubindexes or 0x2000 <= index <= 0x5FFF and infos["struct"] & OD_IdenticalSubindexes:
370             for i in xrange(min(number, length - 1)):
371                 self.RemoveCurrentVariable(index, length - i)
372             self.BufferCurrentNode()
373
374     """
375     Add a SDO Server to current node
376     """
377     def AddSDOServerToCurrent(self):
378         # An SDO Server is already defined at index 0x1200
379         if self.CurrentNode.IsEntry(0x1200):
380             indexlist = [self.GetLineFromIndex(0x1201)]
381             if None not in indexlist:
382                 self.ManageEntriesOfCurrent(indexlist, [])
383         # Add an SDO Server at index 0x1200
384         else:
385             self.ManageEntriesOfCurrent([0x1200], [])
386         
387     """
388     Add a SDO Server to current node
389     """
390     def AddSDOClientToCurrent(self):
391         indexlist = [self.GetLineFromIndex(0x1280)]
392         if None not in indexlist:
393             self.ManageEntriesOfCurrent(indexlist, [])
394
395     """
396     Add a Transmit PDO to current node
397     """
398     def AddPDOTransmitToCurrent(self):
399         indexlist = [self.GetLineFromIndex(0x1800),self.GetLineFromIndex(0x1A00)]
400         if None not in indexlist:
401             self.ManageEntriesOfCurrent(indexlist, [])
402         
403     """
404     Add a Receive PDO to current node
405     """
406     def AddPDOReceiveToCurrent(self):
407         indexlist = [self.GetLineFromIndex(0x1400),self.GetLineFromIndex(0x1600)]
408         if None not in indexlist:
409             self.ManageEntriesOfCurrent(indexlist, [])
410
411     """
412     Add a list of entries defined in profile for menu item selected to current node
413     """
414     def AddSpecificEntryToCurrent(self, menuitem):
415         indexlist = []
416         for menu, indexes in self.CurrentNode.GetSpecificMenu():
417             if menuitem == menu:
418                 for index in indexes:
419                     indexlist.append(self.GetLineFromIndex(index))
420         if None not in indexlist:
421             self.ManageEntriesOfCurrent(indexlist, [])
422
423     """
424     Search the first index available for a pluri entry from base_index
425     """
426     def GetLineFromIndex(self, base_index):
427         found = False
428         index = base_index
429         infos = self.GetEntryInfos(base_index)
430         while index < base_index + infos["incr"]*infos["nbmax"] and not found:
431             if not self.CurrentNode.IsEntry(index):
432                 found = True
433             else:
434                 index += infos["incr"]
435         if found:
436             return index
437         return None
438     
439     """
440     Add entries specified in addinglist and remove entries specified in removinglist
441     """
442     def ManageEntriesOfCurrent(self, addinglist, removinglist):
443         # Add all the entries in addinglist
444         for index in addinglist:
445             infos = self.GetEntryInfos(index)
446             if infos["struct"] & OD_MultipleSubindexes:
447                 # First case entry is a record
448                 if infos["struct"] & OD_IdenticalSubindexes:
449                     subentry_infos = self.GetSubentryInfos(index, 1)
450                     if "default" in subentry_infos:
451                         default = subentry_infos["default"]
452                     else:
453                         default = self.GetTypeDefaultValue(subentry_infos["type"])
454                     self.CurrentNode.AddEntry(index, 1, default)
455                 # Second case entry is a record
456                 else:
457                     i = 1
458                     subentry_infos = self.GetSubentryInfos(index, i)
459                     while subentry_infos:
460                         if "default" in subentry_infos:
461                             default = subentry_infos["default"]
462                         else:
463                             default = self.GetTypeDefaultValue(subentry_infos["type"])
464                         self.CurrentNode.AddEntry(index, i, default)
465                         i += 1
466                         subentry_infos = self.GetSubentryInfos(index, i)
467             # Third case entry is a record
468             else:
469                 subentry_infos = self.GetSubentryInfos(index, 0)
470                 if "default" in subentry_infos:
471                     default = subentry_infos["default"]
472                 else:
473                     default = self.GetTypeDefaultValue(subentry_infos["type"])
474                 self.CurrentNode.AddEntry(index, 0, default)
475         # Remove all the entries in removinglist
476         for index in removinglist:
477             self.RemoveCurrentVariable(index)
478         self.BufferCurrentNode()
479
480
481     """
482     Remove an entry from current node. Analize the index to perform the correct
483     method
484     """
485     def RemoveCurrentVariable(self, index, subIndex = None):
486         Mappings = self.CurrentNode.GetMappings()
487         if index < 0x1000 and subIndex == None:
488             type = self.CurrentNode.GetEntry(index, 1)
489             for i in Mappings[-1]:
490                 for value in Mappings[-1][i]["values"]:
491                     if value["type"] == index:
492                         value["type"] = type
493             self.CurrentNode.RemoveMappingEntry(index)
494             self.CurrentNode.RemoveEntry(index)
495         elif index == 0x1200 and subIndex == None:
496             self.CurrentNode.RemoveEntry(0x1200)
497         elif 0x1201 <= index <= 0x127F and subIndex == None:
498             self.CurrentNode.RemoveLine(index, 0x127F)
499         elif 0x1280 <= index <= 0x12FF and subIndex == None:
500             self.CurrentNode.RemoveLine(index, 0x12FF)
501         elif 0x1400 <= index <= 0x15FF or 0x1600 <= index <= 0x17FF and subIndex == None:
502             if 0x1600 <= index <= 0x17FF and subIndex == None:
503                 index -= 0x200
504             self.CurrentNode.RemoveLine(index, 0x15FF)
505             self.CurrentNode.RemoveLine(index + 0x200, 0x17FF)
506         elif 0x1800 <= index <= 0x19FF or 0x1A00 <= index <= 0x1BFF and subIndex == None:
507             if 0x1A00 <= index <= 0x1BFF:
508                 index -= 0x200
509             self.CurrentNode.RemoveLine(index, 0x19FF)
510             self.CurrentNode.RemoveLine(index + 0x200, 0x1BFF)
511         else:
512             found = False
513             for menu,list in self.CurrentNode.GetSpecificMenu():
514                 for i in list:
515                     iinfos = self.GetEntryInfos(i)
516                     indexes = [i + incr * iinfos["incr"] for incr in xrange(iinfos["nbmax"])] 
517                     if index in indexes:
518                         found = True
519                         diff = index - i
520                         for j in list:
521                             jinfos = self.GetEntryInfos(j)
522                             self.CurrentNode.RemoveLine(j + diff, j + jinfos["incr"]*jinfos["nbmax"], jinfos["incr"])
523             self.CurrentNode.RemoveMapVariable(index, subIndex)
524             if not found:
525                 infos = self.GetEntryInfos(index)
526                 if not infos["need"]:
527                     self.CurrentNode.RemoveEntry(index, subIndex)
528             if index in Mappings[-1]:
529                 self.CurrentNode.RemoveMappingEntry(index, subIndex)
530
531     def AddMapVariableToCurrent(self, index, name, struct, number):
532         if 0x2000 <= index <= 0x5FFF:
533             if not self.CurrentNode.IsEntry(index):
534                 self.CurrentNode.AddMappingEntry(index, name = name, struct = struct)
535                 if struct == var:
536                     values = {"name" : name, "type" : 0x05, "access" : "rw", "pdo" : True}
537                     self.CurrentNode.AddMappingEntry(index, 0, values = values)
538                     self.CurrentNode.AddEntry(index, 0, 0)
539                 else:
540                     values = {"name" : "Number of Entries", "type" : 0x05, "access" : "ro", "pdo" : False}
541                     self.CurrentNode.AddMappingEntry(index, 0, values = values)
542                     if struct == rec:
543                         values = {"name" : name + " %d[(sub)]", "type" : 0x05, "access" : "rw", "pdo" : True, "nbmax" : 0xFE}
544                         self.CurrentNode.AddMappingEntry(index, 1, values = values)
545                         for i in xrange(number):
546                             self.CurrentNode.AddEntry(index, i + 1, 0)
547                     else:
548                         for i in xrange(number):
549                             values = {"name" : "Undefined", "type" : 0x05, "access" : "rw", "pdo" : True}
550                             self.CurrentNode.AddMappingEntry(index, i + 1, values = values)
551                             self.CurrentNode.AddEntry(index, i + 1, 0)
552                 self.BufferCurrentNode()
553                 return None
554             else:
555                 return "Index 0x%04X already defined!"%index
556         else:
557             return "Index 0x%04X isn't a valid index for Map Variable!"%index
558
559     def AddUserTypeToCurrent(self, type, min, max, length):
560         index = 0xA0
561         while index < 0x100 and self.CurrentNode.IsEntry(index):
562             index += 1
563         if index < 0x100:
564             customisabletypes = self.GetCustomisableTypes()
565             name, valuetype = customisabletypes[type]
566             size = self.GetEntryInfos(type)["size"]
567             default = self.GetTypeDefaultValue(type)
568             if valuetype == 0:
569                 self.CurrentNode.AddMappingEntry(index, name = "%s[%d-%d]"%(name, min, max), struct = 3, size = size, default = default)
570                 self.CurrentNode.AddMappingEntry(index, 0, values = {"name" : "Number of Entries", "type" : 0x05, "access" : "ro", "pdo" : False})
571                 self.CurrentNode.AddMappingEntry(index, 1, values = {"name" : "Type", "type" : 0x05, "access" : "ro", "pdo" : False})
572                 self.CurrentNode.AddMappingEntry(index, 2, values = {"name" : "Minimum Value", "type" : type, "access" : "ro", "pdo" : False})
573                 self.CurrentNode.AddMappingEntry(index, 3, values = {"name" : "Maximum Value", "type" : type, "access" : "ro", "pdo" : False})
574                 self.CurrentNode.AddEntry(index, 1, type)
575                 self.CurrentNode.AddEntry(index, 2, min)
576                 self.CurrentNode.AddEntry(index, 3, max)
577             elif valuetype == 1:
578                 self.CurrentNode.AddMappingEntry(index, name = "%s%d"%(name, length), struct = 3, size = length * size, default = default)
579                 self.CurrentNode.AddMappingEntry(index, 0, values = {"name" : "Number of Entries", "type" : 0x05, "access" : "ro", "pdo" : False})
580                 self.CurrentNode.AddMappingEntry(index, 1, values = {"name" : "Type", "type" : 0x05, "access" : "ro", "pdo" : False})
581                 self.CurrentNode.AddMappingEntry(index, 2, values = {"name" : "Length", "type" : 0x05, "access" : "ro", "pdo" : False})
582                 self.CurrentNode.AddEntry(index, 1, type)
583                 self.CurrentNode.AddEntry(index, 2, length)
584             self.BufferCurrentNode()
585             return None
586         else:
587             return "Too many User Types have already been defined!"
588
589 #-------------------------------------------------------------------------------
590 #                      Modify Entry and Mapping Functions
591 #-------------------------------------------------------------------------------
592
593     def SetCurrentEntryCallbacks(self, index, value):
594         if self.CurrentNode and self.CurrentNode.IsEntry(index):
595             entry_infos = self.GetEntryInfos(index)
596             if "callback" not in entry_infos:
597                 self.CurrentNode.SetParamsEntry(index, None, callback = value)
598                 self.BufferCurrentNode()
599
600     def SetCurrentEntry(self, index, subIndex, value, name, editor):
601         if self.CurrentNode and self.CurrentNode.IsEntry(index):
602             if name == "value":
603                 if editor == "map":
604                     value = self.CurrentNode.GetMapValue(value)
605                     if value:
606                         self.CurrentNode.SetEntry(index, subIndex, value)
607                 elif editor == "bool":
608                     value = value == "True"
609                     self.CurrentNode.SetEntry(index, subIndex, value)
610                 elif editor == "time":
611                     self.CurrentNode.SetEntry(index, subIndex, value)
612                 elif editor == "number":
613                     try:
614                         self.CurrentNode.SetEntry(index, subIndex, int(value))
615                     except:
616                         pass
617                 elif editor == "domain":
618                     try:
619                         if len(value) % 2 != 0:
620                             value = "0" + value
621                         value = value.decode('hex_codec')
622                         self.CurrentNode.SetEntry(index, subIndex, value)
623                     except:
624                         pass
625                 else:
626                     subentry_infos = self.GetSubentryInfos(index, subIndex)
627                     type = subentry_infos["type"]
628                     dic = {}
629                     for typeindex, typevalue in CustomisableTypes:
630                         dic[typeindex] = typevalue
631                     if type not in dic:
632                         type = self.CurrentNode.GetEntry(type)[1]
633                     if dic[type] == 0:
634                         try:
635                             value = int(value, 16)
636                             self.CurrentNode.SetEntry(index, subIndex, value)
637                         except:
638                             pass
639                     else:
640                         self.CurrentNode.SetEntry(index, subIndex, value)
641             elif name in ["comment", "save"]:
642                 if editor == "option":
643                     value = value == "Yes"
644                 if name == "save":
645                     self.CurrentNode.SetParamsEntry(index, subIndex, save = value)
646                 elif name == "comment":
647                     self.CurrentNode.SetParamsEntry(index, subIndex, comment = value)
648             else:
649                 if editor == "type":
650                     value = self.GetTypeIndex(value)
651                     size = self.GetEntryInfos(value)["size"]
652                     self.CurrentNode.UpdateMapVariable(index, subIndex, size)
653                 elif editor in ["access","raccess"]:
654                     dic = {}
655                     for abbrev,access in AccessType.iteritems():
656                         dic[access] = abbrev
657                     value = dic[value]
658                     if editor == "raccess" and not self.CurrentNode.IsMappingEntry(index):
659                         entry_infos = self.GetEntryInfos(index)
660                         self.CurrentNode.AddMappingEntry(index, name = entry_infos["name"], struct = 7)
661                         self.CurrentNode.AddMappingEntry(index, 0, values = self.GetSubentryInfos(index, 0, False).copy())
662                         self.CurrentNode.AddMappingEntry(index, 1, values = self.GetSubentryInfos(index, 1, False).copy())
663                 self.CurrentNode.SetMappingEntry(index, subIndex, values = {name : value})
664             self.BufferCurrentNode()
665
666     def SetCurrentEntryName(self, index, name):
667         self.CurrentNode.SetMappingEntry(index, name=name)
668         self.BufferCurrentNode()
669
670     def SetCurrentUserType(self, index, type, min, max, length):
671         customisabletypes = self.GetCustomisableTypes()
672         values, valuetype = self.GetCustomisedTypeValues(index)
673         name, new_valuetype = customisabletypes[type]
674         size = self.GetEntryInfos(type)["size"]
675         default = self.GetTypeDefaultValue(type)
676         if new_valuetype == 0:
677             self.CurrentNode.SetMappingEntry(index, name = "%s[%d-%d]"%(name, min, max), struct = 3, size = size, default = default) 
678             if valuetype == 1:
679                 self.CurrentNode.SetMappingEntry(index, 2, values = {"name" : "Minimum Value", "type" : type, "access" : "ro", "pdo" : False})
680                 self.CurrentNode.AddMappingEntry(index, 3, values = {"name" : "Maximum Value", "type" : type, "access" : "ro", "pdo" : False})
681             self.CurrentNode.SetEntry(index, 1, type)
682             self.CurrentNode.SetEntry(index, 2, min)
683             if valuetype == 1:
684                 self.CurrentNode.AddEntry(index, 3, max)
685             else:
686                 self.CurrentNode.SetEntry(index, 3, max)
687         elif new_valuetype == 1:
688             self.CurrentNode.SetMappingEntry(index, name = "%s%d"%(name, length), struct = 3, size = size, default = default)
689             if valuetype == 0:
690                 self.CurrentNode.SetMappingEntry(index, 2, values = {"name" : "Length", "type" : 0x02, "access" : "ro", "pdo" : False})
691                 self.CurrentNode.RemoveMappingEntry(index, 3)
692             self.CurrentNode.SetEntry(index, 1, type)
693             self.CurrentNode.SetEntry(index, 2, length)
694             if valuetype == 0:
695                 self.CurrentNode.RemoveEntry(index, 3)
696         self.BufferCurrentNode()
697
698 #-------------------------------------------------------------------------------
699 #                      Current Buffering Management Functions
700 #-------------------------------------------------------------------------------
701
702     def BufferCurrentNode(self):
703         self.UndoBuffers[self.NodeIndex].Buffering(self.CurrentNode.Copy())
704
705     def CurrentIsSaved(self):
706         return self.UndoBuffers[self.NodeIndex].IsCurrentSaved()
707
708     def OneFileHasChanged(self):
709         result = False
710         for buffer in self.UndoBuffers.values():
711             result |= not buffer.IsCurrentSaved()
712         return result
713
714     def GetBufferNumber(self):
715         return len(self.UndoBuffers)
716
717     def LoadCurrentPrevious(self):
718         self.CurrentNode = self.UndoBuffers[self.NodeIndex].Previous().Copy()
719     
720     def LoadCurrentNext(self):
721         self.CurrentNode = self.UndoBuffers[self.NodeIndex].Next().Copy()
722
723     def AddNodeBuffer(self, currentstate = None, issaved = False):
724         self.NodeIndex = GetNewId()
725         self.UndoBuffers[self.NodeIndex] = UndoBuffer(currentstate, issaved)
726         self.FilePaths[self.NodeIndex] = ""
727         self.FileNames[self.NodeIndex] = ""
728         return self.NodeIndex
729
730     def ChangeCurrentNode(self, index):
731         if index in self.UndoBuffers.keys():
732             self.NodeIndex = index
733             self.CurrentNode = self.UndoBuffers[self.NodeIndex].Current().Copy()
734     
735     def RemoveNodeBuffer(self, index):
736         self.UndoBuffers.pop(index)
737         self.FilePaths.pop(index)
738         self.FileNames.pop(index)
739     
740     def GetCurrentNodeIndex(self):
741         return self.NodeIndex
742     
743     def GetCurrentFilename(self):
744         return self.GetFilename(self.NodeIndex)
745     
746     def GetAllFilenames(self):
747         indexes = self.UndoBuffers.keys()
748         indexes.sort()
749         return [self.GetFilename(idx) for idx in indexes]
750     
751     def GetFilename(self, index):
752         if self.UndoBuffers[index].IsCurrentSaved():
753             return self.FileNames[index]
754         else:
755             return "~%s~"%self.FileNames[index]
756     
757     def SetCurrentFilePath(self, filepath):
758         self.FilePaths[self.NodeIndex] = filepath
759         if filepath == "":
760             self.LastNewIndex += 1
761             self.FileNames[self.NodeIndex] = "Unnamed%d"%self.LastNewIndex
762         else:
763             self.FileNames[self.NodeIndex] = os.path.splitext(os.path.basename(filepath))[0]
764                 
765     def GetCurrentFilePath(self):
766         if len(self.FilePaths) > 0:
767             return self.FilePaths[self.NodeIndex]
768         else:
769             return ""
770     
771     def GetCurrentBufferState(self):
772         first = self.UndoBuffers[self.NodeIndex].IsFirst()
773         last = self.UndoBuffers[self.NodeIndex].IsLast()
774         return not first, not last
775
776 #-------------------------------------------------------------------------------
777 #                         Profiles Management Functions
778 #-------------------------------------------------------------------------------
779
780     def GetCurrentCommunicationLists(self):
781         list = []
782         for index in MappingDictionary.iterkeys():
783             if 0x1000 <= index < 0x1200:
784                 list.append(index)
785         return self.GetProfileLists(MappingDictionary, list)
786     
787     def GetCurrentDS302Lists(self):
788         return self.GetSpecificProfileLists(self.CurrentNode.GetDS302Profile())
789     
790     def GetCurrentProfileLists(self):
791         return self.GetSpecificProfileLists(self.CurrentNode.GetProfile())
792     
793     def GetSpecificProfileLists(self, mappingdictionary):
794         validlist = []
795         exclusionlist = []
796         for name, list in self.CurrentNode.GetSpecificMenu():
797             exclusionlist.extend(list)
798         for index in mappingdictionary.iterkeys():
799             if index not in exclusionlist:
800                 validlist.append(index)
801         return self.GetProfileLists(mappingdictionary, validlist)
802     
803     def GetProfileLists(self, mappingdictionary, list):
804         dictionary = {}
805         current = []
806         for index in list:
807             dictionary[index] = (mappingdictionary[index]["name"], mappingdictionary[index]["need"])
808             if self.CurrentNode.IsEntry(index):
809                 current.append(index)
810         return dictionary, current
811
812     def GetCurrentNextMapIndex(self):
813         if self.CurrentNode:
814             index = 0x2000
815             while self.CurrentNode.IsEntry(index) and index < 0x5FFF:
816                 index += 1
817             if index < 0x6000:
818                 return index
819             else:
820                 return None
821
822     def CurrentDS302Defined(self):
823         if self.CurrentNode:
824             return len(self.CurrentNode.GetDS302Profile()) > 0
825         return False
826
827 #-------------------------------------------------------------------------------
828 #                         Node State and Values Functions
829 #-------------------------------------------------------------------------------
830     
831     def GetCurrentNodeName(self):
832         if self.CurrentNode:
833             return self.CurrentNode.GetNodeName()
834         else:
835             return ""
836
837     def GetCurrentNodeID(self):
838         if self.CurrentNode:
839             return self.CurrentNode.GetNodeID()
840         else:
841             return None
842
843     def GetCurrentNodeInfos(self):
844         name = self.CurrentNode.GetNodeName()
845         id = self.CurrentNode.GetNodeID()
846         type = self.CurrentNode.GetNodeType()
847         description = self.CurrentNode.GetNodeDescription()
848         return name, id, type, description
849         
850     def SetCurrentNodeInfos(self, name, id, type, description):
851         self.CurrentNode.SetNodeName(name)
852         self.CurrentNode.SetNodeID(id)
853         self.CurrentNode.SetNodeType(type)
854         self.CurrentNode.SetNodeDescription(description)
855         self.BufferCurrentNode()
856
857     def GetCurrentProfileName(self):
858         if self.CurrentNode:
859             return self.CurrentNode.GetProfileName()
860         return ""
861
862     def IsCurrentEntry(self, index):
863         if self.CurrentNode:
864             return self.CurrentNode.IsEntry(index)
865         return False
866     
867     def GetCurrentEntry(self, index, subIndex = None):
868         if self.CurrentNode:
869             return self.CurrentNode.GetEntry(index, subIndex)
870         return None
871     
872     def GetCurrentParamsEntry(self, index, subIndex = None):
873         if self.CurrentNode:
874             return self.CurrentNode.GetParamsEntry(index, subIndex)
875         return None
876     
877     def GetCurrentValidIndexes(self, min, max):
878         validindexes = []
879         for index in self.CurrentNode.GetIndexes():
880             if min <= index <= max:
881                 validindexes.append((self.GetEntryName(index), index))
882         return validindexes
883         
884     def GetCurrentValidChoices(self, min, max):
885         validchoices = []
886         exclusionlist = []
887         for menu, indexes in self.CurrentNode.GetSpecificMenu():
888             exclusionlist.extend(indexes)
889             good = True
890             for index in indexes:
891                 good &= min <= index <= max
892             if good:
893                 validchoices.append((menu, None))
894         list = [index for index in MappingDictionary.keys() if index >= 0x1000]
895         profiles = self.CurrentNode.GetMappings(False)
896         for profile in profiles:
897             list.extend(profile.keys())
898         list.sort()
899         for index in list:
900             if min <= index <= max and not self.CurrentNode.IsEntry(index) and index not in exclusionlist:
901                 validchoices.append((self.GetEntryName(index), index))
902         return validchoices
903     
904     def HasCurrentEntryCallbacks(self, index):
905         if self.CurrentNode and self.CurrentNode.IsEntry(index):
906             entry_infos = self.GetEntryInfos(index)
907             if "callback" in entry_infos:
908                 return entry_infos["callback"]
909             return self.CurrentNode.HasEntryCallbacks(index)
910         return False
911     
912     def GetCurrentEntryValues(self, index):
913         if self.CurrentNode:
914             return self.GetNodeEntryValues(self.CurrentNode, index)
915     
916     def GetNodeEntryValues(self, node, index):
917         if node and node.IsEntry(index):
918             entry_infos = node.GetEntryInfos(index)
919             data = []
920             editors = []
921             values = node.GetEntry(index)
922             params = node.GetParamsEntry(index)
923             if type(values) == ListType:
924                 for i, value in enumerate(values):
925                     data.append({"value" : value})
926                     data[-1].update(params[i])      
927             else:
928                 data.append({"value" : values})
929                 data[-1].update(params)
930             for i, dic in enumerate(data):
931                 infos = node.GetSubentryInfos(index, i)
932                 dic["subindex"] = "0x%02X"%i
933                 dic["name"] = infos["name"]
934                 dic["type"] = node.GetTypeName(infos["type"])
935                 dic["access"] = AccessType[infos["access"]]
936                 dic["save"] = OptionType[dic["save"]]
937                 editor = {"subindex" : None, "save" : "option", "callback" : "option", "comment" : "string"}
938                 if type(values) == ListType and i == 0:
939                     editor["name"] = None
940                     editor["type"] = None
941                     if 0x1600 <= index <= 0x17FF or 0x1A00 <= index <= 0x1C00:
942                         editor["access"] = "raccess"
943                     else:
944                         editor["access"] = None
945                     editor["value"] = None
946                 else:
947                     if infos["user_defined"]:
948                         if entry_infos["struct"] & OD_IdenticalSubindexes:
949                             editor["name"] = None
950                             if i > 1:
951                                 editor["type"] = None
952                                 editor["access"] = None
953                             else:
954                                 editor["type"] = "type"
955                                 editor["access"] = "access"
956                         else:
957                             if entry_infos["struct"] & OD_MultipleSubindexes:
958                                 editor["name"] = "string"
959                             else:
960                                 editor["name"] = None
961                             editor["type"] = "type"
962                             editor["access"] = "access"
963                     else:
964                         editor["name"] = None
965                         editor["type"] = None
966                         editor["access"] = None
967                     if index < 0x260:
968                         editor["value"] = None
969                         if i == 1:
970                             dic["value"] = node.GetTypeName(dic["value"])
971                     elif 0x1600 <= index <= 0x17FF or 0x1A00 <= index <= 0x1C00:
972                         editor["value"] = "map"
973                         dic["value"] = node.GetMapName(dic["value"])
974                     else:
975                         if dic["type"].startswith("VISIBLE_STRING"):
976                             editor["value"] = "string"
977                         elif dic["type"] in ["TIME_OF_DAY","TIME_DIFFERENCE"]:
978                             editor["value"] = "time"
979                         elif dic["type"] == "DOMAIN":
980                             editor["value"] = "domain"
981                             dic["value"] = dic["value"].encode('hex_codec')
982                         elif dic["type"] == "BOOLEAN":
983                             editor["value"] = "bool"
984                             dic["value"] = BoolType[dic["value"]]
985                         result = type_model.match(dic["type"])
986                         if result:
987                             values = result.groups()
988                             if values[0] == "UNSIGNED":
989                                 format = "0x%0" + str(int(values[1])/4) + "X"
990                                 dic["value"] = format%dic["value"]
991                                 editor["value"] = "string"
992                             if values[0] == "INTEGER":
993                                 editor["value"] = "number"
994                             elif values[0] == "REAL":
995                                 editor["value"] = "float"
996                             elif values[0] == "VISIBLE_STRING":
997                                 editor["length"] = values[0]
998                         result = range_model.match(dic["type"])
999                         if result:
1000                             values = result.groups()
1001                             if values[0] in ["UNSIGNED", "INTEGER", "REAL"]:
1002                                 editor["min"] = values[2]
1003                                 editor["max"] = values[3]
1004                 editors.append(editor)
1005             return data, editors
1006         else:
1007             return None
1008
1009 #-------------------------------------------------------------------------------
1010 #                         Node Informations Functions
1011 #-------------------------------------------------------------------------------
1012
1013     def GetCustomisedTypeValues(self, index):
1014         if self.CurrentNode:
1015             values = self.CurrentNode.GetEntry(index)
1016             customisabletypes = self.GetCustomisableTypes()
1017             return values, customisabletypes[values[1]][1]
1018         else:
1019             return None, None
1020
1021     def GetEntryName(self, index):
1022         if self.CurrentNode:
1023             return self.CurrentNode.GetEntryName(index)
1024         else:
1025             return FindEntryName(index, MappingDictionary)
1026     
1027     def GetEntryInfos(self, index):
1028         if self.CurrentNode:
1029             return self.CurrentNode.GetEntryInfos(index)
1030         else:
1031             return FindEntryInfos(index, MappingDictionary)
1032     
1033     def GetSubentryInfos(self, index, subindex):
1034         if self.CurrentNode:
1035             return self.CurrentNode.GetSubentryInfos(index, subindex)
1036         else:
1037             result = FindSubentryInfos(index, subindex, MappingDictionary)
1038             if result:
1039                 result["user_defined"] = False
1040             return result
1041     
1042     def GetTypeIndex(self, typename):
1043         if self.CurrentNode:
1044             return self.CurrentNode.GetTypeIndex(typename)
1045         else:
1046             return FindTypeIndex(typename, MappingDictionary)
1047     
1048     def GetTypeName(self, typeindex):
1049         if self.CurrentNode:
1050             return self.CurrentNode.GetTypeName(typeindex)
1051         else:
1052             return FindTypeName(typeindex, MappingDictionary)
1053     
1054     def GetTypeDefaultValue(self, typeindex):
1055         if self.CurrentNode:
1056             return self.CurrentNode.GetTypeDefaultValue(typeindex)
1057         else:
1058             return FindTypeDefaultValue(typeindex, MappingDictionary)
1059     
1060     def GetMapVariableList(self):
1061         if self.CurrentNode:
1062             return self.CurrentNode.GetMapVariableList()
1063         else:
1064             return []
1065
1066     def GetMandatoryIndexes(self, node = None):
1067         if self.CurrentNode:
1068             return self.CurrentNode.GetMandatoryIndexes()
1069         else:
1070             return FindMandatoryIndexes(MappingDictionary)
1071     
1072     def GetCustomisableTypes(self):
1073         dic = {}
1074         for index, valuetype in CustomisableTypes:
1075             name = self.GetTypeName(index)
1076             dic[index] = [name, valuetype]
1077         return dic
1078     
1079     def GetCurrentSpecificMenu(self):
1080         if self.CurrentNode:
1081             return self.CurrentNode.GetSpecificMenu()
1082         return []
1083