diff --git a/gui/wxpython/datacatalog/tree.py b/gui/wxpython/datacatalog/tree.py index 8dd96fb62e0..2135965f5bf 100644 --- a/gui/wxpython/datacatalog/tree.py +++ b/gui/wxpython/datacatalog/tree.py @@ -2019,6 +2019,34 @@ def done(event): # temp gisrc file must be deleted onDone self._giface.RunCmd(cmd, env=env, onDone=done, userData=gisrc) + def OnShowProjection(self, event): + """Show projection info of selected project (location)""" + + def done(event): + gs.try_remove(event.userData) + + cmd = ["g.proj", "-p"] + gisrc, env = gs.create_environment( + self.selected_grassdb[0].data["name"], + self.selected_location[0].data["name"], + "PERMANENT", + ) + self._giface.RunCmd(cmd, env=env, onDone=done, userData=gisrc) + + def OnShowRegion(self, event): + """Show computational region of selected mapset""" + + def done(event): + gs.try_remove(event.userData) + + cmd = ["g.region", "-p3"] + gisrc, env = gs.create_environment( + self.selected_grassdb[0].data["name"], + self.selected_location[0].data["name"], + self.selected_mapset[0].data["name"], + ) + self._giface.RunCmd(cmd, env=env, onDone=done, userData=gisrc) + def OnCopyName(self, event): """Copy layer name to clipboard""" if wx.TheClipboard.Open(): @@ -2274,6 +2302,11 @@ def _popupMenuMapset(self): menu.AppendItem(item) self.Bind(wx.EVT_MENU, self.OnReloadMapset, item) + menu.AppendSeparator() + item = wx.MenuItem(menu, wx.ID_ANY, _("Show computational region")) + menu.AppendItem(item) + self.Bind(wx.EVT_MENU, self.OnShowRegion, item) + item = wx.MenuItem(menu, wx.ID_ANY, _("&Copy path")) menu.AppendItem(item) self.Bind(wx.EVT_MENU, self.OnCopyMapsetPath, item) @@ -2305,6 +2338,11 @@ def _popupMenuLocation(self): menu.AppendItem(item) self.Bind(wx.EVT_MENU, self.OnReloadLocation, item) + menu.AppendSeparator() + item = wx.MenuItem(menu, wx.ID_ANY, _("Show projection info")) + menu.AppendItem(item) + self.Bind(wx.EVT_MENU, self.OnShowProjection, item) + item = wx.MenuItem(menu, wx.ID_ANY, _("Copy path")) menu.AppendItem(item) self.Bind(wx.EVT_MENU, self.OnCopyLocationPath, item) diff --git a/gui/wxpython/lmgr/statusbar.py b/gui/wxpython/lmgr/statusbar.py index c30fde67d5c..420c92f96f4 100644 --- a/gui/wxpython/lmgr/statusbar.py +++ b/gui/wxpython/lmgr/statusbar.py @@ -21,6 +21,7 @@ import grass.script as gs +import json from core.gcmd import RunCommand from core.watchdog import watchdog_used from gui_core.wrap import Button @@ -34,9 +35,10 @@ def __init__(self, parent, giface): self.giface = giface self.widget = wx.StatusBar(self.parent, id=wx.ID_ANY) self.widget.SetMinHeight(24) - self.widget.SetFieldsCount(2) - self.widget.SetStatusWidths([-1, 100]) + self.widget.SetFieldsCount(3) + self.widget.SetStatusWidths([-1, 100, 100]) self.mask = SbMask(self.widget, self.giface) + self.crs = SbCRS(self.widget, self.giface) self.widget.Bind(wx.EVT_SIZE, self.OnSize) self._repositionStatusbar() @@ -54,9 +56,15 @@ def _repositionStatusbar(self): rect1.y += 1 self.mask.GetWidget().SetRect(rect1) + rect2 = self.GetWidget().GetFieldRect(2) + rect2.x += 1 + rect2.y += 1 + self.crs.GetWidget().SetRect(rect2) + def Refresh(self): - """Refresh statusbar. So far it refreshes just a mask.""" + """Refresh statusbar""" self.mask.Refresh() + self.crs.Refresh() def OnSize(self, event): """Adjust main window statusbar on changing size""" @@ -155,3 +163,60 @@ def OnRemoveMask(self, event): action="delete", element="raster", ) + + +class SbCRS: + """Button to show the EPSG code if available, otherwise 'Custom CRS'. + Clicking it prints Coordinate Reference System (CRS) information for + the current project to the console. + """ + + def __init__(self, parent, giface): + self.name = "crs" + self.giface = giface + self.widget = Button( + parent=parent, id=wx.ID_ANY, label=_("Custom CRS"), style=wx.NO_BORDER + ) + self.widget.Bind(wx.EVT_BUTTON, self.OnShowProjection) + self.widget.SetToolTip( + tip=_("Left mouse click to print detailed projection info") + ) + + self.giface.currentMapsetChanged.connect(self.Refresh) + self.Refresh() + + def Show(self): + self.widget.Show() + + def Hide(self): + self.widget.Hide() + + def GetWidget(self): + """Returns underlying widget. + + :return: widget or None if doesn't exist + """ + return self.widget + + def Refresh(self): + """Fetch the EPSG code, or display 'Custom CRS' if not found""" + + label = _("Custom CRS") + + try: + proj_str = gs.read_command( + "g.proj", flags="p", format="projjson", quiet=True + ) + if proj_str: + proj_info = json.loads(proj_str) + proj_id = proj_info.get("id", {}) + if proj_id.get("authority") == "EPSG" and proj_id.get("code"): + label = f"EPSG: {proj_id['code']}" + except (TypeError, KeyError, json.JSONDecodeError): + pass + + self.widget.SetLabel(label) + self.Show() + + def OnShowProjection(self, event): + self.giface.RunCmd(["g.proj", "-p"])