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