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