Пример #1
0
    def __init__(self, parent, projectOpen=None, buildpath=None, ctr=None, debug=True):
        # Add beremiz's icon in top left corner of the frame
        self.parent = parent
        self.icon = wx.Icon(Bpath("images", "brz.ico"), wx.BITMAP_TYPE_ICO)
        self.__init_execute_path()

        IDEFrame.__init__(self, None, 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)

        AsyncBind(wx.EVT_CLOSE, self.OnCloseFrame, self)

        self._Refresh(TITLE, EDITORTOOLBAR, FILEMENU, EDITMENU, DISPLAYMENU)
        self.RefreshAll()
        self.LogConsole.SetFocus()
        loop = get_event_loop()
        self.startWeb(loop)
Пример #2
0
class Beremiz(IDEFrame):
    running = True

    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.AppendSubMenu(self.RecentProjectsMenu, _("&Recent Projects"))
        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.Append(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(
                Beremiz_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(helpString='', id=wx.ID_HELP, kind=wx.ITEM_NORMAL, item=_('help'))
        self.Bind(wx.EVT_MENU, self.OnHelpMenu, id=wx.ID_HELP)
        parent.Append(helpString='', id=wx.ID_ABOUT,
                      kind=wx.ITEM_NORMAL, item=_(u'About'))
        self.Bind(wx.EVT_MENU, self.OnAboutMenu, id=wx.ID_ABOUT)
        if appchannel == 'alpha':
            new_id = wx.NewIdRef()
            parent.Append(helpString='', id=new_id, kind=wx.ITEM_NORMAL, item=_(u'Test'))
            self.Bind(wx.EVT_MENU, self.OnTest, id=new_id)

    def _init_coll_ConnectionStatusBar_Fields(self, parent):
        parent.SetFieldsCount(5)

        parent.SetStatusText(i=0, text='')
        parent.SetStatusText(i=1, text='')
        parent.SetStatusText(i=2, text='')
        parent.SetStatusText(i=3, text='')
        parent.SetStatusText(i=4, text='')

        parent.SetStatusWidths([80, 300, -1, 300, 200])

    def _init_ctrls(self, prnt):
        IDEFrame._init_ctrls(self, prnt)

        self.EditMenuSize = self.EditMenu.GetMenuItemCount()

        inspectorID = wx.NewIdRef()
        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.NewIdRef()
            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)
        # sel = configini().get('Version', 'updateChannel', appchannel)
        # if sel=='alpha':
        #     self.alpha= WebView.New(self)
        #     self.alpha.LoadURL('file://d:/kvpac/dist/index.html')
        #     self.MainTabs["AlphaViewer"] = (self.alpha, _("AlphaViewer"))
        #     self.BottomNoteBook.AddPage(*self.MainTabs["AlphaViewer"])

        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)
        self._init_coll_ConnectionStatusBar_Fields(self.ConnectionStatusBar)
        # self.updateBar = wx.StaticText(self.ConnectionStatusBar, )
        self.btnUpdate = wx.Button(self.ConnectionStatusBar, label=_('update'))
        self.btnUpdate.Bind(wx.EVT_BUTTON, self.execUpdate)
        self.ProgressStatusBar = wx.Gauge(self.ConnectionStatusBar, -1, range=100)
        # self.ConnectionStatusBar.AddWidget(self.updateBar, esb.ESB_EXACT_FIT, esb.ESB_EXACT_FIT, pos=1)
        self.ConnectionStatusBar.AddWidget(self.btnUpdate, esb.ESB_ALIGN_LEFT, esb.ESB_ALIGN_CENTER_VERTICAL, pos=0)
        self.ConnectionStatusBar.AddWidget(self.ProgressStatusBar, esb.ESB_EXACT_FIT, esb.ESB_EXACT_FIT, 2)
        self.ProgressStatusBar.Hide()
        self.btnUpdate.Hide()
        self.SetStatusBar(self.ConnectionStatusBar)
        self.startUpdater(self.mpUpdater)

    def startUpdater(self, mpUpdater):
        queueCmd = aioprocessing.AioQueue()
        queueData = aioprocessing.AioQueue()
        self.updater = aioprocessing.AioProcess(name='updater', target=startcoUpdater, args=(queueCmd, queueData))
        self.updater.start()
        StartCoroutine(mpUpdater(self.updater, queueCmd, queueData), self)
        return queueCmd, queueData

    async def mpUpdater(self, mp, queueCmd, queueData):
        self.updateCmd = queueCmd
        self.queueData = queueData
        while self.running:
            try:
                result = await queueData.coro_get(timeout=1)
                if result['st'] == 'noupdate':
                    self.ConnectionStatusBar.SetStatusText(result['version'], 1)
                    sel = configini().get('Version', 'updateChannel', appchannel)
                    queueCmd.put({'act': 'CheckForUpdates', 'arg': sel})
                elif result['st'] == 'new':
                    self.ConnectionStatusBar.SetStatusText('Found New Version:%s' % result['version'], 1)
                    self.btnUpdate.Show(True)
                elif result['st'] == 'Downing':
                    self.btnUpdate.Show(False)
                    self.ConnectionStatusBar.SetStatusText('Downing %s%%' % result['per'], 1)
                elif result['st'] == 'restart':
                    wx.PostEvent(self, wx.CommandEvent(wx.EVT_MENU.typeId, wx.ID_EXIT))
                    break
                elif result['st'] == 'msg':
                    self.ConnectionStatusBar.SetStatusText(result['msg'], 1)
            except Empty as ex:
                pass
            except CancelledError as ex:
                pass
            except Exception as ex:
                print(ex)
                print(traceback.format_exc())
        queueCmd.put('exit')
        await mp.coro_join()
        logging.info('mpUpdater Quited .')

    def execUpdate(self, event):
        self.updateCmd.put({'act': 'update'})

    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.parent = parent
        self.icon = wx.Icon(Bpath("images", "brz.ico"), wx.BITMAP_TYPE_ICO)
        self.__init_execute_path()

        IDEFrame.__init__(self, None, 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)

        AsyncBind(wx.EVT_CLOSE, self.OnCloseFrame, self)

        self._Refresh(TITLE, EDITORTOOLBAR, FILEMENU, EDITMENU, DISPLAYMENU)
        self.RefreshAll()
        self.LogConsole.SetFocus()
        loop = get_event_loop()
        self.startWeb(loop)

    def startWeb(self, loop):

        self.app = web.Application(loop=loop)
        # GraphQLView.attach(app,schema=schema,graphiql=True)
        gql_view = GraphQLView(schema=schema, graphiql=True, executor=AsyncioExecutor(loop=loop), )
        self.app.router.add_route('GET', '/graphql', gql_view, name='graphql')
        post = self.app.router.add_route('POST', '/graphql', gql_view, name='graphql')
        cors = aiohttp_cors.setup(
            self.app,
            defaults={
                "*": aiohttp_cors.ResourceOptions(
                    allow_credentials=True,
                    expose_headers="*",
                    allow_headers="*",
                )
            }
        )
        cors.add(post)
        self.app.add_routes(routes)
        static = self.app.router.add_static("/", os.path.join(application_path, 'dist'), show_index=True)
        static = self.app.router.add_static("/help", os.path.join(application_path, 'kvpac_beremiz', 'dist'),
                                            show_index=True)
        StartCoroutine(web._run_app(self.app, port=65000), self)

    def __del__(self):
        self.app.shutdown()
        self.app.cleanup()

    def RefreshTitle(self):
        name = oem.title
        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
            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

    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):
        try:
            if self.running:
                self.RefreshEditMenu()
        except Exception as ex:
            print(traceback.print_exc())
        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 self.ChildWindow():
            window = idx
            if window and isinstance(window.Children[0], (Viewer,
                                                          TextViewer,
                                                          ResourceEditor,
                                                          ConfigurationEditor,
                                                          DataTypeEditor)) and not window.Children[
                0].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)

    async def TryCloseFrame(self):
        if self.CTR is None or self.CheckSaveBeforeClosing(_("Close Application")):
            self.running = False
            await self.app.shutdown()
            await self.app.cleanup()
            # self.updateCmd.close()
            # self.queueData.close()
            # self.updater.terminate()
            # self.updater.join()
            # StartCoroutine(self.app.shutdown,self)
            # sleep(1)
            # StartCoroutine(self.app.cleanup,self)
            self.app = None
            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

    async def OnCloseFrame(self, event):
        if await self.TryCloseFrame():
            self.LogConsole.Disconnect(-1, -1, wx.wxEVT_KILL_FOCUS)
            # self.queueData.put('exit')
            # self.Destroy()
            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.ActiveChild
            if selected and isinstance(selected.Children[0], Viewer):
                window = selected.Children[0]
                is_viewer = isinstance(window, Viewer)
                if is_viewer:
                    viewer_is_modified = window.IsModified()
                else:
                    viewer_is_modified = is_viewer = False
            else:
                viewer_is_modified = is_viewer = False
            if len(self.ChildWindow()) > 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:
            txt = self.GetConfigEntry("RecentProjects", [])
            recent_projects = list(map(DecodeFileSystemPath, txt))
        except Exception:
            recent_projects = []

        while self.RecentProjectsMenu.GetMenuItemCount() > 0:
            item = self.RecentProjectsMenu.FindItemByPosition(0)
            self.RecentProjectsMenu.Remove(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.Append(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.AddTool(
                        toolId=wx.ID_ANY, bitmap=GetBitmap(confnode_method.get("bitmap", "Unknown")),
                        shortHelp=confnode_method["tooltip"], label=confnode_method["name"])
                    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.ActiveChild
            if selected and isinstance(selected.Children[0], Viewer):
                panel = selected
                window = panel.Children[0]
            else:
                panel = None
            if panel != self.LastPanelSelected:
                for i in range(self.EditMenuSize, self.EditMenu.GetMenuItemCount()):
                    item = self.EditMenu.FindItemByPosition(self.EditMenuSize)
                    if item is not None:
                        if item.IsSeparator():
                            self.EditMenu.Remove(item)
                        else:
                            self.EditMenu.Delete(item.GetId())
                self.LastPanelSelected = panel
                if panel is not None:
                    if not hasattr(window, 'GetConfNodeMenuItems'):
                        print(window)
                    items = window.GetConfNodeMenuItems()
                else:
                    items = []
                if len(items) > 0:
                    self.EditMenu.AppendSeparator()
                    self.GenerateMenuRecursive(items, self.EditMenu)
            if panel is not None:
                window.RefreshConfNodeMenu(self.EditMenu)
        else:
            for i in range(self.EditMenuSize, self.EditMenu.GetMenuItemCount()):
                item = self.EditMenu.FindItemByPosition(i)
                if item is not None:
                    if item.IsSeparator():
                        self.EditMenu.Remove(item)
                    else:
                        self.EditMenu.Delete(item.GetId())
            self.LastPanelSelected = None
        self.MenuBar.Refresh()

    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):
        dv = pickle.dumps(default, 0).decode()
        tt = self.Config.Read(entry_name, dv).encode()
        return pickle.loads(tt)

    def ResetConnectionStatusBar(self):
        for field in range(self.ConnectionStatusBar.GetFieldsCount()):
            if field > 1:  # 更新按钮和版本不清除
                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 = list(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)
        txt = list(map(EncodeFileSystemPath, recent_projects[:MAX_RECENT_PROJECTS]))
        tt = pickle.dumps(txt, 0)
        # tt = str(txt)
        self.Config.Write("RecentProjects", tt)
        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").encode())
        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 Save(self):
        for selected in self.ChildWindow():
            window = selected
            if selected and isinstance(selected.Children[0], (Viewer,
                                                              TextViewer,
                                                              ResourceEditor,
                                                              ConfigurationEditor,
                                                              DataTypeEditor)):
                window.Children[0].Save()

    def OnSaveProjectMenu(self, event):
        for selected in self.ChildWindow():
            window = selected
            if selected and isinstance(selected.Children[0], (Viewer,
                                                              TextViewer,
                                                              ResourceEditor,
                                                              ConfigurationEditor,
                                                              DataTypeEditor)):
                window.Children[0].Save()
        if self.CTR is not None:
            self.CTR.SaveProject()
            self.RefreshAfterSave()

    def OnSaveProjectAsMenu(self, event):
        selected = self.ActiveChild
        if selected and isinstance(selected.Children[0], (Viewer,
                                                          TextViewer,
                                                          ResourceEditor,
                                                          ConfigurationEditor,
                                                          DataTypeEditor)):
            window = selected
            window.Children[0].SaveAs()
        if self.CTR is not None:
            self.CTR.SaveProjectAs()
            self.RefreshAfterSave()
            self.RefreshConfigRecentProjects(self.CTR.ProjectPath)

    def OnQuitMenu(self, event):
        self.Close(True)

    def OnHelpMenu(self, event):
        os.startfile("manual.chm")
        # if not hasattr(self, 'help'):
        #     self.help = Html(self, "帮助")
        #     # self.SetTopWindow(h)
        # self.help.Show()

    def OnAboutMenu(self, event):
        info = Beremiz_version.GetAboutDialogInfo()
        ShowAboutDialog(self, info)

    def OnProjectTreeItemBeginEdit(self, event):
        selected = event.GetItem()
        if self.ProjectTree.GetItemData(selected)["type"] == ITEM_CONFNODE:
            event.Veto()
        else:
            IDEFrame.OnProjectTreeItemBeginEdit(self, event)

    def OnProjectTreeRightUp(self, event):
        item = event.GetItem()
        item_infos = self.ProjectTree.GetItemData(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.GetItemData(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.GetItemData(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 and 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.ActiveChild
            if selected and isinstance(selected.Children[0], Viewer):
                viewer = selected
                viewer.AddHighlight(infos[1:], start, end, highlight_type)
        else:
            IDEFrame.ShowHighlight(self, infos, start, end, highlight_type)

    def OnTest(self, event):
        for id in range(65535):
            if not id in [wx.ID_EXIT, ]:
                wx.PostEvent(self, wx.CommandEvent(wx.EVT_MENU.typeId, id))
        wx.PostEvent(self, wx.CommandEvent(wx.EVT_MENU.typeId, wx.ID_EXIT))

    async def test(self):
        self.OpenProject('d:\\danji_V30_20200530F')
        self.CTR.CallMethod('_Build')
        ConnectorFactory('LOCAL://', self.CTR)
        self.Close()
Пример #3
0
class ProgEditor(wx.Dialog):
    def _init_ctrls(self, parent):
        self.UriTypeChoice = wx.Choice(parent=self, choices=self.choices)
        self.UriTypeChoice.SetSelection(0)
        self.Bind(wx.EVT_CHOICE, self.OnTypeChoice, self.UriTypeChoice)
        self.editor_sizer = wx.BoxSizer(wx.HORIZONTAL)
        self.scheme_editor = None
        self.LogConsole = CustomStyledTextCtrl(name='LogConsole',
                                               parent=self,
                                               size=wx.Size(400, 200))
        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.ButtonSizer = self.CreateButtonSizer(wx.CANCEL)

        self.ButtonFlash = wx.Button(self, -1, 'Flash')
        self.ButtonFlash.Bind(wx.EVT_BUTTON, self.flash)
        self.prgBoot = wx.CheckBox(self, label=_("prog Bootloader"))
        self.prgRte = wx.CheckBox(self, label=_("prog Runtime Firmware"))
        self.prgApp = wx.CheckBox(self, label=_("prog PLC APP"))
        self.prgApp.SetValue(True)
        self.prgBoot.SetValue(True)
        self.prgRte.SetValue(True)

    def _init_sizers(self):
        self.mainSizer = wx.BoxSizer(wx.VERTICAL)
        typeSizer = wx.BoxSizer(wx.HORIZONTAL)
        typeSizer.Add(wx.StaticText(self, wx.ID_ANY, _("Scheme :")),
                      border=5,
                      flag=wx.ALIGN_CENTER_VERTICAL | wx.ALL)
        typeSizer.Add(self.UriTypeChoice, border=5, flag=wx.ALL)
        self.mainSizer.Add(typeSizer)

        optionSizer = wx.BoxSizer(wx.VERTICAL)
        optionSizer.Add(self.prgBoot)
        optionSizer.Add(self.prgRte)
        optionSizer.Add(self.prgApp)
        self.mainSizer.Add(optionSizer, border=5, flag=wx.ALL)

        self.mainSizer.Add(self.editor_sizer, border=5, flag=wx.ALL)
        self.mainSizer.Add(
            self.LogConsole,
            border=5,
            flag=wx.EXPAND | wx.ALL | wx.ALIGN_CENTER_HORIZONTAL,
        )
        buttonSizer = wx.BoxSizer(wx.HORIZONTAL)
        buttonSizer.Add(self.ButtonFlash,
                        border=5,
                        flag=wx.BOTTOM | wx.ALIGN_CENTER_HORIZONTAL)
        buttonSizer.Add(self.ButtonSizer,
                        border=5,
                        flag=wx.BOTTOM | wx.ALIGN_CENTER_HORIZONTAL)
        self.mainSizer.Add(buttonSizer,
                           border=5,
                           flag=wx.ALIGN_CENTER_HORIZONTAL | wx.ALL)
        self.SetSizer(self.mainSizer)
        self.Layout()
        self.Fit()

    def __init__(self, parent, ctr):
        self.ctr = ctr
        prjBase = self.ctr.GetProjectPath()

        wx.Dialog.__init__(self,
                           name='ProgEditor',
                           parent=parent,
                           title=_('Prog with Serial'))
        ports = [
            d.product_name
            for d in ConnectHelper.get_all_connected_probes(blocking=False)
        ] + [d.device for d in list_ports.comports()]

        self.choices = ports + [_('ESP-Link')]
        self._init_ctrls(parent)
        self._init_sizers()
        self.CenterOnParent()
        self.Log = LogPseudoFile(self.LogConsole, self.output)
        # self.Log = LogViewer(self.LogConsole, self)
        # self.LogConsole.SetLogSource(logging)
        self.verify = False
        self.boot = 0
        self.reset = 1
        try:
            prjBase = self.ctr.GetProjectPath()
            app_path = self.ctr.GetIECLibPath()
            progBase = os.path.abspath(os.path.join(
                app_path,
                '../../..',
            ))
            board = self.ctr.GetChildByName('board_0')
            if not board:
                dialog = wx.MessageDialog(
                    parent,
                    _('Can not Found "board_0",Please attach one board.'),
                    style=wx.YES_DEFAULT | wx.CENTRE)
                dialog.ShowModal()
                wx.CallAfter(self.Close)
                return
            node = board.GetBoardFile()
            self.model = node['class'].custom_model or node['class'].model
            self.dev_id = node.get('dev_id', None)
            builder = self.ctr.GetBuilder()
            self.appBin = builder.GetBinaryPath()

            Board = board.BoardRoot.getBoard()[0]
            rte = Board.getFirmware()
            if not rte:
                dialog = wx.MessageDialog(parent,
                                          '未选择使用的RTE固件,请检查board配置.',
                                          style=wx.YES_DEFAULT | wx.CENTRE)
                dialog.ShowModal()
                wx.CallAfter(self.Close)
                return
            model = node['class']
            self.rtes = node.get('class').rtes
            self.rtebin = None
            for x in self.rtes.values():
                if x['name'] == rte:
                    self.rte = x
                    break
            if self.rte.get('bin'):
                self.rtebin = os.path.join(progBase, "firmware",
                                           self.rte.get('bin'))
            self.BlkRte = self.rte.get('blocks')
            self.BlkApp = self.rte.get('app_blocks')
            self.adrRte = self.rte.get('start')
            self.adrApp = self.rte.get('app_start')
            self.BlkBoot = None
            bootloader = self.rte.get('bootloader')
            bootName = None
            self.boot = model.prog_boot
            self.reset = model.prog_reset
            if bootloader:
                self.BlkBoot = bootloader.get('blocks')
                bootName = bootloader.get('bin')
            else:
                self.prgBoot.SetValue(False)
                self.prgBoot.Hide()
            if bootName:
                self.bootbin = os.path.join(progBase, "firmware", bootName)
                if not exists(self.bootbin):
                    dialog = wx.MessageDialog(parent,
                                              _("Cannot Get Boot bin."),
                                              style=wx.YES_DEFAULT | wx.CENTRE)
                    dialog.ShowModal()
                    return
            if self.rtebin and not exists(self.rtebin):
                dialog = wx.MessageDialog(parent,
                                          _("Cannot Get Rte bin."),
                                          style=wx.YES_DEFAULT | wx.CENTRE)
                dialog.ShowModal()
                wx.CallAfter(self.Close)
            if not exists(self.appBin):
                dialog = wx.MessageDialog(
                    parent,
                    _("Cannot Get PLC Firmware.Please Exec Build."),
                    style=wx.YES_DEFAULT | wx.CENTRE)
                dialog.ShowModal()
                wx.CallAfter(self.Close)
            if not self.rtebin:
                self.prgRte.SetValue(False)
                self.prgRte.Hide()
        except Exception as ex:
            print(traceback.print_exc())
            dialog = wx.MessageDialog(parent,
                                      str(ex),
                                      style=wx.YES_DEFAULT | wx.CENTRE)
            dialog.ShowModal()
            wx.CallAfter(self.Close)

    def close(self):
        if self.scheme_editor:
            self.scheme_editor.close()

    def OnTypeChoice(self, event):
        index = event.GetSelection()
        self._replaceSchemeEditor(event.GetString() if index > 0 else None)

    def _replaceSchemeEditor(self, scheme):
        self.scheme = scheme

        if scheme != 'ESP-Link' and self.scheme_editor:
            self.editor_sizer.Detach(self.scheme_editor)
            self.scheme_editor.close()
            self.scheme_editor.Destroy()
            self.scheme_editor = None
        elif scheme == 'ESP-Link' and not self.scheme_editor:
            # None is for searching local network
            self.scheme_editor = DiscoveryPanel(
                self, service_type='_%s._tcp.local.' % self.model)
            self.editor_sizer.Add(self.scheme_editor)
            self.scheme_editor.Refresh()
        self.editor_sizer.Layout()
        self.mainSizer.Layout()
        self.Fit()

    def flash(self, val):
        Serial = self.UriTypeChoice.GetString(
            self.UriTypeChoice.GetSelection())
        self.Log.flush()
        self.Log.write(_('Current Board Model :%s\n') % (self.model))

        if Serial == 'ESP-Link':
            location = self.scheme_editor.GetURI()
            # scheme, location = uri.split("://")
            ip, port = location.split(':')
            threading.Thread(target=self.netFlash, args=[ip],
                             name='netFLash').start()
        elif Serial == 'STM32 STLink':
            threading.Thread(target=self.stlinkFlash, args=[],
                             name="STLink").start()
        else:
            threading.Thread(target=self.serialFlash,
                             args=[Serial, self.boot, self.reset],
                             name='serialFlash').start()

    def netFlash(self, ip):
        self.Log.write(_('Flash PLC use Esp Link :%s\n') % (ip))
        try:
            stm = stm32bl_net(ip, logger=self.Log)
            if self.dev_id and stm._dev_id != self.dev_id:
                self.Log.write_error(_("MCU ID Don't Match!"))
                return
            stm.mass_erase()
            if self.bootbin:
                self.Log.write(_('Flash BootLoader ...'))
                stm.write_file(0x8000000, self.bootbin, verify=self.verify)
            self.Log.write(_('Flash firmware ...'))
            stm.write_file(self.adrApp, self.appBin, verify=self.verify)
            stm.exit_bootloader()
            self.Log.write(_('Flash end.'))
        except SerialException as ex:
            self.Log.write_error(str(ex))
        except Exception as e:
            self.Log.write_error(str(e))
            self.Log.write_error(_('Flash Failed.'))

    def serialFlash(self, com, boot, reset):
        self.Log.write(" Flash PLC use %s\n" % (com))
        try:
            stm = Stm32bl(com, logger=self.Log, Boot=boot, Reset=reset)
            if self.dev_id and stm._dev_id != self.dev_id:
                self.Log.write_error(_("MCU ID Don't Match!"))
                return
            # stm.mass_erase()
            if self.prgBoot.IsChecked():
                self.Log.write(_('Flash BootLoader ...'))
                stm.erase_blocks(self.BlkBoot)
                stm.write_file(0x8000000, self.bootbin, verify=self.verify)
            if self.prgRte.IsChecked():
                self.Log.write(_('Flash RTE firmware ...'))
                stm.erase_blocks(self.BlkRte)
                stm.write_file(self.adrRte, self.rtebin, verify=self.verify)
            if self.prgApp.IsChecked():
                self.Log.write(_('Flash PLC APP ...'))
                if len(self.BlkApp) > 128:
                    stm.erase_blocks(self.BlkApp[0:128])
                    self.BlkApp = self.BlkApp[128:]
                stm.erase_blocks(self.BlkApp)
                stm.write_file(self.adrApp, self.appBin, verify=self.verify)
            stm.exit_bootloader()
            self.Log.write(_('Flash end.'))
        except Exception as e:
            self.Log.write_error(_('Error:%s') % str(e))
            self.Log.write_error(_('Flash Failed.'))

    def stlinkFlash(self):
        self.Log.write(" Flash PLC use STLink\n")
        try:
            with ConnectHelper.session_with_chosen_probe() as session:
                target = session.target
                # todo:stlink read cpu id
                # if self.dev_id and stm._dev_id != self.dev_id:
                #     self.Log.write_error(_("MCU ID Don't Match!"))
                #     return
                if self.prgBoot.IsChecked():
                    self.Log.write(_('Flash BootLoader ...'))
                    with FileProgrammer(session,
                                        chip_erase='auto',
                                        smart_flash=True) as programmer:
                        programmer.program(self.bootbin,
                                           file_format='bin',
                                           base_address=0x8000000)
                if self.prgRte.IsChecked():
                    self.Log.write(_('Flash RTE firmware ...'))
                    with FileProgrammer(session,
                                        chip_erase='auto',
                                        smart_flash=True) as programmer:
                        programmer.program(self.rtebin,
                                           file_format='bin',
                                           base_address=self.adrRte)
                if self.prgApp.IsChecked():
                    self.Log.write(_('Flash PLC APP ...'))
                    with FileProgrammer(session,
                                        chip_erase='auto',
                                        smart_flash=True) as programmer:
                        programmer.program(self.appBin,
                                           file_format='bin',
                                           base_address=self.adrApp)
            self.Log.write(_('Flash end.'))
        except Exception as e:
            self.Log.write_error(_('Error:%s') % str(e))
            self.Log.write_error(_('Flash Failed.'))

    def output(self, txt):
        pass
Пример #4
0
    def __init__(self, parent, ctr):
        self.ctr = ctr
        prjBase = self.ctr.GetProjectPath()

        wx.Dialog.__init__(self,
                           name='ProgEditor',
                           parent=parent,
                           title=_('Prog with Serial'))
        ports = [
            d.product_name
            for d in ConnectHelper.get_all_connected_probes(blocking=False)
        ] + [d.device for d in list_ports.comports()]

        self.choices = ports + [_('ESP-Link')]
        self._init_ctrls(parent)
        self._init_sizers()
        self.CenterOnParent()
        self.Log = LogPseudoFile(self.LogConsole, self.output)
        # self.Log = LogViewer(self.LogConsole, self)
        # self.LogConsole.SetLogSource(logging)
        self.verify = False
        self.boot = 0
        self.reset = 1
        try:
            prjBase = self.ctr.GetProjectPath()
            app_path = self.ctr.GetIECLibPath()
            progBase = os.path.abspath(os.path.join(
                app_path,
                '../../..',
            ))
            board = self.ctr.GetChildByName('board_0')
            if not board:
                dialog = wx.MessageDialog(
                    parent,
                    _('Can not Found "board_0",Please attach one board.'),
                    style=wx.YES_DEFAULT | wx.CENTRE)
                dialog.ShowModal()
                wx.CallAfter(self.Close)
                return
            node = board.GetBoardFile()
            self.model = node['class'].custom_model or node['class'].model
            self.dev_id = node.get('dev_id', None)
            builder = self.ctr.GetBuilder()
            self.appBin = builder.GetBinaryPath()

            Board = board.BoardRoot.getBoard()[0]
            rte = Board.getFirmware()
            if not rte:
                dialog = wx.MessageDialog(parent,
                                          '未选择使用的RTE固件,请检查board配置.',
                                          style=wx.YES_DEFAULT | wx.CENTRE)
                dialog.ShowModal()
                wx.CallAfter(self.Close)
                return
            model = node['class']
            self.rtes = node.get('class').rtes
            self.rtebin = None
            for x in self.rtes.values():
                if x['name'] == rte:
                    self.rte = x
                    break
            if self.rte.get('bin'):
                self.rtebin = os.path.join(progBase, "firmware",
                                           self.rte.get('bin'))
            self.BlkRte = self.rte.get('blocks')
            self.BlkApp = self.rte.get('app_blocks')
            self.adrRte = self.rte.get('start')
            self.adrApp = self.rte.get('app_start')
            self.BlkBoot = None
            bootloader = self.rte.get('bootloader')
            bootName = None
            self.boot = model.prog_boot
            self.reset = model.prog_reset
            if bootloader:
                self.BlkBoot = bootloader.get('blocks')
                bootName = bootloader.get('bin')
            else:
                self.prgBoot.SetValue(False)
                self.prgBoot.Hide()
            if bootName:
                self.bootbin = os.path.join(progBase, "firmware", bootName)
                if not exists(self.bootbin):
                    dialog = wx.MessageDialog(parent,
                                              _("Cannot Get Boot bin."),
                                              style=wx.YES_DEFAULT | wx.CENTRE)
                    dialog.ShowModal()
                    return
            if self.rtebin and not exists(self.rtebin):
                dialog = wx.MessageDialog(parent,
                                          _("Cannot Get Rte bin."),
                                          style=wx.YES_DEFAULT | wx.CENTRE)
                dialog.ShowModal()
                wx.CallAfter(self.Close)
            if not exists(self.appBin):
                dialog = wx.MessageDialog(
                    parent,
                    _("Cannot Get PLC Firmware.Please Exec Build."),
                    style=wx.YES_DEFAULT | wx.CENTRE)
                dialog.ShowModal()
                wx.CallAfter(self.Close)
            if not self.rtebin:
                self.prgRte.SetValue(False)
                self.prgRte.Hide()
        except Exception as ex:
            print(traceback.print_exc())
            dialog = wx.MessageDialog(parent,
                                      str(ex),
                                      style=wx.YES_DEFAULT | wx.CENTRE)
            dialog.ShowModal()
            wx.CallAfter(self.Close)
Пример #5
0
    def __init__(self, parent, ctr):
        wx.Dialog.__init__(self,
                           name='UCopyEditor',
                           parent=parent,
                           title=_('Copy Firmware to UDisk'))
        self.ctr = ctr
        self.choices = []
        self._init_ctrls(parent)
        self._init_sizers()
        self.CenterOnParent()
        self.Log = LogPseudoFile(self.LogConsole, self.output)
        # self.Log = LogViewer(self.LogConsole, self)
        # self.LogConsole.SetLogSource(logging)
        self.verify = False

        # return
        self.CenterOnParent()
        self.tmr = wx.Timer(parent, -1)
        parent.Bind(wx.EVT_TIMER, self.onTmr, self.tmr)
        self.tmr.Start(1000)
        try:
            app_path = self.ctr.GetIECLibPath()
            progBase = os.path.abspath(os.path.join(
                app_path,
                '../../..',
            ))
            board = self.ctr.GetChildByName('board_0')
            if not board:
                dialog = wx.MessageDialog(
                    parent,
                    _('Can not Found "board_0",Please attach one board.'),
                    style=wx.YES_DEFAULT | wx.CENTRE)
                dialog.ShowModal()
                wx.CallAfter(self.Close)
                return
            node = board.GetBoardFile()
            self.model = node['class'].custom_model or node['class'].model
            self.dev_id = node.get('dev_id', None)
            builder = self.ctr.GetBuilder()
            self.appBin = builder.GetBinaryPath()

            Board = board.BoardRoot.getBoard()[0]
            rte = Board.getFirmware()
            if not rte:
                dialog = wx.MessageDialog(parent,
                                          '未选择使用的RTE固件,请检查board配置.',
                                          style=wx.YES_DEFAULT | wx.CENTRE)
                dialog.ShowModal()
                wx.CallAfter(self.Close)
                return
            self.rtes = node.get('class').rtes
            for x in self.rtes.values():
                if x['name'] == rte:
                    self.rte = x
                    break
            self.rtebin = os.path.join(progBase, "firmware",
                                       self.rte.get('bin'))
            self.BlkRte = self.rte.get('blocks')
            self.BlkApp = self.rte.get('app_blocks')
            self.adrRte = self.rte['start']
            self.adrApp = self.rte.get('app_start')
            if not exists(self.rtebin):
                dialog = wx.MessageDialog(parent,
                                          _("Cannot Get Boot bin."),
                                          style=wx.YES_DEFAULT | wx.CENTRE)
                dialog.ShowModal()
                wx.CallAfter(self.Close)
            if not exists(self.appBin):
                dialog = wx.MessageDialog(
                    parent,
                    _("Cannot Get PLC Firmware.Please Exec Build."),
                    style=wx.YES_DEFAULT | wx.CENTRE)
                dialog.ShowModal()
                wx.CallAfter(self.Close)
        except Exception as ex:
            print(traceback.print_exc())
            dialog = wx.MessageDialog(parent,
                                      str(ex),
                                      style=wx.YES_DEFAULT | wx.CENTRE)
            dialog.ShowModal()
            wx.CallAfter(self.Close)
Пример #6
0
class UCopyEditor(wx.Dialog):
    def _init_ctrls(self, parent):
        self.UriTypeChoice = wx.Choice(parent=self,
                                       choices=self.choices,
                                       size=wx.Size(200, 32))
        self.UriTypeChoice.SetSelection(0)
        self.Bind(wx.EVT_CHOICE, self.OnTypeChoice, self.UriTypeChoice)
        self.editor_sizer = wx.BoxSizer(wx.HORIZONTAL)
        self.LogConsole = CustomStyledTextCtrl(name='LogConsole',
                                               parent=self,
                                               size=wx.Size(400, 200))
        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.ButtonSizer = self.CreateButtonSizer(wx.CANCEL)

        self.ButtonFlash = wx.Button(self, -1, _('Copy'))
        self.ButtonFlash.Bind(wx.EVT_BUTTON, self.flash)
        self.prgRte = wx.CheckBox(self, label=_("Copy Runtime Firmware"))
        self.prgApp = wx.CheckBox(self, label=_("Copy PLC APP"))
        self.prgRte.SetValue(True)
        self.prgApp.SetValue(True)

    def _init_sizers(self):
        self.mainSizer = wx.BoxSizer(wx.VERTICAL)
        typeSizer = wx.BoxSizer(wx.HORIZONTAL)
        typeSizer.Add(wx.StaticText(self, wx.ID_ANY, _("disk :")),
                      border=5,
                      flag=wx.ALIGN_CENTER_VERTICAL | wx.ALL)
        typeSizer.Add(self.UriTypeChoice,
                      border=5,
                      flag=wx.ALIGN_CENTER_VERTICAL | wx.EXPAND | wx.ALL)
        self.mainSizer.Add(typeSizer, border=5, flag=wx.EXPAND | wx.ALL)

        optionSizer = wx.BoxSizer(wx.VERTICAL)
        optionSizer.Add(self.prgRte)
        optionSizer.Add(self.prgApp)
        self.mainSizer.Add(optionSizer, border=5, flag=wx.ALL)

        self.mainSizer.Add(self.editor_sizer, border=5, flag=wx.ALL)
        self.mainSizer.Add(
            self.LogConsole,
            border=5,
            flag=wx.EXPAND | wx.ALL | wx.ALIGN_CENTER_HORIZONTAL,
        )
        buttonSizer = wx.BoxSizer(wx.HORIZONTAL)
        buttonSizer.Add(self.ButtonFlash,
                        border=5,
                        flag=wx.BOTTOM | wx.ALIGN_CENTER_HORIZONTAL)
        buttonSizer.Add(self.ButtonSizer,
                        border=5,
                        flag=wx.BOTTOM | wx.ALIGN_CENTER_HORIZONTAL)
        self.mainSizer.Add(buttonSizer,
                           border=5,
                           flag=wx.ALIGN_CENTER_HORIZONTAL | wx.ALL)
        self.SetSizer(self.mainSizer)
        self.Layout()
        self.Fit()

    def __init__(self, parent, ctr):
        wx.Dialog.__init__(self,
                           name='UCopyEditor',
                           parent=parent,
                           title=_('Copy Firmware to UDisk'))
        self.ctr = ctr
        self.choices = []
        self._init_ctrls(parent)
        self._init_sizers()
        self.CenterOnParent()
        self.Log = LogPseudoFile(self.LogConsole, self.output)
        # self.Log = LogViewer(self.LogConsole, self)
        # self.LogConsole.SetLogSource(logging)
        self.verify = False

        # return
        self.CenterOnParent()
        self.tmr = wx.Timer(parent, -1)
        parent.Bind(wx.EVT_TIMER, self.onTmr, self.tmr)
        self.tmr.Start(1000)
        try:
            app_path = self.ctr.GetIECLibPath()
            progBase = os.path.abspath(os.path.join(
                app_path,
                '../../..',
            ))
            board = self.ctr.GetChildByName('board_0')
            if not board:
                dialog = wx.MessageDialog(
                    parent,
                    _('Can not Found "board_0",Please attach one board.'),
                    style=wx.YES_DEFAULT | wx.CENTRE)
                dialog.ShowModal()
                wx.CallAfter(self.Close)
                return
            node = board.GetBoardFile()
            self.model = node['class'].custom_model or node['class'].model
            self.dev_id = node.get('dev_id', None)
            builder = self.ctr.GetBuilder()
            self.appBin = builder.GetBinaryPath()

            Board = board.BoardRoot.getBoard()[0]
            rte = Board.getFirmware()
            if not rte:
                dialog = wx.MessageDialog(parent,
                                          '未选择使用的RTE固件,请检查board配置.',
                                          style=wx.YES_DEFAULT | wx.CENTRE)
                dialog.ShowModal()
                wx.CallAfter(self.Close)
                return
            self.rtes = node.get('class').rtes
            for x in self.rtes.values():
                if x['name'] == rte:
                    self.rte = x
                    break
            self.rtebin = os.path.join(progBase, "firmware",
                                       self.rte.get('bin'))
            self.BlkRte = self.rte.get('blocks')
            self.BlkApp = self.rte.get('app_blocks')
            self.adrRte = self.rte['start']
            self.adrApp = self.rte.get('app_start')
            if not exists(self.rtebin):
                dialog = wx.MessageDialog(parent,
                                          _("Cannot Get Boot bin."),
                                          style=wx.YES_DEFAULT | wx.CENTRE)
                dialog.ShowModal()
                wx.CallAfter(self.Close)
            if not exists(self.appBin):
                dialog = wx.MessageDialog(
                    parent,
                    _("Cannot Get PLC Firmware.Please Exec Build."),
                    style=wx.YES_DEFAULT | wx.CENTRE)
                dialog.ShowModal()
                wx.CallAfter(self.Close)
        except Exception as ex:
            print(traceback.print_exc())
            dialog = wx.MessageDialog(parent,
                                      str(ex),
                                      style=wx.YES_DEFAULT | wx.CENTRE)
            dialog.ShowModal()
            wx.CallAfter(self.Close)

    def onTmr(self, event):
        choices = usbpath()
        if choices != self.choices:
            self.choices = choices
            strList = [x[1] for x in choices]
            self.UriTypeChoice.SetItems(strList)
            if len(choices) == 1:
                self.UriTypeChoice.SetSelection(0)
        if self.UriTypeChoice.GetSelection() >= 0 and (
                self.prgApp.IsChecked() or self.prgRte.IsChecked()):
            self.ButtonFlash.Enable()
        else:
            self.ButtonFlash.Disable()
        event.Skip()

    def OnTypeChoice(self, event):
        index = event.GetSelection()
        self.udrive = self.choices[index]

    def flash(self, event):
        self.Log.flush()
        index = self.UriTypeChoice.GetSelection()
        udisk = self.choices[index][0]
        self.udrive = self.choices[index]
        self.Log.write(_('Copy firmware to UDisk %s') % udisk)
        rte = os.path.join(udisk, 'rte.bin')
        if self.prgRte.IsChecked():
            shutil.copy(self.rtebin, rte)
            self.Log.write('RTE固件已复制.')
        elif exists(rte):
            os.remove(rte)
            self.Log.write('从U盘删除了RTE固件.')

        app = os.path.join(udisk, 'plc.bin')
        if self.prgApp.IsChecked():
            shutil.copy(self.appBin, app)
            self.Log.write('PLC程序已复制.')
        elif exists(app):
            os.remove(app)
            self.Log.write('从U盘删除了PLC程序.')
        self.Log.write('复制完成.')

    def output(self, txt):
        pass