pyshell.py 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163
  1. """
  2. @package lmgr.pyshell
  3. @brief wxGUI Interactive Python Shell for Layer Manager
  4. Classes:
  5. - pyshell::PyShellWindow
  6. .. todo::
  7. Run pyshell and evaluate code in a separate instance of python &
  8. design the widget communicate back and forth with it
  9. (C) 2011 by the GRASS Development Team
  10. This program is free software under the GNU General Public License
  11. (>=v2). Read the file COPYING that comes with GRASS for details.
  12. @author Martin Landa <landa.martin gmail.com>
  13. """
  14. from __future__ import print_function
  15. import io
  16. from contextlib import redirect_stdout
  17. import sys
  18. import wx
  19. from wx.py.shell import Shell as PyShell
  20. from wx.py.version import VERSION
  21. import grass.script as grass
  22. from gui_core.wrap import Button, ClearButton, IsDark
  23. from gui_core.pystc import SetDarkMode
  24. from core.globalvar import CheckWxVersion
  25. class PyShellWindow(wx.Panel):
  26. """Python Shell Window"""
  27. def __init__(
  28. self, parent, giface, id=wx.ID_ANY, simpleEditorHandler=None, **kwargs
  29. ):
  30. self.parent = parent
  31. self.giface = giface
  32. wx.Panel.__init__(self, parent=parent, id=id, **kwargs)
  33. self.intro = (
  34. _("Welcome to wxGUI Interactive Python Shell %s") % VERSION
  35. + "\n\n"
  36. + _("Type %s for more GRASS scripting related information.") % '"help(gs)"'
  37. + "\n"
  38. + _("Type %s to add raster or vector to the layer tree.")
  39. % "\"AddLayer('map_name')\""
  40. + "\n\n"
  41. )
  42. shellargs = dict(
  43. parent=self,
  44. id=wx.ID_ANY,
  45. introText=self.intro,
  46. locals={"gs": grass, "AddLayer": self.AddLayer, "help": self.Help},
  47. )
  48. # useStockId (available since wxPython 4.0.2) should be False on macOS
  49. if sys.platform == "darwin" and CheckWxVersion([4, 0, 2]):
  50. shellargs["useStockId"] = False
  51. self.shell = PyShell(**shellargs)
  52. if IsDark():
  53. SetDarkMode(self.shell)
  54. sys.displayhook = self._displayhook
  55. self.btnClear = ClearButton(self)
  56. self.btnClear.Bind(wx.EVT_BUTTON, self.OnClear)
  57. self.btnClear.SetToolTip(_("Delete all text from the shell"))
  58. self.simpleEditorHandler = simpleEditorHandler
  59. if simpleEditorHandler:
  60. self.btnSimpleEditor = Button(self, id=wx.ID_ANY, label=_("Simple &editor"))
  61. self.btnSimpleEditor.Bind(wx.EVT_BUTTON, simpleEditorHandler)
  62. self.btnSimpleEditor.SetToolTip(_("Open a simple Python code editor"))
  63. self._layout()
  64. def _displayhook(self, value):
  65. print(value) # do not modify __builtin__._
  66. def _layout(self):
  67. sizer = wx.BoxSizer(wx.VERTICAL)
  68. sizer.Add(self.shell, proportion=1, flag=wx.EXPAND)
  69. btnSizer = wx.BoxSizer(wx.HORIZONTAL)
  70. if self.simpleEditorHandler:
  71. btnSizer.Add(
  72. self.btnSimpleEditor,
  73. proportion=0,
  74. flag=wx.EXPAND | wx.LEFT | wx.RIGHT,
  75. border=5,
  76. )
  77. btnSizer.AddStretchSpacer()
  78. btnSizer.Add(self.btnClear, proportion=0, flag=wx.EXPAND, border=5)
  79. sizer.Add(btnSizer, proportion=0, flag=wx.ALL | wx.EXPAND, border=5)
  80. sizer.Fit(self)
  81. sizer.SetSizeHints(self)
  82. self.SetSizer(sizer)
  83. self.Fit()
  84. self.SetAutoLayout(True)
  85. self.Layout()
  86. def AddLayer(self, name, ltype="auto"):
  87. """Add selected map to the layer tree
  88. :param name: name of raster/vector map to be added
  89. :param type: map type ('raster', 'vector', 'auto' for autodetection)
  90. """
  91. fname = None
  92. if ltype == "raster" or ltype != "vector":
  93. # check for raster
  94. fname = grass.find_file(name, element="cell")["fullname"]
  95. if fname:
  96. ltype = "raster"
  97. lcmd = "d.rast"
  98. if not fname and (ltype == "vector" or ltype != "raster"):
  99. # if not found check for vector
  100. fname = grass.find_file(name, element="vector")["fullname"]
  101. if fname:
  102. ltype = "vector"
  103. lcmd = "d.vect"
  104. if not fname:
  105. return _("Raster or vector map <%s> not found") % (name)
  106. self.giface.GetLayerTree().AddLayer(
  107. ltype=ltype, lname=fname, lchecked=True, lcmd=[lcmd, "map=%s" % fname]
  108. )
  109. if ltype == "raster":
  110. return _("Raster map <%s> added") % fname
  111. return _("Vector map <%s> added") % fname
  112. def Help(self, obj):
  113. """Override help() function
  114. :param obj object/str: generate the help of the given object
  115. return str: help str of the given object
  116. """
  117. with redirect_stdout(io.StringIO()) as f:
  118. help(obj)
  119. return f.getvalue()
  120. def OnClear(self, event):
  121. """Delete all text from the shell"""
  122. self.shell.clear()
  123. self.shell.showIntro(self.intro)
  124. self.shell.prompt()