def build(self): #Build project self.cflags = ["-DPLC_MD5=" + self.calc_md5()] if toolchain_gcc.build(self): #Run objcopy on success self.CTRInstance.logger.write(" [OBJCOPY] " + self.exe + " -> " + self.exe + ".bin\n") #objcpy = [self.toolchain_prefix + "objcopy", "-O", "ihex", self.exe_path, self.exe_path + ".hex"] objcpy = [ self.toolchain_prefix + "objcopy", "-O", "binary", self.exe_path, self.exe_path + ".bin" ] ProcessLogger(self.CTRInstance.logger, objcpy).spin() self.CTRInstance.logger.write("Output size:\n") size = [self.toolchain_prefix + "size", self.exe_path] ProcessLogger(self.CTRInstance.logger, size).spin() return True return False
def StartLocalRuntime(self, taskbaricon=True): if (self.local_runtime is None) or (self.local_runtime.exitcode is not None): # create temporary directory for runtime working directory self.local_runtime_tmpdir = tempfile.mkdtemp() # choose an arbitrary random port for runtime self.runtime_port = int(random.random() * 1000) + 61131 if hasattr(sys, "frozen"): cmdd = "%s \"%s\" -p %s -i localhost %s %s" % ( os.path.join(os.path.dirname(sys.executable), "Python36", "python.exe"), Bpath("Beremiz_service.py"), self.runtime_port, {False: "-x 0", True: "-x 1"}[taskbaricon], self.local_runtime_tmpdir) else: cmdd = "\"%s\" \"%s\" -p %s -i localhost %s %s" % ( sys.executable, Bpath("Beremiz_service.py"), self.runtime_port, {False: "-x 0", True: "-x 1"}[taskbaricon], self.local_runtime_tmpdir) self.local_runtime = ProcessLogger( self.Log, cmdd, no_gui=True, timeout=500, keyword=self.local_runtime_tmpdir, cwd=self.local_runtime_tmpdir) self.local_runtime.spin() self.Log.write(_('Beremiz_service Started.')) return self.runtime_port
async def NewPLC(self, md5sum, data, extrafiles): if self.MatchMD5(md5sum) == False: res = None failure = None await self.HandleSerialTransaction(SETRTCTransaction()) self.confnodesroot.logger.write_warning( _("Will now upload firmware to PLC.\nThis may take some time, don't close the program.\n")) self.TransactionLock.acquire() # Will now boot target res, failure = await self._HandleSerialTransaction(BOOTTransaction(), False) time.sleep(3) # Close connection self.Connection.Close() # bootloader command # data contains full command line except serial port string which is passed to % operator # cmd = data % self.Connection.port cmd = [token % {"serial_port": self.Connection.port} for token in data] # wrapper to run command in separate window cmdhead = [] cmdtail = [] if os.name in ("nt", "ce"): # cmdwrap = "start \"Loading PLC, please wait...\" /wait %s \r" cmdhead.append("cmd") cmdhead.append("/c") cmdhead.append("start") cmdhead.append("Loading PLC, please wait...") cmdhead.append("/wait") else: # cmdwrap = "xterm -e %s \r" cmdhead.append("xterm") cmdhead.append("-e") # Load a program # try: # os.system( cmdwrap % command ) # except Exception,e: # failure = str(e) command = cmdhead + cmd + cmdtail; status, result, err_result = ProcessLogger(self.confnodesroot.logger, command).spin() """ TODO: Process output? """ # Reopen connection self.Connection.Open() self.TransactionLock.release() if failure is not None: self.confnodesroot.logger.write_warning(failure + "\n") return False else: await self.StopPLC() return self.PLCStatus == "Stopped" else: await self.StopPLC() return self.PLCStatus == "Stopped"
def build(self): srcfiles = [] cflags = [] wholesrcdata = "" for Location, CFilesAndCFLAGS, DoCalls in self.CTRInstance.LocationCFilesAndCFLAGS: # Get CFiles list to give it to makefile for CFile, CFLAGS in CFilesAndCFLAGS: CFileName = os.path.basename(CFile) wholesrcdata += self.concat_deps(CFileName) srcfiles.append(CFileName) if CFLAGS not in cflags: cflags.append(CFLAGS) oldmd5 = self.md5key self.md5key = hashlib.md5(wholesrcdata).hexdigest() props = self.CTRInstance.GetProjectProperties() self.md5key += '#'.join([ props[key] for key in ['companyName', 'projectName', 'productName'] ]) self.md5key += '#' #+','.join(map(str,time.localtime())) # Store new PLC filename based on md5 key f = open(self._GetMD5FileName(), "w") f.write(self.md5key) f.close() if oldmd5 != self.md5key: target = self.CTRInstance.GetTarget().getcontent() beremizcommand = { "src": ' '.join(srcfiles), "cflags": ' '.join(cflags), "md5": self.md5key, "buildpath": self.buildpath } command = [ token % beremizcommand for token in target.getCommand().split(' ') ] # Call Makefile to build PLC code and link it with target specific code status, result, err_result = ProcessLogger(self.CTRInstance.logger, command).spin() if status: self.md5key = None self.CTRInstance.logger.write_error( _("C compilation failed.\n")) return False return True else: self.CTRInstance.logger.write( _("Source didn't change, no build.\n")) return True
def getXenoConfig(self, flagsname): """ Get xeno-config from target parameters """ xeno_config = self.CTRInstance.GetTarget().getcontent().getXenoConfig() if xeno_config: from util.ProcessLogger import ProcessLogger status, result, err_result = ProcessLogger(self.CTRInstance.logger, xeno_config + " --skin=native --"+flagsname, no_stdout=True).spin() if status: self.CTRInstance.logger.write_error(_("Unable to get Xenomai's %s \n") % flagsname) return [result.strip()] return []
def StartLocalRuntime(self, taskbaricon=True): if (self.local_runtime is None) or (self.local_runtime.exitcode is not None): # create temporary directory for runtime working directory self.local_runtime_tmpdir = tempfile.mkdtemp() # choose an arbitrary random port for runtime self.runtime_port = int(random.random() * 1000) + 61131 # launch local runtime self.local_runtime = ProcessLogger( self.Log, "\"%s\" \"%s\" -p %s -i localhost %s %s" % (sys.executable, Bpath("Beremiz_service.py"), self.runtime_port, { False: "-x 0", True: "-x 1" }[taskbaricon], self.local_runtime_tmpdir), no_gui=False, timeout=500, keyword=self.local_runtime_tmpdir, cwd=self.local_runtime_tmpdir) self.local_runtime.spin() return self.runtime_port
def build(self): srcfiles = [] cflags = [] wholesrcdata = "" for _Location, CFilesAndCFLAGS, _DoCalls in self.CTRInstance.LocationCFilesAndCFLAGS: # Get CFiles list to give it to makefile for CFile, CFLAGS in CFilesAndCFLAGS: CFileName = os.path.basename(CFile) wholesrcdata += self.concat_deps(CFileName) srcfiles.append(CFileName) if CFLAGS not in cflags: cflags.append(CFLAGS) oldmd5 = self.md5key self.md5key = hashlib.md5(wholesrcdata).hexdigest() # Store new PLC filename based on md5 key f = open(self._GetMD5FileName(), "w", encoding='utf-8') f.write(self.md5key) f.close() if oldmd5 != self.md5key: target = self.CTRInstance.GetTarget().getcontent() beremizcommand = { "src": ' '.join(srcfiles), "cflags": ' '.join(cflags), "md5": self.md5key, "buildpath": self.buildpath } # clean sequence of multiple whitespaces cmd = re.sub(r"[ ]+", " ", target.getCommand().strip()) command = [token % beremizcommand for token in cmd.split(' ')] # Call Makefile to build PLC code and link it with target specific code status, _result, _err_result = ProcessLogger( self.CTRInstance.logger, command).spin() if status: self.md5key = None self.CTRInstance.logger.write_error( _("C compilation failed.\n")) return False return True else: self.CTRInstance.logger.write( _("Source didn't change, no build.\n")) return True
def StartLocalRuntime(self, taskbaricon=True): if (self.local_runtime is None) or (self.local_runtime.exitcode is not None): # create temporary directory for runtime working directory self.local_runtime_tmpdir = tempfile.mkdtemp() # choose an arbitrary random port for runtime self.runtime_port = int(random.random() * 1000) + 61131 # launch local runtime self.local_runtime = ProcessLogger( self.Log, '"%s" "%s" -p %s -i localhost %s %s' % ( sys.executable, Bpath("Beremiz_service.py"), self.runtime_port, {False: "-x 0", True: "-x 1"}[taskbaricon], self.local_runtime_tmpdir, ), no_gui=False, timeout=500, keyword="working", cwd=self.local_runtime_tmpdir, ) self.local_runtime.spin() return self.runtime_port
def build(self): # Retrieve toolchain user parameters toolchain_params = self.CTRInstance.GetTarget().getcontent() self.compiler = toolchain_params.getCompiler() self.linker = toolchain_params.getLinker() Builder_CFLAGS = ' '.join(self.getBuilderCFLAGS()) ######### GENERATE OBJECT FILES ######################################## obns = [] objs = [] relink = self.GetBinaryCode() is None for Location, CFilesAndCFLAGS, DoCalls in self.CTRInstance.LocationCFilesAndCFLAGS: if CFilesAndCFLAGS: if Location: self.CTRInstance.logger.write( ".".join(map(str, Location)) + " :\n") else: self.CTRInstance.logger.write(_("PLC :\n")) for CFile, CFLAGS in CFilesAndCFLAGS: if CFile.endswith(".c"): bn = os.path.basename(CFile) obn = os.path.splitext(bn)[0] + ".o" objectfilename = os.path.splitext(CFile)[0] + ".o" match = self.check_and_update_hash_and_deps(bn) if match: self.CTRInstance.logger.write(" [pass] " + bn + " -> " + obn + "\n") else: relink = True self.CTRInstance.logger.write(" [CC] " + bn + " -> " + obn + "\n") status, result, err_result = ProcessLogger( self.CTRInstance.logger, "\"%s\" -c \"%s\" -o \"%s\" %s %s" % (self.compiler, CFile, objectfilename, Builder_CFLAGS, CFLAGS)).spin() if status: self.srcmd5.pop(bn) self.CTRInstance.logger.write_error( _("C compilation of %s failed.\n") % bn) return False obns.append(obn) objs.append(objectfilename) elif CFile.endswith(".o"): obns.append(os.path.basename(CFile)) objs.append(CFile) ######### GENERATE library FILE ######################################## # Link all the object files into one binary file self.CTRInstance.logger.write(_("Linking :\n")) if relink: objstring = [] # Generate list .o files listobjstring = '"' + '" "'.join(objs) + '"' ALLldflags = ' '.join(self.getBuilderLDFLAGS()) self.CTRInstance.logger.write(" [CC] " + ' '.join(obns) + " -> " + self.exe + "\n") status, result, err_result = ProcessLogger( self.CTRInstance.logger, "\"%s\" %s -o \"%s\" %s" % (self.linker, listobjstring, self.exe_path, ALLldflags)).spin() if status: return False else: self.CTRInstance.logger.write(" [pass] " + ' '.join(obns) + " -> " + self.exe + "\n") # Calculate md5 key and get data for the new created PLC data = self.GetBinaryCode() self.md5key = hashlib.md5(data).hexdigest() # Store new PLC filename based on md5 key f = open(self._GetMD5FileName(), "w") f.write(self.md5key) f.close() return True
class Beremiz(IDEFrame): def _init_utils(self): self.ConfNodeMenu = wx.Menu(title='') self.RecentProjectsMenu = wx.Menu(title='') IDEFrame._init_utils(self) 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') parent.AppendMenu(ID_FILEMENURECENTPROJECTS, _("&Recent Projects"), self.RecentProjectsMenu) 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=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') + '\tCTRL+SHIFT+W') parent.AppendSeparator() AppendMenu(parent, help='', id=wx.ID_PAGE_SETUP, kind=wx.ITEM_NORMAL, text=_(u'Page Setup') + '\tCTRL+ALT+P') AppendMenu(parent, help='', id=wx.ID_PREVIEW, kind=wx.ITEM_NORMAL, text=_(u'Preview') + '\tCTRL+SHIFT+P') AppendMenu(parent, help='', id=wx.ID_PRINT, kind=wx.ITEM_NORMAL, text=_(u'Print') + '\tCTRL+P') 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.OnSaveProjectMenu, id=wx.ID_SAVE) self.Bind(wx.EVT_MENU, self.OnSaveProjectAsMenu, id=wx.ID_SAVEAS) 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.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.OnQuitMenu, id=wx.ID_EXIT) self.AddToMenuToolBar([(wx.ID_NEW, "new", _(u'New'), None), (wx.ID_OPEN, "open", _(u'Open'), None), (wx.ID_SAVE, "save", _(u'Save'), None), (wx.ID_SAVEAS, "saveas", _(u'Save As...'), None), (wx.ID_PRINT, "print", _(u'Print'), None)]) def _RecursiveAddMenuItems(self, menu, items): for name, text, helpstr, children in items: if len(children) > 0: new_menu = wx.Menu(title='') menu.AppendMenu(wx.ID_ANY, text, new_menu) self._RecursiveAddMenuItems(new_menu, children) else: item = menu.Append(wx.ID_ANY, text, helpstr) self.Bind(wx.EVT_MENU, self.GetAddConfNodeFunction(name), item) def _init_coll_AddMenu_Items(self, parent): IDEFrame._init_coll_AddMenu_Items(self, parent, False) self._RecursiveAddMenuItems(parent, GetAddMenuItems()) def _init_coll_HelpMenu_Items(self, parent): def handler(event): return wx.MessageBox(version.GetCommunityHelpMsg(), _(u'Community support'), wx.OK | wx.ICON_INFORMATION) item = parent.Append(wx.ID_ANY, _(u'Community support'), '') self.Bind(wx.EVT_MENU, handler, item) parent.Append(help='', id=wx.ID_ABOUT, kind=wx.ITEM_NORMAL, text=_(u'About')) self.Bind(wx.EVT_MENU, self.OnAboutMenu, id=wx.ID_ABOUT) def _init_coll_ConnectionStatusBar_Fields(self, parent): parent.SetFieldsCount(3) parent.SetStatusText(number=0, text='') parent.SetStatusText(number=1, text='') parent.SetStatusText(number=2, text='') parent.SetStatusWidths([-1, 300, 200]) def _init_ctrls(self, prnt): IDEFrame._init_ctrls(self, prnt) self.EditMenuSize = self.EditMenu.GetMenuItemCount() inspectorID = wx.NewId() self.Bind(wx.EVT_MENU, self.OnOpenWidgetInspector, id=inspectorID) accels = [ wx.AcceleratorEntry(wx.ACCEL_CTRL | wx.ACCEL_ALT, ord('I'), inspectorID) ] for method, shortcut in [("Stop", wx.WXK_F4), ("Run", wx.WXK_F5), ("Transfer", wx.WXK_F6), ("Connect", wx.WXK_F7), ("Build", wx.WXK_F11)]: def OnMethodGen(obj, meth): def OnMethod(evt): if obj.CTR is not None: obj.CTR.CallMethod('_' + meth) wx.CallAfter(self.RefreshStatusToolBar) return OnMethod newid = wx.NewId() self.Bind(wx.EVT_MENU, OnMethodGen(self, method), id=newid) accels += [wx.AcceleratorEntry(wx.ACCEL_NORMAL, shortcut, newid)] self.SetAcceleratorTable(wx.AcceleratorTable(accels)) self.LogConsole = CustomStyledTextCtrl(name='LogConsole', parent=self.BottomNoteBook, pos=wx.Point(0, 0), size=wx.Size(0, 0)) self.LogConsole.Bind(wx.EVT_SET_FOCUS, self.OnLogConsoleFocusChanged) self.LogConsole.Bind(wx.EVT_KILL_FOCUS, self.OnLogConsoleFocusChanged) self.LogConsole.Bind(wx.stc.EVT_STC_UPDATEUI, self.OnLogConsoleUpdateUI) self.LogConsole.SetReadOnly(True) self.LogConsole.SetWrapMode(wx.stc.STC_WRAP_CHAR) # Define Log Console styles self.LogConsole.StyleSetSpec(wx.stc.STC_STYLE_DEFAULT, "face:%(mono)s,size:%(size)d" % faces) self.LogConsole.StyleClearAll() self.LogConsole.StyleSetSpec( 1, "face:%(mono)s,fore:#FF0000,size:%(size)d" % faces) self.LogConsole.StyleSetSpec( 2, "face:%(mono)s,fore:#FF0000,back:#FFFF00,size:%(size)d" % faces) # Define Log Console markers self.LogConsole.SetMarginSensitive(1, True) self.LogConsole.SetMarginType(1, wx.stc.STC_MARGIN_SYMBOL) self.LogConsole.MarkerDefine(0, wx.stc.STC_MARK_CIRCLE, "BLACK", "RED") self.LogConsole.SetModEventMask(wx.stc.STC_MOD_INSERTTEXT) self.LogConsole.Bind(wx.stc.EVT_STC_MARGINCLICK, self.OnLogConsoleMarginClick) self.LogConsole.Bind(wx.stc.EVT_STC_MODIFIED, self.OnLogConsoleModified) self.MainTabs["LogConsole"] = (self.LogConsole, _("Console")) self.BottomNoteBook.AddPage(*self.MainTabs["LogConsole"]) # self.BottomNoteBook.Split(self.BottomNoteBook.GetPageIndex(self.LogConsole), wx.RIGHT) self.LogViewer = LogViewer(self.BottomNoteBook, self) self.MainTabs["LogViewer"] = (self.LogViewer, _("PLC Log")) self.BottomNoteBook.AddPage(*self.MainTabs["LogViewer"]) # self.BottomNoteBook.Split(self.BottomNoteBook.GetPageIndex(self.LogViewer), wx.RIGHT) StatusToolBar = wx.ToolBar(self, -1, wx.DefaultPosition, wx.DefaultSize, wx.TB_FLAT | wx.TB_NODIVIDER | wx.NO_BORDER) StatusToolBar.SetToolBitmapSize(wx.Size(25, 25)) StatusToolBar.Realize() self.Panes["StatusToolBar"] = StatusToolBar self.AUIManager.AddPane( StatusToolBar, wx.aui.AuiPaneInfo().Name("StatusToolBar").Caption( _("Status ToolBar")).ToolbarPane().Top().Position( 1).LeftDockable(False).RightDockable(False)) self.AUIManager.Update() self.ConnectionStatusBar = esb.EnhancedStatusBar(self, style=wx.ST_SIZEGRIP) self._init_coll_ConnectionStatusBar_Fields(self.ConnectionStatusBar) self.ProgressStatusBar = wx.Gauge(self.ConnectionStatusBar, -1, range=100) self.ConnectionStatusBar.AddWidget(self.ProgressStatusBar, esb.ESB_EXACT_FIT, esb.ESB_EXACT_FIT, 2) self.ProgressStatusBar.Hide() self.SetStatusBar(self.ConnectionStatusBar) def __init_execute_path(self): if os.name == 'nt': # on windows, desktop shortcut launches Beremiz.py # with working dir set to mingw/bin. # then we prefix CWD to PATH in order to ensure that # commands invoked by build process by default are # found here. os.environ["PATH"] = os.getcwd() + ';' + os.environ["PATH"] def __init__(self, parent, projectOpen=None, buildpath=None, ctr=None, debug=True): # Add beremiz's icon in top left corner of the frame self.icon = wx.Icon(Bpath("images", "brz.ico"), wx.BITMAP_TYPE_ICO) self.__init_execute_path() IDEFrame.__init__(self, parent, debug) self.Log = LogPseudoFile(self.LogConsole, self.SelectTab) self.local_runtime = None self.runtime_port = None self.local_runtime_tmpdir = None self.LastPanelSelected = None # Define Tree item icon list self.LocationImageList = wx.ImageList(16, 16) self.LocationImageDict = {} # Icons for location items for imgname, itemtype in [("CONFIGURATION", LOCATION_CONFNODE), ("RESOURCE", LOCATION_MODULE), ("PROGRAM", LOCATION_GROUP), ("VAR_INPUT", LOCATION_VAR_INPUT), ("VAR_OUTPUT", LOCATION_VAR_OUTPUT), ("VAR_LOCAL", LOCATION_VAR_MEMORY)]: self.LocationImageDict[itemtype] = self.LocationImageList.Add( GetBitmap(imgname)) # Icons for other items for imgname, itemtype in [("Extension", ITEM_CONFNODE)]: self.TreeImageDict[itemtype] = self.TreeImageList.Add( GetBitmap(imgname)) if projectOpen is not None: projectOpen = DecodeFileSystemPath(projectOpen, False) if projectOpen is not None and os.path.isdir(projectOpen): self.CTR = ProjectController(self, self.Log) self.Controler = self.CTR result, _err = self.CTR.LoadProject(projectOpen, buildpath) if not result: self.LibraryPanel.SetController(self.Controler) self.ProjectTree.Enable(True) self.PouInstanceVariablesPanel.SetController(self.Controler) self.RefreshConfigRecentProjects(os.path.abspath(projectOpen)) self.RefreshAfterLoad() else: self.ResetView() self.ShowErrorMessage(result) else: self.CTR = ctr self.Controler = ctr if ctr is not None: ctr.SetAppFrame(self, self.Log) self.LibraryPanel.SetController(self.Controler) self.ProjectTree.Enable(True) self.PouInstanceVariablesPanel.SetController(self.Controler) self.RefreshAfterLoad() if self.EnableDebug: self.DebugVariablePanel.SetDataProducer(self.CTR) self.Bind(wx.EVT_CLOSE, self.OnCloseFrame) self._Refresh(TITLE, EDITORTOOLBAR, FILEMENU, EDITMENU, DISPLAYMENU) self.RefreshAll() self.LogConsole.SetFocus() def RefreshTitle(self): name = _("Beremiz") if self.CTR is not None: projectname = self.CTR.GetProjectName() if self.CTR.ProjectTestModified(): projectname = "~%s~" % projectname self.SetTitle("%s - %s" % (name, projectname)) else: self.SetTitle(name) def StartLocalRuntime(self, taskbaricon=True): if (self.local_runtime is None) or (self.local_runtime.exitcode is not None): # create temporary directory for runtime working directory self.local_runtime_tmpdir = tempfile.mkdtemp() # choose an arbitrary random port for runtime self.runtime_port = int(random.random() * 1000) + 61131 # launch local runtime self.local_runtime = ProcessLogger( self.Log, "\"%s\" \"%s\" -p %s -i localhost %s %s" % (sys.executable, Bpath("Beremiz_service.py"), self.runtime_port, { False: "-x 0", True: "-x 1" }[taskbaricon], self.local_runtime_tmpdir), no_gui=False, timeout=500, keyword=self.local_runtime_tmpdir, cwd=self.local_runtime_tmpdir) self.local_runtime.spin() return self.runtime_port def KillLocalRuntime(self): if self.local_runtime is not None: # shutdown local runtime self.local_runtime.kill(gently=False) # clear temp dir shutil.rmtree(self.local_runtime_tmpdir) self.local_runtime = None def OnOpenWidgetInspector(self, evt): # Activate the widget inspection tool from wx.lib.inspection import InspectionTool if not InspectionTool().initialized: InspectionTool().Init() # Find a widget to be selected in the tree. Use either the # one under the cursor, if any, or this frame. wnd = wx.FindWindowAtPointer() if not wnd: wnd = self InspectionTool().Show(wnd, True) def OnLogConsoleFocusChanged(self, event): self.RefreshEditMenu() event.Skip() def OnLogConsoleUpdateUI(self, event): self.SetCopyBuffer(self.LogConsole.GetSelectedText(), True) event.Skip() def OnLogConsoleMarginClick(self, event): line_idx = self.LogConsole.LineFromPosition(event.GetPosition()) wx.CallAfter(self.SearchLineForError, self.LogConsole.GetLine(line_idx)) event.Skip() def OnLogConsoleModified(self, event): line_idx = self.LogConsole.LineFromPosition(event.GetPosition()) line = self.LogConsole.GetLine(line_idx) if line: result = MATIEC_ERROR_MODEL.match(line) if result is not None: self.LogConsole.MarkerAdd(line_idx, 0) event.Skip() def SearchLineForError(self, line): if self.CTR is not None: result = MATIEC_ERROR_MODEL.match(line) if result is not None: first_line, first_column, last_line, last_column, _error = result.groups( ) self.CTR.ShowError(self.Log, (int(first_line), int(first_column)), (int(last_line), int(last_column))) def CheckSaveBeforeClosing(self, title=_("Close Project")): """Function displaying an Error dialog in PLCOpenEditor. :returns: False if closing cancelled. """ if self.CTR.ProjectTestModified(): 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.CTR.SaveProject() elif answer == wx.ID_CANCEL: return False for idx in xrange(self.TabsOpened.GetPageCount()): window = self.TabsOpened.GetPage(idx) if not window.CheckSaveBeforeClosing(): return False return True def GetTabInfos(self, tab): if isinstance(tab, EditorPanel) and \ not isinstance(tab, (Viewer, TextViewer, ResourceEditor, ConfigurationEditor, DataTypeEditor)): return ("confnode", tab.Controler.CTNFullName(), tab.GetTagName()) elif (isinstance(tab, TextViewer) and (tab.Controler is None or isinstance(tab.Controler, MiniTextControler))): return ("confnode", None, tab.GetInstancePath()) else: return IDEFrame.GetTabInfos(self, tab) def LoadTab(self, notebook, page_infos): if page_infos[0] == "confnode": if page_infos[1] is None: confnode = self.CTR else: confnode = self.CTR.GetChildByName(page_infos[1]) return notebook.GetPageIndex(confnode._OpenView(*page_infos[2:])) else: return IDEFrame.LoadTab(self, notebook, page_infos) # Strange hack required by WAMP connector, using twisted. # Twisted reactor needs to be stopped only before quit, # since it cannot be restarted ToDoBeforeQuit = [] def AddToDoBeforeQuit(self, Thing): self.ToDoBeforeQuit.append(Thing) def TryCloseFrame(self): if self.CTR is None or self.CheckSaveBeforeClosing( _("Close Application")): if self.CTR is not None: self.CTR.KillDebugThread() self.KillLocalRuntime() self.SaveLastState() for Thing in self.ToDoBeforeQuit: Thing() self.ToDoBeforeQuit = [] return True return False def OnCloseFrame(self, event): if self.TryCloseFrame(): self.LogConsole.Disconnect(-1, -1, wx.wxEVT_KILL_FOCUS) event.Skip() else: # prevent event to continue, i.e. cancel closing event.Veto() def RefreshFileMenu(self): self.RefreshRecentProjectsMenu() MenuToolBar = self.Panes["MenuToolBar"] if self.CTR is not None: selected = self.TabsOpened.GetSelection() if selected >= 0: window = self.TabsOpened.GetPage(selected) viewer_is_modified = window.IsModified() is_viewer = isinstance(window, Viewer) else: viewer_is_modified = is_viewer = False if self.TabsOpened.GetPageCount() > 0: self.FileMenu.Enable(wx.ID_CLOSE, True) if is_viewer: self.FileMenu.Enable(wx.ID_PREVIEW, True) self.FileMenu.Enable(wx.ID_PRINT, True) MenuToolBar.EnableTool(wx.ID_PRINT, True) else: self.FileMenu.Enable(wx.ID_PREVIEW, False) self.FileMenu.Enable(wx.ID_PRINT, False) MenuToolBar.EnableTool(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) MenuToolBar.EnableTool(wx.ID_PRINT, False) self.FileMenu.Enable(wx.ID_PAGE_SETUP, True) project_modified = self.CTR.ProjectTestModified( ) or viewer_is_modified self.FileMenu.Enable(wx.ID_SAVE, project_modified) MenuToolBar.EnableTool(wx.ID_SAVE, project_modified) self.FileMenu.Enable(wx.ID_SAVEAS, True) MenuToolBar.EnableTool(wx.ID_SAVEAS, True) self.FileMenu.Enable(wx.ID_CLOSE_ALL, 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) MenuToolBar.EnableTool(wx.ID_PRINT, False) self.FileMenu.Enable(wx.ID_SAVE, False) MenuToolBar.EnableTool(wx.ID_SAVE, False) self.FileMenu.Enable(wx.ID_SAVEAS, False) MenuToolBar.EnableTool(wx.ID_SAVEAS, False) self.FileMenu.Enable(wx.ID_CLOSE_ALL, False) def RefreshRecentProjectsMenu(self): try: recent_projects = map(DecodeFileSystemPath, self.GetConfigEntry("RecentProjects", [])) except Exception: recent_projects = [] while self.RecentProjectsMenu.GetMenuItemCount() > 0: item = self.RecentProjectsMenu.FindItemByPosition(0) self.RecentProjectsMenu.RemoveItem(item) self.FileMenu.Enable(ID_FILEMENURECENTPROJECTS, len(recent_projects) > 0) for idx, projectpath in enumerate(recent_projects): text = u'&%d: %s' % (idx + 1, projectpath) item = self.RecentProjectsMenu.Append(wx.ID_ANY, text, '') self.Bind(wx.EVT_MENU, self.GenerateOpenRecentProjectFunction(projectpath), item) def GenerateOpenRecentProjectFunction(self, projectpath): def OpenRecentProject(event): if self.CTR is not None and not self.CheckSaveBeforeClosing(): return self.OpenProject(projectpath) return OpenRecentProject def GenerateMenuRecursive(self, items, menu): for kind, infos in items: if isinstance(kind, list): text, id = infos submenu = wx.Menu('') self.GenerateMenuRecursive(kind, submenu) menu.AppendMenu(id, text, submenu) elif kind == wx.ITEM_SEPARATOR: menu.AppendSeparator() else: text, id, _help, callback = infos AppendMenu(menu, help='', id=id, kind=kind, text=text) if callback is not None: self.Bind(wx.EVT_MENU, callback, id=id) def RefreshEditorToolBar(self): IDEFrame.RefreshEditorToolBar(self) self.AUIManager.GetPane("EditorToolBar").Position(2) self.AUIManager.GetPane("StatusToolBar").Position(1) self.AUIManager.Update() def RefreshStatusToolBar(self): StatusToolBar = self.Panes["StatusToolBar"] StatusToolBar.ClearTools() StatusToolBar.SetMinSize(StatusToolBar.GetToolBitmapSize()) if self.CTR is not None: for confnode_method in self.CTR.StatusMethods: if "method" in confnode_method and confnode_method.get( "shown", True): tool = StatusToolBar.AddSimpleTool( wx.ID_ANY, GetBitmap(confnode_method.get("bitmap", "Unknown")), confnode_method["tooltip"]) self.Bind( wx.EVT_MENU, self.GetMenuCallBackFunction( confnode_method["method"]), tool) StatusToolBar.Realize() self.AUIManager.GetPane("StatusToolBar").BestSize( StatusToolBar.GetBestSize()).Show() else: self.AUIManager.GetPane("StatusToolBar").Hide() self.AUIManager.GetPane("EditorToolBar").Position(2) self.AUIManager.GetPane("StatusToolBar").Position(1) self.AUIManager.Update() def RefreshEditMenu(self): IDEFrame.RefreshEditMenu(self) if self.FindFocus() == self.LogConsole: self.EditMenu.Enable(wx.ID_COPY, True) self.Panes["MenuToolBar"].EnableTool(wx.ID_COPY, True) if self.CTR is not None: selected = self.TabsOpened.GetSelection() if selected >= 0: panel = self.TabsOpened.GetPage(selected) else: panel = None if panel != self.LastPanelSelected: for i in xrange(self.EditMenuSize, self.EditMenu.GetMenuItemCount()): item = self.EditMenu.FindItemByPosition(self.EditMenuSize) if item is not None: if item.IsSeparator(): self.EditMenu.RemoveItem(item) else: self.EditMenu.Delete(item.GetId()) self.LastPanelSelected = panel if panel is not None: items = panel.GetConfNodeMenuItems() else: items = [] if len(items) > 0: self.EditMenu.AppendSeparator() self.GenerateMenuRecursive(items, self.EditMenu) if panel is not None: panel.RefreshConfNodeMenu(self.EditMenu) else: for i in xrange(self.EditMenuSize, self.EditMenu.GetMenuItemCount()): item = self.EditMenu.FindItemByPosition(i) if item is not None: if item.IsSeparator(): self.EditMenu.RemoveItem(item) else: self.EditMenu.Delete(item.GetId()) self.LastPanelSelected = None self.MenuBar.UpdateMenus() def RefreshAll(self): self.RefreshStatusToolBar() def GetMenuCallBackFunction(self, method): """ Generate the callbackfunc for a given CTR method""" def OnMenu(event): # Disable button to prevent re-entrant call event.GetEventObject().Disable() # Call getattr(self.CTR, method)() # Re-enable button event.GetEventObject().Enable() return OnMenu def GetConfigEntry(self, entry_name, default): return cPickle.loads( str(self.Config.Read(entry_name, cPickle.dumps(default)))) def ResetConnectionStatusBar(self): for field in xrange(self.ConnectionStatusBar.GetFieldsCount()): self.ConnectionStatusBar.SetStatusText('', field) def ResetView(self): IDEFrame.ResetView(self) if self.CTR is not None: self.CTR.CloseProject() self.CTR = None self.Log.flush() if self.EnableDebug: self.DebugVariablePanel.SetDataProducer(None) self.ResetConnectionStatusBar() def RefreshConfigRecentProjects(self, projectpath, err=False): try: recent_projects = map(DecodeFileSystemPath, self.GetConfigEntry("RecentProjects", [])) except Exception: recent_projects = [] if projectpath in recent_projects: recent_projects.remove(projectpath) if not err: recent_projects.insert(0, projectpath) self.Config.Write( "RecentProjects", cPickle.dumps( map(EncodeFileSystemPath, recent_projects[:MAX_RECENT_PROJECTS]))) self.Config.Flush() def ResetPerspective(self): IDEFrame.ResetPerspective(self) self.RefreshStatusToolBar() def OnNewProjectMenu(self, event): if self.CTR is not None and not self.CheckSaveBeforeClosing(): return try: defaultpath = DecodeFileSystemPath( self.Config.Read("lastopenedfolder")) except Exception: defaultpath = os.path.expanduser("~") dialog = wx.DirDialog(self, _("Choose an empty directory for new project"), defaultpath) if dialog.ShowModal() == wx.ID_OK: projectpath = dialog.GetPath() self.Config.Write( "lastopenedfolder", EncodeFileSystemPath(os.path.dirname(projectpath))) self.Config.Flush() self.ResetView() ctr = ProjectController(self, self.Log) result = ctr.NewProject(projectpath) if not result: self.CTR = ctr self.Controler = self.CTR self.LibraryPanel.SetController(self.Controler) self.ProjectTree.Enable(True) self.PouInstanceVariablesPanel.SetController(self.Controler) self.RefreshConfigRecentProjects(projectpath) if self.EnableDebug: self.DebugVariablePanel.SetDataProducer(self.CTR) self.RefreshAfterLoad() IDEFrame.OnAddNewProject(self, event) else: self.ResetView() self.ShowErrorMessage(result) self.RefreshAll() self._Refresh(TITLE, EDITORTOOLBAR, FILEMENU, EDITMENU) dialog.Destroy() def OnOpenProjectMenu(self, event): if self.CTR is not None and not self.CheckSaveBeforeClosing(): return try: defaultpath = DecodeFileSystemPath( self.Config.Read("lastopenedfolder")) except Exception: defaultpath = os.path.expanduser("~") dialog = wx.DirDialog(self, _("Choose a project"), defaultpath, style=wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER) if dialog.ShowModal() == wx.ID_OK: self.OpenProject(dialog.GetPath()) dialog.Destroy() def OpenProject(self, projectpath): if os.path.isdir(projectpath): self.Config.Write( "lastopenedfolder", EncodeFileSystemPath(os.path.dirname(projectpath))) self.Config.Flush() self.ResetView() self.CTR = ProjectController(self, self.Log) self.Controler = self.CTR result, err = self.CTR.LoadProject(projectpath) if not result: self.LibraryPanel.SetController(self.Controler) self.ProjectTree.Enable(True) self.PouInstanceVariablesPanel.SetController(self.Controler) if self.EnableDebug: self.DebugVariablePanel.SetDataProducer(self.CTR) self.RefreshAfterLoad() else: self.ResetView() self.ShowErrorMessage(result) self.RefreshAll() self.SearchResultPanel.ResetSearchResults() else: self.ShowErrorMessage( _("\"%s\" folder is not a valid Beremiz project\n") % projectpath) err = True self.RefreshConfigRecentProjects(projectpath, err) self._Refresh(TITLE, EDITORTOOLBAR, FILEMENU, EDITMENU) def OnCloseProjectMenu(self, event): if self.CTR is not None and not self.CheckSaveBeforeClosing(): return self.ResetView() self._Refresh(TITLE, EDITORTOOLBAR, FILEMENU, EDITMENU) self.RefreshAll() def RefreshAfterLoad(self): self._Refresh(PROJECTTREE, POUINSTANCEVARIABLESPANEL, LIBRARYTREE) def RefreshAfterSave(self): self.RefreshAll() self._Refresh(TITLE, FILEMENU, EDITMENU, PAGETITLES) def OnSaveProjectMenu(self, event): selected = self.TabsOpened.GetSelection() if selected != -1: window = self.TabsOpened.GetPage(selected) window.Save() if self.CTR is not None: self.CTR.SaveProject() self.RefreshAfterSave() def OnSaveProjectAsMenu(self, event): selected = self.TabsOpened.GetSelection() if selected != -1: window = self.TabsOpened.GetPage(selected) window.SaveAs() if self.CTR is not None: self.CTR.SaveProjectAs() self.RefreshAfterSave() self.RefreshConfigRecentProjects(self.CTR.ProjectPath) def OnQuitMenu(self, event): self.Close() def OnAboutMenu(self, event): info = version.GetAboutDialogInfo() ShowAboutDialog(self, info) def OnProjectTreeItemBeginEdit(self, event): selected = event.GetItem() if self.ProjectTree.GetPyData(selected)["type"] == ITEM_CONFNODE: event.Veto() else: IDEFrame.OnProjectTreeItemBeginEdit(self, event) def OnProjectTreeRightUp(self, event): item = event.GetItem() item_infos = self.ProjectTree.GetPyData(item) if item_infos["type"] == ITEM_CONFNODE: confnode_menu = wx.Menu(title='') confnode = item_infos["confnode"] if confnode is not None: menu_items = confnode.GetContextualMenuItems() if menu_items is not None: for text, helpstr, callback in menu_items: item = confnode_menu.Append(wx.ID_ANY, text, helpstr) self.Bind(wx.EVT_MENU, callback, item) else: for name, XSDClass, helpstr in confnode.CTNChildrenTypes: if not hasattr(XSDClass, 'CTNMaxCount') or not confnode.Children.get(name) \ or len(confnode.Children[name]) < XSDClass.CTNMaxCount: item = confnode_menu.Append( wx.ID_ANY, _("Add") + " " + name, helpstr) self.Bind( wx.EVT_MENU, self.GetAddConfNodeFunction(name, confnode), item) item = confnode_menu.Append(wx.ID_ANY, _("Delete")) self.Bind(wx.EVT_MENU, self.GetDeleteMenuFunction(confnode), item) self.PopupMenu(confnode_menu) confnode_menu.Destroy() event.Skip() elif item_infos["type"] == ITEM_RESOURCE: # prevent last resource to be delted parent = self.ProjectTree.GetItemParent(item) parent_name = self.ProjectTree.GetItemText(parent) if parent_name == _("Resources"): IDEFrame.OnProjectTreeRightUp(self, event) else: IDEFrame.OnProjectTreeRightUp(self, event) def OnProjectTreeItemActivated(self, event): selected = event.GetItem() item_infos = self.ProjectTree.GetPyData(selected) if item_infos["type"] == ITEM_CONFNODE: item_infos["confnode"]._OpenView() event.Skip() elif item_infos["type"] == ITEM_PROJECT: self.CTR._OpenView() else: IDEFrame.OnProjectTreeItemActivated(self, event) def ProjectTreeItemSelect(self, select_item): if select_item is not None and select_item.IsOk(): item_infos = self.ProjectTree.GetPyData(select_item) if item_infos["type"] == ITEM_CONFNODE: item_infos["confnode"]._OpenView(onlyopened=True) elif item_infos["type"] == ITEM_PROJECT: self.CTR._OpenView(onlyopened=True) else: IDEFrame.ProjectTreeItemSelect(self, select_item) def GetProjectElementWindow(self, element, tagname): is_a_CTN_tagname = len(tagname.split("::")) == 1 if is_a_CTN_tagname: confnode = self.CTR.GetChildByName(tagname) return confnode.GetView() else: return IDEFrame.GetProjectElementWindow(self, element, tagname) def SelectProjectTreeItem(self, tagname): if self.ProjectTree is not None: root = self.ProjectTree.GetRootItem() if root.IsOk(): words = tagname.split("::") if len(words) == 1: if tagname == "Project": self.SelectedItem = root self.ProjectTree.SelectItem(root) self.ResetSelectedItem() else: return self.RecursiveProjectTreeItemSelection( root, [(word, ITEM_CONFNODE) for word in tagname.split(".")]) elif words[0] == "R": return self.RecursiveProjectTreeItemSelection( root, [(words[2], ITEM_RESOURCE)]) elif not os.path.exists(words[0]): IDEFrame.SelectProjectTreeItem(self, tagname) def GetAddConfNodeFunction(self, name, confnode=None): def AddConfNodeMenuFunction(event): wx.CallAfter(self.AddConfNode, name, confnode) return AddConfNodeMenuFunction def GetDeleteMenuFunction(self, confnode): def DeleteMenuFunction(event): wx.CallAfter(self.DeleteConfNode, confnode) return DeleteMenuFunction def AddConfNode(self, ConfNodeType, confnode=None): if self.CTR.CheckProjectPathPerm(): ConfNodeName = "%s_0" % ConfNodeType if confnode is not None: confnode.CTNAddChild(ConfNodeName, ConfNodeType) else: self.CTR.CTNAddChild(ConfNodeName, ConfNodeType) self._Refresh(TITLE, FILEMENU, PROJECTTREE) def DeleteConfNode(self, confnode): if self.CTR.CheckProjectPathPerm(): dialog = wx.MessageDialog( self, _("Really delete node '%s'?") % confnode.CTNName(), _("Remove %s node") % confnode.CTNType, wx.YES_NO | wx.NO_DEFAULT) if dialog.ShowModal() == wx.ID_YES: confnode.CTNRemove() del confnode self._Refresh(TITLE, FILEMENU, PROJECTTREE) dialog.Destroy() # ------------------------------------------------------------------------------- # Highlights showing functions # ------------------------------------------------------------------------------- def ShowHighlight(self, infos, start, end, highlight_type): config_name = self.Controler.GetProjectMainConfigurationName() if config_name is not None and infos[0] == ComputeConfigurationName( config_name): self.CTR._OpenView() selected = self.TabsOpened.GetSelection() if selected != -1: viewer = self.TabsOpened.GetPage(selected) viewer.AddHighlight(infos[1:], start, end, highlight_type) else: IDEFrame.ShowHighlight(self, infos, start, end, highlight_type)
async def build(self): res = False gitPath = os.path.join(self.app_path, 'tool', 'Git', 'cmd') os.environ['PATH'] += ';' + gitPath if exists(os.path.join(gitPath, 'git.exe')): self.CTRInstance.logger.write("git path:%s\n" % gitPath) else: self.CTRInstance.logger.write_error("git not found:%s\n" % gitPath) return res old_path = os.getcwd() os.chdir(self.prjpath) try: f = 'src/POUS.cpp' if exists(f): os.remove(f) md5key = self.calc_source_md5() # 生成platformio.ini self.getBoard() appname = self.CTRInstance.GetProject().getcontentHeader() appname = lazy_pinyin(appname['projectName']) appname = ''.join(appname) appname = appname.replace(" ", "") build_flags = self.build_flags + self.CTRInstance.LDFLAGS + [ '-D SWNAME=\\"%s\\"' % appname, '-DPLC_MD5=%s' % md5key ] config = self.CTRInstance.GetTarget().getcontent() attrib = {} optimization = True for key, value in config.attrib.items(): if value == 'false': attrib[key] = False elif value == 'true': attrib[key] = True else: attrib[key] = value if key == 'STATIC': self.static = attrib[key] if key == 'optimization': optimization = attrib[key] libs = self.libs + self.CTRInstance.Libs if self.mode == 'APP' and 'modbus' in libs: libs.remove('modbus') # 检查 # if 'IP' not in attrib: # raise Exception(_("Please input default ip!")) def_dict = { 'LOCAL_PACKAGE': True if appchannel != 'alpha' else False, 'ONLINE_DEBUG': True } def_dict.update(attrib) packages = package_get(self.CTRInstance.logger, def_dict, libs, staticPackage if self.static else [], self.app_path) package_all = package_get(self.CTRInstance.logger, def_dict, libs + self.lib_other, [], self.app_path) platform = self.getPlatform() for att in def_dict: val = def_dict[att] if val: build_flags.append('-D %s' % att) extra = extra_flag.get(att) or [] for e in extra: build_flags.append('-D %s' % e) build_flags = list(set(build_flags)) self.platformio_ini(platform, self.framework, self.board, build_flags, package_prog=packages, package_test=package_all, upload_protocol=self.upload_protocol, options=self.options) # shutil.copy(os.path.join(self.app_path, 'rtconfig.h'), 'src/rtconfig.h') # shutil.copy(os.path.join(self.app_path, 'rtconfig_cm3.h'), 'src/rtconfig_cm3.h') # shutil.copy(os.path.join(self.app_path, 'rtconfig_stm32.h'), 'src/rtconfig_stm32.h') # if not exists('src/spiffs_config.h'): # shutil.copy(os.path.join(self.app_path, 'spiffs_config.h'), 'src/spiffs_config.h') shutil.copy( os.path.join(os.path.dirname(__file__), 'extra_script.py'), 'extra_script.py') # shutil.copy(os.path.join(self.app_path, 'tool', 'makefsdata.exe'), 'makefsdata.exe') # shutil.copy(os.path.join(self.app_path, 'tool', 'msvcr100d.dll'), 'msvcr100d.dll') # 输出buildnumer json_build = 'build.json' if exists(json_build): with open(json_build, 'r', encoding='utf-8') as f: build = json.load(f) build['build'] += 1 # if build.get('platform') != platform: # build['platform'] = platform # self.CTRInstance.logger.write(_("Platform Changed . Clean Project ... \n")) # os.system("runas /user:Administrator rd /s /q src") os.system("rd /s /q .pio") with open(json_build, 'w', encoding='utf-8') as f: json.dump(build, f) else: build = {'build': 1} with open(json_build, 'w', encoding='utf-8') as f: json.dump(build, f) buildnumber_c = "src/buildnumber.c" f = open(buildnumber_c, "w+") f.write("const unsigned short build_number=%d;" % build['build']) f.close() # f = 'src/LOGGER.c' # if exists(f): # os.remove(f) # self.CTRInstance.logger.write(_("update Compiler Env ... \n")) # status, _result, _err_result = ProcessLogger(self.CTRInstance.logger, "pio --version", no_gui=False, ).spin() # status, _result, _err_result = ProcessLogger(self.CTRInstance.logger, "pio update", no_gui=False, ).spin() # status, _result, _err_result = ProcessLogger(self.CTRInstance.logger, "pio lib update", no_gui=False, ).spin() # if status: # self.CTRInstance.logger.write_error(_("update failed.\n")) # os.chdir(old_path) # return False self.CTRInstance.logger.write(_("Compiling ... \n")) cmd = 'pio.exe' application_path = os.path.dirname(sys.executable) pio_paths = [ os.path.join(self.app_path, 'Python36', 'Scripts'), os.path.join(application_path, 'Scripts') ] pio = self.findObject( pio_paths, lambda p: os.path.isfile(os.path.join(p, cmd))) # if hasattr(sys, "frozen"): # cmdd = "%s/Python36/python.exe %s/%s run --disable-auto-clean" % ( # mt.replace('\\', '/'), pio.replace('\\', '/'), cmd) # else: if optimization: cmdd = "%s/%s run --disable-auto-clean" % (pio.replace( '\\', '/'), cmd) else: cmdd = "%s/%s debug --disable-auto-clean" % (pio.replace( '\\', '/'), cmd) cmdd = cmdd.replace('/', '\\') self.CTRInstance.logger.write(cmdd) status, _result, _err_result = ProcessLogger( self.CTRInstance.logger, cmdd, no_gui=True, ).spin() if status: self.CTRInstance.logger.write_error( _("C compilation failed.\n")) os.chdir(old_path) f = open(self._GetMD5FileName(), "w", encoding='utf-8') f.write(md5key) f.close() res = True except Exception as e: print(traceback.format_exc()) self.CTRInstance.logger.write_error(_("C Build failed.\n")) os.chdir(old_path) return res
class Beremiz(IDEFrame): def _init_utils(self): self.ConfNodeMenu = wx.Menu(title="") self.RecentProjectsMenu = wx.Menu(title="") IDEFrame._init_utils(self) 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") parent.AppendMenu(ID_FILEMENURECENTPROJECTS, _("&Recent Projects"), self.RecentProjectsMenu) 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=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") + "\tCTRL+SHIFT+W" ) parent.AppendSeparator() AppendMenu(parent, help="", id=wx.ID_PAGE_SETUP, kind=wx.ITEM_NORMAL, text=_(u"Page Setup") + "\tCTRL+ALT+P") AppendMenu(parent, help="", id=wx.ID_PREVIEW, kind=wx.ITEM_NORMAL, text=_(u"Preview") + "\tCTRL+SHIFT+P") AppendMenu(parent, help="", id=wx.ID_PRINT, kind=wx.ITEM_NORMAL, text=_(u"Print") + "\tCTRL+P") 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.OnSaveProjectMenu, id=wx.ID_SAVE) self.Bind(wx.EVT_MENU, self.OnSaveProjectAsMenu, id=wx.ID_SAVEAS) 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.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.OnQuitMenu, id=wx.ID_EXIT) self.AddToMenuToolBar( [ (wx.ID_NEW, "new", _(u"New"), None), (wx.ID_OPEN, "open", _(u"Open"), None), (wx.ID_SAVE, "save", _(u"Save"), None), (wx.ID_SAVEAS, "saveas", _(u"Save As..."), None), (wx.ID_PRINT, "print", _(u"Print"), None), ] ) def _RecursiveAddMenuItems(self, menu, items): for name, text, help, children in items: new_id = wx.NewId() if len(children) > 0: new_menu = wx.Menu(title="") menu.AppendMenu(new_id, text, new_menu) self._RecursiveAddMenuItems(new_menu, children) else: AppendMenu(menu, help=help, id=new_id, kind=wx.ITEM_NORMAL, text=text) self.Bind(wx.EVT_MENU, self.GetAddConfNodeFunction(name), id=new_id) def _init_coll_AddMenu_Items(self, parent): IDEFrame._init_coll_AddMenu_Items(self, parent, False) self._RecursiveAddMenuItems(parent, GetAddMenuItems()) def _init_coll_HelpMenu_Items(self, parent): parent.Append(help="", id=wx.ID_ABOUT, kind=wx.ITEM_NORMAL, text=_(u"About")) self.Bind(wx.EVT_MENU, self.OnAboutMenu, id=wx.ID_ABOUT) def _init_coll_ConnectionStatusBar_Fields(self, parent): parent.SetFieldsCount(3) parent.SetStatusText(number=0, text="") parent.SetStatusText(number=1, text="") parent.SetStatusText(number=2, text="") parent.SetStatusWidths([-1, 300, 200]) def _init_ctrls(self, prnt): IDEFrame._init_ctrls(self, prnt) self.EditMenuSize = self.EditMenu.GetMenuItemCount() inspectorID = wx.NewId() self.Bind(wx.EVT_MENU, self.OnOpenWidgetInspector, id=inspectorID) accels = [wx.AcceleratorEntry(wx.ACCEL_CTRL | wx.ACCEL_ALT, ord("I"), inspectorID)] for method, shortcut in [ ("Stop", wx.WXK_F4), ("Run", wx.WXK_F5), ("Transfer", wx.WXK_F6), ("Connect", wx.WXK_F7), ("Build", wx.WXK_F11), ]: def OnMethodGen(obj, meth): def OnMethod(evt): if obj.CTR is not None: obj.CTR.CallMethod("_" + meth) wx.CallAfter(self.RefreshStatusToolBar) return OnMethod newid = wx.NewId() self.Bind(wx.EVT_MENU, OnMethodGen(self, method), id=newid) accels += [wx.AcceleratorEntry(wx.ACCEL_NORMAL, shortcut, newid)] self.SetAcceleratorTable(wx.AcceleratorTable(accels)) self.LogConsole = CustomStyledTextCtrl( name="LogConsole", parent=self.BottomNoteBook, pos=wx.Point(0, 0), size=wx.Size(0, 0) ) self.LogConsole.Bind(wx.EVT_SET_FOCUS, self.OnLogConsoleFocusChanged) self.LogConsole.Bind(wx.EVT_KILL_FOCUS, self.OnLogConsoleFocusChanged) self.LogConsole.Bind(wx.stc.EVT_STC_UPDATEUI, self.OnLogConsoleUpdateUI) self.LogConsole.SetReadOnly(True) self.LogConsole.SetWrapMode(wx.stc.STC_WRAP_CHAR) # Define Log Console styles self.LogConsole.StyleSetSpec(wx.stc.STC_STYLE_DEFAULT, "face:%(mono)s,size:%(size)d" % faces) self.LogConsole.StyleClearAll() self.LogConsole.StyleSetSpec(1, "face:%(mono)s,fore:#FF0000,size:%(size)d" % faces) self.LogConsole.StyleSetSpec(2, "face:%(mono)s,fore:#FF0000,back:#FFFF00,size:%(size)d" % faces) # Define Log Console markers self.LogConsole.SetMarginSensitive(1, True) self.LogConsole.SetMarginType(1, wx.stc.STC_MARGIN_SYMBOL) self.LogConsole.MarkerDefine(0, wx.stc.STC_MARK_CIRCLE, "BLACK", "RED") self.LogConsole.SetModEventMask(wx.stc.STC_MOD_INSERTTEXT) self.LogConsole.Bind(wx.stc.EVT_STC_MARGINCLICK, self.OnLogConsoleMarginClick) self.LogConsole.Bind(wx.stc.EVT_STC_MODIFIED, self.OnLogConsoleModified) self.MainTabs["LogConsole"] = (self.LogConsole, _("Console")) self.BottomNoteBook.AddPage(*self.MainTabs["LogConsole"]) # self.BottomNoteBook.Split(self.BottomNoteBook.GetPageIndex(self.LogConsole), wx.RIGHT) self.LogViewer = LogViewer(self.BottomNoteBook, self) self.MainTabs["LogViewer"] = (self.LogViewer, _("PLC Log")) self.BottomNoteBook.AddPage(*self.MainTabs["LogViewer"]) # self.BottomNoteBook.Split(self.BottomNoteBook.GetPageIndex(self.LogViewer), wx.RIGHT) StatusToolBar = wx.ToolBar( self, -1, wx.DefaultPosition, wx.DefaultSize, wx.TB_FLAT | wx.TB_NODIVIDER | wx.NO_BORDER ) StatusToolBar.SetToolBitmapSize(wx.Size(25, 25)) StatusToolBar.Realize() self.Panes["StatusToolBar"] = StatusToolBar self.AUIManager.AddPane( StatusToolBar, wx.aui.AuiPaneInfo() .Name("StatusToolBar") .Caption(_("Status ToolBar")) .ToolbarPane() .Top() .Position(1) .LeftDockable(False) .RightDockable(False), ) self.AUIManager.Update() self.ConnectionStatusBar = wx.StatusBar(self, style=wx.ST_SIZEGRIP) self._init_coll_ConnectionStatusBar_Fields(self.ConnectionStatusBar) self.SetStatusBar(self.ConnectionStatusBar) def __init__(self, parent, projectOpen=None, buildpath=None, ctr=None, debug=True): IDEFrame.__init__(self, parent, debug) self.Log = LogPseudoFile(self.LogConsole, self.SelectTab) self.local_runtime = None self.runtime_port = None self.local_runtime_tmpdir = None self.LastPanelSelected = None # Define Tree item icon list self.LocationImageList = wx.ImageList(16, 16) self.LocationImageDict = {} # Icons for location items for imgname, itemtype in [ ("CONFIGURATION", LOCATION_CONFNODE), ("RESOURCE", LOCATION_MODULE), ("PROGRAM", LOCATION_GROUP), ("VAR_INPUT", LOCATION_VAR_INPUT), ("VAR_OUTPUT", LOCATION_VAR_OUTPUT), ("VAR_LOCAL", LOCATION_VAR_MEMORY), ]: self.LocationImageDict[itemtype] = self.LocationImageList.Add(GetBitmap(imgname)) # Icons for other items for imgname, itemtype in [("Extension", ITEM_CONFNODE)]: self.TreeImageDict[itemtype] = self.TreeImageList.Add(GetBitmap(imgname)) # Add beremiz's icon in top left corner of the frame self.SetIcon(wx.Icon(Bpath("images", "brz.ico"), wx.BITMAP_TYPE_ICO)) if projectOpen is not None: projectOpen = DecodeFileSystemPath(projectOpen, False) if projectOpen is not None and os.path.isdir(projectOpen): self.CTR = ProjectController(self, self.Log) self.Controler = self.CTR result = self.CTR.LoadProject(projectOpen, buildpath) if not result: self.LibraryPanel.SetController(self.Controler) self.ProjectTree.Enable(True) self.PouInstanceVariablesPanel.SetController(self.Controler) self.RefreshConfigRecentProjects(os.path.abspath(projectOpen)) self._Refresh(PROJECTTREE, POUINSTANCEVARIABLESPANEL, LIBRARYTREE) else: self.ResetView() self.ShowErrorMessage(result) else: self.CTR = ctr self.Controler = ctr if ctr is not None: self.LibraryPanel.SetController(self.Controler) self.ProjectTree.Enable(True) self.PouInstanceVariablesPanel.SetController(self.Controler) self._Refresh(PROJECTTREE, POUINSTANCEVARIABLESPANEL, LIBRARYTREE) if self.EnableDebug: self.DebugVariablePanel.SetDataProducer(self.CTR) self.Bind(wx.EVT_CLOSE, self.OnCloseFrame) self._Refresh(TITLE, EDITORTOOLBAR, FILEMENU, EDITMENU, DISPLAYMENU) self.RefreshAll() self.LogConsole.SetFocus() def RefreshTitle(self): name = _("Beremiz") if self.CTR is not None: projectname = self.CTR.GetProjectName() if self.CTR.ProjectTestModified(): projectname = "~%s~" % projectname self.SetTitle("%s - %s" % (name, projectname)) else: self.SetTitle(name) def StartLocalRuntime(self, taskbaricon=True): if (self.local_runtime is None) or (self.local_runtime.exitcode is not None): # create temporary directory for runtime working directory self.local_runtime_tmpdir = tempfile.mkdtemp() # choose an arbitrary random port for runtime self.runtime_port = int(random.random() * 1000) + 61131 # launch local runtime self.local_runtime = ProcessLogger( self.Log, '"%s" "%s" -p %s -i localhost %s %s' % ( sys.executable, Bpath("Beremiz_service.py"), self.runtime_port, {False: "-x 0", True: "-x 1"}[taskbaricon], self.local_runtime_tmpdir, ), no_gui=False, timeout=500, keyword="working", cwd=self.local_runtime_tmpdir, ) self.local_runtime.spin() return self.runtime_port def KillLocalRuntime(self): if self.local_runtime is not None: # shutdown local runtime self.local_runtime.kill(gently=False) # clear temp dir shutil.rmtree(self.local_runtime_tmpdir) self.local_runtime = None def OnOpenWidgetInspector(self, evt): # Activate the widget inspection tool from wx.lib.inspection import InspectionTool if not InspectionTool().initialized: InspectionTool().Init() # Find a widget to be selected in the tree. Use either the # one under the cursor, if any, or this frame. wnd = wx.FindWindowAtPointer() if not wnd: wnd = self InspectionTool().Show(wnd, True) def OnLogConsoleFocusChanged(self, event): self.RefreshEditMenu() event.Skip() def OnLogConsoleUpdateUI(self, event): self.SetCopyBuffer(self.LogConsole.GetSelectedText(), True) event.Skip() def OnLogConsoleMarginClick(self, event): line_idx = self.LogConsole.LineFromPosition(event.GetPosition()) wx.CallAfter(self.SearchLineForError, self.LogConsole.GetLine(line_idx)) event.Skip() def OnLogConsoleModified(self, event): line_idx = self.LogConsole.LineFromPosition(event.GetPosition()) line = self.LogConsole.GetLine(line_idx) if line: result = MATIEC_ERROR_MODEL.match(line) if result is not None: self.LogConsole.MarkerAdd(line_idx, 0) event.Skip() def SearchLineForError(self, line): if self.CTR is not None: result = MATIEC_ERROR_MODEL.match(line) if result is not None: first_line, first_column, last_line, last_column, error = result.groups() infos = self.CTR.ShowError( self.Log, (int(first_line), int(first_column)), (int(last_line), int(last_column)) ) ## Function displaying an Error dialog in PLCOpenEditor. # @return False if closing cancelled. def CheckSaveBeforeClosing(self, title=_("Close Project")): if self.CTR.ProjectTestModified(): 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.CTR.SaveProject() elif answer == wx.ID_CANCEL: return False for idx in xrange(self.TabsOpened.GetPageCount()): window = self.TabsOpened.GetPage(idx) if not window.CheckSaveBeforeClosing(): return False return True def GetTabInfos(self, tab): if isinstance(tab, EditorPanel) and not isinstance( tab, (Viewer, TextViewer, ResourceEditor, ConfigurationEditor, DataTypeEditor) ): return ("confnode", tab.Controler.CTNFullName(), tab.GetTagName()) elif isinstance(tab, TextViewer) and (tab.Controler is None or isinstance(tab.Controler, MiniTextControler)): return ("confnode", None, tab.GetInstancePath()) else: return IDEFrame.GetTabInfos(self, tab) def LoadTab(self, notebook, page_infos): if page_infos[0] == "confnode": if page_infos[1] is None: confnode = self.CTR else: confnode = self.CTR.GetChildByName(page_infos[1]) return notebook.GetPageIndex(confnode._OpenView(*page_infos[2:])) else: return IDEFrame.LoadTab(self, notebook, page_infos) # Strange hack required by WAMP connector, using twisted. # Twisted reactor needs to be stopped only before quit, # since it cannot be restarted ToDoBeforeQuit = [] def AddToDoBeforeQuit(self, Thing): self.ToDoBeforeQuit.append(Thing) def OnCloseFrame(self, event): for evt_type in [wx.EVT_SET_FOCUS, wx.EVT_KILL_FOCUS, wx.stc.EVT_STC_UPDATEUI]: self.LogConsole.Unbind(evt_type) if self.CTR is None or self.CheckSaveBeforeClosing(_("Close Application")): if self.CTR is not None: self.CTR.KillDebugThread() self.KillLocalRuntime() self.SaveLastState() for Thing in self.ToDoBeforeQuit: Thing() self.ToDoBeforeQuit = [] event.Skip() else: event.Veto() def RefreshFileMenu(self): self.RefreshRecentProjectsMenu() MenuToolBar = self.Panes["MenuToolBar"] if self.CTR is not None: selected = self.TabsOpened.GetSelection() if selected >= 0: window = self.TabsOpened.GetPage(selected) viewer_is_modified = window.IsModified() is_viewer = isinstance(window, Viewer) else: viewer_is_modified = is_viewer = False if self.TabsOpened.GetPageCount() > 0: self.FileMenu.Enable(wx.ID_CLOSE, True) if is_viewer: self.FileMenu.Enable(wx.ID_PREVIEW, True) self.FileMenu.Enable(wx.ID_PRINT, True) MenuToolBar.EnableTool(wx.ID_PRINT, True) else: self.FileMenu.Enable(wx.ID_PREVIEW, False) self.FileMenu.Enable(wx.ID_PRINT, False) MenuToolBar.EnableTool(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) MenuToolBar.EnableTool(wx.ID_PRINT, False) self.FileMenu.Enable(wx.ID_PAGE_SETUP, True) project_modified = self.CTR.ProjectTestModified() or viewer_is_modified self.FileMenu.Enable(wx.ID_SAVE, project_modified) MenuToolBar.EnableTool(wx.ID_SAVE, project_modified) self.FileMenu.Enable(wx.ID_SAVEAS, True) MenuToolBar.EnableTool(wx.ID_SAVEAS, True) self.FileMenu.Enable(wx.ID_CLOSE_ALL, 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) MenuToolBar.EnableTool(wx.ID_PRINT, False) self.FileMenu.Enable(wx.ID_SAVE, False) MenuToolBar.EnableTool(wx.ID_SAVE, False) self.FileMenu.Enable(wx.ID_SAVEAS, False) MenuToolBar.EnableTool(wx.ID_SAVEAS, False) self.FileMenu.Enable(wx.ID_CLOSE_ALL, False) def RefreshRecentProjectsMenu(self): try: recent_projects = map(DecodeFileSystemPath, self.GetConfigEntry("RecentProjects", [])) except: recent_projects = [] self.FileMenu.Enable(ID_FILEMENURECENTPROJECTS, len(recent_projects) > 0) for idx, projectpath in enumerate(recent_projects): text = u"%d: %s" % (idx + 1, projectpath) if idx < self.RecentProjectsMenu.GetMenuItemCount(): item = self.RecentProjectsMenu.FindItemByPosition(idx) id = item.GetId() item.SetItemLabel(text) self.Disconnect(id, id, wx.EVT_BUTTON._getEvtType()) else: id = wx.NewId() AppendMenu(self.RecentProjectsMenu, help="", id=id, kind=wx.ITEM_NORMAL, text=text) self.Bind(wx.EVT_MENU, self.GenerateOpenRecentProjectFunction(projectpath), id=id) def GenerateOpenRecentProjectFunction(self, projectpath): def OpenRecentProject(event): if self.CTR is not None and not self.CheckSaveBeforeClosing(): return self.OpenProject(projectpath) return OpenRecentProject def GenerateMenuRecursive(self, items, menu): for kind, infos in items: if isinstance(kind, ListType): text, id = infos submenu = wx.Menu("") self.GenerateMenuRecursive(kind, submenu) menu.AppendMenu(id, text, submenu) elif kind == wx.ITEM_SEPARATOR: menu.AppendSeparator() else: text, id, help, callback = infos AppendMenu(menu, help="", id=id, kind=kind, text=text) if callback is not None: self.Bind(wx.EVT_MENU, callback, id=id) def RefreshEditorToolBar(self): IDEFrame.RefreshEditorToolBar(self) self.AUIManager.GetPane("EditorToolBar").Position(2) self.AUIManager.GetPane("StatusToolBar").Position(1) self.AUIManager.Update() def RefreshStatusToolBar(self): StatusToolBar = self.Panes["StatusToolBar"] StatusToolBar.ClearTools() if self.CTR is not None: for confnode_method in self.CTR.StatusMethods: if "method" in confnode_method and confnode_method.get("shown", True): id = wx.NewId() StatusToolBar.AddSimpleTool( id, GetBitmap(confnode_method.get("bitmap", "Unknown")), confnode_method["tooltip"] ) self.Bind(wx.EVT_MENU, self.GetMenuCallBackFunction(confnode_method["method"]), id=id) StatusToolBar.Realize() self.AUIManager.GetPane("StatusToolBar").BestSize(StatusToolBar.GetBestSize()).Show() else: self.AUIManager.GetPane("StatusToolBar").Hide() self.AUIManager.GetPane("EditorToolBar").Position(2) self.AUIManager.GetPane("StatusToolBar").Position(1) self.AUIManager.Update() def RefreshEditMenu(self): IDEFrame.RefreshEditMenu(self) if self.FindFocus() == self.LogConsole: self.EditMenu.Enable(wx.ID_COPY, True) self.Panes["MenuToolBar"].EnableTool(wx.ID_COPY, True) if self.CTR is not None: selected = self.TabsOpened.GetSelection() if selected >= 0: panel = self.TabsOpened.GetPage(selected) else: panel = None if panel != self.LastPanelSelected: for i in xrange(self.EditMenuSize, self.EditMenu.GetMenuItemCount()): item = self.EditMenu.FindItemByPosition(self.EditMenuSize) if item is not None: if item.IsSeparator(): self.EditMenu.RemoveItem(item) else: self.EditMenu.Delete(item.GetId()) self.LastPanelSelected = panel if panel is not None: items = panel.GetConfNodeMenuItems() else: items = [] if len(items) > 0: self.EditMenu.AppendSeparator() self.GenerateMenuRecursive(items, self.EditMenu) if panel is not None: panel.RefreshConfNodeMenu(self.EditMenu) else: for i in xrange(self.EditMenuSize, self.EditMenu.GetMenuItemCount()): item = self.EditMenu.FindItemByPosition(i) if item is not None: if item.IsSeparator(): self.EditMenu.RemoveItem(item) else: self.EditMenu.Delete(item.GetId()) self.LastPanelSelected = None self.MenuBar.UpdateMenus() def RefreshAll(self): self.RefreshStatusToolBar() def GetMenuCallBackFunction(self, method): """ Generate the callbackfunc for a given CTR method""" def OnMenu(event): # Disable button to prevent re-entrant call event.GetEventObject().Disable() # Call getattr(self.CTR, method)() # Re-enable button event.GetEventObject().Enable() return OnMenu def GetConfigEntry(self, entry_name, default): return cPickle.loads(str(self.Config.Read(entry_name, cPickle.dumps(default)))) def ResetConnectionStatusBar(self): for field in xrange(self.ConnectionStatusBar.GetFieldsCount()): self.ConnectionStatusBar.SetStatusText("", field) def ResetView(self): IDEFrame.ResetView(self) self.ConfNodeInfos = {} if self.CTR is not None: self.CTR.CloseProject() self.CTR = None self.Log.flush() if self.EnableDebug: self.DebugVariablePanel.SetDataProducer(None) self.ResetConnectionStatusBar() def RefreshConfigRecentProjects(self, projectpath): try: recent_projects = map(DecodeFileSystemPath, self.GetConfigEntry("RecentProjects", [])) except: recent_projects = [] if projectpath in recent_projects: recent_projects.remove(projectpath) recent_projects.insert(0, projectpath) self.Config.Write( "RecentProjects", cPickle.dumps(map(EncodeFileSystemPath, recent_projects[:MAX_RECENT_PROJECTS])) ) self.Config.Flush() def ResetPerspective(self): IDEFrame.ResetPerspective(self) self.RefreshStatusToolBar() def OnNewProjectMenu(self, event): if self.CTR is not None and not self.CheckSaveBeforeClosing(): return try: defaultpath = DecodeFileSystemPath(self.Config.Read("lastopenedfolder")) except: defaultpath = os.path.expanduser("~") dialog = wx.DirDialog(self, _("Choose a project"), defaultpath) if dialog.ShowModal() == wx.ID_OK: projectpath = dialog.GetPath() self.Config.Write("lastopenedfolder", EncodeFileSystemPath(os.path.dirname(projectpath))) self.Config.Flush() self.ResetView() ctr = ProjectController(self, self.Log) result = ctr.NewProject(projectpath) if not result: self.CTR = ctr self.Controler = self.CTR self.LibraryPanel.SetController(self.Controler) self.ProjectTree.Enable(True) self.PouInstanceVariablesPanel.SetController(self.Controler) self.RefreshConfigRecentProjects(projectpath) if self.EnableDebug: self.DebugVariablePanel.SetDataProducer(self.CTR) self._Refresh(PROJECTTREE, POUINSTANCEVARIABLESPANEL, LIBRARYTREE) else: self.ResetView() self.ShowErrorMessage(result) self.RefreshAll() self._Refresh(TITLE, EDITORTOOLBAR, FILEMENU, EDITMENU) dialog.Destroy() def OnOpenProjectMenu(self, event): if self.CTR is not None and not self.CheckSaveBeforeClosing(): return try: defaultpath = DecodeFileSystemPath(self.Config.Read("lastopenedfolder")) except: defaultpath = os.path.expanduser("~") dialog = wx.DirDialog( self, _("Choose a project"), defaultpath, style=wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER ) if dialog.ShowModal() == wx.ID_OK: self.OpenProject(dialog.GetPath()) dialog.Destroy() def OpenProject(self, projectpath): if os.path.isdir(projectpath): self.Config.Write("lastopenedfolder", EncodeFileSystemPath(os.path.dirname(projectpath))) self.Config.Flush() self.ResetView() self.CTR = ProjectController(self, self.Log) self.Controler = self.CTR result = self.CTR.LoadProject(projectpath) if not result: self.LibraryPanel.SetController(self.Controler) self.ProjectTree.Enable(True) self.PouInstanceVariablesPanel.SetController(self.Controler) self.RefreshConfigRecentProjects(projectpath) if self.EnableDebug: self.DebugVariablePanel.SetDataProducer(self.CTR) self._Refresh(PROJECTTREE, POUINSTANCEVARIABLESPANEL, LIBRARYTREE) else: self.ResetView() self.ShowErrorMessage(result) self.RefreshAll() else: self.ShowErrorMessage(_('"%s" folder is not a valid Beremiz project\n') % projectpath) self._Refresh(TITLE, EDITORTOOLBAR, FILEMENU, EDITMENU) def OnCloseProjectMenu(self, event): if self.CTR is not None and not self.CheckSaveBeforeClosing(): return self.ResetView() self._Refresh(TITLE, EDITORTOOLBAR, FILEMENU, EDITMENU) self.RefreshAll() def OnSaveProjectMenu(self, event): selected = self.TabsOpened.GetSelection() if selected != -1: window = self.TabsOpened.GetPage(selected) window.Save() if self.CTR is not None: self.CTR.SaveProject() self.RefreshAll() self._Refresh(TITLE, FILEMENU, EDITMENU, PAGETITLES) def OnSaveProjectAsMenu(self, event): selected = self.TabsOpened.GetSelection() if selected != -1: window = self.TabsOpened.GetPage(selected) window.SaveAs() if self.CTR is not None: self.CTR.SaveProjectAs() self.RefreshAll() self._Refresh(TITLE, FILEMENU, EDITMENU, PAGETITLES) def OnQuitMenu(self, event): self.Close() def OnAboutMenu(self, event): OpenHtmlFrame(self, _("About Beremiz"), Bpath("doc", "about.html"), wx.Size(550, 500)) def OnProjectTreeItemBeginEdit(self, event): selected = event.GetItem() if self.ProjectTree.GetPyData(selected)["type"] == ITEM_CONFNODE: event.Veto() else: IDEFrame.OnProjectTreeItemBeginEdit(self, event) def OnProjectTreeRightUp(self, event): item = event.GetItem() item_infos = self.ProjectTree.GetPyData(item) if item_infos["type"] == ITEM_CONFNODE: confnode_menu = wx.Menu(title="") confnode = item_infos["confnode"] if confnode is not None: menu_items = confnode.GetContextualMenuItems() if menu_items is not None: for text, help, callback in menu_items: new_id = wx.NewId() confnode_menu.Append(help=help, id=new_id, kind=wx.ITEM_NORMAL, text=text) self.Bind(wx.EVT_MENU, callback, id=new_id) else: for name, XSDClass, help in confnode.CTNChildrenTypes: new_id = wx.NewId() confnode_menu.Append(help=help, id=new_id, kind=wx.ITEM_NORMAL, text=_("Add") + " " + name) self.Bind(wx.EVT_MENU, self.GetAddConfNodeFunction(name, confnode), id=new_id) new_id = wx.NewId() AppendMenu(confnode_menu, help="", id=new_id, kind=wx.ITEM_NORMAL, text=_("Delete")) self.Bind(wx.EVT_MENU, self.GetDeleteMenuFunction(confnode), id=new_id) self.PopupMenu(confnode_menu) confnode_menu.Destroy() event.Skip() elif item_infos["type"] == ITEM_RESOURCE: # prevent last resource to be delted parent = self.ProjectTree.GetItemParent(item) parent_name = self.ProjectTree.GetItemText(parent) if parent_name == _("Resources"): IDEFrame.OnProjectTreeRightUp(self, event) else: IDEFrame.OnProjectTreeRightUp(self, event) def OnProjectTreeItemActivated(self, event): selected = event.GetItem() name = self.ProjectTree.GetItemText(selected) item_infos = self.ProjectTree.GetPyData(selected) if item_infos["type"] == ITEM_CONFNODE: item_infos["confnode"]._OpenView() event.Skip() elif item_infos["type"] == ITEM_PROJECT: self.CTR._OpenView() else: IDEFrame.OnProjectTreeItemActivated(self, event) def ProjectTreeItemSelect(self, select_item): if select_item is not None and select_item.IsOk(): name = self.ProjectTree.GetItemText(select_item) item_infos = self.ProjectTree.GetPyData(select_item) if item_infos["type"] == ITEM_CONFNODE: item_infos["confnode"]._OpenView(onlyopened=True) elif item_infos["type"] == ITEM_PROJECT: self.CTR._OpenView(onlyopened=True) else: IDEFrame.ProjectTreeItemSelect(self, select_item) def SelectProjectTreeItem(self, tagname): if self.ProjectTree is not None: root = self.ProjectTree.GetRootItem() if root.IsOk(): words = tagname.split("::") if len(words) == 1: if tagname == "Project": self.SelectedItem = root self.ProjectTree.SelectItem(root) self.ResetSelectedItem() else: return self.RecursiveProjectTreeItemSelection( root, [(word, ITEM_CONFNODE) for word in tagname.split(".")] ) elif words[0] == "R": return self.RecursiveProjectTreeItemSelection(root, [(words[2], ITEM_RESOURCE)]) elif not os.path.exists(words[0]): IDEFrame.SelectProjectTreeItem(self, tagname) def GetAddConfNodeFunction(self, name, confnode=None): def AddConfNodeMenuFunction(event): wx.CallAfter(self.AddConfNode, name, confnode) return AddConfNodeMenuFunction def GetDeleteMenuFunction(self, confnode): def DeleteMenuFunction(event): wx.CallAfter(self.DeleteConfNode, confnode) return DeleteMenuFunction def AddConfNode(self, ConfNodeType, confnode=None): if self.CTR.CheckProjectPathPerm(): ConfNodeName = "%s_0" % ConfNodeType if confnode is not None: confnode.CTNAddChild(ConfNodeName, ConfNodeType) else: self.CTR.CTNAddChild(ConfNodeName, ConfNodeType) self._Refresh(TITLE, FILEMENU, PROJECTTREE) def DeleteConfNode(self, confnode): if self.CTR.CheckProjectPathPerm(): dialog = wx.MessageDialog( self, _("Really delete node '%s'?") % confnode.CTNName(), _("Remove %s node") % confnode.CTNType, wx.YES_NO | wx.NO_DEFAULT, ) if dialog.ShowModal() == wx.ID_YES: confnode.CTNRemove() del confnode self._Refresh(TITLE, FILEMENU, PROJECTTREE) dialog.Destroy() # ------------------------------------------------------------------------------- # Highlights showing functions # ------------------------------------------------------------------------------- def ShowHighlight(self, infos, start, end, highlight_type): config_name = self.Controler.GetProjectMainConfigurationName() if config_name is not None and infos[0] == self.Controler.ComputeConfigurationName(config_name): self.CTR._OpenView() selected = self.TabsOpened.GetSelection() if selected != -1: viewer = self.TabsOpened.GetPage(selected) viewer.AddHighlight(infos[1:], start, end, highlight_type) else: IDEFrame.ShowHighlight(self, infos, start, end, highlight_type)