File indexing completed on 2024-05-12 05:39:38

0001 /***************************************************************************
0002  * Copyright (C) 2014 by Renaud Guezennec                                   *
0003  * http://www.rolisteam.org/                                                *
0004  *                                                                          *
0005  *  This file is part of rcse                                               *
0006  *                                                                          *
0007  * rcse is free software; you can redistribute it and/or modify             *
0008  * it under the terms of the GNU General Public License as published by     *
0009  * the Free Software Foundation; either version 2 of the License, or        *
0010  * (at your option) any later version.                                      *
0011  *                                                                          *
0012  * rcse is distributed in the hope that it will be useful,                  *
0013  * but WITHOUT ANY WARRANTY; without even the implied warranty of           *
0014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the             *
0015  * GNU General Public License for more details.                             *
0016  *                                                                          *
0017  * You should have received a copy of the GNU General Public License        *
0018  * along with this program; if not, write to the                            *
0019  * Free Software Foundation, Inc.,                                          *
0020  * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.                 *
0021  ***************************************************************************/
0022 #include "fieldmodel.h"
0023 
0024 #include <QDebug>
0025 #include <QGraphicsScene>
0026 #include <QJsonArray>
0027 
0028 #include "canvas.h"
0029 #include "qmlgeneratorvisitor.h"
0030 #include <charactersheet_formula/formulamanager.h>
0031 
0032 //////////////////////////////
0033 // Column
0034 /////////////////////////////
0035 Column::Column(QString name, TreeSheetItem::ColumnId pos) : m_name(name), m_pos(pos) {}
0036 
0037 QString Column::getName() const
0038 {
0039     return m_name;
0040 }
0041 
0042 void Column::setName(const QString& name)
0043 {
0044     m_name= name;
0045 }
0046 TreeSheetItem::ColumnId Column::getPos() const
0047 {
0048     return m_pos;
0049 }
0050 
0051 void Column::setPos(const TreeSheetItem::ColumnId& pos)
0052 {
0053     m_pos= pos;
0054 }
0055 
0056 //////////////////////////////
0057 // FieldModel
0058 /////////////////////////////
0059 FieldModel::FieldModel(QObject* parent)
0060     : QAbstractItemModel(parent), m_rootSection{new Section()}, m_formulaManager{new Formula::FormulaManager()}
0061 {
0062     m_colunm << new Column(tr("Id"), TreeSheetItem::ID) << new Column(tr("Label"), TreeSheetItem::LABEL)
0063              << new Column(tr("Value"), TreeSheetItem::VALUE)
0064              << new Column(tr("Possible Values"), TreeSheetItem::VALUES) << new Column(tr("Type"), TreeSheetItem::TYPE)
0065              << new Column(tr("x"), TreeSheetItem::X) << new Column(tr("y"), TreeSheetItem::Y)
0066              << new Column(tr("Width"), TreeSheetItem::WIDTH) << new Column(tr("Height"), TreeSheetItem::HEIGHT)
0067              << new Column(tr("Font Adaptation"), TreeSheetItem::FitFont) << new Column(tr("Font"), TreeSheetItem::FONT)
0068              << new Column(tr("Text-align"), TreeSheetItem::TEXT_ALIGN)
0069              << new Column(tr("Text Color"), TreeSheetItem::TEXTCOLOR)
0070              << new Column(tr("Bg Color"), TreeSheetItem::BGCOLOR) << new Column(tr("Border"), TreeSheetItem::BORDER)
0071              << new Column(tr("Page"), TreeSheetItem::PAGE) << new Column(tr("ToolTip"), TreeSheetItem::TOOLTIP);
0072 
0073     m_alignList << tr("TopRight") << tr("TopMiddle") << tr("TopLeft") << tr("CenterRight") << tr("CenterMiddle")
0074                 << tr("CenterLeft") << tr("BottomRight") << tr("BottomMiddle") << tr("BottomLeft");
0075 }
0076 
0077 FieldModel::~FieldModel()= default;
0078 
0079 QVariant FieldModel::data(const QModelIndex& index, int role) const
0080 {
0081     if(!index.isValid())
0082         return QVariant();
0083     TreeSheetItem* treeitem= static_cast<TreeSheetItem*>(index.internalPointer());
0084 
0085     if(nullptr == treeitem)
0086         return {};
0087 
0088     auto item= dynamic_cast<CSItem*>(treeitem);
0089 
0090     if(nullptr == item)
0091     {
0092         if(index.column() == 0 && role == Qt::DisplayRole)
0093         {
0094             return item->id();
0095         }
0096         else
0097             return {};
0098     }
0099     if((role == Qt::DisplayRole) || (Qt::EditRole == role))
0100     {
0101         QVariant var;
0102         if(TreeSheetItem::VALUE == m_colunm[index.column()]->getPos() && role == Qt::EditRole)
0103         {
0104 
0105             auto formula= item->formula();
0106             var= formula.isEmpty() ? item->valueFrom(m_colunm[index.column()]->getPos(), role) : formula;
0107         }
0108         else
0109             var= item->valueFrom(m_colunm[index.column()]->getPos(), role);
0110         if((index.column() == TreeSheetItem::TEXT_ALIGN) && (Qt::DisplayRole == role))
0111         {
0112             if((var.toInt() >= 0) && (var.toInt() < m_alignList.size()))
0113             {
0114                 var= m_alignList.at(var.toInt());
0115             }
0116         }
0117         return var;
0118     }
0119     if((role == Qt::BackgroundRole)
0120        && ((index.column() == TreeSheetItem::BGCOLOR) || (index.column() == TreeSheetItem::TEXTCOLOR)))
0121     {
0122         QVariant var= item->valueFrom(m_colunm[index.column()]->getPos(), Qt::EditRole);
0123         return var;
0124     }
0125     if(role == Qt::BackgroundRole)
0126     {
0127         auto field= dynamic_cast<FieldController*>(item);
0128         QVariant color;
0129         if(field && !field->generatedCode().isEmpty())
0130         {
0131             color= QColor(Qt::green).lighter();
0132         }
0133         if(field && field->isReadOnly() && (index.column() >= TreeSheetItem::X)
0134            && (index.column() <= TreeSheetItem::HEIGHT))
0135         {
0136             color= QColor(Qt::gray);
0137         }
0138         return color;
0139     }
0140     if((Qt::FontRole == role) && (index.column() == TreeSheetItem::FONT))
0141     {
0142         QVariant var= item->valueFrom(m_colunm[index.column()]->getPos(), Qt::DisplayRole);
0143         QFont font;
0144         font.fromString(var.toString());
0145         return font;
0146     }
0147     return QVariant();
0148 }
0149 
0150 bool FieldModel::setData(const QModelIndex& index, const QVariant& value, int role)
0151 {
0152     if(!index.isValid() || Qt::EditRole != role)
0153         return false;
0154 
0155     TreeSheetItem* treeitem= static_cast<TreeSheetItem*>(index.internalPointer());
0156 
0157     if(nullptr == treeitem)
0158         return false;
0159 
0160     auto item= dynamic_cast<CSItem*>(treeitem);
0161 
0162     if(!item && index.column() == 0 && role == Qt::DisplayRole)
0163     {
0164         treeitem->setId(value.toString());
0165         return true;
0166     }
0167     if(nullptr == item)
0168         return false;
0169 
0170     auto valStr= value.toString();
0171 
0172     if(TreeSheetItem::VALUE == m_colunm[index.column()]->getPos() && valStr.startsWith("="))
0173     {
0174         QHash<QString, QString> hash= buildDicto();
0175         m_formulaManager->setConstantHash(hash);
0176         auto valueAfterComputation= m_formulaManager->getValue(valStr).toString();
0177         item->setFormula(valStr);
0178         item->setValueFrom(m_colunm[index.column()]->getPos(), valueAfterComputation);
0179     }
0180     else
0181     {
0182         item->setValueFrom(m_colunm[index.column()]->getPos(), value);
0183     }
0184     emit valuesChanged(item->valueFrom(TreeSheetItem::ID, Qt::DisplayRole).toString(), value.toString());
0185     emit modelChanged();
0186     return true;
0187 }
0188 
0189 QHash<QString, QString> FieldModel::buildDicto()
0190 {
0191     QHash<QString, QString> dict;
0192     m_rootSection->setFieldInDictionnary(dict);
0193     return dict;
0194 }
0195 
0196 QModelIndex FieldModel::index(int row, int column, const QModelIndex& parent) const
0197 {
0198     if(row < 0)
0199         return QModelIndex();
0200 
0201     TreeSheetItem* parentItem= nullptr;
0202 
0203     // qDebug()<< "Index session " <<row << column << parent;
0204     if(!parent.isValid())
0205         parentItem= m_rootSection.get();
0206     else
0207         parentItem= static_cast<TreeSheetItem*>(parent.internalPointer());
0208 
0209     TreeSheetItem* childItem= parentItem->childAt(row);
0210     if(childItem)
0211         return createIndex(row, column, childItem);
0212     else
0213         return QModelIndex();
0214 }
0215 
0216 QModelIndex FieldModel::parent(const QModelIndex& child) const
0217 {
0218     if(!child.isValid())
0219         return QModelIndex();
0220 
0221     TreeSheetItem* childItem= static_cast<TreeSheetItem*>(child.internalPointer());
0222     TreeSheetItem* parentItem= childItem->parentTreeItem();
0223 
0224     if(parentItem == m_rootSection.get())
0225         return QModelIndex();
0226 
0227     TreeSheetItem* grandParent= parentItem->parentTreeItem();
0228 
0229     return createIndex(grandParent->indexOfChild(parentItem), 0, parentItem);
0230 }
0231 
0232 int FieldModel::rowCount(const QModelIndex& parent) const
0233 {
0234     if(!parent.isValid())
0235         return m_rootSection->childrenCount();
0236 
0237     TreeSheetItem* childItem= static_cast<TreeSheetItem*>(parent.internalPointer());
0238     if(childItem)
0239         return childItem->childrenCount();
0240     else
0241         return 0;
0242 }
0243 
0244 int FieldModel::columnCount(const QModelIndex& parent) const
0245 {
0246     Q_UNUSED(parent)
0247     return m_colunm.count();
0248 }
0249 
0250 QVariant FieldModel::headerData(int section, Qt::Orientation orientation, int role) const
0251 {
0252     if((role == Qt::DisplayRole) && (orientation == Qt::Horizontal))
0253     {
0254         return m_colunm[section]->getName();
0255     }
0256     else
0257     {
0258         return QVariant();
0259     }
0260 }
0261 
0262 void FieldModel::appendField(CSItem* f)
0263 {
0264     beginInsertRows(QModelIndex(), m_rootSection->childrenCount(), m_rootSection->childrenCount());
0265     m_rootSection->appendChild(f);
0266     auto func= [this, f]() { emit updateItem(f); };
0267     connect(f, &CSItem::characterSheetItemChanged, this, func);
0268     connect(f, &CSItem::xChanged, this, func);
0269     connect(f, &CSItem::yChanged, this, func);
0270     connect(f, &CSItem::widthChanged, this, func);
0271     connect(f, &CSItem::heightChanged, this, func);
0272     connect(f, &CSItem::borderChanged, this, func);
0273     connect(f, &CSItem::bgColorChanged, this, func);
0274 
0275     connect(f, &CSItem::valueChanged, this, func);
0276     connect(f, &CSItem::textColorChanged, this, func);
0277     connect(f, &CSItem::textAlignChanged, this, func);
0278     connect(f, &CSItem::bgColorChanged, this, func);
0279     connect(f, &CSItem::valuesChanged, this, func);
0280     connect(f, &CSItem::pageChanged, this, func);
0281     connect(f, &CSItem::readOnlyChanged, this, func);
0282     connect(f, &CSItem::formulaChanged, this, func);
0283     connect(f, &CSItem::idChanged, this, func);
0284     connect(f, &CSItem::labelChanged, this, func);
0285 
0286     endInsertRows();
0287     emit modelChanged();
0288     emit fieldAdded(f);
0289 }
0290 void FieldModel::insertField(CSItem* field, TreeSheetItem* parent, int pos)
0291 {
0292     beginInsertRows(QModelIndex(), pos, pos);
0293     if(parent == m_rootSection.get())
0294     {
0295         m_rootSection->insertChild(field, pos);
0296     }
0297     endInsertRows();
0298     emit modelChanged();
0299 }
0300 Qt::ItemFlags FieldModel::flags(const QModelIndex& index) const
0301 {
0302     if(!index.isValid())
0303         return Qt::ItemIsEnabled;
0304 
0305     // TreeSheetItem* childItem = static_cast<TreeSheetItem*>(index.internalPointer());
0306     if(m_colunm[index.column()]->getPos() == TreeSheetItem::ID)
0307     {
0308         return Qt::ItemIsEnabled | Qt::ItemIsEditable | Qt::ItemIsSelectable;
0309     }
0310     else if(m_colunm[index.column()]->getPos() == TreeSheetItem::TYPE)
0311     {
0312         return Qt::ItemIsEnabled | Qt::ItemIsEditable | Qt::ItemIsSelectable;
0313     }
0314     else if(m_colunm[index.column()]->getPos() == TreeSheetItem::FONT)
0315     {
0316         return Qt::ItemIsEnabled | Qt::ItemIsSelectable;
0317     }
0318     else // if(!childItem->mayHaveChildren())
0319     {
0320         return Qt::ItemIsEnabled | Qt::ItemIsEditable | Qt::ItemIsSelectable /*| Qt::ItemIsUserCheckable */;
0321     }
0322     /*else
0323         return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsUserCheckable ;*/
0324 }
0325 void FieldModel::generateQML(QTextStream& out, int indentation, bool isTable)
0326 {
0327     QmlGeneratorVisitor visitor(out, m_rootSection.get());
0328     visitor.setIndentation(indentation);
0329     visitor.setIsTable(isTable);
0330     visitor.generateTreeSheetItem();
0331     // m_rootSection->generateQML(out,TreeSheetItem::FieldSec,0,isTable);
0332 }
0333 
0334 QString FieldModel::getValue(const QString& key)
0335 {
0336     return key;
0337 }
0338 
0339 QList<TreeSheetItem*> FieldModel::children()
0340 {
0341     QList<TreeSheetItem*> result;
0342     for(int i= 0; i < m_rootSection->childrenCount(); ++i)
0343     {
0344         result.append(m_rootSection->childAt(i));
0345     }
0346     return result;
0347 }
0348 
0349 QList<CSItem*> FieldModel::allChildren() const
0350 {
0351     return m_rootSection->allChildren();
0352 }
0353 
0354 QRectF FieldModel::childrenRect() const
0355 {
0356     QRectF res{0., 0., 1., 1.};
0357     auto alls= allChildren();
0358     for(auto field : alls)
0359     {
0360         if(!field)
0361             continue;
0362         res= res.united(QRectF{field->x(), field->y(), field->width(), field->height()});
0363     }
0364     return res;
0365 }
0366 
0367 void FieldModel::getFieldFromPage(int pagePos, QList<CSItem*>& list)
0368 {
0369     list= m_rootSection->fieldFromPage(pagePos);
0370 }
0371 
0372 FieldController* FieldModel::getFieldFromIndex(const QModelIndex& index)
0373 {
0374     return static_cast<FieldController*>(index.internalPointer());
0375 }
0376 
0377 void FieldModel::updateItem(CSItem* item)
0378 {
0379     int ind= m_rootSection->indexOfChild(item);
0380     if(ind >= 0)
0381     {
0382         emit dataChanged(createIndex(ind, 0, item), createIndex(ind, m_colunm.size(), item));
0383         emit modelChanged();
0384     }
0385     else
0386     {
0387         TreeSheetItem* parent= item->parentTreeItem();
0388         QList<TreeSheetItem*> list;
0389         while(parent != nullptr)
0390         {
0391             list.prepend(parent);
0392             parent= parent->parentTreeItem();
0393         }
0394 
0395         QModelIndex first;
0396         QModelIndex second;
0397         int i= 0;
0398         for(TreeSheetItem* itemtmp : list)
0399         {
0400             TreeSheetItem* next= nullptr;
0401             if(i + 1 > list.size())
0402             {
0403                 next= list[++i];
0404             }
0405             else
0406             {
0407                 next= item;
0408             }
0409 
0410             if(itemtmp == m_rootSection.get())
0411             {
0412                 first= index(itemtmp->indexOfChild(next), 0, first);
0413                 second= index(itemtmp->indexOfChild(next), m_colunm.size(), second);
0414             }
0415         }
0416         emit dataChanged(first, second);
0417         emit modelChanged();
0418     }
0419 }
0420 
0421 Section* FieldModel::getRootSection() const
0422 {
0423     return m_rootSection.get();
0424 }
0425 
0426 void FieldModel::setRootSection(Section* rootSection)
0427 {
0428     beginResetModel();
0429     m_rootSection.reset(rootSection);
0430     endResetModel();
0431 }
0432 void FieldModel::save(QJsonObject& json, bool exp)
0433 {
0434     m_rootSection->save(json, exp);
0435 }
0436 
0437 void FieldModel::load(const QJsonObject& json)
0438 {
0439     beginResetModel();
0440     m_rootSection->load(json);
0441     endResetModel();
0442 }
0443 void FieldModel::removeItem(QModelIndex& index)
0444 {
0445     if(index.isValid())
0446     {
0447         TreeSheetItem* childItem= static_cast<TreeSheetItem*>(index.internalPointer());
0448         Section* parentSection= nullptr;
0449         if(index.parent().isValid())
0450         {
0451             TreeSheetItem* parentItem= static_cast<TreeSheetItem*>(index.internalPointer());
0452             parentSection= dynamic_cast<Section*>(parentItem);
0453         }
0454         else
0455         {
0456             parentSection= m_rootSection.get();
0457         }
0458 
0459         if(nullptr == parentSection)
0460         {
0461             return;
0462         }
0463         beginRemoveRows(index.parent(), parentSection->indexOfChild(childItem), parentSection->indexOfChild(childItem));
0464 
0465         parentSection->deleteChild(childItem);
0466 
0467         endRemoveRows();
0468 
0469         emit modelChanged();
0470     }
0471 }
0472 
0473 void FieldModel::removeField(FieldController* field)
0474 {
0475     // int index = m_rootSection->indexOfChild(field);
0476     QList<TreeSheetItem*> ancestors;
0477 
0478     // ancestors.append(field);
0479     TreeSheetItem* tmp= field;
0480     while(tmp != nullptr)
0481     {
0482         tmp= tmp->parentTreeItem();
0483         if(nullptr != tmp)
0484         {
0485             ancestors.prepend(tmp);
0486         }
0487     }
0488 
0489     QModelIndex parent;
0490     TreeSheetItem* parentSection= nullptr;
0491     for(const auto& ancestor : ancestors)
0492     {
0493         if(nullptr != parentSection)
0494         {
0495             parent= index(parentSection->indexOfChild(ancestor), 0, parent);
0496             // TODO check that
0497             // parent= parent.child(parentSection->indexOfChild(ancestor), 0);
0498         }
0499         parentSection= ancestor;
0500     }
0501 
0502     beginRemoveRows(parent, parentSection->indexOfChild(field), parentSection->indexOfChild(field));
0503 
0504     parentSection->removeChild(field);
0505 
0506     endRemoveRows();
0507     emit modelChanged();
0508 }
0509 void FieldModel::clearModel()
0510 {
0511     beginResetModel();
0512     m_rootSection->removeAll();
0513     endResetModel();
0514 }
0515 
0516 void FieldModel::setValueForAll(QModelIndex& index)
0517 {
0518     if(index.isValid())
0519     {
0520         TreeSheetItem* childItem= static_cast<TreeSheetItem*>(index.internalPointer());
0521         m_rootSection->setValueForAll(childItem, m_colunm[index.column()]->getPos());
0522     }
0523 }
0524 
0525 void FieldModel::resetAllId()
0526 {
0527     beginResetModel();
0528     int i= 0;
0529     m_rootSection->resetAllId(i);
0530     FieldController::setCount(i);
0531     endResetModel();
0532 }