diff --git a/angular.json b/angular.json index e87d2b0a1a6f02297dd35553c7d5cd37e50f7094..daa02deb9f77b04e2cb9ccf9839352466f7cdaf5 100644 --- a/angular.json +++ b/angular.json @@ -28,7 +28,9 @@ "src/styles.scss", "src/theme.scss", "node_modules/material-design-icons/iconfont/material-icons.css", - "node_modules/roboto-fontface/css/roboto/roboto-fontface.css" + "node_modules/roboto-fontface/css/roboto/roboto-fontface.css", + "node_modules/primeng/resources/primeng.min.css", + "node_modules/primeng/resources/themes/nova-light/theme.css" ], "scripts": [], "showCircularDependencies": false diff --git a/jalhyd_branch b/jalhyd_branch index 8b25206ff90e9432f6f1a8600f87a7bd695a24af..19c587308945308f3787a17aee4282c5c6de79df 100644 --- a/jalhyd_branch +++ b/jalhyd_branch @@ -1 +1 @@ -master \ No newline at end of file +33-ajout-du-calcul-d-une-passe-a-bassin diff --git a/package-lock.json b/package-lock.json index 265e3c560a30d324c6d0baf680706804d7c7a706..72d12202a4b58cec9399e6f57b455428be2edaf3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10859,6 +10859,11 @@ "meow": "^3.1.0" } }, + "primeng": { + "version": "8.0.0-rc.1", + "resolved": "https://registry.npmjs.org/primeng/-/primeng-8.0.0-rc.1.tgz", + "integrity": "sha512-xgynBphs4wtCbyyAVQD1ipQCVcSOlfZ697wVVIlZ76V9E1e6eYeNGXN/fLud3NngNyoFiJkP+VJL7kfcfWFnPQ==" + }, "printj": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/printj/-/printj-1.1.2.tgz", diff --git a/package.json b/package.json index bad7e6e723f7aecf7b0cef64641e728ad9467056..4d66e017eecbc9bb2e7625fe0f730789be4c973e 100644 --- a/package.json +++ b/package.json @@ -60,6 +60,7 @@ "ngx-md": "^7.0.0", "ngx-webstorage-service": "^4.0.1", "pako": "^1.0.10", + "primeng": "^8.0.0-rc.1", "roboto-fontface": "^0.10.0", "rxjs": "^6.3.3", "rxjs-compat": "^6.3.3", @@ -103,4 +104,4 @@ "android" ] } -} \ No newline at end of file +} diff --git a/src/app/app.module.ts b/src/app/app.module.ts index 25698c7d554a3b7d5241a93965e23ea8e40f87ec..8b206ab68afcea020eb410182e518a5f91140273 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -26,6 +26,8 @@ import { } from "@angular/material"; import { MaterialFileInputModule } from "ngx-material-file-input"; +import {TableModule} from "primeng/components/table/table"; + import { FlexLayoutModule } from "@angular/flex-layout"; import { CustomBreakPointsProvider, @@ -140,7 +142,8 @@ const appRoutes: Routes = [ enableTracing: false // debugging purposes only } ), - StorageServiceModule + StorageServiceModule, + TableModule ], declarations: [ // composants, pipes et directives AppComponent, diff --git a/src/app/components/pab-table/pab-table.component.html b/src/app/components/pab-table/pab-table.component.html index 7eba1ea01643f72676ee76be88e3603dfdc70ac8..936d5eaeed6248b487bd798906e391e2e3205c6f 100644 --- a/src/app/components/pab-table/pab-table.component.html +++ b/src/app/components/pab-table/pab-table.component.html @@ -5,7 +5,54 @@ </mat-card-header> <mat-card-content> - Ici le tableau méga guedin ! + + <button (click)="zpouet()">CLIKZYVOIR</button> + + <p-table [columns]="cols" [value]="rows" class="pab-data-table"> + + <ng-template pTemplate="header" let-columns> + <tr> + <th *ngFor="let h of headers" + (click)="toggleSelection(h, $event)" + [attr.rowspan]="h.rowspan ? h.rowspan : null" [attr.colspan]="h.colspan ? h.colspan : null" + [class.selectable-cell]="isSelectable(h)" [class.selected-cell]="isSelected(h)"> + + {{ h.title }} + </th> + </tr> + <tr> + <th *ngFor="let col of columns">{{ col.title }}</th> + </tr> + </ng-template> + + <ng-template pTemplate="body" let-row> + <tr [class.selected-row]="isSelected(row)"> + <td *ngFor="let cell of row.cells" + (click)="toggleSelection(cell, $event)" + [ngClass]="cell.class" + [class.editable-cell]="hasModel(cell)" [class.readonly-cell]="! hasModel(cell)" + [class.selectable-cell]="isSelectable(cell)" [class.selected-cell]="isSelected(cell) && ! isSelected(row)" + [attr.rowspan]="rowSpan(cell)" [attr.colspan]="colSpan(cell)"> + + <input matInput *ngIf="isNumberInput(cell)" type="text" [(ngModel)]="cell.model.singleValue"> + + <mat-select *ngIf="isSelect(cell)" [(value)]="cell.model"> + <!-- <mat-option *ngFor="let opt of cell.options | keyvalue" [value]="l.key"> + {{ l.value }} + </mat-option> --> + <mat-option *ngFor="let opt of cell.options" [value]="opt"> + {{ opt }} + </mat-option> + </mat-select> + + <span *ngIf="! hasModel(cell)">{{ cellValue(cell) }}</span> + </td> + </tr> + </ng-template> + </p-table> + + <!-- <pre>{{ rows | json }}</pre> --> + <!-- <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) diff --git a/src/app/components/pab-table/pab-table.component.scss b/src/app/components/pab-table/pab-table.component.scss index fcc76e8963f179c1243149cc1e3a445045d251c9..05a284ae028eb49b574162af406fad93d3d80bd4 100644 --- a/src/app/components/pab-table/pab-table.component.scss +++ b/src/app/components/pab-table/pab-table.component.scss @@ -15,7 +15,7 @@ mat-card-header { // 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; + font-size: 16px !important; margin-bottom: 8px; } } @@ -23,3 +23,93 @@ mat-card-header { mat-card-content { margin-top: 1em; } + +// cells colors + +@import "../../../theme.scss"; + +.editable-cell-bg { + // background-color: #e9f5ff; + // background-color: yellow; + @extend .bg-accent-extralight; +} +.selected-row-bg { + // background-color: green; + // @extend .bg-warn-extralight; + @extend .bg-warn-extralight; +} +.selected-cell-bg { + // background-color: red; + // @extend .bg-warn-extralight; + @extend .bg-warn-extralight; +} +.selected-editable-cell-bg { + // background-color: red; + @extend .bg-accent-verylight; +} + +.pab-data-table { + ::ng-deep .ui-table.ui-widget { + table { + thead.ui-table-thead { + > tr { + > th { + font-size: .8em; + padding: 6px 8px; + &.selectable-cell { + cursor: pointer; + } + &.selected-cell { + @extend .selected-cell-bg; + } + } + } + } + tbody.ui-table-tbody { + > tr { + &.selected-row { + @extend .selected-row-bg; + > td { + &.editable-cell { + @extend .selected-editable-cell-bg; + } + } + } + > td { + &:nth-child(1) { + width: 50px; + } + font-size: .8em; + &.readonly-cell { + cursor: default; + padding: 4px 8px; + } + &.editable-cell { + @extend .editable-cell-bg; + padding: 0; + > input.mat-input-element { + padding: 4px 8px; + } + } + &.selectable-cell { + cursor: pointer; + } + &.selected-cell { + @extend .selected-cell-bg; + &.editable-cell { + @extend .selected-editable-cell-bg; + } + } + &.basin_number { + text-align: center; + font-weight: bold; + } + > mat-select.mat-select { + padding: 0 8px; + } + } + } + } + } + } +} diff --git a/src/app/components/pab-table/pab-table.component.ts b/src/app/components/pab-table/pab-table.component.ts index 695c33fc3cd3f0de55d662ae197c6d580f5b959e..0364c44b810bb7a57adc31496d28a3a18832af77 100644 --- a/src/app/components/pab-table/pab-table.component.ts +++ b/src/app/components/pab-table/pab-table.component.ts @@ -1,6 +1,7 @@ -import { Component, Input, Output, EventEmitter, QueryList, ViewChildren, DoCheck, AfterViewInit } from "@angular/core"; +import { Component, Input, Output, EventEmitter, DoCheck, AfterViewInit, OnInit } from "@angular/core"; + +import { Pab, Session, PabCloisons, Props, CalculatorType, ParallelStructure, LoiDebit, StructureProperties, Cloisons, Nub } from "jalhyd"; -import { FieldSetComponent } from "../field-set/field-set.component"; import { I18nService } from "../../services/internationalisation/internationalisation.service"; import { PabTable } from "../../formulaire/pab-table"; @@ -14,48 +15,45 @@ import { PabTable } from "../../formulaire/pab-table"; "./pab-table.component.scss" ] }) -export class PabTableComponent implements DoCheck, AfterViewInit { +export class PabTableComponent implements /* DoCheck, AfterViewInit, */ OnInit { @Input() private pabTable: PabTable; - /** - * liste des composants FieldSet enfants - */ - @ViewChildren(FieldSetComponent) - private _fieldsetComponents: QueryList<FieldSetComponent>; - - /** - * flag de validité des FieldSet enfants - */ + /** 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é - */ + /** événément de changement de validité */ @Output() private validChange = new EventEmitter(); - /** - * événément de changement de valeur d'un input - */ + /** é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>(); + /** underlying Pab, binded to the rows */ + private model: Pab; + + /** general headers above the columns */ + public headers: any[]; + + /** columns headers description */ + public cols: any[]; + + /** data binded to the table */ + public rows: any[]; + + /** items currently selected */ + private selectedItems: any[]; + + /** used for shift+click implementation */ + private latestClickedCell: any; public constructor( private i18nService: I18nService - ) { } + ) { + this.selectedItems = []; + } public get title(): string { return this.i18nService.localizeText("INFO_PAB_TABLE"); @@ -65,39 +63,570 @@ export class PabTableComponent implements DoCheck, AfterViewInit { return this._isValid; } + /** returns true if the cell has an underlying model (ie. is editable) */ + public hasModel(cell: any): boolean { + return (cell !== undefined && cell.model !== undefined); + } + + /** returns true if the cell is an editable number */ + public isNumberInput(cell: any): boolean { + return this.hasModel(cell) && ! this.isSelect(cell); + } + + /** returns true if the cell is a select box @TODO rename */ + public isSelect(cell: any): boolean { + return this.hasModel(cell) && (cell.options !== undefined); + } + + /** value to display in a cell, if it is not editable */ + public cellValue(cell: any) { + if (cell === undefined) { + return ""; + } else { + if (this.hasModel(cell)) { + return cell.model; + } else { + return cell.value; + } + } + } + + public rowSpan(cell: any) { + if (cell !== undefined && cell.rowspan) { + return cell.rowspan; + } + return undefined; + } + + public colSpan(cell: any) { + if (cell !== undefined && cell.colspan) { + return cell.colspan; + } + return undefined; + } + + /** returns true if the cell / row has a selectable item */ + public isSelectable(cellOrRow: any): boolean { + return ( + cellOrRow !== undefined + && cellOrRow.selectable + ); + } + + /** returns true if the cell / row has a selectableColumn item */ + public isSelectableByColumn(cellOrRow: any): boolean { + return ( + cellOrRow !== undefined + && cellOrRow.selectableColumn + ); + } + /** - * Ajoute un nouveau sous-nub (Structure, PabCloisons selon le cas) - * dans un nouveau fieldset + * - checks if the cell / row has a selectable item, that is currently + * selected + * - if cell / row has a selectableColumn attribute, also checks if + * this column is selected + * + * returns true if at least one criterion is met */ - /* 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; + public isSelected(cellOrRow: any): boolean { + let cellSelected = false; + let columnSelected = false; + // cell + if (this.isSelectable(cellOrRow)) { + cellSelected = true; + if (Array.isArray(cellOrRow.selectable)) { + for (const elt of cellOrRow.selectable) { + cellSelected = cellSelected && this.selectedItems.includes(elt); } + } else { + cellSelected = this.selectedItems.includes(cellOrRow.selectable); } - } else { - this._container.addFromTemplate(0); } - } */ + // column + if (this.isSelectableByColumn(cellOrRow)) { + columnSelected = this.isDeviceColumnSelected(cellOrRow.selectableColumn); + } + // done + return (cellSelected || columnSelected); + } + + /** + * returns true if every wall (including downwall) has its nth device + * selected (or has no nth device) + */ + public isDeviceColumnSelected(n: number): boolean { + let ok = true; + for (const c of this.model.children) { + const nthChild = c.getChildren()[n]; + if (nthChild) { + ok = ok && this.selectedItems.includes(nthChild); + } + } + const nthChildDW = this.model.downWall.getChildren()[n]; + if (nthChildDW) { + ok = ok && this.selectedItems.includes(nthChildDW); + } + return ok; + } + + /** + * selects or unselects the clicked cell, depending on its current state + * and the modifier key held if any + */ + public toggleSelection(cell: any, $event: any) { + if ( + this.isSelectable(cell) + && ! this.hasModel(cell) // editable cells listen to the click event for edition only + ) { + if ($event.shiftKey && cell !== this.latestClickedCell) { // shift + click + // @TODO interpopolate from this.latestClickedCell to this one + console.log("shift + click"); + + } else if ( + $event.ctrlKey // ctrl + click + || ($event.shiftKey && cell === this.latestClickedCell) // shift on same cell => equiv. of ctrl + ) { + if (this.isSelected(cell)) { + // unselect this cell / these cells + if (Array.isArray(cell.selectable)) { + this.selectedItems = this.selectedItems.filter(e => ! cell.selectable.includes(e)); + } else { + this.selectedItems = this.selectedItems.filter(e => e !== cell.selectable); + } + } else { + // add this cell / these cells to selection + if (Array.isArray(cell.selectable)) { + this.selectedItems = this.selectedItems.concat(cell.selectable); + this.selectedItems = this.selectedItems.filter( + (item, index) => this.selectedItems.indexOf(item) === index // deduplicate + ); + } else { + this.selectedItems.push(cell.selectable); + } + } + + } else { // just a click + if (this.isSelected(cell)) { + // select nothing + this.selectedItems = []; + } else { + // select this cell / thses cells only + if (Array.isArray(cell.selectable)) { + this.selectedItems = cell.selectable.slice(); // array copy + } else { + this.selectedItems = [ cell.selectable ]; + } + } + } + this.latestClickedCell = cell; + // @TODO + /* $event.preventDefault(); + $event.stopPropagation(); + return false; */ + } + } - public ngAfterViewInit() { - /* this.onFieldsetListChange(); - this._fieldsetComponents.changes.subscribe(_ => this.onFieldsetListChange()); */ + // DEBUG + private dumpParams(n: Nub) { + console.log(`---- PARAMETERS FOR NUB "${n.uid}" (${n.constructor.name}) ----`); + for (const p of n.parameterIterator) { + if (p.visible) { + console.log(`> ${p.symbol} : ${p.singleValue}, ${p.currentValue}, ${p.v}`); + } + } + } + + public zpouet() { + console.log("!!!------------ zpoueeeeeeeeet ------------!!!"); + for (const c of this.model.children) { + this.dumpParams(c); + } + this.dumpParams(this.model.downWall); + } + + // at this time @Input data is supposed to be already populated + public ngOnInit() { + // get model + this.model = this.pabTable.pab; + + // ------------- TEST ------------------------ + + // empty PAB + const chLen = this.model.children.length; + for (let i = 0; i < chLen; i++) { + this.model.deleteChild(0); + } + + // cloison à 1 ouvrage + const cl1 = Session.getInstance().createNub( + new Props({ calcType: CalculatorType.Cloisons }) + ) as Cloisons; + cl1.addChild(Session.getInstance().createNub( + new Props({ calcType: CalculatorType.Structure, loiDebit: LoiDebit.RectangularOrificeFree }), cl1 + )); + // PabCloison associé + const pc1 = Session.getInstance().createNub( + new Props({ calcType: CalculatorType.PabCloisons }), this.model + ) as PabCloisons; + pc1.initModelCloisons(cl1); + pc1.prms.setCurrentValuesFromModel(); + this.model.addChild(pc1); + this.dumpParams(pc1); + + // cloison à 3 ouvrages + const cl2 = Session.getInstance().createNub( + new Props({ calcType: CalculatorType.Cloisons }) + ) as Cloisons; + cl2.addChild(Session.getInstance().createNub( + new Props({ calcType: CalculatorType.Structure, loiDebit: LoiDebit.GateCem88v }), cl2 + )); + cl2.addChild(Session.getInstance().createNub( + new Props({ calcType: CalculatorType.Structure, loiDebit: LoiDebit.RectangularOrificeFree }), cl2 + )); + cl2.addChild(Session.getInstance().createNub( + new Props({ calcType: CalculatorType.Structure, loiDebit: LoiDebit.RectangularOrificeSubmerged }), cl2 + )); + // PabCloison associé + const pc2 = Session.getInstance().createNub( + new Props({ calcType: CalculatorType.PabCloisons }), this.model + ) as PabCloisons; + pc2.initModelCloisons(cl2); + pc2.prms.setCurrentValuesFromModel(); + this.model.addChild(pc2); + this.dumpParams(pc2); + + // cloison à 2 ouvrages + const cl3 = Session.getInstance().createNub( + new Props({ calcType: CalculatorType.Cloisons }) + ) as Cloisons; + cl3.addChild(Session.getInstance().createNub( + new Props({ calcType: CalculatorType.Structure, loiDebit: LoiDebit.GateCem88v }), cl3 + )); + cl3.addChild(Session.getInstance().createNub( + new Props({ calcType: CalculatorType.Structure, loiDebit: LoiDebit.RectangularOrificeFree }), cl3 + )); + // PabCloison associé + const pc3 = Session.getInstance().createNub( + new Props({ calcType: CalculatorType.PabCloisons }), this.model + ) as PabCloisons; + pc3.initModelCloisons(cl3); + pc3.prms.setCurrentValuesFromModel(); + this.model.addChild(pc3); + this.dumpParams(pc3); + + // cloison aval à 1 ouvrage + const cloisonAval: ParallelStructure = Session.getInstance().createSessionNub( + new Props({ calcType: CalculatorType.ParallelStructure }) + ) as ParallelStructure; + cloisonAval.addChild(Session.getInstance().createNub( + new Props({ calcType: CalculatorType.Structure, loiDebit: LoiDebit.KIVI }), cloisonAval + )); + this.model.setDownWall(cloisonAval.uid); + this.dumpParams(this.model.downWall); + + // debug + console.log("Model in ngOnInit:", this.model); + + // ------------- FIN TEST -------------------- + + this.buildTable(); + } + + /** + * Builds the editable data grid from the Pab model + */ + private buildTable() { + const maxNbDevices = this.findMaxNumberOfDevices(); + + // 0. build spanned headers over real columns + this.headers = []; + // 1 header for basin + this.headers.push({ + title: "Bassin", + colspan: 6 + }); + // 1 header for each device of the wall having the most devices (including downwall) + for (let i = 0; i < maxNbDevices; i++) { + this.headers.push({ + title: "Cloison : ouvrage n°" + (i + 1), + colspan: 3, + selectable: this.model.children.map(c => c.getChildren()[i]).concat(this.model.downWall.getChildren()[i]), + selectableColumn: i + }); + } + + // A. build columns set + this.cols = []; + // 6 cols for basin + this.cols.push({ + title: "N° de bassin" + }); + this.cols.push({ + title: "Longueur" + }); + this.cols.push({ + title: "Largeur" + }); + this.cols.push({ + title: "Débit d'attrait" + }); + this.cols.push({ + title: "Cote radier mi-bassin" + }); + this.cols.push({ + title: "Cote radier amont paroi" + }); + // no col for wall type (defined by rowspan-2 header above) + // 3 cols for each device of the wall having the most devices (including downwall) + for (let i = 0; i < maxNbDevices; i++) { + this.cols.push({ + title: "Type" + }); + this.cols.push({ + title: "Paramètres" + }); + this.cols.push({ + title: "Valeurs" + }); + } + + // B. Build rows set + this.rows = []; + // B.1 many rows for each wall + let childIndex = 0; + for (const cloison of this.model.children) { + // as much rows as the greatest number of parameters among its devices + const maxNbParams = this.findMaxNumberOfDeviceParameters(cloison); + // console.log(">>> max nb params: ", maxNbParams); + for (let i = 0; i < maxNbParams; i++) { + // build device params row + const deviceParamRow = { selectable: cloison, cells: [] }; + // basin number + if (i === 0) { + deviceParamRow.cells.push({ + value: childIndex + 1, + rowspan: maxNbParams + 1, + class: "basin_number", + selectable: cloison + }); + } + // 5 empty cells + if (i === 0) { + deviceParamRow.cells.push({ + colspan: 5, + rowspan: maxNbParams, + selectable: cloison + }); + } + // device param cells : 3 cells for each device + for (const ouvrage of cloison.structures) { + const nvParam = ouvrage.getNthVisibleParam(i); + // cell 1 : device type + if (i === 0) { // 1st row + deviceParamRow.cells.push({ + model: ouvrage.properties.getPropValue("loiDebit"), + // options: StructureProperties.findCompatibleLoiDebit(ouvrage) + options: [ "salut", "coucou", "pouet" ], + selectable: ouvrage + }); + } + // fill space + if (i === 1) { + deviceParamRow.cells.push({ + rowspan: (maxNbParams - 1), + selectable: ouvrage + }); + } + // cell 2 : param name + if (nvParam) { + deviceParamRow.cells.push({ + value: nvParam.symbol, + selectable: ouvrage + }); + } else { + deviceParamRow.cells.push({ + selectable: ouvrage + }); + } + // cell 3 : param value + if (nvParam) { + deviceParamRow.cells.push({ + model: nvParam, + selectable: ouvrage + }); + } else { + deviceParamRow.cells.push({ + selectable: ouvrage + }); + } + } + // fill horizontal space + const devDiff = (maxNbDevices - cloison.structures.length); + if (i === 0) { + for (let j = 0; j < devDiff; j++) { + deviceParamRow.cells.push({ + colspan: 3, + rowspan: maxNbParams, + selectable: cloison, + selectableColumn: cloison.structures.length + j + }); + } + } + // done ! + this.rows.push(deviceParamRow); + } + // 1 row for the basin after the wall + const basinRow: { selectable: any, cells: any[] } = { + selectable: cloison, + cells: [ + // no cell for basin number (defined by rowspan-n cell above) + { + model: cloison.prms.LB + }, + { + model: cloison.prms.BB + }, + { + model: cloison.prms.QA + }, + { + model: cloison.prms.ZRMB + }, + { + model: cloison.prms.ZRAM + } + ] + }; + // fill horizontal space + for (let i = 0; i < maxNbDevices; i++) { + basinRow.cells.push({ + colspan: 3 + }); + } + // done ! + this.rows.push(basinRow); + childIndex ++; + } + + // B.2 many rows for downwall + // as much rows as the greatest number of parameters among its devices + const maxNbParamsDW = this.findMaxNumberOfDeviceParameters(this.model.downWall); + for (let i = 0; i < maxNbParamsDW; i++) { + // build device params row + const deviceParamRowDW = { selectable: this.model.downWall, cells: [] }; + // basin number + if (i === 0) { + deviceParamRowDW.cells.push({ + value: "Aval", + rowspan: maxNbParamsDW, + class: "basin_number", + selectable: this.model.downWall + }); + } + // 5 empty cells + if (i === 0) { + deviceParamRowDW.cells.push({ + colspan: 5, + rowspan: maxNbParamsDW, + selectable: this.model.downWall + }); + } + // downwall device param cells : 3 cells for each device + for (const ouvrage of this.model.downWall.structures) { + const nvParam = ouvrage.getNthVisibleParam(i); + // cell 1 : device type + if (i === 0) { // 1st row + deviceParamRowDW.cells.push({ + model: ouvrage.properties.getPropValue("loiDebit"), + // options: StructureProperties.findCompatibleLoiDebit(ouvrage) + options: [ "salut", "coucou", "pouet" ] + }); + } + // fill space + if (i === 1) { + deviceParamRowDW.cells.push({ + rowspan: (maxNbParamsDW - 1), + selectable: ouvrage + }); + } + // cell 2 : param name + if (nvParam) { + deviceParamRowDW.cells.push({ + value: nvParam.symbol, + selectable: ouvrage + }); + } else { + deviceParamRowDW.cells.push({ + selectable: ouvrage + }); + } + // cell 3 : param value + if (nvParam) { + deviceParamRowDW.cells.push({ + model: nvParam, + selectable: ouvrage + }); + } else { + deviceParamRowDW.cells.push({ + selectable: ouvrage + }); + } + } + // fill horizontal space + const devDiff = (maxNbDevices - this.model.downWall.structures.length); + if (i === 0) { + for (let j = 0; j < devDiff; j++) { + deviceParamRowDW.cells.push({ + colspan: 3, + rowspan: maxNbParamsDW, + selectable: this.model.downWall, + selectableColumn: this.model.downWall.structures.length + j + }); + } + } + // done ! + this.rows.push(deviceParamRowDW); + } + } + + private findMaxNumberOfDevices(): number { + let maxNbDevices = 1; + for (const w of this.model.children) { + maxNbDevices = Math.max(maxNbDevices, w.getChildren().length); + } + maxNbDevices = Math.max(maxNbDevices, this.model.downWall.getChildren().length); + return maxNbDevices; + } + + private findMaxNumberOfDeviceParameters(struct: ParallelStructure): number { + let maxNbParams = 1; + for (const d of struct.getChildren()) { + let nbParams = 0; + for (const p of d.parameterIterator) { + if (p.visible) { + // console.log("(counting)", p.symbol); + nbParams ++; + } + } + // console.log(">>> child params: ", nbParams); + maxNbParams = Math.max(maxNbParams, nbParams); + } + return maxNbParams; + } + + /* 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 - */ + * @TODO Calcul de la validité de la Pab + */ private updateValidity() { this._isValid = false; @@ -130,20 +659,6 @@ export class PabTableComponent implements DoCheck, AfterViewInit { 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 */ diff --git a/src/app/formulaire/definition/concrete/form-pab.ts b/src/app/formulaire/definition/concrete/form-pab.ts index c8dce277d616d4029dfd522596d07a53e1c9e37d..0ad94bf6673b8f267aa56dc9125910cea7473616 100644 --- a/src/app/formulaire/definition/concrete/form-pab.ts +++ b/src/app/formulaire/definition/concrete/form-pab.ts @@ -31,7 +31,7 @@ export class FormulairePab extends FormulaireBase { this._formCompute = new FormComputePab(this, (this._formResult as FormResultPab)); } - private get pabNub(): Pab { + public get pabNub(): Pab { return this.currentNub as Pab; } @@ -230,7 +230,7 @@ export class FormulairePab extends FormulaireBase { // 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})` @@ -238,6 +238,6 @@ export class FormulairePab extends FormulaireBase { } if (pab.downWall) { console.log(`+ downstream wall: ${pab.downWall.uid}`); - } */ + } } } diff --git a/src/app/formulaire/pab-table.ts b/src/app/formulaire/pab-table.ts index 1591b4a188462d0c5fcffb6e8e42c55ab97bdce0..9464eeef8ba8baaacf454afd9e3eb201b5c3e103 100644 --- a/src/app/formulaire/pab-table.ts +++ b/src/app/formulaire/pab-table.ts @@ -1,8 +1,14 @@ +import { Pab } from "jalhyd"; + import { FormulaireElement } from "./formulaire-element"; import { FormulaireNode } from "./formulaire-node"; +import { FormulairePab } from "./definition/concrete/form-pab"; /** - * The big editable data grid for calculator type "Pab" (model) + * The big editable data grid for calculator type "Pab" (form element). + * + * This is just a gateway between the model (FormPab and its underlying Pab) + * and the user interface (PabTableComponent) */ export class PabTable extends FormulaireElement { @@ -15,4 +21,20 @@ export class PabTable extends FormulaireElement { public parseConfig(json: {}) { this._confId = json["id"]; } + + /** + * Returns the parent FormulairePab + */ + public get form(): FormulairePab { + return this.parentForm as FormulairePab; + } + + /** + * Returns the Pab model associated to the parent form + */ + public get pab(): Pab { + if (this.form) { + return this.form.pabNub; + } + } } diff --git a/src/theme.scss b/src/theme.scss index 7c38e7153a7ffc8bddc72f8fedaaa3bb948c16b2..f1704256b417d787226a4cb884504e6ec19c7ea2 100644 --- a/src/theme.scss +++ b/src/theme.scss @@ -183,12 +183,23 @@ $accent: map-get($nghyd-theme, accent); $warn: map-get($nghyd-theme, warn); // convenience classes (functions mat-* cannot be used outside of this file) + .color-primary { color: mat-color($primary); } .bg-primary { background-color: mat-color($primary); } +.bg-primary-light { + background-color: mat-color($primary, 300); +} +.bg-primary-verylight { + background-color: mat-color($primary, 100); +} +.bg-primary-extralight { + background-color: mat-color($primary, 50); +} + .color-accent { color: mat-color($accent); } @@ -198,12 +209,28 @@ $warn: map-get($nghyd-theme, warn); .bg-accent-light { background-color: mat-color($accent, 300); } +.bg-accent-verylight { + background-color: mat-color($accent, 100); +} +.bg-accent-extralight { + background-color: mat-color($accent, 50); +} + .color-warn { color: mat-color($warn); } .bg-warn { background-color: mat-color($warn); } +.bg-warn-light { + background-color: mat-color($warn, 300); +} +.bg-warn-verylight { + background-color: mat-color($warn, 100); +} +.bg-warn-extralight { + background-color: mat-color($warn, 50); +} .mat-button-toggle-checked { background-color: mat-color($accent);