diff --git a/src/app/app.module.ts b/src/app/app.module.ts index 69328bd5fe0b0e395432d09c6de258b8009581d0..25698c7d554a3b7d5241a93965e23ea8e40f87ec 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -76,6 +76,7 @@ import { VarResultsComponent } from "./components/fixedvar-results/var-results.c import { LogEntryComponent } from "./components/log-entry/log-entry.component"; import { ParamLinkComponent } from "./components/param-link/param-link.component"; import { SelectModelFieldLineComponent } from "./components/select-model-field-line/select-model-field-line.component"; +import { PabTableComponent } from "./components/pab-table/pab-table.component"; import { DialogConfirmEmptySessionComponent } from "./components/dialog-confirm-empty-session/dialog-confirm-empty-session.component"; import { DialogConfirmCloseCalcComponent } from "./components/dialog-confirm-close-calc/dialog-confirm-close-calc.component"; @@ -176,6 +177,7 @@ const appRoutes: Routes = [ NgParamInputComponent, PabResultsComponent, PabResultsTableComponent, + PabTableComponent, ParamComputedComponent, ParamFieldLineComponent, ParamLinkComponent, diff --git a/src/app/calculators/pab/pab.config.json b/src/app/calculators/pab/pab.config.json index 443720b8d7f8eea4d5431f752b17ebe6afefaced..197b72eba4a53389c2b78b4f162a6af9da33d361 100644 --- a/src/app/calculators/pab/pab.config.json +++ b/src/app/calculators/pab/pab.config.json @@ -24,46 +24,7 @@ ] }, { - "id": "fs_bassin", - "type": "fieldset_template", - "calcType": "PabCloisons", - "option": "fix", - "fields": [ - { - "id": "select_modele_cloisons", - "type": "select_cloisons", - "select": [] - }, - { - "type": "input", - "id": "QA", - "unit": "m³/s" - } - ] - }, - { - "id": "bassin_container", - "type": "template_container", - "templates": [ - "fs_bassin" - ] - }, - { - "id": "fs_cloison_aval", - "type": "fieldset", - "calcType": "Pab", - "fields": [ - { - "id": "select_modele_cloison_aval", - "type": "select_cloison_aval", - "select": [] - } - ] - }, - { - "type": "options", - "modeleCloisonsSelectId": "select_modele_cloisons", - "modeleCloisonAvalSelectId": "select_modele_cloison_aval", - "idCal": "Q" + "id": "tableau_de_la_mort", + "type": "pab_table" } -] \ No newline at end of file +] diff --git a/src/app/components/field-set/field-set.component.ts b/src/app/components/field-set/field-set.component.ts index ee5e3de853b7a884b6f6b0f8f2b18963205f5f0b..16fa303ad0638ca81d7ce36e47c1487330818651 100644 --- a/src/app/components/field-set/field-set.component.ts +++ b/src/app/components/field-set/field-set.component.ts @@ -211,15 +211,17 @@ export class FieldSetComponent implements DoCheck { * détermine si un Field est du type SelectFieldModel */ private isSelectModelField(f: Field): boolean { - return ( + /* return ( f instanceof SelectFieldModel && f.parentForm instanceof FormulairePab && ( f.id === (f.parentForm as FormulairePab).modeleCloisonsSelectId || f.id === (f.parentForm as FormulairePab).modeleCloisonAvalSelectId ) - ); + ); */ + return false; // tmp patch } + /* * gestion des événements clic sur les radios : * réception d'un message du composant enfant (param-field) diff --git a/src/app/components/generic-calculator/calculator.component.html b/src/app/components/generic-calculator/calculator.component.html index 7356b4b5a3b5e4b5e6798fb1653aab89b87797f5..72238c220a40910aa4b7850ff78f73b7b9dfb24c 100644 --- a/src/app/components/generic-calculator/calculator.component.html +++ b/src/app/components/generic-calculator/calculator.component.html @@ -39,14 +39,18 @@ <ng-template ngFor let-fe [ngForOf]="formElements"> <field-set *ngIf="isFieldset(fe)" [style.display]="getFieldsetStyleDisplay(fe.id)" [fieldSet]=fe - (radio)=onRadioClick($event) (validChange)=OnFieldsetValid() (inputChange)=onInputChange($event) + (radio)=onRadioClick($event) (validChange)=onElementValid() (inputChange)=onInputChange($event) (tabPressed)="onTabPressed($event)"> </field-set> <fieldset-container *ngIf="isFieldsetContainer(fe)" [_container]=fe (radio)=onRadioClick($event) - (validChange)=onFieldsetContainerValid() (inputChange)=onInputChange($event) + (validChange)=onElementValid() (inputChange)=onInputChange($event) (tabPressed)="onTabPressed($event)"> </fieldset-container> + + <pab-table *ngIf="isPabTable(fe)" [pabTable]=fe (radio)=onRadioClick($event) + (validChange)=onElementValid() (inputChange)=onInputChange($event)> + </pab-table> </ng-template> <mat-card-actions> diff --git a/src/app/components/generic-calculator/calculator.component.ts b/src/app/components/generic-calculator/calculator.component.ts index a83ea6303054d252904fe9e013cb68aded671606..3b65cc69bfe4964fdf1bccc52251cb3a184da27b 100644 --- a/src/app/components/generic-calculator/calculator.component.ts +++ b/src/app/components/generic-calculator/calculator.component.ts @@ -21,6 +21,7 @@ import { MatDialog } from "@angular/material"; import { DialogConfirmCloseCalcComponent } from "../dialog-confirm-close-calc/dialog-confirm-close-calc.component"; import { DialogGeneratePABComponent } from "../dialog-generate-pab/dialog-generate-pab.component"; import { SelectFieldModel } from "../../formulaire/select-field-model"; +import { PabTable } from "../../formulaire/pab-table"; @Component({ selector: "hydrocalc", @@ -131,6 +132,13 @@ export class GenericCalculatorComponent extends BaseComponent implements OnInit, return fe instanceof FieldsetContainer; } + /** + * détermine si un FormulaireElement est du type PabTable + */ + public isPabTable(fe: any): boolean { + return fe instanceof PabTable; + } + public get hasForm() { return this._formulaire !== undefined; } @@ -354,16 +362,9 @@ export class GenericCalculatorComponent extends BaseComponent implements OnInit, } /** - * réception d'un événement de validité d'un FieldSetComponent - */ - public OnFieldsetValid() { - this.updateUIValidity(); - } - - /** - * réception d'un événement de validité d'un FieldsetContainerComponent + * réception d'un événement de validité d'un FormElement */ - public onFieldsetContainerValid() { + public onElementValid() { this.updateUIValidity(); } diff --git a/src/app/components/pab-table/pab-table.component.html b/src/app/components/pab-table/pab-table.component.html new file mode 100644 index 0000000000000000000000000000000000000000..7eba1ea01643f72676ee76be88e3603dfdc70ac8 --- /dev/null +++ b/src/app/components/pab-table/pab-table.component.html @@ -0,0 +1,15 @@ +<mat-card-header class="bg-accent-light"> + <mat-card-title> + {{ title }} + </mat-card-title> +</mat-card-header> + +<mat-card-content> + Ici le tableau méga guedin ! + <!-- <field-set *ngFor="let fs of fieldsets" class="fieldset-inner" [fieldSet]=fs + (radio)=onRadioClick($event) (validChange)=onFieldsetValid() (inputChange)=onInputChange($event) + (addFieldset)=onAddFieldset($event) (removeFieldset)=onRemoveFieldset($event) + (moveFieldsetDown)=onMoveFieldsetDown($event) (moveFieldsetUp)=onMoveFieldsetUp($event) + (tabPressed)="onTabPressed($event)"> + </field-set> --> +</mat-card-content> diff --git a/src/app/components/pab-table/pab-table.component.scss b/src/app/components/pab-table/pab-table.component.scss new file mode 100644 index 0000000000000000000000000000000000000000..fcc76e8963f179c1243149cc1e3a445045d251c9 --- /dev/null +++ b/src/app/components/pab-table/pab-table.component.scss @@ -0,0 +1,25 @@ +:host { + display: block; + // reduce margins to avoid inner field-sets being too narrow on 360px display + margin-left: -8px; + margin-right: -8px; +} + +mat-card-header { + margin-left: -8px; + margin-right: -8px; + padding-left: 16px; + padding-top: 8px; + color: white; + + // Pourquoi n'est-ce pas hérité de calculator.component.scss ? + // À cause de la surcharge de mat-card-header ci-dessus ? + mat-card-title { + font-size: 16px; + margin-bottom: 8px; + } +} + +mat-card-content { + margin-top: 1em; +} diff --git a/src/app/components/pab-table/pab-table.component.ts b/src/app/components/pab-table/pab-table.component.ts new file mode 100644 index 0000000000000000000000000000000000000000..695c33fc3cd3f0de55d662ae197c6d580f5b959e --- /dev/null +++ b/src/app/components/pab-table/pab-table.component.ts @@ -0,0 +1,153 @@ +import { Component, Input, Output, EventEmitter, QueryList, ViewChildren, DoCheck, AfterViewInit } from "@angular/core"; + +import { FieldSetComponent } from "../field-set/field-set.component"; +import { I18nService } from "../../services/internationalisation/internationalisation.service"; +import { PabTable } from "../../formulaire/pab-table"; + +/** + * The big editable data grid for calculator type "Pab" (component) + */ +@Component({ + selector: "pab-table", + templateUrl: "./pab-table.component.html", + styleUrls: [ + "./pab-table.component.scss" + ] +}) +export class PabTableComponent implements DoCheck, AfterViewInit { + + @Input() + private pabTable: PabTable; + + /** + * liste des composants FieldSet enfants + */ + @ViewChildren(FieldSetComponent) + private _fieldsetComponents: QueryList<FieldSetComponent>; + + /** + * flag de validité des FieldSet enfants + */ + private _isValid = false; + + /** + * événément de changement d'état d'un radio + */ + // tslint:disable-next-line:no-output-on-prefix + @Output() + private radio = new EventEmitter<any>(); + + /** + * événément de changement de validité + */ + @Output() + private validChange = new EventEmitter(); + + /** + * événément de changement de valeur d'un input + */ + @Output() + private inputChange = new EventEmitter(); + + /** événement signalant un appui sur TAB ou SHIFT+TAB */ + @Output() + protected tabPressed = new EventEmitter<any>(); + + public constructor( + private i18nService: I18nService + ) { } + + public get title(): string { + return this.i18nService.localizeText("INFO_PAB_TABLE"); + } + + public get isValid() { + return this._isValid; + } + + /** + * Ajoute un nouveau sous-nub (Structure, PabCloisons selon le cas) + * dans un nouveau fieldset + */ + /* private addSubNub(after?: FieldSet, clone: boolean = false) { + if (after) { + const newFs = this._container.addFromTemplate(0, after.indexAsKid()); + if (clone) { + // replace in-place to change properties (overkill) + newFs.setPropValue("structureType", after.properties.getPropValue("structureType")); + newFs.setPropValue("loiDebit", after.properties.getPropValue("loiDebit")); + // after.nub.properties + for (const p of after.nub.prms) { + newFs.nub.getParameter(p.symbol).singleValue = p.singleValue; + } + } + } else { + this._container.addFromTemplate(0); + } + } */ + + public ngAfterViewInit() { + /* this.onFieldsetListChange(); + this._fieldsetComponents.changes.subscribe(_ => this.onFieldsetListChange()); */ + } + + public ngDoCheck() { + this.updateValidity(); + } + + /** + * calcul de la validité de tous les FieldSet de la vue + */ + private updateValidity() { + this._isValid = false; + + /* if (this._fieldsetComponents !== undefined) { + this._isValid = this._fieldsetComponents.reduce( + // callback + ( + // accumulator (valeur précédente du résultat) + acc, + // currentValue (élément courant dans le tableau) + fieldset, + // currentIndex (indice courant dans le tableau) + currIndex, + // array (tableau parcouru) + array + ) => { + return acc && fieldset.isValid; + } + // valeur initiale + , this._fieldsetComponents.length > 0); + } */ + + this.validChange.emit(); + } + + /** + * réception d'un événement de changement de valeur d'un input + */ + private onInputChange($event) { + this.inputChange.emit($event); + } + + /** + * relit les valeurs dans l'interface et met à jour les NgParameter + */ + public updateParametersFromUI() { + this._fieldsetComponents.forEach(fsc => fsc.updateParametersFromUI()); + } + + /** + * met à jour les paramètres liés + */ + public updateLinkedParameters() { + this._fieldsetComponents.forEach(fsc => fsc.updateLinkedParameters()); + } + + /** + * Renvoie l'événement au composant du dessus + */ + public onTabPressed(event) { + console.log("tab pressed dans le tablo !"); + } +} diff --git a/src/app/formulaire/definition/concrete/form-pab.ts b/src/app/formulaire/definition/concrete/form-pab.ts index 18b63e068b240f0ba53f36ab2bdfee004887847b..c8dce277d616d4029dfd522596d07a53e1c9e37d 100644 --- a/src/app/formulaire/definition/concrete/form-pab.ts +++ b/src/app/formulaire/definition/concrete/form-pab.ts @@ -1,11 +1,11 @@ -import { Nub, Props, Session, PabCloisons, Pab } from "jalhyd"; +import { /* Nub, Props, Session, PabCloisons, */ Pab } from "jalhyd"; -import { FieldsetContainer } from "../../fieldset-container"; +/* import { FieldsetContainer } from "../../fieldset-container"; import { FieldSet } from "../../fieldset"; import { SelectField } from "../../select-field"; import { NgParameter } from "../../ngparam"; import { FieldsetTemplate } from "../../fieldset-template"; -import { FormulaireNode } from "../../formulaire-node"; +import { FormulaireNode } from "../../formulaire-node"; */ import { FormulaireBase } from "./form-base"; import { FormComputePab } from "../form-compute-pab"; import { FormResultPab } from "../form-result-pab"; @@ -17,10 +17,10 @@ import { FormResultPab } from "../form-result-pab"; export class FormulairePab extends FormulaireBase { /** id du select configurant le modèle de cloisons */ - private _modeleCloisonsSelectId: string; + // private _modeleCloisonsSelectId: string; /** id du select configurant le modèle de la cloison aval */ - private _modeleCloisonAvalSelectId: string; + // private _modeleCloisonAvalSelectId: string; constructor() { super(); @@ -31,71 +31,70 @@ export class FormulairePab extends FormulaireBase { this._formCompute = new FormComputePab(this, (this._formResult as FormResultPab)); } - public get modeleCloisonsSelectId(): string { + private get pabNub(): Pab { + return this.currentNub as Pab; + } + + public doCompute() { + this.dumpPabStructure(this.pabNub); + super.doCompute(); + } + + /* public get modeleCloisonsSelectId(): string { return this._modeleCloisonsSelectId; } public get modeleCloisonAvalSelectId(): string { return this._modeleCloisonAvalSelectId; - } + } */ /** * Creates a virgin PabCloisons when a new fieldset is added through the GUI, * to ensure consistency; this object is not related to any Cloisons */ - private createDummyPabCloisons(templ: FieldsetTemplate): Nub { + /* private createDummyPabCloisons(templ: FieldsetTemplate): Nub { const params = {}; params["calcType"] = templ.calcTypeFromConfig; return this.createBassin(new Props(params)); - } + } */ /** * ajoute un Nub PabCloisons * @param after position après laquelle insérer la structure, à la fin sinon */ - private addPabCloisons(st: PabCloisons, after?: number) { + /* private addPabCloisons(st: PabCloisons, after?: number) { this.pabNub.addChild(st, after); - } - - private get pabNub(): Pab { - return this.currentNub as Pab; - } + } */ /** * Asks JaLHyd to create a PabCloisons Nub as a child of the current Calculator Module * and return it; does not store it in the Session (for PabCloisons, not for Calculator Modules) * @param p properties for the new Nub */ - protected createBassin(p: Props): PabCloisons { + /* protected createBassin(p: Props): PabCloisons { return Session.getInstance().createNub(p, this.currentNub as Pab) as PabCloisons; - } + } */ /** * Replaces the current Nub in the current calculator module, with a new one built with properties "params" * @param params properties to build the new Nub (calcType, loiDebit...) */ - protected replaceNub(sn: PabCloisons, params: Props): Nub { + /* protected replaceNub(sn: PabCloisons, params: Props): Nub { const parent = (this.currentNub as Pab); const newBassin = this.createBassin(params); parent.replaceChildInplace(sn, newBassin); return newBassin; - } + } */ /** * Deleted the given child Nub in the current calculator module * @param params properties to build the new Nub (calcType, loiDebit...) */ - protected deleteNub(sn: PabCloisons) { + /* protected deleteNub(sn: PabCloisons) { const parent = (this.currentNub as PabCloisons); parent.deleteChild(parent.getIndexForChild(sn)); - } - - public doCompute() { - this.dumpPabStructure(this.pabNub); - super.doCompute(); - } - - public createFieldset(parent: FormulaireNode, json: {}, data?: {}, nub?: Nub): FieldSet { + } */ + /* public createFieldset(parent: FormulaireNode, json: {}, data?: {}, nub?: Nub): FieldSet { if (json["calcType"] === "PabCloisons") { // indice après lequel insérer le nouveau FieldSet const after = data["after"]; @@ -122,17 +121,17 @@ export class FormulairePab extends FormulaireBase { } else { return super.createFieldset(parent, json, data); } - } + } */ - protected parseOptions(json: {}) { + /* protected parseOptions(json: {}) { super.parseOptions(json); // id du select configurant les modèles de cloisons this._modeleCloisonsSelectId = this.getOption(json, "modeleCloisonsSelectId"); // id du select configurant le modèle de cloison aval this._modeleCloisonAvalSelectId = this.getOption(json, "modeleCloisonAvalSelectId"); - } + } */ - public afterParseFieldset(fs: FieldSet) { + /* public afterParseFieldset(fs: FieldSet) { // si le FieldSet contient le select de modèles de cloisons if (this._modeleCloisonsSelectId) { const node = fs.getFormulaireNodeById(this._modeleCloisonsSelectId); @@ -151,81 +150,41 @@ export class FormulairePab extends FormulaireBase { fs.properties.addObserver(this); } } - } - - public moveFieldsetUp(fs: FieldSet) { - if (fs.nub instanceof PabCloisons) { - // déplacement du nub - fs.nub.parent.moveChildUp(fs.nub); - // déplacement du fieldset - this.fieldsetContainer.moveFieldsetUp(fs); - - this.resetResults(); - } else { - super.moveFieldsetUp(fs); - } - } - - public moveFieldsetDown(fs: FieldSet) { - if (fs.nub instanceof PabCloisons) { - // déplacement du nub - fs.nub.parent.moveChildDown(fs.nub); - // déplacement du fieldset - this.fieldsetContainer.moveFieldsetDown(fs); - - this.resetResults(); - } else { - super.moveFieldsetDown(fs); - } - } + } */ - public removeFieldset(fs: FieldSet) { - if (fs.nub instanceof PabCloisons) { - // suppression du sous-nub dans le Nub parent - this.deleteNub(fs.nub); - - // suppression du fieldset - this.fieldsetContainer.removeFieldset(fs); - - this.resetResults(); - } else { - super.removeFieldset(fs); - } - } - - protected completeParse(json: {}) { + /* protected completeParse(json: {}) { this.subscribeFieldsetContainer(); - } + } */ - private get fieldsetContainer(): FieldsetContainer { + /* private get fieldsetContainer(): FieldsetContainer { const n = this.getFormulaireNodeById("bassin_container"); if (n === undefined || !(n instanceof FieldsetContainer)) { throw new Error("l'élément 'bassin_container' n'est pas du type FieldsetContainer"); } return n as FieldsetContainer; - } + } */ /** * abonnement en tant qu'observateur du FieldsetContainer */ - private subscribeFieldsetContainer() { + /* private subscribeFieldsetContainer() { this.fieldsetContainer.addObserver(this); - } + } */ /** * abonnement en tant qu'observateur des NgParameter des FieldSet contenus dans le FieldsetContainer */ - private subscribeBasinFields(fs: FieldSet) { + /* private subscribeBasinFields(fs: FieldSet) { for (const n of fs.allFormElements) { if (n instanceof NgParameter || n instanceof SelectField) { n.addObserver(this); } } - } + } */ // interface Observer - public update(sender: any, data: any) { + /* public update(sender: any, data: any) { super.update(sender, data); @@ -266,12 +225,12 @@ export class FormulairePab extends FormulaireBase { break; } } - } + } */ // debug method private dumpPabStructure(pab: Pab) { console.log(`PAB: ${pab.uid}, ${pab.children.length} children`); - for (const c of pab.children) { + /* for (const c of pab.children) { console.log( ` * child: ${c.uid}, based on ${c.properties.getPropValue("modeleCloisons")}` + ` (cote amont ${c.prms.Z1.singleValue}, longueur ${c.prms.LB.singleValue})` @@ -279,6 +238,6 @@ export class FormulairePab extends FormulaireBase { } if (pab.downWall) { console.log(`+ downstream wall: ${pab.downWall.uid}`); - } + } */ } } diff --git a/src/app/formulaire/definition/form-definition.ts b/src/app/formulaire/definition/form-definition.ts index 859cad4fb3953c45572c4a808327d0bad025fb20..6569081e7588e22c576acc9b0f859860f7daf4b1 100644 --- a/src/app/formulaire/definition/form-definition.ts +++ b/src/app/formulaire/definition/form-definition.ts @@ -13,6 +13,7 @@ import { DeepFormulaireElementIterator } from "../form-iterator/deep-element-ite import { TopFormulaireElementIterator } from "../form-iterator/top-element-iterator"; import { CalculatorResults } from "../../results/calculator-results"; import { ServiceFactory } from "../../services/service-factory"; +import { PabTable } from "../pab-table"; /** * classe de base pour tous les formulaires @@ -187,6 +188,12 @@ export abstract class FormulaireDefinition extends FormulaireNode implements Obs this.kids.push(fsc); } + private parse_pab_table(json: {}) { + const tab: PabTable = new PabTable(this); + tab.parseConfig(json); + this.kids.push(tab); + } + public parseDependencies(json: {}) { // tslint:disable-next-line:forin for (const conf_index in json) { @@ -271,6 +278,10 @@ export abstract class FormulaireDefinition extends FormulaireNode implements Obs this.parse_template_container(conf, templates); break; + case "pab_table": // not generic at all + this.parse_pab_table(conf); + break; + default: throw new Error(`type d'objet de module de calcul ${type} non pris en charge`); } diff --git a/src/app/formulaire/pab-table.ts b/src/app/formulaire/pab-table.ts new file mode 100644 index 0000000000000000000000000000000000000000..1591b4a188462d0c5fcffb6e8e42c55ab97bdce0 --- /dev/null +++ b/src/app/formulaire/pab-table.ts @@ -0,0 +1,18 @@ +import { FormulaireElement } from "./formulaire-element"; +import { FormulaireNode } from "./formulaire-node"; + +/** + * The big editable data grid for calculator type "Pab" (model) + */ +export class PabTable extends FormulaireElement { + + constructor(parent: FormulaireNode) { + super(parent); + } + + public parseDependencies(json: {}) { } // implements abstract method of FormulaireNode + + public parseConfig(json: {}) { + this._confId = json["id"]; + } +} diff --git a/src/locale/messages.en.json b/src/locale/messages.en.json index 18aff4ce809251b42820e1da10648c4da458b43e..88bc01abe78c6648e6111c346751442725cddde4 100644 --- a/src/locale/messages.en.json +++ b/src/locale/messages.en.json @@ -195,6 +195,7 @@ "INFO_OUVRAGE": "Structure", "INFO_PAB_TITRE_COURT": "Fish ladder", "INFO_PAB_TITRE": "Fish ladder", + "INFO_PAB_TABLE": "Fish ladder geometry", "INFO_PABCHUTE_TITRE_COURT": "FL: fall", "INFO_PABCHUTE_TITRE": "Fish ladder: fall", "INFO_PABDIMENSIONS_TITRE_COURT": "FL: dimensions", diff --git a/src/locale/messages.fr.json b/src/locale/messages.fr.json index 1f1db90016de2f86a955686a596e8f1173854573..9e7f4dd5cbafc2ce1e31428b5290ea2198420144 100644 --- a/src/locale/messages.fr.json +++ b/src/locale/messages.fr.json @@ -195,6 +195,7 @@ "INFO_OUVRAGE": "Ouvrage", "INFO_PAB_TITRE_COURT": "PAB", "INFO_PAB_TITRE": "Passe à bassins", + "INFO_PAB_TABLE": "Géométrie de la passe", "INFO_PABCHUTE_TITRE_COURT": "PAB : chute", "INFO_PABCHUTE_TITRE": "Passe à bassins : chute", "INFO_PABDIMENSIONS_TITRE_COURT": "PAB : dimensions",