diff --git a/packages/engine-formula/src/basics/common.ts b/packages/engine-formula/src/basics/common.ts index 45f404e8197c..d2414fb36289 100644 --- a/packages/engine-formula/src/basics/common.ts +++ b/packages/engine-formula/src/basics/common.ts @@ -175,6 +175,10 @@ export interface IUnitExcludedCell { [unitId: string]: Nullable<{ [sheetId: string]: ObjectMatrix }>; } +export interface IUnitRowData { + [unitId: string]: Nullable<{ [sheetId: string]: IObjectArrayPrimitiveType> }>; +} + export interface IFormulaDatasetConfig { formulaData: IFormulaData; arrayFormulaCellData: IArrayFormulaUnitCellType; @@ -190,6 +194,7 @@ export interface IFormulaDatasetConfig { allUnitData?: IUnitData; unitStylesData?: IUnitStylesData; unitSheetNameMap?: IUnitSheetNameMap; + rowData?: IUnitRowData; // Include rows hidden by filters } export enum ConcatenateType { diff --git a/packages/engine-formula/src/controller/calculate.controller.ts b/packages/engine-formula/src/controller/calculate.controller.ts index 4fea92d06924..cd82f60f0e45 100644 --- a/packages/engine-formula/src/controller/calculate.controller.ts +++ b/packages/engine-formula/src/controller/calculate.controller.ts @@ -76,7 +76,7 @@ export class CalculateController extends Disposable { private async _calculate( formulaDirtyData: Partial ) { - const { forceCalculation: forceCalculate = false, dirtyRanges = [], dirtyNameMap = {}, dirtyDefinedNameMap = {}, dirtyUnitFeatureMap = {}, dirtyUnitOtherFormulaMap = {}, clearDependencyTreeCache = {} } = formulaDirtyData; + const { forceCalculation: forceCalculate = false, dirtyRanges = [], dirtyNameMap = {}, dirtyDefinedNameMap = {}, dirtyUnitFeatureMap = {}, dirtyUnitOtherFormulaMap = {}, clearDependencyTreeCache = {}, rowData } = formulaDirtyData; const formulaData = this._formulaDataModel.getFormulaData(); @@ -96,6 +96,7 @@ export class CalculateController extends Disposable { dirtyUnitFeatureMap, dirtyUnitOtherFormulaMap, clearDependencyTreeCache, + rowData, }); } diff --git a/packages/engine-formula/src/index.ts b/packages/engine-formula/src/index.ts index ee4094350b64..8b1040323822 100644 --- a/packages/engine-formula/src/index.ts +++ b/packages/engine-formula/src/index.ts @@ -168,3 +168,4 @@ export { ENGINE_FORMULA_PLUGIN_CONFIG_KEY, type IUniverEngineFormulaConfig } fro export { generateRandomDependencyTreeId } from './engine/dependency/formula-dependency'; export { DependencyManagerBaseService } from './services/dependency-manager.service'; +export { type IUnitRowData } from './basics/common'; diff --git a/packages/engine-formula/src/models/formula-data.model.ts b/packages/engine-formula/src/models/formula-data.model.ts index efc32f682c18..53e5667aa73b 100644 --- a/packages/engine-formula/src/models/formula-data.model.ts +++ b/packages/engine-formula/src/models/formula-data.model.ts @@ -14,7 +14,7 @@ * limitations under the License. */ -import type { ICellData, IObjectMatrixPrimitiveType, IRange, IUnitRange, Nullable, Workbook } from '@univerjs/core'; +import type { ICellData, IObjectArrayPrimitiveType, IObjectMatrixPrimitiveType, IRange, IRowData, IUnitRange, Nullable, Workbook } from '@univerjs/core'; import type { IArrayFormulaRangeType, IArrayFormulaUnitCellType, @@ -24,10 +24,12 @@ import type { IRuntimeUnitDataType, ISheetData, IUnitData, + IUnitRowData, IUnitSheetNameMap, + IUnitStylesData, } from '../basics/common'; -import { Disposable, Inject, isFormulaId, isFormulaString, IUniverInstanceService, ObjectMatrix, RANGE_TYPE, UniverInstanceType } from '@univerjs/core'; +import { BooleanNumber, Disposable, Inject, isFormulaId, isFormulaString, IUniverInstanceService, ObjectMatrix, RANGE_TYPE, UniverInstanceType } from '@univerjs/core'; import { LexerTreeBuilder } from '../engine/analysis/lexer-tree-builder'; import { clearArrayFormulaCellDataByCell, updateFormulaDataByCellValue } from './utils/formula-data-util'; @@ -258,6 +260,8 @@ export class FormulaDataModel extends Disposable { const allUnitData: IUnitData = {}; + const unitStylesData: IUnitStylesData = {}; + const unitSheetNameMap: IUnitSheetNameMap = {}; for (const workbook of unitAllSheet) { @@ -287,15 +291,55 @@ export class FormulaDataModel extends Disposable { allUnitData[unitId] = sheetData; + unitStylesData[unitId] = workbook.getStyles(); + unitSheetNameMap[unitId] = sheetNameMap; } return { allUnitData, + unitStylesData, unitSheetNameMap, }; } + /** + * Get the hidden rows that are filtered or manually hidden. + * + * For formulas that are sensitive to hidden rows. + */ + getHiddenRowsFiltered() { + const unitAllSheet = this._univerInstanceService.getAllUnitsForType(UniverInstanceType.UNIVER_SHEET); + const rowData: IUnitRowData = {}; + + for (const workbook of unitAllSheet) { + const unitId = workbook.getUnitId(); + const sheets = workbook.getSheets(); + rowData[unitId] = {}; + + for (const sheet of sheets) { + const sheetId = sheet.getSheetId(); + rowData[unitId][sheetId] = {}; + + const startRow = 0; + const endRow = sheet.getRowCount() - 1; + const sheetRowData: IObjectArrayPrimitiveType> = {}; + + for (let i = startRow; i <= endRow; i++) { + if (!sheet.getRowVisible(i)) { + sheetRowData[i] = { + hd: BooleanNumber.TRUE, + }; + } + } + + rowData[unitId][sheetId] = sheetRowData; + } + } + + return rowData; + } + updateFormulaData(unitId: string, sheetId: string, cellValue: IObjectMatrixPrimitiveType>) { const cellMatrix = new ObjectMatrix(cellValue); diff --git a/packages/engine-formula/src/services/current-data.service.ts b/packages/engine-formula/src/services/current-data.service.ts index fb7344131b03..1853fe4a6190 100644 --- a/packages/engine-formula/src/services/current-data.service.ts +++ b/packages/engine-formula/src/services/current-data.service.ts @@ -14,7 +14,7 @@ * limitations under the License. */ -import type { IObjectArrayPrimitiveType, IRowData, IUnitRange, LocaleType, Nullable, Workbook, Worksheet } from '@univerjs/core'; +import type { IUnitRange, LocaleType, Nullable, Workbook } from '@univerjs/core'; import type { IArrayFormulaRangeType, IDirtyUnitFeatureMap, @@ -24,16 +24,17 @@ import type { IFormulaData, IFormulaDatasetConfig, IRuntimeUnitDataType, - ISheetData, IUnitData, IUnitExcludedCell, + IUnitRowData, IUnitSheetIdToNameMap, IUnitSheetNameMap, IUnitStylesData, } from '../basics/common'; -import { BooleanNumber, createIdentifier, Disposable, Inject, IUniverInstanceService, LocaleService, ObjectMatrix, UniverInstanceType } from '@univerjs/core'; +import { createIdentifier, Disposable, Inject, IUniverInstanceService, LocaleService, ObjectMatrix, UniverInstanceType } from '@univerjs/core'; import { convertUnitDataToRuntime } from '../basics/runtime'; +import { FormulaDataModel } from '../models/formula-data.model'; export interface IFormulaDirtyData { forceCalculation: boolean; @@ -43,6 +44,7 @@ export interface IFormulaDirtyData { dirtyUnitFeatureMap: IDirtyUnitFeatureMap; dirtyUnitOtherFormulaMap: IDirtyUnitOtherFormulaMap; clearDependencyTreeCache: IDirtyUnitSheetNameMap; // unitId -> sheetId + rowData?: IUnitRowData; // Include rows hidden by filters } export interface IFormulaCurrentConfigService { @@ -143,7 +145,8 @@ export class FormulaCurrentConfigService extends Disposable implements IFormulaC constructor( @IUniverInstanceService private readonly _univerInstanceService: IUniverInstanceService, - @Inject(LocaleService) private readonly _localeService: LocaleService + @Inject(LocaleService) private readonly _localeService: LocaleService, + @Inject(FormulaDataModel) private readonly _formulaDataModel: FormulaDataModel ) { super(); } @@ -287,6 +290,11 @@ export class FormulaCurrentConfigService extends Disposable implements IFormulaC this._sheetNameMap = unitSheetNameMap; } + // apply row data, including rows hidden by filters + if (config.rowData) { + this._applyUnitRowData(config.rowData); + } + this._formulaData = config.formulaData; this._arrayFormulaCellData = convertUnitDataToRuntime(config.arrayFormulaCellData); @@ -449,81 +457,50 @@ export class FormulaCurrentConfigService extends Disposable implements IFormulaC } private _loadSheetData() { - const unitAllSheet = this._univerInstanceService.getAllUnitsForType(UniverInstanceType.UNIVER_SHEET); - const workbook = this._univerInstanceService.getCurrentUnitForType(UniverInstanceType.UNIVER_SHEET)!; const worksheet = workbook?.getActiveSheet(); this._executeUnitId = workbook?.getUnitId(); this._executeSubUnitId = worksheet?.getSheetId(); - const allUnitData: IUnitData = {}; - - const unitStylesData: IUnitStylesData = {}; - - const unitSheetNameMap: IUnitSheetNameMap = {}; - - for (const workbook of unitAllSheet) { - const unitId = workbook.getUnitId(); + return this._formulaDataModel.getCalculateData(); + } - const sheets = workbook.getSheets(); + /** + * There is no filter information in the worker, it must be passed in from the main thread after it is ready + * @param rowData + */ + private _applyUnitRowData(rowData: IUnitRowData) { + for (const unitId in rowData) { + if (rowData[unitId] == null) { + continue; + } - const sheetData: ISheetData = {}; + for (const sheetId in rowData[unitId]) { + if (rowData[unitId][sheetId] == null) { + continue; + } - const sheetNameMap: { [sheetName: string]: string } = {}; + if (this._unitData[unitId] == null) { + this._unitData[unitId] = {}; + } - for (const sheet of sheets) { - const sheetId = sheet.getSheetId(); + if (this._unitData[unitId][sheetId] == null) { + this._unitData[unitId][sheetId] = { + cellData: new ObjectMatrix({}), + rowCount: 0, + columnCount: 0, + rowData: {}, + columnData: {}, + }; + } - const sheetConfig = sheet.getConfig(); - sheetData[sheetId] = { - cellData: new ObjectMatrix(sheetConfig.cellData), - rowCount: sheetConfig.rowCount, - columnCount: sheetConfig.columnCount, - rowData: getHiddenRowsFiltered(sheet), - columnData: sheetConfig.columnData, - defaultRowHeight: sheetConfig.defaultRowHeight, - defaultColumnWidth: sheetConfig.defaultColumnWidth, - }; - sheetNameMap[sheet.getName()] = sheet.getSheetId(); + this._unitData[unitId][sheetId].rowData = rowData[unitId][sheetId]; } - - allUnitData[unitId] = sheetData; - - unitStylesData[unitId] = workbook.getStyles(); - - unitSheetNameMap[unitId] = sheetNameMap; } - - return { - allUnitData, - unitStylesData, - unitSheetNameMap, - }; } } export const IFormulaCurrentConfigService = createIdentifier( 'univer.formula.current-data.service' ); - -/** - * Get the hidden rows that are filtered or manually hidden. - * - * For formulas that are sensitive to hidden rows. - */ -function getHiddenRowsFiltered(sheet: Worksheet): IObjectArrayPrimitiveType> { - const startRow = 0; - const endRow = sheet.getRowCount() - 1; - const rowData: IObjectArrayPrimitiveType> = {}; - - for (let i = startRow; i <= endRow; i++) { - if (!sheet.getRowVisible(i)) { - rowData[i] = { - hd: BooleanNumber.TRUE, - }; - } - } - - return rowData; -} diff --git a/packages/sheets-filter/src/controllers/sheets-filter.controller.ts b/packages/sheets-filter/src/controllers/sheets-filter.controller.ts index 3a69f9b4b665..81ead22070c8 100644 --- a/packages/sheets-filter/src/controllers/sheets-filter.controller.ts +++ b/packages/sheets-filter/src/controllers/sheets-filter.controller.ts @@ -19,8 +19,7 @@ import type { EffectRefRangeParams, IAddWorksheetMergeMutationParams, ICopySheet import type { ISetSheetsFilterCriteriaMutationParams, ISetSheetsFilterRangeMutationParams } from '../commands/mutations/sheets-filter.mutation'; import type { FilterColumn } from '../models/filter-model'; -import { Disposable, DisposableCollection, ICommandService, Inject, IUniverInstanceService, moveMatrixArray, Optional, Rectangle } from '@univerjs/core'; -import { DataSyncPrimaryController } from '@univerjs/rpc'; +import { Disposable, DisposableCollection, ICommandService, Inject, IUniverInstanceService, moveMatrixArray, Rectangle } from '@univerjs/core'; import { CopySheetCommand, EffectRefRangId, expandToContinuousRange, getSheetCommandTarget, InsertColCommand, InsertRowCommand, InsertRowMutation, INTERCEPTOR_POINT, MoveRangeCommand, MoveRowsCommand, RefRangeService, RemoveColCommand, RemoveRowCommand, RemoveRowMutation, RemoveSheetCommand, SetRangeValuesMutation, SetWorksheetActiveOperation, SheetInterceptorService } from '@univerjs/sheets'; import { ReCalcSheetsFilterMutation, RemoveSheetsFilterMutation, SetSheetsFilterCriteriaMutation, SetSheetsFilterRangeMutation } from '../commands/mutations/sheets-filter.mutation'; import { SheetsFilterService } from '../services/sheet-filter.service'; @@ -33,9 +32,7 @@ export class SheetsFilterController extends Disposable { @Inject(SheetInterceptorService) private readonly _sheetInterceptorService: SheetInterceptorService, @Inject(SheetsFilterService) private readonly _sheetsFilterService: SheetsFilterService, @IUniverInstanceService private readonly _univerInstanceService: IUniverInstanceService, - @Inject(RefRangeService) private readonly _refRangeService: RefRangeService, - @Optional(DataSyncPrimaryController) private readonly _dataSyncPrimaryController?: DataSyncPrimaryController - ) { + @Inject(RefRangeService) private readonly _refRangeService: RefRangeService) { super(); this._initCommands(); @@ -51,12 +48,7 @@ export class SheetsFilterController extends Disposable { SetSheetsFilterRangeMutation, ReCalcSheetsFilterMutation, RemoveSheetsFilterMutation, - ].forEach((command) => { - this.disposeWithMe(this._commandService.registerCommand(command)); - - // Hidden rows after filtering affect formula calculation - this._dataSyncPrimaryController?.registerSyncingMutations(command); - }); + ].forEach((command) => this.disposeWithMe(this._commandService.registerCommand(command))); } private _initInterceptors(): void { diff --git a/packages/sheets-filter/src/services/sheet-filter-formula.service.ts b/packages/sheets-filter/src/services/sheet-filter-formula.service.ts index 3ced7a3751f0..56836d3d124d 100644 --- a/packages/sheets-filter/src/services/sheet-filter-formula.service.ts +++ b/packages/sheets-filter/src/services/sheet-filter-formula.service.ts @@ -72,7 +72,7 @@ export class SheetsFilterFormulaService extends Disposable { const { startRow, endRow } = range; - // covert range to dirtyRanges + // covert hidden rows to dirtyRanges const dirtyRanges = [{ unitId, sheetId: subUnitId, diff --git a/packages/sheets-formula/src/controllers/trigger-calculation.controller.ts b/packages/sheets-formula/src/controllers/trigger-calculation.controller.ts index 7b2fb49b7a1f..5a34e3e6abdb 100644 --- a/packages/sheets-formula/src/controllers/trigger-calculation.controller.ts +++ b/packages/sheets-formula/src/controllers/trigger-calculation.controller.ts @@ -22,8 +22,7 @@ import type { IExecutionInProgressParams, IFormulaDirtyData, ISetFormulaCalculationNotificationMutation, - ISetFormulaCalculationStartMutation, -} from '@univerjs/engine-formula'; + ISetFormulaCalculationStartMutation } from '@univerjs/engine-formula'; import type { ISetRangeValuesMutationParams } from '@univerjs/sheets'; import type { IUniverSheetsFormulaBaseConfig } from './config.schema'; import { Disposable, ICommandService, IConfigService, ILogService, Inject, LocaleService } from '@univerjs/core'; @@ -164,6 +163,17 @@ export class TriggerCalculationController extends Disposable { } private _commandExecutedListener() { + // The filtering information is not synchronized to the worker and must be passed in from the main thread each time + this.disposeWithMe( + this._commandService.beforeCommandExecuted((command: ICommandInfo) => { + if (command.id === SetFormulaCalculationStartMutation.id) { + const params = command.params as ISetFormulaCalculationStartMutation; + + params.rowData = this._formulaDataModel.getHiddenRowsFiltered(); + } + }) + ); + this.disposeWithMe( this._commandService.onCommandExecuted((command: ICommandInfo, options) => { if (!this._activeDirtyManagerService.get(command.id)) { @@ -512,13 +522,13 @@ export class TriggerCalculationController extends Disposable { } private _initialExecuteFormula() { - const params = this._getDiryDataByCalculationMode(this._calculationMode); + const params = this._getDirtyDataByCalculationMode(this._calculationMode); this._commandService.executeCommand(SetFormulaCalculationStartMutation.id, params, lo); this._registerOtherFormulaService.calculateStarted$.next(true); } - private _getDiryDataByCalculationMode(calculationMode: CalculationMode): IFormulaDirtyData { + private _getDirtyDataByCalculationMode(calculationMode: CalculationMode): IFormulaDirtyData { const forceCalculation = calculationMode === CalculationMode.FORCED; // loop all sheets cell data, and get the dirty data diff --git a/packages/sheets-formula/src/controllers/update-formula.controller.ts b/packages/sheets-formula/src/controllers/update-formula.controller.ts index ad8e02c4886b..b5279b3379e6 100644 --- a/packages/sheets-formula/src/controllers/update-formula.controller.ts +++ b/packages/sheets-formula/src/controllers/update-formula.controller.ts @@ -274,12 +274,12 @@ export class UpdateFormulaController extends Disposable { const config = this._configService.getConfig(PLUGIN_CONFIG_KEY_BASE); const calculationMode = config?.initialFormulaComputing ?? CalculationMode.WHEN_EMPTY; - const params = this._getDiryDataByCalculationMode(calculationMode); + const params = this._getDirtyDataByCalculationMode(calculationMode); this._commandService.executeCommand(SetFormulaCalculationStartMutation.id, params, { onlyLocal: true }); } - private _getDiryDataByCalculationMode(calculationMode: CalculationMode): IFormulaDirtyData { + private _getDirtyDataByCalculationMode(calculationMode: CalculationMode): IFormulaDirtyData { const forceCalculation = calculationMode === CalculationMode.FORCED; // loop all sheets cell data, and get the dirty data