diff --git a/src/Mod/Spreadsheet/Gui/SheetModel.cpp b/src/Mod/Spreadsheet/Gui/SheetModel.cpp index d919edd398..0127ad7a51 100644 --- a/src/Mod/Spreadsheet/Gui/SheetModel.cpp +++ b/src/Mod/Spreadsheet/Gui/SheetModel.cpp @@ -23,10 +23,10 @@ ***************************************************************************/ +#include #include #include - #include #include #include @@ -36,6 +36,7 @@ #include #include "SheetModel.h" +#include "App/Range.h" using namespace SpreadsheetGui; @@ -46,13 +47,17 @@ namespace sp = std::placeholders; SheetModel::SheetModel(Sheet* _sheet, QObject* parent) : QAbstractTableModel(parent) , sheet(_sheet) + , rows(1000) + , cols(26) { + containSheetDataInView(); + // NOLINTBEGIN - cellUpdatedConnection = sheet->cellUpdated.connect( - std::bind(&SheetModel::cellUpdated, this, sp::_1) + connections.emplace_back( + sheet->cellUpdated.connect(std::bind(&SheetModel::cellUpdated, this, sp::_1)) ); - rangeUpdatedConnection = sheet->rangeUpdated.connect( - std::bind(&SheetModel::rangeUpdated, this, sp::_1) + connections.emplace_back( + sheet->rangeUpdated.connect(std::bind(&SheetModel::rangeUpdated, this, sp::_1)) ); // NOLINTEND @@ -65,53 +70,108 @@ SheetModel::SheetModel(Sheet* _sheet, QObject* parent) textFgColor = QColor(QString::fromStdString(hGrp->GetASCII("TextColor", "#000000"))); positiveFgColor = QColor(QString::fromStdString(hGrp->GetASCII("PositiveNumberColor", "#000000"))); negativeFgColor = QColor(QString::fromStdString(hGrp->GetASCII("NegativeNumberColor", "#000000"))); - - - const QStringList alphabet {QStringLiteral("A"), QStringLiteral("B"), QStringLiteral("C"), - QStringLiteral("D"), QStringLiteral("E"), QStringLiteral("F"), - QStringLiteral("G"), QStringLiteral("H"), QStringLiteral("I"), - QStringLiteral("J"), QStringLiteral("K"), QStringLiteral("L"), - QStringLiteral("M"), QStringLiteral("N"), QStringLiteral("O"), - QStringLiteral("P"), QStringLiteral("Q"), QStringLiteral("R"), - QStringLiteral("S"), QStringLiteral("T"), QStringLiteral("U"), - QStringLiteral("V"), QStringLiteral("W"), QStringLiteral("X"), - QStringLiteral("Y"), QStringLiteral("Z")}; - - for (const QString& letter : alphabet) { - columnLabels << letter; - } - - for (const QString& left : alphabet) { - for (const QString& right : alphabet) { - columnLabels << left + right; - } - } - - for (int i = 1; i <= maxRowCount; i++) { - rowLabels << QString::number(i); - } } SheetModel::~SheetModel() -{ - cellUpdatedConnection.disconnect(); - rangeUpdatedConnection.disconnect(); -} +{} int SheetModel::rowCount(const QModelIndex& parent) const { Q_UNUSED(parent); - return maxRowCount; + return rows; } int SheetModel::columnCount(const QModelIndex& parent) const { Q_UNUSED(parent); - return maxColumnCount; + return cols; +} + +bool SheetModel::insertRows(int row, int count, const QModelIndex& parent) +{ + if (rows + count > CellAddress::MAX_ROWS) { + return false; + } + + beginInsertRows(parent, rows, rows + count - 1); + rows += count; + endInsertRows(); + + // Called after endInsertRows to avoid potential nesting. It will call + // `SheetModel::(cell|range)Updated` on modified cells anyways, sending necessary view signals. + sheet->insertRows(row, count); + + return true; +} + +bool SheetModel::insertColumns(int column, int count, const QModelIndex& parent) +{ + if (cols + count > CellAddress::MAX_COLUMNS) { + return false; + } + + beginInsertColumns(parent, column, column + count - 1); + cols += count; + endInsertColumns(); + + // Called after endInsertColumns to avoid potential nesting. It will call + // `SheetModel::(cell|range)Updated` on modified cells anyways, sending necessary view signals. + sheet->insertColumns(column, count); + + return true; +} + +bool SheetModel::removeRows(int row, int count, const QModelIndex& parent) +{ + if (count >= rows) { + // Prevent the header from disappearing + return false; + } + beginRemoveRows(parent, row, row + count - 1); + rows -= count; + endRemoveRows(); + sheet->removeRows(row, count); + return true; +} + +bool SheetModel::removeColumns(int column, int count, const QModelIndex& parent) +{ + if (count >= cols) { + // Prevent the header from disappearing + return false; + } + beginRemoveColumns(parent, column, column + count - 1); + cols -= count; + endRemoveColumns(); + sheet->removeColumns(column, count); + return true; } namespace { +QString encodeColumn(int column) +{ + int toSkipTotal = 0; + int toSkipNext = 26; + int length = 1; + + while (toSkipTotal + toSkipNext <= column) { + toSkipTotal += toSkipNext; + toSkipNext *= 26; + length += 1; + } + + column -= toSkipTotal; + + QString res; + for (int i = 0; i < length; i++) { + res = QString(static_cast('A' + (column % 26))) + res; + column /= 26; + } + + return res; +} + QVariant formatCellDisplay(QString value, const Cell* cell) { std::string alias; @@ -552,16 +612,12 @@ QVariant SheetModel::data(const QModelIndex& index, int role) const QVariant SheetModel::headerData(int section, Qt::Orientation orientation, int role) const { if (role == Qt::SizeHintRole) { - const int width - = (orientation == Qt::Horizontal ? sheet->getColumnWidth(section) - : PropertyColumnWidths::defaultHeaderWidth); - const int height - = (orientation == Qt::Horizontal ? PropertyRowHeights::defaultHeight - : sheet->getRowHeight(section)); - return QSize {width, height}; + return orientation == Qt::Horizontal + ? QSize(sheet->getColumnWidth(section), PropertyRowHeights::defaultHeight) + : QSize(PropertyColumnWidths::defaultHeaderWidth, sheet->getRowHeight(section)); } if (role == Qt::DisplayRole) { - return (orientation == Qt::Horizontal ? columnLabels.at(section) : rowLabels.at(section)); + return orientation == Qt::Horizontal ? encodeColumn(section) : QString::number(section + 1); } return {}; } @@ -621,19 +677,39 @@ Qt::ItemFlags SheetModel::flags(const QModelIndex& /*index*/) const return Qt::ItemIsSelectable | Qt::ItemIsEditable | Qt::ItemIsEnabled; } +void SheetModel::containSheetDataInView() +{ + CellAddress address = std::get<1>(sheet->getUsedRange()); + if (address.row() >= rows) { + beginInsertRows(QModelIndex(), rows, address.row()); + rows = address.row() + 1; + endInsertRows(); + } + if (address.col() >= cols) { + beginInsertColumns(QModelIndex(), cols, address.col()); + cols = address.col() + 1; + endInsertColumns(); + } +} + void SheetModel::cellUpdated(CellAddress address) { - QModelIndex i = index(address.row(), address.col()); - - Q_EMIT dataChanged(i, i); + containSheetDataInView(); + if (address.row() < rows && address.col() < cols) { + QModelIndex i = index(address.row(), address.col()); + Q_EMIT dataChanged(i, i); + } } void SheetModel::rangeUpdated(const Range& range) { - QModelIndex i = index(range.from().row(), range.from().col()); - QModelIndex j = index(range.to().row(), range.to().col()); - - Q_EMIT dataChanged(i, j); + containSheetDataInView(); + if (range.from().row() < rows && range.from().col() < cols) { + QModelIndex i = index(range.from().row(), range.from().col()); + QModelIndex j + = index(std::min(range.to().row(), rows - 1), std::min(range.to().col(), cols - 1)); + Q_EMIT dataChanged(i, j); + } } #include "moc_SheetModel.cpp" diff --git a/src/Mod/Spreadsheet/Gui/SheetModel.h b/src/Mod/Spreadsheet/Gui/SheetModel.h index 2b69c79dc7..97701842ce 100644 --- a/src/Mod/Spreadsheet/Gui/SheetModel.h +++ b/src/Mod/Spreadsheet/Gui/SheetModel.h @@ -24,6 +24,7 @@ #pragma once +#include "fastsignals/connection.h" #include #include @@ -47,6 +48,10 @@ public: explicit SheetModel(QObject* parent); int rowCount(const QModelIndex& parent = QModelIndex()) const override; int columnCount(const QModelIndex& parent = QModelIndex()) const override; + bool insertRows(int row, int count, const QModelIndex& parent = QModelIndex()) override; + bool insertColumns(int column, int count, const QModelIndex& parent = QModelIndex()) override; + bool removeRows(int row, int count, const QModelIndex& parent = QModelIndex()) override; + bool removeColumns(int column, int count, const QModelIndex& parent = QModelIndex()) override; QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override; QVariant headerData(int section, Qt::Orientation orientation, int role) const override; bool setData(const QModelIndex& index, const QVariant& value, int role) override; @@ -56,20 +61,17 @@ private Q_SLOTS: void setCellData(QModelIndex index, QString str); private: + void containSheetDataInView(); void cellUpdated(App::CellAddress address); void rangeUpdated(const App::Range& range); - fastsignals::scoped_connection cellUpdatedConnection; - fastsignals::scoped_connection rangeUpdatedConnection; + std::vector connections; Spreadsheet::Sheet* sheet; + int rows, cols; QColor aliasBgColor; QColor textFgColor; QColor positiveFgColor; QColor negativeFgColor; - - QVariantList columnLabels, rowLabels; - - static constexpr int maxRowCount = 16384, maxColumnCount = 26 + 26 * 26; }; } // namespace SpreadsheetGui diff --git a/src/Mod/Spreadsheet/Gui/SheetTableView.cpp b/src/Mod/Spreadsheet/Gui/SheetTableView.cpp index a82da8a0d7..0d9acb4b06 100644 --- a/src/Mod/Spreadsheet/Gui/SheetTableView.cpp +++ b/src/Mod/Spreadsheet/Gui/SheetTableView.cpp @@ -22,6 +22,7 @@ * * ***************************************************************************/ +#include #include #include #include @@ -47,7 +48,6 @@ #include "DlgBindSheet.h" #include "DlgSheetConf.h" -#include "LineEdit.h" #include "PropertiesDialog.h" #include "SheetTableView.h" @@ -56,6 +56,31 @@ using namespace SpreadsheetGui; using namespace Spreadsheet; using namespace App; +/// Gathers adjacent columns/rows into ranges. Returns the ranges in descending order. +static std::vector> selectionRanges( + const QModelIndexList& selection, + Qt::Orientation orientation +) +{ + std::vector values; + for (const auto& index : selection) { + values.emplace_back(orientation == Qt::Horizontal ? index.column() : index.row()); + } + std::ranges::sort(values, std::greater<>()); + + std::vector> ranges; + for (int value : values) { + if (ranges.empty() || value < ranges.back().first - 1) { + ranges.emplace_back(value, value); + } + else { + ranges.back().first = value; + } + } + + return ranges; +} + void SheetViewHeader::mouseMoveEvent(QMouseEvent* e) { // for some reason QWidget::setCursor() has no effect in QGraphicsView @@ -95,30 +120,6 @@ bool SheetViewHeader::viewportEvent(QEvent* e) return QHeaderView::viewportEvent(e); } -static std::pair selectedMinMaxRows(QModelIndexList list) -{ - int min = std::numeric_limits::max(); - int max = 0; - for (const auto& item : list) { - int row = item.row(); - min = std::min(row, min); - max = std::max(row, max); - } - return {min, max}; -} - -static std::pair selectedMinMaxColumns(QModelIndexList list) -{ - int min = std::numeric_limits::max(); - int max = 0; - for (const auto& item : list) { - int column = item.column(); - min = std::min(column, min); - max = std::max(column, max); - } - return {min, max}; -} - SheetTableView::SheetTableView(QWidget* parent) : QTableView(parent) , sheet(nullptr) @@ -132,23 +133,17 @@ SheetTableView::SheetTableView(QWidget* parent) connect(verticalHeader(), &QWidget::customContextMenuRequested, [this](const QPoint& point) { Q_UNUSED(point) QMenu menu {nullptr}; - const auto selection = selectionModel()->selectedRows(); - const auto& [min, max] = selectedMinMaxRows(selection); - if (bool isContiguous = max - min == selection.size() - 1) { - Q_UNUSED(isContiguous) - /*: This is shown in the context menu for the vertical header in a spreadsheet. - The number refers to how many lines are selected and will be inserted. */ + const auto& selection = selectionModel()->selectedRows(); + const auto& ranges = selectionRanges(selection, Qt::Vertical); + if (ranges.size() <= 1) { auto insertBefore = menu.addAction(tr("Insert %n Rows Above", "", selection.size())); - connect(insertBefore, &QAction::triggered, this, &SheetTableView::insertRows); - - if (max < model()->rowCount() - 1) { - auto insertAfter = menu.addAction(tr("Insert %n Rows Below", "", selection.size())); - connect(insertAfter, &QAction::triggered, this, &SheetTableView::insertRowsAfter); - } + connect(insertBefore, &QAction::triggered, [this] { insertRows(false); }); + auto insertAfter = menu.addAction(tr("Insert %n Rows Below", "", selection.size())); + connect(insertAfter, &QAction::triggered, [this] { insertRows(true); }); } else { auto insert = menu.addAction(tr("Insert %n Non-Contiguous Rows", "", selection.size())); - connect(insert, &QAction::triggered, this, &SheetTableView::insertRows); + connect(insert, &QAction::triggered, [this] { insertRows(false); }); } auto remove = menu.addAction(tr("Remove Rows", "")); connect(remove, &QAction::triggered, this, &SheetTableView::removeRows); @@ -158,23 +153,17 @@ SheetTableView::SheetTableView(QWidget* parent) connect(horizontalHeader(), &QWidget::customContextMenuRequested, [this](const QPoint& point) { Q_UNUSED(point) QMenu menu {nullptr}; - const auto selection = selectionModel()->selectedColumns(); - const auto& [min, max] = selectedMinMaxColumns(selection); - if (bool isContiguous = max - min == selection.size() - 1) { - Q_UNUSED(isContiguous) - /*: This is shown in the context menu for the horizontal header in a spreadsheet. - The number refers to how many lines are selected and will be inserted. */ + const auto& selection = selectionModel()->selectedColumns(); + const auto& ranges = selectionRanges(selection, Qt::Horizontal); + if (ranges.size() <= 1) { auto insertAbove = menu.addAction(tr("Insert %n Columns Left", "", selection.size())); - connect(insertAbove, &QAction::triggered, this, &SheetTableView::insertColumns); - - if (max < model()->columnCount() - 1) { - auto insertAfter = menu.addAction(tr("Insert %n Columns Right", "", selection.size())); - connect(insertAfter, &QAction::triggered, this, &SheetTableView::insertColumnsAfter); - } + connect(insertAbove, &QAction::triggered, [this] { insertColumns(false); }); + auto insertAfter = menu.addAction(tr("Insert %n Columns Right", "", selection.size())); + connect(insertAfter, &QAction::triggered, [this] { insertColumns(true); }); } else { auto insert = menu.addAction(tr("Insert %n Non-Contiguous Columns", "", selection.size())); - connect(insert, &QAction::triggered, this, &SheetTableView::insertColumns); + connect(insert, &QAction::triggered, [this] { insertColumns(false); }); } auto remove = menu.addAction(tr("Remove Columns", "")); connect(remove, &QAction::triggered, this, &SheetTableView::removeColumns); @@ -328,151 +317,55 @@ QModelIndexList SheetTableView::selectedIndexesRaw() const return selectedIndexes(); } -void SheetTableView::insertRows() +void SheetTableView::insertRows(bool after) { - assert(sheet); - - QModelIndexList rows = selectionModel()->selectedRows(); - std::vector sortedRows; - - /* Make sure rows are sorted in ascending order */ - for (const auto& it : rows) { - sortedRows.push_back(it.row()); - } - std::sort(sortedRows.begin(), sortedRows.end()); - - /* Insert rows */ Gui::Command::openCommand(QT_TRANSLATE_NOOP("Command", "Insert Rows")); - std::vector::const_reverse_iterator it = sortedRows.rbegin(); - while (it != sortedRows.rend()) { - int prev = *it; - int count = 1; - - /* Collect neighbouring rows into one chunk */ - ++it; - while (it != sortedRows.rend()) { - if (*it == prev - 1) { - prev = *it; - ++count; - ++it; - } - else { - break; - } + for (const auto& [begin, end] : selectionRanges(selectionModel()->selectedRows(), Qt::Vertical)) { + if (!model()->insertRows(after ? end + 1 : begin, end - begin + 1)) { + Gui::Command::abortCommand(); + return; } - - Gui::cmdAppObjectArgs(sheet, "insertRows('%s', %d)", rowName(prev).c_str(), count); } Gui::Command::commitCommand(); Gui::Command::doCommand(Gui::Command::Doc, "App.ActiveDocument.recompute()"); } -void SheetTableView::insertRowsAfter() +void SheetTableView::insertColumns(bool after) { - assert(sheet); - const auto rows = selectionModel()->selectedRows(); - const auto& [min, max] = selectedMinMaxRows(rows); - assert(max - min == rows.size() - 1); - Q_UNUSED(min) - - Gui::Command::openCommand(QT_TRANSLATE_NOOP("Command", "Insert Rows")); - Gui::cmdAppObjectArgs(sheet, "insertRows('%s', %d)", rowName(max + 1).c_str(), rows.size()); + Gui::Command::openCommand(QT_TRANSLATE_NOOP("Command", "Insert Columns")); + for (const auto& [begin, end] : + selectionRanges(selectionModel()->selectedColumns(), Qt::Horizontal)) { + if (!model()->insertColumns(after ? end + 1 : begin, end - begin + 1)) { + Gui::Command::abortCommand(); + return; + } + } Gui::Command::commitCommand(); Gui::Command::doCommand(Gui::Command::Doc, "App.ActiveDocument.recompute()"); } void SheetTableView::removeRows() { - assert(sheet); - - QModelIndexList rows = selectionModel()->selectedRows(); - std::vector sortedRows; - - /* Make sure rows are sorted in descending order */ - for (const auto& it : rows) { - sortedRows.push_back(it.row()); - } - std::sort(sortedRows.begin(), sortedRows.end(), std::greater<>()); - - /* Remove rows */ Gui::Command::openCommand(QT_TRANSLATE_NOOP("Command", "Remove Rows")); - for (const auto& it : sortedRows) { - Gui::cmdAppObjectArgs(sheet, "removeRows('%s', %d)", rowName(it).c_str(), 1); - } - Gui::Command::commitCommand(); - Gui::Command::doCommand(Gui::Command::Doc, "App.ActiveDocument.recompute()"); -} - -void SheetTableView::insertColumns() -{ - assert(sheet); - - QModelIndexList cols = selectionModel()->selectedColumns(); - std::vector sortedColumns; - - /* Make sure rows are sorted in ascending order */ - for (const auto& it : cols) { - sortedColumns.push_back(it.column()); - } - std::sort(sortedColumns.begin(), sortedColumns.end()); - - /* Insert columns */ - Gui::Command::openCommand(QT_TRANSLATE_NOOP("Command", "Insert Columns")); - std::vector::const_reverse_iterator it = sortedColumns.rbegin(); - while (it != sortedColumns.rend()) { - int prev = *it; - int count = 1; - - /* Collect neighbouring columns into one chunk */ - ++it; - while (it != sortedColumns.rend()) { - if (*it == prev - 1) { - prev = *it; - ++count; - ++it; - } - else { - break; - } + for (const auto& [begin, end] : selectionRanges(selectionModel()->selectedRows(), Qt::Vertical)) { + if (!model()->removeRows(begin, end - begin + 1)) { + Gui::Command::abortCommand(); + return; } - - Gui::cmdAppObjectArgs(sheet, "insertColumns('%s', %d)", columnName(prev).c_str(), count); } Gui::Command::commitCommand(); Gui::Command::doCommand(Gui::Command::Doc, "App.ActiveDocument.recompute()"); } -void SheetTableView::insertColumnsAfter() -{ - assert(sheet); - const auto columns = selectionModel()->selectedColumns(); - const auto& [min, max] = selectedMinMaxColumns(columns); - assert(max - min == columns.size() - 1); - Q_UNUSED(min) - - Gui::Command::openCommand(QT_TRANSLATE_NOOP("Command", "Insert Columns")); - Gui::cmdAppObjectArgs(sheet, "insertColumns('%s', %d)", columnName(max + 1).c_str(), columns.size()); - Gui::Command::commitCommand(); - Gui::Command::doCommand(Gui::Command::Doc, "App.ActiveDocument.recompute()"); -} - void SheetTableView::removeColumns() { - assert(sheet); - - QModelIndexList cols = selectionModel()->selectedColumns(); - std::vector sortedColumns; - - /* Make sure rows are sorted in descending order */ - for (const auto& it : cols) { - sortedColumns.push_back(it.column()); - } - std::sort(sortedColumns.begin(), sortedColumns.end(), std::greater<>()); - - /* Remove columns */ - Gui::Command::openCommand(QT_TRANSLATE_NOOP("Command", "Remove Rows")); - for (const auto& it : sortedColumns) { - Gui::cmdAppObjectArgs(sheet, "removeColumns('%s', %d)", columnName(it).c_str(), 1); + Gui::Command::openCommand(QT_TRANSLATE_NOOP("Command", "Remove Columns")); + for (const auto& [begin, end] : + selectionRanges(selectionModel()->selectedColumns(), Qt::Horizontal)) { + if (!model()->removeColumns(begin, end - begin + 1)) { + Gui::Command::abortCommand(); + return; + } } Gui::Command::commitCommand(); Gui::Command::doCommand(Gui::Command::Doc, "App.ActiveDocument.recompute()"); diff --git a/src/Mod/Spreadsheet/Gui/SheetTableView.h b/src/Mod/Spreadsheet/Gui/SheetTableView.h index 263891d43f..67ef0a069f 100644 --- a/src/Mod/Spreadsheet/Gui/SheetTableView.h +++ b/src/Mod/Spreadsheet/Gui/SheetTableView.h @@ -83,18 +83,17 @@ public Q_SLOTS: protected Q_SLOTS: void commitData(QWidget* editor) override; void updateCellSpan(); - void insertRows(); - void insertRowsAfter(); - void removeRows(); - void insertColumns(); - void insertColumnsAfter(); - void removeColumns(); void cellProperties(); void onRecompute(); void onBind(); void onConfSetup(); protected: + void insertRows(bool after); + void insertColumns(bool after); + void removeRows(); + void removeColumns(); + bool edit(const QModelIndex& index, EditTrigger trigger, QEvent* event) override; bool event(QEvent* event) override; void closeEditor(QWidget* editor, QAbstractItemDelegate::EndEditHint hint) override; diff --git a/src/Mod/Spreadsheet/Gui/ZoomableView.cpp b/src/Mod/Spreadsheet/Gui/ZoomableView.cpp index 592a330c13..d4bd93d433 100644 --- a/src/Mod/Spreadsheet/Gui/ZoomableView.cpp +++ b/src/Mod/Spreadsheet/Gui/ZoomableView.cpp @@ -186,20 +186,20 @@ void ZoomableView::updateView(void) /* QGraphicsView has hardcoded margins therefore we have to avoid fitInView * Find more information at https://bugreports.qt.io/browse/QTBUG-42331 */ - const qreal scale_factor = static_cast(m_zoomLevel) / 100.0, - new_w = static_cast(viewport()->rect().width()) / scale_factor, - new_h = static_cast(viewport()->rect().height()) / scale_factor; + const qreal scale_factor = static_cast(m_zoomLevel) / 100.0; + const qreal new_w = static_cast(viewport()->rect().width()) / scale_factor; + const qreal new_h = static_cast(viewport()->rect().height()) / scale_factor; - const QRectF new_geometry {0.0, 0.0, new_w, new_h}; + const QRectF new_geometry_f {0.0, 0.0, new_w, new_h}; + const QRect new_geometry = new_geometry_f.toRect(); - const QRect old_geometry {stv->geometry()}; - stv->setGeometry(1, 1, old_geometry.width() - 1, old_geometry.height() - 1); + stv->setGeometry(1, 1, new_geometry.width() - 1, new_geometry.height() - 1); resetTransform(); - qpw->setGeometry(new_geometry); - setSceneRect(new_geometry); + qpw->setGeometry(new_geometry_f); + setSceneRect(new_geometry_f); scale(scale_factor, scale_factor); - centerOn(new_geometry.center()); + centerOn(new_geometry_f.center()); } void ZoomableView::focusOutEvent(QFocusEvent* event) diff --git a/src/Mod/Spreadsheet/TestSpreadsheet.py b/src/Mod/Spreadsheet/TestSpreadsheet.py index 70c468b38f..e54fca4a62 100644 --- a/src/Mod/Spreadsheet/TestSpreadsheet.py +++ b/src/Mod/Spreadsheet/TestSpreadsheet.py @@ -1873,6 +1873,15 @@ class SpreadsheetCases(unittest.TestCase): self.assertEqual(sheet.getContents("A1"), "'36C") self.assertEqual(sheet.get("A1"), "36C") + def testDistantCell(self): + sheet = self.doc.addObject("Spreadsheet::Sheet", "Spreadsheet") + sheet.set("ZX12345", "5") + sheet.set("A1", "=ZX12345") + + self.doc.recompute() + + self.assertEqual(sheet.A1, 5) + def testVectorFunctions(self): sheet = self.doc.addObject("Spreadsheet::Sheet", "Spreadsheet")