summaryrefslogtreecommitdiff
path: root/src/mainwindow.cpp
diff options
context:
space:
mode:
authorBrian Munro <brian.alexander.munro@gmail.com>2018-03-05 11:35:58 +0200
committerGitHub <noreply@github.com>2018-03-05 11:35:58 +0200
commitc7e1d9738f06c6c6e7c9b41cdd8d35062d7c06b6 (patch)
treec9c92380fcc82a64df8956face14e22bc3d2b4f7 /src/mainwindow.cpp
parent7dfe0c9a8feae35ba7554493eea4fdb4e33a64d3 (diff)
parenta540a542a47fe75d0d0e4594158422aef4340b3a (diff)
Merge pull request #252 from LePresidente/new_vfs_library
Update master to latest stable code.
Diffstat (limited to 'src/mainwindow.cpp')
-rw-r--r--src/mainwindow.cpp1011
1 files changed, 629 insertions, 382 deletions
diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp
index 72ee8d6a..fe93b546 100644
--- a/src/mainwindow.cpp
+++ b/src/mainwindow.cpp
@@ -38,6 +38,7 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
#include "savegameinfo.h"
#include "spawn.h"
#include "versioninfo.h"
+#include "instancemanager.h"
#include "report.h"
#include "modlist.h"
@@ -58,6 +59,7 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
#include "messagedialog.h"
#include "installationmanager.h"
#include "lockeddialog.h"
+#include "waitingonclosedialog.h"
#include "logbuffer.h"
#include "downloadlistsortproxy.h"
#include "motddialog.h"
@@ -72,14 +74,16 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
#include "previewdialog.h"
#include "browserdialog.h"
#include "aboutdialog.h"
-#include "safewritefile.h"
+#include <safewritefile.h>
#include "nxmaccessmanager.h"
#include "appconfig.h"
+#include "eventfilter.h"
#include <utility.h>
#include <dataarchives.h>
#include <bsainvalidation.h>
#include <taskprogressmanager.h>
#include <scopeguard.h>
+#include <usvfs.h>
#include <QAbstractItemDelegate>
#include <QAbstractProxyModel>
@@ -123,6 +127,7 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
#include <QPoint>
#include <QProcess>
#include <QProgressDialog>
+#include <QDialogButtonBox>
#include <QPushButton>
#include <QRadioButton>
#include <QRect>
@@ -138,20 +143,17 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
#include <QToolTip>
#include <QTranslator>
#include <QTreeWidget>
+#include <QTreeWidgetItemIterator>
#include <QUrl>
#include <QVariantList>
#include <QWhatsThis>
#include <QWidgetAction>
+#include <QWebEngineProfile>
-#include <QtDebug>
+#include <QDebug>
#include <QtGlobal>
-
-#if QT_VERSION >= QT_VERSION_CHECK(5,0,0)
#include <QtConcurrent/QtConcurrentRun>
-#else
-#include <QtConcurrentRun>
-#endif
#ifndef Q_MOC_RUN
#include <boost/thread.hpp>
@@ -181,8 +183,7 @@ using namespace MOBase;
using namespace MOShared;
-MainWindow::MainWindow(const QString &exeName
- , QSettings &initSettings
+MainWindow::MainWindow(QSettings &initSettings
, OrganizerCore &organizerCore
, PluginContainer &pluginContainer
, QWidget *parent)
@@ -190,7 +191,6 @@ MainWindow::MainWindow(const QString &exeName
, ui(new Ui::MainWindow)
, m_WasVisible(false)
, m_Tutorial(this, "MainWindow")
- , m_ExeName(exeName)
, m_OldProfileIndex(-1)
, m_ModListGroupingProxy(nullptr)
, m_ModListSortProxy(nullptr)
@@ -204,10 +204,17 @@ MainWindow::MainWindow(const QString &exeName
, m_DidUpdateMasterList(false)
, m_ArchiveListWriter(std::bind(&MainWindow::saveArchiveList, this))
{
+ QWebEngineProfile::defaultProfile()->setPersistentCookiesPolicy(QWebEngineProfile::NoPersistentCookies);
+ QWebEngineProfile::defaultProfile()->setHttpCacheMaximumSize(52428800);
+ QWebEngineProfile::defaultProfile()->setCachePath(m_OrganizerCore.settings().getCacheDirectory());
+ QWebEngineProfile::defaultProfile()->setPersistentStoragePath(m_OrganizerCore.settings().getCacheDirectory());
ui->setupUi(this);
updateWindowTitle(QString(), false);
+
languageChange(m_OrganizerCore.settings().language());
+ m_CategoryFactory.loadCategories();
+
ui->logList->setModel(LogBuffer::instance());
ui->logList->setColumnWidth(0, 100);
ui->logList->setAutoScroll(true);
@@ -227,6 +234,7 @@ MainWindow::MainWindow(const QString &exeName
m_RefreshProgress->setVisible(false);
statusBar()->addWidget(m_RefreshProgress, 1000);
statusBar()->clearMessage();
+ statusBar()->hide();
ui->actionEndorseMO->setVisible(false);
@@ -247,12 +255,14 @@ MainWindow::MainWindow(const QString &exeName
ui->modList->setItemDelegateForColumn(ModList::COL_FLAGS, new ModFlagIconDelegate(ui->modList));
ui->modList->setItemDelegateForColumn(ModList::COL_CONTENT, contentDelegate);
ui->modList->header()->installEventFilter(m_OrganizerCore.modList());
- if (initSettings.contains("mod_list_state")) {
- ui->modList->header()->restoreState(initSettings.value("mod_list_state").toByteArray());
+ bool modListAdjusted = registerWidgetState(ui->modList->objectName(), ui->modList->header(), "mod_list_state");
+
+ if (modListAdjusted) {
// hack: force the resize-signal to be triggered because restoreState doesn't seem to do that
- ui->modList->header()->resizeSection(ModList::COL_CONTENT, ui->modList->header()->sectionSize(ModList::COL_CONTENT) + 1);
- ui->modList->header()->resizeSection(ModList::COL_CONTENT, ui->modList->header()->sectionSize(ModList::COL_CONTENT) - 1);
+ int sectionSize = ui->modList->header()->sectionSize(ModList::COL_CONTENT);
+ ui->modList->header()->resizeSection(ModList::COL_CONTENT, sectionSize + 1);
+ ui->modList->header()->resizeSection(ModList::COL_CONTENT, sectionSize);
} else {
// hide these columns by default
ui->modList->header()->setSectionHidden(ModList::COL_CONTENT, true);
@@ -269,17 +279,19 @@ MainWindow::MainWindow(const QString &exeName
ui->espList->setModel(m_PluginListSortProxy);
ui->espList->sortByColumn(PluginList::COL_PRIORITY, Qt::AscendingOrder);
ui->espList->setItemDelegateForColumn(PluginList::COL_FLAGS, new GenericIconDelegate(ui->espList));
- if (initSettings.contains("plugin_list_state")) {
- ui->espList->header()->restoreState(initSettings.value("plugin_list_state").toByteArray());
- }
ui->espList->installEventFilter(m_OrganizerCore.pluginList());
ui->bsaList->setLocalMoveOnly(true);
+ bool pluginListAdjusted = registerWidgetState(ui->espList->objectName(), ui->espList->header(), "plugin_list_state");
+ registerWidgetState(ui->dataTree->objectName(), ui->dataTree->header());
+ registerWidgetState(ui->downloadView->objectName(),
+ ui->downloadView->header());
+
ui->splitter->setStretchFactor(0, 3);
ui->splitter->setStretchFactor(1, 2);
- resizeLists(initSettings.contains("mod_list_state"), initSettings.contains("plugin_list_state"));
+ resizeLists(modListAdjusted, pluginListAdjusted);
QMenu *linkMenu = new QMenu(this);
linkMenu->addAction(QIcon(":/MO/gui/link"), tr("Toolbar"), this, SLOT(linkToolbar()));
@@ -289,11 +301,23 @@ MainWindow::MainWindow(const QString &exeName
ui->listOptionsBtn->setMenu(modListContextMenu());
+ ui->openFolderMenu->setMenu(openFolderMenu());
+
updateDownloadListDelegate();
ui->savegameList->installEventFilter(this);
ui->savegameList->setMouseTracking(true);
+ // don't allow mouse wheel to switch grouping, too many people accidentally
+ // turn on grouping and then don't understand what happened
+ EventFilter *noWheel
+ = new EventFilter(this, [](QObject *, QEvent *event) -> bool {
+ return event->type() == QEvent::Wheel;
+ });
+
+ ui->groupCombo->installEventFilter(noWheel);
+ ui->profileBox->installEventFilter(noWheel);
+
connect(ui->savegameList, SIGNAL(itemEntered(QListWidgetItem*)), this, SLOT(saveSelectionChanged(QListWidgetItem*)));
connect(ui->modList, SIGNAL(dropModeUpdate(bool)), m_OrganizerCore.modList(), SLOT(dropModeUpdate(bool)));
@@ -305,16 +329,12 @@ MainWindow::MainWindow(const QString &exeName
connect(ui->espFilterEdit, SIGNAL(textChanged(QString)), m_PluginListSortProxy, SLOT(updateFilter(QString)));
connect(ui->espFilterEdit, SIGNAL(textChanged(QString)), this, SLOT(espFilterChanged(QString)));
- connect(ui->bsaList, SIGNAL(itemsMoved()), this, SLOT(bsaList_itemMoved()));
-
connect(ui->dataTree, SIGNAL(itemExpanded(QTreeWidgetItem*)), this, SLOT(expandDataTreeItem(QTreeWidgetItem*)));
connect(m_OrganizerCore.directoryRefresher(), SIGNAL(refreshed()), this, SLOT(directory_refreshed()));
connect(m_OrganizerCore.directoryRefresher(), SIGNAL(progress(int)), this, SLOT(refresher_progress(int)));
connect(m_OrganizerCore.directoryRefresher(), SIGNAL(error(QString)), this, SLOT(showError(QString)));
- connect(m_OrganizerCore.downloadManager(), SIGNAL(downloadAdded()), ui->downloadView, SLOT(scrollToBottom()));
-
connect(&m_SavesWatcher, SIGNAL(directoryChanged(QString)), this, SLOT(refreshSavesIfOpen()));
connect(&m_OrganizerCore.settings(), SIGNAL(languageChanged(QString)), this, SLOT(languageChange(QString)));
@@ -328,11 +348,8 @@ MainWindow::MainWindow(const QString &exeName
connect(NexusInterface::instance(), SIGNAL(nxmDownloadURLsAvailable(int,int,QVariant,QVariant,int)), this, SLOT(nxmDownloadURLs(int,int,QVariant,QVariant,int)));
connect(NexusInterface::instance(), SIGNAL(needLogin()), &m_OrganizerCore, SLOT(nexusLogin()));
connect(NexusInterface::instance()->getAccessManager(), SIGNAL(loginFailed(QString)), this, SLOT(loginFailed(QString)));
- connect(NexusInterface::instance()->getAccessManager(), &NXMAccessManager::credentialsReceived,
- [this] (const QString &accountName, bool premium) {
- qDebug("user %s premium", premium ? "is" : "is not");
- updateWindowTitle(accountName, premium);
- });
+ connect(NexusInterface::instance()->getAccessManager(), SIGNAL(credentialsReceived(const QString&, bool)),
+ this, SLOT(updateWindowTitle(const QString&, bool)));
connect(&TutorialManager::instance(), SIGNAL(windowTutorialFinished(QString)), this, SLOT(windowTutorialFinished(QString)));
connect(ui->tabWidget, SIGNAL(currentChanged(int)), &TutorialManager::instance(), SIGNAL(tabChanged(int)));
@@ -340,6 +357,7 @@ MainWindow::MainWindow(const QString &exeName
connect(ui->toolBar, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(toolBar_customContextMenuRequested(QPoint)));
connect(&m_OrganizerCore, &OrganizerCore::modInstalled, this, &MainWindow::modInstalled);
+ connect(&m_OrganizerCore, &OrganizerCore::close, this, &QMainWindow::close);
connect(&m_IntegratedBrowser, SIGNAL(requestDownload(QUrl,QNetworkReply*)), &m_OrganizerCore, SLOT(requestDownload(QUrl,QNetworkReply*)));
@@ -348,6 +366,9 @@ MainWindow::MainWindow(const QString &exeName
m_CheckBSATimer.setSingleShot(true);
connect(&m_CheckBSATimer, SIGNAL(timeout()), this, SLOT(checkBSAList()));
+ connect(ui->espList->selectionModel(), SIGNAL(selectionChanged(QItemSelection, QItemSelection)), this, SLOT(esplistSelectionsChanged(QItemSelection)));
+ connect(ui->modList->selectionModel(), SIGNAL(selectionChanged(QItemSelection, QItemSelection)), this, SLOT(modlistSelectionsChanged(QItemSelection)));
+
m_UpdateProblemsTimer.setSingleShot(true);
connect(&m_UpdateProblemsTimer, SIGNAL(timeout()), this, SLOT(updateProblemsButton()));
@@ -389,6 +410,8 @@ MainWindow::MainWindow(const QString &exeName
MainWindow::~MainWindow()
{
+ cleanup();
+
m_PluginContainer.setUserInterface(nullptr, nullptr);
m_OrganizerCore.setUserInterface(nullptr, nullptr);
m_IntegratedBrowser.close();
@@ -402,9 +425,7 @@ void MainWindow::updateWindowTitle(const QString &accountName, bool premium)
m_OrganizerCore.managedGame()->gameName(),
m_OrganizerCore.getVersion().displayString());
- if (accountName.isEmpty()) {
- title.append(" (not logged in)");
- } else {
+ if (!accountName.isEmpty()) {
title.append(QString(" (%1%2)").arg(accountName, premium ? "*" : ""));
}
@@ -575,7 +596,7 @@ void MainWindow::scheduleUpdateButton()
void MainWindow::updateProblemsButton()
{
- int numProblems = checkForProblems();
+ size_t numProblems = checkForProblems();
if (numProblems > 0) {
ui->actionProblems->setEnabled(true);
ui->actionProblems->setIconText(tr("Problems"));
@@ -627,9 +648,9 @@ bool MainWindow::errorReported(QString &logFile)
}
-int MainWindow::checkForProblems()
+size_t MainWindow::checkForProblems()
{
- int numProblems = 0;
+ size_t numProblems = 0;
for (IPluginDiagnose *diagnose : m_PluginContainer.plugins<IPluginDiagnose>()) {
numProblems += diagnose->activeProblems().size();
}
@@ -836,12 +857,15 @@ void MainWindow::showEvent(QShowEvent *event)
m_OrganizerCore.settings().registerAsNXMHandler(false);
m_WasVisible = true;
+ updateProblemsButton();
}
}
void MainWindow::closeEvent(QCloseEvent* event)
{
+ m_closing = true;
+
if (m_OrganizerCore.downloadManager()->downloadsInProgress()) {
if (QMessageBox::question(this, tr("Downloads in progress"),
tr("There are still downloads in progress, do you really want to quit?"),
@@ -853,8 +877,29 @@ void MainWindow::closeEvent(QCloseEvent* event)
}
}
+ std::vector<QString> hiddenList;
+ hiddenList.push_back(QFileInfo(QCoreApplication::applicationFilePath()).fileName());
+ HANDLE injected_process_still_running = m_OrganizerCore.findAndOpenAUSVFSProcess(hiddenList, GetCurrentProcessId());
+ if (injected_process_still_running != INVALID_HANDLE_VALUE)
+ {
+ m_OrganizerCore.waitForApplication(injected_process_still_running);
+ if (!m_closing) { // if operation cancelled
+ event->ignore();
+ return;
+ }
+ }
+
setCursor(Qt::WaitCursor);
+}
+void MainWindow::cleanup()
+{
+ if (ui->logList->model() != nullptr) {
+ disconnect(ui->logList->model(), nullptr, nullptr, nullptr);
+ ui->logList->setModel(nullptr);
+ }
+
+ QWebEngineProfile::defaultProfile()->clearAllVisitedLinks();
m_IntegratedBrowser.close();
}
@@ -1000,14 +1045,15 @@ void MainWindow::startExeAction()
{
QAction *action = qobject_cast<QAction*>(sender());
if (action != nullptr) {
- const Executable &selectedExecutable(m_OrganizerCore.executablesList()->find(action->text()));
+ const Executable &selectedExecutable(
+ m_OrganizerCore.executablesList()->find(action->text()));
+ QString customOverwrite= m_OrganizerCore.currentProfile()->setting("custom_overwrites", selectedExecutable.m_Title).toString();
m_OrganizerCore.spawnBinary(
- selectedExecutable.m_BinaryInfo,
- selectedExecutable.m_Arguments,
- selectedExecutable.m_WorkingDirectory.length() != 0 ? selectedExecutable.m_WorkingDirectory
- : selectedExecutable.m_BinaryInfo.absolutePath(),
- selectedExecutable.m_CloseMO == ExecutableInfo::CloseMOStyle::DEFAULT_CLOSE,
- selectedExecutable.m_SteamAppID);
+ selectedExecutable.m_BinaryInfo, selectedExecutable.m_Arguments,
+ selectedExecutable.m_WorkingDirectory.length() != 0
+ ? selectedExecutable.m_WorkingDirectory
+ : selectedExecutable.m_BinaryInfo.absolutePath(),
+ selectedExecutable.m_SteamAppID, customOverwrite);
} else {
qCritical("not an action?");
}
@@ -1068,9 +1114,7 @@ void MainWindow::on_profileBox_currentIndexChanged(int index)
void MainWindow::updateTo(QTreeWidgetItem *subTree, const std::wstring &directorySoFar, const DirectoryEntry &directoryEntry, bool conflictsOnly)
{
{
- std::vector<FileEntry::Ptr> files = directoryEntry.getFiles();
- for (auto iter = files.begin(); iter != files.end(); ++iter) {
- FileEntry::Ptr current = *iter;
+ for (const FileEntry::Ptr current : directoryEntry.getFiles()) {
if (conflictsOnly && (current->getAlternatives().size() == 0)) {
continue;
}
@@ -1109,17 +1153,17 @@ void MainWindow::updateTo(QTreeWidgetItem *subTree, const std::wstring &director
fileChild->setData(1, Qt::UserRole, source);
fileChild->setData(1, Qt::UserRole + 1, originID);
- std::vector<int> alternatives = current->getAlternatives();
+ std::vector<std::pair<int, std::wstring>> alternatives = current->getAlternatives();
if (!alternatives.empty()) {
std::wostringstream altString;
altString << ToWString(tr("Also in: <br>"));
- for (std::vector<int>::iterator altIter = alternatives.begin();
+ for (std::vector<std::pair<int, std::wstring>>::iterator altIter = alternatives.begin();
altIter != alternatives.end(); ++altIter) {
if (altIter != alternatives.begin()) {
altString << " , ";
}
- altString << "<span style=\"white-space: nowrap;\"><i>" << m_OrganizerCore.directoryStructure()->getOriginByID(*altIter).getName() << "</font></span>";
+ altString << "<span style=\"white-space: nowrap;\"><i>" << m_OrganizerCore.directoryStructure()->getOriginByID(altIter->first).getName() << "</font></span>";
}
fileChild->setToolTip(1, QString("%1").arg(ToQString(altString.str())));
fileChild->setForeground(1, QBrush(Qt::red));
@@ -1165,7 +1209,7 @@ void MainWindow::updateTo(QTreeWidgetItem *subTree, const std::wstring &director
void MainWindow::delayedRemove()
{
- foreach (QTreeWidgetItem *item, m_RemoveWidget) {
+ for (QTreeWidgetItem *item : m_RemoveWidget) {
item->removeChild(item->child(0));
}
m_RemoveWidget.clear();
@@ -1202,7 +1246,7 @@ bool MainWindow::refreshProfiles(bool selectProfile)
profileBox->clear();
profileBox->addItem(QObject::tr("<Manage...>"));
- QDir profilesDir(qApp->property("dataPath").toString() + "/" + QString::fromStdWString(AppConfig::profilesPath()));
+ QDir profilesDir(Settings::instance().getProfileDirectory());
profilesDir.setFilter(QDir::AllDirs | QDir::NoDotAndDotDot);
QDirIterator profileIter(profilesDir);
@@ -1264,7 +1308,38 @@ void MainWindow::refreshDataTree()
updateTo(subTree, L"", *m_OrganizerCore.directoryStructure(), conflictsBox->isChecked());
tree->insertTopLevelItem(0, subTree);
subTree->setExpanded(true);
- tree->header()->resizeSection(0, 200);
+}
+
+void MainWindow::refreshDataTreeKeepExpandedNodes()
+{
+ QCheckBox *conflictsBox = findChild<QCheckBox*>("conflictsCheckBox");
+ QTreeWidget *tree = findChild<QTreeWidget*>("dataTree");
+
+ QStringList expandedNodes;
+ QTreeWidgetItemIterator it1(tree, QTreeWidgetItemIterator::NotHidden | QTreeWidgetItemIterator::HasChildren);
+ while (*it1) {
+ QTreeWidgetItem *current = (*it1);
+ if (current->isExpanded() && !(current->text(0)=="data")) {
+ expandedNodes.append(current->text(0)+"/"+current->parent()->text(0));
+ }
+ ++it1;
+ }
+
+ tree->clear();
+ QStringList columns("data");
+ columns.append("");
+ QTreeWidgetItem *subTree = new QTreeWidgetItem(columns);
+ updateTo(subTree, L"", *m_OrganizerCore.directoryStructure(), conflictsBox->isChecked());
+ tree->insertTopLevelItem(0, subTree);
+ subTree->setExpanded(true);
+ QTreeWidgetItemIterator it2(tree, QTreeWidgetItemIterator::HasChildren);
+ while (*it2) {
+ QTreeWidgetItem *current = (*it2);
+ if (!(current->text(0)=="data") && expandedNodes.contains(current->text(0)+"/"+current->parent()->text(0))) {
+ current->setExpanded(true);
+ }
+ ++it2;
+ }
}
@@ -1320,9 +1395,10 @@ void MainWindow::refreshSaveList()
QDir savesDir = currentSavesDir();
savesDir.setNameFilters(filters);
+ qDebug("reading save games from %s", qPrintable(savesDir.absolutePath()));
QFileInfoList files = savesDir.entryInfoList(QDir::Files, QDir::Time);
- foreach (const QFileInfo &file, files) {
+ for (const QFileInfo &file : files) {
QListWidgetItem *item = new QListWidgetItem(file.fileName());
item->setData(Qt::UserRole, file.absoluteFilePath());
ui->savegameList->addItem(item);
@@ -1349,27 +1425,23 @@ void MainWindow::updateBSAList(const QStringList &defaultArchives, const QString
{
m_DefaultArchives = defaultArchives;
ui->bsaList->clear();
-#if QT_VERSION >= QT_VERSION_CHECK(5,0,0)
ui->bsaList->header()->setSectionResizeMode(QHeaderView::ResizeToContents);
-#else
- ui->bsaList->header()->setResizeMode(QHeaderView::ResizeToContents);
-#endif
-
std::vector<std::pair<UINT32, QTreeWidgetItem*>> items;
- BSAInvalidation *invalidation = m_OrganizerCore.managedGame()->feature<BSAInvalidation>();
+ BSAInvalidation * invalidation = m_OrganizerCore.managedGame()->feature<BSAInvalidation>();
std::vector<FileEntry::Ptr> files = m_OrganizerCore.directoryStructure()->getFiles();
- QStringList plugins = m_OrganizerCore.findFiles("", [] (const QString &fileName) -> bool {
+ QStringList plugins = m_OrganizerCore.findFiles("", [](const QString &fileName) -> bool {
return fileName.endsWith(".esp", Qt::CaseInsensitive)
- || fileName.endsWith(".esm", Qt::CaseInsensitive);
+ || fileName.endsWith(".esm", Qt::CaseInsensitive)
+ || fileName.endsWith(".esl", Qt::CaseInsensitive);
});
auto hasAssociatedPlugin = [&](const QString &bsaName) -> bool {
for (const QString &pluginName : plugins) {
QFileInfo pluginInfo(pluginName);
if (bsaName.startsWith(QFileInfo(pluginName).baseName(), Qt::CaseInsensitive)
- && (m_OrganizerCore.pluginList()->state(pluginInfo.fileName()) == IPluginList::STATE_ACTIVE)) {
+ && (m_OrganizerCore.pluginList()->state(pluginInfo.fileName()) == IPluginList::STATE_ACTIVE)) {
return true;
}
}
@@ -1379,11 +1451,12 @@ void MainWindow::updateBSAList(const QStringList &defaultArchives, const QString
for (FileEntry::Ptr current : files) {
QFileInfo fileInfo(ToQString(current->getName().c_str()));
- if (fileInfo.suffix().toLower() == "bsa") {
+ if (fileInfo.suffix().toLower() == "bsa" || fileInfo.suffix().toLower() == "ba2") {
int index = activeArchives.indexOf(fileInfo.fileName());
if (index == -1) {
index = 0xFFFF;
- } else {
+ }
+ else {
index += 2;
}
@@ -1392,18 +1465,18 @@ void MainWindow::updateBSAList(const QStringList &defaultArchives, const QString
}
int originId = current->getOrigin();
- FilesOrigin &origin = m_OrganizerCore.directoryStructure()->getOriginByID(originId);
+ FilesOrigin & origin = m_OrganizerCore.directoryStructure()->getOriginByID(originId);
- QTreeWidgetItem *newItem = new QTreeWidgetItem(QStringList()
- << fileInfo.fileName()
- << ToQString(origin.getName()));
+ QTreeWidgetItem * newItem = new QTreeWidgetItem(QStringList()
+ << fileInfo.fileName()
+ << ToQString(origin.getName()));
newItem->setData(0, Qt::UserRole, index);
newItem->setData(1, Qt::UserRole, originId);
- newItem->setFlags(newItem->flags() & ~Qt::ItemIsDropEnabled | Qt::ItemIsUserCheckable);
+ newItem->setFlags(newItem->flags() & ~(Qt::ItemIsDropEnabled | Qt::ItemIsUserCheckable));
newItem->setCheckState(0, (index != -1) ? Qt::Checked : Qt::Unchecked);
newItem->setData(0, Qt::UserRole, false);
if (m_OrganizerCore.settings().forceEnableCoreFiles()
- && defaultArchives.contains(fileInfo.fileName())) {
+ && defaultArchives.contains(fileInfo.fileName())) {
newItem->setCheckState(0, Qt::Checked);
newItem->setDisabled(true);
newItem->setData(0, Qt::UserRole, true);
@@ -1414,21 +1487,15 @@ void MainWindow::updateBSAList(const QStringList &defaultArchives, const QString
newItem->setCheckState(0, Qt::Checked);
newItem->setDisabled(true);
} else {
- if (ui->manageArchivesBox->isChecked()) {
- newItem->setCheckState(0, (index != 0xFFFF) ? Qt::Checked : Qt::Unchecked);
- } else {
- newItem->setCheckState(0, Qt::Unchecked);
- newItem->setDisabled(true);
- }
+ newItem->setCheckState(0, Qt::Unchecked);
+ newItem->setDisabled(true);
}
-
if (index < 0) index = 0;
UINT32 sortValue = ((origin.getPriority() & 0xFFFF) << 16) | (index & 0xFFFF);
items.push_back(std::make_pair(sortValue, newItem));
}
}
-
std::sort(items.begin(), items.end(), BySortValue);
for (auto iter = items.begin(); iter != items.end(); ++iter) {
@@ -1442,10 +1509,11 @@ void MainWindow::updateBSAList(const QStringList &defaultArchives, const QString
modName = modInfo->name();
}
QList<QTreeWidgetItem*> items = ui->bsaList->findItems(modName, Qt::MatchFixedString);
- QTreeWidgetItem *subItem = nullptr;
+ QTreeWidgetItem * subItem = nullptr;
if (items.length() > 0) {
subItem = items.at(0);
- } else {
+ }
+ else {
subItem = new QTreeWidgetItem(QStringList(modName));
subItem->setFlags(subItem->flags() & ~Qt::ItemIsDragEnabled);
ui->bsaList->addTopLevelItem(subItem);
@@ -1453,18 +1521,16 @@ void MainWindow::updateBSAList(const QStringList &defaultArchives, const QString
subItem->addChild(iter->second);
subItem->setExpanded(true);
}
-
checkBSAList();
}
-
void MainWindow::checkBSAList()
{
- DataArchives *archives = m_OrganizerCore.managedGame()->feature<DataArchives>();
+ DataArchives * archives = m_OrganizerCore.managedGame()->feature<DataArchives>();
if (archives != nullptr) {
ui->bsaList->blockSignals(true);
- ON_BLOCK_EXIT([&] () { ui->bsaList->blockSignals(false); });
+ ON_BLOCK_EXIT([&]() { ui->bsaList->blockSignals(false); });
QStringList defaultArchives = archives->archives(m_OrganizerCore.currentProfile());
@@ -1472,9 +1538,9 @@ void MainWindow::checkBSAList()
for (int i = 0; i < ui->bsaList->topLevelItemCount(); ++i) {
bool modWarning = false;
- QTreeWidgetItem *tlItem = ui->bsaList->topLevelItem(i);
+ QTreeWidgetItem * tlItem = ui->bsaList->topLevelItem(i);
for (int j = 0; j < tlItem->childCount(); ++j) {
- QTreeWidgetItem *item = tlItem->child(j);
+ QTreeWidgetItem * item = tlItem->child(j);
QString filename = item->text(0);
item->setIcon(0, QIcon());
item->setToolTip(0, QString());
@@ -1492,7 +1558,6 @@ void MainWindow::checkBSAList()
warning = true;
}
}
-
if (warning) {
ui->tabWidget->setTabIcon(1, QIcon(":/MO/gui/warning"));
} else {
@@ -1501,7 +1566,6 @@ void MainWindow::checkBSAList()
}
}
-
void MainWindow::saveModMetas()
{
for (unsigned int i = 0; i < ModInfo::getNumMods(); ++i) {
@@ -1510,7 +1574,6 @@ void MainWindow::saveModMetas()
}
}
-
void MainWindow::fixCategories()
{
for (unsigned int i = 0; i < ModInfo::getNumMods(); ++i) {
@@ -1581,18 +1644,9 @@ void MainWindow::readSettings()
if (settings.value("Settings/use_proxy", false).toBool()) {
activateProxy(true);
}
-
- ui->manageArchivesBox->blockSignals(true);
- ui->manageArchivesBox->setChecked(settings.value("manage_bsas", true).toBool());
- ui->manageArchivesBox->blockSignals(false);
}
-
-void MainWindow::storeSettings(QSettings &settings)
-{
- settings.setValue("mod_list_state", ui->modList->header()->saveState());
- settings.setValue("plugin_list_state", ui->espList->header()->saveState());
-
+void MainWindow::storeSettings(QSettings &settings) {
settings.setValue("group_state", ui->groupCombo->currentIndex());
settings.setValue("window_geometry", saveGeometry());
@@ -1602,22 +1656,32 @@ void MainWindow::storeSettings(QSettings &settings)
settings.setValue("browser_geometry", m_IntegratedBrowser.saveGeometry());
settings.setValue("filters_visible", ui->displayCategoriesBtn->isChecked());
- settings.setValue("manage_bsas", ui->manageArchivesBox->isChecked());
- settings.setValue("selected_executable", ui->executablesListBox->currentIndex());
+ settings.setValue("selected_executable",
+ ui->executablesListBox->currentIndex());
+
+ for (const std::pair<QString, QHeaderView*> kv : m_PersistedGeometry) {
+ QString key = QString("geometry/") + kv.first;
+ settings.setValue(key, kv.second->saveState());
+ }
}
-void MainWindow::lock()
+ILockedWaitingForProcess* MainWindow::lock()
{
if (m_LockDialog != nullptr) {
++m_LockCount;
- return;
+ return m_LockDialog;
}
- m_LockDialog = new LockedDialog(qApp->activeWindow());
+ if (m_closing)
+ m_LockDialog = new WaitingOnCloseDialog(this);
+ else
+ m_LockDialog = new LockedDialog(this, true);
+ m_LockDialog->setModal(true);
m_LockDialog->show();
setEnabled(false);
m_LockDialog->setEnabled(true); //What's the point otherwise?
++m_LockCount;
+ return m_LockDialog;
}
void MainWindow::unlock()
@@ -1629,6 +1693,8 @@ void MainWindow::unlock()
}
--m_LockCount;
if (m_LockCount == 0) {
+ if (m_closing && m_LockDialog->canceled())
+ m_closing = false;
m_LockDialog->hide();
m_LockDialog->deleteLater();
m_LockDialog = nullptr;
@@ -1636,22 +1702,6 @@ void MainWindow::unlock()
}
}
-bool MainWindow::unlockClicked()
-{
- if (m_LockDialog != nullptr) {
- return m_LockDialog->unlockClicked();
- } else {
- return false;
- }
-}
-
-void MainWindow::setProcessName(QString const &name)
-{
- if (m_LockDialog != nullptr) {
- m_LockDialog->setProcessName(name);
- }
-}
-
void MainWindow::on_btnRefreshData_clicked()
{
m_OrganizerCore.refreshDirectoryStructure();
@@ -1667,8 +1717,6 @@ void MainWindow::on_tabWidget_currentChanged(int index)
refreshDataTree();
} else if (index == 3) {
refreshSaveList();
- } else if (index == 4) {
- ui->downloadView->scrollToBottom();
}
}
@@ -1696,21 +1744,17 @@ void MainWindow::installMod(QString fileName)
}
}
-
-void MainWindow::on_startButton_clicked()
-{
+void MainWindow::on_startButton_clicked() {
const Executable &selectedExecutable(getSelectedExecutable());
-
+ QString customOverwrite = m_OrganizerCore.currentProfile()->setting("custom_overwrites", selectedExecutable.m_Title).toString();
m_OrganizerCore.spawnBinary(
- selectedExecutable.m_BinaryInfo,
- selectedExecutable.m_Arguments,
- selectedExecutable.m_WorkingDirectory.length() != 0 ? selectedExecutable.m_WorkingDirectory
- : selectedExecutable.m_BinaryInfo.absolutePath(),
- selectedExecutable.m_CloseMO == ExecutableInfo::CloseMOStyle::DEFAULT_CLOSE,
- selectedExecutable.m_SteamAppID);
+ selectedExecutable.m_BinaryInfo, selectedExecutable.m_Arguments,
+ selectedExecutable.m_WorkingDirectory.length() != 0
+ ? selectedExecutable.m_WorkingDirectory
+ : selectedExecutable.m_BinaryInfo.absolutePath(),
+ selectedExecutable.m_SteamAppID, customOverwrite);
}
-
static HRESULT CreateShortcut(LPCWSTR targetFileName, LPCWSTR arguments,
LPCSTR linkFileName, LPCWSTR description,
LPCTSTR iconFileName, int iconNumber,
@@ -1797,7 +1841,9 @@ bool MainWindow::modifyExecutablesDialog()
{
bool result = false;
try {
- EditExecutablesDialog dialog(*m_OrganizerCore.executablesList());
+ EditExecutablesDialog dialog(*m_OrganizerCore.executablesList(),
+ *m_OrganizerCore.modList(),
+ m_OrganizerCore.currentProfile());
if (dialog.exec() == QDialog::Accepted) {
m_OrganizerCore.setExecutablesList(dialog.getExecutablesList());
result = true;
@@ -1840,7 +1886,7 @@ void MainWindow::wikiTriggered()
void MainWindow::issueTriggered()
{
- ::ShellExecuteW(nullptr, L"open", L"http://issue.tannin.eu/tbg", nullptr, nullptr, SW_SHOWNORMAL);
+ ::ShellExecuteW(nullptr, L"open", L"http://github.com/LePresidente/modorganizer/issues", nullptr, nullptr, SW_SHOWNORMAL);
}
void MainWindow::tutorialTriggered()
@@ -1917,8 +1963,10 @@ void MainWindow::setESPListSorting(int index)
void MainWindow::refresher_progress(int percent)
{
if (percent == 100) {
-// m_RefreshProgress->setVisible(false);
+ m_RefreshProgress->setVisible(false);
+ statusBar()->hide();
} else if (!m_RefreshProgress->isVisible()) {
+ statusBar()->show();
m_RefreshProgress->setVisible(true);
m_RefreshProgress->setRange(0, 100);
m_RefreshProgress->setValue(percent);
@@ -1945,7 +1993,7 @@ void MainWindow::modorder_changed()
}
}
m_OrganizerCore.refreshBSAList();
- m_OrganizerCore.currentProfile()->modlistWriter().write();
+ m_OrganizerCore.currentProfile()->writeModlist();
m_ArchiveListWriter.write();
m_OrganizerCore.directoryStructure()->getFileRegister()->sortOrigins();
@@ -2006,71 +2054,9 @@ void MainWindow::installMod_clicked()
installMod();
}
-void MainWindow::renameModInList(QFile &modList, const QString &oldName, const QString &newName)
-{
- //TODO this code needs to be merged with ModList::readFrom
- if (!modList.open(QIODevice::ReadWrite)) {
- reportError(tr("failed to open %1").arg(modList.fileName()));
- return;
- }
-
- QBuffer outBuffer;
- outBuffer.open(QIODevice::WriteOnly);
-
- while (!modList.atEnd()) {
- QByteArray line = modList.readLine();
-
- if (line.length() == 0) {
- // ignore empty lines
- qWarning("mod list contained invalid data: empty line");
- continue;
- }
-
- char spec = line.at(0);
- if (spec == '#') {
- // don't touch comments
- outBuffer.write(line);
- continue;
- }
-
- QString modName = QString::fromUtf8(line).mid(1).trimmed();
-
- if (modName.isEmpty()) {
- // file broken?
- qWarning("mod list contained invalid data: missing mod name");
- continue;
- }
-
- outBuffer.write(QByteArray(1, spec));
- if (modName == oldName) {
- modName = newName;
- }
- outBuffer.write(modName.toUtf8().constData());
- outBuffer.write("\r\n");
- }
-
- modList.resize(0);
- modList.write(outBuffer.buffer());
- modList.close();
-}
-
-
void MainWindow::modRenamed(const QString &oldName, const QString &newName)
{
- // fix the profiles directly on disc
- for (int i = 0; i < ui->profileBox->count(); ++i) {
- QString profileName = ui->profileBox->itemText(i);
-
- //TODO this functionality should be in the Profile class
- QString modlistName = QString("%1/%2/modlist.txt")
- .arg(qApp->property("dataPath").toString() + "/" + QString::fromStdWString(AppConfig::profilesPath()))
- .arg(profileName);
-
- QFile modList(modlistName);
- if (modList.exists()) {
- renameModInList(modList, oldName, newName);
- }
- }
+ Profile::renameModInAllProfiles(oldName, newName);
// immediately refresh the active profile because the data in memory is invalid
m_OrganizerCore.currentProfile()->refreshModStatus();
@@ -2098,9 +2084,10 @@ void MainWindow::fileMoved(const QString &filePath, const QString &oldOriginName
QString fullNewPath = ToQString(newOrigin.getPath()) + "\\" + filePath;
WIN32_FIND_DATAW findData;
- ::FindFirstFileW(ToWString(fullNewPath).c_str(), &findData);
-
+ HANDLE hFind;
+ hFind = ::FindFirstFileW(ToWString(fullNewPath).c_str(), &findData);
filePtr->addOrigin(newOrigin.getID(), findData.ftCreationTime, L"");
+ FindClose(hFind);
}
if (m_OrganizerCore.directoryStructure()->originExists(ToWString(oldOriginName))) {
FilesOrigin &oldOrigin = m_OrganizerCore.directoryStructure()->getOriginByName(ToWString(oldOriginName));
@@ -2137,11 +2124,14 @@ void MainWindow::addContentFilters()
void MainWindow::addCategoryFilters(QTreeWidgetItem *root, const std::set<int> &categoriesUsed, int targetID)
{
- for (size_t i = 1; i < m_CategoryFactory.numCategories(); ++i) {
+ for (unsigned int i = 1;
+ i < static_cast<unsigned int>(m_CategoryFactory.numCategories()); ++i) {
if ((m_CategoryFactory.getParentID(i) == targetID)) {
int categoryID = m_CategoryFactory.getCategoryID(i);
if (categoriesUsed.find(categoryID) != categoriesUsed.end()) {
- QTreeWidgetItem *item = addFilterItem(root, m_CategoryFactory.getCategoryName(i), categoryID, ModListSortProxy::TYPE_CATEGORY);
+ QTreeWidgetItem *item =
+ addFilterItem(root, m_CategoryFactory.getCategoryName(i),
+ categoryID, ModListSortProxy::TYPE_CATEGORY);
if (m_CategoryFactory.hasChildren(i)) {
addCategoryFilters(item, categoriesUsed, categoryID);
}
@@ -2247,7 +2237,7 @@ void MainWindow::restoreBackup_clicked()
void MainWindow::modlistChanged(const QModelIndex&, int)
{
- m_OrganizerCore.currentProfile()->modlistWriter().write();
+ m_OrganizerCore.currentProfile()->writeModlist();
}
void MainWindow::modlistSelectionChanged(const QModelIndex &current, const QModelIndex&)
@@ -2265,6 +2255,18 @@ void MainWindow::modlistSelectionChanged(const QModelIndex &current, const QMode
ui->modList->verticalScrollBar()->repaint();
}
+void MainWindow::modlistSelectionsChanged(const QItemSelection &selected)
+{
+ m_OrganizerCore.pluginList()->highlightPlugins(selected, *m_OrganizerCore.directoryStructure(), *m_OrganizerCore.currentProfile());
+ ui->espList->verticalScrollBar()->repaint();
+}
+
+void MainWindow::esplistSelectionsChanged(const QItemSelection &selected)
+{
+ m_OrganizerCore.modList()->highlightMods(selected, *m_OrganizerCore.directoryStructure());
+ ui->modList->verticalScrollBar()->repaint();
+}
+
void MainWindow::modListSortIndicatorChanged(int, Qt::SortOrder)
{
ui->modList->verticalScrollBar()->repaint();
@@ -2277,7 +2279,7 @@ void MainWindow::removeMod_clicked()
if (selection->hasSelection() && selection->selectedRows().count() > 1) {
QString mods;
QStringList modNames;
- foreach (QModelIndex idx, selection->selectedRows()) {
+ for (QModelIndex idx : selection->selectedRows()) {
QString name = idx.data().toString();
if (!ModInfo::getByIndex(idx.data(Qt::UserRole + 1).toInt())->isRegular()) {
continue;
@@ -2289,7 +2291,7 @@ void MainWindow::removeMod_clicked()
tr("Remove the following mods?<br><ul>%1</ul>").arg(mods),
QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) {
// use mod names instead of indexes because those become invalid during the removal
- foreach (QString name, modNames) {
+ for (QString name : modNames) {
m_OrganizerCore.modList()->removeRowForce(ModInfo::getIndex(name), QModelIndex());
}
}
@@ -2603,7 +2605,34 @@ void MainWindow::information_clicked()
}
}
+void MainWindow::createEmptyMod_clicked()
+{
+ GuessedValue<QString> name;
+ name.setFilter(&fixDirectoryName);
+
+ while (name->isEmpty()) {
+ bool ok;
+ name.update(QInputDialog::getText(this, tr("Create Mod..."),
+ tr("This will create an empty mod.\n"
+ "Please enter a name:"), QLineEdit::Normal, "", &ok),
+ GUESS_USER);
+ if (!ok) {
+ return;
+ }
+ }
+
+ if (m_OrganizerCore.getMod(name) != nullptr) {
+ reportError(tr("A mod with this name already exists"));
+ return;
+ }
+ IModInterface *newMod = m_OrganizerCore.createMod(name);
+ if (newMod == nullptr) {
+ return;
+ }
+
+ m_OrganizerCore.refreshModList();
+}
void MainWindow::createModFromOverwrite()
{
@@ -2642,6 +2671,31 @@ void MainWindow::createModFromOverwrite()
m_OrganizerCore.refreshModList();
}
+void MainWindow::clearOverwrite()
+{
+ unsigned int overwriteIndex = ModInfo::findMod([](ModInfo::Ptr mod) -> bool {
+ std::vector<ModInfo::EFlag> flags = mod->getFlags();
+ return std::find(flags.begin(), flags.end(), ModInfo::FLAG_OVERWRITE)
+ != flags.end();
+ });
+
+ ModInfo::Ptr modInfo = ModInfo::getByIndex(overwriteIndex);
+ if (modInfo)
+ {
+ QDir overwriteDir(modInfo->absolutePath());
+ if (QMessageBox::question(this, tr("Are you sure?"),
+ tr("About to recursively delete:\n") + overwriteDir.absolutePath(),
+ QMessageBox::Ok | QMessageBox::Cancel) == QMessageBox::Ok)
+ {
+ QStringList delList;
+ for (auto f : overwriteDir.entryList(QDir::AllDirs | QDir::Files | QDir::NoDotAndDotDot))
+ delList.push_back(overwriteDir.absoluteFilePath(f));
+ shellDelete(delList, true);
+ updateProblemsButton();
+ }
+ }
+}
+
void MainWindow::cancelModListEditor()
{
ui->modList->setEnabled(false);
@@ -2682,7 +2736,7 @@ bool MainWindow::populateMenuCategories(QMenu *menu, int targetID)
bool childEnabled = false;
- for (size_t i = 1; i < m_CategoryFactory.numCategories(); ++i) {
+ for (unsigned int i = 1; i < m_CategoryFactory.numCategories(); ++i) {
if (m_CategoryFactory.getParentID(i) == targetID) {
QMenu *targetMenu = menu;
if (m_CategoryFactory.hasChildren(i)) {
@@ -2716,7 +2770,7 @@ bool MainWindow::populateMenuCategories(QMenu *menu, int targetID)
void MainWindow::replaceCategoriesFromMenu(QMenu *menu, int modRow)
{
ModInfo::Ptr modInfo = ModInfo::getByIndex(modRow);
- foreach (QAction* action, menu->actions()) {
+ for (QAction* action : menu->actions()) {
if (action->menu() != nullptr) {
replaceCategoriesFromMenu(action->menu(), modRow);
} else {
@@ -2841,44 +2895,16 @@ void MainWindow::replaceCategories_MenuHandler() {
refreshFilters();
}
-void MainWindow::savePrimaryCategory()
-{
- QMenu *menu = qobject_cast<QMenu*>(sender());
- if (menu == nullptr) {
- qCritical("not a menu?");
- return;
- }
-
- foreach (QAction* action, menu->actions()) {
- QWidgetAction *widgetAction = qobject_cast<QWidgetAction*>(action);
- if (widgetAction != nullptr) {
- QRadioButton *btn = qobject_cast<QRadioButton*>(widgetAction->defaultWidget());
- if (btn->isChecked()) {
- QModelIndexList selected = ui->modList->selectionModel()->selectedRows();
- for (int i = 0; i < selected.size(); ++i) {
- ModInfo::Ptr modInfo = ModInfo::getByIndex(m_ModListSortProxy->mapToSource(selected.at(i)).row());
- modInfo->setPrimaryCategory(widgetAction->data().toInt());
- }
- break;
- }
- }
- }
-}
-
void MainWindow::saveArchiveList()
{
if (m_OrganizerCore.isArchivesInit()) {
SafeWriteFile archiveFile(m_OrganizerCore.currentProfile()->getArchivesFileName());
for (int i = 0; i < ui->bsaList->topLevelItemCount(); ++i) {
- QTreeWidgetItem *tlItem = ui->bsaList->topLevelItem(i);
+ QTreeWidgetItem * tlItem = ui->bsaList->topLevelItem(i);
for (int j = 0; j < tlItem->childCount(); ++j) {
- QTreeWidgetItem *item = tlItem->child(j);
+ QTreeWidgetItem * item = tlItem->child(j);
if (item->checkState(0) == Qt::Checked) {
- // in managed mode, "register" all enabled archives, otherwise register only the files registered in the ini
- if (ui->manageArchivesBox->isChecked()
- || item->data(0, Qt::UserRole).toBool()) {
- archiveFile->write(item->text(0).toUtf8().append("\r\n"));
- }
+ archiveFile->write(item->text(0).toUtf8().append("\r\n"));
}
}
}
@@ -2949,15 +2975,21 @@ void MainWindow::unignoreUpdate()
info->ignoreUpdate(false);
}
-void MainWindow::addPrimaryCategoryCandidates(QMenu *primaryCategoryMenu, ModInfo::Ptr info)
-{
+void MainWindow::addPrimaryCategoryCandidates(QMenu *primaryCategoryMenu,
+ ModInfo::Ptr info) {
const std::set<int> &categories = info->getCategories();
- foreach (int categoryID, categories) {
+ for (int categoryID : categories) {
int catIdx = m_CategoryFactory.getCategoryIndex(categoryID);
QWidgetAction *action = new QWidgetAction(primaryCategoryMenu);
try {
- QRadioButton *categoryBox = new QRadioButton(m_CategoryFactory.getCategoryName(catIdx).replace('&', "&&"),
- primaryCategoryMenu);
+ QRadioButton *categoryBox = new QRadioButton(
+ m_CategoryFactory.getCategoryName(catIdx).replace('&', "&&"),
+ primaryCategoryMenu);
+ connect(categoryBox, &QRadioButton::toggled, [info, categoryID](bool enable) {
+ if (enable) {
+ info->setPrimaryCategory(categoryID);
+ }
+ });
categoryBox->setChecked(categoryID == info->getPrimaryCategory());
action->setDefaultWidget(categoryBox);
} catch (const std::exception &e) {
@@ -2998,58 +3030,191 @@ void MainWindow::disableVisibleMods()
}
}
+void MainWindow::openInstanceFolder()
+{
+ ::ShellExecuteW(nullptr, L"explore", ToWString(m_OrganizerCore.settings().getBaseDirectory()).c_str(), nullptr, nullptr, SW_SHOWNORMAL);
+}
+
+void MainWindow::openInstallFolder()
+{
+ ::ShellExecuteW(nullptr, L"explore", ToWString(qApp->applicationDirPath()).c_str(), nullptr, nullptr, SW_SHOWNORMAL);
+}
+
+void MainWindow::openProfileFolder()
+{
+ ::ShellExecuteW(nullptr, L"explore", ToWString(m_OrganizerCore.currentProfile()->absolutePath()).c_str(), nullptr, nullptr, SW_SHOWNORMAL);
+}
+
+void MainWindow::openDownloadsFolder()
+{
+ ::ShellExecuteW(nullptr, L"explore", ToWString(m_OrganizerCore.settings().getDownloadDirectory()).c_str(), nullptr, nullptr, SW_SHOWNORMAL);
+}
+
+void MainWindow::openGameFolder()
+{
+ ::ShellExecuteW(nullptr, L"explore", ToWString(m_OrganizerCore.managedGame()->gameDirectory().absolutePath()).c_str(), nullptr, nullptr, SW_SHOWNORMAL);
+}
+
+void MainWindow::openMyGamesFolder()
+{
+ ::ShellExecuteW(nullptr, L"explore", ToWString(m_OrganizerCore.managedGame()->documentsDirectory().absolutePath()).c_str(), nullptr, nullptr, SW_SHOWNORMAL);
+}
+
+
void MainWindow::exportModListCSV()
{
- SelectionDialog selection(tr("Choose what to export"));
+ //SelectionDialog selection(tr("Choose what to export"));
- selection.addChoice(tr("Everything"), tr("All installed mods are included in the list"), 0);
- selection.addChoice(tr("Active Mods"), tr("Only active (checked) mods from your current profile are included"), 1);
- selection.addChoice(tr("Visible"), tr("All mods visible in the mod list are included"), 2);
+ //selection.addChoice(tr("Everything"), tr("All installed mods are included in the list"), 0);
+ //selection.addChoice(tr("Active Mods"), tr("Only active (checked) mods from your current profile are included"), 1);
+ //selection.addChoice(tr("Visible"), tr("All mods visible in the mod list are included"), 2);
- if (selection.exec() == QDialog::Accepted) {
- unsigned int numMods = ModInfo::getNumMods();
+ QDialog selection(this);
+ QGridLayout *grid = new QGridLayout;
+ selection.setWindowTitle(tr("Export to csv"));
- try {
- QBuffer buffer;
- buffer.open(QIODevice::ReadWrite);
- CSVBuilder builder(&buffer);
- builder.setEscapeMode(CSVBuilder::TYPE_STRING, CSVBuilder::QUOTE_ALWAYS);
- std::vector<std::pair<QString, CSVBuilder::EFieldType> > fields;
- fields.push_back(std::make_pair(QString("mod_id"), CSVBuilder::TYPE_INTEGER));
- fields.push_back(std::make_pair(QString("mod_installed_name"), CSVBuilder::TYPE_STRING));
- fields.push_back(std::make_pair(QString("mod_version"), CSVBuilder::TYPE_STRING));
- fields.push_back(std::make_pair(QString("file_installed_name"), CSVBuilder::TYPE_STRING));
-// fields.push_back(std::make_pair(QString("file_category"), CSVBuilder::TYPE_INTEGER));
- builder.setFields(fields);
+ 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"));
+ QRadioButton *visible = new QRadioButton(tr("All currently visible mods in the mod list"));
- builder.writeHeader();
+ QVBoxLayout *vbox = new QVBoxLayout;
+ vbox->addWidget(all);
+ vbox->addWidget(active);
+ vbox->addWidget(visible);
+ vbox->addStretch(1);
+ groupBoxRows->setLayout(vbox);
- for (unsigned int i = 0; i < numMods; ++i) {
- ModInfo::Ptr info = ModInfo::getByIndex(i);
- bool enabled = m_OrganizerCore.currentProfile()->modEnabled(i);
- if ((selection.getChoiceData().toInt() == 1) && !enabled) {
- continue;
- } else if ((selection.getChoiceData().toInt() == 2) && !m_ModListSortProxy->filterMatchesMod(info, enabled)) {
- continue;
- }
- std::vector<ModInfo::EFlag> flags = info->getFlags();
- if ((std::find(flags.begin(), flags.end(), ModInfo::FLAG_OVERWRITE) == flags.end()) &&
- (std::find(flags.begin(), flags.end(), ModInfo::FLAG_BACKUP) == flags.end())) {
- builder.setRowField("mod_id", info->getNexusID());
- builder.setRowField("mod_installed_name", info->name());
- builder.setRowField("mod_version", info->getVersion().canonicalString());
- builder.setRowField("file_installed_name", info->getInstallationFile());
- builder.writeRow();
- }
- }
- SaveTextAsDialog saveDialog(this);
- saveDialog.setText(buffer.data());
- saveDialog.exec();
- } catch (const std::exception &e) {
- reportError(tr("export failed: %1").arg(e.what()));
- }
- }
+
+ grid->addWidget(groupBoxRows);
+
+ QButtonGroup *buttonGroupRows = new QButtonGroup();
+ buttonGroupRows->addButton(all, 0);
+ buttonGroupRows->addButton(active, 1);
+ buttonGroupRows->addButton(visible, 2);
+ buttonGroupRows->button(0)->setChecked(true);
+
+
+
+ QGroupBox *groupBoxColumns = new QGroupBox(tr("Choose what Columns to export:"));
+ groupBoxColumns->setFlat(true);
+
+ QCheckBox *mod_Priority = new QCheckBox(tr("Mod_Priority"));
+ mod_Priority->setChecked(true);
+ QCheckBox *mod_Name = new QCheckBox(tr("Mod_Name"));
+ mod_Name->setChecked(true);
+ QCheckBox *mod_Status = new QCheckBox(tr("Mod_Status"));
+ QCheckBox *primary_Category = new QCheckBox(tr("Primary_Category"));
+ QCheckBox *nexus_ID = new QCheckBox(tr("Nexus_ID"));
+ QCheckBox *mod_Nexus_URL = new QCheckBox(tr("Mod_Nexus_URL"));
+ QCheckBox *mod_Version = new QCheckBox(tr("Mod_Version"));
+ QCheckBox *install_Date = new QCheckBox(tr("Install_Date"));
+ QCheckBox *download_File_Name = new QCheckBox(tr("Download_File_Name"));
+
+ QVBoxLayout *vbox1 = new QVBoxLayout;
+ vbox1->addWidget(mod_Priority);
+ vbox1->addWidget(mod_Name);
+ vbox1->addWidget(mod_Status);
+ vbox1->addWidget(primary_Category);
+ vbox1->addWidget(nexus_ID);
+ vbox1->addWidget(mod_Nexus_URL);
+ vbox1->addWidget(mod_Version);
+ vbox1->addWidget(install_Date);
+ vbox1->addWidget(download_File_Name);
+ groupBoxColumns->setLayout(vbox1);
+
+ grid->addWidget(groupBoxColumns);
+
+ QPushButton *ok = new QPushButton("Ok");
+ QPushButton *cancel = new QPushButton("Cancel");
+ QDialogButtonBox *buttons = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
+
+ connect(buttons, SIGNAL(accepted()), &selection, SLOT(accept()));
+ connect(buttons, SIGNAL(rejected()), &selection, SLOT(reject()));
+
+ grid->addWidget(buttons);
+
+ selection.setLayout(grid);
+
+
+ if (selection.exec() == QDialog::Accepted) {
+
+ unsigned int numMods = ModInfo::getNumMods();
+ int selectedRowID = buttonGroupRows->checkedId();
+
+ try {
+ QBuffer buffer;
+ buffer.open(QIODevice::ReadWrite);
+ CSVBuilder builder(&buffer);
+ builder.setEscapeMode(CSVBuilder::TYPE_STRING, CSVBuilder::QUOTE_ALWAYS);
+ std::vector<std::pair<QString, CSVBuilder::EFieldType> > fields;
+ if (mod_Priority->isChecked())
+ fields.push_back(std::make_pair(QString("#Mod_Priority"), CSVBuilder::TYPE_STRING));
+ if (mod_Name->isChecked())
+ fields.push_back(std::make_pair(QString("#Mod_Name"), CSVBuilder::TYPE_STRING));
+ if (mod_Status->isChecked())
+ fields.push_back(std::make_pair(QString("#Mod_Status"), CSVBuilder::TYPE_STRING));
+ if (primary_Category->isChecked())
+ fields.push_back(std::make_pair(QString("#Primary_Category"), CSVBuilder::TYPE_STRING));
+ if (nexus_ID->isChecked())
+ fields.push_back(std::make_pair(QString("#Nexus_ID"), CSVBuilder::TYPE_INTEGER));
+ if (mod_Nexus_URL->isChecked())
+ fields.push_back(std::make_pair(QString("#Mod_Nexus_URL"), CSVBuilder::TYPE_STRING));
+ if (mod_Version->isChecked())
+ fields.push_back(std::make_pair(QString("#Mod_Version"), CSVBuilder::TYPE_STRING));
+ if (install_Date->isChecked())
+ fields.push_back(std::make_pair(QString("#Install_Date"), CSVBuilder::TYPE_STRING));
+ if (download_File_Name->isChecked())
+ fields.push_back(std::make_pair(QString("#Download_File_Name"), CSVBuilder::TYPE_STRING));
+
+ builder.setFields(fields);
+
+ builder.writeHeader();
+
+ for (unsigned int i = 0; i < numMods; ++i) {
+ ModInfo::Ptr info = ModInfo::getByIndex(i);
+ bool enabled = m_OrganizerCore.currentProfile()->modEnabled(i);
+ if ((selectedRowID == 1) && !enabled) {
+ continue;
+ }
+ else if ((selectedRowID == 2) && !m_ModListSortProxy->filterMatchesMod(info, enabled)) {
+ continue;
+ }
+ std::vector<ModInfo::EFlag> flags = info->getFlags();
+ if ((std::find(flags.begin(), flags.end(), ModInfo::FLAG_OVERWRITE) == flags.end()) &&
+ (std::find(flags.begin(), flags.end(), ModInfo::FLAG_BACKUP) == flags.end())) {
+ if (mod_Priority->isChecked())
+ builder.setRowField("#Mod_Priority", QString("%1").arg(m_OrganizerCore.currentProfile()->getModPriority(i), 4, 10, QChar('0')));
+ if (mod_Name->isChecked())
+ builder.setRowField("#Mod_Name", info->name());
+ if (mod_Status->isChecked())
+ builder.setRowField("#Mod_Status", (enabled)? "Enabled" : "Disabled");
+ if (primary_Category->isChecked())
+ builder.setRowField("#Primary_Category", (m_CategoryFactory.categoryExists(info->getPrimaryCategory())) ? m_CategoryFactory.getCategoryName(info->getPrimaryCategory()) : "");
+ if (nexus_ID->isChecked())
+ builder.setRowField("#Nexus_ID", info->getNexusID());
+ if (mod_Nexus_URL->isChecked())
+ builder.setRowField("#Mod_Nexus_URL", info->getURL());
+ if (mod_Version->isChecked())
+ builder.setRowField("#Mod_Version", info->getVersion().canonicalString());
+ if (install_Date->isChecked())
+ builder.setRowField("#Install_Date", info->creationTime().toString("yyyy/MM/dd HH:mm:ss"));
+ if (download_File_Name->isChecked())
+ builder.setRowField("#Download_File_Name", info->getInstallationFile());
+
+ builder.writeRow();
+ }
+ }
+
+ SaveTextAsDialog saveDialog(this);
+ saveDialog.setText(buffer.data());
+ saveDialog.exec();
+ }
+ catch (const std::exception &e) {
+ reportError(tr("export failed: %1").arg(e.what()));
+ }
+ }
}
static void addMenuAsPushButton(QMenu *menu, QMenu *subMenu)
@@ -3061,11 +3226,39 @@ static void addMenuAsPushButton(QMenu *menu, QMenu *subMenu)
menu->addAction(action);
}
+QMenu *MainWindow::openFolderMenu()
+{
+
+ QMenu *FolderMenu = new QMenu(this);
+
+
+ FolderMenu->addAction(tr("Open Instance folder"), this, SLOT(openInstanceFolder()));
+
+ FolderMenu->addAction(tr("Open Profile folder"), this, SLOT(openProfileFolder()));
+
+ 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 MyGames folder"), this, SLOT(openMyGamesFolder()));
+
+
+ return FolderMenu;
+}
+
QMenu *MainWindow::modListContextMenu()
{
QMenu *menu = new QMenu(this);
menu->addAction(tr("Install Mod..."), this, SLOT(installMod_clicked()));
+ menu->addAction(tr("Create empty mod"), this, SLOT(createEmptyMod_clicked()));
+
+ menu->addSeparator();
+
menu->addAction(tr("Enable all visible"), this, SLOT(enableVisibleMods()));
menu->addAction(tr("Disable all visible"), this, SLOT(disableVisibleMods()));
@@ -3074,6 +3267,8 @@ QMenu *MainWindow::modListContextMenu()
menu->addAction(tr("Refresh"), &m_OrganizerCore, SLOT(profileRefresh()));
menu->addAction(tr("Export to csv..."), this, SLOT(exportModListCSV()));
+
+
return menu;
}
@@ -3100,7 +3295,9 @@ void MainWindow::on_modList_customContextMenuRequested(const QPoint &pos)
if (QDir(info->absolutePath()).count() > 2) {
menu->addAction(tr("Sync to Mods..."), &m_OrganizerCore, SLOT(syncOverwrite()));
menu->addAction(tr("Create Mod..."), this, SLOT(createModFromOverwrite()));
+ menu->addAction(tr("Clear Overwrite..."), this, SLOT(clearOverwrite()));
}
+ menu->addAction(tr("Open in explorer"), this, SLOT(openExplorer_clicked()));
} else if (std::find(flags.begin(), flags.end(), ModInfo::FLAG_BACKUP) != flags.end()) {
menu->addAction(tr("Restore Backup"), this, SLOT(restoreBackup_clicked()));
menu->addAction(tr("Remove Backup..."), this, SLOT(removeMod_clicked()));
@@ -3119,7 +3316,6 @@ void MainWindow::on_modList_customContextMenuRequested(const QPoint &pos)
QMenu *primaryCategoryMenu = new QMenu(tr("Primary Category"));
connect(primaryCategoryMenu, SIGNAL(aboutToShow()), this, SLOT(addPrimaryCategoryCandidates()));
- connect(primaryCategoryMenu, SIGNAL(aboutToHide()), this, SLOT(savePrimaryCategory()));
addMenuAsPushButton(menu, primaryCategoryMenu);
menu->addSeparator();
@@ -3138,6 +3334,9 @@ void MainWindow::on_modList_customContextMenuRequested(const QPoint &pos)
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->addSeparator();
+
if (info->getNexusID() > 0) {
switch (info->endorsedState()) {
case ModInfo::ENDORSED_TRUE: {
@@ -3158,6 +3357,8 @@ void MainWindow::on_modList_customContextMenuRequested(const QPoint &pos)
}
}
+ menu->addSeparator();
+
std::vector<ModInfo::EFlag> flags = info->getFlags();
if (std::find(flags.begin(), flags.end(), ModInfo::FLAG_INVALID) != flags.end()) {
menu->addAction(tr("Ignore missing data"), this, SLOT(ignoreMissingData_clicked()));
@@ -3165,11 +3366,7 @@ void MainWindow::on_modList_customContextMenuRequested(const QPoint &pos)
if (info->getNexusID() > 0) {
menu->addAction(tr("Visit on Nexus"), this, SLOT(visitOnNexus_clicked()));
- }
-
- //If a URL is specified which is not the game's URL, pop up 'visit web page'
- if (info->getURL() != "" &&
- !NexusInterface::instance()->isModURL(info->getNexusID(), info->getURL())) {
+ } else if ((info->getURL() != "")) {
menu->addAction(tr("Visit web page"), this, SLOT(visitWebPage_clicked()));
}
@@ -3196,7 +3393,7 @@ void MainWindow::on_categoriesList_itemSelectionChanged()
QModelIndexList indices = ui->categoriesList->selectionModel()->selectedRows();
std::vector<int> categories;
std::vector<int> content;
- foreach (const QModelIndex &index, indices) {
+ for (const QModelIndex &index : indices) {
int filterType = index.data(Qt::UserRole + 1).toInt();
if ((filterType == ModListSortProxy::TYPE_CATEGORY)
|| (filterType == ModListSortProxy::TYPE_SPECIAL)) {
@@ -3212,7 +3409,10 @@ void MainWindow::on_categoriesList_itemSelectionChanged()
m_ModListSortProxy->setCategoryFilter(categories);
m_ModListSortProxy->setContentFilter(content);
- ui->clickBlankLabel->setEnabled(categories.size() > 0);
+ ui->clickBlankButton->setEnabled(categories.size() > 0 || content.size() >0);
+ //ui->clearFiltersButton->setStyleSheet("border:5px solid #ff0000;");
+ ui->clearFiltersButton->setVisible(categories.size() > 0 || content.size() > 0);
+
if (indices.count() == 0) {
ui->currentCategoryLabel->setText(QString("(%1)").arg(tr("<All>")));
} else if (indices.count() > 1) {
@@ -3260,6 +3460,7 @@ void MainWindow::deleteSavegame_clicked()
.arg(savesMsgLabel),
QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) {
shellDelete(deleteFiles, true); // recycle bin delete.
+ refreshSaveList();
}
}
@@ -3277,7 +3478,7 @@ void MainWindow::fixMods_clicked(SaveGameInfo::MissingAssets const &missingAsset
}
}
- m_OrganizerCore.currentProfile()->modlistWriter().write();
+ m_OrganizerCore.currentProfile()->writeModlist();
m_OrganizerCore.refreshLists();
std::set<QString> espsToActivate = dialog.getESPsToActivate();
@@ -3347,7 +3548,7 @@ QString getStartMenuLinkfile(const Executable &exec)
void MainWindow::addWindowsLink(const ShortcutType mapping)
{
- Executable const &selectedExecutable(getSelectedExecutable());
+ const Executable &selectedExecutable(getSelectedExecutable());
QString const linkName = getLinkfile(mapping == ShortcutType::Desktop ? getDesktopDirectory() : getStartMenuDirectory(),
selectedExecutable);
@@ -3363,11 +3564,11 @@ void MainWindow::addWindowsLink(const ShortcutType mapping)
QString executable = QDir::toNativeSeparators(selectedExecutable.m_BinaryInfo.absoluteFilePath());
std::wstring targetFile = ToWString(exeInfo.absoluteFilePath());
- std::wstring parameter = ToWString(QString("\"%1\" %2").arg(executable)
- .arg(selectedExecutable.m_Arguments));
- std::wstring description = ToWString(selectedExecutable.m_BinaryInfo.fileName());
+ std::wstring parameter = ToWString(
+ QString("\"moshortcut://%1:%2\"").arg(InstanceManager::instance().currentInstance(),selectedExecutable.m_Title));
+ std::wstring description = ToWString(QString("Run %1 with ModOrganizer").arg(selectedExecutable.m_Title));
std::wstring iconFile = ToWString(executable);
- std::wstring currentDirectory = ToWString(QDir::toNativeSeparators(exeInfo.absolutePath()));
+ std::wstring currentDirectory = ToWString(QDir::toNativeSeparators(qApp->applicationDirPath()));
if (CreateShortcut(targetFile.c_str()
, parameter.c_str()
@@ -3394,40 +3595,59 @@ void MainWindow::linkMenu()
void MainWindow::on_actionSettings_triggered()
{
- QString oldModDirectory(m_OrganizerCore.settings().getModDirectory());
- QString oldCacheDirectory(m_OrganizerCore.settings().getCacheDirectory());
- bool oldDisplayForeign(m_OrganizerCore.settings().displayForeign());
- bool proxy = m_OrganizerCore.settings().useProxy();
- m_OrganizerCore.settings().query(this);
- m_OrganizerCore.installationManager()->setModsDirectory(m_OrganizerCore.settings().getModDirectory());
- m_OrganizerCore.installationManager()->setDownloadDirectory(m_OrganizerCore.settings().getDownloadDirectory());
+ Settings &settings = m_OrganizerCore.settings();
+
+ QString oldModDirectory(settings.getModDirectory());
+ QString oldCacheDirectory(settings.getCacheDirectory());
+ QString oldProfilesDirectory(settings.getProfileDirectory());
+ bool oldDisplayForeign(settings.displayForeign());
+ bool proxy = settings.useProxy();
+
+ settings.query(this);
+
+ InstallationManager *instManager = m_OrganizerCore.installationManager();
+ instManager->setModsDirectory(settings.getModDirectory());
+ instManager->setDownloadDirectory(settings.getDownloadDirectory());
+
fixCategories();
refreshFilters();
- if (QDir::fromNativeSeparators(m_OrganizerCore.downloadManager()->getOutputDirectory()) != QDir::fromNativeSeparators(m_OrganizerCore.settings().getDownloadDirectory())) {
- if (m_OrganizerCore.downloadManager()->downloadsInProgress()) {
- MessageDialog::showMessage(tr("Can't change download directory while downloads are in progress!"), this);
+
+ if (settings.getProfileDirectory() != oldProfilesDirectory) {
+ refreshProfiles();
+ }
+
+ DownloadManager *dlManager = m_OrganizerCore.downloadManager();
+
+ if (dlManager->getOutputDirectory() != settings.getDownloadDirectory()) {
+ if (dlManager->downloadsInProgress()) {
+ MessageDialog::showMessage(tr("Can't change download directory while "
+ "downloads are in progress!"),
+ this);
} else {
- m_OrganizerCore.downloadManager()->setOutputDirectory(m_OrganizerCore.settings().getDownloadDirectory());
+ dlManager->setOutputDirectory(settings.getDownloadDirectory());
}
}
- m_OrganizerCore.downloadManager()->setPreferredServers(m_OrganizerCore.settings().getPreferredServers());
+ dlManager->setPreferredServers(settings.getPreferredServers());
- if ((m_OrganizerCore.settings().getModDirectory() != oldModDirectory)
- || (m_OrganizerCore.settings().displayForeign() != oldDisplayForeign)) {
+ if ((settings.getModDirectory() != oldModDirectory)
+ || (settings.displayForeign() != oldDisplayForeign)) {
m_OrganizerCore.profileRefresh();
}
- if (m_OrganizerCore.settings().getCacheDirectory() != oldCacheDirectory) {
- NexusInterface::instance()->setCacheDirectory(m_OrganizerCore.settings().getCacheDirectory());
+ if (settings.getCacheDirectory() != oldCacheDirectory) {
+ NexusInterface::instance()->setCacheDirectory(settings.getCacheDirectory());
}
- if (proxy != m_OrganizerCore.settings().useProxy()) {
- activateProxy(m_OrganizerCore.settings().useProxy());
+ if (proxy != settings.useProxy()) {
+ activateProxy(settings.useProxy());
}
- NexusInterface::instance()->setNMMVersion(m_OrganizerCore.settings().getNMMVersion());
+ NexusInterface::instance()->setNMMVersion(settings.getNMMVersion());
updateDownloadListDelegate();
+
+ m_OrganizerCore.updateVFSParams(settings.logLevel(), settings.crashDumpsType());
+ m_OrganizerCore.cycleDiagnostics();
}
@@ -3471,7 +3691,7 @@ void MainWindow::installTranslator(const QString &name)
void MainWindow::languageChange(const QString &newLanguage)
{
- foreach (QTranslator *trans, m_Translators) {
+ for (QTranslator *trans : m_Translators) {
qApp->removeTranslator(trans);
}
m_Translators.clear();
@@ -3491,6 +3711,9 @@ void MainWindow::languageChange(const QString &newLanguage)
updateProblemsButton();
ui->listOptionsBtn->setMenu(modListContextMenu());
+
+ ui->openFolderMenu->setMenu(openFolderMenu());
+
}
void MainWindow::writeDataToFile(QFile &file, const QString &directory, const DirectoryEntry &directoryEntry)
@@ -3605,7 +3828,6 @@ void MainWindow::addAsExecutable()
binaryInfo.absoluteFilePath(),
arguments,
targetInfo.absolutePath(),
- ExecutableInfo::CloseMOStyle::DEFAULT_STAY,
QString(),
Executable::CustomExecutable);
refreshExecutablesList();
@@ -3650,7 +3872,7 @@ void MainWindow::hideFile()
if (QFile::rename(oldName, newName)) {
originModified(m_ContextItem->data(1, Qt::UserRole + 1).toInt());
- refreshDataTree();
+ refreshDataTreeKeepExpandedNodes();
} else {
reportError(tr("failed to rename \"%1\" to \"%2\"").arg(oldName).arg(QDir::toNativeSeparators(newName)));
}
@@ -3674,7 +3896,7 @@ void MainWindow::unhideFile()
}
if (QFile::rename(oldName, newName)) {
originModified(m_ContextItem->data(1, Qt::UserRole + 1).toInt());
- refreshDataTree();
+ refreshDataTreeKeepExpandedNodes();
} else {
reportError(tr("failed to rename \"%1\" to \"%2\"").arg(QDir::toNativeSeparators(oldName)).arg(QDir::toNativeSeparators(newName)));
}
@@ -3716,8 +3938,8 @@ void MainWindow::previewDataFile()
};
addFunc(file->getOrigin());
- foreach (int i, file->getAlternatives()) {
- addFunc(i);
+ for (auto alt : file->getAlternatives()) {
+ addFunc(alt.first);
}
if (preview.numVariants() > 0) {
preview.exec();
@@ -3734,10 +3956,14 @@ void MainWindow::openDataFile()
QString arguments;
switch (getBinaryExecuteInfo(targetInfo, binaryInfo, arguments)) {
case 1: {
- m_OrganizerCore.spawnBinaryDirect(binaryInfo, arguments, m_OrganizerCore.currentProfile()->name(), targetInfo.absolutePath(), "");
+ 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);
+ ::ShellExecuteW(nullptr, L"open",
+ ToWString(targetInfo.absoluteFilePath()).c_str(),
+ nullptr, nullptr, SW_SHOWNORMAL);
} break;
default: {
// nop
@@ -3860,7 +4086,7 @@ void MainWindow::updateDownloadListDelegate()
connect(ui->downloadFilterEdit, SIGNAL(textChanged(QString)), this, SLOT(downloadFilterChanged(QString)));
ui->downloadView->setModel(sortProxy);
- ui->downloadView->sortByColumn(1, Qt::AscendingOrder);
+ ui->downloadView->sortByColumn(1, Qt::DescendingOrder);
ui->downloadView->header()->resizeSections(QHeaderView::Fixed);
connect(ui->downloadView->itemDelegate(), SIGNAL(installDownload(int)), &m_OrganizerCore, SLOT(installDownload(int)));
@@ -3875,8 +4101,7 @@ void MainWindow::updateDownloadListDelegate()
void MainWindow::modDetailsUpdated(bool)
{
- --m_ModsToUpdate;
- if (m_ModsToUpdate == 0) {
+ if (--m_ModsToUpdate == 0) {
statusBar()->hide();
m_ModListSortProxy->setCategoryFilter(boost::assign::list_of(CategoryFactory::CATEGORY_SPECIAL_UPDATEAVAILABLE));
for (int i = 0; i < ui->categoriesList->topLevelItemCount(); ++i) {
@@ -3893,7 +4118,7 @@ void MainWindow::modDetailsUpdated(bool)
void MainWindow::nxmUpdatesAvailable(const std::vector<int> &modIDs, QVariant userData, QVariant resultData, int)
{
- m_ModsToUpdate -= modIDs.size();
+ m_ModsToUpdate -= static_cast<int>(modIDs.size());
QVariantList resultList = resultData.toList();
for (auto iter = resultList.begin(); iter != resultList.end(); ++iter) {
QVariantMap result = iter->toMap();
@@ -3947,7 +4172,7 @@ void MainWindow::nxmDownloadURLs(int, int, QVariant, QVariant resultData, int)
QVariantList serverList = resultData.toList();
QList<ServerInfo> servers;
- foreach (const QVariant &server, serverList) {
+ for (const QVariant &server : serverList) {
QVariantMap serverInfo = server.toMap();
ServerInfo info;
info.name = serverInfo["Name"].toString();
@@ -4070,7 +4295,7 @@ void MainWindow::displayColumnSelection(const QPoint &pos)
// view/hide columns depending on check-state
int i = 1;
- foreach (const QAction *action, menu.actions()) {
+ for (const QAction *action : menu.actions()) {
const QWidgetAction *widgetAction = qobject_cast<const QWidgetAction*>(action);
if (widgetAction != nullptr) {
const QCheckBox *checkBox = qobject_cast<const QCheckBox*>(widgetAction->defaultWidget());
@@ -4082,26 +4307,6 @@ 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::bsaList_itemMoved()
-{
- m_ArchiveListWriter.write();
- m_CheckBSATimer.start(500);
-}
-
-
void MainWindow::on_bsaList_itemChanged(QTreeWidgetItem*, int)
{
m_ArchiveListWriter.write();
@@ -4117,6 +4322,17 @@ void MainWindow::on_actionProblems_triggered()
}
}
+void MainWindow::on_actionChange_Game_triggered()
+{
+ if (QMessageBox::question(this, tr("Are you sure?"),
+ tr("This will restart MO, continue?"),
+ QMessageBox::Yes | QMessageBox::Cancel)
+ == QMessageBox::Yes) {
+ InstanceManager::instance().clearCurrentInstance();
+ qApp->exit(INT_MAX);
+ }
+}
+
void MainWindow::setCategoryListVisible(bool visible)
{
if (visible) {
@@ -4395,7 +4611,11 @@ void MainWindow::on_bossButton_clicked()
std::string reportURL;
std::string errorMessages;
- m_OrganizerCore.currentProfile()->writeModlistNow();
+ //m_OrganizerCore.currentProfile()->writeModlistNow();
+ m_OrganizerCore.savePluginList();
+ //Create a backup of the load orders w/ LOOT in name
+ //to make sure that any sorting is easily undo-able.
+ //Need to figure out how I want to do that.
bool success = false;
@@ -4408,27 +4628,28 @@ void MainWindow::on_bossButton_clicked()
dialog.show();
QString outPath = QDir::temp().absoluteFilePath("lootreport.json");
-
+
QStringList parameters;
- parameters << "--unattended"
- << "--stdout"
- << "--noreport"
- << "--game" << m_OrganizerCore.managedGame()->gameShortName()
+ parameters << "--game" << m_OrganizerCore.managedGame()->gameShortName()
<< "--gamePath" << QString("\"%1\"").arg(m_OrganizerCore.managedGame()->gameDirectory().absolutePath())
- << "--out" << outPath;
+ << "--pluginListPath" << QString("\"%1/loadorder.txt\"").arg(m_OrganizerCore.profilePath())
+ << "--out" << QString("\"%1\"").arg(outPath);
if (m_DidUpdateMasterList) {
parameters << "--skipUpdateMasterlist";
- } else {
- m_DidUpdateMasterList = true;
}
HANDLE stdOutWrite = INVALID_HANDLE_VALUE;
HANDLE stdOutRead = INVALID_HANDLE_VALUE;
createStdoutPipe(&stdOutRead, &stdOutWrite);
+ try {
+ m_OrganizerCore.prepareVFS();
+ } catch (const std::exception &e) {
+ QMessageBox::warning(qApp->activeWindow(), tr("Error"), e.what());
+ return;
+ }
+
HANDLE loot = startBinary(QFileInfo(qApp->applicationDirPath() + "/loot/lootcli.exe"),
parameters.join(" "),
- m_OrganizerCore.currentProfile()->name(),
- m_OrganizerCore.settings().logLevel(),
qApp->applicationDirPath() + "/loot",
true,
stdOutWrite);
@@ -4523,6 +4744,7 @@ void MainWindow::on_bossButton_clicked()
} catch (const std::exception &e) {
reportError(tr("failed to run loot: %1").arg(e.what()));
}
+
if (errorMessages.length() > 0) {
QMessageBox *warn = new QMessageBox(QMessageBox::Warning, tr("Errors occured"), errorMessages.c_str(), QMessageBox::Ok, this);
warn->setModal(false);
@@ -4530,20 +4752,17 @@ void MainWindow::on_bossButton_clicked()
}
if (success) {
- if (reportURL.length() > 0) {
+ m_DidUpdateMasterList = true;
+ /*if (reportURL.length() > 0) {
m_IntegratedBrowser.setWindowTitle("LOOT Report");
QString report(reportURL.c_str());
QStringList temp = report.split("?");
QUrl url = QUrl::fromLocalFile(temp.at(0));
if (temp.size() > 1) {
-#if QT_VERSION >= 0x050000
url.setQuery(temp.at(1).toUtf8());
-#else
- url.setEncodedQuery(temp.at(1).toUtf8());
-#endif
}
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.
@@ -4552,10 +4771,7 @@ void MainWindow::on_bossButton_clicked()
QFile::remove(m_OrganizerCore.currentProfile()->getLoadOrderFileName());
}
m_OrganizerCore.refreshESPList();
- if (m_OrganizerCore.managedGame()->loadOrderMechanism() == IPluginGame::LoadOrderMechanism::FileTime) {
- // the load order should have been retrieved from file time, now save it to our own format
- m_OrganizerCore.savePluginList();
- }
+ m_OrganizerCore.savePluginList();
}
}
@@ -4597,7 +4813,7 @@ QString MainWindow::queryRestore(const QString &filePath)
SelectionDialog dialog(tr("Choose backup to restore"), this);
QRegExp exp(pluginFileInfo.fileName() + PATTERN_BACKUP_REGEX);
QRegExp exp2(pluginFileInfo.fileName() + "\\.(.*)");
- foreach(const QFileInfo &info, files) {
+ for(const QFileInfo &info : files) {
if (exp.exactMatch(info.fileName())) {
QDateTime time = QDateTime::fromString(exp.cap(1), PATTERN_BACKUP_DATE);
dialog.addChoice(time.toString(), "", exp.cap(1));
@@ -4637,7 +4853,7 @@ void MainWindow::on_restoreButton_clicked()
void MainWindow::on_saveModsButton_clicked()
{
- m_OrganizerCore.currentProfile()->modlistWriter().writeImmediately(true);
+ m_OrganizerCore.currentProfile()->writeModlistNow(true);
QDateTime now = QDateTime::currentDateTime();
if (createBackup(m_OrganizerCore.currentProfile()->getModlistFileName(), now)) {
MessageDialog::showMessage(tr("Backup of modlist created"), this);
@@ -4686,12 +4902,7 @@ void MainWindow::on_categoriesOrBtn_toggled(bool checked)
void MainWindow::on_managedArchiveLabel_linkHovered(const QString&)
{
QToolTip::showText(QCursor::pos(),
- ui->managedArchiveLabel->toolTip());
-}
-
-void MainWindow::on_manageArchivesBox_toggled(bool)
-{
- m_OrganizerCore.refreshBSAList();
+ ui->managedArchiveLabel->toolTip());
}
void MainWindow::dragEnterEvent(QDragEnterEvent *event)
@@ -4781,6 +4992,31 @@ void MainWindow::dropLocalFile(const QUrl &url, const QString &outputDir, bool m
}
}
+bool MainWindow::registerWidgetState(const QString &name, QHeaderView *view, const char *oldSettingName) {
+ // register the view so it's geometry gets saved at exit
+ m_PersistedGeometry.push_back(std::make_pair(name, view));
+
+ // also, restore the geometry if it was saved before
+ QSettings &settings = m_OrganizerCore.settings().directInterface();
+
+ QString key = QString("geometry/%1").arg(name);
+ QByteArray data;
+
+ if ((oldSettingName != nullptr) && settings.contains(oldSettingName)) {
+ data = settings.value(oldSettingName).toByteArray();
+ settings.remove(oldSettingName);
+ } else if (settings.contains(key)) {
+ data = settings.value(key).toByteArray();
+ }
+
+ if (!data.isEmpty()) {
+ view->restoreState(data);
+ return true;
+ } else {
+ return false;
+ }
+}
+
void MainWindow::dropEvent(QDropEvent *event)
{
Qt::DropAction action = event->proposedAction();
@@ -4799,3 +5035,14 @@ void MainWindow::dropEvent(QDropEvent *event)
event->accept();
}
+
+void MainWindow::on_clickBlankButton_clicked()
+{
+ deselectFilters();
+}
+
+void MainWindow::on_clearFiltersButton_clicked()
+{
+ deselectFilters();
+}
+