// 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 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(); }