GRASS Programmer's Manual  6.4.2(2012)
gis_set.py
Go to the documentation of this file.
00001 """!
00002 @package gis_set.py
00003 
00004 GRASS start-up screen.
00005 
00006 Initialization module for wxPython GRASS GUI.
00007 Location/mapset management (selection, creation, etc.).
00008 
00009 Classes:
00010  - GRASSStartup
00011  - GListBox
00012  - StartUp
00013 
00014 (C) 2006-2011 by the GRASS Development Team
00015 
00016 This program is free software under the GNU General Public License
00017 (>=v2). Read the file COPYING that comes with GRASS for details.
00018 
00019 @author Michael Barton and Jachym Cepicky (original author)
00020 @author Martin Landa <landa.martin gmail.com> (various updates)
00021 """
00022 
00023 import os
00024 import sys
00025 import glob
00026 import shutil
00027 import copy
00028 import platform
00029 import codecs
00030 
00031 ### i18N
00032 import gettext
00033 gettext.install('grasswxpy', os.path.join(os.getenv("GISBASE"), 'locale'), unicode = True)
00034 
00035 from gui_modules import globalvar
00036 import wx
00037 import wx.html
00038 import wx.lib.rcsizer as rcs
00039 import wx.lib.filebrowsebutton as filebrowse
00040 import wx.lib.mixins.listctrl as listmix
00041 import wx.lib.scrolledpanel as scrolled
00042 
00043 from gui_modules import goutput
00044 from gui_modules.ghelp import HelpFrame
00045 from gui_modules.gcmd  import GMessage, GError
00046 
00047 sys.stderr = codecs.getwriter('utf8')(sys.stderr)
00048 
00049 class GRASSStartup(wx.Frame):
00050     """!GRASS start-up screen"""
00051     def __init__(self, parent = None, id = wx.ID_ANY, style = wx.DEFAULT_FRAME_STYLE):
00052 
00053         #
00054         # GRASS variables
00055         #
00056         self.gisbase  = os.getenv("GISBASE")
00057         self.grassrc  = self._readGisRC()
00058         self.gisdbase = self.GetRCValue("GISDBASE")
00059 
00060         #
00061         # list of locations/mapsets
00062         #
00063         self.listOfLocations = []
00064         self.listOfMapsets = []
00065         self.listOfMapsetsSelectable = []
00066         
00067         wx.Frame.__init__(self, parent = parent, id = id, style = style)
00068         
00069         self.locale = wx.Locale(language = wx.LANGUAGE_DEFAULT)
00070         
00071         self.panel = scrolled.ScrolledPanel(parent = self, id = wx.ID_ANY)
00072         
00073         # i18N
00074         import gettext
00075         gettext.install('grasswxpy', os.path.join(os.getenv("GISBASE"), 'locale'), unicode = True)
00076 
00077         #
00078         # graphical elements
00079         #
00080         # image
00081         try:
00082             name = os.path.join(globalvar.ETCIMGDIR, "startup_banner.gif")
00083             self.hbitmap = wx.StaticBitmap(self.panel, wx.ID_ANY,
00084                                            wx.Bitmap(name = name,
00085                                                      type = wx.BITMAP_TYPE_GIF))
00086         except:
00087             self.hbitmap = wx.StaticBitmap(self.panel, wx.ID_ANY, wx.EmptyBitmap(530,150))
00088 
00089         # labels
00090         ### crashes when LOCATION doesn't exist
00091         versionFile = open(os.path.join(globalvar.ETCDIR, "VERSIONNUMBER"))
00092         grassVersion = versionFile.readline().split(' ')[0].rstrip('\n')
00093         versionFile.close()
00094         
00095         self.select_box = wx.StaticBox (parent = self.panel, id = wx.ID_ANY,
00096                                         label = " %s " % _("Choose project location and mapset"))
00097 
00098         self.manage_box = wx.StaticBox (parent = self.panel, id = wx.ID_ANY,
00099                                         label = " %s " % _("Manage"))
00100         self.lwelcome = wx.StaticText(parent = self.panel, id = wx.ID_ANY,
00101                                       label = _("Welcome to GRASS GIS %s\n"
00102                                               "The world's leading open source GIS") % grassVersion,
00103                                       style = wx.ALIGN_CENTRE)
00104         self.ltitle = wx.StaticText(parent = self.panel, id = wx.ID_ANY,
00105                                     label = _("Select an existing project location and mapset\n"
00106                                             "or define a new location"),
00107                                     style = wx.ALIGN_CENTRE)
00108         self.ldbase = wx.StaticText(parent = self.panel, id = wx.ID_ANY,
00109                                     label = _("GIS Data Directory:"))
00110         self.llocation = wx.StaticText(parent = self.panel, id = wx.ID_ANY,
00111                                        label = _("Project location\n(projection/coordinate system)"),
00112                                        style = wx.ALIGN_CENTRE)
00113         self.lmapset = wx.StaticText(parent = self.panel, id = wx.ID_ANY,
00114                                      label = _("Accessible mapsets\n(directories of GIS files)"),
00115                                      style = wx.ALIGN_CENTRE)
00116         self.lcreate = wx.StaticText(parent = self.panel, id = wx.ID_ANY,
00117                                      label = _("Create new mapset\nin selected location"),
00118                                      style = wx.ALIGN_CENTRE)
00119         self.ldefine = wx.StaticText(parent = self.panel, id = wx.ID_ANY,
00120                                      label = _("Define new location"),
00121                                      style = wx.ALIGN_CENTRE)
00122         self.lmanageloc = wx.StaticText(parent = self.panel, id = wx.ID_ANY,
00123                                         label = _("Rename/delete selected\nmapset or location"),
00124                                         style = wx.ALIGN_CENTRE)
00125 
00126         # buttons
00127         self.bstart = wx.Button(parent = self.panel, id = wx.ID_ANY,
00128                                 label = _("Start &GRASS"))
00129         self.bstart.SetDefault()
00130         self.bexit = wx.Button(parent = self.panel, id = wx.ID_EXIT)
00131         self.bstart.SetMinSize((180, self.bexit.GetSize()[1]))
00132         self.bhelp = wx.Button(parent = self.panel, id = wx.ID_HELP)
00133         self.bbrowse = wx.Button(parent = self.panel, id = wx.ID_ANY,
00134                                  label = _("&Browse"))
00135         self.bmapset = wx.Button(parent = self.panel, id = wx.ID_ANY,
00136                                  label = _("&Create mapset"))
00137         self.bwizard = wx.Button(parent = self.panel, id = wx.ID_ANY,
00138                                  label = _("&Location wizard"))
00139         self.manageloc = wx.Choice(parent = self.panel, id = wx.ID_ANY,
00140                                    choices = [_('Rename mapset'), _('Rename location'),
00141                                             _('Delete mapset'), _('Delete location')])
00142         self.manageloc.SetSelection(0)
00143 
00144         # textinputs
00145         self.tgisdbase = wx.TextCtrl(parent = self.panel, id = wx.ID_ANY, value = "", size = (300, -1),
00146                                      style = wx.TE_PROCESS_ENTER)
00147 
00148         # Locations
00149         self.lpanel = wx.Panel(parent = self.panel, id = wx.ID_ANY)
00150         self.lblocations = GListBox(parent = self.lpanel,
00151                                     id = wx.ID_ANY, size = (180, 200),
00152                                     choices = self.listOfLocations)
00153         
00154         self.lblocations.SetColumnWidth(0, 180)
00155 
00156         # TODO: sort; but keep PERMANENT on top of list
00157         # Mapsets
00158         self.mpanel = wx.Panel(parent = self.panel, id = wx.ID_ANY)
00159         self.lbmapsets = GListBox(parent = self.mpanel,
00160                                   id = wx.ID_ANY, size = (180, 200),
00161                                   choices = self.listOfMapsets)
00162         
00163         self.lbmapsets.SetColumnWidth(0, 180)
00164 
00165         # layout & properties
00166         self._set_properties()
00167         self._do_layout()
00168 
00169         # events
00170         self.bbrowse.Bind(wx.EVT_BUTTON,      self.OnBrowse)
00171         self.bstart.Bind(wx.EVT_BUTTON,       self.OnStart)
00172         self.bexit.Bind(wx.EVT_BUTTON,        self.OnExit)
00173         self.bhelp.Bind(wx.EVT_BUTTON,        self.OnHelp)
00174         self.bmapset.Bind(wx.EVT_BUTTON,      self.OnCreateMapset)
00175         self.bwizard.Bind(wx.EVT_BUTTON,      self.OnWizard)
00176         self.manageloc.Bind(wx.EVT_CHOICE,    self.OnManageLoc)
00177         self.lblocations.Bind(wx.EVT_LIST_ITEM_SELECTED, self.OnSelectLocation)
00178         self.lbmapsets.Bind(wx.EVT_LIST_ITEM_SELECTED,   self.OnSelectMapset)
00179         self.lbmapsets.Bind(wx.EVT_LIST_ITEM_ACTIVATED, self.OnStart)
00180         self.tgisdbase.Bind(wx.EVT_TEXT_ENTER, self.OnSetDatabase)
00181         self.Bind(wx.EVT_CLOSE,               self.OnCloseWindow)
00182         
00183     def _set_properties(self):
00184         """!Set frame properties"""
00185         self.SetTitle(_("Welcome to GRASS GIS"))
00186         self.SetIcon(wx.Icon(os.path.join(globalvar.ETCICONDIR, "grass.ico"),
00187                              wx.BITMAP_TYPE_ICO))
00188 
00189         self.lwelcome.SetForegroundColour(wx.Colour(35, 142, 35))
00190         self.lwelcome.SetFont(wx.Font(13, wx.DEFAULT, wx.NORMAL, wx.BOLD, 0, ""))
00191 
00192         self.bstart.SetForegroundColour(wx.Colour(35, 142, 35))
00193         self.bstart.SetToolTipString(_("Enter GRASS session"))
00194         self.bstart.Enable(False)
00195         self.bmapset.Enable(False)
00196         self.manageloc.Enable(False)
00197 
00198         # set database
00199         if not self.gisdbase:
00200             # sets an initial path for gisdbase if nothing in GISRC
00201             if os.path.isdir(os.getenv("HOME")):
00202                 self.gisdbase = os.getenv("HOME")
00203             else:
00204                 self.gisdbase = os.getcwd()
00205         try:
00206             self.tgisdbase.SetValue(self.gisdbase)
00207         except UnicodeDecodeError:
00208             wx.MessageBox(parent = self, caption = _("Error"),
00209                           message = _("Unable to set GRASS database. "
00210                                       "Check your locale settings."),
00211                           style = wx.OK | wx.ICON_ERROR | wx.CENTRE)
00212         
00213         self.OnSetDatabase(None)
00214         location = self.GetRCValue("LOCATION_NAME")
00215         if location == "<UNKNOWN>" or \
00216                 not os.path.isdir(os.path.join(self.gisdbase, location)):
00217             location = None
00218 
00219         if location:
00220             # list of locations
00221             self.UpdateLocations(self.gisdbase)
00222             try:
00223                 self.lblocations.SetSelection(self.listOfLocations.index(location),
00224                                               force = True)
00225                 self.lblocations.EnsureVisible(self.listOfLocations.index(location))
00226             except ValueError:
00227                 print >> sys.stderr, _("ERROR: Location <%s> not found") % \
00228                     (utils.UnicodeString(location))
00229                 
00230             # list of mapsets
00231             self.UpdateMapsets(os.path.join(self.gisdbase, location))
00232             mapset = self.GetRCValue("MAPSET")
00233             if mapset:
00234                 try:
00235                     self.lbmapsets.SetSelection(self.listOfMapsets.index(mapset),
00236                                                 force = True)
00237                     self.lbmapsets.EnsureVisible(self.listOfMapsets.index(mapset))
00238                 except ValueError:
00239                     self.lbmapsets.Clear()
00240                     print >> sys.stderr, _("ERROR: Mapset <%s> not found") % \
00241                         (utils.UnicodeString(mapset))
00242             
00243     def _do_layout(self):
00244         label_style = wx.ADJUST_MINSIZE | wx.ALIGN_CENTER_HORIZONTAL
00245 
00246         sizer           = wx.BoxSizer(wx.VERTICAL)
00247         dbase_sizer     = wx.BoxSizer(wx.HORIZONTAL)
00248         location_sizer  = wx.FlexGridSizer(rows = 1, cols = 2, vgap = 4, hgap = 4)
00249         select_boxsizer = wx.StaticBoxSizer(self.select_box, wx.VERTICAL)
00250         select_sizer    = wx.FlexGridSizer(rows = 2, cols = 2, vgap = 4, hgap = 4)
00251         manage_boxsizer = wx.StaticBoxSizer(self.manage_box, wx.VERTICAL)
00252         manage_sizer    = wx.BoxSizer(wx.VERTICAL)
00253         btns_sizer      = wx.BoxSizer(wx.HORIZONTAL)
00254 
00255         # gis data directory
00256         dbase_sizer.Add(item = self.ldbase, proportion = 0,
00257                         flag = wx.ALIGN_CENTER_VERTICAL |
00258                         wx.ALIGN_CENTER_HORIZONTAL | wx.ALL,
00259                         border = 3)
00260         dbase_sizer.Add(item = self.tgisdbase, proportion = 0,
00261                         flag = wx.ALIGN_CENTER_VERTICAL |
00262                         wx.ALIGN_CENTER_HORIZONTAL | wx.ALL,
00263                         border = 3)
00264         dbase_sizer.Add(item = self.bbrowse, proportion = 0,
00265                         flag = wx.ALIGN_CENTER_VERTICAL |
00266                         wx.ALIGN_CENTER_HORIZONTAL | wx.ALL,
00267                         border = 3)
00268 
00269         # select sizer
00270         select_sizer.Add(item = self.llocation, proportion = 0,
00271                          flag = label_style | wx.ALL,
00272                          border = 3)
00273         select_sizer.Add(item = self.lmapset, proportion = 0,
00274                          flag = label_style | wx.ALL,
00275                          border = 3)
00276         select_sizer.Add(item = self.lpanel, proportion = 0,
00277                          flag = wx.ADJUST_MINSIZE |
00278                          wx.ALIGN_CENTER_VERTICAL |
00279                          wx.ALIGN_CENTER_HORIZONTAL)
00280         select_sizer.Add(item = self.mpanel, proportion = 0,
00281                          flag = wx.ADJUST_MINSIZE |
00282                          wx.ALIGN_CENTER_VERTICAL |
00283                          wx.ALIGN_CENTER_HORIZONTAL)
00284 
00285         select_boxsizer.Add(item = select_sizer, proportion = 0)
00286 
00287         # define new location and mapset
00288         manage_sizer.Add(item = self.ldefine, proportion = 0,
00289                          flag = label_style | wx.ALL,
00290                          border = 3)
00291         manage_sizer.Add(item = self.bwizard, proportion = 0,
00292                          flag = label_style | wx.BOTTOM,
00293                          border = 5)
00294         manage_sizer.Add(item = self.lcreate, proportion = 0,
00295                          flag = label_style | wx.ALL,
00296                          border = 3)
00297         manage_sizer.Add(item = self.bmapset, proportion = 0,
00298                          flag = label_style | wx.BOTTOM,
00299                          border = 5)
00300         manage_sizer.Add(item = self.lmanageloc, proportion = 0,
00301                          flag = label_style | wx.ALL,
00302                          border = 3)
00303         manage_sizer.Add(item = self.manageloc, proportion = 0,
00304                          flag = label_style | wx.BOTTOM,
00305                          border = 5)
00306 
00307         manage_boxsizer.Add(item = manage_sizer, proportion = 0)
00308 
00309         # location sizer
00310         location_sizer.Add(item = select_boxsizer, proportion = 0,
00311                            flag = wx.ADJUST_MINSIZE |
00312                            wx.ALIGN_CENTER_VERTICAL |
00313                            wx.ALIGN_CENTER_HORIZONTAL |
00314                            wx.RIGHT | wx.LEFT | wx.EXPAND,
00315                            border = 3) # GISDBASE setting
00316         location_sizer.Add(item = manage_boxsizer, proportion = 0,
00317                            flag = wx.ADJUST_MINSIZE |
00318                            wx.ALIGN_TOP |
00319                            wx.ALIGN_CENTER_HORIZONTAL |
00320                            wx.RIGHT | wx.EXPAND,
00321                            border = 3)
00322 
00323         # buttons
00324         btns_sizer.Add(item = self.bstart, proportion = 0,
00325                        flag = wx.ALIGN_CENTER_HORIZONTAL |
00326                        wx.ALIGN_CENTER_VERTICAL |
00327                        wx.ALL,
00328                        border = 5)
00329         btns_sizer.Add(item = self.bexit, proportion = 0,
00330                        flag = wx.ALIGN_CENTER_HORIZONTAL |
00331                        wx.ALIGN_CENTER_VERTICAL |
00332                        wx.ALL,
00333                        border = 5)
00334         btns_sizer.Add(item = self.bhelp, proportion = 0,
00335                        flag = wx.ALIGN_CENTER_HORIZONTAL |
00336                        wx.ALIGN_CENTER_VERTICAL |
00337                        wx.ALL,
00338                        border = 5)
00339 
00340         # main sizer
00341         sizer.Add(item = self.hbitmap,
00342                   proportion = 0,
00343                   flag = wx.ALIGN_CENTER_VERTICAL |
00344                   wx.ALIGN_CENTER_HORIZONTAL |
00345                   wx.ALL,
00346                   border = 3) # image
00347         sizer.Add(item = self.lwelcome, # welcome message
00348                   proportion = 0,
00349                   flag = wx.ALIGN_CENTER_VERTICAL |
00350                   wx.ALIGN_CENTER_HORIZONTAL |
00351                   wx.BOTTOM,
00352                   border=1)
00353         sizer.Add(item = self.ltitle, # title
00354                   proportion = 0,
00355                   flag = wx.ALIGN_CENTER_VERTICAL |
00356                   wx.ALIGN_CENTER_HORIZONTAL)
00357         sizer.Add(item = dbase_sizer, proportion = 0,
00358                   flag = wx.ALIGN_CENTER_HORIZONTAL |
00359                   wx.RIGHT | wx.LEFT,
00360                   border = 1) # GISDBASE setting
00361         sizer.Add(item = location_sizer, proportion = 1,
00362                   flag = wx.ALIGN_CENTER_VERTICAL |
00363                   wx.ALIGN_CENTER_HORIZONTAL |
00364                   wx.RIGHT | wx.LEFT,
00365                   border = 1)
00366         sizer.Add(item = btns_sizer, proportion = 0,
00367                   flag = wx.ALIGN_CENTER_VERTICAL |
00368                   wx.ALIGN_CENTER_HORIZONTAL |
00369                   wx.RIGHT | wx.LEFT,
00370                   border = 1)
00371 
00372         self.panel.SetAutoLayout(True)
00373         self.panel.SetSizer(sizer)
00374         sizer.Fit(self.panel)
00375         sizer.SetSizeHints(self)
00376 
00377         self.Layout()
00378 
00379     def _readGisRC(self):
00380         """
00381         Read variables from $HOME/.grassrc6 file
00382         """
00383 
00384         grassrc = {}
00385         
00386         gisrc = os.getenv("GISRC")
00387         
00388         if gisrc and os.path.isfile(gisrc):
00389             try:
00390                 rc = open(gisrc, "r")
00391                 for line in rc.readlines():
00392                     key, val = line.split(":", 1)
00393                     grassrc[key.strip()] = utils.DecodeString(val.strip())
00394             finally:
00395                 rc.close()
00396         
00397         return grassrc
00398 
00399     def GetRCValue(self, value):
00400         """!Return GRASS variable (read from GISRC)
00401         """
00402         if self.grassrc.has_key(value):
00403             return self.grassrc[value]
00404         else:
00405             return None
00406         
00407     def OnWizard(self, event):
00408         """!Location wizard started"""
00409         from gui_modules import location_wizard
00410         gWizard = location_wizard.LocationWizard(parent = self,
00411                                                  grassdatabase = self.tgisdbase.GetValue())
00412         if gWizard.location !=  None:
00413             self.OnSetDatabase(event)
00414             self.UpdateMapsets(os.path.join(self.gisdbase, gWizard.location))
00415             self.lblocations.SetSelection(self.listOfLocations.index(gWizard.location))
00416             self.lbmapsets.SetSelection(0)
00417 
00418     def OnManageLoc(self, event):
00419         """!Location management choice control handler
00420         """
00421         sel = event.GetSelection()
00422         if sel ==  0:
00423             self.RenameMapset()
00424         elif sel ==  1:
00425             self.RenameLocation()
00426         elif sel ==  2:
00427             self.DeleteMapset()
00428         elif sel ==  3:
00429             self.DeleteLocation()
00430         
00431         event.Skip()
00432         
00433     def RenameMapset(self):
00434         """!Rename selected mapset
00435         """
00436         location = utils.UnicodeString(self.listOfLocations[self.lblocations.GetSelection()])
00437         mapset   = utils.UnicodeString(self.listOfMapsets[self.lbmapsets.GetSelection()])
00438         if mapset ==  'PERMANENT':
00439             GMessage(parent = self,
00440                      message = _('Mapset <PERMANENT> is required for valid GRASS location.\n\n'
00441                                  'This mapset cannot be renamed.'))
00442             return
00443         
00444         dlg = wx.TextEntryDialog(parent = self,
00445                                  message = _('Current name: %s\n\nEnter new name:') % mapset,
00446                                  caption = _('Rename selected mapset'))
00447         
00448         if dlg.ShowModal() ==  wx.ID_OK:
00449             newmapset = dlg.GetValue()
00450             if newmapset ==  mapset:
00451                 dlg.Destroy()
00452                 return
00453             
00454             if newmapset in self.listOfMapsets:
00455                 wx.MessageBox(parent = self,
00456                               caption = _('Message'),
00457                               message = _('Unable to rename mapset.\n\n'
00458                                         'Mapset <%s> already exists in location.') % newmapset,
00459                               style = wx.OK | wx.ICON_INFORMATION | wx.CENTRE)
00460             else:
00461                 try:
00462                     os.rename(os.path.join(self.gisdbase, location, mapset),
00463                               os.path.join(self.gisdbase, location, newmapset))
00464                     self.OnSelectLocation(None)
00465                     self.lbmapsets.SetSelection(self.listOfMapsets.index(newmapset))
00466                 except StandardError, e:
00467                     wx.MessageBox(parent = self,
00468                                   caption = _('Error'),
00469                                   message = _('Unable to rename mapset.\n\n%s') % e,
00470                                   style = wx.OK | wx.ICON_ERROR | wx.CENTRE)
00471             
00472         dlg.Destroy()
00473 
00474     def RenameLocation(self):
00475         """!Rename selected location
00476         """
00477         location = utils.UnicodeString(self.listOfLocations[self.lblocations.GetSelection()])
00478 
00479         dlg = wx.TextEntryDialog(parent = self,
00480                                  message = _('Current name: %s\n\nEnter new name:') % location,
00481                                  caption = _('Rename selected location'))
00482 
00483         if dlg.ShowModal() ==  wx.ID_OK:
00484             newlocation = dlg.GetValue()
00485             if newlocation ==  location:
00486                 dlg.Destroy()
00487                 return
00488 
00489             if newlocation in self.listOfLocations:
00490                 wx.MessageBox(parent = self,
00491                               caption = _('Message'),
00492                               message = _('Unable to rename location.\n\n'
00493                                         'Location <%s> already exists in GRASS database.') % newlocation,
00494                               style = wx.OK | wx.ICON_INFORMATION | wx.CENTRE)
00495             else:
00496                 try:
00497                     os.rename(os.path.join(self.gisdbase, location),
00498                               os.path.join(self.gisdbase, newlocation))
00499                     self.UpdateLocations(self.gisdbase)
00500                     self.lblocations.SetSelection(self.listOfLocations.index(newlocation))
00501                     self.UpdateMapsets(newlocation)
00502                 except StandardError, e:
00503                     wx.MessageBox(parent = self,
00504                                   caption = _('Error'),
00505                                   message = _('Unable to rename location.\n\n%s') % e,
00506                                   style = wx.OK | wx.ICON_ERROR | wx.CENTRE)
00507         
00508         dlg.Destroy()
00509 
00510     def DeleteMapset(self):
00511         """!Delete selected mapset
00512         """
00513         location = self.listOfLocations[self.lblocations.GetSelection()]
00514         mapset   = self.listOfMapsets[self.lbmapsets.GetSelection()]
00515         if mapset ==  'PERMANENT':
00516             GMessage(parent = self,
00517                      message = _('Mapset <PERMANENT> is required for valid GRASS location.\n\n'
00518                                  'This mapset cannot be deleted.'))
00519             return
00520         
00521         dlg = wx.MessageDialog(parent = self, message = _("Do you want to continue with deleting mapset <%(mapset)s> "
00522                                                       "from location <%(location)s>?\n\n"
00523                                                       "ALL MAPS included in this mapset will be "
00524                                                       "PERMANENTLY DELETED!") % {'mapset' : mapset,
00525                                                                                  'location' : location},
00526                                caption = _("Delete selected mapset"),
00527                                style = wx.YES_NO | wx.NO_DEFAULT | wx.ICON_QUESTION)
00528 
00529         if dlg.ShowModal() ==  wx.ID_YES:
00530             try:
00531                 shutil.rmtree(os.path.join(self.gisdbase, location, mapset))
00532                 self.OnSelectLocation(None)
00533                 self.lbmapsets.SetSelection(0)
00534             except:
00535                 wx.MessageBox(message = _('Unable to delete mapset'))
00536 
00537         dlg.Destroy()
00538 
00539     def DeleteLocation(self):
00540         """
00541         Delete selected location
00542         """
00543 
00544         location = self.listOfLocations[self.lblocations.GetSelection()]
00545 
00546         dlg = wx.MessageDialog(parent = self, message = _("Do you want to continue with deleting "
00547                                                       "location <%s>?\n\n"
00548                                                       "ALL MAPS included in this location will be "
00549                                                       "PERMANENTLY DELETED!") % (location),
00550                                caption = _("Delete selected location"),
00551                                style = wx.YES_NO | wx.NO_DEFAULT | wx.ICON_QUESTION)
00552 
00553         if dlg.ShowModal() ==  wx.ID_YES:
00554             try:
00555                 shutil.rmtree(os.path.join(self.gisdbase, location))
00556                 self.UpdateLocations(self.gisdbase)
00557                 self.lblocations.SetSelection(0)
00558                 self.OnSelectLocation(None)
00559                 self.lbmapsets.SetSelection(0)
00560             except:
00561                 wx.MessageBox(message = _('Unable to delete location'))
00562 
00563         dlg.Destroy()
00564 
00565     def UpdateLocations(self, dbase):
00566         """!Update list of locations"""
00567         try:
00568             self.listOfLocations = utils.GetListOfLocations(dbase)
00569         except UnicodeEncodeError:
00570             wx.MessageBox(parent = self, caption = _("Error"),
00571                           message = _("Unable to set GRASS database. "
00572                                       "Check your locale settings."),
00573                           style = wx.OK | wx.ICON_ERROR | wx.CENTRE)
00574         
00575         self.lblocations.Clear()
00576         self.lblocations.InsertItems(self.listOfLocations, 0)
00577 
00578         if len(self.listOfLocations) > 0:
00579             self.lblocations.SetSelection(0)
00580         else:
00581             self.lblocations.SetSelection(wx.NOT_FOUND)
00582 
00583         return self.listOfLocations
00584 
00585     def UpdateMapsets(self, location):
00586         """!Update list of mapsets"""
00587         self.FormerMapsetSelection = wx.NOT_FOUND # for non-selectable item
00588         
00589         self.listOfMapsetsSelectable = list()
00590         self.listOfMapsets = utils.GetListOfMapsets(self.gisdbase, location)
00591         
00592         self.lbmapsets.Clear()
00593         
00594         # disable mapset with denied permission
00595         locationName = os.path.basename(location)
00596         
00597         ret = gcmd.RunCommand('g.mapset',
00598                               read = True,
00599                               flags = 'l',
00600                               location = locationName,
00601                               gisdbase = self.gisdbase)
00602             
00603         if ret:
00604             for line in ret.splitlines():
00605                 self.listOfMapsetsSelectable += line.split(' ')
00606         else:
00607             gcmd.RunCommand("g.gisenv",
00608                             set = "GISDBASE=%s" % self.gisdbase)
00609             gcmd.RunCommand("g.gisenv",
00610                             set = "LOCATION_NAME=%s" % locationName)
00611             gcmd.RunCommand("g.gisenv",
00612                             set = "MAPSET=PERMANENT")
00613             # first run only
00614             self.listOfMapsetsSelectable = copy.copy(self.listOfMapsets)
00615         
00616         disabled = []
00617         idx = 0
00618         for mapset in self.listOfMapsets:
00619             if mapset not in self.listOfMapsetsSelectable or \
00620                     os.path.isfile(os.path.join(self.gisdbase,
00621                                                 locationName,
00622                                                 mapset, ".gislock")):
00623                 disabled.append(idx)
00624             idx +=  1
00625         
00626         self.lbmapsets.InsertItems(self.listOfMapsets, 0, disabled = disabled)
00627         
00628         return self.listOfMapsets
00629 
00630     def OnSelectLocation(self, event):
00631         """!Location selected"""
00632         if event:
00633             self.lblocations.SetSelection(event.GetIndex())
00634             
00635         if self.lblocations.GetSelection() !=  wx.NOT_FOUND:
00636             self.UpdateMapsets(os.path.join(self.gisdbase,
00637                                             self.listOfLocations[self.lblocations.GetSelection()]))
00638         else:
00639             self.listOfMapsets = []
00640         
00641         disabled = []
00642         idx = 0
00643         try:
00644             locationName = self.listOfLocations[self.lblocations.GetSelection()]
00645         except IndexError:
00646             locationName = ''
00647         
00648         for mapset in self.listOfMapsets:
00649             if mapset not in self.listOfMapsetsSelectable or \
00650                     os.path.isfile(os.path.join(self.gisdbase,
00651                                                 locationName,
00652                                                 mapset, ".gislock")):
00653                 disabled.append(idx)
00654             idx +=  1
00655 
00656         self.lbmapsets.Clear()
00657         self.lbmapsets.InsertItems(self.listOfMapsets, 0, disabled = disabled)
00658 
00659         if len(self.listOfMapsets) > 0:
00660             self.lbmapsets.SetSelection(0)
00661             if locationName:
00662                 # enable start button when location and mapset is selected
00663                 self.bstart.Enable()
00664                 self.bmapset.Enable()
00665                 self.manageloc.Enable()
00666         else:
00667             self.lbmapsets.SetSelection(wx.NOT_FOUND)
00668             self.bstart.Enable(False)
00669             self.bmapset.Enable(False)
00670             self.manageloc.Enable(False)
00671         
00672     def OnSelectMapset(self, event):
00673         """!Mapset selected"""
00674         self.lbmapsets.SetSelection(event.GetIndex())
00675 
00676         if event.GetText() not in self.listOfMapsetsSelectable:
00677             self.lbmapsets.SetSelection(self.FormerMapsetSelection)
00678         else:
00679             self.FormerMapsetSelection = event.GetIndex()
00680             event.Skip()
00681 
00682     def OnSetDatabase(self, event):
00683         """!Database set"""
00684         self.gisdbase = self.tgisdbase.GetValue()
00685         
00686         self.UpdateLocations(self.gisdbase)
00687 
00688         self.OnSelectLocation(None)
00689 
00690     def OnBrowse(self, event):
00691         """'Browse' button clicked"""
00692         grassdata = None
00693 
00694         dlg = wx.DirDialog(self, _("Choose GIS Data Directory:"),
00695                            style = wx.DD_DEFAULT_STYLE | wx.DD_NEW_DIR_BUTTON)
00696         if dlg.ShowModal() ==  wx.ID_OK:
00697             self.gisdbase = dlg.GetPath()
00698             self.tgisdbase.SetValue(self.gisdbase)
00699             self.OnSetDatabase(event)
00700 
00701         dlg.Destroy()
00702 
00703     def OnCreateMapset(self,event):
00704         """!Create new mapset"""
00705         self.gisdbase = self.tgisdbase.GetValue()
00706         location = self.listOfLocations[self.lblocations.GetSelection()]
00707 
00708         dlg = wx.TextEntryDialog(parent = self,
00709                                  message = _('Enter name for new mapset:'),
00710                                  caption = _('Create new mapset'))
00711 
00712         if dlg.ShowModal() ==  wx.ID_OK:
00713             mapset = dlg.GetValue()
00714             try:
00715                 os.mkdir(os.path.join(self.gisdbase, location, mapset))
00716                 # copy WIND file and its permissions from PERMANENT and set permissions to u+rw,go+r
00717                 shutil.copy(os.path.join(self.gisdbase, location, 'PERMANENT', 'WIND'),
00718                             os.path.join(self.gisdbase, location, mapset))
00719                 # os.chmod(os.path.join(database,location,mapset,'WIND'), 0644)
00720                 self.OnSelectLocation(None)
00721                 self.lbmapsets.SetSelection(self.listOfMapsets.index(mapset))
00722             except StandardError, e:
00723                 dlg = wx.MessageDialog(parent = self, message = _("Unable to create new mapset: %s") % e,
00724                                        caption = _("Error"), style = wx.OK | wx.ICON_ERROR)
00725                 dlg.ShowModal()
00726                 dlg.Destroy()
00727                 return False
00728         
00729         self.bstart.SetFocus()
00730         
00731         return True
00732 
00733     def OnStart(self, event):
00734         """'Start GRASS' button clicked"""
00735         dbase    = self.tgisdbase.GetValue()
00736         location = self.listOfLocations[self.lblocations.GetSelection()]
00737         mapset   = self.listOfMapsets[self.lbmapsets.GetSelection()]
00738         
00739         lockfile = os.path.join(dbase, location, mapset, '.gislock')
00740         if os.path.isfile(lockfile):
00741             dlg = wx.MessageDialog(parent = self,
00742                                    message = _("GRASS is already running in selected mapset <%(mapset)s>\n"
00743                                                "(file %(lock)s found).\n\n"
00744                                                "Concurrent use not allowed.\n\n"
00745                                                "Do you want to try to remove .gislock (note that you "
00746                                                "need permission for this operation) and continue?") % 
00747                                    { 'mapset' : mapset, 'lock' : lockfile },
00748                                    caption = _("Lock file found"),
00749                                    style = wx.YES_NO | wx.NO_DEFAULT |
00750                                    wx.ICON_QUESTION | wx.CENTRE)
00751             
00752             ret = dlg.ShowModal()
00753             dlg.Destroy()
00754             if ret == wx.ID_YES:
00755                 dlg1 = wx.MessageDialog(parent = self,
00756                                         message = _("ARE YOU REALLY SURE?\n\n"
00757                                                     "If you really are running another GRASS session doing this "
00758                                                     "could corrupt your data. Have another look in the processor "
00759                                                     "manager just to be sure..."),
00760                                         caption = _("Lock file found"),
00761                                         style = wx.YES_NO | wx.NO_DEFAULT |
00762                                         wx.ICON_QUESTION | wx.CENTRE)
00763                 
00764                 ret = dlg1.ShowModal()
00765                 dlg1.Destroy()
00766                 
00767                 if ret == wx.ID_YES:
00768                     try:
00769                         os.remove(lockfile)
00770                     except IOError, e:
00771                         GError(_("Unable to remove '%(lock)s'.\n\n"
00772                                  "Details: %(reason)s") % { 'lock' : lockfile, 'reason' : e})
00773                 else:
00774                     return
00775             else:
00776                 return
00777         
00778         gcmd.RunCommand("g.gisenv",
00779                         set = "GISDBASE=%s" % dbase)
00780         gcmd.RunCommand("g.gisenv",
00781                         set = "LOCATION_NAME=%s" % location)
00782         gcmd.RunCommand("g.gisenv",
00783                         set = "MAPSET=%s" % mapset)
00784         
00785         self.Destroy()
00786         sys.exit(0)
00787 
00788     def OnExit(self, event):
00789         """'Exit' button clicked"""
00790         self.Destroy()
00791         sys.exit (2)
00792 
00793     def OnHelp(self, event):
00794         """'Help' button clicked"""
00795         # help text in lib/init/helptext.html
00796         file = os.path.join(self.gisbase, "docs", "html", "helptext.html")
00797 
00798         helpFrame = HelpFrame(parent = self, id = wx.ID_ANY,
00799                               title = _("GRASS Quickstart"),
00800                               size = (640, 480),
00801                               file = file)
00802         helpFrame.Show(True)
00803 
00804         event.Skip()
00805 
00806     def OnCloseWindow(self, event):
00807         """!Close window event"""
00808         event.Skip()
00809         sys.exit(2)
00810 
00811 class GListBox(wx.ListCtrl, listmix.ListCtrlAutoWidthMixin):
00812     """!Use wx.ListCtrl instead of wx.ListBox, different style for
00813     non-selectable items (e.g. mapsets with denied permission)"""
00814     def __init__(self, parent, id, size,
00815                  choices, disabled = []):
00816         wx.ListCtrl.__init__(self, parent, id, size = size,
00817                              style = wx.LC_REPORT | wx.LC_NO_HEADER | wx.LC_SINGLE_SEL |
00818                              wx.BORDER_SUNKEN)
00819         
00820         listmix.ListCtrlAutoWidthMixin.__init__(self)
00821         
00822         self.InsertColumn(0, '')
00823         
00824         self.selected = wx.NOT_FOUND
00825         
00826         self._LoadData(choices, disabled)
00827         
00828     def _LoadData(self, choices, disabled = []):
00829         """!Load data into list
00830         
00831         @param choices list of item
00832         @param disabled list of indeces of non-selectable items
00833         """
00834         idx = 0
00835         for item in choices:
00836             index = self.InsertStringItem(sys.maxint, item)
00837             self.SetStringItem(index, 0, item)
00838             
00839             if idx in disabled:
00840                 self.SetItemTextColour(idx, wx.Colour(150, 150, 150))
00841             idx +=  1
00842         
00843     def Clear(self):
00844         self.DeleteAllItems()
00845         
00846     def InsertItems(self, choices, pos, disabled = []):
00847         self._LoadData(choices, disabled)
00848         
00849     def SetSelection(self, item, force = False):
00850         if item !=  wx.NOT_FOUND and \
00851                 (platform.system() !=  'Windows' or force):
00852             ### Windows -> FIXME
00853             self.SetItemState(item, wx.LIST_STATE_SELECTED, wx.LIST_STATE_SELECTED)
00854         
00855         self.selected = item
00856         
00857     def GetSelection(self):
00858         return self.selected
00859         
00860 class StartUp(wx.App):
00861     """!Start-up application"""
00862 
00863     def OnInit(self):
00864         wx.InitAllImageHandlers()
00865         StartUp = GRASSStartup()
00866         StartUp.CenterOnScreen()
00867         self.SetTopWindow(StartUp)
00868         StartUp.Show()
00869         
00870         if StartUp.GetRCValue("LOCATION_NAME") ==  "<UNKNOWN>":
00871             wx.MessageBox(parent = StartUp,
00872                           caption = _('Starting GRASS for the first time'),
00873                           message = _('GRASS needs a directory in which to store its data. '
00874                                     'Create one now if you have not already done so. '
00875                                     'A popular choice is "grassdata", located in '
00876                                     'your home directory.'),
00877                           style = wx.OK | wx.ICON_ERROR | wx.CENTRE)
00878             
00879             StartUp.OnBrowse(None)
00880         
00881         return 1
00882 
00883 if __name__ ==  "__main__":
00884 
00885     if os.getenv("GISBASE") is None:
00886         print >> sys.stderr, "Failed to start GUI, GRASS GIS is not running."
00887     else:
00888         import gettext
00889         gettext.install('grasswxpy', os.path.join(os.getenv("GISBASE"), 'locale'), unicode = True)
00890 
00891         import gui_modules.gcmd as gcmd
00892         import gui_modules.utils as utils
00893 
00894         GRASSStartUp = StartUp(0)
00895         GRASSStartUp.MainLoop()
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines