Compare commits

..
Author SHA1 Message Date
Tannin d983c908ee minor stuff 2015-05-11 21:41:00 +02:00
Tannin 0cc077b8c4 Merge 2015-05-09 21:46:40 +02:00
Tannin b245bc2ce3 enabling/disabling a plugin should now immediately cause a check for problems 2015-04-08 18:53:43 +02:00
Tannin 0a1707fa9c Merge in changes by Tom Tanner 2015-03-27 18:24:37 +01:00
Tom Tanner b10b1f28ff Fixed Scons build for existing bits.
Changed pynedit.pro to fetch from 'standard' install location
Changed saveas code to use organizer report rather than uibase - this way it's
not dependant on the vagaries of the include path, and works the same as the
rest of the organiser directory
2015-03-20 10:34:30 +00:00
Tom Tanner 59c10d78cd Merge 2015-03-19 16:48:21 +00:00
Tannin 7dd29a68e2 overwrite is now ignored when determining potential mod order conflicts 2015-03-18 19:38:24 +01:00
Tom Tanner ce0dc685ca Merge with branch1.2 2015-03-18 17:40:29 +00:00
Tom Tanner e426d8efb4 Refactoring and cleanup. 2015-03-18 14:16:04 +00:00
Tom Tanner bf00944706 Every plugin now built 2015-03-17 16:31:15 +00:00
Tannin 97c8769334 Merge with branch1.2 2015-01-24 19:34:12 +01:00
Tannin 05d1782cf1 cleanup (mostly removing unused includes) 2015-01-22 19:44:38 +01:00
Tannin f114b3ee60 bugfix: translations for some plugins weren't loaded 2015-01-11 11:14:58 +01:00
Tannin 0320bd719a Merge 2015-01-04 10:33:37 +01:00
Tannin 943689d5c3 - fixes after merge 2015-01-04 10:13:12 +01:00
Tannin ecf0ff0d02 Merge with branch1.2 2015-01-03 15:58:52 +01:00
Tannin 182ec5f85d bugfix: potential mod order problem reported when there were no mods at all 2014-12-20 17:06:48 +01:00
Tannin 2632e79de7 replaced all uses of NULL with nullptr
fixed a few placed where NULL was used as a number or boolean
2014-11-28 11:19:20 +01:00
Tannin 41eb0d50d4 undid some changes that accidentally made it to this branch 2014-11-26 20:19:07 +01:00
Tannin 863233e1ab - fixed manifest for qt5
- download messages can now be sent from different user accounts
2014-11-14 23:33:49 +01:00
Tannin 9cb9c2cc56 - fixed manifest for qt5
- download messages can now be sent from different user accounts
2014-11-14 23:33:49 +01:00
Tannin 8529da255f - several style fixes suggested by static analysis
- will now support up to 4 levels of version numbers (major.minor.subminor.subsubminor
2014-09-24 19:51:51 +02:00
Tannin dd2203f647 - several style fixes suggested by static analysis
- will now support up to 4 levels of version numbers (major.minor.subminor.subsubminor
2014-09-24 19:51:51 +02:00
Tannin 123d291dc1 bugfix: search for missing masters wasn't case-insensitive 2014-09-10 20:33:23 +02:00
Tannin 926cdedf8c bugfix: search for missing masters wasn't case-insensitive 2014-09-10 20:33:23 +02:00
Tannin 0cc55698f7 - added an additional diagnosis check that warns if there are any missing masters 2014-09-10 20:32:25 +02:00
Tannin 7ea85f751e - added an additional diagnosis check that warns if there are any missing masters 2014-09-10 20:32:25 +02:00
Tannin 2cf83c7681 - re-enabled building of loot_cli and started developing against the new api
- extended set of default categories
- more tolerand bbcode parser
- added a few colors for the bbcode parser
- more fixes to qt5 compatibility
- started work on ability to unloading (and thus re-loading) of plugins
- names of plugins are no longer localizable (because those names are also used to store settings)
- added settings to disable individual diagnosis settings
- path of dependencies is now configured in a .pri file instead of environment variablees
- bugfix: if the modid-input is canceled, the id was saved as -1 and wasn't re-requested from the user
- bugfix: moving files with the SHFileOperation-Api didn't update the vfs correctly (still not perfect but better)
- bugfix: attempt to remove the deleter-file seems to have caused error messages for some users
- bugfix: fixed a couple of cases that might have caused the tutorial to hang
2014-09-08 20:37:23 +02:00
Tannin fb4eacabed - re-enabled building of loot_cli and started developing against the new api
- extended set of default categories
- more tolerand bbcode parser
- added a few colors for the bbcode parser
- more fixes to qt5 compatibility
- started work on ability to unloading (and thus re-loading) of plugins
- names of plugins are no longer localizable (because those names are also used to store settings)
- added settings to disable individual diagnosis settings
- path of dependencies is now configured in a .pri file instead of environment variablees
- bugfix: if the modid-input is canceled, the id was saved as -1 and wasn't re-requested from the user
- bugfix: moving files with the SHFileOperation-Api didn't update the vfs correctly (still not perfect but better)
- bugfix: attempt to remove the deleter-file seems to have caused error messages for some users
- bugfix: fixed a couple of cases that might have caused the tutorial to hang
2014-09-08 20:37:23 +02:00
Tannin 366b3854b8 load order suggestion now picks the first esp for each mod for its suggested
order, even if it's not the origin of that esp. This should fix some dubious
suggestions
2014-08-18 23:03:31 +02:00
Tannin 4bf94e9fda load order suggestion now picks the first esp for each mod for its suggested
order, even if it's not the origin of that esp. This should fix some dubious
suggestions
2014-08-18 23:03:31 +02:00
Tannin 016a2efb88 - download-list will no longer show a file as having incomplete data if there is no file version
- added a new mod column with icons displaying the content of the mod
- MO now differentiates between mods using an internal name that disambiguates between foreign and regular mods
2014-07-21 19:14:24 +02:00
Tannin 6f73fe05a4 - download-list will no longer show a file as having incomplete data if there is no file version
- added a new mod column with icons displaying the content of the mod
- MO now differentiates between mods using an internal name that disambiguates between foreign and regular mods
2014-07-21 19:14:24 +02:00
Tannin 4531207250 Merge 2014-07-15 20:45:29 +02:00
Tannin 266b597e4c merged changes by TheBloke 2014-07-15 17:48:43 +02:00
Tannin 41bd8cc0cd - qt 5 compatibility fixes
- detection for support of optimized find no longer depends on deprecated api
2014-07-15 17:31:44 +02:00
Tannin 06487c2653 - qt 5 compatibility fixes
- detection for support of optimized find no longer depends on deprecated api
2014-07-15 17:31:44 +02:00
Tannin 9b0637fa66 - when highlighting a mod the overwritten and overwriting mods are now highlighted in the list
- when starting an external application MO now wraps the process in a job and waits on that instead. This way MO is not unlocked early when skyrim is started through skse
- mod info dialog no longer offers the esp tab for foreign mods because that caused confusion
- updated translation files
- download directory and mod directory are now created if necessary
- bugfix: staging script created unnecessary copies of translation files
- bugfix: potential invalid array access when trying to determine best mod order
- bugfix: deleter file wasn't removed after esp hiding was disabled
- bugfix: potential access to to un-initialized login reply
- bugfix: changed the initialization order to allow more ui controls to be localized
2014-07-14 21:22:44 +02:00
TheBloke f0957919a5 .pro files - formatting/consistency fixes
Many small formatting changes to the majority of .pro files
 Consistent style for Qt version checking, using greaterThan(QT_MAJOR_VERSION, 4)
  This seems safest, as would continue to work for a future Qt 6 etc.
  Note that this makes redudundant the commit before this one, to organizer.pro
 Consistent indenting
 Moved some file configuration sections to be together with related sections
 Moved some installation-related sections (e.g. OUTDIR/DSTDIR) to be at the bottom,
  immediately before the related POST_LINK install lines.
 Similarly, in some cases separated out CONFIG(debug,.. checks into separate
  LIB/INCLUDE sections (high in file) and installation directory sections (low
   in file)
2014-07-07 23:32:18 +01:00
Tannin 4bce131613 - added pseudo-categories to filter for mo-managed vs. unmanaged mods
- deleted mods are now moved to the recycle bin instead of being deleted permanently
- reduced modinfo dialog for foreign mods
- foreign mods are now displayed with a pseudo-category
- added a signal when a plugin is moved
- bugfix: refreshing of directory structure for mods with bsas didn't work correctly when enabling a mod and on changing display of foreign mods
- bugfix: one mod in the list was assigned the same priority on the directory structure as the data directory
- bugfix: conflicts tab in the mod info dialog offered the hide option for files in bsas
2014-06-16 21:49:57 +02:00
Tannin 849e946284 - loot client now only updates the masterlist once per MO session
- new event to notify plugins of changed mod priority
- overwrite now shows up in the "checked" category instead of "unchecked"
- display of "foreign" mods can now be limited to only official content
- bugfix: bsa extraction dialog showed up even if the plugin was disabled
- bugfix: after detection of foreign mods the priority of the overwrite folder could get messed up
- bugfix: when displaying only the context menu for the mod list as a whole, the menu didn't disappear
- bugfix: MO crashed when trying to download via the integrated browser
2014-06-08 15:10:08 +02:00
Tannin 58a8406335 - plugin-list now displays loot messages 2014-06-02 19:15:23 +02:00
Tannin c8308f1612 - added a new mod type that represents files handled externally (i.e. DLCs) as mods in MO
- hashes of file names in bsa files are no longer checked all the time
- author and description is now read from esp files
- rewrote the code that fixes modlists after a rename, should be a bit more robust
- fixes to qt 5 and msvc 2013 compatibility
- started to update the tutorial (not done yet!)
- bugfix: counter for the problems badge wasn't calculated correctly
2014-05-31 13:43:48 +02:00
Tannin 75d821c46a - files in bsas are now only displayed in the data tab if they are managed by mo
- number of problems detected by MO is now displayed as a badge on the icon
- rephrased the explanation text on the Archives tab. unchecked plugin-loaded bsas no longer prompt a warning
- bsa extraction is now handled in a plugin
- added a way for plugins to react to mod installation
- re-enabled the automatic fix for asset order problems
- bugfix: In some cases when a download wasn't started successfully the download urls weren't stored in the meta file so no resume was possible
- bugfix: MO tried to resume downloads when it didn't have and download urls
- bugfix: downloads couldn't be paused if the download was already broken on the network layer
- bugfix: download managear did not recognize a file as downloaded if the download completed before signals were hooked up
- bugfix: in-place file replacement was re-broken
2014-05-25 15:39:45 +02:00
4 changed files with 198 additions and 107 deletions
+20
View File
@@ -0,0 +1,20 @@
Import('qt_env')
env = qt_env.Clone()
env.AppendUnique(CPPDEFINES = [
'DIAGNOSEBASIC_LIBRARY',
'NOMINMAX',
# suppress a few warnings caused by boost vs vc++ paranoia
'_SCL_SECURE_NO_WARNINGS'
])
env.AppendUnique(CPPPATH = [
'${BOOSTPATH}'
])
lib = env.SharedLibrary('diagnoseBasic', env.Glob('*.cpp'))
env.InstallModule(lib)
res = env['QT_USED_MODULES']
Return('res')
+4 -5
View File
@@ -10,9 +10,7 @@ TEMPLATE = lib
CONFIG += plugins
CONFIG += dll
contains(QT_VERSION, "^5.*") {
QT += widgets
}
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
DEFINES += DIAGNOSEBASIC_LIBRARY
DEFINES += NOMINMAX
@@ -26,11 +24,12 @@ HEADERS += diagnosebasic.h
include(../plugin_template.pri)
INCLUDEPATH += "$(BOOSTPATH)"
INCLUDEPATH += "$${BOOSTPATH}"
#CONFIG += dll
#DEFINES += INIEDITOR_LIBRARY
OTHER_FILES += \
diagnosebasic.json
diagnosebasic.json\
SConscript
+169 -99
View File
@@ -20,9 +20,13 @@
#include "diagnosebasic.h"
#include <report.h>
#include <utility.h>
#include <imodlist.h>
#include <ipluginlist.h>
#include <igameinfo.h>
#include <QtPlugin>
#include <QFile>
#include <QDir>
#include <QDebug>
#include <QCoreApplication>
#include <QMessageBox>
#include <QDateTime>
@@ -44,6 +48,7 @@ using namespace MOBase;
DiagnoseBasic::DiagnoseBasic()
: m_MOInfo(nullptr)
{
}
@@ -54,14 +59,25 @@ bool DiagnoseBasic::init(IOrganizer *moInfo)
m_MOInfo->modList()->onModStateChanged([&] (const QString &modName, IModList::ModStates) {
if (modName == "Overwrite") invalidate();
});
m_MOInfo->pluginList()->onRefreshed([&] () { this->invalidate(); });
m_MOInfo->modList()->onModMoved([&] (const QString&, int, int) {
// invalidates only the assetOrder check but there is currently no way to recheck individual
// checks
invalidate();
});
m_MOInfo->pluginList()->onPluginMoved([&] (const QString&, int, int) {
invalidate();
});
m_MOInfo->pluginList()->onRefreshed([&] () { invalidate(); });
m_MOInfo->pluginList()->onPluginStateChanged([&] (const QString &, IPluginList::PluginStates) {
invalidate();
});
return true;
}
QString DiagnoseBasic::name() const
{
return tr("Basic diagnosis plugin");
return "Basic diagnosis plugin";
}
QString DiagnoseBasic::author() const
@@ -76,7 +92,7 @@ QString DiagnoseBasic::description() const
VersionInfo DiagnoseBasic::version() const
{
return VersionInfo(1, 1, 0, VersionInfo::RELEASE_FINAL);
return VersionInfo(1, 1, 2, VersionInfo::RELEASE_FINAL);
}
bool DiagnoseBasic::isActive() const
@@ -86,13 +102,19 @@ bool DiagnoseBasic::isActive() const
QList<PluginSetting> DiagnoseBasic::settings() const
{
return QList<PluginSetting>();
return QList<PluginSetting>()
<< PluginSetting("check_errorlog", tr("Warn when an error occured last time an application was run"), true)
<< PluginSetting("check_overwrite", tr("Warn when there are files in the overwrite directory"), true)
<< PluginSetting("check_font", tr("Warn when the font configuration refers to files that aren't installed"), true)
<< PluginSetting("check_conflict", tr("Warn when mods are installed that conflict with MO functionality"), true)
<< PluginSetting("check_modorder", tr("Warn when MO determins the mod order may cause problems"), true)
<< PluginSetting("check_missingmasters", tr("Warn when there are esps with missing masters"), true);
}
bool DiagnoseBasic::errorReported() const
{
QDir dir(QCoreApplication::applicationDirPath() + "/logs");
QDir dir(qApp->property("dataPath").toString() + "/logs");
QFileInfoList files = dir.entryInfoList(QStringList("ModOrganizer_??_??_??_??_??.log"),
QDir::Files, QDir::Name | QDir::Reversed);
@@ -141,7 +163,7 @@ bool DiagnoseBasic::errorReported() const
bool DiagnoseBasic::overwriteFiles() const
{
QDir dir(QCoreApplication::applicationDirPath() + "/overwrite");
QDir dir(qApp->property("dataPath").toString() + "/overwrite");
return dir.count() != 2; // account for . and ..
}
@@ -202,16 +224,18 @@ void DiagnoseBasic::topoSort(std::vector<DiagnoseBasic::ListElement> &list) cons
typedef graph_traits<Graph>::vertex_descriptor Vertex;
typedef std::list<Vertex> Order;
// figure out unconnected components of the graph.
// figure out disconnected components of the graph
std::vector<int> component(num_vertices(graph));
if (component.size() == 0) {
throw MyException(tr("failed to sort"));
}
connected_components(graph, &component[0]);
for (int i = 0; i != component.size(); ++i) {
list[i].sortGroup = component[i];
}
Order order;
// do the actual sorting. This sorts the graph in full though the order between unconnected components doesn't
// do the actual sorting. This sorts the graph in full although the order between unconnected components doesn't
// really matter to us
boost::topological_sort(graph, std::front_inserter(order));
}
@@ -224,22 +248,36 @@ void DiagnoseBasic::Sorter::sortGroup(std::vector<ListElement> modList)
{
auto maxSeqBegin = modList.end();
auto maxSeqEnd = modList.end();
int maxSeqAvoidMove = 0;
// first, determine the longest sequence of correctly sorted mods
auto curSeqBegin = modList.begin();
auto curSeqEnd = modList.begin();
int curSeqAvoidMove = 0;
auto iter = modList.begin() + 1;
for (; iter != modList.end(); ++iter) {
if (iter->modPriority < curSeqEnd->modPriority) {
if ((iter->pluginPriority != curSeqEnd->pluginPriority)
&& (iter->modPriority < curSeqEnd->modPriority)) {
// sequence ends
if ((maxSeqBegin == modList.end()) || ((curSeqEnd - curSeqBegin) > (maxSeqEnd - maxSeqBegin))) {
// use this sequence of correctly sorted mods if it is longer than the previously longest
// sequence and doesn't have fewer mods that don't want to move. Thus the need for mods to
// stay in place beats our gole to have the minimal number of moves
if ((maxSeqBegin == modList.end())
|| (((curSeqEnd - curSeqBegin) > (maxSeqEnd - maxSeqBegin))
&& (curSeqAvoidMove >= maxSeqAvoidMove))) {
maxSeqBegin = curSeqBegin;
maxSeqEnd = iter;
maxSeqAvoidMove = curSeqAvoidMove;
}
curSeqBegin = curSeqEnd = iter;
curSeqAvoidMove = 0;
} else {
curSeqEnd = iter;
if (iter->avoidMove) {
++curSeqAvoidMove;
}
}
}
@@ -263,7 +301,8 @@ void DiagnoseBasic::Sorter::sortGroup(std::vector<ListElement> modList)
break;
}
}
if (!found) {
if (!found
&& (iter->pluginPriority != (*sorted.rbegin()).pluginPriority)) {
// add to end!
moves.push_back(Move(*iter, *sorted.rbegin(), Move::AFTER));
}
@@ -302,60 +341,112 @@ bool DiagnoseBasic::assetOrder() const
// list of mods containing conflicted scripts. We care only for those
std::map<QString, QSet<QString>> scriptMods;
foreach (const IOrganizer::FileInfo & pex, m_MOInfo->findFileInfos("scripts",
[] (const IOrganizer::FileInfo &file) -> bool { return file.filePath.endsWith(".pex", Qt::CaseInsensitive); })) {
auto filter = [] (const IOrganizer::FileInfo &file) -> bool {
return file.filePath.endsWith(".pex", Qt::CaseInsensitive); };
for (const IOrganizer::FileInfo &pex : m_MOInfo->findFileInfos("scripts", filter)) {
QStringList origins = pex.origins;
origins.removeAll("data"); // ignore files in base directory
// ignore files in base directories
origins.removeAll("data");
origins.removeAll("Overwrite");
if (origins.size() > 1) {
foreach(const QString &origin, origins) {
for(const QString &origin : origins) {
scriptMods[origin].insert(pex.filePath);
}
}
}
// produce a list with the information we need: plugin, mod and the priority for each
QStringList esps = m_MOInfo->findFiles("", [] (const QString &fileName) -> bool { return fileName.endsWith(".esp", Qt::CaseInsensitive); });
foreach (const QString &esp, esps) {
ListElement ele;
QStringList esps = m_MOInfo->findFiles("",
[] (const QString &fileName) -> bool {
return fileName.endsWith(".esp", Qt::CaseInsensitive)
|| fileName.endsWith(".esm", Qt::CaseInsensitive);
});
for (const QString &esp : esps) {
for (const QString origin : m_MOInfo->getFileOrigins(esp)) {
ListElement ele;
ele.espName = QFileInfo(esp).fileName();
ele.modName = m_MOInfo->pluginList()->origin(ele.espName);
ele.pluginPriority = m_MOInfo->pluginList()->priority(ele.espName);
ele.modPriority = m_MOInfo->modList()->priority(ele.modName);
IModList::ModStates state = m_MOInfo->modList()->state(ele.modName);
auto iter = scriptMods.find(ele.modName);
if (state.testFlag(IModList::STATE_EXISTS) && !state.testFlag(IModList::STATE_ESSENTIAL) &&
(iter != scriptMods.end())) {
ele.relevantScripts = iter->second;
modList.push_back(ele);
ele.espName = QFileInfo(esp).fileName();
ele.modName = origin;
ele.pluginPriority = m_MOInfo->pluginList()->priority(ele.espName);
ele.modPriority = m_MOInfo->modList()->priority(ele.modName);
IModList::ModStates state = m_MOInfo->modList()->state(ele.modName);
ele.avoidMove = state.testFlag(IModList::STATE_ESSENTIAL);
auto iter = scriptMods.find(ele.modName);
if (state.testFlag(IModList::STATE_EXISTS)
&& (iter != scriptMods.end())) {
ele.relevantScripts = iter->second;
modList.push_back(ele);
}
}
}
// generate a copy of list that contains each mod only once, otherwise
// strange things happen if a mod contains multiple esps that are mixed
// with esps from other mods
std::vector<ListElement> distinctModList;
{
// sort the input list so we get predictable results
std::sort(modList.begin(), modList.end(),
[] (const ListElement &lhs, const ListElement &rhs) -> bool {
return lhs.pluginPriority < rhs.pluginPriority;
});
std::set<QString> includedMods;
foreach(const ListElement &ele, modList) {
for (const ListElement &ele : modList) {
if (includedMods.find(ele.modName) == includedMods.end()) {
distinctModList.push_back(ele);
includedMods.insert(ele.modName);
}
}
}
if (distinctModList.size() == 0) {
return false;
}
// sort the list by plugin priority
// sort the list by plugin priority. This step is probably unnecessary as the list was already sorted when we removed duplicates
std::sort(distinctModList.begin(), distinctModList.end(),
[] (const ListElement &lhs, const ListElement &rhs) -> bool { return lhs.pluginPriority < rhs.pluginPriority; });
topoSort(distinctModList);
if (distinctModList.size() > 0) {
topoSort(distinctModList);
// now determine the moves necessary to bring the mod list into this order
minSorter(distinctModList);
m_SuggestedMoves = minSorter.moves;
// now determine the moves necessary to bring the mod list into this order
minSorter(distinctModList);
m_SuggestedMoves = minSorter.moves;
return m_SuggestedMoves.size() > 0;
} else {
return false;
}
}
return m_SuggestedMoves.size() > 0;
bool DiagnoseBasic::missingMasters() const
{
std::set<QString> enabledPlugins;
QStringList esps = m_MOInfo->findFiles("",
[] (const QString &fileName) -> bool { return fileName.endsWith(".esp", Qt::CaseInsensitive)
|| fileName.endsWith(".esm", Qt::CaseInsensitive); });
// gather enabled masters first
foreach (const QString &esp, esps) {
QString baseName = QFileInfo(esp).fileName();
if (m_MOInfo->pluginList()->state(baseName) == IPluginList::STATE_ACTIVE) {
enabledPlugins.insert(baseName.toLower());
}
}
m_MissingMasters.clear();
// for each required master in each esp, test if it's in the list of enabled masters.
foreach (const QString &esp, esps) {
QString baseName = QFileInfo(esp).fileName();
if (m_MOInfo->pluginList()->state(baseName) == IPluginList::STATE_ACTIVE) {
foreach (const QString master, m_MOInfo->pluginList()->masters(baseName)) {
if (enabledPlugins.find(master.toLower()) == enabledPlugins.end()) {
m_MissingMasters.insert(master);
}
}
}
}
return !m_MissingMasters.empty();
}
bool DiagnoseBasic::invalidFontConfig() const
@@ -402,32 +493,28 @@ bool DiagnoseBasic::invalidFontConfig() const
return false;
}
std::vector<unsigned int> DiagnoseBasic::activeProblems() const
{
std::vector<unsigned int> result;
if (errorReported()) {
if (m_MOInfo->pluginSetting(name(), "check_errorlog").toBool() && errorReported()) {
result.push_back(PROBLEM_ERRORLOG);
}
if (overwriteFiles()) {
if (m_MOInfo->pluginSetting(name(), "check_overwrite").toBool() && overwriteFiles()) {
result.push_back(PROBLEM_OVERWRITE);
}
if (invalidFontConfig()) {
if (m_MOInfo->pluginSetting(name(), "check_font").toBool() && invalidFontConfig()) {
result.push_back(PROBLEM_INVALIDFONT);
}
if (nitpickInstalled()) {
if (m_MOInfo->pluginSetting(name(), "check_conflict").toBool() && nitpickInstalled()) {
result.push_back(PROBLEM_NITPICKINSTALLED);
}
if (assetOrder()) {
if (m_MOInfo->pluginSetting(name(), "check_modorder").toBool() && assetOrder()) {
result.push_back(PROBLEM_ASSETORDER);
}
QStringList backups = QDir(m_MOInfo->profilePath()).entryList(QStringList() << "modlist.txt_backup_*");
if (backups.size() > 0) {
m_NewestModlistBackup = backups.last();
result.push_back(PROBLEM_MODLISTBACKUP);
if (m_MOInfo->pluginSetting(name(), "check_missingmasters").toBool() && missingMasters()) {
result.push_back(PROBLEM_MISSINGMASTERS);
}
if (QFile::exists(m_MOInfo->profilePath() + "/profile_tweaks.ini")) {
result.push_back(PROBLEM_PROFILETWEAKS);
}
@@ -448,10 +535,10 @@ QString DiagnoseBasic::shortDescription(unsigned int key) const
return tr("Nitpick installed");
case PROBLEM_ASSETORDER:
return tr("Potential Mod order problem");
case PROBLEM_MODLISTBACKUP:
return tr("Modlist backup exists");
case PROBLEM_PROFILETWEAKS:
return tr("Ini Tweaks overwritten");
case PROBLEM_MISSINGMASTERS:
return tr("Missing Masters");
default:
throw MyException(tr("invalid problem key %1").arg(key));
}
@@ -464,7 +551,7 @@ QString DiagnoseBasic::fullDescription(unsigned int key) const
return "<code>" + m_ErrorMessage.replace("\n", "<br>") + "</code>";
case PROBLEM_OVERWRITE:
return tr("Files in the <font color=\"red\"><i>Overwrite</i></font> mod are are usually files created by an external tool (i.e. Wrye Bash, Automatic Variants, ...).<br>"
"It is advisable you empty Overwrite directory by moving those files to an existing mod. You can do this by double-clicking the <font color=\"red\"><i>Overwrite</i></font> mod and use drag&drop to move the files to a mod.<br>"
"It is advisable you empty the Overwrite directory by moving those files to an existing mod. You can do this by double-clicking the <font color=\"red\"><i>Overwrite</i></font> mod and use drag&drop to move the files to a mod.<br>"
"Alternatively, right-click on <font color=\"red\"><i>Overwrite</i></font> and create a new regular mod from the files there.<br>"
"<br>"
"Why is this necessary? Generated files may depend on the other mods active in a profile and may thus be incompatible with a different profile (i.e. bashed patches from Wrye Bash). "
@@ -478,28 +565,22 @@ QString DiagnoseBasic::fullDescription(unsigned int key) const
"Worse: The two solutions may conflict so it's strongly suggested you remove this plugin.");
case PROBLEM_ASSETORDER: {
QString res = tr("The conflict resolution order for some mods containing scripts differs from that of the corresponding esp.<br>"
"This may lead to subtle, hard to locate bugs. You should re-order the affected mods (left list!).<br>"
"There is no way to reliably know if these changes are necessary but its definitively safer.<br>"
"This may lead to subtle, hard to locate bugs. <b>You should re-order the affected mods (<font color=\"red\">left list!</font>).</b><br>"
"There is no way to reliably know if each of these changes is absolutely necessary but its definitively safer.<br>"
"If someone suggested you ignore this message, please give them a proper slapping from me. <b>Do not ignore this warning</b><br>"
"The following changes should fix the issue:") + "<ul>";
"The following changes should prevent these kinds of errors:") + "<ul>";
foreach(const Move &op, m_SuggestedMoves) {
QString itemName = m_MOInfo->modList()->displayName(op.item.modName);
QString referenceName = m_MOInfo->modList()->displayName(op.reference.modName);
if (op.type == Move::BEFORE) {
res += "<li>" + tr("Move %1 before %2").arg(op.item.modName).arg(op.reference.modName) + "</li>";
res += "<li>" + tr("Move %1 before %2").arg(itemName).arg(referenceName) + "</li>";
} else {
res += "<li>" + tr("Move %1 after %2").arg(op.item.modName).arg(op.reference.modName) + "</li>";
res += "<li>" + tr("Move %1 after %2").arg(itemName).arg(referenceName) + "</li>";
}
}
res += "</ul>";
return res;
} break;
case PROBLEM_MODLISTBACKUP: {
uint timestamp = m_NewestModlistBackup.right(10).toULong();
QDateTime time;
time.setTime_t(timestamp);
return tr("A previous operation created a backup of your mod list on %1.<br>"
"This backup contains both the info which mods are enabled and the ordering.<br>"
"You can restore that backup here.").arg(time.toString());
} break;
case PROBLEM_PROFILETWEAKS: {
QString fileContent = readFileText(m_MOInfo->profilePath() + "/profile_tweaks.ini");
return tr("Settings provided in ini tweaks have been overwritten in-game or in an applications.<br>"
@@ -510,6 +591,11 @@ QString DiagnoseBasic::fullDescription(unsigned int key) const
"Hitting the <i>Fix</i> button will delete that file")
+ "<hr><i>profile_tweaks.ini:</i><pre>" + fileContent + "</pre>";
} break;
case PROBLEM_MISSINGMASTERS: {
return tr("The masters for some plugins (esp/esm) are not enabled.<br>"
"The game will crash unless you install and enable the following plugins: ")
+ "<ul><li>" + SetJoin(m_MissingMasters, "</li><li>") + "</li></ul>";
} break;
default:
throw MyException(tr("invalid problem key %1").arg(key));
}
@@ -517,51 +603,35 @@ QString DiagnoseBasic::fullDescription(unsigned int key) const
bool DiagnoseBasic::hasGuidedFix(unsigned int key) const
{
return /*(key == PROBLEM_ASSETORDER) || */ (key == PROBLEM_MODLISTBACKUP) || (key == PROBLEM_PROFILETWEAKS);
return (key == PROBLEM_ASSETORDER) || (key == PROBLEM_PROFILETWEAKS);
}
void DiagnoseBasic::startGuidedFix(unsigned int key) const
{
switch (key) {
/* case PROBLEM_ASSETORDER: {
* if (QMessageBox::warning(NULL, tr("Continue?"), tr("This <b>BETA</b> feature will rearrange your mods to eliminate all "
* "possible ordering conflicts. A backup of your mod list will be created. Proceed?"), QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) {
* shellCopy(QStringList(m_MOInfo->profilePath() + "/modlist.txt"),
* QStringList(m_MOInfo->profilePath() + "/modlist.txt_backup_" + QString("%1").arg(QDateTime::currentDateTime().toTime_t())));
* foreach (const Move &op, m_SuggestedMoves) {
* int oldPriority = m_MOInfo->modList()->priority(op.item.modName);
* int targetPriority = -1;
* if (op.type == Move::BEFORE) {
* targetPriority = m_MOInfo->modList()->priority(op.reference.modName);
* } else {
* targetPriority = m_MOInfo->modList()->priority(op.reference.modName) + 1;
* }
* if (oldPriority < targetPriority) {
* --targetPriority;
* }
* m_MOInfo->modList()->setPriority(op.item.modName, targetPriority);
* }
* }
* } break;*/
case PROBLEM_MODLISTBACKUP: {
QMessageBox question(QMessageBox::Question, tr("Restore backup?"),
tr("Do you want to restore this backup or delete it?"),
QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel);
question.setButtonText(QMessageBox::Yes, tr("Restore"));
question.setButtonText(QMessageBox::No, tr("Delete"));
question.exec();
if (question.result() == QMessageBox::Yes) {
shellMove(QStringList(m_MOInfo->profilePath() + "/" + m_NewestModlistBackup), QStringList(m_MOInfo->profilePath() + "/modlist.txt"));
m_MOInfo->refreshModList(false);
} else if (question.result() == QMessageBox::No) {
shellDelete(QStringList(m_MOInfo->profilePath() + "/" + m_NewestModlistBackup));
case PROBLEM_ASSETORDER: {
if (QMessageBox::warning(nullptr, tr("Continue?"), tr("This <b>BETA</b> feature will rearrange your mods to eliminate all "
"possible ordering conflicts. Proceed?"), QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) {
foreach (const Move &op, m_SuggestedMoves) {
int oldPriority = m_MOInfo->modList()->priority(op.item.modName);
int targetPriority = -1;
if (op.type == Move::BEFORE) {
targetPriority = m_MOInfo->modList()->priority(op.reference.modName);
} else {
targetPriority = m_MOInfo->modList()->priority(op.reference.modName) + 1;
}
if (oldPriority < targetPriority) {
--targetPriority;
}
m_MOInfo->modList()->setPriority(op.item.modName, targetPriority);
}
}
} break;
case PROBLEM_PROFILETWEAKS: {
shellDeleteQuiet(m_MOInfo->profilePath() + "/profile_tweaks.ini");
} break;
default: throw MyException(tr("invalid problem key %1").arg(key));
default:
throw MyException(tr("invalid problem key %1").arg(key));
}
}
+5 -3
View File
@@ -29,7 +29,7 @@ along with this plugin. If not, see <http://www.gnu.org/licenses/>.
#include <QSet>
class DiagnoseBasic : public QObject, MOBase::IPlugin, MOBase::IPluginDiagnose
class DiagnoseBasic : public QObject, public MOBase::IPlugin, public MOBase::IPluginDiagnose
{
Q_OBJECT
Q_INTERFACES(MOBase::IPlugin MOBase::IPluginDiagnose)
@@ -66,6 +66,7 @@ private:
bool invalidFontConfig() const;
bool nitpickInstalled() const;
bool assetOrder() const;
bool missingMasters() const;
private:
@@ -74,8 +75,8 @@ private:
static const unsigned int PROBLEM_INVALIDFONT = 3;
static const unsigned int PROBLEM_NITPICKINSTALLED = 4;
static const unsigned int PROBLEM_ASSETORDER = 5;
static const unsigned int PROBLEM_MODLISTBACKUP = 6;
static const unsigned int PROBLEM_PROFILETWEAKS = 7;
static const unsigned int PROBLEM_MISSINGMASTERS = 8;
static const unsigned int NUM_CONTEXT_ROWS = 5;
@@ -86,8 +87,8 @@ private:
QString modName;
int pluginPriority;
int modPriority;
int sortPriority;
int sortGroup;
bool avoidMove;
QSet<QString> relevantScripts;
};
@@ -130,6 +131,7 @@ private:
mutable QString m_ErrorMessage;
mutable std::vector <Move> m_SuggestedMoves;
mutable QString m_NewestModlistBackup;
mutable std::set<QString> m_MissingMasters;
};