File indexing completed on 2024-05-19 05:40:49

0001 /***************************************************************************
0002  *  Copyright (C) 2020 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 "updater/media/mindmapupdater.h"
0021 
0022 #include "controller/view_controller/mindmapcontroller.h"
0023 #include "mindmap/data/linkcontroller.h"
0024 #include "mindmap/data/minditem.h"
0025 #include "mindmap/data/mindmaptypes.h"
0026 #include "mindmap/model/minditemmodel.h"
0027 #include "model/contentmodel.h"
0028 #include "network/networkmessagewriter.h"
0029 #include "worker/messagehelper.h"
0030 
0031 #include <QDebug>
0032 #include <QTimer>
0033 
0034 constexpr int timeout{1000 * 5};
0035 
0036 MindMapUpdater::MindMapUpdater(FilteredContentModel* model, campaign::CampaignManager* manager, QObject* parent)
0037     : MediaUpdaterInterface(manager, parent), m_mindmaps(model)
0038 {
0039     ReceiveEvent::registerNetworkReceiver(NetMsg::MindMapCategory, this);
0040 }
0041 
0042 void MindMapUpdater::addMediaController(MediaControllerBase* base)
0043 {
0044     if(nullptr == base)
0045         return;
0046 
0047     auto ctrl= dynamic_cast<MindMapController*>(base);
0048 
0049     if(ctrl == nullptr)
0050         return;
0051 
0052     auto timer= new QTimer(ctrl);
0053 
0054     connect(timer, &QTimer::timeout, this,
0055             [this, ctrl, timer]()
0056             {
0057                 timer->stop();
0058                 if(ctrl->modified())
0059                 {
0060                     saveMediaController(ctrl);
0061                 }
0062             });
0063 
0064     connect(ctrl, &MindMapController::sharingToAllChanged, this,
0065             [ctrl](Core::SharingPermission perm, Core::SharingPermission old)
0066             {
0067                 if(old == Core::SharingPermission::None)
0068                 {
0069                     MessageHelper::sendOffMindmapToAll(ctrl);
0070                 }
0071                 else if(perm == Core::SharingPermission::None)
0072                 {
0073                     MessageHelper::closeMedia(ctrl->uuid(), Core::ContentType::MINDMAP);
0074                 }
0075                 else
0076                 {
0077                     MessageHelper::sendOffMindmapPermissionUpdate(ctrl);
0078                 }
0079             });
0080 
0081     connect(ctrl, &MindMapController::openMindMapTo, this,
0082             [ctrl](const QString& id) { MessageHelper::openMindmapTo(ctrl, id); });
0083 
0084     connect(ctrl, &MindMapController::closeMindMapTo, this,
0085             [ctrl](const QString& id) { MessageHelper::closeMindmapTo(ctrl, id); });
0086 
0087     connect(ctrl, &MindMapController::permissionChangedForUser, this,
0088             [ctrl](const QString& id, Core::SharingPermission perm)
0089             { MessageHelper::sendOffMindmapPermissionUpdateTo(perm, ctrl, id); });
0090 
0091     connect(ctrl, &MindMapController::modifiedChanged, this,
0092             [this, ctrl, timer]()
0093             {
0094                 if(ctrl->modified())
0095                 {
0096                     timer->start(timeout);
0097                 }
0098             });
0099 
0100     if(ctrl->modified())
0101     {
0102         saveMediaController(ctrl);
0103     }
0104     setConnection(ctrl);
0105 }
0106 
0107 bool MindMapUpdater::updateSubobjectProperty(NetworkMessageReader* msg, MindMapController* ctrl)
0108 {
0109     if(nullptr == msg || nullptr == ctrl)
0110         return false;
0111 
0112     auto id= msg->string8();
0113     QHash<NetMsg::Action, mindmap::MindItem::Type> set{{NetMsg::UpdateLink, mindmap::MindItem::LinkType},
0114                                                        {NetMsg::UpdateNode, mindmap::MindItem::NodeType},
0115                                                        {NetMsg::UpdatePackage, mindmap::MindItem::PackageType}};
0116 
0117     if(!set.contains(msg->action()))
0118         return false;
0119 
0120     auto subobject= ctrl->subItem(id, set.value(msg->action()));
0121     if(!subobject)
0122         return false;
0123 
0124     auto property= msg->string16();
0125     QVariant var;
0126 
0127     if(property == QStringLiteral("text"))
0128     {
0129         var= msg->string32();
0130     }
0131     else if(property == QStringLiteral("imageUri"))
0132     {
0133         var= msg->string32();
0134     }
0135     else if(property == QStringLiteral("styleIndex"))
0136     {
0137         var= msg->int64();
0138     }
0139     else if(property == QStringLiteral("direction"))
0140     {
0141         var= QVariant::fromValue(static_cast<mindmap::ArrowDirection>(msg->uint8()));
0142     }
0143 
0144     return subobject->setProperty(property.toLocal8Bit().data(), var);
0145 }
0146 
0147 MindMapController* findController(const QString& id, FilteredContentModel* mindmaps)
0148 {
0149     if(id.isEmpty() || !mindmaps)
0150         return nullptr;
0151 
0152     auto ctrls= mindmaps->contentController<MindMapController*>();
0153 
0154     auto it= std::find_if(ctrls.begin(), ctrls.end(), [id](MindMapController* ctrl) { return id == ctrl->uuid(); });
0155 
0156     if(it == ctrls.end())
0157         return nullptr;
0158     return *it;
0159 }
0160 
0161 void MindMapUpdater::setConnection(MindMapController* ctrl)
0162 {
0163     if(ctrl == nullptr)
0164         return;
0165     disconnectController(ctrl);
0166     ConnectionInfo info;
0167     info.id= ctrl->uuid();
0168 
0169     auto nodeModel= dynamic_cast<mindmap::MindItemModel*>(ctrl->itemModel());
0170     auto imageModel= ctrl->imgModel();
0171     info.connections << connect(imageModel, &mindmap::ImageModel::imageAdded, this,
0172                                 [imageModel, ctrl](const QString& id)
0173                                 {
0174                                     auto info= imageModel->imageInfoFromId(id);
0175                                     if(info.m_pixmap.isNull())
0176                                         return;
0177                                     MessageHelper::sendOffImageInfo(info, ctrl);
0178                                 });
0179     auto idCtrl= ctrl->uuid();
0180 
0181     info.connections << connect(imageModel, &mindmap::ImageModel::imageRemoved, this,
0182                                 [ctrl](const QString& id) { MessageHelper::sendOffRemoveImageInfo(id, ctrl); });
0183 
0184     // connect existing  data
0185     auto nodes= nodeModel->items(mindmap::MindItem::NodeType);
0186     for(auto const& i : nodes)
0187     {
0188         auto n= dynamic_cast<mindmap::MindNode*>(i);
0189         if(!n)
0190             continue;
0191         info.connections << connect(n, &mindmap::MindNode::textChanged, this,
0192                                     [this, idCtrl, n]()
0193                                     { sendOffChange<QString>(idCtrl, QStringLiteral("text"), n, true); });
0194         info.connections << connect(n, &mindmap::MindNode::imageUriChanged, this,
0195                                     [this, idCtrl, n]()
0196                                     { sendOffChange<QString>(idCtrl, QStringLiteral("imageUri"), n, true); });
0197         info.connections << connect(n, &mindmap::MindNode::styleIndexChanged, this,
0198                                     [this, idCtrl, n]()
0199                                     { sendOffChange<int>(idCtrl, QStringLiteral("styleIndex"), n, true); });
0200     }
0201 
0202     auto links= nodeModel->items(mindmap::MindItem::LinkType);
0203     for(auto i : links)
0204     {
0205         auto link= dynamic_cast<mindmap::LinkController*>(i);
0206         if(!link)
0207             continue;
0208 
0209         info.connections << connect(link, &mindmap::LinkController::textChanged, this,
0210                                     [this, idCtrl, link]()
0211                                     { sendOffChange<QString>(idCtrl, QStringLiteral("text"), link, false); });
0212         info.connections << connect(
0213             link, &mindmap::LinkController::directionChanged, this,
0214             [this, idCtrl, link]()
0215             { sendOffChange<mindmap::ArrowDirection>(idCtrl, QStringLiteral("direction"), link, false); });
0216     }
0217 
0218     auto packages= nodeModel->items(mindmap::MindItem::PackageType);
0219     for(auto i : packages)
0220     {
0221         auto pack= dynamic_cast<mindmap::PackageNode*>(i);
0222         if(!pack)
0223             continue;
0224 
0225         info.connections << connect(pack, &mindmap::PackageNode::titleChanged, this,
0226                                     [this, idCtrl, pack]()
0227                                     { sendOffChange<QString>(idCtrl, QStringLiteral("title"), pack, false); });
0228         info.connections << connect(pack, &mindmap::PackageNode::minimumMarginChanged, this,
0229                                     [this, idCtrl, pack]()
0230                                     { sendOffChange<int>(idCtrl, QStringLiteral("minimumMargin"), pack, false); });
0231     }
0232     // end of existing data
0233 
0234     /*info.connections << connect(nodeModel, &mindmap::BoxModel::nodeAdded, this,
0235                                 [this, ctrl](QList<mindmap::MindNode*> nodes) {
0236                                     if(!ctrl || (!ctrl->localIsOwner() && !ctrl->readWrite()))
0237                                         return;
0238 
0239                                     NetworkMessageWriter msg(NetMsg::MindMapCategory, NetMsg::AddNode);
0240                                     auto idCtrl= ctrl->uuid();
0241                                     msg.string8(idCtrl);
0242                                     MessageHelper::buildAddNodeMessage(msg, nodes);
0243 
0244                                     msg.sendToServer();
0245                                     auto info= findConnectionInfo(idCtrl);
0246                                     Q_ASSERT(info);
0247                                 });
0248 
0249     info.connections << connect(linkModel, &mindmap::LinkModel::linkAdded, this,
0250                                 [this, ctrl](QList<mindmap::Link*> links) {
0251                                     if(!ctrl || (!ctrl->localIsOwner() && !ctrl->readWrite()))
0252                                         return;
0253 
0254                                     NetworkMessageWriter msg(NetMsg::MindMapCategory, NetMsg::AddLink);
0255                                     auto idCtrl= ctrl->uuid();
0256                                     msg.string8(idCtrl);
0257                                     MessageHelper::buildAddLinkMessage(msg, links);
0258                                     msg.sendToServer();
0259 
0260                                     Q_ASSERT(info);
0261                                 });*/
0262 
0263     /*info.connections << connect(nodeModel, &mindmap::BoxModel::nodeRemoved, this, [ctrl](const QStringList& ids) {
0264         if(!ctrl->localIsOwner())
0265             return;
0266         NetworkMessageWriter msg(NetMsg::MindMapCategory, NetMsg::RemoveNode);
0267         msg.string8(ctrl->uuid());
0268         msg.uint64(ids.size());
0269         std::for_each(std::begin(ids), std::end(ids), [&msg](const QString& id) { msg.string8(id); });
0270         msg.sendToServer();
0271     });
0272 
0273     info.connections << connect(linkModel, &mindmap::LinkModel::linkRemoved, this, [ctrl](const QStringList& ids) {
0274         if(!ctrl->localIsOwner())
0275             return;
0276         NetworkMessageWriter msg(NetMsg::MindMapCategory, NetMsg::RemoveLink);
0277         msg.string8(ctrl->uuid());
0278         msg.uint64(ids.size());
0279         std::for_each(std::begin(ids), std::end(ids), [&msg](const QString& id) { msg.string8(id); });
0280         msg.sendToServer();
0281     });*/
0282 
0283     m_connections.append(info);
0284 }
0285 
0286 void MindMapUpdater::sendOffRemoveMessage(const QString& idCtrl, const QStringList& nodeids, const QStringList& linksId)
0287 {
0288     NetworkMessageWriter msg(NetMsg::MindMapCategory, NetMsg::RemoveMessage);
0289     msg.string8(idCtrl);
0290     MessageHelper::buildRemoveItemMessage(msg, nodeids, linksId);
0291     msg.sendToServer();
0292 }
0293 
0294 void MindMapUpdater::sendOffAddingMessage(const QString& idCtrl, const QList<mindmap::MindNode*>& nodes,
0295                                           const QList<mindmap::LinkController*>& links)
0296 {
0297     auto info= findConnectionInfo(idCtrl);
0298 
0299     for(auto node : nodes)
0300     {
0301         info->connections << connect(node, &mindmap::MindNode::textChanged, this,
0302                                      [this, idCtrl, node]()
0303                                      { sendOffChange<QString>(idCtrl, QStringLiteral("text"), node, true); });
0304         info->connections << connect(node, &mindmap::MindNode::imageUriChanged, this,
0305                                      [this, idCtrl, node]()
0306                                      { sendOffChange<QString>(idCtrl, QStringLiteral("imageUri"), node, true); });
0307         info->connections << connect(node, &mindmap::MindNode::styleIndexChanged, this,
0308                                      [this, idCtrl, node]()
0309                                      { sendOffChange<int>(idCtrl, QStringLiteral("styleIndex"), node, true); });
0310     }
0311 
0312     for(auto link : qAsConst(links))
0313     {
0314         info->connections << connect(link, &mindmap::LinkController::textChanged, this,
0315                                      [this, idCtrl, link]()
0316                                      { sendOffChange<QString>(idCtrl, QStringLiteral("text"), link, false); });
0317         info->connections << connect(
0318             link, &mindmap::LinkController::directionChanged, this,
0319             [this, idCtrl, link]()
0320             { sendOffChange<mindmap::ArrowDirection>(idCtrl, QStringLiteral("direction"), link, false); });
0321     }
0322     NetworkMessageWriter msg(NetMsg::MindMapCategory, NetMsg::AddMessage);
0323     msg.string8(idCtrl);
0324     MessageHelper::buildAddItemMessage(msg, nodes, links);
0325     msg.sendToServer();
0326 }
0327 
0328 ConnectionInfo* MindMapUpdater::findConnectionInfo(const QString& id)
0329 {
0330     auto it= std::find_if(std::begin(m_connections), std::end(m_connections),
0331                           [id](const ConnectionInfo& info) { return id == info.id; });
0332 
0333     if(it == std::end(m_connections))
0334         return nullptr;
0335     else
0336         return &(*it);
0337 }
0338 
0339 void MindMapUpdater::disconnectController(MindMapController* media)
0340 {
0341     if(!media)
0342         return;
0343 
0344     auto it= std::find_if(std::begin(m_connections), std::end(m_connections),
0345                           [media](const ConnectionInfo& info) { return media->uuid() == info.id; });
0346 
0347     if(it == std::end(m_connections))
0348         return;
0349 
0350     std::for_each(std::begin(it->connections), std::end(it->connections),
0351                   [this](const QMetaObject::Connection& connection) { this->disconnect(connection); });
0352 
0353     m_connections.erase(it);
0354 }
0355 
0356 NetWorkReceiver::SendType MindMapUpdater::processMessage(NetworkMessageReader* msg)
0357 {
0358     if(msg->action() == NetMsg::AddMessage && msg->category() == NetMsg::MindMapCategory)
0359     {
0360         auto id= msg->string8();
0361         MessageHelper::readMindMapAddItem(findController(id, m_mindmaps), msg);
0362     }
0363     else if((msg->action() == NetMsg::UpdateNode || msg->action() == NetMsg::UpdateLink)
0364             && msg->category() == NetMsg::MindMapCategory)
0365     {
0366         auto id= msg->string8();
0367         // auto idnode= msg->string8();
0368         updateSubobjectProperty(msg, findController(id, m_mindmaps));
0369     }
0370     else if(msg->category() == NetMsg::MindMapCategory && msg->action() == NetMsg::RemoveMessage)
0371     {
0372         auto id= msg->string8();
0373         MessageHelper::readMindMapRemoveMessage(findController(id, m_mindmaps), msg);
0374 
0375         // ctrl->removeNode(MessageHelper::readIdList(*msg));
0376     }
0377     else if(msg->action() == NetMsg::UpdateMindMapPermission && msg->category() == NetMsg::MindMapCategory)
0378     {
0379         auto id= msg->string8();
0380         auto ctrl= findController(id, m_mindmaps);
0381         if(ctrl)
0382         {
0383             bool readWrite= static_cast<bool>(msg->uint8());
0384 
0385             ctrl->setSharingToAll(readWrite ? static_cast<int>(Core::SharingPermission::ReadWrite) :
0386                                               static_cast<int>(Core::SharingPermission::ReadOnly));
0387             readWrite ? setConnection(ctrl) : disconnectController(ctrl);
0388         }
0389     }
0390     else if(msg->action() == NetMsg::AddSubImage && msg->category() == NetMsg::MediaCategory)
0391     {
0392         auto id= msg->string8();
0393         auto ctrl= findController(id, m_mindmaps);
0394         MessageHelper::readAddSubImage(ctrl->imgModel(), msg);
0395     }
0396     else if(msg->action() == NetMsg::RemoveSubImage && msg->category() == NetMsg::MediaCategory)
0397     {
0398         auto id= msg->string8();
0399         auto ctrl= findController(id, m_mindmaps);
0400         MessageHelper::readRemoveSubImage(ctrl->imgModel(), msg);
0401     }
0402     return NetWorkReceiver::NONE;
0403 }