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