123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476 |
- """
- @package startup.guiutils
- @brief General GUI-dependent utilities for GUI startup of GRASS GIS
- (C) 2018 by Vaclav Petras 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 Vaclav Petras <wenzeslaus gmail com>
- @author Linda Kladivova <l.kladivova@seznam.cz>
- This is for code which depend on something from GUI (wx or wxGUI).
- """
- import os
- import sys
- import wx
- import grass.script as gs
- from core import globalvar
- from core.gcmd import GError, GMessage, DecodeString, RunCommand
- from gui_core.dialogs import TextEntryDialog
- from location_wizard.dialogs import RegionDef
- from gui_core.widgets import GenericMultiValidator
- from startup.utils import (create_mapset, delete_mapset, delete_location,
- rename_mapset, rename_location, mapset_exists,
- location_exists, get_default_mapset_name)
- def SetSessionMapset(database, location, mapset):
- """Sets database, location and mapset for the current session"""
- RunCommand("g.gisenv", set="GISDBASE=%s" % database)
- RunCommand("g.gisenv", set="LOCATION_NAME=%s" % location)
- RunCommand("g.gisenv", set="MAPSET=%s" % mapset)
- class MapsetDialog(TextEntryDialog):
- def __init__(self, parent=None, default=None, message=None, caption=None,
- database=None, location=None):
- self.database = database
- self.location = location
- # list of tuples consisting of conditions and callbacks
- checks = [(gs.legal_name, self._nameValidationFailed),
- (self._checkMapsetNotExists, self._mapsetAlreadyExists),
- (self._checkOGR, self._reservedMapsetName)]
- validator = GenericMultiValidator(checks)
- TextEntryDialog.__init__(
- self, parent=parent,
- message=message,
- caption=caption,
- defaultValue=default,
- validator=validator,
- )
- def _nameValidationFailed(self, ctrl):
- message = _(
- "Name '{}' is not a valid name for location or mapset. "
- "Please use only ASCII characters excluding characters {} "
- "and space.").format(ctrl.GetValue(), '/"\'@,=*~')
- GError(parent=self, message=message, caption=_("Invalid name"))
- def _checkOGR(self, text):
- """Check user's input for reserved mapset name."""
- if text.lower() == 'ogr':
- return False
- return True
- def _reservedMapsetName(self, ctrl):
- message = _(
- "Name '{}' is reserved for direct "
- "read access to OGR layers. Please use "
- "another name for your mapset.").format(ctrl.GetValue())
- GError(parent=self, message=message,
- caption=_("Reserved mapset name"))
- def _checkMapsetNotExists(self, text):
- """Check whether user's input mapset exists or not."""
- if mapset_exists(self.database, self.location, text):
- return False
- return True
- def _mapsetAlreadyExists(self, ctrl):
- message = _(
- "Mapset '{}' already exists. Please consider using "
- "another name for your mapset.").format(ctrl.GetValue())
- GError(parent=self, message=message,
- caption=_("Existing mapset path"))
- class LocationDialog(TextEntryDialog):
- def __init__(self, parent=None, default=None, message=None, caption=None,
- database=None):
- self.database = database
- # list of tuples consisting of conditions and callbacks
- checks = [(gs.legal_name, self._nameValidationFailed),
- (self._checkLocationNotExists, self._locationAlreadyExists)]
- validator = GenericMultiValidator(checks)
- TextEntryDialog.__init__(
- self, parent=parent,
- message=message,
- caption=caption,
- defaultValue=default,
- validator=validator,
- )
- def _nameValidationFailed(self, ctrl):
- message = _(
- "Name '{}' is not a valid name for location or mapset. "
- "Please use only ASCII characters excluding characters {} "
- "and space.").format(ctrl.GetValue(), '/"\'@,=*~')
- GError(parent=self, message=message, caption=_("Invalid name"))
- def _checkLocationNotExists(self, text):
- """Check whether user's input location exists or not."""
- if location_exists(self.database, text):
- return False
- return True
- def _locationAlreadyExists(self, ctrl):
- message = _(
- "Location '{}' already exists. Please consider using "
- "another name for your location.").format(ctrl.GetValue())
- GError(parent=self, message=message,
- caption=_("Existing location path"))
- # TODO: similar to (but not the same as) read_gisrc function in grass.py
- def read_gisrc():
- """Read variables from a current GISRC file
- Returns a dictionary representation of the file content.
- """
- grassrc = {}
- gisrc = os.getenv("GISRC")
- if gisrc and os.path.isfile(gisrc):
- try:
- rc = open(gisrc, "r")
- for line in rc.readlines():
- try:
- key, val = line.split(":", 1)
- except ValueError as e:
- sys.stderr.write(
- _('Invalid line in GISRC file (%s):%s\n' % (e, line)))
- grassrc[key.strip()] = DecodeString(val.strip())
- finally:
- rc.close()
- return grassrc
- def GetVersion():
- """Gets version and revision
- Returns tuple `(version, revision)`. For standard releases revision
- is an empty string.
- Revision string is currently wrapped in parentheses with added
- leading space. This is an implementation detail and legacy and may
- change anytime.
- """
- versionFile = open(os.path.join(globalvar.ETCDIR, "VERSIONNUMBER"))
- versionLine = versionFile.readline().rstrip('\n')
- versionFile.close()
- try:
- grassVersion, grassRevision = versionLine.split(' ', 1)
- if grassVersion.endswith('dev'):
- grassRevisionStr = ' (%s)' % grassRevision
- else:
- grassRevisionStr = ''
- except ValueError:
- grassVersion = versionLine
- grassRevisionStr = ''
- return (grassVersion, grassRevisionStr)
- def create_mapset_interactively(guiparent, grassdb, location):
- """
- Create new mapset
- """
- dlg = MapsetDialog(
- parent=guiparent,
- default=get_default_mapset_name(),
- message=_("Name for the new mapset:"),
- caption=_("Create new mapset"),
- database=grassdb,
- location=location,
- )
- if dlg.ShowModal() == wx.ID_OK:
- mapset = dlg.GetValue()
- try:
- create_mapset(grassdb, location, mapset)
- except OSError as err:
- GError(
- parent=guiparent,
- message=_("Unable to create new mapset: %s") % err,
- showTraceback=False,
- )
- else:
- mapset = None
- dlg.Destroy()
- return mapset
- def create_location_interactively(guiparent, grassdb):
- """
- Create new location using Location Wizard.
- Returns tuple (database, location, mapset) where mapset is "PERMANENT"
- by default or another mapset a user created and may want to switch to.
- """
- from location_wizard.wizard import LocationWizard
- gWizard = LocationWizard(parent=guiparent,
- grassdatabase=grassdb)
- if gWizard.location is None:
- gWizard_output = (None, None, None)
- # Returns Nones after Cancel
- return gWizard_output
- if gWizard.georeffile:
- message = _(
- "Do you want to import {}"
- "to the newly created location?"
- ).format(gWizard.georeffile)
- dlg = wx.MessageDialog(parent=guiparent,
- message=message,
- caption=_("Import data?"),
- style=wx.YES_NO | wx.YES_DEFAULT |
- wx.ICON_QUESTION)
- dlg.CenterOnParent()
- if dlg.ShowModal() == wx.ID_YES:
- import_file(guiparent, gWizard.georeffile)
- dlg.Destroy()
- if gWizard.default_region:
- defineRegion = RegionDef(guiparent, location=gWizard.location)
- defineRegion.CenterOnParent()
- defineRegion.ShowModal()
- defineRegion.Destroy()
- if gWizard.user_mapset:
- mapset = create_mapset_interactively(guiparent,
- gWizard.grassdatabase,
- gWizard.location)
- # Returns database and location created by user
- # and a mapset user may want to switch to
- gWizard_output = (gWizard.grassdatabase, gWizard.location,
- mapset)
- else:
- # Returns PERMANENT mapset when user mapset not defined
- gWizard_output = (gWizard.grassdatabase, gWizard.location,
- "PERMANENT")
- return gWizard_output
- def rename_mapset_interactively(guiparent, grassdb, location, mapset):
- """
- Rename selected mapset
- """
- newmapset = None
- if mapset == "PERMANENT":
- GMessage(
- parent=guiparent,
- message=_(
- "Mapset <PERMANENT> is required for valid GRASS location.\n\n"
- "This mapset cannot be renamed."
- ),
- )
- return newmapset
- dlg = MapsetDialog(
- parent=guiparent,
- default=mapset,
- message=_("Current name: %s\n\nEnter new name:") % mapset,
- caption=_("Rename selected mapset"),
- database=grassdb,
- location=location,
- )
- if dlg.ShowModal() == wx.ID_OK:
- newmapset = dlg.GetValue()
- try:
- rename_mapset(grassdb, location, mapset, newmapset)
- except OSError as err:
- newmapset = None
- wx.MessageBox(
- parent=guiparent,
- caption=_("Error"),
- message=_("Unable to rename mapset.\n\n%s") % err,
- style=wx.OK | wx.ICON_ERROR | wx.CENTRE,
- )
- dlg.Destroy()
- return newmapset
- def rename_location_interactively(guiparent, grassdb, location):
- """
- Rename selected location
- """
- dlg = LocationDialog(
- parent=guiparent,
- default=location,
- message=_("Current name: %s\n\nEnter new name:") % location,
- caption=_("Rename selected location"),
- database=grassdb,
- )
- if dlg.ShowModal() == wx.ID_OK:
- newlocation = dlg.GetValue()
- try:
- rename_location(grassdb, location, newlocation)
- except OSError as err:
- newlocation = None
- wx.MessageBox(
- parent=guiparent,
- caption=_("Error"),
- message=_("Unable to rename location.\n\n%s") % err,
- style=wx.OK | wx.ICON_ERROR | wx.CENTRE,
- )
- else:
- newlocation = None
- dlg.Destroy()
- return newlocation
- def download_location_interactively(guiparent, grassdb):
- """
- Download new location using Location Wizard.
- Returns tuple (database, location, mapset) where mapset is "PERMANENT"
- by default or in future it could be the mapset the user may want to
- switch to.
- """
- from startup.locdownload import LocationDownloadDialog
- result = (None, None, None)
- loc_download = LocationDownloadDialog(parent=guiparent,
- database=grassdb)
- loc_download.ShowModal()
- if loc_download.GetLocation() is not None:
- # Returns database and location created by user
- # and a mapset user may want to switch to
- result = (grassdb, loc_download.GetLocation(), "PERMANENT")
- loc_download.Destroy()
- return result
- def delete_mapset_interactively(guiparent, grassdb, location, mapset):
- """
- Delete selected mapset
- """
- if mapset == "PERMANENT":
- GMessage(
- parent=guiparent,
- message=_(
- "Mapset <PERMANENT> is required for valid GRASS location.\n\n"
- "This mapset cannot be deleted."
- ),
- )
- return False
- dlg = wx.MessageDialog(
- parent=guiparent,
- message=_(
- "Do you want to continue with deleting mapset <%(mapset)s> "
- "from location <%(location)s>?\n\n"
- "ALL MAPS included in this mapset will be "
- "PERMANENTLY DELETED!"
- )
- % {"mapset": mapset, "location": location},
- caption=_("Delete selected mapset"),
- style=wx.YES_NO | wx.NO_DEFAULT | wx.ICON_QUESTION,
- )
- if dlg.ShowModal() == wx.ID_YES:
- try:
- delete_mapset(grassdb, location, mapset)
- dlg.Destroy()
- return True
- except OSError as err:
- wx.MessageBox(
- parent=guiparent,
- caption=_("Error"),
- message=_("Unable to delete mapset.\n\n%s") % err,
- style=wx.OK | wx.ICON_ERROR | wx.CENTRE,
- )
- dlg.Destroy()
- return False
- def delete_location_interactively(guiparent, grassdb, location):
- """
- Delete selected location
- """
- dlg = wx.MessageDialog(
- parent=guiparent,
- message=_(
- "Do you want to continue with deleting "
- "location <%s>?\n\n"
- "ALL MAPS included in this location will be "
- "PERMANENTLY DELETED!"
- )
- % (location),
- caption=_("Delete selected location"),
- style=wx.YES_NO | wx.NO_DEFAULT | wx.ICON_QUESTION,
- )
- if dlg.ShowModal() == wx.ID_YES:
- try:
- delete_location(grassdb, location)
- dlg.Destroy()
- return True
- except OSError as err:
- wx.MessageBox(
- parent=guiparent,
- caption=_("Error"),
- message=_("Unable to delete location.\n\n%s") % err,
- style=wx.OK | wx.ICON_ERROR | wx.CENTRE,
- )
- dlg.Destroy()
- return False
- def import_file(guiparent, filePath):
- """Tries to import file as vector or raster.
- If successfull sets default region from imported map.
- """
- RunCommand('db.connect', flags='c')
- mapName = os.path.splitext(os.path.basename(filePath))[0]
- vectors = RunCommand('v.in.ogr', input=filePath, flags='l',
- read=True)
- wx.BeginBusyCursor()
- wx.GetApp().Yield()
- if vectors:
- # vector detected
- returncode, error = RunCommand(
- 'v.in.ogr', input=filePath, output=mapName, flags='e',
- getErrorMsg=True)
- else:
- returncode, error = RunCommand(
- 'r.in.gdal', input=filePath, output=mapName, flags='e',
- getErrorMsg=True)
- wx.EndBusyCursor()
- if returncode != 0:
- GError(
- parent=guiparent,
- message=_(
- "Import of <%(name)s> failed.\n"
- "Reason: %(msg)s") % ({
- 'name': filePath,
- 'msg': error}))
- else:
- GMessage(
- message=_(
- "Data file <%(name)s> imported successfully. "
- "The location's default region was set from "
- "this imported map.") % {
- 'name': filePath},
- parent=guiparent)
|