[GRASS-SVN] r53944 - in grass/trunk/gui/wxpython: core gmodeler gui_core lmgr
svn_grass at osgeo.org
svn_grass at osgeo.org
Wed Nov 21 01:05:50 PST 2012
Author: annakrat
Date: 2012-11-21 01:05:50 -0800 (Wed, 21 Nov 2012)
New Revision: 53944
Modified:
grass/trunk/gui/wxpython/core/events.py
grass/trunk/gui/wxpython/gmodeler/dialogs.py
grass/trunk/gui/wxpython/gmodeler/frame.py
grass/trunk/gui/wxpython/gui_core/goutput.py
grass/trunk/gui/wxpython/gui_core/prompt.py
grass/trunk/gui/wxpython/lmgr/frame.py
Log:
wxGUI/GPrompt: decoupling GPrompt and GConsole; standalone GConsole for testing available (co-author: wenzeslaus)
Modified: grass/trunk/gui/wxpython/core/events.py
===================================================================
--- grass/trunk/gui/wxpython/core/events.py 2012-11-21 04:11:16 UTC (rev 53943)
+++ grass/trunk/gui/wxpython/core/events.py 2012-11-21 09:05:50 UTC (rev 53944)
@@ -6,7 +6,12 @@
Put here only truly general events. Once you find that your event can be
generated in more than one class, put your event here. Otherwise,
leave it in your class file.
-
+
+General notice:
+Command events are propagated to parent windows. However they do not propagate
+beyond dialogs. Events do not propagate at all.
+
+
(C) 2012 by the GRASS Development Team
This program is free software under the GNU General Public License
Modified: grass/trunk/gui/wxpython/gmodeler/dialogs.py
===================================================================
--- grass/trunk/gui/wxpython/gmodeler/dialogs.py 2012-11-21 04:11:16 UTC (rev 53943)
+++ grass/trunk/gui/wxpython/gmodeler/dialogs.py 2012-11-21 09:05:50 UTC (rev 53944)
@@ -35,7 +35,7 @@
from gui_core.widgets import SearchModuleWidget, EVT_MODULE_SELECTED
from core.gcmd import GError, EncodeString
from gui_core.dialogs import ElementDialog, MapLayersDialogForModeler
-from gui_core.prompt import GPromptSTC
+from gui_core.prompt import GPromptSTC, EVT_GPROMPT_RUN_CMD
from gui_core.forms import CmdPanel
from gui_core.gselect import Select
from gmodeler.model import *
@@ -130,19 +130,21 @@
self.SetName("ModelerDialog")
self.SetIcon(wx.Icon(os.path.join(globalvar.ETCICONDIR, 'grass.ico'), wx.BITMAP_TYPE_ICO))
+ self._command = None
self.panel = wx.Panel(parent = self, id = wx.ID_ANY)
self.cmdBox = wx.StaticBox(parent = self.panel, id = wx.ID_ANY,
label=" %s " % _("Command"))
modulesData = ModulesData()
- self.cmd_prompt = GPromptSTC(parent = self, modulesData = modulesData)
+ self.cmd_prompt = GPromptSTC(parent = self, modulesData = modulesData, updateCmdHistory = False)
+ self.cmd_prompt.Bind(EVT_GPROMPT_RUN_CMD, self.OnCommand)
self.search = SearchModuleWidget(parent = self.panel,
modulesData = modulesData,
showTip = True)
self.search.Bind(EVT_MODULE_SELECTED,
lambda event:
- self.cmd_prompt.SetTextAndFocus(event.name + ' '))
+ self.cmd_prompt.SetTextAndFocus(event.name + ' '))
wx.CallAfter(self.cmd_prompt.SetFocus)
self.btnCancel = wx.Button(self.panel, wx.ID_CANCEL)
@@ -186,42 +188,48 @@
"""!Get dialog panel"""
return self.panel
- def GetCmd(self):
- """!Get command"""
+ def _getCmd(self):
line = self.cmd_prompt.GetCurLine()[0].strip()
if len(line) == 0:
- list()
-
- try:
- cmd = utils.split(str(line))
- except UnicodeError:
- cmd = utils.split(EncodeString((line)))
-
+ cmd = list()
+ else:
+ try:
+ cmd = utils.split(str(line))
+ except UnicodeError:
+ cmd = utils.split(EncodeString((line)))
return cmd
-
- def OnOk(self, event):
- """!Button 'OK' pressed"""
- # hide autocomplete
- if self.cmd_prompt.AutoCompActive():
- self.cmd_prompt.AutoCompCancel()
-
- self.btnOk.SetFocus()
- cmd = self.GetCmd()
-
+
+ def GetCmd(self):
+ """!Get command"""
+ return self._command
+
+ def ValidateCmd(self, cmd):
if len(cmd) < 1:
GError(parent = self,
message = _("Command not defined.\n\n"
"Unable to add new action to the model."))
- return
+ return False
if cmd[0] not in globalvar.grassCmd:
GError(parent = self,
message = _("'%s' is not a GRASS module.\n\n"
"Unable to add new action to the model.") % cmd[0])
- return
-
- self.EndModal(wx.ID_OK)
-
+ return False
+ return True
+
+ def OnCommand(self, event):
+ """!Command in prompt confirmed"""
+ if self.ValidateCmd(event.cmd):
+ self._command = event.cmd
+ self.EndModal(wx.ID_OK)
+
+ def OnOk(self, event):
+ """!Button 'OK' pressed"""
+ cmd = self._getCmd()
+ if self.ValidateCmd(cmd):
+ self._command = cmd
+ self.EndModal(wx.ID_OK)
+
def OnCancel(self, event):
"""Cancel pressed, close window"""
# hide autocomplete
Modified: grass/trunk/gui/wxpython/gmodeler/frame.py
===================================================================
--- grass/trunk/gui/wxpython/gmodeler/frame.py 2012-11-21 04:11:16 UTC (rev 53943)
+++ grass/trunk/gui/wxpython/gmodeler/frame.py 2012-11-21 09:05:50 UTC (rev 53944)
@@ -36,7 +36,7 @@
from gui_core.widgets import GNotebook
from gui_core.goutput import GConsole, \
EVT_CMD_RUN, EVT_CMD_DONE, EVT_CMD_PREPARE, EVT_OUTPUT_TEXT
-from core.events import EVT_MAP_CREATED
+from core.events import EVT_MAP_CREATED, EVT_SHOW_NOTIFICATION
from core.debug import Debug
from core.gcmd import GMessage, GException, GWarning, GError, RunCommand
from gui_core.dialogs import GetImageHandlers
@@ -112,6 +112,8 @@
self.Bind(EVT_CMD_DONE, self.OnCmdDone)
self.Bind(EVT_CMD_PREPARE, self.OnCmdPrepare)
self.Bind(EVT_MAP_CREATED, self.OnMapCreated)
+ self.Bind(EVT_SHOW_NOTIFICATION,
+ lambda event: self.SetStatusText(event.message))
self.notebook.AddPage(page = self.canvas, text=_('Model'), name = 'model')
self.notebook.AddPage(page = self.itemPanel, text=_('Items'), name = 'items')
Modified: grass/trunk/gui/wxpython/gui_core/goutput.py
===================================================================
--- grass/trunk/gui/wxpython/gui_core/goutput.py 2012-11-21 04:11:16 UTC (rev 53943)
+++ grass/trunk/gui/wxpython/gui_core/goutput.py 2012-11-21 09:05:50 UTC (rev 53944)
@@ -30,6 +30,8 @@
import codecs
import locale
+sys.path.append(os.path.join(os.environ['GISBASE'], "etc", "gui", "wxpython"))
+
import wx
from wx import stc
from wx.lib.newevent import NewEvent
@@ -42,7 +44,7 @@
from core.gcmd import CommandThread, GMessage, GError, GException, EncodeString
from core.events import gShowNotification, gMapCreated
from gui_core.forms import GUI
-from gui_core.prompt import GPromptSTC
+from gui_core.prompt import GPromptSTC, EVT_GPROMPT_RUN_CMD
from core.debug import Debug
from core.settings import UserSettings
from gui_core.widgets import SearchModuleWidget, EVT_MODULE_SELECTED
@@ -276,6 +278,9 @@
# move to the if below
# search depends on cmd prompt
self.cmdPrompt = GPromptSTC(parent = self, modulesData = modulesData)
+ self.cmdPrompt.Bind(EVT_GPROMPT_RUN_CMD,
+ lambda event: self.RunCmd(command = event.cmd))
+
if not self._gcstyle & GC_PROMPT:
self.cmdPrompt.Hide()
@@ -578,7 +583,7 @@
# except ignored commands (event is emitted)
if self._ignoredCmdPattern and \
- re.compile(self._ignoredCmdPattern).search(command[0]) and \
+ re.compile(self._ignoredCmdPattern).search(' '.join(command)) and \
'--help' not in command:
event = gIgnoredCmdRun(cmd = command)
wx.PostEvent(self, event)
@@ -1204,3 +1209,30 @@
self.SetStyling(p2 - p1, self.StyleUnknown)
self.EnsureCaretVisible()
+
+
+class GConsoleFrame(wx.Frame):
+ """!Standalone GConsole for testing only"""
+ def __init__(self, parent, id = wx.ID_ANY, title = "GConsole Test Frame",
+ style = wx.DEFAULT_FRAME_STYLE | wx.TAB_TRAVERSAL, **kwargs):
+ wx.Frame.__init__(self, parent = parent, id = id, title = title)
+
+ panel = wx.Panel(self, id = wx.ID_ANY)
+ self.goutput = GConsole(parent = panel, gcstyle = GC_SEARCH | GC_PROMPT)
+
+ mainSizer = wx.BoxSizer(wx.VERTICAL)
+ mainSizer.Add(item = self.goutput, proportion = 1, flag = wx.EXPAND, border = 0)
+
+ panel.SetSizer(mainSizer)
+ mainSizer.Fit(panel)
+ self.SetMinSize((550, 500))
+
+
+def testGConsole():
+ app = wx.PySimpleApp()
+ frame = GConsoleFrame(parent = None)
+ frame.Show()
+ app.MainLoop()
+
+if __name__ == '__main__':
+ testGConsole()
Modified: grass/trunk/gui/wxpython/gui_core/prompt.py
===================================================================
--- grass/trunk/gui/wxpython/gui_core/prompt.py 2012-11-21 04:11:16 UTC (rev 53943)
+++ grass/trunk/gui/wxpython/gui_core/prompt.py 2012-11-21 09:05:50 UTC (rev 53944)
@@ -29,12 +29,15 @@
import wx.stc
import wx.lib.mixins.listctrl as listmix
+from wx.lib.newevent import NewEvent
+
from grass.script import core as grass
from grass.script import task as gtask
from core import globalvar
from core import utils
from core.gcmd import EncodeString, DecodeString, GetRealCmd
+from core.events import gShowNotification
class PromptListCtrl(wx.ListCtrl, listmix.ListCtrlAutoWidthMixin):
"""!PopUp window used by GPromptPopUp"""
@@ -464,19 +467,17 @@
event.Skip()
+
+gPromptRunCmd, EVT_GPROMPT_RUN_CMD = NewEvent()
+
class GPrompt(object):
"""!Abstract class for interactive wxGUI prompt
See subclass GPromptPopUp and GPromptSTC.
"""
- def __init__(self, parent, modulesData):
+ def __init__(self, parent, modulesData, updateCmdHistory):
self.parent = parent # GConsole
self.panel = self.parent.GetPanel()
-
- if self.parent.parent.GetName() not in ("LayerManager", "Modeler"):
- self.standAlone = True
- else:
- self.standAlone = False
# probably only subclasses need this
self.modulesData = modulesData
@@ -490,6 +491,8 @@
# command description (gtask.grassTask)
self.cmdDesc = None
+
+ self._updateCmdHistory = updateCmdHistory
self.cmdbuffer = self._readHistory()
self.cmdindex = len(self.cmdbuffer)
@@ -530,16 +533,9 @@
@param cmdString command to run (given as a string)
"""
- if self.parent.GetName() == "ModelerDialog":
- self.parent.OnOk(None)
+ if not cmdString:
return
-
- if not cmdString or self.standAlone:
- return
-
- if cmdString[:2] == 'd.' and not self.parent.parent.GetMapDisplay():
- self.parent.parent.NewDisplay(show = True)
-
+
self.commands.append(cmdString) # trace commands
# parse command into list
@@ -548,29 +544,14 @@
except UnicodeError:
cmd = utils.split(EncodeString((cmdString)))
cmd = map(DecodeString, cmd)
-
- # send the command list to the processor
- if cmd[0] in ('r.mapcalc', 'r3.mapcalc') and len(cmd) == 1:
- self.parent.parent.OnMapCalculator(event = None, cmd = cmd)
- else:
- self.parent.RunCmd(cmd)
-
+
+ wx.PostEvent(self, gPromptRunCmd(cmd = cmd))
+
# add command to history & clean prompt
self.UpdateCmdHistory(cmd)
self.OnCmdErase(None)
- self.parent.parent.statusbar.SetStatusText('')
+ self.ShowStatusText('')
- def OnUpdateStatusBar(self, event):
- """!Update Layer Manager status bar"""
- if self.standAlone:
- return
-
- if event is None:
- self.parent.parent.statusbar.SetStatusText("")
- else:
- self.parent.parent.statusbar.SetStatusText(_("Type GRASS command and run by pressing ENTER"))
- event.Skip()
-
def GetPanel(self):
"""!Get main widget panel"""
return self.panel
@@ -643,9 +624,10 @@
class GPromptSTC(GPrompt, wx.stc.StyledTextCtrl):
"""!Styled wxGUI prompt with autocomplete and calltips"""
- def __init__(self, parent, modulesData, id = wx.ID_ANY, margin = False):
- GPrompt.__init__(self, parent, modulesData)
- wx.stc.StyledTextCtrl.__init__(self, self.panel, id)
+ def __init__(self, parent, modulesData, updateCmdHistory = True, margin = False):
+ GPrompt.__init__(self, parent = parent,
+ modulesData = modulesData, updateCmdHistory = updateCmdHistory)
+ wx.stc.StyledTextCtrl.__init__(self, self.panel, id = wx.ID_ANY)
#
# styles
@@ -757,17 +739,10 @@
cmd = text.strip().split(' ')[0]
if not self.cmdDesc or cmd != self.cmdDesc.get_name():
- if cmd in ('r.mapcalc', 'r3.mapcalc') and \
- self.parent.parent.GetName() == 'LayerManager':
- self.parent.parent.OnMapCalculator(event = None, cmd = [cmd])
- # add command to history & clean prompt
- self.UpdateCmdHistory([cmd])
- self.OnCmdErase(None)
- else:
- try:
- self.cmdDesc = gtask.parse_interface(GetRealCmd(cmd))
- except IOError:
- self.cmdDesc = None
+ try:
+ self.cmdDesc = gtask.parse_interface(GetRealCmd(cmd))
+ except IOError:
+ self.cmdDesc = None
def OnKillFocus(self, event):
"""!Hides autocomplete"""
@@ -788,6 +763,8 @@
@param cmd command given as a list
"""
+ if not self._updateCmdHistory:
+ return
# add command to history
self.cmdbuffer.append(' '.join(cmd))
@@ -1057,7 +1034,8 @@
pos = self.GetCurrentPos()
self.InsertText(pos,txt)
self.LineEnd()
- self.parent.parent.statusbar.SetStatusText('')
+
+ self.ShowStatusText('')
elif event.GetKeyCode() == wx.WXK_RETURN and \
self.AutoCompActive() == False:
@@ -1069,9 +1047,7 @@
if len(items) == 1:
cmd = items[0].strip()
if cmd in globalvar.grassCmd and \
- cmd != 'r.mapcalc' and \
(not self.cmdDesc or cmd != self.cmdDesc.get_name()):
-
try:
self.cmdDesc = gtask.parse_interface(GetRealCmd(cmd))
except IOError:
@@ -1083,13 +1059,12 @@
def ShowStatusText(self, text):
"""!Sets statusbar text, if it's too long, it is cut off"""
- maxLen = self.parent.parent.statusbar.GetFieldRect(0).GetWidth()/ 7 # any better way?
- if len(text) < maxLen:
- self.parent.parent.statusbar.SetStatusText(text)
- else:
- self.parent.parent.statusbar.SetStatusText(text[:maxLen]+'...')
+ # event is not propagated beyond dialog
+ # thus when GPrompt in Modeler is inside a dialog,
+ # it does not show text in modeler statusbar which is probably
+ # the right behaviour. The dialog itself should display the text.
+ wx.PostEvent(self, gShowNotification(self.GetId(), message = text))
-
def GetTextLeft(self):
"""!Returns all text left of the caret"""
pos = self.GetCurrentPos()
Modified: grass/trunk/gui/wxpython/lmgr/frame.py
===================================================================
--- grass/trunk/gui/wxpython/lmgr/frame.py 2012-11-21 04:11:16 UTC (rev 53943)
+++ grass/trunk/gui/wxpython/lmgr/frame.py 2012-11-21 09:05:50 UTC (rev 53944)
@@ -23,6 +23,7 @@
import tempfile
import stat
import platform
+import re
try:
import xml.etree.ElementTree as etree
except ImportError:
@@ -261,11 +262,11 @@
# create 'command output' text area
self.goutput = GConsole(self,
gcstyle = GC_SEARCH | GC_PROMPT,
- ignoredCmdPattern = '^d\..*')
+ ignoredCmdPattern = '^d\..*|^r[3]?\.mapcalc$')
self.notebook.AddPage(page = self.goutput, text = _("Command console"), name = 'output')
self.goutput.Bind(EVT_OUTPUT_TEXT, self.OnOutputText)
self.goutput.Bind(EVT_IGNORED_CMD_RUN,
- lambda event: self.DisplayCmdRun(event.cmd))
+ lambda event: self.RunSpecialCmd(event.cmd))
self._setCopyingOfSelectedText()
# create 'search module' notebook page
@@ -536,11 +537,19 @@
self.SetFocus()
self.Raise()
- def DisplayCmdRun(self, command):
+ def RunSpecialCmd(self, command):
+ if re.compile('^d\..*').search(command[0]):
+ self.RunDisplayCmd(command)
+ elif re.compile('r[3]?\.mapcalc').search(command[0]):
+ self.OnMapCalculator(event = None, cmd = command)
+
+ def RunDisplayCmd(self, command):
"""!Handles display commands.
@param command command in a list
"""
+ if not self.currentPage:
+ self.NewDisplay(show = True)
try:
# display GRASS commands
layertype = {'d.rast' : 'raster',
More information about the grass-commit
mailing list