GRASS Programmer's Manual  6.4.2(2012)
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
gis_set.py
Go to the documentation of this file.
1 """!
2 @package gis_set.py
3 
4 GRASS start-up screen.
5 
6 Initialization module for wxPython GRASS GUI.
7 Location/mapset management (selection, creation, etc.).
8 
9 Classes:
10  - GRASSStartup
11  - GListBox
12  - StartUp
13 
14 (C) 2006-2011 by the GRASS Development Team
15 
16 This program is free software under the GNU General Public License
17 (>=v2). Read the file COPYING that comes with GRASS for details.
18 
19 @author Michael Barton and Jachym Cepicky (original author)
20 @author Martin Landa <landa.martin gmail.com> (various updates)
21 """
22 
23 import os
24 import sys
25 import glob
26 import shutil
27 import copy
28 import platform
29 import codecs
30 
31 ### i18N
32 import gettext
33 gettext.install('grasswxpy', os.path.join(os.getenv("GISBASE"), 'locale'), unicode = True)
34 
35 from gui_modules import globalvar
36 import wx
37 import wx.html
38 import wx.lib.rcsizer as rcs
39 import wx.lib.filebrowsebutton as filebrowse
40 import wx.lib.mixins.listctrl as listmix
41 import wx.lib.scrolledpanel as scrolled
42 
43 from gui_modules import goutput
44 from gui_modules.ghelp import HelpFrame
45 from gui_modules.gcmd import GMessage, GError
46 
47 sys.stderr = codecs.getwriter('utf8')(sys.stderr)
48 
49 class GRASSStartup(wx.Frame):
50  """!GRASS start-up screen"""
51  def __init__(self, parent = None, id = wx.ID_ANY, style = wx.DEFAULT_FRAME_STYLE):
52 
53  #
54  # GRASS variables
55  #
56  self.gisbase = os.getenv("GISBASE")
57  self.grassrc = self._readGisRC()
58  self.gisdbase = self.GetRCValue("GISDBASE")
59 
60  #
61  # list of locations/mapsets
62  #
63  self.listOfLocations = []
64  self.listOfMapsets = []
66 
67  wx.Frame.__init__(self, parent = parent, id = id, style = style)
68 
69  self.locale = wx.Locale(language = wx.LANGUAGE_DEFAULT)
70 
71  self.panel = scrolled.ScrolledPanel(parent = self, id = wx.ID_ANY)
72 
73  # i18N
74  import gettext
75  gettext.install('grasswxpy', os.path.join(os.getenv("GISBASE"), 'locale'), unicode = True)
76 
77  #
78  # graphical elements
79  #
80  # image
81  try:
82  name = os.path.join(globalvar.ETCIMGDIR, "startup_banner.gif")
83  self.hbitmap = wx.StaticBitmap(self.panel, wx.ID_ANY,
84  wx.Bitmap(name = name,
85  type = wx.BITMAP_TYPE_GIF))
86  except:
87  self.hbitmap = wx.StaticBitmap(self.panel, wx.ID_ANY, wx.EmptyBitmap(530,150))
88 
89  # labels
90  ### crashes when LOCATION doesn't exist
91  versionFile = open(os.path.join(globalvar.ETCDIR, "VERSIONNUMBER"))
92  grassVersion = versionFile.readline().split(' ')[0].rstrip('\n')
93  versionFile.close()
94 
95  self.select_box = wx.StaticBox (parent = self.panel, id = wx.ID_ANY,
96  label = " %s " % _("Choose project location and mapset"))
97 
98  self.manage_box = wx.StaticBox (parent = self.panel, id = wx.ID_ANY,
99  label = " %s " % _("Manage"))
100  self.lwelcome = wx.StaticText(parent = self.panel, id = wx.ID_ANY,
101  label = _("Welcome to GRASS GIS %s\n"
102  "The world's leading open source GIS") % grassVersion,
103  style = wx.ALIGN_CENTRE)
104  self.ltitle = wx.StaticText(parent = self.panel, id = wx.ID_ANY,
105  label = _("Select an existing project location and mapset\n"
106  "or define a new location"),
107  style = wx.ALIGN_CENTRE)
108  self.ldbase = wx.StaticText(parent = self.panel, id = wx.ID_ANY,
109  label = _("GIS Data Directory:"))
110  self.llocation = wx.StaticText(parent = self.panel, id = wx.ID_ANY,
111  label = _("Project location\n(projection/coordinate system)"),
112  style = wx.ALIGN_CENTRE)
113  self.lmapset = wx.StaticText(parent = self.panel, id = wx.ID_ANY,
114  label = _("Accessible mapsets\n(directories of GIS files)"),
115  style = wx.ALIGN_CENTRE)
116  self.lcreate = wx.StaticText(parent = self.panel, id = wx.ID_ANY,
117  label = _("Create new mapset\nin selected location"),
118  style = wx.ALIGN_CENTRE)
119  self.ldefine = wx.StaticText(parent = self.panel, id = wx.ID_ANY,
120  label = _("Define new location"),
121  style = wx.ALIGN_CENTRE)
122  self.lmanageloc = wx.StaticText(parent = self.panel, id = wx.ID_ANY,
123  label = _("Rename/delete selected\nmapset or location"),
124  style = wx.ALIGN_CENTRE)
125 
126  # buttons
127  self.bstart = wx.Button(parent = self.panel, id = wx.ID_ANY,
128  label = _("Start &GRASS"))
129  self.bstart.SetDefault()
130  self.bexit = wx.Button(parent = self.panel, id = wx.ID_EXIT)
131  self.bstart.SetMinSize((180, self.bexit.GetSize()[1]))
132  self.bhelp = wx.Button(parent = self.panel, id = wx.ID_HELP)
133  self.bbrowse = wx.Button(parent = self.panel, id = wx.ID_ANY,
134  label = _("&Browse"))
135  self.bmapset = wx.Button(parent = self.panel, id = wx.ID_ANY,
136  label = _("&Create mapset"))
137  self.bwizard = wx.Button(parent = self.panel, id = wx.ID_ANY,
138  label = _("&Location wizard"))
139  self.manageloc = wx.Choice(parent = self.panel, id = wx.ID_ANY,
140  choices = [_('Rename mapset'), _('Rename location'),
141  _('Delete mapset'), _('Delete location')])
142  self.manageloc.SetSelection(0)
143 
144  # textinputs
145  self.tgisdbase = wx.TextCtrl(parent = self.panel, id = wx.ID_ANY, value = "", size = (300, -1),
146  style = wx.TE_PROCESS_ENTER)
147 
148  # Locations
149  self.lpanel = wx.Panel(parent = self.panel, id = wx.ID_ANY)
150  self.lblocations = GListBox(parent = self.lpanel,
151  id = wx.ID_ANY, size = (180, 200),
152  choices = self.listOfLocations)
153 
154  self.lblocations.SetColumnWidth(0, 180)
155 
156  # TODO: sort; but keep PERMANENT on top of list
157  # Mapsets
158  self.mpanel = wx.Panel(parent = self.panel, id = wx.ID_ANY)
159  self.lbmapsets = GListBox(parent = self.mpanel,
160  id = wx.ID_ANY, size = (180, 200),
161  choices = self.listOfMapsets)
162 
163  self.lbmapsets.SetColumnWidth(0, 180)
164 
165  # layout & properties
166  self._set_properties()
167  self._do_layout()
168 
169  # events
170  self.bbrowse.Bind(wx.EVT_BUTTON, self.OnBrowse)
171  self.bstart.Bind(wx.EVT_BUTTON, self.OnStart)
172  self.bexit.Bind(wx.EVT_BUTTON, self.OnExit)
173  self.bhelp.Bind(wx.EVT_BUTTON, self.OnHelp)
174  self.bmapset.Bind(wx.EVT_BUTTON, self.OnCreateMapset)
175  self.bwizard.Bind(wx.EVT_BUTTON, self.OnWizard)
176  self.manageloc.Bind(wx.EVT_CHOICE, self.OnManageLoc)
177  self.lblocations.Bind(wx.EVT_LIST_ITEM_SELECTED, self.OnSelectLocation)
178  self.lbmapsets.Bind(wx.EVT_LIST_ITEM_SELECTED, self.OnSelectMapset)
179  self.lbmapsets.Bind(wx.EVT_LIST_ITEM_ACTIVATED, self.OnStart)
180  self.tgisdbase.Bind(wx.EVT_TEXT_ENTER, self.OnSetDatabase)
181  self.Bind(wx.EVT_CLOSE, self.OnCloseWindow)
182 
183  def _set_properties(self):
184  """!Set frame properties"""
185  self.SetTitle(_("Welcome to GRASS GIS"))
186  self.SetIcon(wx.Icon(os.path.join(globalvar.ETCICONDIR, "grass.ico"),
187  wx.BITMAP_TYPE_ICO))
188 
189  self.lwelcome.SetForegroundColour(wx.Colour(35, 142, 35))
190  self.lwelcome.SetFont(wx.Font(13, wx.DEFAULT, wx.NORMAL, wx.BOLD, 0, ""))
191 
192  self.bstart.SetForegroundColour(wx.Colour(35, 142, 35))
193  self.bstart.SetToolTipString(_("Enter GRASS session"))
194  self.bstart.Enable(False)
195  self.bmapset.Enable(False)
196  self.manageloc.Enable(False)
197 
198  # set database
199  if not self.gisdbase:
200  # sets an initial path for gisdbase if nothing in GISRC
201  if os.path.isdir(os.getenv("HOME")):
202  self.gisdbase = os.getenv("HOME")
203  else:
204  self.gisdbase = os.getcwd()
205  try:
206  self.tgisdbase.SetValue(self.gisdbase)
207  except UnicodeDecodeError:
208  wx.MessageBox(parent = self, caption = _("Error"),
209  message = _("Unable to set GRASS database. "
210  "Check your locale settings."),
211  style = wx.OK | wx.ICON_ERROR | wx.CENTRE)
212 
213  self.OnSetDatabase(None)
214  location = self.GetRCValue("LOCATION_NAME")
215  if location == "<UNKNOWN>" or \
216  not os.path.isdir(os.path.join(self.gisdbase, location)):
217  location = None
218 
219  if location:
220  # list of locations
221  self.UpdateLocations(self.gisdbase)
222  try:
223  self.lblocations.SetSelection(self.listOfLocations.index(location),
224  force = True)
225  self.lblocations.EnsureVisible(self.listOfLocations.index(location))
226  except ValueError:
227  print >> sys.stderr, _("ERROR: Location <%s> not found") % \
228  (utils.UnicodeString(location))
229 
230  # list of mapsets
231  self.UpdateMapsets(os.path.join(self.gisdbase, location))
232  mapset = self.GetRCValue("MAPSET")
233  if mapset:
234  try:
235  self.lbmapsets.SetSelection(self.listOfMapsets.index(mapset),
236  force = True)
237  self.lbmapsets.EnsureVisible(self.listOfMapsets.index(mapset))
238  except ValueError:
239  self.lbmapsets.Clear()
240  print >> sys.stderr, _("ERROR: Mapset <%s> not found") % \
241  (utils.UnicodeString(mapset))
242 
243  def _do_layout(self):
244  label_style = wx.ADJUST_MINSIZE | wx.ALIGN_CENTER_HORIZONTAL
245 
246  sizer = wx.BoxSizer(wx.VERTICAL)
247  dbase_sizer = wx.BoxSizer(wx.HORIZONTAL)
248  location_sizer = wx.FlexGridSizer(rows = 1, cols = 2, vgap = 4, hgap = 4)
249  select_boxsizer = wx.StaticBoxSizer(self.select_box, wx.VERTICAL)
250  select_sizer = wx.FlexGridSizer(rows = 2, cols = 2, vgap = 4, hgap = 4)
251  manage_boxsizer = wx.StaticBoxSizer(self.manage_box, wx.VERTICAL)
252  manage_sizer = wx.BoxSizer(wx.VERTICAL)
253  btns_sizer = wx.BoxSizer(wx.HORIZONTAL)
254 
255  # gis data directory
256  dbase_sizer.Add(item = self.ldbase, proportion = 0,
257  flag = wx.ALIGN_CENTER_VERTICAL |
258  wx.ALIGN_CENTER_HORIZONTAL | wx.ALL,
259  border = 3)
260  dbase_sizer.Add(item = self.tgisdbase, proportion = 0,
261  flag = wx.ALIGN_CENTER_VERTICAL |
262  wx.ALIGN_CENTER_HORIZONTAL | wx.ALL,
263  border = 3)
264  dbase_sizer.Add(item = self.bbrowse, proportion = 0,
265  flag = wx.ALIGN_CENTER_VERTICAL |
266  wx.ALIGN_CENTER_HORIZONTAL | wx.ALL,
267  border = 3)
268 
269  # select sizer
270  select_sizer.Add(item = self.llocation, proportion = 0,
271  flag = label_style | wx.ALL,
272  border = 3)
273  select_sizer.Add(item = self.lmapset, proportion = 0,
274  flag = label_style | wx.ALL,
275  border = 3)
276  select_sizer.Add(item = self.lpanel, proportion = 0,
277  flag = wx.ADJUST_MINSIZE |
278  wx.ALIGN_CENTER_VERTICAL |
279  wx.ALIGN_CENTER_HORIZONTAL)
280  select_sizer.Add(item = self.mpanel, proportion = 0,
281  flag = wx.ADJUST_MINSIZE |
282  wx.ALIGN_CENTER_VERTICAL |
283  wx.ALIGN_CENTER_HORIZONTAL)
284 
285  select_boxsizer.Add(item = select_sizer, proportion = 0)
286 
287  # define new location and mapset
288  manage_sizer.Add(item = self.ldefine, proportion = 0,
289  flag = label_style | wx.ALL,
290  border = 3)
291  manage_sizer.Add(item = self.bwizard, proportion = 0,
292  flag = label_style | wx.BOTTOM,
293  border = 5)
294  manage_sizer.Add(item = self.lcreate, proportion = 0,
295  flag = label_style | wx.ALL,
296  border = 3)
297  manage_sizer.Add(item = self.bmapset, proportion = 0,
298  flag = label_style | wx.BOTTOM,
299  border = 5)
300  manage_sizer.Add(item = self.lmanageloc, proportion = 0,
301  flag = label_style | wx.ALL,
302  border = 3)
303  manage_sizer.Add(item = self.manageloc, proportion = 0,
304  flag = label_style | wx.BOTTOM,
305  border = 5)
306 
307  manage_boxsizer.Add(item = manage_sizer, proportion = 0)
308 
309  # location sizer
310  location_sizer.Add(item = select_boxsizer, proportion = 0,
311  flag = wx.ADJUST_MINSIZE |
312  wx.ALIGN_CENTER_VERTICAL |
313  wx.ALIGN_CENTER_HORIZONTAL |
314  wx.RIGHT | wx.LEFT | wx.EXPAND,
315  border = 3) # GISDBASE setting
316  location_sizer.Add(item = manage_boxsizer, proportion = 0,
317  flag = wx.ADJUST_MINSIZE |
318  wx.ALIGN_TOP |
319  wx.ALIGN_CENTER_HORIZONTAL |
320  wx.RIGHT | wx.EXPAND,
321  border = 3)
322 
323  # buttons
324  btns_sizer.Add(item = self.bstart, proportion = 0,
325  flag = wx.ALIGN_CENTER_HORIZONTAL |
326  wx.ALIGN_CENTER_VERTICAL |
327  wx.ALL,
328  border = 5)
329  btns_sizer.Add(item = self.bexit, proportion = 0,
330  flag = wx.ALIGN_CENTER_HORIZONTAL |
331  wx.ALIGN_CENTER_VERTICAL |
332  wx.ALL,
333  border = 5)
334  btns_sizer.Add(item = self.bhelp, proportion = 0,
335  flag = wx.ALIGN_CENTER_HORIZONTAL |
336  wx.ALIGN_CENTER_VERTICAL |
337  wx.ALL,
338  border = 5)
339 
340  # main sizer
341  sizer.Add(item = self.hbitmap,
342  proportion = 0,
343  flag = wx.ALIGN_CENTER_VERTICAL |
344  wx.ALIGN_CENTER_HORIZONTAL |
345  wx.ALL,
346  border = 3) # image
347  sizer.Add(item = self.lwelcome, # welcome message
348  proportion = 0,
349  flag = wx.ALIGN_CENTER_VERTICAL |
350  wx.ALIGN_CENTER_HORIZONTAL |
351  wx.BOTTOM,
352  border=1)
353  sizer.Add(item = self.ltitle, # title
354  proportion = 0,
355  flag = wx.ALIGN_CENTER_VERTICAL |
356  wx.ALIGN_CENTER_HORIZONTAL)
357  sizer.Add(item = dbase_sizer, proportion = 0,
358  flag = wx.ALIGN_CENTER_HORIZONTAL |
359  wx.RIGHT | wx.LEFT,
360  border = 1) # GISDBASE setting
361  sizer.Add(item = location_sizer, proportion = 1,
362  flag = wx.ALIGN_CENTER_VERTICAL |
363  wx.ALIGN_CENTER_HORIZONTAL |
364  wx.RIGHT | wx.LEFT,
365  border = 1)
366  sizer.Add(item = btns_sizer, proportion = 0,
367  flag = wx.ALIGN_CENTER_VERTICAL |
368  wx.ALIGN_CENTER_HORIZONTAL |
369  wx.RIGHT | wx.LEFT,
370  border = 1)
371 
372  self.panel.SetAutoLayout(True)
373  self.panel.SetSizer(sizer)
374  sizer.Fit(self.panel)
375  sizer.SetSizeHints(self)
376 
377  self.Layout()
378 
379  def _readGisRC(self):
380  """
381  Read variables from $HOME/.grassrc6 file
382  """
383 
384  grassrc = {}
385 
386  gisrc = os.getenv("GISRC")
387 
388  if gisrc and os.path.isfile(gisrc):
389  try:
390  rc = open(gisrc, "r")
391  for line in rc.readlines():
392  key, val = line.split(":", 1)
393  grassrc[key.strip()] = utils.DecodeString(val.strip())
394  finally:
395  rc.close()
396 
397  return grassrc
398 
399  def GetRCValue(self, value):
400  """!Return GRASS variable (read from GISRC)
401  """
402  if self.grassrc.has_key(value):
403  return self.grassrc[value]
404  else:
405  return None
406 
407  def OnWizard(self, event):
408  """!Location wizard started"""
409  from gui_modules import location_wizard
410  gWizard = location_wizard.LocationWizard(parent = self,
411  grassdatabase = self.tgisdbase.GetValue())
412  if gWizard.location != None:
413  self.OnSetDatabase(event)
414  self.UpdateMapsets(os.path.join(self.gisdbase, gWizard.location))
415  self.lblocations.SetSelection(self.listOfLocations.index(gWizard.location))
416  self.lbmapsets.SetSelection(0)
417 
418  def OnManageLoc(self, event):
419  """!Location management choice control handler
420  """
421  sel = event.GetSelection()
422  if sel == 0:
423  self.RenameMapset()
424  elif sel == 1:
425  self.RenameLocation()
426  elif sel == 2:
427  self.DeleteMapset()
428  elif sel == 3:
429  self.DeleteLocation()
430 
431  event.Skip()
432 
433  def RenameMapset(self):
434  """!Rename selected mapset
435  """
436  location = utils.UnicodeString(self.listOfLocations[self.lblocations.GetSelection()])
437  mapset = utils.UnicodeString(self.listOfMapsets[self.lbmapsets.GetSelection()])
438  if mapset == 'PERMANENT':
439  GMessage(parent = self,
440  message = _('Mapset <PERMANENT> is required for valid GRASS location.\n\n'
441  'This mapset cannot be renamed.'))
442  return
443 
444  dlg = wx.TextEntryDialog(parent = self,
445  message = _('Current name: %s\n\nEnter new name:') % mapset,
446  caption = _('Rename selected mapset'))
447 
448  if dlg.ShowModal() == wx.ID_OK:
449  newmapset = dlg.GetValue()
450  if newmapset == mapset:
451  dlg.Destroy()
452  return
453 
454  if newmapset in self.listOfMapsets:
455  wx.MessageBox(parent = self,
456  caption = _('Message'),
457  message = _('Unable to rename mapset.\n\n'
458  'Mapset <%s> already exists in location.') % newmapset,
459  style = wx.OK | wx.ICON_INFORMATION | wx.CENTRE)
460  else:
461  try:
462  os.rename(os.path.join(self.gisdbase, location, mapset),
463  os.path.join(self.gisdbase, location, newmapset))
464  self.OnSelectLocation(None)
465  self.lbmapsets.SetSelection(self.listOfMapsets.index(newmapset))
466  except StandardError, e:
467  wx.MessageBox(parent = self,
468  caption = _('Error'),
469  message = _('Unable to rename mapset.\n\n%s') % e,
470  style = wx.OK | wx.ICON_ERROR | wx.CENTRE)
471 
472  dlg.Destroy()
473 
474  def RenameLocation(self):
475  """!Rename selected location
476  """
477  location = utils.UnicodeString(self.listOfLocations[self.lblocations.GetSelection()])
478 
479  dlg = wx.TextEntryDialog(parent = self,
480  message = _('Current name: %s\n\nEnter new name:') % location,
481  caption = _('Rename selected location'))
482 
483  if dlg.ShowModal() == wx.ID_OK:
484  newlocation = dlg.GetValue()
485  if newlocation == location:
486  dlg.Destroy()
487  return
488 
489  if newlocation in self.listOfLocations:
490  wx.MessageBox(parent = self,
491  caption = _('Message'),
492  message = _('Unable to rename location.\n\n'
493  'Location <%s> already exists in GRASS database.') % newlocation,
494  style = wx.OK | wx.ICON_INFORMATION | wx.CENTRE)
495  else:
496  try:
497  os.rename(os.path.join(self.gisdbase, location),
498  os.path.join(self.gisdbase, newlocation))
499  self.UpdateLocations(self.gisdbase)
500  self.lblocations.SetSelection(self.listOfLocations.index(newlocation))
501  self.UpdateMapsets(newlocation)
502  except StandardError, e:
503  wx.MessageBox(parent = self,
504  caption = _('Error'),
505  message = _('Unable to rename location.\n\n%s') % e,
506  style = wx.OK | wx.ICON_ERROR | wx.CENTRE)
507 
508  dlg.Destroy()
509 
510  def DeleteMapset(self):
511  """!Delete selected mapset
512  """
513  location = self.listOfLocations[self.lblocations.GetSelection()]
514  mapset = self.listOfMapsets[self.lbmapsets.GetSelection()]
515  if mapset == 'PERMANENT':
516  GMessage(parent = self,
517  message = _('Mapset <PERMANENT> is required for valid GRASS location.\n\n'
518  'This mapset cannot be deleted.'))
519  return
520 
521  dlg = wx.MessageDialog(parent = self, message = _("Do you want to continue with deleting mapset <%(mapset)s> "
522  "from location <%(location)s>?\n\n"
523  "ALL MAPS included in this mapset will be "
524  "PERMANENTLY DELETED!") % {'mapset' : mapset,
525  'location' : location},
526  caption = _("Delete selected mapset"),
527  style = wx.YES_NO | wx.NO_DEFAULT | wx.ICON_QUESTION)
528 
529  if dlg.ShowModal() == wx.ID_YES:
530  try:
531  shutil.rmtree(os.path.join(self.gisdbase, location, mapset))
532  self.OnSelectLocation(None)
533  self.lbmapsets.SetSelection(0)
534  except:
535  wx.MessageBox(message = _('Unable to delete mapset'))
536 
537  dlg.Destroy()
538 
539  def DeleteLocation(self):
540  """
541  Delete selected location
542  """
543 
544  location = self.listOfLocations[self.lblocations.GetSelection()]
545 
546  dlg = wx.MessageDialog(parent = self, message = _("Do you want to continue with deleting "
547  "location <%s>?\n\n"
548  "ALL MAPS included in this location will be "
549  "PERMANENTLY DELETED!") % (location),
550  caption = _("Delete selected location"),
551  style = wx.YES_NO | wx.NO_DEFAULT | wx.ICON_QUESTION)
552 
553  if dlg.ShowModal() == wx.ID_YES:
554  try:
555  shutil.rmtree(os.path.join(self.gisdbase, location))
556  self.UpdateLocations(self.gisdbase)
557  self.lblocations.SetSelection(0)
558  self.OnSelectLocation(None)
559  self.lbmapsets.SetSelection(0)
560  except:
561  wx.MessageBox(message = _('Unable to delete location'))
562 
563  dlg.Destroy()
564 
565  def UpdateLocations(self, dbase):
566  """!Update list of locations"""
567  try:
568  self.listOfLocations = utils.GetListOfLocations(dbase)
569  except UnicodeEncodeError:
570  wx.MessageBox(parent = self, caption = _("Error"),
571  message = _("Unable to set GRASS database. "
572  "Check your locale settings."),
573  style = wx.OK | wx.ICON_ERROR | wx.CENTRE)
574 
575  self.lblocations.Clear()
576  self.lblocations.InsertItems(self.listOfLocations, 0)
577 
578  if len(self.listOfLocations) > 0:
579  self.lblocations.SetSelection(0)
580  else:
581  self.lblocations.SetSelection(wx.NOT_FOUND)
582 
583  return self.listOfLocations
584 
585  def UpdateMapsets(self, location):
586  """!Update list of mapsets"""
587  self.FormerMapsetSelection = wx.NOT_FOUND # for non-selectable item
588 
589  self.listOfMapsetsSelectable = list()
590  self.listOfMapsets = utils.GetListOfMapsets(self.gisdbase, location)
591 
592  self.lbmapsets.Clear()
593 
594  # disable mapset with denied permission
595  locationName = os.path.basename(location)
596 
597  ret = gcmd.RunCommand('g.mapset',
598  read = True,
599  flags = 'l',
600  location = locationName,
601  gisdbase = self.gisdbase)
602 
603  if ret:
604  for line in ret.splitlines():
605  self.listOfMapsetsSelectable += line.split(' ')
606  else:
607  gcmd.RunCommand("g.gisenv",
608  set = "GISDBASE=%s" % self.gisdbase)
609  gcmd.RunCommand("g.gisenv",
610  set = "LOCATION_NAME=%s" % locationName)
611  gcmd.RunCommand("g.gisenv",
612  set = "MAPSET=PERMANENT")
613  # first run only
614  self.listOfMapsetsSelectable = copy.copy(self.listOfMapsets)
615 
616  disabled = []
617  idx = 0
618  for mapset in self.listOfMapsets:
619  if mapset not in self.listOfMapsetsSelectable or \
620  os.path.isfile(os.path.join(self.gisdbase,
621  locationName,
622  mapset, ".gislock")):
623  disabled.append(idx)
624  idx += 1
625 
626  self.lbmapsets.InsertItems(self.listOfMapsets, 0, disabled = disabled)
627 
628  return self.listOfMapsets
629 
630  def OnSelectLocation(self, event):
631  """!Location selected"""
632  if event:
633  self.lblocations.SetSelection(event.GetIndex())
634 
635  if self.lblocations.GetSelection() != wx.NOT_FOUND:
636  self.UpdateMapsets(os.path.join(self.gisdbase,
637  self.listOfLocations[self.lblocations.GetSelection()]))
638  else:
639  self.listOfMapsets = []
640 
641  disabled = []
642  idx = 0
643  try:
644  locationName = self.listOfLocations[self.lblocations.GetSelection()]
645  except IndexError:
646  locationName = ''
647 
648  for mapset in self.listOfMapsets:
649  if mapset not in self.listOfMapsetsSelectable or \
650  os.path.isfile(os.path.join(self.gisdbase,
651  locationName,
652  mapset, ".gislock")):
653  disabled.append(idx)
654  idx += 1
655 
656  self.lbmapsets.Clear()
657  self.lbmapsets.InsertItems(self.listOfMapsets, 0, disabled = disabled)
658 
659  if len(self.listOfMapsets) > 0:
660  self.lbmapsets.SetSelection(0)
661  if locationName:
662  # enable start button when location and mapset is selected
663  self.bstart.Enable()
664  self.bmapset.Enable()
665  self.manageloc.Enable()
666  else:
667  self.lbmapsets.SetSelection(wx.NOT_FOUND)
668  self.bstart.Enable(False)
669  self.bmapset.Enable(False)
670  self.manageloc.Enable(False)
671 
672  def OnSelectMapset(self, event):
673  """!Mapset selected"""
674  self.lbmapsets.SetSelection(event.GetIndex())
675 
676  if event.GetText() not in self.listOfMapsetsSelectable:
677  self.lbmapsets.SetSelection(self.FormerMapsetSelection)
678  else:
679  self.FormerMapsetSelection = event.GetIndex()
680  event.Skip()
681 
682  def OnSetDatabase(self, event):
683  """!Database set"""
684  self.gisdbase = self.tgisdbase.GetValue()
685 
686  self.UpdateLocations(self.gisdbase)
687 
688  self.OnSelectLocation(None)
689 
690  def OnBrowse(self, event):
691  """'Browse' button clicked"""
692  grassdata = None
693 
694  dlg = wx.DirDialog(self, _("Choose GIS Data Directory:"),
695  style = wx.DD_DEFAULT_STYLE | wx.DD_NEW_DIR_BUTTON)
696  if dlg.ShowModal() == wx.ID_OK:
697  self.gisdbase = dlg.GetPath()
698  self.tgisdbase.SetValue(self.gisdbase)
699  self.OnSetDatabase(event)
700 
701  dlg.Destroy()
702 
703  def OnCreateMapset(self,event):
704  """!Create new mapset"""
705  self.gisdbase = self.tgisdbase.GetValue()
706  location = self.listOfLocations[self.lblocations.GetSelection()]
707 
708  dlg = wx.TextEntryDialog(parent = self,
709  message = _('Enter name for new mapset:'),
710  caption = _('Create new mapset'))
711 
712  if dlg.ShowModal() == wx.ID_OK:
713  mapset = dlg.GetValue()
714  try:
715  os.mkdir(os.path.join(self.gisdbase, location, mapset))
716  # copy WIND file and its permissions from PERMANENT and set permissions to u+rw,go+r
717  shutil.copy(os.path.join(self.gisdbase, location, 'PERMANENT', 'WIND'),
718  os.path.join(self.gisdbase, location, mapset))
719  # os.chmod(os.path.join(database,location,mapset,'WIND'), 0644)
720  self.OnSelectLocation(None)
721  self.lbmapsets.SetSelection(self.listOfMapsets.index(mapset))
722  except StandardError, e:
723  dlg = wx.MessageDialog(parent = self, message = _("Unable to create new mapset: %s") % e,
724  caption = _("Error"), style = wx.OK | wx.ICON_ERROR)
725  dlg.ShowModal()
726  dlg.Destroy()
727  return False
728 
729  self.bstart.SetFocus()
730 
731  return True
732 
733  def OnStart(self, event):
734  """'Start GRASS' button clicked"""
735  dbase = self.tgisdbase.GetValue()
736  location = self.listOfLocations[self.lblocations.GetSelection()]
737  mapset = self.listOfMapsets[self.lbmapsets.GetSelection()]
738 
739  lockfile = os.path.join(dbase, location, mapset, '.gislock')
740  if os.path.isfile(lockfile):
741  dlg = wx.MessageDialog(parent = self,
742  message = _("GRASS is already running in selected mapset <%(mapset)s>\n"
743  "(file %(lock)s found).\n\n"
744  "Concurrent use not allowed.\n\n"
745  "Do you want to try to remove .gislock (note that you "
746  "need permission for this operation) and continue?") %
747  { 'mapset' : mapset, 'lock' : lockfile },
748  caption = _("Lock file found"),
749  style = wx.YES_NO | wx.NO_DEFAULT |
750  wx.ICON_QUESTION | wx.CENTRE)
751 
752  ret = dlg.ShowModal()
753  dlg.Destroy()
754  if ret == wx.ID_YES:
755  dlg1 = wx.MessageDialog(parent = self,
756  message = _("ARE YOU REALLY SURE?\n\n"
757  "If you really are running another GRASS session doing this "
758  "could corrupt your data. Have another look in the processor "
759  "manager just to be sure..."),
760  caption = _("Lock file found"),
761  style = wx.YES_NO | wx.NO_DEFAULT |
762  wx.ICON_QUESTION | wx.CENTRE)
763 
764  ret = dlg1.ShowModal()
765  dlg1.Destroy()
766 
767  if ret == wx.ID_YES:
768  try:
769  os.remove(lockfile)
770  except IOError, e:
771  GError(_("Unable to remove '%(lock)s'.\n\n"
772  "Details: %(reason)s") % { 'lock' : lockfile, 'reason' : e})
773  else:
774  return
775  else:
776  return
777 
778  gcmd.RunCommand("g.gisenv",
779  set = "GISDBASE=%s" % dbase)
780  gcmd.RunCommand("g.gisenv",
781  set = "LOCATION_NAME=%s" % location)
782  gcmd.RunCommand("g.gisenv",
783  set = "MAPSET=%s" % mapset)
784 
785  self.Destroy()
786  sys.exit(0)
787 
788  def OnExit(self, event):
789  """'Exit' button clicked"""
790  self.Destroy()
791  sys.exit (2)
792 
793  def OnHelp(self, event):
794  """'Help' button clicked"""
795  # help text in lib/init/helptext.html
796  file = os.path.join(self.gisbase, "docs", "html", "helptext.html")
797 
798  helpFrame = HelpFrame(parent = self, id = wx.ID_ANY,
799  title = _("GRASS Quickstart"),
800  size = (640, 480),
801  file = file)
802  helpFrame.Show(True)
803 
804  event.Skip()
805 
806  def OnCloseWindow(self, event):
807  """!Close window event"""
808  event.Skip()
809  sys.exit(2)
810 
811 class GListBox(wx.ListCtrl, listmix.ListCtrlAutoWidthMixin):
812  """!Use wx.ListCtrl instead of wx.ListBox, different style for
813  non-selectable items (e.g. mapsets with denied permission)"""
814  def __init__(self, parent, id, size,
815  choices, disabled = []):
816  wx.ListCtrl.__init__(self, parent, id, size = size,
817  style = wx.LC_REPORT | wx.LC_NO_HEADER | wx.LC_SINGLE_SEL |
818  wx.BORDER_SUNKEN)
819 
820  listmix.ListCtrlAutoWidthMixin.__init__(self)
821 
822  self.InsertColumn(0, '')
823 
824  self.selected = wx.NOT_FOUND
825 
826  self._LoadData(choices, disabled)
827 
828  def _LoadData(self, choices, disabled = []):
829  """!Load data into list
830 
831  @param choices list of item
832  @param disabled list of indeces of non-selectable items
833  """
834  idx = 0
835  for item in choices:
836  index = self.InsertStringItem(sys.maxint, item)
837  self.SetStringItem(index, 0, item)
838 
839  if idx in disabled:
840  self.SetItemTextColour(idx, wx.Colour(150, 150, 150))
841  idx += 1
842 
843  def Clear(self):
844  self.DeleteAllItems()
845 
846  def InsertItems(self, choices, pos, disabled = []):
847  self._LoadData(choices, disabled)
848 
849  def SetSelection(self, item, force = False):
850  if item != wx.NOT_FOUND and \
851  (platform.system() != 'Windows' or force):
852  ### Windows -> FIXME
853  self.SetItemState(item, wx.LIST_STATE_SELECTED, wx.LIST_STATE_SELECTED)
854 
855  self.selected = item
856 
857  def GetSelection(self):
858  return self.selected
859 
860 class StartUp(wx.App):
861  """!Start-up application"""
862 
863  def OnInit(self):
864  wx.InitAllImageHandlers()
865  StartUp = GRASSStartup()
866  StartUp.CenterOnScreen()
867  self.SetTopWindow(StartUp)
868  StartUp.Show()
869 
870  if StartUp.GetRCValue("LOCATION_NAME") == "<UNKNOWN>":
871  wx.MessageBox(parent = StartUp,
872  caption = _('Starting GRASS for the first time'),
873  message = _('GRASS needs a directory in which to store its data. '
874  'Create one now if you have not already done so. '
875  'A popular choice is "grassdata", located in '
876  'your home directory.'),
877  style = wx.OK | wx.ICON_ERROR | wx.CENTRE)
878 
879  StartUp.OnBrowse(None)
880 
881  return 1
882 
883 if __name__ == "__main__":
884 
885  if os.getenv("GISBASE") is None:
886  print >> sys.stderr, "Failed to start GUI, GRASS GIS is not running."
887  else:
888  import gettext
889  gettext.install('grasswxpy', os.path.join(os.getenv("GISBASE"), 'locale'), unicode = True)
890 
891  import gui_modules.gcmd as gcmd
892  import gui_modules.utils as utils
893 
894  GRASSStartUp = StartUp(0)
895  GRASSStartUp.MainLoop()