diff -r 000000000000 -r b622defdfd98 PLCOpenEditor.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/PLCOpenEditor.py Wed Jan 31 16:31:39 2007 +0100 @@ -0,0 +1,2216 @@ +#Boa:Frame:PLCOpenEditor +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +#This file is part of PLCOpenEditor, a library implementing an IEC 61131-3 editor +#based on the plcopen standard. +# +#Copyright (C): Edouard TISSERANT and Laurent BESSARD +# +#See COPYING file for copyrights details. +# +#This library is free software; you can redistribute it and/or +#modify it under the terms of the GNU Lesser General Public +#License as published by the Free Software Foundation; either +#version 2.1 of the License, or (at your option) any later version. +# +#This library is distributed in the hope that it will be useful, +#but WITHOUT ANY WARRANTY; without even the implied warranty of +#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +#Lesser General Public License for more details. +# +#You should have received a copy of the GNU Lesser General Public +#License along with this library; if not, write to the Free Software +#Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +from wxPython.wx import * +from wxPython.grid import * +from time import localtime +from datetime import datetime +import wx + +from SFCViewer import * +from FBDViewer import * +from LDViewer import * +from Viewer import * +from PLCControler import * +from plcopen import OpenPDFDoc +from plcopen.structures import * + +import os, re, platform, sys, time, traceback, getopt + +__version__ = "$Revision$" + +def create(parent): + return PLCOpenEditor(parent) + +def usage(): + print "\nUsage of PLCOpenEditor.py :" + print "\n %s [Filepath]\n"%sys.argv[0] + +try: + opts, args = getopt.getopt(sys.argv[1:], "h", ["help"]) +except getopt.GetoptError: + # print help information and exit: + usage() + sys.exit(2) + +for o, a in opts: + if o in ("-h", "--help"): + usage() + sys.exit() + +fileOpen = None +if len(args) > 1: + usage() + sys.exit() +elif len(args) == 1: + fileOpen = args[0] + + +# Test if identifier is valid +def TestIdentifier(identifier): + if identifier[0].isdigit(): + return False + words = identifier.split('_') + for i, word in enumerate(words): + if len(word) == 0 and i != 0: + return False + if len(word) != 0 and not word.isalnum(): + return False + return True + +[wxID_PLCOPENEDITOR, wxID_PLCOPENEDITORPROJECTTREE, + wxID_PLCOPENEDITORSPLITTERWINDOW1, wxID_PLCOPENEDITORTABSOPENED, + wxID_PLCOPENEDITORDEFAULTTOOLBAR, wxID_PLCOPENEDITORSFCTOOLBAR, + wxID_PLCOPENEDITORFBDTOOLBAR, wxID_PLCOPENEDITORLDTOOLBAR, +] = [wx.NewId() for _init_ctrls in range(8)] + +[wxID_PLCOPENEDITORDEFAULTTOOLBARITEMS0, +] = [wx.NewId() for _init_coll_DefaultToolBar_Items in range(1)] + +[wxID_PLCOPENEDITORSFCTOOLBARITEMS0, wxID_PLCOPENEDITORSFCTOOLBARITEMS1, + wxID_PLCOPENEDITORSFCTOOLBARITEMS2, wxID_PLCOPENEDITORSFCTOOLBARITEMS3, + wxID_PLCOPENEDITORSFCTOOLBARITEMS4, wxID_PLCOPENEDITORSFCTOOLBARITEMS5, + wxID_PLCOPENEDITORSFCTOOLBARITEMS6, +] = [wx.NewId() for _init_coll_SFCToolBar_Items in range(7)] + +[wxID_PLCOPENEDITORFBDTOOLBARITEMS0, wxID_PLCOPENEDITORFBDTOOLBARITEMS1, + wxID_PLCOPENEDITORFBDTOOLBARITEMS2, wxID_PLCOPENEDITORFBDTOOLBARITEMS3, + wxID_PLCOPENEDITORFBDTOOLBARITEMS4, wxID_PLCOPENEDITORFBDTOOLBARITEMS5, +] = [wx.NewId() for _init_coll_FBDToolBar_Items in range(6)] + +[wxID_PLCOPENEDITORLDTOOLBARITEMS0, wxID_PLCOPENEDITORLDTOOLBARITEMS1, + wxID_PLCOPENEDITORLDTOOLBARITEMS2, wxID_PLCOPENEDITORLDTOOLBARITEMS3, + wxID_PLCOPENEDITORLDTOOLBARITEMS4, +] = [wx.NewId() for _init_coll_LDToolBar_Items in range(5)] + +[wxID_PLCOPENEDITORFILEMENUITEMS0, wxID_PLCOPENEDITORFILEMENUITEMS1, + wxID_PLCOPENEDITORFILEMENUITEMS2, wxID_PLCOPENEDITORFILEMENUITEMS3, + wxID_PLCOPENEDITORFILEMENUITEMS5, wxID_PLCOPENEDITORFILEMENUITEMS6, + wxID_PLCOPENEDITORFILEMENUITEMS7, wxID_PLCOPENEDITORFILEMENUITEMS9, + wxID_PLCOPENEDITORFILEMENUITEMS11, +] = [wx.NewId() for _init_coll_FileMenu_Items in range(9)] + +[wxID_PLCOPENEDITORHELPMENUITEMS0, wxID_PLCOPENEDITORHELPMENUITEMS1, + wxID_PLCOPENEDITORHELPMENUITEMS2, wxID_PLCOPENEDITORHELPMENUITEMS3, +] = [wx.NewId() for _init_coll_HelpMenu_Items in range(4)] + +[wxID_PLCOPENEDITORSFCMENUITEMS0, wxID_PLCOPENEDITORSFCMENUITEMS1, + wxID_PLCOPENEDITORSFCMENUITEMS2, wxID_PLCOPENEDITORSFCMENUITEMS3, +] = [wx.NewId() for _init_coll_HelpMenu_Items in range(4)] + +[wxID_PLCOPENEDITORCONFIGMENUITEMS0, wxID_PLCOPENEDITORCONFIGMENUITEMS1, +] = [wx.NewId() for _init_coll_HelpMenu_Items in range(2)] + +[wxID_PLCOPENEDITOREDITMENUITEMS0, wxID_PLCOPENEDITOREDITMENUITEMS1, + wxID_PLCOPENEDITOREDITMENUITEMS11, wxID_PLCOPENEDITOREDITMENUITEMS12, + wxID_PLCOPENEDITOREDITMENUITEMS2, wxID_PLCOPENEDITOREDITMENUITEMS4, + wxID_PLCOPENEDITOREDITMENUITEMS5, wxID_PLCOPENEDITOREDITMENUITEMS6, + wxID_PLCOPENEDITOREDITMENUITEMS8, wxID_PLCOPENEDITOREDITMENUITEMS9, +] = [wx.NewId() for _init_coll_EditMenu_Items in range(10)] + +[wxID_PLCOPENEDITORSFCMENUITEMS0, wxID_PLCOPENEDITORSFCMENUITEMS1, + wxID_PLCOPENEDITORSFCMENUITEMS2, wxID_PLCOPENEDITORSFCMENUITEMS3, +] = [wx.NewId() for _init_coll_SFCMenu_Items in range(4)] + +[wxID_PLCOPENEDITORCONFIGMENUITEMS0, wxID_PLCOPENEDITORCONFIGMENUITEMS1, +] = [wx.NewId() for _init_coll_ConfigMenu_Items in range(2)] + +class PLCOpenEditor(wx.Frame): + _custom_classes = {'wx.SashWindow' : ['Viewer']} + + def _init_coll_EditMenu_Items(self, parent): + # generated method, don't edit + + parent.Append(help='', id=wxID_PLCOPENEDITOREDITMENUITEMS0, + kind=wx.ITEM_NORMAL, text=u'Refresh\tCTRL+R') + parent.Append(help='', id=wxID_PLCOPENEDITOREDITMENUITEMS1, + kind=wx.ITEM_NORMAL, text=u'Undo\tCTRL+Z') + parent.Append(help='', id=wxID_PLCOPENEDITOREDITMENUITEMS2, + kind=wx.ITEM_NORMAL, text=u'Redo\tCTRL+Y') + parent.AppendSeparator() + parent.Append(help='', id=wxID_PLCOPENEDITOREDITMENUITEMS4, + kind=wx.ITEM_NORMAL, text=u'Cut\tCTRL+X') + parent.Append(help='', id=wxID_PLCOPENEDITOREDITMENUITEMS5, + kind=wx.ITEM_NORMAL, text=u'Copy\tCTRL+C') + parent.Append(help='', id=wxID_PLCOPENEDITOREDITMENUITEMS6, + kind=wx.ITEM_NORMAL, text=u'Paste\tCTRL+V') + parent.AppendSeparator() + parent.Append(help='', id=wxID_PLCOPENEDITOREDITMENUITEMS8, + kind=wx.ITEM_NORMAL, text=u'Add POU') + parent.Append(help='', id=wxID_PLCOPENEDITOREDITMENUITEMS9, + kind=wx.ITEM_NORMAL, text=u'Remove POU') + parent.AppendSeparator() + parent.Append(help='', id=wxID_PLCOPENEDITOREDITMENUITEMS11, + kind=wx.ITEM_NORMAL, text=u'Add Configuration') + parent.Append(help='', id=wxID_PLCOPENEDITOREDITMENUITEMS12, + kind=wx.ITEM_NORMAL, text=u'Remove Configuration') + self.Bind(wx.EVT_MENU, self.OnRefreshMenu, + id=wxID_PLCOPENEDITOREDITMENUITEMS0) + self.Bind(wx.EVT_MENU, self.OnCutMenu, + id=wxID_PLCOPENEDITOREDITMENUITEMS4) + self.Bind(wx.EVT_MENU, self.OnCopyMenu, + id=wxID_PLCOPENEDITOREDITMENUITEMS5) + self.Bind(wx.EVT_MENU, self.OnPasteMenu, + id=wxID_PLCOPENEDITOREDITMENUITEMS6) + self.Bind(wx.EVT_MENU, self.OnAddPouMenu, + id=wxID_PLCOPENEDITOREDITMENUITEMS8) + self.Bind(wx.EVT_MENU, self.OnRemovePouMenu, + id=wxID_PLCOPENEDITOREDITMENUITEMS9) + self.Bind(wx.EVT_MENU, self.OnAddConfigurationMenu, + id=wxID_PLCOPENEDITOREDITMENUITEMS11) + self.Bind(wx.EVT_MENU, self.OnRemoveConfigurationMenu, + id=wxID_PLCOPENEDITOREDITMENUITEMS12) + + def _init_coll_menuBar1_Menus(self, parent): + # generated method, don't edit + + parent.Append(menu=self.FileMenu, title=u'File') + parent.Append(menu=self.EditMenu, title=u'Edit') + parent.Append(menu=self.HelpMenu, title=u'Help') + + def _init_coll_ConfigMenu_Items(self, parent): + # generated method, don't edit + + parent.Append(help='', id=wxID_PLCOPENEDITORCONFIGMENUITEMS0, + kind=wx.ITEM_NORMAL, text=u'Add Resource') + parent.Append(help='', id=wxID_PLCOPENEDITORCONFIGMENUITEMS1, + kind=wx.ITEM_NORMAL, text=u'Remove Resource') + self.Bind(wx.EVT_MENU, self.OnAddResourceMenu, + id=wxID_PLCOPENEDITORCONFIGMENUITEMS0) + self.Bind(wx.EVT_MENU, self.OnRemoveResourceMenu, + id=wxID_PLCOPENEDITORCONFIGMENUITEMS1) + + def _init_coll_HelpMenu_Items(self, parent): + # generated method, don't edit + + parent.Append(help='', id=wxID_PLCOPENEDITORHELPMENUITEMS0, + kind=wx.ITEM_NORMAL, text=u'PLCOpenEditor\tF1') + parent.Append(help='', id=wxID_PLCOPENEDITORHELPMENUITEMS1, + kind=wx.ITEM_NORMAL, text=u'PLCOpen\tF2') + parent.Append(help='', id=wxID_PLCOPENEDITORHELPMENUITEMS2, + kind=wx.ITEM_NORMAL, text=u'IEC 61131-3\tF3') + parent.Append(help='', id=wxID_PLCOPENEDITORHELPMENUITEMS3, + kind=wx.ITEM_NORMAL, text=u'About') + self.Bind(wx.EVT_MENU, self.OnPLCOpenMenu, + id=wxID_PLCOPENEDITORHELPMENUITEMS1) + + def _init_coll_FileMenu_Items(self, parent): + # generated method, don't edit + + parent.Append(help='', id=wxID_PLCOPENEDITORFILEMENUITEMS0, + kind=wx.ITEM_NORMAL, text=u'New\tCTRL+N') + parent.Append(help='', id=wxID_PLCOPENEDITORFILEMENUITEMS1, + kind=wx.ITEM_NORMAL, text=u'Open\tCTRL+O') + parent.Append(help='', id=wxID_PLCOPENEDITORFILEMENUITEMS2, + kind=wx.ITEM_NORMAL, text=u'Close Tab\tCTRL+W') + parent.Append(help='', id=wxID_PLCOPENEDITORFILEMENUITEMS3, + kind=wx.ITEM_NORMAL, text=u'Close Project') + parent.AppendSeparator() + parent.Append(help='', id=wxID_PLCOPENEDITORFILEMENUITEMS5, + kind=wx.ITEM_NORMAL, text=u'Save\tCTRL+S') + parent.Append(help='', id=wxID_PLCOPENEDITORFILEMENUITEMS6, + kind=wx.ITEM_NORMAL, text=u'Save As...\tCTRL+SHIFT+S') + parent.Append(help='', id=wxID_PLCOPENEDITORFILEMENUITEMS7, + kind=wx.ITEM_NORMAL, text=u'Generate Program\tCTRL+G') + parent.AppendSeparator() + parent.Append(help='', id=wxID_PLCOPENEDITORFILEMENUITEMS9, + kind=wx.ITEM_NORMAL, text=u'Properties') + parent.AppendSeparator() + parent.Append(help='', id=wxID_PLCOPENEDITORFILEMENUITEMS11, + kind=wx.ITEM_NORMAL, text=u'Quit\tCTRL+Q') + self.Bind(wx.EVT_MENU, self.OnNewProjectMenu, + id=wxID_PLCOPENEDITORFILEMENUITEMS0) + self.Bind(wx.EVT_MENU, self.OnOpenProjectMenu, + id=wxID_PLCOPENEDITORFILEMENUITEMS1) + self.Bind(wx.EVT_MENU, self.OnCloseTabMenu, + id=wxID_PLCOPENEDITORFILEMENUITEMS2) + self.Bind(wx.EVT_MENU, self.OnCloseProjectMenu, + id=wxID_PLCOPENEDITORFILEMENUITEMS3) + self.Bind(wx.EVT_MENU, self.OnSaveProjectMenu, + id=wxID_PLCOPENEDITORFILEMENUITEMS5) + self.Bind(wx.EVT_MENU, self.OnSaveProjectAsMenu, + id=wxID_PLCOPENEDITORFILEMENUITEMS6) + self.Bind(wx.EVT_MENU, self.OnGenerateProgramMenu, + id=wxID_PLCOPENEDITORFILEMENUITEMS7) + self.Bind(wx.EVT_MENU, self.OnQuitMenu, + id=wxID_PLCOPENEDITORFILEMENUITEMS11) + + def _init_coll_SFCMenu_Items(self, parent): + # generated method, don't edit + + parent.Append(help='', id=wxID_PLCOPENEDITORSFCMENUITEMS0, + kind=wx.ITEM_NORMAL, text=u'Add Transition') + parent.Append(help='', id=wxID_PLCOPENEDITORSFCMENUITEMS1, + kind=wx.ITEM_NORMAL, text=u'Add Action') + parent.Append(help='', id=wxID_PLCOPENEDITORSFCMENUITEMS2, + kind=wx.ITEM_NORMAL, text=u'Remove Transition') + parent.Append(help='', id=wxID_PLCOPENEDITORSFCMENUITEMS3, + kind=wx.ITEM_NORMAL, text=u'Remove Action') + self.Bind(wx.EVT_MENU, self.OnAddPouTransitionMenu, + id=wxID_PLCOPENEDITORSFCMENUITEMS0) + self.Bind(wx.EVT_MENU, self.OnAddPouActionMenu, + id=wxID_PLCOPENEDITORSFCMENUITEMS1) + self.Bind(wx.EVT_MENU, self.OnRemovePouTransitionMenu, + id=wxID_PLCOPENEDITORSFCMENUITEMS2) + self.Bind(wx.EVT_MENU, self.OnRemovePouActionMenu, + id=wxID_PLCOPENEDITORSFCMENUITEMS3) + + def _init_utils(self): + # generated method, don't edit + self.menuBar1 = wx.MenuBar() + + self.FileMenu = wx.Menu(title=u'') + + self.EditMenu = wx.Menu(title=u'') + + self.HelpMenu = wx.Menu(title='') + + self.SFCMenu = wx.Menu(title='') + + self.ConfigMenu = wx.Menu(title='') + + self._init_coll_menuBar1_Menus(self.menuBar1) + self._init_coll_FileMenu_Items(self.FileMenu) + self._init_coll_EditMenu_Items(self.EditMenu) + self._init_coll_HelpMenu_Items(self.HelpMenu) + self._init_coll_SFCMenu_Items(self.SFCMenu) + self._init_coll_ConfigMenu_Items(self.ConfigMenu) + + def _init_coll_MainGridSizer_Items(self, parent): + # generated method, don't edit + + parent.AddWindow(self.splitterWindow1, 0, border=0, flag=wxGROW) + + def _init_coll_MainGridSizer_Growables(self, parent): + # generated method, don't edit + + parent.AddGrowableCol(0) + parent.AddGrowableRow(0) + + def _init_sizers(self): + # generated method, don't edit + self.MainGridSizer = wx.FlexGridSizer(cols=1, hgap=0, rows=1, vgap=0) + + self._init_coll_MainGridSizer_Growables(self.MainGridSizer) + self._init_coll_MainGridSizer_Items(self.MainGridSizer) + + self.SetSizer(self.MainGridSizer) + + def _init_ctrls(self, prnt): + # generated method, don't edit + wx.Frame.__init__(self, id=wxID_PLCOPENEDITOR, name=u'PLCOpenEditor', + parent=prnt, pos=wx.Point(235, 287), size=wx.Size(1000, 600), + style=wx.DEFAULT_FRAME_STYLE, title=u'PLCOpenEditor') + self._init_utils() + self.SetClientSize(wx.Size(1000, 600)) + self.SetMenuBar(self.menuBar1) + self.Bind(wx.EVT_TREE_BEGIN_LABEL_EDIT, self.OnProjectTreeItemBeginEdit, + id=wxID_PLCOPENEDITORPROJECTTREE) + self.Bind(wx.EVT_TREE_END_LABEL_EDIT, self.OnProjectTreeItemEndEdit, + id=wxID_PLCOPENEDITORPROJECTTREE) + self.Bind(wx.EVT_TREE_ITEM_ACTIVATED, self.OnProjectTreeItemActivated, + id=wxID_PLCOPENEDITORPROJECTTREE) + self.Bind(wx.EVT_TREE_SEL_CHANGED, self.OnProjectTreeItemSelected, + id=wxID_PLCOPENEDITORPROJECTTREE) + + self.splitterWindow1 = wx.SplitterWindow(id=wxID_PLCOPENEDITORSPLITTERWINDOW1, + name='splitterWindow1', parent=self, point=wx.Point(0, 0), + size=wx.Size(-1, -1), style=wx.SP_3D) + self.splitterWindow1.SetNeedUpdating(True) + self.splitterWindow1.SetMinimumPaneSize(1) + + self.TabsOpened = wx.Notebook(id=wxID_PLCOPENEDITORTABSOPENED, + name='TabsOpened', parent=self.splitterWindow1, pos=wx.Point(0, + 0), size=wx.Size(-1, -1), style=0) + self.TabsOpened.Bind(wx.EVT_NOTEBOOK_PAGE_CHANGED, + self.OnPouSelectedChanged, id=wxID_PLCOPENEDITORTABSOPENED) + + self.ProjectTree = wx.TreeCtrl(id=wxID_PLCOPENEDITORPROJECTTREE, + name='treeCtrl1', parent=self.splitterWindow1, pos=wx.Point(0, 0), + size=wx.Size(-1, -1), + style=wx.TR_HAS_BUTTONS|wx.TR_EDIT_LABELS|wx.TR_SINGLE|wx.SUNKEN_BORDER) + self.ProjectTree.Bind(wx.EVT_RIGHT_UP, self.OnProjectTreeRightUp) + self.splitterWindow1.SplitVertically(self.ProjectTree, self.TabsOpened, + 200) + + self._init_sizers() + + def init_coll_DefaultToolBar_Items(self, parent): + parent.AddRadioTool(wxID_PLCOPENEDITORDEFAULTTOOLBARITEMS0, + wxBitmap('Images/select.png'), wxNullBitmap, "Select an object") + self.Bind(wx.EVT_TOOL, self.OnSelectionTool, + id=wxID_PLCOPENEDITORDEFAULTTOOLBARITEMS0) + + def init_coll_SFCToolBar_Items(self, parent): + parent.AddRadioTool(wxID_PLCOPENEDITORSFCTOOLBARITEMS0, + wxBitmap('Images/select.png'), wxNullBitmap, "Select an object") + parent.AddRadioTool(wxID_PLCOPENEDITORSFCTOOLBARITEMS1, + wxBitmap('Images/comment.png'), wxNullBitmap, "Create a new comment") + parent.AddRadioTool(wxID_PLCOPENEDITORSFCTOOLBARITEMS2, + wxBitmap('Images/initial_step.png'), wxNullBitmap, "Create a new initial step") + parent.AddSimpleTool(wxID_PLCOPENEDITORSFCTOOLBARITEMS3, + wxBitmap('Images/step.png'), "Create a new step") + parent.AddSimpleTool(wxID_PLCOPENEDITORSFCTOOLBARITEMS4, + wxBitmap('Images/action.png'), "Add action block to step") + parent.AddSimpleTool(wxID_PLCOPENEDITORSFCTOOLBARITEMS5, + wxBitmap('Images/divergence.png'), "Create a new divergence") + parent.AddSimpleTool(wxID_PLCOPENEDITORSFCTOOLBARITEMS6, + wxBitmap('Images/jump.png'), "Create a new jump") + self.Bind(wx.EVT_TOOL, self.OnSelectionTool, + id=wxID_PLCOPENEDITORSFCTOOLBARITEMS0) + self.Bind(wx.EVT_TOOL, self.OnCommentTool, + id=wxID_PLCOPENEDITORSFCTOOLBARITEMS1) + self.Bind(wx.EVT_TOOL, self.OnSFCInitialStepTool, + id=wxID_PLCOPENEDITORSFCTOOLBARITEMS2) + self.Bind(wx.EVT_TOOL, self.OnSFCStepTool, + id=wxID_PLCOPENEDITORSFCTOOLBARITEMS3) + self.Bind(wx.EVT_TOOL, self.OnSFCActionBlockTool, + id=wxID_PLCOPENEDITORSFCTOOLBARITEMS4) + self.Bind(wx.EVT_TOOL, self.OnSFCDivergenceTool, + id=wxID_PLCOPENEDITORSFCTOOLBARITEMS5) + self.Bind(wx.EVT_TOOL, self.OnSFCJumpTool, + id=wxID_PLCOPENEDITORSFCTOOLBARITEMS6) + + def init_coll_FBDToolBar_Items(self, parent): + parent.AddRadioTool(wxID_PLCOPENEDITORFBDTOOLBARITEMS0, + wxBitmap('Images/select.png'), wxNullBitmap, "Select an object") + parent.AddRadioTool(wxID_PLCOPENEDITORFBDTOOLBARITEMS1, + wxBitmap('Images/comment.png'), wxNullBitmap, "Create a new comment") + parent.AddRadioTool(wxID_PLCOPENEDITORFBDTOOLBARITEMS2, + wxBitmap('Images/variable.png'), wxNullBitmap, "Create a new variable") + parent.AddRadioTool(wxID_PLCOPENEDITORFBDTOOLBARITEMS3, + wxBitmap('Images/block.png'), wxNullBitmap, "Create a new block") + parent.AddRadioTool(wxID_PLCOPENEDITORFBDTOOLBARITEMS4, + wxBitmap('Images/connection.png'), wxNullBitmap, "Create a new connection") + parent.AddRadioTool(wxID_PLCOPENEDITORFBDTOOLBARITEMS5, + wxBitmap('Images/wire.png'), wxNullBitmap, "Create a new wire") + self.Bind(wx.EVT_TOOL, self.OnSelectionTool, + id=wxID_PLCOPENEDITORFBDTOOLBARITEMS0) + self.Bind(wx.EVT_TOOL, self.OnCommentTool, + id=wxID_PLCOPENEDITORFBDTOOLBARITEMS1) + self.Bind(wx.EVT_TOOL, self.OnFBDVariableTool, + id=wxID_PLCOPENEDITORFBDTOOLBARITEMS2) + self.Bind(wx.EVT_TOOL, self.OnFBDBlockTool, + id=wxID_PLCOPENEDITORFBDTOOLBARITEMS3) + self.Bind(wx.EVT_TOOL, self.OnFBDConnectionTool, + id=wxID_PLCOPENEDITORFBDTOOLBARITEMS4) + self.Bind(wx.EVT_TOOL, self.OnWireTool, + id=wxID_PLCOPENEDITORFBDTOOLBARITEMS5) + + def init_coll_LDToolBar_Items(self, parent): + parent.AddRadioTool(wxID_PLCOPENEDITORLDTOOLBARITEMS0, + wxBitmap('Images/select.png'), wxNullBitmap, "Select an object") + parent.AddSimpleTool(wxID_PLCOPENEDITORLDTOOLBARITEMS1, + wxBitmap('Images/coil.png'), "Create a new rung") + parent.AddSimpleTool(wxID_PLCOPENEDITORLDTOOLBARITEMS2, + wxBitmap('Images/contact.png'), "Create a new contact") + parent.AddSimpleTool(wxID_PLCOPENEDITORLDTOOLBARITEMS3, + wxBitmap('Images/block.png'), "Create a new block") + parent.AddSimpleTool(wxID_PLCOPENEDITORLDTOOLBARITEMS4, + wxBitmap('Images/branch.png'), "Create a new branch") + self.Bind(wx.EVT_TOOL, self.OnSelectionTool, + id=wxID_PLCOPENEDITORLDTOOLBARITEMS0) + self.Bind(wx.EVT_TOOL, self.OnLDCoilTool, + id=wxID_PLCOPENEDITORLDTOOLBARITEMS1) + self.Bind(wx.EVT_TOOL, self.OnLDContactTool, + id=wxID_PLCOPENEDITORLDTOOLBARITEMS2) + self.Bind(wx.EVT_TOOL, self.OnLDBlockTool, + id=wxID_PLCOPENEDITORLDTOOLBARITEMS3) + self.Bind(wx.EVT_TOOL, self.OnLDBranchTool, + id=wxID_PLCOPENEDITORLDTOOLBARITEMS4) + + def init_toolbars(self, parent): + self.DefaultToolBar = wxToolBar(id=wxID_PLCOPENEDITORDEFAULTTOOLBAR, name='DefaultToolBar', + parent=parent, pos=wx.Point(0, 27), size=wx.Size(0, 0), + style=wxTB_HORIZONTAL | wxNO_BORDER) + + self.SFCToolBar = wxToolBar(id=wxID_PLCOPENEDITORSFCTOOLBAR, name='SFCToolBar', + parent=parent, pos=wx.Point(0, 27), size=wx.Size(0, 0), + style=wxTB_HORIZONTAL | wxNO_BORDER) + + self.FBDToolBar = wxToolBar(id=wxID_PLCOPENEDITORFBDTOOLBAR, name='FBDToolBar', + parent=parent, pos=wx.Point(0, 27), size=wx.Size(0, 0), + style=wxTB_HORIZONTAL | wxNO_BORDER) + + self.LDToolBar = wxToolBar(id=wxID_PLCOPENEDITORLDTOOLBAR, name='LDToolBar', + parent=parent, pos=wx.Point(0, 27), size=wx.Size(0, 0), + style=wxTB_HORIZONTAL | wxNO_BORDER) + + self.init_coll_DefaultToolBar_Items(self.DefaultToolBar) + self.init_coll_SFCToolBar_Items(self.SFCToolBar) + self.init_coll_FBDToolBar_Items(self.FBDToolBar) + self.init_coll_LDToolBar_Items(self.LDToolBar) + + def __init__(self, parent): + self._init_ctrls(parent) + self.init_toolbars(self) + + self.Controler = PLCControler() + + if fileOpen: + self.Controler.OpenXMLFile(fileOpen) + self.RefreshProjectTree() + + self.RefreshFileMenu() + self.RefreshEditMenu() + self.RefreshToolBar() + + def RefreshFileMenu(self): + if self.Controler.HasOpenedProject(): + if self.TabsOpened.GetPageCount() > 0: + self.FileMenu.FindItemByPosition(2).Enable(True) + else: + self.FileMenu.FindItemByPosition(2).Enable(False) + self.FileMenu.FindItemByPosition(3).Enable(True) + self.FileMenu.FindItemByPosition(5).Enable(True) + self.FileMenu.FindItemByPosition(6).Enable(True) + self.FileMenu.FindItemByPosition(7).Enable(True) + self.FileMenu.FindItemByPosition(9).Enable(True) + else: + self.FileMenu.FindItemByPosition(2).Enable(False) + self.FileMenu.FindItemByPosition(3).Enable(False) + self.FileMenu.FindItemByPosition(5).Enable(False) + self.FileMenu.FindItemByPosition(6).Enable(False) + self.FileMenu.FindItemByPosition(7).Enable(False) + self.FileMenu.FindItemByPosition(9).Enable(False) + + def RefreshEditMenu(self): + self.EditMenu.FindItemByPosition(1).Enable(False) + self.EditMenu.FindItemByPosition(2).Enable(False) + if self.Controler.HasOpenedProject(): + if self.TabsOpened.GetPageCount() > 0: + self.EditMenu.FindItemByPosition(0).Enable(True) + else: + self.EditMenu.FindItemByPosition(0).Enable(False) + self.EditMenu.FindItemByPosition(8).Enable(True) + self.EditMenu.FindItemByPosition(9).Enable(True) + else: + self.EditMenu.FindItemByPosition(0).Enable(False) + self.EditMenu.FindItemByPosition(8).Enable(False) + self.EditMenu.FindItemByPosition(9).Enable(False) + bodytype = self.Controler.GetCurrentElementEditingBodyType() + if bodytype in ["LD","ST"]: + self.EditMenu.FindItemByPosition(4).Enable(True) + self.EditMenu.FindItemByPosition(5).Enable(True) + self.EditMenu.FindItemByPosition(6).Enable(True) + else: + self.EditMenu.FindItemByPosition(4).Enable(False) + self.EditMenu.FindItemByPosition(5).Enable(False) + self.EditMenu.FindItemByPosition(6).Enable(False) + + def OnNewProjectMenu(self, event): + dialog = ProjectDialog(self) + if dialog.ShowModal() == wxID_OK: + values = dialog.GetValues() + projectname = values.pop("projectName") + values["creationDateTime"] = datetime(*localtime()[:6]) + self.Controler.CreateNewProject(projectname) + self.Controler.SetProjectProperties(values) + self.RefreshFileMenu() + self.RefreshEditMenu() + self.RefreshProjectTree() + event.Skip() + + def OnOpenProjectMenu(self, event): + filepath = self.Controler.GetFilePath() + if filepath != "": + directory = os.path.dirname(filepath) + else: + directory = os.getcwd() + dialog = wxFileDialog(self, "Choose a file", directory, "", "PLCOpen files (*.xml)|*.xml|All files|*.*", wxOPEN) + if dialog.ShowModal() == wxID_OK: + filepath = dialog.GetPath() + if os.path.isfile(filepath): + self.Controler.OpenXMLFile(filepath) + self.TabsOpened.DeleteAllPages() + self.RefreshProjectTree() + self.RefreshFileMenu() + self.RefreshEditMenu() + self.RefreshToolBar() + dialog.Destroy() + event.Skip() + + def OnCloseTabMenu(self, event): + selected = self.TabsOpened.GetSelection() + if selected >= 0: + self.Controler.CloseElementEditing() + self.TabsOpened.DeletePage(selected) + if self.TabsOpened.GetPageCount() > 0: + self.TabsOpened.SetSelection(min(selected, self.TabsOpened.GetPageCount() - 1)) + self.RefreshFileMenu() + self.RefreshEditMenu() + self.RefreshToolBar() + event.Skip() + + def OnCloseProjectMenu(self, event): + self.Controler.Reset() + self.TabsOpened.DeleteAllPages() + self.ProjectTree.DeleteAllItems() + self.RefreshFileMenu() + self.RefreshEditMenu() + self.RefreshToolBar() + event.Skip() + + def OnSaveProjectMenu(self, event): + self.SaveProject() + event.Skip() + + def OnSaveProjectAsMenu(self, event): + self.SaveProjectAs() + event.Skip() + + def OnGenerateProgramMenu(self, event): + self.Controler.GenerateProgram() + event.Skip() + + def SaveProject(self): + result = self.Controler.SaveXMLFile() + if not result: + self.SaveProjectAs() + + def SaveProjectAs(self): + filepath = self.Controler.GetFilePath() + if filepath != "": + directory, filename = os.path.split(filepath) + else: + directory, filename = os.getcwd(), "%s.od"%self.Controler.GetProjectName() + dialog = wxFileDialog(self, "Choose a file", directory, filename, "PLCOpen files (*.xml)|*.xml|All files|*.*", wxSAVE|wxOVERWRITE_PROMPT) + if dialog.ShowModal() == wxID_OK: + filepath = dialog.GetPath() + if os.path.isdir(os.path.dirname(filepath)): + result = self.Controler.SaveXMLFile(filepath) + if not result: + message = wxMessageDialog(self, "Can't save project to file %s!"%filepath, "Error", wxOK|wxICON_ERROR) + message.ShowModal() + message.Destroy() + else: + message = wxMessageDialog(self, "%s is not a valid folder!"%os.path.dirname(filepath), "Error", wxOK|wxICON_ERROR) + message.ShowModal() + message.Destroy() + dialog.Destroy() + + def OnQuitMenu(self, event): + self.Close() + event.Skip() + + def OnSelectionTool(self, event): + selected = self.TabsOpened.GetSelection() + if selected != -1: + self.TabsOpened.GetPage(selected).SetMode(MODE_SELECTION) + event.Skip() + + def OnCommentTool(self, event): + selected = self.TabsOpened.GetSelection() + if selected != -1: + self.TabsOpened.GetPage(selected).SetMode(MODE_COMMENT) + event.Skip() + + def OnWireTool(self, event): + selected = self.TabsOpened.GetSelection() + if selected != -1: + self.TabsOpened.GetPage(selected).SetMode(MODE_WIRE) + event.Skip() + + def OnSFCInitialStepTool(self, event): + selected = self.TabsOpened.GetSelection() + if selected != -1: + self.TabsOpened.GetPage(selected).SetMode(MODE_INITIAL_STEP) + event.Skip() + + def OnSFCStepTool(self, event): + selected = self.TabsOpened.GetSelection() + if selected != -1: + self.TabsOpened.GetPage(selected).AddStep() + event.Skip() + + def OnSFCActionBlockTool(self, event): + selected = self.TabsOpened.GetSelection() + if selected != -1: + self.TabsOpened.GetPage(selected).AddStepAction() + event.Skip() + + def OnSFCDivergenceTool(self, event): + selected = self.TabsOpened.GetSelection() + if selected != -1: + self.TabsOpened.GetPage(selected).AddDivergence() + event.Skip() + + def OnSFCJumpTool(self, event): + selected = self.TabsOpened.GetSelection() + if selected != -1: + self.TabsOpened.GetPage(selected).AddJump() + event.Skip() + + def OnFBDVariableTool(self, event): + selected = self.TabsOpened.GetSelection() + if selected != -1: + self.TabsOpened.GetPage(selected).SetMode(MODE_VARIABLE) + event.Skip() + + def OnFBDBlockTool(self, event): + selected = self.TabsOpened.GetSelection() + if selected != -1: + self.TabsOpened.GetPage(selected).SetMode(MODE_BLOCK) + event.Skip() + + def OnFBDConnectionTool(self, event): + selected = self.TabsOpened.GetSelection() + if selected != -1: + self.TabsOpened.GetPage(selected).SetMode(MODE_CONNECTION) + event.Skip() + + def OnLDCoilTool(self, event): + selected = self.TabsOpened.GetSelection() + if selected != -1: + self.TabsOpened.GetPage(selected).AddRung() + event.Skip() + + def OnLDContactTool(self, event): + selected = self.TabsOpened.GetSelection() + if selected != -1: + self.TabsOpened.GetPage(selected).AddContact() + event.Skip() + + def OnLDBlockTool(self, event): + selected = self.TabsOpened.GetSelection() + if selected != -1: + pass + event.Skip() + + def OnLDBranchTool(self, event): + selected = self.TabsOpened.GetSelection() + if selected != -1: + self.TabsOpened.GetPage(selected).AddBranch() + event.Skip() + + def OnPouSelectedChanged(self, event): + selected = event.GetSelection() + if selected >= 0: + self.Controler.RefreshCurrentElementEditing(selected) + found = False + name = self.TabsOpened.GetPageText(selected) + root = self.ProjectTree.GetRootItem() + item, root_cookie = self.ProjectTree.GetFirstChild(root) + while item.IsOk() and not found: + if self.ProjectTree.GetItemText(item) == name: + self.ProjectTree.SelectItem(item) + item, root_cookie = self.ProjectTree.GetNextChild(root, root_cookie) + self.RefreshFileMenu() + self.RefreshEditMenu() + self.RefreshToolBar() + event.Skip() + + def OnProjectTreeItemEndEdit(self, event): + new_name = event.GetLabel() + if new_name != "": + if TestIdentifier(new_name): + item = event.GetItem() + itemtype = self.ProjectTree.GetPyData(item) + if itemtype == ITEM_PROJECT: + self.Controler.SetProjectName(new_name) + elif itemtype == ITEM_POU: + old_name = self.ProjectTree.GetItemText(item) + self.Controler.ChangePouName(old_name, new_name) + self.RefreshTabsOpenedTitles() + elif itemtype == ITEM_TRANSITION: + old_name = self.ProjectTree.GetItemText(item) + parent = self.ProjectTree.GetItemParent(item) + grandparent = self.ProjectTree.GetItemParent(parent) + grandparent_name = self.ProjectTree.GetItemText(grandparent) + self.Controler.ChangePouTransitionName(grandparent_name, old_name, new_name) + self.RefreshTabsOpenedTitles() + elif itemtype == ITEM_ACTION: + old_name = self.ProjectTree.GetItemText(item) + parent = self.ProjectTree.GetItemParent(item) + grandparent = self.ProjectTree.GetItemParent(parent) + grandparent_name = self.ProjectTree.GetItemText(grandparent) + self.Controler.ChangePouActionName(grandparent_name, old_name, new_name) + self.RefreshTabsOpenedTitles() + wxCallAfter(self.RefreshProjectTree) + event.Skip() + else: + message = wxMessageDialog(self, "\"%s\" is not a valid identifier!"%new_name, "Error", wxOK|wxICON_ERROR) + message.ShowModal() + message.Destroy() + item = event.GetItem() + wxCallAfter(self.ProjectTree.EditLabel, item) + event.Veto() + + def OnProjectTreeItemBeginEdit(self, event): + selected = event.GetItem() + if self.ProjectTree.GetPyData(selected) == ITEM_UNEDITABLE: + event.Veto() + else: + event.Skip() + + def OnProjectTreeItemActivated(self, event): + selected = event.GetItem() + if self.ProjectTree.IsExpanded(selected): + self.ProjectTree.Collapse(selected) + else: + self.ProjectTree.Expand(selected) + name = self.ProjectTree.GetItemText(selected) + data = self.ProjectTree.GetPyData(selected) + if name == "Properties": + old_values = self.Controler.GetProjectProperties() + old_values["projectName"] = self.Controler.GetProjectName() + dialog = ProjectDialog(self) + dialog.SetValues(old_values) + if dialog.ShowModal() == wxID_OK: + new_values = dialog.GetValues() + projectname = new_values.pop("projectName") + new_values["creationDateTime"] = old_values["creationDateTime"] + self.Controler.SetProjectName(projectname) + self.Controler.SetProjectProperties(new_values) + self.RefreshProjectTree() + dialog.Destroy() + elif data == ITEM_CLASS: + item = self.ProjectTree.GetItemParent(selected) + item_type = self.ProjectTree.GetPyData(item) + while item_type != ITEM_POU: + item = self.ProjectTree.GetItemParent(item) + item_type = self.ProjectTree.GetPyData(item) + pou_name = self.ProjectTree.GetItemText(item) + dialog = EditVariableDialog(self, pou_name, self.Controler.GetPouType(pou_name), name) + values = {} + values["returnType"] = self.Controler.GetPouInterfaceReturnTypeByName(pou_name) + values["data"] = self.Controler.GetPouInterfaceVarsByName(pou_name) + dialog.SetValues(values) + if dialog.ShowModal() == wxID_OK: + if not self.Controler.PouIsUsed(pou_name): + new_values = dialog.GetValues() + if "returnType" in new_values: + self.Controler.SetPouInterfaceReturnType(pou_name, new_values["returnType"]) + self.Controler.SetPouInterfaceVars(pou_name, new_values["data"]) + pou_names = self.Controler.GetElementsOpenedNames() + if pou_name in pou_names: + window = self.TabsOpened.GetPage(pou_names.index(pou_name)) + if isinstance(window, TextViewer): + varlist = [] + if "returnType" in new_values: + varlist.append(name) + for var in new_values["data"]: + varlist.append(var["Name"]) + window.SetVariables(varlist) + else: + message = wxMessageDialog(self, "\"%s\" is used by one or more POUs. Its interface can't be changed!"%pou_name, "Error", wxOK|wxICON_ERROR) + message.ShowModal() + message.Destroy() + dialog.Destroy() + elif name == "Global Vars": + parent = self.ProjectTree.GetItemParent(selected) + parent_name = self.ProjectTree.GetItemText(parent) + dialog = EditVariableDialog(self, parent_name, None) + if self.ProjectTree.GetPyData(parent) == ITEM_CONFIGURATION: + values = {"data" : self.Controler.GetConfigurationGlobalVars(parent_name)} + dialog.SetValues(values) + if dialog.ShowModal() == wxID_OK: + new_values = dialog.GetValues() + self.Controler.SetConfigurationGlobalVars(parent_name, new_values["data"]) + else: + config = self.ProjectTree.GetItemParent(parent) + config_name = self.ProjectTree.GetItemText(config) + values = {"data" : self.Controler.GetConfigurationResourceGlobalVars(config_name, parent_name)} + dialog.SetValues(values) + if dialog.ShowModal() == wxID_OK: + new_values = dialog.GetValues() + self.Controler.SetConfigurationResourceGlobalVars(config_name, parent_name, new_values["data"]) + elif data in [ITEM_POU, ITEM_TRANSITION, ITEM_ACTION]: + if data == ITEM_POU: + idx = self.Controler.OpenElementEditing(name) + language = self.Controler.GetPouBodyType(name) + varlist = [] + returnType = self.Controler.GetPouInterfaceReturnTypeByName(name) + if returnType: + varlist.append(name) + vars = self.Controler.GetPouInterfaceVarsByName(name) + if vars: + for var in vars: + varlist.append(var["Name"]) + else: + parent = self.ProjectTree.GetItemParent(selected) + parent_name = self.ProjectTree.GetItemText(parent) + grandparent = self.ProjectTree.GetItemParent(parent) + grandparent_name = self.ProjectTree.GetItemText(grandparent) + if data == ITEM_TRANSITION: + idx = self.Controler.OpenPouTransitionEditing(grandparent_name, name) + language = self.Controler.GetTransitionBodyType(grandparent_name, name) + elif data == ITEM_ACTION: + idx = self.Controler.OpenPouActionEditing(grandparent_name, name) + language = self.Controler.GetActionBodyType(grandparent_name, name) + varlist = [name] + vars = self.Controler.GetPouInterfaceVarsByName(grandparent_name) + if vars: + for var in vars: + varlist.append(var["Name"]) + if idx != None: + if language == "FBD": + new_window = FBD_Viewer(self.TabsOpened, self, self.Controler) + elif language == "LD": + new_window = LD_Viewer(self.TabsOpened, self, self.Controler) + elif language == "SFC": + new_window = SFC_Viewer(self.TabsOpened, self, self.Controler) + elif language in ["IL", "ST"]: + new_window = TextViewer(self.TabsOpened, self, self.Controler) + if language == "IL": + new_window.SetKeywords(IL_KEYWORDS) + else: + new_window.SetKeywords(ST_KEYWORDS) + new_window.SetVariables(varlist) + new_window.SetFunctions(self.Controler.GetBlockTypes()) + else: + return + new_window.RefreshView() + self.TabsOpened.AddPage(new_window, "") + self.TabsOpened.SetSelection(idx) + self.RefreshTabsOpenedTitles() + self.RefreshFileMenu() + self.RefreshEditMenu() + self.RefreshToolBar() + else: + if data == ITEM_POU: + idx = self.Controler.ChangeElementEditing(name) + elif data == ITEM_TRANSITION: + idx = self.Controler.ChangePouTransitionEditing(grandparent_name, name) + elif data == ITEM_ACTION: + idx = self.Controler.ChangePouActionEditing(grandparent_name, name) + if idx != None: + self.TabsOpened.SetSelection(idx) + self.RefreshFileMenu() + self.RefreshEditMenu() + self.RefreshToolBar() + elif data == ITEM_RESOURCE: + item = self.ProjectTree.GetItemParent(selected) + item_type = self.ProjectTree.GetPyData(item) + while item_type != ITEM_CONFIGURATION: + item = self.ProjectTree.GetItemParent(item) + item_type = self.ProjectTree.GetPyData(item) + config_name = self.ProjectTree.GetItemText(item) + idx = self.Controler.OpenConfigurationResourceEditing(config_name, name) + if idx != None: + new_window = ResourceEditor(self.TabsOpened, self, self.Controler) + new_window.RefreshView() + self.TabsOpened.AddPage(new_window, "") + self.TabsOpened.SetSelection(idx) + self.RefreshTabsOpenedTitles() + self.RefreshFileMenu() + self.RefreshEditMenu() + self.RefreshToolBar() + else: + idx = self.Controler.ChangeConfigurationResourceEditing(parent_name, name) + if idx != None: + self.TabsOpened.SetSelection(idx) + self.RefreshFileMenu() + self.RefreshEditMenu() + self.RefreshToolBar() + + def OnProjectTreeRightUp(self, event): + selected = self.ProjectTree.GetSelection() + if self.ProjectTree.GetPyData(selected) == ITEM_POU: + name = self.ProjectTree.GetItemText(selected) + if self.Controler.GetPouBodyType(name) == "SFC": + self.PopupMenu(self.SFCMenu) + elif self.ProjectTree.GetPyData(selected) == ITEM_CONFIGURATION: + self.PopupMenu(self.ConfigMenu) + event.Skip() + + def OnProjectTreeItemSelected(self, event): + selected = event.GetItem() + name = self.ProjectTree.GetItemText(selected) + if self.ProjectTree.GetItemParent(selected) == self.ProjectTree.GetRootItem() and name != "Properties": + if self.Controler.IsElementEditing(name): + idx = self.Controler.ChangeElementEditing(name) + if idx != None: + self.TabsOpened.SetSelection(idx) + self.RefreshFileMenu() + self.RefreshEditMenu() + self.RefreshToolBar() + else: + name = self.ProjectTree.GetItemText(selected) + parent = self.ProjectTree.GetItemParent(selected) + parent_name = self.ProjectTree.GetItemText(parent) + grandparent = self.ProjectTree.GetItemParent(parent) + grandparent_name = self.ProjectTree.GetItemText(grandparent) + if parent_name == "Transitions": + idx = self.Controler.ChangePouTransitionEditing(grandparent_name, name) + if idx != None: + self.TabsOpened.SetSelection(idx) + self.RefreshFileMenu() + self.RefreshEditMenu() + self.RefreshToolBar() + elif parent_name == "Action": + idx = self.Controler.ChangePouActionEditing(grandparent_name, name) + if idx != None: + self.TabsOpened.SetSelection(idx) + self.RefreshFileMenu() + self.RefreshEditMenu() + self.RefreshToolBar() + event.Skip() + + def RefreshProjectTree(self): + infos = self.Controler.GetProjectInfos() + root = self.ProjectTree.GetRootItem() + self.GenerateTreeBranch(root, infos) + self.ProjectTree.Expand(self.ProjectTree.GetRootItem()) + + def GenerateTreeBranch(self, root, infos): + to_delete = [] + if root.IsOk(): + self.ProjectTree.SetItemText(root, infos["name"]) + else: + root = self.ProjectTree.AddRoot(infos["name"]) + self.ProjectTree.SetPyData(root, infos["type"]) + item, root_cookie = self.ProjectTree.GetFirstChild(root) + if len(infos["values"]) > 0: + for values in infos["values"]: + if not item.IsOk(): + item = self.ProjectTree.AppendItem(root, "") + item, root_cookie = self.ProjectTree.GetNextChild(root, root_cookie) + self.GenerateTreeBranch(item, values) + item, root_cookie = self.ProjectTree.GetNextChild(root, root_cookie) + while item.IsOk(): + to_delete.append(item) + item, root_cookie = self.ProjectTree.GetNextChild(item, root_cookie) + for item in to_delete: + self.ProjectTree.Delete(item) + + def RefreshToolBar(self): + language = self.Controler.GetCurrentElementEditingBodyType() + if language == "SFC": + self.SFCToolBar.ToggleTool(0, True) + self.SFCToolBar.Show() + self.SetToolBar(self.SFCToolBar) + self.DefaultToolBar.Hide() + self.FBDToolBar.Hide() + self.LDToolBar.Hide() + elif language == "FBD": + self.FBDToolBar.ToggleTool(0, True) + self.FBDToolBar.Show() + self.SetToolBar(self.FBDToolBar) + self.DefaultToolBar.Hide() + self.SFCToolBar.Hide() + self.LDToolBar.Hide() + elif language == "LD": + self.LDToolBar.ToggleTool(0, True) + self.LDToolBar.Show() + self.SetToolBar(self.LDToolBar) + self.DefaultToolBar.Hide() + self.SFCToolBar.Hide() + self.FBDToolBar.Hide() + else: + self.DefaultToolBar.ToggleTool(0, True) + self.DefaultToolBar.Show() + self.SetToolBar(self.DefaultToolBar) + self.SFCToolBar.Hide() + self.FBDToolBar.Hide() + self.LDToolBar.Hide() + + def RefreshTabsOpenedTitles(self): + pous = self.Controler.GetElementsOpenedNames() + for i, pou in enumerate(pous): + self.TabsOpened.SetPageText(i, pou) + + def OnRefreshMenu(self, event): + selected = self.TabsOpened.GetSelection() + if selected != -1: + self.TabsOpened.GetPage(selected).Refresh() + event.Skip() + + def OnCutMenu(self, event): + selected = self.TabsOpened.GetSelection() + if selected != -1: + self.TabsOpened.GetPage(selected).Cut() + event.Skip() + + def OnCopyMenu(self, event): + selected = self.TabsOpened.GetSelection() + if selected != -1: + self.TabsOpened.GetPage(selected).Copy() + event.Skip() + + def OnPasteMenu(self, event): + selected = self.TabsOpened.GetSelection() + if selected != -1: + self.TabsOpened.GetPage(selected).Paste() + event.Skip() + + def OnAddPouMenu(self, event): + dialog = PouDialog(self) + dialog.SetPouNames(self.Controler.GetProjectPouNames()) + if dialog.ShowModal() == wxID_OK: + values = dialog.GetValues() + self.Controler.ProjectAddPou(values["pouName"], values["pouType"], values["language"]) + self.RefreshProjectTree() + dialog.Destroy() + event.Skip() + + def OnRemovePouMenu(self, event): + pous = self.Controler.GetProjectPouNames() + dialog = wxSingleChoiceDialog(self, "Select POU to remove:", "POU Remove", pous, wxOK|wxCANCEL) + if dialog.ShowModal() == wxID_OK: + selected = dialog.GetStringSelection() + if not self.Controler.PouIsUsed(selected): + self.Controler.ProjectRemovePou(selected) + for i in xrange(self.TabsOpened.GetPageCount()): + if self.TabsOpened.GetPageText(i) == selected: + self.TabsOpened.DeletePage(i) + self.RefreshProjectTree() + self.RefreshToolBar() + else: + message = wxMessageDialog(self, "%s is used by one or more POUs. It can't be removed!"%selected, "Error", wxOK|wxICON_ERROR) + message.ShowModal() + message.Destroy() + event.Skip() + + def OnAddConfigurationMenu(self, event): + dialog = wxTextEntryDialog(self, "Enter configuration name:", "Create new configuration", "", wxOK|wxCANCEL) + if dialog.ShowModal() == wxID_OK: + value = dialog.GetValue() + self.Controler.ProjectAddConfiguration(value) + self.RefreshProjectTree() + dialog.Destroy() + event.Skip() + + def OnRemoveConfigurationMenu(self, event): + configs = self.Controler.GetProjectConfigNames() + dialog = wxSingleChoiceDialog(self, "Select Configuration to remove:", "Configuration Remove", configs, wxOK|wxCANCEL) + if dialog.ShowModal() == wxID_OK: + selected = dialog.GetStringSelection() + self.Controler.ProjectRemoveConfiguration(selected) + self.RefreshProjectTree() + event.Skip() + + def OnAddPouTransitionMenu(self, event): + dialog = PouTransitionDialog(self) + dialog.SetPous(self.Controler.GetSFCPous()) + if dialog.ShowModal() == wxID_OK: + values = dialog.GetValues() + self.Controler.ProjectAddPouTransition(values["pouName"], values["transitionName"], values["language"]) + self.RefreshProjectTree() + dialog.Destroy() + event.Skip() + + def OnRemovePouTransitionMenu(self, event): + event.Skip() + + def OnAddPouActionMenu(self, event): + dialog = PouActionDialog(self) + dialog.SetPous(self.Controler.GetSFCPous()) + if dialog.ShowModal() == wxID_OK: + values = dialog.GetValues() + self.Controler.ProjectAddPouAction(values["pouName"], values["actionName"], values["language"]) + self.RefreshProjectTree() + dialog.Destroy() + event.Skip() + + def OnRemovePouActionMenu(self, event): + event.Skip() + + def OnAddResourceMenu(self, event): + selected = self.ProjectTree.GetSelection() + if self.ProjectTree.GetPyData(selected) == ITEM_CONFIGURATION: + config_name = self.ProjectTree.GetItemText(selected) + dialog = wxTextEntryDialog(self, "Enter Resource name:", "Create new Resource", "", wxOK|wxCANCEL) + if dialog.ShowModal() == wxID_OK: + value = dialog.GetValue() + self.Controler.ProjectAddConfigurationResource(config_name, value) + self.RefreshProjectTree() + dialog.Destroy() + event.Skip() + + def OnRemoveResourceMenu(self, event): + selected = self.ProjectTree.GetSelection() + if self.ProjectTree.GetPyData(selected) == ITEM_CONFIGURATION: + config_name = self.ProjectTree.GetItemText(selected) + infos = self.Controler.GetProjectInfos() + resources = [] + for config in infos["configs"]: + if config["name"] == config_name: + resources = config["resources"] + dialog = wxSingleChoiceDialog(self, "Select Resource to remove:", "Resource Remove", resources, wxOK|wxCANCEL) + if dialog.ShowModal() == wxID_OK: + resource = dialog.GetStringSelection() + self.Controler.ProjectRemoveConfigurationResource(config_name, resource) + self.RefreshProjectTree() + dialog.Destroy() + event.Skip() + + def OnPLCOpenMenu(self, event): + result = OpenPDFDoc() + if type(result) == StringType: + message = wxMessageDialog(self, result, "ERROR", wxOK|wxICON_ERROR) + message.ShowModal() + message.Destroy() + event.Skip() + +current_num = 0 +def GetNewNum(): + global current_num + current_num += 1 + return current_num + +#------------------------------------------------------------------------------- +# Create Project Dialog +#------------------------------------------------------------------------------- + +[wxID_PROJECTDIALOG, wxID_PROJECTDIALOGMAINPANEL, + wxID_PROJECTDIALOGPROJECTNAME, wxID_PROJECTDIALOGCOMPANYNAME, + wxID_PROJECTDIALOGCOMPANYURL, wxID_PROJECTDIALOGPRODUCTNAME, + wxID_PROJECTDIALOGPRODUCTVERSION, wxID_PROJECTDIALOGPRODUCTRELEASE, + wxID_PROJECTDIALOGCONTENTDESCRIPTION, wxID_PROJECTDIALOGSTATICTEXT1, + wxID_PROJECTDIALOGSTATICTEXT2, wxID_PROJECTDIALOGSTATICTEXT3, + wxID_PROJECTDIALOGSTATICTEXT4, wxID_PROJECTDIALOGSTATICTEXT5, + wxID_PROJECTDIALOGSTATICTEXT6, wxID_PROJECTDIALOGSTATICTEXT7, +] = [wx.NewId() for _init_ctrls in range(16)] + +class ProjectDialog(wx.Dialog): + def _init_coll_flexGridSizer1_Items(self, parent): + # generated method, don't edit + + parent.AddWindow(self.MainPanel, 0, border=0, flag=0) + + def _init_sizers(self): + # generated method, don't edit + self.flexGridSizer1 = wx.FlexGridSizer(cols=1, hgap=0, rows=2, vgap=0) + + self._init_coll_flexGridSizer1_Items(self.flexGridSizer1) + + self.SetSizer(self.flexGridSizer1) + + def _init_ctrls(self, prnt): + # generated method, don't edit + wx.Dialog.__init__(self, id=wxID_PROJECTDIALOG, + name='ProjectDialog', parent=prnt, pos=wx.Point(376, 223), + size=wx.Size(550, 450), style=wx.DEFAULT_DIALOG_STYLE, + title='Create a new project') + self.SetClientSize(wx.Size(550, 450)) + + self.MainPanel = wx.Panel(id=wxID_PROJECTDIALOGMAINPANEL, + name='MainPanel', parent=self, pos=wx.Point(0, 0), + size=wx.Size(450, 400), style=wx.TAB_TRAVERSAL) + self.MainPanel.SetAutoLayout(True) + + self.staticText1 = wx.StaticText(id=wxID_PROJECTDIALOGSTATICTEXT1, + label='Project Name (required):', name='staticText1', parent=self.MainPanel, + pos=wx.Point(24, 24), size=wx.Size(215, 17), style=0) + + self.ProjectName = wx.TextCtrl(id=wxID_PROJECTDIALOGPROJECTNAME, + name='ProjectName', parent=self.MainPanel, pos=wx.Point(224, 24), + size=wx.Size(295, 24), style=0) + + self.staticText2 = wx.StaticText(id=wxID_PROJECTDIALOGSTATICTEXT2, + label='Company Name (required):', name='staticText2', parent=self.MainPanel, + pos=wx.Point(24, 64), size=wx.Size(215, 17), style=0) + + self.CompanyName = wx.TextCtrl(id=wxID_PROJECTDIALOGCOMPANYNAME, + name='CompanyName', parent=self.MainPanel, pos=wx.Point(224, 64), + size=wx.Size(295, 24), style=0) + + self.staticText3 = wx.StaticText(id=wxID_PROJECTDIALOGSTATICTEXT3, + label='Company URL (optional):', name='staticText3', parent=self.MainPanel, + pos=wx.Point(24, 104), size=wx.Size(215, 17), style=0) + + self.CompanyURL = wx.TextCtrl(id=wxID_PROJECTDIALOGCOMPANYURL, + name='CompanyURL', parent=self.MainPanel, pos=wx.Point(224, 104), + size=wx.Size(295, 24), style=0) + + self.staticText4 = wx.StaticText(id=wxID_PROJECTDIALOGSTATICTEXT4, + label='Product Name (required):', name='staticText4', parent=self.MainPanel, + pos=wx.Point(24, 144), size=wx.Size(215, 17), style=0) + + self.ProductName = wx.TextCtrl(id=wxID_PROJECTDIALOGPRODUCTNAME, + name='ProductName', parent=self.MainPanel, pos=wx.Point(224, 144), + size=wx.Size(295, 24), style=0) + + self.staticText5 = wx.StaticText(id=wxID_PROJECTDIALOGSTATICTEXT5, + label='Product Version (required):', name='staticText5', parent=self.MainPanel, + pos=wx.Point(24, 184), size=wx.Size(215, 17), style=0) + + self.ProductVersion = wx.TextCtrl(id=wxID_PROJECTDIALOGPRODUCTVERSION, + name='ProductVersion', parent=self.MainPanel, pos=wx.Point(224, 184), + size=wx.Size(295, 24), style=0) + + self.staticText6 = wx.StaticText(id=wxID_PROJECTDIALOGSTATICTEXT6, + label='Product Release (optional):', name='staticText6', parent=self.MainPanel, + pos=wx.Point(24, 224), size=wx.Size(215, 17), style=0) + + self.ProductRelease = wx.TextCtrl(id=wxID_PROJECTDIALOGPRODUCTRELEASE, + name='ProductRelease', parent=self.MainPanel, pos=wx.Point(224, 224), + size=wx.Size(295, 24), style=0) + + self.staticText7 = wx.StaticText(id=wxID_PROJECTDIALOGSTATICTEXT7, + label='Content Description (optional):', name='staticText7', parent=self.MainPanel, + pos=wx.Point(24, 264), size=wx.Size(215, 17), style=0) + + self.ContentDescription = wx.TextCtrl(id=wxID_PROJECTDIALOGCONTENTDESCRIPTION, + name='ProductRelease', parent=self.MainPanel, pos=wx.Point(224, 264), + size=wx.Size(295, 120), style=wxTE_MULTILINE) + + self._init_sizers() + + def __init__(self, parent): + self._init_ctrls(parent) + self.ButtonSizer = self.CreateButtonSizer(wxOK|wxCANCEL) + self.flexGridSizer1.Add(self.ButtonSizer, 1, wxALIGN_RIGHT) + + EVT_BUTTON(self, self.ButtonSizer.GetAffirmativeButton().GetId(), self.OnOK) + + def OnOK(self, event): + error = [] + if self.ProjectName.GetValue() == "": + error.append("Project Name") + if self.CompanyName.GetValue() == "": + error.append("Company Name") + if self.ProductName.GetValue() == "": + error.append("Product Name") + if self.ProductVersion.GetValue() == "": + error.append("Product Version") + if len(error) > 0: + text = "" + for i, item in enumerate(error): + if i == 0: + text += item + elif i == len(error) - 1: + text += " and %s"%item + else: + text += ", %s"%item + message = wxMessageDialog(self, "Form isn't complete. %s must be filled!"%text, "Error", wxOK|wxICON_ERROR) + message.ShowModal() + message.Destroy() + else: + self.EndModal(wxID_OK) + + def SetValues(self, values): + for item, value in values.items(): + if item == "projectName": + self.ProjectName.SetValue(value) + elif item == "companyName": + self.CompanyName.SetValue(value) + elif item == "companyURL": + self.CompanyURL.SetValue(value) + elif item == "productName": + self.ProductName.SetValue(value) + elif item == "productVersion": + self.ProductVersion.SetValue(value) + elif item == "productRelease": + self.ProductRelease.SetValue(value) + elif item == "contentDescription": + self.ContentDescription.SetValue(value) + + def GetValues(self): + values = {} + values["projectName"] = self.ProjectName.GetValue() + values["companyName"] = self.CompanyName.GetValue() + if self.CompanyURL.GetValue() != None: + values["companyURL"] = self.CompanyURL.GetValue() + values["productName"] = self.ProductName.GetValue() + values["productVersion"] = self.ProductVersion.GetValue() + if self.ProductRelease.GetValue() != None: + values["productRelease"] = self.ProductRelease.GetValue() + if self.ProductRelease.GetValue() != None: + values["contentDescription"] = self.ContentDescription.GetValue() + return values + +#------------------------------------------------------------------------------- +# Create Pou Dialog +#------------------------------------------------------------------------------- + +[wxID_POUDIALOG, wxID_POUDIALOGMAINPANEL, wxID_POUDIALOGPOUNAME, + wxID_POUDIALOGPOUTYPE, wxID_POUDIALOGLANGUAGE, wxID_POUDIALOGSTATICTEXT1, + wxID_POUDIALOGSTATICTEXT2, wxID_POUDIALOGSTATICTEXT3, +] = [wx.NewId() for _init_ctrls in range(8)] + +class PouDialog(wx.Dialog): + def _init_coll_flexGridSizer1_Items(self, parent): + # generated method, don't edit + + parent.AddWindow(self.MainPanel, 0, border=0, flag=0) + + def _init_sizers(self): + # generated method, don't edit + self.flexGridSizer1 = wx.FlexGridSizer(cols=1, hgap=0, rows=2, vgap=0) + + self._init_coll_flexGridSizer1_Items(self.flexGridSizer1) + + self.SetSizer(self.flexGridSizer1) + + def _init_ctrls(self, prnt): + # generated method, don't edit + wx.Dialog.__init__(self, id=wxID_POUDIALOG, + name='ProjectDialog', parent=prnt, pos=wx.Point(376, 223), + size=wx.Size(300, 200), style=wx.DEFAULT_DIALOG_STYLE, + title='Create a new project') + self.SetClientSize(wx.Size(300, 200)) + + self.MainPanel = wx.Panel(id=wxID_POUDIALOGMAINPANEL, + name='MainPanel', parent=self, pos=wx.Point(0, 0), + size=wx.Size(300, 200), style=wx.TAB_TRAVERSAL) + self.MainPanel.SetAutoLayout(True) + + self.staticText1 = wx.StaticText(id=wxID_POUDIALOGSTATICTEXT1, + label='POU Name:', name='staticText1', parent=self.MainPanel, + pos=wx.Point(24, 24), size=wx.Size(95, 17), style=0) + + self.PouName = wx.TextCtrl(id=wxID_POUDIALOGPOUNAME, + name='POUName', parent=self.MainPanel, pos=wx.Point(104, 24), + size=wx.Size(150, 24), style=0) + + self.staticText2 = wx.StaticText(id=wxID_POUDIALOGSTATICTEXT2, + label='POU Type:', name='staticText2', parent=self.MainPanel, + pos=wx.Point(24, 64), size=wx.Size(95, 17), style=0) + + self.PouType = wx.Choice(id=wxID_POUDIALOGPOUTYPE, + name='POUType', parent=self.MainPanel, pos=wx.Point(104, 64), + size=wx.Size(150, 24), style=0) + EVT_CHOICE(self, wxID_POUDIALOGPOUTYPE, self.OnTypeChanged) + + self.staticText3 = wx.StaticText(id=wxID_POUDIALOGSTATICTEXT3, + label='Language:', name='staticText3', parent=self.MainPanel, + pos=wx.Point(24, 104), size=wx.Size(95, 17), style=0) + + self.Language = wx.Choice(id=wxID_POUDIALOGLANGUAGE, + name='Language', parent=self.MainPanel, pos=wx.Point(104, 104), + size=wx.Size(150, 24), style=0) + + self._init_sizers() + + def __init__(self, parent): + self._init_ctrls(parent) + self.ButtonSizer = self.CreateButtonSizer(wxOK|wxCANCEL) + self.flexGridSizer1.Add(self.ButtonSizer, 1, wxALIGN_RIGHT) + + for option in ["function","functionBlock","program"]: + self.PouType.Append(option) + self.RefreshLanguage() + + EVT_BUTTON(self, self.ButtonSizer.GetAffirmativeButton().GetId(), self.OnOK) + + def OnOK(self, event): + error = [] + pou_name = self.PouName.GetValue() + if pou_name == "": + error.append("POU Name") + if self.PouType.GetStringSelection() == "": + error.append("POU Type") + if self.Language.GetStringSelection() == "": + error.append("Language") + if len(error) > 0: + text = "" + for i, item in enumerate(error): + if i == 0: + text += item + elif i == len(error) - 1: + text += " and %s"%item + else: + text += ", %s"%item + message = wxMessageDialog(self, "Form isn't complete. %s must be filled!"%text, "Error", wxOK|wxICON_ERROR) + message.ShowModal() + message.Destroy() + elif not TestIdentifier(pou_name): + message = wxMessageDialog(self, "\"%s\" is not a valid identifier!"%pou_name, "Error", wxOK|wxICON_ERROR) + message.ShowModal() + message.Destroy() + elif pou_name.upper() in IEC_KEYWORDS: + message = wxMessageDialog(self, "\"%s\" is a keyword. It can't be used!"%pou_name, "Error", wxOK|wxICON_ERROR) + message.ShowModal() + message.Destroy() + elif pou_name.upper() in self.PouNames: + message = wxMessageDialog(self, "\"%s\" pou already exists!"%pou_name, "Error", wxOK|wxICON_ERROR) + message.ShowModal() + message.Destroy() + else: + self.EndModal(wxID_OK) + + def RefreshLanguage(self): + selection = self.Language.GetStringSelection() + self.Language.Clear() + for option in ["IL","ST","LD","FBD","SFC"]: + if option != "SFC" or self.PouType.GetStringSelection() == "program": + self.Language.Append(option) + if self.Language.FindString(selection) != wxNOT_FOUND: + self.Language.SetStringSelection(selection) + + def OnTypeChanged(self, event): + self.RefreshLanguage() + event.Skip() + + def SetPouNames(self, pou_names): + self.PouNames = [pou_name.upper() for pou_name in pou_names] + + def SetValues(self, values): + for item, value in values.items(): + if item == "pouName": + self.PouName.SetValue(value) + elif item == "pouType": + self.PouType.SetStringSelection(value) + elif item == "language": + self.Language.SetStringSelection(value) + + def GetValues(self): + values = {} + values["pouName"] = self.PouName.GetValue() + values["pouType"] = self.PouType.GetStringSelection() + values["language"] = self.Language.GetStringSelection() + return values + + +#------------------------------------------------------------------------------- +# Create Pou Transition Dialog +#------------------------------------------------------------------------------- + +[wxID_POUTRANSITIONDIALOG, wxID_POUTRANSITIONDIALOGMAINPANEL, + wxID_POUTRANSITIONDIALOGPOUNAME, wxID_POUTRANSITIONDIALOGTRANSITIONNAME, + wxID_POUTRANSITIONDIALOGLANGUAGE, wxID_POUTRANSITIONDIALOGSTATICTEXT1, + wxID_POUTRANSITIONDIALOGSTATICTEXT2, wxID_POUTRANSITIONDIALOGSTATICTEXT3, +] = [wx.NewId() for _init_ctrls in range(8)] + +class PouTransitionDialog(wx.Dialog): + def _init_coll_flexGridSizer1_Items(self, parent): + # generated method, don't edit + + parent.AddWindow(self.MainPanel, 0, border=0, flag=0) + + def _init_sizers(self): + # generated method, don't edit + self.flexGridSizer1 = wx.FlexGridSizer(cols=1, hgap=0, rows=2, vgap=0) + + self._init_coll_flexGridSizer1_Items(self.flexGridSizer1) + + self.SetSizer(self.flexGridSizer1) + + def _init_ctrls(self, prnt): + # generated method, don't edit + wx.Dialog.__init__(self, id=wxID_POUTRANSITIONDIALOG, + name='ProjectDialog', parent=prnt, pos=wx.Point(376, 223), + size=wx.Size(350, 200), style=wx.DEFAULT_DIALOG_STYLE, + title='Create a new project') + self.SetClientSize(wx.Size(350, 200)) + + self.MainPanel = wx.Panel(id=wxID_POUTRANSITIONDIALOGMAINPANEL, + name='MainPanel', parent=self, pos=wx.Point(0, 0), + size=wx.Size(350, 200), style=wx.TAB_TRAVERSAL) + self.MainPanel.SetAutoLayout(True) + + self.staticText1 = wx.StaticText(id=wxID_POUTRANSITIONDIALOGSTATICTEXT1, + label='POU Name:', name='staticText1', parent=self.MainPanel, + pos=wx.Point(24, 24), size=wx.Size(145, 17), style=0) + + self.PouName = wx.Choice(id=wxID_POUTRANSITIONDIALOGPOUNAME, + name='POUName', parent=self.MainPanel, pos=wx.Point(154, 24), + size=wx.Size(150, 24), style=0) + + self.staticText2 = wx.StaticText(id=wxID_POUTRANSITIONDIALOGSTATICTEXT2, + label='Transition Name:', name='staticText2', parent=self.MainPanel, + pos=wx.Point(24, 64), size=wx.Size(145, 17), style=0) + + self.TransitionName = wx.TextCtrl(id=wxID_POUTRANSITIONDIALOGTRANSITIONNAME, + name='TransitionName', parent=self.MainPanel, pos=wx.Point(154, 64), + size=wx.Size(150, 24), style=0) + + self.staticText3 = wx.StaticText(id=wxID_POUTRANSITIONDIALOGSTATICTEXT3, + label='Language:', name='staticText3', parent=self.MainPanel, + pos=wx.Point(24, 104), size=wx.Size(145, 17), style=0) + + self.Language = wx.Choice(id=wxID_POUTRANSITIONDIALOGLANGUAGE, + name='Language', parent=self.MainPanel, pos=wx.Point(154, 104), + size=wx.Size(150, 24), style=0) + + self._init_sizers() + + def __init__(self, parent): + self._init_ctrls(parent) + self.ButtonSizer = self.CreateButtonSizer(wxOK|wxCANCEL) + self.flexGridSizer1.Add(self.ButtonSizer, 1, wxALIGN_RIGHT) + + for option in ["IL","ST","LD","FBD"]: + self.Language.Append(option) + + EVT_BUTTON(self, self.ButtonSizer.GetAffirmativeButton().GetId(), self.OnOK) + + def OnOK(self, event): + error = [] + if self.PouName.GetStringSelection() == "": + error.append("POU Name") + if self.TransitionName.GetValue() == "": + error.append("Transition Name") + if self.Language.GetStringSelection() == "": + error.append("Language") + if len(error) > 0: + text = "" + for i, item in enumerate(error): + if i == 0: + text += item + elif i == len(error) - 1: + text += " and %s"%item + else: + text += ", %s"%item + message = wxMessageDialog(self, "Form isn't complete. %s must be filled!"%text, "Error", wxOK|wxICON_ERROR) + message.ShowModal() + message.Destroy() + else: + self.EndModal(wxID_OK) + + def SetPous(self, pous): + for pou in pous: + self.PouName.Append(pou) + + def SetValues(self, values): + for item, value in values.items(): + if item == "pouName": + self.PouName.SetStringSelection(value) + elif item == "transitionName": + self.TransitionName.SetValue(value) + elif item == "language": + self.Language.SetStringSelection(value) + + def GetValues(self): + values = {} + values["pouName"] = self.PouName.GetStringSelection() + values["transitionName"] = self.TransitionName.GetValue() + values["language"] = self.Language.GetStringSelection() + return values + +#------------------------------------------------------------------------------- +# Create Pou Action Dialog +#------------------------------------------------------------------------------- + +[wxID_POUACTIONDIALOG, wxID_POUACTIONDIALOGMAINPANEL, + wxID_POUACTIONDIALOGPOUNAME, wxID_POUACTIONDIALOGACTIONNAME, + wxID_POUACTIONDIALOGLANGUAGE, wxID_POUACTIONDIALOGSTATICTEXT1, + wxID_POUACTIONDIALOGSTATICTEXT2, wxID_POUACTIONDIALOGSTATICTEXT3, +] = [wx.NewId() for _init_ctrls in range(8)] + +class PouActionDialog(wx.Dialog): + def _init_coll_flexGridSizer1_Items(self, parent): + # generated method, don't edit + + parent.AddWindow(self.MainPanel, 0, border=0, flag=0) + + def _init_sizers(self): + # generated method, don't edit + self.flexGridSizer1 = wx.FlexGridSizer(cols=1, hgap=0, rows=2, vgap=0) + + self._init_coll_flexGridSizer1_Items(self.flexGridSizer1) + + self.SetSizer(self.flexGridSizer1) + + def _init_ctrls(self, prnt): + # generated method, don't edit + wx.Dialog.__init__(self, id=wxID_POUACTIONDIALOG, + name='ProjectDialog', parent=prnt, pos=wx.Point(376, 223), + size=wx.Size(320, 200), style=wx.DEFAULT_DIALOG_STYLE, + title='Create a new project') + self.SetClientSize(wx.Size(320, 200)) + + self.MainPanel = wx.Panel(id=wxID_POUACTIONDIALOGMAINPANEL, + name='MainPanel', parent=self, pos=wx.Point(0, 0), + size=wx.Size(350, 200), style=wx.TAB_TRAVERSAL) + self.MainPanel.SetAutoLayout(True) + + self.staticText1 = wx.StaticText(id=wxID_POUACTIONDIALOGSTATICTEXT1, + label='POU Name:', name='staticText1', parent=self.MainPanel, + pos=wx.Point(24, 24), size=wx.Size(145, 17), style=0) + + self.PouName = wx.Choice(id=wxID_POUACTIONDIALOGPOUNAME, + name='POUName', parent=self.MainPanel, pos=wx.Point(124, 24), + size=wx.Size(150, 24), style=0) + + self.staticText2 = wx.StaticText(id=wxID_POUACTIONDIALOGSTATICTEXT2, + label='Action Name:', name='staticText2', parent=self.MainPanel, + pos=wx.Point(24, 64), size=wx.Size(145, 17), style=0) + + self.ActionName = wx.TextCtrl(id=wxID_POUACTIONDIALOGACTIONNAME, + name='ActionName', parent=self.MainPanel, pos=wx.Point(124, 64), + size=wx.Size(150, 24), style=0) + + self.staticText3 = wx.StaticText(id=wxID_POUACTIONDIALOGSTATICTEXT3, + label='Language:', name='staticText3', parent=self.MainPanel, + pos=wx.Point(24, 104), size=wx.Size(145, 17), style=0) + + self.Language = wx.Choice(id=wxID_POUACTIONDIALOGLANGUAGE, + name='Language', parent=self.MainPanel, pos=wx.Point(124, 104), + size=wx.Size(150, 24), style=0) + + self._init_sizers() + + def __init__(self, parent): + self._init_ctrls(parent) + self.ButtonSizer = self.CreateButtonSizer(wxOK|wxCANCEL) + self.flexGridSizer1.Add(self.ButtonSizer, 1, wxALIGN_RIGHT) + + for option in ["IL","ST","LD","FBD"]: + self.Language.Append(option) + + EVT_BUTTON(self, self.ButtonSizer.GetAffirmativeButton().GetId(), self.OnOK) + + def OnOK(self, event): + error = [] + if self.PouName.GetStringSelection() == "": + error.append("POU Name") + if self.ActionName.GetValue() == "": + error.append("Action Name") + if self.Language.GetStringSelection() == "": + error.append("Language") + if len(error) > 0: + text = "" + for i, item in enumerate(error): + if i == 0: + text += item + elif i == len(error) - 1: + text += " and %s"%item + else: + text += ", %s"%item + message = wxMessageDialog(self, "Form isn't complete. %s must be filled!"%text, "Error", wxOK|wxICON_ERROR) + message.ShowModal() + message.Destroy() + else: + self.EndModal(wxID_OK) + + def SetPous(self, pous): + for pou in pous: + self.PouName.Append(pou) + + def SetValues(self, values): + for item, value in values.items(): + if item == "pouName": + self.PouName.SetStringSelection(value) + elif item == "actionName": + self.ActionName.SetValue(value) + elif item == "language": + self.Language.SetStringSelection(value) + + def GetValues(self): + values = {} + values["pouName"] = self.PouName.GetStringSelection() + values["actionName"] = self.ActionName.GetValue() + values["language"] = self.Language.GetStringSelection() + return values + +#------------------------------------------------------------------------------- +# Pou Interface Dialog +#------------------------------------------------------------------------------- + +class VariableTable(wxPyGridTableBase): + + """ + A custom wxGrid Table using user supplied data + """ + def __init__(self, parent, data, colnames): + # The base class must be initialized *first* + wxPyGridTableBase.__init__(self) + self.data = data + self.colnames = colnames + self.Parent = parent + # XXX + # we need to store the row length and collength to + # see if the table has changed size + self._rows = self.GetNumberRows() + self._cols = self.GetNumberCols() + + def GetNumberCols(self): + return len(self.colnames) + + def GetNumberRows(self): + return len(self.data) + + def GetColLabelValue(self, col): + if col < len(self.colnames): + return self.colnames[col] + + def GetRowLabelValues(self, row): + return row + + def GetValue(self, row, col): + if row < self.GetNumberRows(): + name = str(self.data[row].get(self.GetColLabelValue(col), "")) + return name + + def GetValueByName(self, row, colname): + return self.data[row].get(colname) + + def SetValue(self, row, col, value): + if col < len(self.colnames): + self.data[row][self.GetColLabelValue(col)] = value + + def ResetView(self, grid): + """ + (wxGrid) -> Reset the grid view. Call this to + update the grid if rows and columns have been added or deleted + """ + grid.BeginBatch() + for current, new, delmsg, addmsg in [ + (self._rows, self.GetNumberRows(), wxGRIDTABLE_NOTIFY_ROWS_DELETED, wxGRIDTABLE_NOTIFY_ROWS_APPENDED), + (self._cols, self.GetNumberCols(), wxGRIDTABLE_NOTIFY_COLS_DELETED, wxGRIDTABLE_NOTIFY_COLS_APPENDED), + ]: + if new < current: + msg = wxGridTableMessage(self,delmsg,new,current-new) + grid.ProcessTableMessage(msg) + elif new > current: + msg = wxGridTableMessage(self,addmsg,new-current) + grid.ProcessTableMessage(msg) + self.UpdateValues(grid) + grid.EndBatch() + + self._rows = self.GetNumberRows() + self._cols = self.GetNumberCols() + # update the column rendering scheme + self._updateColAttrs(grid) + + # update the scrollbars and the displayed part of the grid + grid.AdjustScrollbars() + grid.ForceRefresh() + + def UpdateValues(self, grid): + """Update all displayed values""" + # This sends an event to the grid table to update all of the values + msg = wxGridTableMessage(self, wxGRIDTABLE_REQUEST_VIEW_GET_VALUES) + grid.ProcessTableMessage(msg) + + def _updateColAttrs(self, grid): + """ + wxGrid -> update the column attributes to add the + appropriate renderer given the column name. + + Otherwise default to the default renderer. + """ + + for col in range(self.GetNumberCols()): + attr = wxGridCellAttr() + attr.SetAlignment(self.Parent.ColAlignements[col], wxALIGN_CENTRE) + grid.SetColAttr(col, attr) + grid.SetColSize(col, self.Parent.ColSizes[col]) + + typelist = None + accesslist = None + for row in range(self.GetNumberRows()): + for col in range(self.GetNumberCols()): + editor = None + renderer = None + colname = self.GetColLabelValue(col) + grid.SetReadOnly(row, col, False) + if colname in ["Name","Initial Value","Location"]: + editor = wxGridCellTextEditor() + renderer = wxGridCellStringRenderer() + elif colname == "Class": + if len(self.Parent.ClassList) == 1: + grid.SetReadOnly(row, col, True) + else: + editor = wxGridCellChoiceEditor() + editor.SetParameters(",".join(self.Parent.ClassList)) + elif colname == "Type": + editor = wxGridCellChoiceEditor() + editor.SetParameters(self.Parent.TypeList) + elif colname in ["Retain", "Constant"]: + editor = wxGridCellChoiceEditor() + editor.SetParameters(self.Parent.OptionList) + + grid.SetCellEditor(row, col, editor) + grid.SetCellRenderer(row, col, renderer) + + grid.SetCellBackgroundColour(row, col, wxWHITE) + + def SetData(self, data): + self.data = data + + def GetData(self): + return self.data + + def GetCurrentIndex(self): + return self.CurrentIndex + + def SetCurrentIndex(self, index): + self.CurrentIndex = index + + def AppendRow(self, row_content): + self.data.append(row_content) + + def RemoveRow(self, row_index): + self.data.pop(row_index) + + def MoveRow(self, row_index, move, grid): + new_index = max(0, min(row_index + move, len(self.data) - 1)) + if new_index != row_index: + self.data.insert(new_index, self.data.pop(row_index)) + grid.SetGridCursor(new_index, grid.GetGridCursorCol()) + + def Empty(self): + self.data = [] + self.editors = [] + +[wxID_EDITVARIABLEDIALOG, wxID_EDITVARIABLEDIALOGMAINPANEL, + wxID_EDITVARIABLEDIALOGVARIABLESGRID, wxID_EDITVARIABLEDIALOGRETURNTYPE, + wxID_EDITVARIABLEDIALOGCLASSFILTER, wxID_EDITVARIABLEDIALOGADDBUTTON, + wxID_EDITVARIABLEDIALOGDELETEBUTTON, wxID_EDITVARIABLEDIALOGUPBUTTON, + wxID_EDITVARIABLEDIALOGDOWNBUTTON, wxID_EDITVARIABLEDIALOGSTATICTEXT1, + wxID_EDITVARIABLEDIALOGSTATICTEXT2, wxID_EDITVARIABLEDIALOGSTATICTEXT3, +] = [wx.NewId() for _init_ctrls in range(12)] + +class EditVariableDialog(wx.Dialog): + def _init_coll_flexGridSizer1_Items(self, parent): + # generated method, don't edit + + parent.AddWindow(self.MainPanel, 0, border=0, flag=0) + + def _init_sizers(self): + # generated method, don't edit + self.flexGridSizer1 = wx.FlexGridSizer(cols=1, hgap=0, rows=2, vgap=0) + + self._init_coll_flexGridSizer1_Items(self.flexGridSizer1) + + self.SetSizer(self.flexGridSizer1) + + def _init_ctrls(self, prnt, name): + # generated method, don't edit + wx.Dialog.__init__(self, id=wxID_EDITVARIABLEDIALOG, + name='EditVariableDialog', parent=prnt, pos=wx.Point(376, 223), + size=wx.Size(600, 440), style=wx.DEFAULT_DIALOG_STYLE, + title='Edit variables of %s'%name) + self.SetClientSize(wx.Size(600, 440)) + + self.MainPanel = wx.Panel(id=wxID_EDITVARIABLEDIALOGMAINPANEL, + name='MainPanel', parent=self, pos=wx.Point(0, 0), + size=wx.Size(600, 440), style=wx.TAB_TRAVERSAL) + self.MainPanel.SetAutoLayout(True) + + self.staticText1 = wx.StaticText(id=wxID_EDITVARIABLEDIALOGSTATICTEXT1, + label='Return Type:', name='staticText1', parent=self.MainPanel, + pos=wx.Point(24, 29), size=wx.Size(95, 17), style=0) + + self.ReturnType = wx.Choice(id=wxID_EDITVARIABLEDIALOGRETURNTYPE, + name='ReturnType', parent=self.MainPanel, pos=wx.Point(124, 24), + size=wx.Size(145, 24), style=0) + + self.staticText2 = wx.StaticText(id=wxID_EDITVARIABLEDIALOGSTATICTEXT2, + label='Class Filter:', name='staticText2', parent=self.MainPanel, + pos=wx.Point(324, 29), size=wx.Size(95, 17), style=0) + + self.ClassFilter = wx.Choice(id=wxID_EDITVARIABLEDIALOGCLASSFILTER, + name='ClassFilter', parent=self.MainPanel, pos=wx.Point(424, 24), + size=wx.Size(145, 24), style=0) + EVT_CHOICE(self, wxID_EDITVARIABLEDIALOGCLASSFILTER, self.OnClassFilter) + + self.staticText3 = wx.StaticText(id=wxID_EDITVARIABLEDIALOGSTATICTEXT3, + label='Variables:', name='staticText3', parent=self.MainPanel, + pos=wx.Point(24, 60), size=wx.Size(95, 17), style=0) + + self.VariablesGrid = wx.grid.Grid(id=wxID_EDITVARIABLEDIALOGVARIABLESGRID, + name='VariablesGrid', parent=self.MainPanel, pos=wx.Point(24, 80), + size=wx.Size(550, 250), style=wxVSCROLL) + self.VariablesGrid.SetFont(wx.Font(12, 77, wx.NORMAL, wx.NORMAL, False, + 'Sans')) + self.VariablesGrid.SetLabelFont(wx.Font(10, 77, wx.NORMAL, wx.NORMAL, + False, 'Sans')) + self.VariablesGrid.DisableDragGridSize() + self.VariablesGrid.EnableScrolling(False, True) + + self.AddButton = wx.Button(id=wxID_EDITVARIABLEDIALOGADDBUTTON, label='Add', + name='AddButton', parent=self.MainPanel, pos=wx.Point(345, 340), + size=wx.Size(72, 32), style=0) + EVT_BUTTON(self, wxID_EDITVARIABLEDIALOGADDBUTTON, self.OnAddButton) + + self.DeleteButton = wx.Button(id=wxID_EDITVARIABLEDIALOGDELETEBUTTON, label='Delete', + name='DeleteButton', parent=self.MainPanel, pos=wx.Point(425, 340), + size=wx.Size(72, 32), style=0) + EVT_BUTTON(self, wxID_EDITVARIABLEDIALOGDELETEBUTTON, self.OnDeleteButton) + + self.UpButton = wx.Button(id=wxID_EDITVARIABLEDIALOGUPBUTTON, label='^', + name='UpButton', parent=self.MainPanel, pos=wx.Point(505, 340), + size=wx.Size(32, 32), style=0) + EVT_BUTTON(self, wxID_EDITVARIABLEDIALOGUPBUTTON, self.OnUpButton) + + self.DownButton = wx.Button(id=wxID_EDITVARIABLEDIALOGDOWNBUTTON, label='v', + name='DownButton', parent=self.MainPanel, pos=wx.Point(545, 340), + size=wx.Size(32, 32), style=0) + EVT_BUTTON(self, wxID_EDITVARIABLEDIALOGDOWNBUTTON, self.OnDownButton) + + self._init_sizers() + + def __init__(self, parent, name, pou_type, filter = "All"): + self._init_ctrls(parent, name) + self.ButtonSizer = self.CreateButtonSizer(wxOK|wxCANCEL) + self.flexGridSizer1.Add(self.ButtonSizer, 1, wxALIGN_RIGHT) + self.Filter = filter + self.FilterChoices = [] + self.FilterChoiceTransfer = {"All" : "All", "Interface" : "Interface", + "Input" : " Input", "Output" : " Output", "InOut" : " InOut", + "External" : " External", "Variables" : "Variables", "Local" : " Local", + "Temp" : " Temp", "Global" : "Global", "Access" : "Access"} + + if pou_type: + self.DefaultValue = {"Name" : "", "Class" : "Input", "Type" : "INT", "Location" : "", "Initial Value" : "", "Retain" : "No", "Constant" : "No"} + else: + self.DefaultValue = {"Name" : "", "Class" : "Global", "Type" : "INT", "Location" : "", "Initial Value" : "", "Retain" : "No", "Constant" : "No"} + if not pou_type or pou_type == "program": + self.Table = VariableTable(self, [], ["Name", "Class", "Type", "Location", "Initial Value", "Retain", "Constant"]) + if pou_type: + self.FilterChoices = ["All","Interface"," Input"," Output"," InOut"," External","Variables"," Local"," Temp","Global","Access"] + else: + self.FilterChoices = ["All","Global","Access"] + self.ColSizes = [80, 70, 80, 80, 80, 60, 70] + self.ColAlignements = [wxALIGN_LEFT, wxALIGN_LEFT, wxALIGN_LEFT, wxALIGN_LEFT, wxALIGN_LEFT, wxALIGN_CENTER, wxALIGN_CENTER] + else: + self.Table = VariableTable(self, [], ["Name", "Class", "Type", "Initial Value", "Retain", "Constant"]) + self.FilterChoices = ["All","Interface"," Input"," Output"," InOut"," External","Variables"," Local"," Temp"] + self.ColSizes = [120, 70, 80, 120, 60, 70] + self.ColAlignements = [wxALIGN_LEFT, wxALIGN_LEFT, wxALIGN_LEFT, wxALIGN_LEFT, wxALIGN_CENTER, wxALIGN_CENTER] + for choice in self.FilterChoices: + self.ClassFilter.Append(choice) + self.ClassFilter.SetStringSelection(self.FilterChoiceTransfer[self.Filter]) + self.RefreshTypeList() + self.RefreshUpDownButtons() + + self.OptionList = "Yes,No" + self.TypeList = "" + for value in TypeHierarchy.keys(): + if not value.startswith("ANY"): + self.TypeList += "%s,"%value + self.TypeList = self.TypeList[:-1] + + if pou_type == "function": + for value in TypeHierarchy.keys(): + if not value.startswith("ANY"): + self.ReturnType.Append(value) + self.ReturnType.Enable(True) + else: + self.ReturnType.Enable(False) + self.staticText2.Hide() + self.ReturnType.Hide() + + self.VariablesGrid.SetTable(self.Table) + self.VariablesGrid.SetRowLabelSize(0) + + self.Table.ResetView(self.VariablesGrid) + + EVT_BUTTON(self, self.ButtonSizer.GetAffirmativeButton().GetId(), self.OnOK) + + def OnOK(self, event): + self.VariablesGrid.SetGridCursor(0, 0) + error = [] + if self.ReturnType.IsEnabled() and self.ReturnType.GetStringSelection() == "": + error.append("Return Type") + if len(error) > 0: + text = "" + for i, item in enumerate(error): + if i == 0: + text += item + elif i == len(error) - 1: + text += " and %s"%item + else: + text += ", %s"%item + message = wxMessageDialog(self, "Form isn't complete. %s must be filled!"%text, "Error", wxOK|wxICON_ERROR) + message.ShowModal() + message.Destroy() + else: + self.EndModal(wxID_OK) + + def OnClassFilter(self, event): + reverse_transfer = {} + for filter, choice in self.FilterChoiceTransfer.items(): + reverse_transfer[choice] = filter + self.Filter = reverse_transfer[self.ClassFilter.GetStringSelection()] + self.RefreshTypeList() + self.RefreshValues() + self.RefreshUpDownButtons() + event.Skip() + + def RefreshTypeList(self): + if self.Filter == "All": + self.ClassList = [choice for choice in self.FilterChoices if choice not in ["All","Interface","Variables"]] + elif self.Filter == "Interface": + self.ClassList = ["Input","Output","InOut","External"] + elif self.Filter == "Variables": + self.ClassList = ["Local","Temp"] + else: + self.ClassList = [self.Filter] + + def RefreshUpDownButtons(self): + if self.Filter == "All": + self.UpButton.Enable(True) + self.DownButton.Enable(True) + else: + self.UpButton.Enable(False) + self.DownButton.Enable(False) + + def OnAddButton(self, event): + self.Table.AppendRow(self.DefaultValue.copy()) + self.Table.ResetView(self.VariablesGrid) + event.Skip() + + def OnDeleteButton(self, event): + row = self.VariablesGrid.GetGridCursorRow() + self.Table.RemoveRow(row) + self.Table.ResetView(self.VariablesGrid) + event.Skip() + + def OnUpButton(self, event): + row = self.VariablesGrid.GetGridCursorRow() + self.Table.MoveRow(row, -1, self.VariablesGrid) + self.Table.ResetView(self.VariablesGrid) + event.Skip() + + def OnDownButton(self, event): + row = self.VariablesGrid.GetGridCursorRow() + self.Table.MoveRow(row, 1, self.VariablesGrid) + self.Table.ResetView(self.VariablesGrid) + event.Skip() + + def SetValues(self, values): + for item, value in values.items(): + if item == "returnType" and value and self.ReturnType.IsEnabled(): + self.ReturnType.SetStringSelection(value) + if item == "data": + self.Values = value + self.RefreshValues() + + def RefreshValues(self): + data = [] + for variable in self.Values: + if variable["Class"] in self.ClassList: + data.append(variable) + self.Table.SetData(data) + self.Table.ResetView(self.VariablesGrid) + + def GetValues(self): + values = {} + if self.ReturnType.IsEnabled(): + values["returnType"] = self.ReturnType.GetStringSelection() + values["data"] = self.Table.GetData() + return values + +#------------------------------------------------------------------------------- +# Exception Handler +#------------------------------------------------------------------------------- + +Max_Traceback_List_Size = 20 + +def Display_Exception_Dialog(e_type,e_value,e_tb): + trcbck_lst = [] + for i,line in enumerate(traceback.extract_tb(e_tb)): + trcbck = " " + str(i+1) + ". " + if line[0].find(os.getcwd()) == -1: + trcbck += "file : " + str(line[0]) + ", " + else: + trcbck += "file : " + str(line[0][len(os.getcwd()):]) + ", " + trcbck += "line : " + str(line[1]) + ", " + "function : " + str(line[2]) + trcbck_lst.append(trcbck) + + # Allow clicking.... + cap = wx.Window_GetCapture() + if cap: + cap.ReleaseMouse() + + dlg = wx.SingleChoiceDialog(None, + """ +An error happens. + +Click on OK for saving an error report. + +Please contact LOLITech at: ++33 (0)3 29 52 95 67 +bugs_PLCOpenEditor@lolitech.fr + + +Error: +""" + + str(e_type) + " : " + str(e_value), + "Error", + trcbck_lst) + try: + res = (dlg.ShowModal() == wx.ID_OK) + finally: + dlg.Destroy() + + return res + +def Display_Error_Dialog(e_value): + message = wxMessageDialog(None, str(e_value), "Error", wxOK|wxICON_ERROR) + message.ShowModal() + message.Destroy() + +def get_last_traceback(tb): + while tb.tb_next: + tb = tb.tb_next + return tb + + +def format_namespace(d, indent=' '): + return '\n'.join(['%s%s: %s' % (indent, k, repr(v)[:10000]) for k, v in d.iteritems()]) + + +ignored_exceptions = [] # a problem with a line in a module is only reported once per session + +def wxAddExceptHook(path, app_version='[No version]'):#, ignored_exceptions=[]): + + def handle_exception(e_type, e_value, e_traceback): + traceback.print_exception(e_type, e_value, e_traceback) # this is very helpful when there's an exception in the rest of this func + last_tb = get_last_traceback(e_traceback) + ex = (last_tb.tb_frame.f_code.co_filename, last_tb.tb_frame.f_lineno) + if str(e_value).startswith("!!!"): + Display_Error_Dialog(e_value) + elif ex not in ignored_exceptions: + result = Display_Exception_Dialog(e_type,e_value,e_traceback) + if result: + ignored_exceptions.append(ex) + info = { + 'app-title' : wx.GetApp().GetAppName(), # app_title + 'app-version' : app_version, + 'wx-version' : wx.VERSION_STRING, + 'wx-platform' : wx.Platform, + 'python-version' : platform.python_version(), #sys.version.split()[0], + 'platform' : platform.platform(), + 'e-type' : e_type, + 'e-value' : e_value, + 'date' : time.ctime(), + 'cwd' : os.getcwd(), + } + if e_traceback: + info['traceback'] = ''.join(traceback.format_tb(e_traceback)) + '%s: %s' % (e_type, e_value) + last_tb = get_last_traceback(e_traceback) + exception_locals = last_tb.tb_frame.f_locals # the locals at the level of the stack trace where the exception actually occurred + info['locals'] = format_namespace(exception_locals) + if 'self' in exception_locals: + info['self'] = format_namespace(exception_locals['self'].__dict__) + + output = open(path+os.sep+"bug_report_"+info['date'].replace(':','-').replace(' ','_')+".txt",'w') + lst = info.keys() + lst.sort() + for a in lst: + output.write(a+":\n"+str(info[a])+"\n\n") + + #sys.excepthook = lambda *args: wx.CallAfter(handle_exception, *args) + sys.excepthook = handle_exception + +if __name__ == '__main__': + app = wxPySimpleApp() + wxInitAllImageHandlers() + + # Install a exception handle for bug reports + wxAddExceptHook(os.getcwd(),__version__) + + frame = PLCOpenEditor(None) + + frame.Show() + app.MainLoop() +