123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512 |
- """!
- @package modules.extensions
- @brief GRASS Addons extensions management classes
- Classes:
- - extensions::InstallExtensionWindow
- - extensions::ExtensionTree
- - extensions::UninstallExtensionWindow
- - extensions::CheckListExtension
- (C) 2008-2012 by the GRASS Development Team
- This program is free software under the GNU General Public License
- (>=v2). Read the file COPYING that comes with GRASS for details.
- @author Martin Landa <landa.martin gmail.com>
- """
- import os
- import sys
- import wx
- try:
- import wx.lib.agw.customtreectrl as CT
- except ImportError:
- import wx.lib.customtreectrl as CT
- import wx.lib.flatnotebook as FN
- import grass.script as grass
- from grass.script import task as gtask
- from core import globalvar
- from core.gcmd import GError, RunCommand
- from core.utils import SetAddOnPath
- from gui_core.forms import GUI
- from gui_core.widgets import ItemTree, GListCtrl, SearchModuleWidget
- class InstallExtensionWindow(wx.Frame):
- def __init__(self, parent, id = wx.ID_ANY,
- title = _("Fetch & install extension from GRASS Addons"), **kwargs):
- self.parent = parent
- 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.ETCICONDIR, '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"))
- self.treeBox = wx.StaticBox(parent = self.panel, id = wx.ID_ANY,
- label = " %s " % _("List of extensions"))
-
- self.repo = wx.TextCtrl(parent = self.panel, id = wx.ID_ANY)
- self.fullDesc = wx.CheckBox(parent = self.panel, id = wx.ID_ANY,
- label = _("Fetch full info including description and keywords"))
- self.fullDesc.SetValue(True)
-
- self.search = SearchModuleWidget(parent = self.panel, modulesData = None)
- self.search.SetSelection(0)
-
- self.tree = ExtensionTree(parent = self.panel, log = parent.GetLogWindow())
-
- self.optionBox = wx.StaticBox(parent = self.panel, id = wx.ID_ANY,
- label = " %s " % _("Options"))
- if sys.platform == 'win32':
- task = gtask.parse_interface('g.extension.py')
- else:
- task = gtask.parse_interface('g.extension')
- ignoreFlags = ['l', 'c', 'g', 'a', 'f', 't', '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)
- self.repo.SetValue(task.get_param(value = 'svnurl').get('default',
- 'http://svn.osgeo.org/grass/grass-addons/grass7'))
-
- 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.btnCmd = wx.Button(parent = self.panel, id = wx.ID_ANY,
- label = _("Command dialog"))
- self.btnCmd.SetToolTipString(_('Open %s dialog') % 'g.extension')
- self.btnClose.Bind(wx.EVT_BUTTON, self.OnCloseWindow)
- self.btnFetch.Bind(wx.EVT_BUTTON, self.OnFetch)
- self.btnInstall.Bind(wx.EVT_BUTTON, self.OnInstall)
- self.btnCmd.Bind(wx.EVT_BUTTON, self.OnCmdDialog)
- self.tree.Bind(wx.EVT_TREE_ITEM_ACTIVATED, self.OnItemActivated)
- self.tree.Bind(wx.EVT_TREE_SEL_CHANGED, self.OnItemSelected)
- self.search.Bind(wx.EVT_TEXT_ENTER, self.OnShowItem)
- self.search.Bind(wx.EVT_TEXT, self.OnUpdateStatusBar)
- 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)
- repoSizer.Add(item = self.fullDesc)
-
- 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.btnCmd, proportion = 0,
- flag = wx.RIGHT, border = 5)
- btnSizer.AddSpacer(10)
- 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, border = 5)
-
- self.panel.SetSizer(sizer)
- sizer.Fit(self.panel)
-
- self.Layout()
- def _getCmd(self):
- item = self.tree.GetSelected()
- if not item or not item.IsOk():
- return ['g.extension']
-
- name = self.tree.GetItemText(item)
- if not name:
- GError(_("Extension not defined"), parent = self)
- return
-
- 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,
- 'svnurl=' + self.repo.GetValue().strip()]
-
- def OnUpdateStatusBar(self, event):
- """!Update statusbar text"""
- element = self.search.GetSelection()
- if not self.tree.IsLoaded():
- self.SetStatusText(_("Fetch list of available extensions by clicking on 'Fetch' button"), 0)
- return
-
- self.tree.SearchItems(element = element,
- value = event.GetString())
-
- nItems = len(self.tree.itemsMarked)
- if event.GetString():
- self.SetStatusText(_("%d items match") % nItems, 0)
- else:
- self.SetStatusText("", 0)
-
- event.Skip()
-
- def OnCloseWindow(self, event):
- """!Close window"""
- self.Destroy()
- def OnFetch(self, event):
- """!Fetch list of available extensions"""
- wx.BeginBusyCursor()
- self.SetStatusText(_("Fetching list of modules from GRASS-Addons SVN (be patient)..."), 0)
- self.tree.Load(url = self.repo.GetValue().strip(), full = self.fullDesc.IsChecked())
- self.SetStatusText("", 0)
- wx.EndBusyCursor()
- def OnItemActivated(self, event):
- item = event.GetItem()
- data = self.tree.GetPyData(item)
- if data and 'command' in data:
- self.OnInstall(event = None)
-
- def OnInstall(self, event):
- """!Install selected extension"""
- log = self.parent.GetLogWindow()
- log.RunCmd(self._getCmd(), onDone = self.OnDone)
-
- def OnDone(self, cmd, returncode):
- if returncode == 0:
- if not os.getenv('GRASS_ADDON_BASE'):
- SetAddOnPath(key = 'BASE')
-
- globalvar.UpdateGRASSAddOnCommands()
- log = self.parent.GetLogWindow()
- log.GetPrompt().SetFilter(None)
- def OnItemSelected(self, event):
- """!Item selected"""
- item = event.GetItem()
- self.tree.itemSelected = item
- data = self.tree.GetPyData(item)
- if data is None:
- self.SetStatusText('', 0)
- self.btnInstall.Enable(False)
- else:
- self.SetStatusText(data.get('description', ''), 0)
- self.btnInstall.Enable(True)
- def OnShowItem(self, event):
- """!Show selected item"""
- self.tree.OnShowItem(event)
- if self.tree.GetSelected():
- self.btnInstall.Enable()
- else:
- self.btnInstall.Enable(False)
- def OnCmdDialog(self, event):
- """!Shows command dialog"""
- GUI(parent = self).ParseCommand(cmd = self._getCmd())
-
- class ExtensionTree(ItemTree):
- """!List of available extensions"""
- def __init__(self, parent, log, id = wx.ID_ANY,
- ctstyle = CT.TR_HIDE_ROOT | CT.TR_FULL_ROW_HIGHLIGHT | CT.TR_HAS_BUTTONS |
- CT.TR_LINES_AT_ROOT | CT.TR_SINGLE,
- **kwargs):
- self.parent = parent # GMFrame
- self.log = log
-
- super(ExtensionTree, self).__init__(parent, id, ctstyle = ctstyle, **kwargs)
-
- self._initTree()
-
- def _initTree(self):
- for prefix in ('display', 'database',
- 'general', 'imagery',
- 'misc', 'postscript', 'paint',
- 'raster', 'raster3D', 'sites', 'vector', 'wxGUI', 'other'):
- self.AppendItem(parentId = self.root,
- text = prefix)
- self._loaded = False
-
- def _expandPrefix(self, c):
- name = { 'd' : 'display',
- 'db' : 'database',
- 'g' : 'general',
- 'i' : 'imagery',
- 'm' : 'misc',
- 'ps' : 'postscript',
- 'p' : 'paint',
- 'r' : 'raster',
- 'r3' : 'raster3D',
- 's' : 'sites',
- 'v' : 'vector',
- 'wx' : 'wxGUI',
- '' : 'other' }
-
- if c in name:
- return name[c]
-
- return c
-
- def _findItem(self, text):
- """!Find item"""
- item = self.GetFirstChild(self.root)[0]
- while item and item.IsOk():
- if text == self.GetItemText(item):
- return item
-
- item = self.GetNextSibling(item)
-
- return None
-
- def Load(self, url, full = False):
- """!Load list of extensions"""
- self.DeleteAllItems()
- self.root = self.AddRoot(_("Menu tree"))
- self._initTree()
-
- if full:
- flags = 'g'
- else:
- flags = 'l'
- ret = RunCommand('g.extension', read = True, parent = self,
- svnurl = url,
- flags = flags, quiet = True)
- if not ret:
- return
-
- mdict = dict()
- for line in ret.splitlines():
- if full:
- try:
- key, value = line.split('=', 1)
- except ValueError:
- key = 'name'
- value = line
-
- if key == 'name':
- try:
- prefix, name = value.split('.', 1)
- except ValueError:
- prefix = ''
- name = value
- if prefix not in mdict:
- mdict[prefix] = dict()
- mdict[prefix][name] = dict()
- else:
- mdict[prefix][name][key] = value
- else:
- try:
- prefix, name = line.strip().split('.', 1)
- except:
- prefix = ''
- name = line.strip()
-
- if self._expandPrefix(prefix) == prefix:
- prefix = ''
-
- if prefix not in mdict:
- mdict[prefix] = dict()
-
- mdict[prefix][name] = { 'command' : prefix + '.' + name }
-
- for prefix in mdict.keys():
- prefixName = self._expandPrefix(prefix)
- item = self._findItem(prefixName)
- names = mdict[prefix].keys()
- names.sort()
- for name in names:
- if prefix:
- text = prefix + '.' + name
- else:
- text = name
- new = self.AppendItem(parentId = item,
- text = text)
- data = dict()
- for key in mdict[prefix][name].keys():
- data[key] = mdict[prefix][name][key]
-
- self.SetPyData(new, data)
-
- self._loaded = True
- def IsLoaded(self):
- """Check if items are loaded"""
- return self._loaded
- class UninstallExtensionWindow(wx.Frame):
- def __init__(self, parent, id = wx.ID_ANY,
- title = _("Uninstall GRASS Addons extensions"), **kwargs):
- self.parent = parent
-
- wx.Frame.__init__(self, parent = parent, id = id, title = title, **kwargs)
- 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.extBox = wx.StaticBox(parent = self.panel, id = wx.ID_ANY,
- label = " %s " % _("List of installed extensions"))
-
- self.extList = CheckListExtension(parent = self.panel)
- # buttons
- self.btnUninstall = wx.Button(parent = self.panel, id = wx.ID_ANY,
- label = _("&Uninstall"))
- self.btnUninstall.SetToolTipString(_("Uninstall selected AddOns extensions"))
- self.btnCmd = wx.Button(parent = self.panel, id = wx.ID_ANY,
- label = _("Command dialog"))
- self.btnCmd.SetToolTipString(_('Open %s dialog') % 'g.extension')
- self.btnClose = wx.Button(parent = self.panel, id = wx.ID_CLOSE)
-
- self.btnUninstall.Bind(wx.EVT_BUTTON, self.OnUninstall)
- self.btnCmd.Bind(wx.EVT_BUTTON, self.OnCmdDialog)
- self.btnClose.Bind(wx.EVT_BUTTON, self.OnCloseWindow)
-
- self._layout()
-
- def _layout(self):
- """!Do layout"""
- sizer = wx.BoxSizer(wx.VERTICAL)
-
- extSizer = wx.StaticBoxSizer(self.extBox, wx.HORIZONTAL)
- extSizer.Add(item = self.extList, proportion = 1,
- flag = wx.ALL | wx.EXPAND, border = 1)
-
- btnSizer = wx.BoxSizer(wx.HORIZONTAL)
- btnSizer.Add(item = self.btnCmd, proportion = 0,
- flag = wx.RIGHT, border = 5)
- btnSizer.AddSpacer(10)
- btnSizer.Add(item = self.btnClose, proportion = 0,
- flag = wx.RIGHT, border = 5)
- btnSizer.Add(item = self.btnUninstall, proportion = 0)
-
- sizer.Add(item = extSizer, proportion = 1,
- flag = wx.ALL | wx.EXPAND, border = 3)
- sizer.Add(item = btnSizer, proportion = 0,
- flag = wx.ALIGN_RIGHT | wx.ALL, border = 5)
-
- self.panel.SetSizer(sizer)
- sizer.Fit(self.panel)
-
- self.Layout()
- def OnCloseWindow(self, event):
- """!Close window"""
- self.Destroy()
- def OnUninstall(self, event):
- """!Uninstall selected extensions"""
- log = self.parent.GetLogWindow()
- eList = self.extList.GetExtensions()
- if not eList:
- GError(_("No extension selected for removal. "
- "Operation canceled."),
- parent = self)
- return
-
- for ext in eList:
- files = RunCommand('g.extension', parent = self, read = True, quiet = True,
- extension = ext, operation = 'remove').splitlines()
- dlg = wx.MessageDialog(parent = self,
- message = _("List of files to be removed:\n%(files)s\n\n"
- "Do you want really to remove <%(ext)s> extension?") % \
- { 'files' : os.linesep.join(files), 'ext' : ext },
- caption = _("Remove extension"),
- style = wx.YES_NO | wx.NO_DEFAULT | wx.ICON_QUESTION)
-
- if dlg.ShowModal() == wx.ID_YES:
- RunCommand('g.extension', flags = 'f', parent = self, quiet = True,
- extension = ext, operation = 'remove')
-
- self.extList.LoadData()
-
- # update prompt
- globalvar.UpdateGRASSAddOnCommands(eList)
- log = self.parent.GetLogWindow()
- log.GetPrompt().SetFilter(None)
-
- def OnCmdDialog(self, event):
- """!Shows command dialog"""
- GUI(parent = self).ParseCommand(cmd = ['g.extension'])
- class CheckListExtension(GListCtrl):
- """!List of mapset/owner/group"""
- def __init__(self, parent):
- GListCtrl.__init__(self, parent)
-
- # load extensions
- self.InsertColumn(0, _('Extension'))
- self.LoadData()
-
- def LoadData(self):
- """!Load data into list"""
- self.DeleteAllItems()
- for ext in RunCommand('g.extension',
- quiet = True, parent = self, read = True,
- flags = 'a').splitlines():
- if ext:
- self.InsertStringItem(sys.maxint, ext)
- def GetExtensions(self):
- """!Get extensions to be un-installed
- """
- extList = list()
- for i in range(self.GetItemCount()):
- if self.IsChecked(i):
- name = self.GetItemText(i)
- if name:
- extList.append(name)
-
- return extList
|