Spreadsheet: Decrease default size (#27152)

* Spreadsheet: dynamic row and coulumn counts

* Spreadsheet: test distant cell

* Spreadsheet: fix removeColumns condition

* Spreadsheet: Fix zoom detachment

* Spreadsheet: Fix SheetModel::containInView

* Spreadsheet: Make sure the number of rows/cols decreases correctly after removal

* Spreadsheet: Code quality fixes

* Spreadsheet: Fix typo

* Spreadsheet: Move sheet->insert/remove outside Qt signals

* Update src/Mod/Spreadsheet/Gui/SheetTableView.cpp

Co-authored-by: Benjamin Nauck <[email protected]>

* Update src/Mod/Spreadsheet/Gui/SheetModel.h

Co-authored-by: Benjamin Nauck <[email protected]>

* Spreadsheet: Add comment about nesting beginInsertColumn

* Spreadsheet: Remove c-style Qt header

---------

Co-authored-by: Benjamin Nauck <[email protected]>
This commit is contained in:
Grzegorz Kwacz
2026-03-07 20:59:49 +01:00
committed by GitHub
co-authored by Benjamin Nauck
parent d2b84db105
commit 1027be1efa
6 changed files with 223 additions and 244 deletions
+127 -51
View File
@@ -23,10 +23,10 @@
***************************************************************************/
#include <QAbstractItemModel>
#include <QFont>
#include <QLocale>
#include <App/Document.h>
#include <Base/Interpreter.h>
#include <Base/Tools.h>
@@ -36,6 +36,7 @@
#include <Mod/Spreadsheet/App/Sheet.h>
#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<char>('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"
+8 -6
View File
@@ -24,6 +24,7 @@
#pragma once
#include "fastsignals/connection.h"
#include <QAbstractTableModel>
#include <App/Range.h>
@@ -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<fastsignals::scoped_connection> 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
+65 -172
View File
@@ -22,6 +22,7 @@
* *
***************************************************************************/
#include <algorithm>
#include <limits>
#include <QAction>
#include <QApplication>
@@ -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<std::pair<int, int>> selectionRanges(
const QModelIndexList& selection,
Qt::Orientation orientation
)
{
std::vector<int> values;
for (const auto& index : selection) {
values.emplace_back(orientation == Qt::Horizontal ? index.column() : index.row());
}
std::ranges::sort(values, std::greater<>());
std::vector<std::pair<int, int>> 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<int, int> selectedMinMaxRows(QModelIndexList list)
{
int min = std::numeric_limits<int>::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<int, int> selectedMinMaxColumns(QModelIndexList list)
{
int min = std::numeric_limits<int>::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<int> 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<int>::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<int> 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<int> 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<int>::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<int> 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()");
+5 -6
View File
@@ -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;
+9 -9
View File
@@ -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<qreal>(m_zoomLevel) / 100.0,
new_w = static_cast<qreal>(viewport()->rect().width()) / scale_factor,
new_h = static_cast<qreal>(viewport()->rect().height()) / scale_factor;
const qreal scale_factor = static_cast<qreal>(m_zoomLevel) / 100.0;
const qreal new_w = static_cast<qreal>(viewport()->rect().width()) / scale_factor;
const qreal new_h = static_cast<qreal>(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)
+9
View File
@@ -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")