[GRASS-SVN] r41624 - in grass/branches/develbranch_6/gui/wxpython:
gui_modules xml
svn_grass at osgeo.org
svn_grass at osgeo.org
Tue Mar 30 09:20:03 EDT 2010
Author: martinl
Date: 2010-03-30 09:20:03 -0400 (Tue, 30 Mar 2010)
New Revision: 41624
Modified:
grass/branches/develbranch_6/gui/wxpython/gui_modules/gcmd.py
grass/branches/develbranch_6/gui/wxpython/gui_modules/gmodeler.py
grass/branches/develbranch_6/gui/wxpython/gui_modules/menuform.py
grass/branches/develbranch_6/gui/wxpython/xml/menudata_modeler.xml
Log:
wxGUI/modeler: open/save model file (gxm)
(merge from r41620 - r41623 from trunk)
Modified: grass/branches/develbranch_6/gui/wxpython/gui_modules/gcmd.py
===================================================================
--- grass/branches/develbranch_6/gui/wxpython/gui_modules/gcmd.py 2010-03-30 13:17:53 UTC (rev 41623)
+++ grass/branches/develbranch_6/gui/wxpython/gui_modules/gcmd.py 2010-03-30 13:20:03 UTC (rev 41624)
@@ -1,7 +1,7 @@
-"""
+"""!
@package gcmd
- at brief GRASS command interface
+ at brief wxGUI command interface
Classes:
- GException
@@ -19,15 +19,13 @@
- RunCommand
-(C) 2007-2008 by the GRASS Development Team
+(C) 2007-2008, 2010 by the GRASS Development Team
This program is free software under the GNU General Public
License (>=v2). Read the file COPYING that comes with GRASS
for details.
@author Jachym Cepicky
-Martin Landa <landa.martin gmail.com>
-
- at date 2007-2008
+ at author Martin Landa <landa.martin gmail.com>
"""
import os
@@ -36,6 +34,7 @@
import errno
import signal
import locale
+import traceback
import wx
@@ -62,6 +61,25 @@
import utils
from debug import Debug as Debug
+class GMessage:
+ def __init__(self, parent, message, msgType = 'error'):
+ if msgType == 'error':
+ caption = _('Error')
+ style = wx.OK | wx.ICON_ERROR | wx.CENTRE
+
+ exception = traceback.format_exc()
+ reason = exception.split('\n')[-2].split(':', 1)[-1].strip()
+
+ if Debug.get_level() > 0:
+ sys.stderr.write(exception)
+
+ wx.MessageBox(parent = parent,
+ message = message + '\n\n%s: %s\n\n%s' % \
+ (_('Reason'),
+ reason, exception),
+ caption = caption,
+ style = style)
+
class GException(Exception):
"""!Generic exception"""
def __init__(self, message, title=_("Error"), parent=None):
Modified: grass/branches/develbranch_6/gui/wxpython/gui_modules/gmodeler.py
===================================================================
--- grass/branches/develbranch_6/gui/wxpython/gui_modules/gmodeler.py 2010-03-30 13:17:53 UTC (rev 41623)
+++ grass/branches/develbranch_6/gui/wxpython/gui_modules/gmodeler.py 2010-03-30 13:20:03 UTC (rev 41624)
@@ -22,6 +22,7 @@
import os
import shlex
import time
+import traceback
try:
import xml.etree.ElementTree as etree
@@ -39,12 +40,14 @@
import toolbars
import menuform
import prompt
-import gcmd
import utils
from debug import Debug
+from gcmd import GMessage
from grass.script import core as grass
+debug = False
+
class ModelFrame(wx.Frame):
def __init__(self, parent, id = wx.ID_ANY, title = _("Graphical modeler (under development)"), **kwargs):
"""!Graphical modeler main window
@@ -114,7 +117,8 @@
def OnModelOpen(self, event):
"""!Load model from file"""
- debug = False
+ filename = ''
+ global debug
if debug is False:
dlg = wx.FileDialog(parent = self, message=_("Choose model file"),
defaultDir = os.getcwd(),
@@ -123,7 +127,7 @@
filename = dlg.GetPath()
else:
- filename = '/home/martin/model.gxm'
+ filename = '/home/martin/model1.gxm'
if not filename:
return
@@ -141,12 +145,61 @@
def OnModelSave(self, event):
"""!Save model to file"""
- pass
-
+ if self.modelFile:
+ dlg = wx.MessageDialog(self, message=_("Model file <%s> already exists. "
+ "Do you want to overwrite this file?") % \
+ self.modelFile,
+ caption=_("Save model"),
+ style=wx.YES_NO | wx.YES_DEFAULT | wx.ICON_QUESTION)
+ if dlg.ShowModal() == wx.ID_NO:
+ dlg.Destroy()
+ else:
+ Debug.msg(4, "ModelFrame.OnModelSave(): filename=%s" % self.modelFile)
+ self.WriteModelFile(self.modelFile)
+ self.SetStatusText(_('File <%s> saved') % self.modelFile, 0)
+ else:
+ self.OnModelSaveAs(None)
+
def OnModelSaveAs(self, event):
"""!Create model to file as"""
- pass
-
+ global debug
+ if debug is False:
+ dlg = wx.FileDialog(parent = self,
+ message = _("Choose file to save current model"),
+ defaultDir = os.getcwd(),
+ wildcard=_("GRASS Model File (*.gxm)|*.gxm"),
+ style=wx.FD_SAVE)
+
+ filename = ''
+ if dlg.ShowModal() == wx.ID_OK:
+ filename = dlg.GetPath()
+ else:
+ filename = '/home/martin/model1.gxm'
+
+ if not filename:
+ return
+
+ # check for extension
+ if filename[-4:] != ".gxm":
+ filename += ".gxm"
+
+ if os.path.exists(filename):
+ dlg = wx.MessageDialog(parent = self,
+ message=_("Model file <%s> already exists. "
+ "Do you want to overwrite this file?") % filename,
+ caption=_("File already exists"),
+ style=wx.YES_NO | wx.YES_DEFAULT | wx.ICON_QUESTION)
+ if dlg.ShowModal() != wx.ID_YES:
+ dlg.Destroy()
+ return
+
+ Debug.msg(4, "GMFrame.OnModelSaveAs(): filename=%s" % filename)
+
+ self.WriteModelFile(filename)
+ self.modelFile = filename
+ self.SetTitle(self.baseTitle + " - " + os.path.basename(self.modelFile))
+ self.SetStatusText(_('File <%s> saved') % self.modelFile, 0)
+
def OnRunModel(self, event):
"""!Run entire model"""
pass
@@ -162,7 +215,7 @@
def OnAddAction(self, event):
"""!Add action to model"""
- debug = False
+ global debug
if debug == False:
if self.searchDialog is None:
self.searchDialog = ModelSearchDialog(self)
@@ -243,8 +296,10 @@
if p.get('age', 'old') == 'old':
self._addLine(data, layer)
+ data.AddAction(layer, direction = 'from')
else:
self._addLine(layer, data)
+ data.AddAction(layer, direction = 'to')
self.canvas.Refresh()
@@ -280,11 +335,11 @@
# parse workspace file
try:
gxmXml = ProcessModelFile(etree.parse(filename))
- except Exception, err:
- raise gcmd.GStdError(_("Reading model file <%(file)s> failed.\n"
- "Invalid file, unable to parse XML document."
- "\n\n%(err)s") % { 'file' : filename, 'err': err},
- parent = self)
+ except:
+ GMessage(parent = self,
+ message = _("Reading model file <%s> failed.\n"
+ "Invalid file, unable to parse XML document.") % filename)
+ return
busy = wx.BusyInfo(message=_("Please wait, loading model..."),
parent=self)
@@ -321,12 +376,42 @@
self.data.append(dataShape)
actionShape = self.actions[0]
- if data['from'] is False:
+ if data['from'] is True:
self._addLine(dataShape, actionShape)
- else:
+ elif data['from'] is False:
self._addLine(actionShape, dataShape)
+
self.canvas.Refresh(True)
+ def WriteModelFile(self, filename):
+ """!Save model to model file
+
+ @return True on success
+ @return False on failure
+ """
+ try:
+ file = open(filename, "w")
+ except IOError:
+ wx.MessageBox(parent = self,
+ message = _("Unable to open file <%s> for writing.") % filename,
+ caption = _("Error"),
+ style = wx.OK | wx.ICON_ERROR | wx.CENTRE)
+ return False
+
+ try:
+ WriteModelFile(fd = file, actions = self.actions, data = self.data)
+ except StandardError:
+ file.close()
+
+ GMessage(parent = self,
+ message = _("Writing current settings to model file failed."))
+
+ return False
+
+ file.close()
+
+ return True
+
class ModelCanvas(ogl.ShapeCanvas):
"""!Canvas where model is drawn"""
def __init__(self, parent):
@@ -379,7 +464,18 @@
return ' '.join(self.cmd)
return self.cmd
+
+ def GetName(self):
+ """!Get name"""
+ if self.cmd and len(self.cmd) > 0:
+ return self.cmd[0]
+
+ return _('unknown')
+ def GetParams(self):
+ """!Get dictionary of parameters"""
+ return self.params
+
class ModelData(ogl.EllipseShape):
"""!Data item class"""
def __init__(self, parent, x, y, name = '', value = '', prompt = '', width = 175, height = 50):
@@ -388,6 +484,8 @@
self.value = value
self.prompt = prompt
+ self.actions = { 'from' : list(), 'to' : list() }
+
ogl.EllipseShape.__init__(self, width, height)
# self.Draggable(True)
@@ -414,7 +512,38 @@
return self.name + '=' + self.value + ' (' + self.prompt + ')'
else:
return _('unknown')
-
+
+ def GetName(self):
+ """!Get name"""
+ return self.name
+
+ def GetPrompt(self):
+ """!Get prompt"""
+ return self.prompt
+
+ def GetValue(self):
+ """!Get value"""
+ return self.value
+
+ def GetActions(self, direction):
+ """!Get related actions
+
+ @param direction direction - 'from' or 'to'
+ """
+ return self.actions[direction]
+
+ def AddAction(self, action, direction):
+ """!Record related actions
+
+ @param action action to be recoreded
+ @param direction direction of relation
+ """
+ self.actions[direction].append(action)
+
+ def GetPropDialog(self):
+ """!Get properties dialog"""
+ return None
+
class ModelEvtHandler(ogl.ShapeEvtHandler):
"""!Model event handler class"""
def __init__(self, log, frame):
@@ -453,12 +582,12 @@
"""!Left mouse button pressed (double-click) -> show properties"""
shape = self.GetShape()
win = shape.GetPropDialog()
- if not win:
+ if isinstance(shape, ModelAction) and not win:
module = menuform.GUI().ParseCommand(shape.cmd,
completed = (self.frame.GetOptData, shape, None),
parentframe = self.frame, show = True)
- elif not win.IsShown():
+ elif win and not win.IsShown():
win.Show()
if win:
@@ -604,7 +733,7 @@
def _getDim(self, node):
"""!Get position and size of shape"""
pos = size = None
- posAttr = node.get('position', None)
+ posAttr = node.get('pos', None)
if posAttr:
posVal = map(int, posAttr.split(','))
try:
@@ -634,7 +763,7 @@
value = self._filterValue(self._getNodeText(param, 'value'))
action = data.find('action')
- aId = direction = None
+ aId = fromDir = None
if action is not None:
aId = int(action.get('id', None))
if action.get('dir', 'to') == 'to':
@@ -672,9 +801,101 @@
return cmd
class WriteModelFile:
- """!Write GRASS model file (gxm)"""
- pass
+ """!Generic class for writing model file"""
+ def __init__(self, fd, actions, data):
+ self.fd = fd
+ self.actions = actions
+ self.data = data
+
+ self.indent = 0
+
+ self._header()
+
+ self._actions()
+ self._data()
+
+ self._footer()
+ def _filterValue(self, value):
+ """!Make value XML-valid"""
+ value = value.replace('<', '<')
+ value = value.replace('>', '>')
+
+ return value
+
+ def _header(self):
+ """!Write header"""
+ self.fd.write('<?xml version="1.0" encoding="UTF-8"?>\n')
+ self.fd.write('<!DOCTYPE gxm SYSTEM "grass-gxm.dtd">\n')
+ self.fd.write('%s<gxm>\n' % (' ' * self.indent))
+
+ def _footer(self):
+ """!Write footer"""
+ self.fd.write('%s</gxm>\n' % (' ' * self.indent))
+
+ def _actions(self):
+ """!Write actions"""
+ id = 1
+ self.indent += 4
+ for action in self.actions:
+ self.fd.write('%s<action id="%d" name="%s" pos="%d,%d" size="%d,%d">\n' % \
+ (' ' * self.indent, id, action.GetName(), action.GetX(), action.GetY(),
+ action.GetWidth(), action.GetHeight()))
+ self.indent += 4
+ self.fd.write('%s<task name="%s">\n' % (' ' * self.indent, action.GetLog(string = False)[0]))
+ self.indent += 4
+ for key, val in action.GetParams().iteritems():
+ if key == 'flags':
+ for f in val:
+ if f.get('value', False):
+ self.fd.write('%s<flag name="%s" />\n' %
+ (' ' * self.indent, f.get('name', '')))
+ else: # parameter
+ for p in val:
+ if not p.get('value', ''):
+ continue
+ self.fd.write('%s<parameter name="%s">\n' %
+ (' ' * self.indent, p.get('name', '')))
+ self.indent += 4
+ self.fd.write('%s<value>%s</value>\n' %
+ (' ' * self.indent, self._filterValue(p.get('value', ''))))
+ self.indent -= 4
+ self.fd.write('%s</parameter>\n' % (' ' * self.indent))
+ self.indent -= 4
+ self.fd.write('%s</task>\n' % (' ' * self.indent))
+ self.indent -= 4
+ self.fd.write('%s</action>\n' % (' ' * self.indent))
+ id += 1
+
+ self.indent -= 4
+
+ def _data(self):
+ """!Write data"""
+ self.indent += 4
+ for data in self.data:
+ self.fd.write('%s<data pos="%d,%d" size="%d,%d">\n' % \
+ (' ' * self.indent, data.GetX(), data.GetY(),
+ data.GetWidth(), data.GetHeight()))
+ self.indent += 4
+ self.fd.write('%s<parameter name="%s" prompt="%s">\n' % \
+ (' ' * self.indent, data.GetName(), data.GetPrompt()))
+ self.indent += 4
+ self.fd.write('%s<value>%s</value>\n' %
+ (' ' * self.indent, self._filterValue(data.GetValue())))
+ self.indent -= 4
+ self.fd.write('%s</parameter>\n' % (' ' * self.indent))
+ self.indent -= 4
+ for action in data.GetActions('from'):
+ self.fd.write('%s<action id="1" dir="from" />\n' % \
+ (' ' * self.indent))
+ for action in data.GetActions('to'):
+ self.fd.write('%s<action id="1" dir="to" />\n' % \
+ (' ' * self.indent))
+
+ self.fd.write('%s</data>\n' % (' ' * self.indent))
+
+ self.indent -= 4
+
def main():
app = wx.PySimpleApp()
frame = ModelFrame(parent = None)
Modified: grass/branches/develbranch_6/gui/wxpython/gui_modules/menuform.py
===================================================================
--- grass/branches/develbranch_6/gui/wxpython/gui_modules/menuform.py 2010-03-30 13:17:53 UTC (rev 41623)
+++ grass/branches/develbranch_6/gui/wxpython/gui_modules/menuform.py 2010-03-30 13:20:03 UTC (rev 41624)
@@ -937,6 +937,8 @@
elif len(self.parent.GetPyData(self.layer)[0]['cmd']) < 1:
self.parent.Delete(self.layer)
self.Destroy()
+ elif self.parent and self.parent.GetName() == 'Modeler':
+ self.Hide()
else:
# cancel for non-display commands
self.Destroy()
Modified: grass/branches/develbranch_6/gui/wxpython/xml/menudata_modeler.xml
===================================================================
--- grass/branches/develbranch_6/gui/wxpython/xml/menudata_modeler.xml 2010-03-30 13:17:53 UTC (rev 41623)
+++ grass/branches/develbranch_6/gui/wxpython/xml/menudata_modeler.xml 2010-03-30 13:20:03 UTC (rev 41624)
@@ -28,10 +28,10 @@
</menuitem>
<separator />
<menuitem>
- <label>Close</label>
- <help>Close modeler</help>
+ <label>Close modeler</label>
+ <help>Close modeler window</help>
<handler>OnCloseWindow</handler>
- <shortcut>Ctrl+E</shortcut>
+ <shortcut>Ctrl+W</shortcut>
</menuitem>
</items>
</menu>
@@ -42,11 +42,13 @@
<label>Add data</label>
<help>Add data item to model</help>
<handler>OnAddData</handler>
+ <shortcut>Ctrl+D</shortcut>
</menuitem>
<menuitem>
<label>Add action</label>
<help>Add action (GRASS module) to model</help>
<handler>OnAddAction</handler>
+ <shortcut>Ctrl+A</shortcut>
</menuitem>
<menuitem>
<label>Remove item</label>
@@ -58,11 +60,13 @@
<label>Run model</label>
<help>Run entire model</help>
<handler>OnRunModel</handler>
+ <shortcut>Ctrl+R</shortcut>
</menuitem>
<menuitem>
<label>Validate model</label>
<help>Validate entire model</help>
<handler>OnValidateModel</handler>
+ <shortcut>Ctrl+V</shortcut>
</menuitem>
</items>
</menu>
More information about the grass-commit
mailing list