diff --git a/gui/wxpython/history/browser.py b/gui/wxpython/history/browser.py index 9589cee3f0d..4c6f471511d 100644 --- a/gui/wxpython/history/browser.py +++ b/gui/wxpython/history/browser.py @@ -28,6 +28,7 @@ from icons.icon import MetaIcon import grass.script as gs +from grass.tools import Tools from grass.grassdb import history @@ -51,6 +52,14 @@ "rows": _("Number of rows:"), "cols": _("Number of columns:"), "cells": _("Number of cells:"), + "t": _("Top:"), + "b": _("Bottom:"), + "tbres": _("Top-bottom resolution:"), + "nsres3": _("3D north-south resolution:"), + "ewres3": _("3D east-west resolution:"), + "rows3": _("Number of 3D rows:"), + "cols3": _("Number of 3D cols:"), + "depths": _("Number of depths:"), } @@ -80,6 +89,7 @@ def __init__(self, parent, giface, title=("Command Info"), style=wx.TAB_TRAVERSA self.title = title self.region_settings = None + self.tools = Tools() self._initImages() @@ -141,6 +151,14 @@ def _createRegionSettingsBox(self): self.region_settings_box, wx.VERTICAL ) + self.sizer_region_name = wx.BoxSizer(wx.HORIZONTAL) + self.sizer_region_settings.Add( + self.sizer_region_name, + proportion=0, + flag=wx.ALL | wx.EXPAND, + border=5, + ) + self.sizer_region_settings_match = wx.BoxSizer(wx.HORIZONTAL) self.sizer_region_settings.Add( self.sizer_region_settings_match, @@ -167,9 +185,6 @@ def _general_info_filter(self, key, value): filter_keys = ["timestamp", "runtime", "status"] return key in filter_keys or ((key in {"mask2d", "mask3d"}) and value is True) - def _region_settings_filter(self, key): - return key not in {"projection", "zone", "cells"} - def _updateGeneralInfoBox(self, command_info): """Update a static box for displaying general info about the command. @@ -216,9 +231,30 @@ def _updateRegionSettingsGrid(self, command_info): self.sizer_region_settings_grid.Clear(True) self.region_settings = command_info["region"] + + Display_Order = [ + "n", + "s", + "e", + "w", + "nsres", + "ewres", + "rows", + "cols", + "t", + "b", + "tbres", + "nsres3", + "ewres3", + "rows3", + "cols3", + "depths", + ] + idx = 0 - for key, value in self.region_settings.items(): - if self._region_settings_filter(key): + for key in Display_Order: + if key in self.region_settings: + value = self.region_settings[key] self.sizer_region_settings_grid.Add( StaticText( parent=self.region_settings_box, @@ -245,14 +281,61 @@ def _updateRegionSettingsGrid(self, command_info): self.region_settings_box.Show() + def _get_saved_region_name(self, history_region): + """Find if history region matches any saved region in the entire project.""" + try: + res = self.tools.g_list(type="region", mapset="*", format="json") + region_names = [r["name"] for r in res] + except (KeyError, TypeError): + return None + + for region_name in region_names: + region_name = region_name.strip() + if region_name: + try: + saved_region = self.tools.g_region( + region=region_name, flags="u3", format="shell" + ).keyval + + if self._compare_regions(history_region, saved_region): + return region_name + except AttributeError: + continue + + return None + + def _compare_regions(self, r1, r2): + """Compare two region dictionaries for equality.""" + for k, v in r1.items(): + try: + if abs(float(v) - float(r2[k])) > 1e-8: + return False + except (KeyError, ValueError, TypeError): + return False + return True + def _updateRegionSettingsMatch(self): """Update text, icon and button dealing with region update""" + self.sizer_region_name.Clear(True) self.sizer_region_settings_match.Clear(True) # Region condition history_region = self.region_settings current_region = self._get_current_region() - region_matches = history_region == current_region + region_matches = self._compare_regions(history_region, current_region) + saved_name = self._get_saved_region_name(history_region) + + if saved_name: + self.sizer_region_name.Add( + StaticText( + parent=self.region_settings_box, + id=wx.ID_ANY, + label=_("Region name: {}").format(saved_name), + ), + proportion=0, + flag=wx.ALIGN_CENTER_VERTICAL | wx.RIGHT, + border=10, + ) # Icon and button according to the condition if region_matches: @@ -322,14 +405,28 @@ def hideCommandInfo(self): def _get_current_region(self): """Get current computational region settings.""" - return gs.region() + return gs.region(region3d=True) def _get_history_region(self): """Get computational region settings of executed command.""" + valid_keys = { + "n", + "s", + "e", + "w", + "nsres", + "ewres", + "t", + "b", + "tbres", + "nsres3", + "ewres3", + } + return { key: value for key, value in self.region_settings.items() - if self._region_settings_filter(key) + if key in valid_keys } def OnUpdateRegion(self, event): diff --git a/python/grass/grassdb/history.py b/python/grass/grassdb/history.py index 7d125196524..7e637335a5d 100644 --- a/python/grass/grassdb/history.py +++ b/python/grass/grassdb/history.py @@ -266,7 +266,7 @@ def get_initial_command_info(env_run): mask3d_name = f"RASTER3D_MASK@{env['MAPSET']}" # Computational region settings - region_settings = gs.region(env=env_run) + region_settings = gs.region(region3d=True, env=env_run) # Finalize the command info dictionary return {