From 1b85cda62682d084ea7bc335713131334955d497 Mon Sep 17 00:00:00 2001 From: Al12rs Date: Sun, 4 Mar 2018 11:59:18 +0100 Subject: [PATCH 01/57] Added open logs folder to open folder toolbar dropdown. --- src/mainwindow.cpp | 25 +++++++++++++++++++++---- src/mainwindow.h | 1 + 2 files changed, 22 insertions(+), 4 deletions(-) diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index fe93b5467..71df8acfb 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -3035,6 +3035,12 @@ void MainWindow::openInstanceFolder() ::ShellExecuteW(nullptr, L"explore", ToWString(m_OrganizerCore.settings().getBaseDirectory()).c_str(), nullptr, nullptr, SW_SHOWNORMAL); } +void MainWindow::openLogsFolder() +{ + QString logsPath = qApp->property("dataPath").toString() + "/" + QString::fromStdWString(AppConfig::logPath()); + ::ShellExecuteW(nullptr, L"explore", ToWString(logsPath).c_str(), nullptr, nullptr, SW_SHOWNORMAL); +} + void MainWindow::openInstallFolder() { ::ShellExecuteW(nullptr, L"explore", ToWString(qApp->applicationDirPath()).c_str(), nullptr, nullptr, SW_SHOWNORMAL); @@ -3231,6 +3237,11 @@ QMenu *MainWindow::openFolderMenu() QMenu *FolderMenu = new QMenu(this); + FolderMenu->addAction(tr("Open Game folder"), this, SLOT(openGameFolder())); + + FolderMenu->addAction(tr("Open MyGames folder"), this, SLOT(openMyGamesFolder())); + + FolderMenu->addSeparator(); FolderMenu->addAction(tr("Open Instance folder"), this, SLOT(openInstanceFolder())); @@ -3238,13 +3249,19 @@ QMenu *MainWindow::openFolderMenu() FolderMenu->addAction(tr("Open Downloads folder"), this, SLOT(openDownloadsFolder())); - FolderMenu->addAction(tr("Open MO Install folder"), this, SLOT(openInstallFolder())); - FolderMenu->addSeparator(); - FolderMenu->addAction(tr("Open Game folder"), this, SLOT(openGameFolder())); + FolderMenu->addAction(tr("Open MO2 Install folder"), this, SLOT(openInstallFolder())); - FolderMenu->addAction(tr("Open MyGames folder"), this, SLOT(openMyGamesFolder())); + FolderMenu->addAction(tr("Open MO2 Logs folder"), this, SLOT(openLogsFolder())); + + + + + + + + return FolderMenu; diff --git a/src/mainwindow.h b/src/mainwindow.h index 2c2e27237..f84931caa 100644 --- a/src/mainwindow.h +++ b/src/mainwindow.h @@ -487,6 +487,7 @@ private slots: void disableVisibleMods(); void exportModListCSV(); void openInstanceFolder(); + void openLogsFolder(); void openInstallFolder(); void openDownloadsFolder(); void openProfileFolder(); From a873f7cfe2581716fd908062831d5d5c8f56392f Mon Sep 17 00:00:00 2001 From: Al12rs Date: Sun, 4 Mar 2018 12:52:28 +0100 Subject: [PATCH 02/57] Removed "Repace category" menu option from the modlist as it was redundant and cluttering the menu. --- src/mainwindow.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 71df8acfb..eb612b6b5 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -3326,10 +3326,13 @@ void MainWindow::on_modList_customContextMenuRequested(const QPoint &pos) connect(addRemoveCategoriesMenu, SIGNAL(aboutToHide()), this, SLOT(addRemoveCategories_MenuHandler())); addMenuAsPushButton(menu, addRemoveCategoriesMenu); + //Removed as it was redundant, just making the categories look more complicated. + /* QMenu *replaceCategoriesMenu = new QMenu(tr("Replace Categories")); populateMenuCategories(replaceCategoriesMenu, 0); connect(replaceCategoriesMenu, SIGNAL(aboutToHide()), this, SLOT(replaceCategories_MenuHandler())); addMenuAsPushButton(menu, replaceCategoriesMenu); + */ QMenu *primaryCategoryMenu = new QMenu(tr("Primary Category")); connect(primaryCategoryMenu, SIGNAL(aboutToShow()), this, SLOT(addPrimaryCategoryCandidates())); From 7cf0c1a29b463885e37a49691daffb98afdf58db Mon Sep 17 00:00:00 2001 From: Al12rs Date: Sun, 4 Mar 2018 19:12:52 +0100 Subject: [PATCH 03/57] Changed tooltip of Open Folder menu. --- src/mainwindow.ui | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mainwindow.ui b/src/mainwindow.ui index 31522c03d..451e3c871 100644 --- a/src/mainwindow.ui +++ b/src/mainwindow.ui @@ -253,7 +253,7 @@ p, li { white-space: pre-wrap; } - Quickly open in Explorer relevant Folders... + Show Open Folders menu... From 513c0629323c066a7b1d5df5ce81f3b9beac85bd Mon Sep 17 00:00:00 2001 From: Al12rs Date: Mon, 5 Mar 2018 15:16:55 +0100 Subject: [PATCH 04/57] Inverted position of reinstall and remove mod, as per user request. --- src/mainwindow.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index eb612b6b5..ddd7ef92f 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -3352,8 +3352,8 @@ void MainWindow::on_modList_customContextMenuRequested(const QPoint &pos) menu->addSeparator(); menu->addAction(tr("Rename Mod..."), this, SLOT(renameMod_clicked())); - menu->addAction(tr("Remove Mod..."), this, SLOT(removeMod_clicked())); menu->addAction(tr("Reinstall Mod"), this, SLOT(reinstallMod_clicked())); + menu->addAction(tr("Remove Mod..."), this, SLOT(removeMod_clicked())); menu->addSeparator(); From 52501e73c9c205c08b1a8a288c88b5c3362a1381 Mon Sep 17 00:00:00 2001 From: Al12rs Date: Sun, 4 Mar 2018 21:05:31 +0100 Subject: [PATCH 05/57] Updated Open Folder icon as it was not very distinguishable. --- src/resources/open-Folder-Icon.png | Bin 17646 -> 16927 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/src/resources/open-Folder-Icon.png b/src/resources/open-Folder-Icon.png index 345671f754d2e201d4c512c6e0edb140e35b2e20..c363be0fdef80bc854db9df8126941461e394d10 100644 GIT binary patch delta 1604 zcma)6eQXnD82{b1z23E5S30`2Y>agqWFqH!+qG-=5yspyG?A$B1JDGvZi^^FOo)FV zW(b7D#6--Q_=hG2KUj>0_z^!sOau`$5#%H49Ak4E&=vN@y7jvDdOhE}8Up|EUh?Ms z_&vYp`906`-t3#yhli*mVLEc{tHzMYRnG^+rv$OFuAwm?@PVMT-z3`Z97d#5rpVn} ztND=hfyGzdC5pXKF<8$>qalH>4~gA;IM@^ByQ6&#Jz_8r>FTMMhAbV`VjvufGzfjX z(AQhX3qo(04+o-AzAG3C)CoOeh}cSP%=$H5U0r=qQ3&!vq_2mML`0DfclU~XZ!$l+KZ+A?BV;9V#<77-y1iN2&{Eb<h5qToL}x)UGBCrS zcyO~^P~+y*l40a5Dy(I5a0-{eq+GDZ`qz4jKH94Ki6-WmQNviD3}!0}D2WtCuBQQO zo_Q&u!F5JK@!36#OID5>WWN10^Hag+RL)djv-);CbW&)n*gOKtJ`eu2f8cU+7(cf9 zUSfF`xG>c{))3j)U!F=$EBbYInMKQdp<1&Gr)KFLZ#gS+ zb7@c}qL_>&QjS0!P}fQV$QnnaFjI)=vgc)Oyl%GCEh=A>G;uIFB(82 zWU~?@n=_C;=p%hm3zkWcmh-hL3I(r+)X=9QL)N5+05%KXIyYWn)-)b{{qXH=2lu)R z5(hhrxyvamE|p{7z9dr9IYP3kQI9bnr|wY8F=$@D0IQSsp8KOpKg#!z!=A>!@hbQ{ zHwo%bP-&K!^EHN7z3$Eo1~09ISodt+fVC>PFxR&vRNWZH>9^$d{I)2>Rw!*x|U@4N+x+2p*x^w!@7c05)Hhuex8e+)`mmHchN zYKFXoYcUVxggmlt<$T`v(6|Q?FL`(FTR_Za0KuhkJyr}gEuSxRWb(lAco8}sW8~p2 zf~F{&d5Jz6>}aJpK_z5;5T4y0XgD%LrbvQq$DsgPHSd0``yf3K^~}N zS(KMJk-NPbO2(v1DJ4oQGZbcSS>;OKHQ8dJ@(Hi0nkPgZWvTh>n743_NYCX-Ts9RG zaWCT2jP7ZrM}=r9(wg|j z7(!xH#7yEp<0J8x0x84@m`FeckwhXQSP^Np(z;Ok-tO+~%y?$DR096sWbfX+_kQO) z-+AnZyUEQr$v%;)JJcKW(K!Myh?`uVAbz|;Rjo^Uo%Yx=m+qj~6ZDAE*L2{H8^Y`k z@7UVa)78DTYe%rPxp~9Ru8wWbM(evDUE8#zb#=4P74Z3Zq1shf^S?ODl3P~y-+N0} z`1#K0_MTPS!_n@ZuASY|3D!Y3wLdLwF&FanFLdsxj%EPQ# zkuWcKLt?z4de;M;#_MxQqoW`lFQmEiZ?qJk0`OyVrS9m zvJDFclw7FG=Ip)o`)c0Oopm#m0TO_Q%(&@GKkB<5pyfXXw`N3R!YE%VvS_Rv@ zEU;$TflZr9`BP=P7A-hm@J)$h5ol~0-7-dHHk6f+DH$WBW*7d3cv=BcY`zqCF!t|W z9{BjmfuSc(we*p1doLd!zH&ojGzRDi6V$G(hGpgDK*@TwGG<7g7#at4e&xl7-&w!3 zGm)516GFgAThxV)E8K}Q$A)k0(Jb)DEgyjC-P27}Cs`x=wJ$}#n^F?^#t~p?(;UcP zE-foOb^kN3R+{J8@nI70^m5psIVpqVwF`sNiJ)_rDrv{oeAP&qO*VX|!J3_i6&aah zBATYbU#B*!CB9k$Gs(<@rWX|rIY(my(0BHlN@x~Pxo*^vi9z*~{48okZV|AG30Nv4 zZOSnPUsN76P=-Xh%QQwnzKBjs0n$HVw`Q5Ki&nD?VvCiUyJKn425nU3^)WCd`anTt zW(xz;<8e3$L9(`xz|mn149Wj|zZ|Qokl)T00hm@`b&`OoV9xn1Dmu~>rJoJGw}0t( z`fYi`M$RT!Yw;7Yts5L|n7c!33uvnVP|75S@e&)a0nr6hu$m(LqI3Adxf!mz{-hJu{p|B5ka%uF|IjP~rIS zRI&hFjW9A! Date: Sun, 4 Mar 2018 19:12:06 +0100 Subject: [PATCH 06/57] Edited "Add/Remove category" menu entry text to "Change Category". --- src/mainwindow.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index ddd7ef92f..f5be22f05 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -3321,7 +3321,7 @@ void MainWindow::on_modList_customContextMenuRequested(const QPoint &pos) } else if (std::find(flags.begin(), flags.end(), ModInfo::FLAG_FOREIGN) != flags.end()) { // nop, nothing to do with this mod } else { - QMenu *addRemoveCategoriesMenu = new QMenu(tr("Add/Remove Categories")); + QMenu *addRemoveCategoriesMenu = new QMenu(tr("Change Categories")); populateMenuCategories(addRemoveCategoriesMenu, 0); connect(addRemoveCategoriesMenu, SIGNAL(aboutToHide()), this, SLOT(addRemoveCategories_MenuHandler())); addMenuAsPushButton(menu, addRemoveCategoriesMenu); From 673a5034f0eb9fb12befdbb52ea8dd5d72ac302e Mon Sep 17 00:00:00 2001 From: Al12rs Date: Wed, 7 Mar 2018 13:49:25 +0100 Subject: [PATCH 07/57] Added check for mod rename to ensure the new name is not already used by another mod. --- src/modlist.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/modlist.cpp b/src/modlist.cpp index 4002a424b..7b2ad1f94 100644 --- a/src/modlist.cpp +++ b/src/modlist.cpp @@ -424,6 +424,11 @@ bool ModList::renameMod(int index, const QString &newName) return false; } + if (ModList::allMods().contains(newName,Qt::CaseInsensitive)) { + MessageDialog::showMessage(tr("Name is already in use by another mod"), nullptr); + return false; + } + ModInfo::Ptr modInfo = ModInfo::getByIndex(index); QString oldName = modInfo->name(); if (newName != oldName) { From c7f660e061f92901b80558c2bfe7640944fc1840 Mon Sep 17 00:00:00 2001 From: Jeremy Rimpo Date: Thu, 8 Mar 2018 15:55:24 -0600 Subject: [PATCH 08/57] Remove outdated namespacing and correct the PATH setting to appends dlls --- src/categories.cpp | 2 +- src/categories.h | 2 +- src/main.cpp | 10 +++++----- src/mainwindow.cpp | 10 +++++----- 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/categories.cpp b/src/categories.cpp index d8cd49fbb..4d89eff97 100644 --- a/src/categories.cpp +++ b/src/categories.cpp @@ -167,7 +167,7 @@ void CategoryFactory::saveCategories() } -unsigned int CategoryFactory::countCategories(std::tr1::function filter) +unsigned int CategoryFactory::countCategories(std::function filter) { unsigned int result = 0; for (const Category &cat : m_Categories) { diff --git a/src/categories.h b/src/categories.h index 66299c307..474a14400 100644 --- a/src/categories.h +++ b/src/categories.h @@ -99,7 +99,7 @@ class CategoryFactory { * @param filter the filter to test * @return number of matching categories */ - unsigned int countCategories(std::tr1::function filter); + unsigned int countCategories(std::function filter); /** * @brief get the id of the parent category diff --git a/src/main.cpp b/src/main.cpp index 935b7404c..0464ca9a3 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -402,6 +402,8 @@ void setupPath() qDebug("MO at: %s", qPrintable(QDir::toNativeSeparators( QCoreApplication::applicationDirPath()))); + QCoreApplication::setLibraryPaths(QStringList(QCoreApplication::applicationDirPath() + "/dlls") + QCoreApplication::libraryPaths()); + boost::scoped_array oldPath(new TCHAR[BUFSIZE]); DWORD offset = ::GetEnvironmentVariable(TEXT("PATH"), oldPath.get(), BUFSIZE); if (offset > BUFSIZE) { @@ -409,12 +411,10 @@ void setupPath() ::GetEnvironmentVariable(TEXT("PATH"), oldPath.get(), offset); } - std::wstring newPath(oldPath.get()); + std::wstring newPath(ToWString(QDir::toNativeSeparators( + QCoreApplication::applicationDirPath())) + L"\\dlls"); newPath += L";"; - newPath += ToWString(QDir::toNativeSeparators( - QCoreApplication::applicationDirPath())) - .c_str(); - newPath += L"\\dlls"; + newPath += oldPath.get(); ::SetEnvironmentVariableW(L"PATH", newPath.c_str()); } diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index f5be22f05..83a124372 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -4596,8 +4596,8 @@ void MainWindow::processLOOTOut(const std::string &lootOut, std::string &errorMe std::vector lines; boost::split(lines, lootOut, boost::is_any_of("\r\n")); - std::tr1::regex exRequires("\"([^\"]*)\" requires \"([^\"]*)\", but it is missing\\."); - std::tr1::regex exIncompatible("\"([^\"]*)\" is incompatible with \"([^\"]*)\", but both are present\\."); + std::regex exRequires("\"([^\"]*)\" requires \"([^\"]*)\", but it is missing\\."); + std::regex exIncompatible("\"([^\"]*)\" is incompatible with \"([^\"]*)\", but both are present\\."); for (const std::string &line : lines) { if (line.length() > 0) { @@ -4609,12 +4609,12 @@ void MainWindow::processLOOTOut(const std::string &lootOut, std::string &errorMe qWarning("%s", line.c_str()); errorMessages.append(boost::algorithm::trim_copy(line.substr(erroridx + 8)) + "\n"); } else { - std::tr1::smatch match; - if (std::tr1::regex_match(line, match, exRequires)) { + std::smatch match; + if (std::regex_match(line, match, exRequires)) { std::string modName(match[1].first, match[1].second); std::string dependency(match[2].first, match[2].second); m_OrganizerCore.pluginList()->addInformation(modName.c_str(), tr("depends on missing \"%1\"").arg(dependency.c_str())); - } else if (std::tr1::regex_match(line, match, exIncompatible)) { + } else if (std::regex_match(line, match, exIncompatible)) { std::string modName(match[1].first, match[1].second); std::string dependency(match[2].first, match[2].second); m_OrganizerCore.pluginList()->addInformation(modName.c_str(), tr("incompatible with \"%1\"").arg(dependency.c_str())); From d7e6adb3def695daf56d6243d08845c49b63e197 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sandro=20J=C3=A4ckel?= Date: Fri, 9 Mar 2018 18:25:48 +0100 Subject: [PATCH 09/57] Don't set zlib_root --- CMakeLists.txt | 2 -- 1 file changed, 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 245626aa8..9c6351f7e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -11,6 +11,4 @@ LIST(APPEND CMAKE_PREFIX_PATH ${QT_ROOT}/lib/cmake) FILE(GLOB_RECURSE BOOST_ROOT ${DEPENDENCIES_DIR}/boost*/project-config.jam) GET_FILENAME_COMPONENT(BOOST_ROOT ${BOOST_ROOT} DIRECTORY) -SET(ZLIB_ROOT ${DEPENDENCIES_DIR}/zlib) - ADD_SUBDIRECTORY(src) From f7ab05767c88dd04dc60fc3a687ffe6d4328e444 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sandro=20J=C3=A4ckel?= Date: Fri, 9 Mar 2018 18:32:07 +0100 Subject: [PATCH 10/57] Update readme.md --- readme.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/readme.md b/readme.md index fd7f3e53b..f7ca93f34 100644 --- a/readme.md +++ b/readme.md @@ -59,7 +59,6 @@ Here is a complete list: * https://github.com/LePresidente/modorganizer-game_oblivion * https://github.com/LePresidente/modorganizer-game_skyrim * https://github.com/LePresidente/modorganizer-game_skyrimSE -* https://github.com/LePresidente/modorganizer-hookdll * https://github.com/LePresidente/modorganizer-installer_bain * https://github.com/LePresidente/modorganizer-installer_bundle * https://github.com/LePresidente/modorganizer-installer_fomod @@ -75,5 +74,8 @@ Here is a complete list: * https://github.com/LePresidente/modorganizer-tool_inibakery * https://github.com/LePresidente/modorganizer-uibase * https://github.com/LePresidente/usvfs + +### Unused Repositories +* https://github.com/LePresidente/modorganizer-hookdll * https://github.com/TanninOne/modorganizer-tool_nmmimport From 9ee2831c59c379e01bd73ced25ce02270dba48df Mon Sep 17 00:00:00 2001 From: LePresidente Date: Sun, 11 Mar 2018 16:21:06 +0200 Subject: [PATCH 11/57] Fix library include for zlibstatic --- src/CMakeLists.txt | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index c94aa6899..60b366833 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -277,6 +277,7 @@ SET(default_project_path "${CMAKE_SOURCE_DIR}/..") GET_FILENAME_COMPONENT(${default_project_path} ${default_project_path} REALPATH) SET(project_path "${default_project_path}" CACHE PATH "path to the other mo projects") +#TODO this should not be a hardcoded path SET(lib_path "${project_path}/../../install/libs") @@ -289,11 +290,9 @@ INCLUDE_DIRECTORIES(${project_path}/uibase/src ${project_path}/game_features/src ${project_path}/githubpp/src) - INCLUDE_DIRECTORIES(shared ${ZLIB_INCLUDE_DIRS}) LINK_DIRECTORIES(${lib_path} - ${project_path}/../zlib/lib) - + ${ZLIB_ROOT}/lib) EXECUTE_PROCESS( COMMAND git log -1 --format=%h WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} From 0983c88c17ec7d3ca42438d9ae07b6a0def3cf3b Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Sun, 11 Mar 2018 23:15:07 +0000 Subject: [PATCH 12/57] Deploy the qtdds.dll as part of the MO install --- src/CMakeLists.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 60b366833..ab7b48364 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -368,6 +368,9 @@ INSTALL( file(REMOVE_RECURSE ${CMAKE_INSTALL_PREFIX}/bin/qtplugins)" ) +# qdds.dll needs installing manually as Qt no longer ships with it by default. +INSTALL(FILES ${CMAKE_CURRENT_SOURCE_DIR}/../qdds.dll DESTINATION bin/dlls/imageformats) + INSTALL(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/stylesheets ${CMAKE_CURRENT_SOURCE_DIR}/tutorials DESTINATION bin) From 8f8beea427af1eb71ba7f7f210279fff70f8d9a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sandro=20J=C3=A4ckel?= Date: Mon, 12 Mar 2018 16:30:45 +0100 Subject: [PATCH 13/57] Updated Repository links --- readme.md | 74 +++++++++++++++++++++++++++---------------------------- 1 file changed, 37 insertions(+), 37 deletions(-) diff --git a/readme.md b/readme.md index f7ca93f34..edd3609b7 100644 --- a/readme.md +++ b/readme.md @@ -12,7 +12,7 @@ Mod Organizer 2 is an open project in the hands of the community, there are prob To have more information, please join the open MO2 Development discord server :* [ModOrganizerDevs](https://discord.gg/vD2ZbfX) If you want to help translate MO2 to your language you should join the discord server too and head to the #translation channel. -To setup a development environment on your machine, there is the [umbrella project](https://github.com/LePresidente/modorganizer-umbrella) that handles that. +To setup a development environment on your machine, there is the [umbrella project](https://github.com/Modorganizer2/modorganizer-umbrella) that handles that. If you want to submit your code changes, please use a good formating style like the default one in Visual Studio. Through the work of a few people of the community MO2 has come quite far, now it needs some more of those people to go further. @@ -24,7 +24,7 @@ Credits to Tannin, LePresidente, Silarn, erasmux, AL12 and many others for the d ## Download Location -* on [GitHub.com](https://github.com/LePresidente/modorganizer/releases) +* on [GitHub.com](https://github.com/Modorganizer2/modorganizer/releases) * on [NexusMods.com](https://www.nexusmods.com/skyrimspecialedition/mods/6194) ## Old Download Location @@ -33,7 +33,7 @@ Credits to Tannin, LePresidente, Silarn, erasmux, AL12 and many others for the d ## Building -Please refer to [LePresidente/modorganizer-umbrella](https://github.com/LePresidente/modorganizer-umbrella) for build instructions. +Please refer to [LePresidente/modorganizer-umbrella](https://github.com/Modorganizer2/modorganizer-umbrella) for build instructions. ## Other Repositories @@ -41,41 +41,41 @@ MO2 consists of multiple repositories on github. The Umbrella project will downl Here is a complete list: * https://github.com/LePresidente/cpython-1 -* https://github.com/LePresidente/githubpp -* https://github.com/LePresidente/modorganizer -* https://github.com/LePresidente/modorganizer-archive -* https://github.com/LePresidente/modorganizer-bsatk -* https://github.com/LePresidente/modorganizer-bsa_extractor -* https://github.com/LePresidente/modorganizer-check_fnis -* https://github.com/LePresidente/modorganizer-diagnose_basic -* https://github.com/LePresidente/modorganizer-esptk -* https://github.com/LePresidente/modorganizer-helper -* https://github.com/LePresidente/modorganizer-game_fallout3 -* https://github.com/LePresidente/modorganizer-game_fallout4 -* https://github.com/LePresidente/modorganizer-game_fallout4vr -* https://github.com/LePresidente/modorganizer-game_falloutnv -* https://github.com/LePresidente/modorganizer-game_features -* https://github.com/LePresidente/modorganizer-game_gamebryo -* https://github.com/LePresidente/modorganizer-game_oblivion -* https://github.com/LePresidente/modorganizer-game_skyrim -* https://github.com/LePresidente/modorganizer-game_skyrimSE -* https://github.com/LePresidente/modorganizer-installer_bain -* https://github.com/LePresidente/modorganizer-installer_bundle -* https://github.com/LePresidente/modorganizer-installer_fomod -* https://github.com/LePresidente/modorganizer-installer_manual -* https://github.com/LePresidente/modorganizer-installer_ncc -* https://github.com/LePresidente/modorganizer-installer_quick -* https://github.com/LePresidente/modorganizer-lootcli -* https://github.com/LePresidente/modorganizer-NCC -* https://github.com/LePresidente/modorganizer-nxmhandler -* https://github.com/LePresidente/modorganizer-plugin_python -* https://github.com/LePresidente/modorganizer-preview_base -* https://github.com/LePresidente/modorganizer-tool_configurator -* https://github.com/LePresidente/modorganizer-tool_inibakery -* https://github.com/LePresidente/modorganizer-uibase -* https://github.com/LePresidente/usvfs +* https://github.com/Modorganizer2/githubpp +* https://github.com/Modorganizer2/modorganizer +* https://github.com/Modorganizer2/modorganizer-archive +* https://github.com/Modorganizer2/modorganizer-bsatk +* https://github.com/Modorganizer2/modorganizer-bsa_extractor +* https://github.com/Modorganizer2/modorganizer-check_fnis +* https://github.com/Modorganizer2/modorganizer-diagnose_basic +* https://github.com/Modorganizer2/modorganizer-esptk +* https://github.com/Modorganizer2/modorganizer-helper +* https://github.com/Modorganizer2/modorganizer-game_fallout3 +* https://github.com/Modorganizer2/modorganizer-game_fallout4 +* https://github.com/Modorganizer2/modorganizer-game_fallout4vr +* https://github.com/Modorganizer2/modorganizer-game_falloutnv +* https://github.com/Modorganizer2/modorganizer-game_features +* https://github.com/Modorganizer2/modorganizer-game_gamebryo +* https://github.com/Modorganizer2/modorganizer-game_oblivion +* https://github.com/Modorganizer2/modorganizer-game_skyrim +* https://github.com/Modorganizer2/modorganizer-game_skyrimSE +* https://github.com/Modorganizer2/modorganizer-installer_bain +* https://github.com/Modorganizer2/modorganizer-installer_bundle +* https://github.com/Modorganizer2/modorganizer-installer_fomod +* https://github.com/Modorganizer2/modorganizer-installer_manual +* https://github.com/Modorganizer2/modorganizer-installer_ncc +* https://github.com/Modorganizer2/modorganizer-installer_quick +* https://github.com/Modorganizer2/modorganizer-lootcli +* https://github.com/Modorganizer2/modorganizer-NCC +* https://github.com/Modorganizer2/modorganizer-nxmhandler +* https://github.com/Modorganizer2/modorganizer-plugin_python +* https://github.com/Modorganizer2/modorganizer-preview_base +* https://github.com/Modorganizer2/modorganizer-tool_configurator +* https://github.com/Modorganizer2/modorganizer-tool_inibakery +* https://github.com/Modorganizer2/modorganizer-uibase +* https://github.com/Modorganizer2/usvfs ### Unused Repositories -* https://github.com/LePresidente/modorganizer-hookdll +* https://github.com/Modorganizer2/modorganizer-hookdll * https://github.com/TanninOne/modorganizer-tool_nmmimport From 0d4a59fd91a33bf62de6850d654623dd99828f3e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sandro=20J=C3=A4ckel?= Date: Mon, 12 Mar 2018 17:10:49 +0100 Subject: [PATCH 14/57] Missed one --- readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readme.md b/readme.md index edd3609b7..42a41360a 100644 --- a/readme.md +++ b/readme.md @@ -33,7 +33,7 @@ Credits to Tannin, LePresidente, Silarn, erasmux, AL12 and many others for the d ## Building -Please refer to [LePresidente/modorganizer-umbrella](https://github.com/Modorganizer2/modorganizer-umbrella) for build instructions. +Please refer to [Modorganizer2/modorganizer-umbrella](https://github.com/Modorganizer2/modorganizer-umbrella) for build instructions. ## Other Repositories From 9f61ef5c9e6c8884a14b7d6f1507199f61a64377 Mon Sep 17 00:00:00 2001 From: Al12rs Date: Mon, 12 Mar 2018 19:53:43 +0100 Subject: [PATCH 15/57] Added a check to the preview function to handle tha case of the file beeing from the actual data folder instead of a mod. --- src/mainwindow.cpp | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 83a124372..bdf79bd56 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -3929,10 +3929,22 @@ void MainWindow::previewDataFile() // what we have is an absolute path to the file in its actual location (for the primary origin) // what we want is the path relative to the virtual data directory - // crude: we search for the next slash after the base mod directory to skip everything up to the data-relative directory - int offset = m_OrganizerCore.settings().getModDirectory().size() + 1; - offset = fileName.indexOf("/", offset); - fileName = fileName.mid(offset + 1); + // we need to look in the virtual directory for the file to make sure the info is up to date. + + // check if the file comes from the actual data folder instead of a mod + QDir gameDirectory = m_OrganizerCore.managedGame()->dataDirectory().absolutePath(); + QString relativePath = gameDirectory.relativeFilePath(fileName); + if (!relativePath.startsWith("..")) { + fileName = relativePath; + } + else { + // crude: we search for the next slash after the base mod directory to skip everything up to the data-relative directory + int offset = m_OrganizerCore.settings().getModDirectory().size() + 1; + offset = fileName.indexOf("/", offset); + fileName = fileName.mid(offset + 1); + } + + const FileEntry::Ptr file = m_OrganizerCore.directoryStructure()->searchFile(ToWString(fileName), nullptr); From 8305d9215725a49dd9c61c2609fa750a20315af9 Mon Sep 17 00:00:00 2001 From: Al12rs Date: Mon, 12 Mar 2018 12:33:05 +0100 Subject: [PATCH 16/57] Reverted some changes added by Qt configurator that caused some wird stretching of the mainwindow. I suspect this is caused by the fact that the archive tab was not disabled in a way that Configurator liked and it is messing with it. --- src/mainwindow.ui | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/mainwindow.ui b/src/mainwindow.ui index 451e3c871..0c0ac6c68 100644 --- a/src/mainwindow.ui +++ b/src/mainwindow.ui @@ -176,7 +176,7 @@ 2 - + @@ -463,7 +463,7 @@ p, li { white-space: pre-wrap; } - + From ccb5ad53e22e54f416c4cc3f33c2b57d0b1b672a Mon Sep 17 00:00:00 2001 From: Al12rs Date: Mon, 12 Mar 2018 23:18:03 +0100 Subject: [PATCH 17/57] Fixed wrong Nexus page url in CSV export. --- src/mainwindow.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index bdf79bd56..5be5cef3b 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -3201,7 +3201,7 @@ void MainWindow::exportModListCSV() if (nexus_ID->isChecked()) builder.setRowField("#Nexus_ID", info->getNexusID()); if (mod_Nexus_URL->isChecked()) - builder.setRowField("#Mod_Nexus_URL", info->getURL()); + builder.setRowField("#Mod_Nexus_URL",(info->getNexusID()>0)? NexusInterface::instance()->getModURL(info->getNexusID()) : ""); if (mod_Version->isChecked()) builder.setRowField("#Mod_Version", info->getVersion().canonicalString()); if (install_Date->isChecked()) From 8dee1d108b4098a587f3a827c187b3c9c2559d12 Mon Sep 17 00:00:00 2001 From: Al12rs Date: Thu, 15 Mar 2018 15:21:37 +0100 Subject: [PATCH 18/57] Fixed default size and positioning of some ui elements to accomodate the new ones. Fixed incorrect settings for the layout stretching. --- src/mainwindow.ui | 61 +++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 51 insertions(+), 10 deletions(-) diff --git a/src/mainwindow.ui b/src/mainwindow.ui index 0c0ac6c68..e0aa6f36e 100644 --- a/src/mainwindow.ui +++ b/src/mainwindow.ui @@ -176,7 +176,7 @@ 2 - + @@ -194,7 +194,7 @@ - + Pick a module collection @@ -463,7 +463,7 @@ p, li { white-space: pre-wrap; } - + @@ -507,15 +507,25 @@ p, li { white-space: pre-wrap; } true - - - + + + + Qt::Horizontal + + + + 40 + 20 + + + + - + 0 0 @@ -523,9 +533,15 @@ p, li { white-space: pre-wrap; } 0 - 25 + 22 + + + 95 + 0 + + false @@ -551,7 +567,26 @@ p, li { white-space: pre-wrap; } - + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 220 + 0 + + Qt::ClickFocus @@ -573,7 +608,13 @@ p, li { white-space: pre-wrap; } - + + + + 220 + 0 + + Namefilter From 2fa1b04cd430315f3abf45dcdd4975c0117ac98a Mon Sep 17 00:00:00 2001 From: Al12rs Date: Fri, 16 Mar 2018 18:02:57 +0100 Subject: [PATCH 19/57] Various text and ui changes: Added description to CSV export. Added line to delete instance error message. Changed delete instance icon for the list of instances. Added red X in the resources, thanks to twizz0r. --- src/instancemanager.cpp | 4 ++-- src/mainwindow.cpp | 4 ++++ src/resources.qrc | 1 + src/resources/multiply-red.png | Bin 0 -> 16018 bytes 4 files changed, 7 insertions(+), 2 deletions(-) create mode 100644 src/resources/multiply-red.png diff --git a/src/instancemanager.cpp b/src/instancemanager.cpp index d12ec119b..43ae152b3 100644 --- a/src/instancemanager.cpp +++ b/src/instancemanager.cpp @@ -105,7 +105,7 @@ QString InstanceManager::manageInstances(const QStringList &instanceList) const nullptr); for (const QString &instance : instanceList) { - selection.addChoice(instance, "", instance); + selection.addChoice(QIcon(":/MO/gui/multiply_red"), instance, "", instance); } if (selection.exec() == QDialog::Rejected) { @@ -120,7 +120,7 @@ QString InstanceManager::manageInstances(const QStringList &instanceList) const if (!deleteLocalInstance(choice)) { QMessageBox::warning(nullptr, QObject::tr("Failed to delete Instance"), - QObject::tr("Could not delete Instance \"%1\"").arg(choice), QMessageBox::Ok); + QObject::tr("Could not delete Instance \"%1\". \nIf the folder was still in use, restart MO and try again.").arg(choice), QMessageBox::Ok); } } } diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 5be5cef3b..2bf25b05f 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -3079,6 +3079,10 @@ void MainWindow::exportModListCSV() QGridLayout *grid = new QGridLayout; selection.setWindowTitle(tr("Export to csv")); + QLabel *csvDescription = new QLabel(); + csvDescription->setText(tr("CSV (Comma Separated Values) is a format that can be imported in programs like Excel to create a spreadsheet.\nYou can also use online editors and converters instead.")); + grid->addWidget(csvDescription); + QGroupBox *groupBoxRows = new QGroupBox(tr("Select what mods you want export:")); QRadioButton *all = new QRadioButton(tr("All installed mods")); QRadioButton *active = new QRadioButton(tr("Only active (checked) mods from your current profile")); diff --git a/src/resources.qrc b/src/resources.qrc index 618d3cfc7..1cfc58a30 100644 --- a/src/resources.qrc +++ b/src/resources.qrc @@ -72,6 +72,7 @@ resources/package.png resources/switch-instance-icon.png resources/open-Folder-Icon.png + resources/multiply-red.png resources/contents/jigsaw-piece.png diff --git a/src/resources/multiply-red.png b/src/resources/multiply-red.png new file mode 100644 index 0000000000000000000000000000000000000000..c238f07f5f2e8e854bb308356770d79cf728a5ae GIT binary patch literal 16018 zcmeI3TWBNK8Gz4jmbU98bV(nYq@fWCOD}XhGaB7ykhPL6CpL+;uGeY2fzXU+j_hG2 zjj9>1wVQ`HErqsErB9{wt(T|LgwQk%hR76>LTK~QLI~N?KnO`wa)Dm5>-A>U|39P4 z_*g!eZc1Oyz^`-u>pAnCi}a%JEu6mZ)`>eO2qCx5&s7$oJ%RG6Pr&Eh|Lob&9B<8? z4G6jUGbl&MkAHGIA?CZ@(sH<5eZX@3#-#1~D|E8cXhAd~g;SlD?VO`wVuh}H&8g%E zTis;BbElFIWvW`WHAC0Dxr=Rj=Hlrk=i)iXbd#rw6NQci1sXK86P-rA8CadEB&%yd zAI)kq!9v1wQ^_(8m{_hZBxd|JO=KpsilZC(M9!SlGiE-O{z@XH=~-1XRXwd}x}}+x zrYHJOvN!>~LffrbiGRAf-6LIbDmwL;HtCa|u(;;)BO$s`UmeERRzXblHy27PuwQSI0*RiD(uhSSqtZHU&}JAwo<26OwdRL@u;w2yTv9_^KCT74jqKE=K(<< z>DbI*=|YRDi!|`p+YX&Q53h31xVI0z+Guh1R6@^zbEh5efHd?(X>2P*D^!4YwPxDX z4*m9$@7IgbE?XENOw7#SuF568_>k9h{f*#D1(i=3t@o%Jt=J(gLS|mk3`Nf_!Dh@D zmXT7lw54gWB2gq)qw2d}?ZUVkY0JpOYs4b?8gPDGJG2i~B_12A<2qK&Z#V3)=r!zB zs;RA3Vm!8f}V> zS5%5c9b6>vYvG37rsY-GA%{8nQPsU^eEEWk-vxE=f3OgNeg4Ll;c%zw2A3gzL;e4j zVYG{#HM_Y=-J&|!zyrhKRxVo4y(epMTKAvC0)9DJaEf6^+3fV_1$CcoG;$QbjHj`_ z&f;?^4IWj;&wgs$&8MCfr^elU>L~NUrWY1d{n0pcEDOIuqwD<){Me(#Y$jvC&BdGf zj0LYl>&q1n?%@FM6Fu9{;T>ZW&mNQ*bMzCVrHcJ5V`nh3!jC@qy{Qg=aPB*v!&~g* z?2O*%XraX`eX#3km#c_l6mh**`l#C$lf#Ki#-s}h%( z59gJ*I3QwGh-+f>7f#xQ|7~u-A2fgd>MJ;vD`;yvDpN99Hb1g4KnU2 zfw2qn1jr`&=@wxHu7C8=CKw(+djEao`ZLdAK>6q|p5KOc_*{Q@x&%tMAAj-#n2WE2 zPxtuJ0wMqUH&ZVEb_?6`@h5-3&1SHB_3AcA`5#X|L&%jYguMG6!33~%QCKqA(1$S? z3$l$>*bLsERmg2yec6*Q$&0uGT1)yVhXQ%wm zv(FLo;fI90`dTE=M;rPu27{r`a@Z=sbeO^%gZ_z66Y|#IBKw`UE94?`3iaEg%{CYM!`PX2>5USj0GuSF2S?# zr@KGd>;3Gzz1~8e3F;sv^!5EE7Ss1*EYtBEVZh6uyJ-`o*Sp{7VGB}%K8Xw3xR_1M zWeom!#}S;&CJ1g%_I}WgdrDyJf;<7TX}sMp0Lp*;z|g(k;`FJPzVN$WXR*rs?CHv{ JrXT&*e*m0cWY7Qr literal 0 HcmV?d00001 From 8095be550f65b77f36c06cc731c8bfb0b9dad8c4 Mon Sep 17 00:00:00 2001 From: Al12rs Date: Sat, 17 Mar 2018 00:58:55 +0100 Subject: [PATCH 20/57] Added archive-conflict icons to resources. --- src/resources.qrc | 4 ++++ src/resources/archive-conflict-loser.png | Bin 0 -> 18052 bytes src/resources/archive-conflict-mixed.png | Bin 0 -> 18052 bytes src/resources/archive-conflict-neutral.png | Bin 0 -> 18052 bytes src/resources/archive-conflict-winner.png | Bin 0 -> 18052 bytes 5 files changed, 4 insertions(+) create mode 100644 src/resources/archive-conflict-loser.png create mode 100644 src/resources/archive-conflict-mixed.png create mode 100644 src/resources/archive-conflict-neutral.png create mode 100644 src/resources/archive-conflict-winner.png diff --git a/src/resources.qrc b/src/resources.qrc index 1cfc58a30..0197b6061 100644 --- a/src/resources.qrc +++ b/src/resources.qrc @@ -73,6 +73,10 @@ resources/switch-instance-icon.png resources/open-Folder-Icon.png resources/multiply-red.png + resources/archive-conflict-looser.png + resources/archive-conflict-mixed.png + resources/archive-conflict-neutral.png + resources/archive-conflict-winner.png resources/contents/jigsaw-piece.png diff --git a/src/resources/archive-conflict-loser.png b/src/resources/archive-conflict-loser.png new file mode 100644 index 0000000000000000000000000000000000000000..77d2e0fafb987ca139f7fad3cb6ad767fe2ea4f0 GIT binary patch literal 18052 zcmeI4TZ|i58GwJg&OMvU=F*lFFb%Q;9B3TKe^J$~@_=So1u`&MuA(+TX4_;{(+`nGv_MA9%3y5z z*zs7@GzMdjC-OqRI!wmQT}NwV|Is}o`q4wWV#Ky(muDtbbWkP@Ejn2)RqE>GV9fQa zqU?0@v8b!kI5Zd=asoyVx}zS(oq@{=QVy=GP$rd5eLezk%%-WZIh4Otq2UGW&bjk3aXy-^rxaNcxne3sxFU%g zTtQ4}oLEdJ3#5>c(h1_OhEDVL%$lxS(b2Vc)EbtK?%RB&R9aCIMB*d`uUQmHnp5PI zfro7zhXf*O>3A!U&)K{{U#gjSC(ueh9m-Y_WLZ-PC&qP!Q>3`gr4vP+D-1L-waaueeWWW5PHy&-Z*=yyGwq()RjpPh&WSV_YaL1SkVjS8GVaNSNpMd4 ztnTb{Vr2M^-uAS*&CL1fOfVtv{QJxojxjMtD)%}kJXfyP!cOW|u`!|5$j~V6AeJM{ z^V(_F?Y{ReK}POgESdL_h`M(8{?ec*qM;bL5+x}~xP%_pxI(HRbIFuYNNI5*3rVe& z<`0pE!|(zrNII2Mc2o)$|y0ieCx_u9UrI6$%TYw6ypU>Hwp#L(Bd*z zAVQH#$mz5srVO1V6Rqp}P?_t#Nd}o~9)4EkFsXfz;|~v64Xb&A_u^vBDo3?ywPfm= zbCmLjD@L;%rgxxd!;1Q<1dqGV$NzAZ8l+}^kQ2r?OTC3D`Z2ra`#w|IDitrS!Orw* z1@9i&S*^4xp!wBJtCaIr=T2u&ImOQV7c+PRz@JH~kGfNmIprnmaoT0xu@{@(v7mG- z@C7SOSxL+BgrRU!S}A%JW7u%8c_XQpGA2D<=0y%VOy|ug~Yr9XsGuo27BLnoLOoHePhzo2LHZZqtMJHuVp8 zo3<^#QZXA@sTr-S+h^tc)b)Oc?Z>}&NH&>B$aq)n?(VkOYfh5Vft-oI!|G1GEGC;a z-2*)h4=!Zr8)zDO+s5}tjGGv*7ystLf0%gs7n3h%v_Ajnh4vMF^uDRbAP7alA_TZt zC{djN7e&D$1h`lzQJnx6MZqEjxL7Drod6d_!6F2>SSV4Q02f8UA_TZtC{djN7e&D$ z1h`lzQJnx6MZqEjxL7Drod6d_!6F2>SSV4Q02f8UA_TZtC{djN7e&D$1h`lzQJnx6 zMZqEjxL7Drod6d_!6F2>SSV4Q02f8UA_TZtC{djN7e&D$1h`lzQJnx6MZqEjxL7Dr zod6d_!6F2>SSV4Q02f8UA_TZtC{djN7e&D$1h`lzQJnx6MZqEjxL7Drod6d_!6Muf z*Yfs58%PD8)G&dMWcco_=ST2y4pDvAzC6IuM*+V1ZGagYKQ94{3jmj&1W&U_!!_vW%56A*VFe_(tFSn~8sN?U z!0UhWkokRtlj=>7a{zCz-3j5ne}I=yeHNXB;o`p{aN9ly;YSz2Yfs;X6DL-}^*cDr zt`>nScL4Zhkh=UFT)8j|Yqt!++26bhQ&*Nk1lGgpUxy(Q4nrn&3t-7S1gNv>0f0-l z5!fQw@U{gT93}AqIRAVfY+ShtBpGx25I%5Z2B&`x^}1Sk`aI46fdO7NgwXglrt0Cv zux|BrkT~o^8Q#Ja&tm^-4A#}czq_!t?`Kb8?-VNap#rWvn6+WfEJwPIsEMztPRq?rKY+ zQ0S#!_9x`%%D#4IQ*!cg{?<**0z-Reb`Bf^bm*>jhqd$FY41A&Pi^6MbY$CK`}u3z UUkbhHCVBUcJ-J_PfAU-Z1t%6q)Bpeg literal 0 HcmV?d00001 diff --git a/src/resources/archive-conflict-mixed.png b/src/resources/archive-conflict-mixed.png new file mode 100644 index 0000000000000000000000000000000000000000..e71e0167ba6c26eff83c379db55e6920aacaa9de GIT binary patch literal 18052 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 literal 0 HcmV?d00001 diff --git a/src/resources/archive-conflict-winner.png b/src/resources/archive-conflict-winner.png new file mode 100644 index 0000000000000000000000000000000000000000..f62605753eec260bd9438279c8bdeeb6ffba54fa GIT binary patch literal 18052 zcmeI4TWlOx8G!%YY@FD+G;x|h8!EONdO`7cE_C<-DHN~l`V&{6_QOj-yKa%)ZMHcf2D!+&OW&yLsY zaN1O$N^_*${r8;za?bakIrHy6%u{=I?^xAwZwCOZ+O@N9FMh6}ujOs{{@E!<$B*{X z&I1*I73=6L1V8xUrvbLUX$|bJ?(hGiX4oU$x@qT0_xMN&wE=pzjF)ud5UED*jXjp^m-X6>U5l zbNy;4({3>qbycc|vazi+V03@~o@lRKCedVfN-*SjCYn~e<)oTX5?xV6l2f9jigH4b zWKB{vNsiW9EZ2cjPuVPJd;7N6!r`}UY^Yi-X`(nbHr72B@3zZ>qO7W_C@G?%2&f@c zjufl(t~6vd$eqjZHI9wn_8{DQr$}$+2L@7>Mb2rt->OH=*XfF$hftL z86EM=+&$%`x(A_Yy=9_T?ec(a59hq?x~HCtXm2mwp6Terk6A_29;8ucVqXu01a(Dy~_U zNk&lPX%i3Igp$rkMAkEjdLW;(1%bX)w(w4%5Bqc&TUCn3b(IKm!cYZO!L?+P1zb>G z(bbF|FT^u)JwyvP3qtL*Xr_-erGe&VANkt+-bSX~GrOdhD}`a=>ztT9;=JC*w3^MVh3QOkA@KbB%omR_HbjcIJ10C>uGZpCDt4hdrkBaq zLA-)^jxf*be6wcvt*;VfardKO?_sIFxO1%PFSl!f1Id6Avr`HrMcK&-YgEs*DnWXus(~^vqm%PVmlli=B zvF05MO1A=Ew8D(5nRp^;s)CYH3tokpm(`R|$lxiiBqY-`u$1+t>T}jAmVKv1rWd7! zn?|&H9{L)%eKlnd{S~QUm5LRUd!*&CbY0Nr^X882r`6{0s9Q~@6$zUt)AyRGf4JH7 z!0k=_!_B4*%dZrzY7Xy@?qr&}eOC0RuJ=1^AO5{Va;ao8p6n5uyPGZcSmR`Pf1icF z!z#31mQyvG=7E-m2NpB*4b%+1%f|OdjGGv*7ystLf0#t}7n3h%tUmwvg~p0Le&5Vv z5QL%N5dvI1l$cI{i=p5V0$e7V1ZyIbGa<)8Rc!zK(Qaqs{j+fSZy`AImr2?cdhR#Z zV8gnl5Do#<)ZoZZU!!BJMO^9UJDiQ%@c9&P18mqBf(>1raP<$f&OT2q^xTPe;hxS2 zc%hiBD}-Mthz=-d{MVZR@6G~ToB^0~;O^{l$bPvKvdRi4qvf14f4>QnQ*-mJ@mt7w z=}`yP;Y6;YVc0i*3*&8Eh6HBdrQ@@3Y9a)Oo_P@$Grxr=-az9ijQkl??p*3Qp~mam z;QH$`@bbyKA-)OV(94zC^$!NjpJ%$>f0kLf^%YtYe^X?W}W3P=i9 zp{@TefO8+f**|*7{64}dZ3^Oj0Pn2b4&gn&gj2744xNPI;y)rV?Ys%$2bRL0o}Gph zCsx9>TR6+67II$P;egl<@Wu_e^3ZqSy^DW_=~Lf@i7U$?0yklOX9q;WVKAOK zcCJ(5^y$;MCc5I)O8_oSBe12g{v8|cU-o@?NL~VwWvg%xtcQ5w28fR$BWx=Rmq7da zW%@i4*20r--Ex5eE*nA!c^Xr7PaCYe>l!Em_Mr?HFvZxunres4gUemH{ucSg`L0#B zo;o-6_zqNhm=5BMW*nHk?m(i5yRM#E^!+~izCPz=a`WcR?^7p{iC2!jcj4`s(CcTz zAa={nuj_igd@a(~rZYF5|!ktmq#?N}HXct}cS_HkG!p2q~yR8FHwefy-0(a** h`h6wqL?({&ttbEelUoO~muc^=ZM*xPf8>cL{{vyxU)TTu literal 0 HcmV?d00001 From 90165b02ab8686015d41c1fee79e5c6314a65357 Mon Sep 17 00:00:00 2001 From: Al12rs Date: Sat, 17 Mar 2018 01:08:02 +0100 Subject: [PATCH 21/57] Disabled iniTweaks part of modinfodialog until it is not fixed. --- src/modinfodialog.ui | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/modinfodialog.ui b/src/modinfodialog.ui index 25822fd06..b53314241 100644 --- a/src/modinfodialog.ui +++ b/src/modinfodialog.ui @@ -110,13 +110,19 @@ + + false + - Ini Tweaks + Ini Tweaks *This feature is non-functional* + + false + 228 From 2def87a143cae7521bc8da898fddda73f213d473 Mon Sep 17 00:00:00 2001 From: Al12rs Date: Sat, 17 Mar 2018 12:42:15 +0100 Subject: [PATCH 22/57] Fixed a typo of the added resource. --- src/resources.qrc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/resources.qrc b/src/resources.qrc index 0197b6061..1c7c92e1c 100644 --- a/src/resources.qrc +++ b/src/resources.qrc @@ -73,7 +73,7 @@ resources/switch-instance-icon.png resources/open-Folder-Icon.png resources/multiply-red.png - resources/archive-conflict-looser.png + resources/archive-conflict-loser.png resources/archive-conflict-mixed.png resources/archive-conflict-neutral.png resources/archive-conflict-winner.png From bbce6506cdf15b5965e12ca2b10063fa8d3b85c0 Mon Sep 17 00:00:00 2001 From: Al12rs Date: Sat, 17 Mar 2018 14:41:43 +0100 Subject: [PATCH 23/57] Fixed another typo in the same resource --- src/resources.qrc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/resources.qrc b/src/resources.qrc index 1c7c92e1c..14c8e5334 100644 --- a/src/resources.qrc +++ b/src/resources.qrc @@ -73,7 +73,7 @@ resources/switch-instance-icon.png resources/open-Folder-Icon.png resources/multiply-red.png - resources/archive-conflict-loser.png + resources/archive-conflict-loser.png resources/archive-conflict-mixed.png resources/archive-conflict-neutral.png resources/archive-conflict-winner.png From 336216ba9a7e07aad972708c862c1e7306f1c67d Mon Sep 17 00:00:00 2001 From: Jeremy Rimpo Date: Tue, 20 Mar 2018 01:29:31 -0500 Subject: [PATCH 24/57] Various save game improvements related to script extender files * Improve handling of SE save transfers and deletes with main save * Add indicator in save popup dialog if SE save file is present --- src/mainwindow.cpp | 12 ++++++++---- src/transfersavesdialog.cpp | 30 ++++++++++-------------------- 2 files changed, 18 insertions(+), 24 deletions(-) diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 2bf25b05f..8bb400720 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -4667,9 +4667,13 @@ void MainWindow::on_bossButton_clicked() QStringList parameters; parameters << "--game" << m_OrganizerCore.managedGame()->gameShortName() - << "--gamePath" << QString("\"%1\"").arg(m_OrganizerCore.managedGame()->gameDirectory().absolutePath()) - << "--pluginListPath" << QString("\"%1/loadorder.txt\"").arg(m_OrganizerCore.profilePath()) - << "--out" << QString("\"%1\"").arg(outPath); + << "--gamePath" << QString("\"%1\"").arg(m_OrganizerCore.managedGame()->gameDirectory().absolutePath()) + << "--out" << QString("\"%1\"").arg(outPath); + + if (m_OrganizerCore.managedGame()->loadOrderMechanism() == IPluginGame::LoadOrderMechanism::FileTime) + parameters << "--pluginListPath" << QString("\"%1/loadorder.txt\"").arg(m_OrganizerCore.profilePath()); + else + parameters << "--pluginListPath" << QString("\"%1/plugins.txt\"").arg(m_OrganizerCore.profilePath()); if (m_DidUpdateMasterList) { parameters << "--skipUpdateMasterlist"; @@ -4802,7 +4806,7 @@ void MainWindow::on_bossButton_clicked() // if the game specifies load order by file time, our own load order file needs to be removed because it's outdated. // refreshESPList will then use the file time as the load order. - if (m_OrganizerCore.managedGame()->loadOrderMechanism() == IPluginGame::LoadOrderMechanism::FileTime) { + if (m_OrganizerCore.managedGame()->loadOrderMechanism() != IPluginGame::LoadOrderMechanism::FileTime) { qDebug("removing loadorder.txt"); QFile::remove(m_OrganizerCore.currentProfile()->getLoadOrderFileName()); } diff --git a/src/transfersavesdialog.cpp b/src/transfersavesdialog.cpp index b8dda056a..61dab6e5f 100644 --- a/src/transfersavesdialog.cpp +++ b/src/transfersavesdialog.cpp @@ -74,6 +74,11 @@ class DummySave : public ISaveGame return { m_File }; } + virtual bool hasScriptExtenderFile() const override + { + return false; + } + private: QString m_File; }; @@ -95,6 +100,11 @@ class DummyInfo : public SaveGameInfo { return nullptr; } + + virtual bool hasScriptExtenderSave(QString const &file) const override + { + return false; + } }; } //end anonymous namespace @@ -334,26 +344,6 @@ bool TransferSavesDialog::transferCharacters( sourceFile.absoluteFilePath().toUtf8().constData(), destinationFile.toUtf8().constData()); } - - QFileInfo sourceFileSE(sourceFile.absolutePath() + "/" + sourceFile.completeBaseName() + "." + m_GamePlugin->savegameSEExtension()); - if (sourceFileSE.exists()) { - QString destinationFileSE(destination.absoluteFilePath(sourceFileSE.fileName())); - - //If the file is already there, let them skip (or not). - if (QFile::exists(destinationFileSE)) { - if (!testOverwrite(overwriteMode, destinationFileSE)) { - continue; - } - //OK, they want to remove it. - QFile::remove(destinationFileSE); - } - - if (!method(sourceFileSE.absoluteFilePath(), destinationFileSE)) { - qCritical(errmsg, - sourceFileSE.absoluteFilePath().toUtf8().constData(), - destinationFileSE.toUtf8().constData()); - } - } } } return true; From 0c792d548f44f71cdd358b5811f5ed06196430d9 Mon Sep 17 00:00:00 2001 From: Jeremy Rimpo Date: Tue, 20 Mar 2018 17:10:35 -0500 Subject: [PATCH 25/57] Fix lootcli destroying loadorder on newer games --- src/mainwindow.cpp | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 8bb400720..e562b2f2c 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -4668,13 +4668,9 @@ void MainWindow::on_bossButton_clicked() QStringList parameters; parameters << "--game" << m_OrganizerCore.managedGame()->gameShortName() << "--gamePath" << QString("\"%1\"").arg(m_OrganizerCore.managedGame()->gameDirectory().absolutePath()) + << "--pluginListPath" << QString("\"%1/loadorder.txt\"").arg(m_OrganizerCore.profilePath()) << "--out" << QString("\"%1\"").arg(outPath); - if (m_OrganizerCore.managedGame()->loadOrderMechanism() == IPluginGame::LoadOrderMechanism::FileTime) - parameters << "--pluginListPath" << QString("\"%1/loadorder.txt\"").arg(m_OrganizerCore.profilePath()); - else - parameters << "--pluginListPath" << QString("\"%1/plugins.txt\"").arg(m_OrganizerCore.profilePath()); - if (m_DidUpdateMasterList) { parameters << "--skipUpdateMasterlist"; } @@ -4793,7 +4789,7 @@ void MainWindow::on_bossButton_clicked() if (success) { m_DidUpdateMasterList = true; - /*if (reportURL.length() > 0) { + if (reportURL.length() > 0) { m_IntegratedBrowser.setWindowTitle("LOOT Report"); QString report(reportURL.c_str()); QStringList temp = report.split("?"); @@ -4802,13 +4798,6 @@ void MainWindow::on_bossButton_clicked() url.setQuery(temp.at(1).toUtf8()); } m_IntegratedBrowser.openUrl(url); - }*/ - - // if the game specifies load order by file time, our own load order file needs to be removed because it's outdated. - // refreshESPList will then use the file time as the load order. - if (m_OrganizerCore.managedGame()->loadOrderMechanism() != IPluginGame::LoadOrderMechanism::FileTime) { - qDebug("removing loadorder.txt"); - QFile::remove(m_OrganizerCore.currentProfile()->getLoadOrderFileName()); } m_OrganizerCore.refreshESPList(); m_OrganizerCore.savePluginList(); From 192b0bafa5ade0e8f9f36fe8ce0f1de137d72e3a Mon Sep 17 00:00:00 2001 From: Jeremy Rimpo Date: Tue, 20 Mar 2018 17:11:00 -0500 Subject: [PATCH 26/57] Update about dialogue and licenses --- src/aboutdialog.cpp | 40 +++++++++++++++++------ src/aboutdialog.h | 15 +++++++-- src/aboutdialog.ui | 78 ++++++++++++++++++++++++++++++++++----------- 3 files changed, 103 insertions(+), 30 deletions(-) diff --git a/src/aboutdialog.cpp b/src/aboutdialog.cpp index ed57a2174..411ef1cf1 100644 --- a/src/aboutdialog.cpp +++ b/src/aboutdialog.cpp @@ -29,7 +29,7 @@ along with Mod Organizer. If not, see . #include #include #include - +#include AboutDialog::AboutDialog(const QString &version, QWidget *parent) : QDialog(parent) @@ -37,24 +37,44 @@ AboutDialog::AboutDialog(const QString &version, QWidget *parent) { ui->setupUi(this); - m_LicenseFiles[LICENSE_LGPL3] = "lgpl-3.0.txt"; - m_LicenseFiles[LICENSE_GPL3] = "gpl-3.0.txt"; - m_LicenseFiles[LICENSE_BSD3] = "bsd3.txt"; + m_LicenseFiles[LICENSE_LGPL3] = "LGPL-v3.0.txt"; + m_LicenseFiles[LICENSE_LGPL21] = "GNU-LGPL-v2.1.txt"; + m_LicenseFiles[LICENSE_GPL3] = "GPL-v3.0.txt"; + m_LicenseFiles[LICENSE_GPL2] = "GPL-v2.0.txt"; m_LicenseFiles[LICENSE_BOOST] = "boost.txt"; + m_LicenseFiles[LICENSE_7ZIP] = "7zip.txt"; m_LicenseFiles[LICENSE_CCBY3] = "by-sa3.txt"; m_LicenseFiles[LICENSE_ZLIB] = "zlib.txt"; - m_LicenseFiles[LICENSE_APACHE2] = "apache-license-2.0.txt"; + m_LicenseFiles[LICENSE_PYTHON] = "python.txt"; + m_LicenseFiles[LICENSE_SSL] = "openssl.txt"; + m_LicenseFiles[LICENSE_CPPTOML] = "cpptoml.txt"; + m_LicenseFiles[LICENSE_UDIS] = "udis86.txt"; + m_LicenseFiles[LICENSE_SPDLOG] = "spdlog.txt"; + m_LicenseFiles[LICENSE_FMT] = "fmt.txt"; + m_LicenseFiles[LICENSE_SIP] = "sip.txt"; + m_LicenseFiles[LICENSE_CASTLE] = "Castle.txt"; + m_LicenseFiles[LICENSE_ANTLR] = "AntlrBuildTask.txt"; + m_LicenseFiles[LICENSE_WIX] = "WixToolkit.txt"; addLicense("Qt", LICENSE_LGPL3); addLicense("Qt Json", LICENSE_GPL3); addLicense("Boost Library", LICENSE_BOOST); - addLicense("7-zip", LICENSE_LGPL3); - addLicense("ZLib", LICENSE_ZLIB); + addLicense("7-zip", LICENSE_7ZIP); + addLicense("ZLib", LICENSE_NONE); addLicense("Tango Icon Theme", LICENSE_NONE); addLicense("RRZE Icon Set", LICENSE_CCBY3); addLicense("Icons by Lorc, Delapouite and sbed available on http://game-icons.net", LICENSE_CCBY3); - addLicense("Castle Core", LICENSE_APACHE2); + addLicense("Castle Core", LICENSE_CASTLE); + addLicense("ANTLR", LICENSE_ANTLR); addLicense("LOOT", LICENSE_GPL3); + addLicense("Python", LICENSE_PYTHON); + addLicense("OpenSSL", LICENSE_SSL); + addLicense("cpptoml", LICENSE_CPPTOML); + addLicense("Udis86", LICENSE_UDIS); + addLicense("spdlog", LICENSE_SPDLOG); + addLicense("{fmt}", LICENSE_FMT); + addLicense("SIP", LICENSE_SIP); + addLicense("WiX Toolset", LICENSE_WIX); ui->nameLabel->setText(QString("%1 %2").arg(ui->nameLabel->text()).arg(version)); #if defined(HGID) @@ -64,6 +84,8 @@ AboutDialog::AboutDialog(const QString &version, QWidget *parent) #else ui->revisionLabel->setText(ui->revisionLabel->text() + " unknown"); #endif + + ui->licenseText->setFont(QFontDatabase::systemFont(QFontDatabase::FixedFont)); } @@ -85,7 +107,7 @@ void AboutDialog::on_creditsList_currentItemChanged(QListWidgetItem *current, QL { auto iter = m_LicenseFiles.find(current->data(Qt::UserRole).toInt()); if (iter != m_LicenseFiles.end()) { - QString filePath = qApp->applicationDirPath() + "/license/" + iter->second; + QString filePath = qApp->applicationDirPath() + "/licenses/" + iter->second; QString text = MOBase::readFileText(filePath); ui->licenseText->setText(text); } else { diff --git a/src/aboutdialog.h b/src/aboutdialog.h index 103a0d2ff..adf8d2c7d 100644 --- a/src/aboutdialog.h +++ b/src/aboutdialog.h @@ -45,12 +45,23 @@ class AboutDialog : public QDialog enum Licenses { LICENSE_NONE, LICENSE_LGPL3, + LICENSE_LGPL21, LICENSE_GPL3, - LICENSE_BSD3, + LICENSE_GPL2, LICENSE_BOOST, LICENSE_CCBY3, + LICENSE_PYTHON, + LICENSE_SSL, + LICENSE_CPPTOML, + LICENSE_7ZIP, LICENSE_ZLIB, - LICENSE_APACHE2 + LICENSE_UDIS, + LICENSE_SPDLOG, + LICENSE_FMT, + LICENSE_SIP, + LICENSE_CASTLE, + LICENSE_ANTLR, + LICENSE_WIX }; private: diff --git a/src/aboutdialog.ui b/src/aboutdialog.ui index 50a9de5ff..348a33b04 100644 --- a/src/aboutdialog.ui +++ b/src/aboutdialog.ui @@ -120,14 +120,14 @@ - Copyright 2011-2016 Sebastian Herbord + <html><head/><body><p>Copyright 2011-2016 Sebastian Herbord</p><p>Copyright 2016-2018 Mod Organizer 2 contributors</p></body></html> - <html><head/><body><p>This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.</p><p>See the GNU General Public License for more details.</p><p>Source code can be found at <a href="https://github.com/TanninOne/modorganizer"><span style=" text-decoration: underline; color:#007af4;">GitHub</span></a>.</p></body></html> + <html><head/><body><p>This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.</p><p>See the GNU General Public License for more details.</p><p>Source code can be found at <a href="https://github.com/Modorganizer2/modorganizer"><span style=" text-decoration: underline; color:#007af4;">GitHub</span></a>.</p></body></html> true @@ -154,7 +154,7 @@ Thanks - + Current Maintainers @@ -167,12 +167,17 @@ - LePresidente + LePresidente (Project Lead) - Silarn + AL12 + + + + + Diana @@ -182,7 +187,7 @@ - Diana + Silarn @@ -203,17 +208,22 @@ - pndrev (German) + Scythe1912 (Chinese) - DaWul (Spanish) + yc0620shen (Chinese) - Fiama (Spanish) + miraclefreak (Czech) + + + + + Cyb3r (Dutch) @@ -233,17 +243,35 @@ - Scythe1912 (Chinese) + Faron (German) - yc0620shen (Chinese) + pndrev (German) - miraclefreak (Czech) + Mordan (Greek) + + + + + Ren (Korean) + + + + + + + + Yoosk (Polish) + + + + + Brgodfx (Portuguese) @@ -253,15 +281,22 @@ - Ren (Korean) + DaWul (Spanish) - - + + + + Fiama (Spanish) + + + + + Jax (Swedish) - ... more (Can't track) + ...and all other Transifex contributors! @@ -275,7 +310,7 @@ - Other Supporter + Other Supporters && Contributors @@ -283,9 +318,14 @@ QAbstractItemView::NoSelection - + + + SuperSandro2000 + + + - Al12 (Discord) + AnyOldName3 From 149ce846b52689b70781bf7716a4b480862bc402 Mon Sep 17 00:00:00 2001 From: Jeremy Rimpo Date: Tue, 20 Mar 2018 17:12:25 -0500 Subject: [PATCH 27/57] Installer license not needed for application --- src/aboutdialog.cpp | 2 -- src/aboutdialog.h | 3 +-- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/src/aboutdialog.cpp b/src/aboutdialog.cpp index 411ef1cf1..9b909ccbe 100644 --- a/src/aboutdialog.cpp +++ b/src/aboutdialog.cpp @@ -54,7 +54,6 @@ AboutDialog::AboutDialog(const QString &version, QWidget *parent) m_LicenseFiles[LICENSE_SIP] = "sip.txt"; m_LicenseFiles[LICENSE_CASTLE] = "Castle.txt"; m_LicenseFiles[LICENSE_ANTLR] = "AntlrBuildTask.txt"; - m_LicenseFiles[LICENSE_WIX] = "WixToolkit.txt"; addLicense("Qt", LICENSE_LGPL3); addLicense("Qt Json", LICENSE_GPL3); @@ -74,7 +73,6 @@ AboutDialog::AboutDialog(const QString &version, QWidget *parent) addLicense("spdlog", LICENSE_SPDLOG); addLicense("{fmt}", LICENSE_FMT); addLicense("SIP", LICENSE_SIP); - addLicense("WiX Toolset", LICENSE_WIX); ui->nameLabel->setText(QString("%1 %2").arg(ui->nameLabel->text()).arg(version)); #if defined(HGID) diff --git a/src/aboutdialog.h b/src/aboutdialog.h index adf8d2c7d..a67c9c738 100644 --- a/src/aboutdialog.h +++ b/src/aboutdialog.h @@ -60,8 +60,7 @@ class AboutDialog : public QDialog LICENSE_FMT, LICENSE_SIP, LICENSE_CASTLE, - LICENSE_ANTLR, - LICENSE_WIX + LICENSE_ANTLR }; private: From bcc4c8d6aaab9ca4a641f7fa6b71a9f927d9bb52 Mon Sep 17 00:00:00 2001 From: Jeremy Rimpo Date: Tue, 20 Mar 2018 17:18:57 -0500 Subject: [PATCH 28/57] Update BY SA v3 license file to match others --- src/aboutdialog.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/aboutdialog.cpp b/src/aboutdialog.cpp index 9b909ccbe..5ac05df77 100644 --- a/src/aboutdialog.cpp +++ b/src/aboutdialog.cpp @@ -43,7 +43,7 @@ AboutDialog::AboutDialog(const QString &version, QWidget *parent) m_LicenseFiles[LICENSE_GPL2] = "GPL-v2.0.txt"; m_LicenseFiles[LICENSE_BOOST] = "boost.txt"; m_LicenseFiles[LICENSE_7ZIP] = "7zip.txt"; - m_LicenseFiles[LICENSE_CCBY3] = "by-sa3.txt"; + m_LicenseFiles[LICENSE_CCBY3] = "BY-SA-v3.0.txt"; m_LicenseFiles[LICENSE_ZLIB] = "zlib.txt"; m_LicenseFiles[LICENSE_PYTHON] = "python.txt"; m_LicenseFiles[LICENSE_SSL] = "openssl.txt"; From 92a8a3dce863c80f540537162e7c7e415cdfd57d Mon Sep 17 00:00:00 2001 From: Al12rs Date: Wed, 21 Mar 2018 00:12:39 +0100 Subject: [PATCH 29/57] Fixed preview "file not found" error if the mod folder containing the file was on a different drive. --- src/mainwindow.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 2bf25b05f..f38ddf155 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -3938,7 +3938,9 @@ void MainWindow::previewDataFile() // check if the file comes from the actual data folder instead of a mod QDir gameDirectory = m_OrganizerCore.managedGame()->dataDirectory().absolutePath(); QString relativePath = gameDirectory.relativeFilePath(fileName); - if (!relativePath.startsWith("..")) { + QDir direRelativePath = gameDirectory.relativeFilePath(fileName); + // if the file is on a different drive the dirRelativePath will actually be an absolute path so we make sure that is not the case + if (!direRelativePath.isAbsolute() && !relativePath.startsWith("..")) { fileName = relativePath; } else { From 82d4742e2814755a4aa812fadb382b2831680692 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sandro=20J=C3=A4ckel?= Date: Wed, 21 Mar 2018 08:23:03 +0100 Subject: [PATCH 30/57] Proper variable naming and fixed Sandros OCD --- src/mainwindow.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index e5eacc410..cae5ee524 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -3938,9 +3938,9 @@ void MainWindow::previewDataFile() // check if the file comes from the actual data folder instead of a mod QDir gameDirectory = m_OrganizerCore.managedGame()->dataDirectory().absolutePath(); QString relativePath = gameDirectory.relativeFilePath(fileName); - QDir direRelativePath = gameDirectory.relativeFilePath(fileName); + QDir dirRelativePath = gameDirectory.relativeFilePath(fileName); // if the file is on a different drive the dirRelativePath will actually be an absolute path so we make sure that is not the case - if (!direRelativePath.isAbsolute() && !relativePath.startsWith("..")) { + if (!dirRelativePath.isAbsolute() && !relativePath.startsWith("..")) { fileName = relativePath; } else { From 0e0c72422cd0a77dbf7da53c502558548232b8ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sandro=20J=C3=A4ckel?= Date: Wed, 21 Mar 2018 10:05:37 +0100 Subject: [PATCH 31/57] Added new repos --- readme.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/readme.md b/readme.md index 42a41360a..0f3d94a61 100644 --- a/readme.md +++ b/readme.md @@ -56,9 +56,11 @@ Here is a complete list: * https://github.com/Modorganizer2/modorganizer-game_falloutnv * https://github.com/Modorganizer2/modorganizer-game_features * https://github.com/Modorganizer2/modorganizer-game_gamebryo +* https://github.com/Modorganizer2/modorganizer-game_morrowind * https://github.com/Modorganizer2/modorganizer-game_oblivion * https://github.com/Modorganizer2/modorganizer-game_skyrim * https://github.com/Modorganizer2/modorganizer-game_skyrimSE +* https://github.com/Modorganizer2/modorganizer-game_ttw * https://github.com/Modorganizer2/modorganizer-installer_bain * https://github.com/Modorganizer2/modorganizer-installer_bundle * https://github.com/Modorganizer2/modorganizer-installer_fomod From ba0a1bd50191fb6387489c6562a2e1fe8e0451d0 Mon Sep 17 00:00:00 2001 From: LePresidente Date: Thu, 22 Mar 2018 09:41:35 +0200 Subject: [PATCH 32/57] Updater and Issue reports now point to Modorganizer2/modorganizer --- src/mainwindow.cpp | 17 ++++++++--------- src/selfupdater.cpp | 2 +- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index e5eacc410..a79e42ba9 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -1886,7 +1886,7 @@ void MainWindow::wikiTriggered() void MainWindow::issueTriggered() { - ::ShellExecuteW(nullptr, L"open", L"http://github.com/LePresidente/modorganizer/issues", nullptr, nullptr, SW_SHOWNORMAL); + ::ShellExecuteW(nullptr, L"open", L"http://github.com/Modorganizer2/modorganizer/issues", nullptr, nullptr, SW_SHOWNORMAL); } void MainWindow::tutorialTriggered() @@ -3036,7 +3036,7 @@ void MainWindow::openInstanceFolder() } void MainWindow::openLogsFolder() -{ +{ QString logsPath = qApp->property("dataPath").toString() + "/" + QString::fromStdWString(AppConfig::logPath()); ::ShellExecuteW(nullptr, L"explore", ToWString(logsPath).c_str(), nullptr, nullptr, SW_SHOWNORMAL); } @@ -3237,7 +3237,7 @@ static void addMenuAsPushButton(QMenu *menu, QMenu *subMenu) } QMenu *MainWindow::openFolderMenu() -{ +{ QMenu *FolderMenu = new QMenu(this); @@ -3261,11 +3261,11 @@ QMenu *MainWindow::openFolderMenu() - - - + + + return FolderMenu; @@ -3950,7 +3950,7 @@ void MainWindow::previewDataFile() fileName = fileName.mid(offset + 1); } - + const FileEntry::Ptr file = m_OrganizerCore.directoryStructure()->searchFile(ToWString(fileName), nullptr); @@ -4666,7 +4666,7 @@ void MainWindow::on_bossButton_clicked() dialog.show(); QString outPath = QDir::temp().absoluteFilePath("lootreport.json"); - + QStringList parameters; parameters << "--game" << m_OrganizerCore.managedGame()->gameShortName() << "--gamePath" << QString("\"%1\"").arg(m_OrganizerCore.managedGame()->gameDirectory().absolutePath()) @@ -5076,4 +5076,3 @@ void MainWindow::on_clearFiltersButton_clicked() { deselectFilters(); } - diff --git a/src/selfupdater.cpp b/src/selfupdater.cpp index 273e9b455..8f962ba4f 100644 --- a/src/selfupdater.cpp +++ b/src/selfupdater.cpp @@ -125,7 +125,7 @@ void SelfUpdater::testForUpdate() // TODO: if prereleases are disabled we could just request the latest release // directly try { - m_GitHub.releases(GitHub::Repository("LePresidente", "modorganizer"), + m_GitHub.releases(GitHub::Repository("Modorganizer2", "modorganizer"), [this](const QJsonArray &releases) { QJsonObject newest; for (const QJsonValue &releaseVal : releases) { From 5eb03a687c2cc676a33b2accef1d4dbc46fc9233 Mon Sep 17 00:00:00 2001 From: ImgBotApp Date: Fri, 23 Mar 2018 14:09:58 +0000 Subject: [PATCH 33/57] [ImgBot] optimizes images *Total -- 173.23kb -> 19.45kb (88.77%) /src/resources/multiply-red.png -- 15.64kb -> 0.65kb (95.84%) /src/resources/archive-conflict-neutral.png -- 17.63kb -> 0.83kb (95.31%) /src/resources/archive-conflict-loser.png -- 17.63kb -> 0.87kb (95.09%) /src/resources/archive-conflict-winner.png -- 17.63kb -> 0.92kb (94.8%) /src/resources/archive-conflict-mixed.png -- 17.63kb -> 0.95kb (94.63%) /src/resources/switch-instance-icon.png -- 56.17kb -> 4.23kb (92.47%) /src/resources/open-Folder-Icon.png -- 16.53kb -> 1.40kb (91.53%) /src/resources/contents/conversation.png -- 1.47kb -> 0.81kb (44.75%) /src/resources/contents/breastplate.png -- 1.39kb -> 0.77kb (44.47%) /src/resources/contents/locked-chest.png -- 1.41kb -> 0.78kb (44.38%) /src/resources/contents/lyre.png -- 1.36kb -> 0.76kb (43.59%) /src/resources/contents/usable.png -- 1.31kb -> 0.81kb (37.99%) /src/resources/contents/hand-of-god.png -- 1.08kb -> 0.67kb (37.6%) /src/resources/contents/double-quaver.png -- 0.99kb -> 0.63kb (36.57%) /src/resources/contents/jigsaw-piece.png -- 0.93kb -> 0.66kb (28.78%) /src/resources/contents/tinker.png -- 1.01kb -> 0.72kb (28.52%) /src/resources/contents/empty-chessboard.png -- 0.69kb -> 0.52kb (23.94%) /src/resources/contents/checkbox-tree.png -- 0.64kb -> 0.52kb (19.15%) /src/resources/check.png -- 0.44kb -> 0.39kb (13.19%) /src/resources/contents/config.png -- 0.54kb -> 0.47kb (13.04%) /src/resources/document-save.png -- 1.12kb -> 1.09kb (2.87%) --- src/resources/archive-conflict-loser.png | Bin 18052 -> 886 bytes src/resources/archive-conflict-mixed.png | Bin 18052 -> 969 bytes src/resources/archive-conflict-neutral.png | Bin 18052 -> 846 bytes src/resources/archive-conflict-winner.png | Bin 18052 -> 939 bytes src/resources/check.png | Bin 455 -> 395 bytes src/resources/contents/breastplate.png | Bin 1419 -> 788 bytes src/resources/contents/checkbox-tree.png | Bin 658 -> 532 bytes src/resources/contents/config.png | Bin 552 -> 480 bytes src/resources/contents/conversation.png | Bin 1506 -> 832 bytes src/resources/contents/double-quaver.png | Bin 1009 -> 640 bytes src/resources/contents/empty-chessboard.png | Bin 706 -> 537 bytes src/resources/contents/hand-of-god.png | Bin 1101 -> 687 bytes src/resources/contents/jigsaw-piece.png | Bin 952 -> 678 bytes src/resources/contents/locked-chest.png | Bin 1440 -> 801 bytes src/resources/contents/lyre.png | Bin 1388 -> 783 bytes src/resources/contents/tinker.png | Bin 1038 -> 742 bytes src/resources/contents/usable.png | Bin 1345 -> 834 bytes src/resources/document-save.png | Bin 1150 -> 1117 bytes src/resources/multiply-red.png | Bin 16018 -> 666 bytes src/resources/open-Folder-Icon.png | Bin 16927 -> 1434 bytes src/resources/switch-instance-icon.png | Bin 57516 -> 4333 bytes 21 files changed, 0 insertions(+), 0 deletions(-) diff --git a/src/resources/archive-conflict-loser.png b/src/resources/archive-conflict-loser.png index 77d2e0fafb987ca139f7fad3cb6ad767fe2ea4f0..561e8be865f66baf10760d2886b2dd9db88d2dca 100644 GIT binary patch delta 814 zcmZqaW&FlAK~jR5fq_9omp>Rtv7|ftIx;Y9?C1WI$U0fUNw1!hZ-&O zowZuS^xMPr+rsqoU9~&H^%Jc$%Di+N0`=1DG>bj7OM&bly$pNJ0ypiY?ZrR?pDgzM zf5h|UQZJzP|6ASuzXzyBA#UoUoFpQ`u&dBFb@p8t<~{y*>a|AGJiOWyxC zyDYEI{D0i*|1H1&^~XH_ANBZu%IjFC+msadTeJNBpY{6xDB%Ao&#xQ3PV~q9T;ult zebC9t;b(fhZ_N$*yWZ{pb>AzKL;vpa`u{WZ{~6DlGkpJF@IJ9_2G9>@7Z(11f!BsCpX=g?zXwfZ+nybnJIx6rqu`kKj-!T znAiUcUfVmP&rXf`f7AE>cK3Hn-Tyxg_d>Fdh=h*_ME({TEh$;*H$&Uv~xhDcmaPDl_C6BJEONlHshO=Vy%Ck~wS|@C?j5^!R#!B!?s>AOzP9G?A7-Xzk*0%8iVG)oefyO7 z@ROI|#DvBbFC?m&x8JbX{-Z@;Lqo!%ilCq(udJd;#ZnOs-Lutg533k!TdPkO*Ew+N z+;RO0)8hj)SQvQ%6hcCHm{eUk8ZT}7)OAX$g@K2G;r~JP*0tB7HGy7JEpd$~Nl7e8 zwMs5Z1ya!rMh1o!x(3F&M#dqACRPTPRwkC(1_o9J2D&c|0#J11=BH$)RpQnVv!&w= PPy>UftDnm{r-UW|MyF%U literal 18052 zcmeI4TZ|i58GwJg&OMvU=F*lFFb%Q;9B3TKe^J$~@_=So1u`&MuA(+TX4_;{(+`nGv_MA9%3y5z z*zs7@GzMdjC-OqRI!wmQT}NwV|Is}o`q4wWV#Ky(muDtbbWkP@Ejn2)RqE>GV9fQa zqU?0@v8b!kI5Zd=asoyVx}zS(oq@{=QVy=GP$rd5eLezk%%-WZIh4Otq2UGW&bjk3aXy-^rxaNcxne3sxFU%g zTtQ4}oLEdJ3#5>c(h1_OhEDVL%$lxS(b2Vc)EbtK?%RB&R9aCIMB*d`uUQmHnp5PI zfro7zhXf*O>3A!U&)K{{U#gjSC(ueh9m-Y_WLZ-PC&qP!Q>3`gr4vP+D-1L-waaueeWWW5PHy&-Z*=yyGwq()RjpPh&WSV_YaL1SkVjS8GVaNSNpMd4 ztnTb{Vr2M^-uAS*&CL1fOfVtv{QJxojxjMtD)%}kJXfyP!cOW|u`!|5$j~V6AeJM{ z^V(_F?Y{ReK}POgESdL_h`M(8{?ec*qM;bL5+x}~xP%_pxI(HRbIFuYNNI5*3rVe& z<`0pE!|(zrNII2Mc2o)$|y0ieCx_u9UrI6$%TYw6ypU>Hwp#L(Bd*z zAVQH#$mz5srVO1V6Rqp}P?_t#Nd}o~9)4EkFsXfz;|~v64Xb&A_u^vBDo3?ywPfm= zbCmLjD@L;%rgxxd!;1Q<1dqGV$NzAZ8l+}^kQ2r?OTC3D`Z2ra`#w|IDitrS!Orw* z1@9i&S*^4xp!wBJtCaIr=T2u&ImOQV7c+PRz@JH~kGfNmIprnmaoT0xu@{@(v7mG- z@C7SOSxL+BgrRU!S}A%JW7u%8c_XQpGA2D<=0y%VOy|ug~Yr9XsGuo27BLnoLOoHePhzo2LHZZqtMJHuVp8 zo3<^#QZXA@sTr-S+h^tc)b)Oc?Z>}&NH&>B$aq)n?(VkOYfh5Vft-oI!|G1GEGC;a z-2*)h4=!Zr8)zDO+s5}tjGGv*7ystLf0%gs7n3h%v_Ajnh4vMF^uDRbAP7alA_TZt zC{djN7e&D$1h`lzQJnx6MZqEjxL7Drod6d_!6F2>SSV4Q02f8UA_TZtC{djN7e&D$ z1h`lzQJnx6MZqEjxL7Drod6d_!6F2>SSV4Q02f8UA_TZtC{djN7e&D$1h`lzQJnx6 zMZqEjxL7Drod6d_!6F2>SSV4Q02f8UA_TZtC{djN7e&D$1h`lzQJnx6MZqEjxL7Dr zod6d_!6F2>SSV4Q02f8UA_TZtC{djN7e&D$1h`lzQJnx6MZqEjxL7Drod6d_!6Muf z*Yfs58%PD8)G&dMWcco_=ST2y4pDvAzC6IuM*+V1ZGagYKQ94{3jmj&1W&U_!!_vW%56A*VFe_(tFSn~8sN?U z!0UhWkokRtlj=>7a{zCz-3j5ne}I=yeHNXB;o`p{aN9ly;YSz2Yfs;X6DL-}^*cDr zt`>nScL4Zhkh=UFT)8j|Yqt!++26bhQ&*Nk1lGgpUxy(Q4nrn&3t-7S1gNv>0f0-l z5!fQw@U{gT93}AqIRAVfY+ShtBpGx25I%5Z2B&`x^}1Sk`aI46fdO7NgwXglrt0Cv zux|BrkT~o^8Q#Ja&tm^-4A#}czq_!t?`Kb8?-VNap#rWvn6+WfEJwPIsEMztPRq?rKY+ zQ0S#!_9x`%%D#4IQ*!cg{?<**0z-Reb`Bf^bm*>jhqd$FY41A&Pi^6MbY$CK`}u3z UUkbhHCVBUcJ-J_PfAU-Z1t%6q)Bpeg diff --git a/src/resources/archive-conflict-mixed.png b/src/resources/archive-conflict-mixed.png index e71e0167ba6c26eff83c379db55e6920aacaa9de..df20532cb0bd0c1c0c9ee5f9059e44a5ac94768d 100644 GIT binary patch delta 897 zcmZqaWjx6~K~jR5fq_9omp>Rtv7|ftIx;Y9?C1WI$U0fUNw1!9bAV5X>;M1%4>elm zJ8QLu>9>dLw}t8FyJ~lY>nB=ilzHg_H8uq5rP*l~duTTV>1Eh!7Px5x1(&uLKUwVi z|A^yLTvtYFt^x$e_)|980m-{tY@;q7}TH{F;DC>?VZt@azd8V#Ip9uChnCjJ1gII zSt0j;Y}aYojNJs+TW0Y^`9)qQ9{IKnwaAZvDJC*d%OKK zbR(r%BW-CimC{ZjS^r0ow%+ZVpEECEJ?a7mCKC~{H386GZ< z)F(hO#w2fd7lsa2S&xZ|;`I#dC7!;n?2nkm`8W-yZ<)LdsN%k-i(`ny<>Z6}0Wm?* zGMbKEnBv2<#u9V7U3u>X>tf> zcUrJ}`S$hoOim1J47MAL4}7{TRK~!N!=PH?8c~vxSdwa$T$Bo=7>o=IEp!cxb&ZTe y3{9*IEUio|wG9lc3=DK%8Uz4C2caQ1KP5A*61Rq!Egf$_k>Kg-=d#Wzp$Py1Lv?uo literal 18052 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 diff --git a/src/resources/archive-conflict-winner.png b/src/resources/archive-conflict-winner.png index f62605753eec260bd9438279c8bdeeb6ffba54fa..5cc568c87e14faa4b719904b6905ad7f2b454909 100644 GIT binary patch delta 867 zcmZqaWn9fZK~jR5fq_9omp>Rtv7|ftIx;Y9?C1WI$U0fUNw1!9Qh-m0>;M1%4>elm zJ8QLu>9>dLw}t8FyJ~lY>nB=ilzHg_H8uq5rP*l~duTTV>1Eh!7Px5x!P55PCyRam zAMt#-)C;Kn|5msEF9QBw_5FX}@Bc;b*NffPr|SKG9`OH!=l|oL|Id5h6a8^N*SP(E zA9QkZ_?aH>TXTc{u6O%?-S^7m(7$`U{{Ia9f5!9X4B!73yicr~0rbP!g@ykg`9ELj zb8eFH|A+opr}-bA5PE8A$p0Pg|95%3dU*TZ$xSz=yKQdr+ur1UW=i0NY4yRzhC2U` zdHuiOwY@X??9>?h>7uEtMBgoS|Nk`L|1IBBGkpFZiur%cW9nJCxff&?-YbT z-?2V#V*?#yBb~0(a^0up7L~>P-{5j;mao+`vDxS4r<{{t_fTp5L#5dl<<{L&%sQaH zI?sJ?x1XWDj^#A5tbMYHdu7Yc%C}us@XkFT+jUwtW4A)!HkrON@=3d87GIRNnI`5q zL+t7KOZ~v07cL3%1H~OG_{zi5^CAu?#+c;o?!wT)D(f*(QM{gky~NYkmHiR3I3K6s z^evN@0aZNmba4!kxSX7jARs0vnw*l9mYAB#z+A}bshKHh=w??Q zEX@0Okh4>PaiPk`Cr^N8efjdG$H&ppku6W|-kO}ra~|B;^QY<1qDMk(VP$r8jh8lk z>N>UR)vQ~)s@OCbw8U~USTY-#^z`%&E=!xR(1S^Ltpg*&nj&rX$BlXU3xNJrEpd$~ zNl7e8wMs5Z1yT$~28I^82FAKZ#vz6#RtA<C<-DHN~l`V&{6_QOj-yKa%)ZMHcf2D!+&OW&yLsY zaN1O$N^_*${r8;za?bakIrHy6%u{=I?^xAwZwCOZ+O@N9FMh6}ujOs{{@E!<$B*{X z&I1*I73=6L1V8xUrvbLUX$|bJ?(hGiX4oU$x@qT0_xMN&wE=pzjF)ud5UED*jXjp^m-X6>U5l zbNy;4({3>qbycc|vazi+V03@~o@lRKCedVfN-*SjCYn~e<)oTX5?xV6l2f9jigH4b zWKB{vNsiW9EZ2cjPuVPJd;7N6!r`}UY^Yi-X`(nbHr72B@3zZ>qO7W_C@G?%2&f@c zjufl(t~6vd$eqjZHI9wn_8{DQr$}$+2L@7>Mb2rt->OH=*XfF$hftL z86EM=+&$%`x(A_Yy=9_T?ec(a59hq?x~HCtXm2mwp6Terk6A_29;8ucVqXu01a(Dy~_U zNk&lPX%i3Igp$rkMAkEjdLW;(1%bX)w(w4%5Bqc&TUCn3b(IKm!cYZO!L?+P1zb>G z(bbF|FT^u)JwyvP3qtL*Xr_-erGe&VANkt+-bSX~GrOdhD}`a=>ztT9;=JC*w3^MVh3QOkA@KbB%omR_HbjcIJ10C>uGZpCDt4hdrkBaq zLA-)^jxf*be6wcvt*;VfardKO?_sIFxO1%PFSl!f1Id6Avr`HrMcK&-YgEs*DnWXus(~^vqm%PVmlli=B zvF05MO1A=Ew8D(5nRp^;s)CYH3tokpm(`R|$lxiiBqY-`u$1+t>T}jAmVKv1rWd7! zn?|&H9{L)%eKlnd{S~QUm5LRUd!*&CbY0Nr^X882r`6{0s9Q~@6$zUt)AyRGf4JH7 z!0k=_!_B4*%dZrzY7Xy@?qr&}eOC0RuJ=1^AO5{Va;ao8p6n5uyPGZcSmR`Pf1icF z!z#31mQyvG=7E-m2NpB*4b%+1%f|OdjGGv*7ystLf0#t}7n3h%tUmwvg~p0Le&5Vv z5QL%N5dvI1l$cI{i=p5V0$e7V1ZyIbGa<)8Rc!zK(Qaqs{j+fSZy`AImr2?cdhR#Z zV8gnl5Do#<)ZoZZU!!BJMO^9UJDiQ%@c9&P18mqBf(>1raP<$f&OT2q^xTPe;hxS2 zc%hiBD}-Mthz=-d{MVZR@6G~ToB^0~;O^{l$bPvKvdRi4qvf14f4>QnQ*-mJ@mt7w z=}`yP;Y6;YVc0i*3*&8Eh6HBdrQ@@3Y9a)Oo_P@$Grxr=-az9ijQkl??p*3Qp~mam z;QH$`@bbyKA-)OV(94zC^$!NjpJ%$>f0kLf^%YtYe^X?W}W3P=i9 zp{@TefO8+f**|*7{64}dZ3^Oj0Pn2b4&gn&gj2744xNPI;y)rV?Ys%$2bRL0o}Gph zCsx9>TR6+67II$P;egl<@Wu_e^3ZqSy^DW_=~Lf@i7U$?0yklOX9q;WVKAOK zcCJ(5^y$;MCc5I)O8_oSBe12g{v8|cU-o@?NL~VwWvg%xtcQ5w28fR$BWx=Rmq7da zW%@i4*20r--Ex5eE*nA!c^Xr7PaCYe>l!Em_Mr?HFvZxunres4gUemH{ucSg`L0#B zo;o-6_zqNhm=5BMW*nHk?m(i5yRM#E^!+~izCPz=a`WcR?^7p{iC2!jcj4`s(CcTz zAa={nuj_igd@a(~rZYF5|!ktmq#?N}HXct}cS_HkG!p2q~yR8FHwefy-0(a** h`h6wqL?({&ttbEelUoO~muc^=ZM*xPf8>cL{{vyxU)TTu diff --git a/src/resources/check.png b/src/resources/check.png index 0f294a02e2dbcb59d77b3bd752cea05ad1f7b038..5df447552d7325940e0c6b2cbe1131d314a64369 100644 GIT binary patch delta 353 zcmX@k+|4{eGKhtNfnn<}^H)HMCEd~2k%3`jKlh(RRv=#?*(1o8fuTx`fuW&=f#DZW zsNn?zL#Y7+!>a@a2CEqi4B`cIb_Lo1C76=D-CY>|xA&jfKhZ(1{t>e{AE)8;Et8i4 zZoTE2VkVy?{!7ZeUCs1@uz5TJ6WVYe+y^r1s-3QHC}`u}gs zdbZDT&o&>FU(a?_aD`MAOSg0XqQqqfFKwP8Tr)@RMA?P6dffBga4k$_+Wcq(hgaFM z`!REN{W{X@%(aa})-^!!lvn-KCm!M#LjvFb`MoAYoqdYnC}Q!>*kachX#((wkU Pfx*+&&xK{3Q$iB}Tb_Jf delta 413 zcmV;O0b>4(1IGi987Bq+001BJ|6u?C00DDSM?wIu&K&6g000JJOGiWi{{a60|De66 zlaXs4f7}8T6FC>3r0@s;0013nR9JLFZ*6U5Zgc_CX>@2HM@dak zWG-a~0003VNklU5Jms2(nTo{RBoaa93TZJ*c^k3&Rs4*Lq%a~E&xp= zZV*v(0wkcKzzr4h0cM*`l+A*c-4r|0$dcvvf9HEVCT7Mf@rD=U*8)nZ>z@VEH08eU z-?J>c-+Qwb4#SX#VSv^e0AP%{N-0mP1mZa6aU7wwhUa;(Z5vX`(<%o_DQ?>qT5Gtj z3nIe#e5TnRq-lD2hU>b9)*31OJng+%gD5bdX`#XF%9A@D!4xa7aR?D)GBnd6`h#p5d%Q7y@ z@(wTAUK9X;D2jNRCLE7P_`Xj+zA-a@%c3ZFZhtQ6-+$u=_vyFZE3xyz00000NkvXX Hu0mjf*8#4w diff --git a/src/resources/contents/breastplate.png b/src/resources/contents/breastplate.png index d3d39407ddb9eb8583037485faa75ac715963b62..f8c787e2960c60dfc050728f9d562d3e5dfdc3dc 100644 GIT binary patch delta 719 zcmeC?p29XkGKc{P!UR<{fD}u*qpu?a!^VE@KZ&eBzCyA`kS_y6l^O#>Lkk1LFQ8Dv z3kHT#0|tgy2@DKYGZ+}e3+C(!v;j&mC3(BMF#K=tKeKEak-ar*3Ke~-zDGVCAplW$wAZ!=#w=UfNt>WOWNe#O>DGuBFW3G2EX zN#Ilr*p(r0ap{Xia#Ivij=V}(^ib`Q=6@NR8B?q~mIxYop1Jw2#(K@!z3*Rd zY(D??_;=>>?Njv?gBtp)jc4HJ6(*{*H$QrG+V{nD2=W-pz1 z7e{bLUE28~X_3N_=ncm`C*9e+c<%gG329dbi;u@q4ZuS87j^{<ra z!L;TeNrN|@jxL6Mf|?a;7_Qxo`4Ai8_a%+*$77p}Xa7Rjj_hH7`i?uiZpp#xt8Se> z6=Q#X!Cv!MpV!}CUv*xz*=GIQOJ9#pc79r~Ho4Sd<}3S0YbQQi7p9z%Dn;XQ~uEe<{TEVH0?uG0QHC#I||PI)!e?NUp!&cSy+9~(LYcRy0spKS)$d~QH z@C}i=2u4CeNMYTC;f)575+z<(ftEKRV}_VG#Z=Ur%3g>JHU$~{B#~LBnS1&EuQsct z(|O^|{|nE};W^LqIlt$e=bYaG0K`5@vY*NS2iOuo5Ci~!fZ1$DMMVWP8Vvy8`0?YY ztgM7msSKNwo}P}TrY2-&W&!|IDita!Do|2V@<+^ni9tJh^eB6JdMJt_0dRhPo+Nqp z>{$ZfxpU`8l51;g{QUVd$H&L{`t@tBtgJAof`S49V0LykNz&u-5CB~+7wvXCQ&Us< zdroPPB0fHU9tMK}Wo2dX`~8TGjfKnQLQ+x^^m;vphljDcx(c7q2c=R8qtO_)l8ucG z{P^($0AMf}002&>6M`T>r_&)hIT@XuomgC4#Pag;W(ks#lF-)Hh7TV;AP@*3CME{? z`T4NfYyg0~ygW#yQq0cI;>eLBsH>~PvuDpRHa3QTk&zKRdGZ7`H8n^~OvK#W925!# z&YU>|0I=C?$j!|SmEhgGcW7y8L27F1W(gV^8uEy$Q z4=IsI=yto=)6>HX7cMX(BZCTsf-04YSy@@MTCIHX;sre(4`nhLo12^IcDorLA5Xj8 zPLiB|n3$kUCgbAbBJbR}6D$Kl4s~^P%*e>#`uaLava+(02?+^QtJSpGZ2VhRtCiQT zT?-rU@9$@9Y%CKJ5@@klNRnQ!mnM^mmoHx?Ne&GSZSH~5(NSnL8kCfjpu4*p<>loN z1Oa`0eaOqp!-EG8px5iS+{J&ZxVRYa-@nIyl`B`^a5!-O{CUL0#NgAXPq=;iHbzHB zF+4mRehU6JqtO_)x}AK1pjKB`DVNK)j1Pd@HlpI%l zO08B$53sPXux9{K6r%^2nwrAK#zxf1=jP_%cDtho`1b7^dV71L2I%bUjOY{bHf(5r zXu$gV`mU3UqKNzV@9!O8W@ZLguU_3%a{|(P;JzP*hZe$;nArEEatI`gKb`r_+ht++2vFh{D3c9RUE_bSVH-sZ@OX_AN=$ zZnrZhCx=ZCmb7fPkl-2-T~S{^%gj3Xl>p^N42-MdUqPNqa63G&H-9mTSHgs^z<};&1N&DQYrKE^TQsMznj5epxJDuAP6*>Onmj~RVdEA zd-rw@AeYP8-rmkYAP@>LGc&_Wmo7!z)z#J2eDmf_XkH)?U|U-oWir|BPl3r~;=sTF zeLf#avcA4PBEZd?H%XE{pO5|h{mjY9iT)S{?eO8lv{)?EYPAu4wOTDG&1N$X9Xb@z j7XS|gDfUbI{%`mnvzg*0*b}sk00000NkvXXu0mjfk|3V? diff --git a/src/resources/contents/checkbox-tree.png b/src/resources/contents/checkbox-tree.png index a44dd5fd581309fc457c199b69301759f89237ec..f4a63237868a90d74213f6f2e64c89ac13ed285a 100644 GIT binary patch delta 461 zcmbQlI)!C|WDo-ogbAu@04bJqM_)$E)e-c@Ne1&9>AYTTCDm4a%h86~fUqGRT z7Yq!g1`G_Z5*Qe)W-u^_7tGleXakgBO7eDhVff$Pe`fzgLy3C!5>H=O_D9U(e4K{U zw@h9JRPo5u#WBR<^xeyf+)RcN$3D7upIooF=6wHx!&dKRJ=9_QsNCUpw(3QxBM-OP z!4i%rzC_nNw&sj2o#Cc;4s_1rQv198ApgCMADR9~toy)rrItZLGgg^Vhiy*rxt~{j znXdl0QqOd4Tkh>wtQPI{i4tyV8S*8M%#t#h@()QQ_k4ZEmLcTCp{Ok0aJ{$mEQ|PE z*&7ypk9letJeHPf3eRa$;3)fdc<=mPjcKKo4EJUPd1=0tNZ2?XNcZbCec+=BN(==F?#bh#3_`P0#55ZvYZg02Sg&+v}0B*_U za$!21egXSXE|&vIk^pp`z&%NlgyC?gnk5p6&$Vssg9*~!Q4IYn2GeEgqM!8(Rnb+%eCBS#G+wI6^vkET~ ziKx~_qfrxf`BZ`s>44v_)ZT4NRotDET-^^#iHtiNz*h4 zg19?xyWK(*#VY_o5D0}rs>NEa6#(!&4~n92I2=@ebEngZe!qVOIG@j87zPZ(+#EWa z%``z&t5vjGE!C{iXnd~U0D$8-a2%&;gJ((in=l*>W3$;PJc^>w>2!VuK$d0jJg@Ks zL3p@dH^6?s$6zo}c%@S5=KyXgpU;D)Y1J$c2w*fC{X2kmyM6cSuGecUmrDSE0XqJS wOePa4j7B3)r_1QWDo-ogbAu@04bJqM_)$E)e-c@Ne1&9>AYTTCDm4a%h86~fUqGRT z7Yq!g1`G_Z5*Qe)W-u^_7tGleXakgBO7eDhVff$Pe`fzgKZ$zw5>H=O_D9U(e4K{U zw@h9JRI$#}#WBR<^wG(NT!$P4T;p?E8fFA{ESbQuabnCN;i@THx7=oqSSof?DM8TS z{-Fh&MvR^Z_%FYyDVuRzeujhJvOE0u?<_eQ@PFd@>z~T@-(qN0D6>0OSx{Rp%gABT z>R-w$xgq4a>dStQsT*?ZjczkICaRqKDARXOd=qb}h)SD->=&bm1*e`y&RcDpRC+Rf zw~_3Pr270-`ztiv1YFS6K-)-ZL)C(_e9(J28DyMDzD;K&PvgxJHzuB$lLF zB^RXvDF!10LknF4V_hTT5JM9y14}CtOKk%KD+2@Fmj(eq4SEP2x%nxXX_dHj#BAw! TGcj46i-Ez@)z4*}Q$iB}2g8t4 delta 488 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 diff --git a/src/resources/contents/hand-of-god.png b/src/resources/contents/hand-of-god.png index e3a05335e7bc3375790dee07c650e9978fa32941..7cbd0102924aee745098262347521e98499a89d4 100644 GIT binary patch delta 618 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 diff --git a/src/resources/contents/locked-chest.png b/src/resources/contents/locked-chest.png index d70d448e9e99fd8ab71b76653377f4cf59d34925..b49e11651ebf58be8195b36d05245fd3757dc97e 100644 GIT binary patch delta 746 zcmZ3$y^w8!WDo-ogbAu@04bJqM_)$E)e-c@Ne1&9>AYTTCDm4a%h86~fUqGRT z7Yq!g1`G_Z5*Qe)W-u^_7tGleXakgBO7eDhVff$Pe`fzgLy3C!5>H=O_D9U(e4K{U zw@hBfz`*$4)5S5w;`G$Zu^yKbMUH-d$f9srjt+mAjr>D_weQG}9{m(t{oB`=;_O@w;#Bs&dH1vv}X*OVSPVr~ST= z?9cFF+u|iLE=oR8JA?Md$CsD(WhV2ys%|{;L$Ud_qXzFTzRwS+!paQ(G&LUJsy;hy5gh0cSgqE!rhPl zww~Q7R&VK_KjHt1`(|%AeX8!<@&P6g)e_f;l9a@fRIB8oR3OD*WMF8aYhbKvWE^5> zVr5`yWn!sqU|?lnp!?Dw07XM?eoAIqC2kEdTRPqVHAsSN2+mI{DNmdjBFV+T;OXk; Jvd$@?2>=ROJyiez delta 1398 zcmV-+1&R8h2A~U&87&3?0047(dh`GQ00eVFNmK|32nc)#WQYI&010qNS#tmY0Nwxq z0Nw%J>Vs;N@B$})1szF5K~z|U#g}hLQ(YX#e|MXk&go{PvKQ$VGBrVo)S)sk{|gQz zhB*Hq7zhzTZ!E$QD@9Nia;cYApyEVbp-7fu`oc)WAO$TYMsqQ;vZB>A+4?>&V%KNc z{`L4g&le8d^Y8cl+;h&o=NyKJK>woz{wg9PBT1*zQBhHU5eWnWGMmjbIXU^SK;YM; z(P;4M)hhtN&dv_5UcCyjSd8@abTlxayS4QjfOMd+S)=|S{f=UD)8mY7X*^a<$}dxL2YgA zpTPWlkV>V0u-R+?0FTFm)2B~EqtRezXD6WfuiD<;MoCFY_yAp9U0e{BWpVWAQ8*lq zu*_#?XL0=aaipZApsTA3j~_qA(9jS{OG^U-$Ye5n{rVLE@cHv+#Kpy-x3@Pe^SgKN zLL?HwXf$%uxVyWH>({R%IyxFEl?siGjnHbf;Pd%^z5p#PEnJ|Uo*ty6q`>WVhiq=K zSRfP%F*G#9l{p*^sMTtyR4PnPPU6RpA6(to*qATC$jAs+nVXyIGabQXwOS#SO2M)$ zSN87RJEWzhp}f4@?*c9_FW(1PUS0<9bNG2Y9#&UZLk6g-szPODCHID*E?|~r_W=|N z1uk8Gx`f-eZ$l&!`3zSe&CkyxA|e9o>+4)uPfrixj(7kC4e^xO3-DzPM$o88#iwF zn0h=OjE#+q7LOi1!ueT!SSZsF9aQy?N_XJGI{vq);fRzP_H;*4D^ovr$1o0kJGgb8~YP9UVhA6)rBZnyzTfkJS2HtzGi0$?h+!D2si`5cSWFi$UZljtL^2o*R9#(7 z{r&y)?AbG77>4rl^61Q&Gc-LtO$7x7!NOC}5ol;=AhB3X=gyrwP$!W{sI|3~mX?-i zczBp(G8w&o{hG{Xb4cbP0SJXc;`8|=7K;P6i;Ih+$jC^N%jF>%dlhgBwzs!`$?0^` z=H@0zBoeaQ?O_EEMSe#hGc%Lyb~_~`Bv5m6GmVap(zkEl{yPAzR!df^mFDK=xG$i& zx%tom1Vlu@?@#6o!;o67Cbe2kCX^YbY` zKmYInwzjtD=FOW#^z%M&<;oR*s;#Z1tgNg1fW z92`VuW+s=Po}PwWF8}Q&Lkk1LFQ8Dv z3kHT#0|tgy2@DKYGZ+}e3+C(!v;j&mC3(BMF#K=tKeKEak-aeD1#UyqPLiDMs+Cz_})@n2~cxG>OzMJjB|iBpU8?}!L-ZslSP z>^h-gq`@_d>$b?&iC!6oncaUhde6*M;8`ef+_j@s@Wuj-u0vP5?>@VqRP=7{%-x(- z;m_wh-)_+fGlv-F>Km#6gCb^SNz&VKhjJiWPW-*Wk5hc>rA+I@E8 ztJs~&4*zfJ%4t^rp2~4ydT>>B(ngh+OoHER+or2UTs$cuA-`~07f0%(C6gUKDlfb8 zb;-F`ImWBzv3`1R#xS8>l@WoX;s(com z5v28@ZJ{FHtHh#Eseq697D}G0(;qIn)Ho~A!1{xk~S$ z;_wCeAG|J^Y}wr$SfTz>yQlK5gPg#GD@=3h%b346o}Q%D(AoR)!3NfxNn2j93*4Q_ z<#(2Gy|8TS*MhmiIjpf75CA74mkSn>1s?3uYLSy{*8?t6S` zzV2T&bLzQiRt7U>eHT$NU%K5UTOxC`tE8qE>|FZ9S)Rwh} zXPFK#HN>lyxJHzuB$lLFB^RXvDF!10LknF4V_hTT5JM9y14}CtOKk%KD+2@Fmj(eq i9S9A%`6-!cmAEy;Z0UG2(M_F;fx*+&&t;ucLK6VBX)}!g delta 1346 zcmV-I1-<%@2J8xu87&3?0047(dh`GQ00eVFNmK|32nc)#WQYI&010qNS#tmY0Nwxq z0Nw%J>Vs;N-U26o1nEgcK~z|U#g|=3Q(+j#e>+WBVpdGDf+&b6mPR#@ippsA2|*y; z1YLAvI09`Lg?6z>(6H>ziX(=j?ecfbbus{ZDfM>+lJO!-3oFCObQS8(r7&`Fxx`dzMHfGOolk zX3U_Zq=dC=*V5nLPcRtd%$YO1d-pD3twgWl;$n$JBGS^*BE7x65>)Nnkg9HKrwg1bPFVfc5CgE^cwr<@zeEsjik|j&TG)-~4-LhuQ8p+7WkdGff%1{LY z0VygflB}$MEYUPgC9&CTl9Q7oWo2a&3QxgG7 zN=igTRDz8gH_G|*=T)McH*bor>nb)3Lq320EZyDRVw$F!@9XQ6$B!SYc>n(WvTxtM zxZFE->`(xz20nfI1i-Ro%K-TC;|Bu+0|0#c_Klr?J9pC5)I=y0qP@MHii!$?!61W! zgScESJRT40)~&;8wNh4AMn^{n0J^Tz-Q69RyR)-1u?93v6R+1R_wV1Af`S48#P9cu zh{&y5w*-);rY7-tJOYTW>#}m?O3BU5m9DNX0p#e>qjLH3WzjTE{d^}+o)nA4B1euK z5x?JmFK)Lxt_IXMV45aguUAo}r>Em|Isv$H<;ocKo+#5axq9^~2M!z{H#Zj%p}f4D z^78V8wWGcVN=r+bHf35hZj1{6pr)n)TvX)2ADp5I=64%X71d%hzNy+h3LBe*8p$dzEyR#di84R>gv$6_|L4Ol#~>% zU%yUvb~XTYb#>gkcki#wqdIl!6oEhhfc*S?s;a6+1~_!+5P5ld0QB_qaPZ*437Z3d z7=}SXK>?;|0^sp@*uH&xJV0hABwr!)Z zurO|}p`jrLP+woq`}gnFO}pLBg9i^-wQALb&G+otLqkIYQ>IK&b9e6C;pNMJmob2W zfdLL5J{-4k&YU?seE5)>ni}TMpFeJ6r_+hg=i}nVi>ly8^HSZ(g$oyCBpHSwckkYn zH*elZRaKSDoH;Y0Bbq&Xw$#?v%BxqeX+~1Co-GB8`oWqi!Cqo}M20 z{{4H>>yI5fHc}fOKVh|6rLwYrGU=qrNY{1MXZ{f&dTrXYNnX5oF=6xO=4Np?9Ah11 zMnBH{*R|9OO)bIvfJ(C<>j$_`Enc%2X?!i z^z?Lo{`^UAZ!evlojia3oM+FT(cIjebRU^Cz`xQj>2o1rlR$7;0000907*qoM6N<$ Ef>&0a5C8xG diff --git a/src/resources/contents/tinker.png b/src/resources/contents/tinker.png index 9709cee86d2d7c386bdb6c33184a630ba1b58d9c..dceb136762022d92b0695d89e82ae121d4cf41b4 100644 GIT binary patch delta 673 zcmeCLkk1LFQ8Dv z3kHT#0|tgy2@DKYGZ+}e3+C(!v;j&mC3(BMF#K=tKeKEak-ak_W1p@(##NPGRo6$!>S!lpP}Y-kF0yu9#;>js64i@IVj179de zXqRL!B=>gqz5liM z@7mUttN-2IB)s~h`_;qs(_jCNw_3Z+jCoFZ_=8>R53H#*VA#>Kt943uwqU>DzD8Eh zpw&wvigCq z&*ThNay{M_JxS@fMQOltug4l%t?z!6c~|Bi*LWJ#Kb^5_{3e>| zqY2-qe)+?u@LQqQe)_zr4LL8G<)?p|!0US0{_l>k6K(Tmb$;NMzjxu^xW(trP2SS4e%xQjPNlNv*U?Fn*Y2&Kx-snBzp5K@z4v_XezbdFP|PaA ze%kr4j|b!G_@9SIpF5SRYfff2-C$^~`_S6t%>56HWYrSah?11Vl2ohYqEsNoU}Ruup=)5QYh)Z^XkukxX=P%mZD3$! pU}m8E(jWjuM{a&fW?Cgq9R@L5I^IllQ|Dq}@O1TaS?83{1OPt|8two9 delta 993 zcmV<710MY51&#=i87&3?0047(dh`GQ00eVFNmK|32nc)#WQYI&010qNS#tmY0Nnrp z0Nnv_Q=$ixwE`!91B*#SK~z|U#g|P;Dp3^2k6#7lqA!Yp$cchhLE0j06BGm$wX2AR zpoLH-v?&l<)Fu}exDav?(IQ$zw9s~;L4iVP>w*%4qD5fPA}~k!zlF@?ycu=02k*dv zJ9o~#|KB~_bLWnRh(Q0*v_eC#*VEF{5*-{Ikjv$wrlzKUUr#Ez^u zy1Tm-&5DJA*Xm4+C=`Vo}NnPbGzNe;t3qbLCI376f71?#Qy>R%sbl1Ch;U5sSs(^?K3V z+zh|pFN;a1)7aeHgvaB7%jLr0;Gpt3PzoX*k0Y1Mm0Z>8>M9l%7G&b%dw|s4z z&1O73Jt>M`UtgoXz8--NHMQb@zktX$4i68@3IqAC+vMbA$w_BsW{}Bb z;BYw90SpZdNkkqW9}xyr0> zS|XxUDn)L$n>IE!=x<{fMr?n4e8}FHv(C;=$@A9M7Ik%XN&3*y(V<9Rc)tUH;o;$m zGjMfvCELiMP^fS}C=V2FuY!fc;bNPpq-(WW*zI=NE)e-c@Ne1&9>AYTTCDm4a%h86~fUqGRT z7Yq!g1`G_Z5*Qe)W-u^_7tGleXakgBO7eDhVff$Pe`fzgLy3C!5>H=O_D9U(e4K{U zw@h9JR3PB#;uvCadg^3*k1L51$L;TNzO-EFEW+x?>uADa_G0Ec(HWN}Xqvbd zbBySCB7b46f!N&^Q%?1&FVj}@ZO!T_xx<;-3T_l zEv$9mc*xu=O?Hj^nPH~W(!Z?IyZ+30k@hOv_OGGIOBuxT910Cxj$O$KzVLsWls40Y z%xzua$_^KI>>MV8#i>23?u6jSWcq{!(eZfPW>sRViBvu43 zXE^tN7Wd|j=eC!J{N2ZH?D%NGEv5s)yCuK+6t!HOFPIVfyV3Qo_IcgMuj39U%P)zK zKg-7~`g<3{k`nb9-;2~fhTV<$&UK*NmnpMX{?Cbm4V}IWkA6Luco^jHBgDfa^HD>A zmO{;v1xKbIR#TjEPSB1aWUEM6%8>W-^Mbnxxs*Y|>scQ@I+e%yT3;bP0K znbGEFBTH?9G%ju8G`(F>@Fp;J@3iBuuZPTk?kXKzx@;@cf=#($SHHJzdUtZwuK5vB zUT>bK)c;p1IU?yB?cTfjX2qQ-RoRm^b8_@856)e9>tAb%)!djDt2zI+KmX6v$FgL? z@^8VDfGJ3|#5JNMC9x#cD!C{XNHG{07+UBW80#7thZvez8CY7GSZW&>SQ!}TzBC9x k(U6;;l9^VCq(K->N6eOvHxu2|xfmEcUHx3vIVCg!0304hi~s-t delta 1302 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 diff --git a/src/resources/multiply-red.png b/src/resources/multiply-red.png index c238f07f5f2e8e854bb308356770d79cf728a5ae..f35adc741b48034ee8a9f8ee7b97f48fa464986b 100644 GIT binary patch literal 666 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJOS+@4BLl<6e(pbstU$g(vPY0F z14ET614BbI1H;e%K>8&EL#Y7+!>a@a2CEqi4C48d;*Yuk)vgHe332@o1Tiijy^P+v z=)AC1eQYj&&p_gqrqF+H<1-QrKq(;l8|er{KSOQ51z2FJysE-;NuK?jG&2wZwLo+M z)&F180o3w;elt+l{~5JFjsGW<0&V%2U!~L1~lz| zm>tl-{{a?21EJ3N|6kZ;(lel&WlDnlK>mh;28RX*1OV~g&udo%N-`#SySp%Su*!M> zIh+L^k;M!Q+`=Ht$S`Y;1W=H@#M9T6{SmV`AEy!D-a|4#p-rAHjv*44Q~TYSnj8dJ zq>YspaC9j3vKTg`{QZAf=6hD`venl)b)qu%m4HLGx^^Xt}Ss_N(Z`LwZt`|BqgyV)hf9t6-Y4{85mmV8W`&u y8HX5}SQ%JanHp#t7+4t?l-w?rMbVI(pOTqYiCY6}+u4Oc4Gf;HelF{r5}E)mOY^M& literal 16018 zcmeI3TWBNK8Gz4jmbU98bV(nYq@fWCOD}XhGaB7ykhPL6CpL+;uGeY2fzXU+j_hG2 zjj9>1wVQ`HErqsErB9{wt(T|LgwQk%hR76>LTK~QLI~N?KnO`wa)Dm5>-A>U|39P4 z_*g!eZc1Oyz^`-u>pAnCi}a%JEu6mZ)`>eO2qCx5&s7$oJ%RG6Pr&Eh|Lob&9B<8? z4G6jUGbl&MkAHGIA?CZ@(sH<5eZX@3#-#1~D|E8cXhAd~g;SlD?VO`wVuh}H&8g%E zTis;BbElFIWvW`WHAC0Dxr=Rj=Hlrk=i)iXbd#rw6NQci1sXK86P-rA8CadEB&%yd zAI)kq!9v1wQ^_(8m{_hZBxd|JO=KpsilZC(M9!SlGiE-O{z@XH=~-1XRXwd}x}}+x zrYHJOvN!>~LffrbiGRAf-6LIbDmwL;HtCa|u(;;)BO$s`UmeERRzXblHy27PuwQSI0*RiD(uhSSqtZHU&}JAwo<26OwdRL@u;w2yTv9_^KCT74jqKE=K(<< z>DbI*=|YRDi!|`p+YX&Q53h31xVI0z+Guh1R6@^zbEh5efHd?(X>2P*D^!4YwPxDX z4*m9$@7IgbE?XENOw7#SuF568_>k9h{f*#D1(i=3t@o%Jt=J(gLS|mk3`Nf_!Dh@D zmXT7lw54gWB2gq)qw2d}?ZUVkY0JpOYs4b?8gPDGJG2i~B_12A<2qK&Z#V3)=r!zB zs;RA3Vm!8f}V> zS5%5c9b6>vYvG37rsY-GA%{8nQPsU^eEEWk-vxE=f3OgNeg4Ll;c%zw2A3gzL;e4j zVYG{#HM_Y=-J&|!zyrhKRxVo4y(epMTKAvC0)9DJaEf6^+3fV_1$CcoG;$QbjHj`_ z&f;?^4IWj;&wgs$&8MCfr^elU>L~NUrWY1d{n0pcEDOIuqwD<){Me(#Y$jvC&BdGf zj0LYl>&q1n?%@FM6Fu9{;T>ZW&mNQ*bMzCVrHcJ5V`nh3!jC@qy{Qg=aPB*v!&~g* z?2O*%XraX`eX#3km#c_l6mh**`l#C$lf#Ki#-s}h%( z59gJ*I3QwGh-+f>7f#xQ|7~u-A2fgd>MJ;vD`;yvDpN99Hb1g4KnU2 zfw2qn1jr`&=@wxHu7C8=CKw(+djEao`ZLdAK>6q|p5KOc_*{Q@x&%tMAAj-#n2WE2 zPxtuJ0wMqUH&ZVEb_?6`@h5-3&1SHB_3AcA`5#X|L&%jYguMG6!33~%QCKqA(1$S? z3$l$>*bLsERmg2yec6*Q$&0uGT1)yVhXQ%wm zv(FLo;fI90`dTE=M;rPu27{r`a@Z=sbeO^%gZ_z66Y|#IBKw`UE94?`3iaEg%{CYM!`PX2>5USj0GuSF2S?# zr@KGd>;3Gzz1~8e3F;sv^!5EE7Ss1*EYtBEVZh6uyJ-`o*Sp{7VGB}%K8Xw3xR_1M zWeom!#}S;&CJ1g%_I}WgdrDyJf;<7TX}sMp0Lp*;z|g(k;`FJPzVN$WXR*rs?CHv{ JrXT&*e*m0cWY7Qr diff --git a/src/resources/open-Folder-Icon.png b/src/resources/open-Folder-Icon.png index c363be0fdef80bc854db9df8126941461e394d10..6218ed39b474ade809e8e806db96beb06ea74a53 100644 GIT binary patch delta 1322 zcmV+_1=aeWgaMihkQo>Q0002ME~H~AqhKj8YC8oZQg&~ZpnQdkg>P$3Lw$39WOHR&a9&VySVoS8 zTXt1Kdv9WLU|xG-Nj#fKJeo>8j#WH?U`k|^L3nmPm{B~SMMJzdQSBR7UerZj)kbgUPk;GXV4r8Xqn1;vlU1vgRJ^23e`#-~mQ(-#4Uda+jEka_k(7^rjFqRMkh!mov#O4>s*Sv| ziI|m}vYtWi(FB8ok^ldf_Un@M>67^Jj{pCV%gw01sXEQMC!Cmi|Nc(*(GS#@t*uBKG~{51OFKL7GJ#=KfqS8u$sPyhWW{NpwM{VA-ZSw2F6)4w>K*rCI9#rIX;Q;)H?GY^rTN*#o+$=`0XLM#~T?LhOOuD{VMLum{k4> z^wgU<=J6N+0004EOGiWihy@);ks%j<00(qQO+^Rd0~ZbnG7i1M8~^|TOG!jQR2b7^ zU|?ioW?^AvW9Q&BFf=kY;o{~oWdH(*FfSj!nR#?fY@CIqRXj*oKu}0nSVUCJIw3JB zIVCkMJtGq&EG{7_B_%CmlVxjX?~t97o0nez5|(vza&~qpbd{4=P*id&DlRF1EdvR= zmseC)R#bT?dwO}R_*B=_*42ZA8ycIMn_F7j+B-VCx_f&2`X@{T2~V0lW$LtP(`U?_ zHEZ^qx%1{PSm+B9UbJ}0(q#~^e8tLDtJkdc^9KsATfbrBCM2+V%hqi`;q5zi?%It4 z_Ur`;@7sUi;2{)nI3SRL;mFZ{W5-V*gOjI%R2djfpE-N(JTka&F<6a(;nL+RS5d&V z>mlk43^#7xx{U(v+zr)WV7Pbx!9x`AC@fr)f#LC!r_YeV^A{0X+6)XYF@z&^bQu_4 zy?%oN-oA^{(`O(F007AI>!U3zHM#%*03~!qSaf7zbY(hYa%Ew3WdJf+FflkSFf%PO zGgL7&IxsmpH83kMFgh?WblY_u0000bbVXQnWMOn=I&E)cX=Zr$ gG&(RjIyEpWFfckWFa?Iqp#T5?07*qoM6N<$f~4|boB#j- literal 16927 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 CMFzwG From 5a98d69dcdf470308823b8648367c2f13b52c593 Mon Sep 17 00:00:00 2001 From: Jeremy Rimpo Date: Fri, 23 Mar 2018 11:35:27 -0500 Subject: [PATCH 34/57] Fix tab index now that the archive tab is back --- src/tutorials/tutorial_conflictresolution_main.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tutorials/tutorial_conflictresolution_main.js b/src/tutorials/tutorial_conflictresolution_main.js index a60a5c8db..3c782af29 100644 --- a/src/tutorials/tutorial_conflictresolution_main.js +++ b/src/tutorials/tutorial_conflictresolution_main.js @@ -65,7 +65,7 @@ function getTutorialSteps() { }, function() { tutorial.text = qsTr("Option A: Switch to the \"Data\"-tab if necessary") - if (!tutorialControl.waitForTabOpen("tabWidget", 1)) { + if (!tutorialControl.waitForTabOpen("tabWidget", 2)) { highlightItem("tabWidget", false) waitForClick() } else { From dcbcb29ec733801025556d294b90c9b8061a31e5 Mon Sep 17 00:00:00 2001 From: Silarn Date: Tue, 3 Apr 2018 14:59:04 -0500 Subject: [PATCH 35/57] Update to allow linking to updated bsatk --- CMakeLists.txt | 1 + src/CMakeLists.txt | 8 +++++--- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 9c6351f7e..b63e8b81b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -8,6 +8,7 @@ set_property(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" PROPERTY VS_STARTUP_PROJECT SET(DEPENDENCIES_DIR CACHE PATH "") # hint to find qt in dependencies path LIST(APPEND CMAKE_PREFIX_PATH ${QT_ROOT}/lib/cmake) +LIST(APPEND CMAKE_PREFIX_PATH ${LZ4_ROOT}/dll) FILE(GLOB_RECURSE BOOST_ROOT ${DEPENDENCIES_DIR}/boost*/project-config.jam) GET_FILENAME_COMPONENT(BOOST_ROOT ${BOOST_ROOT} DIRECTORY) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index ab7b48364..70886f81b 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -288,11 +288,13 @@ INCLUDE_DIRECTORIES(${project_path}/uibase/src ${project_path}/../usvfs/include ${project_path}/game_gamebryo/src ${project_path}/game_features/src - ${project_path}/githubpp/src) + ${project_path}/githubpp/src + ${LZ4_ROOT}/include) INCLUDE_DIRECTORIES(shared ${ZLIB_INCLUDE_DIRS}) LINK_DIRECTORIES(${lib_path} - ${ZLIB_ROOT}/lib) + ${ZLIB_ROOT}/lib + ${LZ4_ROOT}/dll) EXECUTE_PROCESS( COMMAND git log -1 --format=%h WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} @@ -315,7 +317,7 @@ TARGET_LINK_LIBRARIES(ModOrganizer zlibstatic uibase esptk bsatk githubpp ${usvfs_name} - Dbghelp advapi32 Version Shlwapi) + Dbghelp advapi32 Version Shlwapi liblz4) IF (NOT "${OPTIMIZE_COMPILE_FLAGS}" STREQUAL "") SET_TARGET_PROPERTIES(ModOrganizer PROPERTIES COMPILE_FLAGS_RELWITHDEBINFO ${OPTIMIZE_COMPILE_FLAGS}) From 74dd2bb914a1f2a31506c3544b6ee198f65e2b6b Mon Sep 17 00:00:00 2001 From: Silarn Date: Thu, 5 Apr 2018 23:57:24 -0500 Subject: [PATCH 36/57] Return extraction context menu to archive list --- src/mainwindow.cpp | 12 ++++++++++++ src/mainwindow.h | 1 + 2 files changed, 13 insertions(+) diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 0dbe4d53b..faa4b880c 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -4345,6 +4345,18 @@ void MainWindow::displayColumnSelection(const QPoint &pos) } } +void MainWindow::on_bsaList_customContextMenuRequested(const QPoint &pos) +{ + m_ContextItem = ui->bsaList->itemAt(pos); + +// m_ContextRow = ui->bsaList->indexOfTopLevelItem(ui->bsaList->itemAt(pos)); + + QMenu menu; + menu.addAction(tr("Extract..."), this, SLOT(extractBSATriggered())); + + menu.exec(ui->bsaList->mapToGlobal(pos)); +} + void MainWindow::on_bsaList_itemChanged(QTreeWidgetItem*, int) { m_ArchiveListWriter.write(); diff --git a/src/mainwindow.h b/src/mainwindow.h index f84931caa..d0957305c 100644 --- a/src/mainwindow.h +++ b/src/mainwindow.h @@ -553,6 +553,7 @@ private slots: // ui slots void on_actionUpdate_triggered(); void on_actionEndorseMO_triggered(); + void on_bsaList_customContextMenuRequested(const QPoint &pos); void on_clearFiltersButton_clicked(); void on_btnRefreshData_clicked(); void on_categoriesList_customContextMenuRequested(const QPoint &pos); From fed89352d1c9870bb34cbc1a65c3a8d3043086f9 Mon Sep 17 00:00:00 2001 From: Silarn Date: Fri, 6 Apr 2018 00:56:58 -0500 Subject: [PATCH 37/57] Changes to allow plugin loading in the mod info dialog (and rename SE) --- src/modinfo.cpp | 6 +++--- src/modinfo.h | 1 + src/modinfodialog.h | 1 + src/modinforegular.cpp | 2 +- 4 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/modinfo.cpp b/src/modinfo.cpp index c14eedb72..d80c636b4 100644 --- a/src/modinfo.cpp +++ b/src/modinfo.cpp @@ -55,7 +55,7 @@ QMutex ModInfo::s_Mutex(QMutex::Recursive); QString ModInfo::s_HiddenExt(".mohidden"); -static bool ByName(const ModInfo::Ptr &LHS, const ModInfo::Ptr &RHS) +bool ModInfo::ByName(const ModInfo::Ptr &LHS, const ModInfo::Ptr &RHS) { return QString::compare(LHS->name(), RHS->name(), Qt::CaseInsensitive) < 0; } @@ -98,7 +98,7 @@ QString ModInfo::getContentTypeName(int contentType) case CONTENT_INTERFACE: return tr("UI Changes"); case CONTENT_SOUND: return tr("Sound Effects"); case CONTENT_SCRIPT: return tr("Scripts"); - case CONTENT_SKSE: return tr("SKSE Plugins"); + case CONTENT_SKSE: return tr("Script Extender"); case CONTENT_SKYPROC: return tr("SkyProc Tools"); case CONTENT_MCM: return tr("MCM Data"); default: throw MyException(tr("invalid content type %1").arg(contentType)); @@ -239,7 +239,7 @@ void ModInfo::updateFromDisc(const QString &modDirectory, createFromOverwrite(); - std::sort(s_Collection.begin(), s_Collection.end(), ByName); + std::sort(s_Collection.begin(), s_Collection.end(), ModInfo::ByName); updateIndices(); } diff --git a/src/modinfo.h b/src/modinfo.h index d00c04e79..1ceb8e1f5 100644 --- a/src/modinfo.h +++ b/src/modinfo.h @@ -599,6 +599,7 @@ class ModInfo : public QObject, public MOBase::IModInterface ModInfo(); static void updateIndices(); + static bool ByName(const ModInfo::Ptr &LHS, const ModInfo::Ptr &RHS); private: diff --git a/src/modinfodialog.h b/src/modinfodialog.h index 312ff99e8..e7c707622 100644 --- a/src/modinfodialog.h +++ b/src/modinfodialog.h @@ -23,6 +23,7 @@ along with Mod Organizer. If not, see . #include "modinfo.h" #include "tutorabledialog.h" +#include "plugincontainer.h" #include #include diff --git a/src/modinforegular.cpp b/src/modinforegular.cpp index 5486bb2cb..4572f5bf8 100644 --- a/src/modinforegular.cpp +++ b/src/modinforegular.cpp @@ -299,7 +299,7 @@ bool ModInfoRegular::setName(const QString &name) s_ModsByName[m_Name] = index; - std::sort(s_Collection.begin(), s_Collection.end(), ByName); + std::sort(s_Collection.begin(), s_Collection.end(), ModInfo::ByName); updateIndices(); } else { // otherwise mod isn't registered yet? m_Name = name; From a905ce130d0f1f4894f135660d9cf515788bb2ad Mon Sep 17 00:00:00 2001 From: Silarn Date: Fri, 6 Apr 2018 18:25:11 -0500 Subject: [PATCH 38/57] Update About dialog with new contributors (and don't translate names) --- src/aboutdialog.ui | 46 +++++++++++++++++++++++++++++++++------------- 1 file changed, 33 insertions(+), 13 deletions(-) diff --git a/src/aboutdialog.ui b/src/aboutdialog.ui index 348a33b04..69e52708d 100644 --- a/src/aboutdialog.ui +++ b/src/aboutdialog.ui @@ -6,8 +6,8 @@ 0 0 - 604 - 369 + 1010 + 477 @@ -231,6 +231,11 @@ Alyndiar (French) + + + fruttyx (French) + + Jlkawaii (French) @@ -241,6 +246,11 @@ Rigoletto (French) + + + Yoplala (French) + + Faron (German) @@ -320,12 +330,7 @@ - SuperSandro2000 - - - - - AnyOldName3 + AnyOldName3 @@ -348,6 +353,11 @@ Bridger + + + Brixified + + GamerPoet @@ -365,27 +375,37 @@ - Uhuru + ogrotten - Wolverine2710 + Schilduin - z929669 + SuperSandro2000 - thosrtanner + Uhuru + + + + + Wolverine2710 + + + + + z929669 - ogrotten + thosrtanner From 5c39a762e68c3559438a622dbf747eb8bddec7ed Mon Sep 17 00:00:00 2001 From: Al12rs Date: Fri, 6 Apr 2018 21:35:15 +0200 Subject: [PATCH 39/57] Allow MO2 shortcuts that open the indicated MO2 instance in the argument if the executable name is omitted. This should be added after the MO2 exe path: ' "moshortcut://myInstanceName:" '. If there are caracters after the ":" then MO2 will assume that is an execuatble and will try to run it. --- src/main.cpp | 66 +++++++++++++++++++++++-------------------- src/moshortcut.cpp | 3 ++ src/moshortcut.h | 3 ++ src/organizercore.cpp | 5 ++-- 4 files changed, 45 insertions(+), 32 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 0464ca9a3..fc332fe71 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -561,36 +561,42 @@ int runApplication(MOApplication &application, SingleInstance &instance, // if we have a command line parameter, it is either a nxm link or // a binary to start - if (arguments.size() > 1) { - if (MOShortcut shortcut{ arguments.at(1) }) { - try { - organizer.runShortcut(shortcut); - return 0; - } catch (const std::exception &e) { - reportError( - QObject::tr("failed to start shortcut: %1").arg(e.what())); - return 1; - } - } else if (OrganizerCore::isNxmLink(arguments.at(1))) { - qDebug("starting download from command line: %s", - qPrintable(arguments.at(1))); - organizer.externalMessage(arguments.at(1)); - } else { - QString exeName = arguments.at(1); - qDebug("starting %s from command line", qPrintable(exeName)); - arguments.removeFirst(); // remove application name (ModOrganizer.exe) - arguments.removeFirst(); // remove binary name - // pass the remaining parameters to the binary - try { - organizer.startApplication(exeName, arguments, QString(), QString()); - return 0; - } catch (const std::exception &e) { - reportError( - QObject::tr("failed to start application: %1").arg(e.what())); - return 1; - } - } - } + if (arguments.size() > 1) { + if (MOShortcut shortcut{ arguments.at(1) }) { + if (shortcut.hasExecutable()) { + try { + organizer.runShortcut(shortcut); + return 0; + } + catch (const std::exception &e) { + reportError( + QObject::tr("failed to start shortcut: %1").arg(e.what())); + return 1; + } + } + } + else if (OrganizerCore::isNxmLink(arguments.at(1))) { + qDebug("starting download from command line: %s", + qPrintable(arguments.at(1))); + organizer.externalMessage(arguments.at(1)); + } + else { + QString exeName = arguments.at(1); + qDebug("starting %s from command line", qPrintable(exeName)); + arguments.removeFirst(); // remove application name (ModOrganizer.exe) + arguments.removeFirst(); // remove binary name + // pass the remaining parameters to the binary + try { + organizer.startApplication(exeName, arguments, QString(), QString()); + return 0; + } + catch (const std::exception &e) { + reportError( + QObject::tr("failed to start application: %1").arg(e.what())); + return 1; + } + } + } QPixmap pixmap(splashPath); QSplashScreen splash(pixmap); diff --git a/src/moshortcut.cpp b/src/moshortcut.cpp index c8c2ef6f3..aad7380ec 100644 --- a/src/moshortcut.cpp +++ b/src/moshortcut.cpp @@ -24,6 +24,7 @@ along with Mod Organizer. If not, see . MOShortcut::MOShortcut(const QString& link) : m_valid(link.startsWith("moshortcut://")) , m_hasInstance(false) + , m_hasExecutable(false) { if (m_valid) { int start = (int)strlen("moshortcut://"); @@ -35,5 +36,7 @@ MOShortcut::MOShortcut(const QString& link) } else m_executable = link.mid(start); + if(!(m_executable=="")) + m_hasExecutable=true; } } diff --git a/src/moshortcut.h b/src/moshortcut.h index 7b7574b97..2ce54910b 100644 --- a/src/moshortcut.h +++ b/src/moshortcut.h @@ -33,6 +33,8 @@ class MOShortcut { operator bool() const { return m_valid; } bool hasInstance() const { return m_hasInstance; } + + bool hasExecutable() const { return m_hasExecutable; } const QString& instance() const { return m_instance; } @@ -43,4 +45,5 @@ class MOShortcut { QString m_executable; bool m_valid; bool m_hasInstance; + bool m_hasExecutable; }; diff --git a/src/organizercore.cpp b/src/organizercore.cpp index b84488daf..0398e9ace 100644 --- a/src/organizercore.cpp +++ b/src/organizercore.cpp @@ -602,8 +602,9 @@ void OrganizerCore::downloadRequestedNXM(const QString &url) void OrganizerCore::externalMessage(const QString &message) { - if (MOShortcut moshortcut{ message }) { - runShortcut(moshortcut); + if (MOShortcut moshortcut{ message } ) { + if(moshortcut.hasExecutable()) + runShortcut(moshortcut); } else if (isNxmLink(message)) { MessageDialog::showMessage(tr("Download started"), qApp->activeWindow()); From fd9eb032b6df5eafa89a60a515963ba7d4652f24 Mon Sep 17 00:00:00 2001 From: Al12rs Date: Fri, 23 Mar 2018 17:48:00 +0100 Subject: [PATCH 40/57] Added file preview in conflicts tab in the mod information dialog. The preview is not working for the lower file list for some reason but I left the setup of the context menu and all in case somebody else can figure out what I'm missing. --- src/mainwindow.cpp | 2 +- src/modinfodialog.cpp | 98 ++++++++++++++++++++++++++++++++++++++++++- src/modinfodialog.h | 8 +++- src/modinfodialog.ui | 6 +++ 4 files changed, 110 insertions(+), 4 deletions(-) diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index faa4b880c..d9d83231f 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -2450,7 +2450,7 @@ void MainWindow::displayModInformation(ModInfo::Ptr modInfo, unsigned int index, } } else { modInfo->saveMeta(); - ModInfoDialog dialog(modInfo, m_OrganizerCore.directoryStructure(), modInfo->hasFlag(ModInfo::FLAG_FOREIGN), this); + ModInfoDialog dialog(modInfo, m_OrganizerCore.directoryStructure(), modInfo->hasFlag(ModInfo::FLAG_FOREIGN), &m_OrganizerCore, &m_PluginContainer,this); connect(&dialog, SIGNAL(nexusLinkActivated(QString)), this, SLOT(nexusLinkActivated(QString))); connect(&dialog, SIGNAL(downloadRequest(QString)), &m_OrganizerCore, SLOT(downloadRequestedNXM(QString))); connect(&dialog, SIGNAL(modOpen(QString, int)), this, SLOT(displayModInformation(QString, int)), Qt::QueuedConnection); diff --git a/src/modinfodialog.cpp b/src/modinfodialog.cpp index ccd2a122c..f2042d150 100644 --- a/src/modinfodialog.cpp +++ b/src/modinfodialog.cpp @@ -30,6 +30,10 @@ along with Mod Organizer. If not, see . #include "questionboxmemory.h" #include "settings.h" #include "categories.h" +#include "organizercore.h" +#include "pluginlistsortproxy.h" +#include "previewgenerator.h" +#include "previewdialog.h" #include #include @@ -66,11 +70,12 @@ static bool operator<(const ModFileListWidget &LHS, const ModFileListWidget &RHS } -ModInfoDialog::ModInfoDialog(ModInfo::Ptr modInfo, const DirectoryEntry *directory, bool unmanaged, QWidget *parent) +ModInfoDialog::ModInfoDialog(ModInfo::Ptr modInfo, const DirectoryEntry *directory, bool unmanaged, OrganizerCore *organizerCore, PluginContainer *pluginContainer, QWidget *parent) : TutorableDialog("ModInfoDialog", parent), ui(new Ui::ModInfoDialog), m_ModInfo(modInfo), m_ThumbnailMapper(this), m_RequestStarted(false), m_DeleteAction(nullptr), m_RenameAction(nullptr), m_OpenAction(nullptr), - m_Directory(directory), m_Origin(nullptr) + m_Directory(directory), m_Origin(nullptr), + m_OrganizerCore(organizerCore), m_PluginContainer(pluginContainer) { ui->setupUi(this); this->setWindowTitle(modInfo->name()); @@ -1198,6 +1203,69 @@ void ModInfoDialog::unhideConflictFile() } +void ModInfoDialog::previewDataFile() +{ + QString fileName = QDir::fromNativeSeparators(m_ConflictsContextItem->data(0, Qt::UserRole).toString()); + + // what we have is an absolute path to the file in its actual location (for the primary origin) + // what we want is the path relative to the virtual data directory + + // we need to look in the virtual directory for the file to make sure the info is up to date. + + // check if the file comes from the actual data folder instead of a mod + QDir gameDirectory = m_OrganizerCore->managedGame()->dataDirectory().absolutePath(); + QString relativePath = gameDirectory.relativeFilePath(fileName); + QDir direRelativePath = gameDirectory.relativeFilePath(fileName); + // if the file is on a different drive the dirRelativePath will actually be an absolute path so we make sure that is not the case + if (!direRelativePath.isAbsolute() && !relativePath.startsWith("..")) { + fileName = relativePath; + } + else { + // crude: we search for the next slash after the base mod directory to skip everything up to the data-relative directory + int offset = m_OrganizerCore->settings().getModDirectory().size() + 1; + offset = fileName.indexOf("/", offset); + fileName = fileName.mid(offset + 1); + } + + + + const FileEntry::Ptr file = m_OrganizerCore->directoryStructure()->searchFile(ToWString(fileName), nullptr); + + if (file.get() == nullptr) { + reportError(tr("file not found: %1").arg(fileName)); + return; + } + + // set up preview dialog + PreviewDialog preview(fileName); + auto addFunc = [&](int originId) { + FilesOrigin &origin = m_OrganizerCore->directoryStructure()->getOriginByID(originId); + QString filePath = QDir::fromNativeSeparators(ToQString(origin.getPath())) + "/" + fileName; + if (QFile::exists(filePath)) { + // it's very possible the file doesn't exist, because it's inside an archive. we don't support that + QWidget *wid = m_PluginContainer->previewGenerator().genPreview(filePath); + if (wid == nullptr) { + reportError(tr("failed to generate preview for %1").arg(filePath)); + } + else { + preview.addVariant(ToQString(origin.getName()), wid); + } + } + }; + + addFunc(file->getOrigin()); + for (auto alt : file->getAlternatives()) { + addFunc(alt.first); + } + if (preview.numVariants() > 0) { + preview.exec(); + } + else { + QMessageBox::information(this, tr("Sorry"), tr("Sorry, can't preview anything. This function currently does not support extracting from bsas.")); + } +} + + void ModInfoDialog::on_overwriteTree_customContextMenuRequested(const QPoint &pos) { m_ConflictsContextItem = ui->overwriteTree->itemAt(pos.x(), pos.y()); @@ -1211,11 +1279,37 @@ void ModInfoDialog::on_overwriteTree_customContextMenuRequested(const QPoint &po } else { menu.addAction(tr("Hide"), this, SLOT(hideConflictFile())); } + + QString fileName = m_ConflictsContextItem->data(0, Qt::UserRole).toString(); + if (m_PluginContainer->previewGenerator().previewSupported(QFileInfo(fileName).suffix())) { + menu.addAction(tr("Preview"), this, SLOT(previewDataFile())); + } + menu.exec(ui->overwriteTree->mapToGlobal(pos)); } } } +void ModInfoDialog::on_overwrittenTree_customContextMenuRequested(const QPoint &pos) +{ + //For some reason the m_ConflictsContextItem does not pick up valid data from the overwrittenTree. + //TODO: find out what is going wrong. + /*m_ConflictsContextItem = ui->overwrittenTree->itemAt(pos.x(), pos.y()); + + if (m_ConflictsContextItem != nullptr) { + if (!m_ConflictsContextItem->data(1, Qt::UserRole + 2).toBool()) { + QMenu menu; + + QString fileName = m_ConflictsContextItem->data(0, Qt::UserRole).toString(); + if (m_PluginContainer->previewGenerator().previewSupported(QFileInfo(fileName).suffix())) { + menu.addAction(tr("Preview"), this, SLOT(previewDataFile())); + } + + menu.exec(ui->overwrittenTree->mapToGlobal(pos)); + } + }*/ +} + void ModInfoDialog::on_overwrittenTree_itemDoubleClicked(QTreeWidgetItem *item, int) { diff --git a/src/modinfodialog.h b/src/modinfodialog.h index e7c707622..ab878cf92 100644 --- a/src/modinfodialog.h +++ b/src/modinfodialog.h @@ -24,6 +24,7 @@ along with Mod Organizer. If not, see . #include "modinfo.h" #include "tutorabledialog.h" #include "plugincontainer.h" +#include "organizercore.h" #include #include @@ -77,7 +78,7 @@ class ModInfoDialog : public MOBase::TutorableDialog * @param modInfo info structure about the mod to display * @param parent parend widget **/ - explicit ModInfoDialog(ModInfo::Ptr modInfo, const MOShared::DirectoryEntry *directory, bool unmanaged, QWidget *parent = 0); + explicit ModInfoDialog(ModInfo::Ptr modInfo, const MOShared::DirectoryEntry *directory, bool unmanaged, OrganizerCore *organizerCore, PluginContainer *pluginContainer,QWidget *parent = 0); ~ModInfoDialog(); /** @@ -156,6 +157,7 @@ private slots: void hideConflictFile(); void unhideConflictFile(); + void previewDataFile(); void thumbnailClicked(const QString &fileName); void linkClicked(const QUrl &url); @@ -186,6 +188,7 @@ private slots: void on_overwriteTree_itemDoubleClicked(QTreeWidgetItem *item, int column); void on_overwrittenTree_itemDoubleClicked(QTreeWidgetItem *item, int column); void on_overwriteTree_customContextMenuRequested(const QPoint &pos); + void on_overwrittenTree_customContextMenuRequested(const QPoint &pos); void on_fileTree_customContextMenuRequested(const QPoint &pos); void on_refreshButton_clicked(); @@ -209,6 +212,9 @@ private slots: QSignalMapper m_ThumbnailMapper; QString m_RootPath; + OrganizerCore *m_OrganizerCore; + PluginContainer *m_PluginContainer; + QFileSystemModel *m_FileSystemModel; QTreeView *m_FileTree; QModelIndexList m_FileSelection; diff --git a/src/modinfodialog.ui b/src/modinfodialog.ui index b53314241..054154450 100644 --- a/src/modinfodialog.ui +++ b/src/modinfodialog.ui @@ -489,6 +489,9 @@ Most mods do not have optional esps, so chances are good you are looking at an e + + Qt::CustomContextMenu + Qt::ElideLeft @@ -498,6 +501,9 @@ Most mods do not have optional esps, so chances are good you are looking at an e true + + 2 + 365 From a1d92fb67316d907b930737658bdb841fd8bc486 Mon Sep 17 00:00:00 2001 From: Silarn Date: Sat, 7 Apr 2018 17:12:22 -0500 Subject: [PATCH 41/57] Fix up CMAKE to use /MP and allow building through umbrella --- CMakeLists.txt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index b63e8b81b..5d069383d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,4 +1,6 @@ -CMAKE_MINIMUM_REQUIRED(VERSION 2.8) +CMAKE_MINIMUM_REQUIRED(VERSION 2.8.12) + +ADD_COMPILE_OPTIONS($<$:/MP>) PROJECT(organizer) From d62669e1b48687842fb856f2190c3bd84c514fd0 Mon Sep 17 00:00:00 2001 From: Silarn Date: Sat, 7 Apr 2018 18:58:12 -0500 Subject: [PATCH 42/57] Fix overwritten file preview --- src/modinfodialog.cpp | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/modinfodialog.cpp b/src/modinfodialog.cpp index f2042d150..f8655d6b7 100644 --- a/src/modinfodialog.cpp +++ b/src/modinfodialog.cpp @@ -298,7 +298,9 @@ void ModInfoDialog::refreshLists() QStringList fields(relativeName); fields.append(ToQString(realOrigin.getName())); QTreeWidgetItem *item = new QTreeWidgetItem(fields); + item->setData(0, Qt::UserRole, fileName); item->setData(1, Qt::UserRole, ToQString(realOrigin.getName())); + item->setData(1, Qt::UserRole + 2, archive); ui->overwrittenTree->addTopLevelItem(item); ++numOverwritten; } @@ -1280,10 +1282,10 @@ void ModInfoDialog::on_overwriteTree_customContextMenuRequested(const QPoint &po menu.addAction(tr("Hide"), this, SLOT(hideConflictFile())); } - QString fileName = m_ConflictsContextItem->data(0, Qt::UserRole).toString(); - if (m_PluginContainer->previewGenerator().previewSupported(QFileInfo(fileName).suffix())) { - menu.addAction(tr("Preview"), this, SLOT(previewDataFile())); - } + QString fileName = m_ConflictsContextItem->data(0, Qt::UserRole).toString(); + if (m_PluginContainer->previewGenerator().previewSupported(QFileInfo(fileName).suffix())) { + menu.addAction(tr("Preview"), this, SLOT(previewDataFile())); + } menu.exec(ui->overwriteTree->mapToGlobal(pos)); } @@ -1294,7 +1296,7 @@ void ModInfoDialog::on_overwrittenTree_customContextMenuRequested(const QPoint & { //For some reason the m_ConflictsContextItem does not pick up valid data from the overwrittenTree. //TODO: find out what is going wrong. - /*m_ConflictsContextItem = ui->overwrittenTree->itemAt(pos.x(), pos.y()); + m_ConflictsContextItem = ui->overwrittenTree->itemAt(pos.x(), pos.y()); if (m_ConflictsContextItem != nullptr) { if (!m_ConflictsContextItem->data(1, Qt::UserRole + 2).toBool()) { @@ -1307,7 +1309,7 @@ void ModInfoDialog::on_overwrittenTree_customContextMenuRequested(const QPoint & menu.exec(ui->overwrittenTree->mapToGlobal(pos)); } - }*/ + } } From b409a0bef934eb20d10ecd2f7448c2da00c8e500 Mon Sep 17 00:00:00 2001 From: Silarn Date: Sat, 7 Apr 2018 20:09:41 -0500 Subject: [PATCH 43/57] Install the translation file (we need at least one) --- src/CMakeLists.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 70886f81b..ef009e03a 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -253,6 +253,7 @@ FIND_PACKAGE(Qt5LinguistTools) QT5_WRAP_UI(organizer_UIHDRS ${organizer_UIS}) QT5_ADD_RESOURCES(organizer_RCCPPS ${organizer_QRCS}) QT5_CREATE_TRANSLATION(organizer_translations_qm ${CMAKE_SOURCE_DIR}/src ${CMAKE_SOURCE_DIR}/src/organizer_en.ts) +ADD_CUSTOM_TARGET(translations DEPENDS ${organizer_translations_qm}) INCLUDE_DIRECTORIES(${Qt5Declarative_INCLUDES}) @@ -373,6 +374,8 @@ INSTALL( # qdds.dll needs installing manually as Qt no longer ships with it by default. INSTALL(FILES ${CMAKE_CURRENT_SOURCE_DIR}/../qdds.dll DESTINATION bin/dlls/imageformats) +install(FILES ${organizer_translations_qm} DESTINATION bin/translations) + INSTALL(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/stylesheets ${CMAKE_CURRENT_SOURCE_DIR}/tutorials DESTINATION bin) From cc2bd152568a4f1164a0a4ba5e6232e77e7c9945 Mon Sep 17 00:00:00 2001 From: Silarn Date: Sat, 7 Apr 2018 22:18:45 -0500 Subject: [PATCH 44/57] Fix for re-downloading a mod already downloading --- src/downloadmanager.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/downloadmanager.cpp b/src/downloadmanager.cpp index a4fde093a..c0d7fbf3b 100644 --- a/src/downloadmanager.cpp +++ b/src/downloadmanager.cpp @@ -460,7 +460,14 @@ void DownloadManager::addNXMDownload(const QString &url) return; } + if (m_PendingDownloads.contains(std::pair(nxmInfo.modId(), nxmInfo.fileId()))) { + qDebug("download requested is already started (mod: %s, file: %s)", qPrintable(nxmInfo.modId()), qPrintable(nxmInfo.fileId())); + QMessageBox::information(nullptr, tr("Already Started"), tr("A download for this mod file has already been started."), QMessageBox::Ok); + return; + } + emit aboutToUpdate(); + m_PendingDownloads.append(std::make_pair(nxmInfo.modId(), nxmInfo.fileId())); emit update(-1); From 7eba6837dd65eb0e5f3b9f71e67e82fe553a56a6 Mon Sep 17 00:00:00 2001 From: Silarn Date: Sat, 7 Apr 2018 23:54:22 -0500 Subject: [PATCH 45/57] Prevent redownloading a mod if the download is still in progress --- src/downloadmanager.cpp | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/src/downloadmanager.cpp b/src/downloadmanager.cpp index c0d7fbf3b..450708852 100644 --- a/src/downloadmanager.cpp +++ b/src/downloadmanager.cpp @@ -460,10 +460,25 @@ void DownloadManager::addNXMDownload(const QString &url) return; } - if (m_PendingDownloads.contains(std::pair(nxmInfo.modId(), nxmInfo.fileId()))) { - qDebug("download requested is already started (mod: %s, file: %s)", qPrintable(nxmInfo.modId()), qPrintable(nxmInfo.fileId())); - QMessageBox::information(nullptr, tr("Already Started"), tr("A download for this mod file has already been started."), QMessageBox::Ok); - return; + for (auto pair : m_PendingDownloads) { + if (pair.first == nxmInfo.modId() && pair.second == nxmInfo.fileId()) { + qDebug("download requested is already started (mod id: %s, file id: %s)", qPrintable(nxmInfo.modId()), qPrintable(nxmInfo.fileId())); + QMessageBox::information(nullptr, tr("Already Started"), tr("A download for this mod file has already been queued."), QMessageBox::Ok); + return; + } + } + + for (DownloadInfo *download : m_ActiveDownloads) { + if (download->m_FileInfo->modID == nxmInfo.modId() && download->m_FileInfo->fileID == nxmInfo.fileId()) { + if (download->m_State == STATE_DOWNLOADING || download->m_State == STATE_PAUSED || download->m_State == STATE_STARTED) { + qDebug("download requested is already started (mod: %s, file: %s)", qPrintable(download->m_FileInfo->modName), + qPrintable(download->m_FileInfo->fileName)); + + QMessageBox::information(nullptr, tr("Already Started"), tr("There is already a download started for this file (%2).") + .arg(download->m_FileInfo->modName).arg(download->m_FileInfo->name), QMessageBox::Ok); + return; + } + } } emit aboutToUpdate(); From 0f8852f487cb1f8b993141042da4196db965e038 Mon Sep 17 00:00:00 2001 From: Silarn Date: Sun, 8 Apr 2018 03:58:08 -0500 Subject: [PATCH 46/57] Also mark hidden downloads as uninstalled; refresh plugins after files --- src/downloadmanager.cpp | 20 ++++++++++++++++++++ src/downloadmanager.h | 3 +++ src/mainwindow.cpp | 6 ++---- 3 files changed, 25 insertions(+), 4 deletions(-) diff --git a/src/downloadmanager.cpp b/src/downloadmanager.cpp index 450708852..161656b25 100644 --- a/src/downloadmanager.cpp +++ b/src/downloadmanager.cpp @@ -918,6 +918,10 @@ void DownloadManager::markInstalled(int index) setState(m_ActiveDownloads.at(index), STATE_INSTALLED); } +DownloadManager::DownloadInfo* DownloadManager::getDownloadInfo(QString fileName) +{ + return DownloadInfo::createFromMeta(fileName, true); +} void DownloadManager::markUninstalled(int index) { @@ -933,6 +937,22 @@ void DownloadManager::markUninstalled(int index) } +void DownloadManager::markUninstalled(QString fileName) +{ + int index = indexByName(fileName); + if (index >= 0) { + markUninstalled(index); + } else { + DownloadInfo *info = getDownloadInfo(fileName); + if (info != nullptr) { + QSettings metaFile(info->m_Output.fileName() + ".meta", QSettings::IniFormat); + metaFile.setValue("uninstalled", true); + setState(info, STATE_UNINSTALLED); + } + } +} + + QString DownloadManager::getDownloadFileName(const QString &baseName) const { QString fullPath = m_OutputDirectory + "/" + baseName; diff --git a/src/downloadmanager.h b/src/downloadmanager.h index e63a01138..059c6cb56 100644 --- a/src/downloadmanager.h +++ b/src/downloadmanager.h @@ -314,6 +314,8 @@ class DownloadManager : public MOBase::IDownloadManager */ void markUninstalled(int index); + void markUninstalled(QString download); + /** * @brief refreshes the list of downloads */ @@ -431,6 +433,7 @@ private slots: private: void createMetaFile(DownloadInfo *info); + DownloadManager::DownloadInfo* getDownloadInfo(QString fileName); public: diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index d9d83231f..48a097189 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -1980,6 +1980,7 @@ void MainWindow::directory_refreshed() refreshDataTree(); updateProblemsButton(); statusBar()->hide(); + m_OrganizerCore.refreshESPList(); } void MainWindow::modorder_changed() @@ -2307,10 +2308,7 @@ void MainWindow::removeMod_clicked() void MainWindow::modRemoved(const QString &fileName) { if (!fileName.isEmpty() && !QFileInfo(fileName).isAbsolute()) { - int index = m_OrganizerCore.downloadManager()->indexByName(fileName); - if (index >= 0) { - m_OrganizerCore.downloadManager()->markUninstalled(index); - } + m_OrganizerCore.downloadManager()->markUninstalled(fileName); } } From fb1c3765338d600a6362c6583b473de9dd26dc02 Mon Sep 17 00:00:00 2001 From: Al12rs Date: Sun, 8 Apr 2018 14:41:03 +0200 Subject: [PATCH 47/57] Added "Open/Execute" context menu entry to the conflicts tab in the modinfodialog. --- src/modinfodialog.cpp | 90 ++++++++++++++++++++++++++++++++++++++++++- src/modinfodialog.h | 3 ++ 2 files changed, 91 insertions(+), 2 deletions(-) diff --git a/src/modinfodialog.cpp b/src/modinfodialog.cpp index f8655d6b7..6a53d9158 100644 --- a/src/modinfodialog.cpp +++ b/src/modinfodialog.cpp @@ -20,6 +20,7 @@ along with Mod Organizer. If not, see . #include "modinfodialog.h" #include "ui_modinfodialog.h" #include "descriptionpage.h" +#include "mainwindow.h" #include "iplugingame.h" #include "nexusinterface.h" @@ -44,6 +45,7 @@ along with Mod Organizer. If not, see . #include #include #include +#include #include @@ -1204,6 +1206,88 @@ void ModInfoDialog::unhideConflictFile() } } +int ModInfoDialog::getBinaryExecuteInfo(const QFileInfo &targetInfo, QFileInfo &binaryInfo, QString &arguments) +{ + QString extension = targetInfo.suffix(); + if ((extension.compare("cmd", Qt::CaseInsensitive) == 0) || + (extension.compare("com", Qt::CaseInsensitive) == 0) || + (extension.compare("bat", Qt::CaseInsensitive) == 0)) { + binaryInfo = QFileInfo("C:\\Windows\\System32\\cmd.exe"); + arguments = QString("/C \"%1\"").arg(QDir::toNativeSeparators(targetInfo.absoluteFilePath())); + return 1; + } + else if (extension.compare("exe", Qt::CaseInsensitive) == 0) { + binaryInfo = targetInfo; + return 1; + } + else if (extension.compare("jar", Qt::CaseInsensitive) == 0) { + // types that need to be injected into + std::wstring targetPathW = ToWString(targetInfo.absoluteFilePath()); + QString binaryPath; + + { // try to find java automatically + WCHAR buffer[MAX_PATH]; + if (::FindExecutableW(targetPathW.c_str(), nullptr, buffer) > (HINSTANCE)32) { + DWORD binaryType = 0UL; + if (!::GetBinaryTypeW(buffer, &binaryType)) { + qDebug("failed to determine binary type of \"%ls\": %lu", buffer, ::GetLastError()); + } + else if (binaryType == SCS_32BIT_BINARY) { + binaryPath = ToQString(buffer); + } + } + } + if (binaryPath.isEmpty() && (extension == "jar")) { + // second attempt: look to the registry + QSettings javaReg("HKEY_LOCAL_MACHINE\\Software\\JavaSoft\\Java Runtime Environment", QSettings::NativeFormat); + if (javaReg.contains("CurrentVersion")) { + QString currentVersion = javaReg.value("CurrentVersion").toString(); + binaryPath = javaReg.value(QString("%1/JavaHome").arg(currentVersion)).toString().append("\\bin\\javaw.exe"); + } + } + if (binaryPath.isEmpty()) { + binaryPath = QFileDialog::getOpenFileName(this, tr("Select binary"), QString(), tr("Binary") + " (*.exe)"); + } + if (binaryPath.isEmpty()) { + return 0; + } + binaryInfo = QFileInfo(binaryPath); + if (extension == "jar") { + arguments = QString("-jar \"%1\"").arg(QDir::toNativeSeparators(targetInfo.absoluteFilePath())); + } + else { + arguments = QString("\"%1\"").arg(QDir::toNativeSeparators(targetInfo.absoluteFilePath())); + } + return 1; + } + else { + return 2; + } +} + +void ModInfoDialog::openDataFile() +{ + if (m_ConflictsContextItem != nullptr) { + QFileInfo targetInfo(m_ConflictsContextItem->data(0, Qt::UserRole).toString()); + QFileInfo binaryInfo; + QString arguments; + switch (getBinaryExecuteInfo(targetInfo, binaryInfo, arguments)) { + case 1: { + m_OrganizerCore->spawnBinaryDirect( + binaryInfo, arguments, m_OrganizerCore->currentProfile()->name(), + targetInfo.absolutePath(), "", ""); + } break; + case 2: { + ::ShellExecuteW(nullptr, L"open", + ToWString(targetInfo.absoluteFilePath()).c_str(), + nullptr, nullptr, SW_SHOWNORMAL); + } break; + default: { + // nop + } break; + } + } +} void ModInfoDialog::previewDataFile() { @@ -1282,6 +1366,8 @@ void ModInfoDialog::on_overwriteTree_customContextMenuRequested(const QPoint &po menu.addAction(tr("Hide"), this, SLOT(hideConflictFile())); } + menu.addAction(tr("Open/Execute"), this, SLOT(openDataFile())); + QString fileName = m_ConflictsContextItem->data(0, Qt::UserRole).toString(); if (m_PluginContainer->previewGenerator().previewSupported(QFileInfo(fileName).suffix())) { menu.addAction(tr("Preview"), this, SLOT(previewDataFile())); @@ -1294,14 +1380,14 @@ void ModInfoDialog::on_overwriteTree_customContextMenuRequested(const QPoint &po void ModInfoDialog::on_overwrittenTree_customContextMenuRequested(const QPoint &pos) { - //For some reason the m_ConflictsContextItem does not pick up valid data from the overwrittenTree. - //TODO: find out what is going wrong. m_ConflictsContextItem = ui->overwrittenTree->itemAt(pos.x(), pos.y()); if (m_ConflictsContextItem != nullptr) { if (!m_ConflictsContextItem->data(1, Qt::UserRole + 2).toBool()) { QMenu menu; + menu.addAction(tr("Open/Execute"), this, SLOT(openDataFile())); + QString fileName = m_ConflictsContextItem->data(0, Qt::UserRole).toString(); if (m_PluginContainer->previewGenerator().previewSupported(QFileInfo(fileName).suffix())) { menu.addAction(tr("Preview"), this, SLOT(previewDataFile())); diff --git a/src/modinfodialog.h b/src/modinfodialog.h index ab878cf92..9eb17be58 100644 --- a/src/modinfodialog.h +++ b/src/modinfodialog.h @@ -157,7 +157,10 @@ private slots: void hideConflictFile(); void unhideConflictFile(); + int getBinaryExecuteInfo(const QFileInfo &targetInfo, QFileInfo &binaryInfo, QString &arguments); void previewDataFile(); + void openDataFile(); + void thumbnailClicked(const QString &fileName); void linkClicked(const QUrl &url); From 208eaccbf7f1fc0441861d55c68c4b66e5c7d387 Mon Sep 17 00:00:00 2001 From: Silarn Date: Sun, 8 Apr 2018 14:56:46 -0500 Subject: [PATCH 48/57] Updates to allow a full plugin data refresh in certain circumstances --- src/mainwindow.cpp | 5 ++--- src/organizercore.cpp | 16 ++++++++-------- src/organizercore.h | 2 +- src/pluginlist.cpp | 9 ++++++++- src/pluginlist.h | 3 ++- 5 files changed, 21 insertions(+), 14 deletions(-) diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 48a097189..85e969934 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -1980,7 +1980,6 @@ void MainWindow::directory_refreshed() refreshDataTree(); updateProblemsButton(); statusBar()->hide(); - m_OrganizerCore.refreshESPList(); } void MainWindow::modorder_changed() @@ -4811,7 +4810,7 @@ void MainWindow::on_bossButton_clicked() } m_IntegratedBrowser.openUrl(url); } - m_OrganizerCore.refreshESPList(); + m_OrganizerCore.refreshESPList(false); m_OrganizerCore.savePluginList(); } } @@ -4888,7 +4887,7 @@ void MainWindow::on_restoreButton_clicked() QMessageBox::critical(this, tr("Restore failed"), tr("Failed to restore the backup. Errorcode: %1").arg(windowsErrorString(::GetLastError()))); } - m_OrganizerCore.refreshESPList(); + m_OrganizerCore.refreshESPList(true); } } diff --git a/src/organizercore.cpp b/src/organizercore.cpp index 0398e9ace..895b3b9c9 100644 --- a/src/organizercore.cpp +++ b/src/organizercore.cpp @@ -1107,7 +1107,7 @@ void OrganizerCore::spawnBinary(const QFileInfo &binary, const QString &argument } refreshDirectoryStructure(); - refreshESPList(); + refreshESPList(true); savePluginList(); //These callbacks should not fiddle with directoy structure and ESPs. @@ -1559,13 +1559,13 @@ void OrganizerCore::refreshModList(bool saveChanges) refreshDirectoryStructure(); } -void OrganizerCore::refreshESPList() +void OrganizerCore::refreshESPList(bool force) { if (m_DirectoryUpdate) { // don't mess up the esp list if we're currently updating the directory // structure - m_PostRefreshTasks.append([this]() { - this->refreshESPList(); + m_PostRefreshTasks.append([=]() { + this->refreshESPList(force); }); return; } @@ -1574,7 +1574,7 @@ void OrganizerCore::refreshESPList() // clear list try { m_PluginList.refresh(m_CurrentProfile->name(), *m_DirectoryStructure, - m_CurrentProfile->getLockedOrderFileName()); + m_CurrentProfile->getLockedOrderFileName(), force); } catch (const std::exception &e) { reportError(tr("Failed to refresh list of esps: %1").arg(e.what())); } @@ -1615,7 +1615,7 @@ void OrganizerCore::refreshBSAList() void OrganizerCore::refreshLists() { if ((m_CurrentProfile != nullptr) && m_DirectoryStructure->isPopulated()) { - refreshESPList(); + refreshESPList(true); refreshBSAList(); } // no point in refreshing lists if no files have been added to the directory // tree @@ -1678,7 +1678,7 @@ void OrganizerCore::updateModInDirectoryStructure(unsigned int index, modInfo->stealFiles()); DirectoryRefresher::cleanStructure(m_DirectoryStructure); // need to refresh plugin list now so we can activate esps - refreshESPList(); + refreshESPList(true); // activate all esps of the specified mod so the bsas get activated along with // it updateModActiveState(index, true); @@ -1839,7 +1839,7 @@ void OrganizerCore::modStatusChanged(unsigned int index) updateModInDirectoryStructure(index, modInfo); } else { updateModActiveState(index, false); - refreshESPList(); + refreshESPList(true); if (m_DirectoryStructure->originExists(ToWString(modInfo->name()))) { FilesOrigin &origin = m_DirectoryStructure->getOriginByName(ToWString(modInfo->name())); diff --git a/src/organizercore.h b/src/organizercore.h index 9e81f0c36..54d9dd6d6 100644 --- a/src/organizercore.h +++ b/src/organizercore.h @@ -130,7 +130,7 @@ class OrganizerCore : public QObject, public MOBase::IPluginDiagnose void prepareStart(); - void refreshESPList(); + void refreshESPList(bool force = false); void refreshBSAList(); void refreshDirectoryStructure(); diff --git a/src/pluginlist.cpp b/src/pluginlist.cpp index 8bf438f11..9bbcdc116 100644 --- a/src/pluginlist.cpp +++ b/src/pluginlist.cpp @@ -140,8 +140,15 @@ void PluginList::highlightPlugins(const QItemSelection &selected, const MOShared void PluginList::refresh(const QString &profileName , const DirectoryEntry &baseDirectory - , const QString &lockedOrderFile) + , const QString &lockedOrderFile + , bool force) { + if (force) { + m_ESPs.clear(); + m_ESPsByName.clear(); + m_ESPsByPriority.clear(); + } + ChangeBracket layoutChange(this); QStringList primaryPlugins = m_GamePlugin->primaryPlugins(); diff --git a/src/pluginlist.h b/src/pluginlist.h index 4762f79fd..f91738108 100644 --- a/src/pluginlist.h +++ b/src/pluginlist.h @@ -116,7 +116,8 @@ class PluginList : public QAbstractItemModel, public MOBase::IPluginList **/ void refresh(const QString &profileName , const MOShared::DirectoryEntry &baseDirectory - , const QString &lockedOrderFile); + , const QString &lockedOrderFile + , bool refresh); /** * @brief enable a plugin based on its name From 47dc5cded72ff79a3964ef39b7ad23e6b27fcdff Mon Sep 17 00:00:00 2001 From: Silarn Date: Mon, 9 Apr 2018 12:17:15 -0500 Subject: [PATCH 49/57] Add DXTex header licenses for new BSATK handling of FO4 texture BA2s --- src/aboutdialog.cpp | 2 ++ src/aboutdialog.h | 3 ++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/aboutdialog.cpp b/src/aboutdialog.cpp index 5ac05df77..a350036fd 100644 --- a/src/aboutdialog.cpp +++ b/src/aboutdialog.cpp @@ -54,6 +54,7 @@ AboutDialog::AboutDialog(const QString &version, QWidget *parent) m_LicenseFiles[LICENSE_SIP] = "sip.txt"; m_LicenseFiles[LICENSE_CASTLE] = "Castle.txt"; m_LicenseFiles[LICENSE_ANTLR] = "AntlrBuildTask.txt"; + m_LicenseFiles[LICENSE_DXTEX] = "DXTex.txt"; addLicense("Qt", LICENSE_LGPL3); addLicense("Qt Json", LICENSE_GPL3); @@ -73,6 +74,7 @@ AboutDialog::AboutDialog(const QString &version, QWidget *parent) addLicense("spdlog", LICENSE_SPDLOG); addLicense("{fmt}", LICENSE_FMT); addLicense("SIP", LICENSE_SIP); + addLicense("DXTex Headers", LICENSE_DXTEX); ui->nameLabel->setText(QString("%1 %2").arg(ui->nameLabel->text()).arg(version)); #if defined(HGID) diff --git a/src/aboutdialog.h b/src/aboutdialog.h index a67c9c738..3ae3237ba 100644 --- a/src/aboutdialog.h +++ b/src/aboutdialog.h @@ -60,7 +60,8 @@ class AboutDialog : public QDialog LICENSE_FMT, LICENSE_SIP, LICENSE_CASTLE, - LICENSE_ANTLR + LICENSE_ANTLR, + LICENSE_DXTEX }; private: From 9465966b2c782a3b86ed933e868b306194289bbd Mon Sep 17 00:00:00 2001 From: Silarn Date: Mon, 9 Apr 2018 12:18:22 -0500 Subject: [PATCH 50/57] Created threaded process for writing mod meta files to prevent hangs --- src/mainwindow.cpp | 14 +++++++++----- src/mainwindow.h | 3 +++ src/nexusinterface.cpp | 2 +- 3 files changed, 13 insertions(+), 6 deletions(-) diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 85e969934..1e2ec68be 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -153,8 +153,6 @@ along with Mod Organizer. If not, see . #include #include -#include - #ifndef Q_MOC_RUN #include #include @@ -901,6 +899,8 @@ void MainWindow::cleanup() QWebEngineProfile::defaultProfile()->clearAllVisitedLinks(); m_IntegratedBrowser.close(); + m_SaveMetaTimer.stop(); + m_MetaSave.waitForFinished(); } @@ -1568,9 +1568,13 @@ void MainWindow::checkBSAList() void MainWindow::saveModMetas() { - for (unsigned int i = 0; i < ModInfo::getNumMods(); ++i) { - ModInfo::Ptr modInfo = ModInfo::getByIndex(i); - modInfo->saveMeta(); + if (m_MetaSave.isFinished()) { + m_MetaSave = QtConcurrent::run([this]() { + for (unsigned int i = 0; i < ModInfo::getNumMods(); ++i) { + ModInfo::Ptr modInfo = ModInfo::getByIndex(i); + modInfo->saveMeta(); + } + }); } } diff --git a/src/mainwindow.h b/src/mainwindow.h index d0957305c..ef6eb262b 100644 --- a/src/mainwindow.h +++ b/src/mainwindow.h @@ -63,6 +63,7 @@ namespace MOShared { class DirectoryEntry; } #include #include #include +#include class QAction; class QAbstractItemModel; @@ -336,6 +337,8 @@ private slots: QTimer m_SaveMetaTimer; QTimer m_UpdateProblemsTimer; + QFuture m_MetaSave; + QTime m_StartTime; //SaveGameInfoWidget *m_CurrentSaveView; MOBase::ISaveGameInfoWidget *m_CurrentSaveView; diff --git a/src/nexusinterface.cpp b/src/nexusinterface.cpp index eba02a6f4..97186e8ba 100644 --- a/src/nexusinterface.cpp +++ b/src/nexusinterface.cpp @@ -500,7 +500,7 @@ void NexusInterface::requestFinished(std::list::iterator iter) iter->m_URL = reply->attribute(QNetworkRequest::RedirectionTargetAttribute).toString(); iter->m_Reroute = true; m_RequestQueue.enqueue(*iter); - nextRequest(); + //nextRequest(); return; } QByteArray data = reply->readAll(); From 5a24d2b60cbe93cabb8070ddbdccb17801bee8eb Mon Sep 17 00:00:00 2001 From: Silarn Date: Tue, 10 Apr 2018 01:53:59 -0500 Subject: [PATCH 51/57] Minor improvements to download hiding --- src/downloadmanager.cpp | 20 ++------------------ 1 file changed, 2 insertions(+), 18 deletions(-) diff --git a/src/downloadmanager.cpp b/src/downloadmanager.cpp index 161656b25..8977492c5 100644 --- a/src/downloadmanager.cpp +++ b/src/downloadmanager.cpp @@ -580,36 +580,20 @@ void DownloadManager::removeDownload(int index, bool deleteFile) emit aboutToUpdate(); if (index < 0) { - if (index == -1) { - DownloadState minState = STATE_READY; + DownloadState minState = index == -1 ? STATE_READY : STATE_INSTALLED; index = 0; for (QVector::iterator iter = m_ActiveDownloads.begin(); iter != m_ActiveDownloads.end();) { if ((*iter)->m_State >= minState) { removeFile(index, deleteFile); delete *iter; iter = m_ActiveDownloads.erase(iter); + QCoreApplication::processEvents(); } else { ++iter; ++index; } } - } - else { - DownloadState minState = STATE_INSTALLED; - index = 0; - for (QVector::iterator iter = m_ActiveDownloads.begin(); iter != m_ActiveDownloads.end();) { - if ((*iter)->m_State == minState) { - removeFile(index, deleteFile); - delete *iter; - iter = m_ActiveDownloads.erase(iter); - } - else { - ++iter; - ++index; - } - } - } } else { if (index >= m_ActiveDownloads.size()) { reportError(tr("remove: invalid download index %1").arg(index)); From c4bfee0089512e37a84742cf3981545bc0072413 Mon Sep 17 00:00:00 2001 From: Silarn Date: Tue, 10 Apr 2018 23:28:33 -0500 Subject: [PATCH 52/57] Prep for Qt 5.11 (backward-compatible) --- src/CMakeLists.txt | 8 ++++---- src/downloadmanager.cpp | 2 +- src/mainwindow.cpp | 1 + src/queryoverwritedialog.cpp | 2 ++ 4 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index ef009e03a..fef640b31 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,4 +1,4 @@ -CMAKE_MINIMUM_REQUIRED (VERSION 2.8) +CMAKE_MINIMUM_REQUIRED (VERSION 2.8.11) CMAKE_POLICY(SET CMP0020 NEW) #CMAKE_POLICY(SET CMP0043 NEW) @@ -249,6 +249,8 @@ FIND_PACKAGE(Qt5Quick REQUIRED) FIND_PACKAGE(Qt5Network REQUIRED) FIND_PACKAGE(Qt5WinExtras REQUIRED) FIND_PACKAGE(Qt5WebEngineWidgets REQUIRED) +FIND_PACKAGE(Qt5Script REQUIRED) +FIND_PACKAGE(Qt5Qml REQUIRED) FIND_PACKAGE(Qt5LinguistTools) QT5_WRAP_UI(organizer_UIHDRS ${organizer_UIS}) QT5_ADD_RESOURCES(organizer_RCCPPS ${organizer_QRCS}) @@ -314,6 +316,7 @@ ENDIF() ADD_EXECUTABLE(ModOrganizer WIN32 ${organizer_HDRS} ${organizer_SRCS} ${organizer_UIHDRS} ${organizer_RCS} ${organizer_RCCPPS} ${organizer_translations_qm}) TARGET_LINK_LIBRARIES(ModOrganizer Qt5::Widgets Qt5::WinExtras Qt5::WebEngineWidgets Qt5::Quick + Qt5::Script Qt5::Qml Qt5::QuickWidgets Qt5::Network ${Boost_LIBRARIES} zlibstatic uibase esptk bsatk githubpp @@ -327,9 +330,6 @@ SET_TARGET_PROPERTIES(ModOrganizer PROPERTIES LINK_FLAGS_RELWITHDEBINFO "/LARGEADDRESSAWARE ${OPTIMIZE_LINK_FLAGS}") -QT5_USE_MODULES(ModOrganizer Widgets Script Qml QuickWidgets Quick Network WebEngineWidgets) - - ############### ## Installation diff --git a/src/downloadmanager.cpp b/src/downloadmanager.cpp index 8977492c5..c935d20b9 100644 --- a/src/downloadmanager.cpp +++ b/src/downloadmanager.cpp @@ -462,7 +462,7 @@ void DownloadManager::addNXMDownload(const QString &url) for (auto pair : m_PendingDownloads) { if (pair.first == nxmInfo.modId() && pair.second == nxmInfo.fileId()) { - qDebug("download requested is already started (mod id: %s, file id: %s)", qPrintable(nxmInfo.modId()), qPrintable(nxmInfo.fileId())); + qDebug("download requested is already started (mod id: %s, file id: %s)", qPrintable(QString(nxmInfo.modId())), qPrintable(QString(nxmInfo.fileId()))); QMessageBox::information(nullptr, tr("Already Started"), tr("A download for this mod file has already been queued."), QMessageBox::Ok); return; } diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 1e2ec68be..0f66e5055 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -89,6 +89,7 @@ along with Mod Organizer. If not, see . #include #include #include +#include #include #include #include diff --git a/src/queryoverwritedialog.cpp b/src/queryoverwritedialog.cpp index 932b2637c..eb67719dc 100644 --- a/src/queryoverwritedialog.cpp +++ b/src/queryoverwritedialog.cpp @@ -20,6 +20,8 @@ along with Mod Organizer. If not, see . #include "queryoverwritedialog.h" #include "ui_queryoverwritedialog.h" +#include + QueryOverwriteDialog::QueryOverwriteDialog(QWidget *parent, Backup b) : QDialog(parent), ui(new Ui::QueryOverwriteDialog), m_Action(ACT_NONE) From e33da8402c9f843b2efe3883fba518bdd42bcdd3 Mon Sep 17 00:00:00 2001 From: Silarn Date: Wed, 11 Apr 2018 00:55:52 -0500 Subject: [PATCH 53/57] Allow multi-extract via archive origin entry in the BSA tab --- src/mainwindow.cpp | 45 +++++++++++++++++++++++++++++---------------- 1 file changed, 29 insertions(+), 16 deletions(-) diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 0f66e5055..abcb53125 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -4290,27 +4290,40 @@ bool MainWindow::extractProgress(QProgressDialog &progress, int percentage, std: void MainWindow::extractBSATriggered() { QTreeWidgetItem *item = m_ContextItem; + QString origin; QString targetFolder = FileDialogMemory::getExistingDirectory("extractBSA", this, tr("Extract BSA")); + QStringList archives = {}; if (!targetFolder.isEmpty()) { - BSA::Archive archive; - QString originPath = QDir::fromNativeSeparators(ToQString(m_OrganizerCore.directoryStructure()->getOriginByName(ToWString(item->text(1))).getPath())); - QString archivePath = QString("%1\\%2").arg(originPath).arg(item->text(0)); - - BSA::EErrorCode result = archive.read(archivePath.toLocal8Bit().constData(), true); - if ((result != BSA::ERROR_NONE) && (result != BSA::ERROR_INVALIDHASHES)) { - reportError(tr("failed to read %1: %2").arg(archivePath).arg(result)); - return; + if (!item->parent()) { + for (int i = 0; i < item->childCount(); ++i) { + archives.append(item->child(i)->text(0)); + } + origin = QDir::fromNativeSeparators(ToQString(m_OrganizerCore.directoryStructure()->getOriginByName(ToWString(item->text(0))).getPath())); + } else { + origin = QDir::fromNativeSeparators(ToQString(m_OrganizerCore.directoryStructure()->getOriginByName(ToWString(item->text(1))).getPath())); + archives = QStringList({ item->text(0) }); } - QProgressDialog progress(this); - progress.setMaximum(100); - progress.setValue(0); - progress.show(); - archive.extractAll(QDir::toNativeSeparators(targetFolder).toLocal8Bit().constData(), - boost::bind(&MainWindow::extractProgress, this, boost::ref(progress), _1, _2)); - if (result == BSA::ERROR_INVALIDHASHES) { - reportError(tr("This archive contains invalid hashes. Some files may be broken.")); + for (auto archiveName : archives) { + BSA::Archive archive; + QString archivePath = QString("%1\\%2").arg(origin).arg(archiveName); + BSA::EErrorCode result = archive.read(archivePath.toLocal8Bit().constData(), true); + if ((result != BSA::ERROR_NONE) && (result != BSA::ERROR_INVALIDHASHES)) { + reportError(tr("failed to read %1: %2").arg(archivePath).arg(result)); + return; + } + + QProgressDialog progress(this); + progress.setMaximum(100); + progress.setValue(0); + progress.show(); + archive.extractAll(QDir::toNativeSeparators(targetFolder).toLocal8Bit().constData(), + boost::bind(&MainWindow::extractProgress, this, boost::ref(progress), _1, _2)); + if (result == BSA::ERROR_INVALIDHASHES) { + reportError(tr("This archive contains invalid hashes. Some files may be broken.")); + } + archive.close(); } } } From e037caf58e918c5bf4693e800069098d74ff5e96 Mon Sep 17 00:00:00 2001 From: Silarn Date: Wed, 11 Apr 2018 10:58:22 -0500 Subject: [PATCH 54/57] Fix both remove and reinstall updating hidden downloads --- src/downloadmanager.cpp | 21 +++++++++++++++++++-- src/downloadmanager.h | 2 ++ src/organizercore.cpp | 2 ++ 3 files changed, 23 insertions(+), 2 deletions(-) diff --git a/src/downloadmanager.cpp b/src/downloadmanager.cpp index c935d20b9..569a7d319 100644 --- a/src/downloadmanager.cpp +++ b/src/downloadmanager.cpp @@ -902,6 +902,22 @@ void DownloadManager::markInstalled(int index) setState(m_ActiveDownloads.at(index), STATE_INSTALLED); } +void DownloadManager::markInstalled(QString fileName) +{ + int index = indexByName(fileName); + if (index >= 0) { + markInstalled(index); + } else { + DownloadInfo *info = getDownloadInfo(fileName); + if (info != nullptr) { + QSettings metaFile(info->m_Output.fileName() + ".meta", QSettings::IniFormat); + metaFile.setValue("installed", true); + metaFile.setValue("uninstalled", false); + } + delete info; + } +} + DownloadManager::DownloadInfo* DownloadManager::getDownloadInfo(QString fileName) { return DownloadInfo::createFromMeta(fileName, true); @@ -927,12 +943,13 @@ void DownloadManager::markUninstalled(QString fileName) if (index >= 0) { markUninstalled(index); } else { - DownloadInfo *info = getDownloadInfo(fileName); + QString filePath = QDir::fromNativeSeparators(m_OutputDirectory) + "/" + fileName; + DownloadInfo *info = getDownloadInfo(filePath); if (info != nullptr) { QSettings metaFile(info->m_Output.fileName() + ".meta", QSettings::IniFormat); metaFile.setValue("uninstalled", true); - setState(info, STATE_UNINSTALLED); } + delete info; } } diff --git a/src/downloadmanager.h b/src/downloadmanager.h index 059c6cb56..a6d3b20ce 100644 --- a/src/downloadmanager.h +++ b/src/downloadmanager.h @@ -307,6 +307,8 @@ class DownloadManager : public MOBase::IDownloadManager */ void markInstalled(int index); + void markInstalled(QString download); + /** * @brief mark a download as uninstalled * diff --git a/src/organizercore.cpp b/src/organizercore.cpp index 895b3b9c9..999c77328 100644 --- a/src/organizercore.cpp +++ b/src/organizercore.cpp @@ -895,6 +895,8 @@ MOBase::IModInterface *OrganizerCore::installMod(const QString &fileName, ModInfoDialog::TAB_INIFILES); } m_ModInstalled(modName); + m_DownloadManager.markInstalled(fileName); + emit modInstalled(modName); return modInfo.data(); } else { reportError(tr("mod \"%1\" not found").arg(modName)); From 37b1bdd9e66f0c377b51b34ac94a4356dd337a5d Mon Sep 17 00:00:00 2001 From: Silarn Date: Wed, 11 Apr 2018 12:58:46 -0500 Subject: [PATCH 55/57] Bump version to 2.1.2 and update meta info --- src/version.rc | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/version.rc b/src/version.rc index a71a462ab..142065bf2 100644 --- a/src/version.rc +++ b/src/version.rc @@ -1,7 +1,7 @@ #include "Winver.h" -#define VER_FILEVERSION 2,1,1 -#define VER_FILEVERSION_STR "2.1.1\0" +#define VER_FILEVERSION 2,1,2 +#define VER_FILEVERSION_STR "2.1.2\0" VS_VERSION_INFO VERSIONINFO FILEVERSION VER_FILEVERSION @@ -10,17 +10,19 @@ FILEFLAGSMASK VS_FFI_FILEFLAGSMASK FILEFLAGS (0) FILEOS VOS__WINDOWS32 FILETYPE VFT_APP -FILESUBTYPE VFT2_UNKNOWN +FILESUBTYPE (0) BEGIN BLOCK "StringFileInfo" BEGIN BLOCK "040904B0" BEGIN VALUE "FileVersion", VER_FILEVERSION_STR - VALUE "CompanyName", "Tannin\0" - VALUE "FileDescription", "Mod Organizer UI\0" + VALUE "CompanyName", "Mod Organizer 2 Team\0" + VALUE "FileDescription", "Main Mod Oranizer 2 UI\0" VALUE "OriginalFilename", "ModOrganizer.exe\0" - VALUE "ProductName", "Mod Organizer\0" + VALUE "InternalName", "ModOrganizer\0" + VALUE "LegalCopyright", "Copyright 2011-2016 Sebastian Herbord\r\nCopyright 2016-2018 Mod Organizer 2 contributors\0" + VALUE "ProductName", "Mod Organizer 2\0" VALUE "ProductVersion", VER_FILEVERSION_STR END END From be2d39b03583fdd5a60318c73e19a14f99a38374 Mon Sep 17 00:00:00 2001 From: Silarn Date: Wed, 11 Apr 2018 15:12:31 -0500 Subject: [PATCH 56/57] Add flag and description text to ESL-flagged ESPs --- src/pluginlist.cpp | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/pluginlist.cpp b/src/pluginlist.cpp index 9bbcdc116..bd863f527 100644 --- a/src/pluginlist.cpp +++ b/src/pluginlist.cpp @@ -878,8 +878,12 @@ QVariant PluginList::data(const QModelIndex &modelIndex, int role) const text += "
" + tr("Enabled Masters") + ": " + SetJoin(enabledMasters, ", "); } if (m_ESPs[index].m_HasIni) { - text += "
There is an ini file connected to this esp. Its settings will be added to your game settings, overwriting " - "in case of conflicts."; + text += "
" + tr("There is an ini file connected to this esp. " + "Its settings will be added to your game settings, overwriting in case of conflicts."); + } + if (m_ESPs[index].m_IsLightFlagged && !m_ESPs[index].m_IsLight) { + text += "

" + tr("This ESP is flagged as an ESL. " + "It will adhere to the ESP load order but the records will be loaded in ESL space."); } toolTip += text; } @@ -902,6 +906,9 @@ QVariant PluginList::data(const QModelIndex &modelIndex, int role) const if (m_ESPs[index].m_HasIni) { result.append(":/MO/gui/attachment"); } + if (m_ESPs[index].m_IsLightFlagged && !m_ESPs[index].m_IsLight) { + result.append(":/MO/gui/awaiting"); + } return result; } return QVariant(); From 8be73d2e3b0af9cb99616d31418a0d9c74aca466 Mon Sep 17 00:00:00 2001 From: Jeremy Rimpo Date: Fri, 13 Apr 2018 00:38:23 -0500 Subject: [PATCH 57/57] Remove extraneous search code --- CMakeLists.txt | 2 -- 1 file changed, 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 5d069383d..0c5f58a7b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -11,7 +11,5 @@ SET(DEPENDENCIES_DIR CACHE PATH "") # hint to find qt in dependencies path LIST(APPEND CMAKE_PREFIX_PATH ${QT_ROOT}/lib/cmake) LIST(APPEND CMAKE_PREFIX_PATH ${LZ4_ROOT}/dll) -FILE(GLOB_RECURSE BOOST_ROOT ${DEPENDENCIES_DIR}/boost*/project-config.jam) -GET_FILENAME_COMPONENT(BOOST_ROOT ${BOOST_ROOT} DIRECTORY) ADD_SUBDIRECTORY(src)