2 @package modules.extensions 
    4 @brief GRASS Addons extensions management classes 
    7  - extensions::InstallExtensionWindow 
    8  - extensions::ExtensionTree 
    9  - extensions::UninstallExtensionWindow 
   10  - extensions::CheckListExtension 
   12 (C) 2008-2011 by the GRASS Development Team 
   14 This program is free software under the GNU General Public License 
   15 (>=v2). Read the file COPYING that comes with GRASS for details. 
   17 @author Martin Landa <landa.martin gmail.com> 
   24 import wx.lib.mixins.listctrl 
as listmix
 
   26     import wx.lib.agw.customtreectrl 
as CT
 
   28     import wx.lib.customtreectrl 
as CT
 
   29 import wx.lib.flatnotebook 
as FN
 
   34 from core             
import globalvar
 
   37 from gui_core.forms   
import GUI
 
   42     def __init__(self, parent, id = wx.ID_ANY,
 
   43                  title = _(
"Fetch & install extension from GRASS Addons"), **kwargs):
 
   47         wx.Frame.__init__(self, parent = parent, id = id, title = title, **kwargs)
 
   48         self.SetIcon(wx.Icon(os.path.join(globalvar.ETCICONDIR, 
'grass.ico'), wx.BITMAP_TYPE_ICO))
 
   50         self.
panel = wx.Panel(parent = self, id = wx.ID_ANY)
 
   53                                     label = 
" %s " % _(
"Repository"))
 
   55                                     label = 
" %s " % _(
"List of extensions"))
 
   57         self.
repo = wx.TextCtrl(parent = self.
panel, id = wx.ID_ANY)
 
   59                                     label = _(
"Fetch full info including description and keywords"))
 
   60         self.fullDesc.SetValue(
True)
 
   63         self.search.SetSelection(0) 
 
   68                                       label = 
" %s " % _(
"Options"))
 
   70         task = gtask.parse_interface(
'g.extension.py')
 
   72         ignoreFlags = [
'l', 
'c', 
'g', 
'a', 
'f', 
'quiet', 
'verbose']
 
   73         if sys.platform == 
'win32':
 
   74             ignoreFlags.append(
'd')
 
   75             ignoreFlags.append(
'i')
 
   77         for f 
in task.get_options()[
'flags']:
 
   78             name = f.get(
'name', 
'')
 
   79             desc = f.get(
'label', 
'')
 
   81                 desc = f.get(
'description', 
'')
 
   82             if not name 
and not desc:
 
   84             if name 
in ignoreFlags:
 
   86             self.
options[name] = wx.CheckBox(parent = self.
panel, id = wx.ID_ANY,
 
   88         self.repo.SetValue(task.get_param(value = 
'svnurl').get(
'default',
 
   89                                                                 'http://svn.osgeo.org/grass/grass-addons'))
 
   95         self.btnFetch.SetToolTipString(_(
"Fetch list of available modules from GRASS Addons SVN repository"))
 
   98                                     label = _(
"&Install"))
 
   99         self.btnInstall.SetToolTipString(_(
"Install selected add-ons GRASS module"))
 
  100         self.btnInstall.Enable(
False)
 
  102                                 label = _(
"Command dialog"))
 
  103         self.btnCmd.SetToolTipString(_(
'Open %s dialog') % 
'g.extension.py')
 
  106         self.btnFetch.Bind(wx.EVT_BUTTON, self.
OnFetch)
 
  107         self.btnInstall.Bind(wx.EVT_BUTTON, self.
OnInstall)
 
  111         self.search.Bind(wx.EVT_TEXT_ENTER,        self.
OnShowItem)
 
  118         sizer = wx.BoxSizer(wx.VERTICAL)
 
  119         repoSizer = wx.StaticBoxSizer(self.
repoBox, wx.VERTICAL)
 
  120         repo1Sizer = wx.BoxSizer(wx.HORIZONTAL)
 
  121         repo1Sizer.Add(item = self.
repo, proportion = 1,
 
  122                       flag = wx.ALL | wx.ALIGN_CENTER_VERTICAL, border = 1)
 
  123         repo1Sizer.Add(item = self.
btnFetch, proportion = 0,
 
  124                       flag = wx.ALL | wx.ALIGN_CENTER_VERTICAL, border = 1)
 
  125         repoSizer.Add(item = repo1Sizer,
 
  129         findSizer = wx.BoxSizer(wx.HORIZONTAL)
 
  130         findSizer.Add(item = self.
search, proportion = 1)
 
  132         treeSizer = wx.StaticBoxSizer(self.
treeBox, wx.HORIZONTAL)
 
  133         treeSizer.Add(item = self.
tree, proportion = 1,
 
  134                       flag = wx.ALL | wx.EXPAND, border = 1)
 
  137         optionSizer = wx.StaticBoxSizer(self.
optionBox, wx.VERTICAL)
 
  138         for key 
in self.options.keys():
 
  139             optionSizer.Add(item = self.
options[key], proportion = 0)
 
  141         btnSizer = wx.BoxSizer(wx.HORIZONTAL)
 
  142         btnSizer.Add(item = self.
btnCmd, proportion = 0,
 
  143                      flag = wx.RIGHT, border = 5)
 
  144         btnSizer.AddSpacer(10)
 
  145         btnSizer.Add(item = self.
btnClose, proportion = 0,
 
  146                      flag = wx.RIGHT, border = 5)
 
  147         btnSizer.Add(item = self.
btnInstall, proportion = 0)
 
  149         sizer.Add(item = repoSizer, proportion = 0,
 
  150                   flag = wx.ALL | wx.EXPAND, border = 3)
 
  151         sizer.Add(item = findSizer, proportion = 0,
 
  152                   flag = wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.EXPAND, border = 3)
 
  153         sizer.Add(item = treeSizer, proportion = 1,
 
  154                   flag = wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.EXPAND, border = 3)
 
  155         sizer.Add(item = optionSizer, proportion = 0,
 
  156                         flag = wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.EXPAND, border = 3)
 
  157         sizer.Add(item = btnSizer, proportion = 0,
 
  158                   flag = wx.ALIGN_RIGHT | wx.ALL, border = 5)
 
  160         self.panel.SetSizer(sizer)
 
  161         sizer.Fit(self.
panel)
 
  166         item = self.tree.GetSelected()
 
  167         if not item 
or not item.IsOk():
 
  168             return [
'g.extension.py']
 
  170         name = self.tree.GetItemText(item)
 
  172             GError(_(
"Extension not defined"), parent = self)
 
  175         for key 
in self.options.keys():
 
  176             if self.
options[key].IsChecked():
 
  177                 flags.append(
'-%s' % key)
 
  179         return [
'g.extension.py'] + flags + [
'extension=' + name,
 
  180                                              'svnurl=' + self.repo.GetValue().strip()]
 
  183         """!Update statusbar text""" 
  184         element = self.search.GetSelection()
 
  185         if not self.tree.IsLoaded():
 
  186             self.SetStatusText(_(
"Fetch list of available extensions by clicking on 'Fetch' button"), 0)
 
  189         self.tree.SearchItems(element = element,
 
  190                               value = event.GetString())
 
  192         nItems = len(self.tree.itemsMarked)
 
  193         if event.GetString():
 
  194             self.SetStatusText(_(
"%d items match") % nItems, 0)
 
  196             self.SetStatusText(
"", 0)
 
  205         """!Fetch list of available extensions""" 
  207         self.SetStatusText(_(
"Fetching list of modules from GRASS-Addons SVN (be patient)..."), 0)
 
  208         self.tree.Load(url = self.repo.GetValue().strip(), full = self.fullDesc.IsChecked())
 
  209         self.SetStatusText(
"", 0)
 
  213         item = event.GetItem()
 
  214         data = self.tree.GetPyData(item)
 
  215         if data 
and 'command' in data:
 
  219         """!Install selected extension""" 
  220         log = self.parent.GetLogWindow()
 
  225             if not os.getenv(
'GRASS_ADDON_PATH'):
 
  229             log = self.parent.GetLogWindow()
 
  230             log.GetPrompt().SetFilter(
None)
 
  234         item = event.GetItem()
 
  235         self.tree.itemSelected = item
 
  236         data = self.tree.GetPyData(item)
 
  238             self.SetStatusText(
'', 0)
 
  239             self.btnInstall.Enable(
False)
 
  241             self.SetStatusText(data.get(
'description', 
''), 0)
 
  242             self.btnInstall.Enable(
True)
 
  245         """!Show selected item""" 
  246         self.tree.OnShowItem(event)
 
  247         if self.tree.GetSelected():
 
  248             self.btnInstall.Enable()
 
  250             self.btnInstall.Enable(
False)
 
  253         """!Shows command dialog""" 
  254         GUI(parent = self).ParseCommand(cmd = self.
_getCmd())
 
  257     """!List of available extensions""" 
  258     def __init__(self, parent, log, id = wx.ID_ANY,
 
  259                  ctstyle = CT.TR_HIDE_ROOT | CT.TR_FULL_ROW_HIGHLIGHT | CT.TR_HAS_BUTTONS |
 
  260                  CT.TR_LINES_AT_ROOT | CT.TR_SINGLE,
 
  265         super(ExtensionTree, self).
__init__(parent, id, ctstyle = ctstyle, **kwargs)
 
  270         for prefix 
in (
'display', 
'database',
 
  271                        'general', 
'imagery',
 
  272                        'misc', 
'postscript', 
'paint',
 
  273                        'raster', 
'raster3d', 
'sites', 
'vector', 
'wxGUI', 
'other'):
 
  274             self.AppendItem(parentId = self.
root,
 
  278     def _expandPrefix(self, c):
 
  279         name = { 
'd'  : 
'display',
 
  298     def _findItem(self, text):
 
  300         item = self.GetFirstChild(self.
root)[0]
 
  301         while item 
and item.IsOk():
 
  302             if text == self.GetItemText(item):
 
  305             item = self.GetNextSibling(item)
 
  309     def Load(self, url, full = False):
 
  310         """!Load list of extensions""" 
  311         self.DeleteAllItems()
 
  312         self.
root = self.AddRoot(_(
"Menu tree"))
 
  319         ret = 
RunCommand(
'g.extension.py', read = 
True, parent = self,
 
  321                          flags = flags, quiet = 
True)
 
  326         for line 
in ret.splitlines():
 
  329                     key, value = line.split(
'=', 1)
 
  336                         prefix, name = value.split(
'.', 1)
 
  340                     if prefix 
not in mdict:
 
  341                         mdict[prefix] = dict()
 
  342                     mdict[prefix][name] = dict()
 
  344                     mdict[prefix][name][key] = value
 
  347                     prefix, name = line.strip().
split(
'.', 1)
 
  355                 if prefix 
not in mdict:
 
  356                     mdict[prefix] = dict()
 
  358                 mdict[prefix][name] = { 
'command' : prefix + 
'.' + name }
 
  360         for prefix 
in mdict.keys():
 
  363             names = mdict[prefix].keys()
 
  367                     text = prefix + 
'.' + name
 
  370                 new = self.AppendItem(parentId = item,
 
  373                 for key 
in mdict[prefix][name].keys():
 
  374                     data[key] = mdict[prefix][name][key]
 
  376                 self.SetPyData(new, data)
 
  381         """Check if items are loaded""" 
  385     def __init__(self, parent, id = wx.ID_ANY,
 
  386                  title = _(
"Uninstall GRASS Addons extensions"), **kwargs):
 
  389         wx.Frame.__init__(self, parent = parent, id = id, title = title, **kwargs)
 
  390         self.SetIcon(wx.Icon(os.path.join(globalvar.ETCICONDIR, 
'grass.ico'), wx.BITMAP_TYPE_ICO))
 
  392         self.
panel = wx.Panel(parent = self, id = wx.ID_ANY)
 
  395                                    label = 
" %s " % _(
"List of installed extensions"))
 
  401                                     label = _(
"&Uninstall"))
 
  402         self.btnUninstall.SetToolTipString(_(
"Uninstall selected AddOns extensions"))
 
  404                                 label = _(
"Command dialog"))
 
  405         self.btnCmd.SetToolTipString(_(
'Open %s dialog') % 
'g.extension')
 
  408         self.btnUninstall.Bind(wx.EVT_BUTTON, self.
OnUninstall)
 
  416         sizer = wx.BoxSizer(wx.VERTICAL)
 
  418         extSizer = wx.StaticBoxSizer(self.
extBox, wx.HORIZONTAL)
 
  419         extSizer.Add(item = self.
extList, proportion = 1,
 
  420                      flag = wx.ALL | wx.EXPAND, border = 1)
 
  422         btnSizer = wx.BoxSizer(wx.HORIZONTAL)
 
  423         btnSizer.Add(item = self.
btnCmd, proportion = 0,
 
  424                      flag = wx.RIGHT, border = 5)
 
  425         btnSizer.AddSpacer(10)
 
  426         btnSizer.Add(item = self.
btnClose, proportion = 0,
 
  427                      flag = wx.RIGHT, border = 5)
 
  430         sizer.Add(item = extSizer, proportion = 1,
 
  431                   flag = wx.ALL | wx.EXPAND, border = 3)
 
  432         sizer.Add(item = btnSizer, proportion = 0,
 
  433                   flag = wx.ALIGN_RIGHT | wx.ALL, border = 5)
 
  435         self.panel.SetSizer(sizer)
 
  436         sizer.Fit(self.
panel)
 
  445         """!Uninstall selected extensions""" 
  446         log = self.parent.GetLogWindow()
 
  447         eList = self.extList.GetExtensions()
 
  449             GError(_(
"No extension selected for removal. " 
  450                      "Operation canceled."),
 
  455             files = 
RunCommand(
'g.extension.py', parent = self, read = 
True, quiet = 
True,
 
  456                                extension = ext, operation = 
'remove').splitlines()
 
  457             dlg = wx.MessageDialog(parent = self,
 
  458                                    message = _(
"List of files to be removed:\n%(files)s\n\n" 
  459                                                "Do you want really to remove <%(ext)s> extension?") % \
 
  460                                        { 
'files' : os.linesep.join(files), 
'ext' : ext },
 
  461                                    caption = _(
"Remove extension"),
 
  462                                    style = wx.YES_NO | wx.NO_DEFAULT | wx.ICON_QUESTION)
 
  464             if dlg.ShowModal() ==  wx.ID_YES:
 
  465                 RunCommand(
'g.extension.py', flags = 
'f', parent = self, quiet = 
True,
 
  466                            extension = ext, operation = 
'remove')
 
  468         self.extList.LoadData()
 
  472         log = self.parent.GetLogWindow()
 
  473         log.GetPrompt().SetFilter(
None)
 
  476         """!Shows command dialog""" 
  477         GUI(parent = self).ParseCommand(cmd = [
'g.extension.py'])
 
  480     """!List of mapset/owner/group""" 
  484         wx.ListCtrl.__init__(self, parent, id = wx.ID_ANY,
 
  485                              style = wx.LC_REPORT)
 
  486         listmix.CheckListCtrlMixin.__init__(self)
 
  489         listmix.ListCtrlAutoWidthMixin.__init__(self)
 
  491         self.InsertColumn(0, _(
'Extension'))
 
  495         """!Load data into list""" 
  496         self.DeleteAllItems()
 
  498                               quiet = 
True, parent = self, read = 
True,
 
  499                               flags = 
'a').splitlines():
 
  501                 self.InsertStringItem(sys.maxint, ext)
 
  504         """!Get extensions to be un-installed 
  507         for i 
in range(self.GetItemCount()):
 
  508             if self.IsChecked(i):
 
  509                 name = self.GetItemText(i)
 
List of mapset/owner/group. 
 
def Load
Load list of extensions. 
 
def OnShowItem
Show selected item. 
 
def split
Platform spefic shlex.split. 
 
def OnInstall
Install selected extension. 
 
def SetAddOnPath
Set default AddOn path. 
 
def OnUpdateStatusBar
Update statusbar text. 
 
def OnFetch
Fetch list of available extensions. 
 
def OnItemSelected
Item selected. 
 
def OnCloseWindow
Close window. 
 
Misc utilities for wxGUI. 
 
def OnCmdDialog
Shows command dialog. 
 
def OnCloseWindow
Close window. 
 
def LoadData
Load data into list. 
 
def UpdateGRASSAddOnCommands
Update list of available GRASS AddOns commands to use when parsing string from the command line...
 
def OnCmdDialog
Shows command dialog. 
 
def GetExtensions
Get extensions to be un-installed. 
 
def RunCommand
Run GRASS command. 
 
List of available extensions. 
 
def OnUninstall
Uninstall selected extensions.