Exemple #1
0
    def UpdateMapsets(self, location):
        """Update list of mapsets"""
        self.FormerMapsetSelection = wx.NOT_FOUND  # for non-selectable item

        self.listOfMapsetsSelectable = list()
        self.listOfMapsets = GetListOfMapsets(self.gisdbase, location)

        self.lbmapsets.Clear()

        # disable mapset with denied permission
        locationName = os.path.basename(location)

        ret = RunCommand('g.mapset',
                         read=True,
                         flags='l',
                         location=locationName,
                         gisdbase=self.gisdbase)

        if ret:
            for line in ret.splitlines():
                self.listOfMapsetsSelectable += line.split(' ')
        else:
            RunCommand("g.gisenv",
                       set="GISDBASE=%s" % self.gisdbase)
            RunCommand("g.gisenv",
                       set="LOCATION_NAME=%s" % locationName)
            RunCommand("g.gisenv",
                       set="MAPSET=PERMANENT")
            # first run only
            self.listOfMapsetsSelectable = copy.copy(self.listOfMapsets)

        disabled = []
        idx = 0
        for mapset in self.listOfMapsets:
            if mapset not in self.listOfMapsetsSelectable or \
                    os.path.isfile(os.path.join(self.gisdbase,
                                                locationName,
                                                mapset, ".gislock")):
                disabled.append(idx)
            idx += 1

        self.lbmapsets.InsertItems(self.listOfMapsets, 0, disabled=disabled)

        return self.listOfMapsets
Exemple #2
0
    def UpdateMapsets(self, location):
        """Update list of mapsets"""
        self.FormerMapsetSelection = wx.NOT_FOUND  # for non-selectable item

        self.listOfMapsetsSelectable = list()
        self.listOfMapsets = GetListOfMapsets(self.gisdbase, location)

        self.lbmapsets.Clear()

        # disable mapset with denied permission
        locationName = os.path.basename(location)

        ret = RunCommand('g.mapset',
                         read=True,
                         flags='l',
                         location=locationName,
                         gisdbase=self.gisdbase)

        if ret:
            for line in ret.splitlines():
                self.listOfMapsetsSelectable += line.split(' ')
        else:
            self.SetLocation(self.gisdbase, locationName, "PERMANENT")
            # first run only
            self.listOfMapsetsSelectable = copy.copy(self.listOfMapsets)

        disabled = []
        idx = 0
        for mapset in self.listOfMapsets:
            if mapset not in self.listOfMapsetsSelectable or \
                    get_lockfile_if_present(self.gisdbase,
                                            locationName, mapset):
                disabled.append(idx)
            idx += 1

        self.lbmapsets.InsertItems(self.listOfMapsets, 0, disabled=disabled)

        return self.listOfMapsets
Exemple #3
0
 def UpdateMapsets(self, location):
     """Update list of mapsets"""
     self.FormerMapsetSelection = wx.NOT_FOUND # for non-selectable item
     
     self.listOfMapsetsSelectable = list()
     self.listOfMapsets = GetListOfMapsets(self.gisdbase, location)
     
     self.lbmapsets.Clear()
     
     # disable mapset with denied permission
     locationName = os.path.basename(location)
     
     ret = RunCommand('g.mapset',
                      read = True,
                      flags = 'l',
                      location = locationName,
                      gisdbase = self.gisdbase)
         
     if ret:
         for line in ret.splitlines():
             self.listOfMapsetsSelectable += line.split(' ')
     else:
         RunCommand("g.gisenv",
                    set = "GISDBASE=%s" % self.gisdbase)
         RunCommand("g.gisenv",
                    set = "LOCATION_NAME=%s" % locationName)
         RunCommand("g.gisenv",
                    set = "MAPSET=PERMANENT")
         # first run only
         self.listOfMapsetsSelectable = copy.copy(self.listOfMapsets)
     
     disabled = []
     idx = 0
     for mapset in self.listOfMapsets:
         if mapset not in self.listOfMapsetsSelectable or \
                 os.path.isfile(os.path.join(self.gisdbase,
                                             locationName,
                                             mapset, ".gislock")):
             disabled.append(idx)
         idx +=  1
     
     self.lbmapsets.InsertItems(self.listOfMapsets, 0, disabled = disabled)
     
     return self.listOfMapsets
Exemple #4
0
class GRASSStartup(wx.Frame):
    exit_success = 0
    # 2 is file not found from python interpreter
    exit_user_requested = 5
    """GRASS start-up screen"""
    def __init__(self,
                 parent=None,
                 id=wx.ID_ANY,
                 style=wx.DEFAULT_FRAME_STYLE):

        #
        # GRASS variables
        #
        self.gisbase = os.getenv("GISBASE")
        self.grassrc = sgui.read_gisrc()
        self.gisdbase = self.GetRCValue("GISDBASE")

        #
        # list of locations/mapsets
        #
        self.listOfLocations = []
        self.listOfMapsets = []
        self.listOfMapsetsSelectable = []

        wx.Frame.__init__(self, parent=parent, id=id, style=style)

        self.locale = wx.Locale(language=wx.LANGUAGE_DEFAULT)

        # scroll panel was used here but not properly and is probably not need
        # as long as it is not high too much
        self.panel = wx.Panel(parent=self, id=wx.ID_ANY)

        # i18N

        #
        # graphical elements
        #
        # image
        try:
            if os.getenv('ISISROOT'):
                name = os.path.join(globalvar.GUIDIR, "images",
                                    "startup_banner_isis.png")
            else:
                name = os.path.join(globalvar.GUIDIR, "images",
                                    "startup_banner.png")
            self.hbitmap = wx.StaticBitmap(
                self.panel, wx.ID_ANY,
                wx.Bitmap(name=name, type=wx.BITMAP_TYPE_PNG))
        except:
            self.hbitmap = wx.StaticBitmap(
                self.panel, wx.ID_ANY, BitmapFromImage(wx.EmptyImage(530,
                                                                     150)))

        # labels
        # crashes when LOCATION doesn't exist
        # get version & revision
        grassVersion, grassRevisionStr = sgui.GetVersion()

        self.gisdbase_box = StaticBox(
            parent=self.panel,
            id=wx.ID_ANY,
            label=" %s " % _("1. Select GRASS GIS database directory"))
        self.location_box = StaticBox(parent=self.panel,
                                      id=wx.ID_ANY,
                                      label=" %s " %
                                      _("2. Select GRASS Location"))
        self.mapset_box = StaticBox(parent=self.panel,
                                    id=wx.ID_ANY,
                                    label=" %s " % _("3. Select GRASS Mapset"))

        self.lmessage = StaticText(parent=self.panel)
        # It is not clear if all wx versions supports color, so try-except.
        # The color itself may not be correct for all platforms/system settings
        # but in http://xoomer.virgilio.it/infinity77/wxPython/Widgets/wx.SystemSettings.html
        # there is no 'warning' color.
        try:
            self.lmessage.SetForegroundColour(wx.Colour(255, 0, 0))
        except AttributeError:
            pass

        self.gisdbase_panel = wx.Panel(parent=self.panel)
        self.location_panel = wx.Panel(parent=self.panel)
        self.mapset_panel = wx.Panel(parent=self.panel)

        self.ldbase = StaticText(
            parent=self.gisdbase_panel,
            id=wx.ID_ANY,
            label=_("GRASS GIS database directory contains Locations."))

        self.llocation = StaticWrapText(
            parent=self.location_panel,
            id=wx.ID_ANY,
            label=_("All data in one Location is in the same "
                    " coordinate reference system (projection)."
                    " One Location can be one project."
                    " Location contains Mapsets."),
            style=wx.ALIGN_LEFT)

        self.lmapset = StaticWrapText(
            parent=self.mapset_panel,
            id=wx.ID_ANY,
            label=_("Mapset contains GIS data related"
                    " to one project, task within one project,"
                    " subregion or user."),
            style=wx.ALIGN_LEFT)

        try:
            for label in [self.ldbase, self.llocation, self.lmapset]:
                label.SetForegroundColour(
                    wx.SystemSettings.GetColour(wx.SYS_COLOUR_GRAYTEXT))
        except AttributeError:
            # for explanation of try-except see above
            pass

        # buttons
        self.bstart = Button(parent=self.panel,
                             id=wx.ID_ANY,
                             label=_("Start &GRASS session"))
        self.bstart.SetDefault()
        self.bexit = Button(parent=self.panel, id=wx.ID_EXIT)
        self.bstart.SetMinSize((180, self.bexit.GetSize()[1]))
        self.bhelp = Button(parent=self.panel, id=wx.ID_HELP)
        self.bbrowse = Button(parent=self.gisdbase_panel,
                              id=wx.ID_ANY,
                              label=_("&Browse"))
        self.bmapset = Button(
            parent=self.mapset_panel,
            id=wx.ID_ANY,
            # GTC New mapset
            label=_("&New"))
        self.bmapset.SetToolTip(_("Create a new Mapset in selected Location"))
        self.bwizard = Button(
            parent=self.location_panel,
            id=wx.ID_ANY,
            # GTC New location
            label=_("N&ew"))
        self.bwizard.SetToolTip(
            _("Create a new location using location wizard."
              " After location is created successfully,"
              " GRASS session is started."))
        self.rename_location_button = Button(
            parent=self.location_panel,
            id=wx.ID_ANY,
            # GTC Rename location
            label=_("Ren&ame"))
        self.rename_location_button.SetToolTip(_("Rename selected location"))
        self.delete_location_button = Button(
            parent=self.location_panel,
            id=wx.ID_ANY,
            # GTC Delete location
            label=_("De&lete"))
        self.delete_location_button.SetToolTip(_("Delete selected location"))
        self.download_location_button = Button(parent=self.location_panel,
                                               id=wx.ID_ANY,
                                               label=_("Do&wnload"))
        self.download_location_button.SetToolTip(_("Download sample location"))

        self.rename_mapset_button = Button(
            parent=self.mapset_panel,
            id=wx.ID_ANY,
            # GTC Rename mapset
            label=_("&Rename"))
        self.rename_mapset_button.SetToolTip(_("Rename selected mapset"))
        self.delete_mapset_button = Button(
            parent=self.mapset_panel,
            id=wx.ID_ANY,
            # GTC Delete mapset
            label=_("&Delete"))
        self.delete_mapset_button.SetToolTip(_("Delete selected mapset"))

        # textinputs
        self.tgisdbase = TextCtrl(parent=self.gisdbase_panel,
                                  id=wx.ID_ANY,
                                  value="",
                                  size=(300, -1),
                                  style=wx.TE_PROCESS_ENTER)

        # Locations
        self.lblocations = GListBox(parent=self.location_panel,
                                    id=wx.ID_ANY,
                                    size=(180, 200),
                                    choices=self.listOfLocations)
        self.lblocations.SetColumnWidth(0, 180)

        # TODO: sort; but keep PERMANENT on top of list
        # Mapsets
        self.lbmapsets = GListBox(parent=self.mapset_panel,
                                  id=wx.ID_ANY,
                                  size=(180, 200),
                                  choices=self.listOfMapsets)
        self.lbmapsets.SetColumnWidth(0, 180)

        # layout & properties, first do layout so everything is created
        self._do_layout()
        self._set_properties(grassVersion, grassRevisionStr)

        # events
        self.bbrowse.Bind(wx.EVT_BUTTON, self.OnBrowse)
        self.bstart.Bind(wx.EVT_BUTTON, self.OnStart)
        self.bexit.Bind(wx.EVT_BUTTON, self.OnExit)
        self.bhelp.Bind(wx.EVT_BUTTON, self.OnHelp)
        self.bmapset.Bind(wx.EVT_BUTTON, self.OnCreateMapset)
        self.bwizard.Bind(wx.EVT_BUTTON, self.OnWizard)

        self.rename_location_button.Bind(wx.EVT_BUTTON, self.RenameLocation)
        self.delete_location_button.Bind(wx.EVT_BUTTON, self.DeleteLocation)
        self.download_location_button.Bind(wx.EVT_BUTTON,
                                           self.DownloadLocation)
        self.rename_mapset_button.Bind(wx.EVT_BUTTON, self.RenameMapset)
        self.delete_mapset_button.Bind(wx.EVT_BUTTON, self.DeleteMapset)

        self.lblocations.Bind(wx.EVT_LIST_ITEM_SELECTED, self.OnSelectLocation)
        self.lbmapsets.Bind(wx.EVT_LIST_ITEM_SELECTED, self.OnSelectMapset)
        self.lbmapsets.Bind(wx.EVT_LIST_ITEM_ACTIVATED, self.OnStart)
        self.tgisdbase.Bind(wx.EVT_TEXT_ENTER, self.OnSetDatabase)
        self.Bind(wx.EVT_CLOSE, self.OnCloseWindow)

    def _set_properties(self, version, revision):
        """Set frame properties

        :param version: Version in the form of X.Y.Z
        :param revision: Version control revision with leading space

        *revision* should be an empty string in case of release and
        otherwise it needs a leading space to be separated from the rest
        of the title.
        """
        self.SetTitle(_("GRASS GIS %s Startup%s") % (version, revision))
        self.SetIcon(
            wx.Icon(os.path.join(globalvar.ICONDIR, "grass.ico"),
                    wx.BITMAP_TYPE_ICO))

        self.bstart.SetForegroundColour(wx.Colour(35, 142, 35))
        self.bstart.SetToolTip(_("Enter GRASS session"))
        self.bstart.Enable(False)
        self.bmapset.Enable(False)
        # this all was originally a choice, perhaps just mapset needed
        self.rename_location_button.Enable(False)
        self.delete_location_button.Enable(False)
        self.rename_mapset_button.Enable(False)
        self.delete_mapset_button.Enable(False)

        # set database
        if not self.gisdbase:
            # sets an initial path for gisdbase if nothing in GISRC
            if os.path.isdir(os.getenv("HOME")):
                self.gisdbase = os.getenv("HOME")
            else:
                self.gisdbase = os.getcwd()
        try:
            self.tgisdbase.SetValue(self.gisdbase)
        except UnicodeDecodeError:
            wx.MessageBox(parent=self,
                          caption=_("Error"),
                          message=_("Unable to set GRASS database. "
                                    "Check your locale settings."),
                          style=wx.OK | wx.ICON_ERROR | wx.CENTRE)

        self.OnSetDatabase(None)
        location = self.GetRCValue("LOCATION_NAME")
        if location == "<UNKNOWN>" or location is None:
            return
        if not os.path.isdir(os.path.join(self.gisdbase, location)):
            location = None

        # list of locations
        self.UpdateLocations(self.gisdbase)
        try:
            self.lblocations.SetSelection(self.listOfLocations.index(location),
                                          force=True)
            self.lblocations.EnsureVisible(
                self.listOfLocations.index(location))
        except ValueError:
            sys.stderr.write(
                _("ERROR: Location <%s> not found\n") %
                self.GetRCValue("LOCATION_NAME"))
            if len(self.listOfLocations) > 0:
                self.lblocations.SetSelection(0, force=True)
                self.lblocations.EnsureVisible(0)
                location = self.listOfLocations[0]
            else:
                return

        # list of mapsets
        self.UpdateMapsets(os.path.join(self.gisdbase, location))
        mapset = self.GetRCValue("MAPSET")
        if mapset:
            try:
                self.lbmapsets.SetSelection(self.listOfMapsets.index(mapset),
                                            force=True)
                self.lbmapsets.EnsureVisible(self.listOfMapsets.index(mapset))
            except ValueError:
                sys.stderr.write(_("ERROR: Mapset <%s> not found\n") % mapset)
                self.lbmapsets.SetSelection(0, force=True)
                self.lbmapsets.EnsureVisible(0)

    def _do_layout(self):
        sizer = wx.BoxSizer(wx.VERTICAL)
        self.sizer = sizer  # for the layout call after changing message
        dbase_sizer = wx.BoxSizer(wx.HORIZONTAL)

        location_mapset_sizer = wx.BoxSizer(wx.HORIZONTAL)

        gisdbase_panel_sizer = wx.BoxSizer(wx.VERTICAL)
        gisdbase_boxsizer = wx.StaticBoxSizer(self.gisdbase_box, wx.VERTICAL)

        btns_sizer = wx.BoxSizer(wx.HORIZONTAL)

        self.gisdbase_panel.SetSizer(gisdbase_panel_sizer)

        # gis data directory

        gisdbase_boxsizer.Add(self.gisdbase_panel,
                              proportion=1,
                              flag=wx.EXPAND | wx.ALL,
                              border=1)

        gisdbase_panel_sizer.Add(dbase_sizer,
                                 proportion=1,
                                 flag=wx.EXPAND | wx.ALL,
                                 border=1)
        gisdbase_panel_sizer.Add(self.ldbase,
                                 proportion=0,
                                 flag=wx.EXPAND | wx.ALL,
                                 border=1)

        dbase_sizer.Add(self.tgisdbase,
                        proportion=1,
                        flag=wx.ALIGN_CENTER_VERTICAL | wx.ALL,
                        border=1)
        dbase_sizer.Add(self.bbrowse,
                        proportion=0,
                        flag=wx.ALIGN_CENTER_VERTICAL | wx.ALL,
                        border=1)

        gisdbase_panel_sizer.Fit(self.gisdbase_panel)

        # location and mapset lists

        def layout_list_box(box, panel, list_box, buttons, description):
            panel_sizer = wx.BoxSizer(wx.VERTICAL)
            main_sizer = wx.BoxSizer(wx.HORIZONTAL)
            box_sizer = wx.StaticBoxSizer(box, wx.VERTICAL)
            buttons_sizer = wx.BoxSizer(wx.VERTICAL)

            panel.SetSizer(panel_sizer)
            panel_sizer.Fit(panel)

            main_sizer.Add(list_box,
                           proportion=1,
                           flag=wx.EXPAND | wx.ALL,
                           border=1)
            main_sizer.Add(buttons_sizer,
                           proportion=0,
                           flag=wx.ALIGN_CENTER_HORIZONTAL | wx.ALL,
                           border=1)
            for button in buttons:
                buttons_sizer.Add(button,
                                  proportion=0,
                                  flag=wx.EXPAND | wx.LEFT | wx.RIGHT
                                  | wx.BOTTOM,
                                  border=3)
            box_sizer.Add(panel,
                          proportion=1,
                          flag=wx.EXPAND | wx.ALL,
                          border=1)
            panel_sizer.Add(main_sizer,
                            proportion=1,
                            flag=wx.EXPAND | wx.ALL,
                            border=1)
            panel_sizer.Add(description,
                            proportion=0,
                            flag=wx.EXPAND | wx.ALL,
                            border=1)
            return box_sizer

        location_boxsizer = layout_list_box(box=self.location_box,
                                            panel=self.location_panel,
                                            list_box=self.lblocations,
                                            buttons=[
                                                self.bwizard,
                                                self.rename_location_button,
                                                self.delete_location_button,
                                                self.download_location_button
                                            ],
                                            description=self.llocation)
        mapset_boxsizer = layout_list_box(box=self.mapset_box,
                                          panel=self.mapset_panel,
                                          list_box=self.lbmapsets,
                                          buttons=[
                                              self.bmapset,
                                              self.rename_mapset_button,
                                              self.delete_mapset_button
                                          ],
                                          description=self.lmapset)

        # location and mapset sizer
        location_mapset_sizer.Add(location_boxsizer,
                                  proportion=1,
                                  flag=wx.LEFT | wx.RIGHT | wx.EXPAND,
                                  border=3)
        location_mapset_sizer.Add(mapset_boxsizer,
                                  proportion=1,
                                  flag=wx.RIGHT | wx.EXPAND,
                                  border=3)

        # buttons
        btns_sizer.Add(self.bstart,
                       proportion=0,
                       flag=wx.ALIGN_CENTER_HORIZONTAL
                       | wx.ALIGN_CENTER_VERTICAL | wx.ALL,
                       border=5)
        btns_sizer.Add(self.bexit,
                       proportion=0,
                       flag=wx.ALIGN_CENTER_HORIZONTAL
                       | wx.ALIGN_CENTER_VERTICAL | wx.ALL,
                       border=5)
        btns_sizer.Add(self.bhelp,
                       proportion=0,
                       flag=wx.ALIGN_CENTER_HORIZONTAL
                       | wx.ALIGN_CENTER_VERTICAL | wx.ALL,
                       border=5)

        # main sizer
        sizer.Add(self.hbitmap,
                  proportion=0,
                  flag=wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_CENTER_HORIZONTAL
                  | wx.ALL,
                  border=3)  # image
        sizer.Add(gisdbase_boxsizer,
                  proportion=0,
                  flag=wx.ALIGN_CENTER_HORIZONTAL | wx.RIGHT | wx.LEFT | wx.TOP
                  | wx.EXPAND,
                  border=3)  # GISDBASE setting

        # warning/error message
        sizer.Add(self.lmessage,
                  proportion=0,
                  flag=wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_LEFT | wx.ALL
                  | wx.EXPAND,
                  border=5)
        sizer.Add(location_mapset_sizer,
                  proportion=1,
                  flag=wx.RIGHT | wx.LEFT | wx.EXPAND,
                  border=1)
        sizer.Add(btns_sizer,
                  proportion=0,
                  flag=wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_CENTER_HORIZONTAL
                  | wx.RIGHT | wx.LEFT,
                  border=3)

        self.panel.SetAutoLayout(True)
        self.panel.SetSizer(sizer)
        sizer.Fit(self.panel)
        sizer.SetSizeHints(self)
        self.Layout()

    def _showWarning(self, text):
        """Displays a warning, hint or info message to the user.

        This function can be used for all kinds of messages except for
        error messages.

        .. note::
            There is no cleaning procedure. You should call _hideMessage when
            you know that there is everything correct now.
        """
        self.lmessage.SetLabel(text)
        self.lmessage.Wrap(self.GetClientSize()[0])
        self.sizer.Layout()

    def _showError(self, text):
        """Displays a error message to the user.

        This function should be used only when something serious and unexpected
        happens, otherwise _showWarning should be used.

        .. note::
            There is no cleaning procedure. You should call _hideMessage when
            you know that there is everything correct now.
        """
        self.lmessage.SetLabel(_("Error: {text}").format(text=text))
        self.lmessage.Wrap(self.GetClientSize()[0])
        self.sizer.Layout()

    def _hideMessage(self):
        """Clears/hides the error message."""
        # we do no hide widget
        # because we do not want the dialog to change the size
        self.lmessage.SetLabel("")
        self.sizer.Layout()

    def GetRCValue(self, value):
        """Return GRASS variable (read from GISRC)
        """
        if value in self.grassrc:
            return self.grassrc[value]
        else:
            return None

    def SuggestDatabase(self):
        """Suggest (set) possible GRASS Database value"""
        # only if nothing is set (<UNKNOWN> comes from init script)
        if self.GetRCValue("LOCATION_NAME") != "<UNKNOWN>":
            return
        path = get_possible_database_path()
        if path:
            try:
                self.tgisdbase.SetValue(path)
            except UnicodeDecodeError:
                # restore previous state
                # wizard gives error in this case, we just ignore
                path = None
                self.tgisdbase.SetValue(self.gisdbase)
            # if we still have path
            if path:
                self.gisdbase = path
                self.OnSetDatabase(None)
        else:
            # nothing found
            # TODO: should it be warning, hint or message?
            self._showWarning(
                _('GRASS needs a directory (GRASS database) '
                  'in which to store its data. '
                  'Create one now if you have not already done so. '
                  'A popular choice is "grassdata", located in '
                  'your home directory. '
                  'Press Browse button to select the directory.'))

    def OnWizard(self, event):
        """Location wizard started"""
        from location_wizard.wizard import LocationWizard
        gWizard = LocationWizard(parent=self,
                                 grassdatabase=self.tgisdbase.GetValue())
        if gWizard.location is not None:
            self.tgisdbase.SetValue(gWizard.grassdatabase)
            self.OnSetDatabase(None)
            self.UpdateMapsets(os.path.join(self.gisdbase, gWizard.location))
            self.lblocations.SetSelection(
                self.listOfLocations.index(gWizard.location))
            self.lbmapsets.SetSelection(0)
            self.SetLocation(self.gisdbase, gWizard.location, 'PERMANENT')
            if gWizard.georeffile:
                message = _(
                    "Do you want to import <%(name)s> to the newly created location?"
                ) % {
                    'name': gWizard.georeffile
                }
                dlg = wx.MessageDialog(parent=self,
                                       message=message,
                                       caption=_("Import data?"),
                                       style=wx.YES_NO | wx.YES_DEFAULT
                                       | wx.ICON_QUESTION)
                dlg.CenterOnParent()
                if dlg.ShowModal() == wx.ID_YES:
                    self.ImportFile(gWizard.georeffile)
                dlg.Destroy()
            if gWizard.default_region:
                defineRegion = RegionDef(self, location=gWizard.location)
                defineRegion.CenterOnParent()
                defineRegion.ShowModal()
                defineRegion.Destroy()

            if gWizard.user_mapset:
                self.OnCreateMapset(event)

    def ImportFile(self, 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=self,
                   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=self)

    # the event can be refactored out by using lambda in bind
    def RenameMapset(self, event):
        """Rename selected mapset
        """
        location = self.listOfLocations[self.lblocations.GetSelection()]
        mapset = self.listOfMapsets[self.lbmapsets.GetSelection()]
        if mapset == 'PERMANENT':
            GMessage(
                parent=self,
                message=_(
                    'Mapset <PERMANENT> is required for valid GRASS location.\n\n'
                    'This mapset cannot be renamed.'))
            return

        dlg = TextEntryDialog(
            parent=self,
            message=_('Current name: %s\n\nEnter new name:') % mapset,
            caption=_('Rename selected mapset'),
            validator=GenericValidator(grass.legal_name,
                                       self._nameValidationFailed))

        if dlg.ShowModal() == wx.ID_OK:
            newmapset = dlg.GetValue()
            if newmapset == mapset:
                dlg.Destroy()
                return

            if newmapset in self.listOfMapsets:
                wx.MessageBox(
                    parent=self,
                    caption=_('Message'),
                    message=_('Unable to rename mapset.\n\n'
                              'Mapset <%s> already exists in location.') %
                    newmapset,
                    style=wx.OK | wx.ICON_INFORMATION | wx.CENTRE)
            else:
                try:
                    sutils.rename_mapset(self.gisdbase, location, mapset,
                                         newmapset)
                    self.OnSelectLocation(None)
                    self.lbmapsets.SetSelection(
                        self.listOfMapsets.index(newmapset))
                except Exception as e:
                    wx.MessageBox(parent=self,
                                  caption=_('Error'),
                                  message=_('Unable to rename mapset.\n\n%s') %
                                  e,
                                  style=wx.OK | wx.ICON_ERROR | wx.CENTRE)

        dlg.Destroy()

    def RenameLocation(self, event):
        """Rename selected location
        """
        location = self.listOfLocations[self.lblocations.GetSelection()]

        dlg = TextEntryDialog(
            parent=self,
            message=_('Current name: %s\n\nEnter new name:') % location,
            caption=_('Rename selected location'),
            validator=GenericValidator(grass.legal_name,
                                       self._nameValidationFailed))

        if dlg.ShowModal() == wx.ID_OK:
            newlocation = dlg.GetValue()
            if newlocation == location:
                dlg.Destroy()
                return

            if newlocation in self.listOfLocations:
                wx.MessageBox(
                    parent=self,
                    caption=_('Message'),
                    message=_(
                        'Unable to rename location.\n\n'
                        'Location <%s> already exists in GRASS database.') %
                    newlocation,
                    style=wx.OK | wx.ICON_INFORMATION | wx.CENTRE)
            else:
                try:
                    sutils.rename_location(self.gisdbase, location,
                                           newlocation)
                    self.UpdateLocations(self.gisdbase)
                    self.lblocations.SetSelection(
                        self.listOfLocations.index(newlocation))
                    self.UpdateMapsets(newlocation)
                except Exception as e:
                    wx.MessageBox(
                        parent=self,
                        caption=_('Error'),
                        message=_('Unable to rename location.\n\n%s') % e,
                        style=wx.OK | wx.ICON_ERROR | wx.CENTRE)

        dlg.Destroy()

    def DeleteMapset(self, event):
        """Delete selected mapset
        """
        location = self.listOfLocations[self.lblocations.GetSelection()]
        mapset = self.listOfMapsets[self.lbmapsets.GetSelection()]
        if mapset == 'PERMANENT':
            GMessage(
                parent=self,
                message=_(
                    'Mapset <PERMANENT> is required for valid GRASS location.\n\n'
                    'This mapset cannot be deleted.'))
            return

        dlg = wx.MessageDialog(
            parent=self,
            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:
                sutils.delete_mapset(self.gisdbase, location, mapset)
                self.OnSelectLocation(None)
                self.lbmapsets.SetSelection(0)
            except:
                wx.MessageBox(message=_('Unable to delete mapset'))

        dlg.Destroy()

    def DeleteLocation(self, event):
        """
        Delete selected location
        """

        location = self.listOfLocations[self.lblocations.GetSelection()]

        dlg = wx.MessageDialog(
            parent=self,
            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:
                sutils.delete_location(self.gisdbase, location)
                self.UpdateLocations(self.gisdbase)
                self.lblocations.SetSelection(0)
                self.OnSelectLocation(None)
                self.lbmapsets.SetSelection(0)
            except:
                wx.MessageBox(message=_('Unable to delete location'))

        dlg.Destroy()

    def DownloadLocation(self, event):
        """Download location online"""
        from startup.locdownload import LocationDownloadDialog

        loc_download = LocationDownloadDialog(parent=self,
                                              database=self.gisdbase)
        loc_download.ShowModal()
        location = loc_download.GetLocation()
        if location:
            # get the new location to the list
            self.UpdateLocations(self.gisdbase)
            # seems to be used in similar context
            self.UpdateMapsets(os.path.join(self.gisdbase, location))
            self.lblocations.SetSelection(self.listOfLocations.index(location))
            # wizard does this as well, not sure if needed
            self.SetLocation(self.gisdbase, location, 'PERMANENT')
            # seems to be used in similar context
            self.OnSelectLocation(None)
        loc_download.Destroy()

    def UpdateLocations(self, dbase):
        """Update list of locations"""
        try:
            self.listOfLocations = GetListOfLocations(dbase)
        except (UnicodeEncodeError, UnicodeDecodeError) as e:
            GError(parent=self,
                   message=_(
                       "Unicode error detected. "
                       "Check your locale settings. Details: {0}").format(e),
                   showTraceback=False)

        self.lblocations.Clear()
        self.lblocations.InsertItems(self.listOfLocations, 0)

        if len(self.listOfLocations) > 0:
            self._hideMessage()
            self.lblocations.SetSelection(0)
        else:
            self.lblocations.SetSelection(wx.NOT_FOUND)
            self._showWarning(
                _("No GRASS Location found in '%s'."
                  " Create a new Location or choose different"
                  " GRASS database directory.") % self.gisdbase)

        return self.listOfLocations

    def UpdateMapsets(self, location):
        """Update list of mapsets"""
        self.FormerMapsetSelection = wx.NOT_FOUND  # for non-selectable item

        self.listOfMapsetsSelectable = list()
        self.listOfMapsets = GetListOfMapsets(self.gisdbase, location)

        self.lbmapsets.Clear()

        # disable mapset with denied permission
        locationName = os.path.basename(location)

        ret = RunCommand('g.mapset',
                         read=True,
                         flags='l',
                         location=locationName,
                         gisdbase=self.gisdbase)

        if ret:
            for line in ret.splitlines():
                self.listOfMapsetsSelectable += line.split(' ')
        else:
            self.SetLocation(self.gisdbase, locationName, "PERMANENT")
            # first run only
            self.listOfMapsetsSelectable = copy.copy(self.listOfMapsets)

        disabled = []
        idx = 0
        for mapset in self.listOfMapsets:
            if mapset not in self.listOfMapsetsSelectable or \
                    get_lockfile_if_present(self.gisdbase,
                                            locationName, mapset):
                disabled.append(idx)
            idx += 1

        self.lbmapsets.InsertItems(self.listOfMapsets, 0, disabled=disabled)

        return self.listOfMapsets

    def OnSelectLocation(self, event):
        """Location selected"""
        if event:
            self.lblocations.SetSelection(event.GetIndex())

        if self.lblocations.GetSelection() != wx.NOT_FOUND:
            self.UpdateMapsets(
                os.path.join(
                    self.gisdbase,
                    self.listOfLocations[self.lblocations.GetSelection()]))
        else:
            self.listOfMapsets = []

        disabled = []
        idx = 0
        try:
            locationName = self.listOfLocations[
                self.lblocations.GetSelection()]
        except IndexError:
            locationName = ''

        for mapset in self.listOfMapsets:
            if mapset not in self.listOfMapsetsSelectable or \
                    get_lockfile_if_present(self.gisdbase,
                                            locationName, mapset):
                disabled.append(idx)
            idx += 1

        self.lbmapsets.Clear()
        self.lbmapsets.InsertItems(self.listOfMapsets, 0, disabled=disabled)

        if len(self.listOfMapsets) > 0:
            self.lbmapsets.SetSelection(0)
            if locationName:
                # enable start button when location and mapset is selected
                self.bstart.Enable()
                self.bstart.SetFocus()
                self.bmapset.Enable()
                # replacing disabled choice, perhaps just mapset needed
                self.rename_location_button.Enable()
                self.delete_location_button.Enable()
                self.rename_mapset_button.Enable()
                self.delete_mapset_button.Enable()
        else:
            self.lbmapsets.SetSelection(wx.NOT_FOUND)
            self.bstart.Enable(False)
            self.bmapset.Enable(False)
            # this all was originally a choice, perhaps just mapset needed
            self.rename_location_button.Enable(False)
            self.delete_location_button.Enable(False)
            self.rename_mapset_button.Enable(False)
            self.delete_mapset_button.Enable(False)

    def OnSelectMapset(self, event):
        """Mapset selected"""
        self.lbmapsets.SetSelection(event.GetIndex())

        if event.GetText() not in self.listOfMapsetsSelectable:
            self.lbmapsets.SetSelection(self.FormerMapsetSelection)
        else:
            self.FormerMapsetSelection = event.GetIndex()
            event.Skip()

    def OnSetDatabase(self, event):
        """Database set"""
        gisdbase = self.tgisdbase.GetValue()
        self._hideMessage()
        if not os.path.exists(gisdbase):
            self._showError(_("Path '%s' doesn't exist.") % gisdbase)
            return

        self.gisdbase = self.tgisdbase.GetValue()
        self.UpdateLocations(self.gisdbase)

        self.OnSelectLocation(None)

    def OnBrowse(self, event):
        """'Browse' button clicked"""
        if not event:
            defaultPath = os.getenv('HOME')
        else:
            defaultPath = ""

        dlg = wx.DirDialog(parent=self,
                           message=_("Choose GIS Data Directory"),
                           defaultPath=defaultPath,
                           style=wx.DD_DEFAULT_STYLE)

        if dlg.ShowModal() == wx.ID_OK:
            self.gisdbase = dlg.GetPath()
            self.tgisdbase.SetValue(self.gisdbase)
            self.OnSetDatabase(event)

        dlg.Destroy()

    def OnCreateMapset(self, event):
        """Create new mapset"""
        dlg = NewMapsetDialog(
            parent=self,
            default=self._getDefaultMapsetName(),
            validation_failed_handler=self._nameValidationFailed,
            help_hanlder=self.OnHelp,
        )
        if dlg.ShowModal() == wx.ID_OK:
            mapset = dlg.GetValue()
            return self.CreateNewMapset(mapset=mapset)
        else:
            return False

    def CreateNewMapset(self, mapset):
        if mapset in self.listOfMapsets:
            GMessage(parent=self,
                     message=_("Mapset <%s> already exists.") % mapset)
            return False

        if mapset.lower() == 'ogr':
            dlg1 = wx.MessageDialog(
                parent=self,
                message=_(
                    "Mapset <%s> is reserved for direct "
                    "read access to OGR layers. Please consider to use "
                    "another name for your mapset.\n\n"
                    "Are you really sure that you want to create this mapset?")
                % mapset,
                caption=_("Reserved mapset name"),
                style=wx.YES_NO | wx.NO_DEFAULT | wx.ICON_QUESTION)
            ret = dlg1.ShowModal()
            dlg1.Destroy()
            if ret == wx.ID_NO:
                dlg1.Destroy()
                return False

        try:
            self.gisdbase = self.tgisdbase.GetValue()
            location = self.listOfLocations[self.lblocations.GetSelection()]
            create_mapset(self.gisdbase, location, mapset)
            self.OnSelectLocation(None)
            self.lbmapsets.SetSelection(self.listOfMapsets.index(mapset))
            self.bstart.SetFocus()

            return True
        except Exception as e:
            GError(parent=self,
                   message=_("Unable to create new mapset: %s") % e,
                   showTraceback=False)
            return False

    def OnStart(self, event):
        """'Start GRASS' button clicked"""
        dbase = self.tgisdbase.GetValue()
        location = self.listOfLocations[self.lblocations.GetSelection()]
        mapset = self.listOfMapsets[self.lbmapsets.GetSelection()]

        lockfile = get_lockfile_if_present(dbase, location, mapset)
        if lockfile:
            dlg = wx.MessageDialog(
                parent=self,
                message=_(
                    "GRASS is already running in selected mapset <%(mapset)s>\n"
                    "(file %(lock)s found).\n\n"
                    "Concurrent use not allowed.\n\n"
                    "Do you want to try to remove .gislock (note that you "
                    "need permission for this operation) and continue?") % {
                        'mapset': mapset,
                        'lock': lockfile
                    },
                caption=_("Lock file found"),
                style=wx.YES_NO | wx.NO_DEFAULT | wx.ICON_QUESTION | wx.CENTRE)

            ret = dlg.ShowModal()
            dlg.Destroy()
            if ret == wx.ID_YES:
                dlg1 = wx.MessageDialog(
                    parent=self,
                    message=
                    _("ARE YOU REALLY SURE?\n\n"
                      "If you really are running another GRASS session doing this "
                      "could corrupt your data. Have another look in the processor "
                      "manager just to be sure..."),
                    caption=_("Lock file found"),
                    style=wx.YES_NO | wx.NO_DEFAULT | wx.ICON_QUESTION
                    | wx.CENTRE)

                ret = dlg1.ShowModal()
                dlg1.Destroy()

                if ret == wx.ID_YES:
                    try:
                        os.remove(lockfile)
                    except IOError as e:
                        GError(
                            _("Unable to remove '%(lock)s'.\n\n"
                              "Details: %(reason)s") % {
                                  'lock': lockfile,
                                  'reason': e
                              })
                else:
                    return
            else:
                return
        self.SetLocation(dbase, location, mapset)
        self.ExitSuccessfully()

    def SetLocation(self, dbase, location, mapset):
        SetSessionMapset(dbase, location, mapset)

    def _getDefaultMapsetName(self):
        """Returns default name for mapset."""
        try:
            defaultName = getpass.getuser()
            # raise error if not ascii (not valid mapset name)
            defaultName.encode('ascii')
        except:  # whatever might go wrong
            defaultName = 'user'

        return defaultName

    def ExitSuccessfully(self):
        self.Destroy()
        sys.exit(self.exit_success)

    def OnExit(self, event):
        """'Exit' button clicked"""
        self.Destroy()
        sys.exit(self.exit_user_requested)

    def OnHelp(self, event):
        """'Help' button clicked"""

        # help text in lib/init/helptext.html
        RunCommand('g.manual', entry='helptext')

    def OnCloseWindow(self, event):
        """Close window event"""
        event.Skip()
        sys.exit(self.exit_user_requested)

    def _nameValidationFailed(self, ctrl):
        message = _(
            "Name <%(name)s> is not a valid name for location or mapset. "
            "Please use only ASCII characters excluding %(chars)s "
            "and space.") % {
                'name': ctrl.GetValue(),
                'chars': '/"\'@,=*~'
            }
        GError(parent=self, message=message, caption=_("Invalid name"))
Exemple #5
0
class GRASSStartup(wx.Frame):
    exit_success = 0
    # 2 is file not found from python interpreter
    exit_user_requested = 5

    """GRASS start-up screen"""
    def __init__(self, parent = None, id = wx.ID_ANY, style = wx.DEFAULT_FRAME_STYLE):

        #
        # GRASS variables
        #
        self.gisbase  = os.getenv("GISBASE")
        self.grassrc  = self._readGisRC()
        self.gisdbase = self.GetRCValue("GISDBASE")

        #
        # list of locations/mapsets
        #
        self.listOfLocations = []
        self.listOfMapsets = []
        self.listOfMapsetsSelectable = []
        
        wx.Frame.__init__(self, parent = parent, id = id, style = style)
        
        self.locale = wx.Locale(language = wx.LANGUAGE_DEFAULT)

        # scroll panel was used here but not properly and is probably not need
        # as long as it is not high too much
        self.panel = wx.Panel(parent=self, id=wx.ID_ANY)

        # i18N

        #
        # graphical elements
        #
        # image
        try:
            if os.getenv('ISISROOT'):
                name = os.path.join(globalvar.GUIDIR, "images", "startup_banner_isis.png")
            else:
                name = os.path.join(globalvar.GUIDIR, "images", "startup_banner.png")
            self.hbitmap = wx.StaticBitmap(self.panel, wx.ID_ANY,
                                           wx.Bitmap(name = name,
                                                     type = wx.BITMAP_TYPE_PNG))
        except:
            self.hbitmap = wx.StaticBitmap(self.panel, wx.ID_ANY, wx.BitmapFromImage(wx.EmptyImage(530,150)))

        # labels
        ### crashes when LOCATION doesn't exist
        # get version & revision
        versionFile = open(os.path.join(globalvar.ETCDIR, "VERSIONNUMBER"))
        versionLine = versionFile.readline().rstrip('\n')
        versionFile.close()
        try:
            grassVersion, grassRevision = versionLine.split(' ', 1)
            if grassVersion.endswith('svn'):
                grassRevisionStr = ' (%s)' % grassRevision
            else:
                grassRevisionStr = ''
        except ValueError:
            grassVersion = versionLine
            grassRevisionStr = ''
        
        self.gisdbase_box = wx.StaticBox(parent=self.panel, id=wx.ID_ANY,
                                         label=" %s " % _("1. Select GRASS GIS database directory"))
        self.location_box = wx.StaticBox(parent=self.panel, id=wx.ID_ANY,
                                         label=" %s " % _("2. Select GRASS Location"))
        self.mapset_box = wx.StaticBox(parent=self.panel, id=wx.ID_ANY,
                                         label=" %s " % _("3. Select GRASS Mapset"))

        self.lmessage = wx.StaticText(parent=self.panel)
        # It is not clear if all wx versions supports color, so try-except.
        # The color itself may not be correct for all platforms/system settings
        # but in http://xoomer.virgilio.it/infinity77/wxPython/Widgets/wx.SystemSettings.html
        # there is no 'warning' color.
        try:
            self.lmessage.SetForegroundColour(wx.Colour(255, 0, 0))
        except AttributeError:
            pass
        
        self.gisdbase_panel = wx.Panel(parent=self.panel)
        self.location_panel = wx.Panel(parent=self.panel)
        self.mapset_panel = wx.Panel(parent=self.panel)

        self.ldbase = wx.StaticText(
            parent=self.gisdbase_panel, id=wx.ID_ANY,
            label=_("GRASS GIS database directory contains Locations."))

        self.llocation = StaticWrapText(
            parent=self.location_panel, id=wx.ID_ANY,
            label=_("All data in one Location is in the same "
                    " coordinate reference system (projection)."
                    " One Location can be one project."
                    " Location contains Mapsets."),
            style=wx.ALIGN_LEFT)

        self.lmapset = StaticWrapText(
            parent=self.mapset_panel, id=wx.ID_ANY,
            label=_("Mapset contains GIS data related"
                    " to one project, task within one project,"
                    " subregion or user."),
            style=wx.ALIGN_LEFT)

        try:
            for label in [self.ldbase, self.llocation, self.lmapset]:
                label.SetForegroundColour(
                    wx.SystemSettings_GetColour(wx.SYS_COLOUR_GRAYTEXT))
        except AttributeError:
            # for explanation of try-except see above
            pass

        # buttons
        self.bstart = wx.Button(parent = self.panel, id = wx.ID_ANY,
                                label = _("Start &GRASS session"))
        self.bstart.SetDefault()
        self.bexit = wx.Button(parent = self.panel, id = wx.ID_EXIT)
        self.bstart.SetMinSize((180, self.bexit.GetSize()[1]))
        self.bhelp = wx.Button(parent = self.panel, id = wx.ID_HELP)
        self.bbrowse = wx.Button(parent = self.gisdbase_panel, id = wx.ID_ANY,
                                 label = _("&Browse"))
        self.bmapset = wx.Button(parent = self.mapset_panel, id = wx.ID_ANY,
        # GTC New mapset
                                 label = _("&New"))
        self.bmapset.SetToolTipString(
            _("Create a new Mapset in selected Location"))
        self.bwizard = wx.Button(parent = self.location_panel, id = wx.ID_ANY,
        # GTC New location
                                 label = _("N&ew"))
        self.bwizard.SetToolTipString(_("Create a new location using location wizard."
                                        " After location is created successfully,"
                                        " GRASS session is started."))
        self.rename_location_button = wx.Button(parent=self.location_panel, id=wx.ID_ANY,
        # GTC Rename location
                                                label=_("Ren&ame"))
        self.rename_location_button.SetToolTipString(_("Rename selected location"))
        self.delete_location_button = wx.Button(parent=self.location_panel, id=wx.ID_ANY,
        # GTC Delete location
                                                label=_("De&lete"))
        self.delete_location_button.SetToolTipString(_("Delete selected location"))
        self.rename_mapset_button = wx.Button(parent=self.mapset_panel, id=wx.ID_ANY,
        # GTC Rename mapset
                                                label=_("&Rename"))
        self.rename_mapset_button.SetToolTipString(_("Rename selected mapset"))
        self.delete_mapset_button = wx.Button(parent=self.mapset_panel, id=wx.ID_ANY,
        # GTC Delete mapset
                                              label=_("&Delete"))
        self.delete_mapset_button.SetToolTipString(_("Delete selected mapset"))

        # textinputs
        self.tgisdbase = wx.TextCtrl(parent = self.gisdbase_panel, id = wx.ID_ANY, value = "", size = (300, -1),
                                     style = wx.TE_PROCESS_ENTER)

        # Locations
        self.lblocations = GListBox(parent = self.location_panel,
                                    id=wx.ID_ANY, size=(180, 200),
                                    choices = self.listOfLocations)
        self.lblocations.SetColumnWidth(0, 180)

        # TODO: sort; but keep PERMANENT on top of list
        # Mapsets
        self.lbmapsets = GListBox(parent = self.mapset_panel,
                                  id=wx.ID_ANY, size=(180, 200),
                                  choices = self.listOfMapsets)
        self.lbmapsets.SetColumnWidth(0, 180)

        # layout & properties, first do layout so everything is created
        self._do_layout()
        self._set_properties(grassVersion, grassRevisionStr)

        # events
        self.bbrowse.Bind(wx.EVT_BUTTON,      self.OnBrowse)
        self.bstart.Bind(wx.EVT_BUTTON,       self.OnStart)
        self.bexit.Bind(wx.EVT_BUTTON,        self.OnExit)
        self.bhelp.Bind(wx.EVT_BUTTON,        self.OnHelp)
        self.bmapset.Bind(wx.EVT_BUTTON,      self.OnCreateMapset)
        self.bwizard.Bind(wx.EVT_BUTTON,      self.OnWizard)
        
        self.rename_location_button.Bind(wx.EVT_BUTTON, self.RenameLocation)
        self.delete_location_button.Bind(wx.EVT_BUTTON, self.DeleteLocation)
        self.rename_mapset_button.Bind(wx.EVT_BUTTON, self.RenameMapset)
        self.delete_mapset_button.Bind(wx.EVT_BUTTON, self.DeleteMapset)
        
        self.lblocations.Bind(wx.EVT_LIST_ITEM_SELECTED, self.OnSelectLocation)
        self.lbmapsets.Bind(wx.EVT_LIST_ITEM_SELECTED,   self.OnSelectMapset)
        self.lbmapsets.Bind(wx.EVT_LIST_ITEM_ACTIVATED, self.OnStart)
        self.tgisdbase.Bind(wx.EVT_TEXT_ENTER, self.OnSetDatabase)
        self.Bind(wx.EVT_CLOSE,               self.OnCloseWindow)
        
    def _set_properties(self, version, revision):
        """Set frame properties"""
        self.SetTitle(_("GRASS GIS %s startup%s") % (version, revision))
        self.SetIcon(wx.Icon(os.path.join(globalvar.ICONDIR, "grass.ico"),
                             wx.BITMAP_TYPE_ICO))

        self.bstart.SetForegroundColour(wx.Colour(35, 142, 35))
        self.bstart.SetToolTipString(_("Enter GRASS session"))
        self.bstart.Enable(False)
        self.bmapset.Enable(False)
        # this all was originally a choice, perhaps just mapset needed
        self.rename_location_button.Enable(False)
        self.delete_location_button.Enable(False)
        self.rename_mapset_button.Enable(False)
        self.delete_mapset_button.Enable(False)

        # set database
        if not self.gisdbase:
            # sets an initial path for gisdbase if nothing in GISRC
            if os.path.isdir(os.getenv("HOME")):
                self.gisdbase = os.getenv("HOME")
            else:
                self.gisdbase = os.getcwd()
        try:
            self.tgisdbase.SetValue(self.gisdbase)
        except UnicodeDecodeError:
            wx.MessageBox(parent = self, caption = _("Error"),
                          message = _("Unable to set GRASS database. "
                                      "Check your locale settings."),
                          style = wx.OK | wx.ICON_ERROR | wx.CENTRE)
        
        self.OnSetDatabase(None)
        location = self.GetRCValue("LOCATION_NAME")
        if location == "<UNKNOWN>":
            return
        if not os.path.isdir(os.path.join(self.gisdbase, location)):
            location = None
        
        # list of locations
        self.UpdateLocations(self.gisdbase)
        try:
            self.lblocations.SetSelection(self.listOfLocations.index(location),
                                          force = True)
            self.lblocations.EnsureVisible(self.listOfLocations.index(location))
        except ValueError:
            sys.stderr.write(_("ERROR: Location <%s> not found\n") % self.GetRCValue("LOCATION_NAME"))
            if len(self.listOfLocations) > 0:
                self.lblocations.SetSelection(0, force = True)
                self.lblocations.EnsureVisible(0)
                location = self.listOfLocations[0]
            else:
                return
        
        # list of mapsets
        self.UpdateMapsets(os.path.join(self.gisdbase, location))
        mapset = self.GetRCValue("MAPSET")
        if mapset:
            try:
                self.lbmapsets.SetSelection(self.listOfMapsets.index(mapset),
                                            force = True)
                self.lbmapsets.EnsureVisible(self.listOfMapsets.index(mapset))
            except ValueError:
                sys.stderr.write(_("ERROR: Mapset <%s> not found\n") % mapset)
                self.lbmapsets.SetSelection(0, force = True)
                self.lbmapsets.EnsureVisible(0)
        
    def _do_layout(self):
        sizer = wx.BoxSizer(wx.VERTICAL)
        self.sizer = sizer  # for the layout call after changing message
        dbase_sizer     = wx.BoxSizer(wx.HORIZONTAL)
        
        location_mapset_sizer  = wx.BoxSizer(wx.HORIZONTAL)

        gisdbase_panel_sizer  = wx.BoxSizer(wx.VERTICAL)
        gisdbase_boxsizer = wx.StaticBoxSizer(self.gisdbase_box, wx.VERTICAL)        

        btns_sizer      = wx.BoxSizer(wx.HORIZONTAL)
        
        self.gisdbase_panel.SetSizer(gisdbase_panel_sizer)

        # gis data directory
        
        gisdbase_boxsizer.Add(item=self.gisdbase_panel, proportion=1,
                              flag=wx.EXPAND | wx.ALL,
                              border=1)
        
        gisdbase_panel_sizer.Add(item=dbase_sizer, proportion=1,
                                 flag=wx.EXPAND | wx.ALL,
                                 border=1)
        gisdbase_panel_sizer.Add(item=self.ldbase, proportion=0,
                                 flag=wx.EXPAND | wx.ALL,
                                 border=1)

        dbase_sizer.Add(item = self.tgisdbase, proportion = 1,
                        flag = wx.ALIGN_CENTER_VERTICAL | wx.ALL,
                        border = 1)
        dbase_sizer.Add(item = self.bbrowse, proportion = 0,
                        flag = wx.ALIGN_CENTER_VERTICAL | wx.ALL,
                        border = 1)

        gisdbase_panel_sizer.Fit(self.gisdbase_panel)

        # location and mapset lists

        def layout_list_box(box, panel, list_box, buttons, description):
            panel_sizer = wx.BoxSizer(wx.VERTICAL)
            main_sizer = wx.BoxSizer(wx.HORIZONTAL)
            box_sizer = wx.StaticBoxSizer(box, wx.VERTICAL)
            buttons_sizer = wx.BoxSizer(wx.VERTICAL)

            panel.SetSizer(panel_sizer)
            panel_sizer.Fit(panel)

            main_sizer.Add(item=list_box, proportion=1,
                           flag=wx.EXPAND | wx.ALL,
                           border=1)
            main_sizer.Add(item=buttons_sizer, proportion=0,
                           flag=wx.ALIGN_CENTER_HORIZONTAL | wx.ALL,
                           border=1)
            for button in buttons:
                buttons_sizer.Add(item=button, proportion=0,
                                  flag=wx.EXPAND | wx.LEFT | wx.RIGHT | wx.BOTTOM,
                                  border=3)
            box_sizer.Add(item=panel, proportion=1,
                          flag=wx.EXPAND | wx.ALL,
                          border=1)
            panel_sizer.Add(item=main_sizer, proportion=1,
                            flag=wx.EXPAND | wx.ALL,
                            border=1)
            panel_sizer.Add(item=description, proportion=0,
                            flag=wx.EXPAND | wx.ALL,
                            border=1)
            return box_sizer

        location_boxsizer = layout_list_box(
            box=self.location_box,
            panel=self.location_panel,
            list_box=self.lblocations,
            buttons=[self.bwizard, self.rename_location_button,
                     self.delete_location_button],
            description=self.llocation)
        mapset_boxsizer = layout_list_box(
            box=self.mapset_box,
            panel=self.mapset_panel,
            list_box=self.lbmapsets,
            buttons=[self.bmapset, self.rename_mapset_button,
                     self.delete_mapset_button],
            description=self.lmapset)

        # location and mapset sizer
        location_mapset_sizer.Add(item=location_boxsizer, proportion=1,
                           flag = wx.LEFT | wx.RIGHT | wx.EXPAND,
                           border = 3) 
        location_mapset_sizer.Add(item=mapset_boxsizer, proportion=1,
                           flag = wx.RIGHT | wx.EXPAND,
                           border = 3)

        # buttons
        btns_sizer.Add(item = self.bstart, proportion = 0,
                       flag = wx.ALIGN_CENTER_HORIZONTAL |
                       wx.ALIGN_CENTER_VERTICAL |
                       wx.ALL,
                       border = 5)
        btns_sizer.Add(item = self.bexit, proportion = 0,
                       flag = wx.ALIGN_CENTER_HORIZONTAL |
                       wx.ALIGN_CENTER_VERTICAL |
                       wx.ALL,
                       border = 5)
        btns_sizer.Add(item = self.bhelp, proportion = 0,
                       flag = wx.ALIGN_CENTER_HORIZONTAL |
                       wx.ALIGN_CENTER_VERTICAL |
                       wx.ALL,
                       border = 5)
        
        # main sizer
        sizer.Add(item = self.hbitmap,
                  proportion = 0,
                  flag = wx.ALIGN_CENTER_VERTICAL |
                  wx.ALIGN_CENTER_HORIZONTAL |
                  wx.ALL,
                  border = 3) # image
        sizer.Add(item=gisdbase_boxsizer, proportion=0,
                  flag = wx.ALIGN_CENTER_HORIZONTAL |
                  wx.RIGHT | wx.LEFT | wx.TOP | wx.EXPAND,
                  border = 3) # GISDBASE setting

        # warning/error message
        sizer.Add(item=self.lmessage,
                  proportion=0,
                  flag=wx.ALIGN_CENTER_VERTICAL |
                  wx.ALIGN_LEFT | wx.ALL | wx.EXPAND, border=5)
        sizer.Add(item=location_mapset_sizer, proportion=1,
                  flag = wx.RIGHT | wx.LEFT | wx.EXPAND,
                  border = 1)
        sizer.Add(item = btns_sizer, proportion = 0,
                  flag = wx.ALIGN_CENTER_VERTICAL |
                  wx.ALIGN_CENTER_HORIZONTAL |
                  wx.RIGHT | wx.LEFT,
                  border = 3)

        self.panel.SetAutoLayout(True)
        self.panel.SetSizer(sizer)
        sizer.Fit(self.panel)
        sizer.SetSizeHints(self)
        self.Layout()

    def _readGisRC(self):
        """Read variables from $HOME/.grass7/rc file
        """
        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 _showWarning(self, text):
        """Displays a warning, hint or info message to the user.

        This function can be used for all kinds of messages except for
        error messages.

        .. note::
            There is no cleaning procedure. You should call _hideMessage when
            you know that there is everything correct now.
        """
        self.lmessage.SetLabel(text)
        self.lmessage.Wrap(self.GetClientSize()[0])
        self.sizer.Layout()

    def _showError(self, text):
        """Displays a error message to the user.

        This function should be used only when something serious and unexpected
        happens, otherwise _showWarning should be used.

        .. note::
            There is no cleaning procedure. You should call _hideMessage when
            you know that there is everything correct now.
        """
        self.lmessage.SetLabel(_("Error: {text}").format(text=text))
        self.lmessage.Wrap(self.GetClientSize()[0])
        self.sizer.Layout()

    def _hideMessage(self):
        """Clears/hides the error message."""
        # we do no hide widget
        # because we do not want the dialog to change the size
        self.lmessage.SetLabel("")
        self.sizer.Layout()

    def GetRCValue(self, value):
        """Return GRASS variable (read from GISRC)
        """
        if self.grassrc.has_key(value):
            return self.grassrc[value]
        else:
            return None
        
    def OnWizard(self, event):
        """Location wizard started"""
        from location_wizard.wizard import LocationWizard
        gWizard = LocationWizard(parent = self,
                                 grassdatabase = self.tgisdbase.GetValue())
        if gWizard.location !=  None:
            self.tgisdbase.SetValue(gWizard.grassdatabase)
            self.OnSetDatabase(None)
            self.UpdateMapsets(os.path.join(self.gisdbase, gWizard.location))
            self.lblocations.SetSelection(self.listOfLocations.index(gWizard.location))
            self.lbmapsets.SetSelection(0)
            self.SetLocation(self.gisdbase, gWizard.location, 'PERMANENT')
            if gWizard.georeffile:
                message = _("Do you want to import <%(name)s> to the newly created location?") % \
                    {'name': gWizard.georeffile}
                dlg = wx.MessageDialog(parent = self,
                                       message = message,
                                       caption = _("Import data?"),
                                       style = wx.YES_NO | wx.YES_DEFAULT | wx.ICON_QUESTION)
                dlg.CenterOnScreen()
                if dlg.ShowModal() == wx.ID_YES:
                    self.ImportFile(gWizard.georeffile)
                else:
                    self.SetDefaultRegion(location = gWizard.location)
                dlg.Destroy()
            else:
                self.SetDefaultRegion(location = gWizard.location)

            dlg = TextEntryDialog(parent=self,
                                  message=_("Do you want to create new mapset?"),
                                  caption=_("Create new mapset"),
                                  defaultValue=self._getDefaultMapsetName(),
                                  validator=GenericValidator(grass.legal_name, self._nameValidationFailed),
                                  style=wx.OK | wx.CANCEL | wx.HELP)
            help = dlg.FindWindowById(wx.ID_HELP)
            help.Bind(wx.EVT_BUTTON, self.OnHelp)
            if dlg.ShowModal() == wx.ID_OK:
                mapsetName = dlg.GetValue()
                self.CreateNewMapset(mapsetName)

    def SetDefaultRegion(self, location):
        """Asks to set default region."""
        caption = _("Location <%s> created") % location
        message = _("Do you want to set the default "
                    "region extents and resolution now?")
        dlg = wx.MessageDialog(parent = self,
                               message = "%(caption)s.\n\n%(extent)s" % ({'caption': caption,
                                                                          'extent': message}),
                               caption = caption,
                               style = wx.YES_NO | wx.NO_DEFAULT | wx.ICON_QUESTION)
        dlg.CenterOnScreen()
        if dlg.ShowModal() == wx.ID_YES:
            dlg.Destroy()
            defineRegion = RegionDef(self, location = location)
            defineRegion.CenterOnScreen()
            defineRegion.ShowModal()
            defineRegion.Destroy()
        else:
            dlg.Destroy()

    def ImportFile(self, 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.Yield()
        if mapName in 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 = self,
                   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=self)

    # the event can be refactored out by using lambda in bind
    def RenameMapset(self, event):
        """Rename selected mapset
        """
        location = self.listOfLocations[self.lblocations.GetSelection()]
        mapset   = self.listOfMapsets[self.lbmapsets.GetSelection()]
        if mapset ==  'PERMANENT':
            GMessage(parent = self,
                     message = _('Mapset <PERMANENT> is required for valid GRASS location.\n\n'
                                 'This mapset cannot be renamed.'))
            return
        
        dlg = TextEntryDialog(parent = self,
                              message = _('Current name: %s\n\nEnter new name:') % mapset,
                              caption = _('Rename selected mapset'),
                              validator = GenericValidator(grass.legal_name, self._nameValidationFailed))
        
        if dlg.ShowModal() ==  wx.ID_OK:
            newmapset = dlg.GetValue()
            if newmapset ==  mapset:
                dlg.Destroy()
                return
            
            if newmapset in self.listOfMapsets:
                wx.MessageBox(parent = self,
                              caption = _('Message'),
                              message = _('Unable to rename mapset.\n\n'
                                        'Mapset <%s> already exists in location.') % newmapset,
                              style = wx.OK | wx.ICON_INFORMATION | wx.CENTRE)
            else:
                try:
                    os.rename(os.path.join(self.gisdbase, location, mapset),
                              os.path.join(self.gisdbase, location, newmapset))
                    self.OnSelectLocation(None)
                    self.lbmapsets.SetSelection(self.listOfMapsets.index(newmapset))
                except StandardError as e:
                    wx.MessageBox(parent = self,
                                  caption = _('Error'),
                                  message = _('Unable to rename mapset.\n\n%s') % e,
                                  style = wx.OK | wx.ICON_ERROR | wx.CENTRE)
            
        dlg.Destroy()

    def RenameLocation(self, event):
        """Rename selected location
        """
        location = self.listOfLocations[self.lblocations.GetSelection()]

        dlg = TextEntryDialog(parent = self,
                              message = _('Current name: %s\n\nEnter new name:') % location,
                              caption = _('Rename selected location'),
                              validator = GenericValidator(grass.legal_name, self._nameValidationFailed))

        if dlg.ShowModal() ==  wx.ID_OK:
            newlocation = dlg.GetValue()
            if newlocation ==  location:
                dlg.Destroy()
                return

            if newlocation in self.listOfLocations:
                wx.MessageBox(parent = self,
                              caption = _('Message'),
                              message = _('Unable to rename location.\n\n'
                                        'Location <%s> already exists in GRASS database.') % newlocation,
                              style = wx.OK | wx.ICON_INFORMATION | wx.CENTRE)
            else:
                try:
                    os.rename(os.path.join(self.gisdbase, location),
                              os.path.join(self.gisdbase, newlocation))
                    self.UpdateLocations(self.gisdbase)
                    self.lblocations.SetSelection(self.listOfLocations.index(newlocation))
                    self.UpdateMapsets(newlocation)
                except StandardError as e:
                    wx.MessageBox(parent = self,
                                  caption = _('Error'),
                                  message = _('Unable to rename location.\n\n%s') % e,
                                  style = wx.OK | wx.ICON_ERROR | wx.CENTRE)
        
        dlg.Destroy()

    def DeleteMapset(self, event):
        """Delete selected mapset
        """
        location = self.listOfLocations[self.lblocations.GetSelection()]
        mapset   = self.listOfMapsets[self.lbmapsets.GetSelection()]
        if mapset ==  'PERMANENT':
            GMessage(parent = self,
                     message = _('Mapset <PERMANENT> is required for valid GRASS location.\n\n'
                                 'This mapset cannot be deleted.'))
            return
        
        dlg = wx.MessageDialog(parent = self, 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:
                shutil.rmtree(os.path.join(self.gisdbase, location, mapset))
                self.OnSelectLocation(None)
                self.lbmapsets.SetSelection(0)
            except:
                wx.MessageBox(message = _('Unable to delete mapset'))

        dlg.Destroy()

    def DeleteLocation(self, event):
        """
        Delete selected location
        """

        location = self.listOfLocations[self.lblocations.GetSelection()]

        dlg = wx.MessageDialog(parent = self, 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:
                shutil.rmtree(os.path.join(self.gisdbase, location))
                self.UpdateLocations(self.gisdbase)
                self.lblocations.SetSelection(0)
                self.OnSelectLocation(None)
                self.lbmapsets.SetSelection(0)
            except:
                wx.MessageBox(message = _('Unable to delete location'))

        dlg.Destroy()

    def UpdateLocations(self, dbase):
        """Update list of locations"""
        try:
            self.listOfLocations = GetListOfLocations(dbase)
        except UnicodeEncodeError:
            GError(parent = self,
                   message = _("Unable to set GRASS database. "
                               "Check your locale settings."))
                
        self.lblocations.Clear()
        self.lblocations.InsertItems(self.listOfLocations, 0)

        if len(self.listOfLocations) > 0:
            self._hideMessage()
            self.lblocations.SetSelection(0)
        else:
            self.lblocations.SetSelection(wx.NOT_FOUND)
            self._showWarning(_("No GRASS Location found in '%s'."
                                " Create a new Location or choose different"
                                " GRASS database directory.")
                              % self.gisdbase)

        return self.listOfLocations

    def UpdateMapsets(self, location):
        """Update list of mapsets"""
        self.FormerMapsetSelection = wx.NOT_FOUND # for non-selectable item
        
        self.listOfMapsetsSelectable = list()
        self.listOfMapsets = GetListOfMapsets(self.gisdbase, location)
        
        self.lbmapsets.Clear()
        
        # disable mapset with denied permission
        locationName = os.path.basename(location)
        
        ret = RunCommand('g.mapset',
                         read = True,
                         flags = 'l',
                         location = locationName,
                         gisdbase = self.gisdbase)
            
        if ret:
            for line in ret.splitlines():
                self.listOfMapsetsSelectable += line.split(' ')
        else:
            RunCommand("g.gisenv",
                       set = "GISDBASE=%s" % self.gisdbase)
            RunCommand("g.gisenv",
                       set = "LOCATION_NAME=%s" % locationName)
            RunCommand("g.gisenv",
                       set = "MAPSET=PERMANENT")
            # first run only
            self.listOfMapsetsSelectable = copy.copy(self.listOfMapsets)
        
        disabled = []
        idx = 0
        for mapset in self.listOfMapsets:
            if mapset not in self.listOfMapsetsSelectable or \
                    os.path.isfile(os.path.join(self.gisdbase,
                                                locationName,
                                                mapset, ".gislock")):
                disabled.append(idx)
            idx +=  1
        
        self.lbmapsets.InsertItems(self.listOfMapsets, 0, disabled = disabled)
        
        return self.listOfMapsets

    def OnSelectLocation(self, event):
        """Location selected"""
        if event:
            self.lblocations.SetSelection(event.GetIndex())
            
        if self.lblocations.GetSelection() !=  wx.NOT_FOUND:
            self.UpdateMapsets(os.path.join(self.gisdbase,
                                            self.listOfLocations[self.lblocations.GetSelection()]))
        else:
            self.listOfMapsets = []
        
        disabled = []
        idx = 0
        try:
            locationName = self.listOfLocations[self.lblocations.GetSelection()]
        except IndexError:
            locationName = ''
        
        for mapset in self.listOfMapsets:
            if mapset not in self.listOfMapsetsSelectable or \
                    os.path.isfile(os.path.join(self.gisdbase,
                                                locationName,
                                                mapset, ".gislock")):
                disabled.append(idx)
            idx +=  1

        self.lbmapsets.Clear()
        self.lbmapsets.InsertItems(self.listOfMapsets, 0, disabled = disabled)

        if len(self.listOfMapsets) > 0:
            self.lbmapsets.SetSelection(0)
            if locationName:
                # enable start button when location and mapset is selected
                self.bstart.Enable()
                self.bstart.SetFocus()
                self.bmapset.Enable()
                # replacing disabled choice, perhaps just mapset needed
                self.rename_location_button.Enable()
                self.delete_location_button.Enable()
                self.rename_mapset_button.Enable()
                self.delete_mapset_button.Enable()
        else:
            self.lbmapsets.SetSelection(wx.NOT_FOUND)
            self.bstart.Enable(False)
            self.bmapset.Enable(False)
            # this all was originally a choice, perhaps just mapset needed
            self.rename_location_button.Enable(False)
            self.delete_location_button.Enable(False)
            self.rename_mapset_button.Enable(False)
            self.delete_mapset_button.Enable(False)
        
    def OnSelectMapset(self, event):
        """Mapset selected"""
        self.lbmapsets.SetSelection(event.GetIndex())

        if event.GetText() not in self.listOfMapsetsSelectable:
            self.lbmapsets.SetSelection(self.FormerMapsetSelection)
        else:
            self.FormerMapsetSelection = event.GetIndex()
            event.Skip()

    def OnSetDatabase(self, event):
        """Database set"""
        gisdbase = self.tgisdbase.GetValue()
        self._hideMessage()
        if not os.path.exists(gisdbase):
            self._showError(_("Path '%s' doesn't exist.") % gisdbase)
            return
        
        self.gisdbase = self.tgisdbase.GetValue()
        self.UpdateLocations(self.gisdbase)
        
        self.OnSelectLocation(None)

    def OnBrowse(self, event):
        """'Browse' button clicked"""
        if not event:
            defaultPath = os.getenv('HOME')
        else:
            defaultPath = ""
        
        dlg = wx.DirDialog(parent = self, message = _("Choose GIS Data Directory"),
                           defaultPath = defaultPath, style = wx.DD_DEFAULT_STYLE)
        
        if dlg.ShowModal() ==  wx.ID_OK:
            self.gisdbase = dlg.GetPath()
            self.tgisdbase.SetValue(self.gisdbase)
            self.OnSetDatabase(event)
        
        dlg.Destroy()

    def OnCreateMapset(self, event):
        """Create new mapset"""
        dlg = TextEntryDialog(parent = self,
                              message = _('Enter name for new mapset:'),
                              caption = _('Create new mapset'),
                              defaultValue = self._getDefaultMapsetName(),
                              validator = GenericValidator(grass.legal_name, self._nameValidationFailed))
        if dlg.ShowModal() == wx.ID_OK:
            mapset = dlg.GetValue()
            return self.CreateNewMapset(mapset = mapset)
        else:
            return False

    def CreateNewMapset(self, mapset):
        if mapset in self.listOfMapsets:
            GMessage(parent = self,
                     message = _("Mapset <%s> already exists.") % mapset)
            return False

        if mapset.lower() == 'ogr':
            dlg1 = wx.MessageDialog(parent = self,
                                    message = _("Mapset <%s> is reserved for direct "
                                                "read access to OGR layers. Please consider to use "
                                                "another name for your mapset.\n\n"
                                                "Are you really sure that you want to create this mapset?") % mapset,
                                    caption = _("Reserved mapset name"),
                                    style = wx.YES_NO | wx.NO_DEFAULT | wx.ICON_QUESTION)
            ret = dlg1.ShowModal()
            dlg1.Destroy()
            if ret == wx.ID_NO:
                dlg1.Destroy()
                return False
        
        try:
            self.gisdbase = self.tgisdbase.GetValue()
            location = self.listOfLocations[self.lblocations.GetSelection()]
            os.mkdir(os.path.join(self.gisdbase, location, mapset))
            # copy WIND file and its permissions from PERMANENT and set permissions to u+rw,go+r
            shutil.copy(os.path.join(self.gisdbase, location, 'PERMANENT', 'WIND'),
                        os.path.join(self.gisdbase, location, mapset))
            # os.chmod(os.path.join(database,location,mapset,'WIND'), 0644)
            self.OnSelectLocation(None)
            self.lbmapsets.SetSelection(self.listOfMapsets.index(mapset))
            self.bstart.SetFocus()

            return True
        except StandardError as e:
            GError(parent = self,
                   message = _("Unable to create new mapset: %s") % e,
                   showTraceback = False)
            return False

    def OnStart(self, event):
        """'Start GRASS' button clicked"""
        dbase    = self.tgisdbase.GetValue()
        location = self.listOfLocations[self.lblocations.GetSelection()]
        mapset   = self.listOfMapsets[self.lbmapsets.GetSelection()]
        
        lockfile = os.path.join(dbase, location, mapset, '.gislock')
        if os.path.isfile(lockfile):
            dlg = wx.MessageDialog(parent = self,
                                   message = _("GRASS is already running in selected mapset <%(mapset)s>\n"
                                               "(file %(lock)s found).\n\n"
                                               "Concurrent use not allowed.\n\n"
                                               "Do you want to try to remove .gislock (note that you "
                                               "need permission for this operation) and continue?") % 
                                   { 'mapset' : mapset, 'lock' : lockfile },
                                   caption = _("Lock file found"),
                                   style = wx.YES_NO | wx.NO_DEFAULT |
                                   wx.ICON_QUESTION | wx.CENTRE)
            
            ret = dlg.ShowModal()
            dlg.Destroy()
            if ret == wx.ID_YES:
                dlg1 = wx.MessageDialog(parent = self,
                                        message = _("ARE YOU REALLY SURE?\n\n"
                                                    "If you really are running another GRASS session doing this "
                                                    "could corrupt your data. Have another look in the processor "
                                                    "manager just to be sure..."),
                                        caption = _("Lock file found"),
                                        style = wx.YES_NO | wx.NO_DEFAULT |
                                        wx.ICON_QUESTION | wx.CENTRE)
                
                ret = dlg1.ShowModal()
                dlg1.Destroy()
                
                if ret == wx.ID_YES:
                    try:
                        os.remove(lockfile)
                    except IOError as e:
                        GError(_("Unable to remove '%(lock)s'.\n\n"
                                 "Details: %(reason)s") % { 'lock' : lockfile, 'reason' : e})
                else:
                    return
            else:
                return
        self.SetLocation(dbase, location, mapset)
        self.ExitSuccessfully()

    def SetLocation(self, dbase, location, mapset):
        RunCommand("g.gisenv",
                   set = "GISDBASE=%s" % dbase)
        RunCommand("g.gisenv",
                   set = "LOCATION_NAME=%s" % location)
        RunCommand("g.gisenv",
                   set = "MAPSET=%s" % mapset)

    def _getDefaultMapsetName(self):
        """Returns default name for mapset."""
        try:
            defaultName = getpass.getuser()
            defaultName.encode('ascii') # raise error if not ascii (not valid mapset name)
        except: # whatever might go wrong
            defaultName = 'user'

        return defaultName

    def ExitSuccessfully(self):
        self.Destroy()
        sys.exit(self.exit_success)

    def OnExit(self, event):
        """'Exit' button clicked"""
        self.Destroy()
        sys.exit(self.exit_user_requested)

    def OnHelp(self, event):
        """'Help' button clicked"""

        # help text in lib/init/helptext.html
        RunCommand('g.manual', entry = 'helptext')

    def OnCloseWindow(self, event):
        """Close window event"""
        event.Skip()
        sys.exit(self.exit_user_requested)

    def _nameValidationFailed(self, ctrl):
        message = _("Name <%(name)s> is not a valid name for location or mapset. "
                    "Please use only ASCII characters excluding %(chars)s "
                    "and space.") % {'name': ctrl.GetValue(), 'chars': '/"\'@,=*~'}
        GError(parent=self, message=message, caption=_("Invalid name"))
Exemple #6
0
class GRASSStartup(wx.Frame):
    """GRASS start-up screen"""
    def __init__(self,
                 parent=None,
                 id=wx.ID_ANY,
                 style=wx.DEFAULT_FRAME_STYLE):

        #
        # GRASS variables
        #
        self.gisbase = os.getenv("GISBASE")
        self.grassrc = self._readGisRC()
        self.gisdbase = self.GetRCValue("GISDBASE")

        #
        # list of locations/mapsets
        #
        self.listOfLocations = []
        self.listOfMapsets = []
        self.listOfMapsetsSelectable = []

        wx.Frame.__init__(self, parent=parent, id=id, style=style)

        self.locale = wx.Locale(language=wx.LANGUAGE_DEFAULT)

        self.panel = scrolled.ScrolledPanel(parent=self, id=wx.ID_ANY)

        # i18N

        #
        # graphical elements
        #
        # image
        try:
            if os.getenv('ISISROOT'):
                name = os.path.join(globalvar.GUIDIR, "images",
                                    "startup_banner_isis.png")
            else:
                name = os.path.join(globalvar.GUIDIR, "images",
                                    "startup_banner.png")
            self.hbitmap = wx.StaticBitmap(
                self.panel, wx.ID_ANY,
                wx.Bitmap(name=name, type=wx.BITMAP_TYPE_PNG))
        except:
            self.hbitmap = wx.StaticBitmap(
                self.panel, wx.ID_ANY,
                wx.BitmapFromImage(wx.EmptyImage(530, 150)))

        # labels
        ### crashes when LOCATION doesn't exist
        # get version & revision
        versionFile = open(os.path.join(globalvar.ETCDIR, "VERSIONNUMBER"))
        versionLine = versionFile.readline().rstrip('\n')
        versionFile.close()
        try:
            grassVersion, grassRevision = versionLine.split(' ', 1)
            if grassVersion.endswith('svn'):
                grassRevisionStr = ' (%s)' % grassRevision
            else:
                grassRevisionStr = ''
        except ValueError:
            grassVersion = versionLine
            grassRevisionStr = ''

        self.select_box = wx.StaticBox(parent=self.panel,
                                       id=wx.ID_ANY,
                                       label=" %s " %
                                       _("Choose project location and mapset"))

        self.manage_box = wx.StaticBox(parent=self.panel,
                                       id=wx.ID_ANY,
                                       label=" %s " % _("Manage"))
        self.lwelcome = wx.StaticText(
            parent=self.panel,
            id=wx.ID_ANY,
            label=_("Welcome to GRASS GIS %s%s\n"
                    "The world's leading open source GIS") %
            (grassVersion, grassRevisionStr),
            style=wx.ALIGN_CENTRE)
        self.ltitle = wx.StaticText(
            parent=self.panel,
            id=wx.ID_ANY,
            label=_("Select an existing project location and mapset\n"
                    "or define a new location"),
            style=wx.ALIGN_CENTRE)
        self.ldbase = wx.StaticText(parent=self.panel,
                                    id=wx.ID_ANY,
                                    label=_("GIS Data Directory:"))
        # no message at the beginning
        self.lmessage = wx.StaticText(parent=self.panel,
                                      id=wx.ID_ANY,
                                      label=_(""))
        # It is not clear if all wx versions supports color, so try-except.
        # The color itself may not be correct for all platforms/system settings
        # but in http://xoomer.virgilio.it/infinity77/wxPython/Widgets/wx.SystemSettings.html
        # there is no 'warning' color.
        try:
            self.lmessage.SetForegroundColour(wx.Colour(255, 0, 0))
        except AttributeError:
            pass
        self.llocation = wx.StaticText(
            parent=self.panel,
            id=wx.ID_ANY,
            label=_("Project location\n(projection/coordinate system)"),
            style=wx.ALIGN_CENTRE)
        self.lmapset = wx.StaticText(
            parent=self.panel,
            id=wx.ID_ANY,
            label=_("Accessible mapsets\n(directories of GIS files)"),
            style=wx.ALIGN_CENTRE)
        self.lcreate = wx.StaticText(
            parent=self.panel,
            id=wx.ID_ANY,
            label=_("Create new mapset\nin selected location"),
            style=wx.ALIGN_CENTRE)
        self.ldefine = wx.StaticText(parent=self.panel,
                                     id=wx.ID_ANY,
                                     label=_("Define new location"),
                                     style=wx.ALIGN_CENTRE)
        self.lmanageloc = wx.StaticText(
            parent=self.panel,
            id=wx.ID_ANY,
            label=_("Rename/delete selected\nmapset or location"),
            style=wx.ALIGN_CENTRE)

        # buttons
        self.bstart = wx.Button(parent=self.panel,
                                id=wx.ID_ANY,
                                label=_("Start &GRASS"))
        self.bstart.SetDefault()
        self.bexit = wx.Button(parent=self.panel, id=wx.ID_EXIT)
        self.bstart.SetMinSize((180, self.bexit.GetSize()[1]))
        self.bhelp = wx.Button(parent=self.panel, id=wx.ID_HELP)
        self.bbrowse = wx.Button(parent=self.panel,
                                 id=wx.ID_ANY,
                                 label=_("&Browse"))
        self.bmapset = wx.Button(parent=self.panel,
                                 id=wx.ID_ANY,
                                 label=_("&Create mapset"))
        self.bwizard = wx.Button(parent=self.panel,
                                 id=wx.ID_ANY,
                                 label=_("&Location wizard"))
        self.bwizard.SetToolTipString(
            _("Start location wizard."
              " After location is created successfully,"
              " GRASS session is started."))
        self.manageloc = wx.Choice(parent=self.panel,
                                   id=wx.ID_ANY,
                                   choices=[
                                       _('Rename mapset'),
                                       _('Rename location'),
                                       _('Delete mapset'),
                                       _('Delete location')
                                   ])
        self.manageloc.SetSelection(0)

        # textinputs
        self.tgisdbase = wx.TextCtrl(parent=self.panel,
                                     id=wx.ID_ANY,
                                     value="",
                                     size=(300, -1),
                                     style=wx.TE_PROCESS_ENTER)

        # Locations
        self.lblocations = GListBox(parent=self.panel,
                                    id=wx.ID_ANY,
                                    size=(180, 200),
                                    choices=self.listOfLocations)

        self.lblocations.SetColumnWidth(0, 180)

        # TODO: sort; but keep PERMANENT on top of list
        # Mapsets
        self.lbmapsets = GListBox(parent=self.panel,
                                  id=wx.ID_ANY,
                                  size=(180, 200),
                                  choices=self.listOfMapsets)

        self.lbmapsets.SetColumnWidth(0, 180)

        # layout & properties
        self._set_properties()
        self._do_layout()

        # events
        self.bbrowse.Bind(wx.EVT_BUTTON, self.OnBrowse)
        self.bstart.Bind(wx.EVT_BUTTON, self.OnStart)
        self.bexit.Bind(wx.EVT_BUTTON, self.OnExit)
        self.bhelp.Bind(wx.EVT_BUTTON, self.OnHelp)
        self.bmapset.Bind(wx.EVT_BUTTON, self.OnCreateMapset)
        self.bwizard.Bind(wx.EVT_BUTTON, self.OnWizard)
        self.manageloc.Bind(wx.EVT_CHOICE, self.OnManageLoc)
        self.lblocations.Bind(wx.EVT_LIST_ITEM_SELECTED, self.OnSelectLocation)
        self.lbmapsets.Bind(wx.EVT_LIST_ITEM_SELECTED, self.OnSelectMapset)
        self.lbmapsets.Bind(wx.EVT_LIST_ITEM_ACTIVATED, self.OnStart)
        self.tgisdbase.Bind(wx.EVT_TEXT_ENTER, self.OnSetDatabase)
        self.Bind(wx.EVT_CLOSE, self.OnCloseWindow)

    def _set_properties(self):
        """Set frame properties"""
        self.SetTitle(_("Welcome to GRASS GIS"))
        self.SetIcon(
            wx.Icon(os.path.join(globalvar.ICONDIR, "grass.ico"),
                    wx.BITMAP_TYPE_ICO))

        self.lwelcome.SetForegroundColour(wx.Colour(35, 142, 35))
        self.lwelcome.SetFont(
            wx.Font(13, wx.DEFAULT, wx.NORMAL, wx.BOLD, 0, ""))

        self.bstart.SetForegroundColour(wx.Colour(35, 142, 35))
        self.bstart.SetToolTipString(_("Enter GRASS session"))
        self.bstart.Enable(False)
        self.bmapset.Enable(False)
        self.manageloc.Enable(False)

        # set database
        if not self.gisdbase:
            # sets an initial path for gisdbase if nothing in GISRC
            if os.path.isdir(os.getenv("HOME")):
                self.gisdbase = os.getenv("HOME")
            else:
                self.gisdbase = os.getcwd()
        try:
            self.tgisdbase.SetValue(self.gisdbase)
        except UnicodeDecodeError:
            wx.MessageBox(parent=self,
                          caption=_("Error"),
                          message=_("Unable to set GRASS database. "
                                    "Check your locale settings."),
                          style=wx.OK | wx.ICON_ERROR | wx.CENTRE)

        self.OnSetDatabase(None)
        location = self.GetRCValue("LOCATION_NAME")
        if location == "<UNKNOWN>":
            return
        if not os.path.isdir(os.path.join(self.gisdbase, location)):
            location = None

        # list of locations
        self.UpdateLocations(self.gisdbase)
        try:
            self.lblocations.SetSelection(self.listOfLocations.index(location),
                                          force=True)
            self.lblocations.EnsureVisible(
                self.listOfLocations.index(location))
        except ValueError:
            sys.stderr.write(
                _("ERROR: Location <%s> not found\n") %
                self.GetRCValue("LOCATION_NAME"))
            if len(self.listOfLocations) > 0:
                self.lblocations.SetSelection(0, force=True)
                self.lblocations.EnsureVisible(0)
                location = self.listOfLocations[0]
            else:
                return

        # list of mapsets
        self.UpdateMapsets(os.path.join(self.gisdbase, location))
        mapset = self.GetRCValue("MAPSET")
        if mapset:
            try:
                self.lbmapsets.SetSelection(self.listOfMapsets.index(mapset),
                                            force=True)
                self.lbmapsets.EnsureVisible(self.listOfMapsets.index(mapset))
            except ValueError:
                sys.stderr.write(_("ERROR: Mapset <%s> not found\n") % mapset)
                self.lbmapsets.SetSelection(0, force=True)
                self.lbmapsets.EnsureVisible(0)

    def _do_layout(self):
        sizer = wx.BoxSizer(wx.VERTICAL)
        dbase_sizer = wx.BoxSizer(wx.HORIZONTAL)
        location_sizer = wx.BoxSizer(wx.HORIZONTAL)
        select_boxsizer = wx.StaticBoxSizer(self.select_box, wx.VERTICAL)
        select_sizer = wx.FlexGridSizer(rows=2, cols=2, vgap=4, hgap=4)
        select_sizer.AddGrowableRow(1)
        select_sizer.AddGrowableCol(0)
        select_sizer.AddGrowableCol(1)
        manage_sizer = wx.StaticBoxSizer(self.manage_box, wx.VERTICAL)
        btns_sizer = wx.BoxSizer(wx.HORIZONTAL)

        # gis data directory
        dbase_sizer.Add(item=self.ldbase,
                        proportion=0,
                        flag=wx.ALIGN_CENTER_VERTICAL
                        | wx.ALIGN_CENTER_HORIZONTAL | wx.ALL,
                        border=3)
        dbase_sizer.Add(item=self.tgisdbase,
                        proportion=1,
                        flag=wx.ALIGN_CENTER_VERTICAL | wx.ALL,
                        border=3)
        dbase_sizer.Add(item=self.bbrowse,
                        proportion=0,
                        flag=wx.ALIGN_CENTER_VERTICAL | wx.ALL,
                        border=3)

        # select sizer
        select_sizer.Add(item=self.llocation,
                         proportion=0,
                         flag=wx.ALIGN_CENTER_HORIZONTAL | wx.ALL,
                         border=3)
        select_sizer.Add(item=self.lmapset,
                         proportion=0,
                         flag=wx.ALIGN_CENTER_HORIZONTAL | wx.ALL,
                         border=3)
        select_sizer.Add(item=self.lblocations, proportion=1, flag=wx.EXPAND)
        select_sizer.Add(item=self.lbmapsets, proportion=1, flag=wx.EXPAND)

        select_boxsizer.Add(item=select_sizer, proportion=1, flag=wx.EXPAND)

        # define new location and mapset
        manage_sizer.Add(item=self.ldefine,
                         proportion=0,
                         flag=wx.ALIGN_CENTER_HORIZONTAL | wx.ALL,
                         border=3)
        manage_sizer.Add(item=self.bwizard,
                         proportion=0,
                         flag=wx.ALIGN_CENTER_HORIZONTAL | wx.BOTTOM,
                         border=5)
        manage_sizer.Add(item=self.lcreate,
                         proportion=0,
                         flag=wx.ALIGN_CENTER_HORIZONTAL | wx.ALL,
                         border=3)
        manage_sizer.Add(item=self.bmapset,
                         proportion=0,
                         flag=wx.ALIGN_CENTER_HORIZONTAL | wx.BOTTOM,
                         border=5)
        manage_sizer.Add(item=self.lmanageloc,
                         proportion=0,
                         flag=wx.ALIGN_CENTER_HORIZONTAL | wx.ALL,
                         border=3)
        manage_sizer.Add(item=self.manageloc,
                         proportion=0,
                         flag=wx.ALIGN_CENTER_HORIZONTAL | wx.BOTTOM,
                         border=5)

        # location sizer
        location_sizer.Add(item=select_boxsizer,
                           proportion=1,
                           flag=wx.LEFT | wx.RIGHT | wx.EXPAND,
                           border=3)
        location_sizer.Add(item=manage_sizer,
                           proportion=0,
                           flag=wx.RIGHT | wx.EXPAND,
                           border=3)

        # buttons
        btns_sizer.Add(item=self.bstart,
                       proportion=0,
                       flag=wx.ALIGN_CENTER_HORIZONTAL
                       | wx.ALIGN_CENTER_VERTICAL | wx.ALL,
                       border=5)
        btns_sizer.Add(item=self.bexit,
                       proportion=0,
                       flag=wx.ALIGN_CENTER_HORIZONTAL
                       | wx.ALIGN_CENTER_VERTICAL | wx.ALL,
                       border=5)
        btns_sizer.Add(item=self.bhelp,
                       proportion=0,
                       flag=wx.ALIGN_CENTER_HORIZONTAL
                       | wx.ALIGN_CENTER_VERTICAL | wx.ALL,
                       border=5)

        # main sizer
        sizer.Add(item=self.hbitmap,
                  proportion=0,
                  flag=wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_CENTER_HORIZONTAL
                  | wx.ALL,
                  border=3)  # image
        sizer.Add(
            item=self.lwelcome,  # welcome message
            proportion=0,
            flag=wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_CENTER_HORIZONTAL
            | wx.BOTTOM,
            border=5)
        sizer.Add(
            item=self.ltitle,  # title
            proportion=0,
            flag=wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_CENTER_HORIZONTAL)
        sizer.Add(item=dbase_sizer,
                  proportion=0,
                  flag=wx.ALIGN_CENTER_HORIZONTAL | wx.RIGHT | wx.LEFT
                  | wx.EXPAND,
                  border=20)  # GISDBASE setting
        # warning/error message
        sizer.Add(item=self.lmessage,
                  proportion=0,
                  flag=wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_LEFT | wx.LEFT
                  | wx.RIGHT | wx.BOTTOM,
                  border=8)
        sizer.Add(item=location_sizer,
                  proportion=1,
                  flag=wx.RIGHT | wx.LEFT | wx.EXPAND,
                  border=1)
        sizer.Add(item=btns_sizer,
                  proportion=0,
                  flag=wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_CENTER_HORIZONTAL
                  | wx.RIGHT | wx.LEFT,
                  border=1)

        self.panel.SetAutoLayout(True)
        self.panel.SetSizer(sizer)
        sizer.Fit(self.panel)
        sizer.SetSizeHints(self)

        self.Layout()

    def _readGisRC(self):
        """Read variables from $HOME/.grass7/rc file
        """
        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 _showWarning(self, text):
        """Displays a warning message to the user.

        There is no cleaning procedure. You should call _hideMessage when
        you know that there is everything correct now.
        """
        self.lmessage.SetLabel(_("Warning: ") + text)

    def _showError(self, text):
        """Displays a error message to the user.

        There is no cleaning procedure. You should call _hideMessage when
        you know that there is everything correct now.
        """
        self.lmessage.SetLabel(_("Error: ") + text)

    def _hideMessage(self):
        """Clears/hides the error message."""
        # we do no hide widget
        # because we do not want the dialog to change the size
        self.lmessage.SetLabel("")

    def GetRCValue(self, value):
        """Return GRASS variable (read from GISRC)
        """
        if self.grassrc.has_key(value):
            return self.grassrc[value]
        else:
            return None

    def OnWizard(self, event):
        """Location wizard started"""
        from location_wizard.wizard import LocationWizard
        gWizard = LocationWizard(parent=self,
                                 grassdatabase=self.tgisdbase.GetValue())
        if gWizard.location != None:
            self.tgisdbase.SetValue(gWizard.grassdatabase)
            self.OnSetDatabase(None)
            self.UpdateMapsets(os.path.join(self.gisdbase, gWizard.location))
            self.lblocations.SetSelection(
                self.listOfLocations.index(gWizard.location))
            self.lbmapsets.SetSelection(0)
            self.SetLocation(self.gisdbase, gWizard.location, 'PERMANENT')
            if gWizard.georeffile:
                message = _(
                    "Do you want to import <%(name)s> to the newly created location? "
                    "The location's default region will be set from this imported "
                    "map.") % {
                        'name': gWizard.georeffile
                    }
                dlg = wx.MessageDialog(parent=self,
                                       message=message,
                                       caption=_("Import data?"),
                                       style=wx.YES_NO | wx.YES_DEFAULT
                                       | wx.ICON_QUESTION)
                dlg.CenterOnScreen()
                if dlg.ShowModal() == wx.ID_YES:
                    self.ImportFile(gWizard.georeffile)
                else:
                    self.SetDefaultRegion(location=gWizard.location)
                dlg.Destroy()
            else:
                self.SetDefaultRegion(location=gWizard.location)

            dlg = TextEntryDialog(
                parent=self,
                message=_("Do you want to create new mapset?"),
                caption=_("Create new mapset"),
                defaultValue=self._getDefaultMapsetName(),
                validator=GenericValidator(grass.legal_name,
                                           self._nameValidationFailed),
                style=wx.OK | wx.CANCEL | wx.HELP)
            help = dlg.FindWindowById(wx.ID_HELP)
            help.Bind(wx.EVT_BUTTON, self.OnHelp)
            if dlg.ShowModal() == wx.ID_OK:
                mapsetName = dlg.GetValue()
                self.CreateNewMapset(mapsetName)

    def SetDefaultRegion(self, location):
        """Asks to set default region."""
        caption = _("Location <%s> created") % location
        message = _("Do you want to set the default "
                    "region extents and resolution now?")
        dlg = wx.MessageDialog(
            parent=self,
            message="%(caption)s.\n\n%(extent)s" % ({
                'caption': caption,
                'extent': message
            }),
            caption=caption,
            style=wx.YES_NO | wx.NO_DEFAULT | wx.ICON_QUESTION)
        dlg.CenterOnScreen()
        if dlg.ShowModal() == wx.ID_YES:
            dlg.Destroy()
            defineRegion = RegionDef(self, location=location)
            defineRegion.CenterOnScreen()
            defineRegion.ShowModal()
            defineRegion.Destroy()
        else:
            dlg.Destroy()

    def ImportFile(self, 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', dsn=filePath, flags='l', read=True)

        wx.BeginBusyCursor()
        wx.Yield()
        if mapName in vectors:
            # vector detected
            returncode, error = RunCommand('v.in.ogr',
                                           dsn=filePath,
                                           output=mapName,
                                           getErrorMsg=True)
        else:
            returncode, error = RunCommand('r.in.gdal',
                                           input=filePath,
                                           output=mapName,
                                           getErrorMsg=True)
        wx.EndBusyCursor()

        if returncode != 0:
            GError(parent=self,
                   message=_("Import of <%(name)s> failed.\n"
                             "Reason: %(msg)s") % ({
                                 'name': filePath,
                                 'msg': error
                             }))
        else:
            GMessage(message=_("Data file <%(name)s> imported successfully.") %
                     {'name': filePath},
                     parent=self)
            if not grass.find_file(element = 'cell', name = mapName)['fullname'] and \
                    not grass.find_file(element = 'vector', name = mapName)['fullname']:
                GError(parent=self, message=_("Map <%s> not found.") % mapName)
            else:
                if mapName in vectors:
                    args = {'vect': mapName}
                else:
                    args = {'rast': mapName}
                RunCommand('g.region', flags='s', parent=self, **args)

    def OnManageLoc(self, event):
        """Location management choice control handler
        """
        sel = event.GetSelection()
        if sel == 0:
            self.RenameMapset()
        elif sel == 1:
            self.RenameLocation()
        elif sel == 2:
            self.DeleteMapset()
        elif sel == 3:
            self.DeleteLocation()

        event.Skip()

    def RenameMapset(self):
        """Rename selected mapset
        """
        location = self.listOfLocations[self.lblocations.GetSelection()]
        mapset = self.listOfMapsets[self.lbmapsets.GetSelection()]
        if mapset == 'PERMANENT':
            GMessage(
                parent=self,
                message=_(
                    'Mapset <PERMANENT> is required for valid GRASS location.\n\n'
                    'This mapset cannot be renamed.'))
            return

        dlg = TextEntryDialog(
            parent=self,
            message=_('Current name: %s\n\nEnter new name:') % mapset,
            caption=_('Rename selected mapset'),
            validator=GenericValidator(grass.legal_name,
                                       self._nameValidationFailed))

        if dlg.ShowModal() == wx.ID_OK:
            newmapset = dlg.GetValue()
            if newmapset == mapset:
                dlg.Destroy()
                return

            if newmapset in self.listOfMapsets:
                wx.MessageBox(
                    parent=self,
                    caption=_('Message'),
                    message=_('Unable to rename mapset.\n\n'
                              'Mapset <%s> already exists in location.') %
                    newmapset,
                    style=wx.OK | wx.ICON_INFORMATION | wx.CENTRE)
            else:
                try:
                    os.rename(os.path.join(self.gisdbase, location, mapset),
                              os.path.join(self.gisdbase, location, newmapset))
                    self.OnSelectLocation(None)
                    self.lbmapsets.SetSelection(
                        self.listOfMapsets.index(newmapset))
                except StandardError as e:
                    wx.MessageBox(parent=self,
                                  caption=_('Error'),
                                  message=_('Unable to rename mapset.\n\n%s') %
                                  e,
                                  style=wx.OK | wx.ICON_ERROR | wx.CENTRE)

        dlg.Destroy()

    def RenameLocation(self):
        """Rename selected location
        """
        location = self.listOfLocations[self.lblocations.GetSelection()]

        dlg = TextEntryDialog(
            parent=self,
            message=_('Current name: %s\n\nEnter new name:') % location,
            caption=_('Rename selected location'),
            validator=GenericValidator(grass.legal_name,
                                       self._nameValidationFailed))

        if dlg.ShowModal() == wx.ID_OK:
            newlocation = dlg.GetValue()
            if newlocation == location:
                dlg.Destroy()
                return

            if newlocation in self.listOfLocations:
                wx.MessageBox(
                    parent=self,
                    caption=_('Message'),
                    message=_(
                        'Unable to rename location.\n\n'
                        'Location <%s> already exists in GRASS database.') %
                    newlocation,
                    style=wx.OK | wx.ICON_INFORMATION | wx.CENTRE)
            else:
                try:
                    os.rename(os.path.join(self.gisdbase, location),
                              os.path.join(self.gisdbase, newlocation))
                    self.UpdateLocations(self.gisdbase)
                    self.lblocations.SetSelection(
                        self.listOfLocations.index(newlocation))
                    self.UpdateMapsets(newlocation)
                except StandardError as e:
                    wx.MessageBox(
                        parent=self,
                        caption=_('Error'),
                        message=_('Unable to rename location.\n\n%s') % e,
                        style=wx.OK | wx.ICON_ERROR | wx.CENTRE)

        dlg.Destroy()

    def DeleteMapset(self):
        """Delete selected mapset
        """
        location = self.listOfLocations[self.lblocations.GetSelection()]
        mapset = self.listOfMapsets[self.lbmapsets.GetSelection()]
        if mapset == 'PERMANENT':
            GMessage(
                parent=self,
                message=_(
                    'Mapset <PERMANENT> is required for valid GRASS location.\n\n'
                    'This mapset cannot be deleted.'))
            return

        dlg = wx.MessageDialog(
            parent=self,
            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:
                shutil.rmtree(os.path.join(self.gisdbase, location, mapset))
                self.OnSelectLocation(None)
                self.lbmapsets.SetSelection(0)
            except:
                wx.MessageBox(message=_('Unable to delete mapset'))

        dlg.Destroy()

    def DeleteLocation(self):
        """
        Delete selected location
        """

        location = self.listOfLocations[self.lblocations.GetSelection()]

        dlg = wx.MessageDialog(
            parent=self,
            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:
                shutil.rmtree(os.path.join(self.gisdbase, location))
                self.UpdateLocations(self.gisdbase)
                self.lblocations.SetSelection(0)
                self.OnSelectLocation(None)
                self.lbmapsets.SetSelection(0)
            except:
                wx.MessageBox(message=_('Unable to delete location'))

        dlg.Destroy()

    def UpdateLocations(self, dbase):
        """Update list of locations"""
        try:
            self.listOfLocations = GetListOfLocations(dbase)
        except UnicodeEncodeError:
            GError(parent=self,
                   message=_("Unable to set GRASS database. "
                             "Check your locale settings."))

        self.lblocations.Clear()
        self.lblocations.InsertItems(self.listOfLocations, 0)

        if len(self.listOfLocations) > 0:
            self._hideMessage()
            self.lblocations.SetSelection(0)
        else:
            self.lblocations.SetSelection(wx.NOT_FOUND)
            self._showWarning(
                _("No GRASS location found in '%s'.") % self.gisdbase)

        return self.listOfLocations

    def UpdateMapsets(self, location):
        """Update list of mapsets"""
        self.FormerMapsetSelection = wx.NOT_FOUND  # for non-selectable item

        self.listOfMapsetsSelectable = list()
        self.listOfMapsets = GetListOfMapsets(self.gisdbase, location)

        self.lbmapsets.Clear()

        # disable mapset with denied permission
        locationName = os.path.basename(location)

        ret = RunCommand('g.mapset',
                         read=True,
                         flags='l',
                         location=locationName,
                         gisdbase=self.gisdbase)

        if ret:
            for line in ret.splitlines():
                self.listOfMapsetsSelectable += line.split(' ')
        else:
            RunCommand("g.gisenv", set="GISDBASE=%s" % self.gisdbase)
            RunCommand("g.gisenv", set="LOCATION_NAME=%s" % locationName)
            RunCommand("g.gisenv", set="MAPSET=PERMANENT")
            # first run only
            self.listOfMapsetsSelectable = copy.copy(self.listOfMapsets)

        disabled = []
        idx = 0
        for mapset in self.listOfMapsets:
            if mapset not in self.listOfMapsetsSelectable or \
                    os.path.isfile(os.path.join(self.gisdbase,
                                                locationName,
                                                mapset, ".gislock")):
                disabled.append(idx)
            idx += 1

        self.lbmapsets.InsertItems(self.listOfMapsets, 0, disabled=disabled)

        return self.listOfMapsets

    def OnSelectLocation(self, event):
        """Location selected"""
        if event:
            self.lblocations.SetSelection(event.GetIndex())

        if self.lblocations.GetSelection() != wx.NOT_FOUND:
            self.UpdateMapsets(
                os.path.join(
                    self.gisdbase,
                    self.listOfLocations[self.lblocations.GetSelection()]))
        else:
            self.listOfMapsets = []

        disabled = []
        idx = 0
        try:
            locationName = self.listOfLocations[
                self.lblocations.GetSelection()]
        except IndexError:
            locationName = ''

        for mapset in self.listOfMapsets:
            if mapset not in self.listOfMapsetsSelectable or \
                    os.path.isfile(os.path.join(self.gisdbase,
                                                locationName,
                                                mapset, ".gislock")):
                disabled.append(idx)
            idx += 1

        self.lbmapsets.Clear()
        self.lbmapsets.InsertItems(self.listOfMapsets, 0, disabled=disabled)

        if len(self.listOfMapsets) > 0:
            self.lbmapsets.SetSelection(0)
            if locationName:
                # enable start button when location and mapset is selected
                self.bstart.Enable()
                self.bmapset.Enable()
                self.manageloc.Enable()
        else:
            self.lbmapsets.SetSelection(wx.NOT_FOUND)
            self.bstart.Enable(False)
            self.bmapset.Enable(False)
            self.manageloc.Enable(False)

    def OnSelectMapset(self, event):
        """Mapset selected"""
        self.lbmapsets.SetSelection(event.GetIndex())

        if event.GetText() not in self.listOfMapsetsSelectable:
            self.lbmapsets.SetSelection(self.FormerMapsetSelection)
        else:
            self.FormerMapsetSelection = event.GetIndex()
            event.Skip()

    def OnSetDatabase(self, event):
        """Database set"""
        gisdbase = self.tgisdbase.GetValue()
        self._hideMessage()
        if not os.path.exists(gisdbase):
            self._showError(_("Path '%s' doesn't exist.") % gisdbase)
            return

        self.gisdbase = self.tgisdbase.GetValue()
        self.UpdateLocations(self.gisdbase)

        self.OnSelectLocation(None)

    def OnBrowse(self, event):
        """'Browse' button clicked"""
        if not event:
            defaultPath = os.getenv('HOME')
        else:
            defaultPath = ""

        dlg = wx.DirDialog(parent=self,
                           message=_("Choose GIS Data Directory"),
                           defaultPath=defaultPath,
                           style=wx.DD_DEFAULT_STYLE)

        if dlg.ShowModal() == wx.ID_OK:
            self.gisdbase = dlg.GetPath()
            self.tgisdbase.SetValue(self.gisdbase)
            self.OnSetDatabase(event)

        dlg.Destroy()

    def OnCreateMapset(self, event):
        """Create new mapset"""
        dlg = TextEntryDialog(parent=self,
                              message=_('Enter name for new mapset:'),
                              caption=_('Create new mapset'),
                              defaultValue=self._getDefaultMapsetName(),
                              validator=GenericValidator(
                                  grass.legal_name,
                                  self._nameValidationFailed))
        if dlg.ShowModal() == wx.ID_OK:
            mapset = dlg.GetValue()
            return self.CreateNewMapset(mapset=mapset)
        else:
            return False

    def CreateNewMapset(self, mapset):
        if mapset in self.listOfMapsets:
            GMessage(parent=self,
                     message=_("Mapset <%s> already exists.") % mapset)
            return False

        if mapset.lower() == 'ogr':
            dlg1 = wx.MessageDialog(
                parent=self,
                message=_(
                    "Mapset <%s> is reserved for direct "
                    "read access to OGR layers. Please consider to use "
                    "another name for your mapset.\n\n"
                    "Are you really sure that you want to create this mapset?")
                % mapset,
                caption=_("Reserved mapset name"),
                style=wx.YES_NO | wx.NO_DEFAULT | wx.ICON_QUESTION)
            ret = dlg1.ShowModal()
            dlg1.Destroy()
            if ret == wx.ID_NO:
                dlg.Destroy()
                return False

        try:
            self.gisdbase = self.tgisdbase.GetValue()
            location = self.listOfLocations[self.lblocations.GetSelection()]
            os.mkdir(os.path.join(self.gisdbase, location, mapset))
            # copy WIND file and its permissions from PERMANENT and set permissions to u+rw,go+r
            shutil.copy(
                os.path.join(self.gisdbase, location, 'PERMANENT', 'WIND'),
                os.path.join(self.gisdbase, location, mapset))
            # os.chmod(os.path.join(database,location,mapset,'WIND'), 0644)
            self.OnSelectLocation(None)
            self.lbmapsets.SetSelection(self.listOfMapsets.index(mapset))
            self.bstart.SetFocus()
            return True
        except StandardError as e:
            GError(parent=self,
                   message=_("Unable to create new mapset: %s") % e,
                   showTraceback=False)
            return False

    def OnStart(self, event):
        """'Start GRASS' button clicked"""
        dbase = self.tgisdbase.GetValue()
        location = self.listOfLocations[self.lblocations.GetSelection()]
        mapset = self.listOfMapsets[self.lbmapsets.GetSelection()]

        lockfile = os.path.join(dbase, location, mapset, '.gislock')
        if os.path.isfile(lockfile):
            dlg = wx.MessageDialog(
                parent=self,
                message=_(
                    "GRASS is already running in selected mapset <%(mapset)s>\n"
                    "(file %(lock)s found).\n\n"
                    "Concurrent use not allowed.\n\n"
                    "Do you want to try to remove .gislock (note that you "
                    "need permission for this operation) and continue?") % {
                        'mapset': mapset,
                        'lock': lockfile
                    },
                caption=_("Lock file found"),
                style=wx.YES_NO | wx.NO_DEFAULT | wx.ICON_QUESTION | wx.CENTRE)

            ret = dlg.ShowModal()
            dlg.Destroy()
            if ret == wx.ID_YES:
                dlg1 = wx.MessageDialog(
                    parent=self,
                    message=
                    _("ARE YOU REALLY SURE?\n\n"
                      "If you really are running another GRASS session doing this "
                      "could corrupt your data. Have another look in the processor "
                      "manager just to be sure..."),
                    caption=_("Lock file found"),
                    style=wx.YES_NO | wx.NO_DEFAULT | wx.ICON_QUESTION
                    | wx.CENTRE)

                ret = dlg1.ShowModal()
                dlg1.Destroy()

                if ret == wx.ID_YES:
                    try:
                        os.remove(lockfile)
                    except IOError as e:
                        GError(
                            _("Unable to remove '%(lock)s'.\n\n"
                              "Details: %(reason)s") % {
                                  'lock': lockfile,
                                  'reason': e
                              })
                else:
                    return
            else:
                return
        self.SetLocation(dbase, location, mapset)
        self.ExitSuccessfully()

    def SetLocation(self, dbase, location, mapset):
        RunCommand("g.gisenv", set="GISDBASE=%s" % dbase)
        RunCommand("g.gisenv", set="LOCATION_NAME=%s" % location)
        RunCommand("g.gisenv", set="MAPSET=%s" % mapset)

    def _getDefaultMapsetName(self):
        """Returns default name for mapset."""
        try:
            defaultName = getpass.getuser()
            defaultName.encode(
                'ascii')  # raise error if not ascii (not valid mapset name)
        except:  # whatever might go wrong
            defaultName = 'user'

        return defaultName

    def ExitSuccessfully(self):
        self.Destroy()
        sys.exit(0)

    def OnExit(self, event):
        """'Exit' button clicked"""
        self.Destroy()
        sys.exit(2)

    def OnHelp(self, event):
        """'Help' button clicked"""

        # help text in lib/init/helptext.html
        RunCommand('g.manual', entry='helptext')

    def OnCloseWindow(self, event):
        """Close window event"""
        event.Skip()
        sys.exit(2)

    def _nameValidationFailed(self, ctrl):
        message = _(
            "Name <%(name)s> is not a valid name for location or mapset. "
            "Please use only ASCII characters excluding %(chars)s "
            "and space.") % {
                'name': ctrl.GetValue(),
                'chars': '/"\'@,=*~'
            }
        GError(parent=self, message=message, caption=_("Invalid name"))