Add the Spreadsheet example
The example demonstrates a Spreadsheet that provides adding, editing,
and deleting data, and also the ability to write formulas for numeric
data. Also, it's possible to select cells, rows, and columns for
deleting them or their data, copying or cutting the data, and dragging
them to other places. The user can hide columns or rows, and also show
them again. Thanks to the reordering API, columns and rows can be
reordered and also can be reset to the default order.
There is a SpreadModel class which handles the entered data. It only
stores the data of the cells that is provided by the user. It means
that it does not create any empty data structure for empty cells, in
order to reduce memory usage.
Task-number: QTBUG-125767
Pick-to: 6.8
Change-Id: I1d9cc5b4b8d902257e9ed508d4a712b0574490f3
Reviewed-by: Richard Moe Gustavsen <richard.gustavsen@qt.io>
2024-05-27 16:06:47 +00:00
|
|
|
// Copyright (C) 2024 The Qt Company Ltd.
|
|
|
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
|
|
|
|
|
|
|
#ifndef SPREADMODEL_H
|
|
|
|
#define SPREADMODEL_H
|
|
|
|
|
|
|
|
#include "datamodel.h"
|
|
|
|
|
|
|
|
#include <QQmlEngine>
|
|
|
|
#include <QAbstractTableModel>
|
|
|
|
#include <QItemSelectionModel>
|
2024-06-06 11:06:15 +00:00
|
|
|
#include <QMutex>
|
Add the Spreadsheet example
The example demonstrates a Spreadsheet that provides adding, editing,
and deleting data, and also the ability to write formulas for numeric
data. Also, it's possible to select cells, rows, and columns for
deleting them or their data, copying or cutting the data, and dragging
them to other places. The user can hide columns or rows, and also show
them again. Thanks to the reordering API, columns and rows can be
reordered and also can be reset to the default order.
There is a SpreadModel class which handles the entered data. It only
stores the data of the cells that is provided by the user. It means
that it does not create any empty data structure for empty cells, in
order to reduce memory usage.
Task-number: QTBUG-125767
Pick-to: 6.8
Change-Id: I1d9cc5b4b8d902257e9ed508d4a712b0574490f3
Reviewed-by: Richard Moe Gustavsen <richard.gustavsen@qt.io>
2024-05-27 16:06:47 +00:00
|
|
|
|
|
|
|
|
|
|
|
class DataModel;
|
|
|
|
class SpreadModel;
|
2024-09-09 10:05:51 +00:00
|
|
|
class Formula;
|
Add the Spreadsheet example
The example demonstrates a Spreadsheet that provides adding, editing,
and deleting data, and also the ability to write formulas for numeric
data. Also, it's possible to select cells, rows, and columns for
deleting them or their data, copying or cutting the data, and dragging
them to other places. The user can hide columns or rows, and also show
them again. Thanks to the reordering API, columns and rows can be
reordered and also can be reset to the default order.
There is a SpreadModel class which handles the entered data. It only
stores the data of the cells that is provided by the user. It means
that it does not create any empty data structure for empty cells, in
order to reduce memory usage.
Task-number: QTBUG-125767
Pick-to: 6.8
Change-Id: I1d9cc5b4b8d902257e9ed508d4a712b0574490f3
Reviewed-by: Richard Moe Gustavsen <richard.gustavsen@qt.io>
2024-05-27 16:06:47 +00:00
|
|
|
|
|
|
|
class SpreadModel final : public QAbstractTableModel
|
|
|
|
{
|
|
|
|
Q_OBJECT
|
|
|
|
QML_ELEMENT
|
|
|
|
QML_SINGLETON
|
|
|
|
Q_DISABLE_COPY_MOVE(SpreadModel)
|
|
|
|
|
|
|
|
friend class SpreadSelectionModel;
|
|
|
|
friend class SpreadCell;
|
|
|
|
friend struct Formula;
|
|
|
|
|
|
|
|
protected:
|
|
|
|
explicit SpreadModel(QObject *parent = nullptr) : QAbstractTableModel(parent) { }
|
|
|
|
|
|
|
|
public:
|
|
|
|
int rowCount() const { return rowCount(QModelIndex{}); }
|
|
|
|
int columnCount() const { return columnCount(QModelIndex{}); }
|
|
|
|
|
|
|
|
const DataModel *dataModel() { return &m_dataModel; }
|
|
|
|
|
|
|
|
int columnNumberFromName(const QString &text);
|
|
|
|
int rowNumberFromName(const QString &text);
|
|
|
|
// returns nullptr if it's not been created yet.
|
|
|
|
static SpreadModel *instance();
|
|
|
|
static SpreadModel *create(QQmlEngine *, QJSEngine *);
|
|
|
|
|
|
|
|
protected:
|
2024-06-06 11:06:15 +00:00
|
|
|
Q_INVOKABLE void update(int row, int column);
|
Add the Spreadsheet example
The example demonstrates a Spreadsheet that provides adding, editing,
and deleting data, and also the ability to write formulas for numeric
data. Also, it's possible to select cells, rows, and columns for
deleting them or their data, copying or cutting the data, and dragging
them to other places. The user can hide columns or rows, and also show
them again. Thanks to the reordering API, columns and rows can be
reordered and also can be reset to the default order.
There is a SpreadModel class which handles the entered data. It only
stores the data of the cells that is provided by the user. It means
that it does not create any empty data structure for empty cells, in
order to reduce memory usage.
Task-number: QTBUG-125767
Pick-to: 6.8
Change-Id: I1d9cc5b4b8d902257e9ed508d4a712b0574490f3
Reviewed-by: Richard Moe Gustavsen <richard.gustavsen@qt.io>
2024-05-27 16:06:47 +00:00
|
|
|
Q_INVOKABLE void clearHighlight();
|
|
|
|
Q_INVOKABLE void setHighlight(const QModelIndex &index, bool highlight);
|
|
|
|
Q_INVOKABLE bool clearItemData(const QModelIndexList &indexes);
|
|
|
|
Q_INVOKABLE bool removeColumns(QModelIndexList indexes);
|
|
|
|
Q_INVOKABLE bool removeRows(QModelIndexList indexes);
|
|
|
|
Q_INVOKABLE void mapColumn(int model, int view);
|
|
|
|
Q_INVOKABLE void mapRow(int model, int view);
|
|
|
|
Q_INVOKABLE void resetColumnMapping() { m_viewColumns.clear(); }
|
|
|
|
Q_INVOKABLE void resetRowMapping() { m_viewRows.clear(); }
|
|
|
|
|
|
|
|
// QAbstractItemModel interface
|
|
|
|
int rowCount(const QModelIndex &parent) const override;
|
|
|
|
int columnCount(const QModelIndex &parent) const override;
|
|
|
|
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
|
|
|
|
bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) override;
|
|
|
|
Q_INVOKABLE bool clearItemData(const QModelIndex &index) override;
|
|
|
|
Qt::ItemFlags flags(const QModelIndex &index) const override;
|
|
|
|
QHash<int, QByteArray> roleNames() const override;
|
|
|
|
QVariant headerData(int section, Qt::Orientation orientation, int role) const override;
|
|
|
|
bool insertColumns(int column, int count, const QModelIndex &parent = QModelIndex{}) override;
|
|
|
|
bool insertRows(int row, int count, const QModelIndex &parent = QModelIndex{}) override;
|
|
|
|
bool removeColumns(int column, int count, const QModelIndex &parent = QModelIndex{}) override;
|
|
|
|
bool removeRows(int row, int count, const QModelIndex &parent = QModelIndex{}) override;
|
|
|
|
|
|
|
|
private:
|
|
|
|
Formula parseFormulaString(const QString &text);
|
|
|
|
QString formulaValueText(const Formula &formula);
|
|
|
|
int getViewColumn(int modelColumn) const;
|
|
|
|
int getModelColumn(int viewColumn) const;
|
|
|
|
int getViewRow(int modelRow) const;
|
|
|
|
int getModelRow(int viewRow) const;
|
|
|
|
|
|
|
|
private:
|
|
|
|
std::pair<int, int> m_size {1000, 26}; // rows:1-1000, columns:A-Z
|
|
|
|
DataModel m_dataModel;
|
|
|
|
QMap<int, int> m_viewColumns;
|
|
|
|
QMap<int, int> m_viewRows;
|
2024-06-06 11:06:15 +00:00
|
|
|
QMutex m_updateMutex;
|
Add the Spreadsheet example
The example demonstrates a Spreadsheet that provides adding, editing,
and deleting data, and also the ability to write formulas for numeric
data. Also, it's possible to select cells, rows, and columns for
deleting them or their data, copying or cutting the data, and dragging
them to other places. The user can hide columns or rows, and also show
them again. Thanks to the reordering API, columns and rows can be
reordered and also can be reset to the default order.
There is a SpreadModel class which handles the entered data. It only
stores the data of the cells that is provided by the user. It means
that it does not create any empty data structure for empty cells, in
order to reduce memory usage.
Task-number: QTBUG-125767
Pick-to: 6.8
Change-Id: I1d9cc5b4b8d902257e9ed508d4a712b0574490f3
Reviewed-by: Richard Moe Gustavsen <richard.gustavsen@qt.io>
2024-05-27 16:06:47 +00:00
|
|
|
static inline SpreadModel *s_instance {nullptr};
|
|
|
|
};
|
|
|
|
|
|
|
|
class SpreadSelectionModel : public QItemSelectionModel
|
|
|
|
{
|
|
|
|
Q_OBJECT
|
|
|
|
QML_ELEMENT
|
|
|
|
|
|
|
|
Q_PROPERTY(Behavior behavior READ getBehavior WRITE setBehavior NOTIFY behaviorChanged FINAL)
|
|
|
|
|
|
|
|
public:
|
|
|
|
enum Behavior {
|
|
|
|
DisabledBehavior,
|
|
|
|
SelectCells,
|
|
|
|
SelectColumns,
|
|
|
|
SelectRows,
|
|
|
|
};
|
|
|
|
Q_ENUM(Behavior)
|
|
|
|
|
|
|
|
public:
|
|
|
|
Q_INVOKABLE void toggleColumn(int column);
|
|
|
|
Q_INVOKABLE void deselectColumn(int column);
|
|
|
|
Q_INVOKABLE void selectColumn(int column, bool clear = true);
|
|
|
|
Q_INVOKABLE void toggleRow(int row);
|
|
|
|
Q_INVOKABLE void deselectRow(int row);
|
|
|
|
Q_INVOKABLE void selectRow(int row, bool clear = true);
|
|
|
|
|
|
|
|
protected:
|
|
|
|
Behavior getBehavior() const { return m_behavior; }
|
|
|
|
|
|
|
|
protected slots:
|
|
|
|
void setBehavior(Behavior);
|
|
|
|
|
|
|
|
signals:
|
|
|
|
void behaviorChanged();
|
|
|
|
|
|
|
|
private:
|
|
|
|
Behavior m_behavior = Behavior::DisabledBehavior;
|
|
|
|
};
|
|
|
|
|
|
|
|
class HeaderSelectionModel : public QItemSelectionModel
|
|
|
|
{
|
|
|
|
Q_OBJECT
|
|
|
|
QML_ELEMENT
|
|
|
|
|
|
|
|
Q_PROPERTY(SpreadSelectionModel* selectionModel READ getSelectionModel WRITE setSelectionModel NOTIFY selectionModelChanged FINAL)
|
|
|
|
Q_PROPERTY(Qt::Orientation orientation READ getOrientation WRITE setOrientation NOTIFY orientationChanged FINAL)
|
|
|
|
|
|
|
|
protected:
|
|
|
|
Q_INVOKABLE void setCurrent(int current = -1);
|
|
|
|
SpreadSelectionModel *getSelectionModel() { return m_selectionModel; }
|
|
|
|
Qt::Orientation getOrientation() const { return m_orientation; }
|
|
|
|
|
|
|
|
protected slots:
|
|
|
|
void setSelectionModel(SpreadSelectionModel *selectionModel);
|
|
|
|
void setOrientation(Qt::Orientation orientation);
|
|
|
|
|
|
|
|
private slots:
|
|
|
|
void onSelectionChanged(const QItemSelection &selected, const QItemSelection &deselected);
|
|
|
|
|
|
|
|
signals:
|
|
|
|
void selectionModelChanged();
|
|
|
|
void orientationChanged();
|
|
|
|
|
|
|
|
private:
|
|
|
|
SpreadSelectionModel *m_selectionModel = nullptr;
|
|
|
|
Qt::Orientation m_orientation = Qt::Horizontal;
|
|
|
|
};
|
|
|
|
|
|
|
|
#endif // SPREADMODEL_H
|