diff --git a/gui/wxpython/gmodeler/canvas.py b/gui/wxpython/gmodeler/canvas.py index 830e9983ccd..59e3b02adee 100644 --- a/gui/wxpython/gmodeler/canvas.py +++ b/gui/wxpython/gmodeler/canvas.py @@ -482,19 +482,29 @@ def OnHasDisplay(self, event): shape.SetHasDisplay(event.IsChecked()) self.frame.canvas.Refresh() + model = self.frame.GetModel() + run_params = getattr(model, "_runParams", None) + resolved = {} + if run_params and "variables" in run_params: + for p in run_params["variables"]["params"]: + name = p.get("name", "") + value = p.get("value", "") + if name and value: + resolved[name] = value + try: if event.IsChecked(): # add map layer to display self.frame._giface.GetLayerList().AddLayer( ltype=shape.GetPrompt(), - name=shape.GetValue(), + name=shape.GetResolvedValue(resolved), checked=True, - cmd=shape.GetDisplayCmd(), + cmd=shape.GetDisplayCmd(resolved), ) else: # remove map layer(s) from display layers = self.frame._giface.GetLayerList().GetLayersByName( - shape.GetValue() + shape.GetResolvedValue(resolved) ) for layer in layers: self.frame._giface.GetLayerList().DeleteLayer(layer) diff --git a/gui/wxpython/gmodeler/model.py b/gui/wxpython/gmodeler/model.py index 1d75f3869df..c43cff582c1 100644 --- a/gui/wxpython/gmodeler/model.py +++ b/gui/wxpython/gmodeler/model.py @@ -486,7 +486,8 @@ def Validate(self): sval = pattern.search(value) if not sval: continue - var = sval.group(2).strip()[2:-1] # strip '%{...}' + s = sval.group(2).strip() + var = s[2:-1] if s.startswith("%{") else s[1:] # strip curly braces only if present found = False for v in variables: if var.startswith(v): @@ -539,7 +540,8 @@ def _substituteFile(self, item, params=None, checkOnly=False): write = False variables = self.GetVariables() for variable in variables: - pattern = re.compile("%{" + variable + "}") + # curly braces are optional + pattern = re.compile(r"%(?:\{" + variable + r"\}|" + variable + r")") value = "" if params and "variables" in params: for p in params["variables"]["params"]: @@ -560,7 +562,8 @@ def _substituteFile(self, item, params=None, checkOnly=False): pattern = re.compile(r"(.*)(%\{.+})(.*)") sval = pattern.search(data) if sval: - var = sval.group(2).strip()[2:-1] # ignore '%{...}' + s = sval.group(2).strip() + var = s[2:-1] if s.startswith("%{") else s[1:] # strip curly braces only if present cmd = item.GetLog(string=False)[0] errList.append(cmd + ": " + _("undefined variable '%s'") % var) @@ -690,7 +693,8 @@ def Run(self, log, onDone, parent=None): # substitute variables in condition variables = self.GetVariables() for variable in variables: - pattern = re.compile("%{" + variable + "}") + # curly braces are optional + pattern = re.compile(r"%(?:\{" + variable + r"\}|" + variable + r")") if not pattern.search(cond): continue value = "" @@ -713,7 +717,8 @@ def Run(self, log, onDone, parent=None): # split condition # TODO: this part needs some better solution condVar, condText = (x.strip() for x in re.split(r"\s* in \s*", cond)) - pattern = re.compile("%{" + condVar + "}") + # curly braces are optional + pattern = re.compile(r"%(?:\{" + condVar + r"\}|" + condVar + r")") # for vars()[condVar] in eval(condText): ? vlist = [] if condText[0] == "`" and condText[-1] == "`": @@ -742,12 +747,9 @@ def Run(self, log, onDone, parent=None): if delInterData: self.DeleteIntermediateData(log) - - # discard values - if params: - for item in params.values(): - for p in item["params"]: - p["value"] = "" + + # store run params + self._runParams = params def DeleteIntermediateData(self, log): """Delete intermediate data""" diff --git a/gui/wxpython/gmodeler/model_convert.py b/gui/wxpython/gmodeler/model_convert.py index ab9f6885eb2..07735a1b0ee 100644 --- a/gui/wxpython/gmodeler/model_convert.py +++ b/gui/wxpython/gmodeler/model_convert.py @@ -56,7 +56,8 @@ def _writeItem(self, item, ignoreBlock=True, variables={}): # substitute condition cond = item.GetLabel() for variable in self.model.GetVariables(): - pattern = re.compile("%{" + variable + "}") + # curly braces are optional + pattern = re.compile(r"%(?:\{" + variable + r"\}|" + variable + r")") if pattern.search(cond): value = variables[variable].get("value", "") if variables[variable].get("type", "string") == "string": @@ -969,14 +970,15 @@ def _substitutePythonParamValue( # check for variables formattedVar = False for var in variables["vars"]: - pattern = re.compile("%{" + var + "}") - found = pattern.search(value) + # curly braces are optional + pattern = re.compile(r"%(?:\{" + var + r"\}|" + var + r")") + found = pattern.search(parameterizedValue) if found: foundVar = True if found.end() != len(value): formattedVar = True parameterizedValue = pattern.sub( - "{options['" + var + "']}", value + "{options['" + var + "']}", parameterizedValue ) else: parameterizedValue = f'options["{var}"]' diff --git a/gui/wxpython/gmodeler/model_items.py b/gui/wxpython/gmodeler/model_items.py index c866817ea55..3dfb963e36d 100644 --- a/gui/wxpython/gmodeler/model_items.py +++ b/gui/wxpython/gmodeler/model_items.py @@ -347,7 +347,8 @@ def GetLog(self, string=True, substitute=None): # order variables by length for variable in sorted(variables, key=len, reverse=True): - pattern = re.compile("%{" + variable + "}") + # curly braces are optional + pattern = re.compile(r"%(?:\{" + variable + r"\}|" + variable + r")") value = "" if substitute and "variables" in substitute: for p in substitute["variables"]["params"]: @@ -678,8 +679,30 @@ def Update(self): self._setPen() self.SetLabel() - def GetDisplayCmd(self): - """Get display command as list""" + def GetResolvedValue(self, resolved=None): + """Get value with model substituted variables + + :param resolved: dict mapping variable name to resolved value, + or None to return the raw value + """ + if not resolved: + return self.value + value = self.value + + # find the variable in resolved + for variable, var_value in resolved.items(): + pattern = re.compile(r"%(?:\{" + variable + r"\}|" + variable + r")") + value = pattern.sub(var_value, value) + + # return substituted value + return value + + def GetDisplayCmd(self, resolved=None): + """Get display command as list + + :param resolved: dict mapping variable name to resolved value, + or None to return the raw value + """ cmd = [] if self.prompt == "raster": cmd.append("d.rast") @@ -689,7 +712,7 @@ def GetDisplayCmd(self): msg = "Unsupported display prompt: {}".format(self.prompt) raise GException(msg) - cmd.append("map=" + self.value) + cmd.append("map=" + self.GetResolvedValue(resolved)) return cmd diff --git a/gui/wxpython/gmodeler/panels.py b/gui/wxpython/gmodeler/panels.py index 506f6169305..6dd12dd0ca6 100644 --- a/gui/wxpython/gmodeler/panels.py +++ b/gui/wxpython/gmodeler/panels.py @@ -408,13 +408,23 @@ def OnModelDone(self, event): # delete intermediate data self._deleteIntermediateData() + # store resolved variables + run_params = getattr(self.model, "_runParams", None) + resolved = {} + if run_params and "variables" in run_params: + for p in run_params["variables"]["params"]: + name = p.get("name", "") + value = p.get("value", "") + if name and value: + resolved[name] = value + # display data if required for data in self.model.GetData(): if not data.HasDisplay(): continue # remove existing map layers first - layers = self._giface.GetLayerList().GetLayersByName(data.GetValue()) + layers = self._giface.GetLayerList().GetLayersByName(data.GetResolvedValue(resolved)) if layers: for layer in layers: self._giface.GetLayerList().DeleteLayer(layer) @@ -422,10 +432,17 @@ def OnModelDone(self, event): # add new map layer self._giface.GetLayerList().AddLayer( ltype=data.GetPrompt(), - name=data.GetValue(), + name=data.GetResolvedValue(resolved), checked=True, - cmd=data.GetDisplayCmd(), + cmd=data.GetDisplayCmd(resolved), ) + + # discard values + if run_params: + for item in run_params.values(): + for p in item["params"]: + p["value"] = "" + del self.model._runParams def _switchPageHandler(self, event, notification): self._switchPage(notification=notification) @@ -1801,6 +1818,36 @@ def OnDone(self, event): try_remove(self.filename) self.filename = None + # store resolved variables + model = self.parent.GetModel() + run_params = getattr(model, "_runParams", None) + resolved = {} + if run_params and "variables" in run_params: + for p in run_params["variables"]["params"]: + name = p.get("name", "") + value = p.get("value", "") + if name and value: + resolved[name] = value + + # display data if required + for data in model.GetData(): + if not data.HasDisplay(): + continue + + # remove existing map layers first + layers = self.parent._giface.GetLayerList().GetLayersByName(data.GetResolvedValue(resolved)) + if layers: + for layer in layers: + self.parent._giface.GetLayerList().DeleteLayer(layer) + + # add new map layer + self.parent._giface.GetLayerList().AddLayer( + ltype=data.GetPrompt(), + name=data.GetResolvedValue(resolved), + checked=True, + cmd=data.GetDisplayCmd(resolved), + ) + def OnChangeScriptType(self, event): new_script_type = self.script_type_box.GetStringSelection()