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

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/modelhelper.h"
0021 
0022 #include <QApplication>
0023 #include <QBuffer>
0024 #include <QDebug>
0025 #include <QFileInfo>
0026 #include <QFontDatabase>
0027 #include <QJsonDocument>
0028 #include <QMessageBox>
0029 #include <QSettings>
0030 #include <QUuid>
0031 
0032 #include "charactersheet/charactersheetmodel.h"
0033 #include "charactersheet/imagemodel.h"
0034 #include "controller/audiocontroller.h"
0035 #include "controller/contentcontroller.h"
0036 #include "data/campaign.h"
0037 #include "data/media.h"
0038 #include "diceparser/dicealias.h"
0039 #include "media/mediatype.h"
0040 #include "model/characterstatemodel.h"
0041 #include "model/contentmodel.h"
0042 #include "model/dicealiasmodel.h"
0043 #include "model/historymodel.h"
0044 #include "model/musicmodel.h"
0045 #include "model/nonplayablecharactermodel.h"
0046 #include "model/profilemodel.h"
0047 #include "network/connectionprofile.h"
0048 #include "worker/fileserializer.h"
0049 #include "worker/iohelper.h"
0050 
0051 namespace SettingsHelper
0052 {
0053 constexpr char const* rolisteam{"rolisteam"};
0054 constexpr char const* historyGroup{"History"};
0055 constexpr char const* historyArray{"HistoryArray"};
0056 constexpr char const* historyCapacity{"HistoryMaxCapacity"};
0057 
0058 constexpr char const* hist_key_id{"id"};
0059 constexpr char const* hist_key_displayName{"displayName"};
0060 constexpr char const* hist_key_path{"path"};
0061 constexpr char const* hist_key_lastaccess{"access"};
0062 constexpr char const* hist_key_bookmark{"bookmark"};
0063 constexpr char const* hist_key_type{"type"};
0064 
0065 const static QStringList CharacterFields({"CharacterHp", "CharacterMaxHp", "CharacterMinHp", "CharacterDistPerTurn",
0066                                           "CharacterStateId", "CharacterLifeColor", "CharacterInitCmd","CharacterInit"
0067                                           "CharacterHasInit"});
0068 
0069 namespace profiles
0070 {
0071 constexpr auto const* groupName{"ConnectionProfiles"};
0072 constexpr auto const* arrayName{"ConnectionProfilesArray"};
0073 constexpr auto const* address{"address"};
0074 constexpr auto const* name{"name"};
0075 constexpr auto const* title{"title"};
0076 constexpr auto const* playerId{"playerId"};
0077 constexpr auto const* port{"port"};
0078 constexpr auto const* server{"server"};
0079 constexpr auto const* gm{"gm"};
0080 constexpr auto const* campaignPath{"campaignPath"};
0081 constexpr auto const* password{"password"};
0082 constexpr auto const* playerColor{"PlayerColor"};
0083 constexpr auto const* playerAvatar{"playerAvatarData"};
0084 constexpr auto const* characterCount{"characterCount"};
0085 constexpr auto const* characterName{"CharacterName"};
0086 constexpr auto const* characterId{"CharacterId"};
0087 constexpr auto const* characterData{"CharacterData"};
0088 constexpr auto const* characterColor{"CharacterColor"};
0089 } // namespace profiles
0090 
0091 void readConnectionProfileModel(ProfileModel* model)
0092 {
0093 #ifdef QT_DEBUG
0094     QSettings settings(QString("bla_%1").arg(QDate::currentDate().toString("MM-YYYY")),
0095                        QString("bla_%1").arg(QDate::currentDate().toString("MM-YYYY")));
0096 #else
0097     QSettings settings(rolisteam, rolisteam);
0098 #endif
0099     settings.beginGroup(profiles::groupName);
0100     int size= settings.beginReadArray(profiles::arrayName);
0101     for(int i= 0; i < size; ++i)
0102     {
0103         settings.setArrayIndex(i);
0104         ConnectionProfile* profile= new ConnectionProfile();
0105         profile->setAddress(settings.value(profiles::address).toString());
0106         profile->setPlayerName(settings.value(profiles::name).toString());
0107         profile->setProfileTitle(settings.value(profiles::title).toString());
0108         profile->setPlayerId(
0109             settings.value(profiles::playerId, QUuid::createUuid().toString(QUuid::WithoutBraces)).toString());
0110         profile->setPort(static_cast<quint16>(settings.value(profiles::port).toInt()));
0111         profile->setServerMode(settings.value(profiles::server).toBool());
0112         profile->setGm(settings.value(profiles::gm).toBool());
0113         profile->setCampaignPath(settings.value(profiles::campaignPath).toString());
0114         profile->setHash(QByteArray::fromBase64(settings.value(profiles::password).toByteArray()));
0115 
0116         QColor color= settings.value(profiles::playerColor).value<QColor>();
0117         profile->setPlayerColor(color);
0118         profile->setPlayerAvatar(settings.value(profiles::playerAvatar).toByteArray());
0119 
0120         auto characterCount= settings.beginReadArray(profiles::characterCount);
0121         profile->clearCharacter();
0122         for(int j= 0; j < characterCount; ++j)
0123         {
0124             settings.setArrayIndex(j);
0125 
0126             auto uuid= settings.value(profiles::characterId, QUuid::createUuid().toString()).toString();
0127             auto name= settings.value(profiles::characterName).toString();
0128             auto path= settings.value(profiles::characterData).toByteArray();
0129             auto color= settings.value(profiles::characterColor).value<QColor>();
0130             QHash<QString, QVariant> params;
0131             for(const auto& key : CharacterFields)
0132             {
0133                 params.insert(key, settings.value(key));
0134             }
0135             profile->addCharacter(connection::CharacterData({uuid, name, color, path, params}));
0136         }
0137         settings.endArray();
0138 
0139         if(characterCount == 0 && !profile->isGM())
0140         {
0141             auto uuid= settings.value(profiles::characterId, QUuid::createUuid().toString()).toString();
0142             auto name= settings.value(profiles::characterName).toString();
0143             auto path= settings.value(profiles::characterData).toByteArray();
0144             auto color= settings.value(profiles::characterColor).value<QColor>();
0145 
0146             QHash<QString, QVariant> params;
0147             profile->addCharacter(connection::CharacterData({uuid, name, color, path, params}));
0148         }
0149         model->appendProfile(profile);
0150     }
0151     settings.endArray();
0152     settings.endGroup();
0153 
0154     if(size == 0)
0155     {
0156         ConnectionProfile* profile= new ConnectionProfile();
0157         model->appendProfile(profile);
0158     }
0159 }
0160 
0161 void writeConnectionProfileModel(ProfileModel* model)
0162 {
0163 #ifdef QT_DEBUG
0164     QSettings settings(QString("bla_%1").arg(QDate::currentDate().toString("MM-YYYY")),
0165                        QString("bla_%1").arg(QDate::currentDate().toString("MM-YYYY")));
0166 #else
0167     QSettings settings(rolisteam, rolisteam);
0168 #endif
0169     settings.beginGroup(profiles::groupName);
0170 
0171     auto size= model->rowCount(QModelIndex());
0172     settings.beginWriteArray(profiles::arrayName, size);
0173     for(int i= 0; i < size; ++i)
0174     {
0175         auto profile= model->getProfile(i);
0176 
0177         if(nullptr == profile)
0178             continue;
0179 
0180         settings.setArrayIndex(i);
0181 
0182         settings.setValue(profiles::address, profile->address());
0183         settings.setValue(profiles::name, profile->playerName());
0184         settings.setValue(profiles::title, profile->profileTitle());
0185         settings.setValue(profiles::server, profile->isServer());
0186         settings.setValue(profiles::port, profile->port());
0187         settings.setValue(profiles::playerId, profile->playerId());
0188         settings.setValue(profiles::gm, profile->isGM());
0189         settings.setValue(profiles::password, profile->password().toBase64());
0190         settings.setValue(profiles::playerColor, profile->playerColor());
0191         settings.setValue(profiles::playerAvatar, profile->playerAvatar());
0192         settings.setValue(profiles::campaignPath, profile->campaignPath());
0193 
0194         settings.beginWriteArray(profiles::characterCount);
0195         for(int j= 0; j < profile->characterCount(); ++j)
0196         {
0197             settings.setArrayIndex(j);
0198             auto charact= profile->character(j);
0199 
0200             settings.setValue(profiles::characterId, charact.m_uuid);
0201             settings.setValue(profiles::characterName, charact.m_name);
0202             settings.setValue(profiles::characterData, charact.m_avatarData);
0203             settings.setValue(profiles::characterColor, charact.m_color);
0204 
0205             for(const auto& key : CharacterFields)
0206             {
0207                 settings.setValue(key, charact.m_params[key]);
0208             }
0209         }
0210         settings.endArray();
0211     }
0212     settings.endArray();
0213     settings.endGroup();
0214 }
0215 
0216 void readHistoryModel(history::HistoryModel* model)
0217 {
0218     QSettings settings(rolisteam, rolisteam);
0219     settings.beginGroup(historyGroup);
0220     model->setMaxCapacity(settings.value(historyCapacity, 15).toInt());
0221     int size= settings.beginReadArray(historyArray);
0222     QList<history::LinkInfo> infos;
0223     for(int i= 0; i < size; ++i)
0224     {
0225         settings.setArrayIndex(i);
0226         history::LinkInfo info{settings.value(hist_key_id).toString(),
0227                                settings.value(hist_key_displayName).toString(),
0228                                settings.value(hist_key_path).toUrl(),
0229                                static_cast<Core::ContentType>(settings.value(hist_key_type).toInt()),
0230                                settings.value(hist_key_lastaccess).toDateTime(),
0231                                settings.value(hist_key_bookmark).toBool()};
0232 
0233         infos << info;
0234     }
0235     model->setLinks(infos);
0236 }
0237 
0238 void writeHistoryModel(history::HistoryModel* model)
0239 {
0240     QSettings settings(rolisteam, rolisteam);
0241     settings.beginGroup(historyGroup);
0242     settings.setValue(historyCapacity, model->maxCapacity());
0243     auto const& links= model->data();
0244 
0245     settings.beginWriteArray(historyArray, links.size());
0246     int i= 0;
0247     for(auto const& info : links)
0248     {
0249         settings.setArrayIndex(i);
0250         settings.setValue(hist_key_id, info.id);
0251         settings.setValue(hist_key_displayName, info.displayName);
0252         settings.setValue(hist_key_path, info.url);
0253         settings.setValue(hist_key_lastaccess, info.lastAccess);
0254         settings.setValue(hist_key_bookmark, info.bookmarked);
0255         settings.setValue(hist_key_type, static_cast<int>(info.type));
0256         ++i;
0257     }
0258     settings.endArray();
0259     settings.endGroup();
0260 }
0261 } // namespace SettingsHelper
0262 
0263 namespace ModelHelper
0264 {
0265 
0266 bool saveSession(const ContentController* ctrl)
0267 {
0268     auto model= ctrl->contentModel();
0269     if(model == nullptr)
0270         return false;
0271 
0272     auto ctrls= model->controllers();
0273 
0274     for(auto ctrl : ctrls)
0275     {
0276         if(nullptr == ctrl)
0277             continue;
0278 
0279         campaign::FileSerializer::writeFileIntoCampaign(ctrl->url().toLocalFile(), IOHelper::saveController(ctrl));
0280     }
0281     return true;
0282 }
0283 
0284 bool saveAudioController(const AudioController* ctrl)
0285 {
0286     // TODO
0287     return false;
0288 }
0289 
0290 bool saveCharacterSheet(const QString& path, const CharacterSheetModel* model)
0291 {
0292     // TODO ??
0293     return false;
0294 }
0295 
0296 bool loadCharacterSheet(const QString& path, CharacterSheetModel* model, charactersheet::ImageModel* imgModel,
0297                         QJsonObject& root, QString& qmlCode)
0298 {
0299     if(path.isEmpty())
0300         return false;
0301 
0302     QFile file(path);
0303     if(!file.open(QIODevice::ReadOnly))
0304     {
0305         return false;
0306     }
0307 
0308     QJsonDocument json= QJsonDocument::fromJson(file.readAll());
0309     QJsonObject jsonObj= json.object();
0310 
0311     root= jsonObj["data"].toObject();
0312 
0313     qmlCode= jsonObj["qml"].toString();
0314 
0315     QJsonArray images= jsonObj["background"].toArray();
0316 
0317     for(auto jsonpix : images)
0318     {
0319         QJsonObject obj= jsonpix.toObject();
0320         QString str= obj["bin"].toString();
0321         QString key= obj["key"].toString();
0322         QString filename= obj["filename"].toString();
0323         bool isBg= obj["isBg"].toBool();
0324         QByteArray array= QByteArray::fromBase64(str.toUtf8());
0325         QPixmap pix;
0326         pix.loadFromData(array);
0327         imgModel->insertImage(pix, key, filename, isBg);
0328     }
0329 
0330     const auto fonts= jsonObj["fonts"].toArray();
0331     for(const auto& obj : fonts)
0332     {
0333         const auto font= obj.toObject();
0334         const auto fontData= QByteArray::fromBase64(font["data"].toString("").toLatin1());
0335         QFontDatabase::addApplicationFontFromData(fontData);
0336     }
0337 
0338     // m_errorList.clear();
0339     model->readModel(jsonObj, true);
0340     // displayError(m_errorList);
0341     return true;
0342 }
0343 void fetchCharacterStateModel(const QJsonArray& obj, CharacterStateModel* model)
0344 {
0345     for(const auto& stateRef : obj)
0346     {
0347         auto state= stateRef.toObject();
0348         CharacterState da;
0349         da.setId(state["id"].toString());
0350         da.setLabel(state["label"].toString());
0351         auto base64= state["image"].toString();
0352         da.setImagePath(base64);
0353         QColor col;
0354         col.setNamedColor(state["color"].toString());
0355         da.setColor(col);
0356         model->appendState(std::move(da));
0357     }
0358 }
0359 
0360 QJsonArray saveCharacterStateModel(CharacterStateModel* model)
0361 {
0362     QJsonArray states;
0363     auto const& statesList= model->statesList();
0364     for(auto const& stateInfo : statesList)
0365     {
0366         QJsonObject stateObj;
0367         stateObj["label"]= stateInfo->label();
0368         stateObj["color"]= stateInfo->color().name();
0369         QPixmap pix= stateInfo->imagePath();
0370         if(!pix.isNull())
0371         {
0372             QByteArray bytes;
0373             QBuffer buffer(&bytes);
0374             buffer.open(QIODevice::WriteOnly);
0375             pix.save(&buffer, "PNG");
0376             stateObj["image"]= QString(buffer.data().toBase64());
0377         }
0378         states.append(stateObj);
0379     }
0380     return states;
0381 }
0382 
0383 void fetchDiceModel(const QJsonArray& dice, DiceAliasModel* model)
0384 {
0385     for(const auto& obj : dice)
0386     {
0387         auto diceCmd= obj.toObject();
0388 
0389         DiceAlias alias(
0390             diceCmd[Core::DiceAlias::k_dice_pattern].toString(), diceCmd[Core::DiceAlias::k_dice_command].toString(),
0391             diceCmd[Core::DiceAlias::k_dice_comment].toString(), diceCmd[Core::DiceAlias::k_dice_replacement].toBool(),
0392             diceCmd[Core::DiceAlias::k_dice_enabled].toBool());
0393 
0394         model->appendAlias(std::move(alias));
0395     }
0396 }
0397 
0398 void fetchMedia(const QJsonArray& medias, campaign::Campaign* campaign)
0399 {
0400     for(const auto& ref : medias)
0401     {
0402         auto const& obj= ref.toObject();
0403         auto mediaRoot= campaign->directory(campaign::Campaign::Place::MEDIA_ROOT);
0404         auto id= obj[Core::JsonKey::JSON_MEDIA_ID].toString();
0405         auto path= QString("%1/%2").arg(mediaRoot, obj[Core::JsonKey::JSON_MEDIA_PATH].toString());
0406         auto time= QDateTime::fromString(obj[Core::JsonKey::JSON_MEDIA_CREATIONTIME].toString(), Qt::ISODate);
0407         auto type= campaign::FileSerializer::typeFromExtention(path);
0408         QFileInfo info(path);
0409         auto name= info.baseName();
0410 
0411         std::unique_ptr<campaign::Media> media(new campaign::Media(id, name, path, type, time));
0412         campaign->addMedia(std::move(media));
0413     }
0414 }
0415 
0416 void fetchNpcModel(const QJsonArray& npc, campaign::NonPlayableCharacterModel* model, const QString& rootDir)
0417 {
0418     std::vector<campaign::NonPlayableCharacter*> vec;
0419     for(const auto& obj : npc)
0420     {
0421         auto npcObj= obj.toObject();
0422 
0423         auto npc= IOHelper::jsonObjectToNpc(npcObj, rootDir);
0424         vec.push_back(npc);
0425     }
0426     model->setModelData(vec);
0427 }
0428 
0429 void fetchMusicModelWithTableTop(MusicModel* model)
0430 {
0431     QString url= QStringLiteral("http://tabletopaudio.com/download.php?downld_file=%1");
0432     static QStringList list({QStringLiteral("1_The_Inner_Core.mp3"),
0433                              QStringLiteral("2_Bubbling_Pools.mp3"),
0434                              QStringLiteral("3_The_March_of_the_Faithful.mp3"),
0435                              QStringLiteral("4_Solemn_Vow-a.mp3"),
0436                              QStringLiteral("5_Desert_Bazaar.mp3"),
0437                              QStringLiteral("6_Abyssal_Gaze.mp3"),
0438                              QStringLiteral("7_The_Desert_Awaits.mp3"),
0439                              QStringLiteral("8_New_Dust_to_Dust.mp3"),
0440                              QStringLiteral("9_Before_The_Storm.mp3"),
0441                              QStringLiteral("10_In_The_Shadows.mp3"),
0442                              QStringLiteral("11_Shelter_from_the_Storm.mp3"),
0443                              QStringLiteral("12_Disembodied_Spirits.mp3"),
0444                              QStringLiteral("13_Cave_of_Time.mp3"),
0445                              QStringLiteral("14_Protean_Fields.mp3"),
0446                              QStringLiteral("15_Alien_Machine_Shop.mp3"),
0447                              QStringLiteral("16_Busy_Space_Port.mp3"),
0448                              QStringLiteral("17_Alien_Night_Club.mp3"),
0449                              QStringLiteral("18_House_on_the_Hill.mp3"),
0450                              QStringLiteral("19_Age_of_Sail.mp3"),
0451                              QStringLiteral("20_Dark_Continent_aa.mp3"),
0452                              QStringLiteral("21_Derelict_Freighter.mp3"),
0453                              QStringLiteral("22_True_West_a.mp3"),
0454                              QStringLiteral("23_The_Slaughtered_Ox.mp3"),
0455                              QStringLiteral("24_Forbidden_Galaxy.mp3"),
0456                              QStringLiteral("25_Deep_Space_EVA.mp3"),
0457                              QStringLiteral("26_Uncommon_Valor_a.mp3"),
0458                              QStringLiteral("27_Xingu_Nights.mp3"),
0459                              QStringLiteral("28_Nephilim_Labs_FE.mp3"),
0460                              QStringLiteral("29_Kaltoran_Craft_FE.mp3"),
0461                              QStringLiteral("30_Los_Vangeles_3030.mp3"),
0462                              QStringLiteral("31_Frozen_Wastes.mp3"),
0463                              QStringLiteral("32_City_and_the_City.mp3"),
0464                              QStringLiteral("33_Far_Above_the_World.mp3"),
0465                              QStringLiteral("34_Clash_of_Kings.mp3"),
0466                              QStringLiteral("35_Swamplandia.mp3"),
0467                              QStringLiteral("36_Down_by_the_Sea.mp3"),
0468                              QStringLiteral("37_Catacombs.mp3"),
0469                              QStringLiteral("38_Into_the_Deep.mp3"),
0470                              QStringLiteral("39_Temple_of_the_Eye.mp3"),
0471                              QStringLiteral("40_The_Long_Rain.mp3"),
0472                              QStringLiteral("41_Starship_Bridge.mp3"),
0473                              QStringLiteral("42_Rise_of_the_Ancients.mp3"),
0474                              QStringLiteral("43_Dome_City_Center.mp3"),
0475                              QStringLiteral("44_Victorian_London.mp3"),
0476                              QStringLiteral("45_Samurai_HQ.mp3"),
0477                              QStringLiteral("46_Cathedral.mp3"),
0478                              QStringLiteral("47_There_be_Dragons.mp3"),
0479                              QStringLiteral("48_Overland_with_Oxen.mp3"),
0480                              QStringLiteral("49_Goblin's_Cave.mp3"),
0481                              QStringLiteral("50_Super_Hero.mp3"),
0482                              QStringLiteral("51_Woodland_Campsite.mp3"),
0483                              QStringLiteral("52_Warehouse_13.mp3"),
0484                              QStringLiteral("53_Strangers_on_a_Train.mp3"),
0485                              QStringLiteral("54_Mountain_Tavern.mp3"),
0486                              QStringLiteral("55_Ice_Cavern.mp3"),
0487                              QStringLiteral("56_Medieval_Town.mp3"),
0488                              QStringLiteral("57_Colosseum.mp3"),
0489                              QStringLiteral("58_Terror.mp3"),
0490                              QStringLiteral("59_Dinotopia.mp3"),
0491                              QStringLiteral("60_Dark_and_Stormy.mp3"),
0492                              QStringLiteral("61_Orbital_Platform.mp3"),
0493                              QStringLiteral("62_Middle_Earth_Dawn.mp3"),
0494                              QStringLiteral("63_Industrial_Shipyard.mp3"),
0495                              QStringLiteral("64_Mountain_Pass.mp3"),
0496                              QStringLiteral("65_Dungeon_I.mp3"),
0497                              QStringLiteral("66_Royal_Salon.mp3"),
0498                              QStringLiteral("67_Asylum.mp3"),
0499                              QStringLiteral("68_1940s_Office.mp3"),
0500                              QStringLiteral("69_Forest_Night.mp3"),
0501                              QStringLiteral("70_Age_of_Steam.mp3")});
0502 
0503     QList<QUrl> urls;
0504 
0505     for(auto const& song : qAsConst(list))
0506     {
0507         urls.append(QUrl::fromUserInput(url.arg(song)));
0508     }
0509 
0510     model->addSong(urls);
0511 }
0512 
0513 } // namespace ModelHelper