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