Adding support for drag'n dropping variable from global defined in configurations and resources to POU variable panel or body editor for declaring external variables
Adding support for drag'n dropping located variables from topology panel to configurations and resources variable panel for declaring global located variables
#!/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) 2007: 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 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
#General Public License for more details.
#
#You should have received a copy of the GNU 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 datetime import datetime
import wx, wx.grid
if wx.VERSION >= (2, 8, 0):
import wx.aui
USE_AUI = True
else:
USE_AUI = False
import os, re, platform, sys, time, traceback, getopt
import cPickle
CWD = os.path.split(os.path.realpath(__file__))[0]
base_folder = os.path.split(CWD)[0]
sys.path.append(base_folder)
from docutils import *
from types import TupleType
__version__ = "$Revision: 1.130 $"
if __name__ == '__main__':
# Usage message displayed when help request or when error detected in
# command line
def usage():
print "\nUsage of PLCOpenEditor.py :"
print "\n %s [Filepath]\n"%sys.argv[0]
# Parse options given to PLCOpenEditor in command line
try:
opts, args = getopt.getopt(sys.argv[1:], "h", ["help"])
except getopt.GetoptError:
# print help information and exit:
usage()
sys.exit(2)
# Extract if help has been requested
for o, a in opts:
if o in ("-h", "--help"):
usage()
sys.exit()
# Extract the optional filename to open
fileOpen = None
if len(args) > 1:
usage()
sys.exit()
elif len(args) == 1:
fileOpen = args[0]
# Create wxApp (Need to create App before internationalization because of
# Windows)
app = wx.PySimpleApp()
# Import module for internationalization
import gettext
import __builtin__
# Get folder containing translation files
localedir = os.path.join(CWD,"locale")
# Get the default language
langid = wx.LANGUAGE_DEFAULT
# Define translation domain (name of translation files)
domain = "PLCOpenEditor"
# Define locale for wx
loc = __builtin__.__dict__.get('loc', None)
if loc is None:
test_loc = wx.Locale(langid)
test_loc.AddCatalogLookupPathPrefix(localedir)
if test_loc.AddCatalog(domain):
loc = wx.Locale(langid)
else:
loc = wx.Locale(wx.LANGUAGE_ENGLISH)
__builtin__.__dict__['loc'] = loc
# Define location for searching translation files
loc.AddCatalogLookupPathPrefix(localedir)
# Define locale domain
loc.AddCatalog(domain)
if __name__ == '__main__':
__builtin__.__dict__['_'] = wx.GetTranslation
from SFCViewer import *
from LDViewer import *
from Viewer import *
from TextViewer import *
from GraphicViewer import *
from RessourceEditor import *
from DataTypeEditor import *
from PLCControler import *
from SearchResultPanel import SearchResultPanel
from controls import CustomGrid, CustomTable
# Define PLCOpenEditor controls id
[ID_PLCOPENEDITOR, ID_PLCOPENEDITORLEFTNOTEBOOK,
ID_PLCOPENEDITORBOTTOMNOTEBOOK, ID_PLCOPENEDITORRIGHTNOTEBOOK,
ID_PLCOPENEDITORTYPESTREE, ID_PLCOPENEDITORINSTANCESTREE,
ID_PLCOPENEDITORMAINSPLITTER, ID_PLCOPENEDITORSECONDSPLITTER,
ID_PLCOPENEDITORTHIRDSPLITTER, ID_PLCOPENEDITORLIBRARYPANEL,
ID_PLCOPENEDITORLIBRARYTREE, ID_PLCOPENEDITORLIBRARYCOMMENT,
ID_PLCOPENEDITORTABSOPENED, ID_PLCOPENEDITORTABSOPENED,
ID_PLCOPENEDITORTOOLBAR, ID_PLCOPENEDITORDEFAULTTOOLBAR,
ID_PLCOPENEDITORSFCTOOLBAR, ID_PLCOPENEDITORFBDTOOLBAR,
ID_PLCOPENEDITORLDTOOLBAR,
] = [wx.NewId() for _init_ctrls in range(19)]
# Define PLCOpenEditor FileMenu extra items id
[ID_PLCOPENEDITORFILEMENUGENERATE,
] = [wx.NewId() for _init_coll_FileMenu_Items in range(1)]
# Define PLCOpenEditor EditMenu extra items id
[ID_PLCOPENEDITOREDITMENUENABLEUNDOREDO, ID_PLCOPENEDITOREDITMENUADDDATATYPE,
ID_PLCOPENEDITOREDITMENUADDFUNCTION, ID_PLCOPENEDITOREDITMENUADDFUNCTIONBLOCK,
ID_PLCOPENEDITOREDITMENUADDPROGRAM, ID_PLCOPENEDITOREDITMENUADDCONFIGURATION,
ID_PLCOPENEDITOREDITMENUSEARCHINPROJECT,
] = [wx.NewId() for _init_coll_EditMenu_Items in range(7)]
#-------------------------------------------------------------------------------
# ToolBars definitions
#-------------------------------------------------------------------------------
# Define PLCOpenEditor Toolbar items id
[ID_PLCOPENEDITORTOOLBARSELECTION, ID_PLCOPENEDITORTOOLBARCOMMENT,
ID_PLCOPENEDITORTOOLBARVARIABLE, ID_PLCOPENEDITORTOOLBARBLOCK,
ID_PLCOPENEDITORTOOLBARCONNECTION, ID_PLCOPENEDITORTOOLBARWIRE,
ID_PLCOPENEDITORTOOLBARPOWERRAIL, ID_PLCOPENEDITORTOOLBARRUNG,
ID_PLCOPENEDITORTOOLBARCOIL, ID_PLCOPENEDITORTOOLBARCONTACT,
ID_PLCOPENEDITORTOOLBARBRANCH, ID_PLCOPENEDITORTOOLBARINITIALSTEP,
ID_PLCOPENEDITORTOOLBARSTEP, ID_PLCOPENEDITORTOOLBARTRANSITION,
ID_PLCOPENEDITORTOOLBARACTIONBLOCK, ID_PLCOPENEDITORTOOLBARDIVERGENCE,
ID_PLCOPENEDITORTOOLBARJUMP, ID_PLCOPENEDITORTOOLBARMOTION,
] = [wx.NewId() for _init_coll_DefaultToolBar_Items in range(18)]
# Define behaviour of each Toolbar item according to current POU body type
# Informations meaning are in this order:
# - Item is toggled
# - PLCOpenEditor mode where item is displayed (could be more then one)
# - Item id
# - Item callback function name
# - Item icon filename
# - Item tooltip text
ToolBarItems = {
"FBD" : [(True, FREEDRAWING_MODE|DRIVENDRAWING_MODE,
ID_PLCOPENEDITORTOOLBARMOTION, "OnMotionTool",
"move.png", _("Move the view")),
(True, FREEDRAWING_MODE|DRIVENDRAWING_MODE,
ID_PLCOPENEDITORTOOLBARCOMMENT, "OnCommentTool",
"add_comment.png", _("Create a new comment")),
(True, FREEDRAWING_MODE|DRIVENDRAWING_MODE,
ID_PLCOPENEDITORTOOLBARVARIABLE, "OnVariableTool",
"add_variable.png", _("Create a new variable")),
(True, FREEDRAWING_MODE|DRIVENDRAWING_MODE,
ID_PLCOPENEDITORTOOLBARBLOCK, "OnBlockTool",
"add_block.png", _("Create a new block")),
(True, FREEDRAWING_MODE|DRIVENDRAWING_MODE,
ID_PLCOPENEDITORTOOLBARCONNECTION, "OnConnectionTool",
"add_connection.png", _("Create a new connection"))],
"LD" : [(True, FREEDRAWING_MODE|DRIVENDRAWING_MODE,
ID_PLCOPENEDITORTOOLBARMOTION, "OnMotionTool",
"move.png", _("Move the view")),
(True, FREEDRAWING_MODE,
ID_PLCOPENEDITORTOOLBARCOMMENT, "OnCommentTool",
"add_comment.png", _("Create a new comment")),
(True, FREEDRAWING_MODE,
ID_PLCOPENEDITORTOOLBARPOWERRAIL, "OnPowerRailTool",
"add_powerrail.png", _("Create a new power rail")),
(False, DRIVENDRAWING_MODE,
ID_PLCOPENEDITORTOOLBARRUNG, "OnRungTool",
"add_rung.png", _("Create a new rung")),
(True, FREEDRAWING_MODE,
ID_PLCOPENEDITORTOOLBARCOIL, "OnCoilTool",
"add_coil.png", _("Create a new coil")),
(False, FREEDRAWING_MODE|DRIVENDRAWING_MODE,
ID_PLCOPENEDITORTOOLBARCONTACT, "OnContactTool",
"add_contact.png", _("Create a new contact")),
(False, DRIVENDRAWING_MODE,
ID_PLCOPENEDITORTOOLBARBRANCH, "OnBranchTool",
"add_branch.png", _("Create a new branch")),
(True, FREEDRAWING_MODE,
ID_PLCOPENEDITORTOOLBARVARIABLE, "OnVariableTool",
"add_variable.png", _("Create a new variable")),
(False, FREEDRAWING_MODE|DRIVENDRAWING_MODE,
ID_PLCOPENEDITORTOOLBARBLOCK, "OnBlockTool",
"add_block.png", _("Create a new block")),
(True, FREEDRAWING_MODE,
ID_PLCOPENEDITORTOOLBARCONNECTION, "OnConnectionTool",
"add_connection.png", _("Create a new connection"))],
"SFC" : [(True, FREEDRAWING_MODE|DRIVENDRAWING_MODE,
ID_PLCOPENEDITORTOOLBARMOTION, "OnMotionTool",
"move.png", _("Move the view")),
(True, FREEDRAWING_MODE|DRIVENDRAWING_MODE,
ID_PLCOPENEDITORTOOLBARCOMMENT, "OnCommentTool",
"add_comment.png", _("Create a new comment")),
(True, FREEDRAWING_MODE|DRIVENDRAWING_MODE,
ID_PLCOPENEDITORTOOLBARINITIALSTEP, "OnInitialStepTool",
"add_initial_step.png", _("Create a new initial step")),
(False, FREEDRAWING_MODE|DRIVENDRAWING_MODE,
ID_PLCOPENEDITORTOOLBARSTEP, "OnStepTool",
"add_step.png", _("Create a new step")),
(True, FREEDRAWING_MODE,
ID_PLCOPENEDITORTOOLBARTRANSITION, "OnTransitionTool",
"add_transition.png", _("Create a new transition")),
(False, FREEDRAWING_MODE|DRIVENDRAWING_MODE,
ID_PLCOPENEDITORTOOLBARACTIONBLOCK, "OnActionBlockTool",
"add_action.png", _("Create a new action block")),
(False, FREEDRAWING_MODE|DRIVENDRAWING_MODE,
ID_PLCOPENEDITORTOOLBARDIVERGENCE, "OnDivergenceTool",
"add_divergence.png", _("Create a new divergence")),
(False, FREEDRAWING_MODE|DRIVENDRAWING_MODE,
ID_PLCOPENEDITORTOOLBARJUMP, "OnJumpTool",
"add_jump.png", _("Create a new jump")),
(True, FREEDRAWING_MODE,
ID_PLCOPENEDITORTOOLBARVARIABLE, "OnVariableTool",
"add_variable.png", _("Create a new variable")),
(True, FREEDRAWING_MODE,
ID_PLCOPENEDITORTOOLBARBLOCK, "OnBlockTool",
"add_block.png", _("Create a new block")),
(True, FREEDRAWING_MODE,
ID_PLCOPENEDITORTOOLBARCONNECTION, "OnConnectionTool",
"add_connection.png", _("Create a new connection")),
(True, FREEDRAWING_MODE,
ID_PLCOPENEDITORTOOLBARPOWERRAIL, "OnPowerRailTool",
"add_powerrail.png", _("Create a new power rail")),
(True, FREEDRAWING_MODE,
ID_PLCOPENEDITORTOOLBARCONTACT, "OnContactTool",
"add_contact.png", _("Create a new contact"))],
"ST" : [],
"IL" : []
}
#-------------------------------------------------------------------------------
# Helper Functions
#-------------------------------------------------------------------------------
# Compatibility function for wx versions < 2.6
def AppendMenu(parent, help, id, kind, text):
if wx.VERSION >= (2, 6, 0):
parent.Append(help=help, id=id, kind=kind, text=text)
else:
parent.Append(helpString=help, id=id, kind=kind, item=text)
[TITLE, TOOLBAR, FILEMENU, EDITMENU, DISPLAYMENU, TYPESTREE,
INSTANCESTREE, LIBRARYTREE, SCALING, PAGETITLES
] = range(10)
def GetShortcutKeyCallbackFunction(viewer_function):
def ShortcutKeyFunction(self, event):
control = self.FindFocus()
if control is not None and control.GetName() in ["Viewer", "TextViewer"]:
getattr(control.Parent, viewer_function)()
elif isinstance(control, wx.stc.StyledTextCtrl):
getattr(control, viewer_function)()
elif isinstance(control, wx.TextCtrl):
control.ProcessEvent(event)
return ShortcutKeyFunction
def GetParentName(tree, item, parent_type):
parent_item = tree.GetItemParent(item)
parent_item_type = tree.GetPyData(parent_item)
while parent_item_type != parent_type:
parent_item = tree.GetItemParent(parent_item)
parent_item_type = tree.GetPyData(parent_item)
return tree.GetItemText(parent_item)
def GetDeleteElementFunction(remove_function, parent_type=None, check_function=None):
def DeleteElementFunction(self, selected):
name = self.TypesTree.GetItemText(selected)
if check_function is None or not check_function(self.Controler, name):
if parent_type is not None:
parent_name = GetParentName(self.TypesTree, selected, parent_type)
remove_function(self.Controler, parent_name, name)
else:
remove_function(self.Controler, name)
else:
self.ShowErrorMessage(_("\"%s\" is used by one or more POUs. It can't be removed!")%name)
return DeleteElementFunction
#-------------------------------------------------------------------------------
# IDEFrame Base Class
#-------------------------------------------------------------------------------
UNEDITABLE_NAMES_DICT = dict([(_(name), name) for name in UNEDITABLE_NAMES])
class IDEFrame(wx.Frame):
# Compatibility function for wx versions < 2.6
if wx.VERSION < (2, 6, 0):
def Bind(self, event, function, id = None):
if id is not None:
event(self, id, function)
else:
event(self, function)
def _init_coll_MenuBar_Menus(self, parent):
parent.Append(menu=self.FileMenu, title=_(u'&File'))
parent.Append(menu=self.EditMenu, title=_(u'&Edit'))
parent.Append(menu=self.DisplayMenu, title=_(u'&Display'))
parent.Append(menu=self.HelpMenu, title=_(u'&Help'))
def _init_coll_FileMenu_Items(self, parent):
pass
def _init_coll_EditMenu_Items(self, parent):
AppendMenu(parent, help='', id=wx.ID_UNDO,
kind=wx.ITEM_NORMAL, text=_(u'Undo\tCTRL+Z'))
AppendMenu(parent, help='', id=wx.ID_REDO,
kind=wx.ITEM_NORMAL, text=_(u'Redo\tCTRL+Y'))
#AppendMenu(parent, help='', id=ID_PLCOPENEDITOREDITMENUENABLEUNDOREDO,
# kind=wx.ITEM_CHECK, text=_(u'Enable Undo/Redo'))
enable_undo_redo = _(u'Enable Undo/Redo') # Keeping text in translations for possible menu reactivation
parent.AppendSeparator()
AppendMenu(parent, help='', id=wx.ID_CUT,
kind=wx.ITEM_NORMAL, text=_(u'Cut\tCTRL+X'))
AppendMenu(parent, help='', id=wx.ID_COPY,
kind=wx.ITEM_NORMAL, text=_(u'Copy\tCTRL+C'))
AppendMenu(parent, help='', id=wx.ID_PASTE,
kind=wx.ITEM_NORMAL, text=_(u'Paste\tCTRL+V'))
parent.AppendSeparator()
AppendMenu(parent, help='', id=ID_PLCOPENEDITOREDITMENUSEARCHINPROJECT,
kind=wx.ITEM_NORMAL, text=_(u'Search in Project'))
parent.AppendSeparator()
addmenu = wx.Menu(title='')
parent.AppendMenu(wx.ID_ADD, _("Add Element"), addmenu)
AppendMenu(addmenu, help='', id=ID_PLCOPENEDITOREDITMENUADDDATATYPE,
kind=wx.ITEM_NORMAL, text=_(u'Data Type'))
AppendMenu(addmenu, help='', id=ID_PLCOPENEDITOREDITMENUADDFUNCTION,
kind=wx.ITEM_NORMAL, text=_(u'Function'))
AppendMenu(addmenu, help='', id=ID_PLCOPENEDITOREDITMENUADDFUNCTIONBLOCK,
kind=wx.ITEM_NORMAL, text=_(u'Function Block'))
AppendMenu(addmenu, help='', id=ID_PLCOPENEDITOREDITMENUADDPROGRAM,
kind=wx.ITEM_NORMAL, text=_(u'Program'))
AppendMenu(addmenu, help='', id=ID_PLCOPENEDITOREDITMENUADDCONFIGURATION,
kind=wx.ITEM_NORMAL, text=_(u'Configuration'))
AppendMenu(parent, help='', id=wx.ID_SELECTALL,
kind=wx.ITEM_NORMAL, text=_(u'Select All\tCTRL+A'))
AppendMenu(parent, help='', id=wx.ID_DELETE,
kind=wx.ITEM_NORMAL, text=_(u'Delete'))
self.Bind(wx.EVT_MENU, self.OnUndoMenu, id=wx.ID_UNDO)
self.Bind(wx.EVT_MENU, self.OnRedoMenu, id=wx.ID_REDO)
#self.Bind(wx.EVT_MENU, self.OnEnableUndoRedoMenu, id=ID_PLCOPENEDITOREDITMENUENABLEUNDOREDO)
self.Bind(wx.EVT_MENU, self.OnCutMenu, id=wx.ID_CUT)
self.Bind(wx.EVT_MENU, self.OnCopyMenu, id=wx.ID_COPY)
self.Bind(wx.EVT_MENU, self.OnPasteMenu, id=wx.ID_PASTE)
self.Bind(wx.EVT_MENU, self.OnSearchInProjectMenu,
id=ID_PLCOPENEDITOREDITMENUSEARCHINPROJECT)
self.Bind(wx.EVT_MENU, self.OnAddDataTypeMenu,
id=ID_PLCOPENEDITOREDITMENUADDDATATYPE)
self.Bind(wx.EVT_MENU, self.GenerateAddPouFunction("function"),
id=ID_PLCOPENEDITOREDITMENUADDFUNCTION)
self.Bind(wx.EVT_MENU, self.GenerateAddPouFunction("functionBlock"),
id=ID_PLCOPENEDITOREDITMENUADDFUNCTIONBLOCK)
self.Bind(wx.EVT_MENU, self.GenerateAddPouFunction("program"),
id=ID_PLCOPENEDITOREDITMENUADDPROGRAM)
self.Bind(wx.EVT_MENU, self.OnAddConfigurationMenu,
id=ID_PLCOPENEDITOREDITMENUADDCONFIGURATION)
self.Bind(wx.EVT_MENU, self.OnSelectAllMenu, id=wx.ID_SELECTALL)
self.Bind(wx.EVT_MENU, self.OnDeleteMenu, id=wx.ID_DELETE)
def _init_coll_DisplayMenu_Items(self, parent):
AppendMenu(parent, help='', id=wx.ID_REFRESH,
kind=wx.ITEM_NORMAL, text=_(u'Refresh\tCTRL+R'))
if self.EnableDebug:
AppendMenu(parent, help='', id=wx.ID_CLEAR,
kind=wx.ITEM_NORMAL, text=_(u'Clear Errors\tCTRL+K'))
parent.AppendSeparator()
zoommenu = wx.Menu(title='')
parent.AppendMenu(wx.ID_ZOOM_FIT, _("Zoom"), zoommenu)
for idx, value in enumerate(ZOOM_FACTORS):
new_id = wx.NewId()
AppendMenu(zoommenu, help='', id=new_id,
kind=wx.ITEM_RADIO, text=str(int(round(value * 100))) + "%")
self.Bind(wx.EVT_MENU, self.GenerateZoomFunction(idx), id=new_id)
self.Bind(wx.EVT_MENU, self.OnRefreshMenu, id=wx.ID_REFRESH)
if self.EnableDebug:
self.Bind(wx.EVT_MENU, self.OnClearErrorsMenu, id=wx.ID_CLEAR)
def _init_coll_HelpMenu_Items(self, parent):
pass
def _init_utils(self):
self.MenuBar = wx.MenuBar()
self.FileMenu = wx.Menu(title='')
self.EditMenu = wx.Menu(title='')
self.DisplayMenu = wx.Menu(title='')
self.HelpMenu = wx.Menu(title='')
self._init_coll_MenuBar_Menus(self.MenuBar)
self._init_coll_FileMenu_Items(self.FileMenu)
self._init_coll_EditMenu_Items(self.EditMenu)
self._init_coll_DisplayMenu_Items(self.DisplayMenu)
self._init_coll_HelpMenu_Items(self.HelpMenu)
def _init_coll_MainLibrarySizer_Items(self, parent):
parent.AddWindow(self.LibraryTree, 0, border=0, flag=wx.GROW)
parent.AddSizer(self.LibraryComment, 0, border=0, flag=wx.GROW)
def _init_coll_MainLibrarySizer_Growables(self, parent):
parent.AddGrowableCol(0)
parent.AddGrowableRow(0)
def _init_sizers(self):
self.MainLibrarySizer = wx.FlexGridSizer(cols=1, hgap=0, rows=2, vgap=0)
self._init_coll_MainLibrarySizer_Growables(self.MainLibrarySizer)
self._init_coll_MainLibrarySizer_Items(self.MainLibrarySizer)
self.LibraryPanel.SetSizer(self.MainLibrarySizer)
def _init_ctrls(self, prnt):
wx.Frame.__init__(self, id=ID_PLCOPENEDITOR, name='IDEFrame',
parent=prnt, pos=wx.DefaultPosition, size=wx.Size(1000, 600),
style=wx.DEFAULT_FRAME_STYLE)
self._init_utils()
self.SetClientSize(wx.Size(1000, 600))
self.SetMenuBar(self.MenuBar)
self.TabsImageList = wx.ImageList(31, 16)
self.TabsImageListIndexes = {}
#-----------------------------------------------------------------------
# Creating main structure
#-----------------------------------------------------------------------
if USE_AUI:
self.AUIManager = wx.aui.AuiManager(self)
self.AUIManager.SetDockSizeConstraint(0.5, 0.5)
self.Panes = {}
self.LeftNoteBook = wx.aui.AuiNotebook(self, ID_PLCOPENEDITORLEFTNOTEBOOK,
style=wx.aui.AUI_NB_TOP|wx.aui.AUI_NB_TAB_SPLIT|wx.aui.AUI_NB_TAB_MOVE|
wx.aui.AUI_NB_SCROLL_BUTTONS|wx.aui.AUI_NB_TAB_EXTERNAL_MOVE)
self.AUIManager.AddPane(self.LeftNoteBook,
wx.aui.AuiPaneInfo().Caption(_("Project")).Left().Layer(1).
BestSize(wx.Size(300, 500)).CloseButton(False))
self.BottomNoteBook = wx.aui.AuiNotebook(self, ID_PLCOPENEDITORBOTTOMNOTEBOOK,
style=wx.aui.AUI_NB_TOP|wx.aui.AUI_NB_TAB_SPLIT|wx.aui.AUI_NB_TAB_MOVE|
wx.aui.AUI_NB_SCROLL_BUTTONS|wx.aui.AUI_NB_TAB_EXTERNAL_MOVE)
self.AUIManager.AddPane(self.BottomNoteBook,
wx.aui.AuiPaneInfo().Bottom().Layer(0).
BestSize(wx.Size(800, 300)).CloseButton(False))
self.RightNoteBook = wx.aui.AuiNotebook(self, ID_PLCOPENEDITORRIGHTNOTEBOOK,
style=wx.aui.AUI_NB_TOP|wx.aui.AUI_NB_TAB_SPLIT|wx.aui.AUI_NB_TAB_MOVE|
wx.aui.AUI_NB_SCROLL_BUTTONS|wx.aui.AUI_NB_TAB_EXTERNAL_MOVE)
self.AUIManager.AddPane(self.RightNoteBook,
wx.aui.AuiPaneInfo().Right().Layer(0).
BestSize(wx.Size(250, 400)).CloseButton(False))
self.TabsOpened = wx.aui.AuiNotebook(self, ID_PLCOPENEDITORTABSOPENED,
style=wx.aui.AUI_NB_DEFAULT_STYLE|wx.aui.AUI_NB_WINDOWLIST_BUTTON)
self.TabsOpened.Bind(wx.aui.EVT_AUINOTEBOOK_PAGE_CHANGING,
self.OnPouSelectedChanged)
self.TabsOpened.Bind(wx.aui.EVT_AUINOTEBOOK_PAGE_CLOSE,
self.OnPageClose)
self.TabsOpened.Bind(wx.aui.EVT_AUINOTEBOOK_END_DRAG,
self.OnPageDragged)
self.AUIManager.AddPane(self.TabsOpened, wx.aui.AuiPaneInfo().CentrePane())
else:
self.MainSplitter = wx.SplitterWindow(id=ID_PLCOPENEDITORMAINSPLITTER,
name='MainSplitter', parent=self, point=wx.Point(0, 0),
size=wx.Size(0, 0), style=wx.SP_3D)
self.MainSplitter.SetNeedUpdating(True)
self.MainSplitter.SetMinimumPaneSize(1)
self.LeftNoteBook = wx.Notebook(id=ID_PLCOPENEDITORLEFTNOTEBOOK,
name='LeftNoteBook', parent=self.MainSplitter, pos=wx.Point(0,
0), size=wx.Size(0, 0), style=0)
self.SecondSplitter = wx.SplitterWindow(id=ID_PLCOPENEDITORSECONDSPLITTER,
name='SecondSplitter', parent=self.MainSplitter, point=wx.Point(0, 0),
size=wx.Size(0, 0), style=wx.SP_3D)
self.SecondSplitter.SetMinimumPaneSize(1)
self.MainSplitter.SplitVertically(self.LeftNoteBook, self.SecondSplitter, 200)
self.ThirdSplitter = wx.SplitterWindow(id=ID_PLCOPENEDITORTHIRDSPLITTER,
name='ThirdSplitter', parent=self.SecondSplitter, point=wx.Point(0, 0),
size=wx.Size(0, 0), style=wx.SP_3D)
self.ThirdSplitter.SetMinimumPaneSize(1)
self.BottomNoteBook = wx.Notebook(id=ID_PLCOPENEDITORBOTTOMNOTEBOOK,
name='BottomNoteBook', parent=self.SecondSplitter, pos=wx.Point(0,
0), size=wx.Size(0, 0), style=0)
self.SecondSplitter.SplitHorizontally(self.ThirdSplitter, self.BottomNoteBook, -200)
self.TabsOpened = wx.Notebook(id=ID_PLCOPENEDITORTABSOPENED,
name='TabsOpened', parent=self.ThirdSplitter, pos=wx.Point(0,
0), size=wx.Size(0, 0), style=0)
self.TabsOpened.SetImageList(self.TabsImageList)
if wx.VERSION >= (2, 6, 0):
self.TabsOpened.Bind(wx.EVT_NOTEBOOK_PAGE_CHANGING,
self.OnPouSelectedChanged, id=ID_PLCOPENEDITORTABSOPENED)
else:
wx.EVT_NOTEBOOK_PAGE_CHANGING(self.TabsOpened, ID_PLCOPENEDITORTABSOPENED,
self.OnPouSelectedChanged)
self.RightNoteBook = wx.Notebook(id=ID_PLCOPENEDITORRIGHTNOTEBOOK,
name='RightNoteBook', parent=self.ThirdSplitter, pos=wx.Point(0,
0), size=wx.Size(0, 0), style=0)
self.ThirdSplitter.SplitVertically(self.TabsOpened, self.RightNoteBook, -250)
#-----------------------------------------------------------------------
# Creating PLCopen Project tree
#-----------------------------------------------------------------------
self.TypesTree = wx.TreeCtrl(id=ID_PLCOPENEDITORTYPESTREE,
name='TypesTree', parent=self.LeftNoteBook,
pos=wx.Point(0, 0), size=wx.Size(0, 0),
style=wx.TR_HAS_BUTTONS|wx.TR_SINGLE|wx.SUNKEN_BORDER|wx.TR_EDIT_LABELS)
if wx.Platform == '__WXMSW__':
self.Bind(wx.EVT_TREE_ITEM_RIGHT_CLICK, self.OnTypesTreeRightUp,
id=ID_PLCOPENEDITORTYPESTREE)
self.Bind(wx.EVT_TREE_SEL_CHANGED, self.OnTypesTreeItemSelected,
id=ID_PLCOPENEDITORTYPESTREE)
else:
if wx.VERSION >= (2, 6, 0):
self.TypesTree.Bind(wx.EVT_RIGHT_UP, self.OnTypesTreeRightUp)
self.TypesTree.Bind(wx.EVT_LEFT_UP, self.OnTypesTreeLeftUp)
else:
wx.EVT_RIGHT_UP(self.TypesTree, self.OnTypesTreeRightUp)
wx.EVT_LEFT_UP(self.TypesTree, self.OnTypesTreeLeftUp)
self.Bind(wx.EVT_TREE_SEL_CHANGING, self.OnTypesTreeItemChanging,
id=ID_PLCOPENEDITORTYPESTREE)
self.Bind(wx.EVT_TREE_BEGIN_DRAG, self.OnTypesTreeBeginDrag,
id=ID_PLCOPENEDITORTYPESTREE)
self.Bind(wx.EVT_TREE_BEGIN_LABEL_EDIT, self.OnTypesTreeItemBeginEdit,
id=ID_PLCOPENEDITORTYPESTREE)
self.Bind(wx.EVT_TREE_END_LABEL_EDIT, self.OnTypesTreeItemEndEdit,
id=ID_PLCOPENEDITORTYPESTREE)
self.Bind(wx.EVT_TREE_ITEM_ACTIVATED, self.OnTypesTreeItemActivated,
id=ID_PLCOPENEDITORTYPESTREE)
self.LeftNoteBook.AddPage(self.TypesTree, _("Types"))
#-----------------------------------------------------------------------
# Creating PLCopen Project tree
#-----------------------------------------------------------------------
self.InstancesTree = wx.TreeCtrl(id=ID_PLCOPENEDITORINSTANCESTREE,
name='InstancesTree', parent=self.LeftNoteBook,
pos=wx.Point(0, 0), size=wx.Size(0, 0),
style=wx.TR_HAS_BUTTONS|wx.TR_SINGLE|wx.SUNKEN_BORDER)
if self.EnableDebug:
if wx.VERSION >= (2, 6, 0):
self.InstancesTree.Bind(wx.EVT_RIGHT_UP, self.OnInstancesTreeRightUp)
else:
wx.EVT_RIGHT_UP(self.InstancesTree, self.OnInstancesTreeRightUp)
self.Bind(wx.EVT_TREE_BEGIN_DRAG, self.OnInstancesTreeBeginDrag,
id=ID_PLCOPENEDITORINSTANCESTREE)
self.Bind(wx.EVT_TREE_ITEM_ACTIVATED, self.OnInstancesTreeItemActivated,
id=ID_PLCOPENEDITORINSTANCESTREE)
self.LeftNoteBook.AddPage(self.InstancesTree, _("Instances"))
#-----------------------------------------------------------------------
# Creating Tool Bar
#-----------------------------------------------------------------------
if USE_AUI:
ToolBar = wx.ToolBar(self, ID_PLCOPENEDITORTOOLBAR, wx.DefaultPosition, wx.DefaultSize,
wx.TB_FLAT | wx.TB_NODIVIDER | wx.NO_BORDER)
ToolBar.SetToolBitmapSize(wx.Size(25, 25))
ToolBar.AddRadioTool(ID_PLCOPENEDITORTOOLBARSELECTION,
wx.Bitmap(os.path.join(CWD, 'Images', 'select.png')), wx.NullBitmap, _("Select an object"))
ToolBar.Realize()
self.Panes["ToolBar"] = ToolBar
self.AUIManager.AddPane(ToolBar, wx.aui.AuiPaneInfo().
Name("ToolBar").Caption(_("Toolbar")).
ToolbarPane().Top().
LeftDockable(False).RightDockable(False))
else:
self.ToolBar = self.CreateToolBar(wx.TB_HORIZONTAL|wx.TB_FLAT|wx.NO_BORDER,
ID_PLCOPENEDITORTOOLBAR, 'ToolBar')
self.ToolBar.SetToolBitmapSize(wx.Size(25, 25))
self.ToolBar.AddRadioTool(ID_PLCOPENEDITORTOOLBARSELECTION,
wx.Bitmap(os.path.join(CWD, 'Images', 'select.png')), wx.NullBitmap, _("Select an object"))
self.ToolBar.Realize()
self.Bind(wx.EVT_TOOL, self.OnSelectionTool,
id=ID_PLCOPENEDITORTOOLBARSELECTION)
self.SearchResultPanel = SearchResultPanel(self.BottomNoteBook, self)
self.BottomNoteBook.AddPage(self.SearchResultPanel, _("Search"))
self.LibraryPanel = wx.Panel(id=ID_PLCOPENEDITORLIBRARYPANEL,
name='LibraryPanel', parent=self.RightNoteBook, pos=wx.Point(0,
0), size=wx.Size(0, 0), style=0)
self.RightNoteBook.AddPage(self.LibraryPanel, _("Library"))
self.LibraryTree = wx.TreeCtrl(id=ID_PLCOPENEDITORLIBRARYTREE,
name='LibraryTree', parent=self.LibraryPanel,
pos=wx.Point(0, 0), size=wx.Size(0, 0),
style=wx.TR_HAS_BUTTONS|wx.TR_SINGLE|wx.SUNKEN_BORDER|wx.TR_HIDE_ROOT|wx.TR_LINES_AT_ROOT)
self.Bind(wx.EVT_TREE_SEL_CHANGED, self.OnLibraryTreeItemSelected,
id=ID_PLCOPENEDITORLIBRARYTREE)
self.Bind(wx.EVT_TREE_BEGIN_DRAG, self.OnLibraryTreeBeginDrag,
id=ID_PLCOPENEDITORLIBRARYTREE)
self.LibraryComment = wx.TextCtrl(id=ID_PLCOPENEDITORLIBRARYCOMMENT,
name='LibraryComment', parent=self.LibraryPanel,
pos=wx.Point(0, 0), size=wx.Size(0, 160),
style=wx.TE_READONLY|wx.TE_MULTILINE)
self._init_sizers()
if self.EnableDebug:
self.DebugVariablePanel = DebugVariablePanel(self.RightNoteBook, self.Controler)
self.RightNoteBook.AddPage(self.DebugVariablePanel, _("Debugger"))
if USE_AUI:
self.AUIManager.Update()
## Constructor of the PLCOpenEditor class.
# @param parent The parent window.
# @param controler The controler been used by PLCOpenEditor (default: None).
# @param fileOpen The filepath to open if no controler defined (default: None).
# @param debug The filepath to open if no controler defined (default: False).
def __init__(self, parent, enable_debug = False):
self.Controler = None
self.Config = wx.ConfigBase.Get()
self.EnableDebug = enable_debug
self._init_ctrls(parent)
# Define Tree item icon list
self.TreeImageList = wx.ImageList(16, 16)
self.TreeImageDict = {}
# Icons for languages
for language in LANGUAGES:
self.TreeImageDict[language]=self.TreeImageList.Add(wx.Bitmap(os.path.join(CWD, 'Images', '%s.png'%language)))
# Icons for other items
for imgname, itemtype in [
#editables
("PROJECT", ITEM_PROJECT),
#("POU", ITEM_POU),
#("VARIABLE", ITEM_VARIABLE),
("TRANSITION", ITEM_TRANSITION),
("ACTION", ITEM_ACTION),
("CONFIGURATION", ITEM_CONFIGURATION),
("RESOURCE", ITEM_RESOURCE),
("DATATYPE", ITEM_DATATYPE),
# uneditables
("DATATYPES", ITEM_DATATYPES),
("FUNCTION", ITEM_FUNCTION),
("FUNCTIONBLOCK", ITEM_FUNCTIONBLOCK),
("PROGRAM", ITEM_PROGRAM),
("VAR_LOCAL", ITEM_VAR_LOCAL),
("VAR_LOCAL", ITEM_VAR_GLOBAL),
("VAR_LOCAL", ITEM_VAR_EXTERNAL),
("VAR_LOCAL", ITEM_VAR_TEMP),
("VAR_INPUT", ITEM_VAR_INPUT),
("VAR_OUTPUT", ITEM_VAR_OUTPUT),
("VAR_INOUT", ITEM_VAR_INOUT),
("TRANSITIONS", ITEM_TRANSITIONS),
("ACTIONS", ITEM_ACTIONS),
("CONFIGURATIONS", ITEM_CONFIGURATIONS),
("RESOURCES", ITEM_RESOURCES),
("PROPERTIES", ITEM_PROPERTIES)]:
self.TreeImageDict[itemtype]=self.TreeImageList.Add(wx.Bitmap(os.path.join(CWD, 'Images', '%s.png'%imgname)))
# Assign icon list to TreeCtrls
self.TypesTree.SetImageList(self.TreeImageList)
self.InstancesTree.SetImageList(self.TreeImageList)
self.CurrentToolBar = []
self.CurrentLanguage = ""
self.SelectedItem = None
self.Highlights = {}
self.DrawingMode = FREEDRAWING_MODE
#self.DrawingMode = DRIVENDRAWING_MODE
if USE_AUI:
self.AuiTabCtrl = []
# Initialize Printing configuring elements
self.PrintData = wx.PrintData()
self.PrintData.SetPaperId(wx.PAPER_A4)
self.PrintData.SetPrintMode(wx.PRINT_MODE_PRINTER)
self.PageSetupData = wx.PageSetupDialogData(self.PrintData)
self.PageSetupData.SetMarginTopLeft(wx.Point(10, 15))
self.PageSetupData.SetMarginBottomRight(wx.Point(10, 20))
self.SetRefreshFunctions()
def Show(self):
wx.Frame.Show(self)
wx.CallAfter(self.RestoreFrameSize)
def RestoreFrameSize(self):
frame_size = None
if self.Config.HasEntry("framesize"):
frame_size = cPickle.loads(str(self.Config.Read("framesize")))
if frame_size is None:
self.Maximize()
else:
self.SetClientSize(frame_size)
def SaveFrameSize(self):
if not self.IsMaximized():
self.Config.Write("framesize", cPickle.dumps(self.GetClientSize()))
elif self.Config.HasEntry("framesize"):
self.Config.DeleteEntry("framesize")
self.Config.Flush()
#-------------------------------------------------------------------------------
# General Functions
#-------------------------------------------------------------------------------
def SetRefreshFunctions(self):
self.RefreshFunctions = {
TITLE : self.RefreshTitle,
TOOLBAR : self.RefreshToolBar,
FILEMENU : self.RefreshFileMenu,
EDITMENU : self.RefreshEditMenu,
DISPLAYMENU : self.RefreshDisplayMenu,
TYPESTREE : self.RefreshTypesTree,
INSTANCESTREE : self.RefreshInstancesTree,
LIBRARYTREE : self.RefreshLibraryTree,
SCALING : self.RefreshScaling,
PAGETITLES: self.RefreshPageTitles}
## Call PLCOpenEditor refresh functions.
# @param elements List of elements to refresh.
def _Refresh(self, *elements):
for element in elements:
self.RefreshFunctions[element]()
## Callback function when AUINotebook Page closed with CloseButton
# @param event AUINotebook Event.
def OnPageClose(self, event):
wx.CallAfter(self.RefreshTabCtrlEvent)
event.Skip()
def GetCopyBuffer(self):
data = None
if wx.TheClipboard.IsOpened() or wx.TheClipboard.Open():
dataobj = wx.TextDataObject()
if wx.TheClipboard.GetData(dataobj):
data = dataobj.GetText()
if wx.TheClipboard.IsOpened():
wx.TheClipboard.Close()
return data
def SetCopyBuffer(self, text):
if wx.TheClipboard.IsOpened() or wx.TheClipboard.Open():
data = wx.TextDataObject()
data.SetText(text)
wx.TheClipboard.SetData(data)
wx.TheClipboard.Flush()
if wx.TheClipboard.IsOpened():
wx.TheClipboard.Close()
self.RefreshEditMenu()
def GetDrawingMode(self):
return self.DrawingMode
def RefreshScaling(self):
for i in xrange(self.TabsOpened.GetPageCount()):
editor = self.TabsOpened.GetPage(i)
editor.RefreshScaling()
def ShowProperties(self):
old_values = self.Controler.GetProjectProperties()
dialog = ProjectDialog(self)
dialog.SetValues(old_values)
if dialog.ShowModal() == wx.ID_OK:
new_values = dialog.GetValues()
new_values["creationDateTime"] = old_values["creationDateTime"]
if new_values != old_values:
self.Controler.SetProjectProperties(None, new_values)
self._Refresh(TITLE, TOOLBAR, FILEMENU, EDITMENU, DISPLAYMENU,
TYPESTREE, INSTANCESTREE, SCALING)
dialog.Destroy()
#-------------------------------------------------------------------------------
# Notebook Unified Functions
#-------------------------------------------------------------------------------
## Function that generate bitmap for
# for wx.aui.AUINotebook.
# @param window Panel to display in tab.
# @param text title for the tab ctrl.
def GenerateBitmap(self, icon1_name, icon2_name = None):
# Find index of bitmap if already created
index = self.TabsImageListIndexes.get((icon1_name, icon2_name), None)
# Return index or bitmap if found
if index is not None:
if USE_AUI:
return self.TabsImageList.GetBitmap(index)
else:
return index
if icon2_name is None:
# Bitmap with only one icon
bitmap = wx.Bitmap(os.path.join(CWD, 'Images', '%s.png'%icon1_name))
else:
# Bitmap with two icon
icon1 = wx.Bitmap(os.path.join(CWD, 'Images', '%s.png'%icon1_name))
icon2 = wx.Bitmap(os.path.join(CWD, 'Images', '%s.png'%icon2_name))
# Calculate bitmap size
width = icon1.GetWidth() + icon2.GetWidth() - 1
height = max(icon1.GetHeight(), icon2.GetHeight())
# Create bitmap with both icons
bitmap = wx.EmptyBitmap(width, height)
dc = wx.MemoryDC()
dc.SelectObject(bitmap)
dc.Clear()
dc.DrawBitmap(icon1, 0, 0)
dc.DrawBitmap(icon2, icon1.GetWidth() - 1, 0)
dc.Destroy()
# Store bitmap in ImageList
index = self.TabsImageList.Add(bitmap)
# Save bitmap index in ImageList in dictionary
self.TabsImageListIndexes[(icon1_name, icon2_name)] = index
if USE_AUI:
return bitmap
else:
return index
## Function that add a tab in Notebook, calling refresh for tab DClick event
# for wx.aui.AUINotebook.
# @param window Panel to display in tab.
# @param text title for the tab ctrl.
def AddPage(self, window, text):
self.TabsOpened.AddPage(window, text)
self.RefreshTabCtrlEvent()
## Function that add a tab in Notebook, calling refresh for tab DClick event
# for wx.aui.AUINotebook.
# @param window Panel to display in tab.
# @param text title for the tab ctrl.
def DeletePage(self, window):
for idx in xrange(self.TabsOpened.GetPageCount()):
if self.TabsOpened.GetPage(idx) == window:
self.TabsOpened.DeletePage(idx)
self.RefreshTabCtrlEvent()
return
## Function that fix difference in deleting all tabs between
# wx.Notebook and wx.aui.AUINotebook.
def DeleteAllPages(self):
if USE_AUI:
for idx in xrange(self.TabsOpened.GetPageCount()):
self.TabsOpened.DeletePage(0)
else:
self.TabsOpened.DeleteAllPages()
self.RefreshTabCtrlEvent()
## Function that fix difference in setting picture on tab between
# wx.Notebook and wx.aui.AUINotebook.
# @param idx Tab index.
# @param bitmap wx.Bitmap to define on tab.
# @return True if operation succeeded
def SetPageBitmap(self, idx, bitmap):
if USE_AUI:
return self.TabsOpened.SetPageBitmap(idx, bitmap)
else:
return self.TabsOpened.SetPageImage(idx, bitmap)
#-------------------------------------------------------------------------------
# Dialog Message Functions
#-------------------------------------------------------------------------------
## Function displaying an Error dialog in PLCOpenEditor.
# @param message The message to display.
def ShowErrorMessage(self, message):
dialog = wx.MessageDialog(self, message, _("Error"), wx.OK|wx.ICON_ERROR)
dialog.ShowModal()
dialog.Destroy()
## Function displaying an Error dialog in PLCOpenEditor.
# @return False if closing cancelled.
def CheckSaveBeforeClosing(self, title=_("Close Project")):
if not self.Controler.ProjectIsSaved():
dialog = wx.MessageDialog(self, _("There are changes, do you want to save?"), title, wx.YES_NO|wx.CANCEL|wx.ICON_QUESTION)
answer = dialog.ShowModal()
dialog.Destroy()
if answer == wx.ID_YES:
self.SaveProject()
elif answer == wx.ID_CANCEL:
return False
return True
#-------------------------------------------------------------------------------
# File Menu Functions
#-------------------------------------------------------------------------------
def RefreshFileMenu(self):
pass
def ResetView(self):
self.DeleteAllPages()
self.TypesTree.DeleteAllItems()
self.InstancesTree.DeleteAllItems()
self.LibraryTree.DeleteAllItems()
self.Controler = None
def OnCloseTabMenu(self, event):
selected = self.TabsOpened.GetSelection()
if selected >= 0:
self.TabsOpened.DeletePage(selected)
if self.TabsOpened.GetPageCount() > 0:
new_index = min(selected, self.TabsOpened.GetPageCount() - 1)
self.TabsOpened.SetSelection(new_index)
# Refresh all window elements that have changed
self._Refresh(TITLE, TOOLBAR, FILEMENU, EDITMENU, DISPLAYMENU)
self.RefreshTabCtrlEvent()
def OnPageSetupMenu(self, event):
dialog = wx.PageSetupDialog(self, self.PageSetupData)
if dialog.ShowModal() == wx.ID_OK:
self.PageSetupData = wx.PageSetupDialogData(dialog.GetPageSetupData())
self.PrintData = wx.PrintData(self.PageSetupData.GetPrintData())
dialog.Destroy()
def OnPreviewMenu(self, event):
selected = self.TabsOpened.GetSelection()
if selected != -1:
window = self.TabsOpened.GetPage(selected)
data = wx.PrintDialogData(self.PrintData)
properties = self.Controler.GetProjectProperties(window.IsDebugging())
page_size = map(int, properties["pageSize"])
margins = (self.PageSetupData.GetMarginTopLeft(), self.PageSetupData.GetMarginBottomRight())
printout = GraphicPrintout(window, page_size, margins, True)
printout2 = GraphicPrintout(window, page_size, margins, True)
preview = wx.PrintPreview(printout, printout2, data)
if preview.Ok():
preview_frame = wx.PreviewFrame(preview, self, _("Print preview"), style=wx.DEFAULT_FRAME_STYLE|wx.FRAME_FLOAT_ON_PARENT)
preview_frame.Initialize()
preview_canvas = preview.GetCanvas()
preview_canvas.SetMinSize(preview_canvas.GetVirtualSize())
preview_frame.Fit()
preview_frame.Show(True)
def OnPrintMenu(self, event):
selected = self.TabsOpened.GetSelection()
if selected != -1:
window = self.TabsOpened.GetPage(selected)
dialog_data = wx.PrintDialogData(self.PrintData)
dialog_data.SetToPage(1)
properties = self.Controler.GetProjectProperties(window.IsDebugging())
page_size = map(int, properties["pageSize"])
margins = (self.PageSetupData.GetMarginTopLeft(), self.PageSetupData.GetMarginBottomRight())
printer = wx.Printer(dialog_data)
printout = GraphicPrintout(window, page_size, margins)
if not printer.Print(self, printout, True) and printer.GetLastError() != wx.PRINTER_CANCELLED:
self.ShowErrorMessage(_("There was a problem printing.\nPerhaps your current printer is not set correctly?"))
printout.Destroy()
def OnPropertiesMenu(self, event):
self.ShowProperties()
def OnQuitMenu(self, event):
self.Close()
#-------------------------------------------------------------------------------
# Edit Menu Functions
#-------------------------------------------------------------------------------
def RefreshEditMenu(self):
if self.Controler is not None:
selected = self.TabsOpened.GetSelection()
if selected > -1:
window = self.TabsOpened.GetPage(selected)
undo, redo = window.GetBufferState()
else:
undo, redo = self.Controler.GetBufferState()
self.EditMenu.Enable(wx.ID_UNDO, undo)
self.EditMenu.Enable(wx.ID_REDO, redo)
#self.EditMenu.Enable(ID_PLCOPENEDITOREDITMENUENABLEUNDOREDO, True)
#self.EditMenu.Check(ID_PLCOPENEDITOREDITMENUENABLEUNDOREDO,
# self.Controler.IsProjectBufferEnabled())
self.EditMenu.Enable(ID_PLCOPENEDITOREDITMENUSEARCHINPROJECT, True)
self.EditMenu.Enable(wx.ID_ADD, True)
self.EditMenu.Enable(wx.ID_DELETE, True)
if self.TabsOpened.GetPageCount() > 0:
self.EditMenu.Enable(wx.ID_CUT, True)
self.EditMenu.Enable(wx.ID_COPY, True)
if self.GetCopyBuffer() is not None:
self.EditMenu.Enable(wx.ID_PASTE, True)
else:
self.EditMenu.Enable(wx.ID_PASTE, False)
self.EditMenu.Enable(wx.ID_SELECTALL, True)
else:
self.EditMenu.Enable(wx.ID_CUT, False)
self.EditMenu.Enable(wx.ID_COPY, False)
self.EditMenu.Enable(wx.ID_PASTE, False)
self.EditMenu.Enable(wx.ID_SELECTALL, False)
else:
self.EditMenu.Enable(wx.ID_UNDO, False)
self.EditMenu.Enable(wx.ID_REDO, False)
#self.EditMenu.Enable(ID_PLCOPENEDITOREDITMENUENABLEUNDOREDO, False)
self.EditMenu.Enable(wx.ID_CUT, False)
self.EditMenu.Enable(wx.ID_COPY, False)
self.EditMenu.Enable(wx.ID_PASTE, False)
self.EditMenu.Enable(wx.ID_SELECTALL, False)
self.EditMenu.Enable(ID_PLCOPENEDITOREDITMENUSEARCHINPROJECT, False)
self.EditMenu.Enable(wx.ID_ADD, False)
self.EditMenu.Enable(wx.ID_DELETE, False)
def CloseTabsWithoutModel(self):
idxs = range(self.TabsOpened.GetPageCount())
idxs.reverse()
for idx in idxs:
window = self.TabsOpened.GetPage(idx)
if window.HasNoModel():
self.TabsOpened.DeletePage(idx)
def OnUndoMenu(self, event):
selected = self.TabsOpened.GetSelection()
if selected != -1:
window = self.TabsOpened.GetPage(selected)
window.Undo()
else:
self.Controler.LoadPrevious()
self._Refresh(TITLE, FILEMENU, EDITMENU, TYPESTREE, INSTANCESTREE, LIBRARYTREE,
SCALING, PAGETITLES)
def OnRedoMenu(self, event):
selected = self.TabsOpened.GetSelection()
if selected != -1:
window = self.TabsOpened.GetPage(selected)
window.Redo()
else:
self.Controler.LoadNext()
self._Refresh(TITLE, FILEMENU, EDITMENU, TYPESTREE, INSTANCESTREE, LIBRARYTREE,
SCALING, PAGETITLES)
def OnEnableUndoRedoMenu(self, event):
self.Controler.EnableProjectBuffer(event.IsChecked())
self.RefreshEditMenu()
OnCutMenu = GetShortcutKeyCallbackFunction("Cut")
OnCopyMenu = GetShortcutKeyCallbackFunction("Copy")
OnPasteMenu = GetShortcutKeyCallbackFunction("Paste")
def OnSelectAllMenu(self, event):
control = self.FindFocus()
if control is not None and control.GetName() == "Viewer":
control.Parent.SelectAll()
elif isinstance(control, wx.stc.StyledTextCtrl):
control.SelectAll()
elif isinstance(control, wx.TextCtrl):
control.SetSelection(0, control.GetLastPosition())
elif isinstance(control, wx.ComboBox):
control.SetMark(0, control.GetLastPosition() + 1)
DeleteFunctions = {
ITEM_DATATYPE: GetDeleteElementFunction(PLCControler.ProjectRemoveDataType, check_function=PLCControler.DataTypeIsUsed),
ITEM_POU: GetDeleteElementFunction(PLCControler.ProjectRemovePou, check_function=PLCControler.PouIsUsed),
ITEM_TRANSITION: GetDeleteElementFunction(PLCControler.ProjectRemovePouTransition, ITEM_POU),
ITEM_ACTION: GetDeleteElementFunction(PLCControler.ProjectRemovePouAction, ITEM_POU),
ITEM_CONFIGURATION: GetDeleteElementFunction(PLCControler.ProjectRemoveConfiguration),
ITEM_RESOURCE: GetDeleteElementFunction(PLCControler.ProjectRemoveConfigurationResource, ITEM_CONFIGURATION)
}
def OnDeleteMenu(self, event):
window = self.FindFocus()
if window == self.TypesTree or window is None:
selected = self.TypesTree.GetSelection()
if selected.IsOk():
type = self.TypesTree.GetPyData(selected)
function = self.DeleteFunctions.get(type, None)
if function is not None:
function(self, selected)
self.CloseTabsWithoutModel()
self._Refresh(TITLE, TOOLBAR, FILEMENU, EDITMENU, TYPESTREE,
INSTANCESTREE, LIBRARYTREE)
elif isinstance(window, (Viewer, TextViewer)):
event = wx.KeyEvent(wx.EVT_CHAR._getEvtType())
event.m_keyCode = wx.WXK_DELETE
window.ProcessEvent(event)
def OnSearchInProjectMenu(self, event):
dialog = SearchInProjectDialog(self)
if dialog.ShowModal() == wx.ID_OK:
criteria = dialog.GetCriteria()
result = self.Controler.SearchInProject(criteria)
self.ClearSearchResults()
self.SearchResultPanel.SetSearchResults(criteria, result)
self.BottomNoteBook.SetSelection(self.BottomNoteBook.GetPageIndex(self.SearchResultPanel))
#-------------------------------------------------------------------------------
# Display Menu Functions
#-------------------------------------------------------------------------------
def RefreshDisplayMenu(self):
if self.Controler is not None:
if self.TabsOpened.GetPageCount() > 0:
self.DisplayMenu.Enable(wx.ID_REFRESH, True)
selected = self.TabsOpened.GetSelection()
if selected != -1:
window = self.TabsOpened.GetPage(selected)
if isinstance(window, Viewer):
self.DisplayMenu.Enable(wx.ID_ZOOM_FIT, True)
zoommenu = self.DisplayMenu.FindItemById(wx.ID_ZOOM_FIT).GetSubMenu()
zoomitem = zoommenu.FindItemByPosition(window.GetScale())
zoomitem.Check(True)
else:
self.DisplayMenu.Enable(wx.ID_ZOOM_FIT, False)
else:
self.DisplayMenu.Enable(wx.ID_ZOOM_FIT, False)
else:
self.DisplayMenu.Enable(wx.ID_REFRESH, False)
self.DisplayMenu.Enable(wx.ID_ZOOM_FIT, False)
if self.EnableDebug:
self.DisplayMenu.Enable(wx.ID_CLEAR, True)
else:
self.DisplayMenu.Enable(wx.ID_REFRESH, False)
if self.EnableDebug:
self.DisplayMenu.Enable(wx.ID_CLEAR, False)
self.DisplayMenu.Enable(wx.ID_ZOOM_FIT, False)
def OnRefreshMenu(self, event):
self.RefreshEditor()
def OnClearErrorsMenu(self, event):
self.ClearErrors()
def GenerateZoomFunction(self, idx):
def ZoomFunction(event):
selected = self.TabsOpened.GetSelection()
if selected != -1:
window = self.TabsOpened.GetPage(selected)
window.SetScale(idx)
window.RefreshVisibleElements()
window.RefreshScrollBars()
event.Skip()
return ZoomFunction
#-------------------------------------------------------------------------------
# Project Editor Panels Management Functions
#-------------------------------------------------------------------------------
def OnPageDragged(self, event):
wx.CallAfter(self.RefreshTabCtrlEvent)
event.Skip()
def RefreshTabCtrlEvent(self):
if USE_AUI:
auitabctrl = []
for child in self.TabsOpened.GetChildren():
if isinstance(child, wx.aui.AuiTabCtrl):
auitabctrl.append(child)
if child not in self.AuiTabCtrl:
child.Bind(wx.EVT_LEFT_DCLICK, self.GetTabsOpenedDClickFunction(child))
self.AuiTabCtrl = auitabctrl
if self.TabsOpened.GetPageCount() == 0:
pane = self.AUIManager.GetPane(self.TabsOpened)
if pane.IsMaximized():
self.AUIManager.RestorePane(pane)
self.AUIManager.Update()
def OnPouSelectedChanged(self, event):
old_selected = self.TabsOpened.GetSelection()
if old_selected >= 0:
window = self.TabsOpened.GetPage(old_selected)
if not window.IsDebugging():
window.ResetBuffer()
selected = event.GetSelection()
if selected >= 0:
window = self.TabsOpened.GetPage(selected)
if not window.IsDebugging():
print "Is not Debugging"
wx.CallAfter(self.SelectTypesTreeItem, window.GetTagName())
else:
print "Is Debugging"
wx.CallAfter(self.SelectInstancesTreeItem, self.InstancesTree.GetRootItem(), window.GetInstancePath())
window.RefreshView()
self._Refresh(FILEMENU, EDITMENU, DISPLAYMENU, TOOLBAR)
event.Skip()
def RefreshEditor(self):
selected = self.TabsOpened.GetSelection()
if USE_AUI:
for child in self.TabsOpened.GetChildren():
if isinstance(child, wx.aui.AuiTabCtrl):
active_page = child.GetActivePage()
if active_page >= 0:
window = child.GetWindowFromIdx(active_page)
window.RefreshView()
elif selected >= 0:
window = self.TabsOpened.GetPage(idx)
window.RefreshView()
def RefreshEditorNames(self, old_tagname, new_tagname):
for i in xrange(self.TabsOpened.GetPageCount()):
editor = self.TabsOpened.GetPage(i)
if editor.GetTagName() == old_tagname:
editor.SetTagName(new_tagname)
def IsOpened(self, tagname):
for idx in xrange(self.TabsOpened.GetPageCount()):
if self.TabsOpened.GetPage(idx).IsViewing(tagname):
return idx
return None
def RefreshPageTitles(self):
for idx in xrange(self.TabsOpened.GetPageCount()):
window = self.TabsOpened.GetPage(idx)
icon = window.GetIcon()
if icon is not None:
self.SetPageBitmap(idx, icon)
self.TabsOpened.SetPageText(idx, window.GetTitle())
def GetTabsOpenedDClickFunction(self, tabctrl):
def OnTabsOpenedDClick(event):
pos = event.GetPosition()
if tabctrl.TabHitTest(pos.x, pos.y, None):
pane = self.AUIManager.GetPane(self.TabsOpened)
if pane.IsMaximized():
self.AUIManager.RestorePane(pane)
else:
self.AUIManager.MaximizePane(pane)
self.AUIManager.Update()
event.Skip()
return OnTabsOpenedDClick
#-------------------------------------------------------------------------------
# Types Tree Management Functions
#-------------------------------------------------------------------------------
def RefreshTypesTree(self):
infos = self.Controler.GetProjectInfos()
root = self.TypesTree.GetRootItem()
if not root.IsOk():
root = self.TypesTree.AddRoot(infos["name"])
self.GenerateTypesTreeBranch(root, infos)
self.TypesTree.Expand(root)
def ResetSelectedItem(self):
self.SelectedItem = None
def GenerateTypesTreeBranch(self, root, infos, topology=False):
to_delete = []
item_name = infos["name"]
if infos["type"] in ITEMS_UNEDITABLE:
item_name = _(item_name)
self.TypesTree.SetItemText(root, item_name)
self.TypesTree.SetPyData(root, infos["type"])
highlight_colours = self.Highlights.get(infos.get("tagname", None), (wx.WHITE, wx.BLACK))
self.TypesTree.SetItemBackgroundColour(root, highlight_colours[0])
self.TypesTree.SetItemTextColour(root, highlight_colours[1])
if infos["type"] == ITEM_POU:
self.TypesTree.SetItemImage(root, self.TreeImageDict[self.Controler.GetPouBodyType(infos["name"])])
else:
self.TypesTree.SetItemImage(root, self.TreeImageDict[infos["type"]])
if wx.VERSION >= (2, 6, 0):
item, root_cookie = self.TypesTree.GetFirstChild(root)
else:
item, root_cookie = self.TypesTree.GetFirstChild(root, 0)
for values in infos["values"]:
if not item.IsOk():
item = self.TypesTree.AppendItem(root, "")
if wx.Platform != '__WXMSW__':
item, root_cookie = self.TypesTree.GetNextChild(root, root_cookie)
self.GenerateTypesTreeBranch(item, values)
item, root_cookie = self.TypesTree.GetNextChild(root, root_cookie)
while item.IsOk():
to_delete.append(item)
item, root_cookie = self.TypesTree.GetNextChild(root, root_cookie)
for item in to_delete:
self.TypesTree.Delete(item)
def SelectTypesTreeItem(self, tagname):
if self.TypesTree is not None:
root = self.TypesTree.GetRootItem()
words = tagname.split("::")
if words[0] == "D":
return self.RecursiveTypesTreeItemSelection(root, [(words[1], ITEM_DATATYPE)])
elif words[0] == "P":
return self.RecursiveTypesTreeItemSelection(root, [(words[1], ITEM_POU)])
elif words[0] == "T":
return self.RecursiveTypesTreeItemSelection(root, [(words[1], ITEM_POU), (words[2], ITEM_TRANSITION)])
elif words[0] == "A":
return self.RecursiveTypesTreeItemSelection(root, [(words[1], ITEM_POU), (words[2], ITEM_ACTION)])
elif words[0] == "C":
return self.RecursiveTypesTreeItemSelection(root, [(words[1], ITEM_CONFIGURATION)])
elif words[0] == "R":
return self.RecursiveTypesTreeItemSelection(root, [(words[1], ITEM_CONFIGURATION), (words[2], ITEM_RESOURCE)])
return False
def RecursiveTypesTreeItemSelection(self, root, items):
found = False
if self.TypesTree is not None:
if wx.VERSION >= (2, 6, 0):
item, root_cookie = self.TypesTree.GetFirstChild(root)
else:
item, root_cookie = self.TypesTree.GetFirstChild(root, 0)
while item.IsOk() and not found:
if (self.TypesTree.GetItemText(item), self.TypesTree.GetPyData(item)) == items[0]:
if len(items) == 1:
self.SelectedItem = item
self.TypesTree.SelectItem(item)
wx.CallAfter(self.ResetSelectedItem)
return True
else:
found = self.RecursiveTypesTreeItemSelection(item, items[1:])
else:
found = self.RecursiveTypesTreeItemSelection(item, items)
item, root_cookie = self.TypesTree.GetNextChild(root, root_cookie)
return found
def OnTypesTreeBeginDrag(self, event):
if wx.Platform == '__WXMSW__':
self.SelectedItem = event.GetItem()
if self.SelectedItem is not None and self.TypesTree.GetPyData(self.SelectedItem) == ITEM_POU:
block_name = self.TypesTree.GetItemText(self.SelectedItem)
block_type = self.Controler.GetPouType(block_name)
if block_type != "program":
data = wx.TextDataObject(str((block_name, block_type, "")))
dragSource = wx.DropSource(self.TypesTree)
dragSource.SetData(data)
dragSource.DoDragDrop()
self.ResetSelectedItem()
def OnTypesTreeItemBeginEdit(self, event):
selected = event.GetItem()
if self.TypesTree.GetPyData(selected) in ITEMS_UNEDITABLE:
event.Veto()
else:
event.Skip()
def OnTypesTreeItemEndEdit(self, event):
message = None
abort = False
new_name = event.GetLabel()
if new_name != "":
if not TestIdentifier(new_name):
message = _("\"%s\" is not a valid identifier!")%new_name
elif new_name.upper() in IEC_KEYWORDS:
message = _("\"%s\" is a keyword. It can't be used!")%new_name
else:
item = event.GetItem()
old_name = self.TypesTree.GetItemText(item)
itemtype = self.TypesTree.GetPyData(item)
if itemtype == ITEM_PROJECT:
self.Controler.SetProjectProperties(name = new_name)
elif itemtype == ITEM_DATATYPE:
if new_name.upper() in [name.upper() for name in self.Controler.GetProjectDataTypeNames() if name != old_name]:
message = _("\"%s\" data type already exists!")%new_name
abort = True
if not abort:
self.Controler.ChangeDataTypeName(old_name, new_name)
self.RefreshEditorNames(self.Controler.ComputeDataTypeName(old_name),
self.Controler.ComputeDataTypeName(new_name))
self.RefreshPageTitles()
elif itemtype == ITEM_POU:
if new_name.upper() in [name.upper() for name in self.Controler.GetProjectPouNames() if name != old_name]:
message = _("\"%s\" pou already exists!")%new_name
abort = True
elif new_name.upper() in [name.upper() for name in self.Controler.GetProjectPouVariables()]:
messageDialog = wx.MessageDialog(self, _("A POU has an element named \"%s\". This could cause a conflict. Do you wish to continue?")%new_name, _("Error"), wx.YES_NO|wx.ICON_QUESTION)
if messageDialog.ShowModal() == wx.ID_NO:
abort = True
messageDialog.Destroy()
if not abort:
self.Controler.ChangePouName(old_name, new_name)
self.RefreshEditorNames(self.Controler.ComputePouName(old_name),
self.Controler.ComputePouName(new_name))
self.RefreshLibraryTree()
self.RefreshPageTitles()
elif itemtype == ITEM_TRANSITION:
pou_name = GetParentName(self.TypesTree, item, ITEM_POU)
if new_name.upper() in [name.upper() for name in self.Controler.GetProjectPouNames()]:
message = _("A POU named \"%s\" already exists!")%new_name
elif new_name.upper() in [name.upper() for name in self.Controler.GetProjectPouVariables(pou_name) if name != old_name]:
message = _("A variable with \"%s\" as name already exists in this pou!")%new_name
else:
self.Controler.ChangePouTransitionName(pou_name, old_name, new_name)
self.RefreshEditorNames(self.Controler.ComputePouTransitionName(pou_name, old_name),
self.Controler.ComputePouTransitionName(pou_name, new_name))
self.RefreshPageTitles()
elif itemtype == ITEM_ACTION:
pou_name = GetParentName(self.TypesTree, item, ITEM_POU)
if new_name.upper() in [name.upper() for name in self.Controler.GetProjectPouNames()]:
message = _("A POU named \"%s\" already exists!")%new_name
elif new_name.upper() in [name.upper() for name in self.Controler.GetProjectPouVariables(pou_name) if name != old_name]:
message = _("A variable with \"%s\" as name already exists in this pou!")%new_name
else:
self.Controler.ChangePouActionName(pou_name, old_name, new_name)
self.RefreshEditorNames(self.Controler.ComputePouActionName(pou_name, old_name),
self.Controler.ComputePouActionName(pou_name, new_name))
self.RefreshPageTitles()
elif itemtype == ITEM_CONFIGURATION:
if new_name.upper() in [name.upper() for name in self.Controler.GetProjectConfigNames() if name != old_name]:
message = _("\"%s\" config already exists!")%new_name
abort = True
elif new_name.upper() in [name.upper() for name in self.Controler.GetProjectPouNames()]:
messageDialog = wx.MessageDialog(self, _("There is a POU named \"%s\". This could cause a conflict. Do you wish to continue?")%new_name, _("Error"), wx.YES_NO|wx.ICON_QUESTION)
if messageDialog.ShowModal() == wx.ID_NO:
abort = True
messageDialog.Destroy()
elif new_name.upper() in [name.upper() for name in self.Controler.GetProjectPouVariables()]:
messageDialog = wx.MessageDialog(self, _("A POU has an element named \"%s\". This could cause a conflict. Do you wish to continue?")%new_name, _("Error"), wx.YES_NO|wx.ICON_QUESTION)
if messageDialog.ShowModal() == wx.ID_NO:
abort = True
messageDialog.Destroy()
if not abort:
self.Controler.ChangeConfigurationName(old_name, new_name)
self.RefreshEditorNames(self.Controler.ComputeConfigurationName(old_name),
self.Controler.ComputeConfigurationName(new_name))
self.RefreshPageTitles()
elif itemtype == ITEM_RESOURCE:
config_name = GetParentName(self.TypesTree, item, ITEM_CONFIGURATION)
if new_name.upper() in [name.upper() for name in self.Controler.GetProjectConfigNames()]:
message = _("\"%s\" config already exists!")%new_name
abort = True
elif new_name.upper() in [name.upper() for name in self.Controler.GetProjectPouNames()]:
messageDialog = wx.MessageDialog(self, _("There is a POU named \"%s\". This could cause a conflict. Do you wish to continue?")%new_name, _("Error"), wx.YES_NO|wx.ICON_QUESTION)
if messageDialog.ShowModal() == wx.ID_NO:
abort = True
messageDialog.Destroy()
elif new_name.upper() in [name.upper() for name in self.Controler.GetProjectPouVariables()]:
messageDialog = wx.MessageDialog(self, _("A POU has an element named \"%s\". This could cause a conflict. Do you wish to continue?")%new_name, _("Error"), wx.YES_NO|wx.ICON_QUESTION)
if messageDialog.ShowModal() == wx.ID_NO:
abort = True
messageDialog.Destroy()
if not abort:
self.Controler.ChangeConfigurationResourceName(config_name, old_name, new_name)
self.RefreshEditorNames(self.Controler.ComputeConfigurationResourceName(config_name, old_name),
self.Controler.ComputeConfigurationResourceName(config_name, new_name))
self.RefreshPageTitles()
if message or abort:
if message:
self.ShowErrorMessage(message)
item = event.GetItem()
wx.CallAfter(self.TypesTree.EditLabel, item)
event.Veto()
else:
wx.CallAfter(self.RefreshTypesTree)
self.RefreshEditor()
self._Refresh(TITLE, FILEMENU, EDITMENU)
event.Skip()
def OnTypesTreeItemActivated(self, event):
selected = event.GetItem()
name = self.TypesTree.GetItemText(selected)
data = self.TypesTree.GetPyData(selected)
if UNEDITABLE_NAMES_DICT.get(name, name) == "Properties":
self.ShowProperties()
if data == ITEM_DATATYPE:
self.EditProjectElement(data, self.Controler.ComputeDataTypeName(name))
elif data == ITEM_POU:
self.EditProjectElement(data, self.Controler.ComputePouName(name))
elif data == ITEM_CONFIGURATION:
self.EditProjectElement(data, self.Controler.ComputeConfigurationName(name))
elif data == ITEM_RESOURCE:
config_name = GetParentName(self.TypesTree, selected, ITEM_CONFIGURATION)
self.EditProjectElement(data, self.Controler.ComputeConfigurationResourceName(config_name, name))
elif data in [ITEM_TRANSITION, ITEM_ACTION]:
pou_name = GetParentName(self.TypesTree, selected, ITEM_POU)
if data == ITEM_TRANSITION:
tagname = self.Controler.ComputePouTransitionName(pou_name, name)
elif data == ITEM_ACTION:
tagname = self.Controler.ComputePouActionName(pou_name, name)
self.EditProjectElement(data, tagname)
event.Skip()
def TypesTreeItemSelect(self, select_item):
name = self.TypesTree.GetItemText(select_item)
data = self.TypesTree.GetPyData(select_item)
if data == ITEM_DATATYPE:
self.EditProjectElement(data, self.Controler.ComputeDataTypeName(name), True)
elif data == ITEM_POU:
self.EditProjectElement(data, self.Controler.ComputePouName(name), True)
elif data == ITEM_CONFIGURATION:
self.EditProjectElement(data, self.Controler.ComputeConfigurationName(name), True)
elif data == ITEM_RESOURCE:
config_name = GetParentName(self.TypesTree, select_item, ITEM_CONFIGURATION)
self.EditProjectElement(data, self.Controler.ComputeConfigurationResourceName(config_name, name), True)
elif data in [ITEM_TRANSITION, ITEM_ACTION]:
pou_name = GetParentName(self.TypesTree, select_item, ITEM_POU)
if data == ITEM_TRANSITION:
tagname = self.Controler.ComputePouTransitionName(pou_name, name)
elif data == ITEM_ACTION:
tagname = self.Controler.ComputePouActionName(pou_name, name)
self.EditProjectElement(data, tagname, True)
def OnTypesTreeLeftUp(self, event):
if self.SelectedItem is not None:
self.TypesTree.SelectItem(self.SelectedItem)
self.TypesTreeItemSelect(self.SelectedItem)
wx.CallAfter(self.ResetSelectedItem)
event.Skip()
def OnTypesTreeItemSelected(self, event):
self.TypesTreeItemSelect(event.GetItem())
event.Skip()
def OnTypesTreeItemChanging(self, event):
if self.TypesTree.GetPyData(event.GetItem()) not in ITEMS_UNEDITABLE and self.SelectedItem is None:
self.SelectedItem = event.GetItem()
event.Veto()
else:
event.Skip()
def EditProjectElement(self, element, tagname, onlyopened = False):
openedidx = self.IsOpened(tagname)
if openedidx is not None:
old_selected = self.TabsOpened.GetSelection()
if old_selected != openedidx:
if old_selected >= 0:
self.TabsOpened.GetPage(old_selected).ResetBuffer()
self.TabsOpened.SetSelection(openedidx)
self._Refresh(FILEMENU, EDITMENU, TOOLBAR, PAGETITLES)
elif not onlyopened:
new_window = None
if element == ITEM_CONFIGURATION:
new_window = ConfigurationEditor(self.TabsOpened, tagname, self, self.Controler)
new_window.SetIcon(self.GenerateBitmap("CONFIGURATION"))
self.AddPage(new_window, "")
elif element == ITEM_RESOURCE:
new_window = ResourceEditor(self.TabsOpened, tagname, self, self.Controler)
new_window.SetIcon(self.GenerateBitmap("RESOURCE"))
self.AddPage(new_window, "")
elif element in [ITEM_POU, ITEM_TRANSITION, ITEM_ACTION]:
bodytype = self.Controler.GetEditedElementBodyType(tagname)
if bodytype == "FBD":
new_window = Viewer(self.TabsOpened, tagname, self, self.Controler)
new_window.RefreshScaling(False)
elif bodytype == "LD":
new_window = LD_Viewer(self.TabsOpened, tagname, self, self.Controler)
new_window.RefreshScaling(False)
elif bodytype == "SFC":
new_window = SFC_Viewer(self.TabsOpened, tagname, self, self.Controler)
new_window.RefreshScaling(False)
else:
new_window = TextViewer(self.TabsOpened, tagname, self, self.Controler)
new_window.SetTextSyntax(bodytype)
if bodytype == "IL":
new_window.SetKeywords(IL_KEYWORDS)
else:
new_window.SetKeywords(ST_KEYWORDS)
if element == ITEM_POU:
pou_type = self.Controler.GetEditedElementType(tagname)[1].upper()
icon = self.GenerateBitmap(pou_type, bodytype)
elif element == ITEM_TRANSITION:
icon = self.GenerateBitmap("TRANSITION", bodytype)
elif element == ITEM_ACTION:
icon = self.GenerateBitmap("ACTION", bodytype)
new_window.SetIcon(icon)
self.AddPage(new_window, "")
words = tagname.split("::")
elif element == ITEM_DATATYPE:
new_window = DataTypeEditor(self.TabsOpened, tagname, self, self.Controler)
new_window.SetIcon(self.GenerateBitmap("DATATYPE"))
self.AddPage(new_window, "")
elif isinstance(element, EditorPanel):
new_window = element
self.AddPage(element, "")
if new_window is not None:
openedidx = self.IsOpened(tagname)
old_selected = self.TabsOpened.GetSelection()
if old_selected != openedidx:
if old_selected >= 0:
self.TabsOpened.GetPage(old_selected).ResetBuffer()
for i in xrange(self.TabsOpened.GetPageCount()):
window = self.TabsOpened.GetPage(i)
if window == new_window:
self.TabsOpened.SetSelection(i)
window.SetFocus()
self.RefreshPageTitles()
def OnTypesTreeRightUp(self, event):
if wx.Platform == '__WXMSW__':
item = event.GetItem()
else:
item, flags = self.TypesTree.HitTest(wx.Point(event.GetX(), event.GetY()))
self.TypesTree.SelectItem(item)
self.TypesTreeItemSelect(item)
name = self.TypesTree.GetItemText(item)
type = self.TypesTree.GetPyData(item)
if type == ITEM_POU:
menu = wx.Menu(title='')
if self.Controler.GetPouBodyType(name) == "SFC":
new_id = wx.NewId()
AppendMenu(menu, help='', id=new_id, kind=wx.ITEM_NORMAL, text=_("Add Transition"))
self.Bind(wx.EVT_MENU, self.GenerateAddTransitionFunction(name), id=new_id)
new_id = wx.NewId()
AppendMenu(menu, help='', id=new_id, kind=wx.ITEM_NORMAL, text=_("Add Action"))
self.Bind(wx.EVT_MENU, self.GenerateAddActionFunction(name), id=new_id)
menu.AppendSeparator()
new_id = wx.NewId()
AppendMenu(menu, help='', id=new_id, kind=wx.ITEM_NORMAL, text=_("Copy POU"))
self.Bind(wx.EVT_MENU, self.OnCopyPou, id=new_id)
pou_type = self.Controler.GetPouType(name)
if pou_type in ["function", "functionBlock"]:
change_menu = wx.Menu(title='')
if pou_type == "function":
new_id = wx.NewId()
AppendMenu(change_menu, help='', id=new_id, kind=wx.ITEM_NORMAL, text=_("Function Block"))
self.Bind(wx.EVT_MENU, self.GenerateChangePouTypeFunction(name, "functionBlock"), id=new_id)
new_id = wx.NewId()
AppendMenu(change_menu, help='', id=new_id, kind=wx.ITEM_NORMAL, text=_("Program"))
self.Bind(wx.EVT_MENU, self.GenerateChangePouTypeFunction(name, "program"), id=new_id)
menu.AppendMenu(wx.NewId(), _("Change POU Type To"), change_menu)
new_id = wx.NewId()
AppendMenu(menu, help='', id=new_id, kind=wx.ITEM_NORMAL, text=_("Rename"))
self.Bind(wx.EVT_MENU, self.OnRenamePouMenu, id=new_id)
new_id = wx.NewId()
AppendMenu(menu, help='', id=new_id, kind=wx.ITEM_NORMAL, text=_("Delete"))
self.Bind(wx.EVT_MENU, self.OnDeleteMenu, id=new_id)
self.PopupMenu(menu)
elif type == ITEM_CONFIGURATION:
menu = wx.Menu(title='')
new_id = wx.NewId()
AppendMenu(menu, help='', id=new_id, kind=wx.ITEM_NORMAL, text=_("Add Resource"))
self.Bind(wx.EVT_MENU, self.GenerateAddResourceFunction(name), id=new_id)
new_id = wx.NewId()
AppendMenu(menu, help='', id=new_id, kind=wx.ITEM_NORMAL, text=_("Delete"))
self.Bind(wx.EVT_MENU, self.OnDeleteMenu, id=new_id)
self.PopupMenu(menu)
elif type in [ITEM_DATATYPE, ITEM_TRANSITION, ITEM_ACTION, ITEM_RESOURCE]:
menu = wx.Menu(title='')
new_id = wx.NewId()
AppendMenu(menu, help='', id=new_id, kind=wx.ITEM_NORMAL, text=_("Delete"))
self.Bind(wx.EVT_MENU, self.OnDeleteMenu, id=new_id)
self.PopupMenu(menu)
elif type in ITEMS_UNEDITABLE:
name = UNEDITABLE_NAMES_DICT[name]
if name == "Data Types":
menu = wx.Menu(title='')
new_id = wx.NewId()
AppendMenu(menu, help='', id=new_id, kind=wx.ITEM_NORMAL, text=_("Add DataType"))
self.Bind(wx.EVT_MENU, self.OnAddDataTypeMenu, id=new_id)
self.PopupMenu(menu)
elif name in ["Functions", "Function Blocks", "Programs"]:
menu = wx.Menu(title='')
new_id = wx.NewId()
AppendMenu(menu, help='', id=new_id, kind=wx.ITEM_NORMAL, text=_("Add POU"))
self.Bind(wx.EVT_MENU, self.GenerateAddPouFunction({"Functions" : "function", "Function Blocks" : "functionBlock", "Programs" : "program"}[name]), id=new_id)
new_id = wx.NewId()
AppendMenu(menu, help='', id=new_id, kind=wx.ITEM_NORMAL, text=_("Paste POU"))
self.Bind(wx.EVT_MENU, self.OnPastePou, id=new_id)
if self.GetCopyBuffer() is None:
menu.Enable(new_id, False)
self.PopupMenu(menu)
elif name == "Configurations":
menu = wx.Menu(title='')
new_id = wx.NewId()
AppendMenu(menu, help='', id=new_id, kind=wx.ITEM_NORMAL, text=_("Add Configuration"))
self.Bind(wx.EVT_MENU, self.OnAddConfigurationMenu, id=new_id)
self.PopupMenu(menu)
elif name == "Transitions":
menu = wx.Menu(title='')
new_id = wx.NewId()
AppendMenu(menu, help='', id=new_id, kind=wx.ITEM_NORMAL, text=_("Add Transition"))
parent = self.TypesTree.GetItemParent(item)
parent_type = self.TypesTree.GetPyData(parent)
while parent_type != ITEM_POU:
parent = self.TypesTree.GetItemParent(parent)
parent_type = self.TypesTree.GetPyData(parent)
self.Bind(wx.EVT_MENU, self.GenerateAddTransitionFunction(self.TypesTree.GetItemText(parent)), id=new_id)
self.PopupMenu(menu)
elif name == "Actions":
menu = wx.Menu(title='')
new_id = wx.NewId()
AppendMenu(menu, help='', id=new_id, kind=wx.ITEM_NORMAL, text=_("Add Action"))
parent = self.TypesTree.GetItemParent(item)
parent_type = self.TypesTree.GetPyData(parent)
while parent_type != ITEM_POU:
parent = self.TypesTree.GetItemParent(parent)
parent_type = self.TypesTree.GetPyData(parent)
self.Bind(wx.EVT_MENU, self.GenerateAddActionFunction(self.TypesTree.GetItemText(parent)), id=new_id)
self.PopupMenu(menu)
elif name == "Resources":
menu = wx.Menu(title='')
new_id = wx.NewId()
AppendMenu(menu, help='', id=new_id, kind=wx.ITEM_NORMAL, text=_("Add Resource"))
parent = self.TypesTree.GetItemParent(item)
parent_type = self.TypesTree.GetPyData(parent)
while parent_type != ITEM_CONFIGURATION:
parent = self.TypesTree.GetItemParent(parent)
parent_type = self.TypesTree.GetPyData(parent)
self.Bind(wx.EVT_MENU, self.GenerateAddResourceFunction(self.TypesTree.GetItemText(parent)), id=new_id)
self.PopupMenu(menu)
event.Skip()
#-------------------------------------------------------------------------------
# Instances Tree Management Functions
#-------------------------------------------------------------------------------
def RefreshInstancesTree(self):
infos = self.Controler.GetProjectTopology(self.EnableDebug)
root = self.InstancesTree.GetRootItem()
if not root.IsOk():
root = self.InstancesTree.AddRoot(infos["name"])
self.GenerateInstancesTreeBranch(root, infos)
self.InstancesTree.Expand(root)
def GenerateInstancesTreeBranch(self, root, infos):
to_delete = []
if infos.get("elmt_type", None) is not None:
self.InstancesTree.SetItemText(root, "%s (%s)"%(infos["name"], infos["elmt_type"]))
else:
self.InstancesTree.SetItemText(root, infos["name"])
self.InstancesTree.SetPyData(root, (infos["type"], infos.get("tagname", None)))
self.InstancesTree.SetItemImage(root, self.TreeImageDict[infos["type"]])
if wx.VERSION >= (2, 6, 0):
item, root_cookie = self.InstancesTree.GetFirstChild(root)
else:
item, root_cookie = self.InstancesTree.GetFirstChild(root, 0)
for values in infos["values"]:
if not item.IsOk():
item = self.InstancesTree.AppendItem(root, "")
if wx.Platform != '__WXMSW__':
item, root_cookie = self.InstancesTree.GetNextChild(root, root_cookie)
self.GenerateInstancesTreeBranch(item, values)
item, root_cookie = self.InstancesTree.GetNextChild(root, root_cookie)
while item.IsOk():
to_delete.append(item)
item, root_cookie = self.InstancesTree.GetNextChild(root, root_cookie)
for item in to_delete:
self.InstancesTree.Delete(item)
if infos["type"] in [ITEM_CONFIGURATION, ITEM_RESOURCE]:
self.InstancesTree.Expand(root)
def OnInstancesTreeBeginDrag(self, event):
if self.Controler.DebugAvailable():
selected_item = event.GetItem()
selected_infos = self.InstancesTree.GetPyData(selected_item)
if selected_item is not None and selected_infos[0] in ITEMS_VARIABLE:
var_path = self.InstancesTree.GetItemText(selected_item).split(" (")[0]
parent_item = self.InstancesTree.GetItemParent(selected_item)
while self.InstancesTree.GetPyData(parent_item)[0] != ITEM_PROJECT:
parent_name = self.InstancesTree.GetItemText(parent_item).split(" (")[0]
var_path = "%s.%s"%(parent_name, var_path)
parent_item = self.InstancesTree.GetItemParent(parent_item)
data = wx.TextDataObject(str((var_path, "debug")))
dragSource = wx.DropSource(self.InstancesTree)
dragSource.SetData(data)
dragSource.DoDragDrop()
event.Skip()
else:
event.Veto()
def OnInstancesTreeItemActivated(self, event):
if self.Controler.DebugAvailable():
selected_item = event.GetItem()
selected_infos = self.InstancesTree.GetPyData(selected_item)
if selected_item is not None and selected_infos[0] in [ITEM_FUNCTIONBLOCK, ITEM_PROGRAM, ITEM_TRANSITION, ITEM_ACTION]:
instance_path = self.InstancesTree.GetItemText(selected_item).split(" (")[0]
parent_item = self.InstancesTree.GetItemParent(selected_item)
while self.InstancesTree.GetPyData(parent_item)[0] != ITEM_PROJECT:
parent_name = self.InstancesTree.GetItemText(parent_item).split(" (")[0]
instance_path = "%s.%s"%(parent_name, instance_path)
parent_item = self.InstancesTree.GetItemParent(parent_item)
openedidx = self.IsOpened(instance_path)
if openedidx is not None:
old_selected = self.TabsOpened.GetSelection()
if old_selected != openedidx:
if old_selected >= 0:
self.TabsOpened.GetPage(old_selected).ResetBuffer()
self.TabsOpened.SetSelection(openedidx)
elif selected_infos[1] is not None:
bodytype = self.Controler.GetEditedElementBodyType(selected_infos[1], True)
if bodytype == "FBD":
new_window = Viewer(self.TabsOpened, selected_infos[1], self, self.Controler, True, instance_path)
new_window.RefreshScaling(False)
elif bodytype == "LD":
new_window = LD_Viewer(self.TabsOpened, selected_infos[1], self, self.Controler, True, instance_path)
new_window.RefreshScaling(False)
elif bodytype == "SFC":
new_window = SFC_Viewer(self.TabsOpened, selected_infos[1], self, self.Controler, True, instance_path)
new_window.RefreshScaling(False)
else:
new_window = TextViewer(self.TabsOpened, selected_infos[1], self, self.Controler, True, instance_path)
new_window.SetTextSyntax(bodytype)
if bodytype == "IL":
new_window.SetKeywords(IL_KEYWORDS)
else:
new_window.SetKeywords(ST_KEYWORDS)
if selected_infos[0] in [ITEM_FUNCTIONBLOCK, ITEM_PROGRAM]:
pou_type = self.Controler.GetEditedElementType(selected_infos[1], True)[1].upper()
icon = self.GenerateBitmap(pou_type, bodytype)
elif selected_infos[0] == ITEM_TRANSITION:
icon = self.GenerateBitmap("TRANSITION", bodytype)
elif selected_infos[0] == ITEM_ACTION:
icon = self.GenerateBitmap("ACTION", bodytype)
new_window.SetIcon(icon)
self.AddPage(new_window, "")
new_window.SetFocus()
self.RefreshPageTitles()
if selected_item is not None and selected_infos[0] in ITEMS_VARIABLE:
var_path, var_type = self.InstancesTree.GetItemText(selected_item).split(" (")
var_type = var_type.split(")")[0]
if self.Controler.IsOfType(var_type, "ANY_NUM", True) or\
self.Controler.IsOfType(var_type, "ANY_BIT", True):
parent_item = self.InstancesTree.GetItemParent(selected_item)
while self.InstancesTree.GetPyData(parent_item)[0] != ITEM_PROJECT:
parent_name = self.InstancesTree.GetItemText(parent_item).split(" (")[0]
var_path = "%s.%s"%(parent_name, var_path)
parent_item = self.InstancesTree.GetItemParent(parent_item)
self.OpenGraphicViewer(var_path)
event.Skip()
def OpenGraphicViewer(self, var_path):
new_window = GraphicViewer(self.TabsOpened, self, self.Controler, var_path)
self.AddPage(new_window, "")
new_window.SetFocus()
self.RefreshPageTitles()
def OnInstancesTreeRightUp(self, event):
if self.Controler.DebugAvailable():
if wx.Platform == '__WXMSW__':
selected_item = event.GetItem()
else:
selected_item = self.InstancesTree.GetSelection()
selected_infos = self.InstancesTree.GetPyData(selected_item)
if selected_item is not None and selected_infos[0] in ITEMS_VARIABLE:
var_path, var_type = self.InstancesTree.GetItemText(selected_item).split(" (")
var_type = var_type.split(")")[0]
if self.Controler.IsOfType(var_type, "ANY_NUM", True) or\
self.Controler.IsOfType(var_type, "ANY_BIT", True):
parent_item = self.InstancesTree.GetItemParent(selected_item)
while self.InstancesTree.GetPyData(parent_item)[0] != ITEM_PROJECT:
parent_name = self.InstancesTree.GetItemText(parent_item).split(" (")[0]
var_path = "%s.%s"%(parent_name, var_path)
parent_item = self.InstancesTree.GetItemParent(parent_item)
menu = wx.Menu(title='')
new_id = wx.NewId()
AppendMenu(menu, help='', id=new_id, kind=wx.ITEM_NORMAL, text=_("Graphic Panel"))
self.Bind(wx.EVT_MENU, self.AddVariableGraphicFunction(var_path), id=new_id)
new_id = wx.NewId()
AppendMenu(menu, help='', id=new_id, kind=wx.ITEM_NORMAL, text=_("CSV Log"))
self.PopupMenu(menu)
event.Skip()
def AddVariableGraphicFunction(self, iec_path):
def AddVariableGraphic(event):
self.OpenGraphicViewer(iec_path)
event.Skip()
return AddVariableGraphic
def SelectInstancesTreeItem(self, root, instancepath):
found = False
if self.InstancesTree is not None:
paths = instancepath.split(".", 1)
if wx.VERSION >= (2, 6, 0):
item, root_cookie = self.InstancesTree.GetFirstChild(root)
else:
item, root_cookie = self.InstancesTree.GetFirstChild(root, 0)
while item.IsOk() and not found:
name = self.InstancesTree.GetItemText(item).split(" (")[0]
if name == paths[0]:
if len(paths) == 1:
self.InstancesTree.SelectItem(item)
return True
else:
found = self.SelectInstancesTreeItem(item, paths[1])
item, root_cookie = self.InstancesTree.GetNextChild(root, root_cookie)
return found
def ResetGraphicViewers(self):
for i in xrange(self.TabsOpened.GetPageCount()):
editor = self.TabsOpened.GetPage(i)
if isinstance(editor, GraphicViewer):
editor.ResetView()
def CloseDebugTabs(self):
if self.EnableDebug:
idxs = range(self.TabsOpened.GetPageCount())
idxs.reverse()
for idx in idxs:
window = self.TabsOpened.GetPage(idx)
if window.IsDebugging():
self.TabsOpened.DeletePage(idx)
self.DebugVariablePanel.ResetGrid()
def AddDebugVariable(self, iec_path):
if self.EnableDebug:
self.DebugVariablePanel.InsertValue(iec_path)
#-------------------------------------------------------------------------------
# Library Tree Management Functions
#-------------------------------------------------------------------------------
def RefreshLibraryTree(self):
if self.Controler is not None:
to_delete = []
blocktypes = self.Controler.GetBlockTypes()
root = self.LibraryTree.GetRootItem()
if not root.IsOk():
root = self.LibraryTree.AddRoot("")
if wx.VERSION >= (2, 6, 0):
category_item, root_cookie = self.LibraryTree.GetFirstChild(root)
else:
category_item, root_cookie = self.LibraryTree.GetFirstChild(root, 0)
for category in blocktypes:
category_name = category["name"]
if not category_item.IsOk():
category_item = self.LibraryTree.AppendItem(root, _(category_name))
if wx.Platform != '__WXMSW__':
category_item, root_cookie = self.LibraryTree.GetNextChild(root, root_cookie)
else:
self.LibraryTree.SetItemText(category_item, _(category_name))
self.LibraryTree.SetPyData(category_item, {"type" : CATEGORY})
if wx.VERSION >= (2, 6, 0):
blocktype_item, category_cookie = self.LibraryTree.GetFirstChild(category_item)
else:
blocktype_item, category_cookie = self.LibraryTree.GetFirstChild(category_item, 0)
for blocktype in category["list"]:
if not blocktype_item.IsOk():
blocktype_item = self.LibraryTree.AppendItem(category_item, blocktype["name"])
if wx.Platform != '__WXMSW__':
blocktype_item, category_cookie = self.LibraryTree.GetNextChild(category_item, category_cookie)
else:
self.LibraryTree.SetItemText(blocktype_item, blocktype["name"])
self.LibraryTree.SetPyData(blocktype_item, {"type" : BLOCK, "block_type" : blocktype["type"], "inputs" : tuple([type for name, type, modifier in blocktype["inputs"]])})
blocktype_item, category_cookie = self.LibraryTree.GetNextChild(category_item, category_cookie)
while blocktype_item.IsOk():
to_delete.append(blocktype_item)
blocktype_item, category_cookie = self.LibraryTree.GetNextChild(category_item, category_cookie)
category_item, root_cookie = self.LibraryTree.GetNextChild(root, root_cookie)
while category_item.IsOk():
to_delete.append(category_item)
category_item, root_cookie = self.LibraryTree.GetNextChild(root, root_cookie)
for item in to_delete:
self.LibraryTree.Delete(item)
def OnLibraryTreeItemSelected(self, event):
selected = event.GetItem()
pydata = self.LibraryTree.GetPyData(selected)
if pydata is not None and pydata["type"] != CATEGORY:
blocktype = self.Controler.GetBlockType(self.LibraryTree.GetItemText(selected), pydata["inputs"])
if blocktype:
comment = blocktype["comment"]
self.LibraryComment.SetValue(_(comment) + blocktype.get("usage", ""))
else:
self.LibraryComment.SetValue("")
else:
self.LibraryComment.SetValue("")
event.Skip()
def OnLibraryTreeBeginDrag(self, event):
selected = event.GetItem()
pydata = self.LibraryTree.GetPyData(selected)
if pydata is not None and pydata["type"] == BLOCK:
data = wx.TextDataObject(str((self.LibraryTree.GetItemText(selected),
pydata["block_type"], "", pydata["inputs"])))
dragSource = wx.DropSource(self.LibraryTree)
dragSource.SetData(data)
dragSource.DoDragDrop()
#-------------------------------------------------------------------------------
# ToolBar Management Functions
#-------------------------------------------------------------------------------
def ResetToolBar(self):
if USE_AUI:
ToolBar = self.Panes["ToolBar"]
else:
ToolBar = self.ToolBar
for item in self.CurrentToolBar:
if wx.VERSION >= (2, 6, 0):
self.Unbind(wx.EVT_MENU, id=item)
else:
self.Disconnect(id=item, eventType=wx.wxEVT_COMMAND_MENU_SELECTED)
if ToolBar:
ToolBar.DeleteTool(item)
if ToolBar:
ToolBar.Realize()
if USE_AUI:
self.AUIManager.GetPane("ToolBar").BestSize(ToolBar.GetBestSize())
self.AUIManager.Update()
def RefreshToolBar(self):
selected = self.TabsOpened.GetSelection()
language = None
if selected != -1:
window = self.TabsOpened.GetPage(selected)
if not window.IsDebugging():
language = self.Controler.GetEditedElementBodyType(window.GetTagName())
if language is not None and language != self.CurrentLanguage:
self.ResetToolBar()
self.CurrentLanguage = language
self.CurrentToolBar = []
if USE_AUI:
ToolBar = self.Panes["ToolBar"]
else:
ToolBar = self.ToolBar
if ToolBar:
for radio, modes, id, method, picture, help in ToolBarItems[language]:
if modes & self.DrawingMode:
if radio or self.DrawingMode == FREEDRAWING_MODE:
ToolBar.AddRadioTool(id, wx.Bitmap(os.path.join(CWD, "Images", picture)), wx.NullBitmap, help)
else:
ToolBar.AddSimpleTool(id, wx.Bitmap(os.path.join(CWD, "Images", picture)), help)
self.Bind(wx.EVT_TOOL, getattr(self, method), id=id)
self.CurrentToolBar.append(id)
ToolBar.Realize()
if USE_AUI:
self.AUIManager.GetPane("ToolBar").BestSize(ToolBar.GetBestSize())
self.AUIManager.Update()
elif not language:
self.ResetToolBar()
self.CurrentLanguage = language
self.ResetCurrentMode()
#-------------------------------------------------------------------------------
# ToolBar Items Functions
#-------------------------------------------------------------------------------
def ResetCurrentMode(self):
selected = self.TabsOpened.GetSelection()
if selected != -1:
window = self.TabsOpened.GetPage(selected)
window.SetMode(MODE_SELECTION)
if USE_AUI:
ToolBar = self.Panes["ToolBar"]
else:
ToolBar = self.ToolBar
if ToolBar:
ToolBar.ToggleTool(ID_PLCOPENEDITORTOOLBARSELECTION, False)
ToolBar.ToggleTool(ID_PLCOPENEDITORTOOLBARSELECTION, True)
def ResetToolToggle(self, id):
if USE_AUI:
tool = self.Panes["ToolBar"].FindById(id)
else:
tool = self.ToolBar.FindById(id)
tool.SetToggle(False)
def OnSelectionTool(self, event):
selected = self.TabsOpened.GetSelection()
if selected != -1:
self.TabsOpened.GetPage(selected).SetMode(MODE_SELECTION)
def OnMotionTool(self, event):
selected = self.TabsOpened.GetSelection()
if selected != -1:
self.TabsOpened.GetPage(selected).SetMode(MODE_MOTION)
def OnCommentTool(self, event):
self.ResetToolToggle(ID_PLCOPENEDITORTOOLBARCOMMENT)
selected = self.TabsOpened.GetSelection()
if selected != -1:
self.TabsOpened.GetPage(selected).SetMode(MODE_COMMENT)
def OnVariableTool(self, event):
self.ResetToolToggle(ID_PLCOPENEDITORTOOLBARVARIABLE)
selected = self.TabsOpened.GetSelection()
if selected != -1:
self.TabsOpened.GetPage(selected).SetMode(MODE_VARIABLE)
def OnBlockTool(self, event):
self.ResetToolToggle(ID_PLCOPENEDITORTOOLBARBLOCK)
selected = self.TabsOpened.GetSelection()
if selected != -1:
self.TabsOpened.GetPage(selected).SetMode(MODE_BLOCK)
def OnConnectionTool(self, event):
self.ResetToolToggle(ID_PLCOPENEDITORTOOLBARCONNECTION)
selected = self.TabsOpened.GetSelection()
if selected != -1:
self.TabsOpened.GetPage(selected).SetMode(MODE_CONNECTION)
def OnPowerRailTool(self, event):
self.ResetToolToggle(ID_PLCOPENEDITORTOOLBARPOWERRAIL)
selected = self.TabsOpened.GetSelection()
if selected != -1:
self.TabsOpened.GetPage(selected).SetMode(MODE_POWERRAIL)
def OnRungTool(self, event):
selected = self.TabsOpened.GetSelection()
if selected != -1:
self.TabsOpened.GetPage(selected).AddLadderRung()
event.Skip()
def OnCoilTool(self, event):
self.ResetToolToggle(ID_PLCOPENEDITORTOOLBARCOIL)
selected = self.TabsOpened.GetSelection()
if selected != -1:
self.TabsOpened.GetPage(selected).SetMode(MODE_COIL)
event.Skip()
def OnContactTool(self, event):
if self.DrawingMode == FREEDRAWING_MODE:
self.ResetToolToggle(ID_PLCOPENEDITORTOOLBARCONTACT)
selected = self.TabsOpened.GetSelection()
if selected != -1:
if self.DrawingMode == FREEDRAWING_MODE:
self.TabsOpened.GetPage(selected).SetMode(MODE_CONTACT)
else:
self.TabsOpened.GetPage(selected).AddLadderContact()
def OnBranchTool(self, event):
selected = self.TabsOpened.GetSelection()
if selected != -1:
self.TabsOpened.GetPage(selected).AddLadderBranch()
def OnInitialStepTool(self, event):
self.ResetToolToggle(ID_PLCOPENEDITORTOOLBARINITIALSTEP)
selected = self.TabsOpened.GetSelection()
if selected != -1:
self.TabsOpened.GetPage(selected).SetMode(MODE_INITIALSTEP)
def OnStepTool(self, event):
if self.GetDrawingMode() == FREEDRAWING_MODE:
self.ResetToolToggle(ID_PLCOPENEDITORTOOLBARSTEP)
selected = self.TabsOpened.GetSelection()
if selected != -1:
if self.GetDrawingMode() == FREEDRAWING_MODE:
self.TabsOpened.GetPage(selected).SetMode(MODE_STEP)
else:
self.TabsOpened.GetPage(selected).AddStep()
def OnActionBlockTool(self, event):
if self.GetDrawingMode() == FREEDRAWING_MODE:
self.ResetToolToggle(ID_PLCOPENEDITORTOOLBARACTIONBLOCK)
selected = self.TabsOpened.GetSelection()
if selected != -1:
if self.GetDrawingMode() == FREEDRAWING_MODE:
self.TabsOpened.GetPage(selected).SetMode(MODE_ACTION)
else:
self.TabsOpened.GetPage(selected).AddStepAction()
def OnTransitionTool(self, event):
self.ResetToolToggle(ID_PLCOPENEDITORTOOLBARTRANSITION)
selected = self.TabsOpened.GetSelection()
if selected != -1:
self.TabsOpened.GetPage(selected).SetMode(MODE_TRANSITION)
def OnDivergenceTool(self, event):
if self.GetDrawingMode() == FREEDRAWING_MODE:
self.ResetToolToggle(ID_PLCOPENEDITORTOOLBARDIVERGENCE)
selected = self.TabsOpened.GetSelection()
if selected != -1:
if self.GetDrawingMode() == FREEDRAWING_MODE:
self.TabsOpened.GetPage(selected).SetMode(MODE_DIVERGENCE)
else:
self.TabsOpened.GetPage(selected).AddDivergence()
def OnJumpTool(self, event):
if self.GetDrawingMode() == FREEDRAWING_MODE:
self.ResetToolToggle(ID_PLCOPENEDITORTOOLBARJUMP)
selected = self.TabsOpened.GetSelection()
if selected != -1:
if self.GetDrawingMode() == FREEDRAWING_MODE:
self.TabsOpened.GetPage(selected).SetMode(MODE_JUMP)
else:
self.TabsOpened.GetPage(selected).AddJump()
#-------------------------------------------------------------------------------
# Add Project Elements Functions
#-------------------------------------------------------------------------------
def OnAddDataTypeMenu(self, event):
dialog = DataTypeDialog(self, _("Add a new data type"), _("Please enter data type name"), "", wx.OK|wx.CANCEL)
dialog.SetDataTypeNames(self.Controler.GetProjectDataTypeNames())
if dialog.ShowModal() == wx.ID_OK:
tagname = self.Controler.ProjectAddDataType(dialog.GetValue())
if tagname is not None:
self._Refresh(TITLE, FILEMENU, EDITMENU, TYPESTREE)
self.EditProjectElement(ITEM_DATATYPE, tagname)
dialog.Destroy()
def GenerateAddPouFunction(self, pou_type):
def OnAddPouMenu(event):
dialog = PouDialog(self, pou_type)
dialog.SetPouNames(self.Controler.GetProjectPouNames())
dialog.SetPouElementNames(self.Controler.GetProjectPouVariables())
if dialog.ShowModal() == wx.ID_OK:
values = dialog.GetValues()
tagname = self.Controler.ProjectAddPou(values["pouName"], values["pouType"], values["language"])
if tagname is not None:
self._Refresh(TITLE, FILEMENU, EDITMENU, TYPESTREE, LIBRARYTREE)
self.EditProjectElement(ITEM_POU, tagname)
dialog.Destroy()
return OnAddPouMenu
def GenerateAddTransitionFunction(self, pou_name):
def OnAddTransitionMenu(event):
dialog = PouTransitionDialog(self)
dialog.SetPouNames(self.Controler.GetProjectPouNames())
dialog.SetPouElementNames(self.Controler.GetProjectPouVariables(pou_name))
if dialog.ShowModal() == wx.ID_OK:
values = dialog.GetValues()
tagname = self.Controler.ProjectAddPouTransition(pou_name, values["transitionName"], values["language"])
if tagname is not None:
self._Refresh(TITLE, FILEMENU, EDITMENU, TYPESTREE)
self.EditProjectElement(ITEM_TRANSITION, tagname)
dialog.Destroy()
return OnAddTransitionMenu
def GenerateAddActionFunction(self, pou_name):
def OnAddActionMenu(event):
dialog = PouActionDialog(self)
dialog.SetPouNames(self.Controler.GetProjectPouNames())
dialog.SetPouElementNames(self.Controler.GetProjectPouVariables(pou_name))
if dialog.ShowModal() == wx.ID_OK:
values = dialog.GetValues()
tagname = self.Controler.ProjectAddPouAction(pou_name, values["actionName"], values["language"])
if tagname is not None:
self._Refresh(TITLE, FILEMENU, EDITMENU, TYPESTREE)
self.EditProjectElement(ITEM_ACTION, tagname)
dialog.Destroy()
return OnAddActionMenu
def OnAddConfigurationMenu(self, event):
dialog = ConfigurationNameDialog(self, _("Please enter configuration name"), _("Add new configuration"))
dialog.SetPouNames(self.Controler.GetProjectPouNames())
dialog.SetPouElementNames(self.Controler.GetProjectPouVariables())
if dialog.ShowModal() == wx.ID_OK:
value = dialog.GetValue()
tagname = self.Controler.ProjectAddConfiguration(value)
if tagname is not None:
self._Refresh(TITLE, FILEMENU, EDITMENU, TYPESTREE, INSTANCESTREE)
self.EditProjectElement(ITEM_CONFIGURATION, tagname)
dialog.Destroy()
def GenerateAddResourceFunction(self, config_name):
def OnAddResourceMenu(event):
dialog = ResourceNameDialog(self, _("Please enter resource name"), _("Add new resource"))
dialog.SetPouNames(self.Controler.GetProjectPouNames())
dialog.SetPouElementNames(self.Controler.GetProjectPouVariables())
if dialog.ShowModal() == wx.ID_OK:
value = dialog.GetValue()
tagname = self.Controler.ProjectAddConfigurationResource(config_name, value)
if tagname is not None:
self._Refresh(TITLE, FILEMENU, EDITMENU, TYPESTREE, INSTANCESTREE)
self.EditProjectElement(ITEM_RESOURCE, tagname)
dialog.Destroy()
return OnAddResourceMenu
def GenerateChangePouTypeFunction(self, name, new_type):
def OnChangePouTypeMenu(event):
selected = self.TypesTree.GetSelection()
if self.TypesTree.GetPyData(selected) == ITEM_POU:
self.Controler.ProjectChangePouType(name, new_type)
self._Refresh(TITLE, TOOLBAR, FILEMENU, EDITMENU, TYPESTREE, LIBRARYTREE)
return OnChangePouTypeMenu
def OnCopyPou(self, event):
selected = self.TypesTree.GetSelection()
pou_name = self.TypesTree.GetItemText(selected)
pou_xml = self.Controler.GetPouXml(pou_name)
if pou_xml is not None:
self.SetCopyBuffer(pou_xml)
self._Refresh(EDITMENU)
def OnPastePou(self, event):
selected = self.TypesTree.GetSelection()
pou_type = self.TypesTree.GetItemText(selected)
pou_type = UNEDITABLE_NAMES_DICT[pou_type] # one of 'Functions', 'Function Blocks' or 'Programs'
pou_type = {'Functions': 'function', 'Function Blocks': 'functionBlock', 'Programs': 'program'}[pou_type]
pou_xml = self.GetCopyBuffer()
result = self.Controler.PastePou(pou_type, pou_xml)
if result is not None:
message = wx.MessageDialog(self, result, _("Error"), wx.OK|wx.ICON_ERROR)
message.ShowModal()
message.Destroy()
else:
self._Refresh(TITLE, TOOLBAR, FILEMENU, EDITMENU, TYPESTREE, LIBRARYTREE)
#-------------------------------------------------------------------------------
# Remove Project Elements Functions
#-------------------------------------------------------------------------------
def OnRemoveDataTypeMenu(self, event):
selected = self.TypesTree.GetSelection()
if self.TypesTree.GetPyData(selected) == ITEM_DATATYPE:
name = self.TypesTree.GetItemText(selected)
if not self.Controler.DataTypeIsUsed(name):
self.Controler.ProjectRemoveDataType(name)
tagname = self.Controler.ComputeDataTypeName(name)
idx = self.IsOpened(tagname)
if idx is not None:
self.TabsOpened.DeletePage(idx)
self._Refresh(TITLE, TOOLBAR, FILEMENU, EDITMENU, TYPESTREE)
else:
self.ShowErrorMessage(_("\"%s\" is used by one or more POUs. It can't be removed!"))
def OnRenamePouMenu(self, event):
selected = self.TypesTree.GetSelection()
if self.TypesTree.GetPyData(selected) == ITEM_POU:
wx.CallAfter(self.TypesTree.EditLabel, selected)
def OnRemovePouMenu(self, event):
selected = self.TypesTree.GetSelection()
if self.TypesTree.GetPyData(selected) == ITEM_POU:
name = self.TypesTree.GetItemText(selected)
if not self.Controler.PouIsUsed(name):
self.Controler.ProjectRemovePou(name)
tagname = self.Controler.ComputePouName(name)
idx = self.IsOpened(tagname)
if idx is not None:
self.TabsOpened.DeletePage(idx)
self._Refresh(TITLE, TOOLBAR, FILEMENU, EDITMENU, TYPESTREE, INSTANCESTREE, LIBRARYTREE)
else:
self.ShowErrorMessage(_("\"%s\" is used by one or more POUs. It can't be removed!"))
def OnRemoveTransitionMenu(self, event):
selected = self.TypesTree.GetSelection()
if self.TypesTree.GetPyData(selected) == ITEM_TRANSITION:
transition = self.TypesTree.GetItemText(selected)
item = self.TypesTree.GetItemParent(selected)
item_type = self.TypesTree.GetPyData(item)
while item_type != ITEM_POU:
item = self.TypesTree.GetItemParent(item)
item_type = self.TypesTree.GetPyData(item)
pou_name = self.TypesTree.GetItemText(item)
self.Controler.ProjectRemovePouTransition(pou_name, transition)
tagname = self.Controler.ComputePouTransitionName(pou_name, transition)
idx = self.IsOpened(tagname)
if idx is not None:
self.TabsOpened.DeletePage(idx)
self._Refresh(TITLE, FILEMENU, EDITMENU, TYPESTREE)
def OnRemoveActionMenu(self, event):
selected = self.TypesTree.GetSelection()
if self.TypesTree.GetPyData(selected) == ITEM_ACTION:
action = self.TypesTree.GetItemText(selected)
item = self.TypesTree.GetItemParent(selected)
item_type = self.TypesTree.GetPyData(item)
while item_type != ITEM_POU:
item = self.TypesTree.GetItemParent(item)
item_type = self.TypesTree.GetPyData(item)
pou_name = self.TypesTree.GetItemText(item)
self.Controler.ProjectRemovePouAction(pou_name, action)
tagname = self.Controler.ComputePouActionName(pou_name, action)
idx = self.IsOpened(tagname)
if idx is not None:
self.TabsOpened.DeletePage(idx)
self._Refresh(TITLE, FILEMENU, EDITMENU, TYPESTREE)
def OnRemoveConfigurationMenu(self, event):
selected = self.TypesTree.GetSelection()
if self.TypesTree.GetPyData(selected) == ITEM_CONFIGURATION:
name = self.TypesTree.GetItemText(selected)
self.Controler.ProjectRemoveConfiguration(name)
tagname = self.Controler.ComputeConfigurationName(name)
idx = self.IsOpened(tagname)
if idx is not None:
self.TabsOpened.DeletePage(idx)
self._Refresh(TITLE, FILEMENU, EDITMENU, TYPESTREE, INSTANCESTREE)
def OnRemoveResourceMenu(self, event):
selected = self.TypesTree.GetSelection()
if self.TypesTree.GetPyData(selected) == ITEM_RESOURCE:
resource = self.TypesTree.GetItemText(selected)
item = self.TypesTree.GetItemParent(selected)
item_type = self.TypesTree.GetPyData(item)
while item_type != ITEM_CONFIGURATION:
item = self.TypesTree.GetItemParent(item)
item_type = self.TypesTree.GetPyData(item)
config_name = self.TypesTree.GetItemText(item)
self.Controler.ProjectRemoveConfigurationResource(config_name, resource)
tagname = self.Controler.ComputeConfigurationResourceName(config_name, selected)
idx = self.IsOpened(tagname)
if idx is not None:
self.TabsOpened.DeletePage(idx)
self._Refresh(TITLE, FILEMENU, EDITMENU, TYPESTREE, INSTANCESTREE)
def OnPLCOpenEditorMenu(self, event):
wx.MessageBox(_("No documentation available.\nComing soon."))
def OnPLCOpenMenu(self, event):
open_pdf(os.path.join(CWD, "plcopen", "TC6_XML_V101.pdf"))
def OnAboutMenu(self, event):
OpenHtmlFrame(self,_("About PLCOpenEditor"), os.path.join(CWD, "doc","about.html"), wx.Size(350, 350))
#-------------------------------------------------------------------------------
# Highlights showing functions
#-------------------------------------------------------------------------------
def ShowHighlight(self, infos, start, end, highlight_type):
self.SelectTypesTreeItem(infos[0])
if infos[1] == "name":
self.Highlights[infos[0]] = highlight_type
self.RefreshTypesTree()
self.TypesTree.Unselect()
else:
self.EditProjectElement(self.Controler.GetElementType(infos[0]), infos[0])
selected = self.TabsOpened.GetSelection()
if selected != -1:
viewer = self.TabsOpened.GetPage(selected)
viewer.AddHighlight(infos[1:], start, end, highlight_type)
def ShowError(self, infos, start, end):
self.ShowHighlight(infos, start, end, ERROR_HIGHLIGHT)
def ShowSearchResult(self, infos, start, end):
self.ShowHighlight(infos, start, end, SEARCH_RESULT_HIGHLIGHT)
def ClearHighlights(self, highlight_type=None):
if highlight_type is None:
self.Highlights = {}
else:
self.Highlights = dict([(name, highlight) for name, highlight in self.Highlights.iteritems() if highlight != highlight_type])
self.RefreshTypesTree()
for i in xrange(self.TabsOpened.GetPageCount()):
viewer = self.TabsOpened.GetPage(i)
viewer.ClearHighlights(highlight_type)
def ClearErrors(self):
self.ClearHighlights(ERROR_HIGHLIGHT)
def ClearSearchResults(self):
self.ClearHighlights(SEARCH_RESULT_HIGHLIGHT)
#-------------------------------------------------------------------------------
# PLCOpenEditor Main Class
#-------------------------------------------------------------------------------
class PLCOpenEditor(IDEFrame):
# Compatibility function for wx versions < 2.6
if wx.VERSION < (2, 6, 0):
def Bind(self, event, function, id = None):
if id is not None:
event(self, id, function)
else:
event(self, function)
def _init_coll_FileMenu_Items(self, parent):
AppendMenu(parent, help='', id=wx.ID_NEW,
kind=wx.ITEM_NORMAL, text=_(u'New\tCTRL+N'))
AppendMenu(parent, help='', id=wx.ID_OPEN,
kind=wx.ITEM_NORMAL, text=_(u'Open\tCTRL+O'))
AppendMenu(parent, help='', id=wx.ID_CLOSE,
kind=wx.ITEM_NORMAL, text=_(u'Close Tab\tCTRL+W'))
AppendMenu(parent, help='', id=wx.ID_CLOSE_ALL,
kind=wx.ITEM_NORMAL, text=_(u'Close Project'))
parent.AppendSeparator()
AppendMenu(parent, help='', id=wx.ID_SAVE,
kind=wx.ITEM_NORMAL, text=_(u'Save\tCTRL+S'))
AppendMenu(parent, help='', id=wx.ID_SAVEAS,
kind=wx.ITEM_NORMAL, text=_(u'Save As...\tCTRL+SHIFT+S'))
AppendMenu(parent, help='', id=ID_PLCOPENEDITORFILEMENUGENERATE,
kind=wx.ITEM_NORMAL, text=_(u'Generate Program\tCTRL+G'))
parent.AppendSeparator()
AppendMenu(parent, help='', id=wx.ID_PAGE_SETUP,
kind=wx.ITEM_NORMAL, text=_(u'Page Setup'))
AppendMenu(parent, help='', id=wx.ID_PREVIEW,
kind=wx.ITEM_NORMAL, text=_(u'Preview'))
AppendMenu(parent, help='', id=wx.ID_PRINT,
kind=wx.ITEM_NORMAL, text=_(u'Print'))
parent.AppendSeparator()
AppendMenu(parent, help='', id=wx.ID_PROPERTIES,
kind=wx.ITEM_NORMAL, text=_(u'Properties'))
parent.AppendSeparator()
AppendMenu(parent, help='', id=wx.ID_EXIT,
kind=wx.ITEM_NORMAL, text=_(u'Quit\tCTRL+Q'))
self.Bind(wx.EVT_MENU, self.OnNewProjectMenu, id=wx.ID_NEW)
self.Bind(wx.EVT_MENU, self.OnOpenProjectMenu, id=wx.ID_OPEN)
self.Bind(wx.EVT_MENU, self.OnCloseTabMenu, id=wx.ID_CLOSE)
self.Bind(wx.EVT_MENU, self.OnCloseProjectMenu, id=wx.ID_CLOSE_ALL)
self.Bind(wx.EVT_MENU, self.OnSaveProjectMenu, id=wx.ID_SAVE)
self.Bind(wx.EVT_MENU, self.OnSaveProjectAsMenu, id=wx.ID_SAVEAS)
self.Bind(wx.EVT_MENU, self.OnGenerateProgramMenu,
id=ID_PLCOPENEDITORFILEMENUGENERATE)
self.Bind(wx.EVT_MENU, self.OnPageSetupMenu, id=wx.ID_PAGE_SETUP)
self.Bind(wx.EVT_MENU, self.OnPreviewMenu, id=wx.ID_PREVIEW)
self.Bind(wx.EVT_MENU, self.OnPrintMenu, id=wx.ID_PRINT)
self.Bind(wx.EVT_MENU, self.OnPropertiesMenu, id=wx.ID_PROPERTIES)
self.Bind(wx.EVT_MENU, self.OnQuitMenu, id=wx.ID_EXIT)
def _init_coll_HelpMenu_Items(self, parent):
AppendMenu(parent, help='', id=wx.ID_HELP,
kind=wx.ITEM_NORMAL, text=_(u'PLCOpenEditor\tF1'))
#AppendMenu(parent, help='', id=wx.ID_HELP_CONTENTS,
# kind=wx.ITEM_NORMAL, text=u'PLCOpen\tF2')
#AppendMenu(parent, help='', id=wx.ID_HELP_CONTEXT,
# kind=wx.ITEM_NORMAL, text=u'IEC 61131-3\tF3')
AppendMenu(parent, help='', id=wx.ID_ABOUT,
kind=wx.ITEM_NORMAL, text=_(u'About'))
self.Bind(wx.EVT_MENU, self.OnPLCOpenEditorMenu, id=wx.ID_HELP)
#self.Bind(wx.EVT_MENU, self.OnPLCOpenMenu, id=wx.ID_HELP_CONTENTS)
self.Bind(wx.EVT_MENU, self.OnAboutMenu, id=wx.ID_ABOUT)
## Constructor of the PLCOpenEditor class.
# @param parent The parent window.
# @param controler The controler been used by PLCOpenEditor (default: None).
# @param fileOpen The filepath to open if no controler defined (default: None).
# @param debug The filepath to open if no controler defined (default: False).
def __init__(self, parent, fileOpen = None):
IDEFrame.__init__(self, parent)
result = None
# Open the filepath if defined
if fileOpen is not None and os.path.isfile(fileOpen):
# Create a new controller
self.Controler = PLCControler()
result = self.Controler.OpenXMLFile(fileOpen)
if result is None:
self._Refresh(TYPESTREE, INSTANCESTREE, LIBRARYTREE)
# Define PLCOpenEditor icon
self.SetIcon(wx.Icon(os.path.join(CWD,"Images", "poe.ico"),wx.BITMAP_TYPE_ICO))
self.Bind(wx.EVT_CLOSE, self.OnCloseFrame)
self._Refresh(TITLE, TOOLBAR, FILEMENU, EDITMENU, DISPLAYMENU)
if result is not None:
self.ShowErrorMessage(result)
def OnCloseFrame(self, event):
if self.Controler is None or self.CheckSaveBeforeClosing(_("Close Application")):
if USE_AUI:
self.AUIManager.UnInit()
self.SaveFrameSize()
event.Skip()
else:
event.Veto()
def RefreshTitle(self):
name = _("PLCOpenEditor")
if self.Controler is not None:
self.SetTitle("%s - %s"%(name, self.Controler.GetFilename()))
else:
self.SetTitle(name)
#-------------------------------------------------------------------------------
# File Menu Functions
#-------------------------------------------------------------------------------
def RefreshFileMenu(self):
if self.Controler is not None:
selected = self.TabsOpened.GetSelection()
if selected >= 0:
graphic_viewer = isinstance(self.TabsOpened.GetPage(selected), Viewer)
else:
graphic_viewer = False
if self.TabsOpened.GetPageCount() > 0:
self.FileMenu.Enable(wx.ID_CLOSE, True)
if graphic_viewer:
self.FileMenu.Enable(wx.ID_PREVIEW, True)
self.FileMenu.Enable(wx.ID_PRINT, True)
else:
self.FileMenu.Enable(wx.ID_PREVIEW, False)
self.FileMenu.Enable(wx.ID_PRINT, False)
else:
self.FileMenu.Enable(wx.ID_CLOSE, False)
self.FileMenu.Enable(wx.ID_PREVIEW, False)
self.FileMenu.Enable(wx.ID_PRINT, False)
self.FileMenu.Enable(wx.ID_PAGE_SETUP, True)
self.FileMenu.Enable(wx.ID_SAVE, True)
self.FileMenu.Enable(wx.ID_PROPERTIES, True)
self.FileMenu.Enable(wx.ID_CLOSE_ALL, True)
self.FileMenu.Enable(wx.ID_SAVEAS, True)
self.FileMenu.Enable(ID_PLCOPENEDITORFILEMENUGENERATE, True)
else:
self.FileMenu.Enable(wx.ID_CLOSE, False)
self.FileMenu.Enable(wx.ID_PAGE_SETUP, False)
self.FileMenu.Enable(wx.ID_PREVIEW, False)
self.FileMenu.Enable(wx.ID_PRINT, False)
self.FileMenu.Enable(wx.ID_SAVE, False)
self.FileMenu.Enable(wx.ID_PROPERTIES, False)
self.FileMenu.Enable(wx.ID_CLOSE_ALL, False)
self.FileMenu.Enable(wx.ID_SAVEAS, False)
self.FileMenu.Enable(ID_PLCOPENEDITORFILEMENUGENERATE, False)
def OnNewProjectMenu(self, event):
if self.Controler is not None and not self.CheckSaveBeforeClosing():
return
dialog = ProjectDialog(self)
if dialog.ShowModal() == wx.ID_OK:
properties = dialog.GetValues()
self.ResetView()
self.Controler = PLCControler()
self.Controler.CreateNewProject(properties)
self._Refresh(TITLE, FILEMENU, EDITMENU, TYPESTREE, INSTANCESTREE,
LIBRARYTREE)
def OnOpenProjectMenu(self, event):
if self.Controler is not None and not self.CheckSaveBeforeClosing():
return
filepath = ""
if self.Controler is not None:
filepath = self.Controler.GetFilePath()
if filepath != "":
directory = os.path.dirname(filepath)
else:
directory = os.getcwd()
result = None
dialog = wx.FileDialog(self, _("Choose a file"), directory, "", _("PLCOpen files (*.xml)|*.xml|All files|*.*"), wx.OPEN)
if dialog.ShowModal() == wx.ID_OK:
filepath = dialog.GetPath()
if os.path.isfile(filepath):
self.ResetView()
self.Controler = PLCControler()
result = self.Controler.OpenXMLFile(filepath)
if result is None:
self._Refresh(TYPESTREE, INSTANCESTREE, LIBRARYTREE)
self._Refresh(TITLE, TOOLBAR, FILEMENU, EDITMENU)
dialog.Destroy()
if result is not None:
self.ShowErrorMessage(result)
def OnCloseProjectMenu(self, event):
if not self.CheckSaveBeforeClosing():
return
self.ResetView()
self._Refresh(TITLE, TOOLBAR, FILEMENU, EDITMENU)
def OnSaveProjectMenu(self, event):
self.SaveProject()
def OnSaveProjectAsMenu(self, event):
self.SaveProjectAs()
def OnGenerateProgramMenu(self, event):
dialog = wx.FileDialog(self, _("Choose a file"), os.getcwd(), self.Controler.GetProgramFilePath(), _("ST files (*.st)|*.st|All files|*.*"), wx.SAVE|wx.CHANGE_DIR)
if dialog.ShowModal() == wx.ID_OK:
filepath = dialog.GetPath()
message_text = ""
header, icon = _("Done"), wx.ICON_INFORMATION
if os.path.isdir(os.path.dirname(filepath)):
program, errors, warnings = self.Controler.GenerateProgram(filepath)
message_text += "".join([_("warning: %s\n") for warning in warnings])
if len(errors) > 0:
message_text += "".join([_("error: %s\n") for error in errors])
message_text += _("Can't generate program to file %s!")%filepath
header, icon = _("Error"), wx.ICON_ERROR
else:
message_text += _("Program was successfully generated!")
else:
message_text += _("\"%s\" is not a valid folder!")%os.path.dirname(filepath)
header, icon = _("Error"), wx.ICON_ERROR
message = wx.MessageDialog(self, message_text, header, wx.OK|icon)
message.ShowModal()
message.Destroy()
dialog.Destroy()
def SaveProject(self):
result = self.Controler.SaveXMLFile()
if not result:
self.SaveProjectAs()
else:
self._Refresh(TITLE, FILEMENU, PAGETITLES)
def SaveProjectAs(self):
filepath = self.Controler.GetFilePath()
if filepath != "":
directory, filename = os.path.split(filepath)
else:
directory, filename = os.getcwd(), "%(projectName)s.xml"%self.Controler.GetProjectProperties()
dialog = wx.FileDialog(self, _("Choose a file"), directory, filename, _("PLCOpen files (*.xml)|*.xml|All files|*.*"), wx.SAVE|wx.OVERWRITE_PROMPT)
if dialog.ShowModal() == wx.ID_OK:
filepath = dialog.GetPath()
if os.path.isdir(os.path.dirname(filepath)):
result = self.Controler.SaveXMLFile(filepath)
if not result:
self.ShowErrorMessage(_("Can't save project to file %s!")%filepath)
else:
self.ShowErrorMessage(_("\"%s\" is not a valid folder!")%os.path.dirname(filepath))
self._Refresh(TITLE, FILEMENU, PAGETITLES)
dialog.Destroy()
#-------------------------------------------------------------------------------
# Create Project Dialog
#-------------------------------------------------------------------------------
[ID_SCALINGPANEL, ID_SCALINGPANELXSCALE,
ID_SCALINGPANELYSCALE, ID_SCALINGPANELSTATICTEXT1,
ID_SCALINGPANELSTATICTEXT2,
] = [wx.NewId() for _init_ctrls in range(5)]
class ScalingPanel(wx.Panel):
def _init_coll_ScalingPanelSizer_Items(self, parent):
parent.AddWindow(self.staticText1, 0, border=10, flag=wx.ALIGN_CENTER_VERTICAL|wx.TOP|wx.LEFT)
parent.AddWindow(self.XScale, 0, border=10, flag=wx.GROW|wx.TOP|wx.RIGHT)
parent.AddWindow(self.staticText2, 0, border=10, flag=wx.ALIGN_CENTER_VERTICAL|wx.BOTTOM|wx.LEFT)
parent.AddWindow(self.YScale, 0, border=10, flag=wx.GROW|wx.BOTTOM|wx.RIGHT)
def _init_coll_ScalingPanelSizer_Growables(self, parent):
parent.AddGrowableCol(1)
def _init_sizers(self):
self.ScalingPanelSizer = wx.FlexGridSizer(cols=2, hgap=5, rows=2, vgap=5)
self._init_coll_ScalingPanelSizer_Items(self.ScalingPanelSizer)
self._init_coll_ScalingPanelSizer_Growables(self.ScalingPanelSizer)
self.SetSizer(self.ScalingPanelSizer)
def _init_ctrls(self, prnt):
wx.Panel.__init__(self, id=ID_SCALINGPANEL,
name='ScalingPanel', parent=prnt, pos=wx.Point(0, 0),
size=wx.Size(0, 0), style=wx.TAB_TRAVERSAL)
self.staticText1 = wx.StaticText(id=ID_SCALINGPANELSTATICTEXT1,
label=_('Horizontal:'), name='staticText1', parent=self,
pos=wx.Point(0, 0), size=wx.DefaultSize, style=0)
self.XScale = wx.SpinCtrl(id=ID_SCALINGPANELXSCALE,
name='XScale', parent=self, pos=wx.Point(0, 0),
size=wx.Size(0, 24), style=0, min=0, max=2**16)
self.staticText2 = wx.StaticText(id=ID_SCALINGPANELSTATICTEXT2,
label=_('Vertical:'), name='staticText2', parent=self,
pos=wx.Point(0, 0), size=wx.DefaultSize, style=0)
self.YScale = wx.SpinCtrl(id=ID_SCALINGPANELYSCALE,
name='YScale', parent=self, pos=wx.Point(0, 0),
size=wx.Size(0, 24), style=0, min=0, max=2**16)
self._init_sizers()
def __init__(self, parent):
self._init_ctrls(parent)
def SetScaling(self, x, y):
self.XScale.SetValue(x)
self.YScale.SetValue(y)
def GetScaling(self):
return self.XScale.GetValue(), self.YScale.GetValue()
[ID_PROJECTDIALOG, ID_PROJECTDIALOGMAINNOTEBOOK,
ID_PROJECTDIALOGPROJECTPANEL, ID_PROJECTDIALOGAUTHORPANEL,
ID_PROJECTDIALOGGRAPHICSPANEL, ID_PROJECTDIALOGMISCELLANEOUSPANEL,
ID_PROJECTDIALOGPROJECTNAME, ID_PROJECTDIALOGPROJECTVERSION,
ID_PROJECTDIALOGPRODUCTNAME, ID_PROJECTDIALOGPRODUCTVERSION,
ID_PROJECTDIALOGPRODUCTRELEASE, ID_PROJECTDIALOGCOMPANYNAME,
ID_PROJECTDIALOGCOMPANYURL, ID_PROJECTDIALOGAUTHORNAME,
ID_PROJECTDIALOGORGANIZATION, ID_PROJECTDIALOGLANGUAGE,
ID_PROJECTDIALOGCONTENTDESCRIPTION, ID_PROJECTDIALOGSCALINGNOTEBOOK,
ID_PROJECTDIALOGPAGEWIDTH, ID_PROJECTDIALOGPAGEHEIGHT,
ID_PROJECTDIALOGSTATICTEXT1, ID_PROJECTDIALOGSTATICTEXT2,
ID_PROJECTDIALOGSTATICTEXT3, ID_PROJECTDIALOGSTATICTEXT4,
ID_PROJECTDIALOGSTATICTEXT5, ID_PROJECTDIALOGSTATICTEXT6,
ID_PROJECTDIALOGSTATICTEXT7, ID_PROJECTDIALOGSTATICTEXT8,
ID_PROJECTDIALOGSTATICTEXT9, ID_PROJECTDIALOGSTATICTEXT10,
ID_PROJECTDIALOGSTATICTEXT11, ID_PROJECTDIALOGSTATICTEXT12,
ID_PROJECTDIALOGSTATICTEXT13, ID_PROJECTDIALOGSTATICTEXT14,
ID_PROJECTDIALOGSTATICTEXT15,
] = [wx.NewId() for _init_ctrls in range(35)]
class ProjectDialog(wx.Dialog):
if wx.VERSION < (2, 6, 0):
def Bind(self, event, function, id = None):
if id is not None:
event(self, id, function)
else:
event(self, function)
def _init_coll_flexGridSizer1_Items(self, parent):
parent.AddSizer(self.MainNotebook, 0, border=0, flag=wx.GROW)
parent.AddSizer(self.ButtonSizer, 0, border=20, flag=wx.ALIGN_RIGHT|wx.BOTTOM|wx.LEFT|wx.RIGHT)
def _init_coll_flexGridSizer1_Growables(self, parent):
parent.AddGrowableCol(0)
parent.AddGrowableRow(0)
def _init_coll_ProjectPanelSizer_Items(self, parent):
parent.AddWindow(self.staticText1, 0, border=10, flag=wx.ALIGN_CENTER_VERTICAL|wx.TOP|wx.LEFT)
parent.AddWindow(self.ProjectName, 0, border=10, flag=wx.GROW|wx.TOP|wx.RIGHT)
parent.AddWindow(self.staticText2, 0, border=10, flag=wx.ALIGN_CENTER_VERTICAL|wx.LEFT)
parent.AddWindow(self.ProjectVersion, 0, border=10, flag=wx.GROW|wx.RIGHT)
parent.AddWindow(self.staticText3, 0, border=10, flag=wx.ALIGN_CENTER_VERTICAL|wx.LEFT)
parent.AddWindow(self.ProductName, 0, border=10, flag=wx.GROW|wx.RIGHT)
parent.AddWindow(self.staticText4, 0, border=10, flag=wx.ALIGN_CENTER_VERTICAL|wx.LEFT)
parent.AddWindow(self.ProductVersion, 0, border=10, flag=wx.GROW|wx.RIGHT)
parent.AddWindow(self.staticText5, 0, border=10, flag=wx.ALIGN_CENTER_VERTICAL|wx.BOTTOM|wx.LEFT)
parent.AddWindow(self.ProductRelease, 0, border=10, flag=wx.GROW|wx.BOTTOM|wx.RIGHT)
def _init_coll_ProjectPanelSizer_Growables(self, parent):
parent.AddGrowableCol(1)
def _init_coll_AuthorPanelSizer_Items(self, parent):
parent.AddWindow(self.staticText6, 0, border=10, flag=wx.ALIGN_CENTER_VERTICAL|wx.TOP|wx.LEFT)
parent.AddWindow(self.CompanyName, 0, border=10, flag=wx.GROW|wx.TOP|wx.RIGHT)
parent.AddWindow(self.staticText7, 0, border=10, flag=wx.ALIGN_CENTER_VERTICAL|wx.LEFT)
parent.AddWindow(self.CompanyURL, 0, border=10, flag=wx.GROW|wx.RIGHT)
parent.AddWindow(self.staticText8, 0, border=10, flag=wx.ALIGN_CENTER_VERTICAL|wx.LEFT)
parent.AddWindow(self.AuthorName, 0, border=10, flag=wx.GROW|wx.RIGHT)
parent.AddWindow(self.staticText9, 0, border=10, flag=wx.ALIGN_CENTER_VERTICAL|wx.BOTTOM|wx.LEFT)
parent.AddWindow(self.Organization, 0, border=10, flag=wx.GROW|wx.BOTTOM|wx.RIGHT)
def _init_coll_AuthorPanelSizer_Growables(self, parent):
parent.AddGrowableCol(1)
def _init_coll_GraphicsPanelSizer_Items(self, parent):
parent.AddWindow(self.staticText12, 0, border=10, flag=wx.ALIGN_CENTER_VERTICAL|wx.TOP|wx.LEFT|wx.RIGHT)
parent.AddSizer(self.GraphicsPageSizeSizer, 0, border=10, flag=wx.GROW|wx.LEFT|wx.RIGHT)
parent.AddWindow(self.staticText15, 0, border=10, flag=wx.ALIGN_CENTER_VERTICAL|wx.LEFT|wx.RIGHT)
parent.AddWindow(self.ScalingNotebook, 0, border=10, flag=wx.GROW|wx.BOTTOM|wx.LEFT|wx.RIGHT)
def _init_coll_GraphicsPanelSizer_Growables(self, parent):
parent.AddGrowableCol(0)
parent.AddGrowableRow(3)
def _init_coll_GraphicsPageSizeSizer_Items(self, parent):
parent.AddWindow(self.staticText13, 0, border=12, flag=wx.ALIGN_CENTER_VERTICAL|wx.LEFT)
parent.AddWindow(self.PageWidth, 0, border=0, flag=wx.GROW)
parent.AddWindow(self.staticText14, 0, border=12, flag=wx.ALIGN_CENTER_VERTICAL|wx.LEFT)
parent.AddWindow(self.PageHeight, 0, border=0, flag=wx.GROW)
def _init_coll_GraphicsPageSizeSizer_Growables(self, parent):
parent.AddGrowableCol(1)
def _init_coll_MiscellaneousPanelSizer_Items(self, parent):
parent.AddWindow(self.staticText10, 0, border=10, flag=wx.ALIGN_CENTER_VERTICAL|wx.TOP|wx.LEFT)
parent.AddWindow(self.Language, 0, border=10, flag=wx.GROW|wx.TOP|wx.RIGHT)
parent.AddWindow(self.staticText11, 0, border=10, flag=wx.BOTTOM|wx.LEFT)
parent.AddWindow(self.ContentDescription, 0, border=10, flag=wx.GROW|wx.BOTTOM|wx.RIGHT)
def _init_coll_MiscellaneousPanelSizer_Growables(self, parent):
parent.AddGrowableCol(1)
parent.AddGrowableRow(1)
def _init_sizers(self):
self.flexGridSizer1 = wx.FlexGridSizer(cols=1, hgap=0, rows=2, vgap=10)
self.ProjectPanelSizer = wx.FlexGridSizer(cols=2, hgap=5, rows=5, vgap=15)
self.AuthorPanelSizer = wx.FlexGridSizer(cols=2, hgap=5, rows=4, vgap=15)
self.GraphicsPanelSizer = wx.FlexGridSizer(cols=1, hgap=5, rows=4, vgap=5)
self.GraphicsPageSizeSizer = wx.FlexGridSizer(cols=2, hgap=5, rows=2, vgap=5)
self.MiscellaneousPanelSizer = wx.FlexGridSizer(cols=2, hgap=5, rows=2, vgap=15)
self._init_coll_flexGridSizer1_Items(self.flexGridSizer1)
self._init_coll_flexGridSizer1_Growables(self.flexGridSizer1)
self._init_coll_ProjectPanelSizer_Items(self.ProjectPanelSizer)
self._init_coll_ProjectPanelSizer_Growables(self.ProjectPanelSizer)
self._init_coll_AuthorPanelSizer_Items(self.AuthorPanelSizer)
self._init_coll_AuthorPanelSizer_Growables(self.AuthorPanelSizer)
self._init_coll_GraphicsPanelSizer_Items(self.GraphicsPanelSizer)
self._init_coll_GraphicsPanelSizer_Growables(self.GraphicsPanelSizer)
self._init_coll_GraphicsPageSizeSizer_Items(self.GraphicsPageSizeSizer)
self._init_coll_GraphicsPageSizeSizer_Growables(self.GraphicsPageSizeSizer)
self._init_coll_MiscellaneousPanelSizer_Items(self.MiscellaneousPanelSizer)
self._init_coll_MiscellaneousPanelSizer_Growables(self.MiscellaneousPanelSizer)
self.SetSizer(self.flexGridSizer1)
self.ProjectPanel.SetSizer(self.ProjectPanelSizer)
self.AuthorPanel.SetSizer(self.AuthorPanelSizer)
self.GraphicsPanel.SetSizer(self.GraphicsPanelSizer)
self.MiscellaneousPanel.SetSizer(self.MiscellaneousPanelSizer)
def _init_ctrls(self, prnt):
wx.Dialog.__init__(self, id=ID_PROJECTDIALOG,
name='ProjectDialog', parent=prnt,
size=wx.Size(500, 350), style=wx.DEFAULT_DIALOG_STYLE,
title=_('Project properties'))
self.SetClientSize(wx.Size(500, 350))
self.MainNotebook = wx.Notebook(id=ID_PROJECTDIALOGMAINNOTEBOOK,
name='MainNotebook', parent=self, pos=wx.Point(0,
0), size=wx.Size(0, 0), style=0)
# Project Panel elements
self.ProjectPanel = wx.Panel(id=ID_PROJECTDIALOGPROJECTPANEL,
name='ProjectPanel', parent=self.MainNotebook, pos=wx.Point(0, 0),
size=wx.Size(0, 0), style=wx.TAB_TRAVERSAL)
self.staticText1 = wx.StaticText(id=ID_PROJECTDIALOGSTATICTEXT1,
label=_('Project Name (required):'), name='staticText1', parent=self.ProjectPanel,
pos=wx.Point(0, 0), size=wx.DefaultSize, style=0)
self.ProjectName = wx.TextCtrl(id=ID_PROJECTDIALOGPROJECTNAME,
name='ProjectName', parent=self.ProjectPanel, pos=wx.Point(0, 0),
size=wx.Size(0, 24), style=0)
self.staticText2 = wx.StaticText(id=ID_PROJECTDIALOGSTATICTEXT2,
label=_('Project Version (optional):'), name='staticText2', parent=self.ProjectPanel,
pos=wx.Point(0, 0), size=wx.DefaultSize, style=0)
self.ProjectVersion = wx.TextCtrl(id=ID_PROJECTDIALOGPROJECTVERSION,
name='ProjectVersion', parent=self.ProjectPanel, pos=wx.Point(0, 0),
size=wx.Size(0, 24), style=0)
self.staticText3 = wx.StaticText(id=ID_PROJECTDIALOGSTATICTEXT3,
label=_('Product Name (required):'), name='staticText3', parent=self.ProjectPanel,
pos=wx.Point(0, 0), size=wx.DefaultSize, style=0)
self.ProductName = wx.TextCtrl(id=ID_PROJECTDIALOGPRODUCTNAME,
name='ProductName', parent=self.ProjectPanel, pos=wx.Point(0, 0),
size=wx.Size(0, 24), style=0)
self.staticText4 = wx.StaticText(id=ID_PROJECTDIALOGSTATICTEXT4,
label=_('Product Version (required):'), name='staticText4', parent=self.ProjectPanel,
pos=wx.Point(0, 0), size=wx.DefaultSize, style=0)
self.ProductVersion = wx.TextCtrl(id=ID_PROJECTDIALOGPRODUCTVERSION,
name='ProductVersion', parent=self.ProjectPanel, pos=wx.Point(0, 0),
size=wx.Size(0, 24), style=0)
self.staticText5 = wx.StaticText(id=ID_PROJECTDIALOGSTATICTEXT5,
label=_('Product Release (optional):'), name='staticText5', parent=self.ProjectPanel,
pos=wx.Point(0, 0), size=wx.DefaultSize, style=0)
self.ProductRelease = wx.TextCtrl(id=ID_PROJECTDIALOGPRODUCTRELEASE,
name='ProductRelease', parent=self.ProjectPanel, pos=wx.Point(0, 0),
size=wx.Size(0, 24), style=0)
self.MainNotebook.AddPage(self.ProjectPanel, _("Project"))
# Author Panel elements
self.AuthorPanel = wx.Panel(id=ID_PROJECTDIALOGAUTHORPANEL,
name='AuthorPanel', parent=self.MainNotebook, pos=wx.Point(0, 0),
size=wx.Size(0, 0), style=wx.TAB_TRAVERSAL)
self.staticText6 = wx.StaticText(id=ID_PROJECTDIALOGSTATICTEXT6,
label=_('Company Name (required):'), name='staticText6', parent=self.AuthorPanel,
pos=wx.Point(0, 0), size=wx.DefaultSize, style=0)
self.CompanyName = wx.TextCtrl(id=ID_PROJECTDIALOGCOMPANYNAME,
name='CompanyName', parent=self.AuthorPanel, pos=wx.Point(0, 0),
size=wx.Size(0, 24), style=0)
self.staticText7 = wx.StaticText(id=ID_PROJECTDIALOGSTATICTEXT7,
label=_('Company URL (optional):'), name='staticText7', parent=self.AuthorPanel,
pos=wx.Point(0, 0), size=wx.DefaultSize, style=0)
self.CompanyURL = wx.TextCtrl(id=ID_PROJECTDIALOGCOMPANYURL,
name='CompanyURL', parent=self.AuthorPanel, pos=wx.Point(0, 0),
size=wx.Size(0, 24), style=0)
self.staticText8 = wx.StaticText(id=ID_PROJECTDIALOGSTATICTEXT8,
label=_('Author Name (optional):'), name='staticText8', parent=self.AuthorPanel,
pos=wx.Point(0, 0), size=wx.DefaultSize, style=0)
self.AuthorName = wx.TextCtrl(id=ID_PROJECTDIALOGAUTHORNAME,
name='AuthorName', parent=self.AuthorPanel, pos=wx.Point(0, 0),
size=wx.Size(0, 24), style=0)
self.staticText9 = wx.StaticText(id=ID_PROJECTDIALOGSTATICTEXT9,
label=_('Organization (optional):'), name='staticText9', parent=self.AuthorPanel,
pos=wx.Point(0, 0), size=wx.DefaultSize, style=0)
self.Organization = wx.TextCtrl(id=ID_PROJECTDIALOGORGANIZATION,
name='Organization', parent=self.AuthorPanel, pos=wx.Point(0, 0),
size=wx.Size(0, 24), style=0)
self.MainNotebook.AddPage(self.AuthorPanel, _("Author"))
# Graphics Panel elements
self.GraphicsPanel = wx.Panel(id=ID_PROJECTDIALOGGRAPHICSPANEL,
name='GraphicsPanel', parent=self.MainNotebook, pos=wx.Point(0, 0),
size=wx.Size(0, 0), style=wx.TAB_TRAVERSAL)
self.staticText12 = wx.StaticText(id=ID_PROJECTDIALOGSTATICTEXT12,
label=_('Page Size (optional):'), name='staticText12', parent=self.GraphicsPanel,
pos=wx.Point(0, 0), size=wx.DefaultSize, style=0)
self.staticText13 = wx.StaticText(id=ID_PROJECTDIALOGSTATICTEXT13,
label=_('Width:'), name='staticText13', parent=self.GraphicsPanel,
pos=wx.Point(0, 0), size=wx.DefaultSize, style=0)
self.PageWidth = wx.SpinCtrl(id=ID_PROJECTDIALOGPAGEWIDTH,
name='PageWidth', parent=self.GraphicsPanel, pos=wx.Point(0, 0),
size=wx.Size(0, 24), style=0, min=0, max=2**16)
self.staticText14 = wx.StaticText(id=ID_PROJECTDIALOGSTATICTEXT14,
label=_('Height:'), name='staticText14', parent=self.GraphicsPanel,
pos=wx.Point(0, 0), size=wx.DefaultSize, style=0)
self.PageHeight = wx.SpinCtrl(id=ID_PROJECTDIALOGPAGEHEIGHT,
name='PageHeight', parent=self.GraphicsPanel, pos=wx.Point(0, 0),
size=wx.Size(0, 24), style=0, min=0, max=2**16)
self.staticText15 = wx.StaticText(id=ID_PROJECTDIALOGSTATICTEXT15,
label=_('Grid Resolution:'), name='staticText15', parent=self.GraphicsPanel,
pos=wx.Point(0, 0), size=wx.DefaultSize, style=0)
self.ScalingNotebook = wx.Notebook(id=ID_PROJECTDIALOGSCALINGNOTEBOOK,
name='ScalingNotebook', parent=self.GraphicsPanel, pos=wx.Point(0,
0), size=wx.Size(0, 0), style=0)
self.Scalings = {}
for language, translation in [("FBD",_("FBD")), ("LD",_("LD")), ("SFC",_("SFC"))]:
window = ScalingPanel(self.ScalingNotebook)
self.Scalings[language] = window
self.ScalingNotebook.AddPage(window, translation)
self.MainNotebook.AddPage(self.GraphicsPanel, _("Graphics"))
# Miscellaneous Panel elements
self.MiscellaneousPanel = wx.Panel(id=ID_PROJECTDIALOGMISCELLANEOUSPANEL,
name='MiscellaneousPanel', parent=self.MainNotebook, pos=wx.Point(0, 0),
size=wx.Size(0, 0), style=wx.TAB_TRAVERSAL)
self.staticText10 = wx.StaticText(id=ID_PROJECTDIALOGSTATICTEXT10,
label=_('Language (optional):'), name='staticText10', parent=self.MiscellaneousPanel,
pos=wx.Point(0, 0), size=wx.DefaultSize, style=0)
self.Language = wx.ComboBox(id=ID_PROJECTDIALOGLANGUAGE,
name='Language', parent=self.MiscellaneousPanel, pos=wx.Point(0, 0),
size=wx.Size(0, 28), style=wx.CB_READONLY)
self.staticText11 = wx.StaticText(id=ID_PROJECTDIALOGSTATICTEXT11,
label=_('Content Description (optional):'), name='staticText11', parent=self.MiscellaneousPanel,
pos=wx.Point(0, 0), size=wx.DefaultSize, style=0)
self.ContentDescription = wx.TextCtrl(id=ID_PROJECTDIALOGCONTENTDESCRIPTION,
name='ContentDescription', parent=self.MiscellaneousPanel, pos=wx.Point(0, 0),
size=wx.Size(0, 24), style=wx.TE_MULTILINE)
self.MainNotebook.AddPage(self.MiscellaneousPanel, _("Miscellaneous"))
self.ButtonSizer = self.CreateButtonSizer(wx.OK|wx.CANCEL|wx.CENTRE)
self.Bind(wx.EVT_BUTTON, self.OnOK, id=self.ButtonSizer.GetAffirmativeButton().GetId())
self._init_sizers()
def __init__(self, parent, enable_required=True):
self._init_ctrls(parent)
self.ProjectName.Enable(enable_required)
self.ProductName.Enable(enable_required)
self.ProductVersion.Enable(enable_required)
self.CompanyName.Enable(enable_required)
languages = ["", "en-US", "fr-FR", "zh-CN"]
for language in languages:
self.Language.Append(language)
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 = wx.MessageDialog(self, _("Form isn't complete. %s must be filled!")%text, _("Error"), wx.OK|wx.ICON_ERROR)
message.ShowModal()
message.Destroy()
else:
self.EndModal(wx.ID_OK)
def SetValues(self, values):
for item, value in values.items():
if item == "projectName":
self.ProjectName.SetValue(value)
elif item == "projectVersion":
self.ProjectVersion.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 == "companyName":
self.CompanyName.SetValue(value)
elif item == "companyURL":
self.CompanyURL.SetValue(value)
elif item == "authorName":
self.AuthorName.SetValue(value)
elif item == "organization":
self.Organization.SetValue(value)
elif item == "language":
self.Language.SetStringSelection(value)
elif item == "contentDescription":
self.ContentDescription.SetValue(value)
elif item == "pageSize":
self.PageWidth.SetValue(value[0])
self.PageHeight.SetValue(value[1])
elif item == "scaling":
for language, (x, y) in value.items():
if language in self.Scalings:
self.Scalings[language].SetScaling(x, y)
def GetValues(self):
values = {}
values["projectName"] = self.ProjectName.GetValue()
if self.ProjectVersion.GetValue() != "":
values["projectVersion"] = self.ProjectVersion.GetValue()
values["productName"] = self.ProductName.GetValue()
values["productVersion"] = self.ProductVersion.GetValue()
if self.ProductRelease.GetValue() != "":
values["productRelease"] = self.ProductRelease.GetValue()
values["companyName"] = self.CompanyName.GetValue()
if self.CompanyURL.GetValue() != "":
values["companyURL"] = self.CompanyURL.GetValue()
if self.AuthorName.GetValue() != "":
values["authorName"] = self.AuthorName.GetValue()
if self.Organization.GetValue() != "":
values["organization"] = self.Organization.GetValue()
if self.Language.GetStringSelection() != "":
values["language"] = self.Language.GetStringSelection()
if self.ProductRelease.GetValue() != "":
values["contentDescription"] = self.ContentDescription.GetValue()
values["pageSize"] = (self.PageWidth.GetValue(), self.PageHeight.GetValue())
values["scaling"] = {}
for language in ["FBD", "LD", "SFC"]:
values["scaling"][language] = self.Scalings[language].GetScaling()
return values
#-------------------------------------------------------------------------------
# Edit Step Name Dialog
#-------------------------------------------------------------------------------
class DataTypeDialog(wx.TextEntryDialog):
if wx.VERSION < (2, 6, 0):
def Bind(self, event, function, id = None):
if id is not None:
event(self, id, function)
else:
event(self, function)
def __init__(self, parent, message, caption = _("Please enter text"), defaultValue = "",
style = wx.OK|wx.CANCEL|wx.CENTRE, pos = wx.DefaultPosition):
wx.TextEntryDialog.__init__(self, parent, message, caption, defaultValue, style, pos)
self.DataTypeNames = []
if wx.VERSION >= (2, 8, 0):
self.Bind(wx.EVT_BUTTON, self.OnOK, id=self.GetSizer().GetItem(2).GetSizer().GetItem(1).GetSizer().GetAffirmativeButton().GetId())
elif wx.VERSION >= (2, 6, 0):
self.Bind(wx.EVT_BUTTON, self.OnOK, id=self.GetSizer().GetItem(3).GetSizer().GetAffirmativeButton().GetId())
else:
self.Bind(wx.EVT_BUTTON, self.OnOK, id=self.GetSizer().GetItem(3).GetSizer().GetChildren()[0].GetSizer().GetChildren()[0].GetWindow().GetId())
def OnOK(self, event):
datatype_name = self.GetSizer().GetItem(1).GetWindow().GetValue()
if datatype_name == "":
message = wx.MessageDialog(self, _("You must type a name!"), _("Error"), wx.OK|wx.ICON_ERROR)
message.ShowModal()
message.Destroy()
elif not TestIdentifier(datatype_name):
message = wx.MessageDialog(self, _("\"%s\" is not a valid identifier!")%datatype_name, _("Error"), wx.OK|wx.ICON_ERROR)
message.ShowModal()
message.Destroy()
elif datatype_name.upper() in IEC_KEYWORDS:
message = wx.MessageDialog(self, _("\"%s\" is a keyword. It can't be used!")%datatype_name, _("Error"), wx.OK|wx.ICON_ERROR)
message.ShowModal()
message.Destroy()
elif datatype_name.upper() in self.DataTypeNames:
message = wx.MessageDialog(self, _("\"%s\" data type already exists!")%datatype_name, _("Error"), wx.OK|wx.ICON_ERROR)
message.ShowModal()
message.Destroy()
else:
self.EndModal(wx.ID_OK)
def SetDataTypeNames(self, datatype_names):
self.DataTypeNames = [datatype_name.upper() for datatype_name in datatype_names]
def GetValue(self):
return self.GetSizer().GetItem(1).GetWindow().GetValue()
#-------------------------------------------------------------------------------
# Create Pou Dialog
#-------------------------------------------------------------------------------
[ID_POUDIALOG, ID_POUDIALOGPOUNAME,
ID_POUDIALOGPOUTYPE, ID_POUDIALOGLANGUAGE, ID_POUDIALOGSTATICTEXT1,
ID_POUDIALOGSTATICTEXT2, ID_POUDIALOGSTATICTEXT3,
] = [wx.NewId() for _init_ctrls in range(7)]
def GetTransitionLanguages():
_ = lambda x : x
return [_("IL"), _("ST"), _("LD"), _("FBD")]
TRANSITION_LANGUAGES_DICT = dict([(_(language), language) for language in GetTransitionLanguages()])
def GetPouTypes():
_ = lambda x : x
return [_("function"), _("functionBlock"), _("program")]
POU_TYPES_DICT = dict([(_(pou_type), pou_type) for pou_type in GetPouTypes()])
def GetPouLanguages():
_ = lambda x : x
return [_("IL"), _("ST"), _("LD"), _("FBD"), _("SFC")]
POU_LANGUAGES_DICT = dict([(_(language), language) for language in GetPouLanguages()])
class PouDialog(wx.Dialog):
if wx.VERSION < (2, 6, 0):
def Bind(self, event, function, id = None):
if id is not None:
event(self, id, function)
else:
event(self, function)
def _init_coll_flexGridSizer1_Items(self, parent):
parent.AddSizer(self.MainSizer, 0, border=20, flag=wx.GROW|wx.TOP|wx.LEFT|wx.RIGHT)
parent.AddSizer(self.ButtonSizer, 0, border=20, flag=wx.ALIGN_RIGHT|wx.BOTTOM|wx.LEFT|wx.RIGHT)
def _init_coll_flexGridSizer1_Growables(self, parent):
parent.AddGrowableCol(0)
parent.AddGrowableRow(0)
def _init_coll_MainSizer_Items(self, parent):
parent.AddWindow(self.staticText1, 0, border=4, flag=wx.ALIGN_CENTER_VERTICAL|wx.TOP)
parent.AddWindow(self.PouName, 0, border=0, flag=wx.GROW)
parent.AddWindow(self.staticText2, 0, border=4, flag=wx.ALIGN_CENTER_VERTICAL|wx.TOP)
parent.AddWindow(self.PouType, 0, border=0, flag=wx.GROW)
parent.AddWindow(self.staticText3, 0, border=4, flag=wx.ALIGN_CENTER_VERTICAL|wx.TOP)
parent.AddWindow(self.Language, 0, border=0, flag=wx.GROW)
def _init_coll_MainSizer_Growables(self, parent):
parent.AddGrowableCol(1)
def _init_sizers(self):
self.flexGridSizer1 = wx.FlexGridSizer(cols=1, hgap=0, rows=2, vgap=10)
self.MainSizer = wx.FlexGridSizer(cols=2, hgap=5, rows=3, vgap=15)
self._init_coll_flexGridSizer1_Items(self.flexGridSizer1)
self._init_coll_flexGridSizer1_Growables(self.flexGridSizer1)
self._init_coll_MainSizer_Items(self.MainSizer)
self._init_coll_MainSizer_Growables(self.MainSizer)
self.SetSizer(self.flexGridSizer1)
def _init_ctrls(self, prnt):
wx.Dialog.__init__(self, id=ID_POUDIALOG,
name='PouDialog', parent=prnt,
size=wx.Size(300, 200), style=wx.DEFAULT_DIALOG_STYLE,
title=_('Create a new POU'))
self.SetClientSize(wx.Size(300, 200))
self.staticText1 = wx.StaticText(id=ID_POUDIALOGSTATICTEXT1,
label=_('POU Name:'), name='staticText1', parent=self,
pos=wx.Point(0, 0), size=wx.DefaultSize, style=0)
self.PouName = wx.TextCtrl(id=ID_POUDIALOGPOUNAME,
name='POUName', parent=self, pos=wx.Point(0, 0),
size=wx.Size(0, 24), style=0)
self.staticText2 = wx.StaticText(id=ID_POUDIALOGSTATICTEXT2,
label=_('POU Type:'), name='staticText2', parent=self,
pos=wx.Point(0, 0), size=wx.DefaultSize, style=0)
self.PouType = wx.ComboBox(id=ID_POUDIALOGPOUTYPE,
name='POUType', parent=self, pos=wx.Point(0, 0),
size=wx.Size(0, 28), style=wx.CB_READONLY)
self.Bind(wx.EVT_COMBOBOX, self.OnTypeChanged, id=ID_POUDIALOGPOUTYPE)
self.staticText3 = wx.StaticText(id=ID_POUDIALOGSTATICTEXT3,
label=_('Language:'), name='staticText3', parent=self,
pos=wx.Point(0, 0), size=wx.DefaultSize, style=0)
self.Language = wx.ComboBox(id=ID_POUDIALOGLANGUAGE,
name='Language', parent=self, pos=wx.Point(0, 0),
size=wx.Size(0, 28), style=wx.CB_READONLY)
self.ButtonSizer = self.CreateButtonSizer(wx.OK|wx.CANCEL|wx.CENTRE)
self.Bind(wx.EVT_BUTTON, self.OnOK, id=self.ButtonSizer.GetAffirmativeButton().GetId())
self._init_sizers()
def __init__(self, parent, pou_type = None):
self._init_ctrls(parent)
for option in GetPouTypes():
self.PouType.Append(_(option))
if pou_type is not None:
self.PouType.SetStringSelection(_(pou_type))
self.RefreshLanguage()
self.PouNames = []
self.PouElementNames = []
def OnOK(self, event):
error = []
pou_name = self.PouName.GetValue()
if pou_name == "":
error.append(_("POU Name"))
if self.PouType.GetSelection() == -1:
error.append(_("POU Type"))
if self.Language.GetSelection() == -1:
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 = wx.MessageDialog(self, _("Form isn't complete. %s must be filled!")%text, _("Error"), wx.OK|wx.ICON_ERROR)
message.ShowModal()
message.Destroy()
elif not TestIdentifier(pou_name):
message = wx.MessageDialog(self, _("\"%s\" is not a valid identifier!")%pou_name, _("Error"), wx.OK|wx.ICON_ERROR)
message.ShowModal()
message.Destroy()
elif pou_name.upper() in IEC_KEYWORDS:
message = wx.MessageDialog(self, _("\"%s\" is a keyword. It can't be used!")%pou_name, _("Error"), wx.OK|wx.ICON_ERROR)
message.ShowModal()
message.Destroy()
elif pou_name.upper() in self.PouNames:
message = wx.MessageDialog(self, _("\"%s\" pou already exists!")%pou_name, _("Error"), wx.OK|wx.ICON_ERROR)
message.ShowModal()
message.Destroy()
elif pou_name.upper() in self.PouElementNames:
message = wx.MessageDialog(self, _("A POU has an element named \"%s\". This could cause a conflict. Do you wish to continue?")%pou_name, _("Warning"), wx.YES_NO|wx.ICON_EXCLAMATION)
result = message.ShowModal()
message.Destroy()
if result == wx.ID_YES:
self.EndModal(wx.ID_OK)
else:
self.EndModal(wx.ID_OK)
def RefreshLanguage(self):
selection = POU_LANGUAGES_DICT.get(self.Language.GetStringSelection(), "")
self.Language.Clear()
for language in GetPouLanguages():
if language != "SFC" or POU_TYPES_DICT[self.PouType.GetStringSelection()] != "function":
self.Language.Append(language)
if self.Language.FindString(_(selection)) != wx.NOT_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 SetPouElementNames(self, element_names):
self.PouElementNames = [element_name.upper() for element_name in element_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(_(POU_LANGUAGES_DICT))
def GetValues(self):
values = {}
values["pouName"] = self.PouName.GetValue()
values["pouType"] = POU_TYPES_DICT[self.PouType.GetStringSelection()]
values["language"] = POU_LANGUAGES_DICT[self.Language.GetStringSelection()]
return values
#-------------------------------------------------------------------------------
# Create Pou Transition Dialog
#-------------------------------------------------------------------------------
[ID_POUTRANSITIONDIALOG, ID_POUTRANSITIONDIALOGTRANSITIONNAME,
ID_POUTRANSITIONDIALOGLANGUAGE, ID_POUTRANSITIONDIALOGSTATICTEXT1,
ID_POUTRANSITIONDIALOGSTATICTEXT2,
] = [wx.NewId() for _init_ctrls in range(5)]
def GetTransitionLanguages():
_ = lambda x : x
return [_("IL"), _("ST"), _("LD"), _("FBD")]
TRANSITION_LANGUAGES_DICT = dict([(_(language), language) for language in GetTransitionLanguages()])
class PouTransitionDialog(wx.Dialog):
if wx.VERSION < (2, 6, 0):
def Bind(self, event, function, id = None):
if id is not None:
event(self, id, function)
else:
event(self, function)
def _init_coll_flexGridSizer1_Items(self, parent):
parent.AddSizer(self.MainSizer, 0, border=20, flag=wx.GROW|wx.TOP|wx.LEFT|wx.RIGHT)
parent.AddSizer(self.ButtonSizer, 0, border=20, flag=wx.ALIGN_RIGHT|wx.BOTTOM|wx.LEFT|wx.RIGHT)
def _init_coll_flexGridSizer1_Growables(self, parent):
parent.AddGrowableCol(0)
parent.AddGrowableRow(0)
def _init_coll_MainSizer_Items(self, parent):
parent.AddWindow(self.staticText1, 0, border=4, flag=wx.ALIGN_CENTER_VERTICAL|wx.TOP)
parent.AddWindow(self.TransitionName, 0, border=0, flag=wx.GROW)
parent.AddWindow(self.staticText2, 0, border=4, flag=wx.ALIGN_CENTER_VERTICAL|wx.TOP)
parent.AddWindow(self.Language, 0, border=0, flag=wx.GROW)
def _init_coll_MainSizer_Growables(self, parent):
parent.AddGrowableCol(1)
def _init_sizers(self):
self.flexGridSizer1 = wx.FlexGridSizer(cols=1, hgap=0, rows=2, vgap=10)
self.MainSizer = wx.FlexGridSizer(cols=2, hgap=5, rows=2, vgap=15)
self._init_coll_flexGridSizer1_Items(self.flexGridSizer1)
self._init_coll_flexGridSizer1_Growables(self.flexGridSizer1)
self._init_coll_MainSizer_Items(self.MainSizer)
self._init_coll_MainSizer_Growables(self.MainSizer)
self.SetSizer(self.flexGridSizer1)
def _init_ctrls(self, prnt):
wx.Dialog.__init__(self, id=ID_POUTRANSITIONDIALOG,
name='PouTransitionDialog', parent=prnt,
size=wx.Size(350, 200), style=wx.DEFAULT_DIALOG_STYLE,
title=_('Create a new transition'))
self.SetClientSize(wx.Size(350, 160))
self.staticText1 = wx.StaticText(id=ID_POUTRANSITIONDIALOGSTATICTEXT1,
label=_('Transition Name:'), name='staticText1', parent=self,
pos=wx.Point(0, 0), size=wx.DefaultSize, style=0)
self.TransitionName = wx.TextCtrl(id=ID_POUTRANSITIONDIALOGTRANSITIONNAME,
name='TransitionName', parent=self, pos=wx.Point(0, 0),
size=wx.Size(0, 24), style=0)
self.staticText2 = wx.StaticText(id=ID_POUTRANSITIONDIALOGSTATICTEXT2,
label=_('Language:'), name='staticText2', parent=self,
pos=wx.Point(0, 0), size=wx.DefaultSize, style=0)
self.Language = wx.ComboBox(id=ID_POUTRANSITIONDIALOGLANGUAGE,
name='Language', parent=self, pos=wx.Point(0, 0),
size=wx.Size(0, 28), style=wx.CB_READONLY)
self.ButtonSizer = self.CreateButtonSizer(wx.OK|wx.CANCEL|wx.CENTRE)
self.Bind(wx.EVT_BUTTON, self.OnOK, id=self.ButtonSizer.GetAffirmativeButton().GetId())
self._init_sizers()
def __init__(self, parent):
self._init_ctrls(parent)
for language in GetTransitionLanguages():
self.Language.Append(_(language))
self.PouNames = []
self.PouElementNames = []
def OnOK(self, event):
error = []
transition_name = self.TransitionName.GetValue()
if self.TransitionName.GetValue() == "":
error.append(_("Transition Name"))
if self.Language.GetSelection() == -1:
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 = wx.MessageDialog(self, _("Form isn't complete. %s must be filled!")%text, _("Error"), wx.OK|wx.ICON_ERROR)
message.ShowModal()
message.Destroy()
elif not TestIdentifier(transition_name):
message = wx.MessageDialog(self, _("\"%s\" is not a valid identifier!")%transition_name, _("Error"), wx.OK|wx.ICON_ERROR)
message.ShowModal()
message.Destroy()
elif transition_name.upper() in IEC_KEYWORDS:
message = wx.MessageDialog(self, _("\"%s\" is a keyword. It can't be used!")%transition_name, _("Error"), wx.OK|wx.ICON_ERROR)
message.ShowModal()
message.Destroy()
elif transition_name.upper() in self.PouNames:
message = wx.MessageDialog(self, _("A POU named \"%s\" already exists!")%transition_name, _("Error"), wx.OK|wx.ICON_ERROR)
message.ShowModal()
message.Destroy()
elif transition_name.upper() in self.PouElementNames:
message = wx.MessageDialog(self, _("\"%s\" element for this pou already exists!")%transition_name, _("Error"), wx.OK|wx.ICON_ERROR)
message.ShowModal()
message.Destroy()
else:
self.EndModal(wx.ID_OK)
def SetPouNames(self, pou_names):
self.PouNames = [pou_name.upper() for pou_name in pou_names]
def SetPouElementNames(self, pou_names):
self.PouElementNames = [pou_name.upper() for pou_name in pou_names]
def SetValues(self, values):
for item, value in values.items():
if item == "transitionName":
self.TransitionName.SetValue(value)
elif item == "language":
self.Language.SetSelection(_(value))
def GetValues(self):
values = {}
values["transitionName"] = self.TransitionName.GetValue()
values["language"] = TRANSITION_LANGUAGES_DICT[self.Language.GetStringSelection()]
return values
#-------------------------------------------------------------------------------
# Create Pou Action Dialog
#-------------------------------------------------------------------------------
[ID_POUACTIONDIALOG, ID_POUACTIONDIALOGACTIONNAME,
ID_POUACTIONDIALOGLANGUAGE, ID_POUACTIONDIALOGSTATICTEXT1,
ID_POUACTIONDIALOGSTATICTEXT2,
] = [wx.NewId() for _init_ctrls in range(5)]
def GetActionLanguages():
_ = lambda x : x
return [_("IL"), _("ST"), _("LD"), _("FBD")]
ACTION_LANGUAGES_DICT = dict([(_(language), language) for language in GetActionLanguages()])
class PouActionDialog(wx.Dialog):
if wx.VERSION < (2, 6, 0):
def Bind(self, event, function, id = None):
if id is not None:
event(self, id, function)
else:
event(self, function)
def _init_coll_flexGridSizer1_Items(self, parent):
parent.AddSizer(self.MainSizer, 0, border=20, flag=wx.GROW|wx.TOP|wx.LEFT|wx.RIGHT)
parent.AddSizer(self.ButtonSizer, 0, border=20, flag=wx.ALIGN_RIGHT|wx.BOTTOM|wx.LEFT|wx.RIGHT)
def _init_coll_flexGridSizer1_Growables(self, parent):
parent.AddGrowableCol(0)
parent.AddGrowableRow(0)
def _init_coll_MainSizer_Items(self, parent):
parent.AddWindow(self.staticText1, 0, border=4, flag=wx.ALIGN_CENTER_VERTICAL|wx.TOP)
parent.AddWindow(self.ActionName, 0, border=0, flag=wx.GROW)
parent.AddWindow(self.staticText2, 0, border=4, flag=wx.ALIGN_CENTER_VERTICAL|wx.TOP)
parent.AddWindow(self.Language, 0, border=0, flag=wx.GROW)
def _init_coll_MainSizer_Growables(self, parent):
parent.AddGrowableCol(1)
def _init_sizers(self):
self.flexGridSizer1 = wx.FlexGridSizer(cols=1, hgap=0, rows=2, vgap=10)
self.MainSizer = wx.FlexGridSizer(cols=2, hgap=5, rows=2, vgap=15)
self._init_coll_flexGridSizer1_Items(self.flexGridSizer1)
self._init_coll_flexGridSizer1_Growables(self.flexGridSizer1)
self._init_coll_MainSizer_Items(self.MainSizer)
self._init_coll_MainSizer_Growables(self.MainSizer)
self.SetSizer(self.flexGridSizer1)
def _init_ctrls(self, prnt):
wx.Dialog.__init__(self, id=ID_POUACTIONDIALOG,
name='PouActionDialog', parent=prnt,
size=wx.Size(320, 200), style=wx.DEFAULT_DIALOG_STYLE|wx.RESIZE_BORDER,
title=_('Create a new action'))
self.SetClientSize(wx.Size(320, 160))
self.staticText1 = wx.StaticText(id=ID_POUACTIONDIALOGSTATICTEXT1,
label=_('Action Name:'), name='staticText1', parent=self,
pos=wx.Point(0, 0), size=wx.DefaultSize, style=0)
self.ActionName = wx.TextCtrl(id=ID_POUACTIONDIALOGACTIONNAME,
name='ActionName', parent=self, pos=wx.Point(0, 0),
size=wx.Size(0, 24), style=0)
self.staticText2 = wx.StaticText(id=ID_POUACTIONDIALOGSTATICTEXT2,
label=_('Language:'), name='staticText2', parent=self,
pos=wx.Point(0, 0), size=wx.DefaultSize, style=0)
self.Language = wx.ComboBox(id=ID_POUACTIONDIALOGLANGUAGE,
name='Language', parent=self, pos=wx.Point(0, 0),
size=wx.Size(0, 28), style=wx.CB_READONLY)
self.ButtonSizer = self.CreateButtonSizer(wx.OK|wx.CANCEL|wx.CENTRE)
self.Bind(wx.EVT_BUTTON, self.OnOK, id=self.ButtonSizer.GetAffirmativeButton().GetId())
self._init_sizers()
def __init__(self, parent):
self._init_ctrls(parent)
for option in GetActionLanguages():
self.Language.Append(_(option))
self.PouNames = []
self.PouElementNames = []
def OnOK(self, event):
error = []
action_name = self.ActionName.GetValue()
if action_name == "":
error.append(_("Action Name"))
if self.Language.GetSelection() == -1:
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 = wx.MessageDialog(self, _("Form isn't complete. %s must be filled!")%text, _("Error"), wx.OK|wx.ICON_ERROR)
message.ShowModal()
message.Destroy()
elif not TestIdentifier(action_name):
message = wx.MessageDialog(self, _("\"%s\" is not a valid identifier!")%action_name, _("Error"), wx.OK|wx.ICON_ERROR)
message.ShowModal()
message.Destroy()
elif action_name.upper() in IEC_KEYWORDS:
message = wx.MessageDialog(self, _("\"%s\" is a keyword. It can't be used!")%action_name, _("Error"), wx.OK|wx.ICON_ERROR)
message.ShowModal()
message.Destroy()
elif action_name.upper() in self.PouNames:
message = wx.MessageDialog(self, _("A POU named \"%s\" already exists!")%action_name, _("Error"), wx.OK|wx.ICON_ERROR)
message.ShowModal()
message.Destroy()
elif action_name.upper() in self.PouElementNames:
message = wx.MessageDialog(self, _("\"%s\" element for this pou already exists!")%action_name, _("Error"), wx.OK|wx.ICON_ERROR)
message.ShowModal()
message.Destroy()
else:
self.EndModal(wx.ID_OK)
def SetPouNames(self, pou_names):
self.PouNames = [pou_name.upper() for pou_name in pou_names]
def SetPouElementNames(self, element_names):
self.PouElementNames = [element_name.upper() for element_name in element_names]
def SetValues(self, values):
for item, value in values.items():
if item == "actionName":
self.ActionName.SetValue(value)
elif item == "language":
self.Language.SetStringSelection(_(value))
def GetValues(self):
values = {}
values["actionName"] = self.ActionName.GetValue()
values["language"] = ACTION_LANGUAGES_DICT[self.Language.GetStringSelection()]
return values
#-------------------------------------------------------------------------------
# Configuration Name Dialog
#-------------------------------------------------------------------------------
class ConfigurationNameDialog(wx.TextEntryDialog):
if wx.VERSION < (2, 6, 0):
def Bind(self, event, function, id = None):
if id is not None:
event(self, id, function)
else:
event(self, function)
def __init__(self, parent, message, caption = _("Please enter configuration name"), defaultValue = "",
style = wx.OK|wx.CANCEL|wx.CENTRE, pos = wx.DefaultPosition):
wx.TextEntryDialog.__init__(self, parent, message, caption, defaultValue, style, pos)
self.PouNames = []
self.PouElementNames = []
if wx.VERSION >= (2, 8, 0):
self.Bind(wx.EVT_BUTTON, self.OnOK, id=self.GetSizer().GetItem(2).GetSizer().GetItem(1).GetSizer().GetAffirmativeButton().GetId())
elif wx.VERSION >= (2, 6, 0):
self.Bind(wx.EVT_BUTTON, self.OnOK, id=self.GetSizer().GetItem(3).GetSizer().GetAffirmativeButton().GetId())
else:
self.Bind(wx.EVT_BUTTON, self.OnOK, id=self.GetSizer().GetItem(3).GetSizer().GetChildren()[0].GetSizer().GetChildren()[0].GetWindow().GetId())
def OnOK(self, event):
config_name = self.GetSizer().GetItem(1).GetWindow().GetValue()
if config_name == "":
message = wx.MessageDialog(self, _("You must type a name!"), _("Error"), wx.OK|wx.ICON_ERROR)
message.ShowModal()
message.Destroy()
elif not TestIdentifier(config_name):
message = wx.MessageDialog(self, _("\"%s\" is not a valid identifier!")%config_name, _("Error"), wx.OK|wx.ICON_ERROR)
message.ShowModal()
message.Destroy()
elif config_name.upper() in IEC_KEYWORDS:
message = wx.MessageDialog(self, _("\"%s\" is a keyword. It can't be used!")%config_name, _("Error"), wx.OK|wx.ICON_ERROR)
message.ShowModal()
message.Destroy()
elif config_name.upper() in self.PouNames:
message = wx.MessageDialog(self, _("A POU named \"%s\" already exists!")%config_name, _("Error"), wx.OK|wx.ICON_ERROR)
message.ShowModal()
message.Destroy()
elif config_name.upper() in self.PouElementNames:
message = wx.MessageDialog(self, _("A POU has an element named \"%s\". This could cause a conflict. Do you wish to continue?")%config_name, _("Warning"), wx.YES_NO|wx.ICON_EXCLAMATION)
result = message.ShowModal()
message.Destroy()
if result == wx.ID_YES:
self.EndModal(wx.ID_OK)
else:
self.EndModal(wx.ID_OK)
def SetPouNames(self, pou_names):
self.PouNames = [pou_name.upper() for pou_name in pou_names]
def SetPouElementNames(self, pou_names):
self.PouElementNames = [pou_name.upper() for pou_name in pou_names]
def GetValue(self):
return self.GetSizer().GetItem(1).GetWindow().GetValue()
#-------------------------------------------------------------------------------
# Resource Name Dialog
#-------------------------------------------------------------------------------
class ResourceNameDialog(wx.TextEntryDialog):
if wx.VERSION < (2, 6, 0):
def Bind(self, event, function, id = None):
if id is not None:
event(self, id, function)
else:
event(self, function)
def __init__(self, parent, message, caption = _("Please enter resource name"), defaultValue = "",
style = wx.OK|wx.CANCEL|wx.CENTRE, pos = wx.DefaultPosition):
wx.TextEntryDialog.__init__(self, parent, message, caption, defaultValue, style, pos)
self.PouNames = []
self.PouElementNames = []
if wx.VERSION >= (2, 8, 0):
self.Bind(wx.EVT_BUTTON, self.OnOK, id=self.GetSizer().GetItem(2).GetSizer().GetItem(1).GetSizer().GetAffirmativeButton().GetId())
elif wx.VERSION >= (2, 6, 0):
self.Bind(wx.EVT_BUTTON, self.OnOK, id=self.GetSizer().GetItem(3).GetSizer().GetAffirmativeButton().GetId())
else:
self.Bind(wx.EVT_BUTTON, self.OnOK, id=self.GetSizer().GetItem(3).GetSizer().GetChildren()[0].GetSizer().GetChildren()[0].GetWindow().GetId())
def OnOK(self, event):
resource_name = self.GetSizer().GetItem(1).GetWindow().GetValue()
if resource_name == "":
message = wx.MessageDialog(self, _("You must type a name!"), _("Error"), wx.OK|wx.ICON_ERROR)
message.ShowModal()
message.Destroy()
elif not TestIdentifier(resource_name):
message = wx.MessageDialog(self, _("\"%s\" is not a valid identifier!")%resource_name, _("Error"), wx.OK|wx.ICON_ERROR)
message.ShowModal()
message.Destroy()
elif resource_name.upper() in IEC_KEYWORDS:
message = wx.MessageDialog(self, _("\"%s\" is a keyword. It can't be used!")%resource_name, _("Error"), wx.OK|wx.ICON_ERROR)
message.ShowModal()
message.Destroy()
elif resource_name.upper() in self.PouNames:
message = wx.MessageDialog(self, _("A POU named \"%s\" already exists!")%resource_name, _("Error"), wx.OK|wx.ICON_ERROR)
message.ShowModal()
message.Destroy()
elif resource_name.upper() in self.PouElementNames:
message = wx.MessageDialog(self, _("A POU has an element named \"%s\". This could cause a conflict. Do you wish to continue?")%resource_name, _("Warning"), wx.YES_NO|wx.ICON_EXCLAMATION)
result = message.ShowModal()
message.Destroy()
if result == wx.ID_YES:
self.EndModal(wx.ID_OK)
else:
self.EndModal(wx.ID_OK)
def SetPouNames(self, pou_names):
self.PouNames = [pou_name.upper() for pou_name in pou_names]
def SetPouElementNames(self, pou_names):
self.PouElementNames = [pou_name.upper() for pou_name in pou_names]
def GetValue(self):
return self.GetSizer().GetItem(1).GetWindow().GetValue()
#-------------------------------------------------------------------------------
# Debug Variables Panel
#-------------------------------------------------------------------------------
def GetDebugVariablesTableColnames():
_ = lambda x : x
return [_("Variable"), _("Value")]
class VariableTableItem(DebugDataConsumer):
def __init__(self, parent, variable, value):
DebugDataConsumer.__init__(self)
self.Parent = parent
self.Variable = variable
self.Value = value
def __del__(self):
self.Parent = None
def SetVariable(self, variable):
if self.Parent and self.Variable != variable:
self.Variable = variable
self.Parent.RefreshGrid()
def GetVariable(self):
return self.Variable
def SetForced(self, forced):
if self.Forced != forced:
self.Forced = forced
self.Parent.HasNewData = True
def SetValue(self, value):
if self.Value != value:
self.Value = value
self.Parent.HasNewData = True
def GetValue(self):
return self.Value
class DebugVariableTable(CustomTable):
def GetValue(self, row, col):
if row < self.GetNumberRows():
return self.GetValueByName(row, self.GetColLabelValue(col, False))
return ""
def SetValue(self, row, col, value):
if col < len(self.colnames):
self.SetValueByName(row, self.GetColLabelValue(col, False), value)
def GetValueByName(self, row, colname):
if row < self.GetNumberRows():
if colname == "Variable":
return self.data[row].GetVariable()
elif colname == "Value":
return self.data[row].GetValue()
return ""
def SetValueByName(self, row, colname, value):
if row < self.GetNumberRows():
if colname == "Variable":
self.data[row].SetVariable(value)
elif colname == "Value":
self.data[row].SetValue(value)
def IsForced(self, row):
if row < self.GetNumberRows():
return self.data[row].IsForced()
return False
def _updateColAttrs(self, grid):
"""
wx.grid.Grid -> update the column attributes to add the
appropriate renderer given the column name.
Otherwise default to the default renderer.
"""
for row in range(self.GetNumberRows()):
for col in range(self.GetNumberCols()):
if self.GetColLabelValue(col, False) == "Value":
if self.IsForced(row):
grid.SetCellTextColour(row, col, wx.BLUE)
else:
grid.SetCellTextColour(row, col, wx.BLACK)
grid.SetReadOnly(row, col, True)
self.ResizeRow(grid, row)
def AppendItem(self, data):
self.data.append(data)
def InsertItem(self, idx, data):
self.data.insert(idx, data)
def RemoveItem(self, idx):
self.data.pop(idx)
def MoveItem(self, idx, new_idx):
self.data.insert(new_idx, self.data.pop(idx))
def GetItem(self, idx):
return self.data[idx]
class DebugVariableDropTarget(wx.TextDropTarget):
def __init__(self, parent):
wx.TextDropTarget.__init__(self)
self.ParentWindow = parent
def OnDropText(self, x, y, data):
x, y = self.ParentWindow.VariablesGrid.CalcUnscrolledPosition(x, y)
row = self.ParentWindow.VariablesGrid.YToRow(y - self.ParentWindow.VariablesGrid.GetColLabelSize())
if row == wx.NOT_FOUND:
row = self.ParentWindow.Table.GetNumberRows()
message = None
try:
values = eval(data)
except:
message = _("Invalid value \"%s\" for debug variable")%data
values = None
if not isinstance(values, TupleType):
message = _("Invalid value \"%s\" for debug variable")%data
values = None
if values is not None and values[1] == "debug":
self.ParentWindow.InsertValue(values[0], row)
if message is not None:
wx.CallAfter(self.ShowMessage, message)
def ShowMessage(self, message):
message = wx.MessageDialog(self.ParentWindow, message, _("Error"), wx.OK|wx.ICON_ERROR)
message.ShowModal()
message.Destroy()
[ID_DEBUGVARIABLEPANEL, ID_DEBUGVARIABLEPANELVARIABLESGRID,
ID_DEBUGVARIABLEPANELUPBUTTON, ID_DEBUGVARIABLEPANELDOWNBUTTON,
ID_DEBUGVARIABLEPANELDELETEBUTTON,
] = [wx.NewId() for _init_ctrls in range(5)]
class DebugVariablePanel(wx.Panel, DebugViewer):
if wx.VERSION < (2, 6, 0):
def Bind(self, event, function, id = None):
if id is not None:
event(self, id, function)
else:
event(self, function)
def _init_coll_MainSizer_Items(self, parent):
parent.AddSizer(self.ButtonPanelSizer, 0, border=5, flag=wx.ALIGN_RIGHT|wx.ALL)
parent.AddWindow(self.VariablesGrid, 0, border=0, flag=wx.GROW)
def _init_coll_MainSizer_Growables(self, parent):
parent.AddGrowableCol(0)
parent.AddGrowableRow(1)
def _init_coll_ButtonPanelSizer_Items(self, parent):
parent.AddWindow(self.UpButton, 0, border=5, flag=wx.RIGHT)
parent.AddWindow(self.DownButton, 0, border=5, flag=wx.RIGHT)
parent.AddWindow(self.DeleteButton, 0, border=0, flag=0)
def _init_sizers(self):
self.MainSizer = wx.FlexGridSizer(cols=1, hgap=10, rows=2, vgap=0)
self.ButtonPanelSizer = wx.BoxSizer(wx.HORIZONTAL)
self._init_coll_MainSizer_Items(self.MainSizer)
self._init_coll_MainSizer_Growables(self.MainSizer)
self._init_coll_ButtonPanelSizer_Items(self.ButtonPanelSizer)
self.SetSizer(self.MainSizer)
def _init_ctrls(self, prnt):
wx.Panel.__init__(self, id=ID_DEBUGVARIABLEPANEL,
name='DebugVariablePanel', parent=prnt, pos=wx.Point(0, 0),
size=wx.Size(0, 0), style=wx.TAB_TRAVERSAL)
self.VariablesGrid = CustomGrid(id=ID_DEBUGVARIABLEPANELVARIABLESGRID,
name='VariablesGrid', parent=self, pos=wx.Point(0, 0),
size=wx.Size(0, 150), style=wx.VSCROLL)
self.VariablesGrid.SetDropTarget(DebugVariableDropTarget(self))
if wx.VERSION >= (2, 6, 0):
self.VariablesGrid.Bind(wx.grid.EVT_GRID_CELL_RIGHT_CLICK, self.OnVariablesGridCellRightClick)
else:
wx.grid.EVT_GRID_CELL_RIGHT_CLICK(self.VariablesGrid, self.OnVariablesGridCellRightClick)
self.UpButton = wx.Button(id=ID_DEBUGVARIABLEPANELUPBUTTON, label='^',
name='UpButton', parent=self, pos=wx.Point(0, 0),
size=wx.Size(32, 32), style=0)
self.DownButton = wx.Button(id=ID_DEBUGVARIABLEPANELDOWNBUTTON, label='v',
name='DownButton', parent=self, pos=wx.Point(0, 0),
size=wx.Size(32, 32), style=0)
self.DeleteButton = wx.Button(id=ID_DEBUGVARIABLEPANELDELETEBUTTON, label=_('Delete'),
name='DeleteButton', parent=self, pos=wx.Point(0, 0),
size=wx.DefaultSize, style=0)
self._init_sizers()
def __init__(self, parent, producer):
self._init_ctrls(parent)
DebugViewer.__init__(self, producer, True)
self.HasNewData = False
self.Table = DebugVariableTable(self, [], GetDebugVariablesTableColnames())
self.VariablesGrid.SetTable(self.Table)
self.VariablesGrid.SetButtons({"Delete": self.DeleteButton,
"Up": self.UpButton,
"Down": self.DownButton})
def _AddVariable(new_row):
return self.VariablesGrid.GetGridCursorRow()
setattr(self.VariablesGrid, "_AddRow", _AddVariable)
def _DeleteVariable(row):
item = self.Table.GetItem(row)
self.RemoveDataConsumer(item)
self.Table.RemoveItem(row)
self.RefreshGrid()
setattr(self.VariablesGrid, "_DeleteRow", _DeleteVariable)
def _MoveVariable(row, move):
new_row = max(0, min(row + move, self.Table.GetNumberRows() - 1))
if new_row != row:
self.Table.MoveItem(row, new_row)
self.RefreshGrid()
return new_row
setattr(self.VariablesGrid, "_MoveRow", _MoveVariable)
self.VariablesGrid.SetRowLabelSize(0)
for col in range(self.Table.GetNumberCols()):
attr = wx.grid.GridCellAttr()
attr.SetAlignment(wx.ALIGN_RIGHT, wx.ALIGN_CENTER)
self.VariablesGrid.SetColAttr(col, attr)
self.VariablesGrid.SetColSize(col, 100)
self.Table.ResetView(self.VariablesGrid)
self.VariablesGrid.RefreshButtons()
def RefreshNewData(self):
if self.HasNewData:
self.HasNewData = False
self.RefreshGrid()
DebugViewer.RefreshNewData(self)
def RefreshGrid(self):
self.Freeze()
self.Table.ResetView(self.VariablesGrid)
self.VariablesGrid.RefreshButtons()
self.Thaw()
def ResetGrid(self):
self.DeleteDataConsumers()
self.Table.Empty()
self.Freeze()
self.Table.ResetView(self.VariablesGrid)
self.VariablesGrid.RefreshButtons()
self.Thaw()
def GetForceVariableMenuFunction(self, iec_path, item):
iec_type = self.GetDataType(iec_path)
def ForceVariableFunction(event):
if iec_type is not None:
dialog = ForceVariableDialog(self, iec_type, str(item.GetValue()))
if dialog.ShowModal() == wx.ID_OK:
self.ForceDataValue(iec_path, dialog.GetValue())
return ForceVariableFunction
def GetReleaseVariableMenuFunction(self, iec_path):
def ReleaseVariableFunction(event):
self.ReleaseDataValue(iec_path)
return ReleaseVariableFunction
def OnVariablesGridCellRightClick(self, event):
row, col = event.GetRow(), event.GetCol()
if self.Table.GetColLabelValue(col, False) == "Value":
iec_path = self.Table.GetValueByName(row, "Variable").upper()
menu = wx.Menu(title='')
new_id = wx.NewId()
AppendMenu(menu, help='', id=new_id, kind=wx.ITEM_NORMAL, text=_("Force value"))
self.Bind(wx.EVT_MENU, self.GetForceVariableMenuFunction(iec_path.upper(), self.Table.GetItem(row)), id=new_id)
new_id = wx.NewId()
AppendMenu(menu, help='', id=new_id, kind=wx.ITEM_NORMAL, text=_("Release value"))
self.Bind(wx.EVT_MENU, self.GetReleaseVariableMenuFunction(iec_path.upper()), id=new_id)
if self.Table.IsForced(row):
menu.Enable(new_id, True)
else:
menu.Enable(new_id, False)
self.PopupMenu(menu)
event.Skip()
def InsertValue(self, iec_path, idx = None):
if idx is None:
idx = self.Table.GetNumberRows()
for item in self.Table.GetData():
if iec_path == item.GetVariable():
return
item = VariableTableItem(self, iec_path, "")
result = self.AddDataConsumer(iec_path.upper(), item)
if result is not None:
self.Table.InsertItem(idx, item)
self.RefreshGrid()
#-------------------------------------------------------------------------------
# Viewer Printout
#-------------------------------------------------------------------------------
UPPER_DIV = lambda x, y: (x / y) + {True : 0, False : 1}[(x % y) == 0]
class GraphicPrintout(wx.Printout):
def __init__(self, viewer, page_size, margins, preview = False):
wx.Printout.__init__(self)
self.Viewer = viewer
self.PageSize = page_size
if self.PageSize[0] == 0 or self.PageSize[1] == 0:
self.PageSize = (1050, 1485)
self.Preview = preview
self.Margins = margins
self.FontSize = 5
self.TextMargin = 3
maxx, maxy = viewer.GetMaxSize()
self.PageGrid = (UPPER_DIV(maxx, self.PageSize[0]),
UPPER_DIV(maxy, self.PageSize[1]))
def GetPageNumber(self):
return self.PageGrid[0] * self.PageGrid[1]
def HasPage(self, page):
return page <= self.GetPageNumber()
def GetPageInfo(self):
page_number = self.GetPageNumber()
return (1, page_number, 1, page_number)
def OnBeginDocument(self, startPage, endPage):
dc = self.GetDC()
if not self.Preview and isinstance(dc, wx.PostScriptDC):
dc.SetResolution(720)
super(GraphicPrintout, self).OnBeginDocument(startPage, endPage)
def OnPrintPage(self, page):
dc = self.GetDC()
dc.SetUserScale(1.0, 1.0)
dc.SetDeviceOrigin(0, 0)
dc.printing = not self.Preview
# Get the size of the DC in pixels
ppiPrinterX, ppiPrinterY = self.GetPPIPrinter()
ppiScreenX, ppiScreenY = self.GetPPIScreen()
pw, ph = self.GetPageSizePixels()
dw, dh = dc.GetSizeTuple()
Xscale = (float(dw) * float(ppiPrinterX)) / (float(pw) * 25.4)
Yscale = (float(dh) * float(ppiPrinterY)) / (float(ph) * 25.4)
fontsize = self.FontSize * Yscale
text_margin = self.TextMargin * Yscale
margin_left = self.Margins[0].x * Xscale
margin_top = self.Margins[0].y * Yscale
area_width = dw - self.Margins[1].x * Xscale - margin_left
area_height = dh - self.Margins[1].y * Yscale - margin_top
dc.SetPen(MiterPen(wx.BLACK))
dc.SetBrush(wx.TRANSPARENT_BRUSH)
dc.DrawRectangle(margin_left, margin_top, area_width, area_height)
dc.SetFont(wx.Font(fontsize, wx.DEFAULT, wx.NORMAL, wx.NORMAL))
dc.SetTextForeground(wx.BLACK)
block_name = " - ".join(self.Viewer.GetTagName().split("::")[1:])
text_width, text_height = dc.GetTextExtent(block_name)
dc.DrawText(block_name, margin_left, margin_top - text_height - self.TextMargin)
dc.DrawText(_("Page: %d") % page, margin_left, margin_top + area_height + self.TextMargin)
# Calculate the position on the DC for centering the graphic
posX = area_width * ((page - 1) % self.PageGrid[0])
posY = area_height * ((page - 1) / self.PageGrid[0])
scaleX = float(area_width) / float(self.PageSize[0])
scaleY = float(area_height) / float(self.PageSize[1])
scale = min(scaleX, scaleY)
# Set the scale and origin
dc.SetDeviceOrigin(-posX + margin_left, -posY + margin_top)
dc.SetClippingRegion(posX, posY, self.PageSize[0] * scale, self.PageSize[1] * scale)
dc.SetUserScale(scale, scale)
#-------------------------------------------
self.Viewer.DoDrawing(dc, True)
return True
#-------------------------------------------------------------------------------
# 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 has occurred.
Click OK to save an error report.
Please be kind enough to send this file to:
edouard.tisserant@gmail.com
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 = wx.MessageDialog(None, str(e_value), _("Error"), wx.OK|wx.ICON_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 AddExceptHook(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__':
wx.InitAllImageHandlers()
# Install a exception handle for bug reports
AddExceptHook(os.getcwd(),__version__)
frame = PLCOpenEditor(None, fileOpen=fileOpen)
frame.Show()
app.MainLoop()