]> rtime.felk.cvut.cz Git - CanFestival-3.git/blob - objdictgen/networkedit.py
4e9e46d02898e621055a1070c4142c0783680e52
[CanFestival-3.git] / objdictgen / networkedit.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 wxPython.wx import *
25 from wxPython.grid import *
26 import wx
27 from wx.lib.anchors import LayoutAnchors
28 import wx.grid
29
30 from types import *
31 import os, re, platform, sys, time, traceback, getopt
32
33 __version__ = "$Revision: 1.2 $"
34
35 from nodelist import *
36 from nodemanager import *
37 from subindextable import *
38 from commondialogs import *
39 from doc_index.DS301_index import *
40
41 def create(parent):
42     return networkedit(parent)
43
44 def usage():
45     print "\nUsage of networkedit.py :"
46     print "\n   %s [Projectpath]\n"%sys.argv[0]
47
48 try:
49     opts, args = getopt.getopt(sys.argv[1:], "h", ["help"])
50 except getopt.GetoptError:
51     # print help information and exit:
52     usage()
53     sys.exit(2)
54
55 for o, a in opts:
56     if o in ("-h", "--help"):
57         usage()
58         sys.exit()
59
60 if len(args) == 0:
61     projectOpen = None 
62 elif len(args) == 1:
63     projectOpen = args[0]
64 else:
65     usage()
66     sys.exit(2)
67
68 ScriptDirectory = sys.path[0]
69
70 try:
71     from wxPython.html import *
72
73     wxEVT_HTML_URL_CLICK = wxNewId()
74
75     def EVT_HTML_URL_CLICK(win, func):
76         win.Connect(-1, -1, wxEVT_HTML_URL_CLICK, func)
77
78     class wxHtmlWindowUrlClick(wxPyEvent):
79         def __init__(self, linkinfo):
80             wxPyEvent.__init__(self)
81             self.SetEventType(wxEVT_HTML_URL_CLICK)
82             self.linkinfo = (linkinfo.GetHref(), linkinfo.GetTarget())
83
84     class wxUrlClickHtmlWindow(wxHtmlWindow):
85         """ HTML window that generates and OnLinkClicked event.
86
87         Use this to avoid having to override HTMLWindow
88         """
89         def OnLinkClicked(self, linkinfo):
90             wxPostEvent(self, wxHtmlWindowUrlClick(linkinfo))
91     
92 #-------------------------------------------------------------------------------
93 #                                Html Frame
94 #-------------------------------------------------------------------------------
95
96     [wxID_HTMLFRAME, wxID_HTMLFRAMEHTMLCONTENT] = [wx.NewId() for _init_ctrls in range(2)]
97
98     class HtmlFrame(wx.Frame):
99         def _init_ctrls(self, prnt):
100             # generated method, don't edit
101             wx.Frame.__init__(self, id=wxID_HTMLFRAME, name='HtmlFrame',
102                   parent=prnt, pos=wx.Point(320, 231), size=wx.Size(853, 616),
103                   style=wx.DEFAULT_FRAME_STYLE, title='')
104             self.Bind(wx.EVT_CLOSE, self.OnCloseFrame, id=wxID_HTMLFRAME)
105             
106             self.HtmlContent = wxUrlClickHtmlWindow(id=wxID_HTMLFRAMEHTMLCONTENT,
107                   name='HtmlContent', parent=self, pos=wx.Point(0, 0),
108                   size=wx.Size(-1, -1), style=wxHW_SCROLLBAR_AUTO|wxHW_NO_SELECTION)
109             EVT_HTML_URL_CLICK(self.HtmlContent, self.OnLinkClick)
110
111         def __init__(self, parent, opened):
112             self._init_ctrls(parent)
113             self.HtmlFrameOpened = opened
114         
115         def SetHtmlCode(self, htmlcode):
116             self.HtmlContent.SetPage(htmlcode)
117             
118         def SetHtmlPage(self, htmlpage):
119             self.HtmlContent.LoadPage(htmlpage)
120             
121         def OnCloseFrame(self, event):
122             self.HtmlFrameOpened.remove(self.GetTitle())
123             event.Skip()
124         
125         def OnLinkClick(self, event):
126             url = event.linkinfo[0]
127             try:
128                 import webbrowser
129             except ImportError:
130                 wxMessageBox('Please point your browser at: %s' % url)
131             else:
132                 webbrowser.open(url)
133     
134     Html_Window = True
135 except:
136     Html_Window = False
137
138
139 [wxID_NETWORKEDIT, wxID_NETWORKEDITNETWORKNODES, 
140  wxID_NETWORKEDITHELPBAR,
141 ] = [wx.NewId() for _init_ctrls in range(3)]
142
143 [wxID_NETWORKEDITADDMENUITEMS0, wxID_NETWORKEDITADDMENUITEMS1, 
144  wxID_NETWORKEDITADDMENUITEMS2, wxID_NETWORKEDITADDMENUITEMS3, 
145  wxID_NETWORKEDITADDMENUITEMS4, wxID_NETWORKEDITADDMENUITEMS5, 
146 ] = [wx.NewId() for _init_coll_AddMenu_Items in range(6)]
147
148 [wxID_NETWORKEDITFILEMENUITEMS0, wxID_NETWORKEDITFILEMENUITEMS1, 
149  wxID_NETWORKEDITFILEMENUITEMS2, wxID_NETWORKEDITFILEMENUITEMS4, 
150  wxID_NETWORKEDITFILEMENUITEMS5, wxID_NETWORKEDITFILEMENUITEMS6,
151 ] = [wx.NewId() for _init_coll_FileMenu_Items in range(6)]
152
153 [wxID_NETWORKEDITNETWORKMENUITEMS0, wxID_NETWORKEDITNETWORKMENUITEMS1, 
154  wxID_NETWORKEDITNETWORKMENUITEMS3, 
155 ] = [wx.NewId() for _init_coll_AddMenu_Items in range(3)]
156
157
158 [wxID_NETWORKEDITEDITMENUITEMS0, wxID_NETWORKEDITEDITMENUITEMS1, 
159  wxID_NETWORKEDITEDITMENUITEMS2, wxID_NETWORKEDITEDITMENUITEMS4, 
160  wxID_NETWORKEDITEDITMENUITEMS6, wxID_NETWORKEDITEDITMENUITEMS7, 
161  wxID_NETWORKEDITEDITMENUITEMS8, 
162 ] = [wx.NewId() for _init_coll_EditMenu_Items in range(7)]
163
164 [wxID_NETWORKEDITHELPMENUITEMS0, wxID_NETWORKEDITHELPMENUITEMS1,
165  wxID_NETWORKEDITHELPMENUITEMS2,
166 ] = [wx.NewId() for _init_coll_HelpMenu_Items in range(3)]
167
168 class networkedit(wx.Frame):
169     def _init_coll_menuBar1_Menus(self, parent):
170         # generated method, don't edit
171
172         if self.Mode == "solo":
173             parent.Append(menu=self.FileMenu, title='File')
174         parent.Append(menu=self.NetworkMenu, title='Network')
175         parent.Append(menu=self.EditMenu, title='Edit')
176         parent.Append(menu=self.AddMenu, title='Add')
177         parent.Append(menu=self.HelpMenu, title='Help')
178
179     def _init_coll_EditMenu_Items(self, parent):
180         # generated method, don't edit
181
182         parent.Append(help='', id=wxID_NETWORKEDITEDITMENUITEMS4,
183               kind=wx.ITEM_NORMAL, text='Refresh\tCTRL+R')
184         parent.AppendSeparator()
185         parent.Append(help='', id=wxID_NETWORKEDITEDITMENUITEMS1,
186               kind=wx.ITEM_NORMAL, text='Undo\tCTRL+Z')
187         parent.Append(help='', id=wxID_NETWORKEDITEDITMENUITEMS0,
188               kind=wx.ITEM_NORMAL, text='Redo\tCTRL+Y')
189         parent.AppendSeparator()
190         parent.Append(help='', id=wxID_NETWORKEDITEDITMENUITEMS6,
191               kind=wx.ITEM_NORMAL, text='Node infos')
192         parent.Append(help='', id=wxID_NETWORKEDITEDITMENUITEMS2,
193               kind=wx.ITEM_NORMAL, text='DS-301 Profile')
194         parent.Append(help='', id=wxID_NETWORKEDITEDITMENUITEMS8,
195               kind=wx.ITEM_NORMAL, text='DS-302 Profile')
196         parent.Append(help='', id=wxID_NETWORKEDITEDITMENUITEMS7,
197               kind=wx.ITEM_NORMAL, text='Other Profile')
198         self.Bind(wx.EVT_MENU, self.OnUndoMenu,
199               id=wxID_NETWORKEDITEDITMENUITEMS1)
200         self.Bind(wx.EVT_MENU, self.OnRedoMenu,
201               id=wxID_NETWORKEDITEDITMENUITEMS0)
202         self.Bind(wx.EVT_MENU, self.OnCommunicationMenu,
203               id=wxID_NETWORKEDITEDITMENUITEMS2)
204         self.Bind(wx.EVT_MENU, self.OnRefreshMenu,
205               id=wxID_NETWORKEDITEDITMENUITEMS4)
206         self.Bind(wx.EVT_MENU, self.OnNodeInfosMenu,
207               id=wxID_NETWORKEDITEDITMENUITEMS6)
208         self.Bind(wx.EVT_MENU, self.OnEditProfileMenu,
209               id=wxID_NETWORKEDITEDITMENUITEMS7)
210         self.Bind(wx.EVT_MENU, self.OnOtherCommunicationMenu,
211               id=wxID_NETWORKEDITEDITMENUITEMS8)
212
213     def _init_coll_HelpMenu_Items(self, parent):
214         # generated method, don't edit
215
216         parent.Append(help='', id=wxID_NETWORKEDITHELPMENUITEMS0,
217               kind=wx.ITEM_NORMAL, text='DS-301 Standard\tF1')
218         self.Bind(wx.EVT_MENU, self.OnHelpDS301Menu,
219               id=wxID_NETWORKEDITHELPMENUITEMS0)
220         parent.Append(help='', id=wxID_NETWORKEDITHELPMENUITEMS1,
221               kind=wx.ITEM_NORMAL, text='CAN Festival Docs\tF2')
222         self.Bind(wx.EVT_MENU, self.OnHelpCANFestivalMenu,
223               id=wxID_NETWORKEDITHELPMENUITEMS1)
224         if Html_Window and self.Mode == "solo":
225             parent.Append(help='', id=wxID_NETWORKEDITHELPMENUITEMS2,
226                   kind=wx.ITEM_NORMAL, text='About')
227             self.Bind(wx.EVT_MENU, self.OnAboutMenu,
228                   id=wxID_NETWORKEDITHELPMENUITEMS2)
229
230     def _init_coll_FileMenu_Items(self, parent):
231         # generated method, don't edit
232
233         parent.Append(help='', id=wxID_NETWORKEDITFILEMENUITEMS5,
234               kind=wx.ITEM_NORMAL, text='New\tCTRL+N')
235         parent.Append(help='', id=wxID_NETWORKEDITFILEMENUITEMS0,
236               kind=wx.ITEM_NORMAL, text='Open\tCTRL+O')
237         parent.Append(help='', id=wxID_NETWORKEDITFILEMENUITEMS1,
238               kind=wx.ITEM_NORMAL, text='Save\tCTRL+S')
239         parent.Append(help='', id=wxID_NETWORKEDITFILEMENUITEMS2,
240               kind=wx.ITEM_NORMAL, text='Close\tCTRL+W')
241         parent.AppendSeparator()
242         parent.Append(help='', id=wxID_NETWORKEDITFILEMENUITEMS4,
243               kind=wx.ITEM_NORMAL, text='Exit')
244         self.Bind(wx.EVT_MENU, self.OnOpenProjectMenu,
245               id=wxID_NETWORKEDITFILEMENUITEMS0)
246         self.Bind(wx.EVT_MENU, self.OnSaveProjectMenu,
247               id=wxID_NETWORKEDITFILEMENUITEMS1)
248 ##        self.Bind(wx.EVT_MENU, self.OnCloseProjectMenu,
249 ##              id=wxID_NETWORKEDITFILEMENUITEMS2)
250         self.Bind(wx.EVT_MENU, self.OnQuitMenu,
251               id=wxID_NETWORKEDITFILEMENUITEMS4)
252         self.Bind(wx.EVT_MENU, self.OnNewProjectMenu,
253               id=wxID_NETWORKEDITFILEMENUITEMS5)
254     
255     def _init_coll_NetworkMenu_Items(self, parent):
256         # generated method, don't edit
257
258         parent.Append(help='', id=wxID_NETWORKEDITNETWORKMENUITEMS0,
259               kind=wx.ITEM_NORMAL, text='Add Slave Node')
260         parent.Append(help='', id=wxID_NETWORKEDITNETWORKMENUITEMS1,
261               kind=wx.ITEM_NORMAL, text='Remove Slave Node')
262         parent.AppendSeparator()
263         parent.Append(help='', id=wxID_NETWORKEDITNETWORKMENUITEMS3,
264               kind=wx.ITEM_NORMAL, text='Build Master Dictionary')
265         self.Bind(wx.EVT_MENU, self.OnAddSlaveMenu,
266               id=wxID_NETWORKEDITNETWORKMENUITEMS0)
267         self.Bind(wx.EVT_MENU, self.OnRemoveSlaveMenu,
268               id=wxID_NETWORKEDITNETWORKMENUITEMS1)
269 ##        self.Bind(wx.EVT_MENU, self.OnBuildMasterMenu,
270 ##              id=wxID_NETWORKEDITNETWORKMENUITEMS3)
271     
272     def _init_coll_AddMenu_Items(self, parent):
273         # generated method, don't edit
274
275         parent.Append(help='', id=wxID_NETWORKEDITADDMENUITEMS0,
276               kind=wx.ITEM_NORMAL, text='SDO Server')
277         parent.Append(help='', id=wxID_NETWORKEDITADDMENUITEMS1,
278               kind=wx.ITEM_NORMAL, text='SDO Client')
279         parent.Append(help='', id=wxID_NETWORKEDITADDMENUITEMS2,
280               kind=wx.ITEM_NORMAL, text='PDO Transmit')
281         parent.Append(help='', id=wxID_NETWORKEDITADDMENUITEMS3,
282               kind=wx.ITEM_NORMAL, text='PDO Receive')
283         parent.Append(help='', id=wxID_NETWORKEDITADDMENUITEMS4,
284               kind=wx.ITEM_NORMAL, text='Map Variable')
285         parent.Append(help='', id=wxID_NETWORKEDITADDMENUITEMS5,
286               kind=wx.ITEM_NORMAL, text='User Type')
287         self.Bind(wx.EVT_MENU, self.OnAddSDOServerMenu,
288               id=wxID_NETWORKEDITADDMENUITEMS0)
289         self.Bind(wx.EVT_MENU, self.OnAddSDOClientMenu,
290               id=wxID_NETWORKEDITADDMENUITEMS1)
291         self.Bind(wx.EVT_MENU, self.OnAddPDOTransmitMenu,
292               id=wxID_NETWORKEDITADDMENUITEMS2)
293         self.Bind(wx.EVT_MENU, self.OnAddPDOReceiveMenu,
294               id=wxID_NETWORKEDITADDMENUITEMS3)
295         self.Bind(wx.EVT_MENU, self.OnAddMapVariableMenu,
296               id=wxID_NETWORKEDITADDMENUITEMS4)
297         self.Bind(wx.EVT_MENU, self.OnAddUserTypeMenu,
298               id=wxID_NETWORKEDITADDMENUITEMS5)
299
300     def _init_coll_HelpBar_Fields(self, parent):
301         # generated method, don't edit
302         parent.SetFieldsCount(3)
303
304         parent.SetStatusText(number=0, text='')
305         parent.SetStatusText(number=1, text='')
306         parent.SetStatusText(number=2, text='')
307
308         parent.SetStatusWidths([100, 110, -1])
309
310     def _init_utils(self):
311         # generated method, don't edit
312         self.menuBar1 = wx.MenuBar()
313         self.menuBar1.SetEvtHandlerEnabled(True)
314         
315         if self.Mode == "solo":
316             self.FileMenu = wx.Menu(title='')
317         
318         self.NetworkMenu = wx.Menu(title='')
319
320         self.EditMenu = wx.Menu(title='')
321
322         self.AddMenu = wx.Menu(title='')
323
324         self.HelpMenu = wx.Menu(title='')
325
326         self._init_coll_menuBar1_Menus(self.menuBar1)
327         if self.Mode == "solo":
328             self._init_coll_FileMenu_Items(self.FileMenu)
329         self._init_coll_NetworkMenu_Items(self.NetworkMenu)
330         self._init_coll_EditMenu_Items(self.EditMenu)
331         self._init_coll_AddMenu_Items(self.AddMenu)
332         self._init_coll_HelpMenu_Items(self.HelpMenu)
333
334     def _init_ctrls(self, prnt):
335         # generated method, don't edit
336         wx.Frame.__init__(self, id=wxID_NETWORKEDIT, name='networkedit',
337               parent=prnt, pos=wx.Point(149, 178), size=wx.Size(1000, 700),
338               style=wx.DEFAULT_FRAME_STYLE, title='Networkedit')
339         self._init_utils()
340         self.SetClientSize(wx.Size(1000, 700))
341         self.SetMenuBar(self.menuBar1)
342 ##        self.Bind(wx.EVT_CLOSE, self.OnCloseFrame, id=wxID_NETWORKEDIT)
343
344         self.NetworkNodes = wx.Notebook(id=wxID_NETWORKEDITNETWORKNODES,
345               name='NetworkNodes', parent=self, pos=wx.Point(0, 0),
346               size=wx.Size(0, 0), style=wxNB_LEFT)
347         self.NetworkNodes.Bind(wx.EVT_NOTEBOOK_PAGE_CHANGED,
348               self.OnNodeSelectedChanged, id=wxID_NETWORKEDITNETWORKNODES)
349
350         self.HelpBar = wx.StatusBar(id=wxID_NETWORKEDITHELPBAR, name='HelpBar',
351               parent=self, style=wxST_SIZEGRIP)
352         self._init_coll_HelpBar_Fields(self.HelpBar)
353         self.SetStatusBar(self.HelpBar)
354
355     def __init__(self, parent, mode = "solo", nodelist = None):
356         self.Mode = mode
357         self._init_ctrls(parent)
358         self.HtmlFrameOpened = []
359         
360         if self.Mode == "solo":
361             self.Manager = NodeManager(ScriptDirectory)
362             if projectOpen:
363                 self.NodeList = NodeList(self.Manager)
364                 result = self.NodeList.LoadProject(projectOpen)
365                 if not result:
366                     self.RefreshNetworkNodes()
367             else:
368                 self.NodeList = None
369         else:
370             self.NodeList = nodelist
371             self.Manager = self.NodeList.GetManager()
372         
373         self.RefreshBufferState()
374         self.RefreshTitle()
375         self.RefreshMainMenu()
376
377     def GetNoteBook(self):
378         return self.NetworkNodes
379
380     def OnQuitMenu(self, event):
381         self.Close()
382         event.Skip()
383
384     def OnAddSDOServerMenu(self, event):
385         self.Manager.AddSDOServerToCurrent()
386         self.RefreshBufferState()
387         self.RefreshCurrentIndexList()
388         event.Skip()
389     
390     def OnAddSDOClientMenu(self, event):
391         self.Manager.AddSDOClientToCurrent()
392         self.RefreshBufferState()
393         self.RefreshCurrentIndexList()
394         event.Skip()
395
396     def OnAddPDOTransmitMenu(self, event):
397         self.Manager.AddPDOTransmitToCurrent()
398         self.RefreshBufferState()
399         self.RefreshCurrentIndexList()
400         event.Skip()
401
402     def OnAddPDOReceiveMenu(self, event):
403         self.Manager.AddPDOReceiveToCurrent()
404         self.RefreshBufferState()
405         self.RefreshCurrentIndexList()
406         event.Skip()
407
408     def OnAddMapVariableMenu(self, event):
409         self.AddMapVariable()
410         event.Skip()
411
412     def OnAddUserTypeMenu(self, event):
413         self.AddUserType()
414         event.Skip()
415
416     def OnNodeSelectedChanged(self, event):
417         selected = event.GetSelection()
418         # At init selected = -1
419         if selected > 0:
420             window = self.NetworkNodes.GetPage(selected)
421             self.NodeList.SetCurrentSelected(window.GetIndex())
422         self.RefreshMainMenu()
423         self.RefreshStatusBar()
424         event.Skip()
425
426 #-------------------------------------------------------------------------------
427 #                         Load and Save Funtions
428 #-------------------------------------------------------------------------------
429
430     def OnNewProjectMenu(self, event):
431         if self.NodeList:
432             defaultpath = os.path.dirname(self.NodeList.GetRoot())
433         else:
434             defaultpath = os.getcwd()
435         dialog = wxDirDialog(self , "Choose a project", defaultpath, wxDD_NEW_DIR_BUTTON)
436         if dialog.ShowModal() == wxID_OK:
437             projectpath = dialog.GetPath()
438             if os.path.isdir(projectpath) and len(os.listdir(projectpath)) == 0:
439                 manager = NodeManager(ScriptDirectory)
440                 nodelist = NodeList(manager)
441                 result = nodelist.LoadProject(projectpath)
442                 if not result:
443                     self.Manager = manager
444                     self.NodeList = nodelist
445                     self.NodeList.SetCurrentSelected(0)
446                                         
447                     self.RefreshNetworkNodes()
448                     self.RefreshBufferState()
449                     self.RefreshTitle()
450                     self.RefreshProfileMenu()
451                     self.RefreshMainMenu()
452                 else:
453                     message = wxMessageDialog(self, result, "ERROR", wxOK|wxICON_ERROR)
454                     message.ShowModal()
455                     message.Destroy()
456         event.Skip()
457
458     def OnOpenProjectMenu(self, event):
459         if self.NodeList:
460             defaultpath = os.path.dirname(self.NodeList.GetRoot())
461         else:
462             defaultpath = os.getcwd()
463         dialog = wxDirDialog(self , "Choose a project", defaultpath, 0)
464         if dialog.ShowModal() == wxID_OK:
465             projectpath = dialog.GetPath()
466             if os.path.isdir(projectpath):
467                 manager = NodeManager(ScriptDirectory)
468                 nodelist = NodeList(manager)
469                 result = nodelist.LoadProject(projectpath)
470                 if not result:
471                     self.Manager = manager
472                     self.NodeList = nodelist
473                     self.NodeList.SetCurrentSelected(0)
474                     
475                     self.RefreshNetworkNodes()
476                     self.RefreshBufferState()
477                     self.RefreshTitle()
478                     self.RefreshProfileMenu()
479                     self.RefreshMainMenu()
480                 else:
481                     message = wxMessageDialog(self, result, "Error", wxOK|wxICON_ERROR)
482                     message.ShowModal()
483                     message.Destroy()
484         dialog.Destroy()
485         event.Skip()
486
487     def OnSaveProjectMenu(self, event):
488         result = self.NodeList.SaveProject()
489         if result:
490             message = wxMessageDialog(self, result, "Error", wxOK|wxICON_ERROR)
491             message.ShowModal()
492             message.Destroy()
493         event.Skip()
494
495 #-------------------------------------------------------------------------------
496 #                             Slave Nodes Management
497 #-------------------------------------------------------------------------------
498
499     def OnAddSlaveMenu(self, event):
500         dialog = AddSlaveDialog(self)
501         dialog.SetNodeList(self.NodeList)
502         if dialog.ShowModal() == wxID_OK:
503             values = dialog.GetValues()
504             result = self.NodeList.AddSlaveNode(values["slaveName"], values["slaveNodeID"], values["edsFile"])
505             if not result:
506                 new_editingpanel = EditingPanel(self, self.NodeList, False)
507                 new_editingpanel.SetIndex(values["slaveNodeID"])
508                 idx = self.NodeList.GetOrderNumber(values["slaveNodeID"])
509                 self.NetworkNodes.InsertPage(idx, new_editingpanel, "")
510                 self.NodeList.SetCurrentSelected(idx)
511                 self.NetworkNodes.SetSelection(idx)
512                 self.RefreshBufferState()
513             else:
514                 message = wxMessageDialog(self, result, "Error", wxOK|wxICON_ERROR)
515                 message.ShowModal()
516                 message.Destroy()
517         dialog.Destroy()
518         event.Skip()
519
520     def OnRemoveSlaveMenu(self, event):
521         slavenames = self.NodeList.GetSlaveNames()
522         slaveids = self.NodeList.GetSlaveIDs()
523         dialog = wxSingleChoiceDialog(self, "Choose a slave to remove", "Remove slave", slavenames)
524         if dialog.ShowModal() == wxID_OK:
525             choice = dialog.GetSelection()
526             result = self.NodeList.RemoveSlaveNode(slaveids[choice])
527             if not result:
528                 slaveids.pop(choice)
529                 current = self.NetworkNodes.GetSelection()
530                 self.NetworkNodes.DeletePage(choice + 1)
531                 if self.NetworkNodes.GetPageCount() > 0:
532                     new_selection = min(current, self.NetworkNodes.GetPageCount() - 1)
533                     self.NetworkNodes.SetSelection(new_selection)
534                     if new_selection > 0:
535                         self.NodeList.SetCurrentSelected(slaveids[new_selection - 1])
536                     self.RefreshBufferState()
537             else:
538                 message = wxMessageDialog(self, result, "Error", wxOK|wxICON_ERROR)
539                 message.ShowModal()
540                 message.Destroy()
541         event.Skip()
542
543 #-------------------------------------------------------------------------------
544 #                             Refresh Functions
545 #-------------------------------------------------------------------------------
546
547     def RefreshTitle(self):
548         if self.NodeList != None:
549             self.SetTitle("Networkedit - %s"%self.NodeList.GetNetworkName())
550         else:
551             self.SetTitle("Networkedit")
552
553     def OnRefreshMenu(self, event):
554         self.RefreshCurrentIndexList()
555         event.Skip()
556
557     def RefreshCurrentIndexList(self):
558         selected = self.NetworkNodes.GetSelection()
559         if selected == 0:
560             window = self.NetworkNodes.GetPage(selected)
561             window.RefreshIndexList()
562         else:
563             pass
564
565     def RefreshNetworkNodes(self):
566         if self.NetworkNodes.GetPageCount() > 0:
567             self.NetworkNodes.DeleteAllPages()
568         if self.NodeList:
569             new_editingpanel = EditingPanel(self, self.Manager)
570             new_editingpanel.SetIndex(0)
571             self.NetworkNodes.AddPage(new_editingpanel, "")
572             for idx in self.NodeList.GetSlaveIDs():
573                 new_editingpanel = EditingPanel(self, self.NodeList, False)
574                 new_editingpanel.SetIndex(idx)
575                 self.NetworkNodes.AddPage(new_editingpanel, "")
576
577     def RefreshStatusBar(self):
578         if self.HelpBar:
579             window = self.NetworkNodes.GetPage(self.NetworkNodes.GetSelection())
580             selection = window.GetSelection()
581             if selection:
582                 index, subIndex = selection
583                 if self.NodeList.IsCurrentEntry(index):
584                     self.HelpBar.SetStatusText("Index: 0x%04X"%index, 0)
585                     self.HelpBar.SetStatusText("Subindex: 0x%02X"%subIndex, 1)
586                     entryinfos = self.NodeList.GetEntryInfos(index)
587                     name = entryinfos["name"]
588                     category = "Optional"
589                     if entryinfos["need"]:
590                         category = "Mandatory"
591                     struct = "VAR"
592                     number = ""
593                     if entryinfos["struct"] & OD_IdenticalIndexes:
594                         number = " possibly defined %d times"%entryinfos["nbmax"]
595                     if entryinfos["struct"] & OD_IdenticalSubindexes:
596                         struct = "REC"
597                     elif entryinfos["struct"] & OD_MultipleSubindexes:
598                         struct = "ARRAY"
599                     text = "%s: %s entry of struct %s%s."%(name,category,struct,number)
600                     self.HelpBar.SetStatusText(text, 2)
601                 else:
602                     for i in xrange(3):
603                         self.HelpBar.SetStatusText("", i)
604             else:
605                 for i in xrange(3):
606                     self.HelpBar.SetStatusText("", i)
607
608     def RefreshMainMenu(self):
609         if self.menuBar1:
610             self.NetworkMenu.Enable(wxID_NETWORKEDITNETWORKMENUITEMS3, False)
611             if self.NodeList == None:
612                 if self.Mode == "solo":
613                     self.menuBar1.EnableTop(1, False)
614                     self.menuBar1.EnableTop(2, False)
615                     self.menuBar1.EnableTop(3, False)
616                     if self.FileMenu:
617                         self.FileMenu.Enable(wxID_NETWORKEDITFILEMENUITEMS1, False)
618                         self.FileMenu.Enable(wxID_NETWORKEDITFILEMENUITEMS2, False)
619                 else:
620                     self.menuBar1.EnableTop(0, False)
621                     self.menuBar1.EnableTop(1, False)
622                     self.menuBar1.EnableTop(2, False)
623             else:
624                 if self.Mode == "solo":
625                     self.menuBar1.EnableTop(1, True)
626                     if self.FileMenu:
627                         self.FileMenu.Enable(wxID_NETWORKEDITFILEMENUITEMS1, True)
628                         self.FileMenu.Enable(wxID_NETWORKEDITFILEMENUITEMS2, False)
629                     if self.NetworkNodes.GetSelection() == 0:
630                         self.menuBar1.EnableTop(2, True)
631                         self.menuBar1.EnableTop(3, True)
632                     else:
633                         self.menuBar1.EnableTop(2, False)      
634                         self.menuBar1.EnableTop(3, False)
635                 else:
636                     self.menuBar1.EnableTop(0, True)
637                     if self.NetworkNodes.GetSelection() == 0:
638                         self.menuBar1.EnableTop(1, True)
639                         self.menuBar1.EnableTop(2, True)
640                     else:
641                         self.menuBar1.EnableTop(1, False)      
642                         self.menuBar1.EnableTop(2, False)
643
644     def RefreshProfileMenu(self):
645         if self.EditMenu:
646             profile = self.Manager.GetCurrentProfileName()
647             edititem = self.EditMenu.FindItemById(wxID_NETWORKEDITEDITMENUITEMS7)
648             if edititem:
649                 length = self.AddMenu.GetMenuItemCount()
650                 for i in xrange(length-6):
651                     additem = self.AddMenu.FindItemByPosition(6)
652                     self.AddMenu.Delete(additem.GetId())
653                 if profile not in ("None", "DS-301"):
654                     edititem.SetText("%s Profile"%profile)
655                     edititem.Enable(True)
656                     self.AddMenu.AppendSeparator()
657                     for text, indexes in self.Manager.GetCurrentSpecificMenu():
658                         new_id = wx.NewId()
659                         self.AddMenu.Append(help='', id=new_id, kind=wx.ITEM_NORMAL, text=text)
660                         self.Bind(wx.EVT_MENU, self.GetProfileCallBack(text), id=new_id)
661                 else:
662                     edititem.SetText("Other Profile")
663                     edititem.Enable(False)
664
665 #-------------------------------------------------------------------------------
666 #                              Buffer Functions
667 #-------------------------------------------------------------------------------
668
669     def RefreshBufferState(self):
670         if self.NodeList:
671             nodeID = self.Manager.GetCurrentNodeID()
672             if nodeID != None:
673                 nodename = "0x%2.2X %s"%(nodeID, self.Manager.GetCurrentNodeName())
674             else:
675                 nodename = self.Manager.GetCurrentNodeName()
676             self.NetworkNodes.SetPageText(0, nodename)
677             for idx, name in enumerate(self.NodeList.GetSlaveNames()):
678                 self.NetworkNodes.SetPageText(idx + 1, name)
679             self.RefreshTitle()
680
681     def OnUndoMenu(self, event):
682         self.Manager.LoadCurrentPrevious()
683         self.RefreshCurrentIndexList()
684         self.RefreshBufferState()
685         event.Skip()
686
687     def OnRedoMenu(self, event):
688         self.Manager.LoadCurrentNext()
689         self.RefreshCurrentIndexList()
690         self.RefreshBufferState()
691         event.Skip()
692
693 #-------------------------------------------------------------------------------
694 #                                Help Method
695 #-------------------------------------------------------------------------------
696
697     def OnHelpDS301Menu(self, event):
698         find_index = False
699         selected = self.NetworkNodes.GetSelection()
700         if selected >= 0:
701             window = self.NetworkNodes.GetPage(selected)
702             result = window.GetSelection()
703             if result:
704                 find_index = True
705                 index, subIndex = result
706                 result = OpenPDFDocIndex(index, ScriptDirectory)
707                 if type(result) == StringType:
708                     message = wxMessageDialog(self, result, "ERROR", wxOK|wxICON_ERROR)
709                     message.ShowModal()
710                     message.Destroy()
711         if not find_index:
712             result = OpenPDFDocIndex(None, ScriptDirectory)
713             if type(result) == StringType:
714                 message = wxMessageDialog(self, result, "ERROR", wxOK|wxICON_ERROR)
715                 message.ShowModal()
716                 message.Destroy()
717         event.Skip()
718         
719     def OnHelpCANFestivalMenu(self, event):
720         #self.OpenHtmlFrame("CAN Festival Reference", os.path.join(ScriptDirectory, "doc/canfestival.html"), wx.Size(1000, 600))
721         os.system("xpdf -remote CANFESTIVAL %s %d &"%(os.path.join(ScriptDirectory, "doc/manual_en.pdf"),16))
722         event.Skip()
723
724     def OnAboutMenu(self, event):
725         self.OpenHtmlFrame("About CAN Festival", os.path.join(ScriptDirectory, "doc/about.html"), wx.Size(500, 450))
726         event.Skip()
727
728     def OpenHtmlFrame(self, title, file, size):
729         if title not in self.HtmlFrameOpened:
730             self.HtmlFrameOpened.append(title)
731             window = HtmlFrame(self, self.HtmlFrameOpened)
732             window.SetTitle(title)
733             window.SetHtmlPage(file)
734             window.SetClientSize(size)
735             window.Show()
736
737 #-------------------------------------------------------------------------------
738 #                          Editing Profiles functions
739 #-------------------------------------------------------------------------------
740
741     def OnCommunicationMenu(self, event):
742         dictionary,current = self.Manager.GetCurrentCommunicationLists()
743         self.EditProfile("Edit DS-301 Profile", dictionary, current)
744         event.Skip()
745     
746     def OnOtherCommunicationMenu(self, event):
747         dictionary,current = self.Manager.GetCurrentDS302Lists()
748         self.EditProfile("Edit DS-301 Profile", dictionary, current)
749         event.Skip()
750     
751     def OnEditProfileMenu(self, event):
752         title = "Edit %s Profile"%self.Manager.GetCurrentProfileName()
753         dictionary,current = self.Manager.GetCurrentProfileLists()
754         self.EditProfile(title, dictionary, current)
755         event.Skip()
756     
757     def EditProfile(self, title, dictionary, current):
758         dialog = CommunicationDialog(self)
759         dialog.SetTitle(title)
760         dialog.SetIndexDictionary(dictionary)
761         dialog.SetCurrentList(current)
762         dialog.RefreshLists()
763         if dialog.ShowModal() == wxID_OK:
764             new_profile = dialog.GetCurrentList()
765             addinglist = []
766             removinglist = []
767             for index in new_profile:
768                 if index not in current:
769                     addinglist.append(index)
770             for index in current:
771                 if index not in new_profile:
772                     removinglist.append(index)
773             self.Manager.ManageEntriesOfCurrent(addinglist, removinglist)
774             self.Manager.GenerateMapList()
775             self.Manager.BufferCurrentNode()
776             self.RefreshBufferState()
777             self.RefreshCurrentIndexList()
778         dialog.Destroy()
779
780 #-------------------------------------------------------------------------------
781 #                         Edit Node informations function
782 #-------------------------------------------------------------------------------
783
784     def OnNodeInfosMenu(self, event):
785         dialog = NodeInfosDialog(self)
786         name, id, type, description = self.Manager.GetCurrentNodeInfos()
787         dialog.SetValues(name, id, type, description)
788         if dialog.ShowModal() == wxID_OK:
789             name, id, type, description = dialog.GetValues()
790             self.Manager.SetCurrentNodeInfos(name, id, type, description)
791             self.RefreshBufferState()
792             self.RefreshProfileMenu()
793             selected = self.FileOpened.GetSelection()
794             if selected >= 0:
795                 window = self.FileOpened.GetPage(selected)
796                 window.RefreshTable()
797         event.Skip()
798
799
800 #-------------------------------------------------------------------------------
801 #                           Add User Types and Variables
802 #-------------------------------------------------------------------------------
803         
804     def AddMapVariable(self):
805         index = self.Manager.GetCurrentNextMapIndex()
806         if index:
807             dialog = MapVariableDialog(self)
808             dialog.SetIndex(index)
809             if dialog.ShowModal() == wxID_OK:
810                 index, name, struct, number = dialog.GetValues()
811                 result = self.Manager.AddMapVariableToCurrent(index, name, struct, number)
812                 if type(result) != StringType:
813                     self.RefreshBufferState()
814                     self.RefreshCurrentIndexList()
815                 else:
816                     message = wxMessageDialog(self, result, "Error", wxOK|wxICON_ERROR)
817                     message.ShowModal()
818                     message.Destroy()
819             dialog.Destroy()
820         else:
821             message = wxMessageDialog(self, result, "No map variable index left!", wxOK|wxICON_ERROR)
822             message.ShowModal()
823             message.Destroy()
824         
825     def AddUserType(self):
826         dialog = UserTypeDialog(self)
827         dialog.SetTypeList(self.Manager.GetCustomisableTypes())
828         if dialog.ShowModal() == wxID_OK:
829             type, min, max, length = dialog.GetValues()
830             result = self.Manager.AddUserTypeToCurrent(type, min, max, length)
831             if not IsOfType(result, StringType):
832                 self.RefreshBufferState()
833                 self.RefreshCurrentIndexList()
834             else:
835                 message = wxMessageDialog(self, result, "Error", wxOK|wxICON_ERROR)
836                 message.ShowModal()
837                 message.Destroy()
838         dialog.Destroy()
839
840 #-------------------------------------------------------------------------------
841 #                               Exception Handler
842 #-------------------------------------------------------------------------------
843
844 Max_Traceback_List_Size = 20
845
846 def Display_Exception_Dialog(e_type,e_value,e_tb):
847     trcbck_lst = []
848     for i,line in enumerate(traceback.extract_tb(e_tb)):
849         trcbck = " " + str(i+1) + ". "
850         if line[0].find(os.getcwd()) == -1:
851             trcbck += "file : " + str(line[0]) + ",   "
852         else:
853             trcbck += "file : " + str(line[0][len(os.getcwd()):]) + ",   "
854         trcbck += "line : " + str(line[1]) + ",   " + "function : " + str(line[2])
855         trcbck_lst.append(trcbck)
856         
857     # Allow clicking....
858     cap = wx.Window_GetCapture()
859     if cap:
860         cap.ReleaseMouse()
861
862     dlg = wx.SingleChoiceDialog(None, 
863         """
864 An error happens.
865
866 Click on OK for saving an error report.
867
868 Please contact LOLITech at:
869 +33 (0)3 29 52 95 67
870 bugs_networkedit@lolitech.fr
871
872
873 Error:
874 """ +
875         str(e_type) + " : " + str(e_value), 
876         "Error",
877         trcbck_lst)
878     try:
879         res = (dlg.ShowModal() == wx.ID_OK)
880     finally:
881         dlg.Destroy()
882
883     return res
884
885 def Display_Error_Dialog(e_value):
886     message = wxMessageDialog(None, str(e_value), "Error", wxOK|wxICON_ERROR)
887     message.ShowModal()
888     message.Destroy()
889
890 def get_last_traceback(tb):
891     while tb.tb_next:
892         tb = tb.tb_next
893     return tb
894
895
896 def format_namespace(d, indent='    '):
897     return '\n'.join(['%s%s: %s' % (indent, k, repr(v)[:10000]) for k, v in d.iteritems()])
898
899
900 ignored_exceptions = [] # a problem with a line in a module is only reported once per session
901
902 def wxAddExceptHook(path, app_version='[No version]'):#, ignored_exceptions=[]):
903     
904     def handle_exception(e_type, e_value, e_traceback):
905         traceback.print_exception(e_type, e_value, e_traceback) # this is very helpful when there's an exception in the rest of this func
906         last_tb = get_last_traceback(e_traceback)
907         ex = (last_tb.tb_frame.f_code.co_filename, last_tb.tb_frame.f_lineno)
908         if str(e_value).startswith("!!!"):
909             Display_Error_Dialog(e_value)
910         elif ex not in ignored_exceptions:
911             ignored_exceptions.append(ex)
912             result = Display_Exception_Dialog(e_type,e_value,e_traceback)
913             if result:
914                 info = {
915                     'app-title' : wx.GetApp().GetAppName(), # app_title
916                     'app-version' : app_version,
917                     'wx-version' : wx.VERSION_STRING,
918                     'wx-platform' : wx.Platform,
919                     'python-version' : platform.python_version(), #sys.version.split()[0],
920                     'platform' : platform.platform(),
921                     'e-type' : e_type,
922                     'e-value' : e_value,
923                     'date' : time.ctime(),
924                     'cwd' : os.getcwd(),
925                     }
926                 if e_traceback:
927                     info['traceback'] = ''.join(traceback.format_tb(e_traceback)) + '%s: %s' % (e_type, e_value)
928                     last_tb = get_last_traceback(e_traceback)
929                     exception_locals = last_tb.tb_frame.f_locals # the locals at the level of the stack trace where the exception actually occurred
930                     info['locals'] = format_namespace(exception_locals)
931                     if 'self' in exception_locals:
932                         info['self'] = format_namespace(exception_locals['self'].__dict__)
933                 
934                 output = open(path+os.sep+"bug_report_"+info['date'].replace(':','-').replace(' ','_')+".txt",'w')
935                 lst = info.keys()
936                 lst.sort()
937                 for a in lst:
938                     output.write(a+":\n"+str(info[a])+"\n\n")
939
940     #sys.excepthook = lambda *args: wx.CallAfter(handle_exception, *args)
941     sys.excepthook = handle_exception
942
943 if __name__ == '__main__':
944     app = wxPySimpleApp()
945     wxInitAllImageHandlers()
946     
947     # Install a exception handle for bug reports
948     wxAddExceptHook(os.getcwd(),__version__)
949     
950     frame = networkedit(None)
951
952     frame.Show()
953     app.MainLoop()