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