32
if __name__ == "__main__":
33
sys.path.append(os.path.join(os.getenv('GISBASE'), 'etc', 'wxpython'))
36
32
from wx.lib import ogl
37
33
import wx.lib.flatnotebook as FN
39
35
from core import globalvar
36
from core.utils import _
40
37
from gui_core.widgets import GNotebook
41
from gui_core.goutput import GMConsole, PyStc
38
from core.gconsole import GConsole, \
39
EVT_CMD_RUN, EVT_CMD_DONE, EVT_CMD_PREPARE
40
from gui_core.goutput import GConsoleWindow
42
41
from core.debug import Debug
43
42
from core.gcmd import GMessage, GException, GWarning, GError, RunCommand
44
43
from gui_core.dialogs import GetImageHandlers
44
from gui_core.ghelp import ShowAboutDialog
45
45
from gui_core.preferences import PreferencesBaseDialog
46
46
from core.settings import UserSettings
47
from core.menudata import MenuData
48
47
from gui_core.menu import Menu
49
from gmodeler.menudata import ModelerData
48
from gmodeler.menudata import ModelerMenuData
50
49
from gui_core.forms import GUI
51
50
from gmodeler.preferences import PreferencesDialog, PropertiesDialog
52
51
from gmodeler.toolbars import ModelerToolbar
52
from core.giface import Notification
53
from gui_core.pystc import PyStc
54
from gmodeler.giface import GraphicalModelerGrassInterface
54
55
from gmodeler.model import *
55
56
from gmodeler.dialogs import *
58
from grass.script.utils import try_remove
57
59
from grass.script import core as grass
59
61
class ModelFrame(wx.Frame):
60
def __init__(self, parent, id = wx.ID_ANY,
61
title = _("GRASS GIS Graphical Modeler (experimental prototype)"), **kwargs):
62
"""!Graphical modeler main window
62
def __init__(self, parent, giface, id = wx.ID_ANY,
63
title = _("GRASS GIS Graphical Modeler"), **kwargs):
64
"""Graphical modeler main window
64
@param parent parent window
66
@param title window title
66
:param parent: parent window
68
:param title: window title
68
@param kwargs wx.Frames' arguments
70
:param kwargs: wx.Frames' arguments
70
72
self.parent = parent
71
74
self.searchDialog = None # module search dialog
72
75
self.baseTitle = title
73
76
self.modelFile = None # loaded model
82
85
wx.Frame.__init__(self, parent = parent, id = id, title = title, **kwargs)
83
86
self.SetName("Modeler")
84
self.SetIcon(wx.Icon(os.path.join(globalvar.ETCICONDIR, 'grass.ico'), wx.BITMAP_TYPE_ICO))
86
self.menubar = Menu(parent = self, data = ModelerData())
87
self.SetIcon(wx.Icon(os.path.join(globalvar.ICONDIR, 'grass.ico'), wx.BITMAP_TYPE_ICO))
89
self.menubar = Menu(parent = self, model = ModelerMenuData().GetModel(separators=True))
88
90
self.SetMenuBar(self.menubar)
90
92
self.toolbar = ModelerToolbar(parent = self)
91
self.SetToolBar(self.toolbar)
93
# workaround for http://trac.wxwidgets.org/ticket/13888
94
if sys.platform != 'darwin':
95
self.SetToolBar(self.toolbar)
93
97
self.statusbar = self.CreateStatusBar(number = 1)
109
113
self.pythonPanel = PythonPanel(parent = self)
111
self.goutput = GMConsole(parent = self, notebook = self.notebook)
115
self._gconsole = GConsole(guiparent = self)
116
self.goutput = GConsoleWindow(parent = self, gconsole = self._gconsole)
117
self.goutput.showNotification.connect(lambda message: self.SetStatusText(message))
119
# here events are binded twice
120
self._gconsole.Bind(EVT_CMD_RUN,
121
lambda event: self._switchPageHandler(event=event, notification=Notification.MAKE_VISIBLE))
122
self._gconsole.Bind(EVT_CMD_DONE,
123
lambda event: self._switchPageHandler(event=event, notification=Notification.RAISE_WINDOW))
124
self.Bind(EVT_CMD_RUN, self.OnCmdRun)
125
self._gconsole.Bind(EVT_CMD_DONE, self.OnCmdDone) # rewrite default method to avoid hiding progress bar
126
self.Bind(EVT_CMD_PREPARE, self.OnCmdPrepare)
113
128
self.notebook.AddPage(page = self.canvas, text=_('Model'), name = 'model')
114
129
self.notebook.AddPage(page = self.itemPanel, text=_('Items'), name = 'items')
192
207
def OnVariables(self, event):
193
"""!Switch to variables page"""
208
"""Switch to variables page"""
194
209
self.notebook.SetSelectionByName('variables')
196
211
def OnRemoveItem(self, event):
199
214
self.GetCanvas().RemoveSelected()
201
216
def OnCanvasRefresh(self, event):
202
"""!Refresh canvas"""
203
218
self.SetStatusText(_("Redrawing model..."), 0)
204
219
self.GetCanvas().Refresh()
205
220
self.SetStatusText("", 0)
207
222
def OnCmdRun(self, event):
210
225
action = self.GetModel().GetItems()[event.pid]
211
226
if hasattr(action, "task"):
222
237
params = event.userData['params'])
224
239
def OnCmdDone(self, event):
225
"""!Command done (or aborted)"""
240
"""Command done (or aborted)"""
241
self.goutput.GetProgressBar().SetValue(0)
227
243
action = self.GetModel().GetItems()[event.pid]
228
244
if hasattr(action, "task"):
229
245
action.Update(running = True)
230
246
except IndexError:
233
249
def OnCloseWindow(self, event):
235
251
if self.modelChanged and \
236
252
UserSettings.Get(group='manager', key='askOnQuit', subkey='enabled'):
237
253
if self.modelFile:
267
283
def OnPreferences(self, event):
268
"""!Open preferences dialog"""
269
dlg = PreferencesDialog(parent = self)
284
"""Open preferences dialog"""
285
dlg = PreferencesDialog(parent = self, giface = self._giface)
270
286
dlg.CenterOnParent()
273
289
self.canvas.Refresh()
275
291
def OnHelp(self, event):
277
if self.parent and self.parent.GetName() == 'LayerManager':
278
log = self.parent.GetLogWindow()
279
log.RunCmd(['g.manual',
280
'entry=wxGUI.Modeler'])
282
RunCommand('g.manual',
284
entry = 'wxGUI.Modeler')
293
self._giface.Help(entry = 'wxGUI.gmodeler')
286
295
def OnModelProperties(self, event):
287
"""!Model properties dialog"""
296
"""Model properties dialog"""
288
297
dlg = PropertiesDialog(parent = self)
289
298
dlg.CentreOnParent()
290
299
properties = self.model.GetProperties()
320
self.goutput.RunCmd(['g.remove', 'rast=%s' %','.join(rast)])
329
self._gconsole.RunCmd(['g.remove', '-f', 'type=raster',
330
'name=%s' %','.join(rast)])
322
self.goutput.RunCmd(['g.remove', 'rast3d=%s' %','.join(rast3d)])
332
self._gconsole.RunCmd(['g.remove', '-f', 'type=raster_3d',
333
'name=%s' %','.join(rast3d)])
324
self.goutput.RunCmd(['g.remove', 'vect=%s' %','.join(vect)])
335
self._gconsole.RunCmd(['g.remove', '-f', 'type=vector',
336
'name=%s' %','.join(vect)])
326
338
self.SetStatusText(_("%d maps deleted from current mapset") % \
327
339
int(len(rast) + len(rast3d) + len(vect)))
365
377
self.modelChanged = False
366
378
self.SetTitle(self.baseTitle)
380
def GetModelFile(self, ext=True):
383
:param bool ext: False to avoid extension
385
if not self.modelFile:
388
return self.modelFile
389
return os.path.splitext(self.modelFile)[0]
368
391
def OnModelOpen(self, event):
369
"""!Load model from file"""
392
"""Load model from file"""
371
394
dlg = wx.FileDialog(parent = self, message=_("Choose model file"),
372
395
defaultDir = os.getcwd(),
477
500
self.canvas.Refresh()
479
502
def OnRunModel(self, event):
480
"""!Run entire model"""
481
self.model.Run(self.goutput, self.OnDone, parent = self)
503
"""Run entire model"""
504
self.model.Run(self._gconsole, self.OnDone, parent = self)
483
506
def OnDone(self, cmd, returncode):
484
"""!Computation finished"""
507
"""Computation finished
510
not called -- must be fixed
485
512
self.SetStatusText('', 0)
486
513
# restore original files
487
514
if hasattr(self.model, "fileInput"):
582
609
def OnExportPython(self, event = None, text = None):
583
"""!Export model to Python script"""
610
"""Export model to Python script"""
584
611
filename = self.pythonPanel.SaveAs(force = True)
585
612
self.SetStatusText(_("Model exported to <%s>") % filename)
587
614
def OnDefineRelation(self, event):
588
"""!Define relation between data and action items"""
615
"""Define relation between data and action items"""
589
616
self.canvas.SetCursor(self.cursors["cross"])
590
617
self.defineRelation = { 'from' : None,
593
620
def OnDefineLoop(self, event):
594
"""!Define new loop in the model"""
621
"""Define new loop in the model
595
626
self.ModelChanged()
597
628
width, height = self.canvas.GetSize()
640
675
# add action to canvas
641
676
x, y = self.canvas.GetNewShapePos()
677
label, comment = self.searchDialog.GetLabel()
642
678
action = ModelAction(self.model, cmd = cmd,
643
679
x = x + self._randomShift(),
644
680
y = y + self._randomShift(),
645
id = self.model.GetNextId())
681
id = self.model.GetNextId(), label = label, comment = comment)
646
682
overwrite = self.model.GetProperties().get('overwrite', None)
647
683
if overwrite is not None:
648
684
action.GetTask().set_flag('overwrite', overwrite)
660
696
# show properties dialog
661
697
win = action.GetPropDialog()
699
cmdLength = len(action.GetLog(string=False))
700
if cmdLength > 1 and action.IsValid():
664
701
self.GetOptData(dcmd = action.GetLog(string = False), layer = action,
665
702
params = action.GetParams(), propwin = None)
667
GUI(parent = self, show = True).ParseCommand(action.GetLog(string = False),
668
completed = (self.GetOptData, action, action.GetParams()))
704
gmodule = GUI(parent = self, show = True,
705
giface = GraphicalModelerGrassInterface(self.model))
706
gmodule.ParseCommand(action.GetLog(string = False),
707
completed = (self.GetOptData, action, action.GetParams()))
669
708
elif win and not win.IsShown():
698
737
self.model.AddItem(data)
700
739
self.canvas.Refresh()
703
def OnHelp(self, event):
704
"""!Display manual page"""
705
grass.run_command('g.manual',
706
entry = 'wxGUI.Modeler')
741
def OnAddComment(self, event):
742
"""Add comment to the model"""
743
dlg = wx.TextEntryDialog(parent = self, message = _("Comment:"), caption = _("Add comment"),
744
style = wx.OK | wx.CANCEL | wx.CENTRE | wx.TE_MULTILINE)
745
if dlg.ShowModal() == wx.ID_OK:
746
comment = dlg.GetValue()
748
GError(_("Empty comment. Nothing to add to the model."), parent = self)
750
x, y = self.canvas.GetNewShapePos()
751
commentObj = ModelComment(self.model, x = x + self._randomShift(), y = y + self._randomShift(),
752
id = self.model.GetNextId(), label = comment)
753
self.canvas.diagram.AddShape(commentObj)
754
commentObj.Show(True)
755
self._addEvent(commentObj)
756
self.model.AddItem(commentObj)
758
self.canvas.Refresh()
763
def _switchPageHandler(self, event, notification):
764
self._switchPage(notification=notification)
767
def _switchPage(self, notification):
768
"""Manages @c 'output' notebook page according to event notification."""
769
if notification == Notification.HIGHLIGHT:
770
self.notebook.HighlightPageByName('output')
771
if notification == Notification.MAKE_VISIBLE:
772
self.notebook.SetSelectionByName('output')
773
if notification == Notification.RAISE_WINDOW:
774
self.notebook.SetSelectionByName('output')
708
778
def OnAbout(self, event):
709
"""!Display About window"""
710
info = wx.AboutDialogInfo()
712
info.SetIcon(wx.Icon(os.path.join(globalvar.ETCICONDIR, 'grass.ico'), wx.BITMAP_TYPE_ICO))
713
info.SetName(_('wxGUI Graphical Modeler'))
714
info.SetWebSite('http://grass.osgeo.org')
715
year = grass.version()['date']
716
info.SetDescription(_('(C) 2010-%s by the GRASS Development Team\n\n') % year +
717
'\n'.join(textwrap.wrap(_('This program is free software under the GNU General Public License'
718
'(>=v2). Read the file COPYING that comes with GRASS for details.'), 75)))
779
"""Display About window"""
780
ShowAboutDialog(prgName=_('wxGUI Graphical Modeler'), startYear='2010')
722
782
def GetOptData(self, dcmd, layer, params, propwin):
723
"""!Process action data"""
783
"""Process action data"""
724
784
if params: # add data items
725
785
width, height = self.canvas.GetSize()
726
786
x = width/2 - 200 + self._randomShift()
727
787
y = height/2 + self._randomShift()
728
788
for p in params['params']:
729
if p.get('prompt', '') in ('raster', 'vector', 'raster3d') and \
789
if p.get('prompt', '') in ('raster', 'vector', 'raster_3d') and \
730
790
(p.get('value', None) or \
731
791
(p.get('age', 'old') != 'old' and p.get('required', 'no') == 'yes')):
732
792
data = layer.FindData(p.get('name', ''))
808
868
def LoadModelFile(self, filename):
809
"""!Load model definition stored in GRASS Model XML file (gxm)
869
"""Load model definition stored in GRASS Model XML file (gxm)
812
872
self.model.LoadModel(filename)
813
except GException, e:
873
except GException as e:
814
874
GError(parent = self,
815
875
message = _("Reading model file <%s> failed.\n"
816
"Invalid file, unable to parse XML document.") % filename)
876
"Invalid file, unable to parse XML document.\n\n%s") % \
878
showTraceback = False)
818
881
self.modelFile = filename
819
882
self.SetTitle(self.baseTitle + " - " + os.path.basename(self.modelFile))
942
1011
self.canvas.Refresh()
944
1013
def DefineCondition(self, condition):
945
"""!Define if-else statement with given list of items"""
1014
"""Define if-else statement with given list of items"""
1015
items = condition.GetItems(self.model.GetItems(objType=ModelAction))
1016
if not items['if'] and not items['else']:
946
1019
parent = condition
947
items = condition.GetItems()
948
if not items['if'] and not items['else']:
951
1021
# remove defined relations first
952
1022
for rel in condition.GetRelations():
986
1056
self.SetScrollbars(20, 20, 2000/20, 2000/20)
988
self.Bind(wx.EVT_CHAR, self.OnChar)
990
def OnChar(self, event):
1058
self.Bind(wx.EVT_KEY_UP, self.OnKeyUp)
1059
self.Bind(wx.EVT_LEFT_DOWN, self.OnLeftDown)
1061
def OnKeyUp(self, event):
992
1063
kc = event.GetKeyCode()
993
diagram = self.GetDiagram()
994
1064
if kc == wx.WXK_DELETE:
995
1065
self.RemoveSelected()
1067
def OnLeftDown(self, evt):
997
1071
def RemoveSelected(self):
998
"""!Remove selected shapes"""
1072
"""Remove selected shapes"""
999
1073
self.parent.ModelChanged()
1001
1075
diagram = self.GetDiagram()
1035
1109
yNew += yBox * 3
1037
1111
return xNew, yNew
1113
def GetShapesSelected(self):
1114
"""Get list of selected shapes"""
1116
diagram = self.GetDiagram()
1117
for shape in diagram.GetShapeList():
1118
if shape.Selected():
1119
selected.append(shape)
1039
1123
class ModelEvtHandler(ogl.ShapeEvtHandler):
1040
"""!Model event handler class"""
1124
"""Model event handler class"""
1041
1125
def __init__(self, log, frame):
1042
1126
ogl.ShapeEvtHandler.__init__(self)
1087
1172
self.log.SetStatusText('', 0)
1089
1174
def OnLeftDoubleClick(self, x, y, keys = 0, attachment = 0):
1090
"""!Left mouse button pressed (double-click) -> show properties"""
1175
"""Left mouse button pressed (double-click) -> show properties"""
1091
1176
self.OnProperties()
1093
1178
def OnProperties(self, event = None):
1094
"""!Show properties dialog"""
1179
"""Show properties dialog"""
1095
1180
self.frame.ModelChanged()
1096
1181
shape = self.GetShape()
1097
1182
if isinstance(shape, ModelAction):
1098
module = GUI(parent = self.frame, show = True).ParseCommand(shape.GetLog(string = False),
1099
completed = (self.frame.GetOptData, shape, shape.GetParams()))
1183
gmodule = GUI(parent = self.frame, show = True,
1184
giface = GraphicalModelerGrassInterface(self.frame.GetModel()))
1185
gmodule.ParseCommand(shape.GetLog(string = False),
1186
completed = (self.frame.GetOptData, shape, shape.GetParams()))
1101
1188
elif isinstance(shape, ModelData):
1102
1189
dlg = ModelDataDialog(parent = self.frame, shape = shape)
1108
1195
dlg = ModelLoopDialog(parent = self.frame, shape = shape)
1109
1196
dlg.CentreOnParent()
1110
1197
if dlg.ShowModal() == wx.ID_OK:
1111
shape.SetText(dlg.GetCondition())
1198
shape.SetLabel(dlg.GetCondition())
1199
model = self.frame.GetModel()
1200
ids = dlg.GetItems()
1113
ids = dlg.GetItems()
1114
1202
for aId in ids['unchecked']:
1115
action = self.frame.GetModel().GetItem(aId)
1116
action.UnSetBlock(shape)
1203
action = model.GetItem(aId, objType=ModelAction)
1205
action.UnSetBlock(shape)
1117
1206
for aId in ids['checked']:
1118
action = self.frame.GetModel().GetItem(aId)
1119
action.SetBlock(shape)
1207
action = model.GetItem(aId, objType=ModelAction)
1121
alist.append(action)
1209
action.SetBlock(shape)
1122
1211
shape.SetItems(alist)
1123
1212
self.frame.DefineLoop(shape)
1124
1213
self.frame.SetStatusText(shape.GetLog(), 0)
1130
1219
dlg = ModelConditionDialog(parent = self.frame, shape = shape)
1131
1220
dlg.CentreOnParent()
1132
1221
if dlg.ShowModal() == wx.ID_OK:
1133
shape.SetText(dlg.GetCondition())
1222
shape.SetLabel(dlg.GetCondition())
1223
model = self.frame.GetModel()
1134
1224
ids = dlg.GetItems()
1135
1225
for b in ids.keys():
1137
1227
for aId in ids[b]['unchecked']:
1138
action = self.frame.GetModel().GetItem(aId)
1228
action = model.GetItem(aId, objType=ModelAction)
1139
1229
action.UnSetBlock(shape)
1140
1230
for aId in ids[b]['checked']:
1141
action = self.frame.GetModel().GetItem(aId)
1231
action = model.GetItem(aId, objType=ModelAction)
1142
1232
action.SetBlock(shape)
1144
alist.append(action)
1145
1235
shape.SetItems(alist, branch = b)
1146
1236
self.frame.DefineCondition(shape)
1147
1237
self.frame.GetCanvas().Refresh()
1151
1241
def OnBeginDragLeft(self, x, y, keys = 0, attachment = 0):
1152
"""!Drag shape (begining)"""
1242
"""Drag shape (begining)"""
1153
1243
self.frame.ModelChanged()
1154
1244
if self._previousHandler:
1155
1245
self._previousHandler.OnBeginDragLeft(x, y, keys, attachment)
1157
1247
def OnEndDragLeft(self, x, y, keys = 0, attachment = 0):
1158
"""!Drag shape (end)"""
1248
"""Drag shape (end)"""
1159
1249
if self._previousHandler:
1160
1250
self._previousHandler.OnEndDragLeft(x, y, keys, attachment)
1170
1260
self.frame.DefineLoop(mo)
1171
1261
elif isinstance(mo, ModelCondition):
1172
1262
self.frame.DefineCondition(mo)
1264
shape = self.GetShape()
1265
canvas = shape.GetCanvas()
1174
1268
def OnEndSize(self, x, y):
1176
1270
self.frame.ModelChanged()
1177
1271
if self._previousHandler:
1178
1272
self._previousHandler.OnEndSize(x, y)
1180
1274
def OnRightClick(self, x, y, keys = 0, attachment = 0):
1181
"""!Right click -> pop-up menu"""
1275
"""Right click -> pop-up menu"""
1182
1276
if not hasattr (self, "popupID"):
1183
1277
self.popupID = dict()
1184
1278
for key in ('remove', 'enable', 'addPoint',
1185
'delPoint', 'intermediate', 'props', 'id'):
1279
'delPoint', 'intermediate', 'props', 'id',
1280
'label', 'comment'):
1186
1281
self.popupID[key] = wx.NewId()
1188
1283
# record coordinates
1204
1299
popupMenu.Append(self.popupID['enable'], text=_('Enable'))
1205
1300
self.frame.Bind(wx.EVT_MENU, self.OnEnable, id = self.popupID['enable'])
1301
if isinstance(shape, ModelAction) or isinstance(shape, ModelComment):
1302
popupMenu.AppendSeparator()
1303
if isinstance(shape, ModelAction):
1304
popupMenu.Append(self.popupID['label'], text=_('Set label'))
1305
self.frame.Bind(wx.EVT_MENU, self.OnSetLabel, id = self.popupID['label'])
1306
if isinstance(shape, ModelAction) or isinstance(shape, ModelComment):
1307
popupMenu.Append(self.popupID['comment'], text=_('Set comment'))
1308
self.frame.Bind(wx.EVT_MENU, self.OnSetComment, id = self.popupID['comment'])
1207
1310
if isinstance(shape, ModelRelation):
1208
1311
popupMenu.AppendSeparator()
1209
1312
popupMenu.Append(self.popupID['addPoint'], text=_('Add control point'))
1245
1348
shape.Enable(enable)
1246
1349
self.frame.ModelChanged()
1247
1350
self.frame.canvas.Refresh()
1249
def _onSelectShape(self, shape):
1352
def OnSetLabel(self, event):
1353
shape = self.GetShape()
1354
dlg = wx.TextEntryDialog(parent = self.frame, message = _("Label:"), caption = _("Set label"),
1355
defaultValue = shape.GetLabel())
1356
if dlg.ShowModal() == wx.ID_OK:
1357
label = dlg.GetValue()
1358
shape.SetLabel(label)
1359
self.frame.ModelChanged()
1360
self.frame.itemPanel.Update()
1361
self.frame.canvas.Refresh()
1364
def OnSetComment(self, event):
1365
shape = self.GetShape()
1366
dlg = wx.TextEntryDialog(parent = self.frame, message = _("Comment:"), caption = _("Set comment"),
1367
defaultValue = shape.GetComment(), style = wx.OK | wx.CANCEL | wx.CENTRE | wx.TE_MULTILINE)
1368
if dlg.ShowModal() == wx.ID_OK:
1369
comment = dlg.GetValue()
1370
shape.SetComment(comment)
1371
self.frame.ModelChanged()
1374
def _onSelectShape(self, shape, append=False):
1250
1375
canvas = shape.GetCanvas()
1251
1376
dc = wx.ClientDC(canvas)
1287
1413
self.frame.canvas.Refresh()
1289
1415
def OnIntermediate(self, event):
1290
"""!Mark data as intermediate"""
1416
"""Mark data as intermediate"""
1291
1417
self.frame.ModelChanged()
1292
1418
shape = self.GetShape()
1293
1419
shape.SetIntermediate(event.IsChecked())
1294
1420
self.frame.canvas.Refresh()
1296
1422
def OnRemove(self, event):
1299
1425
self.frame.GetCanvas().RemoveShapes([self.GetShape()])
1300
1426
self.frame.itemPanel.Update()
1302
1428
class VariablePanel(wx.Panel):
1303
1429
def __init__(self, parent, id = wx.ID_ANY,
1305
"""!Manage model variables panel
1431
"""Manage model variables panel
1307
1433
self.parent = parent
1436
1564
self.parent.ModelChanged()
1438
1566
def Update(self):
1439
"""!Reload list of variables"""
1567
"""Reload list of variables"""
1440
1568
self.list.OnReload(None)
1442
1570
def Reset(self):
1443
"""!Remove all variables"""
1571
"""Remove all variables"""
1444
1572
self.list.DeleteAllItems()
1445
1573
self.parent.GetModel().SetVariables([])
1447
1575
class ItemPanel(wx.Panel):
1448
1576
def __init__(self, parent, id = wx.ID_ANY,
1450
"""!Manage model items
1578
"""Manage model items
1452
1580
self.parent = parent
1457
1585
label=" %s " % _("List of items - right-click to delete"))
1459
1587
self.list = ItemListCtrl(parent = self,
1460
columns = [_("ID"), _("Name"), _("In block"),
1461
_("Command / Condition")])
1588
columns = [_("Label"), _("In loop"),
1590
columnsNotEditable = [1, 2],
1591
frame = self.parent)
1593
self.btnMoveUp = wx.Button(parent=self, id=wx.ID_UP)
1594
self.btnMoveDown = wx.Button(parent=self, id=wx.ID_DOWN)
1596
self.btnMoveUp.Bind(wx.EVT_BUTTON, self.OnMoveItemsUp)
1597
self.btnMoveDown.Bind(wx.EVT_BUTTON, self.OnMoveItemsDown)
1465
1601
def _layout(self):
1466
"""!Layout dialog"""
1467
1603
listSizer = wx.StaticBoxSizer(self.listBox, wx.VERTICAL)
1468
1604
listSizer.Add(item = self.list, proportion = 1,
1469
1605
flag = wx.EXPAND)
1471
mainSizer = wx.BoxSizer(wx.VERTICAL)
1607
manageSizer = wx.BoxSizer(wx.VERTICAL)
1608
manageSizer.Add(item=self.btnMoveUp, border = 5, flag = wx.ALL)
1609
manageSizer.Add(item=self.btnMoveDown, border = 5,
1610
flag = wx.LEFT | wx.RIGHT)
1612
mainSizer = wx.BoxSizer(wx.HORIZONTAL)
1472
1613
mainSizer.Add(item = listSizer, proportion = 1,
1473
flag = wx.EXPAND | wx.ALL | wx.ALIGN_CENTER, border = 5)
1614
flag = wx.EXPAND | wx.ALL | wx.ALIGN_CENTER, border = 3)
1615
mainSizer.Add(item = manageSizer, proportion = 0,
1616
flag = wx.EXPAND | wx.ALL | wx.ALIGN_CENTER, border = 3)
1475
1618
self.SetSizer(mainSizer)
1476
1619
mainSizer.Fit(self)
1478
1621
def Update(self):
1479
"""!Reload list of variables"""
1622
"""Reload list of variables"""
1480
1623
self.list.OnReload(None)
1625
def _getSelectedItems(self):
1626
"""Get list of selected items, indeces start at 0"""
1630
next = self.list.GetNextSelected(current)
1637
GMessage(_("No items to selected."), parent = self)
1641
def OnMoveItemsUp(self, event):
1642
"""Item moved up, update action ids"""
1643
items = self._getSelectedItems()
1646
self.list.MoveItems(items, up = True)
1647
self.parent.GetCanvas().Refresh()
1648
self.parent.ModelChanged()
1650
def OnMoveItemsDown(self, event):
1651
"""Item moved up, update action ids"""
1652
items = self._getSelectedItems()
1655
self.list.MoveItems(items, up = False)
1656
self.parent.GetCanvas().Refresh()
1657
self.parent.ModelChanged()
1482
1659
class PythonPanel(wx.Panel):
1483
1660
def __init__(self, parent, id = wx.ID_ANY,
1485
"""!Model as python script
1662
"""Model as python script
1487
1664
self.parent = parent
1547
1724
mode = stat.S_IMODE(os.lstat(self.filename)[stat.ST_MODE])
1548
1725
os.chmod(self.filename, mode | stat.S_IXUSR)
1550
self.parent.goutput.RunCmd([fd.name], switchPage = True,
1551
skipInterface = True, onDone = self.OnDone)
1727
self.parent._gconsole.RunCmd([fd.name], skipInterface=True, onDone=self.OnDone)
1555
1731
def OnDone(self, cmd, returncode):
1556
"""!Python script finished"""
1557
grass.try_remove(self.filename)
1732
"""Python script finished"""
1733
try_remove(self.filename)
1558
1734
self.filename = None
1560
1736
def SaveAs(self, force = False):
1561
"""!Save python script to file
1737
"""Save python script to file
1566
1742
dlg = wx.FileDialog(parent = self,
1567
1743
message = _("Choose file to save"),
1744
defaultFile = self.parent.GetModelFile(ext=False) + '.py',
1568
1745
defaultDir = os.getcwd(),
1569
1746
wildcard = _("Python script (*.py)|*.py"),
1570
1747
style = wx.FD_SAVE)
1641
1818
def OnRefresh(self, event):
1642
"""!Refresh Python script"""
1819
"""Refresh Python script"""
1643
1820
if self.RefreshScript():
1644
1821
self.parent.SetStatusText(_('Python script is up-to-date'), 0)
1647
1824
def IsModified(self):
1648
"""!Check if python script has been modified"""
1825
"""Check if python script has been modified"""
1649
1826
return self.body.modified
1651
1828
def IsEmpty(self):
1652
"""!Check if python script is empty"""
1829
"""Check if python script is empty"""
1653
1830
return len(self.body.GetText()) == 0
1657
gettext.install('grasswxpy', os.path.join(os.getenv("GISBASE"), 'locale'), unicode = True)
1659
app = wx.PySimpleApp()
1660
if not globalvar.CheckWxVersion([2, 9]):
1661
wx.InitAllImageHandlers()
1662
frame = ModelFrame(parent = None)
1663
if len(sys.argv) > 1:
1664
frame.LoadModelFile(sys.argv[1])
1669
if __name__ == "__main__":