155 lines
5.0 KiB
C++
155 lines
5.0 KiB
C++
// 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>
|
|
#include <QMutex>
|
|
|
|
|
|
class DataModel;
|
|
class SpreadModel;
|
|
class Formula;
|
|
|
|
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:
|
|
Q_INVOKABLE void update(int row, int column);
|
|
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;
|
|
QMutex m_updateMutex;
|
|
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
|