268 lines
7.7 KiB
C++
268 lines
7.7 KiB
C++
// Copyright (C) 2024 The Qt Company Ltd.
|
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
|
|
|
#include "datamodel.h"
|
|
#include "spreadrole.h"
|
|
|
|
bool DataModel::empty() const
|
|
{
|
|
return m_keys.empty();
|
|
}
|
|
|
|
std::pair<SpreadKey, SpreadKey> DataModel::clearHighlight()
|
|
{
|
|
SpreadKey top_left{INT_MAX, INT_MAX};
|
|
SpreadKey bottom_right{-1, -1};
|
|
|
|
for (auto it = m_cells.begin(); it != m_cells.end();) {
|
|
it.value().set(spread::Role::Hightlight, false);
|
|
if (it.key().first < top_left.first)
|
|
top_left.first = it.key().first;
|
|
if (it.key().second < top_left.second)
|
|
top_left.second = it.key().second;
|
|
if (bottom_right.first < it.key().first)
|
|
bottom_right.first = it.key().first;
|
|
if (bottom_right.second < it.key().second)
|
|
bottom_right.second = it.key().second;
|
|
if (it.value().isNull()) {
|
|
m_keys.remove(it.value().id);
|
|
auto cit = spread::make_const(m_cells, it);
|
|
it = m_cells.erase(cit);
|
|
} else {
|
|
++it;
|
|
}
|
|
}
|
|
|
|
return std::make_pair(top_left, bottom_right);
|
|
}
|
|
|
|
bool DataModel::setHighlight(const SpreadKey &key, bool highlight)
|
|
{
|
|
if (auto it = m_cells.find(key); it != m_cells.end()) {
|
|
it.value().set(spread::Role::Hightlight, highlight);
|
|
if (it.value().isNull()) {
|
|
m_keys.remove(it.value().id);
|
|
auto cit = spread::make_const(m_cells, it);
|
|
m_cells.erase(cit);
|
|
}
|
|
return true;
|
|
}
|
|
if (highlight) {
|
|
SpreadCell cell;
|
|
cell.set(spread::Role::Hightlight, true);
|
|
cell.id = ++lastId;
|
|
m_cells.insert(key, cell);
|
|
m_keys.insert(cell.id, key);
|
|
return true;
|
|
}
|
|
// we skipped false highlight for non-existing cell
|
|
// because we don't store cells with only false hightlight data
|
|
// to save memory
|
|
return false;
|
|
}
|
|
|
|
QVariant DataModel::getData(int id, int role) const
|
|
{
|
|
auto it_key = m_keys.find(id);
|
|
if (it_key == m_keys.end())
|
|
return QVariant{};
|
|
const SpreadKey &key = it_key.value();
|
|
auto it_cell = m_cells.find(key);
|
|
if (it_cell == m_cells.end())
|
|
return QVariant{};
|
|
return it_cell.value().get(role);
|
|
}
|
|
|
|
QVariant DataModel::getData(const SpreadKey &key, int role) const
|
|
{
|
|
auto it = m_cells.find(key);
|
|
return it == m_cells.end() ? QVariant{} : it.value().get(role);
|
|
}
|
|
|
|
bool DataModel::setData(const SpreadKey &key, const QVariant &value, int role)
|
|
{
|
|
// special roles
|
|
switch (role) {
|
|
case spread::Role::Hightlight:
|
|
return setHighlight(key, value.toBool());
|
|
default: break;
|
|
}
|
|
|
|
// no special handling for the role
|
|
if (auto it = m_cells.find(key); it != m_cells.end()) {
|
|
it.value().set(role, value);
|
|
if (it.value().isNull()) {
|
|
clearData(key);
|
|
return true;
|
|
}
|
|
} else {
|
|
SpreadCell cell;
|
|
cell.set(role, value);
|
|
cell.id = ++lastId;
|
|
if (!cell.isNull()) {
|
|
m_cells.insert(key, cell);
|
|
m_keys.insert(cell.id, key);
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool DataModel::clearData(const SpreadKey &key)
|
|
{
|
|
auto find_key = [&key](const auto &i) { return i == key; };
|
|
auto it = std::find_if(m_keys.cbegin(), m_keys.cend(), find_key);
|
|
if (it == m_keys.cend())
|
|
return 0;
|
|
m_keys.erase(it);
|
|
return m_cells.remove(key) > 0;
|
|
}
|
|
|
|
void DataModel::shiftColumns(int from, int count)
|
|
{
|
|
if (count > 0) {
|
|
// the reason for reverse iteration is because of the coverage of
|
|
// the updated keys (bigger keys) and existing keys (next keys)
|
|
QMapIterator i(m_cells);
|
|
i.toBack();
|
|
while (i.hasPrevious()) {
|
|
i.previous();
|
|
if (i.key().second >= from) {
|
|
SpreadKey key = i.key();
|
|
SpreadCell cell = i.value();
|
|
m_cells.remove(key);
|
|
key.second += count;
|
|
m_cells.insert(key, cell);
|
|
}
|
|
}
|
|
} else if (count < 0) {
|
|
// the reason for normal iteration is because of the coverage of
|
|
// the updated keys (smaller keys) and existing keys (previous keys)
|
|
for (auto it = m_cells.begin(); it != m_cells.end(); ++it) {
|
|
if (it.key().second >= from) {
|
|
SpreadKey key = it.key();
|
|
SpreadCell cell = it.value();
|
|
m_cells.remove(key);
|
|
key.second += count;
|
|
m_cells.insert(key, cell);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (count != 0) {
|
|
for (auto it = m_keys.begin(); it != m_keys.end(); ++it) {
|
|
SpreadKey &key = it.value();
|
|
if (key.second >= from)
|
|
key.second += count;
|
|
}
|
|
}
|
|
}
|
|
|
|
void DataModel::removeColumnCells(int column)
|
|
{
|
|
for (auto it = m_cells.begin(); it != m_cells.end(); ) {
|
|
if (it.key().second == column) {
|
|
auto cit = spread::make_const(m_cells, it);
|
|
it = m_cells.erase(cit);
|
|
} else {
|
|
++it;
|
|
}
|
|
}
|
|
|
|
for (auto it = m_keys.begin(); it != m_keys.end(); ) {
|
|
if (it.value().second == column) {
|
|
auto cit = spread::make_const(m_keys, it);
|
|
it = m_keys.erase(cit);
|
|
} else {
|
|
++it;
|
|
}
|
|
}
|
|
}
|
|
|
|
void DataModel::shiftRows(int from, int count)
|
|
{
|
|
if (count > 0) {
|
|
// the reason for reverse iteration is because of the coverage of
|
|
// the updated keys (bigger keys) and existing keys (next keys)
|
|
QMapIterator i(m_cells);
|
|
i.toBack();
|
|
while (i.hasPrevious()) {
|
|
i.previous();
|
|
if (i.key().first < from)
|
|
break;
|
|
SpreadKey key = i.key();
|
|
SpreadCell cell = i.value();
|
|
m_cells.remove(key);
|
|
key.first += count;
|
|
m_cells.insert(key, cell);
|
|
}
|
|
} else if (count < 0) {
|
|
// the reason for normal iteration is because of the coverage of
|
|
// the updated keys (smaller keys) and existing keys (previous keys)
|
|
for (auto it = m_cells.begin(); it != m_cells.end(); ++it) {
|
|
if (it.key().first >= from) {
|
|
SpreadKey key = it.key();
|
|
SpreadCell cell = it.value();
|
|
m_cells.remove(key);
|
|
key.first += count;
|
|
m_cells.insert(key, cell);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (count != 0) {
|
|
for (auto it = m_keys.begin(); it != m_keys.end(); ++it) {
|
|
SpreadKey &key = it.value();
|
|
if (key.first >= from)
|
|
key.first += count;
|
|
}
|
|
}
|
|
}
|
|
|
|
void DataModel::removeRowCells(int row)
|
|
{
|
|
for (auto it = m_cells.begin(); it != m_cells.end(); ) {
|
|
if (it.key().first == row) {
|
|
auto cit = spread::make_const(m_cells, it);
|
|
it = m_cells.erase(cit);
|
|
} else {
|
|
++it;
|
|
}
|
|
}
|
|
|
|
for (auto it = m_keys.begin(); it != m_keys.end(); ) {
|
|
if (it.value().first == row) {
|
|
auto cit = spread::make_const(m_keys, it);
|
|
it = m_keys.erase(cit);
|
|
} else {
|
|
++it;
|
|
}
|
|
}
|
|
}
|
|
|
|
int DataModel::createId(const SpreadKey &key)
|
|
{
|
|
auto find_key = [&key](const auto &elem) { return key == elem; };
|
|
auto it = std::find_if(m_keys.begin(), m_keys.end(), find_key);
|
|
if (it != m_keys.end())
|
|
return it.key();
|
|
const int id = ++lastId;
|
|
m_keys.insert(id, key);
|
|
return id;
|
|
}
|
|
|
|
int DataModel::getId(const SpreadKey &key) const
|
|
{
|
|
auto find_key = [&key](const auto &elem) { return key == elem; };
|
|
auto it = std::find_if(m_keys.begin(), m_keys.end(), find_key);
|
|
if (it == m_keys.end())
|
|
return 0;
|
|
return it.key();
|
|
}
|
|
|
|
SpreadKey DataModel::getKey(int id) const
|
|
{
|
|
auto it = m_keys.find(id);
|
|
return it == m_keys.end() ? SpreadKey{-1, -1} : it.value();
|
|
}
|