1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154
|
// 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
|