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