File indexing completed on 2024-05-05 05:40:24

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 "controller/contentcontroller.h"
0021 
0022 #include <QFileInfo>
0023 
0024 #include "controller/view_controller/charactersheetcontroller.h"
0025 #include "controller/view_controller/imagecontroller.h"
0026 #include "controller/view_controller/mindmapcontroller.h"
0027 #include "controller/view_controller/sharednotecontroller.h"
0028 #include "controller/view_controller/vectorialmapcontroller.h"
0029 
0030 #include "updater/media/charactersheetupdater.h"
0031 #include "updater/media/genericupdater.h"
0032 #include "updater/media/mediaupdaterinterface.h"
0033 #include "updater/media/mindmapupdater.h"
0034 #include "updater/media/sharednotecontrollerupdater.h"
0035 #include "updater/media/vmapupdater.h"
0036 #include "updater/media/webviewupdater.h"
0037 #include "updater/vmapitem/vmapitemcontrollerupdater.h"
0038 
0039 #include "data/campaignmanager.h"
0040 
0041 #include "controller/gamecontroller.h"
0042 #include "media/mediafactory.h"
0043 #include "model/contentmodel.h"
0044 #include "model/playermodel.h"
0045 #include "model/remoteplayermodel.h"
0046 #include "network/networkmessage.h"
0047 #include "network/networkmessagereader.h"
0048 #include "preferences/preferencesmanager.h"
0049 #include "undoCmd/newmediacontroller.h"
0050 #include "undoCmd/openmediacontroller.h"
0051 #include "worker/iohelper.h"
0052 #include "worker/messagehelper.h"
0053 
0054 
0055 void sendOffMediaController(MediaControllerBase* ctrl)
0056 {
0057     if(!ctrl->localIsOwner() || ctrl->remote())
0058         return;
0059 
0060     switch(ctrl->contentType())
0061     {
0062     case Core::ContentType::PICTURE:
0063         MessageHelper::sendOffImage(dynamic_cast<ImageController*>(ctrl));
0064         break;
0065     case Core::ContentType::VECTORIALMAP:
0066         MessageHelper::sendOffVMap(dynamic_cast<VectorialMapController*>(ctrl));
0067         break;
0068     default:
0069         break;
0070     }
0071 }
0072 
0073 ContentController::ContentController(campaign::CampaignManager* campaign, PlayerModel* playerModel,
0074                                      CharacterModel* characterModel, QClipboard* clipboard, QObject* parent)
0075     : AbstractControllerInterface(parent)
0076     , m_sessionModel(new QFileSystemModel())
0077     , m_contentModel(new ContentModel)
0078     , m_historyModel(new history::HistoryModel)
0079     , m_clipboard(clipboard)
0080 {
0081     CharacterSheetController::setCharacterModel(characterModel);
0082     SharedNoteController::setPlayerModel(playerModel);
0083     CharacterFinder::setPlayerModel(playerModel);
0084     MindMapController::setRemotePlayerModel(new RemotePlayerModel(playerModel));
0085 
0086     connect(m_sessionModel.get(), &QFileSystemModel::rootPathChanged, this, &ContentController::mediaRootChanged);
0087 
0088     ReceiveEvent::registerNetworkReceiver(NetMsg::MediaCategory, this);
0089 
0090     auto fModel= new FilteredContentModel(Core::ContentType::VECTORIALMAP);
0091     fModel->setSourceModel(m_contentModel.get());
0092 
0093     auto fModel2= new FilteredContentModel(Core::ContentType::SHAREDNOTE);
0094     fModel2->setSourceModel(m_contentModel.get());
0095 
0096     auto fModel3= new FilteredContentModel(Core::ContentType::MINDMAP);
0097     fModel3->setSourceModel(m_contentModel.get());
0098 
0099     std::unique_ptr<VMapUpdater> vmapUpdater(new VMapUpdater(campaign, fModel));
0100     std::unique_ptr<SharedNoteControllerUpdater> sharedNoteUpdater(new SharedNoteControllerUpdater(fModel2, campaign));
0101     std::unique_ptr<WebViewUpdater> webviewUpdater(new WebViewUpdater(campaign));
0102     std::unique_ptr<MindMapUpdater> mindMapUpdater(new MindMapUpdater(fModel3, campaign));
0103     std::unique_ptr<GenericUpdater> imageUpdater(new GenericUpdater(campaign));
0104     std::unique_ptr<GenericUpdater> notesUpdater(new GenericUpdater(campaign));
0105     std::unique_ptr<CharacterSheetUpdater> characterSheetUpdater(new CharacterSheetUpdater(campaign));
0106     std::unique_ptr<GenericUpdater> pdfUpdater(new GenericUpdater(campaign));
0107     MindMapController::setMindMapUpdater(mindMapUpdater.get());
0108 
0109     m_mediaUpdaters.insert({Core::ContentType::VECTORIALMAP, std::move(vmapUpdater)});
0110     m_mediaUpdaters.insert({Core::ContentType::SHAREDNOTE, std::move(sharedNoteUpdater)});
0111     m_mediaUpdaters.insert({Core::ContentType::WEBVIEW, std::move(webviewUpdater)});
0112     m_mediaUpdaters.insert({Core::ContentType::MINDMAP, std::move(mindMapUpdater)});
0113     m_mediaUpdaters.insert({Core::ContentType::PICTURE, std::move(imageUpdater)});
0114     m_mediaUpdaters.insert({Core::ContentType::NOTES, std::move(notesUpdater)});
0115     m_mediaUpdaters.insert({Core::ContentType::CHARACTERSHEET, std::move(characterSheetUpdater)});
0116     m_mediaUpdaters.insert({Core::ContentType::PDF, std::move(pdfUpdater)});
0117 
0118     connect(m_contentModel.get(), &ContentModel::mediaControllerAdded, this,
0119             [this](MediaControllerBase* ctrl)
0120             {
0121                 if(nullptr == ctrl)
0122                     return;
0123                 connect(ctrl, &MediaControllerBase::performCommand, this, &ContentController::performCommand);
0124                 connect(ctrl, &MediaControllerBase::popCommand, this, &ContentController::popCommand);
0125                 emit mediaControllerCreated(ctrl);
0126                 sendOffMediaController(ctrl);
0127                 auto it= m_mediaUpdaters.find(ctrl->contentType());
0128                 if(it != m_mediaUpdaters.end())
0129                     it->second->addMediaController(ctrl);
0130                 if(!localIsGM())
0131                     m_historyModel->addLink(ctrl->url(), ctrl->name(), ctrl->contentType());
0132             });
0133 
0134     connect(m_clipboard, &QClipboard::dataChanged, this, [this]() { emit canPasteChanged(canPaste()); });
0135 
0136     connect(m_historyModel.get(), &history::HistoryModel::modelReset, this, &ContentController::historyChanged);
0137     connect(m_historyModel.get(), &history::HistoryModel::rowsInserted, this, &ContentController::historyChanged);
0138     connect(m_historyModel.get(), &history::HistoryModel::rowsRemoved, this, &ContentController::historyChanged);
0139 }
0140 
0141 ContentController::~ContentController()= default;
0142 
0143 void ContentController::setGameController(GameController* game)
0144 {
0145     m_preferences= game->preferencesManager();
0146     m_preferences->registerListener("BackGroundPositioning", this);
0147     m_preferences->registerListener("PathOfBackgroundImage", this);
0148     m_preferences->registerListener("BackGroundColor", this);
0149     m_preferences->registerListener("shortNameInTabMode", this);
0150     m_preferences->registerListener("MaxLengthTabName", this);
0151 }
0152 
0153 void ContentController::preferencesHasChanged(const QString& key)
0154 {
0155     if(key == QStringLiteral("BackGroundPositioning"))
0156         emit workspacePositioningChanged();
0157     else if(key == QStringLiteral("PathOfBackgroundImage"))
0158         emit workspaceFilenameChanged();
0159     else if(key == QStringLiteral("BackGroundColor"))
0160         emit workspaceColorChanged();
0161     else if(key == QStringLiteral("shortNameInTabMode"))
0162         emit shortTitleTabChanged();
0163     else if(key == QStringLiteral("MaxLengthTabName"))
0164         emit maxLengthTabNameChanged();
0165 }
0166 
0167 void ContentController::newMedia(campaign::CampaignEditor* editor, const std::map<QString, QVariant>& params)
0168 {
0169     auto arg= params;
0170     arg.insert({Core::keys::KEY_OWNERID, m_localId});
0171     arg.insert({Core::keys::KEY_LOCALID, m_localId});
0172     arg.insert({Core::keys::KEY_GMID, m_gameMasterId});
0173     emit performCommand(new NewMediaController(m_contentModel.get(), arg, localColor(), localIsGM(), editor));
0174 }
0175 
0176 void ContentController::openMedia(const std::map<QString, QVariant>& args)
0177 {
0178     auto it= args.find(Core::keys::KEY_TYPE);
0179 
0180     if(it == args.end())
0181         return;
0182 
0183     auto type= it->second.value<Core::ContentType>();
0184 
0185     emit performCommand(new OpenMediaController(m_contentModel.get(), type, args, localColor(), localIsGM()));
0186 }
0187 
0188 QFileSystemModel* ContentController::sessionModel() const
0189 {
0190     return m_sessionModel.get();
0191 }
0192 
0193 ContentModel* ContentController::contentModel() const
0194 {
0195     return m_contentModel.get();
0196 }
0197 
0198 history::HistoryModel* ContentController::historyModel() const
0199 {
0200     return m_historyModel.get();
0201 }
0202 
0203 int ContentController::contentCount() const
0204 {
0205     return m_contentModel->rowCount();
0206 }
0207 
0208 void ContentController::setMediaRoot(const QString& path)
0209 {
0210     qDebug()<< "PathMedia root:" << path << m_sessionModel->rootPath();
0211     if(m_sessionModel->rootPath() == path)
0212         return;
0213     m_sessionModel->setRootPath(path);
0214     emit mediaRootChanged();
0215 }
0216 
0217 QString ContentController::gameMasterId() const
0218 {
0219     return m_gameMasterId;
0220 }
0221 
0222 QString ContentController::currentMediaId() const
0223 {
0224     return m_contentModel->activeMediaId();
0225 }
0226 
0227 MediaControllerBase* ContentController::media(const QString& id) const
0228 {
0229     return m_contentModel->media(id);
0230 }
0231 
0232 QString ContentController::localId() const
0233 {
0234     return m_localId;
0235 }
0236 
0237 bool ContentController::localIsGM() const
0238 {
0239     return m_localId == m_gameMasterId;
0240 }
0241 
0242 void ContentController::setGameMasterId(const QString& id)
0243 {
0244     if(id == m_gameMasterId)
0245         return;
0246     m_gameMasterId= id;
0247     emit gameMasterIdChanged(m_gameMasterId);
0248 }
0249 
0250 void ContentController::setLocalId(const QString& id)
0251 {
0252     if(m_localId == id)
0253         return;
0254     m_localId= id;
0255     Media::MediaFactory::setLocalId(id);
0256     emit localIdChanged(m_localId);
0257 }
0258 
0259 void ContentController::clear()
0260 {
0261     m_contentModel->clearData();
0262 }
0263 
0264 void ContentController::clearHistory()
0265 {
0266     m_historyModel->clear();
0267 }
0268 
0269 void ContentController::closeCurrentMedia()
0270 {
0271     m_contentModel->removeMedia(m_contentModel->activeMediaId());
0272 }
0273 
0274 int ContentController::maxLengthTabName() const
0275 {
0276     return m_preferences->value(QStringLiteral("MaxLengthTabName"), 20).toInt();
0277 }
0278 
0279 bool ContentController::shortTitleTab() const
0280 {
0281     return m_preferences->value(QStringLiteral("shortNameInTabMode"), false).toBool();
0282 }
0283 QString ContentController::workspaceFilename() const
0284 {
0285     return m_preferences->value(QStringLiteral("PathOfBackgroundImage"), 20).toString();
0286 }
0287 QColor ContentController::workspaceColor() const
0288 {
0289     return m_preferences->value(QStringLiteral("BackGroundColor"), QColor(191, 191, 191)).value<QColor>();
0290 }
0291 int ContentController::workspacePositioning() const
0292 {
0293     return m_preferences->value(QStringLiteral("BackGroundPositioning"), 0).toInt();
0294 }
0295 
0296 NetWorkReceiver::SendType ContentController::processMessage(NetworkMessageReader* msg)
0297 {
0298     NetWorkReceiver::SendType result= NetWorkReceiver::NONE;
0299     std::set<NetMsg::Action> actions({NetMsg::AddMedia, NetMsg::UpdateMediaProperty, NetMsg::CloseMedia,
0300                                       NetMsg::AddSubImage, NetMsg::RemoveSubImage});
0301 
0302     if(actions.find(msg->action()) == actions.end())
0303         return result;
0304 
0305     QSet<NetMsg::Action> subActions{NetMsg::UpdateMediaProperty, NetMsg::AddSubImage, NetMsg::RemoveSubImage};
0306 
0307     if(msg->action() == NetMsg::CloseMedia)
0308     {
0309         Q_UNUSED(static_cast<Core::ContentType>(msg->uint8()));
0310         auto id= MessageHelper::readMediaId(msg);
0311         m_contentModel->removeMedia(id);
0312     }
0313     else if(msg->action() == NetMsg::AddMedia)
0314     {
0315         auto type= static_cast<Core::ContentType>(msg->uint8());
0316         auto media= Media::MediaFactory::createRemoteMedia(type, msg, localColor(), localIsGM());
0317         m_contentModel->appendMedia(media);
0318     }
0319     else if(subActions.contains(msg->action()))
0320     {
0321         auto type= static_cast<Core::ContentType>(msg->uint8());
0322         auto it= m_mediaUpdaters.find(type);
0323         if(it != m_mediaUpdaters.end())
0324         {
0325             auto updater= it->second.get();
0326             updater->processMessage(msg);
0327         }
0328         else
0329         {
0330             QString mediaId= msg->string8();
0331         }
0332     }
0333     return result;
0334 }
0335 
0336 void ContentController::copyData() {}
0337 
0338 void ContentController::pasteData()
0339 {
0340     auto mediaCtrl= m_contentModel->media(m_contentModel->activeMediaId());
0341     if(!m_clipboard)
0342         return;
0343     const QMimeData* mimeData= m_clipboard->mimeData();
0344     if(!mimeData)
0345         return;
0346 
0347     bool accepted= false;
0348     if(mediaCtrl)
0349         accepted= mediaCtrl->pasteData(*mimeData);
0350 
0351     if(!accepted)
0352         readMimeData(*mimeData);
0353 }
0354 
0355 void ContentController::readMimeData(const QMimeData& data)
0356 {
0357     if(data.hasImage())
0358     {
0359         auto pix= qvariant_cast<QPixmap>(data.imageData());
0360         if(pix.isNull())
0361             return;
0362         auto imageBytes= IOHelper::pixmapToData(pix);
0363         QString name(IOHelper::htmlToTitle(data, tr("Copied Image")));
0364 
0365         openMedia({{"type", QVariant::fromValue(Core::ContentType::PICTURE)},
0366                    {"ownerId", m_localId},
0367                    {"data", imageBytes},
0368                    {"name", name}});
0369     }
0370     else if(data.hasUrls())
0371     {
0372         // qDebug() << "hasURL";
0373     }
0374     else if(data.hasHtml())
0375     {
0376         // qDebug() << "hasHTML";
0377         // setText(data.html());
0378         // setTextFormat(Qt::RichText);
0379     }
0380     else if(data.hasText())
0381     {
0382         // qDebug() << "hasTEXT";
0383         // setText(data.text());
0384         // setTextFormat(Qt::PlainText);
0385     }
0386     else
0387     {
0388         // qDebug() << "nothing";
0389         // setText(tr("Cannot display data"));
0390     }
0391 }
0392 
0393 bool ContentController::canPaste() const
0394 {
0395     bool res= false;
0396 
0397     if(!m_clipboard)
0398         return res;
0399 
0400     auto data= m_clipboard->mimeData();
0401     if(!data)
0402         return res;
0403 
0404     res= data->hasImage();
0405     return res;
0406 }
0407 
0408 bool ContentController::canCopy() const
0409 {
0410     return false;
0411 }
0412 
0413 QString ContentController::mediaRoot() const
0414 {
0415     return m_sessionModel->rootPath();
0416 }
0417 /*void ContentController::setActiveMediaController(AbstractMediaContainerController* mediaCtrl)
0418 {
0419     std::find_if(m_mediaControllers.begin(), m_mediaControllers.end(),
0420                  [this](const std::pair<Core::ContentType, MediaControllerInterface*>& pair) {
0421 
0422                  });
0423     if()
0424 }*/
0425 
0426 const QColor& ContentController::localColor() const
0427 {
0428     return m_localColor;
0429 }
0430 
0431 void ContentController::setLocalColor(const QColor& newLocalColor)
0432 {
0433     if(m_localColor == newLocalColor)
0434         return;
0435     m_localColor= newLocalColor;
0436     emit localColorChanged();
0437 }