Jelajahi Sumber

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

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

@@ -258,8 +258,8 @@ def create_location_interactively(guiparent, grassdb):
 
 
     if gWizard.user_mapset:
     if gWizard.user_mapset:
         mapset = create_mapset_interactively(guiparent,
         mapset = create_mapset_interactively(guiparent,
-                                                  gWizard.grassdatabase,
-                                                  gWizard.location)
+                                             gWizard.grassdatabase,
+                                             gWizard.location)
         # Returns database and location created by user
         # Returns database and location created by user
         # and a mapset user may want to switch to
         # and a mapset user may want to switch to
         gWizard_output = (gWizard.grassdatabase, gWizard.location,
         gWizard_output = (gWizard.grassdatabase, gWizard.location,
@@ -272,71 +272,132 @@ def create_location_interactively(guiparent, grassdb):
 
 
 
 
 def rename_mapset_interactively(guiparent, grassdb, location, mapset):
 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
     newmapset = None
+    issue = None
+
+    # Check for permanent mapsets
     if mapset == "PERMANENT":
     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,
             parent=guiparent,
             message=_(
             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()
     dlg.Destroy()
     return newmapset
     return newmapset
 
 
 
 
 def rename_location_interactively(guiparent, grassdb, location):
 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:
     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()
     dlg.Destroy()
     return newlocation
     return newlocation
 
 
@@ -383,7 +444,7 @@ def delete_mapsets_interactively(guiparent, mapsets):
 
 
     Exceptions during deletation are handled in this function.
     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
     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
     deleted (see above the possible reasons) or if an error was encountered when
     deleting the first mapset in the list.
     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}>:"
                         "The following error occured when deleting mapset <{path}>:"
                         "\n\n{error}\n\n"
                         "\n\n{error}\n\n"
                         "Deleting of mapsets was interrupted."
                         "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,
                     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):
 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()
     dlg.Destroy()
-    return False
+    return modified
 
 
 
 
 def import_file(guiparent, filePath):
 def import_file(guiparent, filePath):