diff options
| -rw-r--r-- | src/loot.cpp | 131 | ||||
| -rw-r--r-- | src/loot.h | 62 | ||||
| -rw-r--r-- | src/pluginlist.cpp | 293 | ||||
| -rw-r--r-- | src/pluginlist.h | 17 |
4 files changed, 295 insertions, 208 deletions
diff --git a/src/loot.cpp b/src/loot.cpp index 88ea8ce8..66e8a01d 100644 --- a/src/loot.cpp +++ b/src/loot.cpp @@ -58,10 +58,6 @@ public: [&](auto&& lv, auto&& s){ log(lv, s); }, Qt::QueuedConnection); QObject::connect( - &m_loot, &Loot::information, this, - [&](auto&& mod, auto&& i){ setInfo(mod, i); }, Qt::QueuedConnection); - - QObject::connect( &m_loot, &Loot::finished, this, [&]{ onFinished(); }, Qt::QueuedConnection); } @@ -116,11 +112,6 @@ public: } } - void setInfo(const QString& mod, const QString& info) - { - m_core.pluginList()->addInformation(mod.toStdString().c_str(), info); - } - bool result() const { return m_loot.result(); @@ -237,6 +228,7 @@ private: if (m_cancelling) { close(); } else { + handleReport(); m_report->setEnabled(true); m_buttons->setStandardButtons(QDialogButtonBox::Close); } @@ -252,83 +244,55 @@ private: addLineOutput(QString("[%1] %2").arg(log::levelToString(lv)).arg(s)); } } -}; - - -struct Loot::Message -{ - QString type; - QString text; -}; - -struct Loot::File -{ - QString name; - QString displayName; -}; - -struct Loot::Dirty -{ - qint64 crc=0; - qint64 itm=0; - qint64 deletedReferences=0; - qint64 deletedNavmesh=0; - QString cleaningUtility; - QString info; - QString toString(bool isClean) const + void handleReport() { - if (isClean) { - return QObject::tr("Verified clean by %1") - .arg(cleaningUtility.isEmpty() ? "?" : cleaningUtility); - } - - QString s = cleaningString(); + const auto& report = m_loot.report(); - if (!info.isEmpty()) { - s += " " + info; + if (!report.messages.empty()) { + addLineOutput(""); } - return s; - } + for (auto&& m : report.messages) { + log(levelFromLoot( + lootcli::logLevelFromString(m.type.toStdString())), + m.text); + } - QString cleaningString() const - { - return QObject::tr("%1 found %2 ITM record(s), %3 deleted reference(s) and %4 deleted navmesh(es).") - .arg(cleaningUtility.isEmpty() ? "?" : cleaningUtility) - .arg(itm) - .arg(deletedReferences) - .arg(deletedNavmesh); + for (auto&& p : report.plugins) { + for (auto&& d : p.dirty) { + m_core.pluginList()->addInformation(p.name, d.toString(false)); + } + } } }; -struct Loot::Plugin -{ - QString name; - std::vector<File> incompatibilities; - std::vector<Message> messages; - std::vector<Dirty> dirty, clean; - std::vector<QString> missingMasters; - bool loadsArchive = false; - bool isMaster = false; - bool isLightMaster = false; -}; -struct Loot::Stats +QString Loot::Dirty::toString(bool isClean) const { - qint64 time = 0; - QString version; -}; + if (isClean) { + return QObject::tr("Verified clean by %1") + .arg(cleaningUtility.isEmpty() ? "?" : cleaningUtility); + } -struct Loot::Report -{ - std::vector<Message> messages; - std::vector<Plugin> plugins; - Stats stats; -}; + QString s = cleaningString(); + if (!info.isEmpty()) { + s += " " + info; + } + + return s; +} + +QString Loot::Dirty::cleaningString() const +{ + return QObject::tr("%1 found %2 ITM record(s), %3 deleted reference(s) and %4 deleted navmesh(es).") + .arg(cleaningUtility.isEmpty() ? "?" : cleaningUtility) + .arg(itm) + .arg(deletedReferences) + .arg(deletedNavmesh); +} -class ReportFailed {}; Loot::Loot() : m_thread(nullptr), m_cancel(false), m_result(false) @@ -437,6 +401,11 @@ const QString& Loot::outPath() const return m_outPath; } +const Loot::Report& Loot::report() const +{ + return m_report; +} + void Loot::lootThread() { try { @@ -558,7 +527,7 @@ void Loot::processStdout(const std::string &lootOut) void Loot::processMessage(const lootcli::Message& m) { - static const std::regex exRequires("\"([^\"]*)\" requires \"([^\"]*)\", but it is missing\\."); + /*static const std::regex exRequires("\"([^\"]*)\" requires \"([^\"]*)\", but it is missing\\."); static const std::regex exIncompatible("\"([^\"]*)\" is incompatible with \"([^\"]*)\", but both are present\\."); switch (m.type) @@ -595,7 +564,7 @@ void Loot::processMessage(const lootcli::Message& m) emit progress(m.progress); break; } - } + }*/ } void Loot::processOutputFile() @@ -623,19 +592,7 @@ void Loot::processOutputFile() return; } - const auto report = createReport(doc); - - for (auto&& m : report.messages) { - emit log(levelFromLoot( - lootcli::logLevelFromString(m.type.toStdString())), - m.text); - } - - for (auto&& p : report.plugins) { - for (auto&& d : p.dirty) { - emit information(p.name, d.toString(false)); - } - } + m_report = createReport(doc); } Loot::Report Loot::createReport(const QJsonDocument& doc) const @@ -17,6 +17,57 @@ class Loot : public QObject Q_OBJECT; public: + struct Message + { + QString type; + QString text; + }; + + struct File + { + QString name; + QString displayName; + }; + + struct Dirty + { + qint64 crc=0; + qint64 itm=0; + qint64 deletedReferences=0; + qint64 deletedNavmesh=0; + QString cleaningUtility; + QString info; + + QString toString(bool isClean) const; + QString cleaningString() const; + }; + + struct Plugin + { + QString name; + std::vector<File> incompatibilities; + std::vector<Message> messages; + std::vector<Dirty> dirty, clean; + std::vector<QString> missingMasters; + bool loadsArchive = false; + bool isMaster = false; + bool isLightMaster = false; + }; + + struct Stats + { + qint64 time = 0; + QString version; + }; + + struct Report + { + std::vector<Message> messages; + std::vector<Plugin> plugins; + Stats stats; + }; + + Loot(); ~Loot(); @@ -24,23 +75,15 @@ public: void cancel(); bool result() const; const QString& outPath() const; + const Report& report() const; signals: void output(const QString& s); void progress(const lootcli::Progress p); void log(MOBase::log::Levels level, const QString& s); - void information(const QString& mod, const QString& info); void finished(); private: - struct Report; - struct Stats; - struct Message; - struct Plugin; - struct Dirty; - struct File; - class BadReport {}; - std::unique_ptr<QThread> m_thread; std::atomic<bool> m_cancel; std::atomic<bool> m_result; @@ -48,6 +91,7 @@ private: env::HandlePtr m_lootProcess; env::HandlePtr m_stdout; std::string m_outputBuffer; + Report m_report; std::string readFromPipe(); diff --git a/src/pluginlist.cpp b/src/pluginlist.cpp index b50a51d8..ab421f2b 100644 --- a/src/pluginlist.cpp +++ b/src/pluginlist.cpp @@ -423,6 +423,17 @@ void PluginList::addInformation(const QString &name, const QString &message) }
}
+void PluginList::addLootReport(const QString& name, Loot::Plugin plugin)
+{
+ auto iter = m_ESPsByName.find(name.toLower());
+
+ if (iter != m_ESPsByName.end()) {
+ m_AdditionalInfo[name.toLower()].m_Loot = std::move(plugin);
+ } else {
+ log::warn("failed to associate loot report for \"{}\"", name);
+ }
+}
+
bool PluginList::isEnabled(int index)
{
return m_ESPs.at(index).m_Enabled;
@@ -908,137 +919,195 @@ void PluginList::testMasters() QVariant PluginList::data(const QModelIndex &modelIndex, int role) const
{
int index = modelIndex.row();
- if ((role == Qt::DisplayRole)
- || (role == Qt::EditRole)) {
- switch (modelIndex.column()) {
- case COL_NAME: {
- return m_ESPs[index].m_Name;
- } break;
- case COL_PRIORITY: {
- return m_ESPs[index].m_Priority;
- } break;
- case COL_MODINDEX: {
- return m_ESPs[index].m_Index;
- } break;
- default: {
- return QVariant();
- } break;
- }
+
+ if ((role == Qt::DisplayRole) || (role == Qt::EditRole)) {
+ return displayData(modelIndex);
} else if ((role == Qt::CheckStateRole) && (modelIndex.column() == 0)) {
- if (m_ESPs[index].m_ForceEnabled) {
- return QVariant();
- } else {
- return m_ESPs[index].m_Enabled ? Qt::Checked : Qt::Unchecked;
- }
+ return checkstateData(modelIndex);
} else if (role == Qt::ForegroundRole) {
- if ((modelIndex.column() == COL_NAME) &&
- m_ESPs[index].m_ForceEnabled) {
- return QBrush(Qt::gray);
- }
- } else if (role == Qt::BackgroundRole
- || (role == ViewMarkingScrollBar::DEFAULT_ROLE)) {
- if (m_ESPs[index].m_ModSelected) {
- return Settings::instance().colors().pluginListContained();
- } else {
- return QVariant();
- }
+ return foregroundData(modelIndex);
+ } else if (role == Qt::BackgroundRole || (role == ViewMarkingScrollBar::DEFAULT_ROLE)) {
+ return backgroundData(modelIndex);
} else if (role == Qt::FontRole) {
- QFont result;
- if (m_ESPs[index].m_IsMaster) {
- result.setItalic(true);
- result.setWeight(QFont::Bold);
- } else if (m_ESPs[index].m_IsLight || m_ESPs[index].m_IsLightFlagged) {
- result.setItalic(true);
- }
- return result;
+ return fontData(modelIndex);
} else if (role == Qt::TextAlignmentRole) {
- if (modelIndex.column() == 0) {
- return QVariant(Qt::AlignLeft | Qt::AlignVCenter);
- } else {
- return QVariant(Qt::AlignHCenter | Qt::AlignVCenter);
- }
+ return alignmentData(modelIndex);
} else if (role == Qt::ToolTipRole) {
- QString name = m_ESPs[index].m_Name.toLower();
- auto addInfoIter = m_AdditionalInfo.find(name);
- QString toolTip;
- if (addInfoIter != m_AdditionalInfo.end()) {
- if (!addInfoIter->second.m_Messages.isEmpty()) {
- toolTip += "<ul style=\"margin-left:15px; -qt-list-indent: 0;\">";
- for (auto&& message : addInfoIter->second.m_Messages) {
- toolTip += "<li>" + message + "</li>";
- }
- toolTip += "</ul><hr>";
+ return tooltipData(modelIndex);
+ } else if (role == Qt::UserRole + 1) {
+ return iconData(modelIndex);
+ }
+ return QVariant();
+}
+
+QVariant PluginList::displayData(const QModelIndex &modelIndex) const
+{
+ int index = modelIndex.row();
+
+ switch (modelIndex.column()) {
+ case COL_NAME: {
+ return m_ESPs[index].m_Name;
+ } break;
+ case COL_PRIORITY: {
+ return m_ESPs[index].m_Priority;
+ } break;
+ case COL_MODINDEX: {
+ return m_ESPs[index].m_Index;
+ } break;
+ default: {
+ return QVariant();
+ } break;
+ }
+}
+
+QVariant PluginList::checkstateData(const QModelIndex &modelIndex) const
+{
+ int index = modelIndex.row();
+
+ if (m_ESPs[index].m_ForceEnabled) {
+ return QVariant();
+ } else {
+ return m_ESPs[index].m_Enabled ? Qt::Checked : Qt::Unchecked;
+ }
+}
+
+QVariant PluginList::foregroundData(const QModelIndex &modelIndex) const
+{
+ int index = modelIndex.row();
+
+ if ((modelIndex.column() == COL_NAME) &&
+ m_ESPs[index].m_ForceEnabled) {
+ return QBrush(Qt::gray);
+ }
+
+ return {};
+}
+
+QVariant PluginList::backgroundData(const QModelIndex &modelIndex) const
+{
+ int index = modelIndex.row();
+
+ if (m_ESPs[index].m_ModSelected) {
+ return Settings::instance().colors().pluginListContained();
+ } else {
+ return QVariant();
+ }
+}
+
+QVariant PluginList::fontData(const QModelIndex &modelIndex) const
+{
+ int index = modelIndex.row();
+
+ QFont result;
+
+ if (m_ESPs[index].m_IsMaster) {
+ result.setItalic(true);
+ result.setWeight(QFont::Bold);
+ } else if (m_ESPs[index].m_IsLight || m_ESPs[index].m_IsLightFlagged) {
+ result.setItalic(true);
+ }
+
+ return result;
+}
+
+QVariant PluginList::alignmentData(const QModelIndex &modelIndex) const
+{
+ int index = modelIndex.row();
+
+ if (modelIndex.column() == 0) {
+ return QVariant(Qt::AlignLeft | Qt::AlignVCenter);
+ } else {
+ return QVariant(Qt::AlignHCenter | Qt::AlignVCenter);
+ }
+}
+
+QVariant PluginList::tooltipData(const QModelIndex &modelIndex) const
+{
+ int index = modelIndex.row();
+
+ QString name = m_ESPs[index].m_Name.toLower();
+ auto addInfoIter = m_AdditionalInfo.find(name);
+ QString toolTip;
+ if (addInfoIter != m_AdditionalInfo.end()) {
+ if (!addInfoIter->second.m_Messages.isEmpty()) {
+ toolTip += "<ul style=\"margin-left:15px; -qt-list-indent: 0;\">";
+ for (auto&& message : addInfoIter->second.m_Messages) {
+ toolTip += "<li>" + message + "</li>";
}
+ toolTip += "</ul><hr>";
}
- if (m_ESPs[index].m_ForceEnabled) {
- QString text = tr("<b>Origin</b>: %1").arg(m_ESPs[index].m_OriginName);
- text += tr("<br><b><i>This plugin can't be disabled (enforced by the game).</i></b>");
- toolTip += text;
- } else {
- QString text = tr("<b>Origin</b>: %1").arg(m_ESPs[index].m_OriginName);
- if (m_ESPs[index].m_Author.size() > 0) {
- text += "<br><b>" + tr("Author") + "</b>: " + TruncateString(m_ESPs[index].m_Author);
- }
- if (m_ESPs[index].m_Description.size() > 0) {
- text += "<br><b>" + tr("Description") + "</b>: " + TruncateString(m_ESPs[index].m_Description);
- }
- if (m_ESPs[index].m_MasterUnset.size() > 0) {
- text += "<br><b>" + tr("Missing Masters") + "</b>: <b>" + TruncateString(SetJoin(m_ESPs[index].m_MasterUnset, ", ")) + "</b>";
- }
- std::set<QString> enabledMasters;
- std::set_difference(m_ESPs[index].m_Masters.begin(), m_ESPs[index].m_Masters.end(),
- m_ESPs[index].m_MasterUnset.begin(), m_ESPs[index].m_MasterUnset.end(),
- std::inserter(enabledMasters, enabledMasters.end()));
- if (!enabledMasters.empty()) {
- text += "<br><b>" + tr("Enabled Masters") + "</b>: " + TruncateString(SetJoin(enabledMasters, ", "));
- }
- if (!m_ESPs[index].m_Archives.empty()) {
- text += "<br><b>" + tr("Loads Archives") + "</b>: " + TruncateString(SetJoin(m_ESPs[index].m_Archives, ", "));
- text += "<br>" + tr("There are Archives connected to this plugin. "
- "Their assets will be added to your game, overwriting in case of conflicts following the plugin order. "
- "Loose files will always overwrite assets from Archives. (This flag only checks for Archives from the same mod as the plugin)");
- }
- if (m_ESPs[index].m_HasIni) {
- text += "<br><b>" + tr("Loads INI settings") + "</b>: ";
- text += "<br>" + tr("There is an ini file connected to this plugin. "
- "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 += "<br><br>" + 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;
+ }
+ if (m_ESPs[index].m_ForceEnabled) {
+ QString text = tr("<b>Origin</b>: %1").arg(m_ESPs[index].m_OriginName);
+ text += tr("<br><b><i>This plugin can't be disabled (enforced by the game).</i></b>");
+ toolTip += text;
+ } else {
+ QString text = tr("<b>Origin</b>: %1").arg(m_ESPs[index].m_OriginName);
+ if (m_ESPs[index].m_Author.size() > 0) {
+ text += "<br><b>" + tr("Author") + "</b>: " + TruncateString(m_ESPs[index].m_Author);
+ }
+ if (m_ESPs[index].m_Description.size() > 0) {
+ text += "<br><b>" + tr("Description") + "</b>: " + TruncateString(m_ESPs[index].m_Description);
}
- return toolTip;
- } else if (role == Qt::UserRole + 1) {
- QVariantList result;
- QString nameLower = m_ESPs[index].m_Name.toLower();
if (m_ESPs[index].m_MasterUnset.size() > 0) {
- result.append(":/MO/gui/warning");
+ text += "<br><b>" + tr("Missing Masters") + "</b>: <b>" + TruncateString(SetJoin(m_ESPs[index].m_MasterUnset, ", ")) + "</b>";
}
- if (m_LockedOrder.find(nameLower) != m_LockedOrder.end()) {
- result.append(":/MO/gui/locked");
+ std::set<QString> enabledMasters;
+ std::set_difference(m_ESPs[index].m_Masters.begin(), m_ESPs[index].m_Masters.end(),
+ m_ESPs[index].m_MasterUnset.begin(), m_ESPs[index].m_MasterUnset.end(),
+ std::inserter(enabledMasters, enabledMasters.end()));
+ if (!enabledMasters.empty()) {
+ text += "<br><b>" + tr("Enabled Masters") + "</b>: " + TruncateString(SetJoin(enabledMasters, ", "));
}
- auto bossInfoIter = m_AdditionalInfo.find(nameLower);
- if (bossInfoIter != m_AdditionalInfo.end()) {
- if (!bossInfoIter->second.m_Messages.isEmpty()) {
- result.append(":/MO/gui/information");
- }
+ if (!m_ESPs[index].m_Archives.empty()) {
+ text += "<br><b>" + tr("Loads Archives") + "</b>: " + TruncateString(SetJoin(m_ESPs[index].m_Archives, ", "));
+ text += "<br>" + tr("There are Archives connected to this plugin. "
+ "Their assets will be added to your game, overwriting in case of conflicts following the plugin order. "
+ "Loose files will always overwrite assets from Archives. (This flag only checks for Archives from the same mod as the plugin)");
}
if (m_ESPs[index].m_HasIni) {
- result.append(":/MO/gui/attachment");
- }
- if (!m_ESPs[index].m_Archives.empty()) {
- result.append(":/MO/gui/archive_conflict_neutral");
+ text += "<br><b>" + tr("Loads INI settings") + "</b>: ";
+ text += "<br>" + tr("There is an ini file connected to this plugin. "
+ "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) {
- result.append(":/MO/gui/awaiting");
+ text += "<br><br>" + 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.");
}
- return result;
+ toolTip += text;
}
- return QVariant();
+ return toolTip;
}
+QVariant PluginList::iconData(const QModelIndex &modelIndex) const
+{
+ int index = modelIndex.row();
+
+ QVariantList result;
+ QString nameLower = m_ESPs[index].m_Name.toLower();
+ if (m_ESPs[index].m_MasterUnset.size() > 0) {
+ result.append(":/MO/gui/warning");
+ }
+ if (m_LockedOrder.find(nameLower) != m_LockedOrder.end()) {
+ result.append(":/MO/gui/locked");
+ }
+ auto bossInfoIter = m_AdditionalInfo.find(nameLower);
+ if (bossInfoIter != m_AdditionalInfo.end()) {
+ if (!bossInfoIter->second.m_Messages.isEmpty()) {
+ result.append(":/MO/gui/information");
+ }
+ }
+ if (m_ESPs[index].m_HasIni) {
+ result.append(":/MO/gui/attachment");
+ }
+ if (!m_ESPs[index].m_Archives.empty()) {
+ result.append(":/MO/gui/archive_conflict_neutral");
+ }
+ if (m_ESPs[index].m_IsLightFlagged && !m_ESPs[index].m_IsLight) {
+ result.append(":/MO/gui/awaiting");
+ }
+ return result;
+}
bool PluginList::setData(const QModelIndex &modIndex, const QVariant &value, int role)
{
diff --git a/src/pluginlist.h b/src/pluginlist.h index 092ba378..5cbe0a17 100644 --- a/src/pluginlist.h +++ b/src/pluginlist.h @@ -23,6 +23,8 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. #include <directoryentry.h>
#include <ipluginlist.h>
#include "profile.h"
+#include "loot.h"
+
namespace MOBase { class IPluginGame; }
#include <QString>
@@ -155,6 +157,11 @@ public: void addInformation(const QString &name, const QString &message);
/**
+ * adds information from a loot report
+ */
+ void addLootReport(const QString& name, Loot::Plugin plugin);
+
+ /**
* @brief test if a plugin is enabled
*
* @param index index of the plugin to look up
@@ -324,6 +331,7 @@ private: struct AdditionalInfo {
QStringList m_Messages;
+ Loot::Plugin m_Loot;
};
friend bool ByName(const ESPInfo& LHS, const ESPInfo& RHS);
@@ -372,6 +380,15 @@ private: const MOBase::IPluginGame *m_GamePlugin;
+
+ QVariant displayData(const QModelIndex &modelIndex) const;
+ QVariant checkstateData(const QModelIndex &modelIndex) const;
+ QVariant foregroundData(const QModelIndex &modelIndex) const;
+ QVariant backgroundData(const QModelIndex &modelIndex) const;
+ QVariant fontData(const QModelIndex &modelIndex) const;
+ QVariant alignmentData(const QModelIndex &modelIndex) const;
+ QVariant tooltipData(const QModelIndex &modelIndex) const;
+ QVariant iconData(const QModelIndex &modelIndex) const;
};
#pragma warning(pop)
|
