Example #1
0
class SearchModuleWindow(wx.Panel):
    """Menu tree and search widget for searching modules.

    Signal:
        showNotification - attribute 'message'
    """

    def __init__(self, parent, handlerObj, giface, model, id=wx.ID_ANY,
                 **kwargs):
        self.parent = parent
        self._handlerObj = handlerObj
        self._giface = giface

        self.showNotification = Signal('SearchModuleWindow.showNotification')
        wx.Panel.__init__(self, parent=parent, id=id, **kwargs)

        # tree
        self._tree = CTreeView(model=model, parent=self)
        self._tree.SetToolTip(
            _("Double-click or Ctrl-Enter to run selected module"))

#        self._dataBox = wx.StaticBox(parent = self, id = wx.ID_ANY,
#                                     label = " %s " % _("Module tree"))

        # search widget
        self._search = SearchModuleWidget(parent=self,
                                          model=model,
                                          showChoice=False)
        self._search.showSearchResult.connect(
            lambda result: self._tree.Select(result))
        self._search.showNotification.connect(self.showNotification)

        self._helpText = StaticText(
            parent=self, id=wx.ID_ANY,
            label="Press Enter for next match, Ctrl+Enter to run command")
        self._helpText.SetForegroundColour(
            wx.SystemSettings.GetColour(
                wx.SYS_COLOUR_GRAYTEXT))

        # buttons
        self._btnRun = Button(self, id=wx.ID_OK, label=_("&Run"))
        self._btnRun.SetToolTip(_("Run selected module from the tree"))
        self._btnHelp = Button(self, id=wx.ID_ANY, label=_("H&elp"))
        self._btnHelp.SetToolTip(
            _("Show manual for selected module from the tree"))
        self._btnAdvancedSearch = Button(self, id=wx.ID_ANY,
                                         label=_("Adva&nced search..."))
        self._btnAdvancedSearch.SetToolTip(
            _("Do advanced search using %s module") % 'g.search.module')

        # bindings
        self._btnRun.Bind(wx.EVT_BUTTON, lambda evt: self.Run())
        self._btnHelp.Bind(wx.EVT_BUTTON, lambda evt: self.Help())
        self._btnAdvancedSearch.Bind(wx.EVT_BUTTON,
                                     lambda evt: self.AdvancedSearch())
        self.Bind(wx.EVT_KEY_UP, self.OnKeyUp)

        self._tree.selectionChanged.connect(self.OnItemSelected)
        self._tree.itemActivated.connect(lambda node: self.Run(node))

        self._layout()

        self._search.SetFocus()

    def _layout(self):
        """Do dialog layout"""
        sizer = wx.BoxSizer(wx.VERTICAL)

        # body
        dataSizer = wx.BoxSizer(wx.HORIZONTAL)
        dataSizer.Add(self._tree, proportion=1,
                      flag=wx.EXPAND)

        # buttons
        btnSizer = wx.BoxSizer(wx.HORIZONTAL)
        btnSizer.Add(self._btnAdvancedSearch, proportion=0)
        btnSizer.AddStretchSpacer()
        btnSizer.Add(self._btnHelp, proportion=0)
        btnSizer.Add(self._btnRun, proportion=0)

        sizer.Add(dataSizer, proportion=1,
                  flag=wx.EXPAND | wx.ALL, border=5)

        sizer.Add(self._search, proportion=0,
                  flag=wx.EXPAND | wx.LEFT | wx.RIGHT | wx.BOTTOM, border=5)

        sizer.Add(btnSizer, proportion=0,
                  flag=wx.EXPAND | wx.LEFT | wx.RIGHT | wx.BOTTOM, border=5)

        sizer.Add(self._helpText,
                  proportion=0, flag=wx.EXPAND | wx.LEFT, border=5)

        sizer.Fit(self)
        sizer.SetSizeHints(self)

        self.SetSizer(sizer)

        self.Fit()
        self.SetAutoLayout(True)
        self.Layout()

    def _GetSelectedNode(self):
        selection = self._tree.GetSelected()
        if not selection:
            return None
        return selection[0]

    def Run(self, node=None):
        """Run selected command.

        :param node: a tree node associated with the module or other item
        """
        if not node:
            node = self._GetSelectedNode()
        # nothing selected
        if not node:
            return
        data = node.data
        # non-leaf nodes
        if not data:
            return

        # extract name of the handler and create a new call
        handler = 'self._handlerObj.' + data['handler'].lstrip('self.')

        if data['command']:
            eval(handler)(event=None, cmd=data['command'].split())
        else:
            eval(handler)(event=None)

    def Help(self, node=None):
        """Show documentation for a module"""
        if not node:
            node = self._GetSelectedNode()
        # nothing selected
        if not node:
            return
        data = node.data
        # non-leaf nodes
        if not data:
            return

        if not data['command']:
            # showing nothing for non-modules
            return
        # strip parameters from command if present
        name = data['command'].split()[0]
        self._giface.Help(name)
        self.showNotification.emit(
            message=_("Documentation for %s is now open in the web browser")
            % name)

    def AdvancedSearch(self):
        """Show advanced search window"""
        self._handlerObj.RunMenuCmd(cmd=['g.search.modules'])

    def OnKeyUp(self, event):
        """Key or key combination pressed"""
        if event.ControlDown() and \
                event.GetKeyCode() in (wx.WXK_RETURN, wx.WXK_NUMPAD_ENTER):
            self.Run()

    def OnItemSelected(self, node):
        """Item selected"""
        data = node.data
        if not data or 'command' not in data:
            return

        if data['command']:
            label = data['command']
            if data['description']:
                label += ' -- ' + data['description']
        else:
            label = data['description']

        self.showNotification.emit(message=label)
Example #2
0
class InstallExtensionWindow(wx.Frame):
    def __init__(self,
                 parent,
                 giface,
                 id=wx.ID_ANY,
                 title=_("Fetch & install extension from GRASS Addons"),
                 **kwargs):
        self.parent = parent
        self._giface = giface
        self.options = dict()  # list of options

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

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

        self.repoBox = wx.StaticBox(
            parent=self.panel,
            id=wx.ID_ANY,
            label=" %s " %
            _("Repository (leave empty to use the official one)"))
        self.treeBox = wx.StaticBox(
            parent=self.panel,
            id=wx.ID_ANY,
            label=" %s " % _("List of extensions - double-click to install"))

        self.repo = wx.TextCtrl(parent=self.panel, id=wx.ID_ANY)

        # modelBuilder loads data into tree model
        self.modelBuilder = ExtensionTreeModelBuilder()
        # tree view displays model data
        self.tree = CTreeView(parent=self.panel,
                              model=self.modelBuilder.GetModel())

        self.search = SearchModuleWidget(parent=self.panel,
                                         model=self.modelBuilder.GetModel(),
                                         showChoice=False)
        self.search.showSearchResult.connect(
            lambda result: self.tree.Select(result))
        # show text in statusbar when notification appears
        self.search.showNotification.connect(
            lambda message: self.SetStatusText(message))
        # load data in different thread
        self.thread = gThread()

        self.optionBox = wx.StaticBox(parent=self.panel,
                                      id=wx.ID_ANY,
                                      label=" %s " % _("Options"))
        task = gtask.parse_interface('g.extension')
        ignoreFlags = ['l', 'c', 'g', 'a', 'f', 't', 'help', 'quiet']
        if sys.platform == 'win32':
            ignoreFlags.append('d')
            ignoreFlags.append('i')

        for f in task.get_options()['flags']:
            name = f.get('name', '')
            desc = f.get('label', '')
            if not desc:
                desc = f.get('description', '')
            if not name and not desc:
                continue
            if name in ignoreFlags:
                continue
            self.options[name] = wx.CheckBox(parent=self.panel,
                                             id=wx.ID_ANY,
                                             label=desc)
        defaultUrl = ''  # default/official one will be used when option empty
        self.repo.SetValue(
            task.get_param(value='url').get('default', defaultUrl))

        self.statusbar = self.CreateStatusBar(number=1)

        self.btnFetch = wx.Button(parent=self.panel,
                                  id=wx.ID_ANY,
                                  label=_("&Fetch"))
        self.btnFetch.SetToolTipString(
            _("Fetch list of available modules "
              "from GRASS Addons SVN repository"))
        self.btnClose = wx.Button(parent=self.panel, id=wx.ID_CLOSE)
        self.btnInstall = wx.Button(parent=self.panel,
                                    id=wx.ID_ANY,
                                    label=_("&Install"))
        self.btnInstall.SetToolTipString(
            _("Install selected add-ons GRASS module"))
        self.btnInstall.Enable(False)
        self.btnHelp = wx.Button(parent=self.panel, id=wx.ID_HELP)
        self.btnHelp.SetToolTipString(_("Show g.extension manual page"))

        self.btnClose.Bind(wx.EVT_BUTTON, lambda evt: self.Close())
        self.btnFetch.Bind(wx.EVT_BUTTON, self.OnFetch)
        self.btnInstall.Bind(wx.EVT_BUTTON, self.OnInstall)
        self.btnHelp.Bind(wx.EVT_BUTTON, self.OnHelp)
        self.tree.selectionChanged.connect(self.OnItemSelected)
        self.tree.itemActivated.connect(self.OnItemActivated)
        self.tree.contextMenu.connect(self.OnContextMenu)

        wx.CallAfter(self._fetch)

        self._layout()

    def _layout(self):
        """Do layout"""
        sizer = wx.BoxSizer(wx.VERTICAL)
        repoSizer = wx.StaticBoxSizer(self.repoBox, wx.VERTICAL)
        repo1Sizer = wx.BoxSizer(wx.HORIZONTAL)
        repo1Sizer.Add(item=self.repo,
                       proportion=1,
                       flag=wx.ALL | wx.ALIGN_CENTER_VERTICAL,
                       border=1)
        repo1Sizer.Add(item=self.btnFetch,
                       proportion=0,
                       flag=wx.ALL | wx.ALIGN_CENTER_VERTICAL,
                       border=1)
        repoSizer.Add(item=repo1Sizer, flag=wx.EXPAND)

        findSizer = wx.BoxSizer(wx.HORIZONTAL)
        findSizer.Add(item=self.search, proportion=1)

        treeSizer = wx.StaticBoxSizer(self.treeBox, wx.HORIZONTAL)
        treeSizer.Add(item=self.tree,
                      proportion=1,
                      flag=wx.ALL | wx.EXPAND,
                      border=1)

        # options
        optionSizer = wx.StaticBoxSizer(self.optionBox, wx.VERTICAL)
        for key in self.options.keys():
            optionSizer.Add(item=self.options[key], proportion=0)

        btnSizer = wx.BoxSizer(wx.HORIZONTAL)
        btnSizer.Add(item=self.btnHelp, proportion=0)
        btnSizer.AddStretchSpacer()
        btnSizer.Add(item=self.btnClose, proportion=0, flag=wx.RIGHT, border=5)
        btnSizer.Add(item=self.btnInstall, proportion=0)

        sizer.Add(item=repoSizer,
                  proportion=0,
                  flag=wx.ALL | wx.EXPAND,
                  border=3)
        sizer.Add(item=findSizer,
                  proportion=0,
                  flag=wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.EXPAND,
                  border=3)
        sizer.Add(item=treeSizer,
                  proportion=1,
                  flag=wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.EXPAND,
                  border=3)
        sizer.Add(item=optionSizer,
                  proportion=0,
                  flag=wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.EXPAND,
                  border=3)
        sizer.Add(item=btnSizer,
                  proportion=0,
                  flag=wx.ALIGN_RIGHT | wx.ALL | wx.EXPAND,
                  border=5)

        self.panel.SetSizer(sizer)
        sizer.Fit(self.panel)

        self.Layout()

    def _getCmd(self):
        item = self.tree.GetSelected()
        if not item or 'command' not in item[0].data:
            GError(_("Extension not defined"), parent=self)
            return

        name = item[0].data['command']

        flags = list()
        for key in self.options.keys():
            if self.options[key].IsChecked():
                if len(key) == 1:
                    flags.append('-%s' % key)
                else:
                    flags.append('--%s' % key)

        return ['g.extension'] + flags + [
            'extension=' + name, 'url=' + self.repo.GetValue().strip()
        ]

    def OnFetch(self, event):
        """Fetch list of available extensions"""
        self._fetch()

    def _fetch(self):
        """Fetch list of available extensions"""
        wx.BeginBusyCursor()
        self.SetStatusText(
            _("Fetching list of modules from GRASS-Addons SVN (be patient)..."
              ), 0)
        try:
            self.thread.Run(callable=self.modelBuilder.Load,
                            url=self.repo.GetValue().strip(),
                            ondone=lambda event: self._fetchDone())
        except GException as e:
            self._fetchDone()
            GError(unicode(e), parent=self, showTraceback=False)

    def _fetchDone(self):
        self.tree.RefreshItems()
        nitems = len(self.modelBuilder.GetModel().SearchNodes(key='command',
                                                              value='*'))
        self.SetStatusText(_("%d extensions loaded") % nitems, 0)
        wx.EndBusyCursor()

    def OnContextMenu(self, node):
        if not hasattr(self, "popupID"):
            self.popupID = dict()
            for key in ('install', 'help'):
                self.popupID[key] = wx.NewId()

        data = node.data
        if data and 'command' in data:
            self.popupMenu = wx.Menu()
            self.popupMenu.Append(self.popupID['install'], text=_("Install"))
            self.Bind(wx.EVT_MENU, self.OnInstall, id=self.popupID['install'])
            self.popupMenu.AppendSeparator()
            self.popupMenu.Append(self.popupID['help'],
                                  text=_("Show manual page"))
            self.Bind(wx.EVT_MENU, self.OnItemHelp, id=self.popupID['help'])

            self.PopupMenu(self.popupMenu)
            self.popupMenu.Destroy()

    def OnItemActivated(self, node):
        data = node.data
        if data and 'command' in data:
            self.OnInstall(event=None)

    def OnInstall(self, event):
        """Install selected extension"""
        log = self.parent.GetLogWindow()
        cmd = self._getCmd()
        if cmd:
            log.RunCmd(cmd, onDone=self.OnDone)

    def OnDone(self, event):
        if event.returncode == 0:
            if not os.getenv('GRASS_ADDON_BASE'):
                SetAddOnPath(key='BASE')

            globalvar.UpdateGRASSAddOnCommands()
            toolboxesOutdated()

    def OnItemHelp(self, event):
        item = self.tree.GetSelected()
        if not item or 'command' not in item[0].data:
            return

        self._giface.Help(entry=item[0].data['command'], online=True)

    def OnHelp(self, event):
        self._giface.Help(entry='g.extension')

    def OnItemSelected(self, node):
        """Item selected"""
        data = node.data
        if data is None:
            self.SetStatusText('', 0)
            self.btnInstall.Enable(False)
        else:
            self.SetStatusText(data.get('description', ''), 0)
            self.btnInstall.Enable(True)
Example #3
0
class SearchModuleWindow(wx.Panel):
    """Menu tree and search widget for searching modules.
    
    Signal:
        showNotification - attribute 'message'
    """
    def __init__(self, parent, handlerObj, model, id=wx.ID_ANY, **kwargs):
        self.parent = parent
        self.handlerObj = handlerObj

        self.showNotification = Signal('SearchModuleWindow.showNotification')
        wx.Panel.__init__(self, parent=parent, id=id, **kwargs)

        # tree
        self._tree = CTreeView(model=model, parent=self)
        self._tree.SetToolTipString(
            _("Double-click or Ctrl-Enter to run selected module"))

        #        self._dataBox = wx.StaticBox(parent = self, id = wx.ID_ANY,
        #                                     label = " %s " % _("Module tree"))

        # search widget
        self._search = SearchModuleWidget(parent=self,
                                          model=model,
                                          showChoice=False)
        self._search.showSearchResult.connect(
            lambda result: self._tree.Select(result))
        self._search.showNotification.connect(self.showNotification)

        self._helpText = wx.StaticText(
            parent=self,
            id=wx.ID_ANY,
            label="Press Enter for next match, Ctrl+Enter to run command")
        self._helpText.SetForegroundColour(
            wx.SystemSettings_GetColour(wx.SYS_COLOUR_GRAYTEXT))

        # buttons
        self._btnRun = wx.Button(self, id=wx.ID_OK, label=_("&Run"))
        self._btnRun.SetToolTipString(_("Run selected module from the tree"))

        # bindings
        self._btnRun.Bind(wx.EVT_BUTTON, lambda evt: self.Run())
        self.Bind(wx.EVT_KEY_UP, self.OnKeyUp)

        self._tree.selectionChanged.connect(self.OnItemSelected)
        self._tree.itemActivated.connect(lambda node: self.Run(node))

        self._layout()

        self._search.SetFocus()

    def _layout(self):
        """Do dialog layout"""
        sizer = wx.BoxSizer(wx.VERTICAL)

        # body
        dataSizer = wx.BoxSizer(wx.HORIZONTAL)
        dataSizer.Add(item=self._tree, proportion=1, flag=wx.EXPAND)

        # buttons
        btnSizer = wx.BoxSizer(wx.HORIZONTAL)
        btnSizer.Add(item=self._btnRun, proportion=0)

        sizer.Add(item=dataSizer,
                  proportion=1,
                  flag=wx.EXPAND | wx.ALL,
                  border=5)

        sizer.Add(item=self._search,
                  proportion=0,
                  flag=wx.EXPAND | wx.LEFT | wx.RIGHT | wx.BOTTOM,
                  border=5)

        sizer.Add(item=btnSizer,
                  proportion=0,
                  flag=wx.ALIGN_RIGHT | wx.BOTTOM | wx.RIGHT,
                  border=5)

        sizer.Add(item=self._helpText,
                  proportion=0,
                  flag=wx.EXPAND | wx.LEFT,
                  border=5)

        sizer.Fit(self)
        sizer.SetSizeHints(self)

        self.SetSizer(sizer)

        self.Fit()
        self.SetAutoLayout(True)
        self.Layout()

    def Run(self, module=None):
        """Run selected command.
        
        :param module: module (represented by tree node)
        """
        if module is None:
            if not self._tree.GetSelected():
                return

            module = self._tree.GetSelected()[0]
        data = module.data
        if not data:
            return

        handler = 'self.handlerObj.' + data['handler'].lstrip('self.')

        if data['command']:
            eval(handler)(event=None, cmd=data['command'].split())
        else:
            eval(handler)(event=None)

    def OnKeyUp(self, event):
        """Key or key combination pressed"""
        if event.ControlDown() and \
                event.GetKeyCode() in (wx.WXK_RETURN, wx.WXK_NUMPAD_ENTER):
            self.Run()

    def OnItemSelected(self, node):
        """Item selected"""
        data = node.data
        if not data or 'command' not in data:
            return

        if data['command']:
            label = data['command']
            if data['description']:
                label += ' -- ' + data['description']
        else:
            label = data['description']

        self.showNotification.emit(message=label)