瀏覽代碼

wxGUI: An action should be required before modifying other mapsets (#848)

* wxGUI/datacatalog: The function isCurrent was a bit changed. Popup functions adjusted to 'Allow renaming and deleting other mapsets or locations only when the allow editing mode is on.

* wxGUI/datacatalog: If clauses qualified according to self._restricted variable.

* wxGUI/datacatalog: The rename and delete interactive functions improved to be able to handle conditions: current mapset and location cannot be renamed or deleted even if the self._restricted mode is False.

* wxGUI/datacatalog: Flake8 and message title corrected.

* wxGUI/datacatalog: Deletion of location corrected.
Linda Kladivova 4 年之前
父節點
當前提交
94f7353647
共有 2 個文件被更改,包括 196 次插入108 次删除
  1. 10 26
      gui/wxpython/datacatalog/tree.py
  2. 186 82
      gui/wxpython/startup/guiutils.py

+ 10 - 26
gui/wxpython/datacatalog/tree.py

@@ -276,7 +276,6 @@ class DataCatalogTree(TreeView):
         self.startEdit.connect(self.OnStartEditLabel)
         self.endEdit.connect(self.OnEditLabel)
 
-
     def _reloadMapsetNode(self, mapset_node):
         """Recursively reload the model of a specific mapset node"""
         if mapset_node.children:
@@ -384,7 +383,7 @@ class DataCatalogTree(TreeView):
                 proc_list = []
                 queue_list = []
                 loc_list = []
-                location_nodes = []    
+                location_nodes = []
 
         for node in all_location_nodes:
             self._model.SortChildren(node)
@@ -408,7 +407,7 @@ class DataCatalogTree(TreeView):
             error = self._reloadGrassDBNode(grassdb_node)
             if error:
                 errors.append(error)
-            
+
         if errors:
             wx.CallAfter(GWarning, '\n'.join(errors))
         Debug.msg(1, "Tree filled")
@@ -1193,18 +1192,17 @@ class DataCatalogTree(TreeView):
                     currentLocation = False
                     currentMapset = False
                     break
-            if currentLocation:
+            if currentLocation and self.selected_location[0]:
                 for i in range(len(self.selected_location)):
                     if self.selected_location[i].data['name'] != genv['LOCATION_NAME']:
                         currentLocation = False
                         currentMapset = False
                         break
-            if currentMapset:
+            if currentMapset and self.selected_mapset[0]:
                 for i in range(len(self.selected_mapset)):
                     if self.selected_mapset[i].data['name'] != genv['MAPSET']:
                         currentMapset = False
                         break
-
             return currentGrassDb, currentLocation, currentMapset
         else:
             return True, True, True
@@ -1288,21 +1286,13 @@ class DataCatalogTree(TreeView):
         item = wx.MenuItem(menu, wx.ID_ANY, _("&Delete mapset"))
         menu.AppendItem(item)
         self.Bind(wx.EVT_MENU, self.OnDeleteMapset, item)
-        if (
-            self.selected_grassdb[0].data['name'] == genv['GISDBASE']
-            and self.selected_location[0].data['name'] == genv['LOCATION_NAME']
-            and self.selected_mapset[0].data['name'] == genv['MAPSET']
-        ):
+        if self._restricted:
             item.Enable(False)
 
         item = wx.MenuItem(menu, wx.ID_ANY, _("&Rename mapset"))
         menu.AppendItem(item)
         self.Bind(wx.EVT_MENU, self.OnRenameMapset, item)
-        if (
-            self.selected_grassdb[0].data['name'] == genv['GISDBASE']
-            and self.selected_location[0].data['name'] == genv['LOCATION_NAME']
-            and self.selected_mapset[0].data['name'] == genv['MAPSET']
-        ):
+        if self._restricted:
             item.Enable(False)
 
         self.PopupMenu(menu)
@@ -1311,7 +1301,6 @@ class DataCatalogTree(TreeView):
     def _popupMenuLocation(self):
         """Create popup menu for locations"""
         menu = Menu()
-        genv = gisenv()
 
         item = wx.MenuItem(menu, wx.ID_ANY, _("&Create mapset"))
         menu.AppendItem(item)
@@ -1320,19 +1309,13 @@ class DataCatalogTree(TreeView):
         item = wx.MenuItem(menu, wx.ID_ANY, _("&Delete location"))
         menu.AppendItem(item)
         self.Bind(wx.EVT_MENU, self.OnDeleteLocation, item)
-        if (
-            self.selected_grassdb[0].data['name'] == genv['GISDBASE']
-            and self.selected_location[0].data['name'] == genv['LOCATION_NAME']
-        ):
+        if self._restricted:
             item.Enable(False)
 
         item = wx.MenuItem(menu, wx.ID_ANY, _("&Rename location"))
         menu.AppendItem(item)
         self.Bind(wx.EVT_MENU, self.OnRenameLocation, item)
-        if (
-            self.selected_grassdb[0].data['name'] == genv['GISDBASE']
-            and self.selected_location[0].data['name'] == genv['LOCATION_NAME']
-        ):
+        if self._restricted:
             item.Enable(False)
 
         self.PopupMenu(menu)
@@ -1370,10 +1353,11 @@ class DataCatalogTree(TreeView):
     def _popupMenuMultipleMapsets(self):
         """Create popup menu for multiple selected mapsets"""
         menu = Menu()
-
         item = wx.MenuItem(menu, wx.ID_ANY, _("&Delete mapsets"))
         menu.AppendItem(item)
         self.Bind(wx.EVT_MENU, self.OnDeleteMapset, item)
+        if self._restricted:
+            item.Enable(False)
 
         self.PopupMenu(menu)
         menu.Destroy()

+ 186 - 82
gui/wxpython/startup/guiutils.py

@@ -258,8 +258,8 @@ def create_location_interactively(guiparent, grassdb):
 
     if gWizard.user_mapset:
         mapset = create_mapset_interactively(guiparent,
-                                                  gWizard.grassdatabase,
-                                                  gWizard.location)
+                                             gWizard.grassdatabase,
+                                             gWizard.location)
         # Returns database and location created by user
         # and a mapset user may want to switch to
         gWizard_output = (gWizard.grassdatabase, gWizard.location,
@@ -272,71 +272,132 @@ def create_location_interactively(guiparent, grassdb):
 
 
 def rename_mapset_interactively(guiparent, grassdb, location, mapset):
+    """Rename mapset with user interaction.
+
+    If PERMANENT or current mapset found, rename operation is not performed.
+
+    Exceptions during renaming are handled in this function.
+
+    Returns newmapset if there was a change or None if the mapset cannot be
+    renamed (see above the possible reasons) or if another error was encountered.
     """
-    Rename selected mapset
-    """
+    genv = gisenv()
+
+    # Check selected mapset and remember issue.
+    # Each error is reported only once (using elif).
+    mapset_path = os.path.join(grassdb, location, mapset)
     newmapset = None
+    issue = None
+
+    # Check for permanent mapsets
     if mapset == "PERMANENT":
-        GMessage(
+        issue = _("<{}> is required for a valid location.").format(mapset_path)
+    # Check for current mapset
+    elif (
+            grassdb == genv['GISDBASE'] and
+            location == genv['LOCATION_NAME'] and
+            mapset == genv['MAPSET']
+    ):
+        issue = _("<{}> is the current mapset.").format(mapset_path)
+
+    # If an issue, display the warning message and do not rename mapset
+    if issue:
+        dlg = wx.MessageDialog(
             parent=guiparent,
             message=_(
-                "Mapset <PERMANENT> is required for valid GRASS location.\n\n"
-                "This mapset cannot be renamed."
-            ),
+                "Cannot rename selected mapset for the following reason:\n\n"
+                "{}\n\n"
+                "No mapset will be renamed."
+            ).format(issue),
+            caption=_("Unable to rename selected mapset"),
+            style=wx.OK | wx.ICON_WARNING
+        )
+        dlg.ShowModal()
+    else:
+        dlg = MapsetDialog(
+            parent=guiparent,
+            default=mapset,
+            message=_("Current name: {}\n\nEnter new name:").format(mapset),
+            caption=_("Rename selected mapset"),
+            database=grassdb,
+            location=location,
         )
-        return newmapset
-
-    dlg = MapsetDialog(
-        parent=guiparent,
-        default=mapset,
-        message=_("Current name: {}\n\nEnter new name:").format(mapset),
-        caption=_("Rename selected mapset"),
-        database=grassdb,
-        location=location,
-    )
 
-    if dlg.ShowModal() == wx.ID_OK:
-        newmapset = dlg.GetValue()
-        try:
-            rename_mapset(grassdb, location, mapset, newmapset)
-        except OSError as err:
-            newmapset = None
-            wx.MessageBox(
-                parent=guiparent,
-                caption=_("Error"),
-                message=_("Unable to rename mapset.\n\n{}").format(err),
-                style=wx.OK | wx.ICON_ERROR | wx.CENTRE,
-            )
+        if dlg.ShowModal() == wx.ID_OK:
+            newmapset = dlg.GetValue()
+            try:
+                rename_mapset(grassdb, location, mapset, newmapset)
+            except OSError as err:
+                newmapset = None
+                wx.MessageBox(
+                    parent=guiparent,
+                    caption=_("Error"),
+                    message=_("Unable to rename mapset.\n\n{}").format(err),
+                    style=wx.OK | wx.ICON_ERROR | wx.CENTRE,
+                )
     dlg.Destroy()
     return newmapset
 
 
 def rename_location_interactively(guiparent, grassdb, location):
+    """Rename location with user interaction.
+
+    If current location found, rename operation is not performed.
+
+    Exceptions during renaming are handled in this function.
+
+    Returns newlocation if there was a change or None if the location cannot be
+    renamed (see above the possible reasons) or if another error was encountered.
     """
-    Rename selected location
-    """
-    dlg = LocationDialog(
-        parent=guiparent,
-        default=location,
-        message=_("Current name: {}\n\nEnter new name:").format(location),
-        caption=_("Rename selected location"),
-        database=grassdb,
-    )
+    genv = gisenv()
 
-    if dlg.ShowModal() == wx.ID_OK:
-        newlocation = dlg.GetValue()
-        try:
-            rename_location(grassdb, location, newlocation)
-        except OSError as err:
-            newlocation = None
-            wx.MessageBox(
-                parent=guiparent,
-                caption=_("Error"),
-                message=_("Unable to rename location.\n\n{}").format(err),
-                style=wx.OK | wx.ICON_ERROR | wx.CENTRE,
-            )
+    # Check selected location and remember issue.
+    # Each error is reported only once (using elif).
+    location_path = os.path.join(grassdb, location)
+    newlocation = None
+    issue = None
+
+    # Check for current location
+    if (
+            grassdb == genv['GISDBASE'] and
+            location == genv['LOCATION_NAME']
+    ):
+        issue = _("<{}> is the current location.").format(location_path)
+
+    # If an issue, display the warning message and do not rename location
+    if issue:
+        dlg = wx.MessageDialog(
+            parent=guiparent,
+            message=_(
+                "Cannot rename selected location for the following reason:\n\n"
+                "{}\n\n"
+                "No location will be renamed."
+            ).format(issue),
+            caption=_("Unable to rename selected location"),
+            style=wx.OK | wx.ICON_WARNING
+        )
+        dlg.ShowModal()
     else:
-        newlocation = None
+        dlg = LocationDialog(
+            parent=guiparent,
+            default=location,
+            message=_("Current name: {}\n\nEnter new name:").format(location),
+            caption=_("Rename selected location"),
+            database=grassdb,
+        )
+
+        if dlg.ShowModal() == wx.ID_OK:
+            newlocation = dlg.GetValue()
+            try:
+                rename_location(grassdb, location, newlocation)
+            except OSError as err:
+                newlocation = None
+                wx.MessageBox(
+                    parent=guiparent,
+                    caption=_("Error"),
+                    message=_("Unable to rename location.\n\n{}").format(err),
+                    style=wx.OK | wx.ICON_ERROR | wx.CENTRE,
+                )
     dlg.Destroy()
     return newlocation
 
@@ -383,7 +444,7 @@ def delete_mapsets_interactively(guiparent, mapsets):
 
     Exceptions during deletation are handled in this function.
 
-    Retuns True if there was a change, i.e., all mapsets were successfuly deleted
+    Returns True if there was a change, i.e., all mapsets were successfuly deleted
     or at least one mapset was deleted. Returns False if one or more mapsets cannot be
     deleted (see above the possible reasons) or if an error was encountered when
     deleting the first mapset in the list.
@@ -455,9 +516,9 @@ def delete_mapsets_interactively(guiparent, mapsets):
                         "The following error occured when deleting mapset <{path}>:"
                         "\n\n{error}\n\n"
                         "Deleting of mapsets was interrupted."
-                        ).format(
-                            path=os.path.join(grassdb, location, mapset),
-                            error=error,
+                    ).format(
+                        path=os.path.join(grassdb, location, mapset),
+                        error=error,
                     ),
                     style=wx.OK | wx.ICON_ERROR | wx.CENTRE,
                 )
@@ -466,35 +527,78 @@ def delete_mapsets_interactively(guiparent, mapsets):
 
 
 def delete_location_interactively(guiparent, grassdb, location):
+    """Delete a location with user interaction.
+
+    If current location found, delete operation is not performed.
+
+    Exceptions during deletation are handled in this function.
+
+    Returns True if there was a change, returns False if a location cannot be
+    deleted (see above the possible reasons) or if another error was encountered.
     """
-    Delete selected location
-    """
-    dlg = wx.MessageDialog(
-        parent=guiparent,
-        message=_(
-            "Do you want to continue with deleting "
-            "location {}?\n\n"
-            "ALL MAPS included in this location will be "
-            "PERMANENTLY DELETED!"
-        ).format(location),
-        caption=_("Delete selected location"),
-        style=wx.YES_NO | wx.NO_DEFAULT | wx.ICON_QUESTION,
-    )
+    genv = gisenv()
+    issue = None
 
-    if dlg.ShowModal() == wx.ID_YES:
-        try:
-            delete_location(grassdb, location)
-            dlg.Destroy()
-            return True
-        except OSError as err:
-            wx.MessageBox(
-                parent=guiparent,
-                caption=_("Error"),
-                message=_("Unable to delete location.\n\n{}").format(err),
-                style=wx.OK | wx.ICON_ERROR | wx.CENTRE,
-            )
+    # Check selected location and remember issue.
+    # Each error is reported only once (using elif).
+    location_path = os.path.join(grassdb, location)
+
+    # Check for current location
+    if (
+        grassdb == genv['GISDBASE'] and
+        location == genv['LOCATION_NAME']
+    ):
+        issue = _("<{}> is the current location.").format(location_path)
+
+    modified = False  # True after first successful delete
+
+    # If any issues, display the warning message and do not delete anything
+    if issue:
+        dlg = wx.MessageDialog(
+            parent=guiparent,
+            message=_(
+                "Cannot delete selected location for the following reasons:\n\n"
+                "{}\n\n"
+                "No location will be deleted."
+            ).format(issue),
+            caption=_("Unable to delete selected location"),
+            style=wx.OK | wx.ICON_WARNING
+        )
+        dlg.ShowModal()
+    else:
+        dlg = wx.MessageDialog(
+            parent=guiparent,
+            message=_(
+                "Do you want to continue with deleting"
+                "the following location?\n\n"
+                "{}\n\n"
+                "All mapsets included in this location will be permanently deleted!"
+            ).format(location_path),
+            caption=_("Delete selected location"),
+            style=wx.YES_NO | wx.NO_DEFAULT | wx.ICON_QUESTION,
+        )
+        if dlg.ShowModal() == wx.ID_YES:
+            try:
+                delete_location(grassdb, location)
+                modified = True
+                dlg.Destroy()
+                return modified
+            except OSError as error:
+                wx.MessageBox(
+                    parent=guiparent,
+                    caption=_("Error when deleting location"),
+                    message=_(
+                        "The following error occured when deleting location <{path}>:"
+                        "\n\n{error}\n\n"
+                        "Deleting was interrupted."
+                    ).format(
+                        path=os.path.join(grassdb, location),
+                        error=error,
+                    ),
+                    style=wx.OK | wx.ICON_ERROR | wx.CENTRE,
+                )
     dlg.Destroy()
-    return False
+    return modified
 
 
 def import_file(guiparent, filePath):