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

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 "worker/iohelper.h"
0021 
0022 #include <QBuffer>
0023 #include <QCborValue>
0024 #include <QClipboard>
0025 #include <QColor>
0026 #include <QDataStream>
0027 #include <QDir>
0028 #include <QFile>
0029 #include <QGuiApplication>
0030 #include <QMimeData>
0031 #include <QMutex>
0032 #include <QMutexLocker>
0033 #include <QSaveFile>
0034 #include <QString>
0035 #include <QStyleFactory>
0036 #include <QVariant>
0037 #include <map>
0038 
0039 #include "charactersheet/charactersheetmodel.h"
0040 #include "charactersheet/imagemodel.h"
0041 #include "charactersheet/worker/ioworker.h"
0042 #include "controller/audioplayercontroller.h"
0043 #include "controller/view_controller/charactersheetcontroller.h"
0044 #include "controller/view_controller/imagecontroller.h"
0045 #include "controller/view_controller/mediacontrollerbase.h"
0046 #include "controller/view_controller/mindmapcontroller.h"
0047 #include "controller/view_controller/mindmapcontrollerbase.h"
0048 #include "controller/view_controller/notecontroller.h"
0049 #include "controller/view_controller/pdfcontroller.h"
0050 #include "controller/view_controller/sharednotecontroller.h"
0051 #include "controller/view_controller/vectorialmapcontroller.h"
0052 #include "controller/view_controller/webpagecontroller.h"
0053 #include "data/character.h"
0054 #include "data/rolisteamtheme.h"
0055 #include "diceparser/dicealias.h"
0056 #include "media/mediatype.h"
0057 #include "mindmap/data/linkcontroller.h"
0058 #include "mindmap/data/mindnode.h"
0059 #include "mindmap/model/imagemodel.h"
0060 #include "mindmap/model/minditemmodel.h"
0061 #include "model/musicmodel.h"
0062 #include "model/nonplayablecharactermodel.h"
0063 #include "utils/iohelper.h"
0064 #include "worker/utilshelper.h"
0065 #include "worker/vectorialmapmessagehelper.h"
0066 
0067 constexpr char const* k_language_dir_path{":/translations"};
0068 constexpr char const* k_rolisteam_pattern{"rolisteam"};
0069 constexpr char const* k_qt_pattern{"qt"};
0070 constexpr char const* k_state_id{"id"};
0071 constexpr char const* k_state_label{"label"};
0072 constexpr char const* k_state_color{"color"};
0073 constexpr char const* k_state_image{"image"};
0074 
0075 namespace
0076 {
0077 template <class T>
0078 T* convertField(CharacterField* field)
0079 {
0080     return dynamic_cast<T*>(field);
0081 }
0082 } // namespace
0083 
0084 IOHelper::IOHelper() {}
0085 
0086 /*bool IOHelper::loadToken(campaign::NonPlayableCharacter* character, const QString& root,
0087                          std::map<QString, QVariant>& params)
0088 {
0089     bool ok;
0090     auto obj= loadJsonFileIntoObject(QString("%1/%2").arg(root, character->tokenPath()), ok);
0091 
0092     if(!ok)
0093         return false;
0094 
0095     params["side"]= obj[Core::JsonKey::JSON_TOKEN_SIZE].toDouble();
0096 
0097 
0098     character->setName(obj[Core::JsonKey::JSON_TOKEN_SIZE].toString());
0099     character->setColor(obj[Core::JsonKey::JSON_NPC_COLOR].toString());
0100     character->setHealthPointsMax(obj[Core::JsonKey::JSON_NPC_MAXHP].toInt());
0101     character->setHealthPointsMin(obj[Core::JsonKey::JSON_NPC_MINHP].toInt());
0102     character->setHealthPointsCurrent(obj[Core::JsonKey::JSON_NPC_HP].toInt());
0103 
0104     character->setInitiativeScore(obj[Core::JsonKey::JSON_NPC_INITVALUE].toInt());
0105     character->setInitCommand(obj[Core::JsonKey::JSON_NPC_INITCOMMAND].toString());
0106     // character->setAvatarPath(obj["avatarUri"].toString());
0107 
0108     auto img= loadFile(QString("%1/%2").arg(root, obj[Core::JsonKey::JSON_NPC_AVATAR].toString()));
0109 
0110     character->setAvatar(img);
0111 
0112     auto actionArray= obj[Core::JsonKey::JSON_NPC_ACTIONS].toArray();
0113     for(auto act : actionArray)
0114     {
0115         auto actObj= act.toObject();
0116         auto action= new CharacterAction();
0117         action->setName(actObj[Core::JsonKey::JSON_NPC_ACTION_NAME].toString());
0118         action->setCommand(actObj[Core::JsonKey::JSON_NPC_ACTION_COMMAND].toString());
0119         character->addAction(action);
0120     }
0121 
0122     auto propertyArray= obj[Core::JsonKey::JSON_NPC_PROPERTIES].toArray();
0123     for(auto pro : propertyArray)
0124     {
0125         auto proObj= pro.toObject();
0126         auto property= new CharacterProperty();
0127         property->setName(proObj[Core::JsonKey::JSON_NPC_PROPERTY_NAME].toString());
0128         property->setValue(proObj[Core::JsonKey::JSON_NPC_PROPERTY_VALUE].toString());
0129         character->addProperty(property);
0130     }
0131 
0132     auto shapeArray= obj[Core::JsonKey::JSON_NPC_SHAPES].toArray();
0133     for(auto sha : shapeArray)
0134     {
0135         auto objSha= sha.toObject();
0136         auto shape= new CharacterShape();
0137         shape->setName(objSha[Core::JsonKey::JSON_NPC_SHAPE_NAME].toString());
0138         auto avatarData= QByteArray::fromBase64(objSha[Core::JsonKey::JSON_NPC_SHAPE_DATAIMG].toString().toUtf8());
0139         QImage img= QImage::fromData(avatarData);
0140         shape->setImage(img);
0141         character->addShape(shape);
0142     }
0143 
0144     params["character"]= QVariant::fromValue(character);
0145     return true;
0146 }*/
0147 
0148 QList<QUrl> IOHelper::readM3uPlayList(const QString& filepath)
0149 {
0150     QList<QUrl> res;
0151     QFile file(filepath);
0152     /// @todo make this job in thread.
0153     if(file.open(QIODevice::ReadOnly))
0154     {
0155         QTextStream read(&file);
0156         QString line;
0157         while(!read.atEnd())
0158         {
0159             line= read.readLine();
0160             if(line.startsWith("#EXTINF", Qt::CaseSensitive) || line.isEmpty())
0161                 continue;
0162 
0163             auto url= QUrl::fromUserInput(line);
0164             if(url.isValid())
0165                 res.append(url);
0166         }
0167     }
0168     return res;
0169 }
0170 
0171 QJsonObject IOHelper::byteArrayToJsonObj(const QByteArray& data)
0172 {
0173     auto doc= QCborValue(data);
0174     return doc.toJsonValue().toObject();
0175 }
0176 
0177 QJsonObject IOHelper::textByteArrayToJsonObj(const QByteArray& data)
0178 {
0179     QJsonDocument doc= QJsonDocument::fromJson(data);
0180     return doc.object();
0181 }
0182 
0183 QJsonArray IOHelper::byteArrayToJsonArray(const QByteArray& data)
0184 {
0185     auto doc= QCborValue(data);
0186     return doc.toJsonValue().toArray();
0187 }
0188 
0189 QByteArray IOHelper::jsonObjectToByteArray(const QJsonObject& obj)
0190 {
0191     QJsonDocument doc;
0192     doc.setObject(obj);
0193     return doc.toJson(QJsonDocument::Indented);
0194 }
0195 
0196 QJsonObject IOHelper::loadJsonFileIntoObject(const QString& filename, bool& ok)
0197 {
0198     QJsonDocument doc= QJsonDocument::fromJson(utils::IOHelper::loadFile(filename));
0199     ok= !doc.isEmpty();
0200     return doc.object();
0201 }
0202 
0203 QJsonArray IOHelper::loadJsonFileIntoArray(const QString& filename, bool& ok)
0204 {
0205     QJsonDocument doc= QJsonDocument::fromJson(utils::IOHelper::loadFile(filename));
0206     ok= !doc.isEmpty();
0207     return doc.array();
0208 }
0209 
0210 QJsonArray IOHelper::fetchLanguageModel()
0211 {
0212     QJsonArray array;
0213     QDir dir(k_language_dir_path);
0214 
0215     auto list= dir.entryList(QStringList() << QStringLiteral("*.qm"), QDir::Files);
0216 
0217     static QRegularExpression reQt(QStringLiteral("%1_(.*)\\.qm").arg(k_qt_pattern));
0218     QHash<QString, QString> hash;
0219     for(const auto& info : qAsConst(list))
0220     {
0221         auto match= reQt.match(info);
0222         if(match.hasMatch())
0223         {
0224             hash.insert(match.captured(1), info);
0225         }
0226     }
0227 
0228     static QRegularExpression reRolisteam(QStringLiteral("%1_(.*)\\.qm").arg(k_rolisteam_pattern));
0229     for(auto info : qAsConst(list))
0230     {
0231         auto match= reRolisteam.match(info);
0232         if(match.hasMatch())
0233         {
0234             auto iso= match.captured(1);
0235             QJsonObject obj;
0236             QJsonArray paths;
0237             paths << QString("%1/%2").arg(k_language_dir_path, info);
0238             if(hash.contains(iso))
0239                 paths << QString("%1/%2").arg(k_language_dir_path, hash.value(iso));
0240             // else
0241             // qWarning() << "No Qt translation for " << iso;
0242 
0243             QLocale local(iso);
0244 
0245             obj[Core::i18n::KEY_PATH]= paths;
0246             obj[Core::i18n::KEY_CODE]= iso;
0247             obj[Core::i18n::KEY_COMMONNAME]= QLocale::languageToString(local.language());
0248             obj[Core::i18n::KEY_LANGNAME]= local.nativeLanguageName();
0249             array.append(obj);
0250         }
0251     }
0252 
0253     return array;
0254 }
0255 
0256 void IOHelper::saveBase(MediaControllerBase* base, QDataStream& output)
0257 {
0258     if(!base)
0259         return;
0260 
0261     output << base->contentType();
0262     output << base->uuid();
0263     output << base->url();
0264     output << base->name();
0265     output << base->ownerId();
0266 }
0267 
0268 void IOHelper::saveMediaBaseIntoJSon(MediaControllerBase* base, QJsonObject& obj)
0269 {
0270     if(!base)
0271         return;
0272 
0273     obj[Core::jsonctrl::base::JSON_CONTENT_TYPE]= static_cast<int>(base->contentType());
0274     obj[Core::jsonctrl::base::JSON_UUID]= base->uuid();
0275     obj[Core::jsonctrl::base::JSON_PATH]= base->url().toString();
0276     obj[Core::jsonctrl::base::JSON_NAME]= base->name();
0277     obj[Core::jsonctrl::base::JSON_OWNERID]= base->ownerId();
0278 }
0279 
0280 void IOHelper::readBaseFromJson(MediaControllerBase* base, const QJsonObject& data)
0281 {
0282     if(!base)
0283         return;
0284 
0285     base->setUuid(data[Core::jsonctrl::base::JSON_UUID].toString());
0286     base->setUrl(QUrl::fromUserInput(data[Core::jsonctrl::base::JSON_PATH].toString()));
0287     base->setName(data[Core::jsonctrl::base::JSON_NAME].toString());
0288     base->setOwnerId(data[Core::jsonctrl::base::JSON_OWNERID].toString());
0289 }
0290 
0291 QByteArray IOHelper::pixmapToData(const QPixmap& pix)
0292 {
0293     QByteArray bytes;
0294     QBuffer buffer(&bytes);
0295     buffer.open(QIODevice::WriteOnly);
0296     pix.save(&buffer, "PNG");
0297     return bytes;
0298 }
0299 
0300 QByteArray IOHelper::imageToData(const QImage& pix)
0301 {
0302     QByteArray bytes;
0303     QBuffer buffer(&bytes);
0304     buffer.open(QIODevice::WriteOnly);
0305     pix.save(&buffer, "PNG");
0306     return bytes;
0307 }
0308 
0309 const QMimeData* IOHelper::clipboardMineData()
0310 {
0311     auto clipboard= QGuiApplication::clipboard();
0312     if(!clipboard)
0313         return {};
0314 
0315     return clipboard->mimeData();
0316 }
0317 
0318 QString IOHelper::htmlToTitle(const QMimeData& data, const QString& defaultName)
0319 {
0320     QString name= defaultName;
0321     if(data.hasHtml())
0322     {
0323         QRegularExpression reg("src=\\\"([^\\s]+)\\\"");
0324         auto match= reg.match(data.html());
0325         if(match.hasMatch())
0326         {
0327             auto urlString= QUrl::fromUserInput(match.captured(1));
0328             name= urlString.fileName();
0329         }
0330     }
0331     return name;
0332 }
0333 
0334 QImage IOHelper::readImageFromURL(const QUrl& url)
0335 {
0336     QImage img;
0337     if(url.isLocalFile())
0338     {
0339         img= readImageFromFile(url.toLocalFile());
0340     }
0341     return img;
0342 }
0343 
0344 QImage IOHelper::readImageFromFile(const QString& url)
0345 {
0346     return QImage(url);
0347 }
0348 
0349 QPixmap IOHelper::dataToPixmap(const QByteArray& data)
0350 {
0351     QPixmap pix;
0352     pix.loadFromData(data);
0353     return pix;
0354 }
0355 
0356 QByteArray saveImage(ImageController* ctrl)
0357 {
0358     QByteArray data;
0359     if(!ctrl)
0360         return data;
0361 
0362     QDataStream output(&data, QIODevice::WriteOnly);
0363 
0364     IOHelper::saveBase(ctrl, output);
0365 
0366     output << ctrl->fitWindow();
0367     output << ctrl->data();
0368     output << ctrl->zoomLevel();
0369 
0370     return data;
0371 }
0372 
0373 QByteArray saveNotes(NoteController* ctrl)
0374 {
0375     QByteArray data;
0376     if(!ctrl)
0377         return data;
0378     QDataStream output(&data, QIODevice::WriteOnly);
0379     IOHelper::saveBase(ctrl, output);
0380 
0381     output << ctrl->text();
0382     return data;
0383 }
0384 
0385 QByteArray saveCharacterSheet(CharacterSheetController* ctrl)
0386 {
0387     QByteArray data;
0388     if(!ctrl)
0389         return data;
0390     QDataStream output(&data, QIODevice::WriteOnly);
0391     IOHelper::saveBase(ctrl, output);
0392 
0393     QJsonDocument doc;
0394     QJsonObject obj; //= //ctrl->rootObject();
0395     auto model= ctrl->model();
0396     QJsonObject dataObj;
0397     model->writeModel(dataObj);
0398 
0399     obj["character"]= dataObj;
0400 
0401     auto images= ctrl->imageModel();
0402 
0403     auto array= IOWorker::saveImageModel(images);
0404 
0405     obj["images"]= array;
0406 
0407     doc.setObject(obj);
0408 
0409     QCborValue val(doc.toJson());
0410     output << val;
0411 
0412     return data;
0413 }
0414 
0415 QByteArray saveSharedNote(SharedNoteController* ctrl)
0416 {
0417     QByteArray data;
0418     if(!ctrl)
0419         return data;
0420     QDataStream output(&data, QIODevice::WriteOnly);
0421 
0422     IOHelper::saveBase(ctrl, output);
0423 
0424     // output << ctrl->permission();
0425     output << ctrl->text();
0426     output << ctrl->highligthedSyntax();
0427     output << ctrl->markdownVisible();
0428     return data;
0429 }
0430 
0431 QByteArray saveWebView(WebpageController* ctrl)
0432 {
0433     QByteArray data;
0434     if(!ctrl)
0435         return data;
0436     QDataStream output(&data, QIODevice::WriteOnly);
0437 
0438     IOHelper::saveBase(ctrl, output);
0439 
0440     output << ctrl->hideUrl();
0441     output << ctrl->keepSharing();
0442     output << ctrl->htmlSharing();
0443     output << ctrl->urlSharing();
0444     output << ctrl->html();
0445     output << ctrl->url();
0446     output << ctrl->pageUrl();
0447     output << ctrl->state();
0448     output << ctrl->sharingMode();
0449     return data;
0450 }
0451 
0452 QByteArray saveMindmap(MindMapController* ctrl)
0453 {
0454     if(!ctrl)
0455         return {};
0456 
0457     QJsonObject objCtrl;
0458     IOHelper::saveMediaBaseIntoJSon(ctrl, objCtrl);
0459 
0460     objCtrl[Core::jsonctrl::Mindmap::JSON_CTRL_DEFAULT_INDEX_STYLE]= ctrl->defaultStyleIndex();
0461     objCtrl[Core::jsonctrl::Mindmap::JSON_CTRL_SPACING]= ctrl->spacing();
0462     objCtrl[Core::jsonctrl::Mindmap::JSON_CTRL_LINK_LABEL_VISIBILITY]= ctrl->linkLabelVisibility();
0463 
0464     auto updateMindItem= [](QJsonObject& obj, mindmap::MindItem* item)
0465     {
0466         namespace ujm= Core::jsonctrl::Mindmap;
0467         obj[ujm::JSON_MINDITEM_ID]= item->id();
0468         obj[ujm::JSON_MINDITEM_TEXT]= item->text();
0469         obj[ujm::JSON_MINDITEM_VISIBLE]= item->isVisible();
0470         obj[ujm::JSON_MINDITEM_SELECTED]= item->selected();
0471         obj[ujm::JSON_MINDITEM_TYPE]= item->type();
0472     };
0473 
0474     auto updatePositionItem= [updateMindItem](QJsonObject& obj, mindmap::PositionedItem* pitem)
0475     {
0476         namespace ujm= Core::jsonctrl::Mindmap;
0477         updateMindItem(obj, pitem);
0478         obj[ujm::JSON_POSITIONED_POSITIONX]= pitem->position().x();
0479         obj[ujm::JSON_POSITIONED_POSITIONY]= pitem->position().y();
0480         obj[ujm::JSON_POSITIONED_CENTERX]= pitem->centerPoint().x();
0481         obj[ujm::JSON_POSITIONED_CENTERY]= pitem->centerPoint().y();
0482         obj[ujm::JSON_POSITIONED_WIDTH]= pitem->width();
0483         obj[ujm::JSON_POSITIONED_HEIGHT]= pitem->height();
0484         obj[ujm::JSON_POSITIONED_DRAGGED]= pitem->isDragged();
0485         obj[ujm::JSON_POSITIONED_OPEN]= pitem->open();
0486         obj[ujm::JSON_POSITIONED_LOCKED]= pitem->isLocked();
0487         obj[ujm::JSON_POSITIONED_MASS]= pitem->mass();
0488     };
0489 
0490     auto model= dynamic_cast<mindmap::MindItemModel*>(ctrl->itemModel());
0491     auto nodes= model->items(mindmap::MindItem::NodeType);
0492     QJsonArray nodeArray;
0493     for(auto const& i : nodes)
0494     {
0495         auto node= dynamic_cast<mindmap::MindNode*>(i);
0496         if(!node)
0497             continue;
0498         QJsonObject obj;
0499         updatePositionItem(obj, node);
0500         obj[Core::jsonctrl::Mindmap::JSON_NODE_IMAGE]= node->imageUri();
0501         obj[Core::jsonctrl::Mindmap::JSON_NODE_STYLE]= node->styleIndex();
0502         obj[Core::jsonctrl::Mindmap::JSON_NODE_DESC]= node->description();
0503         obj[Core::jsonctrl::Mindmap::JSON_NODE_TAGS]= QJsonArray::fromStringList(node->tags());
0504 
0505         nodeArray.append(obj);
0506     }
0507 
0508     objCtrl[Core::jsonctrl::Mindmap::JSON_NODES]= nodeArray;
0509 
0510     QJsonArray packagesArray;
0511     auto packagesItem= model->items(mindmap::MindItem::PackageType);
0512     for(auto const& i : packagesItem)
0513     {
0514 
0515         auto pack= dynamic_cast<mindmap::PackageNode*>(i);
0516         if(!pack)
0517             continue;
0518         QJsonObject obj;
0519         updatePositionItem(obj, pack);
0520         obj[Core::jsonctrl::Mindmap::JSON_PACK_TITLE]= pack->title();
0521         obj[Core::jsonctrl::Mindmap::JSON_PACK_MINMARGE]= pack->minimumMargin();
0522 
0523         obj[Core::jsonctrl::Mindmap::JSON_PACK_INTERNAL_CHILDREN]= QJsonArray::fromStringList(pack->childrenId());
0524         packagesArray.append(obj);
0525     }
0526     objCtrl[Core::jsonctrl::Mindmap::JSON_PACK_PACKAGES]= packagesArray;
0527 
0528     QJsonArray linkArray;
0529     auto links= model->items(mindmap::MindItem::LinkType);
0530     for(auto const& i : links)
0531     {
0532 
0533         auto link= dynamic_cast<mindmap::LinkController*>(i);
0534         if(!link)
0535             continue;
0536 
0537         QJsonObject obj;
0538         updateMindItem(obj, link);
0539         auto start= link->start();
0540         obj[Core::jsonctrl::Mindmap::JSON_LINK_IDSTART]= start ? start->id() : QString();
0541         auto end= link->end();
0542         obj[Core::jsonctrl::Mindmap::JSON_LINK_IDEND]= end ? end->id() : QString();
0543         obj[Core::jsonctrl::Mindmap::JSON_LINK_DIRECTION]= static_cast<int>(link->direction());
0544         linkArray.append(obj);
0545     }
0546     objCtrl[Core::jsonctrl::Mindmap::JSON_LINKS]= linkArray;
0547 
0548     auto imgModel= ctrl->imgModel();
0549     auto imgs= imgModel->imageInfos();
0550     QJsonArray imgArray;
0551     for(const auto& img : imgs)
0552     {
0553         QJsonObject obj;
0554         obj[Core::jsonctrl::Mindmap::JSON_IMG_ID]= img.m_id;
0555         obj[Core::jsonctrl::Mindmap::JSON_IMG_DATA]= QString::fromUtf8(IOHelper::pixmapToData(img.m_pixmap).toBase64());
0556         obj[Core::jsonctrl::Mindmap::JSON_IMG_URL]= img.m_url.toString();
0557         imgArray.append(obj);
0558     }
0559     objCtrl[Core::jsonctrl::Mindmap::JSON_IMGS]= imgArray;
0560 
0561     return IOHelper::jsonObjectToByteArray(objCtrl);
0562 }
0563 
0564 QByteArray savePdfView(PdfController* ctrl)
0565 {
0566     QByteArray data;
0567     if(!ctrl)
0568         return data;
0569     QDataStream output(&data, QIODevice::WriteOnly);
0570 
0571     IOHelper::saveBase(ctrl, output);
0572 
0573     output << ctrl->data();
0574     return data;
0575 }
0576 
0577 QByteArray IOHelper::saveController(MediaControllerBase* media)
0578 {
0579     QByteArray data;
0580 
0581     if(!media)
0582         return data;
0583 
0584     auto uri= media->contentType();
0585     switch(uri)
0586     {
0587     case Core::ContentType::VECTORIALMAP:
0588         data= VectorialMapMessageHelper::saveVectorialMap(dynamic_cast<VectorialMapController*>(media));
0589         break;
0590     case Core::ContentType::PICTURE:
0591         data= saveImage(dynamic_cast<ImageController*>(media));
0592         break;
0593     case Core::ContentType::NOTES:
0594         data= saveNotes(dynamic_cast<NoteController*>(media));
0595         break;
0596     case Core::ContentType::CHARACTERSHEET:
0597         data= saveCharacterSheet(dynamic_cast<CharacterSheetController*>(media));
0598         break;
0599     case Core::ContentType::SHAREDNOTE:
0600         data= saveSharedNote(dynamic_cast<SharedNoteController*>(media));
0601         break;
0602     case Core::ContentType::WEBVIEW:
0603         data= saveWebView(dynamic_cast<WebpageController*>(media));
0604         break;
0605     case Core::ContentType::MINDMAP:
0606         data= saveMindmap(dynamic_cast<MindMapController*>(media));
0607         break;
0608     case Core::ContentType::PDF:
0609         data= savePdfView(dynamic_cast<PdfController*>(media));
0610         break;
0611     default:
0612         break;
0613     }
0614 
0615     return data;
0616 }
0617 
0618 /*MediaControllerBase* IOHelper::loadController(const QByteArray& data)
0619 {
0620     QDataStream input(data);
0621     Core::ContentType type;
0622     input >> type;
0623 
0624     MediaControllerBase* value= nullptr;
0625     switch(type)
0626     {
0627     case Core::ContentType::VECTORIALMAP:
0628     {
0629         auto ctrl= new VectorialMapController();
0630         value= ctrl;
0631         VectorialMapMessageHelper::readVectorialMapController(ctrl, data);
0632     }
0633     break;
0634     case Core::ContentType::PICTURE:
0635     {
0636         auto ctrl= new ImageController();
0637         value= ctrl;
0638         readImageController(ctrl, data);
0639     }
0640     break;
0641     case Core::ContentType::NOTES:
0642     {
0643         auto ctrl= new NoteController();
0644         value= ctrl;
0645         readNoteController(ctrl, data);
0646     }
0647     break;
0648     case Core::ContentType::CHARACTERSHEET:
0649     {
0650         auto ctrl= new CharacterSheetController();
0651         value= ctrl;
0652         readCharacterSheetController(ctrl, data);
0653     }
0654     break;
0655     case Core::ContentType::SHAREDNOTE:
0656     {
0657         auto ctrl= new SharedNoteController();
0658         value= ctrl;
0659         readSharedNoteController(ctrl, data);
0660     }
0661     break;
0662     case Core::ContentType::WEBVIEW:
0663     {
0664         auto ctrl= new WebpageController();
0665         value= ctrl;
0666         readWebpageController(ctrl, data);
0667     }
0668     break;
0669     case Core::ContentType::MINDMAP:
0670     {
0671         auto ctrl= new MindMapController({});
0672         value= ctrl;
0673         readMindmapController(ctrl, data);
0674     }
0675     case Core::ContentType::PDF:
0676     {
0677         auto ctrl= new PdfController();
0678         value= ctrl;
0679         readPdfController(ctrl, data);
0680     }
0681     break;
0682     default:
0683         Q_ASSERT(false); // No valid contentType
0684         break;
0685     }
0686 
0687     return value;
0688 }*/
0689 
0690 void IOHelper::writePlaylist(const QString& path, const QList<QUrl>& urls)
0691 {
0692     QByteArray array;
0693     QTextStream stream(array);
0694     for(auto const& url : urls)
0695     {
0696         stream << url.toString();
0697     }
0698 
0699     utils::IOHelper::writeFile(path, array);
0700 }
0701 
0702 QJsonObject IOHelper::saveAudioPlayerController(AudioPlayerController* controller)
0703 {
0704     QJsonObject obj;
0705     if(!controller)
0706         return obj;
0707     obj[Core::jsonctrl::Audio::JSON_AUDIO_VOLUME]= static_cast<int>(controller->volume());
0708     obj[Core::jsonctrl::Audio::JSON_AUDIO_VISIBLE]= controller->visible();
0709     obj[Core::jsonctrl::Audio::JSON_PLAYING_MODE]= controller->mode();
0710 
0711     auto m= controller->model()->urls();
0712     QJsonArray array;
0713     std::transform(std::begin(m), std::end(m), std::back_inserter(array),
0714                    [](const QUrl& url) { return url.toString(); });
0715     obj[Core::jsonctrl::Audio::JSON_AUDIO_URLS]= array;
0716 
0717     return obj;
0718 }
0719 
0720 void IOHelper::fetchAudioPlayerController(AudioPlayerController* controller, const QJsonObject& obj)
0721 {
0722     if(!controller)
0723         return;
0724 
0725     controller->setVolume(static_cast<uint>(obj[Core::jsonctrl::Audio::JSON_AUDIO_VOLUME].toInt()));
0726     controller->setVisible(obj[Core::jsonctrl::Audio::JSON_AUDIO_VISIBLE].toBool());
0727     controller->setPlayingMode(
0728         static_cast<AudioPlayerController::PlayingMode>(obj[Core::jsonctrl::Audio::JSON_PLAYING_MODE].toInt()));
0729 
0730     auto urlArray= obj[Core::jsonctrl::Audio::JSON_AUDIO_URLS].toArray();
0731     QList<QUrl> urls;
0732     std::transform(std::begin(urlArray), std::end(urlArray), std::back_inserter(urls),
0733                    [](const QJsonValueRef& ref) { return QUrl::fromUserInput(ref.toString()); });
0734 
0735     controller->clear();
0736     controller->addSong(urls);
0737 }
0738 
0739 void IOHelper::readBase(MediaControllerBase* base, QDataStream& input)
0740 {
0741     if(!base)
0742         return;
0743 
0744     Core::ContentType type;
0745     input >> type;
0746     QString uuid;
0747     input >> uuid;
0748     QUrl path;
0749     input >> path;
0750 
0751     QString name;
0752     input >> name;
0753 
0754     QString ownerId;
0755     input >> ownerId;
0756 
0757     base->setUuid(uuid);
0758     base->setName(name);
0759     base->setUrl(path);
0760     base->setOwnerId(ownerId);
0761 }
0762 
0763 void IOHelper::readCharacterSheetController(CharacterSheetController* ctrl, const QByteArray& array)
0764 {
0765     if(!ctrl || array.isEmpty())
0766         return;
0767 
0768     qDebug() << "array" << array.size();
0769     auto data= IOHelper::textByteArrayToJsonObj(array);
0770     qDebug() << "\n\n\n\n\ndata" << data.size();
0771     IOHelper::readBaseFromJson(ctrl, data);
0772 
0773     // auto charactersData= data[Core::jsonctrl::sheet::JSON_CHARACTER_CONTENT].toArray();
0774     auto images= data[Core::jsonctrl::sheet::JSON_IMAGES_CONTENT].toArray();
0775     ctrl->setQmlCode(data[Core::jsonctrl::sheet::JSON_QML_CONTENT].toString());
0776 
0777     auto model= ctrl->model();
0778     model->readModel(data, true);
0779     auto imagesModel= ctrl->imageModel();
0780     IOWorker::fetchImageModel(imagesModel, images);
0781 }
0782 
0783 QString IOHelper::copyImageFileIntoCampaign(const QString& path, const QString& dest)
0784 {
0785     if(path.startsWith(dest))
0786         return path;
0787     else
0788         return utils::IOHelper::copyFile(path, dest);
0789 }
0790 
0791 Character* IOHelper::dupplicateCharacter(const Character *obj)
0792 {
0793     auto res = new Character();
0794 
0795     res->setHealthPointsCurrent(obj->getHealthPointsCurrent());
0796     res->setHealthPointsMax(obj->getHealthPointsMax());
0797     res->setHealthPointsMin(obj->getHealthPointsMin());
0798     res->setNpc(obj->isNpc());
0799     res->setInitCommand(obj->initCommand());
0800     res->setInitiativeScore(obj->getInitiativeScore());
0801     res->setImageProvider(obj->getImageProvider());
0802     res->setCurrentShape(obj->currentShape());
0803     res->setLifeColor(obj->getLifeColor());
0804     res->setStateId(obj->stateId());
0805     res->setDistancePerTurn(obj->getDistancePerTurn());
0806     res->setNumber(obj->number());
0807     res->setName(obj->name());
0808     res->setUuid(obj->uuid());
0809     res->setColor(obj->getColor());
0810     res->setSheet(obj->getSheet());
0811     res->defineActionList(obj->actionList());
0812     res->defineShapeList(obj->shapeList());
0813     res->definePropertiesList(obj->propertiesList());
0814     res->setAvatar(obj->avatar());
0815 
0816     return res;
0817 }
0818 
0819 void IOHelper::readPdfController(PdfController* ctrl, const QByteArray& array)
0820 {
0821     if(!ctrl || array.isEmpty())
0822         return;
0823     auto data= array;
0824     QDataStream input(&data, QIODevice::ReadOnly);
0825 
0826     IOHelper::readBase(ctrl, input);
0827 
0828     QByteArray pdfData;
0829     input >> pdfData;
0830     if(!pdfData.isEmpty())
0831         ctrl->setData(pdfData);
0832 }
0833 
0834 void IOHelper::readImageController(ImageController* ctrl, const QByteArray& array)
0835 {
0836     if(!ctrl || array.isEmpty())
0837         return;
0838 
0839     auto data= array;
0840     QDataStream input(&data, QIODevice::ReadOnly);
0841 
0842     IOHelper::readBase(ctrl, input);
0843 
0844     bool b;
0845     input >> b;
0846 
0847     QByteArray dataByte;
0848     input >> dataByte;
0849 
0850     qreal zoom;
0851     input >> zoom;
0852 
0853     ctrl->setFitWindow(b);
0854     ctrl->setData(dataByte);
0855     ctrl->setZoomLevel(zoom);
0856 }
0857 
0858 void IOHelper::readWebpageController(WebpageController* ctrl, const QByteArray& array)
0859 {
0860     if(!ctrl || array.isEmpty())
0861         return;
0862     auto data= array;
0863     QDataStream input(&data, QIODevice::ReadOnly);
0864 
0865     IOHelper::readBase(ctrl, input);
0866 
0867     bool hide;
0868     input >> hide;
0869 
0870     bool keepSharing;
0871     input >> keepSharing;
0872 
0873     bool htmlSharing;
0874     input >> htmlSharing;
0875 
0876     bool urlSharing;
0877     input >> urlSharing;
0878 
0879     QString html;
0880     input >> html;
0881 
0882     QUrl url;
0883     input >> url;
0884 
0885     QUrl pageUrl;
0886     input >> pageUrl;
0887 
0888     WebpageController::State state;
0889     input >> state;
0890 
0891     WebpageController::SharingMode mode;
0892     input >> mode;
0893 
0894     ctrl->setHideUrl(hide);
0895     ctrl->setKeepSharing(keepSharing);
0896     ctrl->setHtmlSharing(htmlSharing);
0897     ctrl->setUrlSharing(urlSharing);
0898     ctrl->setState(state);
0899     ctrl->setSharingMode(mode);
0900     ctrl->setPageUrl(pageUrl);
0901     ctrl->setUrl(url);
0902 }
0903 QJsonObject IOHelper::readMindmapController(MindMapController* ctrl, const QByteArray& array)
0904 {
0905     if(!ctrl || array.isEmpty())
0906         return {};
0907 
0908     auto objCtrl= IOHelper::textByteArrayToJsonObj(array);
0909 
0910     IOHelper::readMindmapControllerBase(ctrl, objCtrl);
0911 
0912     return objCtrl;
0913 }
0914 void IOHelper::readMindmapControllerBase(mindmap::MindMapControllerBase* ctrl, const QJsonObject& objCtrl)
0915 {
0916     if(!ctrl)
0917         return;
0918 
0919     IOHelper::readBaseFromJson(ctrl, objCtrl);
0920 
0921     ctrl->setDefaultStyleIndex(objCtrl[Core::jsonctrl::Mindmap::JSON_CTRL_DEFAULT_INDEX_STYLE].toInt());
0922     ctrl->setSpacing(objCtrl[Core::jsonctrl::Mindmap::JSON_CTRL_SPACING].toBool());
0923     ctrl->setLinkLabelVisibility(objCtrl[Core::jsonctrl::Mindmap::JSON_CTRL_LINK_LABEL_VISIBILITY].toBool());
0924 
0925     auto imgs= objCtrl[Core::jsonctrl::Mindmap::JSON_IMGS].toArray();
0926     auto imgModel= ctrl->imgModel();
0927     for(auto const& imgRef : imgs)
0928     {
0929         auto img= imgRef.toObject();
0930         auto pixmap= IOHelper::dataToPixmap(
0931             QByteArray::fromBase64(img[Core::jsonctrl::Mindmap::JSON_IMG_DATA].toString().toUtf8()));
0932         auto id= img[Core::jsonctrl::Mindmap::JSON_IMG_ID].toString();
0933         auto url= QUrl::fromUserInput(img[Core::jsonctrl::Mindmap::JSON_IMG_URL].toString());
0934         imgModel->insertPixmap(id, pixmap, url);
0935     }
0936 
0937     auto updateMindItem= [](const QJsonObject& obj, mindmap::MindItem* item)
0938     {
0939         namespace ujm= Core::jsonctrl::Mindmap;
0940         item->setId(obj[ujm::JSON_MINDITEM_ID].toString());
0941         item->setText(obj[ujm::JSON_MINDITEM_TEXT].toString());
0942         item->setVisible(obj[ujm::JSON_MINDITEM_VISIBLE].toBool());
0943         item->setSelected(false); // obj[ujm::JSON_MINDITEM_SELECTED].toBool()
0944     };
0945 
0946     auto updatePositionItem= [updateMindItem](const QJsonObject& obj, mindmap::PositionedItem* pitem)
0947     {
0948         namespace ujm= Core::jsonctrl::Mindmap;
0949         updateMindItem(obj, pitem);
0950         pitem->setPosition(
0951             {obj[ujm::JSON_POSITIONED_POSITIONX].toDouble(), obj[ujm::JSON_POSITIONED_POSITIONY].toDouble()});
0952 
0953         qDebug() << "position" << pitem->position();
0954 
0955         pitem->setWidth(obj[ujm::JSON_POSITIONED_WIDTH].toDouble());
0956         pitem->setHeight(obj[ujm::JSON_POSITIONED_HEIGHT].toDouble());
0957         pitem->setDragged(obj[ujm::JSON_POSITIONED_DRAGGED].toBool());
0958         pitem->setOpen(obj[ujm::JSON_POSITIONED_OPEN].toBool());
0959         pitem->setLocked(obj[ujm::JSON_POSITIONED_LOCKED].toBool());
0960         pitem->setMass(obj[ujm::JSON_POSITIONED_MASS].toInt());
0961     };
0962 
0963     auto nodes= objCtrl[Core::jsonctrl::Mindmap::JSON_NODES].toArray();
0964     auto model= dynamic_cast<mindmap::MindItemModel*>(ctrl->itemModel());
0965     for(auto const& nodeRef : nodes)
0966     {
0967         auto nodeJson= nodeRef.toObject();
0968         auto node= new mindmap::MindNode();
0969         updatePositionItem(nodeJson, node);
0970 
0971         node->setImageUri(nodeJson[Core::jsonctrl::Mindmap::JSON_NODE_IMAGE].toString());
0972         node->setStyleIndex(nodeJson[Core::jsonctrl::Mindmap::JSON_NODE_STYLE].toInt());
0973         node->setDescription(nodeJson[Core::jsonctrl::Mindmap::JSON_NODE_DESC].toString());
0974         auto tagArray= nodeJson[Core::jsonctrl::Mindmap::JSON_NODE_TAGS].toArray();
0975         QStringList tags;
0976         std::transform(std::begin(tagArray), std::end(tagArray), std::back_inserter(tags),
0977                        [](const QJsonValue& val) { return val.toString(); });
0978         node->setTags(tags);
0979 
0980         model->appendItem({node});
0981     }
0982 
0983     auto packages= objCtrl[Core::jsonctrl::Mindmap::JSON_PACK_PACKAGES].toArray();
0984     for(auto const& packRef : packages)
0985     {
0986         auto pack= packRef.toObject();
0987         auto node= new mindmap::PackageNode();
0988         updatePositionItem(pack, node);
0989 
0990         node->setTitle(pack[Core::jsonctrl::Mindmap::JSON_PACK_TITLE].toString());
0991         node->setMinimumMargin(pack[Core::jsonctrl::Mindmap::JSON_PACK_MINMARGE].toInt());
0992 
0993         auto childArray= pack[Core::jsonctrl::Mindmap::JSON_PACK_INTERNAL_CHILDREN].toArray();
0994         std::for_each(std::begin(childArray), std::end(childArray),
0995                       [node, model](const QJsonValue& val) { node->addChild(model->positionItem(val.toString())); });
0996 
0997         model->appendItem({node});
0998     }
0999 
1000     auto linkArrays= objCtrl[Core::jsonctrl::Mindmap::JSON_LINKS].toArray();
1001     for(auto const& linkRef : linkArrays)
1002     {
1003         auto obj= linkRef.toObject();
1004         auto link= new mindmap::LinkController();
1005         updateMindItem(obj, link);
1006 
1007         auto startId= obj[Core::jsonctrl::Mindmap::JSON_LINK_IDSTART].toString();
1008         auto endId= obj[Core::jsonctrl::Mindmap::JSON_LINK_IDEND].toString();
1009         auto start= model->positionItem(startId);
1010         auto end= model->positionItem(endId);
1011 
1012         link->setStart(start);
1013         link->setEnd(end);
1014         link->setDirection(
1015             static_cast<mindmap::LinkController::Direction>(obj[Core::jsonctrl::Mindmap::JSON_LINK_DIRECTION].toInt()));
1016         model->appendItem({link});
1017     }
1018 
1019     // TODO read data to define mindmapcontroller.
1020 }
1021 
1022 bool IOHelper::mergePlayList(const QString& source, const QString& dest)
1023 {
1024     bool ok;
1025     auto sourceJson= loadJsonFileIntoObject(source, ok);
1026     if(!ok)
1027         return ok;
1028     auto destJson= loadJsonFileIntoObject(dest, ok);
1029 
1030     if(!ok)
1031     {
1032         utils::IOHelper::copyFile(source, dest);
1033         return true;
1034     }
1035 
1036     auto arraySrc= sourceJson[Core::jsonctrl::Audio::JSON_AUDIO_URLS].toArray();
1037     auto arrayDst= destJson[Core::jsonctrl::Audio::JSON_AUDIO_URLS].toArray();
1038 
1039     arrayDst.append(arraySrc);
1040     destJson[Core::jsonctrl::Audio::JSON_AUDIO_URLS]= arrayDst;
1041 
1042     writeJsonObjectIntoFile(dest, destJson);
1043     return true;
1044 }
1045 
1046 QStringList IOHelper::mediaList(const QString& source, Core::MediaType type)
1047 {
1048     QDir dir(source);
1049     return dir.entryList(helper::utils::extentionPerType(helper::utils::mediaTypeToContentType(type), false, true),
1050                          QDir::Files | QDir::Readable);
1051 }
1052 
1053 bool IOHelper::copyArrayModelAndFile(const QString& source, const QString& sourceDir, const QString& dest,
1054                                      const QString& destDir)
1055 {
1056     bool ok;
1057     auto sourceJson= loadJsonFileIntoArray(source, ok);
1058     if(!ok)
1059         return false; // nothing to do
1060     auto destJson= loadJsonFileIntoArray(dest, ok);
1061 
1062     if(!ok)
1063     {
1064         utils::IOHelper::copyFile(source, dest);
1065     }
1066 
1067     destJson.append(sourceJson);
1068     writeJsonArrayIntoFile(dest, destJson);
1069 
1070     // Copy npcs files
1071     QDir dir(sourceDir);
1072     auto fileList= dir.entryList(QDir::Files | QDir::Readable);
1073     for(auto const& file : fileList)
1074     {
1075         utils::IOHelper::copyFile(QString("%1/%2").arg(sourceDir, file), QString("%1/%2").arg(destDir, file));
1076     }
1077     return true;
1078 }
1079 
1080 /*bool IOHelper::copyMedia(const QString &source, const QString &dest, Core::MediaType type)
1081 {
1082 
1083 }*/
1084 
1085 /*QString IOHelper::shortNameFromPath(const QString& path)
1086 {
1087     QFileInfo info(path);
1088     return info.baseName();
1089 }
1090 
1091 QString IOHelper::shortNameFromUrl(const QUrl& url)
1092 {
1093     return shortNameFromPath(url.fileName());
1094 }
1095 
1096 QString IOHelper::absoluteToRelative(const QString& absolute, const QString& root)
1097 {
1098     QDir dir(root);
1099     QFileInfo path(absolute);
1100     if(!path.isAbsolute())
1101         return absolute;
1102 
1103     return dir.relativeFilePath(absolute);
1104 }*/
1105 
1106 QJsonObject IOHelper::stateToJSonObject(CharacterState* state, const QString& root)
1107 {
1108     QJsonObject stateJson;
1109 
1110     stateJson[k_state_id]= state->id();
1111     stateJson[k_state_label]= state->label();
1112     stateJson[k_state_color]= state->color().name();
1113     auto pathImg= state->imagePath();
1114     pathImg= utils::IOHelper::absoluteToRelative(pathImg, root);
1115     stateJson[k_state_image]= pathImg;
1116     return stateJson;
1117 }
1118 
1119 QJsonObject IOHelper::npcToJsonObject(const campaign::NonPlayableCharacter* npc, const QString& destination)
1120 {
1121     if(nullptr == npc)
1122         return {};
1123     QJsonObject obj;
1124 
1125     obj[Core::JsonKey::JSON_NPC_ID]= npc->uuid();
1126     obj[Core::JsonKey::JSON_NPC_NAME]= npc->name();
1127     obj[Core::JsonKey::JSON_NPC_AVATAR]= utils::IOHelper::absoluteToRelative(npc->avatarPath(), destination);
1128     obj[Core::JsonKey::JSON_NPC_TAGS]= QJsonArray::fromStringList(npc->tags());
1129     obj[Core::JsonKey::JSON_NPC_DESCRIPTION]= npc->description();
1130 
1131     obj[Core::JsonKey::JSON_NPC_INITCOMMAND]= npc->initCommand();
1132     obj[Core::JsonKey::JSON_NPC_INITVALUE]= npc->getInitiativeScore();
1133     obj[Core::JsonKey::JSON_NPC_COLOR]= npc->getColor().name();
1134     obj[Core::JsonKey::JSON_NPC_HP]= npc->getHealthPointsCurrent();
1135     obj[Core::JsonKey::JSON_NPC_MAXHP]= npc->getHealthPointsMax();
1136     obj[Core::JsonKey::JSON_NPC_MINHP]= npc->getHealthPointsMin();
1137     obj[Core::JsonKey::JSON_NPC_DIST_PER_TURN]= npc->getDistancePerTurn();
1138     obj[Core::JsonKey::JSON_NPC_STATEID]= npc->stateId();
1139     obj[Core::JsonKey::JSON_NPC_LIFECOLOR]= npc->getLifeColor().name();
1140     obj[Core::JsonKey::JSON_TOKEN_SIZE]= npc->size();
1141 
1142     QJsonArray actionArray;
1143     auto actionList= npc->actionList();
1144     for(auto act : actionList)
1145     {
1146         if(act == nullptr)
1147             continue;
1148         QJsonObject actJson;
1149         actJson[Core::JsonKey::JSON_NPC_ACTION_NAME]= act->name();
1150         actJson[Core::JsonKey::JSON_NPC_ACTION_COMMAND]= act->command();
1151         actionArray.append(actJson);
1152     }
1153     obj[Core::JsonKey::JSON_NPC_ACTIONS]= actionArray;
1154 
1155     QJsonArray propertyArray;
1156     auto properties= npc->propertiesList();
1157     for(auto property : properties)
1158     {
1159         if(property == nullptr)
1160             continue;
1161         QJsonObject actJson;
1162         actJson[Core::JsonKey::JSON_NPC_PROPERTY_NAME]= property->name();
1163         actJson[Core::JsonKey::JSON_NPC_PROPERTY_VALUE]= property->value();
1164         propertyArray.append(actJson);
1165     }
1166     obj[Core::JsonKey::JSON_NPC_PROPERTIES]= propertyArray;
1167 
1168     QJsonArray shapeArray;
1169     auto shapes= npc->shapeList();
1170     for(auto shape : shapes)
1171     {
1172         if(shape == nullptr)
1173             continue;
1174         QJsonObject actJson;
1175         actJson[Core::JsonKey::JSON_NPC_SHAPE_NAME]= shape->name();
1176 
1177         auto data= IOHelper::imageToData(shape->image());
1178 
1179         actJson[Core::JsonKey::JSON_NPC_SHAPE_DATAIMG]= QString::fromUtf8(data.toBase64());
1180         shapeArray.append(actJson);
1181     }
1182     obj[Core::JsonKey::JSON_NPC_SHAPES]= shapeArray;
1183 
1184     return obj;
1185 }
1186 
1187 campaign::NonPlayableCharacter* IOHelper::jsonObjectToNpc(const QJsonObject& obj, const QString& rootDir)
1188 {
1189     auto npc= new campaign::NonPlayableCharacter();
1190     auto uuid= obj[Core::JsonKey::JSON_NPC_ID].toString();
1191     auto desc= obj[Core::JsonKey::JSON_NPC_DESCRIPTION].toString();
1192     auto name= obj[Core::JsonKey::JSON_NPC_NAME].toString();
1193     auto avatar= obj[Core::JsonKey::JSON_NPC_AVATAR].toString();
1194     auto stateid= obj[Core::JsonKey::JSON_NPC_STATEID].toString();
1195     auto tags= obj[Core::JsonKey::JSON_NPC_TAGS].toArray();
1196     auto tokenPath= obj[Core::JsonKey::JSON_NPC_TOKEN].toString();
1197     QStringList list;
1198     std::transform(std::begin(tags), std::end(tags), std::back_inserter(list),
1199                    [](const QJsonValue& val) { return val.toString(); });
1200 
1201     npc->setUuid(uuid);
1202     npc->setName(name);
1203     npc->setDescription(desc);
1204     npc->setStateId(stateid);
1205     npc->setAvatar(utils::IOHelper::loadFile(QString("%1/%2").arg(rootDir, avatar)));
1206     npc->setAvatarPath(avatar);
1207     npc->setTags(list);
1208 
1209     npc->setSize(obj[Core::JsonKey::JSON_TOKEN_SIZE].toInt());
1210     npc->setColor(obj[Core::JsonKey::JSON_NPC_COLOR].toString());
1211     npc->setHealthPointsMax(obj[Core::JsonKey::JSON_NPC_MAXHP].toInt());
1212     npc->setHealthPointsMin(obj[Core::JsonKey::JSON_NPC_MINHP].toInt());
1213     npc->setHealthPointsCurrent(obj[Core::JsonKey::JSON_NPC_HP].toInt());
1214 
1215     npc->setInitiativeScore(obj[Core::JsonKey::JSON_NPC_INITVALUE].toInt());
1216     npc->setInitCommand(obj[Core::JsonKey::JSON_NPC_INITCOMMAND].toString());
1217 
1218     auto actionArray= obj[Core::JsonKey::JSON_NPC_ACTIONS].toArray();
1219     for(auto act : actionArray)
1220     {
1221         auto actObj= act.toObject();
1222         auto action= new CharacterAction();
1223         action->setName(actObj[Core::JsonKey::JSON_NPC_ACTION_NAME].toString());
1224         action->setCommand(actObj[Core::JsonKey::JSON_NPC_ACTION_COMMAND].toString());
1225         npc->addAction(action);
1226     }
1227 
1228     auto propertyArray= obj[Core::JsonKey::JSON_NPC_PROPERTIES].toArray();
1229     for(auto pro : propertyArray)
1230     {
1231         auto proObj= pro.toObject();
1232         auto property= new CharacterProperty();
1233         property->setName(proObj[Core::JsonKey::JSON_NPC_PROPERTY_NAME].toString());
1234         property->setValue(proObj[Core::JsonKey::JSON_NPC_PROPERTY_VALUE].toString());
1235         npc->addProperty(property);
1236     }
1237 
1238     auto shapeArray= obj[Core::JsonKey::JSON_NPC_SHAPES].toArray();
1239     for(auto sha : shapeArray)
1240     {
1241         auto objSha= sha.toObject();
1242         auto shape= new CharacterShape();
1243         shape->setName(objSha[Core::JsonKey::JSON_NPC_SHAPE_NAME].toString());
1244         auto avatarData= QByteArray::fromBase64(objSha[Core::JsonKey::JSON_NPC_SHAPE_DATAIMG].toString().toUtf8());
1245         QImage img= QImage::fromData(avatarData);
1246         shape->setImage(img);
1247         npc->addShape(shape);
1248     }
1249 
1250     return npc;
1251 }
1252 
1253 QJsonObject IOHelper::diceAliasToJSonObject(DiceAlias* alias)
1254 {
1255     QJsonObject aliasJson;
1256     aliasJson[Core::DiceAlias::k_dice_command]= alias->command();
1257     aliasJson[Core::DiceAlias::k_dice_comment]= alias->comment();
1258     aliasJson[Core::DiceAlias::k_dice_pattern]= alias->pattern();
1259     aliasJson[Core::DiceAlias::k_dice_enabled]= alias->isEnable();
1260     aliasJson[Core::DiceAlias::k_dice_replacement]= alias->isReplace();
1261     return aliasJson;
1262 }
1263 
1264 RolisteamTheme* IOHelper::jsonToTheme(const QJsonObject& json)
1265 {
1266     auto theme= new RolisteamTheme();
1267     theme->setName(json["name"].toString());
1268     theme->setRemovable(json["removable"].toBool());
1269     theme->setCss(json["css"].toString());
1270     theme->setBackgroundPosition(json["position"].toInt());
1271     QString bgColorName= json["bgColor"].toString();
1272     QColor color;
1273     color.setNamedColor(bgColorName);
1274     theme->setBackgroundColor(color);
1275 
1276     theme->setBackgroundImage(json["bgPath"].toString());
1277     theme->setStyle(QStyleFactory::create(json["stylename"].toString()));
1278     QColor diceColor;
1279     diceColor.setNamedColor(json["diceHighlight"].toString());
1280     theme->setDiceHighlightColor(diceColor);
1281     QJsonArray colors= json["colors"].toArray();
1282     int i= 0;
1283     auto model= theme->paletteModel();
1284     for(auto const& ref : colors)
1285     {
1286         QJsonObject paletteObject= ref.toObject();
1287         QColor color;
1288         color.setNamedColor(paletteObject["color"].toString());
1289         model->setColor(i, color);
1290         ++i;
1291     }
1292 
1293     return theme;
1294 }
1295 
1296 QJsonObject IOHelper::themeToObject(const RolisteamTheme* theme)
1297 {
1298     QJsonObject json;
1299     json["name"]= theme->getName();
1300     json["removable"]= theme->isRemovable();
1301     json["css"]= theme->getCss();
1302     json["position"]= theme->getBackgroundPosition();
1303     json["bgColor"]= theme->getBackgroundColor().name();
1304     json["diceHighlight"]= theme->getDiceHighlightColor().name();
1305     json["bgPath"]= theme->getBackgroundImage();
1306     json["stylename"]= theme->getStyleName();
1307 
1308     QJsonArray colors;
1309     auto const& data= theme->paletteModel()->data();
1310     for(auto const& tmp : data)
1311     {
1312         QJsonObject paletteObject;
1313         tmp->writeTo(paletteObject);
1314         /*json["role"]= static_cast<int>(tmp->getRole());
1315         json["group"]= static_cast<int>(tmp->getGroup());
1316         json["name"]= tmp->getName();*/
1317         json["color"]= tmp->getColor().name();
1318         colors.append(paletteObject);
1319     }
1320     json["colors"]= colors;
1321     return json;
1322 }
1323 
1324 void IOHelper::writeJsonArrayIntoFile(const QString& destination, const QJsonArray& array)
1325 {
1326     static QMutex mutex;
1327     QMutexLocker locker(&mutex);
1328     QJsonDocument doc;
1329     doc.setArray(array);
1330 
1331     QFile file(destination);
1332     if(file.open(QIODevice::WriteOnly))
1333     {
1334         file.write(doc.toJson(QJsonDocument::Indented));
1335     }
1336 }
1337 
1338 void IOHelper::writeJsonObjectIntoFile(const QString& destination, const QJsonObject& obj)
1339 {
1340     static QMutex mutex;
1341     QMutexLocker locker(&mutex);
1342     QJsonDocument doc;
1343     doc.setObject(obj);
1344 
1345     QFile file(destination);
1346     if(file.open(QIODevice::WriteOnly))
1347     {
1348         file.write(doc.toJson(QJsonDocument::Indented));
1349     }
1350 }
1351 
1352 void IOHelper::readNoteController(NoteController* ctrl, const QByteArray& array)
1353 {
1354     if(!ctrl || array.isEmpty())
1355         return;
1356     auto data= array;
1357     QDataStream input(&data, QIODevice::ReadOnly);
1358 
1359     IOHelper::readBase(ctrl, input);
1360 
1361     QString text;
1362     input >> text;
1363     ctrl->setText(text);
1364 }
1365 
1366 void IOHelper::readSharedNoteController(SharedNoteController* ctrl, const QByteArray& array)
1367 {
1368     if(!ctrl || array.isEmpty())
1369         return;
1370     auto data= array;
1371     QDataStream input(&data, QIODevice::ReadOnly);
1372 
1373     IOHelper::readBase(ctrl, input);
1374 
1375     /*ParticipantModel::Permission perm;
1376     input >> perm;*/
1377 
1378     QString text;
1379     input >> text;
1380 
1381     SharedNoteController::HighlightedSyntax syntax;
1382     input >> syntax;
1383 
1384     bool b;
1385     input >> b;
1386 
1387     ctrl->setMarkdownVisible(b);
1388     ctrl->setText(text);
1389     ctrl->setHighligthedSyntax(syntax);
1390     // ctrl->setPermission(perm);
1391 }
1392 
1393 QUrl IOHelper::findSong(const QString& name, QStringList list)
1394 {
1395     QUrl url(name, QUrl::StrictMode);
1396     if(!url.scheme().isEmpty())
1397     {
1398         return url;
1399     }
1400     else
1401     {
1402         for(auto const& path : list)
1403         {
1404             QFileInfo info(QString("%1/%2").arg(path, name));
1405             if(info.exists())
1406                 return QUrl::fromLocalFile(info.absoluteFilePath());
1407         }
1408     }
1409 
1410     return {};
1411 }
1412 // QHash<QString, std::map<QString, QVariant>>