Пример #1
0
class GConsoleWindow(wx.SplitterWindow):
    """Create and manage output console for commands run by GUI."""

    def __init__(
        self,
        parent,
        giface,
        gconsole,
        menuModel=None,
        margin=False,
        style=wx.TAB_TRAVERSAL | wx.FULL_REPAINT_ON_RESIZE,
        gcstyle=GC_EMPTY,
        **kwargs,
    ):
        """
        :param parent: gui parent
        :param gconsole: console logic
        :param menuModel: tree model of modules (from menu)
        :param margin: use margin in output pane (GStc)
        :param style: wx.SplitterWindow style
        :param gcstyle: GConsole style
                        (GC_EMPTY, GC_PROMPT to show command prompt)
        """
        wx.SplitterWindow.__init__(self, parent, id=wx.ID_ANY, style=style, **kwargs)
        self.SetName("GConsole")

        self.panelOutput = wx.Panel(parent=self, id=wx.ID_ANY)
        self.panelProgress = wx.Panel(
            parent=self.panelOutput, id=wx.ID_ANY, name="progressPanel"
        )
        self.panelPrompt = wx.Panel(parent=self, id=wx.ID_ANY)
        # initialize variables
        self.parent = parent  # GMFrame | CmdPanel | ?
        self._gconsole = gconsole
        self._menuModel = menuModel

        self._gcstyle = gcstyle
        self.lineWidth = 80

        # signal which requests showing of a notification
        self.showNotification = Signal("GConsoleWindow.showNotification")
        # signal emitted when text appears in the console
        # parameter 'notification' suggests form of notification (according to
        # core.giface.Notification)
        self.contentChanged = Signal("GConsoleWindow.contentChanged")

        # progress bar
        self.progressbar = wx.Gauge(
            parent=self.panelProgress,
            id=wx.ID_ANY,
            range=100,
            pos=(110, 50),
            size=(-1, 25),
            style=wx.GA_HORIZONTAL,
        )
        self._gconsole.Bind(EVT_CMD_PROGRESS, self.OnCmdProgress)
        self._gconsole.Bind(EVT_CMD_OUTPUT, self.OnCmdOutput)
        self._gconsole.Bind(EVT_CMD_RUN, self.OnCmdRun)
        self._gconsole.Bind(EVT_CMD_DONE, self.OnCmdDone)

        self._gconsole.writeLog.connect(self.WriteLog)
        self._gconsole.writeCmdLog.connect(self.WriteCmdLog)
        self._gconsole.writeWarning.connect(self.WriteWarning)
        self._gconsole.writeError.connect(self.WriteError)

        # text control for command output
        self.cmdOutput = GStc(
            parent=self.panelOutput, id=wx.ID_ANY, margin=margin, wrap=None
        )

        # command prompt
        # move to the if below
        # search depends on cmd prompt
        self.cmdPrompt = GPromptSTC(
            parent=self, giface=giface, menuModel=self._menuModel
        )
        self.cmdPrompt.promptRunCmd.connect(
            lambda cmd: self._gconsole.RunCmd(command=cmd)
        )
        self.cmdPrompt.showNotification.connect(self.showNotification)

        if not self._gcstyle & GC_PROMPT:
            self.cmdPrompt.Hide()

        if self._gcstyle & GC_PROMPT:
            cmdLabel = _("Command prompt")
            self.outputBox = StaticBox(
                parent=self.panelOutput, id=wx.ID_ANY, label=" %s " % _("Output window")
            )

            self.cmdBox = StaticBox(
                parent=self.panelOutput, id=wx.ID_ANY, label=" %s " % cmdLabel
            )

        # buttons
        self.btnOutputClear = ClearButton(parent=self.panelOutput)
        self.btnOutputClear.SetToolTip(_("Clear output window content"))
        self.btnCmdClear = ClearButton(parent=self.panelOutput)
        self.btnCmdClear.SetToolTip(_("Clear command prompt content"))
        self.btnOutputSave = Button(parent=self.panelOutput, id=wx.ID_SAVE)
        self.btnOutputSave.SetToolTip(_("Save output window content to the file"))
        self.btnCmdAbort = Button(parent=self.panelProgress, id=wx.ID_STOP)
        self.btnCmdAbort.SetToolTip(_("Abort running command"))
        self.btnCmdProtocol = ToggleButton(
            parent=self.panelOutput,
            id=wx.ID_ANY,
            label=_("&Log file"),
            size=self.btnCmdClear.GetSize(),
        )
        self.btnCmdProtocol.SetToolTip(
            _(
                "Toggle to save list of executed commands into "
                "a file; content saved when switching off."
            )
        )
        self.cmdFileProtocol = None

        if not self._gcstyle & GC_PROMPT:
            self.btnCmdClear.Hide()
            self.btnCmdProtocol.Hide()

        self.btnCmdClear.Bind(wx.EVT_BUTTON, self.cmdPrompt.OnCmdErase)
        self.btnOutputClear.Bind(wx.EVT_BUTTON, self.OnOutputClear)
        self.btnOutputSave.Bind(wx.EVT_BUTTON, self.OnOutputSave)
        self.btnCmdAbort.Bind(wx.EVT_BUTTON, self._gconsole.OnCmdAbort)
        self.btnCmdProtocol.Bind(wx.EVT_TOGGLEBUTTON, self.OnCmdProtocol)

        self._layout()

    def _layout(self):
        """Do layout"""
        self.outputSizer = wx.BoxSizer(wx.VERTICAL)
        progressSizer = wx.BoxSizer(wx.HORIZONTAL)
        btnSizer = wx.BoxSizer(wx.HORIZONTAL)
        if self._gcstyle & GC_PROMPT:
            outBtnSizer = wx.StaticBoxSizer(self.outputBox, wx.HORIZONTAL)
            cmdBtnSizer = wx.StaticBoxSizer(self.cmdBox, wx.HORIZONTAL)
        else:
            outBtnSizer = wx.BoxSizer(wx.HORIZONTAL)
            cmdBtnSizer = wx.BoxSizer(wx.HORIZONTAL)

        if self._gcstyle & GC_PROMPT:
            promptSizer = wx.BoxSizer(wx.VERTICAL)
            promptSizer.Add(
                self.cmdPrompt,
                proportion=1,
                flag=wx.EXPAND | wx.LEFT | wx.RIGHT | wx.TOP,
                border=3,
            )
            helpText = StaticText(
                self.panelPrompt,
                id=wx.ID_ANY,
                label="Press Tab to display command help, Ctrl+Space to autocomplete",
            )
            helpText.SetForegroundColour(
                wx.SystemSettings.GetColour(wx.SYS_COLOUR_GRAYTEXT)
            )
            promptSizer.Add(helpText, proportion=0, flag=wx.EXPAND | wx.LEFT, border=5)

        self.outputSizer.Add(
            self.cmdOutput, proportion=1, flag=wx.EXPAND | wx.ALL, border=3
        )
        if self._gcstyle & GC_PROMPT:
            proportion = 1
        else:
            proportion = 0
            outBtnSizer.AddStretchSpacer()

        outBtnSizer.Add(
            self.btnOutputClear,
            proportion=proportion,
            flag=wx.ALIGN_LEFT | wx.LEFT | wx.RIGHT | wx.BOTTOM,
            border=5,
        )

        outBtnSizer.Add(
            self.btnOutputSave,
            proportion=proportion,
            flag=wx.RIGHT | wx.BOTTOM,
            border=5,
        )

        cmdBtnSizer.Add(
            self.btnCmdProtocol,
            proportion=1,
            flag=wx.ALIGN_CENTER
            | wx.ALIGN_CENTER_VERTICAL
            | wx.LEFT
            | wx.RIGHT
            | wx.BOTTOM,
            border=5,
        )
        cmdBtnSizer.Add(
            self.btnCmdClear,
            proportion=1,
            flag=wx.ALIGN_CENTER | wx.RIGHT | wx.BOTTOM,
            border=5,
        )
        progressSizer.Add(
            self.btnCmdAbort, proportion=0, flag=wx.ALL | wx.ALIGN_CENTER, border=5
        )
        progressSizer.Add(
            self.progressbar,
            proportion=1,
            flag=wx.ALIGN_CENTER | wx.RIGHT | wx.TOP | wx.BOTTOM,
            border=5,
        )

        self.panelProgress.SetSizer(progressSizer)
        progressSizer.Fit(self.panelProgress)

        btnSizer.Add(outBtnSizer, proportion=1, flag=wx.ALL | wx.ALIGN_CENTER, border=5)
        btnSizer.Add(
            cmdBtnSizer,
            proportion=1,
            flag=wx.ALIGN_CENTER | wx.TOP | wx.BOTTOM | wx.RIGHT,
            border=5,
        )
        self.outputSizer.Add(self.panelProgress, proportion=0, flag=wx.EXPAND)
        self.outputSizer.Add(btnSizer, proportion=0, flag=wx.EXPAND)

        self.outputSizer.Fit(self)
        self.outputSizer.SetSizeHints(self)
        self.panelOutput.SetSizer(self.outputSizer)
        self.outputSizer.FitInside(self.panelOutput)
        if self._gcstyle & GC_PROMPT:
            promptSizer.Fit(self)
            promptSizer.SetSizeHints(self)
            self.panelPrompt.SetSizer(promptSizer)

        # split window
        if self._gcstyle & GC_PROMPT:
            self.SplitHorizontally(self.panelOutput, self.panelPrompt, -50)
        else:
            self.SplitHorizontally(self.panelOutput, self.panelPrompt, -45)
            self.Unsplit()
        self.SetMinimumPaneSize(self.btnCmdClear.GetSize()[1] + 25)

        self.SetSashGravity(1.0)

        self.outputSizer.Hide(self.panelProgress)
        # layout
        self.SetAutoLayout(True)
        self.Layout()

    def GetPanel(self, prompt=True):
        """Get panel

        :param prompt: get prompt / output panel

        :return: wx.Panel reference
        """
        if prompt:
            return self.panelPrompt

        return self.panelOutput

    def WriteLog(
        self, text, style=None, wrap=None, notification=Notification.HIGHLIGHT
    ):
        """Generic method for writing log message in
        given style.

        Emits contentChanged signal.

        :param line: text line
        :param style: text style (see GStc)
        :param stdout: write to stdout or stderr
        :param notification: form of notification
        """

        self.cmdOutput.SetStyle()

        # documenting old behavior/implementation:
        # switch notebook if required
        # now, let user to bind to the old event

        if not style:
            style = self.cmdOutput.StyleDefault

        # p1 = self.cmdOutput.GetCurrentPos()
        p1 = self.cmdOutput.GetEndStyled()
        # self.cmdOutput.GotoPos(p1)
        self.cmdOutput.DocumentEnd()

        for line in text.splitlines():
            # fill space
            if len(line) < self.lineWidth:
                diff = self.lineWidth - len(line)
                line += diff * " "

            self.cmdOutput.AddTextWrapped(line, wrap=wrap)  # adds '\n'

            p2 = self.cmdOutput.GetCurrentPos()

            # between wxWidgets 3.0 and 3.1 they dropped mask param
            try:
                self.cmdOutput.StartStyling(p1)
            except TypeError:
                self.cmdOutput.StartStyling(p1, 0xFF)
            self.cmdOutput.SetStyling(p2 - p1, style)

        self.cmdOutput.EnsureCaretVisible()

        self.contentChanged.emit(notification=notification)

    def WriteCmdLog(self, text, pid=None, notification=Notification.MAKE_VISIBLE):
        """Write message in selected style

        :param text: message to be printed
        :param pid: process pid or None
        :param switchPage: True to switch page
        """
        if pid:
            text = "(" + str(pid) + ") " + text
        self.WriteLog(
            text, style=self.cmdOutput.StyleCommand, notification=notification
        )

    def WriteWarning(self, text):
        """Write message in warning style"""
        self.WriteLog(
            text,
            style=self.cmdOutput.StyleWarning,
            notification=Notification.MAKE_VISIBLE,
        )

    def WriteError(self, text):
        """Write message in error style"""
        self.WriteLog(
            text,
            style=self.cmdOutput.StyleError,
            notification=Notification.MAKE_VISIBLE,
        )

    def OnOutputClear(self, event):
        """Clear content of output window"""
        self.cmdOutput.SetReadOnly(False)
        self.cmdOutput.ClearAll()
        self.cmdOutput.SetReadOnly(True)
        self.progressbar.SetValue(0)

    def GetProgressBar(self):
        """Return progress bar widget"""
        return self.progressbar

    def OnOutputSave(self, event):
        """Save (selected) text from output window to the file"""
        text = self.cmdOutput.GetSelectedText()
        if not text:
            text = self.cmdOutput.GetText()

        # add newline if needed
        if len(text) > 0 and text[-1] != "\n":
            text += "\n"

        dlg = wx.FileDialog(
            self,
            message=_("Save file as..."),
            defaultFile="grass_cmd_output.txt",
            wildcard=_("%(txt)s (*.txt)|*.txt|%(files)s (*)|*")
            % {"txt": _("Text files"), "files": _("Files")},
            style=wx.FD_SAVE | wx.FD_OVERWRITE_PROMPT,
        )

        # Show the dialog and retrieve the user response. If it is the OK response,
        # process the data.
        if dlg.ShowModal() == wx.ID_OK:
            path = dlg.GetPath()

            try:
                output = open(path, "w")
                output.write(text)
            except IOError as e:
                GError(
                    _("Unable to write file '%(path)s'.\n\nDetails: %(error)s")
                    % {"path": path, "error": e}
                )
            finally:
                output.close()
            message = _("Command output saved into '%s'") % path
            self.showNotification.emit(message=message)

        dlg.Destroy()

    def SetCopyingOfSelectedText(self, copy):
        """Enable or disable copying of selected text in to clipboard.
        Effects prompt and output.

        :param bool copy: True for enable, False for disable
        """
        if copy:
            self.cmdPrompt.Bind(
                stc.EVT_STC_PAINTED, self.cmdPrompt.OnTextSelectionChanged
            )
            self.cmdOutput.Bind(
                stc.EVT_STC_PAINTED, self.cmdOutput.OnTextSelectionChanged
            )
        else:
            self.cmdPrompt.Unbind(stc.EVT_STC_PAINTED)
            self.cmdOutput.Unbind(stc.EVT_STC_PAINTED)

    def OnCmdOutput(self, event):
        """Prints command output.

        Emits contentChanged signal.
        """
        message = event.text
        type = event.type

        self.cmdOutput.AddStyledMessage(message, type)

        if event.type in ("warning", "error"):
            self.contentChanged.emit(notification=Notification.MAKE_VISIBLE)
        else:
            self.contentChanged.emit(notification=Notification.HIGHLIGHT)

    def OnCmdProgress(self, event):
        """Update progress message info"""
        self.progressbar.SetValue(event.value)
        event.Skip()

    def CmdProtocolSave(self):
        """Save list of manually entered commands into a text log file"""
        if self.cmdFileProtocol is None:
            return  # it should not happen

        try:
            with open(self.cmdFileProtocol, "a") as output:
                cmds = self.cmdPrompt.GetCommands()
                output.write("\n".join(cmds))
                if len(cmds) > 0:
                    output.write("\n")
        except IOError as e:
            GError(
                _("Unable to write file '{filePath}'.\n\nDetails: {error}").format(
                    filePath=self.cmdFileProtocol, error=e
                )
            )

        self.showNotification.emit(
            message=_("Command log saved to '{}'".format(self.cmdFileProtocol))
        )
        self.cmdFileProtocol = None

    def OnCmdProtocol(self, event=None):
        """Save commands into file"""
        if not event.IsChecked():
            # stop capturing commands, save list of commands to the
            # protocol file
            self.CmdProtocolSave()
        else:
            # start capturing commands
            self.cmdPrompt.ClearCommands()
            # ask for the file
            dlg = wx.FileDialog(
                self,
                message=_("Save file as..."),
                defaultFile="grass_cmd_log.txt",
                wildcard=_("%(txt)s (*.txt)|*.txt|%(files)s (*)|*")
                % {"txt": _("Text files"), "files": _("Files")},
                style=wx.FD_SAVE,
            )
            if dlg.ShowModal() == wx.ID_OK:
                self.cmdFileProtocol = dlg.GetPath()
            else:
                wx.CallAfter(self.btnCmdProtocol.SetValue, False)

            dlg.Destroy()

        event.Skip()

    def OnCmdRun(self, event):
        """Run command"""
        self.outputSizer.Show(self.panelProgress)
        self.outputSizer.Layout()
        event.Skip()

    def OnCmdDone(self, event):
        """Command done (or aborted)"""
        self.progressbar.SetValue(0)  # reset progress bar on '0%'
        wx.CallLater(100, self._hideProgress)
        event.Skip()

    def _hideProgress(self):
        self.outputSizer.Hide(self.panelProgress)
        self.outputSizer.Layout()

    def ResetFocus(self):
        """Reset focus"""
        self.cmdPrompt.SetFocus()

    def GetPrompt(self):
        """Get prompt"""
        return self.cmdPrompt
Пример #2
0
class ModelSearchDialog(wx.Dialog):

    def __init__(self, parent, title=_("Add GRASS command to the model"),
                 style=wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER, **kwargs):
        """Graphical modeler module search window

        :param parent: parent window
        :param id: window id
        :param title: window title
        :param kwargs: wx.Dialogs' arguments
        """
        self.parent = parent

        wx.Dialog.__init__(
            self,
            parent=parent,
            id=wx.ID_ANY,
            title=title,
            **kwargs)
        self.SetName("ModelerDialog")
        self.SetIcon(
            wx.Icon(
                os.path.join(
                    globalvar.ICONDIR,
                    'grass.ico'),
                wx.BITMAP_TYPE_ICO))

        self._command = None
        self.panel = wx.Panel(parent=self, id=wx.ID_ANY)

        self.cmdBox = StaticBox(parent=self.panel, id=wx.ID_ANY,
                                label=" %s " % _("Command"))
        self.labelBox = StaticBox(parent=self.panel, id=wx.ID_ANY,
                                  label=" %s " % _("Label and comment"))

        # menu data for search widget and prompt
        menuModel = LayerManagerMenuData()

        self.cmd_prompt = GPromptSTC(
            parent=self, menuModel=menuModel.GetModel())
        self.cmd_prompt.promptRunCmd.connect(self.OnCommand)
        self.cmd_prompt.commandSelected.connect(
            lambda command: self.label.SetValue(command))
        self.search = SearchModuleWidget(parent=self.panel,
                                         model=menuModel.GetModel(),
                                         showTip=True)
        self.search.moduleSelected.connect(
            lambda name: self.cmd_prompt.SetTextAndFocus(name + ' '))
        wx.CallAfter(self.cmd_prompt.SetFocus)

        self.label = TextCtrl(parent=self.panel, id=wx.ID_ANY)
        self.comment = TextCtrl(
            parent=self.panel,
            id=wx.ID_ANY,
            style=wx.TE_MULTILINE)

        self.btnCancel = Button(self.panel, wx.ID_CANCEL)
        self.btnOk = Button(self.panel, wx.ID_OK)
        self.btnOk.SetDefault()

        self.Bind(wx.EVT_BUTTON, self.OnOk, self.btnOk)
        self.Bind(wx.EVT_BUTTON, self.OnCancel, self.btnCancel)

        self._layout()

        self.SetSize((500, -1))

    def _layout(self):
        cmdSizer = wx.StaticBoxSizer(self.cmdBox, wx.VERTICAL)
        cmdSizer.Add(self.cmd_prompt, proportion=1,
                     flag=wx.EXPAND)
        labelSizer = wx.StaticBoxSizer(self.labelBox, wx.VERTICAL)
        gridSizer = wx.GridBagSizer(hgap=5, vgap=5)
        gridSizer.Add(StaticText(parent=self.panel, id=wx.ID_ANY,
                                 label=_("Label:")),
                      flag=wx.ALIGN_CENTER_VERTICAL, pos=(0, 0))
        gridSizer.Add(self.label, pos=(0, 1), flag=wx.EXPAND)
        gridSizer.Add(StaticText(parent=self.panel, id=wx.ID_ANY,
                                 label=_("Comment:")),
                      flag=wx.ALIGN_CENTER_VERTICAL, pos=(1, 0))
        gridSizer.Add(self.comment, pos=(1, 1), flag=wx.EXPAND)
        gridSizer.AddGrowableRow(1)
        gridSizer.AddGrowableCol(1)
        labelSizer.Add(gridSizer, proportion=1, flag=wx.EXPAND)

        btnSizer = wx.StdDialogButtonSizer()
        btnSizer.AddButton(self.btnCancel)
        btnSizer.AddButton(self.btnOk)
        btnSizer.Realize()

        mainSizer = wx.BoxSizer(wx.VERTICAL)
        mainSizer.Add(self.search, proportion=0,
                      flag=wx.EXPAND | wx.ALL, border=3)
        mainSizer.Add(cmdSizer, proportion=1,
                      flag=wx.EXPAND | wx.LEFT | wx.RIGHT | wx.TOP, border=3)
        mainSizer.Add(labelSizer, proportion=1,
                      flag=wx.EXPAND | wx.LEFT | wx.RIGHT | wx.TOP, border=3)
        mainSizer.Add(btnSizer, proportion=0,
                      flag=wx.EXPAND | wx.ALL | wx.ALIGN_CENTER, border=5)

        self.panel.SetSizer(mainSizer)
        mainSizer.Fit(self)

        self.Layout()

    def GetPanel(self):
        """Get dialog panel"""
        return self.panel

    def _getCmd(self):
        line = self.cmd_prompt.GetCurLine()[0].strip()
        if len(line) == 0:
            cmd = list()
        else:
            try:
                cmd = utils.split(str(line))
            except UnicodeError:
                cmd = utils.split(EncodeString((line)))
        return cmd

    def GetCmd(self):
        """Get command"""
        return self._command

    def GetLabel(self):
        """Get label and comment"""
        return self.label.GetValue(), self.comment.GetValue()

    def ValidateCmd(self, cmd):
        if len(cmd) < 1:
            GError(parent=self,
                   message=_("Command not defined.\n\n"
                             "Unable to add new action to the model."))
            return False

        if cmd[0] not in globalvar.grassCmd:
            GError(
                parent=self, message=_(
                    "'%s' is not a GRASS module.\n\n"
                    "Unable to add new action to the model.") %
                cmd[0])
            return False
        return True

    def OnCommand(self, cmd):
        """Command in prompt confirmed"""
        if self.ValidateCmd(cmd):
            self._command = cmd
            self.EndModal(wx.ID_OK)

    def OnOk(self, event):
        """Button 'OK' pressed"""
        cmd = self._getCmd()
        if self.ValidateCmd(cmd):
            self._command = cmd
            self.EndModal(wx.ID_OK)

    def OnCancel(self, event):
        """Cancel pressed, close window"""
        self.Hide()

    def Reset(self):
        """Reset dialog"""
        self.search.Reset()
        self.label.SetValue('')
        self.comment.SetValue('')
        self.cmd_prompt.OnCmdErase(None)
        self.cmd_prompt.SetFocus()
Пример #3
0
class ModelSearchDialog(wx.Dialog):
    def __init__(self,
                 parent,
                 id=wx.ID_ANY,
                 title=_("Add new GRASS module to the model"),
                 style=wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER,
                 **kwargs):
        """!Graphical modeler module search window
        
        @param parent parent window
        @param id window id
        @param title window title
        @param kwargs wx.Dialogs' arguments
        """
        self.parent = parent

        wx.Dialog.__init__(self, parent=parent, id=id, title=title, **kwargs)
        self.SetName("ModelerDialog")
        self.SetIcon(
            wx.Icon(os.path.join(globalvar.ETCICONDIR, 'grass.ico'),
                    wx.BITMAP_TYPE_ICO))

        self.panel = wx.Panel(parent=self, id=wx.ID_ANY)

        self.cmdBox = wx.StaticBox(parent=self.panel,
                                   id=wx.ID_ANY,
                                   label=" %s " % _("Command"))

        self.cmd_prompt = GPromptSTC(parent=self)
        self.search = SearchModuleWindow(parent=self.panel,
                                         cmdPrompt=self.cmd_prompt,
                                         showTip=True)
        wx.CallAfter(self.cmd_prompt.SetFocus)

        # get commands
        items = self.cmd_prompt.GetCommandItems()

        self.btnCancel = wx.Button(self.panel, wx.ID_CANCEL)
        self.btnOk = wx.Button(self.panel, wx.ID_OK)
        self.btnOk.SetDefault()
        self.btnOk.Enable(False)

        self.cmd_prompt.Bind(wx.EVT_KEY_UP, self.OnText)
        self.search.searchChoice.Bind(wx.EVT_CHOICE, self.OnText)
        self.Bind(wx.EVT_BUTTON, self.OnOk, self.btnOk)
        self.Bind(wx.EVT_BUTTON, self.OnCancel, self.btnCancel)

        self._layout()

        self.SetSize((500, 275))

    def _layout(self):
        cmdSizer = wx.StaticBoxSizer(self.cmdBox, wx.VERTICAL)
        cmdSizer.Add(item=self.cmd_prompt, proportion=1, flag=wx.EXPAND)

        btnSizer = wx.StdDialogButtonSizer()
        btnSizer.AddButton(self.btnCancel)
        btnSizer.AddButton(self.btnOk)
        btnSizer.Realize()

        mainSizer = wx.BoxSizer(wx.VERTICAL)
        mainSizer.Add(item=self.search,
                      proportion=0,
                      flag=wx.EXPAND | wx.ALL,
                      border=3)
        mainSizer.Add(item=cmdSizer,
                      proportion=1,
                      flag=wx.EXPAND | wx.LEFT | wx.RIGHT | wx.TOP,
                      border=3)
        mainSizer.Add(item=btnSizer,
                      proportion=0,
                      flag=wx.EXPAND | wx.ALL | wx.ALIGN_CENTER,
                      border=5)

        self.panel.SetSizer(mainSizer)
        mainSizer.Fit(self.panel)

        self.Layout()

    def GetPanel(self):
        """!Get dialog panel"""
        return self.panel

    def GetCmd(self):
        """!Get command"""
        line = self.cmd_prompt.GetCurLine()[0].strip()
        if len(line) == 0:
            list()

        try:
            cmd = utils.split(str(line))
        except UnicodeError:
            cmd = utils.split(utils.EncodeString((line)))

        return cmd

    def OnOk(self, event):
        """!Button 'OK' pressed"""
        # hide autocomplete
        if self.cmd_prompt.AutoCompActive():
            self.cmd_prompt.AutoCompCancel()

        self.btnOk.SetFocus()
        cmd = self.GetCmd()

        if len(cmd) < 1:
            GError(parent=self,
                   message=_("Command not defined.\n\n"
                             "Unable to add new action to the model."))
            return

        if cmd[0] not in globalvar.grassCmd:
            GError(parent=self,
                   message=_("'%s' is not a GRASS module.\n\n"
                             "Unable to add new action to the model.") %
                   cmd[0])
            return

        self.EndModal(wx.ID_OK)

    def OnCancel(self, event):
        """Cancel pressed, close window"""
        # hide autocomplete
        if self.cmd_prompt.AutoCompActive():
            self.cmd_prompt.AutoCompCancel()

        self.Hide()

    def OnText(self, event):
        """!Text in prompt changed"""
        if self.cmd_prompt.AutoCompActive():
            event.Skip()
            return

        if isinstance(event, wx.KeyEvent):
            entry = self.cmd_prompt.GetTextLeft()
        elif isinstance(event, wx.stc.StyledTextEvent):
            entry = event.GetText()
        else:
            entry = event.GetString()

        if entry:
            self.btnOk.Enable()
        else:
            self.btnOk.Enable(False)

        event.Skip()

    def Reset(self):
        """!Reset dialog"""
        self.search.Reset()
        self.cmd_prompt.OnCmdErase(None)
        self.btnOk.Enable(False)
        self.cmd_prompt.SetFocus()