@odoo/o-spreadsheet 17.5.0-alpha.6 → 17.5.0-alpha.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -2,9 +2,9 @@
2
2
  /**
3
3
  * This file is generated by o-spreadsheet build tools. Do not edit it.
4
4
  * @see https://github.com/odoo/o-spreadsheet
5
- * @version 17.5.0-alpha.6
6
- * @date 2024-08-19T08:12:01.220Z
7
- * @hash c067f5d
5
+ * @version 17.5.0-alpha.7
6
+ * @date 2024-08-26T13:49:04.156Z
7
+ * @hash f8d3f23
8
8
  */
9
9
 
10
10
  'use strict';
@@ -267,6 +267,7 @@ const PIVOT_TABLE_CONFIG = {
267
267
  bandedRows: true,
268
268
  bandedColumns: false,
269
269
  styleId: "TableStyleMedium5",
270
+ automaticAutofill: true,
270
271
  };
271
272
 
272
273
  //------------------------------------------------------------------------------
@@ -2323,7 +2324,6 @@ exports.CommandResult = void 0;
2323
2324
  CommandResult["NoSplitSeparatorInSelection"] = "NoSplitSeparatorInSelection";
2324
2325
  CommandResult["NoActiveSheet"] = "NoActiveSheet";
2325
2326
  CommandResult["InvalidLocale"] = "InvalidLocale";
2326
- CommandResult["AlreadyInPaintingFormatMode"] = "AlreadyInPaintingFormatMode";
2327
2327
  CommandResult["MoreThanOneRangeSelected"] = "MoreThanOneRangeSelected";
2328
2328
  CommandResult["NoColumnsProvided"] = "NoColumnsProvided";
2329
2329
  CommandResult["ColumnsNotIncludedInZone"] = "ColumnsNotIncludedInZone";
@@ -4640,6 +4640,42 @@ function isOneDimensional(zone) {
4640
4640
  const { numberOfCols, numberOfRows } = zoneToDimension(zone);
4641
4641
  return numberOfCols === 1 || numberOfRows === 1;
4642
4642
  }
4643
+ function excludeTopLeft(zone) {
4644
+ const { top, left, bottom, right } = zone;
4645
+ if (getZoneArea(zone) === 1) {
4646
+ return [];
4647
+ }
4648
+ const leftColumnZone = {
4649
+ top: top + 1,
4650
+ bottom,
4651
+ left,
4652
+ right: left,
4653
+ };
4654
+ if (right === left) {
4655
+ return [leftColumnZone];
4656
+ }
4657
+ const rightPartZone = {
4658
+ top,
4659
+ bottom,
4660
+ left: left + 1,
4661
+ right,
4662
+ };
4663
+ if (top === bottom) {
4664
+ return [rightPartZone];
4665
+ }
4666
+ return [leftColumnZone, rightPartZone];
4667
+ }
4668
+ function aggregatePositionsToZones(positions) {
4669
+ const result = {};
4670
+ for (const position of positions) {
4671
+ result[position.sheetId] ??= [];
4672
+ result[position.sheetId].push(positionToZone(position));
4673
+ }
4674
+ for (const sheetId in result) {
4675
+ result[sheetId] = recomputeZones(result[sheetId]);
4676
+ }
4677
+ return result;
4678
+ }
4643
4679
  /**
4644
4680
  * Array of all positions in the zone.
4645
4681
  */
@@ -4814,16 +4850,6 @@ function getZonesRows(zones) {
4814
4850
  }
4815
4851
  return set;
4816
4852
  }
4817
- function unionPositionsToZone(positions) {
4818
- const zone = { top: Infinity, left: Infinity, bottom: -Infinity, right: -Infinity };
4819
- for (const { col, row } of positions) {
4820
- zone.top = Math.min(zone.top, row);
4821
- zone.left = Math.min(zone.left, col);
4822
- zone.bottom = Math.max(zone.bottom, row);
4823
- zone.right = Math.max(zone.right, col);
4824
- }
4825
- return zone;
4826
- }
4827
4853
  /**
4828
4854
  * Check if two zones are contiguous, ie. that they share a border
4829
4855
  */
@@ -10979,8 +11005,8 @@ const RANDARRAY = {
10979
11005
  const _min = toNumber(min, this.locale);
10980
11006
  const _max = toNumber(max, this.locale);
10981
11007
  const _whole_number = toBoolean(wholeNumber);
10982
- assertPositive(_t("The number columns (%s) must be positive.", _cols.toString()), _cols);
10983
- assertPositive(_t("The number rows (%s) must be positive.", _rows.toString()), _rows);
11008
+ assertPositive(_t("The number of columns (%s) must be positive.", _cols.toString()), _cols);
11009
+ assertPositive(_t("The number of rows (%s) must be positive.", _rows.toString()), _rows);
10984
11010
  assert(() => _min <= _max, _t("The maximum (%s) must be greater than or equal to the minimum (%s).", _max.toString(), _min.toString()));
10985
11011
  if (_whole_number) {
10986
11012
  assert(() => Number.isInteger(_min) && Number.isInteger(_max), _t("The maximum (%s) and minimum (%s) must be integers when whole_number is TRUE.", _max.toString(), _min.toString()));
@@ -11140,6 +11166,32 @@ const SECH = {
11140
11166
  isExported: true,
11141
11167
  };
11142
11168
  // -----------------------------------------------------------------------------
11169
+ // SEQUENCE
11170
+ // -----------------------------------------------------------------------------
11171
+ const SEQUENCE = {
11172
+ description: _t("Returns a sequence of numbers."),
11173
+ args: [
11174
+ arg("rows (number)", _t("The number of rows to return")),
11175
+ arg("columns (number, optional, default=1)", _t("The number of columns to return")),
11176
+ arg("start (number, optional, default=1)", _t("The first number in the sequence")),
11177
+ arg("step (number, optional, default=1)", _t("The amount to increment each value in the sequence")),
11178
+ ],
11179
+ compute: function (rows, columns = { value: 1 }, start = { value: 1 }, step = { value: 1 }) {
11180
+ const _start = toNumber(start, this.locale);
11181
+ const _step = toNumber(step, this.locale);
11182
+ const _rows = toInteger(rows, this.locale);
11183
+ const _columns = toInteger(columns, this.locale);
11184
+ assertPositive(_t("The number of columns (%s) must be positive.", _columns), _columns);
11185
+ assertPositive(_t("The number of rows (%s) must be positive.", _rows), _rows);
11186
+ return generateMatrix(_columns, _rows, (col, row) => {
11187
+ return {
11188
+ value: _start + row * _columns * _step + col * _step,
11189
+ };
11190
+ });
11191
+ },
11192
+ isExported: true,
11193
+ };
11194
+ // -----------------------------------------------------------------------------
11143
11195
  // SIN
11144
11196
  // -----------------------------------------------------------------------------
11145
11197
  const SIN = {
@@ -11351,6 +11403,7 @@ var math = /*#__PURE__*/Object.freeze({
11351
11403
  ROUNDUP: ROUNDUP,
11352
11404
  SEC: SEC,
11353
11405
  SECH: SECH,
11406
+ SEQUENCE: SEQUENCE,
11354
11407
  SIN: SIN,
11355
11408
  SINH: SINH,
11356
11409
  SQRT: SQRT,
@@ -30636,6 +30689,7 @@ const deleteSheet = {
30636
30689
  execute: (env) => env.askConfirmation(_t("Are you sure you want to delete this sheet?"), () => {
30637
30690
  env.model.dispatch("DELETE_SHEET", { sheetId: env.model.getters.getActiveSheetId() });
30638
30691
  }),
30692
+ icon: "o-spreadsheet-Icon.TRASH",
30639
30693
  };
30640
30694
  const duplicateSheet = {
30641
30695
  name: _t("Duplicate"),
@@ -30648,11 +30702,13 @@ const duplicateSheet = {
30648
30702
  });
30649
30703
  env.model.dispatch("ACTIVATE_SHEET", { sheetIdFrom, sheetIdTo });
30650
30704
  },
30705
+ icon: "o-spreadsheet-Icon.COPY",
30651
30706
  };
30652
30707
  const renameSheet = (args) => {
30653
30708
  return {
30654
30709
  name: _t("Rename"),
30655
30710
  execute: args.renameSheetCallback,
30711
+ icon: "o-spreadsheet-Icon.RENAME_SHEET",
30656
30712
  };
30657
30713
  };
30658
30714
  const sheetMoveRight = {
@@ -30666,6 +30722,7 @@ const sheetMoveRight = {
30666
30722
  sheetId: env.model.getters.getActiveSheetId(),
30667
30723
  delta: 1,
30668
30724
  }),
30725
+ icon: "o-spreadsheet-Icon.MOVE_SHEET_RIGHT",
30669
30726
  };
30670
30727
  const sheetMoveLeft = {
30671
30728
  name: _t("Move left"),
@@ -30677,11 +30734,13 @@ const sheetMoveLeft = {
30677
30734
  sheetId: env.model.getters.getActiveSheetId(),
30678
30735
  delta: -1,
30679
30736
  }),
30737
+ icon: "o-spreadsheet-Icon.MOVE_SHEET_LEFT",
30680
30738
  };
30681
30739
  const hideSheet = {
30682
30740
  name: _t("Hide sheet"),
30683
30741
  isVisible: (env) => env.model.getters.getVisibleSheetIds().length !== 1,
30684
30742
  execute: (env) => env.model.dispatch("HIDE_SHEET", { sheetId: env.model.getters.getActiveSheetId() }),
30743
+ icon: "o-spreadsheet-Icon.HIDE_SHEET",
30685
30744
  };
30686
30745
 
30687
30746
  //------------------------------------------------------------------------------
@@ -39806,7 +39865,6 @@ class FindAndReplaceStore extends SpreadsheetStore {
39806
39865
  searchScope: "activeSheet",
39807
39866
  specificRange: undefined,
39808
39867
  };
39809
- updateSearchContent = debounce(this._updateSearchContent.bind(this), 200);
39810
39868
  constructor(get) {
39811
39869
  super(get);
39812
39870
  this.initialShowFormulaState = this.model.getters.shouldShowFormulas();
@@ -39815,7 +39873,6 @@ class FindAndReplaceStore extends SpreadsheetStore {
39815
39873
  highlightStore.register(this);
39816
39874
  this.onDispose(() => {
39817
39875
  this.model.dispatch("SET_FORMULA_VISIBILITY", { show: this.initialShowFormulaState });
39818
- this.updateSearchContent.stopDebounce();
39819
39876
  highlightStore.unRegister(this);
39820
39877
  });
39821
39878
  }
@@ -39829,7 +39886,7 @@ class FindAndReplaceStore extends SpreadsheetStore {
39829
39886
  return this.specificRangeMatches;
39830
39887
  }
39831
39888
  }
39832
- _updateSearchContent(toSearch) {
39889
+ updateSearchContent(toSearch) {
39833
39890
  this._updateSearch(toSearch, this.searchOptions);
39834
39891
  }
39835
39892
  updateSearchOptions(searchOptions) {
@@ -39845,9 +39902,6 @@ class FindAndReplaceStore extends SpreadsheetStore {
39845
39902
  selectNextMatch() {
39846
39903
  this.selectNextCell(Direction.next);
39847
39904
  }
39848
- get pendingSearch() {
39849
- return this.updateSearchContent.isDebouncePending();
39850
- }
39851
39905
  handle(cmd) {
39852
39906
  switch (cmd.type) {
39853
39907
  case "SET_FORMULA_VISIBILITY":
@@ -40179,6 +40233,7 @@ class FindAndReplacePanel extends owl.Component {
40179
40233
  searchInput = owl.useRef("searchInput");
40180
40234
  store;
40181
40235
  state;
40236
+ updateSearchContent;
40182
40237
  get hasSearchResult() {
40183
40238
  return this.store.selectedMatchIndex !== null;
40184
40239
  }
@@ -40220,12 +40275,14 @@ class FindAndReplacePanel extends owl.Component {
40220
40275
  this.store = useLocalStore(FindAndReplaceStore);
40221
40276
  this.state = owl.useState({ dataRange: "" });
40222
40277
  owl.onMounted(() => this.searchInput.el?.focus());
40278
+ owl.onWillUnmount(() => this.updateSearchContent.stopDebounce());
40279
+ this.updateSearchContent = debounce(this.store.updateSearchContent, 200);
40223
40280
  }
40224
40281
  onFocusSearch() {
40225
40282
  this.updateDataRange();
40226
40283
  }
40227
40284
  onSearchInput(ev) {
40228
- this.store.updateSearchContent(ev.target?.value || "");
40285
+ this.updateSearchContent(ev.target.value);
40229
40286
  }
40230
40287
  onKeydownSearch(ev) {
40231
40288
  if (ev.key === "Enter") {
@@ -40264,6 +40321,9 @@ class FindAndReplacePanel extends owl.Component {
40264
40321
  const specificRange = this.env.model.getters.getRangeFromSheetXC(this.env.model.getters.getActiveSheetId(), this.state.dataRange);
40265
40322
  this.store.updateSearchOptions({ specificRange });
40266
40323
  }
40324
+ get pendingSearch() {
40325
+ return this.updateSearchContent.isDebouncePending();
40326
+ }
40267
40327
  }
40268
40328
 
40269
40329
  css /* scss */ `
@@ -40816,34 +40876,9 @@ class CogWheelMenu extends owl.Component {
40816
40876
  }
40817
40877
  }
40818
40878
 
40819
- /** @odoo-module */
40820
- class EditableName extends owl.Component {
40821
- static template = "o-spreadsheet-EditableName";
40822
- static props = {
40823
- name: String,
40824
- displayName: String,
40825
- onChanged: Function,
40826
- };
40827
- state;
40828
- setup() {
40829
- this.state = owl.useState({
40830
- isEditing: false,
40831
- name: "",
40832
- });
40833
- }
40834
- rename() {
40835
- this.state.isEditing = true;
40836
- this.state.name = this.props.name;
40837
- }
40838
- save() {
40839
- this.props.onChanged(this.state.name.trim());
40840
- this.state.isEditing = false;
40841
- }
40842
- }
40843
-
40844
40879
  class PivotTitleSection extends owl.Component {
40845
40880
  static template = "o-spreadsheet-PivotTitleSection";
40846
- static components = { CogWheelMenu, Section, EditableName };
40881
+ static components = { CogWheelMenu, Section, TextInput };
40847
40882
  static props = {
40848
40883
  pivotId: String,
40849
40884
  flipAxis: Function,
@@ -41410,6 +41445,12 @@ function orderDataEntriesKeys(groups, dimension) {
41410
41445
  * Used to order two values
41411
41446
  */
41412
41447
  function compareDimensionValues(dimension, a, b) {
41448
+ if (a === "null") {
41449
+ return dimension.order === "asc" ? 1 : -1;
41450
+ }
41451
+ if (b === "null") {
41452
+ return dimension.order === "asc" ? -1 : 1;
41453
+ }
41413
41454
  if (dimension.type === "integer" || dimension.type === "date") {
41414
41455
  return dimension.order === "asc" ? Number(a) - Number(b) : Number(b) - Number(a);
41415
41456
  }
@@ -41773,7 +41814,7 @@ class SpreadsheetPivot {
41773
41814
  if (cell.type === CellValueType.error) {
41774
41815
  throw new EvaluationError(_t("The pivot cannot be created because cell %s contains an error", toXC(col, row)));
41775
41816
  }
41776
- if (cell.type === CellValueType.empty) {
41817
+ if (cell.type === CellValueType.empty || cell.value === "") {
41777
41818
  throw new EvaluationError(_t("The pivot cannot be created because cell %s is empty", toXC(col, row)));
41778
41819
  }
41779
41820
  if (cell.value === "__count") {
@@ -42118,15 +42159,11 @@ class PivotSpreadsheetSidePanel extends owl.Component {
42118
42159
  }
42119
42160
  onSelectionConfirmed() {
42120
42161
  if (this.state.range) {
42121
- const { sheetName, xc } = splitReference(this.state.range);
42122
- const sheetId = sheetName
42123
- ? this.env.model.getters.getSheetIdByName(sheetName)
42124
- : this.env.model.getters.getActiveSheetId();
42125
- if (!sheetId) {
42162
+ const range = this.env.model.getters.getRangeFromSheetXC(this.env.model.getters.getActiveSheetId(), this.state.range);
42163
+ if (range.invalidSheetName || range.invalidXc) {
42126
42164
  return;
42127
42165
  }
42128
- const zone = toZone(xc);
42129
- const dataSet = { sheetId, zone };
42166
+ const dataSet = { sheetId: range.sheetId, zone: range.zone };
42130
42167
  this.store.update({ dataSet });
42131
42168
  // Immediately apply the update to recompute the pivot fields
42132
42169
  this.store.applyUpdate();
@@ -43064,10 +43101,6 @@ class TablePanel extends owl.Component {
43064
43101
  });
43065
43102
  }
43066
43103
  onRangeChanged(ranges) {
43067
- if (!ranges[0] || !ranges[0].match(rangeReference)) {
43068
- this.state.tableZoneErrors = ["InvalidRange" /* CommandResult.InvalidRange */];
43069
- return;
43070
- }
43071
43104
  const sheetId = this.env.model.getters.getActiveSheetId();
43072
43105
  this.state.tableXc = ranges[0];
43073
43106
  const newTableRange = this.env.model.getters.getRangeFromSheetXC(sheetId, this.state.tableXc);
@@ -43107,11 +43140,6 @@ class TablePanel extends owl.Component {
43107
43140
  const newTableRange = updatedTable.range;
43108
43141
  this.state.tableXc = this.env.model.getters.getRangeString(newTableRange, sheetId);
43109
43142
  }
43110
- else {
43111
- const oldTableRange = this.props.table.range;
43112
- this.state.tableXc = this.env.model.getters.getRangeString(oldTableRange, sheetId);
43113
- }
43114
- this.state.tableZoneErrors = [];
43115
43143
  }
43116
43144
  deleteTable() {
43117
43145
  const sheetId = this.env.model.getters.getActiveSheetId();
@@ -45200,6 +45228,64 @@ class GridAddRowsFooter extends owl.Component {
45200
45228
  }
45201
45229
  }
45202
45230
 
45231
+ class PaintFormatStore extends SpreadsheetStore {
45232
+ mutators = ["activate", "cancel", "pasteFormat"];
45233
+ highlightStore = this.get(HighlightStore);
45234
+ cellClipboardHandler = new CellClipboardHandler(this.getters, this.model.dispatch);
45235
+ status = "inactive";
45236
+ copiedData;
45237
+ constructor(get) {
45238
+ super(get);
45239
+ this.highlightStore.register(this);
45240
+ this.onDispose(() => {
45241
+ this.highlightStore.unRegister(this);
45242
+ });
45243
+ }
45244
+ activate(args) {
45245
+ this.copiedData = this.copyFormats();
45246
+ this.status = args.persistent ? "persistent" : "oneOff";
45247
+ }
45248
+ cancel() {
45249
+ this.status = "inactive";
45250
+ this.copiedData = undefined;
45251
+ }
45252
+ pasteFormat(target) {
45253
+ if (this.copiedData) {
45254
+ const sheetId = this.getters.getActiveSheetId();
45255
+ this.cellClipboardHandler.paste({ zones: target, sheetId }, this.copiedData, {
45256
+ isCutOperation: false,
45257
+ pasteOption: "onlyFormat",
45258
+ });
45259
+ }
45260
+ if (this.status === "oneOff") {
45261
+ this.cancel();
45262
+ }
45263
+ }
45264
+ get isActive() {
45265
+ return this.status !== "inactive";
45266
+ }
45267
+ copyFormats() {
45268
+ const sheetId = this.getters.getActiveSheetId();
45269
+ const zones = this.getters.getSelectedZones();
45270
+ return this.cellClipboardHandler.copy(getClipboardDataPositions(sheetId, zones));
45271
+ }
45272
+ get highlights() {
45273
+ const data = this.copiedData;
45274
+ if (!data) {
45275
+ return [];
45276
+ }
45277
+ return data.zones.map((zone) => ({
45278
+ zone,
45279
+ color: SELECTION_BORDER_COLOR,
45280
+ dashed: true,
45281
+ sheetId: data.sheetId,
45282
+ noFill: true,
45283
+ thinLine: true,
45284
+ interactive: false,
45285
+ }));
45286
+ }
45287
+ }
45288
+
45203
45289
  const CURSOR_SVG = /*xml*/ `
45204
45290
  <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="14" height="16"><path d="M6.5.4c1.3-.8 2.9-.1 3.8 1.4l2.9 5.1c.2.4.9 1.6-.4 2.3l-1.6.9 1.8 3.1c.2.4.1 1-.2 1.2l-1.6 1c-.3.1-.9 0-1.1-.4l-1.8-3.1-1.6 1c-.6.4-1.7 0-2.2-.8L0 4.3"/><path fill="#fff" d="M9.1 2a1.4 1.1 60 0 0-1.7-.6L5.5 2.5l.9 1.6-1 .6-.9-1.6-.6.4 1.8 3.1-1.3.7-1.8-3.1-1 .6 3.8 6.6 6.8-3.98M3.9 8.8 10.82 5l.795 1.4-6.81 3.96"/></svg>
45205
45291
  `;
@@ -45346,6 +45432,7 @@ class GridOverlay extends owl.Component {
45346
45432
  gridOverlay = owl.useRef("gridOverlay");
45347
45433
  gridOverlayRect = useAbsoluteBoundingRect(this.gridOverlay);
45348
45434
  cellPopovers;
45435
+ paintFormatStore;
45349
45436
  setup() {
45350
45437
  useCellHovered(this.env, this.gridOverlay, this.props.onCellHovered);
45351
45438
  const resizeObserver = new ResizeObserver(() => {
@@ -45368,6 +45455,7 @@ class GridOverlay extends owl.Component {
45368
45455
  return scrollY > 0;
45369
45456
  });
45370
45457
  this.cellPopovers = useStore(CellPopoverStore);
45458
+ this.paintFormatStore = useStore(PaintFormatStore);
45371
45459
  }
45372
45460
  get gridOverlayEl() {
45373
45461
  if (!this.gridOverlay.el) {
@@ -45379,7 +45467,7 @@ class GridOverlay extends owl.Component {
45379
45467
  return this.props.gridOverlayDimensions;
45380
45468
  }
45381
45469
  get isPaintingFormat() {
45382
- return this.env.model.getters.isPaintingFormat();
45470
+ return this.paintFormatStore.isActive;
45383
45471
  }
45384
45472
  onMouseDown(ev) {
45385
45473
  if (ev.button > 0) {
@@ -47266,6 +47354,7 @@ class Grid extends owl.Component {
47266
47354
  cellPopovers;
47267
47355
  composerFocusStore;
47268
47356
  DOMFocusableElementStore;
47357
+ paintFormatStore;
47269
47358
  onMouseWheel;
47270
47359
  canvasPosition;
47271
47360
  hoveredCell;
@@ -47283,6 +47372,7 @@ class Grid extends owl.Component {
47283
47372
  this.composerFocusStore = useStore(ComposerFocusStore);
47284
47373
  this.DOMFocusableElementStore = useStore(DOMFocusableElementStore);
47285
47374
  this.sidePanel = useStore(SidePanelStore);
47375
+ this.paintFormatStore = useStore(PaintFormatStore);
47286
47376
  useStore(ArrayFormulaHighlight);
47287
47377
  owl.useChildSubEnv({ getPopoverContainerRect: () => this.getGridRect() });
47288
47378
  owl.useExternalListener(document.body, "cut", this.copy.bind(this, true));
@@ -47359,8 +47449,8 @@ class Grid extends owl.Component {
47359
47449
  else if (this.menuState.isOpen) {
47360
47450
  this.closeMenu();
47361
47451
  }
47362
- else if (this.env.model.getters.isPaintingFormat()) {
47363
- this.env.model.dispatch("CANCEL_PAINT_FORMAT");
47452
+ else if (this.paintFormatStore.isActive) {
47453
+ this.paintFormatStore.cancel();
47364
47454
  }
47365
47455
  else {
47366
47456
  this.env.model.dispatch("CLEAN_CLIPBOARD_HIGHLIGHT");
@@ -47583,10 +47673,8 @@ class Grid extends owl.Component {
47583
47673
  }
47584
47674
  };
47585
47675
  const onMouseUp = () => {
47586
- if (this.env.model.getters.isPaintingFormat()) {
47587
- this.env.model.dispatch("PASTE", {
47588
- target: this.env.model.getters.getSelectedZones(),
47589
- });
47676
+ if (this.paintFormatStore.isActive) {
47677
+ this.paintFormatStore.pasteFormat(this.env.model.getters.getSelectedZones());
47590
47678
  }
47591
47679
  };
47592
47680
  dragAndDropBeyondTheViewport(this.env, onMouseMove, onMouseUp);
@@ -47612,10 +47700,8 @@ class Grid extends owl.Component {
47612
47700
  this.cellPopovers.close();
47613
47701
  }
47614
47702
  updateSelectionWithArrowKeys(ev, this.env.model.selection);
47615
- if (this.env.model.getters.isPaintingFormat()) {
47616
- this.env.model.dispatch("PASTE", {
47617
- target: this.env.model.getters.getSelectedZones(),
47618
- });
47703
+ if (this.paintFormatStore.isActive) {
47704
+ this.paintFormatStore.pasteFormat(this.env.model.getters.getSelectedZones());
47619
47705
  }
47620
47706
  }
47621
47707
  onKeydown(ev) {
@@ -47844,6 +47930,31 @@ class Grid extends owl.Component {
47844
47930
  }
47845
47931
  }
47846
47932
 
47933
+ /** @odoo-module */
47934
+ class EditableName extends owl.Component {
47935
+ static template = "o-spreadsheet-EditableName";
47936
+ static props = {
47937
+ name: String,
47938
+ displayName: String,
47939
+ onChanged: Function,
47940
+ };
47941
+ state;
47942
+ setup() {
47943
+ this.state = owl.useState({
47944
+ isEditing: false,
47945
+ name: "",
47946
+ });
47947
+ }
47948
+ rename() {
47949
+ this.state.isEditing = true;
47950
+ this.state.name = this.props.name;
47951
+ }
47952
+ save() {
47953
+ this.props.onChanged(this.state.name.trim());
47954
+ this.state.isEditing = false;
47955
+ }
47956
+ }
47957
+
47847
47958
  /**
47848
47959
  * BasePlugin
47849
47960
  *
@@ -49503,6 +49614,8 @@ class ConditionalFormatPlugin extends CorePlugin {
49503
49614
  "LessThan",
49504
49615
  "LessThanOrEqual",
49505
49616
  "NotContains",
49617
+ "Equal",
49618
+ "NotEqual",
49506
49619
  ]), this.checkOperatorArgsNumber(0, ["IsEmpty", "IsNotEmpty"]), this.checkCFValues);
49507
49620
  case "ColorScaleRule": {
49508
49621
  return this.checkValidations(rule, this.chainValidations(this.checkThresholds(this.checkFormulaCompilation)), this.chainValidations(this.checkThresholds(this.checkNaN), this.batchValidations(this.checkMinBiggerThanMax, this.checkMinBiggerThanMid, this.checkMidBiggerThanMax
@@ -49694,7 +49807,7 @@ class DataValidationPlugin extends CorePlugin {
49694
49807
  allowDispatch(cmd) {
49695
49808
  switch (cmd.type) {
49696
49809
  case "ADD_DATA_VALIDATION_RULE":
49697
- return this.checkValidations(cmd, this.chainValidations(this.checkCriterionTypeIsValid, this.checkCriterionHasValidNumberOfValues, this.checkCriterionValuesAreValid));
49810
+ return this.checkValidations(cmd, this.chainValidations(this.checkEmptyRange, this.checkCriterionTypeIsValid, this.checkCriterionHasValidNumberOfValues, this.checkCriterionValuesAreValid));
49698
49811
  case "REMOVE_DATA_VALIDATION_RULE":
49699
49812
  if (!this.rules[cmd.sheetId].find((rule) => rule.id === cmd.id)) {
49700
49813
  return "UnknownDataValidationRule" /* CommandResult.UnknownDataValidationRule */;
@@ -49822,6 +49935,9 @@ class DataValidationPlugin extends CorePlugin {
49822
49935
  this.dispatch("UPDATE_CELL", { ...position, style });
49823
49936
  }
49824
49937
  }
49938
+ checkEmptyRange(cmd) {
49939
+ return cmd.ranges.length ? "Success" /* CommandResult.Success */ : "EmptyRange" /* CommandResult.EmptyRange */;
49940
+ }
49825
49941
  import(data) {
49826
49942
  for (const sheet of data.sheets) {
49827
49943
  this.rules[sheet.id] = [];
@@ -50052,7 +50168,10 @@ class HeaderSizePlugin extends CorePlugin {
50052
50168
  handle(cmd) {
50053
50169
  switch (cmd.type) {
50054
50170
  case "CREATE_SHEET": {
50055
- this.history.update("sizes", cmd.sheetId, { COL: [], ROW: [] });
50171
+ this.history.update("sizes", cmd.sheetId, {
50172
+ COL: Array(this.getters.getNumberCols(cmd.sheetId)).fill(undefined),
50173
+ ROW: Array(this.getters.getNumberRows(cmd.sheetId)).fill(undefined),
50174
+ });
50056
50175
  break;
50057
50176
  }
50058
50177
  case "DUPLICATE_SHEET":
@@ -53123,6 +53242,9 @@ class PivotCorePlugin extends CorePlugin {
53123
53242
  if (deepEquals(cmd.pivot, this.pivots[cmd.pivotId]?.definition)) {
53124
53243
  return "NoChanges" /* CommandResult.NoChanges */;
53125
53244
  }
53245
+ if (cmd.pivot.name === "") {
53246
+ return "EmptyName" /* CommandResult.EmptyName */;
53247
+ }
53126
53248
  break;
53127
53249
  }
53128
53250
  case "RENAME_PIVOT":
@@ -54701,47 +54823,47 @@ class SpreadingRelation {
54701
54823
  * | 4 | | E | |
54702
54824
  * -----------------
54703
54825
  * ```
54704
- * We will have `resultsToArrayFormulas` looking like:
54705
- * - (B2) --> (A2, B1) meaning B2 can be the result of A2 OR B1
54706
- * - (C2) --> (A2) meaning C2 is the result of A2
54707
- * - (B3) --> (B1) meaning B3 is the result of B1
54708
- * - (B4) --> (B1) meaning B4 is the result of B1
54826
+ * We have `resultsToArrayFormulas` is an R-tree looking like:
54827
+ * - (A2:C2) --> A2 meaning values in A2:C2 are the result of A2
54828
+ * - (B1:B4) --> B1 meaning values in B1:B4 are the result of B1
54829
+ *
54830
+ * Note that B2 is part of both zones because it can be the result of
54831
+ * A2 or B1.
54832
+ * Using an R-tree allows for fast insertions while still having
54833
+ * a relatively fast lookup.
54709
54834
  *
54710
- * We will have `arrayFormulasToResults` looking like:
54711
- * - (A2) --> (B2, C2) meaning A2 spreads on B2 and C2
54712
- * - (B1) --> (B2, B3, B4) meaning B1 spreads on B2, B3 and B4
54835
+ * We have `arrayFormulasToResults` looking like:
54836
+ * - (A2) --> A2:C2 meaning A2 spreads on the zone A2:C2
54837
+ * - (B1) --> B1:B4 meaning B1 spreads on the zone B1:B4
54713
54838
  *
54714
54839
  */
54715
- resultsToArrayFormulas = new PositionMap();
54840
+ resultsToArrayFormulas = new SpreadsheetRTree();
54716
54841
  arrayFormulasToResults = new PositionMap();
54717
- getFormulaPositionsSpreadingOn(resultPosition) {
54718
- return this.resultsToArrayFormulas.get(resultPosition) || EMPTY_ARRAY;
54842
+ searchFormulaPositionsSpreadingOn(sheetId, zone) {
54843
+ return (this.resultsToArrayFormulas.search({ sheetId, zone }).map((node) => node.data) || EMPTY_ARRAY);
54719
54844
  }
54720
- getArrayResultPositions(formulasPosition) {
54721
- return this.arrayFormulasToResults.get(formulasPosition) || EMPTY_ARRAY;
54845
+ getArrayResultZone(formulasPosition) {
54846
+ return this.arrayFormulasToResults.get(formulasPosition);
54722
54847
  }
54723
54848
  /**
54724
54849
  * Remove a node, also remove it from other nodes adjacency list
54725
54850
  */
54726
54851
  removeNode(position) {
54727
- this.resultsToArrayFormulas.delete(position);
54852
+ this.resultsToArrayFormulas.remove({
54853
+ boundingBox: { sheetId: position.sheetId, zone: positionToZone(position) },
54854
+ data: position,
54855
+ });
54728
54856
  this.arrayFormulasToResults.delete(position);
54729
54857
  }
54730
54858
  /**
54731
54859
  * Create a spreading relation between two cells
54732
54860
  */
54733
- addRelation({ arrayFormulaPosition, resultPosition, }) {
54734
- if (!this.resultsToArrayFormulas.has(resultPosition)) {
54735
- this.resultsToArrayFormulas.set(resultPosition, []);
54736
- }
54737
- this.resultsToArrayFormulas.get(resultPosition)?.push(arrayFormulaPosition);
54738
- if (!this.arrayFormulasToResults.has(arrayFormulaPosition)) {
54739
- this.arrayFormulasToResults.set(arrayFormulaPosition, []);
54740
- }
54741
- this.arrayFormulasToResults.get(arrayFormulaPosition)?.push(resultPosition);
54742
- }
54743
- hasArrayFormulaResult(position) {
54744
- return this.resultsToArrayFormulas.has(position);
54861
+ addRelation({ arrayFormulaPosition, resultZone: resultPosition, }) {
54862
+ this.resultsToArrayFormulas.insert({
54863
+ boundingBox: { sheetId: arrayFormulaPosition.sheetId, zone: resultPosition },
54864
+ data: arrayFormulaPosition,
54865
+ });
54866
+ this.arrayFormulasToResults.set(arrayFormulaPosition, resultPosition);
54745
54867
  }
54746
54868
  isArrayFormula(position) {
54747
54869
  return this.arrayFormulasToResults.has(position);
@@ -54769,7 +54891,8 @@ class Evaluator {
54769
54891
  return this.evaluatedCells.get(position) || EMPTY_CELL;
54770
54892
  }
54771
54893
  getSpreadZone(position, options = { ignoreSpillError: false }) {
54772
- if (!this.spreadingRelations.isArrayFormula(position)) {
54894
+ const spreadZone = this.spreadingRelations.getArrayResultZone(position);
54895
+ if (!spreadZone) {
54773
54896
  return undefined;
54774
54897
  }
54775
54898
  const evaluatedCell = this.evaluatedCells.get(position);
@@ -54777,8 +54900,7 @@ class Evaluator {
54777
54900
  !(options.ignoreSpillError && evaluatedCell?.value === CellErrorType.SpilledBlocked)) {
54778
54901
  return positionToZone(position);
54779
54902
  }
54780
- const spreadPositions = Array.from(this.spreadingRelations.getArrayResultPositions(position));
54781
- return union(positionToZone(position), unionPositionsToZone(spreadPositions));
54903
+ return union(positionToZone(position), spreadZone);
54782
54904
  }
54783
54905
  getEvaluatedPositions() {
54784
54906
  return this.evaluatedCells.keys();
@@ -54787,10 +54909,12 @@ class Evaluator {
54787
54909
  return this.evaluatedCells.keysForSheet(sheetId);
54788
54910
  }
54789
54911
  getArrayFormulaSpreadingOn(position) {
54790
- if (!this.spreadingRelations.hasArrayFormulaResult(position)) {
54912
+ const hasArrayFormulaResult = this.getEvaluatedCell(position).type !== CellValueType.empty &&
54913
+ !this.getters.getCell(position)?.isFormula;
54914
+ if (!hasArrayFormulaResult) {
54791
54915
  return this.spreadingRelations.isArrayFormula(position) ? position : undefined;
54792
54916
  }
54793
- const arrayFormulas = this.spreadingRelations.getFormulaPositionsSpreadingOn(position);
54917
+ const arrayFormulas = this.spreadingRelations.searchFormulaPositionsSpreadingOn(position.sheetId, positionToZone(position));
54794
54918
  return Array.from(arrayFormulas).find((position) => !this.blockedArrayFormulas.has(position));
54795
54919
  }
54796
54920
  updateDependencies(position) {
@@ -54854,7 +54978,12 @@ class Evaluator {
54854
54978
  impactedPositions.add(position);
54855
54979
  }
54856
54980
  }
54857
- impactedPositions.addMany(this.getArrayFormulasBlockedBy(impactedPositions));
54981
+ const zonesBySheetIds = aggregatePositionsToZones(impactedPositions);
54982
+ for (const sheetId in zonesBySheetIds) {
54983
+ for (const zone of zonesBySheetIds[sheetId]) {
54984
+ impactedPositions.addMany(this.getArrayFormulasBlockedBy(sheetId, zone));
54985
+ }
54986
+ }
54858
54987
  return impactedPositions;
54859
54988
  }
54860
54989
  buildDependencyGraph() {
@@ -54906,19 +55035,14 @@ class Evaluator {
54906
55035
  * Return the position of formulas blocked by the given positions
54907
55036
  * as well as all their dependencies.
54908
55037
  */
54909
- getArrayFormulasBlockedBy(positions) {
55038
+ getArrayFormulasBlockedBy(sheetId, zone) {
54910
55039
  const arrayFormulaPositions = this.createEmptyPositionSet();
54911
- for (const position of positions) {
54912
- if (!this.spreadingRelations.hasArrayFormulaResult(position)) {
54913
- continue;
54914
- }
54915
- const arrayFormulas = this.spreadingRelations.getFormulaPositionsSpreadingOn(position);
54916
- arrayFormulaPositions.addMany(arrayFormulas);
54917
- const arrayFormulaPosition = this.getArrayFormulaSpreadingOn(position);
54918
- if (arrayFormulaPosition) {
54919
- // ignore the formula spreading on the position. Keep only the blocked ones
54920
- arrayFormulaPositions.delete(arrayFormulaPosition);
54921
- }
55040
+ const arrayFormulas = this.spreadingRelations.searchFormulaPositionsSpreadingOn(sheetId, zone);
55041
+ arrayFormulaPositions.addMany(arrayFormulas);
55042
+ const spilledPositions = [...arrayFormulas].filter((position) => !this.blockedArrayFormulas.has(position));
55043
+ if (spilledPositions.length) {
55044
+ // ignore the formula spreading on the position. Keep only the blocked ones
55045
+ arrayFormulaPositions.deleteMany(spilledPositions);
54922
55046
  }
54923
55047
  arrayFormulaPositions.addMany(this.getCellsDependingOn(arrayFormulaPositions));
54924
55048
  return arrayFormulaPositions;
@@ -54996,37 +55120,24 @@ class Evaluator {
54996
55120
  this.assertSheetHasEnoughSpaceToSpreadFormulaResult(formulaPosition, formulaReturn);
54997
55121
  const nbColumns = formulaReturn.length;
54998
55122
  const nbRows = formulaReturn[0].length;
54999
- forEachSpreadPositionInMatrix(nbColumns, nbRows, this.updateSpreadRelation(formulaPosition));
55123
+ const resultZone = {
55124
+ top: formulaPosition.row,
55125
+ bottom: formulaPosition.row + nbRows - 1,
55126
+ left: formulaPosition.col,
55127
+ right: formulaPosition.col + nbColumns - 1,
55128
+ };
55129
+ this.spreadingRelations.addRelation({ resultZone, arrayFormulaPosition: formulaPosition });
55000
55130
  this.assertNoMergedCellsInSpreadZone(formulaPosition, formulaReturn);
55001
55131
  forEachSpreadPositionInMatrix(nbColumns, nbRows, this.checkCollision(formulaPosition));
55002
55132
  forEachSpreadPositionInMatrix(nbColumns, nbRows,
55003
55133
  // thanks to the isMatrix check above, we know that formulaReturn is MatrixFunctionReturn
55004
55134
  this.spreadValues(formulaPosition, formulaReturn));
55005
- this.invalidatePositionsDependingOnSpread(formulaPosition, nbColumns, nbRows);
55135
+ this.invalidatePositionsDependingOnSpread(formulaPosition.sheetId, resultZone);
55006
55136
  return createEvaluatedCell(nullValueToZeroValue(formulaReturn[0][0]), this.getters.getLocale(), cellData);
55007
55137
  }
55008
- invalidatePositionsDependingOnSpread(arrayFormulaPosition, nbColumns, nbRows) {
55138
+ invalidatePositionsDependingOnSpread(sheetId, resultZone) {
55009
55139
  // the result matrix is split in 2 zones to exclude the array formula position
55010
- const top = arrayFormulaPosition.row;
55011
- const left = arrayFormulaPosition.col;
55012
- const bottom = top + nbRows - 1;
55013
- const leftColumnZone = {
55014
- top: top + 1,
55015
- bottom,
55016
- left,
55017
- right: left,
55018
- };
55019
- const rightPartZone = {
55020
- top,
55021
- bottom,
55022
- left: left + 1,
55023
- right: left + nbColumns - 1,
55024
- };
55025
- const sheetId = arrayFormulaPosition.sheetId;
55026
- const invalidatedPositions = this.formulaDependencies().getCellsDependingOn([
55027
- { sheetId, zone: rightPartZone },
55028
- { sheetId, zone: leftColumnZone },
55029
- ]);
55140
+ const invalidatedPositions = this.formulaDependencies().getCellsDependingOn(excludeTopLeft(resultZone).map((zone) => ({ sheetId, zone })));
55030
55141
  this.nextPositionsToUpdate.addMany(invalidatedPositions);
55031
55142
  }
55032
55143
  assertSheetHasEnoughSpaceToSpreadFormulaResult({ sheetId, col, row }, matrixResult) {
@@ -55057,14 +55168,6 @@ class Evaluator {
55057
55168
  }
55058
55169
  throw new SplillBlockedError(_t("Merged cells found in the spill zone. Please unmerge cells before using array formulas."));
55059
55170
  }
55060
- updateSpreadRelation({ sheetId, col, row, }) {
55061
- const arrayFormulaPosition = { sheetId, col, row };
55062
- const updateSpreadRelation = (i, j) => {
55063
- const position = { sheetId, col: i + col, row: j + row };
55064
- this.spreadingRelations.addRelation({ resultPosition: position, arrayFormulaPosition });
55065
- };
55066
- return updateSpreadRelation;
55067
- }
55068
55171
  checkCollision(formulaPosition) {
55069
55172
  const { sheetId, col, row } = formulaPosition;
55070
55173
  const checkCollision = (i, j) => {
@@ -55089,22 +55192,25 @@ class Evaluator {
55089
55192
  return spreadValues;
55090
55193
  }
55091
55194
  invalidateSpreading(position) {
55092
- if (!this.spreadingRelations.isArrayFormula(position)) {
55195
+ const zone = this.spreadingRelations.getArrayResultZone(position);
55196
+ if (!zone) {
55093
55197
  return;
55094
55198
  }
55095
- const invalidated = this.createEmptyPositionSet();
55096
- for (const child of this.spreadingRelations.getArrayResultPositions(position)) {
55097
- const content = this.getters.getCell(child)?.content;
55098
- if (content) {
55099
- // there's no point at re-evaluating overlapping array formulas,
55100
- // there's still a collision
55101
- continue;
55199
+ for (let col = zone.left; col <= zone.right; col++) {
55200
+ for (let row = zone.top; row <= zone.bottom; row++) {
55201
+ const resultPosition = { sheetId: position.sheetId, col, row };
55202
+ const content = this.getters.getCell(resultPosition)?.content;
55203
+ if (content) {
55204
+ // there's no point at re-evaluating overlapping array formulas,
55205
+ // there's still a collision
55206
+ continue;
55207
+ }
55208
+ this.evaluatedCells.delete(resultPosition);
55102
55209
  }
55103
- invalidated.add(child);
55104
- this.evaluatedCells.delete(child);
55105
55210
  }
55106
- this.nextPositionsToUpdate.addMany(this.getCellsDependingOn(invalidated));
55107
- this.nextPositionsToUpdate.addMany(this.getArrayFormulasBlockedBy(invalidated));
55211
+ const sheetId = position.sheetId;
55212
+ this.invalidatePositionsDependingOnSpread(sheetId, zone);
55213
+ this.nextPositionsToUpdate.addMany(this.getArrayFormulasBlockedBy(sheetId, zone));
55108
55214
  }
55109
55215
  // ----------------------------------------------------------
55110
55216
  // COMMON FUNCTIONALITY
@@ -55284,9 +55390,10 @@ class EvaluationPlugin extends UIPlugin {
55284
55390
  if (!("content" in cmd || "format" in cmd) || this.shouldRebuildDependenciesGraph) {
55285
55391
  return;
55286
55392
  }
55287
- this.positionsToUpdate.push(cmd);
55393
+ const position = { sheetId: cmd.sheetId, row: cmd.row, col: cmd.col };
55394
+ this.positionsToUpdate.push(position);
55288
55395
  if ("content" in cmd) {
55289
- this.evaluator.updateDependencies(cmd);
55396
+ this.evaluator.updateDependencies(position);
55290
55397
  }
55291
55398
  break;
55292
55399
  case "EVALUATE_CELLS":
@@ -56572,10 +56679,6 @@ class PivotUIPlugin extends UIPlugin {
56572
56679
  this.setupPivot(cmd.pivotId, { recreate: true });
56573
56680
  break;
56574
56681
  }
56575
- case "REMOVE_PIVOT": {
56576
- delete this.pivots[cmd.pivotId];
56577
- break;
56578
- }
56579
56682
  case "DELETE_SHEET":
56580
56683
  case "UPDATE_CELL": {
56581
56684
  this.unusedPivots = undefined;
@@ -56717,6 +56820,9 @@ class PivotUIPlugin extends UIPlugin {
56717
56820
  }
56718
56821
  }
56719
56822
  getPivot(pivotId) {
56823
+ if (!this.getters.isExistingPivot(pivotId)) {
56824
+ throw new Error(`pivot ${pivotId} not found`);
56825
+ }
56720
56826
  return this.pivots[pivotId];
56721
56827
  }
56722
56828
  isPivotUnused(pivotId) {
@@ -58799,7 +58905,7 @@ class InsertPivotPlugin extends UIPlugin {
58799
58905
  sheetId,
58800
58906
  col,
58801
58907
  row,
58802
- content: `=PIVOT("${pivotFormulaId}")`,
58908
+ content: `=PIVOT(${pivotFormulaId})`,
58803
58909
  });
58804
58910
  const zone = {
58805
58911
  left: col,
@@ -60123,10 +60229,8 @@ class ClipboardPlugin extends UIPlugin {
60123
60229
  "getClipboardId",
60124
60230
  "getClipboardTextContent",
60125
60231
  "isCutOperation",
60126
- "isPaintingFormat",
60127
60232
  ];
60128
60233
  status = "invisible";
60129
- paintFormatStatus = "inactive";
60130
60234
  originSheetId;
60131
60235
  copiedData;
60132
60236
  _isCutOperation = false;
@@ -60141,14 +60245,14 @@ class ClipboardPlugin extends UIPlugin {
60141
60245
  return this.isCutAllowedOn(zones);
60142
60246
  case "PASTE_FROM_OS_CLIPBOARD": {
60143
60247
  const copiedData = this.convertOSClipboardData(cmd.clipboardContent[ClipboardMIMEType.PlainText] ?? "");
60144
- const pasteOption = cmd.pasteOption || (this.paintFormatStatus !== "inactive" ? "onlyFormat" : undefined);
60248
+ const pasteOption = cmd.pasteOption;
60145
60249
  return this.isPasteAllowed(cmd.target, copiedData, { pasteOption, isCutOperation: false });
60146
60250
  }
60147
60251
  case "PASTE": {
60148
60252
  if (!this.copiedData) {
60149
60253
  return "EmptyClipboard" /* CommandResult.EmptyClipboard */;
60150
60254
  }
60151
- const pasteOption = cmd.pasteOption || (this.paintFormatStatus !== "inactive" ? "onlyFormat" : undefined);
60255
+ const pasteOption = cmd.pasteOption;
60152
60256
  return this.isPasteAllowed(cmd.target, this.copiedData, {
60153
60257
  pasteOption: pasteOption,
60154
60258
  isCutOperation: this._isCutOperation,
@@ -60178,12 +60282,6 @@ class ClipboardPlugin extends UIPlugin {
60178
60282
  const copiedData = this.copy(cut);
60179
60283
  return this.isPasteAllowed(paste, copiedData, { isCutOperation: true });
60180
60284
  }
60181
- case "ACTIVATE_PAINT_FORMAT": {
60182
- if (this.paintFormatStatus !== "inactive") {
60183
- return "AlreadyInPaintingFormatMode" /* CommandResult.AlreadyInPaintingFormatMode */;
60184
- }
60185
- return "Success" /* CommandResult.Success */;
60186
- }
60187
60285
  }
60188
60286
  return "Success" /* CommandResult.Success */;
60189
60287
  }
@@ -60205,7 +60303,7 @@ class ClipboardPlugin extends UIPlugin {
60205
60303
  else {
60206
60304
  this.copiedData = this.convertOSClipboardData(cmd.clipboardContent[ClipboardMIMEType.PlainText] ?? "");
60207
60305
  }
60208
- const pasteOption = cmd.pasteOption || (this.paintFormatStatus !== "inactive" ? "onlyFormat" : undefined);
60306
+ const pasteOption = cmd.pasteOption;
60209
60307
  this.paste(cmd.target, this.copiedData, {
60210
60308
  pasteOption,
60211
60309
  selectTarget: true,
@@ -60215,18 +60313,16 @@ class ClipboardPlugin extends UIPlugin {
60215
60313
  break;
60216
60314
  }
60217
60315
  case "PASTE": {
60218
- const pasteOption = cmd.pasteOption || (this.paintFormatStatus !== "inactive" ? "onlyFormat" : undefined);
60316
+ const pasteOption = cmd.pasteOption;
60219
60317
  this.paste(cmd.target, this.copiedData, {
60220
60318
  pasteOption,
60221
60319
  selectTarget: true,
60222
60320
  isCutOperation: this._isCutOperation,
60223
60321
  });
60224
- if (this.paintFormatStatus === "oneOff") {
60225
- this.paintFormatStatus = "inactive";
60226
- }
60227
60322
  this.status = "invisible";
60228
60323
  if (this._isCutOperation) {
60229
60324
  this.copiedData = undefined;
60325
+ this._isCutOperation = false;
60230
60326
  }
60231
60327
  break;
60232
60328
  }
@@ -60322,18 +60418,6 @@ class ClipboardPlugin extends UIPlugin {
60322
60418
  });
60323
60419
  break;
60324
60420
  }
60325
- case "ACTIVATE_PAINT_FORMAT": {
60326
- const zones = this.getters.getSelectedZones();
60327
- this.copiedData = this.copy(zones);
60328
- this.status = "visible";
60329
- if (cmd.persistent) {
60330
- this.paintFormatStatus = "persistent";
60331
- }
60332
- else {
60333
- this.paintFormatStatus = "oneOff";
60334
- }
60335
- break;
60336
- }
60337
60421
  case "DELETE_SHEET":
60338
60422
  if (this._isCutOperation !== true) {
60339
60423
  return;
@@ -60343,11 +60427,6 @@ class ClipboardPlugin extends UIPlugin {
60343
60427
  this.status = "invisible";
60344
60428
  }
60345
60429
  break;
60346
- case "CANCEL_PAINT_FORMAT": {
60347
- this.paintFormatStatus = "inactive";
60348
- this.status = "invisible";
60349
- break;
60350
- }
60351
60430
  default:
60352
60431
  if (isCoreCommand(cmd)) {
60353
60432
  this.status = "invisible";
@@ -60563,7 +60642,7 @@ class ClipboardPlugin extends UIPlugin {
60563
60642
  }
60564
60643
  const cells = this.copiedData.cells;
60565
60644
  if (cells.length === 1 && cells[0].length === 1) {
60566
- return this.getters.getCellText(cells[0][0].position);
60645
+ return `<div data-clipboard-id="${this.clipboardId}">${this.getters.getCellText(cells[0][0].position)}</div>`;
60567
60646
  }
60568
60647
  if (!cells[0][0]) {
60569
60648
  return "";
@@ -60587,9 +60666,6 @@ class ClipboardPlugin extends UIPlugin {
60587
60666
  isCutOperation() {
60588
60667
  return this._isCutOperation ?? false;
60589
60668
  }
60590
- isPaintingFormat() {
60591
- return this.paintFormatStatus !== "inactive";
60592
- }
60593
60669
  // ---------------------------------------------------------------------------
60594
60670
  // Private methods
60595
60671
  // ---------------------------------------------------------------------------
@@ -64494,18 +64570,22 @@ class PaintFormatButton extends owl.Component {
64494
64570
  static props = {
64495
64571
  class: { type: String, optional: true },
64496
64572
  };
64573
+ paintFormatStore;
64574
+ setup() {
64575
+ this.paintFormatStore = useStore(PaintFormatStore);
64576
+ }
64497
64577
  get isActive() {
64498
- return this.env.model.getters.isPaintingFormat();
64578
+ return this.paintFormatStore.isActive;
64499
64579
  }
64500
64580
  onDblClick() {
64501
- this.env.model.dispatch("ACTIVATE_PAINT_FORMAT", { persistent: true });
64581
+ this.paintFormatStore.activate({ persistent: true });
64502
64582
  }
64503
64583
  togglePaintFormat() {
64504
64584
  if (this.isActive) {
64505
- this.env.model.dispatch("CANCEL_PAINT_FORMAT");
64585
+ this.paintFormatStore.cancel();
64506
64586
  }
64507
64587
  else {
64508
- this.env.model.dispatch("ACTIVATE_PAINT_FORMAT", { persistent: false });
64588
+ this.paintFormatStore.activate({ persistent: false });
64509
64589
  }
64510
64590
  }
64511
64591
  }
@@ -68956,6 +69036,7 @@ class Model extends EventBus {
68956
69036
  case 0 /* Status.Ready */:
68957
69037
  const result = this.checkDispatchAllowed(command);
68958
69038
  if (!result.isSuccessful) {
69039
+ this.trigger("update");
68959
69040
  return result;
68960
69041
  }
68961
69042
  this.status = 1 /* Status.Running */;
@@ -69275,6 +69356,7 @@ const components = {
69275
69356
  PivotTitleSection,
69276
69357
  CogWheelMenu,
69277
69358
  TextInput,
69359
+ SidePanelCollapsible,
69278
69360
  };
69279
69361
  const hooks = {
69280
69362
  useDragAndDropListItems,
@@ -69361,6 +69443,6 @@ exports.tokenColors = tokenColors;
69361
69443
  exports.tokenize = tokenize;
69362
69444
 
69363
69445
 
69364
- __info__.version = "17.5.0-alpha.6";
69365
- __info__.date = "2024-08-19T08:12:01.220Z";
69366
- __info__.hash = "c067f5d";
69446
+ __info__.version = "17.5.0-alpha.7";
69447
+ __info__.date = "2024-08-26T13:49:04.156Z";
69448
+ __info__.hash = "f8d3f23";