lpcmanager

Parents 74e1cf35fc20
Children b8992ad86bb7
Added functions and override that from beremiz. Change some logic on the build.Added fault handler library for cache errors.
  • +1229 -405
    LPCManager.py
  • --- a/LPCManager.py Thu Jun 01 10:24:03 2017 +0200
    +++ b/LPCManager.py Thu Jun 01 11:26:25 2017 +0200
    @@ -4,6 +4,9 @@
    import socket
    import zipfile
    import fnmatch
    +import threading
    +import faulthandler
    +faulthandler.enable()
    __version__ = "$Revision$"
    @@ -22,6 +25,7 @@
    import wxversion
    wxversion.select(['2.8', '3.0'])
    import wx
    + # from wx.lib.pubsub import pub
    def Bpath(*args):
    @@ -124,9 +128,9 @@
    from LPCconnector.PYRO import MW_PYRO_connector_factory
    from LPCconnector.WAMP import MWWAMP_connector_factory
    -connectors.connectors["LPC"] = lambda: LPC_connector_factory
    -connectors.connectors["PYRO"] = lambda: MW_PYRO_connector_factory
    -connectors.connectors["WAMP"] = lambda: MWWAMP_connector_factory
    +# connectors.connectors["LPC"] = lambda: LPC_connector_factory
    +# connectors.connectors["PYRO"] = lambda: MW_PYRO_connector_factory
    +# connectors.connectors["WAMP"] = lambda: MWWAMP_connector_factory
    import targets
    from LPCtarget import LPC_target
    @@ -144,13 +148,809 @@
    from ProjectController import ProjectController
    from ConfigTreeNode import ConfigTreeNode
    from editors.ProjectNodeEditor import ProjectNodeEditor
    +from editors.ConfTreeNodeEditor import ConfTreeNodeEditor
    from editors.CodeFileEditor import VariablesTable
    from editors.CodeFileEditor import VariablesEditor
    +from editors.CodeFileEditor import CodeEditor
    from editors.TextViewer import TextViewer, EditorPanel
    from controls.CustomStyledTextCtrl import GetCursorPos
    +from controls import ProjectPropertiesPanel
    +from controls.SearchResultPanel import SearchResultPanel
    +# from controls.LogViewer import LogViewer
    from WampOptionsEditor import WampOptionsEditor
    from VariableExporter import VariableWriter
    -from PLCControler import PLCControler
    +from PLCControler import PLCControler, ITEMS_UNEDITABLE, ITEM_POU
    +from wx.lib.scrolledpanel import ScrolledPanel
    +from types import MethodType
    +from IDEFrame import IDEFrame
    +from dialogs import SearchInProjectDialog
    +from UriLocationEditor import UriLocationEditor
    +from UriLocationEditor import UriTextControl
    +from controls import TextCtrlAutoComplete
    +from py_ext import PythonFileCTNMixin
    +
    +
    +def CTNGenerate_C(self, buildpath, locations):
    + # location string for that CTN
    + location_str = "_".join(map(lambda x: str(x),
    + self.GetCurrentLocation()))
    + configname = self.GetCTRoot().GetProjectConfigNames()[0]
    +
    + pyextname = self.CTNName()
    + varinfos = map(lambda variable: {
    + "name": variable.getname(),
    + "desc": repr(variable.getdesc()),
    + "onchangecode": '"' + variable.getonchange() + \
    + "('" + variable.getname() + "')\"" \
    + if variable.getonchange() else '""',
    + "onchange": repr(variable.getonchange()) \
    + if variable.getonchange() else None,
    + "opts": repr(variable.getopts()),
    + "configname": configname.upper(),
    + "uppername": variable.getname().upper(),
    + "IECtype": variable.gettype(),
    + "initial": repr(variable.getinitial()),
    + "pyextname": pyextname},
    + self.CodeFile.variables.variable)
    + # python side PLC global variables access stub
    + globalstubs = "\n".join(["""\
    +_%(name)s_ctype, _%(name)s_unpack, _%(name)s_pack = \\
    + TypeTranslator["%(IECtype)s"]
    +_PySafeGetPLCGlob_%(name)s = PLCBinary.__SafeGetPLCGlob_%(name)s
    +_PySafeGetPLCGlob_%(name)s.restype = None
    +_PySafeGetPLCGlob_%(name)s.argtypes = [ctypes.POINTER(_%(name)s_ctype)]
    +_PySafeSetPLCGlob_%(name)s = PLCBinary.__SafeSetPLCGlob_%(name)s
    +_PySafeSetPLCGlob_%(name)s.restype = None
    +_PySafeSetPLCGlob_%(name)s.argtypes = [ctypes.POINTER(_%(name)s_ctype)]
    +_%(pyextname)sGlobalsDesc.append((
    + "%(name)s",
    + "%(IECtype)s",
    + %(initial)s,
    + %(desc)s,
    + %(onchange)s,
    + %(opts)s))
    +""" % varinfo
    + for varinfo in varinfos])
    +
    + # Runtime calls (start, stop, init, and cleanup)
    + rtcalls = ""
    + for section in self.SECTIONS_NAMES:
    + if section != "globals":
    + rtcalls += "def _runtime_%s_%s():\n" % (location_str, section)
    + sectiontext = self.GetSection(section).strip()
    + if sectiontext:
    + rtcalls += ' ' + \
    + sectiontext.replace('\n', '\n ') + "\n\n"
    + else:
    + rtcalls += " pass\n\n"
    +
    + globalsection = self.GetSection("globals")
    +
    + PyFileContent = """\
    +#!/usr/bin/env python
    +# -*- coding: utf-8 -*-
    +## Code generated by Beremiz python mixin confnode
    +##
    +
    +## Code for PLC global variable access
    +from targets.typemapping import TypeTranslator
    +import ctypes
    +_%(pyextname)sGlobalsDesc = []
    +__ext_name__ = "%(pyextname)s"
    +PLCGlobalsDesc.append(( "%(pyextname)s" , _%(pyextname)sGlobalsDesc ))
    +%(globalstubs)s
    +
    +## User code in "global" scope
    +%(globalsection)s
    +
    +## Beremiz python runtime calls
    +%(rtcalls)s
    +
    +del __ext_name__
    +
    +""" % locals()
    +
    + # write generated content to python file
    + runtimefile_path = os.path.join(buildpath,
    + "runtime_%s.py" % location_str)
    + runtimefile = open(runtimefile_path, 'w')
    + runtimefile.write(PyFileContent.encode('utf-8'))
    + runtimefile.close()
    +
    + # C code for safe global variables access
    +
    + vardecfmt = """\
    +extern __IEC_%(IECtype)s_t %(configname)s__%(uppername)s;
    +IEC_%(IECtype)s __%(name)s_rbuffer = __INIT_%(IECtype)s;
    +IEC_%(IECtype)s __%(name)s_wbuffer;
    +long __%(name)s_rlock = 0;
    +long __%(name)s_wlock = 0;
    +int __%(name)s_wbuffer_written = 0;
    +void __SafeGetPLCGlob_%(name)s(IEC_%(IECtype)s *pvalue){
    + while(AtomicCompareExchange(&__%(name)s_rlock, 0, 1));
    + *pvalue = __%(name)s_rbuffer;
    + AtomicCompareExchange((long*)&__%(name)s_rlock, 1, 0);
    +}
    +void __SafeSetPLCGlob_%(name)s(IEC_%(IECtype)s *value){
    + while(AtomicCompareExchange(&__%(name)s_wlock, 0, 1));
    + __%(name)s_wbuffer = *value;
    + __%(name)s_wbuffer_written = 1;
    + AtomicCompareExchange((long*)&__%(name)s_wlock, 1, 0);
    +}
    +
    +"""
    +
    + vardeconchangefmt = """\
    +PYTHON_POLL* __%(name)s_notifier;
    +"""
    +
    + varretfmt = """\
    + if(!AtomicCompareExchange(&__%(name)s_wlock, 0, 1)){
    + if(__%(name)s_wbuffer_written == 1){
    + %(configname)s__%(uppername)s.value = __%(name)s_wbuffer;
    + __%(name)s_wbuffer_written = 0;
    + }
    + AtomicCompareExchange((long*)&__%(name)s_wlock, 1, 0);
    + }
    +"""
    + varpubfmt = """\
    + if(!AtomicCompareExchange(&__%(name)s_rlock, 0, 1)){
    + __%(name)s_rbuffer = __GET_VAR(%(configname)s__%(uppername)s);
    + AtomicCompareExchange((long*)&__%(name)s_rlock, 1, 0);
    + }
    +"""
    +
    + varpubonchangefmt = """\
    + if(!AtomicCompareExchange(&__%(name)s_rlock, 0, 1)){
    + IEC_%(IECtype)s tmp = __GET_VAR(%(configname)s__%(uppername)s);
    + if(__%(name)s_rbuffer != tmp){
    + __%(name)s_rbuffer = %(configname)s__%(uppername)s.value;
    + PYTHON_POLL_body__(__%(name)s_notifier);
    + }
    + AtomicCompareExchange((long*)&__%(name)s_rlock, 1, 0);
    + }
    +"""
    + varinitonchangefmt = """\
    + __%(name)s_notifier = __GET_GLOBAL_ON%(uppername)sCHANGE();
    + __SET_VAR(__%(name)s_notifier->,TRIG,,__BOOL_LITERAL(TRUE));
    + __SET_VAR(__%(name)s_notifier->,CODE,,__STRING_LITERAL(%(onchangelen)d,%(onchangecode)s));
    +"""
    + vardec = "\n".join([(vardecfmt + vardeconchangefmt
    + if varinfo["onchange"] else vardecfmt) % varinfo
    + for varinfo in varinfos])
    + varret = "\n".join([varretfmt % varinfo for varinfo in varinfos])
    + varpub = "\n".join([(varpubonchangefmt if varinfo["onchange"] else
    + varpubfmt) % varinfo
    + for varinfo in varinfos])
    + varinit = "\n".join([varinitonchangefmt % dict(
    + onchangelen=len(varinfo["onchangecode"]), **varinfo)
    + for varinfo in varinfos if varinfo["onchange"]])
    +
    + # TODO : use config name obtained from model instead of default
    + # "config.h". User cannot change config name, but project imported
    + # or created in older beremiz vesion could use different name.
    + PyCFileContent = """\
    +/*
    + * Code generated by Beremiz py_ext confnode
    + * for safe global variables access
    + */
    +#include "iec_types_all.h"
    +#include "POUS.h"
    +#include "config.h"
    +#include "beremiz.h"
    +
    +/* User variables reference */
    +%(vardec)s
    +
    +/* Beremiz confnode functions */
    +int __init_%(location_str)s(int argc,char **argv){
    +%(varinit)s
    + return 0;
    +}
    +
    +void __cleanup_%(location_str)s(void){
    +}
    +
    +void __retrieve_%(location_str)s(void){
    +%(varret)s
    +}
    +
    +void __publish_%(location_str)s(void){
    +%(varpub)s
    +}
    +""" % locals()
    +
    + Gen_PyCfile_path = os.path.join(buildpath, "PyCFile_%s.c" % location_str)
    + pycfile = open(Gen_PyCfile_path, 'w')
    + pycfile.write(PyCFileContent)
    + pycfile.close()
    +
    + matiec_CFLAGS = '"-I%s"' % os.path.abspath(
    + self.GetCTRoot().GetIECLibPath())
    +
    + return ([(Gen_PyCfile_path, matiec_CFLAGS)],
    + "",
    + True,
    + ("runtime_%s.py" % location_str, file(runtimefile_path, "rb")))
    +PythonFileCTNMixin.CTNGenerate_C = CTNGenerate_C
    +
    +def GenerateSizerElements(self, sizer, elements, path, clean=True):
    + def UriOptions(event):
    + CTR = self.ParentWindow.CTR
    + CTR_BeremizRoot = CTR.BeremizRoot
    + CTR_AppFrame = CTR.AppFrame
    + # Get connector uri
    + uri = CTR_BeremizRoot.getURI_location().strip()
    +
    + dialog = UriLocationEditor(CTR_AppFrame, uri)
    + answer = dialog.ShowModal()
    + uri = dialog.GetURI()
    + dialog.Destroy()
    +
    + if answer == wx.ID_OK:
    + CTR_BeremizRoot.setURI_location(uri)
    + if CTR._View is not None:
    + CTR._View.RefreshView()
    + if CTR_AppFrame is not None:
    + CTR_AppFrame.RefreshTitle()
    + CTR_AppFrame.RefreshFileMenu()
    + CTR_AppFrame.RefreshEditMenu()
    + CTR_AppFrame.RefreshPageTitles()
    + import types
    + from editors.ConfTreeNodeEditor import GenStaticBitmap
    +
    + if clean:
    + sizer.Clear(True)
    + first = True
    + for element_infos in elements:
    + if path:
    + element_path = "%s.%s" % (path, element_infos["name"])
    + else:
    + element_path = element_infos["name"]
    + if element_infos["type"] == "element":
    + name = element_infos["name"]
    + value = element_infos["value"]
    + label = _(name)
    + if value is not None:
    + label += " - %s" % _(value)
    + staticbox = wx.StaticBox(self.ParamsEditor,
    + label=_(label), size=wx.Size(10, 0))
    + staticboxsizer = wx.StaticBoxSizer(staticbox, wx.VERTICAL)
    + flags = (wx.GROW | wx.BOTTOM | wx.LEFT | wx.RIGHT)
    + if first:
    + flags |= wx.TOP
    + sizer.AddSizer(staticboxsizer, border=5, flag=flags)
    + self.GenerateSizerElements(staticboxsizer,
    + element_infos["children"],
    + element_path)
    + else:
    + boxsizer = wx.FlexGridSizer(cols=3, rows=1)
    + boxsizer.AddGrowableCol(1)
    + flags = (wx.GROW | wx.BOTTOM | wx.LEFT | wx.RIGHT)
    + if first:
    + flags |= wx.TOP
    + sizer.AddSizer(boxsizer, border=5, flag=flags)
    + staticbitmap = GenStaticBitmap(ID=-1, bitmapname=element_infos["name"],
    + name="%s_bitmap" % element_infos["name"], parent=self.ParamsEditor,
    + pos=wx.Point(0, 0), size=wx.Size(24, 24), style=0)
    + boxsizer.AddWindow(staticbitmap, border=5, flag=wx.RIGHT)
    +
    + statictext = wx.StaticText(self.ParamsEditor,
    + label="%s:" % _(element_infos["name"]))
    + boxsizer.AddWindow(statictext, border=5,
    + flag=wx.ALIGN_CENTER_VERTICAL | wx.RIGHT)
    +
    + if isinstance(element_infos["type"], types.ListType):
    + if isinstance(element_infos["value"], types.TupleType):
    + browse_boxsizer = wx.BoxSizer(wx.HORIZONTAL)
    + boxsizer.AddSizer(browse_boxsizer)
    +
    + textctrl = wx.TextCtrl(self.ParamsEditor,
    + size=wx.Size(275, -1), style=wx.TE_READONLY)
    + if element_infos["value"] is not None:
    + textctrl.SetValue(element_infos["value"][0])
    + value_infos = element_infos["value"][1]
    + else:
    + value_infos = None
    + browse_boxsizer.AddWindow(textctrl)
    +
    + button = wx.Button(self.ParamsEditor,
    + label="...", size=wx.Size(25, 25))
    + browse_boxsizer.AddWindow(button)
    + button.Bind(wx.EVT_BUTTON,
    + self.GetBrowseCallBackFunction(element_infos["name"], textctrl, element_infos["type"],
    + value_infos, element_path),
    + button)
    + else:
    + combobox = wx.ComboBox(self.ParamsEditor,
    + size=wx.Size(300, -1), style=wx.CB_READONLY)
    + boxsizer.AddWindow(combobox)
    +
    + if element_infos["use"] == "optional":
    + combobox.Append("")
    + if len(element_infos["type"]) > 0 and isinstance(element_infos["type"][0], types.TupleType):
    + for choice, xsdclass in element_infos["type"]:
    + combobox.Append(choice)
    + name = element_infos["name"]
    + value = element_infos["value"]
    +
    + staticbox = wx.StaticBox(self.ParamsEditor,
    + label="%s - %s" % (_(name), _(value)), size=wx.Size(10, 0))
    + staticboxsizer = wx.StaticBoxSizer(staticbox, wx.VERTICAL)
    + sizer.AddSizer(staticboxsizer, border=5, flag=wx.GROW | wx.BOTTOM | wx.LEFT | wx.RIGHT)
    + self.GenerateSizerElements(staticboxsizer, element_infos["children"], element_path)
    + callback = self.GetChoiceContentCallBackFunction(combobox, staticboxsizer, element_path)
    + else:
    + for choice in element_infos["type"]:
    + combobox.Append(choice)
    + callback = self.GetChoiceCallBackFunction(combobox, element_path)
    + if element_infos["value"] is None:
    + combobox.SetStringSelection("")
    + else:
    + combobox.SetStringSelection(element_infos["value"])
    + combobox.Bind(wx.EVT_COMBOBOX, callback, combobox)
    +
    + elif isinstance(element_infos["type"], types.DictType):
    + scmin = -(2 ** 31)
    + scmax = 2 ** 31 - 1
    + if "min" in element_infos["type"]:
    + scmin = element_infos["type"]["min"]
    + if "max" in element_infos["type"]:
    + scmax = element_infos["type"]["max"]
    + spinctrl = wx.SpinCtrl(self.ParamsEditor,
    + size=wx.Size(300, -1), style=wx.SP_ARROW_KEYS | wx.ALIGN_RIGHT)
    + spinctrl.SetRange(scmin, scmax)
    + boxsizer.AddWindow(spinctrl)
    + if element_infos["value"] is not None:
    + spinctrl.SetValue(element_infos["value"])
    + spinctrl.Bind(wx.EVT_SPINCTRL,
    + self.GetTextCtrlCallBackFunction(spinctrl, element_path),
    + spinctrl)
    +
    + else:
    + if element_infos["type"] == "boolean":
    + checkbox = wx.CheckBox(self.ParamsEditor, size=wx.Size(17, 25))
    + boxsizer.AddWindow(checkbox)
    + if element_infos["value"] is not None:
    + checkbox.SetValue(element_infos["value"])
    + checkbox.Bind(wx.EVT_CHECKBOX,
    + self.GetCheckBoxCallBackFunction(checkbox, element_path),
    + checkbox)
    +
    + elif element_infos["type"] in ["unsignedLong", "long", "integer"]:
    + if element_infos["type"].startswith("unsigned"):
    + scmin = 0
    + else:
    + scmin = -(2 ** 31)
    + scmax = 2 ** 31 - 1
    + spinctrl = wx.SpinCtrl(self.ParamsEditor,
    + size=wx.Size(300, -1), style=wx.SP_ARROW_KEYS | wx.ALIGN_RIGHT)
    + spinctrl.SetRange(scmin, scmax)
    + boxsizer.AddWindow(spinctrl)
    + if element_infos["value"] is not None:
    + spinctrl.SetValue(element_infos["value"])
    + spinctrl.Bind(wx.EVT_SPINCTRL,
    + self.GetTextCtrlCallBackFunction(spinctrl, element_path),
    + spinctrl)
    +
    + else:
    + choices = self.ParentWindow.GetConfigEntry(element_path, [""])
    + CTR = self.ParentWindow.CTR
    + if element_infos["name"] == "URI_location":
    + textctrl = UriTextControl(name=element_infos["name"],
    + parent=self.ParamsEditor,
    + choices=choices,
    + element_path=element_path,
    + size=wx.Size(300, -1),
    + Click=True,
    + function=UriOptions)
    + else:
    + textctrl = TextCtrlAutoComplete(name=element_infos["name"],
    + parent=self.ParamsEditor,
    + choices=choices,
    + element_path=element_path,
    + size=wx.Size(300, -1))
    +
    + boxsizer.AddWindow(textctrl)
    + if element_infos["value"] is not None:
    + textctrl.ChangeValue(str(element_infos["value"]))
    + callback = self.GetTextCtrlCallBackFunction(textctrl, element_path)
    + textctrl.Bind(wx.EVT_TEXT_ENTER, callback)
    + textctrl.Bind(wx.EVT_TEXT, callback)
    + textctrl.Bind(wx.EVT_KILL_FOCUS, callback)
    + first = False
    + sizer.Layout()
    + self.RefreshScrollbars()
    +ConfTreeNodeEditor.GenerateSizerElements = GenerateSizerElements
    +
    +def ResetSearchResults(self):
    + self.Highlights = []
    + self.SearchParams = None
    + self.SearchResults = None
    + self.VariableSearchResults = []
    + self.CurrentFindHighlight = None
    + self.index = 0
    +CodeEditor.ResetSearchResults = ResetSearchResults
    +
    +from graphics.GraphicCommons import ERROR_HIGHLIGHT, SEARCH_RESULT_HIGHLIGHT, REFRESH_HIGHLIGHT_PERIOD
    +[STC_CODE_ERROR, STC_CODE_SEARCH_RESULT,
    + STC_CODE_SECTION] = range(15, 18)
    +
    +HIGHLIGHT_TYPES = {
    + ERROR_HIGHLIGHT: STC_CODE_ERROR,
    + SEARCH_RESULT_HIGHLIGHT: STC_CODE_SEARCH_RESULT,
    +}
    +def FindVariable(self, direction, search_params, variables):
    + first = False
    + if self.SearchParams != search_params:
    + first = True
    + self.SearchParams = search_params
    + if len(self.VariableSearchResults) > 0:
    + (r, c) = self.VariableSearchResults[self.index]
    + variables.VariablesGrid.SetCellBackgroundColour(r, c, SEARCH_RESULT_HIGHLIGHT[1])
    + grid = variables.VariablesGrid
    + cols = grid.GetNumberCols()
    + rows = grid.GetNumberRows()
    + self.VariableSearchResults = []
    + for row in range(rows):
    + for col in range(cols):
    + value = variables.VariablesGrid.GetCellValue(row, col)
    + search_value = search_params['find_pattern']
    + if search_params['case_sensitive'] == False:
    + search_value = search_value.lower()
    + value = value.lower()
    + if search_value in value:
    + self.VariableSearchResults.append((row, col))
    + self.index = 0
    + if len(self.VariableSearchResults) > 0:
    + (r, c) = self.VariableSearchResults[self.index]
    + variables.VariablesGrid.SetCellBackgroundColour(r, c, SEARCH_RESULT_HIGHLIGHT[1])
    + if not first:
    + self.index += direction
    + self.index = self.index % len(self.VariableSearchResults)
    + (r, c) = self.VariableSearchResults[self.index]
    + variables.VariablesGrid.SetCellBackgroundColour(r, c, SEARCH_RESULT_HIGHLIGHT[0])
    + variables.VariablesGrid.MakeCellVisible(r, c)
    + variables.VariablesGrid.ForceRefresh()
    +CodeEditor.FindVariable = FindVariable
    +
    +def SearchInPyfile(self, criteria):
    + result = []
    + from xml.dom import minidom
    + dir_list = next(os.walk(self.ProjectPath))[1]
    + for dir in dir_list:
    + if dir not in ["build", "CanOpen@CanOpen", "project_files"]:
    + path = os.path.join(self.ProjectPath, dir, 'pyfile.xml')
    + variablelist = []
    + if os.path.exists(path):
    + pyfile = minidom.parse(path)
    + variablelist = pyfile.getElementsByTagName('variable')
    + for s in variablelist:
    + if criteria["find_pattern"] in s.attributes['name'].value:
    + result.append(dir)
    + return result
    +PLCControler.SearchInPyfile = SearchInPyfile
    +
    +def OnSearchInProjectMenu(self, event):
    + dialog = SearchInProjectDialog(self)
    + if dialog.ShowModal() == wx.ID_OK:
    + criteria = dialog.GetCriteria()
    + if len(criteria) > 0:
    + result = self.Controler.SearchInProject(criteria)
    + pyresult = self.Controler.SearchInPyfile(criteria)
    + self.ClearSearchResults()
    + self.SearchResultPanel.SetSearchResults(criteria, result, pyresult)
    + self.SearchResultPanel.AddPyFileResults(pyresult)
    + self.SelectTab(self.SearchResultPanel)
    +IDEFrame.OnSearchInProjectMenu = OnSearchInProjectMenu
    +
    +def GenerateProjectTreeBranch(self, root, infos, item_alone=False):
    + to_delete = []
    + item_name = infos["name"]
    + if infos["type"] in ITEMS_UNEDITABLE:
    + if len(infos["values"]) == 1:
    + return self.GenerateProjectTreeBranch(root, infos["values"][0], True)
    + item_name = _(item_name)
    + self.ProjectTree.SetItemText(root, item_name)
    + self.ProjectTree.SetPyData(root, infos)
    + highlight_colours = self.Highlights.get(infos.get("tagname", None), (wx.WHITE, wx.BLACK))
    + self.ProjectTree.SetItemBackgroundColour(root, highlight_colours[0])
    + self.ProjectTree.SetItemTextColour(root, highlight_colours[1])
    + self.ProjectTree.SetItemExtraImage(root, None)
    + if infos["type"] == ITEM_POU:
    + self.ProjectTree.SetItemImage(root,
    + self.TreeImageDict[self.Controler.GetPouBodyType(infos["name"])])
    + if item_alone:
    + self.ProjectTree.SetItemExtraImage(root, self.Controler.GetPouType(infos["name"]))
    + elif infos.has_key("icon") and infos["icon"] is not None:
    + icon_name = infos["icon"]
    + if not self.TreeImageDict.has_key(icon_name):
    + self.TreeImageDict[icon_name] = self.TreeImageList.Add(GetBitmap(icon_name))
    + self.ProjectTree.SetItemImage(root, self.TreeImageDict[icon_name])
    + elif self.TreeImageDict.has_key(infos["type"]):
    + self.ProjectTree.SetItemImage(root, self.TreeImageDict[infos["type"]])
    +
    + item, root_cookie = self.ProjectTree.GetFirstChild(root)
    + for values in infos["values"]:
    + if values["type"] not in ITEMS_UNEDITABLE or len(values["values"]) > 0:
    + if item is None or not item.IsOk():
    + item = self.ProjectTree.AppendItem(root, "")
    + item, root_cookie = self.ProjectTree.GetNextChild(root, root_cookie)
    + self.GenerateProjectTreeBranch(item, values)
    + item, root_cookie = self.ProjectTree.GetNextChild(root, root_cookie)
    + while item is not None and item.IsOk():
    + to_delete.append(item)
    + item, root_cookie = self.ProjectTree.GetNextChild(root, root_cookie)
    + for item in to_delete:
    + self.ProjectTree.Delete(item)
    +IDEFrame.GenerateProjectTreeBranch = GenerateProjectTreeBranch
    +
    +defaultSearchResultPanelInit = SearchResultPanel.__init__
    +def SearchResultPanelInit(self, parent, window):
    + defaultSearchResultPanelInit(self, parent, window)
    + self.TreeImageDict["py_file"] = self.TreeImageList.Add(GetBitmap("py_file"))
    + self.TreeImageDict["wx_glade"] = self.TreeImageList.Add(GetBitmap("wx_glade"))
    +SearchResultPanel.__init__ = SearchResultPanelInit
    +
    +def SetSearchResults(self, criteria, search_results, py_results):
    + self.Criteria = criteria
    + self.SearchResults = {}
    + self.ElementsOrder = []
    + self.PySearchResults = py_results
    +
    + for infos, start, end, text in search_results:
    + if infos[0] not in self.ElementsOrder:
    + self.ElementsOrder.append(infos[0])
    +
    + results = self.SearchResults.setdefault(infos[0], [])
    + results.append((infos, start, end, text))
    +
    + self.RefreshView()
    +SearchResultPanel.SetSearchResults = SetSearchResults
    +
    +def AddPyFileResults(self, search_results):
    + distinct_list = list(set(search_results))
    + for result in distinct_list:
    + name = result.split('@')
    + matches = search_results.count(result)
    + if name[1] == "py_ext":
    + root = self.SearchResultsTree.GetRootItem()
    + self.SearchResultsTree.AppendItem(root, name[0], image=self.TreeImageDict["py_file"])
    + else:
    + root = self.SearchResultsTree.GetRootItem()
    + self.SearchResultsTree.AppendItem(root, name[0], image=self.TreeImageDict["wx_glade"])
    + if matches > 1:
    + text = _("(%d matches)") % search_results.count(result)
    + start_idx, end_idx = 0, len(text)
    + style = wx.TextAttr(wx.Colour(0, 127, 174))
    + text_ctrl_style = wx.BORDER_NONE | wx.TE_READONLY | wx.TE_RICH2
    + if wx.Platform != '__WXMSW__' or len(text.splitlines()) > 1:
    + text_ctrl_style |= wx.TE_MULTILINE
    + text_ctrl = wx.TextCtrl(id=-1, parent=self.SearchResultsTree, pos=wx.Point(0, 0),
    + value=text, style=text_ctrl_style)
    + width, height = text_ctrl.GetTextExtent(text)
    + text_ctrl.SetClientSize(wx.Size(width + 1, height))
    + text_ctrl.SetBackgroundColour(self.SearchResultsTree.GetBackgroundColour())
    + child = self.SearchResultsTree.GetLastChild(root)
    + text_ctrl.SetInsertionPoint(0)
    + text_ctrl.SetStyle(start_idx, end_idx, style)
    + self.SearchResultsTree.SetItemWindow(child, text_ctrl)
    +SearchResultPanel.AddPyFileResults = AddPyFileResults
    +
    +
    +def ResetSearchResults(self):
    + self.Criteria = None
    + self.ElementsOrder = []
    + self.SearchResults = {}
    + self.PySearchResults = []
    + self.RefreshView()
    +SearchResultPanel.ResetSearchResults = ResetSearchResults
    +
    +
    +def GetPythonTextCtrlDClickFunction(self, item):
    + for type in self.ParentWindow.CTR.Children.values():
    + for name in type:
    + if name.BaseParams.attrib['Name'] == item:
    + name._OpenView()
    + selected = self.ParentWindow.TabsOpened.GetSelection()
    + if selected != -1:
    + window = self.ParentWindow.TabsOpened.GetPage(selected)
    + window.CodeEditor.FindVariable(1, {'find_pattern': self.Criteria['find_pattern'],
    + 'regular_expression': self.Criteria['regular_expression'],
    + 'pattern': self.Criteria['pattern'],
    + 'case_sensitive': self.Criteria['case_sensitive'],
    + 'filter': self.Criteria['filter']}, window.VariablesPanel)
    + for (r, c) in window.CodeEditor.VariableSearchResults:
    + window.VariablesPanel.VariablesGrid.SetCellBackgroundColour(r, c,
    + SEARCH_RESULT_HIGHLIGHT[0])
    +SearchResultPanel.GetPythonTextCtrlDClickFunction = GetPythonTextCtrlDClickFunction
    +
    +
    +def OnSearchResultsTreeItemActivated(self, event):
    + self.ShowSearchResults(event.GetItem())
    + if event.GetItem()._data is None:
    + self.GetPythonTextCtrlDClickFunction(event.GetItem()._text)
    + event.Skip()
    +SearchResultPanel.OnSearchResultsTreeItemActivated = OnSearchResultsTreeItemActivated
    +
    +defaultProjectPropertiesPanelInit = ProjectPropertiesPanel.__init__
    +def OurProjectPropertiesPanelInit(self, parent, controller=None, window=None, enable_required=True):
    +
    + REQUIRED_PARAMS = ["projectName", "productName", "productVersion", "companyName"]
    + [TITLE, EDITORTOOLBAR, FILEMENU, EDITMENU, DISPLAYMENU, PROJECTTREE,
    + POUINSTANCEVARIABLESPANEL, LIBRARYTREE, SCALING, PAGETITLES
    + ] = range(10)
    +
    + def create_project_panel(self):
    + self.ProjectPanel = ScrolledPanel(self, -1, style=wx.TAB_TRAVERSAL)
    + self.ProjectPanel.SetAutoLayout(1)
    + self.ProjectPanel.SetupScrolling()
    + self.AddPage(self.ProjectPanel, _("Project"))
    +
    + projectpanel_sizer = wx.FlexGridSizer(cols=2, hgap=5, rows=5, vgap=15)
    + projectpanel_sizer.AddGrowableCol(1)
    + self.ProjectPanel.SetSizer(projectpanel_sizer)
    +
    + self.AddSizerParams(self.ProjectPanel, projectpanel_sizer,
    + [("projectName", _('Project Name (required):')),
    + ("projectVersion", _('Project Version (optional):')),
    + ("productName", _('Product Name (required):')),
    + ("productVersion", _('Product Version (required):')),
    + ("productRelease", _('Product Release (optional):'))])
    +
    + self.AddPage(self.ProjectPanel, _("Project"))
    +
    + def create_author_panel(self):
    + self.AuthorPanel = ScrolledPanel(self, -1, style=wx.TAB_TRAVERSAL)
    + self.AuthorPanel.SetAutoLayout(1)
    + self.AuthorPanel.SetupScrolling()
    +
    + authorpanel_sizer = wx.FlexGridSizer(cols=2, hgap=5, rows=4, vgap=15)
    + authorpanel_sizer.AddGrowableCol(1)
    + self.AuthorPanel.SetSizer(authorpanel_sizer)
    +
    + self.AddSizerParams(self.AuthorPanel, authorpanel_sizer,
    + [("companyName", _('Company Name (required):')),
    + ("companyURL", _('Company URL (optional):')),
    + ("authorName", _('Author Name (optional):')),
    + ("organization", _('Organization (optional):'))])
    +
    + self.AddPage(self.AuthorPanel, _("Author"))
    +
    + def create_graphic_panel(self):
    + self.GraphicsPanel = ScrolledPanel(self, -1, style=wx.TAB_TRAVERSAL)
    + self.GraphicsPanel.SetAutoLayout(1)
    + self.GraphicsPanel.SetupScrolling()
    +
    + graphicpanel_sizer = wx.FlexGridSizer(cols=1, hgap=5, rows=4, vgap=5)
    + graphicpanel_sizer.AddGrowableCol(0)
    + graphicpanel_sizer.AddGrowableRow(3)
    + self.GraphicsPanel.SetSizer(graphicpanel_sizer)
    +
    + pageSize_st = wx.StaticText(self.GraphicsPanel,
    + label=_('Page Size (optional):'))
    + graphicpanel_sizer.AddWindow(pageSize_st, border=10,
    + flag=wx.ALIGN_CENTER_VERTICAL | wx.TOP | wx.LEFT | wx.RIGHT)
    +
    + pageSize_sizer = wx.FlexGridSizer(cols=2, hgap=5, rows=2, vgap=5)
    + pageSize_sizer.AddGrowableCol(1)
    + graphicpanel_sizer.AddSizer(pageSize_sizer, border=10,
    + flag=wx.GROW | wx.LEFT | wx.RIGHT)
    +
    + for name, label in [('PageWidth', _('Width:')), ('PageHeight', _('Height:'))]:
    + st = wx.StaticText(self.GraphicsPanel, label=label)
    + pageSize_sizer.AddWindow(st, border=12,
    + flag=wx.ALIGN_CENTER_VERTICAL | wx.LEFT)
    +
    + sp = wx.SpinCtrl(self.GraphicsPanel,
    + min=0, max=2 ** 16, style=wx.TE_PROCESS_ENTER)
    + setattr(self, name, sp)
    + callback = self.GetPageSizeChangedFunction(sp, name)
    + self.Bind(wx.EVT_TEXT_ENTER, callback, sp)
    + sp.Bind(wx.EVT_KILL_FOCUS, callback)
    + pageSize_sizer.AddWindow(sp, flag=wx.GROW)
    +
    + scaling_st = wx.StaticText(self.GraphicsPanel,
    + label=_('Grid Resolution:'))
    + graphicpanel_sizer.AddWindow(scaling_st, border=10,
    + flag=wx.GROW | wx.LEFT | wx.RIGHT)
    +
    + scaling_nb = wx.Notebook(self.GraphicsPanel)
    + graphicpanel_sizer.AddWindow(scaling_nb, border=10,
    + flag=wx.GROW | wx.BOTTOM | wx.LEFT | wx.RIGHT)
    +
    + self.Scalings = {}
    + for language, translation in [("FBD", _("FBD")), ("LD", _("LD")), ("SFC", _("SFC"))]:
    + scaling_panel = wx.Panel(scaling_nb, style=wx.TAB_TRAVERSAL)
    + scalingpanel_sizer = wx.FlexGridSizer(cols=2, hgap=5, rows=2, vgap=5)
    + scalingpanel_sizer.AddGrowableCol(1)
    + scaling_panel.SetSizer(scalingpanel_sizer)
    +
    + scaling_controls = []
    + for idx, (name, label) in enumerate([('XScale', _('Horizontal:')),
    + ('YScale', _('Vertical:'))]):
    + if idx == 0:
    + border = wx.TOP
    + else:
    + border = wx.BOTTOM
    +
    + st = wx.StaticText(scaling_panel, label=label)
    + scalingpanel_sizer.AddWindow(st, border=10,
    + flag=wx.ALIGN_CENTER_VERTICAL | border | wx.LEFT)
    +
    + sp = wx.SpinCtrl(scaling_panel,
    + min=0, max=2 ** 16, style=wx.TE_PROCESS_ENTER)
    + scaling_controls.append(sp)
    + callback = self.GetScalingChangedFunction(sp, language, name)
    + self.Bind(wx.EVT_TEXT_ENTER, callback, sp)
    + sp.Bind(wx.EVT_KILL_FOCUS, callback)
    + scalingpanel_sizer.AddWindow(sp, border=10,
    + flag=wx.GROW | border | wx.RIGHT)
    +
    + self.Scalings[language] = scaling_controls
    + scaling_nb.AddPage(scaling_panel, translation)
    +
    + self.AddPage(self.GraphicsPanel, _("Graphics"))
    +
    + def create_miscellaneous_panel(self):
    + self.MiscellaneousPanel = ScrolledPanel(id=-1, parent=self,
    + name='MiscellaneousPanel', pos=wx.Point(0, 0),
    + size=wx.Size(0, 0), style=wx.TAB_TRAVERSAL)
    + self.MiscellaneousPanel.SetAutoLayout(1)
    + self.MiscellaneousPanel.SetupScrolling()
    +
    + miscellaneouspanel_sizer = wx.FlexGridSizer(cols=2, hgap=5, rows=2, vgap=15)
    + miscellaneouspanel_sizer.AddGrowableCol(1)
    + miscellaneouspanel_sizer.AddGrowableRow(1)
    + self.MiscellaneousPanel.SetSizer(miscellaneouspanel_sizer)
    +
    + language_label = wx.StaticText(self.MiscellaneousPanel,
    + label=_('Language (optional):'))
    + miscellaneouspanel_sizer.AddWindow(language_label, border=10,
    + flag=wx.ALIGN_CENTER_VERTICAL | wx.TOP | wx.LEFT)
    +
    + self.Language = wx.ComboBox(self.MiscellaneousPanel,
    + style=wx.CB_READONLY)
    + self.Bind(wx.EVT_COMBOBOX, self.OnLanguageChanged, self.Language)
    + miscellaneouspanel_sizer.AddWindow(self.Language, border=10,
    + flag=wx.GROW | wx.TOP | wx.RIGHT)
    +
    + description_label = wx.StaticText(self.MiscellaneousPanel,
    + label=_('Content Description (optional):'))
    + miscellaneouspanel_sizer.AddWindow(description_label, border=10,
    + flag=wx.BOTTOM | wx.LEFT)
    +
    + self.ContentDescription = wx.TextCtrl(self.MiscellaneousPanel,
    + style=wx.TE_MULTILINE | wx.TE_PROCESS_ENTER)
    + self.Bind(wx.EVT_TEXT_ENTER, self.OnContentDescriptionChanged,
    + self.ContentDescription)
    + self.ContentDescription.Bind(wx.EVT_KILL_FOCUS,
    + self.OnContentDescriptionChanged)
    + miscellaneouspanel_sizer.AddWindow(self.ContentDescription, border=10,
    + flag=wx.GROW | wx.BOTTOM | wx.RIGHT)
    +
    + self.AddPage(self.MiscellaneousPanel, _("Miscellaneous"))
    +
    + wx.Notebook.__init__(self, parent, size=wx.Size(500, 300))
    +
    + self.Controller = controller
    + self.ParentWindow = window
    + self.Values = None
    +
    + create_project_panel(self)
    +
    + create_author_panel(self)
    +
    + create_graphic_panel(self)
    +
    + create_miscellaneous_panel(self)
    +
    + for param in REQUIRED_PARAMS:
    + getattr(self, param).Enable(enable_required)
    + languages = ["", "en-US", "fr-FR", "zh-CN", "ru-RU"]
    + for language in languages:
    + self.Language.Append(language)
    +ProjectPropertiesPanel.__init__ = OurProjectPropertiesPanelInit
    def GetFunctionBlockTypes(self, tagname="", debug=False):
    @@ -291,14 +1091,23 @@
    self.Parent.VariablesEditorSetCollSize()
    # added left click option on grid, with function LeftClick added in VariablesTable class
    self.grid.Bind(wx.grid.EVT_GRID_CELL_LEFT_DCLICK, self.LeftClick)
    -
    VariablesTable._updateColAttrs = _updateColAttrs
    +"""Zakomentirano ker je ze v beremiz-u"""
    +# def OnCleanButton(self, event):
    +# if self.LogSource is not None:
    +# rez = self.LogSource.ResetLogCount()
    +# if not rez:
    +# self.GrandParent.CTR.logger.write_warning("Can not reset log messages!\n")
    +# self.ResetLogMessages()
    +# self.RefreshView()
    +# event.Skip()
    +# LogViewer.OnCleanButton = OnCleanButton
    +
    from PLCControler import PLCControler, LOCATION_MODULE, LOCATION_GROUP, \
    LOCATION_VAR_INPUT, LOCATION_VAR_OUTPUT, LOCATION_VAR_MEMORY
    from IDEFrame import IDEFrame
    from dialogs import ProjectDialog
    -from controls import TextCtrlAutoComplete
    defaultGenerateNewName = PLCControler.GenerateNewName
    def newGenerateNewName(self, tagname, name, format, start_idx=0, exclude={}, debug=False):
    @@ -683,6 +1492,7 @@
    self.logger.write(_("Export file is not created because eror: %s\n") % e)
    def _Build(self):
    + threads = threading.enumerate()
    def __Build(args, save):
    self.building = True
    build_succeeded = ProjectController._Build(args)
    @@ -691,6 +1501,7 @@
    if save:
    wx.CallAfter(args.AppFrame.RefreshAll)
    self.building = False
    + # pub.sendMessage("build", msg="True")
    self._Clean(building = True)
    save = self.ProjectTestModified()
    @@ -699,10 +1510,15 @@
    self.AppFrame._Refresh(TITLE, FILEMENU)
    if self.BuildPath is not None:
    mycopytree(self.OrigBuildPath, self.BuildPath)
    - if not self.building:
    - build_thread = Thread(target=__Build, args=(self,save))
    + if len(filter(lambda x: x.getName() == "OnBuildThread", threads)) == 0:
    + build_thread = Thread(name="OnBuildThread", target=__Build, args=(self,save))
    build_thread.daemon = True
    build_thread.start()
    + # if self.AppFrame:
    + # frame = splash.SmartehScreenSplash(self.AppFrame, bitmap=GetPath(splash.SPLASH_FN), pub=pub)
    + # frame.ShowModal()
    + else:
    + self.logger.write(_("Already building project.\n"))
    # build_succeeded = ProjectController._Build(self)
    # if build_succeeded:
    # self.ToZIPFile()
    @@ -1652,406 +2468,414 @@
    if __name__ == '__main__':
    - from threading import Thread, Timer, Semaphore, Lock
    - import cmd
    -
    - build_lock = Lock()
    - wx_eval_lock = Semaphore(0)
    - eval_res = None
    -
    -
    - def wx_evaluator(callable, *args, **kwargs):
    - global eval_res
    + try:
    +
    + from threading import Thread, Timer, Semaphore, Lock
    + import cmd
    +
    + build_lock = Lock()
    + wx_eval_lock = Semaphore(0)
    eval_res = None
    - try:
    - eval_res = callable(*args, **kwargs)
    - finally:
    - wx_eval_lock.release()
    -
    -
    - def evaluator(callable, *args, **kwargs):
    - global eval_res
    - wx.CallAfter(wx_evaluator, callable, *args, **kwargs)
    - wx_eval_lock.acquire()
    - return eval_res
    -
    -
    - # Command log for debug, for viewing from wxInspector
    - if BMZ_DBG:
    - __builtins__.cmdlog = []
    -
    -
    - class LPCBeremiz_Cmd(cmd.Cmd):
    -
    - prompt = ""
    - RefreshTimer = None
    -
    - def __init__(self, CTR, Log):
    - cmd.Cmd.__init__(self, stdin=Log, stdout=Log)
    - self.use_rawinput = False
    - self.restore_last_state = False
    - self.Log = Log
    - self.CTR = CTR
    -
    - def RestartTimer(self):
    - if self.RefreshTimer is not None:
    - self.RefreshTimer.cancel()
    - self.RefreshTimer = Timer(0.1, wx.CallAfter, args=[self.Refresh])
    - self.RefreshTimer.start()
    -
    - def Exit(self):
    - global frame, app
    - self.Close()
    - app.ExitMainLoop()
    - return True
    -
    - def do_EOF(self, line):
    - return self.Exit()
    -
    - def Show(self):
    - global frame
    - if frame is not None:
    - self.CTR.SetAppFrame(frame, frame.Log)
    - self.CTR.UpdateMethodsFromPLCStatus()
    - frame.Show()
    - frame.Raise()
    - self.restore_last_state = True
    - #self.RestartTimer()
    -
    - def Refresh(self):
    - global frame
    - if frame is not None:
    - if self.restore_last_state:
    - self.restore_last_state = False
    - frame.RestoreLastState()
    +
    +
    + def wx_evaluator(callable, *args, **kwargs):
    + global eval_res
    + eval_res = None
    + try:
    + eval_res = callable(*args, **kwargs)
    + finally:
    + wx_eval_lock.release()
    +
    +
    + def evaluator(callable, *args, **kwargs):
    + global eval_res
    + wx.CallAfter(wx_evaluator, callable, *args, **kwargs)
    + wx_eval_lock.acquire()
    + return eval_res
    +
    +
    + # Command log for debug, for viewing from wxInspector
    + if BMZ_DBG:
    + __builtins__.cmdlog = []
    +
    +
    + class LPCBeremiz_Cmd(cmd.Cmd):
    +
    + prompt = ""
    + RefreshTimer = None
    +
    + def __init__(self, CTR, Log):
    + cmd.Cmd.__init__(self, stdin=Log, stdout=Log)
    + self.use_rawinput = False
    + self.restore_last_state = False
    + self.Log = Log
    + self.CTR = CTR
    +
    + def RestartTimer(self):
    + if self.RefreshTimer is not None:
    + self.RefreshTimer.cancel()
    + self.RefreshTimer = Timer(0.1, wx.CallAfter, args=[self.Refresh])
    + self.RefreshTimer.start()
    +
    + def Exit(self):
    + global frame, app
    + self.Close()
    + app.ExitMainLoop()
    + return True
    +
    + def do_EOF(self, line):
    + return self.Exit()
    +
    + def Show(self):
    + global frame
    + if frame is not None:
    + self.CTR.SetAppFrame(frame, frame.Log)
    + self.CTR.UpdateMethodsFromPLCStatus()
    + frame.Show()
    + frame.Raise()
    + self.restore_last_state = True
    + #self.RestartTimer()
    +
    + def Refresh(self):
    + global frame
    + if frame is not None:
    + if self.restore_last_state:
    + self.restore_last_state = False
    + frame.RestoreLastState()
    + else:
    + frame.RefreshEditor()
    + frame._Refresh(TITLE, PROJECTTREE, POUINSTANCEVARIABLESPANEL, FILEMENU, EDITMENU)
    + frame.RefreshAll()
    +
    + def Close(self):
    + global frame
    +
    + self.CTR.ResetAppFrame(self.Log)
    + if frame is not None:
    + frame.Hide()
    +
    + def Compile(self):
    + self.CTR._Build()
    +
    + def SetProjectProperties(self, projectname, productname, productversion, companyname):
    + new_properties = {
    + "projectName": projectname,
    + "productName": productname,
    + "productVersion": productversion,
    + "companyName": companyname}
    + self.CTR.SetProjectProperties(properties=new_properties, buffer=False)
    + self.RestartTimer()
    +
    + def SetOnlineMode(self, mode, path=None):
    + self.CTR.SetOnlineMode(mode, path)
    + self.RestartTimer()
    +
    + def AddBus(self, iec_channel, name, icon=None):
    + for child in self.CTR.IterChildren():
    + if child.BaseParams.getName() == name:
    + return "Error: A bus named %s already exists\n" % name
    + elif child.BaseParams.getIEC_Channel() == iec_channel:
    + return "Error: A bus with IEC_channel %d already exists\n" % iec_channel
    + bus = self.CTR.CTNAddChild(name, "LPCBus", iec_channel)
    + if bus is None:
    + return "Error: Unable to create bus\n"
    + bus.SetIcon(icon)
    + self.RestartTimer()
    +
    + def RenameBus(self, iec_channel, name):
    + bus = self.CTR.GetChildByIECLocation((iec_channel,))
    + if bus is None:
    + return "Error: No bus found\n"
    + for child in self.CTR.IterChildren():
    + if child != bus and child.BaseParams.getName() == name:
    + return "Error: A bus named %s already exists\n" % name
    + bus.BaseParams.setName(name)
    + self.RestartTimer()
    +
    + def ChangeBusIECChannel(self, old_iec_channel, new_iec_channel):
    + bus = self.CTR.GetChildByIECLocation((old_iec_channel,))
    + if bus is None:
    + return "Error: No bus found\n"
    + for child in self.CTR.IterChildren():
    + if child != bus and child.BaseParams.getIEC_Channel() == new_iec_channel:
    + return "Error: A bus with IEC_channel %d already exists\n" % new_iec_channel
    + if wx.GetApp() is None:
    + self.CTR.UpdateProjectVariableLocation(str(old_iec_channel),
    + str(new_iec_channel))
    else:
    - frame.RefreshEditor()
    - frame._Refresh(TITLE, PROJECTTREE, POUINSTANCEVARIABLESPANEL, FILEMENU, EDITMENU)
    - frame.RefreshAll()
    -
    - def Close(self):
    - global frame
    -
    - self.CTR.ResetAppFrame(self.Log)
    - if frame is not None:
    - frame.Hide()
    -
    - def Compile(self):
    - self.CTR._Build()
    -
    - def SetProjectProperties(self, projectname, productname, productversion, companyname):
    - new_properties = {
    - "projectName": projectname,
    - "productName": productname,
    - "productVersion": productversion,
    - "companyName": companyname}
    - self.CTR.SetProjectProperties(properties=new_properties, buffer=False)
    - self.RestartTimer()
    -
    - def SetOnlineMode(self, mode, path=None):
    - self.CTR.SetOnlineMode(mode, path)
    - self.RestartTimer()
    -
    - def AddBus(self, iec_channel, name, icon=None):
    - for child in self.CTR.IterChildren():
    - if child.BaseParams.getName() == name:
    - return "Error: A bus named %s already exists\n" % name
    - elif child.BaseParams.getIEC_Channel() == iec_channel:
    - return "Error: A bus with IEC_channel %d already exists\n" % iec_channel
    - bus = self.CTR.CTNAddChild(name, "LPCBus", iec_channel)
    - if bus is None:
    - return "Error: Unable to create bus\n"
    - bus.SetIcon(icon)
    - self.RestartTimer()
    -
    - def RenameBus(self, iec_channel, name):
    - bus = self.CTR.GetChildByIECLocation((iec_channel,))
    - if bus is None:
    - return "Error: No bus found\n"
    - for child in self.CTR.IterChildren():
    - if child != bus and child.BaseParams.getName() == name:
    - return "Error: A bus named %s already exists\n" % name
    - bus.BaseParams.setName(name)
    - self.RestartTimer()
    -
    - def ChangeBusIECChannel(self, old_iec_channel, new_iec_channel):
    - bus = self.CTR.GetChildByIECLocation((old_iec_channel,))
    - if bus is None:
    - return "Error: No bus found\n"
    - for child in self.CTR.IterChildren():
    - if child != bus and child.BaseParams.getIEC_Channel() == new_iec_channel:
    - return "Error: A bus with IEC_channel %d already exists\n" % new_iec_channel
    - if wx.GetApp() is None:
    - self.CTR.UpdateProjectVariableLocation(str(old_iec_channel),
    - str(new_iec_channel))
    - else:
    - self.CTR.UpdateProjectVariableLocation(
    - str(old_iec_channel),
    - str(new_iec_channel))
    - bus.BaseParams.setIEC_Channel(new_iec_channel)
    - self.RestartTimer()
    -
    - def RemoveBus(self, iec_channel):
    - bus = self.CTR.GetChildByIECLocation((iec_channel,))
    - if bus is None:
    - return "Error: No bus found\n"
    - self.CTR.RemoveProjectVariableByFilter(str(iec_channel))
    - self.CTR.Children["LPCBus"].remove(bus)
    - self.RestartTimer()
    -
    - def AddModule(self, parent, iec_channel, name, icode, icon=None):
    - module = self.CTR.GetChildByIECLocation(parent)
    - if module is None:
    - return "Error: No parent found\n"
    - for child in GetModuleChildren(module):
    - if child["name"] == name:
    - return "Error: A module named %s already exists\n" % name
    - elif child["IEC_Channel"] == iec_channel:
    - return "Error: A module with IEC_channel %d already exists\n" % iec_channel
    - GetLastModuleGroup(module).append({"name": name,
    - "type": LOCATION_MODULE,
    - "IEC_Channel": iec_channel,
    - "icon": icon,
    - "init": icode,
    - "children": []})
    - self.RestartTimer()
    -
    - def RenameModule(self, iec_location, name):
    - module = self.CTR.GetChildByIECLocation(iec_location)
    - if module is None:
    - return "Error: No module found\n"
    - parent = self.CTR.GetChildByIECLocation(iec_location[:-1])
    - if parent is self.CTR:
    - return "Error: No module found\n"
    - if module["name"] != name:
    - for child in GetModuleChildren(parent):
    + self.CTR.UpdateProjectVariableLocation(
    + str(old_iec_channel),
    + str(new_iec_channel))
    + bus.BaseParams.setIEC_Channel(new_iec_channel)
    + self.RestartTimer()
    +
    + def RemoveBus(self, iec_channel):
    + bus = self.CTR.GetChildByIECLocation((iec_channel,))
    + if bus is None:
    + return "Error: No bus found\n"
    + self.CTR.RemoveProjectVariableByFilter(str(iec_channel))
    + self.CTR.Children["LPCBus"].remove(bus)
    + self.RestartTimer()
    +
    + def AddModule(self, parent, iec_channel, name, icode, icon=None):
    + module = self.CTR.GetChildByIECLocation(parent)
    + if module is None:
    + return "Error: No parent found\n"
    + for child in GetModuleChildren(module):
    if child["name"] == name:
    return "Error: A module named %s already exists\n" % name
    - module["name"] = name
    - self.RestartTimer()
    -
    - def ChangeModuleIECChannel(self, old_iec_location, new_iec_channel):
    - module = self.CTR.GetChildByIECLocation(old_iec_location)
    - if module is None:
    - return "Error: No module found\n"
    - parent = self.CTR.GetChildByIECLocation(old_iec_location[:-1])
    - if parent is self.CTR:
    - return "Error: No module found\n"
    - if module["IEC_Channel"] != new_iec_channel:
    - for child in GetModuleChildren(parent):
    - if child["IEC_Channel"] == new_iec_channel:
    - return "Error: A module with IEC_channel %d already exists\n" % new_iec_channel
    - self.CTR.UpdateProjectVariableLocation(".".join(map(str, old_iec_location)),
    - ".".join(map(str, old_iec_location[:1] + (new_iec_channel,))))
    - module["IEC_Channel"] = new_iec_channel
    - self.RestartTimer()
    -
    - def ChangeModuleInitCode(self, iec_location, icode):
    - module = self.CTR.GetChildByIECLocation(iec_location)
    - if module is None:
    - return "Error: No module found\n"
    - module["init"] = icode
    -
    - def RemoveModule(self, parent, iec_channel):
    - module = self.CTR.GetChildByIECLocation(parent)
    - if module is None:
    - return "Error: No parent found\n"
    - child = GetModuleBySomething(module, "IEC_Channel", (iec_channel,))
    - if child is None:
    - return "Error: No module found\n"
    - self.CTR.RemoveProjectVariableByFilter(".".join(map(str, parent + (iec_channel,))))
    - RemoveModuleChild(module, child)
    - self.RestartTimer()
    -
    - def StartGroup(self, parent, name, icon=None):
    - module = self.CTR.GetChildByIECLocation(parent)
    - if module is None:
    - return "Error: No parent found\n"
    - for child in module["children"]:
    - if child["type"] == LOCATION_GROUP and child["name"] == name:
    - return "Error: A group named %s already exists\n" % name
    - module["children"].append({"name": name,
    - "type": LOCATION_GROUP,
    - "icon": icon,
    - "children": []})
    - self.RestartTimer()
    -
    - def AddVariable(self, parent, location, name, direction, type, rcode, pcode, description=""):
    - module = self.CTR.GetChildByIECLocation(parent)
    - if module is None:
    - return "Error: No parent found\n"
    - for child in GetModuleChildren(module):
    - if child["name"] == name:
    - return "Error: A variable named %s already exists\n" % name
    - if child["location"] == location and child["type"] == LOCATION_TYPES[direction]:
    - return "Error: A variable with location %s already exists\n" % ".".join(map(str, location))
    - GetLastModuleGroup(module).append({"name": name,
    - "location": location,
    - "type": LOCATION_TYPES[direction],
    - "IEC_type": type,
    - "description": description,
    - "retrieve": rcode,
    - "publish": pcode})
    - self.RestartTimer()
    -
    - def ChangeVariableParams(self, parent, location, new_name, new_direction, new_type, new_rcode, new_pcode,
    - new_description=None):
    - module = self.CTR.GetChildByIECLocation(parent)
    - if module is None:
    - return "Error: No parent found\n"
    - variable = None
    - for child in GetModuleChildren(module):
    - if child["location"] == location and child["type"] == LOCATION_TYPES[new_direction]:
    - variable = child
    - elif child["name"] == new_name:
    - return "Error: A variable named %s already exists\n" % new_name
    - if variable is None:
    - return "Error: No variable found\n"
    - if variable["name"] != new_name:
    - self.CTR.UpdateProjectVariableName(variable["name"], new_name)
    - variable["name"] = new_name
    - variable["type"] = LOCATION_TYPES[new_direction]
    - variable["IEC_type"] = new_type
    - variable["retrieve"] = new_rcode
    - variable["publish"] = new_pcode
    - if new_description is not None:
    - variable["description"] = new_description
    - self.RestartTimer()
    -
    - def RemoveVariable(self, parent, location, direction):
    - module = self.CTR.GetChildByIECLocation(parent)
    - if module is None:
    - return "Error: No parent found\n"
    - child = GetModuleVariable(module, location, direction)
    - if child is None:
    - return "Error: No variable found\n"
    - size = LOCATION_SIZES[self.CTR.GetBaseType(child["IEC_type"])]
    - address = "%" + LOCATION_DIRS[child["type"]] + size + ".".join(map(str, parent + location))
    - self.CTR.RemoveProjectVariableByAddress(address)
    - RemoveModuleChild(module, child)
    - self.RestartTimer()
    -
    -
    - def location(loc):
    - return tuple(map(int, loc.split(".")))
    -
    -
    - def GetCmdFunction(function, arg_types, opt=0):
    - arg_number = len(arg_types)
    -
    - def CmdFunction(self, line):
    - args_toks = line.split('"')
    - if len(args_toks) % 2 == 0:
    - self.Log.write("Error: Invalid command\n")
    - sys.stdout.flush()
    - return
    - args = []
    - for num, arg in enumerate(args_toks):
    - if num % 2 == 0:
    - stripped = arg.strip()
    - if stripped:
    - args.extend(stripped.split(" "))
    - else:
    - args.append(arg)
    - number = None
    - extra = ""
    - if opt == 0 and len(args) != arg_number:
    - number = arg_number
    - elif len(args) > arg_number:
    - number = arg_number
    - extra = " at most"
    - elif len(args) < arg_number - opt:
    - number = arg_number - opt
    - extra = " at least"
    - if number is not None:
    - if number == 0:
    - self.Log.write("Error: No argument%s expected\n" % extra)
    - elif number == 1:
    - self.Log.write("Error: 1 argument%s expected\n" % extra)
    - else:
    - self.Log.write("Error: %d arguments%s expected\n" % (number, extra))
    - sys.stdout.flush()
    - return
    - for num, arg in enumerate(args):
    - try:
    - args[num] = arg_types[num](arg)
    - except:
    - self.Log.write("Error: Invalid value for argument %d\n" % (num + 1))
    + elif child["IEC_Channel"] == iec_channel:
    + return "Error: A module with IEC_channel %d already exists\n" % iec_channel
    + GetLastModuleGroup(module).append({"name": name,
    + "type": LOCATION_MODULE,
    + "IEC_Channel": iec_channel,
    + "icon": icon,
    + "init": icode,
    + "children": []})
    + self.RestartTimer()
    +
    + def RenameModule(self, iec_location, name):
    + module = self.CTR.GetChildByIECLocation(iec_location)
    + if module is None:
    + return "Error: No module found\n"
    + parent = self.CTR.GetChildByIECLocation(iec_location[:-1])
    + if parent is self.CTR:
    + return "Error: No module found\n"
    + if module["name"] != name:
    + for child in GetModuleChildren(parent):
    + if child["name"] == name:
    + return "Error: A module named %s already exists\n" % name
    + module["name"] = name
    + self.RestartTimer()
    +
    + def ChangeModuleIECChannel(self, old_iec_location, new_iec_channel):
    + module = self.CTR.GetChildByIECLocation(old_iec_location)
    + if module is None:
    + return "Error: No module found\n"
    + parent = self.CTR.GetChildByIECLocation(old_iec_location[:-1])
    + if parent is self.CTR:
    + return "Error: No module found\n"
    + if module["IEC_Channel"] != new_iec_channel:
    + for child in GetModuleChildren(parent):
    + if child["IEC_Channel"] == new_iec_channel:
    + return "Error: A module with IEC_channel %d already exists\n" % new_iec_channel
    + self.CTR.UpdateProjectVariableLocation(".".join(map(str, old_iec_location)),
    + ".".join(map(str, old_iec_location[:1] + (new_iec_channel,))))
    + module["IEC_Channel"] = new_iec_channel
    + self.RestartTimer()
    +
    + def ChangeModuleInitCode(self, iec_location, icode):
    + module = self.CTR.GetChildByIECLocation(iec_location)
    + if module is None:
    + return "Error: No module found\n"
    + module["init"] = icode
    +
    + def RemoveModule(self, parent, iec_channel):
    + module = self.CTR.GetChildByIECLocation(parent)
    + if module is None:
    + return "Error: No parent found\n"
    + child = GetModuleBySomething(module, "IEC_Channel", (iec_channel,))
    + if child is None:
    + return "Error: No module found\n"
    + self.CTR.RemoveProjectVariableByFilter(".".join(map(str, parent + (iec_channel,))))
    + RemoveModuleChild(module, child)
    + self.RestartTimer()
    +
    + def StartGroup(self, parent, name, icon=None):
    + module = self.CTR.GetChildByIECLocation(parent)
    + if module is None:
    + return "Error: No parent found\n"
    + for child in module["children"]:
    + if child["type"] == LOCATION_GROUP and child["name"] == name:
    + return "Error: A group named %s already exists\n" % name
    + module["children"].append({"name": name,
    + "type": LOCATION_GROUP,
    + "icon": icon,
    + "children": []})
    + self.RestartTimer()
    +
    + def AddVariable(self, parent, location, name, direction, type, rcode, pcode, description=""):
    + module = self.CTR.GetChildByIECLocation(parent)
    + if module is None:
    + return "Error: No parent found\n"
    + for child in GetModuleChildren(module):
    + if child["name"] == name:
    + return "Error: A variable named %s already exists\n" % name
    + if child["location"] == location and child["type"] == LOCATION_TYPES[direction]:
    + return "Error: A variable with location %s already exists\n" % ".".join(map(str, location))
    + GetLastModuleGroup(module).append({"name": name,
    + "location": location,
    + "type": LOCATION_TYPES[direction],
    + "IEC_type": type,
    + "description": description,
    + "retrieve": rcode,
    + "publish": pcode})
    + self.RestartTimer()
    +
    + def ChangeVariableParams(self, parent, location, new_name, new_direction, new_type, new_rcode, new_pcode,
    + new_description=None):
    + module = self.CTR.GetChildByIECLocation(parent)
    + if module is None:
    + return "Error: No parent found\n"
    + variable = None
    + for child in GetModuleChildren(module):
    + if child["location"] == location and child["type"] == LOCATION_TYPES[new_direction]:
    + variable = child
    + elif child["name"] == new_name:
    + return "Error: A variable named %s already exists\n" % new_name
    + if variable is None:
    + return "Error: No variable found\n"
    + if variable["name"] != new_name:
    + self.CTR.UpdateProjectVariableName(variable["name"], new_name)
    + variable["name"] = new_name
    + variable["type"] = LOCATION_TYPES[new_direction]
    + variable["IEC_type"] = new_type
    + variable["retrieve"] = new_rcode
    + variable["publish"] = new_pcode
    + if new_description is not None:
    + variable["description"] = new_description
    + self.RestartTimer()
    +
    + def RemoveVariable(self, parent, location, direction):
    + module = self.CTR.GetChildByIECLocation(parent)
    + if module is None:
    + return "Error: No parent found\n"
    + child = GetModuleVariable(module, location, direction)
    + if child is None:
    + return "Error: No variable found\n"
    + size = LOCATION_SIZES[self.CTR.GetBaseType(child["IEC_type"])]
    + address = "%" + LOCATION_DIRS[child["type"]] + size + ".".join(map(str, parent + location))
    + self.CTR.RemoveProjectVariableByAddress(address)
    + RemoveModuleChild(module, child)
    + self.RestartTimer()
    +
    +
    + def location(loc):
    + return tuple(map(int, loc.split(".")))
    +
    +
    + def GetCmdFunction(function, arg_types, opt=0):
    + arg_number = len(arg_types)
    +
    + def CmdFunction(self, line):
    + args_toks = line.split('"')
    + if len(args_toks) % 2 == 0:
    + self.Log.write("Error: Invalid command\n")
    sys.stdout.flush()
    return
    -
    - func = getattr(self, function)
    - res = evaluator(func, *args)
    -
    - if BMZ_DBG:
    - cmdlog.append((function, line, res))
    - if len(cmdlog) > 100: # prevent debug log to grow too much
    - cmdlog.pop(0)
    -
    - if isinstance(res, (StringType, UnicodeType)):
    - self.Log.write(res)
    - return False
    - else:
    - return res
    -
    - return CmdFunction
    -
    -
    - def CmdThreadProc(CTR, Log):
    - global lpcberemiz_cmd
    - for function, (arg_types, opt) in {"Exit": ([], 0),
    - "Show": ([], 0),
    - "Refresh": ([], 0),
    - "Close": ([], 0),
    - "Compile": ([], 0),
    - "SetProjectProperties": ([str, str, str, str], 0),
    - "SetOnlineMode": ([str, str], 1),
    - "AddBus": ([int, str, str], 1),
    - "RenameBus": ([int, str], 0),
    - "ChangeBusIECChannel": ([int, int], 0),
    - "RemoveBus": ([int], 0),
    - "AddModule": ([location, int, str, str, str], 1),
    - "RenameModule": ([location, str], 0),
    - "ChangeModuleIECChannel": ([location, int], 0),
    - "ChangeModuleInitCode": ([location, str], 0),
    - "RemoveModule": ([location, int], 0),
    - "StartGroup": ([location, str, str], 1),
    - "AddVariable": ([location, location, str, str, str, str, str, str], 1),
    - "ChangeVariableParams": (
    - [location, location, str, str, str, str, str, str], 1),
    - "RemoveVariable": ([location, location], 0)}.iteritems():
    - setattr(LPCBeremiz_Cmd, "do_%s" % function, GetCmdFunction(function, arg_types, opt))
    - lpcberemiz_cmd = LPCBeremiz_Cmd(CTR, Log)
    - lpcberemiz_cmd.cmdloop()
    -
    - def ResetwxGlade():
    - # reset pid of running wxGlade
    - config = wx.ConfigBase.Get()
    - wxGladePid = 0
    - config.Write("BeremizRoot.wxGlade", str(wxGladePid))
    - config.Flush()
    -
    - Log = StdoutPseudoFile(port)
    -
    - if projectOpen is not None:
    - projectOpen = DecodeFileSystemPath(projectOpen, False)
    -
    - CTR = LPCProjectController(None, Log, buildpath)
    - if projectOpen is not None and os.path.isdir(projectOpen):
    - result = CTR.LoadProject(projectOpen)
    - if result:
    - Log.write("Error: Invalid project directory", result)
    - else:
    - Log.write("Error: No such file or directory")
    -
    - cmd_thread = Thread(target=CmdThreadProc, args=[CTR, Log])
    - cmd_thread.start()
    -
    - # Install a exception handle for bug reports
    - AddExceptHook(os.getcwd(), __version__)
    -
    - frame = LPCBeremiz(None, ctr=CTR, debug=True)
    -
    - ResetwxGlade()
    -
    - app.MainLoop()
    + args = []
    + for num, arg in enumerate(args_toks):
    + if num % 2 == 0:
    + stripped = arg.strip()
    + if stripped:
    + args.extend(stripped.split(" "))
    + else:
    + args.append(arg)
    + number = None
    + extra = ""
    + if opt == 0 and len(args) != arg_number:
    + number = arg_number
    + elif len(args) > arg_number:
    + number = arg_number
    + extra = " at most"
    + elif len(args) < arg_number - opt:
    + number = arg_number - opt
    + extra = " at least"
    + if number is not None:
    + if number == 0:
    + self.Log.write("Error: No argument%s expected\n" % extra)
    + elif number == 1:
    + self.Log.write("Error: 1 argument%s expected\n" % extra)
    + else:
    + self.Log.write("Error: %d arguments%s expected\n" % (number, extra))
    + sys.stdout.flush()
    + return
    + for num, arg in enumerate(args):
    + try:
    + args[num] = arg_types[num](arg)
    + except:
    + self.Log.write("Error: Invalid value for argument %d\n" % (num + 1))
    + sys.stdout.flush()
    + return
    +
    + func = getattr(self, function)
    + res = evaluator(func, *args)
    +
    + if BMZ_DBG:
    + cmdlog.append((function, line, res))
    + if len(cmdlog) > 100: # prevent debug log to grow too much
    + cmdlog.pop(0)
    +
    + if isinstance(res, (StringType, UnicodeType)):
    + self.Log.write(res)
    + return False
    + else:
    + return res
    +
    + return CmdFunction
    +
    +
    + def CmdThreadProc(CTR, Log):
    + global lpcberemiz_cmd
    + for function, (arg_types, opt) in {"Exit": ([], 0),
    + "Show": ([], 0),
    + "Refresh": ([], 0),
    + "Close": ([], 0),
    + "Compile": ([], 0),
    + "SetProjectProperties": ([str, str, str, str], 0),
    + "SetOnlineMode": ([str, str], 1),
    + "AddBus": ([int, str, str], 1),
    + "RenameBus": ([int, str], 0),
    + "ChangeBusIECChannel": ([int, int], 0),
    + "RemoveBus": ([int], 0),
    + "AddModule": ([location, int, str, str, str], 1),
    + "RenameModule": ([location, str], 0),
    + "ChangeModuleIECChannel": ([location, int], 0),
    + "ChangeModuleInitCode": ([location, str], 0),
    + "RemoveModule": ([location, int], 0),
    + "StartGroup": ([location, str, str], 1),
    + "AddVariable": ([location, location, str, str, str, str, str, str], 1),
    + "ChangeVariableParams": (
    + [location, location, str, str, str, str, str, str], 1),
    + "RemoveVariable": ([location, location], 0)}.iteritems():
    + setattr(LPCBeremiz_Cmd, "do_%s" % function, GetCmdFunction(function, arg_types, opt))
    + lpcberemiz_cmd = LPCBeremiz_Cmd(CTR, Log)
    + lpcberemiz_cmd.cmdloop()
    +
    + def ResetwxGlade():
    + # reset pid of running wxGlade
    + config = wx.ConfigBase.Get()
    + wxGladePid = 0
    + config.Write("BeremizRoot.wxGlade", str(wxGladePid))
    + config.Flush()
    +
    + Log = StdoutPseudoFile(port)
    +
    + if projectOpen is not None:
    + projectOpen = DecodeFileSystemPath(projectOpen, False)
    +
    + CTR = LPCProjectController(None, Log, buildpath)
    + if projectOpen is not None and os.path.isdir(projectOpen):
    + result = CTR.LoadProject(projectOpen)
    + if result:
    + Log.write("Error: Invalid project directory", result)
    + else:
    + Log.write("Error: No such file or directory")
    +
    + cmd_thread = Thread(target=CmdThreadProc, args=[CTR, Log])
    + cmd_thread.start()
    +
    + # Install a exception handle for bug reports
    + AddExceptHook(os.getcwd(), __version__)
    +
    + frame = LPCBeremiz(None, ctr=CTR, debug=True)
    +
    + ResetwxGlade()
    +
    + app.MainLoop()
    +
    + except Exception, e:
    + import traceback
    + errmess = traceback.format_exc()
    + print("Traceback: {}\n{}".format(e, errmess))
    +