diff --git a/e2e/clone-calc.e2e-spec.ts b/e2e/clone-calc.e2e-spec.ts index 459b3d7677ad34afc3e41932b10226fc678d8eb6..dab35d14926c0479f57d88661c61e5192392e63d 100644 --- a/e2e/clone-calc.e2e-spec.ts +++ b/e2e/clone-calc.e2e-spec.ts @@ -2,7 +2,6 @@ import { AppPage } from "./app.po"; import { ListPage } from "./list.po"; import { CalculatorPage } from "./calculator.po"; import { Navbar } from "./navbar.po"; -import { SideNav } from "./sidenav.po"; import { browser } from "protractor"; /** @@ -13,14 +12,12 @@ describe("ngHyd − clone a calculator", () => { let listPage: ListPage; let calcPage: CalculatorPage; let navbar: Navbar; - let sidenav: SideNav; beforeEach(() => { startPage = new AppPage(); listPage = new ListPage(); calcPage = new CalculatorPage(); navbar = new Navbar(); - sidenav = new SideNav(); }); it("when cloning a calculator, the clone should have the same values for all parameters", async () => { diff --git a/src/app/components/base-param-input/base-param-input.component.ts b/src/app/components/base-param-input/base-param-input.component.ts index e04b0a4607e2d3632eab3e07700c7a8b2c0bb888..001a186d784d62138e45772d9570d56c08e56a0b 100644 --- a/src/app/components/base-param-input/base-param-input.component.ts +++ b/src/app/components/base-param-input/base-param-input.component.ts @@ -75,7 +75,7 @@ export class NgBaseParam extends Observable { valid = true; } catch (e) { if (e instanceof Message) { - // @TODO ici au début le service de localisation n'a pas encore chargé ses messages… + // ici au début le service de localisation n'a pas encore chargé ses messages… msg = ServiceFactory.instance.i18nService.localizeMessage(e); } else { msg = "invalid value"; diff --git a/src/app/components/fixedvar-results/fixedvar-results.component.ts b/src/app/components/fixedvar-results/fixedvar-results.component.ts index d6dca7a41a47100383d7af0cc518c1190b680ad1..3392fb698cf71523bca8cd1a036c9f8380bfb0dc 100644 --- a/src/app/components/fixedvar-results/fixedvar-results.component.ts +++ b/src/app/components/fixedvar-results/fixedvar-results.component.ts @@ -98,6 +98,7 @@ export class FixedVarResultsComponent implements DoCheck { this.resultsGraphComponent.results = undefined; } + // set _doUpdate flag so that results are rebuilt on the next Angular display cycle this._doUpdate = false; if (this._fixedResults !== undefined) { this._doUpdate = this._fixedResults.hasResults || this._fixedResults.hasLog; diff --git a/src/app/components/param-values/param-values.component.ts b/src/app/components/param-values/param-values.component.ts index 07a32d45538a814032ef953f0ff3ccffcd3cdea2..95c9e3c71a6a8a95a7399f84c05c1bd35e04644c 100644 --- a/src/app/components/param-values/param-values.component.ts +++ b/src/app/components/param-values/param-values.component.ts @@ -63,7 +63,7 @@ export class ParamValuesComponent implements AfterViewInit, Observer { this.openDialog(); }); } - // subscribe to parameter values change (through dialog actions) @TODO draft + // subscribe to parameter values change (through dialog actions) this.param.addObserver(this); } diff --git a/src/app/formulaire/definition/concrete/form-courbe-remous.ts b/src/app/formulaire/definition/concrete/form-courbe-remous.ts index 4e96da330ac707ad9818125c23386e0047384dfd..99be68efbe0f6056950e05f519570a271993fbaf 100644 --- a/src/app/formulaire/definition/concrete/form-courbe-remous.ts +++ b/src/app/formulaire/definition/concrete/form-courbe-remous.ts @@ -49,6 +49,9 @@ export class FormulaireCourbeRemous extends FormulaireBase { // interface Observer update(sender: IObservable, data: any) { + + super.update(sender, data); + if (sender instanceof FieldSet && data.action === "propertyChange") { switch (sender.id) { case "fs_section": diff --git a/src/app/formulaire/definition/concrete/form-lechapt-calmon.ts b/src/app/formulaire/definition/concrete/form-lechapt-calmon.ts index c84864baaa2b1821e56e86e9ff037f2882d24a22..db299120666ff8b777715e0a25fe388e005c912a 100644 --- a/src/app/formulaire/definition/concrete/form-lechapt-calmon.ts +++ b/src/app/formulaire/definition/concrete/form-lechapt-calmon.ts @@ -26,6 +26,9 @@ export class FormulaireLechaptCalmon extends FormulaireBase implements Observer // interface Observer public update(sender: any, data: any) { + + super.update(sender, data); + // en cas de changement de valeur du select de matériau, effacement des résultats et MAJ des champs L,M,N if (sender instanceof SelectField) { if (data.action === "select") { diff --git a/src/app/formulaire/definition/concrete/form-parallel-structures.ts b/src/app/formulaire/definition/concrete/form-parallel-structures.ts index d71119c87ae08f5e629eed734231dbed1536fb98..ec840a97075a5039d7851a883607fb9cb9346d2c 100644 --- a/src/app/formulaire/definition/concrete/form-parallel-structures.ts +++ b/src/app/formulaire/definition/concrete/form-parallel-structures.ts @@ -338,6 +338,9 @@ export class FormulaireParallelStructure extends FormulaireBase { // interface Observer public update(sender: any, data: any) { + + super.update(sender, data); + if (sender instanceof FieldsetContainer) { switch (data.action) { case "newFieldset": diff --git a/src/app/formulaire/definition/concrete/form-regime-uniforme.ts b/src/app/formulaire/definition/concrete/form-regime-uniforme.ts index 35a08225c68a004936013c8447310cde4c8b3d8d..503bdaba7730c5063406427250e04d9364a0e252 100644 --- a/src/app/formulaire/definition/concrete/form-regime-uniforme.ts +++ b/src/app/formulaire/definition/concrete/form-regime-uniforme.ts @@ -33,6 +33,9 @@ export class FormulaireRegimeUniforme extends FormulaireBase implements Observer // interface Observer update(sender: IObservable, data: any) { + + super.update(sender, data); + // changement de propriété du FieldSet contenant le select de choix du type de section if (sender instanceof FieldSet && sender.id === "fs_section" && data.action === "propertyChange") { this.replaceCurrentNub(sender.properties); diff --git a/src/app/formulaire/definition/concrete/form-section-parametree.ts b/src/app/formulaire/definition/concrete/form-section-parametree.ts index 9c48c038bcf3278528703ad13e4cd98268e1238b..1a3ef62b123e5dbdd21200d20c06966c34da069f 100644 --- a/src/app/formulaire/definition/concrete/form-section-parametree.ts +++ b/src/app/formulaire/definition/concrete/form-section-parametree.ts @@ -31,6 +31,9 @@ export class FormulaireSectionParametree extends FormulaireBase { // interface Observer update(sender: IObservable, data: any) { + + super.update(sender, data); + // changement de propriété du FieldSet contenant le select de choix du type de section if (sender instanceof FieldSet && data.action === "propertyChange") { switch (sender.id) { diff --git a/src/app/formulaire/definition/form-compute-courbe-remous.ts b/src/app/formulaire/definition/form-compute-courbe-remous.ts index dc3a6a2e26789f4c9f2431fbb663e1150b4fbd81..b69986e83c954b0795184a17145b424b6c3e7958 100644 --- a/src/app/formulaire/definition/form-compute-courbe-remous.ts +++ b/src/app/formulaire/definition/form-compute-courbe-remous.ts @@ -7,6 +7,11 @@ import { FormCompute } from "./form-compute"; import { FormResultRemous } from "./form-result-remous"; export class FormComputeCourbeRemous extends FormCompute { + + private resultYn: Result; + + private resultYc: Result; + constructor(formBase: FormulaireDefinition, private _formSection: FormDefSection, formResult: FormResultRemous) { super(formBase, formResult); } @@ -21,8 +26,15 @@ export class FormComputeCourbeRemous extends FormCompute { const prmCR: CourbeRemousParams = cr.prms as CourbeRemousParams; const sect: acSection = prmCR.Sn; - const Yn: Result = sect.Calc("Yn"); // hauteur normale - const Yc: Result = sect.Calc("Yc"); // hauteur critique + this.resultYn = sect.Calc("Yn"); // hauteur normale + this.resultYc = sect.Calc("Yc"); // hauteur critique + + this.reaffectResultComponents(); + } + + protected reaffectResultComponents() { + const cr: CourbeRemous = this._formBase.currentNub as CourbeRemous; + const prmCR: CourbeRemousParams = cr.prms as CourbeRemousParams; this.remousResults.parameters = prmCR; @@ -33,8 +45,8 @@ export class FormComputeCourbeRemous extends FormCompute { this.remousResults.result = cr.calculRemous(this.remousResults.extraParamSymbol); // données du graphe - this.remousResults.hauteurNormale = Yn.resultElement; - this.remousResults.hauteurCritique = Yc.resultElement; + this.remousResults.hauteurNormale = this.resultYn.resultElement; + this.remousResults.hauteurCritique = this.resultYc.resultElement; if (this.remousResults.extraParamSymbol) { this.remousResults.extraGraph = ["Hs", "Hsc", "Yf", "Yt", "Yco"].indexOf(this.remousResults.extraParamSymbol) === -1; } else { diff --git a/src/app/formulaire/definition/form-compute-fixedvar.ts b/src/app/formulaire/definition/form-compute-fixedvar.ts index 151b875bfbae1e4c4178b8c09b228b54e2febc7f..6168991607cff3a6c066e4bcaec1ad521da6f040 100644 --- a/src/app/formulaire/definition/form-compute-fixedvar.ts +++ b/src/app/formulaire/definition/form-compute-fixedvar.ts @@ -1,4 +1,4 @@ -import { Nub, Result, ComputeNode, ParamValueMode } from "jalhyd"; +import { Nub, Result, ComputeNode } from "jalhyd"; import { FormCompute } from "./form-compute"; import { NgParameter, ParamRadioConfig } from "../ngparam"; @@ -45,22 +45,28 @@ export class FormComputeFixedVar extends FormCompute { protected compute() { const nub: Nub = this._formBase.currentNub; const computedParam: NgParameter = this.getComputedParameter(); + + const res: Result = this.runNubCalc(nub, computedParam); + + this.reaffectResultComponents(); + } + + protected reaffectResultComponents() { + const nub: Nub = this._formBase.currentNub; + const computedParam: NgParameter = this.getComputedParameter(); this.formResult.addFixedParameters(); const varParam: NgParameter = this.getVariatedParameter(); if (varParam === undefined) { // pas de paramètre à varier - const res: Result = this.runNubCalc(nub, computedParam); - this.formResult.fixedResults.result = res; + this.formResult.fixedResults.result = nub.result; this.formResult.fixedResults.calculatedParameter = computedParam; } else { // il y a un paramètre à varier - const res: Result = this.runNubCalc(nub, computedParam); - this.formResult.varResults.variatedParameter = varParam; this.formResult.varResults.calculatedParameter = computedParam; - this.formResult.varResults.result = res; + this.formResult.varResults.result = nub.result; this.formResult.varResults.update(false); } } diff --git a/src/app/formulaire/definition/form-compute-section-parametree.ts b/src/app/formulaire/definition/form-compute-section-parametree.ts index fc41974d9505d7c5da73d60c060969968198c296..068dce9d2aac4b7024fa2028e01afedc374c8306 100644 --- a/src/app/formulaire/definition/form-compute-section-parametree.ts +++ b/src/app/formulaire/definition/form-compute-section-parametree.ts @@ -12,6 +12,8 @@ import { FormulaireNode } from "../formulaire-node"; export class FormComputeSectionParametree extends FormCompute { + private tmpResult: Result; + constructor(formBase: FormulaireDefinition, private _formSection: FormDefSection, formResult: FormResult) { super(formBase, formResult); } @@ -62,20 +64,25 @@ export class FormComputeSectionParametree extends FormCompute { const sectNub: SectionParametree = this._formBase.currentNub as SectionParametree; - const sect: acSection = sectNub.section; - this._sectionResults.section = sect; - - const tmpResult: Result = sectNub.CalcSerie( + this.tmpResult = sectNub.CalcSerie( undefined, // valeur initiale, non utilisée dans ce cas undefined // variable à calculer, non utilisée ); + this.reaffectResultComponents(); + } + + protected reaffectResultComponents() { + const sectNub: SectionParametree = this._formBase.currentNub as SectionParametree; + const sect: acSection = sectNub.section; + this._sectionResults.section = sect; + // résultats de section (avec le graphique de section) - this._sectionResults.result = tmpResult; + this._sectionResults.result = this.tmpResult; // résultats complémentaires des paramètres fixés this._formSectionResult.addSectionFixedParameters(false); - this._formSectionResult.fixedResults.result = tmpResult; + this._formSectionResult.fixedResults.result = this.tmpResult; } /** diff --git a/src/app/formulaire/definition/form-compute.ts b/src/app/formulaire/definition/form-compute.ts index 4e8494753862af7cb478da8204cf880959a5a5b5..d1e848b28cb3c79ee81d2fdff7e39c4325c736cc 100644 --- a/src/app/formulaire/definition/form-compute.ts +++ b/src/app/formulaire/definition/form-compute.ts @@ -1,11 +1,14 @@ -import { Nub, Result, ParamDomainValue } from "jalhyd"; +import { Nub, Result, ParamDomainValue, Observer } from "jalhyd"; import { FormResult } from "./form-result"; import { FormulaireDefinition } from "./form-definition"; import { NgParameter } from "../ngparam"; -export abstract class FormCompute { +export abstract class FormCompute implements Observer { + constructor(protected _formBase: FormulaireDefinition, protected _formResult: FormResult) { + // indirectly subscribe to Nub result updates + this._formBase.addObserver(this); } protected abstract compute(); @@ -23,14 +26,25 @@ export abstract class FormCompute { } /** - * lance le calcul d'un paramètre en déterminant une valeur initiale + * Copies current Nub result into result components for display on page. + * Should be called every time the Nub result changes + */ + protected abstract reaffectResultComponents(); + + /** + * Lance le calcul d'un paramètre en déterminant une valeur initiale. + * Si nécessaire déclenche un calcul en chaîne des modules en amont. */ protected runNubCalc(nub: Nub, computedParam: NgParameter): Result { let init: number; + // require chain computation; redundant with Nub.CalcSerie but required + // to get initial value here... + const computedParamValue = computedParam.getValue(true); + switch (computedParam.domain.domain) { case ParamDomainValue.ANY: if (computedParam && computedParam.isDefined) { - init = computedParam.getValue(); + init = computedParamValue; } if (init === undefined) { init = 0; @@ -39,7 +53,7 @@ export abstract class FormCompute { case ParamDomainValue.POS_NULL: if (computedParam && computedParam.isDefined) { - init = Math.max(computedParam.getValue(), 0); + init = Math.max(computedParamValue, 0); } if (init === undefined) { init = 0; @@ -52,7 +66,7 @@ export abstract class FormCompute { case ParamDomainValue.NOT_NULL: if (computedParam && computedParam.isDefined) { - init = computedParam.getValue(); + init = computedParamValue; } if (init === undefined || init === 0) { init = 1e-8; @@ -61,7 +75,7 @@ export abstract class FormCompute { case ParamDomainValue.POS: if (computedParam && computedParam.isDefined) { - init = Math.max(computedParam.getValue(), 1e-8); + init = Math.max(computedParamValue, 1e-8); } if (init === undefined) { init = 1e-8; @@ -72,6 +86,9 @@ export abstract class FormCompute { return nub.CalcSerie(init, this.getParameterRefid(computedParam)); } + /** + * Triggers computation of the Nub, updates form results + */ public doCompute() { this._formResult.resetResults(); @@ -81,4 +98,21 @@ export abstract class FormCompute { "action": "resultsUpdated", }, this._formBase); } + + // interface Observer + + public update(sender: any, data: any): void { + if (sender instanceof Nub) { + switch (data.action) { + case "nubResultUpdated": + // forward Nub results update notification to FormCompute objects + this.reaffectResultComponents(); + /* console.log("_____forwarding 2"); + this._formBase.notifyObservers({ + "action": "resultsUpdated", + }, this._formBase); */ + break; + } + } + } } diff --git a/src/app/formulaire/definition/form-def-parallel-structures.ts b/src/app/formulaire/definition/form-def-parallel-structures.ts index a4856994d88a189b00a3d07e67a66a25113147b6..5206d9cc0f74141f5474fb99eafef8d12dfd6427 100644 --- a/src/app/formulaire/definition/form-def-parallel-structures.ts +++ b/src/app/formulaire/definition/form-def-parallel-structures.ts @@ -1,7 +1,3 @@ -import { CalculatorType, StructureType, LoiDebit } from "jalhyd"; - -import { FieldSet } from "../fieldset"; - /** * gestion des formulaires "ouvrages parallèles" */ diff --git a/src/app/formulaire/definition/form-definition.ts b/src/app/formulaire/definition/form-definition.ts index 4d14b15b7bdadc31e5a26e1c21d09b46d51d9d31..daa57be194f36df52f60597dd48d540606cabee4 100644 --- a/src/app/formulaire/definition/form-definition.ts +++ b/src/app/formulaire/definition/form-definition.ts @@ -1,4 +1,4 @@ -import { CalculatorType, ComputeNodeType, Nub, Props, Observer, Session, ParallelStructure } from "jalhyd"; +import { CalculatorType, ComputeNodeType, Nub, Props, Observer, Session } from "jalhyd"; import { FormulaireElement } from "../formulaire-element"; import { NgParameter, ParamRadioConfig } from "../ngparam"; @@ -94,7 +94,7 @@ export abstract class FormulaireDefinition extends FormulaireNode implements Obs } public initNub(props?: Props) { - this._currentNub = this.createNub(props ? props : new Props(this.defaultProperties)); + this.currentNub = this.createNub(props ? props : new Props(this.defaultProperties)); } public get currentNub(): Nub { @@ -108,7 +108,15 @@ export abstract class FormulaireDefinition extends FormulaireNode implements Obs `Nub ${n.properties["calcType"]} incompatible avec le formulaire ${this._calculatorName} (${this._props["calcType"]})` ); } + // unsubscribe from old Nub + if (this._currentNub) { + this._currentNub.removeObserver(this); + } + // replace Nub this._currentNub = n; + // subscribe to new Nub (for result updates) + console.log("SET CURRENT NUB -- (re)subscribe to Nub", this._currentNub.uid); + this._currentNub.addObserver(this); } /** @@ -351,6 +359,16 @@ export abstract class FormulaireDefinition extends FormulaireNode implements Obs }, this); } + /** + * Forwards Nub's result updated notification. + * Used by FormCompute to update results display + */ + protected notifyNubResultUpdated(sender) { + this.notifyObservers({ + action: "nubResultUpdated" + }, sender); + } + /** * réinitialisation du formulaire suite à un changement d'une valeur, d'une option, ... : * effacement des résultats, application des dépendances, ... @@ -469,5 +487,14 @@ export abstract class FormulaireDefinition extends FormulaireNode implements Obs // interface Observer public update(sender: any, data: any) { + console.log("--- FormDefinition received update", sender.constructor.name, data); + if (sender instanceof Nub) { + switch (data.action) { + case "resultUpdated": + // forward Nub results update notification to FormCompute objects + this.notifyNubResultUpdated(sender); + break; + } + } } } diff --git a/src/app/formulaire/fieldset.ts b/src/app/formulaire/fieldset.ts index ffa32a38d50050e230430c5671c7e06bde31ee6e..ff2789eb397c9c9e4cdd7f06657be1d9669e92d7 100644 --- a/src/app/formulaire/fieldset.ts +++ b/src/app/formulaire/fieldset.ts @@ -133,9 +133,6 @@ export class FieldSet extends FormulaireElement implements Observer { if (res) { res.parseConfig(json, { "radioConfig": default_radio_config }); - // set parent Nub on Parameter to ensure UID availability - // should always be done @TODO check - // res.paramDefinition.parent = this._nub; } return res; diff --git a/src/app/formulaire/ngparam.ts b/src/app/formulaire/ngparam.ts index 809b9d1f74ac8ac7d720ed2f6decc96464700030..10ed519628c99864921882ea8ba5d925b68f5fc1 100644 --- a/src/app/formulaire/ngparam.ts +++ b/src/app/formulaire/ngparam.ts @@ -51,7 +51,6 @@ export class NgParameter extends InputField implements Observer { /** * Returns a text preview of the current value(s), depending on the value mode - * @TODO use display precision to limit decimals */ public static preview(p: ParamDefinition): string { let valuePreview: string; @@ -107,7 +106,12 @@ export class NgParameter extends InputField implements Observer { return v.toFixed(nDigits); }).slice(0, 5).join("; ") + "…"; } else { - valuePreview = String(p.referencedValue.nub.result.vCalc.toFixed(nDigits)); + const vCalc = p.referencedValue.nub.result.vCalc; + if (vCalc) { + valuePreview = String(vCalc.toFixed(nDigits)); + } else { + throw new Error("NgParameter.preview() : No vCalc for computed target Nub !"); + } } } else { valuePreview = i18n.localizeText("INFO_PARAMFIELD_IN_CALCULATION"); @@ -120,7 +124,6 @@ export class NgParameter extends InputField implements Observer { // was the result already computed ? try { const remoteValues = p.referencedValue.getParamValues(); - // @TODO is the computed value fresh or stale ? if (p.referencedValue.hasMultipleValues()) { // like LIST mode valuePreview = i18n.localizeText("INFO_PARAMFIELD_PARAMVARIER_VALUES"); @@ -269,8 +272,11 @@ export class NgParameter extends InputField implements Observer { throw new Error("invalid parameter radio configuration " + s); } - public getValue() { - return this._paramDef.v; + /** + * Asks the ParamDefinition for its current value + */ + public getValue(triggerChainComputation: boolean = false) { + return this._paramDef.getValue(triggerChainComputation); } /**