diff options
| -rw-r--r-- | src/loot.cpp | 78 | ||||
| -rw-r--r-- | src/loot.h | 8 | ||||
| -rw-r--r-- | src/lootdialog.cpp | 56 | ||||
| -rw-r--r-- | src/lootdialog.h | 5 | ||||
| -rw-r--r-- | src/lootdialog.ui | 455 | ||||
| -rw-r--r-- | src/pluginlistview.cpp | 25 |
6 files changed, 372 insertions, 255 deletions
diff --git a/src/loot.cpp b/src/loot.cpp index 2c52aaa1..a888b577 100644 --- a/src/loot.cpp +++ b/src/loot.cpp @@ -9,8 +9,9 @@ using namespace MOBase; using namespace json; -static QString LootReportPath = QDir::temp().absoluteFilePath("lootreport.json"); -static const DWORD PipeTimeout = 500; +static QString LootReportPath = QDir::temp().absoluteFilePath("lootreport.json"); +static QString SortedPluginListPath = QDir::temp().absoluteFilePath("loadorder.txt"); +static const DWORD PipeTimeout = 500; class AsyncPipe { @@ -423,11 +424,13 @@ Loot::~Loot() } deleteReportFile(); + deleteSortedLoadOrder(); } bool Loot::start(QWidget* parent, bool didUpdateMasterList) { deleteReportFile(); + deleteSortedLoadOrder(); log::debug("starting loot"); @@ -476,6 +479,8 @@ bool Loot::spawnLootcli(QWidget* parent, bool didUpdateMasterList, << "--out" << QString("\"%1\"").arg(LootReportPath) + << "--pluginListOutputPath" << QString("\"%1\"").arg(SortedPluginListPath) + << "--language" << m_core.settings().interface().language(); if (didUpdateMasterList) { @@ -514,11 +519,16 @@ bool Loot::result() const return m_result; } -const QString& Loot::outPath() const +const QString& Loot::reportPath() const { return LootReportPath; } +const QString& Loot::sortedPluginListPath() const +{ + return SortedPluginListPath; +} + const Loot::Report& Loot::report() const { return m_report; @@ -676,7 +686,7 @@ Loot::Report Loot::createReport() const r.warnings = m_warnings; if (m_result) { - processOutputFile(r); + processReport(r); } return r; @@ -695,21 +705,33 @@ void Loot::deleteReportFile() } } -void Loot::processOutputFile(Report& r) const +void Loot::deleteSortedLoadOrder() +{ + if (QFile::exists(SortedPluginListPath)) { + log::debug("deleting temporary sorted plugin list '{}'", SortedPluginListPath); + const auto r = shell::Delete(QFileInfo(SortedPluginListPath)); + if (!r) { + log::error("failed to remove temporary sorted plugin list '{}': {}", + SortedPluginListPath, r.toString()); + } + } +} + +void Loot::processReport(Report& r) const { log::debug("parsing json output file at '{}'", LootReportPath); - QFile outFile(LootReportPath); - if (!outFile.open(QIODevice::ReadOnly)) { + QFile reportFile(LootReportPath); + if (!reportFile.open(QIODevice::ReadOnly)) { emit log(MOBase::log::Error, QString("failed to open file, %1 (error %2)") - .arg(outFile.errorString()) - .arg(outFile.error())); + .arg(reportFile.errorString()) + .arg(reportFile.error())); return; } QJsonParseError e; - const QJsonDocument doc = QJsonDocument::fromJson(outFile.readAll(), &e); + const QJsonDocument doc = QJsonDocument::fromJson(reportFile.readAll(), &e); if (doc.isNull()) { emit log(MOBase::log::Error, QString("invalid json, %1 (error %2)").arg(e.errorString()).arg(e.error)); @@ -745,6 +767,42 @@ std::vector<Loot::Plugin> Loot::reportPlugins(const QJsonArray& plugins) const return v; } +const QString Loot::getSortedPluginListMarkdown() const +{ + if (!m_result) { + return {}; + } + + log::debug("parsing sorted plugin list at '{}'", SortedPluginListPath); + + QFile pluginListFile(SortedPluginListPath); + if (!pluginListFile.open(QIODevice::ReadOnly)) { + emit log(MOBase::log::Error, QString("failed to open file, %1 (error %2)") + .arg(pluginListFile.errorString()) + .arg(pluginListFile.error())); + return {}; + } + + // skip "# This file was automatically generated by Mod Organizer" + pluginListFile.readLine(); + + QString markdown = "### " + tr("Sorted plugins") + "\n<details><summary>" + + tr("Show") + "</summary>\n\n"; + + const auto pluginList = m_core.pluginList(); + while (!pluginListFile.atEnd()) { + const QString pluginName = QString::fromUtf8(pluginListFile.readLine().trimmed()); + const bool active = pluginList->isEnabled(pluginName); + const QString prefix = active ? " - [x] " : " - [ ] "; + markdown += prefix + pluginName + "\n"; + } + + markdown += "</details>\n"; + + pluginListFile.close(); + return markdown; +} + Loot::Plugin Loot::reportPlugin(const QJsonObject& plugin) const { Plugin p; @@ -91,8 +91,10 @@ public: void cancel(); bool result() const; - const QString& outPath() const; + const QString& reportPath() const; + const QString& sortedPluginListPath() const; const Report& report() const; + const QString getSortedPluginListMarkdown() const; const std::vector<QString>& errors() const; const std::vector<QString>& warnings() const; @@ -123,9 +125,11 @@ private: void processMessage(const lootcli::Message& m); Report createReport() const; - void processOutputFile(Report& r) const; + void processReport(Report& r) const; void deleteReportFile(); + void deleteSortedLoadOrder(); + Message reportMessage(const QJsonObject& message) const; std::vector<Plugin> reportPlugins(const QJsonArray& plugins) const; Loot::Plugin reportPlugin(const QJsonObject& plugin) const; diff --git a/src/lootdialog.cpp b/src/lootdialog.cpp index 6e31b8a6..e1e88843 100644 --- a/src/lootdialog.cpp +++ b/src/lootdialog.cpp @@ -146,9 +146,15 @@ void LootDialog::cancel() } } +void LootDialog::openSortedPluginList() +{ + const auto& path = m_loot.sortedPluginListPath(); + shell::Open(path); +} + void LootDialog::openReport() { - const auto path = m_loot.outPath(); + const auto& path = m_loot.reportPath(); shell::Open(path); } @@ -209,7 +215,11 @@ void LootDialog::createUI() } m_expander.set(ui->details, ui->detailsPanel); + ui->openPluginList->setEnabled(false); ui->openJsonReport->setEnabled(false); + connect(ui->openPluginList, &QPushButton::clicked, [&] { + openSortedPluginList(); + }); connect(ui->openJsonReport, &QPushButton::clicked, [&] { openReport(); }); @@ -253,8 +263,9 @@ void LootDialog::onFinished() showReport(); + ui->openPluginList->setEnabled(true); ui->openJsonReport->setEnabled(true); - ui->buttons->setStandardButtons(QDialogButtonBox::Close); + ui->buttons->setStandardButtons(QDialogButtonBox::Apply | QDialogButtonBox::Cancel); // if loot failed, the Done progress won't be received; this makes sure // the progress bar is stopped @@ -284,5 +295,44 @@ void LootDialog::showReport() } } - m_report.setText(lootReport.toMarkdown()); + const auto markdown = + m_loot.getSortedPluginListMarkdown() + "\n" + lootReport.toMarkdown(); + + m_report.setText(markdown); +} + +void LootDialog::applySortedLoadOrder() +{ + const auto& sortedPluginListPath = m_loot.sortedPluginListPath(); + if (!QFile::exists(sortedPluginListPath)) { + log::error("sorted plugin list '{}' does not exist, cannot apply sorted load order", + sortedPluginListPath); + return; + } + + const auto& pluginListPath = m_core.profilePath() + "/loadorder.txt"; + log::debug("moving sorted load order from '{}' to '{}'", sortedPluginListPath, + pluginListPath); + + const auto r = shellMove(sortedPluginListPath, pluginListPath, true, this); + if (!r) { + const auto e = GetLastError(); + log::error("failed to move sorted plugin list from '{}' to '{}': {}", + sortedPluginListPath, pluginListPath, formatSystemMessage(e)); + } +} + +void LootDialog::on_buttons_clicked(QAbstractButton* b) +{ + const auto role = ui->buttons->buttonRole(b); + switch (role) { + case QDialogButtonBox::ApplyRole: + ui->buttons->setEnabled(false); + applySortedLoadOrder(); + close(); + break; + case QDialogButtonBox::RejectRole: + reject(); + break; + } } diff --git a/src/lootdialog.h b/src/lootdialog.h index f632b9c1..b107e5be 100644 --- a/src/lootdialog.h +++ b/src/lootdialog.h @@ -54,6 +54,7 @@ public: void addOutput(const QString& s); bool result() const; void cancel(); + void openSortedPluginList(); void openReport(); int exec() override; @@ -75,6 +76,10 @@ private: void onFinished(); void log(MOBase::log::Levels lv, const QString& s); void showReport(); + void applySortedLoadOrder(); + +private slots: + void on_buttons_clicked(QAbstractButton* b); }; #endif // MODORGANIZER_LOOTDIALOG_H diff --git a/src/lootdialog.ui b/src/lootdialog.ui index e366ce41..2f5f11c3 100644 --- a/src/lootdialog.ui +++ b/src/lootdialog.ui @@ -1,241 +1,248 @@ <?xml version="1.0" encoding="UTF-8"?> <ui version="4.0"> - <class>LootDialog</class> - <widget class="QDialog" name="LootDialog"> - <property name="geometry"> - <rect> - <x>0</x> - <y>0</y> - <width>457</width> - <height>600</height> - </rect> - </property> - <property name="windowTitle"> - <string>LOOT</string> - </property> - <layout class="QVBoxLayout" name="verticalLayout"> - <item> - <widget class="QWidget" name="widget" native="true"> - <layout class="QVBoxLayout" name="verticalLayout_5" stretch="1,0"> - <property name="leftMargin"> - <number>0</number> - </property> - <property name="topMargin"> - <number>0</number> - </property> - <property name="rightMargin"> - <number>0</number> - </property> - <property name="bottomMargin"> - <number>0</number> - </property> + <class>LootDialog</class> + <widget class="QDialog" name="LootDialog"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>457</width> + <height>600</height> + </rect> + </property> + <property name="windowTitle"> + <string>LOOT</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout"> <item> - <widget class="QWidget" name="widget_2" native="true"> - <layout class="QVBoxLayout" name="verticalLayout_2" stretch="0,0,1"> - <property name="leftMargin"> - <number>0</number> - </property> - <property name="topMargin"> - <number>0</number> - </property> - <property name="rightMargin"> - <number>0</number> - </property> - <property name="bottomMargin"> - <number>0</number> - </property> - <item> - <widget class="QLabel" name="progressText"> - <property name="text"> - <string>Progress</string> - </property> - </widget> - </item> - <item> - <widget class="QProgressBar" name="progressBar"> - <property name="value"> - <number>24</number> - </property> - <property name="textVisible"> - <bool>false</bool> - </property> - </widget> - </item> - <item> - <widget class="QFrame" name="frame"> - <property name="frameShape"> - <enum>QFrame::StyledPanel</enum> - </property> - <property name="frameShadow"> - <enum>QFrame::Sunken</enum> - </property> - <layout class="QVBoxLayout" name="verticalLayout_6"> + <widget class="QWidget" name="widget" native="true"> + <layout class="QVBoxLayout" name="verticalLayout_5" stretch="1,0"> <property name="leftMargin"> - <number>0</number> + <number>0</number> </property> <property name="topMargin"> - <number>0</number> + <number>0</number> </property> <property name="rightMargin"> - <number>0</number> + <number>0</number> </property> <property name="bottomMargin"> - <number>0</number> + <number>0</number> </property> <item> - <widget class="QWebEngineView" name="report"> - <property name="url"> - <url> - <string>about:blank</string> - </url> - </property> - </widget> + <widget class="QWidget" name="widget_2" native="true"> + <layout class="QVBoxLayout" name="verticalLayout_2" stretch="0,0,1"> + <property name="leftMargin"> + <number>0</number> + </property> + <property name="topMargin"> + <number>0</number> + </property> + <property name="rightMargin"> + <number>0</number> + </property> + <property name="bottomMargin"> + <number>0</number> + </property> + <item> + <widget class="QLabel" name="progressText"> + <property name="text"> + <string>Progress</string> + </property> + </widget> + </item> + <item> + <widget class="QProgressBar" name="progressBar"> + <property name="value"> + <number>24</number> + </property> + <property name="textVisible"> + <bool>false</bool> + </property> + </widget> + </item> + <item> + <widget class="QFrame" name="frame"> + <property name="frameShape"> + <enum>QFrame::StyledPanel</enum> + </property> + <property name="frameShadow"> + <enum>QFrame::Sunken</enum> + </property> + <layout class="QVBoxLayout" name="verticalLayout_6"> + <property name="leftMargin"> + <number>0</number> + </property> + <property name="topMargin"> + <number>0</number> + </property> + <property name="rightMargin"> + <number>0</number> + </property> + <property name="bottomMargin"> + <number>0</number> + </property> + <item> + <widget class="QWebEngineView" name="report"> + <property name="url"> + <url> + <string>about:blank</string> + </url> + </property> + </widget> + </item> + </layout> + </widget> + </item> + </layout> + </widget> </item> - </layout> - </widget> - </item> - </layout> - </widget> - </item> - <item> - <widget class="QWidget" name="widget_3" native="true"> - <layout class="QVBoxLayout" name="verticalLayout_4"> - <property name="leftMargin"> - <number>0</number> - </property> - <property name="topMargin"> - <number>0</number> - </property> - <property name="rightMargin"> - <number>0</number> - </property> - <property name="bottomMargin"> - <number>0</number> - </property> - <item> - <widget class="QToolButton" name="details"> - <property name="text"> - <string>Details</string> - </property> - </widget> - </item> - <item> - <widget class="QWidget" name="detailsPanel" native="true"> - <layout class="QVBoxLayout" name="verticalLayout_3"> - <property name="leftMargin"> - <number>0</number> - </property> - <property name="topMargin"> - <number>0</number> - </property> - <property name="rightMargin"> - <number>0</number> - </property> - <property name="bottomMargin"> - <number>0</number> - </property> <item> - <widget class="QWidget" name="widget_5" native="true"> - <layout class="QHBoxLayout" name="horizontalLayout"> - <property name="leftMargin"> - <number>0</number> - </property> - <property name="topMargin"> - <number>0</number> - </property> - <property name="rightMargin"> - <number>0</number> - </property> - <property name="bottomMargin"> - <number>0</number> - </property> - <item> - <widget class="QPushButton" name="openJsonReport"> - <property name="text"> - <string>Open JSON report</string> - </property> - </widget> - </item> - <item> - <spacer name="horizontalSpacer"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>40</width> - <height>20</height> - </size> - </property> - </spacer> - </item> - </layout> - </widget> + <widget class="QWidget" name="widget_3" native="true"> + <layout class="QVBoxLayout" name="verticalLayout_4"> + <property name="leftMargin"> + <number>0</number> + </property> + <property name="topMargin"> + <number>0</number> + </property> + <property name="rightMargin"> + <number>0</number> + </property> + <property name="bottomMargin"> + <number>0</number> + </property> + <item> + <widget class="QToolButton" name="details"> + <property name="text"> + <string>Details</string> + </property> + </widget> + </item> + <item> + <widget class="QWidget" name="detailsPanel" native="true"> + <layout class="QVBoxLayout" name="verticalLayout_3"> + <property name="leftMargin"> + <number>0</number> + </property> + <property name="topMargin"> + <number>0</number> + </property> + <property name="rightMargin"> + <number>0</number> + </property> + <property name="bottomMargin"> + <number>0</number> + </property> + <item> + <widget class="QWidget" name="widget_5" native="true"> + <layout class="QHBoxLayout" name="horizontalLayout"> + <property name="leftMargin"> + <number>0</number> + </property> + <property name="topMargin"> + <number>0</number> + </property> + <property name="rightMargin"> + <number>0</number> + </property> + <property name="bottomMargin"> + <number>0</number> + </property> + <item> + <widget class="QPushButton" name="openPluginList"> + <property name="text"> + <string>Open sorted plugin list</string> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="openJsonReport"> + <property name="text"> + <string>Open JSON report</string> + </property> + </widget> + </item> + <item> + <spacer name="horizontalSpacer"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + </layout> + </widget> + </item> + <item> + <widget class="QPlainTextEdit" name="output"/> + </item> + </layout> + </widget> + </item> + </layout> + </widget> </item> - <item> - <widget class="QPlainTextEdit" name="output"/> - </item> - </layout> - </widget> - </item> - </layout> - </widget> + </layout> + </widget> + </item> + <item> + <widget class="QDialogButtonBox" name="buttons"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="standardButtons"> + <set>QDialogButtonBox::Close</set> + </property> + </widget> </item> - </layout> - </widget> - </item> - <item> - <widget class="QDialogButtonBox" name="buttons"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="standardButtons"> - <set>QDialogButtonBox::Close</set> - </property> - </widget> - </item> - </layout> - </widget> - <customwidgets> - <customwidget> - <class>QWebEngineView</class> - <extends>QWidget</extends> - <header location="global">QtWebEngineWidgets/QWebEngineView</header> - </customwidget> - </customwidgets> - <resources/> - <connections> - <connection> - <sender>buttons</sender> - <signal>accepted()</signal> - <receiver>LootDialog</receiver> - <slot>accept()</slot> - <hints> - <hint type="sourcelabel"> - <x>248</x> - <y>254</y> - </hint> - <hint type="destinationlabel"> - <x>157</x> - <y>274</y> - </hint> - </hints> - </connection> - <connection> - <sender>buttons</sender> - <signal>rejected()</signal> - <receiver>LootDialog</receiver> - <slot>reject()</slot> - <hints> - <hint type="sourcelabel"> - <x>316</x> - <y>260</y> - </hint> - <hint type="destinationlabel"> - <x>286</x> - <y>274</y> - </hint> - </hints> - </connection> - </connections> + </layout> + </widget> + <customwidgets> + <customwidget> + <class>QWebEngineView</class> + <extends>QWidget</extends> + <header location="global">QtWebEngineWidgets/QWebEngineView</header> + </customwidget> + </customwidgets> + <resources/> + <connections> + <connection> + <sender>buttons</sender> + <signal>accepted()</signal> + <receiver>LootDialog</receiver> + <slot>accept()</slot> + <hints> + <hint type="sourcelabel"> + <x>248</x> + <y>254</y> + </hint> + <hint type="destinationlabel"> + <x>157</x> + <y>274</y> + </hint> + </hints> + </connection> + <connection> + <sender>buttons</sender> + <signal>rejected()</signal> + <receiver>LootDialog</receiver> + <slot>reject()</slot> + <hints> + <hint type="sourcelabel"> + <x>316</x> + <y>260</y> + </hint> + <hint type="destinationlabel"> + <x>286</x> + <y>274</y> + </hint> + </hints> + </connection> + </connections> </ui> diff --git a/src/pluginlistview.cpp b/src/pluginlistview.cpp index f8990a94..c7dc1507 100644 --- a/src/pluginlistview.cpp +++ b/src/pluginlistview.cpp @@ -181,23 +181,16 @@ void PluginListView::onSortButtonClicked() { const bool offline = m_core->settings().network().offlineMode(); - auto r = QMessageBox::No; - if (offline) { - r = QMessageBox::question(topLevelWidget(), tr("Sorting plugins"), - tr("Are you sure you want to sort your plugins list?") + - "\r\n\r\n" + - tr("Note: You are currently in offline mode and LOOT " - "will not update the master list."), - QMessageBox::Yes | QMessageBox::No); - } else { - r = QMessageBox::question(topLevelWidget(), tr("Sorting plugins"), - tr("Are you sure you want to sort your plugins list?"), - QMessageBox::Yes | QMessageBox::No); - } - - if (r != QMessageBox::Yes) { - return; + const auto r = QMessageBox::question( + topLevelWidget(), tr("Sorting plugins"), + tr("Are you sure you want to sort your plugins list?") + "\r\n\r\n" + + tr("Note: You are currently in offline mode and LOOT " + "will not update the master list."), + QMessageBox::Yes | QMessageBox::No); + if (r != QMessageBox::Yes) { + return; + } } m_core->savePluginList(); |
