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 }