From 94c0a1c776b4821d82f81e55e50cabf612c4f31d Mon Sep 17 00:00:00 2001 From: "mathias.chouet" <mathias.chouet@irstea.fr> Date: Tue, 11 Feb 2020 10:56:18 +0100 Subject: [PATCH 1/2] Fix #363 enhanced Solveur --- jalhyd_branch | 2 +- src/app/calculators/solveur/config.json | 9 ++ src/app/calculators/solveur/en.json | 1 + src/app/calculators/solveur/fr.json | 1 + src/app/formulaire/definition/form-solveur.ts | 83 +++++++++++++++---- src/app/formulaire/elements/fieldset.ts | 2 +- .../formulaire/elements/select-field-nub.ts | 22 +++-- .../elements/select-field-parameter.ts | 8 +- .../elements/select-field-reference.ts | 12 +-- src/app/formulaire/elements/select-field.ts | 43 ++++++++-- 10 files changed, 143 insertions(+), 40 deletions(-) diff --git a/jalhyd_branch b/jalhyd_branch index feb22275f..b2cd21bbf 100644 --- a/jalhyd_branch +++ b/jalhyd_branch @@ -1 +1 @@ -197-mise-a-jour-vers-typescript-3-7 +188-solveur-pouvoir-cibler-un-resultat-complementaire-eventuellement-sur-un-seul-nub diff --git a/src/app/calculators/solveur/config.json b/src/app/calculators/solveur/config.json index 40b0bbb8c..fa1da444f 100644 --- a/src/app/calculators/solveur/config.json +++ b/src/app/calculators/solveur/config.json @@ -9,6 +9,13 @@ "reference": "nub", "source": "solveur_target" }, + { + "id": "select_target_result", + "type": "select", + "property": "targettedResult", + "source": "solveur_targetted_result", + "default": "" + }, "Ytarget" ] }, @@ -27,7 +34,9 @@ }, { "type": "options", + "selectIds": [ "select_target_result" ], "targetNubSelectId": "select_target_nub", + "targettedResultSelectId": "select_target_result", "searchedParamSelectId": "select_searched_param", "_help": "solveur.html" } diff --git a/src/app/calculators/solveur/en.json b/src/app/calculators/solveur/en.json index df14b3764..a8e5ea027 100644 --- a/src/app/calculators/solveur/en.json +++ b/src/app/calculators/solveur/en.json @@ -7,5 +7,6 @@ "X": "Value for searched parameter", "select_target_nub": "Module and parameter to calculate", + "select_target_result": "Targetted result", "select_searched_param": "Searched parameter" } \ No newline at end of file diff --git a/src/app/calculators/solveur/fr.json b/src/app/calculators/solveur/fr.json index 1439bd8da..9c2c639bb 100644 --- a/src/app/calculators/solveur/fr.json +++ b/src/app/calculators/solveur/fr.json @@ -7,5 +7,6 @@ "X": "Valeur du paramètre recherché", "select_target_nub": "Module et paramètre à calculer", + "select_target_result": "Résultat ciblé", "select_searched_param": "Paramètre recherché" } \ No newline at end of file diff --git a/src/app/formulaire/definition/form-solveur.ts b/src/app/formulaire/definition/form-solveur.ts index 2057ce084..b6987a5d5 100644 --- a/src/app/formulaire/definition/form-solveur.ts +++ b/src/app/formulaire/definition/form-solveur.ts @@ -1,9 +1,11 @@ -import { IObservable, ParamDefinition } from "jalhyd"; +import { IObservable, ParamDefinition, Nub } from "jalhyd"; import { SelectFieldNub } from "../elements/select-field-nub"; import { SelectFieldParameter } from "../elements/select-field-parameter"; import { NgParameter } from "../elements/ngparam"; import { FormulaireFixedVar } from "./form-fixedvar"; +import { SelectField } from "../elements/select-field"; +import { FieldSet } from "../elements/fieldset"; /** * Formulaire pour les Solveurs @@ -13,31 +15,49 @@ export class FormulaireSolveur extends FormulaireFixedVar { /** id of select configuring target Nub */ private _targetNubSelectId: string; + /** id of select configuring targetted result */ + private _targettedResultSelectId: string; + /** id of select configuring searched param */ private _searchedParamSelectId: string; protected parseOptions(json: {}) { super.parseOptions(json); this._targetNubSelectId = this.getOption(json, "targetNubSelectId"); + this._targettedResultSelectId = this.getOption(json, "targettedResultSelectId"); this._searchedParamSelectId = this.getOption(json, "searchedParamSelectId"); } - protected completeParse(json: {}) { + protected completeParse(json: {}, firstNotif: boolean = true) { super.completeParse(json); if (this._targetNubSelectId) { const sel = this.getFormulaireNodeById(this._targetNubSelectId); if (sel) { sel.addObserver(this); - // force 1st observation - (sel as SelectFieldNub).notifySelectValueChanged(); + if (firstNotif) { + // force 1st observation + (sel as SelectFieldNub).notifySelectValueChanged(); + } + } + } + if (this._targettedResultSelectId) { + const sel = this.getFormulaireNodeById(this._targettedResultSelectId); + if (sel) { + sel.addObserver(this); + if (firstNotif) { + // force 1st observation + (sel as SelectField).notifyValueChanged(); + } } } if (this._searchedParamSelectId) { const sel = this.getFormulaireNodeById(this._searchedParamSelectId); if (sel) { sel.addObserver(this); - // force 1st observation - (sel as SelectFieldNub).notifySelectValueChanged(); + if (firstNotif) { + // force 1st observation + (sel as SelectFieldNub).notifySelectValueChanged(); + } } } @@ -46,7 +66,20 @@ export class FormulaireSolveur extends FormulaireFixedVar { // interface Observer public update(sender: IObservable, data: any) { - super.update(sender, data); + // copied from FormDefinition, to avoid calling super.update() + if (sender instanceof Nub) { + switch (data.action) { + case "resultUpdated": + // forward Nub results update notification to FormCompute objects + this.reaffectResultComponents(); + break; + } + } + // copied from FormFixedVar, to avoid calling super.update() + if (data.action === "propertyChange") { + this.reset(); + } + if (sender instanceof SelectFieldNub) { if (data.action === "select") { // update Solveur property: Nub to calculate @@ -56,17 +89,17 @@ export class FormulaireSolveur extends FormulaireFixedVar { // nubToCalculate is updated anyway; here, just inhibit the error this._currentNub.properties.setPropValue("nubToCalculate", data.value.value); } catch (e) { } - // refresh parameters selector - const sel = this.getFormulaireNodeById(this._searchedParamSelectId) as SelectFieldParameter; - if (sel) { - sel.updateEntries(); - // reflect changes in GUI - const inputYtarget = this.getFormulaireNodeById("Ytarget") as NgParameter; - inputYtarget.notifyValueModified(this); + // refresh targetted result selector + const trSel = this.getFormulaireNodeById(this._targettedResultSelectId) as SelectField; + if (trSel) { + (trSel.parent as FieldSet).updateFields(); + // trick to re-set observers + this.completeParse({}, false); } + // refresh parameters selector + this.refreshParameterEntries(); } - } - if (sender instanceof SelectFieldParameter) { + } else if (sender instanceof SelectFieldParameter) { if (data.action === "select") { // update Solveur property: searched Parameter try { @@ -80,6 +113,24 @@ export class FormulaireSolveur extends FormulaireFixedVar { const inputXinit = this.getFormulaireNodeById("Xinit") as NgParameter; inputXinit.notifyValueModified(this); } + } else if (sender instanceof SelectField) { + if (sender.id === "select_target_result") { + // refresh parameters selector + this.refreshParameterEntries(); + } + } + } + + /** + * Re-populate searched parameter selector with fresh entries + */ + private refreshParameterEntries() { + const pSel = this.getFormulaireNodeById(this._searchedParamSelectId) as SelectFieldParameter; + if (pSel) { + pSel.updateEntries(); + // reflect changes in GUI + const inputYtarget = this.getFormulaireNodeById("Ytarget") as NgParameter; + inputYtarget.notifyValueModified(this); } } } diff --git a/src/app/formulaire/elements/fieldset.ts b/src/app/formulaire/elements/fieldset.ts index 0472fdc52..c6e49fa9b 100644 --- a/src/app/formulaire/elements/fieldset.ts +++ b/src/app/formulaire/elements/fieldset.ts @@ -381,7 +381,7 @@ export class FieldSet extends FormulaireElement implements Observer { if (senderId === sId) { // find select element in parent form const fe = this.parentForm.getFieldById(sId); - if (fe) { + if (fe && data.value !== undefined) { const prop = (fe as SelectField).associatedProperty; this.setPropValue(prop, data.value.value); } diff --git a/src/app/formulaire/elements/select-field-nub.ts b/src/app/formulaire/elements/select-field-nub.ts index 52053385b..2ddd07337 100644 --- a/src/app/formulaire/elements/select-field-nub.ts +++ b/src/app/formulaire/elements/select-field-nub.ts @@ -25,18 +25,24 @@ export class SelectFieldNub extends SelectFieldReference { */ protected populate() { switch (this._source) { - case "solveur_target": // Solveur, paramètre cible (à calculer) + case "solveur_target": // Solveur, module cible (à calculer) // find all Nubs having at least one link to another Nub's result const fs = ServiceFactory.instance.formulaireService; - const downstreamNubs = Session.getInstance().getDownstreamNubs(); - for (const dn of downstreamNubs) { - const calc = fs.getFormulaireFromId(dn.uid).calculatorName; + const candidateNubs = + Session.getInstance().getDownstreamNubs().concat( + Session.getInstance().getUpstreamNubsHavingExtraResults() + ).filter( + (element, index, self) => self.findIndex((e) => e.uid === element.uid) === index + ); + for (const cn of candidateNubs) { + const calc = fs.getFormulaireFromId(cn.uid).calculatorName; let label = calc; - if (dn.calculatedParam !== undefined) { - const varName = fs.expandVariableName(dn.calcType, dn.calculatedParam.symbol); - label += ` / ${varName} (${dn.calculatedParam.symbol})`; + // calculated param + if (cn.calculatedParam !== undefined) { + const varName = fs.expandVariableName(cn.calcType, cn.calculatedParam.symbol); + label += ` / ${varName} (${cn.calculatedParam.symbol})`; } - this.addEntry(new SelectEntry(this._entriesBaseId + dn.uid, dn.uid, decodeHtml(label))); + this.addEntry(new SelectEntry(this._entriesBaseId + cn.uid, cn.uid, decodeHtml(label))); } break; } diff --git a/src/app/formulaire/elements/select-field-parameter.ts b/src/app/formulaire/elements/select-field-parameter.ts index c643edd71..c5a9d7291 100644 --- a/src/app/formulaire/elements/select-field-parameter.ts +++ b/src/app/formulaire/elements/select-field-parameter.ts @@ -29,8 +29,12 @@ export class SelectFieldParameter extends SelectFieldReference { // find all non-calculated, non-linked parameters of all Nubs that // the current "target" Nub depends on (if any) const fs = ServiceFactory.instance.formulaireService; - const ntc: Nub = (this.parentForm.currentNub as Solveur).nubToCalculate; - const searchableParams = Solveur.getDependingNubsSearchableParams(ntc); + const solv = this.parentForm.currentNub as Solveur; + const ntc: Nub = solv.nubToCalculate; + const searchableParams = Solveur.getDependingNubsSearchableParams( + ntc, + solv.targettedResult !== undefined && solv.targettedResult !== "" + ); for (const p of searchableParams) { if (p.visible) { const calc = fs.getFormulaireFromId(p.originNub.uid).calculatorName; diff --git a/src/app/formulaire/elements/select-field-reference.ts b/src/app/formulaire/elements/select-field-reference.ts index 3a0d8396c..4cbe101ed 100644 --- a/src/app/formulaire/elements/select-field-reference.ts +++ b/src/app/formulaire/elements/select-field-reference.ts @@ -43,13 +43,13 @@ export abstract class SelectFieldReference extends SelectField { this.clearEntries(); // populate this.populate(); - // keep previously selected entry if possible - if (pse && pse.id) { - this.setValueFromId(pse.id); + // if no entry is available anymore, unset value + if (this.entries.length === 0) { + super.setValue(undefined); } else { - // if no entry is available anymore, unset value - if (this.entries.length === 0) { - super.setValue(undefined); + // keep previously selected entry if possible + if (pse && pse.id) { + this.setValueFromId(pse.id); } else { this.setDefaultValue(); } diff --git a/src/app/formulaire/elements/select-field.ts b/src/app/formulaire/elements/select-field.ts index cfd54a582..2fe1e85ea 100644 --- a/src/app/formulaire/elements/select-field.ts +++ b/src/app/formulaire/elements/select-field.ts @@ -1,11 +1,11 @@ import { - acSection, CourbeRemous, Nub, ParallelStructure, StructureType, LoiDebit, - Session + Session, + Solveur } from "jalhyd"; import { Field } from "./field"; @@ -13,6 +13,7 @@ import { SelectEntry } from "./select-entry"; import { StringMap } from "../../stringmap"; import { FormulaireNode } from "./formulaire-node"; import { FormulaireDefinition } from "../definition/form-definition"; +import { ServiceFactory } from "../../services/service-factory"; export class SelectField extends Field { @@ -105,13 +106,17 @@ export class SelectField extends Field { public setValue(v: SelectEntry) { if (this._selectedEntry !== v) { this._selectedEntry = v; - this.notifyObservers({ - "action": "select", - "value": v - }, this); + this.notifyValueChanged(); } } + public notifyValueChanged() { + this.notifyObservers({ + "action": "select", + "value": this._selectedEntry + }, this); + } + public getLabel() { if (this._selectedEntry) { return this._selectedEntry.label; @@ -147,6 +152,32 @@ export class SelectField extends Field { } break; + // driven by string[], not enum + case "solveur_targetted_result": + // 1. calculated param + const ntc = (nub as Solveur).nubToCalculate; + if (ntc !== undefined) { + const varName = ServiceFactory.instance.formulaireService.expandVariableName(ntc.calcType, ntc.calculatedParam.symbol); + this.addEntry(new SelectEntry( + this._entriesBaseId + "none", + "", + `${varName} (${ntc.calculatedParam.symbol})` + )); + } + // 2. extra results + if (ntc !== undefined && ntc.resultsFamilies !== undefined) { + for (const er of Object.keys(ntc.resultsFamilies)) { + const varName = ServiceFactory.instance.formulaireService.expandVariableName(ntc.calcType, er); + const e: SelectEntry = new SelectEntry( + this._entriesBaseId + er, + er, + `${varName} (${er})` + ); + this.addEntry(e); + } + } + break; + // possible values depend on CalcType case "device_structure_type": for (const st in (nub as ParallelStructure).getLoisAdmissibles()) { -- GitLab From fd74b42c8a3de4173100f22894cc652caf5b18a4 Mon Sep 17 00:00:00 2001 From: "mathias.chouet" <mathias.chouet@irstea.fr> Date: Thu, 20 Feb 2020 14:35:05 +0100 Subject: [PATCH 2/2] Translation for jalhyd#198 --- src/locale/messages.en.json | 1 + src/locale/messages.fr.json | 1 + 2 files changed, 2 insertions(+) diff --git a/src/locale/messages.en.json b/src/locale/messages.en.json index 89299e905..a4862ce4d 100644 --- a/src/locale/messages.en.json +++ b/src/locale/messages.en.json @@ -60,6 +60,7 @@ "ERROR_SECTION_PENTE_NEG_NULLE_HNORMALE_INF": "The slope is negative or zero, the normal depth is infinite", "ERROR_SECTION_SURFACE_NULLE": "Section: calculation is impossible when surface is null", "ERROR_SOMETHING_FAILED_IN_CHILD": "Calculation of child module #%number% failed", + "ERROR_SOLVEUR_NO_VARIATED_PARAMS_ALLOWED": "Solver cannot be used with a modules chain containing variated parameters", "ERROR_STRUCTURE_Q_TROP_ELEVE": "The flow passing through the other devices is too high: the requested parameter is not calculable.", "INFO_CALCULATOR_CALC_NAME": "Calculator name", "INFO_CALCULATOR_CALCULER": "Compute", diff --git a/src/locale/messages.fr.json b/src/locale/messages.fr.json index b9c0993ee..87b9c928e 100644 --- a/src/locale/messages.fr.json +++ b/src/locale/messages.fr.json @@ -60,6 +60,7 @@ "ERROR_SECTION_PENTE_NEG_NULLE_HNORMALE_INF": "La pente est négative ou nulle, la hauteur normale est infinie", "ERROR_SECTION_SURFACE_NULLE": "Section : calcul impossible à cause d'une surface nulle", "ERROR_SOMETHING_FAILED_IN_CHILD": "Le calcul du module enfant n°%number% a échoué", + "ERROR_SOLVEUR_NO_VARIATED_PARAMS_ALLOWED": "Le solveur ne peut pas être utilisé avec une chaîne de modules contenant des paramètres variés", "ERROR_STRUCTURE_Q_TROP_ELEVE": "Le débit passant par les autres ouvrages est trop élevé: le paramètre demandé n'est pas calculable.", "INFO_CALCULATOR_CALC_NAME": "Nom du module de calcul", "INFO_CALCULATOR_CALCULER": "Calculer", -- GitLab