Laurent@814: #!/usr/bin/env python Laurent@814: # -*- coding: utf-8 -*- Laurent@814: andrej@1571: # This file is part of Beremiz, a Integrated Development Environment for andrej@1571: # programming IEC 61131-3 automates supporting plcopen standard and CanFestival. Laurent@814: # andrej@1571: # Copyright (C) 2007: Edouard TISSERANT and Laurent BESSARD andrej@1680: # Copyright (C) 2017: Andrey Skvortsov Laurent@814: # andrej@1571: # See COPYING file for copyrights details. Laurent@814: # andrej@1571: # This program is free software; you can redistribute it and/or andrej@1571: # modify it under the terms of the GNU General Public License andrej@1571: # as published by the Free Software Foundation; either version 2 andrej@1571: # of the License, or (at your option) any later version. Laurent@814: # andrej@1571: # This program is distributed in the hope that it will be useful, andrej@1571: # but WITHOUT ANY WARRANTY; without even the implied warranty of andrej@1571: # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the andrej@1571: # GNU General Public License for more details. Laurent@814: # andrej@1571: # You should have received a copy of the GNU General Public License andrej@1571: # along with this program; if not, write to the Free Software andrej@1571: # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Laurent@814: andrej@1826: kinsamanka@3750: kinsamanka@3750: andrej@1732: import os andrej@1732: import sys andrej@1732: import getopt andrej@1792: andrej@1832: import wx edouard@3570: import wx.adv andrej@1832: andrej@1560: import version andrej@1680: import util.paths as paths andrej@1792: import util.ExceptionHandler andrej@1834: from util.misc import InstallLocalRessources andrej@1814: from IDEFrame import IDEFrame, AppendMenu andrej@1814: from IDEFrame import \ andrej@1814: TITLE, \ andrej@1814: EDITORTOOLBAR, \ andrej@1814: FILEMENU, \ andrej@1814: EDITMENU, \ andrej@1814: DISPLAYMENU, \ andrej@1814: PROJECTTREE, \ andrej@1814: POUINSTANCEVARIABLESPANEL, \ andrej@1814: LIBRARYTREE, \ andrej@1850: PAGETITLES, \ andrej@1850: DecodeFileSystemPath andrej@1814: from editors.Viewer import Viewer andrej@1814: from PLCControler import PLCControler andrej@1814: from dialogs import ProjectDialog andrej@1814: from dialogs.AboutDialog import ShowAboutDialog andrej@1791: Laurent@814: andrej@1782: # ------------------------------------------------------------------------------- Laurent@814: # PLCOpenEditor Main Class andrej@1782: # ------------------------------------------------------------------------------- Laurent@814: Laurent@814: # Define PLCOpenEditor FileMenu extra items id andrej@1773: [ andrej@1773: ID_PLCOPENEDITORFILEMENUGENERATE, schlumpf@2532: ID_PLCOPENEDITORFILEMENUGENERATEAS, kinsamanka@3766: ] = [wx.NewIdRef() for _init_coll_FileMenu_Items in range(2)] Laurent@814: andrej@1736: andrej@1814: beremiz_dir = paths.AbsDir(__file__) andrej@1814: andrej@1814: Laurent@814: class PLCOpenEditor(IDEFrame): Laurent@814: Laurent@814: def _init_coll_FileMenu_Items(self, parent): Laurent@814: AppendMenu(parent, help='', id=wx.ID_NEW, kinsamanka@3750: kind=wx.ITEM_NORMAL, text=_('New') + '\tCTRL+N') Laurent@814: AppendMenu(parent, help='', id=wx.ID_OPEN, kinsamanka@3750: kind=wx.ITEM_NORMAL, text=_('Open') + '\tCTRL+O') Laurent@814: AppendMenu(parent, help='', id=wx.ID_CLOSE, kinsamanka@3750: kind=wx.ITEM_NORMAL, text=_('Close Tab') + '\tCTRL+W') Laurent@814: AppendMenu(parent, help='', id=wx.ID_CLOSE_ALL, kinsamanka@3750: kind=wx.ITEM_NORMAL, text=_('Close Project') + '\tCTRL+SHIFT+W') Laurent@814: parent.AppendSeparator() Laurent@814: AppendMenu(parent, help='', id=wx.ID_SAVE, kinsamanka@3750: kind=wx.ITEM_NORMAL, text=_('Save') + '\tCTRL+S') Laurent@814: AppendMenu(parent, help='', id=wx.ID_SAVEAS, kinsamanka@3750: kind=wx.ITEM_NORMAL, text=_('Save As...') + '\tCTRL+SHIFT+S') Laurent@814: AppendMenu(parent, help='', id=ID_PLCOPENEDITORFILEMENUGENERATE, kinsamanka@3750: kind=wx.ITEM_NORMAL, text=_('Generate Program') + '\tCTRL+G') schlumpf@2532: AppendMenu(parent, help='', id=ID_PLCOPENEDITORFILEMENUGENERATEAS, kinsamanka@3750: kind=wx.ITEM_NORMAL, text=_('Generate Program As...') + '\tCTRL+SHIFT+G') Laurent@814: parent.AppendSeparator() Laurent@814: AppendMenu(parent, help='', id=wx.ID_PAGE_SETUP, kinsamanka@3750: kind=wx.ITEM_NORMAL, text=_('Page Setup') + '\tCTRL+ALT+P') Laurent@814: AppendMenu(parent, help='', id=wx.ID_PREVIEW, kinsamanka@3750: kind=wx.ITEM_NORMAL, text=_('Preview') + '\tCTRL+SHIFT+P') Laurent@814: AppendMenu(parent, help='', id=wx.ID_PRINT, kinsamanka@3750: kind=wx.ITEM_NORMAL, text=_('Print') + '\tCTRL+P') Laurent@814: parent.AppendSeparator() Laurent@814: AppendMenu(parent, help='', id=wx.ID_PROPERTIES, kinsamanka@3750: kind=wx.ITEM_NORMAL, text=_('&Properties')) Laurent@814: parent.AppendSeparator() Laurent@814: AppendMenu(parent, help='', id=wx.ID_EXIT, kinsamanka@3750: kind=wx.ITEM_NORMAL, text=_('Quit') + '\tCTRL+Q') Edouard@1451: Laurent@814: self.Bind(wx.EVT_MENU, self.OnNewProjectMenu, id=wx.ID_NEW) Laurent@814: self.Bind(wx.EVT_MENU, self.OnOpenProjectMenu, id=wx.ID_OPEN) Laurent@814: self.Bind(wx.EVT_MENU, self.OnCloseTabMenu, id=wx.ID_CLOSE) Laurent@814: self.Bind(wx.EVT_MENU, self.OnCloseProjectMenu, id=wx.ID_CLOSE_ALL) Laurent@814: self.Bind(wx.EVT_MENU, self.OnSaveProjectMenu, id=wx.ID_SAVE) Laurent@814: self.Bind(wx.EVT_MENU, self.OnSaveProjectAsMenu, id=wx.ID_SAVEAS) Laurent@814: self.Bind(wx.EVT_MENU, self.OnGenerateProgramMenu, andrej@1768: id=ID_PLCOPENEDITORFILEMENUGENERATE) schlumpf@2532: self.Bind(wx.EVT_MENU, self.OnGenerateProgramAsMenu, schlumpf@2532: id=ID_PLCOPENEDITORFILEMENUGENERATEAS) Laurent@814: self.Bind(wx.EVT_MENU, self.OnPageSetupMenu, id=wx.ID_PAGE_SETUP) Laurent@814: self.Bind(wx.EVT_MENU, self.OnPreviewMenu, id=wx.ID_PREVIEW) Laurent@814: self.Bind(wx.EVT_MENU, self.OnPrintMenu, id=wx.ID_PRINT) Laurent@814: self.Bind(wx.EVT_MENU, self.OnPropertiesMenu, id=wx.ID_PROPERTIES) Laurent@814: self.Bind(wx.EVT_MENU, self.OnQuitMenu, id=wx.ID_EXIT) Edouard@1451: kinsamanka@3750: self.AddToMenuToolBar([(wx.ID_NEW, "new", _('New'), None), kinsamanka@3750: (wx.ID_OPEN, "open", _('Open'), None), kinsamanka@3750: (wx.ID_SAVE, "save", _('Save'), None), kinsamanka@3750: (wx.ID_SAVEAS, "saveas", _('Save As...'), None), kinsamanka@3750: (wx.ID_PRINT, "print", _('Print'), None), kinsamanka@3750: (ID_PLCOPENEDITORFILEMENUGENERATE, "Build", _('Generate Program'), None)]) Edouard@1451: Laurent@814: def _init_coll_HelpMenu_Items(self, parent): andrej@1762: def handler(event): andrej@1762: return wx.MessageBox( andrej@1762: version.GetCommunityHelpMsg(), kinsamanka@3750: _('Community support'), andrej@1762: wx.OK | wx.ICON_INFORMATION) andrej@1762: edouard@4057: menu_entry = parent.Append(wx.ID_ANY, _('Community support'), '') Edouard@2737: self.Bind(wx.EVT_MENU, handler, menu_entry) andrej@1730: edouard@4057: parent.Append(wx.MenuItem(helpString='', id=wx.ID_ABOUT, edouard@4057: kind=wx.ITEM_NORMAL, text=_('About'))) Laurent@814: self.Bind(wx.EVT_MENU, self.OnAboutMenu, id=wx.ID_ABOUT) Laurent@814: andrej@1744: def __init__(self, parent, fileOpen=None): andrej@1781: """ Constructor of the PLCOpenEditor class. andrej@1781: andrej@1781: :param parent: The parent window. andrej@1781: :param fileOpen: The filepath to open if no controler defined (default: None). andrej@1781: """ andrej@1533: self.icon = wx.Icon(os.path.join(beremiz_dir, "images", "poe.ico"), wx.BITMAP_TYPE_ICO) Laurent@814: IDEFrame.__init__(self, parent) Edouard@1451: Laurent@814: result = None Edouard@1451: Laurent@814: # Open the filepath if defined Laurent@814: if fileOpen is not None: Laurent@814: fileOpen = DecodeFileSystemPath(fileOpen, False) Laurent@814: if os.path.isfile(fileOpen): Laurent@814: # Create a new controller Laurent@814: controler = PLCControler() Laurent@814: result = controler.OpenXMLFile(fileOpen) Laurent@1330: self.Controler = controler Laurent@1330: self.LibraryPanel.SetController(controler) Laurent@1330: self.ProjectTree.Enable(True) Laurent@1330: self.PouInstanceVariablesPanel.SetController(controler) Laurent@1330: self._Refresh(PROJECTTREE, POUINSTANCEVARIABLESPANEL, LIBRARYTREE) Edouard@1451: Laurent@814: # Define PLCOpenEditor icon andrej@1533: self.SetIcon(self.icon) Laurent@814: Laurent@814: self.Bind(wx.EVT_CLOSE, self.OnCloseFrame) Edouard@1451: Laurent@814: self._Refresh(TITLE, EDITORTOOLBAR, FILEMENU, EDITMENU, DISPLAYMENU) Edouard@1451: Laurent@814: if result is not None: andrej@1581: (num, line) = result andrej@1744: self.ShowErrorMessage(_("PLC syntax error at line {a1}:\n{a2}").format(a1=num, a2=line)) Laurent@814: Laurent@814: def OnCloseFrame(self, event): Laurent@814: if self.Controler is None or self.CheckSaveBeforeClosing(_("Close Application")): Laurent@814: self.AUIManager.UnInit() Edouard@1451: Laurent@814: self.SaveLastState() Edouard@1451: Laurent@814: event.Skip() Laurent@814: else: Laurent@814: event.Veto() Laurent@814: Laurent@814: def RefreshTitle(self): Laurent@814: name = _("PLCOpenEditor") Laurent@814: if self.Controler is not None: andrej@1734: self.SetTitle("%s - %s" % (name, self.Controler.GetFilename())) Laurent@814: else: Laurent@814: self.SetTitle(name) Laurent@814: andrej@1782: # ------------------------------------------------------------------------------- andrej@1782: # File Menu Functions andrej@1782: # ------------------------------------------------------------------------------- Laurent@814: Laurent@814: def RefreshFileMenu(self): Laurent@814: MenuToolBar = self.Panes["MenuToolBar"] Laurent@814: if self.Controler is not None: Laurent@814: selected = self.TabsOpened.GetSelection() Laurent@814: if selected >= 0: Laurent@814: graphic_viewer = isinstance(self.TabsOpened.GetPage(selected), Viewer) Laurent@814: else: Laurent@814: graphic_viewer = False Laurent@814: if self.TabsOpened.GetPageCount() > 0: Laurent@814: self.FileMenu.Enable(wx.ID_CLOSE, True) Laurent@814: if graphic_viewer: Laurent@814: self.FileMenu.Enable(wx.ID_PREVIEW, True) Laurent@814: self.FileMenu.Enable(wx.ID_PRINT, True) Laurent@814: MenuToolBar.EnableTool(wx.ID_PRINT, True) Laurent@814: else: Laurent@814: self.FileMenu.Enable(wx.ID_PREVIEW, False) Laurent@814: self.FileMenu.Enable(wx.ID_PRINT, False) Laurent@814: MenuToolBar.EnableTool(wx.ID_PRINT, False) Laurent@814: else: Laurent@814: self.FileMenu.Enable(wx.ID_CLOSE, False) Laurent@814: self.FileMenu.Enable(wx.ID_PREVIEW, False) Laurent@814: self.FileMenu.Enable(wx.ID_PRINT, False) Laurent@814: MenuToolBar.EnableTool(wx.ID_PRINT, False) Laurent@814: self.FileMenu.Enable(wx.ID_PAGE_SETUP, True) Laurent@814: project_modified = not self.Controler.ProjectIsSaved() Laurent@814: self.FileMenu.Enable(wx.ID_SAVE, project_modified) Laurent@814: MenuToolBar.EnableTool(wx.ID_SAVE, project_modified) Laurent@814: self.FileMenu.Enable(wx.ID_PROPERTIES, True) Laurent@814: self.FileMenu.Enable(wx.ID_CLOSE_ALL, True) Laurent@814: self.FileMenu.Enable(wx.ID_SAVEAS, True) Laurent@814: MenuToolBar.EnableTool(wx.ID_SAVEAS, True) Laurent@814: self.FileMenu.Enable(ID_PLCOPENEDITORFILEMENUGENERATE, True) schlumpf@2531: MenuToolBar.EnableTool(ID_PLCOPENEDITORFILEMENUGENERATE, True) schlumpf@2532: self.FileMenu.Enable(ID_PLCOPENEDITORFILEMENUGENERATEAS, True) Laurent@814: else: Laurent@814: self.FileMenu.Enable(wx.ID_CLOSE, False) Laurent@814: self.FileMenu.Enable(wx.ID_PAGE_SETUP, False) Laurent@814: self.FileMenu.Enable(wx.ID_PREVIEW, False) Laurent@814: self.FileMenu.Enable(wx.ID_PRINT, False) Laurent@814: MenuToolBar.EnableTool(wx.ID_PRINT, False) Laurent@814: self.FileMenu.Enable(wx.ID_SAVE, False) Laurent@814: MenuToolBar.EnableTool(wx.ID_SAVE, False) Laurent@814: self.FileMenu.Enable(wx.ID_PROPERTIES, False) Laurent@814: self.FileMenu.Enable(wx.ID_CLOSE_ALL, False) Laurent@814: self.FileMenu.Enable(wx.ID_SAVEAS, False) Laurent@814: MenuToolBar.EnableTool(wx.ID_SAVEAS, False) Laurent@814: self.FileMenu.Enable(ID_PLCOPENEDITORFILEMENUGENERATE, False) schlumpf@2531: MenuToolBar.EnableTool(ID_PLCOPENEDITORFILEMENUGENERATE, False) schlumpf@2532: self.FileMenu.Enable(ID_PLCOPENEDITORFILEMENUGENERATEAS, False) Laurent@814: Laurent@814: def OnNewProjectMenu(self, event): Laurent@814: if self.Controler is not None and not self.CheckSaveBeforeClosing(): Laurent@814: return Laurent@814: dialog = ProjectDialog(self) Laurent@814: if dialog.ShowModal() == wx.ID_OK: Laurent@814: properties = dialog.GetValues() Laurent@814: self.ResetView() Laurent@814: self.Controler = PLCControler() Laurent@814: self.Controler.CreateNewProject(properties) Laurent@814: self.LibraryPanel.SetController(self.Controler) Laurent@1295: self.ProjectTree.Enable(True) Edouard@1451: self._Refresh(TITLE, FILEMENU, EDITMENU, PROJECTTREE, POUINSTANCEVARIABLESPANEL, Laurent@814: LIBRARYTREE) Laurent@814: Laurent@814: def OnOpenProjectMenu(self, event): Laurent@814: if self.Controler is not None and not self.CheckSaveBeforeClosing(): Laurent@814: return Laurent@814: filepath = "" Laurent@814: if self.Controler is not None: Laurent@814: filepath = self.Controler.GetFilePath() Laurent@814: if filepath != "": Laurent@814: directory = os.path.dirname(filepath) Laurent@814: else: Laurent@814: directory = os.getcwd() Edouard@1451: Laurent@814: result = None Edouard@1451: edouard@4064: dialog = wx.FileDialog(self, _("Choose a file"), directory, "", _("PLCOpen files (*.xml)|*.xml|All files|*.*"), wx.FD_OPEN) Laurent@814: if dialog.ShowModal() == wx.ID_OK: Laurent@814: filepath = dialog.GetPath() Laurent@814: if os.path.isfile(filepath): Laurent@814: self.ResetView() Laurent@814: controler = PLCControler() Laurent@814: result = controler.OpenXMLFile(filepath) Laurent@1330: self.Controler = controler Laurent@1330: self.LibraryPanel.SetController(controler) Laurent@1330: self.ProjectTree.Enable(True) Laurent@1330: self.PouInstanceVariablesPanel.SetController(controler) Laurent@1330: self._Refresh(PROJECTTREE, LIBRARYTREE) Laurent@814: self._Refresh(TITLE, EDITORTOOLBAR, FILEMENU, EDITMENU) Laurent@814: dialog.Destroy() Edouard@1451: Laurent@814: if result is not None: andrej@1581: (num, line) = result andrej@1744: self.ShowErrorMessage(_("PLC syntax error at line {a1}:\n{a2}").format(a1=num, a2=line)) Edouard@1451: Laurent@814: def OnCloseProjectMenu(self, event): Laurent@814: if not self.CheckSaveBeforeClosing(): Laurent@814: return Laurent@814: self.ResetView() Laurent@814: self._Refresh(TITLE, EDITORTOOLBAR, FILEMENU, EDITMENU) Laurent@814: Laurent@814: def OnSaveProjectMenu(self, event): Laurent@814: self.SaveProject() Laurent@814: Laurent@814: def OnSaveProjectAsMenu(self, event): Laurent@814: self.SaveProjectAs() Laurent@814: Laurent@814: def OnGenerateProgramMenu(self, event): schlumpf@2532: result = self.Controler.GetProgramFilePath() schlumpf@2532: if not result: schlumpf@2532: self.GenerateProgramAs() schlumpf@2532: else: schlumpf@2532: self.GenerateProgram(result) schlumpf@2532: schlumpf@2532: def OnGenerateProgramAsMenu(self, event): schlumpf@2532: self.GenerateProgramAs() schlumpf@2532: schlumpf@2532: def GenerateProgramAs(self): schlumpf@2497: dialog = wx.FileDialog(self, _("Choose a file"), os.getcwd(), os.path.basename(self.Controler.GetProgramFilePath()), _("ST files (*.st)|*.st|All files|*.*"), wx.SAVE | wx.CHANGE_DIR) Laurent@814: if dialog.ShowModal() == wx.ID_OK: schlumpf@2532: self.GenerateProgram(dialog.GetPath()) schlumpf@2532: dialog.Destroy() schlumpf@2532: schlumpf@2532: def GenerateProgram(self, filepath=None): schlumpf@2532: message_text = "" schlumpf@2532: header, icon = _("Done"), wx.ICON_INFORMATION schlumpf@2532: if os.path.isdir(os.path.dirname(filepath)): schlumpf@2532: _program, errors, warnings = self.Controler.GenerateProgram(filepath) schlumpf@2532: message_text += "".join([_("warning: %s\n") % warning for warning in warnings]) schlumpf@2532: if len(errors) > 0: schlumpf@2532: message_text += "".join([_("error: %s\n") % error for error in errors]) schlumpf@2532: message_text += _("Can't generate program to file %s!") % filepath schlumpf@2532: header, icon = _("Error"), wx.ICON_ERROR Laurent@814: else: schlumpf@2532: message_text += _("Program was successfully generated!") schlumpf@2532: else: schlumpf@2532: message_text += _("\"%s\" is not a valid folder!") % os.path.dirname(filepath) schlumpf@2532: header, icon = _("Error"), wx.ICON_ERROR schlumpf@2532: message = wx.MessageDialog(self, message_text, header, wx.OK | icon) schlumpf@2532: message.ShowModal() schlumpf@2532: message.Destroy() Laurent@814: Laurent@814: def OnAboutMenu(self, event): edouard@3570: info = wx.adv.AboutDialogInfo() edouard@3906: info = version.GetAboutDialogInfo(info) andrej@1565: info.Name = "PLCOpenEditor" andrej@1565: info.Description = _("PLCOpenEditor is part of Beremiz project.\n\n" andrej@1565: "Beremiz is an ") + info.Description andrej@1565: info.Icon = wx.Icon(os.path.join(beremiz_dir, "images", "aboutlogo.png"), wx.BITMAP_TYPE_PNG) andrej@1565: ShowAboutDialog(self, info) Laurent@814: Laurent@814: def SaveProject(self): Laurent@814: result = self.Controler.SaveXMLFile() Laurent@814: if not result: Laurent@814: self.SaveProjectAs() Laurent@814: else: Laurent@814: self._Refresh(TITLE, FILEMENU, PAGETITLES) Edouard@1451: Laurent@814: def SaveProjectAs(self): Laurent@814: filepath = self.Controler.GetFilePath() Laurent@814: if filepath != "": Laurent@814: directory, filename = os.path.split(filepath) Laurent@814: else: andrej@1734: directory, filename = os.getcwd(), "%(projectName)s.xml" % self.Controler.GetProjectProperties() andrej@1745: dialog = wx.FileDialog(self, _("Choose a file"), directory, filename, _("PLCOpen files (*.xml)|*.xml|All files|*.*"), wx.SAVE | wx.OVERWRITE_PROMPT) Laurent@814: if dialog.ShowModal() == wx.ID_OK: Laurent@814: filepath = dialog.GetPath() Laurent@814: if os.path.isdir(os.path.dirname(filepath)): Laurent@814: result = self.Controler.SaveXMLFile(filepath) Laurent@814: if not result: andrej@1734: self.ShowErrorMessage(_("Can't save project to file %s!") % filepath) Laurent@814: else: andrej@1734: self.ShowErrorMessage(_("\"%s\" is not a valid folder!") % os.path.dirname(filepath)) Laurent@814: self._Refresh(TITLE, FILEMENU, PAGETITLES) Laurent@814: dialog.Destroy() Laurent@814: andrej@1749: andrej@1814: class PLCOpenEditorApp(wx.App): andrej@1814: # def SetOpenFile( andrej@1814: andrej@1814: def PrintUsage(self): andrej@1826: print("\nUsage of PLCOpenEditor.py :") andrej@1826: print("\n %s [Filepath]\n" % sys.argv[0]) andrej@1814: andrej@1814: def ParseCommandLine(self): andrej@1814: # Parse options given to PLCOpenEditor in command line andrej@1814: try: andrej@1814: opts, args = getopt.getopt(sys.argv[1:], "h", ["help"]) andrej@1814: except getopt.GetoptError: andrej@1814: # print help information and exit: andrej@1814: self.PrintUsage() andrej@1814: sys.exit(2) andrej@1814: andrej@1814: # Extract if help has been requested andrej@1847: for o, _a in opts: andrej@1814: if o in ("-h", "--help"): andrej@1814: self.PrintUsage() andrej@1814: sys.exit() andrej@1814: andrej@1814: # Extract the optional filename to open andrej@1814: self.fileOpen = None andrej@1814: if len(args) > 1: andrej@1814: self.PrintUsage() andrej@1814: sys.exit() andrej@1814: elif len(args) == 1: andrej@1814: self.fileOpen = args[0] andrej@1814: andrej@1814: def OnInit(self): andrej@1815: self.SetAppName('plcopeneditor') andrej@1814: self.ParseCommandLine() andrej@1814: InstallLocalRessources(beremiz_dir) andrej@1814: util.ExceptionHandler.AddExceptHook(version.app_version) andrej@1814: self.frame = PLCOpenEditor(None, fileOpen=self.fileOpen) andrej@1814: return True andrej@1814: andrej@1814: def Show(self): andrej@1814: self.frame.Show() andrej@1814: andrej@1814: Laurent@814: if __name__ == '__main__': andrej@1814: app = PLCOpenEditorApp() andrej@1814: app.Show() Laurent@814: app.MainLoop()