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