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