Skip to content

Commit

Permalink
wxGUI: New History pane for launching commands from history log (#3234)
Browse files Browse the repository at this point in the history
  • Loading branch information
lindakarlovska authored Dec 8, 2023
1 parent 75328b4 commit 8fd28c4
Show file tree
Hide file tree
Showing 14 changed files with 372 additions and 115 deletions.
4 changes: 2 additions & 2 deletions gui/wxpython/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ include $(MODULE_TOPDIR)/include/Make/Python.make
DSTDIR = $(GUIDIR)/wxpython

SRCFILES := $(wildcard icons/*.py scripts/*.py xml/*) \
$(wildcard animation/*.py core/*.py datacatalog/*.py dbmgr/*.py gcp/*.py gmodeler/*.py \
$(wildcard animation/*.py core/*.py datacatalog/*.py history/*.py dbmgr/*.py gcp/*.py gmodeler/*.py \
gui_core/*.py iclass/*.py lmgr/*.py location_wizard/*.py main_window/*.py mapwin/*.py mapdisp/*.py \
mapswipe/*.py modules/*.py nviz/*.py psmap/*.py rdigit/*.py \
rlisetup/*.py startup/*.py timeline/*.py vdigit/*.py \
Expand All @@ -19,7 +19,7 @@ SRCFILES := $(wildcard icons/*.py scripts/*.py xml/*) \
DSTFILES := $(patsubst %,$(DSTDIR)/%,$(SRCFILES)) \
$(patsubst %.py,$(DSTDIR)/%.pyc,$(filter %.py,$(SRCFILES)))

PYDSTDIRS := $(patsubst %,$(DSTDIR)/%,animation core datacatalog dbmgr gcp gmodeler \
PYDSTDIRS := $(patsubst %,$(DSTDIR)/%,animation core datacatalog history dbmgr gcp gmodeler \
gui_core iclass lmgr location_wizard main_window mapwin mapdisp modules nviz psmap \
mapswipe vdigit wxplot web_services rdigit rlisetup startup \
vnet timeline iscatt tplot photo2image image2target)
Expand Down
32 changes: 2 additions & 30 deletions gui/wxpython/core/gconsole.py
Original file line number Diff line number Diff line change
Expand Up @@ -495,8 +495,8 @@ def RunCmd(
Debug.msg(2, "GPrompt:RunCmd(): empty command")
return

# update history file
self.UpdateHistoryFile(cmd_save_to_history)
# update history file, command prompt history and history model
self._giface.updateHistory.emit(cmd=cmd_save_to_history)

if command[0] in globalvar.grassCmd:
# send GRASS command without arguments to GUI command interface
Expand Down Expand Up @@ -810,31 +810,3 @@ def OnCmdDone(self, event):

def OnProcessPendingOutputWindowEvents(self, event):
wx.GetApp().ProcessPendingEvents()

def UpdateHistoryFile(self, command):
"""Update history file
:param command: the command given as a string
"""
env = grass.gisenv()
try:
filePath = os.path.join(
env["GISDBASE"], env["LOCATION_NAME"], env["MAPSET"], ".wxgui_history"
)
fileHistory = codecs.open(filePath, encoding="utf-8", mode="a")
except IOError as e:
GError(
_("Unable to write file '%(filePath)s'.\n\nDetails: %(error)s")
% {"filePath": filePath, "error": e},
parent=self._guiparent,
)
return

try:
fileHistory.write(command + os.linesep)
finally:
fileHistory.close()

# update wxGUI prompt
if self._giface:
self._giface.UpdateCmdHistory(command)
16 changes: 3 additions & 13 deletions gui/wxpython/core/giface.py
Original file line number Diff line number Diff line change
Expand Up @@ -199,15 +199,6 @@ def GetProgress(self):
"""
raise NotImplementedError()

def UpdateCmdHistory(self, cmd):
"""Add the command to the current history list shown to the user
.. note::
Some implementations may not implement this method or do nothing.
"""
raise NotImplementedError()


class StandaloneGrassInterface(GrassInterface):
"""@implements GrassInterface"""
Expand Down Expand Up @@ -241,6 +232,9 @@ def __init__(self):
# Signal emitted when workspace is changed
self.workspaceChanged = Signal("StandaloneGrassInterface.workspaceChanged")

# Signal emitted when history should be updated
self.updateHistory = Signal("StandaloneGrassInterface.updateHistory")

# workaround, standalone grass interface should be moved to sep. file
from core.gconsole import GConsole, EVT_CMD_OUTPUT, EVT_CMD_PROGRESS

Expand Down Expand Up @@ -343,7 +337,3 @@ def GetProgress(self):
# TODO: implement some progress with same inface as gui one
# (probably using g.message or similarly to Write... functions)
raise NotImplementedError()

def UpdateCmdHistory(self, cmd):
"""There is no history displayed to the user, doing nothing"""
pass
5 changes: 1 addition & 4 deletions gui/wxpython/core/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -169,10 +169,7 @@ def _defaultSettings(self):
# ask when quitting wxGUI or closing display
"askOnQuit": {"enabled": True},
# hide tabs
"hideTabs": {
"search": False,
"pyshell": False,
},
"hideTabs": {"search": False, "pyshell": False, "history": False},
"copySelectedTextToClipboard": {"enabled": False},
},
#
Expand Down
46 changes: 45 additions & 1 deletion gui/wxpython/gui_core/goutput.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,18 @@

import textwrap

import os
import wx
from wx import stc

from grass.pydispatch.signal import Signal
from grass.grassdb.history import (
read_history,
create_history_file,
update_history,
copy_history,
get_current_mapset_gui_history_path,
)

# needed just for testing
if __name__ == "__main__":
Expand Down Expand Up @@ -84,6 +92,7 @@ def __init__(
self.panelPrompt = wx.Panel(parent=self, id=wx.ID_ANY)
# initialize variables
self.parent = parent # GMFrame | CmdPanel | ?
self.giface = giface
self._gconsole = gconsole
self._menuModel = menuModel

Expand Down Expand Up @@ -135,6 +144,18 @@ def __init__(
if not self._gcstyle & GC_PROMPT:
self.cmdPrompt.Hide()

# read history file
self._loadHistory()
if self.giface:
self.giface.currentMapsetChanged.connect(self._loadHistory)

if self._gcstyle == GC_PROMPT:
# connect update history signal only for main Console Window
self.giface.updateHistory.connect(
lambda cmd: self.cmdPrompt.UpdateCmdHistory(cmd)
)
self.giface.updateHistory.connect(lambda cmd: self.UpdateHistory(cmd))

# buttons
self.btnClear = ClearButton(parent=self.panelPrompt)
self.btnClear.SetToolTip(_("Clear prompt and output window"))
Expand Down Expand Up @@ -238,6 +259,17 @@ def _layout(self):
self.SetAutoLayout(True)
self.Layout()

def _loadHistory(self):
"""Load history from a history file to data structures"""
history_path = get_current_mapset_gui_history_path()
try:
if not os.path.exists(history_path):
create_history_file(history_path)
self.cmdPrompt.cmdbuffer = read_history(history_path)
self.cmdPrompt.cmdindex = len(self.cmdPrompt.cmdbuffer)
except OSError as e:
GError(str(e))

def GetPanel(self, prompt=True):
"""Get panel
Expand Down Expand Up @@ -416,6 +448,14 @@ def OnCmdProgress(self, event):
self.progressbar.SetValue(event.value)
event.Skip()

def UpdateHistory(self, cmd):
"""Update command history"""
history_path = get_current_mapset_gui_history_path()
try:
update_history(cmd, history_path)
except OSError as e:
GError(str(e))

def OnCmdExportHistory(self, event):
"""Export the history of executed commands stored
in a .wxgui_history file to a selected file."""
Expand All @@ -431,10 +471,14 @@ def OnCmdExportHistory(self, event):

if dlg.ShowModal() == wx.ID_OK:
path = dlg.GetPath()
if self.cmdPrompt.CopyHistory(path):
history_path = get_current_mapset_gui_history_path()
try:
copy_history(path, history_path)
self.showNotification.emit(
message=_("Command history saved to '{}'".format(path))
)
except OSError as e:
GError(str(e))

dlg.Destroy()
event.Skip()
Expand Down
14 changes: 14 additions & 0 deletions gui/wxpython/gui_core/preferences.py
Original file line number Diff line number Diff line change
Expand Up @@ -334,6 +334,20 @@ def _createGeneralPage(self, notebook):

gridSizer.Add(hideSearch, pos=(row, 0), span=(1, 2))

row += 1
hideHistory = wx.CheckBox(
parent=panel,
id=wx.ID_ANY,
label=_("Hide '%s' tab (requires GUI restart)") % _("History"),
name="IsChecked",
)
hideHistory.SetValue(
self.settings.Get(group="manager", key="hideTabs", subkey="history")
)
self.winId["manager:hideTabs:history"] = hideHistory.GetId()

gridSizer.Add(hideHistory, pos=(row, 0), span=(1, 2))

row += 1
hidePyShell = wx.CheckBox(
parent=panel,
Expand Down
62 changes: 1 addition & 61 deletions gui/wxpython/gui_core/prompt.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,8 @@
@author Wolf Bergenheim <wolf bergenheim.net> (#962)
"""

import os
import difflib
import codecs
import sys
import shutil

import wx
import wx.stc
Expand All @@ -34,7 +31,7 @@

from core import globalvar
from core import utils
from core.gcmd import EncodeString, DecodeString, GError
from core.gcmd import EncodeString, DecodeString


class GPrompt(object):
Expand Down Expand Up @@ -65,10 +62,6 @@ def __init__(self, parent, giface, menuModel):
# command description (gtask.grassTask)
self.cmdDesc = None

self._loadHistory()
if giface:
giface.currentMapsetChanged.connect(self._loadHistory)

# list of traced commands
self.commands = list()

Expand All @@ -77,38 +70,6 @@ def __init__(self, parent, giface, menuModel):
giface.currentMapsetChanged.connect(self._reloadListOfMaps)
giface.grassdbChanged.connect(self._reloadListOfMaps)

def _readHistory(self):
"""Get list of commands from history file"""
hist = list()
env = grass.gisenv()
try:
fileHistory = codecs.open(
os.path.join(
env["GISDBASE"],
env["LOCATION_NAME"],
env["MAPSET"],
".wxgui_history",
),
encoding="utf-8",
mode="r",
errors="replace",
)
except IOError:
return hist

try:
for line in fileHistory.readlines():
hist.append(line.replace("\n", ""))
finally:
fileHistory.close()

return hist

def _loadHistory(self):
"""Load history from a history file to data structures"""
self.cmdbuffer = self._readHistory()
self.cmdindex = len(self.cmdbuffer)

def _getListOfMaps(self):
"""Get list of maps"""
result = dict()
Expand Down Expand Up @@ -140,27 +101,6 @@ def _runCmd(self, cmdString):
self.CmdErase()
self.ShowStatusText("")

def CopyHistory(self, targetFile):
"""Copy history file to the target location.
Returns True if file is successfully copied."""
env = grass.gisenv()
historyFile = os.path.join(
env["GISDBASE"],
env["LOCATION_NAME"],
env["MAPSET"],
".wxgui_history",
)
try:
shutil.copyfile(historyFile, targetFile)
except (IOError, OSError) as e:
GError(
_("Unable to copy file {} to {}'.\n\nDetails: {}").format(
historyFile, targetFile, e
)
)
return False
return True

def GetCommands(self):
"""Get list of launched commands"""
return self.commands
Expand Down
Loading

0 comments on commit 8fd28c4

Please sign in to comment.