File indexing completed on 2024-12-08 13:28:01
0001 /*************************************************************************** 0002 * Copyright (C) 2019 by Renaud Guezennec * 0003 * http://www.rolisteam.org/contact * 0004 * * 0005 * This software is free software; you can redistribute it and/or modify * 0006 * it under the terms of the GNU General Public License as published by * 0007 * the Free Software Foundation; either version 2 of the License, or * 0008 * (at your option) any later version. * 0009 * * 0010 * This program is distributed in the hope that it will be useful, * 0011 * but WITHOUT ANY WARRANTY; without even the implied warranty of * 0012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 0013 * GNU General Public License for more details. * 0014 * * 0015 * You should have received a copy of the GNU General Public License * 0016 * along with this program; if not, write to the * 0017 * Free Software Foundation, Inc., * 0018 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * 0019 ***************************************************************************/ 0020 #include "minditemmodel.h" 0021 0022 #include <QColor> 0023 #include <QDebug> 0024 #include <QRectF> 0025 0026 #include "mindmap/data/linkcontroller.h" 0027 #include "mindmap/model/imagemodel.h" 0028 #include "mindmap/model/nodeimageprovider.h" 0029 0030 namespace mindmap 0031 { 0032 std::tuple<std::vector<MindItem*>&, int> getVector(std::vector<MindItem*>& links, std::vector<MindItem*>& package, 0033 std::vector<MindItem*>& node, MindItem::Type type) 0034 { 0035 0036 if(type == MindItem::LinkType) 0037 return {links, 0}; 0038 else if(type == MindItem::PackageType) 0039 return {package, links.size()}; 0040 else // if(type == MindItem::NodeType) 0041 return {node, links.size() + package.size()}; 0042 } 0043 0044 MindItemModel::MindItemModel(ImageModel* imgModel, QObject* parent) : QAbstractListModel(parent), m_imgModel(imgModel) 0045 { 0046 } 0047 0048 MindItemModel::~MindItemModel() {} 0049 0050 int MindItemModel::rowCount(const QModelIndex& parent) const 0051 { 0052 // qDebug() << "rowCount :"; 0053 if(parent.isValid()) 0054 return 0; 0055 // qDebug() << "links" << m_links.size() << "node:" << m_nodes.size(); 0056 return static_cast<int>(m_links.size() + m_packages.size() + m_nodes.size()); 0057 } 0058 0059 QVariant MindItemModel::data(const QModelIndex& index, int role) const 0060 { 0061 0062 if(!index.isValid()) 0063 return QVariant(); 0064 0065 QVariant result; 0066 0067 auto r= index.row(); 0068 auto linkCount= static_cast<int>(m_links.size()); 0069 auto packageCount= static_cast<int>(m_packages.size()); 0070 auto nodeCount= static_cast<int>(m_nodes.size()); 0071 0072 MindItem* mindNode= nullptr; 0073 0074 if(r < linkCount) 0075 { 0076 mindNode= m_links[r]; 0077 } 0078 else 0079 { 0080 r-= linkCount; 0081 if(r < packageCount) 0082 mindNode= m_packages[r]; 0083 else 0084 { 0085 r-= packageCount; 0086 if(r < nodeCount) 0087 mindNode= m_nodes[r]; 0088 } 0089 } 0090 0091 if(!mindNode) 0092 return {}; 0093 0094 if(role == Qt::DisplayRole) 0095 role= Label; 0096 0097 QSet<int> allowedRole{Visible, Label, Selected, Type, Uuid, Object, HasPicture}; 0098 0099 if(!allowedRole.contains(role)) 0100 return {}; 0101 0102 switch(role) 0103 { 0104 case Visible: 0105 result= mindNode->isVisible(); 0106 break; 0107 case Label: 0108 result= mindNode->text().isEmpty() ? QString("Node") : mindNode->text(); 0109 break; 0110 case Selected: 0111 result= mindNode->selected(); 0112 break; 0113 case Type: 0114 result= mindNode->type(); 0115 break; 0116 case Uuid: 0117 result= mindNode->id(); 0118 break; 0119 case Object: 0120 result= QVariant::fromValue(mindNode); 0121 break; 0122 case HasPicture: 0123 result= mindNode->type() == MindItem::NodeType ? m_imgModel->hasPixmap(mindNode->id()) : false; 0124 break; 0125 } 0126 return result; 0127 } 0128 0129 bool MindItemModel::setData(const QModelIndex& index, const QVariant& value, int role) 0130 { 0131 if(data(index, role) != value) 0132 { 0133 emit dataChanged(index, index, QVector<int>() << role); 0134 return true; 0135 } 0136 return false; 0137 } 0138 0139 void MindItemModel::update(const QString& id, int role) 0140 { 0141 auto current= item(id); 0142 0143 if(!current) 0144 return; 0145 0146 int row= 0; 0147 if(current->type() == MindItem::LinkType) 0148 { 0149 auto it= std::find(std::begin(m_links), std::end(m_links), current); 0150 if(it != std::end(m_links)) 0151 row= std::distance(std::begin(m_links), it); 0152 } 0153 else if(current->type() == MindItem::PackageType) 0154 { 0155 auto it= std::find(std::begin(m_packages), std::end(m_packages), current); 0156 if(it != std::end(m_packages)) 0157 row= std::distance(std::begin(m_packages), it) + m_links.size(); 0158 } 0159 else if(current->type() == MindItem::NodeType) 0160 { 0161 auto it= std::find(std::begin(m_nodes), std::end(m_nodes), current); 0162 if(it != std::end(m_nodes)) 0163 row= std::distance(std::begin(m_nodes), it) + m_links.size() + m_packages.size(); 0164 } 0165 0166 emit dataChanged(index(row, 0), index(row, 0), {role}); 0167 } 0168 0169 void MindItemModel::setImageUriToNode(const QString& id, const QString& url) 0170 { 0171 auto it= std::find_if(m_nodes.begin(), m_nodes.end(), [id](const MindItem* node) { return node->id() == id; }); 0172 if(it == m_nodes.end()) 0173 return; 0174 0175 auto dis= std::distance(m_nodes.begin(), it); 0176 auto node= dynamic_cast<MindNode*>(*it); 0177 if(!node) 0178 return; 0179 0180 node->setImageUri(url); 0181 auto idx= index(dis, 0, QModelIndex()); 0182 emit dataChanged(idx, idx, QVector<int>()); 0183 } 0184 0185 Qt::ItemFlags MindItemModel::flags(const QModelIndex& index) const 0186 { 0187 if(!index.isValid()) 0188 return Qt::NoItemFlags; 0189 0190 return Qt::ItemIsEditable | Qt::ItemIsEnabled | Qt::ItemIsSelectable; 0191 } 0192 0193 QHash<int, QByteArray> MindItemModel::roleNames() const 0194 { 0195 static QHash<int, QByteArray> roles= {{MindItemModel::Label, "label"}, 0196 {MindItemModel::Visible, "visible"}, 0197 {MindItemModel::Selected, "selected"}, 0198 {MindItemModel::Type, "type"}, 0199 {MindItemModel::Uuid, "id"}, 0200 {MindItemModel::Object, "object"}, 0201 {MindItemModel::HasPicture, "hasPicture"}}; 0202 return roles; 0203 } 0204 0205 void MindItemModel::clear() 0206 { 0207 0208 QVector<MindItem*> backup; 0209 backup.reserve(rowCount()); 0210 for(auto const& l : m_links) 0211 backup.append(l); 0212 0213 for(auto const& l : m_packages) 0214 backup.append(l); 0215 0216 for(auto const& l : m_nodes) 0217 backup.append(l); 0218 0219 beginResetModel(); 0220 m_links.clear(); 0221 m_packages.clear(); 0222 m_nodes.clear(); 0223 endResetModel(); 0224 } 0225 0226 void MindItemModel::appendItem(const QList<MindItem*>& nodes) 0227 { 0228 for(auto const& node : nodes) 0229 { 0230 if(node == nullptr) 0231 return; 0232 0233 auto [vec, offset]= getVector(m_links, m_packages, m_nodes, node->type()); 0234 0235 int row= offset + vec.size(); 0236 0237 if(node->type() == MindItem::LinkType) 0238 { 0239 0240 auto link= dynamic_cast<mindmap::LinkController*>(node); 0241 if(link) 0242 { 0243 connect(link, &mindmap::LinkController::startPointChanged, this, 0244 [this, link]() 0245 { 0246 QModelIndex parent; 0247 auto it= std::find(m_links.begin(), m_links.end(), link); 0248 if(it == m_links.end()) 0249 return; 0250 auto offset= std::distance(m_links.begin(), it); 0251 auto idx1= index(offset, 0, parent); 0252 auto start= link->start(); 0253 emit dataChanged(idx1, idx1, 0254 start->isDragged() ? QVector<int>{Object, LinkStartPosition} : 0255 QVector<int>{Object, LinkPositionFromSpacing}); 0256 }); 0257 } 0258 } 0259 else 0260 { 0261 auto pItem= dynamic_cast<mindmap::PositionedItem*>(node); 0262 if(pItem) 0263 { 0264 connect(pItem, &mindmap::PositionedItem::positionChanged, this, &MindItemModel::geometryChanged); 0265 connect(pItem, &mindmap::PositionedItem::textChanged, this, &MindItemModel::geometryChanged); 0266 connect(pItem, &mindmap::PositionedItem::textChanged, this, [pItem, this](){ 0267 auto [vec, offset]= getVector(m_links, m_packages, m_nodes, pItem->type()); 0268 auto row= offset + static_cast<int>(vec.size()); 0269 auto idx = index(row, 0); 0270 emit dataChanged(idx,idx,{Roles::Label}); 0271 }); 0272 connect(pItem, &mindmap::PositionedItem::widthChanged, this, &MindItemModel::geometryChanged); 0273 connect(pItem, &mindmap::PositionedItem::heightChanged, this, &MindItemModel::geometryChanged); 0274 } 0275 } 0276 0277 beginInsertRows(QModelIndex(), row, row); 0278 vec.push_back(node); 0279 endInsertRows(); 0280 } 0281 } 0282 std::vector<PositionedItem*> MindItemModel::positionnedItems() const 0283 { 0284 std::vector<PositionedItem*> vec; 0285 vec.reserve(m_packages.size() + m_nodes.size()); 0286 0287 for(auto const& item : m_packages) 0288 { 0289 auto pack= dynamic_cast<PositionedItem*>(item); 0290 0291 if(!pack) 0292 continue; 0293 0294 vec.push_back(pack); 0295 } 0296 0297 for(auto const& item : m_nodes) 0298 { 0299 auto pack= dynamic_cast<PositionedItem*>(item); 0300 0301 if(!pack) 0302 continue; 0303 0304 vec.push_back(pack); 0305 } 0306 0307 return vec; 0308 } 0309 0310 std::pair<MindItem*, LinkController*> MindItemModel::addItem(const QString& idparent, MindItem::Type type) 0311 { 0312 0313 auto [vec, offset]= getVector(m_links, m_packages, m_nodes, type); 0314 0315 auto row= offset + static_cast<int>(vec.size()); 0316 Q_UNUSED(row) 0317 0318 std::pair<MindItem*, LinkController*> result; 0319 0320 if(type == MindItem::NodeType) 0321 { 0322 0323 auto root= new MindNode(); 0324 root->setStyleIndex(defaultStyleIndex()); 0325 appendItem({root}); 0326 0327 if(idparent.isEmpty()) 0328 return {root, nullptr}; 0329 0330 auto data= positionnedItems(); 0331 auto id= std::find_if(data.begin(), data.end(), 0332 [idparent](const PositionedItem* node) { return idparent == node->id(); }); 0333 if(id == data.end()) 0334 return {root, nullptr}; 0335 0336 auto rectParent= (*id)->boundingRect(); 0337 auto pos= rectParent.topLeft() + QPointF(rectParent.width() * 1.5, rectParent.height() * 1.5); 0338 root->setPosition(pos); 0339 0340 auto link= new mindmap::LinkController(); 0341 link->setStart((*id)); 0342 link->setEnd(root); 0343 root->setParentNode(*id); 0344 0345 appendItem({link}); 0346 0347 result= std::make_pair(root, link); 0348 } 0349 else if(type == MindItem::PackageType) 0350 { 0351 auto pack= new PackageNode(); 0352 appendItem({pack}); 0353 emit latestInsertedPackage(pack); 0354 result= std::make_pair(pack, nullptr); 0355 } 0356 else if(type == MindItem::LinkType) 0357 { 0358 auto link= new LinkController(); 0359 appendItem({link}); 0360 result= std::make_pair(link, link); 0361 } 0362 0363 return result; 0364 } 0365 0366 bool MindItemModel::removeItem(const MindItem* node) 0367 { 0368 if(node == nullptr) 0369 return false; 0370 0371 auto [vec, offset]= getVector(m_links, m_packages, m_nodes, node->type()); 0372 0373 auto it= std::find(vec.begin(), vec.end(), node); 0374 0375 if(it == std::end(m_nodes)) 0376 return false; 0377 0378 auto idx= offset + static_cast<int>(std::distance(vec.begin(), it)); 0379 0380 // qDebug() << "Indexremove item:" << idx << node->type(); 0381 0382 if(node->type() == MindItem::LinkType) 0383 { 0384 0385 auto const link= dynamic_cast<const mindmap::LinkController*>(node); 0386 if(link) 0387 { 0388 disconnect(link, 0, this, 0); 0389 /*connect(link, &mindmap::LinkController::startPointChanged, this, [this, link]() { 0390 QModelIndex parent; 0391 auto it= std::find(m_links.begin(), m_links.end(), link); 0392 if(it == m_links.end()) 0393 return; 0394 auto offset= std::distance(m_links.begin(), it); 0395 auto idx1= index(offset, 0, parent); 0396 emit dataChanged(idx1, idx1, QVector<int>()); 0397 });*/ 0398 } 0399 } 0400 0401 beginRemoveRows(QModelIndex(), idx, idx); 0402 vec.erase(it); 0403 endRemoveRows(); 0404 0405 return true; 0406 } 0407 0408 void MindItemModel::openItem(const QString& id, bool status) 0409 { 0410 auto it= item(id); 0411 0412 if(nullptr == it) 0413 return; 0414 0415 auto node= dynamic_cast<PositionedItem*>(it); 0416 0417 if(nullptr == node) 0418 return; 0419 0420 if(node->open() == status) 0421 return; 0422 0423 node->setOpen(status); 0424 } 0425 0426 MindItem* MindItemModel::item(const QString& id) const 0427 { 0428 // MindItem* result= nullptr; 0429 0430 auto it= std::find_if(m_nodes.begin(), m_nodes.end(), [id](const MindItem* node) { return node->id() == id; }); 0431 0432 if(it != m_nodes.end()) 0433 return *it; 0434 0435 auto it2= std::find_if(m_links.begin(), m_links.end(), [id](const MindItem* node) { return node->id() == id; }); 0436 0437 if(it2 != m_links.end()) 0438 return *it2; 0439 0440 auto it3 0441 = std::find_if(m_packages.begin(), m_packages.end(), [id](const MindItem* node) { return node->id() == id; }); 0442 0443 if(it3 != m_packages.end()) 0444 return *it3; 0445 0446 return nullptr; 0447 } 0448 0449 PositionedItem* MindItemModel::positionItem(const QString& id) const 0450 { 0451 auto it= std::find_if(m_nodes.begin(), m_nodes.end(), [id](const MindItem* node) { return node->id() == id; }); 0452 0453 if(it != m_nodes.end()) 0454 return dynamic_cast<PositionedItem*>(*it); 0455 0456 auto it3 0457 = std::find_if(m_packages.begin(), m_packages.end(), [id](const MindItem* node) { return node->id() == id; }); 0458 0459 if(it3 != m_packages.end()) 0460 return dynamic_cast<PositionedItem*>(*it3); 0461 0462 return nullptr; 0463 } 0464 0465 QRectF MindItemModel::contentRect() const 0466 { 0467 QRectF rect(0., 0., 1., 1.); 0468 0469 for(auto const& item : m_nodes) 0470 { 0471 auto node= dynamic_cast<PositionedItem*>(item); 0472 if(!node) 0473 continue; 0474 rect= node->boundingRect().united(rect); 0475 } 0476 0477 for(auto const& item : m_packages) 0478 { 0479 auto pack= dynamic_cast<PositionedItem*>(item); 0480 if(!pack) 0481 continue; 0482 rect= pack->boundingRect().united(rect); 0483 } 0484 return rect; 0485 } 0486 0487 std::vector<MindItem*>& MindItemModel::items(MindItem::Type type) 0488 { 0489 return std::get<0>(getVector(m_links, m_packages, m_nodes, type)); 0490 } 0491 0492 std::vector<LinkController*> MindItemModel::sublink(const QString& id) const 0493 { 0494 std::vector<LinkController*> vec; 0495 0496 for(auto item : m_links) 0497 { 0498 auto link= dynamic_cast<LinkController*>(item); 0499 if(!link) 0500 continue; 0501 0502 auto st= link->start(); 0503 if(!st) 0504 continue; 0505 0506 if(id == st->id() && (std::end(vec) == std::find(std::begin(vec), std::end(vec), link))) 0507 vec.push_back(link); 0508 0509 auto end= link->end(); 0510 if(!end) 0511 continue; 0512 0513 if(id == end->id() && (std::end(vec) == std::find(std::begin(vec), std::end(vec), link))) 0514 vec.push_back(link); 0515 } 0516 0517 return vec; 0518 } 0519 0520 int MindItemModel::defaultStyleIndex() const 0521 { 0522 return m_defaultStyleIndex; 0523 } 0524 0525 void MindItemModel::setDefaultStyleIndex(int newDefaultStyleIndex) 0526 { 0527 if (m_defaultStyleIndex == newDefaultStyleIndex) 0528 return; 0529 m_defaultStyleIndex = newDefaultStyleIndex; 0530 emit defaultStyleIndexChanged(); 0531 } 0532 0533 } // namespace mindmap