// Copyright (C) 2024 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause #include "spreadformula.h" #include "datamodel.h" #include "spreadkey.h" #include "spreadrole.h" #include "spreadmodel.h" bool Formula::includesLoop(SpreadModel *model, const DataModel *dataModel, QSet *history) const { if (m_operator == Operator::Invalid) return false; if (history == nullptr) { QSet history; return includesLoop(model, dataModel, &history); } if (m_operator == Operator::Sum) { SpreadKey top_left = dataModel->getKey(m_cellIds.first); SpreadKey bottom_right = dataModel->getKey(m_cellIds.second); if (bottom_right.first < top_left.first) std::swap(top_left.first, bottom_right.first); if (bottom_right.second < top_left.second) std::swap(top_left.second, bottom_right.second); for (int row = top_left.first; row <= bottom_right.first; ++row) { for (int column = top_left.second; column <= bottom_right.second; ++column) { const int id = dataModel->getId(SpreadKey{row, column}); if (history->find(id) != history->end()) return true; const QString edit_text = dataModel->getData(id, spread::Role::Edit).toString(); const Formula formula = model->parseFormulaString(edit_text); if (!formula.isValid()) continue; auto it = history->insert(id); if (formula.includesLoop(model, dataModel, history)) return true; auto cit = spread::make_const(*history, it); history->erase(cit); } } } else { const int id_1 = m_cellIds.first; if (history->find(id_1) != history->end()) return true; const QString edit_text = dataModel->getData(id_1, spread::Role::Edit).toString(); const Formula formula = model->parseFormulaString(edit_text); if (!formula.isValid()) return false; auto it = history->insert(id_1); if (formula.includesLoop(model, dataModel, history)) return true; auto cit = spread::make_const(*history, it); history->erase(cit); if (m_operator != Operator::Assign) { const int id_2 = m_cellIds.second; if (history->find(id_2) != history->end()) return true; const QString edit_text = dataModel->getData(id_2, spread::Role::Edit).toString(); const Formula formula = model->parseFormulaString(edit_text); if (!formula.isValid()) return false; auto it = history->insert(id_2); if (formula.includesLoop(model, dataModel, history)) return true; auto cit = spread::make_const(*history, it); history->erase(cit); } } return false; }