From 7f4f4cafea5a196ddf824adf7c4e65cec5d44d88 Mon Sep 17 00:00:00 2001 From: Tannin Date: Tue, 17 Nov 2015 18:58:00 +0100 Subject: first work on interfacing with usvfs --- src/mainwindow.ui | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) (limited to 'src/mainwindow.ui') diff --git a/src/mainwindow.ui b/src/mainwindow.ui index ca93ea54..7d7eeca8 100644 --- a/src/mainwindow.ui +++ b/src/mainwindow.ui @@ -902,24 +902,14 @@ p, li { white-space: pre-wrap; } 6 - - - - - - - - true - - - + <html><head/><body><p>BSAs are bundles of game assets (textures, scripts, ...). By default, the engine loads these bundles in a separate step from loose files. MO can manage those archives to align their load order with that of loose files:</p><p>If archives are <span style=" font-weight:600;">managed</span>, their load order is specified by the priority of the corresponding mod (left pane), the same as the loose files. You can manually enable any BSA that has no corresponding plugin active.<br/></p><p>If archives are <span style=" font-weight:600;">not managed</span> their load order is specified by the priority of the corresponding plugin (right pane, plugins tab). You can then not manually enable BSAs where the plugin isn't active.</p><p>In either case you can not disable archives if there is a matching plugin, the game will load them no matter what.</p></body></html> - <html><head/><body><p>Have MO manage archives (<a href="#"><span style=" text-decoration: underline; color:#0000ff;">read more</span></a>)</p></body></html> + <html><head/><body><p>Archive order follows Plugin order.</p></body></html> true -- cgit v1.3.1 From fe8c3aaea58400425b9195bb670a1b4e8c9db10d Mon Sep 17 00:00:00 2001 From: Tannin Date: Mon, 23 Nov 2015 21:44:47 +0100 Subject: some fixes and removed obsolete code --- src/main.cpp | 2 +- src/mainwindow.cpp | 184 ++----------------------------------------------- src/mainwindow.h | 5 -- src/mainwindow.ui | 101 --------------------------- src/usvfsconnector.cpp | 8 ++- 5 files changed, 12 insertions(+), 288 deletions(-) (limited to 'src/mainwindow.ui') diff --git a/src/main.cpp b/src/main.cpp index 07d6fa19..7061a6e3 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -123,7 +123,7 @@ bool bootstrap() // cycle logfile removeOldFiles(qApp->property("dataPath").toString() + "/" + QString::fromStdWString(AppConfig::logPath()), - "ModOrganizer*.log", 5, QDir::Name); + "usvfs*.log", 5, QDir::Name); createAndMakeWritable(AppConfig::profilesPath()); createAndMakeWritable(AppConfig::modsPath()); diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index e34d8b03..71013c3c 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -186,6 +186,7 @@ MainWindow::MainWindow(const QString &exeName m_RefreshProgress->setVisible(false); statusBar()->addWidget(m_RefreshProgress, 1000); statusBar()->clearMessage(); + statusBar()->hide(); ui->actionEndorseMO->setVisible(false); @@ -233,8 +234,6 @@ MainWindow::MainWindow(const QString &exeName } ui->espList->installEventFilter(m_OrganizerCore.pluginList()); - ui->bsaList->setLocalMoveOnly(true); - ui->splitter->setStretchFactor(0, 3); ui->splitter->setStretchFactor(1, 2); @@ -302,9 +301,6 @@ MainWindow::MainWindow(const QString &exeName connect(this, SIGNAL(styleChanged(QString)), this, SLOT(updateStyle(QString))); - m_CheckBSATimer.setSingleShot(true); - connect(&m_CheckBSATimer, SIGNAL(timeout()), this, SLOT(checkBSAList())); - m_UpdateProblemsTimer.setSingleShot(true); connect(&m_UpdateProblemsTimer, SIGNAL(timeout()), this, SLOT(updateProblemsButton())); @@ -1317,157 +1313,6 @@ static QStringList toStringList(InputIterator current, InputIterator end) return result; } -void MainWindow::updateBSAList(const QStringList &defaultArchives, const QStringList &activeArchives) -{ - 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> items; - - IPluginGame *gamePlugin = qApp->property("managed_game").value(); - BSAInvalidation *invalidation = gamePlugin->feature(); - std::vector files = m_OrganizerCore.directoryStructure()->getFiles(); - - QStringList plugins = m_OrganizerCore.findFiles("", [] (const QString &fileName) -> bool { - return fileName.endsWith(".esp", Qt::CaseInsensitive) - || fileName.endsWith(".esm", 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)) { - return true; - } - } - return false; - }; - - for (FileEntry::Ptr current : files) { - QFileInfo fileInfo(ToQString(current->getName().c_str())); - - if (fileInfo.suffix().toLower() == "bsa") { - int index = activeArchives.indexOf(fileInfo.fileName()); - if (index == -1) { - index = 0xFFFF; - } else { - index += 2; - } - - if ((invalidation != nullptr) && invalidation->isInvalidationBSA(fileInfo.fileName())) { - index = 1; - } - - int originId = current->getOrigin(); - FilesOrigin &origin = m_OrganizerCore.directoryStructure()->getOriginByID(originId); - - 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->setCheckState(0, (index != -1) ? Qt::Checked : Qt::Unchecked); - newItem->setData(0, Qt::UserRole, false); - if (m_OrganizerCore.settings().forceEnableCoreFiles() - && defaultArchives.contains(fileInfo.fileName())) { - newItem->setCheckState(0, Qt::Checked); - newItem->setDisabled(true); - newItem->setData(0, Qt::UserRole, true); - } else if (fileInfo.fileName().compare("update.bsa", Qt::CaseInsensitive) == 0) { - newItem->setCheckState(0, Qt::Checked); - newItem->setDisabled(true); - } else if (hasAssociatedPlugin(fileInfo.fileName())) { - newItem->setCheckState(0, Qt::Checked); - 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) { - int originID = iter->second->data(1, Qt::UserRole).toInt(); - - FilesOrigin origin = m_OrganizerCore.directoryStructure()->getOriginByID(originID); - QString modName("data"); - unsigned int modIndex = ModInfo::getIndex(ToQString(origin.getName())); - if (modIndex != UINT_MAX) { - ModInfo::Ptr modInfo = ModInfo::getByIndex(modIndex); - modName = modInfo->name(); - } - QList items = ui->bsaList->findItems(modName, Qt::MatchFixedString); - QTreeWidgetItem *subItem = nullptr; - if (items.length() > 0) { - subItem = items.at(0); - } else { - subItem = new QTreeWidgetItem(QStringList(modName)); - subItem->setFlags(subItem->flags() & ~Qt::ItemIsDragEnabled); - ui->bsaList->addTopLevelItem(subItem); - } - subItem->addChild(iter->second); - subItem->setExpanded(true); - } - - checkBSAList(); -} - - -void MainWindow::checkBSAList() -{ - DataArchives *archives = m_OrganizerCore.managedGame()->feature(); - - if (archives != nullptr) { - ui->bsaList->blockSignals(true); - ON_BLOCK_EXIT([&] () { ui->bsaList->blockSignals(false); }); - - QStringList defaultArchives = archives->archives(m_OrganizerCore.currentProfile()); - - bool warning = false; - - for (int i = 0; i < ui->bsaList->topLevelItemCount(); ++i) { - bool modWarning = false; - QTreeWidgetItem *tlItem = ui->bsaList->topLevelItem(i); - for (int j = 0; j < tlItem->childCount(); ++j) { - QTreeWidgetItem *item = tlItem->child(j); - QString filename = item->text(0); - item->setIcon(0, QIcon()); - item->setToolTip(0, QString()); - - if (item->checkState(0) == Qt::Unchecked) { - if (defaultArchives.contains(filename)) { - item->setIcon(0, QIcon(":/MO/gui/warning")); - item->setToolTip(0, tr("This bsa is enabled in the ini file so it may be required!")); - modWarning = true; - } - } - } - if (modWarning) { - ui->bsaList->expandItem(ui->bsaList->topLevelItem(i)); - warning = true; - } - } - - if (warning) { - ui->tabWidget->setTabIcon(1, QIcon(":/MO/gui/warning")); - } else { - ui->tabWidget->setTabIcon(1, QIcon()); - } - } -} - - void MainWindow::saveModMetas() { for (unsigned int i = 0; i < ModInfo::getNumMods(); ++i) { @@ -1476,7 +1321,6 @@ void MainWindow::saveModMetas() } } - void MainWindow::fixCategories() { for (unsigned int i = 0; i < ModInfo::getNumMods(); ++i) { @@ -1856,8 +1700,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); @@ -3815,8 +3661,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) { @@ -4022,19 +3867,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::on_actionProblems_triggered() { ProblemsDialog problems(m_PluginContainer.plugins(), this); @@ -4610,12 +4442,6 @@ void MainWindow::on_categoriesOrBtn_toggled(bool checked) } } -void MainWindow::on_managedArchiveLabel_linkHovered(const QString&) -{ - QToolTip::showText(QCursor::pos(), - ui->managedArchiveLabel->toolTip()); -} - void MainWindow::dragEnterEvent(QDragEnterEvent *event) { //Accept copy or move drags to the download window. Link drags are not diff --git a/src/mainwindow.h b/src/mainwindow.h index 279c8922..44f46f4b 100644 --- a/src/mainwindow.h +++ b/src/mainwindow.h @@ -88,7 +88,6 @@ public: virtual bool unlockClicked() override; bool addProfile(); - void updateBSAList(const QStringList &defaultArchives, const QStringList &activeArchives); void refreshDataTree(); void refreshSaveList(); @@ -439,8 +438,6 @@ private slots: void startExeAction(); - void checkBSAList(); - void updateProblemsButton(); void saveModMetas(); @@ -494,7 +491,6 @@ private slots: // ui slots void on_actionUpdate_triggered(); void on_actionEndorseMO_triggered(); - void on_bsaList_customContextMenuRequested(const QPoint &pos); void on_btnRefreshData_clicked(); void on_categoriesList_customContextMenuRequested(const QPoint &pos); void on_conflictsCheckBox_toggled(bool checked); @@ -522,7 +518,6 @@ private slots: // ui slots void on_actionCopy_Log_to_Clipboard_triggered(); void on_categoriesAndBtn_toggled(bool checked); void on_categoriesOrBtn_toggled(bool checked); - void on_managedArchiveLabel_linkHovered(const QString &link); }; diff --git a/src/mainwindow.ui b/src/mainwindow.ui index 7d7eeca8..02319bee 100644 --- a/src/mainwindow.ui +++ b/src/mainwindow.ui @@ -884,102 +884,6 @@ p, li { white-space: pre-wrap; } - - - Archives - - - - 6 - - - 6 - - - 6 - - - 6 - - - - - - - <html><head/><body><p>BSAs are bundles of game assets (textures, scripts, ...). By default, the engine loads these bundles in a separate step from loose files. MO can manage those archives to align their load order with that of loose files:</p><p>If archives are <span style=" font-weight:600;">managed</span>, their load order is specified by the priority of the corresponding mod (left pane), the same as the loose files. You can manually enable any BSA that has no corresponding plugin active.<br/></p><p>If archives are <span style=" font-weight:600;">not managed</span> their load order is specified by the priority of the corresponding plugin (right pane, plugins tab). You can then not manually enable BSAs where the plugin isn't active.</p><p>In either case you can not disable archives if there is a matching plugin, the game will load them no matter what.</p></body></html> - - - <html><head/><body><p>Archive order follows Plugin order.</p></body></html> - - - true - - - - - - - - - Qt::CustomContextMenu - - - List of available BS Archives. Archives not checked here are not managed by MO and ignore installation order. - - - BSA files are archives (comparable to .zip files) that contain data assets (meshes, textures, ...) to be used by the game. As such they "compete" with loose files in your data directory over which is loaded. -By default, BSAs that share their base name with an enabled ESP (i.e. plugin.esp and plugin.bsa) are automatically loaded and will have precedence over all loose files, the installation order you set up to the left is then ignored! - -BSAs checked here are loaded in such a way that your installation order is obeyed properly. - - - QAbstractItemView::NoEditTriggers - - - true - - - false - - - false - - - QAbstractItemView::DragDrop - - - Qt::MoveAction - - - QAbstractItemView::SingleSelection - - - QAbstractItemView::SelectRows - - - 20 - - - true - - - 1 - - - false - - - 200 - - - - File - - - - - - Data @@ -1477,11 +1381,6 @@ Right now this has very limited functionality QTreeView
modlistview.h
- - MOBase::SortableTreeWidget - QTreeWidget -
sortabletreewidget.h
-
diff --git a/src/usvfsconnector.cpp b/src/usvfsconnector.cpp index 62145475..a29d806e 100644 --- a/src/usvfsconnector.cpp +++ b/src/usvfsconnector.cpp @@ -22,6 +22,7 @@ along with Mod Organizer. If not, see . #include #include #include +#include #include @@ -53,10 +54,13 @@ extern "C" DLLEXPORT void __cdecl InitHooks(LPVOID userData, size_t userDataSize LogWorker::LogWorker() : m_Buffer(1024, '\0') , m_QuitRequested(false) - , m_LogFile(qApp->property("dataPath").toString() + "/logs/usvfs.log") + , m_LogFile(qApp->property("dataPath").toString() + + QString("/logs/usvfs-%1.log").arg( + QDateTime::currentDateTimeUtc().toString("yyyy-MM-dd_hh-mm-ss"))) { m_LogFile.open(QIODevice::WriteOnly); - qDebug("usvfs log messages are written to %s", qPrintable(m_LogFile.fileName())); + qDebug("usvfs log messages are written to %s", + qPrintable(m_LogFile.fileName())); } LogWorker::~LogWorker() -- cgit v1.3.1 From b085aeea0e9f3b2c35e08a325759a57fec4cbd28 Mon Sep 17 00:00:00 2001 From: Tannin Date: Tue, 9 Feb 2016 20:51:56 +0100 Subject: changed focus policy on grouping selection to prevent accidentally changing the grouping mode --- src/mainwindow.ui | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src/mainwindow.ui') diff --git a/src/mainwindow.ui b/src/mainwindow.ui index 02319bee..7d23cde5 100644 --- a/src/mainwindow.ui +++ b/src/mainwindow.ui @@ -475,6 +475,9 @@ p, li { white-space: pre-wrap; }
+ + Qt::ClickFocus + No groups -- cgit v1.3.1 From eb97c46ed68a965d6ddf44fa6741fa929fd7d278 Mon Sep 17 00:00:00 2001 From: Tannin Date: Sat, 7 May 2016 00:03:38 +0200 Subject: cleanup --- src/CMakeLists.txt | 12 ++++- src/aboutdialog.cpp | 5 ++- src/aboutdialog.ui | 50 +++++++++++++++++++-- src/categories.cpp | 2 +- src/directoryrefresher.cpp | 2 +- src/downloadmanager.cpp | 47 +++++++++---------- src/editexecutablesdialog.cpp | 8 ++-- src/editexecutablesdialog.ui | 4 +- src/executableslist.h | 3 +- src/installationmanager.cpp | 3 +- src/logbuffer.cpp | 22 +++++---- src/main.cpp | 6 +-- src/mainwindow.cpp | 14 +++--- src/mainwindow.ui | 40 +++++++++++------ src/modflagicondelegate.cpp | 6 +-- src/modinfo.cpp | 6 +-- src/modinfodialog.cpp | 10 +++-- src/nexusinterface.cpp | 11 ++--- src/organizercore.cpp | 12 +++-- src/persistentcookiejar.cpp | 2 +- src/plugincontainer.cpp | 4 +- src/profile.cpp | 17 +++---- src/profile.h | 2 +- src/profilesdialog.cpp | 102 ++++++++++++++++++++---------------------- src/profilesdialog.ui | 4 +- src/shared/util.cpp | 8 +++- src/usvfsconnector.cpp | 9 +++- src/version.rc | 4 +- 28 files changed, 248 insertions(+), 167 deletions(-) (limited to 'src/mainwindow.ui') diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 02c63ad2..a8b43c59 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -272,14 +272,22 @@ INCLUDE_DIRECTORIES(${project_path}/uibase/src ${project_path}/archive/src ${project_path}/../usvfs/usvfs ${project_path}/game_gamebryo/src - ${project_path}/game_features/src) + ${project_path}/game_features/src + ${project_path}/githubpp/src) INCLUDE_DIRECTORIES(shared ${ZLIB_INCLUDE_DIRS}) LINK_DIRECTORIES(${lib_path} ${project_path}/../zlib/lib) -ADD_DEFINITIONS(-D_UNICODE -DUNICODE -DNOMINMAX -D_CRT_SECURE_NO_WARNINGS) +EXECUTE_PROCESS( + COMMAND git log -1 --format=%h + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} + OUTPUT_VARIABLE GIT_COMMIT_HASH + OUTPUT_STRIP_TRAILING_WHITESPACE +) + +ADD_DEFINITIONS(-D_UNICODE -DUNICODE -DNOMINMAX -D_CRT_SECURE_NO_WARNINGS -DGITID="${GIT_COMMIT_HASH}") IF("${CMAKE_SIZEOF_VOID_P}" EQUAL "8") SET(usvfs_name usvfs_x64) diff --git a/src/aboutdialog.cpp b/src/aboutdialog.cpp index 3657a10d..ed57a217 100644 --- a/src/aboutdialog.cpp +++ b/src/aboutdialog.cpp @@ -54,10 +54,13 @@ AboutDialog::AboutDialog(const QString &version, QWidget *parent) addLicense("RRZE Icon Set", LICENSE_CCBY3); addLicense("Icons by Lorc, Delapouite and sbed available on http://game-icons.net", LICENSE_CCBY3); addLicense("Castle Core", LICENSE_APACHE2); + addLicense("LOOT", LICENSE_GPL3); ui->nameLabel->setText(QString("%1 %2").arg(ui->nameLabel->text()).arg(version)); -#ifdef HGID +#if defined(HGID) ui->revisionLabel->setText(ui->revisionLabel->text() + " " + HGID); +#elif defined(GITID) + ui->revisionLabel->setText(ui->revisionLabel->text() + " " + GITID); #else ui->revisionLabel->setText(ui->revisionLabel->text() + " unknown"); #endif diff --git a/src/aboutdialog.ui b/src/aboutdialog.ui index ea5d2141..8d560f2b 100644 --- a/src/aboutdialog.ui +++ b/src/aboutdialog.ui @@ -6,8 +6,8 @@ 0 0 - 508 - 335 + 746 + 369 @@ -18,13 +18,50 @@ + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + 0 + 0 + + + + + 250 + 250 + + + + + 250 + 250 + + - :/MO/gui/mo_icon.ico + :/MO/gui/splash + + + true + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter @@ -83,7 +120,7 @@ - Copyright 2011-2015 Sebastian Herbord + Copyright 2011-2016 Sebastian Herbord @@ -265,6 +302,11 @@ thosrtanner + + + ogrotten + + diff --git a/src/categories.cpp b/src/categories.cpp index 7539d3fd..50ba5271 100644 --- a/src/categories.cpp +++ b/src/categories.cpp @@ -188,7 +188,7 @@ int CategoryFactory::addCategory(const QString &name, const std::vector &ne void CategoryFactory::addCategory(int id, const QString &name, const std::vector &nexusIDs, int parentID) { - int index = m_Categories.size(); + int index = static_cast(m_Categories.size()); m_Categories.push_back(Category(index, id, name, nexusIDs, parentID)); for (int nexusID : nexusIDs) { m_NexusMap[nexusID] = index; diff --git a/src/directoryrefresher.cpp b/src/directoryrefresher.cpp index 4eac4103..0a8b82be 100644 --- a/src/directoryrefresher.cpp +++ b/src/directoryrefresher.cpp @@ -159,7 +159,7 @@ void DirectoryRefresher::refresh() } catch (const std::exception &e) { emit error(tr("failed to read mod (%1): %2").arg(iter->modName, e.what())); } - emit progress((i * 100) / m_Mods.size() + 1); + emit progress((i * 100) / static_cast(m_Mods.size()) + 1); } emit progress(100); diff --git a/src/downloadmanager.cpp b/src/downloadmanager.cpp index 6b4628cc..b92e171e 100644 --- a/src/downloadmanager.cpp +++ b/src/downloadmanager.cpp @@ -88,7 +88,8 @@ DownloadManager::DownloadInfo *DownloadManager::DownloadInfo::createFromMeta(con QString fileName = QFileInfo(filePath).fileName(); if (fileName.endsWith(UNFINISHED)) { - info->m_FileName = fileName.mid(0, fileName.length() - strlen(UNFINISHED)); + info->m_FileName = fileName.mid( + 0, fileName.length() - static_cast(strlen(UNFINISHED))); info->m_State = STATE_PAUSED; } else { info->m_FileName = fileName; @@ -471,7 +472,7 @@ void DownloadManager::addNXMDownload(const QString &url) void DownloadManager::removeFile(int index, bool deleteFile) { if (index >= m_ActiveDownloads.size()) { - throw MyException(tr("invalid index")); + throw MyException(tr("remove: invalid download index %1").arg(index)); } DownloadInfo *download = m_ActiveDownloads.at(index); @@ -538,7 +539,7 @@ void DownloadManager::refreshAlphabeticalTranslation() void DownloadManager::restoreDownload(int index) { if ((index < 0) || (index >= m_ActiveDownloads.size())) { - throw MyException(tr("invalid index")); + throw MyException(tr("restore: invalid download index: %1").arg(index)); } DownloadInfo *download = m_ActiveDownloads.at(index); @@ -571,7 +572,7 @@ void DownloadManager::removeDownload(int index, bool deleteFile) } } else { if (index >= m_ActiveDownloads.size()) { - reportError(tr("invalid index %1").arg(index)); + reportError(tr("remove: invalid download index %1").arg(index)); return; } @@ -589,7 +590,7 @@ void DownloadManager::removeDownload(int index, bool deleteFile) void DownloadManager::cancelDownload(int index) { if ((index < 0) || (index >= m_ActiveDownloads.size())) { - reportError(tr("invalid index %1").arg(index)); + reportError(tr("cancel: invalid download index %1").arg(index)); return; } @@ -602,7 +603,7 @@ void DownloadManager::cancelDownload(int index) void DownloadManager::pauseDownload(int index) { if ((index < 0) || (index >= m_ActiveDownloads.size())) { - reportError(tr("invalid index %1").arg(index)); + reportError(tr("pause: invalid download index %1").arg(index)); return; } @@ -622,7 +623,7 @@ void DownloadManager::pauseDownload(int index) void DownloadManager::resumeDownload(int index) { if ((index < 0) || (index >= m_ActiveDownloads.size())) { - reportError(tr("invalid index %1").arg(index)); + reportError(tr("resume: invalid download index %1").arg(index)); return; } DownloadInfo *info = m_ActiveDownloads[index]; @@ -633,7 +634,7 @@ void DownloadManager::resumeDownload(int index) void DownloadManager::resumeDownloadInt(int index) { if ((index < 0) || (index >= m_ActiveDownloads.size())) { - reportError(tr("invalid index %1").arg(index)); + reportError(tr("resume (int): invalid download index %1").arg(index)); return; } DownloadInfo *info = m_ActiveDownloads[index]; @@ -673,7 +674,7 @@ DownloadManager::DownloadInfo *DownloadManager::downloadInfoByID(unsigned int id void DownloadManager::queryInfo(int index) { if ((index < 0) || (index >= m_ActiveDownloads.size())) { - reportError(tr("invalid index %1").arg(index)); + reportError(tr("query: invalid download index %1").arg(index)); return; } DownloadInfo *info = m_ActiveDownloads[index]; @@ -721,7 +722,7 @@ int DownloadManager::numPendingDownloads() const std::pair DownloadManager::getPendingDownload(int index) { if ((index < 0) || (index >= m_PendingDownloads.size())) { - throw MyException(tr("invalid index")); + throw MyException(tr("get pending: invalid download index %1").arg(index)); } return m_PendingDownloads.at(index); @@ -730,7 +731,7 @@ std::pair DownloadManager::getPendingDownload(int index) QString DownloadManager::getFilePath(int index) const { if ((index < 0) || (index >= m_ActiveDownloads.size())) { - throw MyException(tr("invalid index")); + throw MyException(tr("get path: invalid download index %1").arg(index)); } return m_OutputDirectory + "/" + m_ActiveDownloads.at(index)->m_FileName; @@ -751,7 +752,7 @@ QString DownloadManager::getFileTypeString(int fileType) QString DownloadManager::getDisplayName(int index) const { if ((index < 0) || (index >= m_ActiveDownloads.size())) { - throw MyException(tr("invalid index")); + throw MyException(tr("display name: invalid download index %1").arg(index)); } DownloadInfo *info = m_ActiveDownloads.at(index); @@ -768,7 +769,7 @@ QString DownloadManager::getDisplayName(int index) const QString DownloadManager::getFileName(int index) const { if ((index < 0) || (index >= m_ActiveDownloads.size())) { - throw MyException(tr("invalid index")); + throw MyException(tr("file name: invalid download index %1").arg(index)); } return m_ActiveDownloads.at(index)->m_FileName; @@ -777,7 +778,7 @@ QString DownloadManager::getFileName(int index) const QDateTime DownloadManager::getFileTime(int index) const { if ((index < 0) || (index >= m_ActiveDownloads.size())) { - throw MyException(tr("invalid index")); + throw MyException(tr("file time: invalid download index %1").arg(index)); } DownloadInfo *info = m_ActiveDownloads.at(index); @@ -791,7 +792,7 @@ QDateTime DownloadManager::getFileTime(int index) const qint64 DownloadManager::getFileSize(int index) const { if ((index < 0) || (index >= m_ActiveDownloads.size())) { - throw MyException(tr("invalid index")); + throw MyException(tr("file size: invalid download index %1").arg(index)); } return m_ActiveDownloads.at(index)->m_TotalSize; @@ -801,7 +802,7 @@ qint64 DownloadManager::getFileSize(int index) const int DownloadManager::getProgress(int index) const { if ((index < 0) || (index >= m_ActiveDownloads.size())) { - throw MyException(tr("invalid index")); + throw MyException(tr("progress: invalid download index %1").arg(index)); } return m_ActiveDownloads.at(index)->m_Progress; @@ -811,7 +812,7 @@ int DownloadManager::getProgress(int index) const DownloadManager::DownloadState DownloadManager::getState(int index) const { if ((index < 0) || (index >= m_ActiveDownloads.size())) { - throw MyException(tr("invalid index")); + throw MyException(tr("state: invalid download index %1").arg(index)); } return m_ActiveDownloads.at(index)->m_State; @@ -821,7 +822,7 @@ DownloadManager::DownloadState DownloadManager::getState(int index) const bool DownloadManager::isInfoIncomplete(int index) const { if ((index < 0) || (index >= m_ActiveDownloads.size())) { - throw MyException(tr("invalid index")); + throw MyException(tr("infocomplete: invalid download index %1").arg(index)); } DownloadInfo *info = m_ActiveDownloads.at(index); @@ -836,7 +837,7 @@ bool DownloadManager::isInfoIncomplete(int index) const int DownloadManager::getModID(int index) const { if ((index < 0) || (index >= m_ActiveDownloads.size())) { - throw MyException(tr("invalid index")); + throw MyException(tr("mod id: invalid download index %1").arg(index)); } return m_ActiveDownloads.at(index)->m_FileInfo->modID; } @@ -844,7 +845,7 @@ int DownloadManager::getModID(int index) const bool DownloadManager::isHidden(int index) const { if ((index < 0) || (index >= m_ActiveDownloads.size())) { - throw MyException(tr("invalid index")); + throw MyException(tr("ishidden: invalid download index %1").arg(index)); } return m_ActiveDownloads.at(index)->m_Hidden; } @@ -853,7 +854,7 @@ bool DownloadManager::isHidden(int index) const const ModRepositoryFileInfo *DownloadManager::getFileInfo(int index) const { if ((index < 0) || (index >= m_ActiveDownloads.size())) { - throw MyException(tr("invalid index")); + throw MyException(tr("file info: invalid download index %1").arg(index)); } return m_ActiveDownloads.at(index)->m_FileInfo; @@ -863,7 +864,7 @@ const ModRepositoryFileInfo *DownloadManager::getFileInfo(int index) const void DownloadManager::markInstalled(int index) { if ((index < 0) || (index >= m_ActiveDownloads.size())) { - throw MyException(tr("invalid index")); + throw MyException(tr("mark installed: invalid download index %1").arg(index)); } DownloadInfo *info = m_ActiveDownloads.at(index); @@ -878,7 +879,7 @@ void DownloadManager::markInstalled(int index) void DownloadManager::markUninstalled(int index) { if ((index < 0) || (index >= m_ActiveDownloads.size())) { - throw MyException(tr("invalid index")); + throw MyException(tr("mark uninstalled: invalid download index %1").arg(index)); } DownloadInfo *info = m_ActiveDownloads.at(index); diff --git a/src/editexecutablesdialog.cpp b/src/editexecutablesdialog.cpp index 1b2d5a48..05a7603d 100644 --- a/src/editexecutablesdialog.cpp +++ b/src/editexecutablesdialog.cpp @@ -126,15 +126,17 @@ void EditExecutablesDialog::on_addButton_clicked() void EditExecutablesDialog::on_browseButton_clicked() { - QString binaryName = FileDialogMemory::getOpenFileName("editExecutableBinary", this, - tr("Select a binary"), QString(), tr("Executable (%1)").arg("*.exe *.bat *.jar")); + QString binaryName = FileDialogMemory::getOpenFileName( + "editExecutableBinary", this, tr("Select a binary"), QString(), + tr("Executable (%1)").arg("*.exe *.bat *.jar")); if (binaryName.endsWith(".jar", Qt::CaseInsensitive)) { QString binaryPath; { // try to find java automatically std::wstring binaryNameW = ToWString(binaryName); WCHAR buffer[MAX_PATH]; - if (::FindExecutableW(binaryNameW.c_str(), nullptr, buffer) > (HINSTANCE)32) { + if (::FindExecutableW(binaryNameW.c_str(), nullptr, buffer) + > reinterpret_cast(32)) { DWORD binaryType = 0UL; if (!::GetBinaryTypeW(binaryNameW.c_str(), &binaryType)) { qDebug("failed to determine binary type of \"%ls\": %lu", binaryNameW.c_str(), ::GetLastError()); diff --git a/src/editexecutablesdialog.ui b/src/editexecutablesdialog.ui index a2aad19a..2640bb15 100644 --- a/src/editexecutablesdialog.ui +++ b/src/editexecutablesdialog.ui @@ -6,8 +6,8 @@ 0 0 - 384 - 446 + 426 + 460 diff --git a/src/executableslist.h b/src/executableslist.h index eb7d2d6f..0534c09e 100644 --- a/src/executableslist.h +++ b/src/executableslist.h @@ -133,7 +133,8 @@ public: const QString &steamAppID, Executable::Flags flags) { - updateExecutable(title, executableName, arguments, workingDirectory, steamAppID, Executable::AllFlags, flags); + updateExecutable(title, executableName, arguments, workingDirectory, + steamAppID, Executable::AllFlags, flags); } /** diff --git a/src/installationmanager.cpp b/src/installationmanager.cpp index 8ab27124..bf5ee91a 100644 --- a/src/installationmanager.cpp +++ b/src/installationmanager.cpp @@ -346,7 +346,8 @@ DirectoryTree *InstallationManager::createFilesTree() // to uncheck all files in a directory while keeping the dir checked. Those directories are // currently not installed. DirectoryTree::Node *newNode = new DirectoryTree::Node; - newNode->setData(DirectoryTreeInformation(*componentIter, i)); + newNode->setData( + DirectoryTreeInformation(*componentIter, static_cast(i))); currentNode->addNode(newNode, false); currentNode = newNode; } else { diff --git a/src/logbuffer.cpp b/src/logbuffer.cpp index 8207dcbb..522ce3c8 100644 --- a/src/logbuffer.cpp +++ b/src/logbuffer.cpp @@ -53,13 +53,15 @@ void LogBuffer::logMessage(QtMsgType type, const QString &message) if (type >= m_MinMsgType) { Message msg = {type, QTime::currentTime(), message}; if (m_NumMessages < m_Messages.size()) { - beginInsertRows(QModelIndex(), m_NumMessages, m_NumMessages + 1); + beginInsertRows(QModelIndex(), static_cast(m_NumMessages), + static_cast(m_NumMessages) + 1); } m_Messages.at(m_NumMessages % m_Messages.size()) = msg; if (m_NumMessages < m_Messages.size()) { endInsertRows(); } else { - emit dataChanged(createIndex(0, 0), createIndex(m_Messages.size(), 0)); + emit dataChanged(createIndex(0, 0), + createIndex(static_cast(m_Messages.size()), 0)); } ++m_NumMessages; if (type >= QtCriticalMsg) { @@ -84,9 +86,10 @@ void LogBuffer::write() const return; } - unsigned int i = (m_NumMessages > m_Messages.size()) - ? m_NumMessages - m_Messages.size() - : 0U; + unsigned int i + = (m_NumMessages > m_Messages.size()) + ? static_cast(m_NumMessages - m_Messages.size()) + : 0U; for (; i < m_NumMessages; ++i) { file.write(m_Messages.at(i % m_Messages.size()).toString().toUtf8()); file.write("\r\n"); @@ -165,7 +168,7 @@ int LogBuffer::rowCount(const QModelIndex &parent) const if (parent.isValid()) return 0; else - return std::min(m_NumMessages, m_Messages.size()); + return static_cast(std::min(m_NumMessages, m_Messages.size())); } int LogBuffer::columnCount(const QModelIndex &) const @@ -175,9 +178,10 @@ int LogBuffer::columnCount(const QModelIndex &) const QVariant LogBuffer::data(const QModelIndex &index, int role) const { - unsigned offset = m_NumMessages < m_Messages.size() - ? 0 - : m_NumMessages - m_Messages.size(); + unsigned int offset + = m_NumMessages < m_Messages.size() + ? 0 + : static_cast(m_NumMessages - m_Messages.size()); unsigned int msgIndex = (offset + index.row() + 1) % m_Messages.size(); switch (role) { case Qt::DisplayRole: { diff --git a/src/main.cpp b/src/main.cpp index eb3a7248..6db5a50e 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -161,9 +161,9 @@ static LONG WINAPI MyUnhandledExceptionFilter(struct _EXCEPTION_POINTERS *except if (dbgDLL) { FuncMiniDumpWriteDump funcDump = (FuncMiniDumpWriteDump)::GetProcAddress(dbgDLL, "MiniDumpWriteDump"); if (funcDump) { - wchar_t exeNameBuffer[MAX_PATH]; - ::GetModuleFileNameW(nullptr, exeNameBuffer, MAX_PATH); - QString dumpName = QString::fromWCharArray(exeNameBuffer) + ".dmp"; + QString dataPath = qApp->property("dataPath").toString(); + QString exeName = QFileInfo(qApp->applicationFilePath()).fileName(); + QString dumpName = dataPath + "/" + exeName + ".dmp"; if (QMessageBox::question(nullptr, QObject::tr("Woops"), QObject::tr("ModOrganizer has crashed! " diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 24391999..e174a17c 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -144,15 +144,10 @@ along with Mod Organizer. If not, see . #include #include -#include +#include #include - -#if QT_VERSION >= QT_VERSION_CHECK(5,0,0) #include -#else -#include -#endif #ifndef Q_MOC_RUN #include @@ -4198,7 +4193,12 @@ void MainWindow::on_bossButton_clicked() HANDLE stdOutWrite = INVALID_HANDLE_VALUE; HANDLE stdOutRead = INVALID_HANDLE_VALUE; createStdoutPipe(&stdOutRead, &stdOutWrite); - m_OrganizerCore.prepareVFS(); + 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(" "), diff --git a/src/mainwindow.ui b/src/mainwindow.ui index 7d23cde5..f504994a 100644 --- a/src/mainwindow.ui +++ b/src/mainwindow.ui @@ -45,7 +45,10 @@ Categories - + + + 0 + 3 @@ -92,25 +95,34 @@ - - - false + + + + 0 + 0 + + + + + 0 + 25 + - Click blank area to deselect + Clear + + + true - - - - - - false - - - false + + + + 0 + 0 + diff --git a/src/modflagicondelegate.cpp b/src/modflagicondelegate.cpp index d66c3ac5..5c4167ad 100644 --- a/src/modflagicondelegate.cpp +++ b/src/modflagicondelegate.cpp @@ -58,7 +58,7 @@ size_t ModFlagIconDelegate::getNumIcons(const QModelIndex &index) const if (modIdx < ModInfo::getNumMods()) { ModInfo::Ptr info = ModInfo::getByIndex(modIdx); std::vector flags = info->getFlags(); - int count = flags.size(); + size_t count = flags.size(); if (std::find_first_of(flags.begin(), flags.end(), m_ConflictFlags, m_ConflictFlags + 4) == flags.end()) { ++count; } @@ -71,11 +71,11 @@ size_t ModFlagIconDelegate::getNumIcons(const QModelIndex &index) const QSize ModFlagIconDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &modelIndex) const { - int count = getNumIcons(modelIndex); + size_t count = getNumIcons(modelIndex); unsigned int index = modelIndex.data(Qt::UserRole + 1).toInt(); QSize result; if (index < ModInfo::getNumMods()) { - result = QSize(count * 40, 20); + result = QSize(static_cast(count) * 40, 20); } else { result = QSize(1, 20); } diff --git a/src/modinfo.cpp b/src/modinfo.cpp index 5593b0f0..3c97ca85 100644 --- a/src/modinfo.cpp +++ b/src/modinfo.cpp @@ -112,7 +112,7 @@ void ModInfo::createFromOverwrite() unsigned int ModInfo::getNumMods() { QMutexLocker locker(&s_Mutex); - return s_Collection.size(); + return static_cast(s_Collection.size()); } @@ -121,7 +121,7 @@ ModInfo::Ptr ModInfo::getByIndex(unsigned int index) QMutexLocker locker(&s_Mutex); if (index >= s_Collection.size()) { - throw MyException(tr("invalid index %1").arg(index)); + throw MyException(tr("invalid mod index %1").arg(index)); } return s_Collection[index]; } @@ -150,7 +150,7 @@ bool ModInfo::removeMod(unsigned int index) QMutexLocker locker(&s_Mutex); if (index >= s_Collection.size()) { - throw MyException(tr("invalid index %1").arg(index)); + throw MyException(tr("remove: invalid mod index %1").arg(index)); } // update the indices first ModInfo::Ptr modInfo = s_Collection[index]; diff --git a/src/modinfodialog.cpp b/src/modinfodialog.cpp index feaac2d4..e1a2183c 100644 --- a/src/modinfodialog.cpp +++ b/src/modinfodialog.cpp @@ -351,14 +351,18 @@ void ModInfoDialog::refreshLists() void ModInfoDialog::addCategories(const CategoryFactory &factory, const std::set &enabledCategories, QTreeWidgetItem *root, int rootLevel) { - for (size_t i = 0; i < factory.numCategories(); ++i) { + for (int i = 0; i < static_cast(factory.numCategories()); ++i) { if (factory.getParentID(i) != rootLevel) { continue; } int categoryID = factory.getCategoryID(i); - QTreeWidgetItem *newItem = new QTreeWidgetItem(QStringList(factory.getCategoryName(i))); + QTreeWidgetItem *newItem + = new QTreeWidgetItem(QStringList(factory.getCategoryName(i))); newItem->setFlags(newItem->flags() | Qt::ItemIsUserCheckable); - newItem->setCheckState(0, enabledCategories.find(categoryID) != enabledCategories.end() ? Qt::Checked : Qt::Unchecked); + newItem->setCheckState(0, enabledCategories.find(categoryID) + != enabledCategories.end() + ? Qt::Checked + : Qt::Unchecked); newItem->setData(0, Qt::UserRole, categoryID); if (factory.hasChildren(i)) { addCategories(factory, enabledCategories, newItem, categoryID); diff --git a/src/nexusinterface.cpp b/src/nexusinterface.cpp index c689501f..4a44c067 100644 --- a/src/nexusinterface.cpp +++ b/src/nexusinterface.cpp @@ -206,11 +206,12 @@ void NexusInterface::interpretNexusFileName(const QString &fileName, QString &mo std::string candidate2 = result[2].str(); if (candidate2.length() != 0 && (candidate2.find_last_of("VvRr") == std::string::npos)) { // well, that second match might be an id too... - unsigned offset = strspn(candidate2.c_str(), "-_ "); + size_t offset = strspn(candidate2.c_str(), "-_ "); if (offset < candidate2.length() && query) { SelectionDialog selection(tr("Failed to guess mod id for \"%1\", please pick the correct one").arg(fileName)); QString r2Highlight(fileName); - r2Highlight.insert(result.position(2) + result.length(2), "* ").insert(result.position(2) + offset, " *"); + r2Highlight.insert(result.position(2) + result.length(2), "* ") + .insert(result.position(2) + static_cast(offset), " *"); QString r3Highlight(fileName); r3Highlight.insert(result.position(3) + result.length(3), "* ").insert(result.position(3), " *"); @@ -264,14 +265,14 @@ QString NexusInterface::getModURL(int modID) const return QString("%1/mods/%2").arg(getGameURL()).arg(modID); } -bool NexusInterface::isModURL(int modID, QString const &url) const +bool NexusInterface::isModURL(int modID, const QString &url) const { - if (url == getModURL(modID)) { + if (QUrl(url) == QUrl(getModURL(modID))) { return true; } //Try the alternate (old style) mod name QString alt = QString("%1/%2").arg(getOldModsURL()).arg(modID); - return alt == url; + return QUrl(alt) == QUrl(url); } int NexusInterface::requestDescription(int modID, QObject *receiver, QVariant userData, diff --git a/src/organizercore.cpp b/src/organizercore.cpp index f6196aa7..b1eaaef3 100644 --- a/src/organizercore.cpp +++ b/src/organizercore.cpp @@ -1345,8 +1345,6 @@ void OrganizerCore::refreshESPList() // clear list try { m_PluginList.refresh(m_CurrentProfile->name(), *m_DirectoryStructure, - m_CurrentProfile->getPluginsFileName(), - m_CurrentProfile->getLoadOrderFileName(), m_CurrentProfile->getLockedOrderFileName()); } catch (const std::exception &e) { reportError(tr("Failed to refresh list of esps: %1").arg(e.what())); @@ -1621,7 +1619,7 @@ void OrganizerCore::loginSuccessful(bool necessary) if (necessary) { MessageDialog::showMessage(tr("login successful"), qApp->activeWindow()); } - foreach (QString url, m_PendingDownloads) { + for (QString url : m_PendingDownloads) { downloadRequestedNXM(url); } m_PendingDownloads.clear(); @@ -1765,9 +1763,7 @@ void OrganizerCore::savePluginList() m_PostRefreshTasks.append([&]() { this->savePluginList(); }); return; } - m_PluginList.saveTo(m_CurrentProfile->getPluginsFileName(), - m_CurrentProfile->getLoadOrderFileName(), - m_CurrentProfile->getLockedOrderFileName(), + m_PluginList.saveTo(m_CurrentProfile->getLockedOrderFileName(), m_CurrentProfile->getDeleterFileName(), m_Settings.hideUncheckedPlugins()); m_PluginList.saveLoadOrder(*m_DirectoryStructure); @@ -1825,6 +1821,7 @@ std::vector OrganizerCore::fileMapping() return result; } + std::vector OrganizerCore::fileMapping( const QString &dataPath, const QString &relPath, const DirectoryEntry *base, const DirectoryEntry *directoryEntry, int createDestination) @@ -1841,8 +1838,9 @@ std::vector OrganizerCore::fileMapping( QString originPath = QString::fromStdWString(base->getOriginByID(origin).getPath()); QString fileName = QString::fromStdWString(current->getName()); +// QString fileName = ToQString(current->getName()); QString source = originPath + relPath + fileName; - QString target = dataPath + relPath + fileName; + QString target = dataPath + relPath + fileName; if (source != target) { result.push_back({source, target, false, false}); } diff --git a/src/persistentcookiejar.cpp b/src/persistentcookiejar.cpp index 6ca0de39..44537491 100644 --- a/src/persistentcookiejar.cpp +++ b/src/persistentcookiejar.cpp @@ -26,7 +26,7 @@ void PersistentCookieJar::save() { QList cookies = allCookies(); data << static_cast(cookies.size()); - foreach (const QNetworkCookie &cookie, allCookies()) { + for (const QNetworkCookie &cookie : allCookies()) { data << cookie.toRawForm(); } diff --git a/src/plugincontainer.cpp b/src/plugincontainer.cpp index a594f703..c4976d2c 100644 --- a/src/plugincontainer.cpp +++ b/src/plugincontainer.cpp @@ -200,7 +200,7 @@ void PluginContainer::unloadPlugins() bf::for_each(m_Plugins, clearPlugins()); - foreach (const boost::signals2::connection &connection, m_DiagnosisConnections) { + for (const boost::signals2::connection &connection : m_DiagnosisConnections) { connection.disconnect(); } m_DiagnosisConnections.clear(); @@ -283,7 +283,7 @@ void PluginContainer::loadPlugins() m_PluginLoaders.push_back(pluginLoader.release()); } else { m_FailedPlugins.push_back(pluginName); - qWarning("plugin \"%s\" failed to load", qPrintable(pluginName)); + qWarning("plugin \"%s\" failed to load (may be outdated)", qPrintable(pluginName)); } } } diff --git a/src/profile.cpp b/src/profile.cpp index 8cc60cc0..d71b5a0f 100644 --- a/src/profile.cpp +++ b/src/profile.cpp @@ -163,7 +163,7 @@ void Profile::writeModlistNow() return; } - for (int i = m_ModStatus.size() - 1; i >= 0; --i) { + for (int i = static_cast(m_ModStatus.size()) - 1; i >= 0; --i) { // the priority order was inverted on load so it has to be inverted again unsigned int index = m_ModIndexByPriority[i]; if (index != UINT_MAX) { @@ -311,7 +311,7 @@ void Profile::refreshModStatus() // invert priority order to match that of the pluginlist. Also // give priorities to mods not referenced in the profile for (size_t i = 0; i < m_ModStatus.size(); ++i) { - ModInfo::Ptr modInfo = ModInfo::getByIndex(i); + ModInfo::Ptr modInfo = ModInfo::getByIndex(static_cast(i)); if (modInfo->alwaysEnabled()) { m_ModStatus[i].m_Enabled = true; } @@ -340,7 +340,7 @@ void Profile::refreshModStatus() if (topInsert < 0) { int offset = topInsert * -1; for (size_t i = 0; i < m_ModStatus.size(); ++i) { - ModInfo::Ptr modInfo = ModInfo::getByIndex(i); + ModInfo::Ptr modInfo = ModInfo::getByIndex(static_cast(i)); if (modInfo->getFixedPriority() == INT_MAX) { continue; } @@ -636,11 +636,12 @@ bool Profile::enableLocalSaves(bool enable) m_Directory.mkdir("saves"); } } else { - QMessageBox::StandardButton res = QMessageBox::question(QApplication::activeModalWidget(), tr("Delete savegames?"), - tr("Do you want to delete local savegames? (If you select \"No\", the save games " - "will show up again if you re-enable local savegames)"), - QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel, - QMessageBox::Cancel); + QMessageBox::StandardButton res = QMessageBox::question( + QApplication::activeModalWidget(), tr("Delete savegames?"), + tr("Do you want to delete local savegames? (If you select \"No\", the " + "save games will show up again if you re-enable local savegames)"), + QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel, + QMessageBox::Cancel); if (res == QMessageBox::Yes) { shellDelete(QStringList(m_Directory.absoluteFilePath("saves"))); } else if (res == QMessageBox::No) { diff --git a/src/profile.h b/src/profile.h index ece23ef9..87dd91a5 100644 --- a/src/profile.h +++ b/src/profile.h @@ -174,7 +174,7 @@ public: /** * @return path to this profile **/ - QString absolutePath() const; + virtual QString absolutePath() const override; /** * @return path to this profile's save games diff --git a/src/profilesdialog.cpp b/src/profilesdialog.cpp index 1a47cf74..40f01f0e 100644 --- a/src/profilesdialog.cpp +++ b/src/profilesdialog.cpp @@ -66,17 +66,15 @@ ProfilesDialog::ProfilesDialog(const QString &profileName, MOBase::IPluginGame c profileIter.next(); QListWidgetItem *item = addItem(profileIter.filePath()); if (profileName == profileIter.fileName()) { - m_ProfilesList->setCurrentItem(item); + ui->profilesList->setCurrentItem(item); } } - QCheckBox *invalidationBox = findChild("invalidationBox"); - BSAInvalidation *invalidation = game->feature(); if (invalidation == nullptr) { - invalidationBox->setToolTip(tr("Archive invalidation isn't required for this game.")); - invalidationBox->setEnabled(false); + ui->invalidationBox->setToolTip(tr("Archive invalidation isn't required for this game.")); + ui->invalidationBox->setEnabled(false); } } @@ -89,13 +87,13 @@ void ProfilesDialog::showEvent(QShowEvent *event) { TutorableDialog::showEvent(event); - if (m_ProfilesList->count() == 0) { - QPoint pos = m_ProfilesList->mapToGlobal(QPoint(0, 0)); - pos.rx() += m_ProfilesList->width() / 2; - pos.ry() += (m_ProfilesList->height() / 2) - 20; + if (ui->profilesList->count() == 0) { + QPoint pos = ui->profilesList->mapToGlobal(QPoint(0, 0)); + pos.rx() += ui->profilesList->width() / 2; + pos.ry() += (ui->profilesList->height() / 2) - 20; QWhatsThis::showText(pos, QObject::tr("Before you can use ModOrganizer, you need to create at least one profile. " - "ATTENTION: Run the game at least once before creating a profile!"), m_ProfilesList); + "ATTENTION: Run the game at least once before creating a profile!"), ui->profilesList); } } @@ -108,7 +106,7 @@ void ProfilesDialog::on_closeButton_clicked() QListWidgetItem *ProfilesDialog::addItem(const QString &name) { QDir profileDir(name); - QListWidgetItem *newItem = new QListWidgetItem(profileDir.dirName(), m_ProfilesList); + QListWidgetItem *newItem = new QListWidgetItem(profileDir.dirName(), ui->profilesList); try { newItem->setData(Qt::UserRole, QVariant::fromValue(Profile::Ptr(new Profile(profileDir, m_Game)))); m_FailState = false; @@ -121,10 +119,9 @@ QListWidgetItem *ProfilesDialog::addItem(const QString &name) void ProfilesDialog::createProfile(const QString &name, bool useDefaultSettings) { try { - QListWidget *profilesList = findChild("profilesList"); - QListWidgetItem *newItem = new QListWidgetItem(name, profilesList); + QListWidgetItem *newItem = new QListWidgetItem(name, ui->profilesList); newItem->setData(Qt::UserRole, QVariant::fromValue(Profile::Ptr(new Profile(name, m_Game, useDefaultSettings)))); - profilesList->addItem(newItem); + ui->profilesList->addItem(newItem); m_FailState = false; } catch (const std::exception&) { m_FailState = true; @@ -135,10 +132,9 @@ void ProfilesDialog::createProfile(const QString &name, bool useDefaultSettings) void ProfilesDialog::createProfile(const QString &name, const Profile &reference) { try { - QListWidget *profilesList = findChild("profilesList"); - QListWidgetItem *newItem = new QListWidgetItem(name, profilesList); + QListWidgetItem *newItem = new QListWidgetItem(name, ui->profilesList); newItem->setData(Qt::UserRole, QVariant::fromValue(Profile::Ptr(Profile::createPtrFrom(name, reference, m_Game)))); - profilesList->addItem(newItem); + ui->profilesList->addItem(newItem); m_FailState = false; } catch (const std::exception&) { m_FailState = true; @@ -164,20 +160,23 @@ void ProfilesDialog::on_addProfileButton_clicked() void ProfilesDialog::on_copyProfileButton_clicked() { bool okClicked; - QString name = QInputDialog::getText(this, tr("Name"), tr("Please enter a name for the new profile"), QLineEdit::Normal, QString(), &okClicked); + QString name = QInputDialog::getText( + this, tr("Name"), tr("Please enter a name for the new profile"), + QLineEdit::Normal, QString(), &okClicked); fixDirectoryName(name); if (okClicked) { if (name.size() > 0) { - QListWidget *profilesList = findChild("profilesList"); - try { - const Profile::Ptr currentProfile = profilesList->currentItem()->data(Qt::UserRole).value(); + const Profile::Ptr currentProfile = ui->profilesList->currentItem() + ->data(Qt::UserRole) + .value(); createProfile(name, *currentProfile); } catch (const std::exception &e) { reportError(tr("failed to copy profile: %1").arg(e.what())); } } else { - QMessageBox::warning(this, tr("Invalid name"), tr("Invalid profile name")); + QMessageBox::warning(this, tr("Invalid name"), + tr("Invalid profile name")); } } } @@ -188,13 +187,11 @@ void ProfilesDialog::on_removeProfileButton_clicked() QMessageBox::Yes | QMessageBox::No); if (confirmBox.exec() == QMessageBox::Yes) { - QListWidget *profilesList = findChild("profilesList"); - - Profile::Ptr currentProfile = profilesList->currentItem()->data(Qt::UserRole).value(); + Profile::Ptr currentProfile = ui->profilesList->currentItem()->data(Qt::UserRole).value(); QString profilePath; if (currentProfile.get() == nullptr) { profilePath = Settings::instance().getProfileDirectory() - + "/" + profilesList->currentItem()->text(); + + "/" + ui->profilesList->currentItem()->text(); if (QMessageBox::question(this, tr("Profile broken"), tr("This profile you're about to delete seems to be broken or the path is invalid. " "I'm about to delete the following folder: \"%1\". Proceed?").arg(profilePath), QMessageBox::Yes | QMessageBox::No) == QMessageBox::No) { @@ -205,7 +202,7 @@ void ProfilesDialog::on_removeProfileButton_clicked() // we have to get rid of the it before deleting the directory profilePath = currentProfile->absolutePath(); } - QListWidgetItem* item = profilesList->takeItem(profilesList->currentRow()); + QListWidgetItem* item = ui->profilesList->takeItem(ui->profilesList->currentRow()); if (item != nullptr) { delete item; } @@ -270,53 +267,50 @@ void ProfilesDialog::on_invalidationBox_stateChanged(int state) void ProfilesDialog::on_profilesList_currentItemChanged(QListWidgetItem *current, QListWidgetItem*) { - QCheckBox *invalidationBox = findChild("invalidationBox"); - QCheckBox *localSavesBox = findChild("localSavesBox"); - QPushButton *copyButton = findChild("copyProfileButton"); - QPushButton *removeButton = findChild("removeProfileButton"); - QPushButton *transferButton = findChild("transferButton"); - QPushButton *renameButton = findChild("renameButton"); - if (current != nullptr) { if (!current->data(Qt::UserRole).isValid()) return; const Profile::Ptr currentProfile = current->data(Qt::UserRole).value(); try { bool invalidationSupported = false; - invalidationBox->blockSignals(true); - invalidationBox->setChecked(currentProfile->invalidationActive(&invalidationSupported)); - invalidationBox->setEnabled(invalidationSupported); - invalidationBox->blockSignals(false); + ui->invalidationBox->blockSignals(true); + ui->invalidationBox->setChecked(currentProfile->invalidationActive(&invalidationSupported)); + ui->invalidationBox->setEnabled(invalidationSupported); + ui->invalidationBox->blockSignals(false); bool localSaves = currentProfile->localSavesEnabled(); - transferButton->setEnabled(localSaves); + ui->transferButton->setEnabled(localSaves); // prevent the stateChanged-event for the saves-box from triggering, otherwise it may think local saves // were disabled and delete the files/rename the dir - localSavesBox->blockSignals(true); - localSavesBox->setChecked(localSaves); - localSavesBox->blockSignals(false); + ui->localSavesBox->blockSignals(true); + ui->localSavesBox->setChecked(localSaves); + ui->localSavesBox->blockSignals(false); + + ui->copyProfileButton->setEnabled(true); + ui->removeProfileButton->setEnabled(true); + ui->renameButton->setEnabled(true); - copyButton->setEnabled(true); - removeButton->setEnabled(true); - renameButton->setEnabled(true); + ui->localIniFilesBox->blockSignals(true); + ui->localIniFilesBox->setChecked(currentProfile->localSettingsEnabled()); + ui->localIniFilesBox->blockSignals(false); } catch (const std::exception& E) { reportError(tr("failed to determine if invalidation is active: %1").arg(E.what())); - copyButton->setEnabled(false); - removeButton->setEnabled(false); - renameButton->setEnabled(false); - invalidationBox->setChecked(false); + ui->copyProfileButton->setEnabled(false); + ui->removeProfileButton->setEnabled(false); + ui->renameButton->setEnabled(false); + ui->invalidationBox->setChecked(false); } } else { - invalidationBox->setChecked(false); - copyButton->setEnabled(false); - removeButton->setEnabled(false); - renameButton->setEnabled(false); + ui->invalidationBox->setChecked(false); + ui->copyProfileButton->setEnabled(false); + ui->removeProfileButton->setEnabled(false); + ui->renameButton->setEnabled(false); } } void ProfilesDialog::on_localSavesBox_stateChanged(int state) { - Profile::Ptr currentProfile = m_ProfilesList->currentItem()->data(Qt::UserRole).value(); + Profile::Ptr currentProfile = ui->profilesList->currentItem()->data(Qt::UserRole).value(); if (currentProfile->enableLocalSaves(state == Qt::Checked)) { ui->transferButton->setEnabled(state == Qt::Checked); diff --git a/src/profilesdialog.ui b/src/profilesdialog.ui index 0c952877..fe03f466 100644 --- a/src/profilesdialog.ui +++ b/src/profilesdialog.ui @@ -6,8 +6,8 @@ 0 0 - 471 - 318 + 482 + 332 diff --git a/src/shared/util.cpp b/src/shared/util.cpp index 3692aae1..5491a9e6 100644 --- a/src/shared/util.cpp +++ b/src/shared/util.cpp @@ -81,12 +81,16 @@ std::wstring ToWString(const std::string &source, bool utf8) if (!utf8) { codepage = AreFileApisANSI() ? GetACP() : GetOEMCP(); } - int sizeRequired = ::MultiByteToWideChar(codepage, 0, source.c_str(), source.length(), nullptr, 0); + int sizeRequired + = ::MultiByteToWideChar(codepage, 0, source.c_str(), + static_cast(source.length()), nullptr, 0); if (sizeRequired == 0) { throw windows_error("failed to convert string to wide character"); } result.resize(sizeRequired, L'\0'); - ::MultiByteToWideChar(codepage, 0, source.c_str(), source.length(), &result[0], sizeRequired); + ::MultiByteToWideChar(codepage, 0, source.c_str(), + static_cast(source.length()), &result[0], + sizeRequired); } return result; diff --git a/src/usvfsconnector.cpp b/src/usvfsconnector.cpp index db20a54f..bc818685 100644 --- a/src/usvfsconnector.cpp +++ b/src/usvfsconnector.cpp @@ -76,13 +76,16 @@ LogWorker::~LogWorker() void LogWorker::process() { + int noLogCycles = 0; while (!m_QuitRequested) { if (GetLogMessages(&m_Buffer[0], m_Buffer.size(), false)) { m_LogFile.write(m_Buffer.c_str()); m_LogFile.write("\n"); m_LogFile.flush(); + noLogCycles = 0; } else { - QThread::sleep(1); + QThread::msleep(std::min(40, noLogCycles) * 5); + ++noLogCycles; } } emit finished(); @@ -148,11 +151,13 @@ void UsvfsConnector::updateMapping(const MappingType &mapping) if (value % 10 == 0) { QCoreApplication::processEvents(); } + if (map.isDirectory) { VirtualLinkDirectoryStatic(map.source.toStdWString().c_str(), map.destination.toStdWString().c_str(), (map.createTarget ? LINKFLAG_CREATETARGET : 0) - | LINKFLAG_RECURSIVE); + | LINKFLAG_RECURSIVE + ); } else { VirtualLinkFile(map.source.toStdWString().c_str(), map.destination.toStdWString().c_str(), 0); diff --git a/src/version.rc b/src/version.rc index 028912d7..872c65d7 100644 --- a/src/version.rc +++ b/src/version.rc @@ -1,7 +1,7 @@ #include "Winver.h" -#define VER_FILEVERSION 2,0,4 -#define VER_FILEVERSION_STR "2,0,4alpha\0" +#define VER_FILEVERSION 2,0,5 +#define VER_FILEVERSION_STR "2.0.5beta\0" VS_VERSION_INFO VERSIONINFO FILEVERSION VER_FILEVERSION -- cgit v1.3.1 From bfbb19099839019c785dc81c83b07dadbd394168 Mon Sep 17 00:00:00 2001 From: Tannin Date: Fri, 27 May 2016 14:04:00 +0200 Subject: moved button to switch instance (and to portable mode) to the main window --- src/instancemanager.cpp | 100 +++++++++++++++++++++++----------------------- src/instancemanager.h | 15 +++---- src/main.cpp | 4 +- src/mainwindow.cpp | 12 ++++++ src/mainwindow.h | 3 ++ src/mainwindow.ui | 13 ++++++ src/nxmaccessmanager.cpp | 2 - src/resources.qrc | 3 +- src/resources/mo_icon.png | Bin 0 -> 1011 bytes src/resources/package.png | Bin 0 -> 1067 bytes src/settingsdialog.cpp | 12 ------ src/settingsdialog.h | 23 ++++------- src/settingsdialog.ui | 52 ++++++------------------ 13 files changed, 109 insertions(+), 130 deletions(-) create mode 100644 src/resources/mo_icon.png create mode 100644 src/resources/package.png (limited to 'src/mainwindow.ui') diff --git a/src/instancemanager.cpp b/src/instancemanager.cpp index c74f3c1a..f7b953ad 100644 --- a/src/instancemanager.cpp +++ b/src/instancemanager.cpp @@ -27,6 +27,7 @@ along with Mod Organizer. If not, see . #include #include #include +#include static const char COMPANY_NAME[] = "Tannin"; @@ -40,6 +41,11 @@ InstanceManager::InstanceManager() { } +InstanceManager &InstanceManager::instance() +{ + static InstanceManager s_Instance; + return s_Instance; +} QString InstanceManager::currentInstance() const { @@ -49,6 +55,7 @@ QString InstanceManager::currentInstance() const void InstanceManager::clearCurrentInstance() { setCurrentInstance(""); + m_Reset = true; } void InstanceManager::setCurrentInstance(const QString &name) @@ -81,26 +88,51 @@ QString InstanceManager::queryInstanceName() const QString InstanceManager::chooseInstance(const QStringList &instanceList) const { - SelectionDialog selection(QObject::tr("Choose Instance"), nullptr); + enum class Special : uint8_t { + NewInstance, + Portable + }; + + SelectionDialog selection( + QString("

%1


%2") + .arg(QObject::tr("Choose Instance")) + .arg(QObject::tr( + "Each Instance is a full set of MO data files (mods, " + "downloads, profiles, configuration, ...). Use multiple " + "instances for different games. If your MO folder is " + "writable, you can also store a single instance locally (called " + "a portable install).")), + nullptr); selection.disableCancel(); for (const QString &instance : instanceList) { selection.addChoice(instance, "", instance); } - selection.addChoice(QObject::tr("New"), + selection.addChoice(QIcon(":/MO/gui/add"), QObject::tr("New"), QObject::tr("Create a new instance."), - ""); + static_cast(Special::NewInstance)); + + if (QFileInfo(qApp->applicationDirPath()).isWritable()) { + selection.addChoice(QIcon(":/MO/gui/package"), QObject::tr("Portable"), + QObject::tr("Use MO folder for data."), + static_cast(Special::Portable)); + } + if (selection.exec() == QDialog::Rejected) { qDebug("rejected"); throw MOBase::MyException(QObject::tr("Canceled")); } - QString choice = selection.getChoiceData().toString(); + QVariant choice = selection.getChoiceData(); - if (choice.isEmpty()) { - return queryInstanceName(); + if (choice.type() == QVariant::String) { + return choice.toString(); } else { - return choice; + switch (choice.value()) { + case Special::NewInstance: return queryInstanceName(); + case Special::Portable: return QString(); + default: throw std::runtime_error("invalid selection"); + } } } @@ -125,27 +157,6 @@ bool InstanceManager::portableInstall() const } -InstanceManager::InstallationMode InstanceManager::queryInstallMode() const -{ - SelectionDialog selection(QObject::tr("Installation Mode"), nullptr); - selection.disableCancel(); - selection.addChoice(QObject::tr("Portable"), - QObject::tr("Everything in one directory, only one game per installation."), - 0); - selection.addChoice(QObject::tr("Regular"), - QObject::tr("Data in separate directory, multiple games supported."), - 1); - if (selection.exec() == QDialog::Rejected) { - throw MOBase::MyException(QObject::tr("Canceled")); - } - - switch (selection.getChoiceData().toInt()) { - case 0: return InstallationMode::PORTABLE; - default: return InstallationMode::REGULAR; - } -} - - void InstanceManager::createDataPath(const QString &dataPath) const { if (!QDir(dataPath).exists()) { @@ -166,31 +177,22 @@ void InstanceManager::createDataPath(const QString &dataPath) const QString InstanceManager::determineDataPath() { QString instanceId = currentInstance(); + if (instanceId.isEmpty() && portableInstall() && !m_Reset) { + // startup, apparently using portable mode before + return qApp->applicationDirPath(); + } + QString dataPath = QDir::fromNativeSeparators( QStandardPaths::writableLocation(QStandardPaths::DataLocation) + "/" + instanceId); - if ((instanceId.isEmpty() || !QFileInfo::exists(dataPath)) && !portableInstall()) { - // no portable install and no selected instance - - QStringList instanceList = instances(); - - if (instanceList.size() == 0) { - if (QFileInfo(qApp->applicationDirPath()).isWritable()) { - switch (queryInstallMode()) { - case InstallationMode::PORTABLE: { - instanceId = QString(); - } break; - case InstallationMode::REGULAR: { - instanceId = queryInstanceName(); - } break; - } - } else { - instanceId = queryInstanceName(); - } - } else { - // don't offer portable instance if we can't set one up. - instanceId = chooseInstance(instanceList); + + if (instanceId.isEmpty() || !QFileInfo::exists(dataPath)) { + instanceId = chooseInstance(instances()); + if (!instanceId.isEmpty()) { + dataPath = QDir::fromNativeSeparators( + QStandardPaths::writableLocation(QStandardPaths::DataLocation) + + "/" + instanceId); } } diff --git a/src/instancemanager.h b/src/instancemanager.h index 2e17d1c0..a0a5df09 100644 --- a/src/instancemanager.h +++ b/src/instancemanager.h @@ -27,25 +27,21 @@ along with Mod Organizer. If not, see . class InstanceManager { - enum class InstallationMode { - PORTABLE, - REGULAR - }; - public: - InstanceManager(); + static InstanceManager &instance(); QString determineDataPath(); - QStringList instances() const; void clearCurrentInstance(); private: + InstanceManager(); + QString currentInstance() const; QString instancePath() const; - bool portableInstall() const; + QStringList instances() const; void setCurrentInstance(const QString &name); @@ -53,10 +49,11 @@ private: QString chooseInstance(const QStringList &instanceList) const; void createDataPath(const QString &dataPath) const; - InstallationMode queryInstallMode() const; + bool portableInstall() const; private: QSettings m_AppSettings; + bool m_Reset {false}; }; diff --git a/src/main.cpp b/src/main.cpp index 6940e288..e289453c 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -630,13 +630,12 @@ int main(int argc, char *argv[]) QString dataPath; try { - dataPath = InstanceManager().determineDataPath(); + dataPath = InstanceManager::instance().determineDataPath(); } catch (const std::exception &e) { QMessageBox::critical(nullptr, QObject::tr("Failed to set up instance"), e.what()); return 1; } - application.setProperty("dataPath", dataPath); LogBuffer::init(100, QtDebugMsg, qApp->property("dataPath").toString() + "/logs/mo_interface.log"); @@ -647,7 +646,6 @@ int main(int argc, char *argv[]) } int result = runApplication(application, instance, splash); - if (result != INT_MAX) { return result; } diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index dcff139a..66c2b557 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -37,6 +37,7 @@ along with Mod Organizer. If not, see . #include "savegameinfo.h" #include "spawn.h" #include "versioninfo.h" +#include "instancemanager.h" #include "report.h" #include "modlist.h" @@ -3883,6 +3884,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) { diff --git a/src/mainwindow.h b/src/mainwindow.h index 43b2bede..3364bb37 100644 --- a/src/mainwindow.h +++ b/src/mainwindow.h @@ -183,6 +183,9 @@ protected: virtual void dragEnterEvent(QDragEnterEvent *event); virtual void dropEvent(QDropEvent *event); +private slots: + void on_actionChange_Game_triggered(); + private slots: void on_clickBlankButton_clicked(); diff --git a/src/mainwindow.ui b/src/mainwindow.ui index f504994a..e30a165d 100644 --- a/src/mainwindow.ui +++ b/src/mainwindow.ui @@ -1197,6 +1197,7 @@ p, li { white-space: pre-wrap; } false + @@ -1383,6 +1384,18 @@ Right now this has very limited functionality Ctrl+C
+ + + + :/MO/gui/app_icon:/MO/gui/app_icon + + + Change Game + + + Open the game selection dialog + +
diff --git a/src/nxmaccessmanager.cpp b/src/nxmaccessmanager.cpp index 3f90647b..17c50e35 100644 --- a/src/nxmaccessmanager.cpp +++ b/src/nxmaccessmanager.cpp @@ -215,7 +215,6 @@ void NXMAccessManager::login(const QString &username, const QString &password) emit loginSuccessful(false); return; } - m_Username = username; m_Password = password; pageLogin(); @@ -237,7 +236,6 @@ QString NXMAccessManager::userAgent(const QString &subModule) const void NXMAccessManager::pageLogin() { qDebug("logging %s in on Nexus", qPrintable(m_Username)); - QString requestString = (Nexus_Management_URL + "/Sessions/?Login&uri=%1") .arg(QString(QUrl::toPercentEncoding(Nexus_Management_URL))); diff --git a/src/resources.qrc b/src/resources.qrc index 8434b367..d357801c 100644 --- a/src/resources.qrc +++ b/src/resources.qrc @@ -26,7 +26,6 @@ resources/software-update-available.png resources/emblem-important.png resources/check.png - mo_icon.ico resources/dialog-warning.png resources/symbol-backup.png resources/applications-accessories.png @@ -68,6 +67,8 @@ resources/status_active.png resources/status_awaiting.png resources/status_inactive.png + resources/mo_icon.png + resources/package.png resources/contents/jigsaw-piece.png diff --git a/src/resources/mo_icon.png b/src/resources/mo_icon.png new file mode 100644 index 00000000..c926d722 Binary files /dev/null and b/src/resources/mo_icon.png differ diff --git a/src/resources/package.png b/src/resources/package.png new file mode 100644 index 00000000..4b55b504 Binary files /dev/null and b/src/resources/package.png differ diff --git a/src/settingsdialog.cpp b/src/settingsdialog.cpp index c66cc243..0d86018c 100644 --- a/src/settingsdialog.cpp +++ b/src/settingsdialog.cpp @@ -217,18 +217,6 @@ void SettingsDialog::on_associateButton_clicked() Settings::instance().registerAsNXMHandler(true); } -void SettingsDialog::on_changeInstanceButton_clicked() -{ - if (QMessageBox::question(this, tr("Are you sure?"), - tr("This will restart MO, continue?"), - QMessageBox::Yes | QMessageBox::Cancel) - == QMessageBox::Yes) { - InstanceManager().clearCurrentInstance(); - this->reject(); - qApp->exit(INT_MAX); - } -} - void SettingsDialog::on_clearCacheButton_clicked() { QDir(Settings::instance().getCacheDirectory()).removeRecursively(); diff --git a/src/settingsdialog.h b/src/settingsdialog.h index 1ae21015..658fbce4 100644 --- a/src/settingsdialog.h +++ b/src/settingsdialog.h @@ -52,21 +52,6 @@ signals: void resetDialogs(); -private slots: - void on_clearCacheButton_clicked(); - -private slots: - void on_browseBaseDirBtn_clicked(); - -private slots: - void on_browseOverwriteDirBtn_clicked(); - -private slots: - void on_browseProfilesDirBtn_clicked(); - -private slots: - void on_changeInstanceButton_clicked(); - private: void storeSettings(QListWidgetItem *pluginItem); @@ -92,6 +77,14 @@ private slots: void on_associateButton_clicked(); + void on_clearCacheButton_clicked(); + + void on_browseBaseDirBtn_clicked(); + + void on_browseOverwriteDirBtn_clicked(); + + void on_browseProfilesDirBtn_clicked(); + private: Ui::SettingsDialog *ui; }; diff --git a/src/settingsdialog.ui b/src/settingsdialog.ui index 9ebed3b8..1f751da8 100644 --- a/src/settingsdialog.ui +++ b/src/settingsdialog.ui @@ -124,19 +124,6 @@ If you use pre-releases, never contact me directly by e-mail or via private mess
- - - - Qt::Vertical - - - - 20 - 40 - - - - @@ -182,6 +169,19 @@ If you use pre-releases, never contact me directly by e-mail or via private mess + + + + Qt::Vertical + + + + 20 + 40 + + + + @@ -198,32 +198,6 @@ If you use pre-releases, never contact me directly by e-mail or via private mess - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - Restart MO and choose a different set of data paths. - - - This will restart MO and give you opportunity to switch to a different set of data paths. - - - Change Instance - - - -- cgit v1.3.1 From d1ed7ae5d74ee7cba30ad8973cf64c0d29b427aa Mon Sep 17 00:00:00 2001 From: LePresidente Date: Wed, 21 Dec 2016 00:54:41 -0800 Subject: Migrate to version numbers with buildnumber. Added Comment for removal of ModBase::isOneof --- src/mainwindow.ui | 3 +++ src/organizercore.cpp | 1 + src/selfupdater.cpp | 3 ++- 3 files changed, 6 insertions(+), 1 deletion(-) (limited to 'src/mainwindow.ui') diff --git a/src/mainwindow.ui b/src/mainwindow.ui index e30a165d..6ce156c8 100644 --- a/src/mainwindow.ui +++ b/src/mainwindow.ui @@ -732,6 +732,9 @@ p, li { white-space: pre-wrap; } Sort + + false + :/MO/gui/sort:/MO/gui/sort diff --git a/src/organizercore.cpp b/src/organizercore.cpp index 46d146dc..142c9eba 100644 --- a/src/organizercore.cpp +++ b/src/organizercore.cpp @@ -1239,6 +1239,7 @@ bool OrganizerCore::waitForProcessCompletion(HANDLE handle, LPDWORD exitCode) DWORD res; // Wait for a an event on the handle, a key press, mouse click or timeout + //TODO: Remove MOBase::isOneOf from this query as it was always returning true. while ( res = ::MsgWaitForMultipleObjects(1, &handle, false, 500, QS_KEY | QS_MOUSE), diff --git a/src/selfupdater.cpp b/src/selfupdater.cpp index 1b6b4684..3e98a5ec 100644 --- a/src/selfupdater.cpp +++ b/src/selfupdater.cpp @@ -105,7 +105,8 @@ SelfUpdater::SelfUpdater(NexusInterface *nexusInterface) m_MOVersion = VersionInfo(version.dwFileVersionMS >> 16, version.dwFileVersionMS & 0xFFFF, - version.dwFileVersionLS >> 16); + version.dwFileVersionLS >> 16, + version.dwFileVersionLS & 0xFFFF); } -- cgit v1.3.1 From c48d1c36b781fc3da2c6a003529865b96c6ed187 Mon Sep 17 00:00:00 2001 From: Brian Munro Date: Tue, 3 Jan 2017 19:34:56 +0200 Subject: Update mainwindow.ui Reverted Tabs to spaces --- src/mainwindow.ui | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src/mainwindow.ui') diff --git a/src/mainwindow.ui b/src/mainwindow.ui index 6ce156c8..b464a384 100644 --- a/src/mainwindow.ui +++ b/src/mainwindow.ui @@ -732,9 +732,9 @@ p, li { white-space: pre-wrap; } Sort - - false - + + false + :/MO/gui/sort:/MO/gui/sort -- cgit v1.3.1 From f2b33d75cb147965306e075f0b921cbad6c04334 Mon Sep 17 00:00:00 2001 From: ZachHaber Date: Mon, 16 Jan 2017 19:34:02 -0600 Subject: Loot Button Re-enabled the button --- src/mainwindow.ui | 3 --- 1 file changed, 3 deletions(-) (limited to 'src/mainwindow.ui') diff --git a/src/mainwindow.ui b/src/mainwindow.ui index b464a384..e30a165d 100644 --- a/src/mainwindow.ui +++ b/src/mainwindow.ui @@ -732,9 +732,6 @@ p, li { white-space: pre-wrap; } Sort - - false - :/MO/gui/sort:/MO/gui/sort -- cgit v1.3.1 From 0da2060da415f7cf55a6b581f8b94d04be9a3316 Mon Sep 17 00:00:00 2001 From: ZachHaber Date: Tue, 17 Jan 2017 17:11:06 -0600 Subject: Revert "Loot Button" This reverts commit f2b33d75cb147965306e075f0b921cbad6c04334. --- src/mainwindow.ui | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src/mainwindow.ui') diff --git a/src/mainwindow.ui b/src/mainwindow.ui index e30a165d..b464a384 100644 --- a/src/mainwindow.ui +++ b/src/mainwindow.ui @@ -732,6 +732,9 @@ p, li { white-space: pre-wrap; } Sort + + false + :/MO/gui/sort:/MO/gui/sort -- cgit v1.3.1 From 45cc67da05c57f3088e2b17e4c588905fda6c43c Mon Sep 17 00:00:00 2001 From: ZachHaber Date: Tue, 17 Jan 2017 17:14:38 -0600 Subject: Re-enabled the boss button Properly this time =P --- src/mainwindow.ui | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/mainwindow.ui') diff --git a/src/mainwindow.ui b/src/mainwindow.ui index b464a384..4b5467ed 100644 --- a/src/mainwindow.ui +++ b/src/mainwindow.ui @@ -733,7 +733,7 @@ p, li { white-space: pre-wrap; } Sort - false + true -- cgit v1.3.1 From a611c355ce732961c2a9ba1a8909f0c144afa860 Mon Sep 17 00:00:00 2001 From: Jeremy Rimpo Date: Fri, 20 Oct 2017 20:27:06 -0500 Subject: Basic ESL updates --- src/activatemodsdialog.ui | 4 +- src/mainwindow.ui | 2 +- src/modinfodialog.cpp | 3 +- src/modinfodialog.ui | 4 +- src/modinforegular.cpp | 4 +- src/modlist.cpp | 4 +- src/organizer_en.ts | 691 +++++++++++----------- src/organizer_en_US.ts | 14 +- src/organizercore.cpp | 18 +- src/pluginlist.cpp | 2 +- src/settingsdialog.ui | 2 +- src/tutorials/tutorial_conflictresolution_main.js | 2 +- src/tutorials/tutorial_primer_main.js | 2 +- 13 files changed, 384 insertions(+), 368 deletions(-) (limited to 'src/mainwindow.ui') diff --git a/src/activatemodsdialog.ui b/src/activatemodsdialog.ui index f6124bbc..cd8b0eec 100644 --- a/src/activatemodsdialog.ui +++ b/src/activatemodsdialog.ui @@ -17,14 +17,14 @@ - This is a list of esps and esms that were active when the save game was created. + This is a list of esps, esms, and esls that were active when the save game was created. <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">This is a list of esps and esms that were active when the save game was created.</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">This is a list of esps, esms, and esls that were active when the save game was created.</span></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">For each esp, the right column contains the mod (or mods) that can be enabled to make the missing esps/esms available.</span></p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">If you hit Ok, all the mods selected in the right columns and all missing esps that have become available will be activated.</span></p></body></html> diff --git a/src/mainwindow.ui b/src/mainwindow.ui index 4b5467ed..743ce012 100644 --- a/src/mainwindow.ui +++ b/src/mainwindow.ui @@ -846,7 +846,7 @@ p, li { white-space: pre-wrap; } <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">This list contains the esps and esms contained in the active mods. These require their own load order. Use drag&amp;drop to modify this load order. Please note that MO will only save the load order for mods that are active/checked.<br />There is a great tool named &quot;BOSS&quot; to automatically sort these files.</span></p></body></html> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">This list contains the esps, esms, and esls contained in the active mods. These require their own load order. Use drag&amp;drop to modify this load order. Please note that MO will only save the load order for mods that are active/checked.<br />There is a great tool named &quot;BOSS&quot; to automatically sort these files.</span></p></body></html> true diff --git a/src/modinfodialog.cpp b/src/modinfodialog.cpp index 0e77859a..c96c2b4a 100644 --- a/src/modinfodialog.cpp +++ b/src/modinfodialog.cpp @@ -314,7 +314,8 @@ void ModInfoDialog::refreshLists() ui->iniFileList->addItem(namePart); } } else if (fileName.endsWith(".esp", Qt::CaseInsensitive) || - fileName.endsWith(".esm", Qt::CaseInsensitive)) { + fileName.endsWith(".esm", Qt::CaseInsensitive) || + fileName.endsWith(".esl", Qt::CaseInsensitive)) { QString relativePath = fileName.mid(m_RootPath.length() + 1); if (relativePath.contains('/')) { QFileInfo fileInfo(fileName); diff --git a/src/modinfodialog.ui b/src/modinfodialog.ui index a452bc59..25822fd0 100644 --- a/src/modinfodialog.ui +++ b/src/modinfodialog.ui @@ -279,10 +279,10 @@ - List of esps and esms that can not be loaded by the game. + List of esps, esms, and esls that can not be loaded by the game. - List of esps and esms contained in this plugin that currently can not be loaded by the game. They will not even appear in the esp-list in the main MO-window. + List of esps, esms, and esls contained in this plugin that currently can not be loaded by the game. They will not even appear in the esp-list in the main MO-window. They usually contain optional functionality, see the readme. Most mods do not have optional esps, so chances are good you are looking at an empty list. diff --git a/src/modinforegular.cpp b/src/modinforegular.cpp index 231e5497..bacc21f7 100644 --- a/src/modinforegular.cpp +++ b/src/modinforegular.cpp @@ -430,7 +430,7 @@ std::vector ModInfoRegular::getContents() const if (m_LastContentCheck.isNull() || (m_LastContentCheck.secsTo(now) > 60)) { m_CachedContent.clear(); QDir dir(absolutePath()); - if (dir.entryList(QStringList() << "*.esp" << "*.esm").size() > 0) { + if (dir.entryList(QStringList() << "*.esp" << "*.esm" << "*.esl").size() > 0) { m_CachedContent.push_back(CONTENT_PLUGIN); } if (dir.entryList(QStringList() << "*.bsa" << "*.ba2").size() > 0) { @@ -476,7 +476,7 @@ int ModInfoRegular::getHighlight() const QString ModInfoRegular::getDescription() const { if (!isValid()) { - return tr("%1 contains no esp/esm and no asset (textures, meshes, interface, ...) directory").arg(name()); + return tr("%1 contains no esp/esm/esl and no asset (textures, meshes, interface, ...) directory").arg(name()); } else { const std::set &categories = getCategories(); std::wostringstream categoryString; diff --git a/src/modlist.cpp b/src/modlist.cpp index fca98aac..0aea7a98 100644 --- a/src/modlist.cpp +++ b/src/modlist.cpp @@ -60,7 +60,7 @@ ModList::ModList(QObject *parent) , m_FontMetrics(QFont()) , m_DropOnItems(false) { - m_ContentIcons[ModInfo::CONTENT_PLUGIN] = std::make_tuple(":/MO/gui/content/plugin", tr("Game plugins (esp/esm)")); + m_ContentIcons[ModInfo::CONTENT_PLUGIN] = std::make_tuple(":/MO/gui/content/plugin", tr("Game plugins (esp/esm/esl)")); m_ContentIcons[ModInfo::CONTENT_INTERFACE] = std::make_tuple(":/MO/gui/content/interface", tr("Interface")); m_ContentIcons[ModInfo::CONTENT_MESH] = std::make_tuple(":/MO/gui/content/mesh", tr("Meshes")); m_ContentIcons[ModInfo::CONTENT_BSA] = std::make_tuple(":/MO/gui/content/bsa", tr("BSA")); @@ -1026,7 +1026,7 @@ QString ModList::getColumnToolTip(int column) case COL_FLAGS: return tr("Emblemes to highlight things that might require attention."); case COL_CONTENT: return tr("Depicts the content of the mod:
" "" - "" + "" "" "" "" diff --git a/src/organizer_en.ts b/src/organizer_en.ts index da3a3c6e..f73717f2 100644 --- a/src/organizer_en.ts +++ b/src/organizer_en.ts @@ -64,7 +64,7 @@ - This is a list of esps and esms that were active when the save game was created. + This is a list of esps, esms, and esls that were active when the save game was created. @@ -73,7 +73,7 @@ <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">This is a list of esps and esms that were active when the save game was created.</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">This is a list of esps, esms, and esls that were active when the save game was created.</span></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">For each esp, the right column contains the mod (or mods) that can be enabled to make the missing esps/esms available.</span></p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">If you hit Ok, all the mods selected in the right columns and all missing esps that have become available will be activated.</span></p></body></html> @@ -1325,13 +1325,13 @@ p, li { white-space: pre-wrap; } - + Restore Backup... - + Create Backup @@ -1362,8 +1362,8 @@ p, li { white-space: pre-wrap; } - - + + Namefilter @@ -1431,74 +1431,74 @@ p, li { white-space: pre-wrap; } - + List of available esp/esm files - + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">This list contains the esps and esms contained in the active mods. These require their own load order. Use drag&amp;drop to modify this load order. Please note that MO will only save the load order for mods that are active/checked.<br />There is a great tool named &quot;BOSS&quot; to automatically sort these files.</span></p></body></html> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">This list contains the esps, esms, and esls contained in the active mods. These require their own load order. Use drag&amp;drop to modify this load order. Please note that MO will only save the load order for mods that are active/checked.<br />There is a great tool named &quot;BOSS&quot; to automatically sort these files.</span></p></body></html> - + Data - + refresh data-directory overview - + Refresh the overview. This may take a moment. - - - + + + Refresh - + This is an overview of your data directory as visible to the game (and tools). - + File - + Mod - + Filter the above list so that only conflicts are displayed. - + Show only conflicts - + Saves - + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } @@ -1509,155 +1509,155 @@ p, li { white-space: pre-wrap; } - + Downloads - + This is a list of mods you downloaded from Nexus. Double click one to install it. You can also drag an archive into here. - + Show Hidden - + Tool Bar - + Install Mod - + Install &Mod - + Install a new mod from an archive - + Ctrl+M - + Profiles - + &Profiles - + Configure Profiles - + Ctrl+P - + Executables - + &Executables - + Configure the executables that can be started through Mod Organizer - + Ctrl+E - - + + Tools - + &Tools - + Ctrl+I - + Settings - + &Settings - + Configure settings and workarounds - + Ctrl+S - + Nexus - + Search nexus network for more mods - + Ctrl+N - - + + Update - + Mod Organizer is up-to-date - + No Problems - + This button will be highlighted if MO discovered potential problems in your setup and provide tips on how to fix them. !Work in progress! @@ -1665,44 +1665,44 @@ Right now this has very limited functionality - + Help - + Ctrl+H - + Endorse MO - - + + Endorse Mod Organizer - + Copy Log to Clipboard - + Ctrl+C - + Change Game - + Open the game selection dialog @@ -1817,469 +1817,469 @@ Right now this has very limited functionality - + Also in: <br> - + No conflict - + <Edit...> - + Activating Network Proxy - + Choose Mod - + Mod Archive - + Start Tutorial? - + You're about to start a tutorial. For technical reasons it's not possible to end the tutorial early. Continue? - + failed to spawn notepad.exe: %1 - + failed to open %1 - + failed to change origin name: %1 - + failed to move "%1" from mod "%2" to "%3": %4 - + <Contains %1> - + <Checked> - + <Unchecked> - + <Update> - + <Managed by MO> - + <Managed outside MO> - + <No category> - + <Conflicted> - + <Not Endorsed> - + failed to rename mod: %1 - + Overwrite? - + This will replace the existing mod "%1". Continue? - + failed to remove mod "%1" - - - + + + failed to rename "%1" to "%2" - - - - + + + + Confirm - + Remove the following mods?<br><ul>%1</ul> - + failed to remove mod: %1 - - + + Failed - + Installation file no longer exists - + Mods installed with old versions of MO can't be reinstalled in this way. - + You need to be logged in with Nexus to resume a download - - + + You need to be logged in with Nexus to endorse - + Failed to display overwrite dialog: %1 - + Nexus ID for this Mod is unknown - + Web page for this mod is unknown - - - + + + Create Mod... - + This will create an empty mod. Please enter a name: - - + + A mod with this name already exists - + This will move all files from overwrite into a new, regular mod. Please enter a name: - + Not logged in, endorsement information will be wrong - + Continue? - + The versioning scheme decides which version is considered newer than another. This function will guess the versioning scheme under the assumption that the installed version is outdated. - - + + Sorry - + I don't know a versioning scheme where %1 is newer than %2. - + Really enable all visible mods? - + Really disable all visible mods? - + Choose what to export - + Everything - + All installed mods are included in the list - + Active Mods - + Only active (checked) mods from your current profile are included - + Visible - + All mods visible in the mod list are included - + export failed: %1 - + Install Mod... - + Create empty mod - + Enable all visible - + Disable all visible - + Check all for update - + Export to csv... - + All Mods - + Sync to Mods... - + Restore Backup - + Remove Backup... - + Add/Remove Categories - + Replace Categories - + Primary Category - + Change versioning scheme - + Un-ignore update - + Ignore update - + Rename Mod... - + Remove Mod... - + Reinstall Mod - + Un-Endorse - - + + Endorse - + Won't endorse - + Endorsement state unknown - + Ignore missing data - + Visit on Nexus - + Visit web page - + Open in explorer - + Information... - - + + Exception: - - + + Unknown exception - + <All> - + <Multiple> - + %1 more - + Are you sure you want to remove the following %n save(s)?<br><ul>%1</ul><br>Removed saves will be sent to the Recycle Bin. @@ -2287,12 +2287,12 @@ This function will guess the versioning scheme under the assumption that the ins - + Enable Mods... - + Delete %n save(s) @@ -2300,319 +2300,319 @@ This function will guess the versioning scheme under the assumption that the ins - + failed to remove %1 - + failed to create %1 - + Can't change download directory while downloads are in progress! - + failed to write to file %1 - + %1 written - + Select binary - + Binary - + Enter Name - + Please enter a name for the executable - + Not an executable - + This is not a recognized executable. - - + + Replace file? - + There already is a hidden version of this file. Replace it? - - + + File operation failed - - + + Failed to remove "%1". Maybe you lack the required file permissions? - + There already is a visible version of this file. Replace it? - + file not found: %1 - + failed to generate preview for %1 - + Sorry, can't preview anything. This function currently does not support extracting from bsas. - + Update available - + Open/Execute - + Add as Executable - + Preview - + Un-Hide - + Hide - + Write To File... - + Do you want to endorse Mod Organizer on %1 now? - + Thank you! - + Thank you for your endorsement! - + Request to Nexus failed: %1 - - + + failed to read %1: %2 - - + + Error - + failed to extract %1 (errorcode %2) - + Extract BSA - + This archive contains invalid hashes. Some files may be broken. - + Are you sure? - + This will restart MO, continue? - + Edit Categories... - + Deselect filter - + Remove - + Enable all - + Disable all - + Unlock load order - + Lock load order - + depends on missing "%1" - + incompatible with "%1" - + Please wait while LOOT is running - + loot failed. Exit code was: %1 - + failed to start loot - + failed to run loot: %1 - + Errors occured - + Backup of load order created - + Choose backup to restore - + No Backups - + There are no backups to restore - - + + Restore failed - - + + Failed to restore the backup. Errorcode: %1 - + Backup of modlist created - + A file with the same name has already been downloaded. What would you like to do? - + Overwrite - + Rename new file - + Ignore file @@ -2793,12 +2793,12 @@ This function will guess the versioning scheme under the assumption that the ins - List of esps and esms that can not be loaded by the game. + List of esps, esms, and esls that can not be loaded by the game. - List of esps and esms contained in this plugin that currently can not be loaded by the game. They will not even appear in the esp-list in the main MO-window. + List of esps, esms, and esls contained in this plugin that currently can not be loaded by the game. They will not even appear in the esp-list in the main MO-window. They usually contain optional functionality, see the readme. Most mods do not have optional esps, so chances are good you are looking at an empty list. @@ -2989,227 +2989,227 @@ p, li { white-space: pre-wrap; } - + &Delete - + &Rename - + &Hide - + &Unhide - + &Open - + &New Folder - - + + Save changes? - - + + Save changes to "%1"? - + File Exists - + A file with that name exists, please enter a new one - + failed to move file - + failed to create directory "optional" - - + + Info requested, please wait - + Main - + Update - + Optional - + Old - + Misc - + Unknown - + Current Version: %1 - + No update available - + (description incomplete, please visit nexus) - + <a href="%1">Visit on Nexus</a> - + Failed to delete %1 - - + + Confirm - + Are sure you want to delete "%1"? - + Are sure you want to delete the selected files? - - + + New Folder - + Failed to create "%1" - - + + Replace file? - + There already is a hidden version of this file. Replace it? - - + + File operation failed - - + + Failed to remove "%1". Maybe you lack the required file permissions? - - + + failed to rename %1 to %2 - + There already is a visible version of this file. Replace it? - + Un-Hide - + Hide - + Name - + Please enter a name - - + + Error - + Invalid name. Must be a valid file name - + A tweak by that name exists - + Create Tweak @@ -3593,147 +3593,147 @@ p, li { white-space: pre-wrap; } - - + + Installation successful - - + + Configure Mod - - + + This mod contains ini tweaks. Do you want to configure them now? - - + + mod "%1" not found - - + + Installation cancelled - - + + The mod was not installed completely. - + Executable "%1" not found - + Start Steam? - + Steam is required to be running already to correctly start the game. Should MO try to start steam now? - + Error - + No profile set - + Failed to refresh list of esps: %1 - + Multiple esps activated, please check that they don't conflict. - + Download? - + A download has been started but no installed page plugin recognizes it. If you download anyway no information (i.e. version) will be associated with the download. Continue? - + failed to update mod list: %1 - - + + login successful - + Login failed - + Login failed, try again? - + login failed: %1. Download will not be associated with an account - + login failed: %1 - + login failed: %1. You need to log-in with Nexus to update MO. - - Too many esps and esms enabled + + Too many esps, esms, and esls enabled - - + + Description missing - + The game doesn't allow more than 255 active plugins (including the official ones) to be loaded. You have to disable some unused plugins or merge some plugins into one. You can find a guide here: <a href="http://wiki.step-project.com/Guide:Merging_Plugins">http://wiki.step-project.com/Guide:Merging_Plugins</a> - + failed to save load order: %1 - + The designated write target "%1" is not enabled. @@ -4338,7 +4338,7 @@ p, li { white-space: pre-wrap; } - + invalid game type %1 @@ -4509,7 +4509,8 @@ p, li { white-space: pre-wrap; } - ModOrganizer has crashed! Should a diagnostic file be created? If you send me this file (%1) to sherb@gmx.net, the bug is a lot more likely to be fixed. Please include a short description of what you were doing when the crash happened + ModOrganizer has crashed! Should a diagnostic file be created? If you send me this file (%1) to modorganizer@gmail.com, the bug is a lot more likely to be fixed. Please include a short description of what you were doing when the crash happened + ModOrganizer has crashed! Should a diagnostic file be created? If you send me this file (%1) to sherb@gmx.net, the bug is a lot more likely to be fixed. Please include a short description of what you were doing when the crash happened @@ -4570,13 +4571,13 @@ p, li { white-space: pre-wrap; } - - + + <Manage...> - + failed to parse profile %1: %2 @@ -4764,52 +4765,52 @@ Start elevated anyway? (you will be asked if you want to allow ModOrganizer.exe - + New update available (%1) - + Install - + Download failed - + Failed to find correct download, please try again later. - + Update - + Download in progress - + Download failed: %1 - + Failed to install update: %1 - + Failed to start %1: %2 - + Error @@ -5318,7 +5319,7 @@ Uncheck this if you want to use Mod Organizer with total conversions (like Nehri By default Mod Organizer will display esp+bsa bundles installed with foreign tools as mods (left pane). This allows you to control their priority in relation to other mods. This is particularly useful if you also use Steam Workshop to install mods. However, if you installed loose file mods outside MO which conflict with BSAs also installed outside MO those conflicts can't be resolved correctly. -If you disable this feature, MO will only display official DLCs this way. Please note that plugins (esps and esms) displayed in the right pane are completely unaffected by this feature. +If you disable this feature, MO will only display official DLCs this way. Please note that plugins (esps, esms, and esls) displayed in the right pane are completely unaffected by this feature. diff --git a/src/organizer_en_US.ts b/src/organizer_en_US.ts index 075132c2..4e657785 100644 --- a/src/organizer_en_US.ts +++ b/src/organizer_en_US.ts @@ -54,7 +54,7 @@ - This is a list of esps and esms that were active when the save game was created. + This is a list of esps, esms, and esls that were active when the save game was created. @@ -63,7 +63,7 @@ <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">This is a list of esps and esms that were active when the save game was created.</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">This is a list of esps, esms, and esls that were active when the save game was created.</span></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">For each esp, the right column contains the mod (or mods) that can be enabled to make the missing esps/esms available.</span></p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">If you hit Ok, all the mods selected in the right columns and all missing esps that have become available will be activated.</span></p></body></html> @@ -1467,7 +1467,7 @@ p, li { white-space: pre-wrap; } <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">This list contains the esps and esms contained in the active mods. These require their own load order. Use drag&amp;drop to modify this load order. Please note that MO will only save the load order for mods that are active/checked.<br />There is a great tool named &quot;BOSS&quot; to automatically sort these files.</span></p></body></html> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">This list contains the esps, esms, and esls contained in the active mods. These require their own load order. Use drag&amp;drop to modify this load order. Please note that MO will only save the load order for mods that are active/checked.<br />There is a great tool named &quot;BOSS&quot; to automatically sort these files.</span></p></body></html> @@ -1993,7 +1993,7 @@ Continue? - Too many esps and esms enabled + Too many esps, esms, and esls enabled @@ -2937,12 +2937,12 @@ This function will guess the versioning scheme under the assumption that the ins - List of esps and esms that can not be loaded by the game. + List of esps, esms, and esls that can not be loaded by the game. - List of esps and esms contained in this plugin that currently can not be loaded by the game. They will not even appear in the esp-list in the main MO-window. + List of esps, esms, and esls contained in this plugin that currently can not be loaded by the game. They will not even appear in the esp-list in the main MO-window. They usually contain optional functionality, see the readme. Most mods do not have optional esps, so chances are good you are looking at an empty list. @@ -5177,7 +5177,7 @@ Uncheck this if you want to use Mod Organizer with total conversions (like Nehri By default Mod Organizer will display esp+bsa bundles installed with foreign tools as mods (left pane). This allows you to control their priority in relation to other mods. This is particularly useful if you also use Steam Workshop to install mods. However, if you installed loose file mods outside MO which conflict with BSAs also installed outside MO those conflicts can't be resolved correctly. -If you disable this feature, MO will only display official DLCs this way. Please note that plugins (esps and esms) displayed in the right pane are completely unaffected by this feature. +If you disable this feature, MO will only display official DLCs this way. Please note that plugins (esps, esms, and esls) displayed in the right pane are completely unaffected by this feature. diff --git a/src/organizercore.cpp b/src/organizercore.cpp index d9ed6ab6..c55504a8 100644 --- a/src/organizercore.cpp +++ b/src/organizercore.cpp @@ -1413,6 +1413,20 @@ void OrganizerCore::updateModActiveState(int index, bool active) m_PluginList.enableESP(esm, active); } int enabled = 0; + for (const QString &esl : + dir.entryList(QStringList() << "*.esl", QDir::Files)) { + const FileEntry::Ptr file = m_DirectoryStructure->findFile(ToWString(esl)); + if (file.get() == nullptr) { + qWarning("failed to activate %s", qPrintable(esl)); + continue; + } + + if (active != m_PluginList.isEnabled(esl) + && file->getAlternatives().empty()) { + m_PluginList.enableESP(esl, active); + ++enabled; + } + } QStringList esps = dir.entryList(QStringList() << "*.esp", QDir::Files); for (const QString &esp : esps) { const FileEntry::Ptr file = m_DirectoryStructure->findFile(ToWString(esp)); @@ -1429,7 +1443,7 @@ void OrganizerCore::updateModActiveState(int index, bool active) } if (active && (enabled > 1)) { MessageDialog::showMessage( - tr("Multiple esps activated, please check that they don't conflict."), + tr("Multiple esps/esls activated, please check that they don't conflict."), qApp->activeWindow()); } m_PluginList.refreshLoadOrder(); @@ -1723,7 +1737,7 @@ QString OrganizerCore::shortDescription(unsigned int key) const { switch (key) { case PROBLEM_TOOMANYPLUGINS: { - return tr("Too many esps and esms enabled"); + return tr("Too many esps, esms, and esls enabled"); } break; default: { return tr("Description missing"); diff --git a/src/pluginlist.cpp b/src/pluginlist.cpp index a4d8561c..f2c52d5b 100644 --- a/src/pluginlist.cpp +++ b/src/pluginlist.cpp @@ -135,7 +135,7 @@ void PluginList::refresh(const QString &profileName QString extension = filename.right(3).toLower(); - if ((extension == "esp") || (extension == "esm")) { + if ((extension == "esp") || (extension == "esm") || (extension == "esl")) { bool forceEnabled = Settings::instance().forceEnableCoreFiles() && std::find(primaryPlugins.begin(), primaryPlugins.end(), filename.toLower()) != primaryPlugins.end(); diff --git a/src/settingsdialog.ui b/src/settingsdialog.ui index a38530da..f5e37ea6 100644 --- a/src/settingsdialog.ui +++ b/src/settingsdialog.ui @@ -970,7 +970,7 @@ Uncheck this if you want to use Mod Organizer with total conversions (like Nehri By default Mod Organizer will display esp+bsa bundles installed with foreign tools as mods (left pane). This allows you to control their priority in relation to other mods. This is particularly useful if you also use Steam Workshop to install mods. However, if you installed loose file mods outside MO which conflict with BSAs also installed outside MO those conflicts can't be resolved correctly. -If you disable this feature, MO will only display official DLCs this way. Please note that plugins (esps and esms) displayed in the right pane are completely unaffected by this feature. +If you disable this feature, MO will only display official DLCs this way. Please note that plugins (esps, esms, and esls) displayed in the right pane are completely unaffected by this feature. Display mods installed outside MO diff --git a/src/tutorials/tutorial_conflictresolution_main.js b/src/tutorials/tutorial_conflictresolution_main.js index 3a7160c6..00ca8d67 100644 --- a/src/tutorials/tutorial_conflictresolution_main.js +++ b/src/tutorials/tutorial_conflictresolution_main.js @@ -93,7 +93,7 @@ function getTutorialSteps() { waitForClick() }, function() { - tutorial.text = qsTr("I told you in the \"First Steps\" tutorial how the esp/esm plugins contain changes to the game world " + tutorial.text = qsTr("I told you in the \"First Steps\" tutorial how the esp/esm/esl plugins contain changes to the game world " +"like modifications to the terrain or existing NPCs. Each change like this is stored in a record, hence the " +"name \"record conflict\". For example when two mods try to change the same location, only one change can become active.") waitForClick() diff --git a/src/tutorials/tutorial_primer_main.js b/src/tutorials/tutorial_primer_main.js index 12df2c86..7ef65df9 100644 --- a/src/tutorials/tutorial_primer_main.js +++ b/src/tutorials/tutorial_primer_main.js @@ -75,7 +75,7 @@ function setupTooptips() { switch (manager.findControl("tabWidget").currentIndex) { case 0: - tooltipWidget("espList", qsTr("Plugins (esp/esm files) of the mods in the current profile. They need to be checked to be loaded.")) + tooltipWidget("espList", qsTr("Plugins (esp/esm/esl files) of the mods in the current profile. They need to be checked to be loaded.")) tooltipWidget("bossButton", qsTr("Automatically sort plugins using the bundled LOOT application.")) tooltipWidget("espFilterEdit", qsTr("Quickly filter plugin list as you type.")) break -- cgit v1.3.1 From d7bc542b3d1a96a546d48850e61d3ecdc953c4cc Mon Sep 17 00:00:00 2001 From: Jeremy Rimpo Date: Thu, 30 Nov 2017 16:37:14 -0600 Subject: Implement mod/plugin highlighting when pair is selected --- src/CMakeLists.txt | 2 + src/mainwindow.cpp | 15 + src/mainwindow.h | 3 + src/mainwindow.ui | 7 +- src/modinfo.cpp | 5 + src/modinfo.h | 14 +- src/modinfooverwrite.cpp | 8 +- src/modinforegular.cpp | 10 +- src/modlist.cpp | 37 ++- src/modlist.h | 3 + src/organizer_en.ts | 812 ++++++++++++++++++++++++----------------------- src/pluginlist.cpp | 34 +- src/pluginlist.h | 3 + src/pluginlistview.cpp | 58 ++++ src/pluginlistview.h | 24 ++ 15 files changed, 629 insertions(+), 406 deletions(-) create mode 100644 src/pluginlistview.cpp create mode 100644 src/pluginlistview.h (limited to 'src/mainwindow.ui') diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index d5ebf6ae..d603336c 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -23,6 +23,7 @@ SET(organizer_SRCS profile.cpp pluginlistsortproxy.cpp pluginlist.cpp + pluginlistview.cpp overwriteinfodialog.cpp nxmaccessmanager.cpp nexusinterface.cpp @@ -109,6 +110,7 @@ SET(organizer_HDRS profile.h pluginlistsortproxy.h pluginlist.h + pluginlistview.h overwriteinfodialog.h nxmaccessmanager.h nexusinterface.h diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 0a6e32c3..84860767 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -357,6 +357,9 @@ MainWindow::MainWindow(QSettings &initSettings connect(this, SIGNAL(styleChanged(QString)), this, SLOT(updateStyle(QString))); + 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())); @@ -2121,6 +2124,18 @@ void MainWindow::modlistSelectionChanged(const QModelIndex ¤t, const QMode ui->modList->verticalScrollBar()->repaint(); } +void MainWindow::modlistSelectionsChanged(const QItemSelection &selected) +{ + m_OrganizerCore.pluginList()->highlightPlugins(selected, *m_OrganizerCore.directoryStructure()); + 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(); diff --git a/src/mainwindow.h b/src/mainwindow.h index 06c51203..cec6c407 100644 --- a/src/mainwindow.h +++ b/src/mainwindow.h @@ -520,6 +520,9 @@ private slots: void modlistSelectionChanged(const QModelIndex ¤t, const QModelIndex &previous); void modListSortIndicatorChanged(int column, Qt::SortOrder order); + void modlistSelectionsChanged(const QItemSelection ¤t); + void esplistSelectionsChanged(const QItemSelection ¤t); + private slots: // ui slots // actions void on_actionAdd_Profile_triggered(); diff --git a/src/mainwindow.ui b/src/mainwindow.ui index 743ce012..26b9e375 100644 --- a/src/mainwindow.ui +++ b/src/mainwindow.ui @@ -791,7 +791,7 @@ p, li { white-space: pre-wrap; } - + 250 @@ -1412,6 +1412,11 @@ Right now this has very limited functionality QTreeView
modlistview.h
+ + PluginListView + QTreeView +
pluginlistview.h
+
diff --git a/src/modinfo.cpp b/src/modinfo.cpp index 5d3c1e41..77df6216 100644 --- a/src/modinfo.cpp +++ b/src/modinfo.cpp @@ -301,6 +301,11 @@ void ModInfo::setVersion(const VersionInfo &version) m_Version = version; } +void ModInfo::setPluginSelected(const bool &isSelected) +{ + m_PluginSelected = isSelected; +} + void ModInfo::addCategory(const QString &categoryName) { int id = CategoryFactory::instance().getCategoryID(categoryName); diff --git a/src/modinfo.h b/src/modinfo.h index 1485a4b3..c62df549 100644 --- a/src/modinfo.h +++ b/src/modinfo.h @@ -67,7 +67,8 @@ public: FLAG_CONFLICT_OVERWRITE, FLAG_CONFLICT_OVERWRITTEN, FLAG_CONFLICT_MIXED, - FLAG_CONFLICT_REDUNDANT + FLAG_CONFLICT_REDUNDANT, + FLAG_PLUGIN_SELECTED }; enum EContent { @@ -89,7 +90,8 @@ public: HIGHLIGHT_NONE = 0, HIGHLIGHT_INVALID = 1, HIGHLIGHT_CENTER = 2, - HIGHLIGHT_IMPORTANT = 4 + HIGHLIGHT_IMPORTANT = 4, + HIGHLIGHT_PLUGIN = 8 }; enum EEndorsedState { @@ -268,6 +270,12 @@ public: */ virtual void setVersion(const MOBase::VersionInfo &version); + /** + * @brief Controls if mod should be highlighted based on plugin selection + * @param isSelected whether or not the plugin has a selected mod + **/ + virtual void setPluginSelected(const bool &isSelected); + /** * @brief set the newest version of this mod on the nexus * @@ -599,6 +607,8 @@ protected: MOBase::VersionInfo m_Version; + bool m_PluginSelected = false; + private: static QMutex s_Mutex; diff --git a/src/modinfooverwrite.cpp b/src/modinfooverwrite.cpp index 0104998a..6b8c9bd9 100644 --- a/src/modinfooverwrite.cpp +++ b/src/modinfooverwrite.cpp @@ -29,12 +29,18 @@ std::vector ModInfoOverwrite::getFlags() const { std::vector result; result.push_back(FLAG_OVERWRITE); + if (m_PluginSelected) + result.push_back(FLAG_PLUGIN_SELECTED); return result; } int ModInfoOverwrite::getHighlight() const { - return (isValid() ? HIGHLIGHT_IMPORTANT : HIGHLIGHT_INVALID) | HIGHLIGHT_CENTER; + int highlight = (isValid() ? HIGHLIGHT_IMPORTANT : HIGHLIGHT_INVALID) | HIGHLIGHT_CENTER; + auto flags = getFlags(); + if (std::find(flags.begin(), flags.end(), ModInfo::FLAG_PLUGIN_SELECTED) != flags.end()) + highlight |= HIGHLIGHT_PLUGIN; + return highlight; } QString ModInfoOverwrite::getDescription() const diff --git a/src/modinforegular.cpp b/src/modinforegular.cpp index c296d792..9d94002b 100644 --- a/src/modinforegular.cpp +++ b/src/modinforegular.cpp @@ -420,6 +420,9 @@ std::vector ModInfoRegular::getFlags() const if (m_Notes.length() != 0) { result.push_back(ModInfo::FLAG_NOTES); } + if (m_PluginSelected) { + result.push_back(ModInfo::FLAG_PLUGIN_SELECTED); + } return result; } @@ -471,7 +474,12 @@ std::vector ModInfoRegular::getContents() const int ModInfoRegular::getHighlight() const { - return isValid() ? HIGHLIGHT_NONE: HIGHLIGHT_INVALID; + if (!isValid()) + return HIGHLIGHT_INVALID; + auto flags = getFlags(); + if (std::find(flags.begin(), flags.end(), ModInfo::FLAG_PLUGIN_SELECTED) != flags.end()) + return HIGHLIGHT_PLUGIN; + return HIGHLIGHT_NONE; } diff --git a/src/modlist.cpp b/src/modlist.cpp index ffbdee95..c6341251 100644 --- a/src/modlist.cpp +++ b/src/modlist.cpp @@ -338,6 +338,7 @@ QVariant ModList::data(const QModelIndex &modelIndex, int role) const int highlight = modInfo->getHighlight(); if (highlight & ModInfo::HIGHLIGHT_IMPORTANT) return QBrush(Qt::darkRed); else if (highlight & ModInfo::HIGHLIGHT_INVALID) return QBrush(Qt::darkGray); + else if (highlight & ModInfo::HIGHLIGHT_PLUGIN) return QBrush(Qt::darkBlue); } else if (column == COL_VERSION) { if (!modInfo->getNewestVersion().isValid()) { return QVariant(); @@ -350,7 +351,9 @@ QVariant ModList::data(const QModelIndex &modelIndex, int role) const return QVariant(); } else if ((role == Qt::BackgroundRole) || (role == ViewMarkingScrollBar::DEFAULT_ROLE)) { - if (m_Overwrite.find(modIndex) != m_Overwrite.end()) { + if (modInfo->getHighlight() & ModInfo::HIGHLIGHT_PLUGIN) { + return QColor(0, 0, 255, 32); + } else if (m_Overwrite.find(modIndex) != m_Overwrite.end()) { return QColor(0, 255, 0, 32); } else if (m_Overwritten.find(modIndex) != m_Overwritten.end()) { return QColor(255, 0, 0, 32); @@ -685,6 +688,38 @@ int ModList::timeElapsedSinceLastChecked() const return m_LastCheck.elapsed(); } +void ModList::highlightMods(const QItemSelection &selected, const MOShared::DirectoryEntry &directoryEntry) +{ + for (unsigned int i = 0; i < ModInfo::getNumMods(); ++i) { + ModInfo::getByIndex(i)->setPluginSelected(false); + } + for (QModelIndex idx : selected.indexes()) { + QString modName = idx.data().toString(); + + const MOShared::FileEntry::Ptr fileEntry = directoryEntry.findFile(modName.toStdWString()); + if (fileEntry.get() != nullptr) { + QString fileName; + bool archive = false; + std::vector origins; + { + std::vector alternatives = fileEntry->getAlternatives(); + origins.push_back(fileEntry->getOrigin(archive)); + origins.insert(origins.end(), alternatives.begin(), alternatives.end()); + } + for (int originId : origins) { + MOShared::FilesOrigin &origin = directoryEntry.getOriginByID(originId); + for (unsigned int i = 0; i < ModInfo::getNumMods(); ++i) { + if (ModInfo::getByIndex(i)->internalName() == QString::fromStdWString(origin.getName())) { + ModInfo::getByIndex(i)->setPluginSelected(true); + break; + } + } + } + } + } + notifyChange(0, rowCount() - 1); +} + IModList::ModStates ModList::state(unsigned int modIndex) const { IModList::ModStates result; diff --git a/src/modlist.h b/src/modlist.h index 358fd583..bd715107 100644 --- a/src/modlist.h +++ b/src/modlist.h @@ -27,6 +27,7 @@ along with Mod Organizer. If not, see . #include "profile.h" #include +#include #include #include @@ -113,6 +114,8 @@ public: int timeElapsedSinceLastChecked() const; + void highlightMods(const QItemSelection &selected, const MOShared::DirectoryEntry &directoryEntry); + public: /// \copydoc MOBase::IModList::displayName diff --git a/src/organizer_en.ts b/src/organizer_en.ts index f8e6ffaa..cd6277df 100644 --- a/src/organizer_en.ts +++ b/src/organizer_en.ts @@ -820,148 +820,148 @@ p, li { white-space: pre-wrap; } EditExecutablesDialog - + Modify Executables - + List of configured executables - + This is a list of your configured executables. Executables in grey are automatically recognised and can not be modified. - + Title - - + + Name of the executable. This is only for display purposes. - + Binary - - + + Binary to run - + Browse filesystem - + Browse filesystem for the executable to run. - - + + ... - + Start in - + Arguments - - + + Arguments to pass to the application - + Allow the Steam AppID to be used for this executable to be changed. - + Allow the Steam AppID to be used for this executable to be changed. Every game/tool distributed through Steam has a unique ID. MO needs to know this ID to start those programs directly, otherwise the program is started by steam and then MO will not work. By default, MO will use the AppID for the game. Right now the only case I know of where this needs to be overwritten is for the Skyrim Creation Kit which has its own AppID. This overwrite is already preconfigured. - + Overwrite Steam AppID - + Steam AppID to use for this executable that differs from the games AppID. - + Steam AppID to use for this executable that differs from the games AppID. Every game/tool distributed through Steam has a unique ID. MO needs to know this ID to start those programs directly, otherwise the program is started by steam and then MO will not work. By default, MO will use the AppID for the game (usually 72850). Right now the only case I know of where this needs to be overwritten is for the Skyrim Creation Kit which has its own AppID (usually 202480). This overwrite is already preconfigured. - + If this is enabled, new files are created in the specified mod instead of the "Overwrite" mod. - + Create Files in Mod instead of Overwrite (*) - + Use Application's Icon for shortcuts - + (*) This setting is profile-specific - - + + Add an executable - + Add - - + + Remove the selected executable - + Remove - + Close @@ -1131,87 +1131,87 @@ p, li { white-space: pre-wrap; }
- + Extracting files - + failed to create backup - + Mod Name - + Name - + Invalid name - + The name you entered is invalid, please enter a different one. - + File format "%1" not supported - + None of the available installer plugins were able to handle that archive - + no error - + 7z.dll not found - + 7z.dll isn't valid - + archive not found - + failed to open archive - + unsupported archive type - + internal library error - + archive invalid - + unknown archive error @@ -1461,8 +1461,8 @@ p, li { white-space: pre-wrap; } - - + + Refresh @@ -1641,7 +1641,7 @@ p, li { white-space: pre-wrap; } - + Update @@ -1652,7 +1652,7 @@ p, li { white-space: pre-wrap; } - + No Problems @@ -1682,7 +1682,7 @@ Right now this has very limited functionality - + Endorse Mod Organizer @@ -1707,579 +1707,579 @@ Right now this has very limited functionality - + Toolbar - + Desktop - + Start Menu - + Problems - + There are potential problems with your setup - + Everything seems to be in order - + Help on UI - + Documentation Wiki - + Report Issue - + Tutorials - + About - + About Qt - + Name - + Please enter a name for the new profile - + failed to create profile: %1 - + Show tutorial? - + You are starting Mod Organizer for the first time. Do you want to show a tutorial of its basic features? If you choose no you can always start the tutorial from the "Help"-menu. - + Downloads in progress - + There are still downloads in progress, do you really want to quit? - + Plugin "%1" failed: %2 - + Plugin "%1" failed - + Browse Mod Page - + Also in: <br> - + No conflict - + <Edit...> - + Activating Network Proxy - + Choose Mod - + Mod Archive - + Start Tutorial? - + You're about to start a tutorial. For technical reasons it's not possible to end the tutorial early. Continue? - + failed to spawn notepad.exe: %1 - + failed to open %1 - + failed to change origin name: %1 - + failed to move "%1" from mod "%2" to "%3": %4 - + <Contains %1> - + <Checked> - + <Unchecked> - + <Update> - + <Managed by MO> - + <Managed outside MO> - + <No category> - + <Conflicted> - + <Not Endorsed> - + failed to rename mod: %1 - + Overwrite? - + This will replace the existing mod "%1". Continue? - + failed to remove mod "%1" - - - + + + failed to rename "%1" to "%2" - - - - + + + + Confirm - + Remove the following mods?<br><ul>%1</ul> - + failed to remove mod: %1 - - + + Failed - + Installation file no longer exists - + Mods installed with old versions of MO can't be reinstalled in this way. - + You need to be logged in with Nexus to resume a download - - + + You need to be logged in with Nexus to endorse - + Failed to display overwrite dialog: %1 - + Nexus ID for this Mod is unknown - + Web page for this mod is unknown - - - + + + Create Mod... - + This will create an empty mod. Please enter a name: - - + + A mod with this name already exists - + This will move all files from overwrite into a new, regular mod. Please enter a name: - + Not logged in, endorsement information will be wrong - + Continue? - + The versioning scheme decides which version is considered newer than another. This function will guess the versioning scheme under the assumption that the installed version is outdated. - - + + Sorry - + I don't know a versioning scheme where %1 is newer than %2. - + Really enable all visible mods? - + Really disable all visible mods? - + Choose what to export - + Everything - + All installed mods are included in the list - + Active Mods - + Only active (checked) mods from your current profile are included - + Visible - + All mods visible in the mod list are included - + export failed: %1 - + Install Mod... - + Create empty mod - + Enable all visible - + Disable all visible - + Check all for update - + Export to csv... - + All Mods - + Sync to Mods... - + Restore Backup - + Remove Backup... - + Add/Remove Categories - + Replace Categories - + Primary Category - + Change versioning scheme - + Un-ignore update - + Ignore update - + Rename Mod... - + Remove Mod... - + Reinstall Mod - + Un-Endorse - - + + Endorse - + Won't endorse - + Endorsement state unknown - + Ignore missing data - + Visit on Nexus - + Visit web page - + Open in explorer - + Information... - - + + Exception: - - + + Unknown exception - + <All> - + <Multiple> - + %1 more - + Are you sure you want to remove the following %n save(s)?<br><ul>%1</ul><br>Removed saves will be sent to the Recycle Bin. @@ -2287,12 +2287,12 @@ This function will guess the versioning scheme under the assumption that the ins - + Enable Mods... - + Delete %n save(s) @@ -2300,319 +2300,319 @@ This function will guess the versioning scheme under the assumption that the ins - + failed to remove %1 - + failed to create %1 - + Can't change download directory while downloads are in progress! - + failed to write to file %1 - + %1 written - + Select binary - + Binary - + Enter Name - + Please enter a name for the executable - + Not an executable - + This is not a recognized executable. - - + + Replace file? - + There already is a hidden version of this file. Replace it? - - + + File operation failed - - + + Failed to remove "%1". Maybe you lack the required file permissions? - + There already is a visible version of this file. Replace it? - + file not found: %1 - + failed to generate preview for %1 - + Sorry, can't preview anything. This function currently does not support extracting from bsas. - + Update available - + Open/Execute - + Add as Executable - + Preview - + Un-Hide - + Hide - + Write To File... - + Do you want to endorse Mod Organizer on %1 now? - + Thank you! - + Thank you for your endorsement! - + Request to Nexus failed: %1 - - + + failed to read %1: %2 - - + + Error - + failed to extract %1 (errorcode %2) - + Extract BSA - + This archive contains invalid hashes. Some files may be broken. - + Are you sure? - + This will restart MO, continue? - + Edit Categories... - + Deselect filter - + Remove - + Enable all - + Disable all - + Unlock load order - + Lock load order - + depends on missing "%1" - + incompatible with "%1" - + Please wait while LOOT is running - + loot failed. Exit code was: %1 - + failed to start loot - + failed to run loot: %1 - + Errors occured - + Backup of load order created - + Choose backup to restore - + No Backups - + There are no backups to restore - - + + Restore failed - - + + Failed to restore the backup. Errorcode: %1 - + Backup of modlist created - + A file with the same name has already been downloaded. What would you like to do? - + Overwrite - + Rename new file - + Ignore file @@ -2675,16 +2675,21 @@ This function will guess the versioning scheme under the assumption that the ins + MCM Data + + + + invalid content type %1 - + invalid mod index %1 - + remove: invalid mod index %1 @@ -3225,7 +3230,7 @@ p, li { white-space: pre-wrap; } ModInfoOverwrite - + This pseudo mod contains files from the virtual data tree that got modified (i.e. by the construction kit) @@ -3239,13 +3244,13 @@ p, li { white-space: pre-wrap; } - + %1 contains no esp/esm/esl and no asset (textures, meshes, interface, ...) directory %1 contains no esp/esm and no asset (textures, meshes, interface, ...) directory - + Categories: <br> @@ -3254,8 +3259,8 @@ p, li { white-space: pre-wrap; } ModList - Game plugins (esp/esm/esl) - Game plugins (esp/esm) + Game Plugins (ESP/ESM/ESL) + Game plugins (esp/esm/esl) @@ -3299,174 +3304,179 @@ p, li { white-space: pre-wrap; } - + + MCM Configuration + + + + This entry contains files that have been created inside the virtual data tree (i.e. by the construction kit) - + Backup - + No valid game data - + Not endorsed yet - + Overwrites files - + Overwritten files - + Overwrites & Overwritten - + Redundant - + Non-MO - + invalid - + installed version: "%1", newest version: "%2" - + The newest version on Nexus seems to be older than the one you have installed. This could either mean the version you have has been withdrawn (i.e. due to a bug) or the author uses a non-standard versioning scheme and that newest version is actually newer. Either way you may want to "upgrade". - + Categories: <br> - + Invalid name - + drag&drop failed: %1 - + Confirm - + Are you sure you want to remove "%1"? - + Flags - + Content - + Mod Name - + Version - + Priority - + Category - + Nexus ID - + Installation - - + + unknown - + Name of your mods - + Version of the mod (if available) - + Installation priority of your mod. The higher, the more "important" it is and thus overwrites files from mods with lower priority. - + Category of the mod. - + Id of the mod as used on Nexus. - + Emblemes to highlight things that might require attention. - + Depicts the content of the mod:<br><table cellspacing=7><tr><td><img src=":/MO/gui/content/plugin" width=32/></td><td>Game plugins (esp/esm/esl)</tr><tr><td><img src=":/MO/gui/content/interface" width=32/></td><td>Interface</tr><tr><td><img src=":/MO/gui/content/mesh" width=32/></td><td>Meshes</tr><tr><td><img src=":/MO/gui/content/bsa" width=32/></td><td>BSA</tr><tr><td><img src=":/MO/gui/content/texture" width=32/></td><td>Textures</tr><tr><td><img src=":/MO/gui/content/sound" width=32/></td><td>Sounds</tr><tr><td><img src=":/MO/gui/content/music" width=32/></td><td>Music</tr><tr><td><img src=":/MO/gui/content/string" width=32/></td><td>Strings</tr><tr><td><img src=":/MO/gui/content/script" width=32/></td><td>Scripts (Papyrus)</tr><tr><td><img src=":/MO/gui/content/skse" width=32/></td><td>Script Extender plugins</tr><tr><td><img src=":/MO/gui/content/skyproc" width=32/></td><td>SkyProc Patcher</tr></table> Depicts the content of the mod:<br><table cellspacing=7><tr><td><img src=":/MO/gui/content/plugin" width=32/></td><td>Game plugins (esp/esm)</tr><tr><td><img src=":/MO/gui/content/interface" width=32/></td><td>Interface</tr><tr><td><img src=":/MO/gui/content/mesh" width=32/></td><td>Meshes</tr><tr><td><img src=":/MO/gui/content/bsa" width=32/></td><td>BSA</tr><tr><td><img src=":/MO/gui/content/texture" width=32/></td><td>Textures</tr><tr><td><img src=":/MO/gui/content/sound" width=32/></td><td>Sounds</tr><tr><td><img src=":/MO/gui/content/music" width=32/></td><td>Music</tr><tr><td><img src=":/MO/gui/content/string" width=32/></td><td>Strings</tr><tr><td><img src=":/MO/gui/content/script" width=32/></td><td>Scripts (Papyrus)</tr><tr><td><img src=":/MO/gui/content/skse" width=32/></td><td>Script Extender plugins</tr><tr><td><img src=":/MO/gui/content/skyproc" width=32/></td><td>SkyProc Patcher</tr></table> - + Time this mod was installed @@ -3554,189 +3564,189 @@ p, li { white-space: pre-wrap; } OrganizerCore - - + + Failed to write settings - + An error occured trying to update MO settings to %1: %2 - + File is write protected - + Invalid file format (probably a bug) - + Unknown error %1 - + An error occured trying to write back MO settings to %1: %2 - - + + Download started - + Download failed - - + + Installation successful - - + + Configure Mod - - + + This mod contains ini tweaks. Do you want to configure them now? - - + + mod "%1" not found - - + + Installation cancelled - - + + The mod was not installed completely. - + Executable "%1" not found - + Start Steam? - + Steam is required to be running already to correctly start the game. Should MO try to start steam now? - + Error - + No profile set - + Failed to refresh list of esps: %1 - + Multiple esps/esls activated, please check that they don't conflict. - + Download? - + A download has been started but no installed page plugin recognizes it. If you download anyway no information (i.e. version) will be associated with the download. Continue? - + failed to update mod list: %1 - - + + login successful - + Login failed - + Login failed, try again? - + login failed: %1. Download will not be associated with an account - + login failed: %1 - + login failed: %1. You need to log-in with Nexus to update MO. - + Too many esps, esms, and esls enabled - - + + Description missing - + The game doesn't allow more than 255 active plugins (including the official ones) to be loaded. You have to disable some unused plugins or merge some plugins into one. You can find a guide here: <a href="http://wiki.step-project.com/Guide:Merging_Plugins">http://wiki.step-project.com/Guide:Merging_Plugins</a> - + failed to save load order: %1 - + The designated write target "%1" is not enabled. @@ -3833,110 +3843,110 @@ Continue? PluginList - + Name - + Priority - + Mod Index - + Flags - - + + unknown - + Name of your mods - + Load priority of your mod. The higher, the more "important" it is and thus overwrites data from plugins with lower priority. - + The modindex determines the formids of objects originating from this mods. The modindex determins the formids of objects originating from this mods. - + failed to update esp info for file %1 (source id: %2), error: %3 - + esp not found: %1 - - + + Confirm - + Really enable all plugins? - + Really disable all plugins? - + The file containing locked plugin indices is broken - + This plugin can't be disabled (enforced by the game) - + <b>Origin</b>: %1 - + Author - + Description - + Missing Masters - + Enabled Masters - + failed to restore load order for %1 @@ -4289,15 +4299,15 @@ p, li { white-space: pre-wrap; } - - - - + + + + invalid index %1 - + invalid category id %1 @@ -4442,66 +4452,72 @@ p, li { white-space: pre-wrap; } - + game doesn't support a script extender - + + Failed to delete %1 + + + + Failed to deactivate script extender loading - + Failed to remove %1: %2 - - + + Failed to rename %1 to %2 - + Failed to deactivate proxy-dll loading - + Failed to set up script extender loading - + Failed to delete old proxy-dll %1 - + + Failed to copy %1 to %2 - + Failed to overwrite %1 - + Failed to set up proxy-dll loading - + Error - + Failed to create "%1". Your user account probably lacks permission. @@ -4528,75 +4544,75 @@ p, li { white-space: pre-wrap; } - + Could not use configuration settings for game "%1", path "%2". - - + + Please select the game to manage - + No game identified in "%1". The directory is required to contain the game binary and its launcher. - + Please select the game edition you have (MO can't start the game correctly if this is set incorrectly!) - + failed to start application: %1 - + Mod Organizer - + An instance of Mod Organizer is already running - + Failed to set up instance - + Please use "Help" from the toolbar to get usage instructions to all elements - - + + <Manage...> - + failed to parse profile %1: %2 - + Failed to start "%1" - + Waiting - + Please press OK once you're logged into steam. @@ -4617,12 +4633,12 @@ p, li { white-space: pre-wrap; } - + failed to access %1 - + failed to set file time %1 diff --git a/src/pluginlist.cpp b/src/pluginlist.cpp index 4420bf17..a215b9d3 100644 --- a/src/pluginlist.cpp +++ b/src/pluginlist.cpp @@ -21,6 +21,7 @@ along with Mod Organizer. If not, see . #include "settings.h" #include "scopeguard.h" #include "modinfo.h" +#include "viewmarkingscrollbar.h" #include #include #include @@ -107,6 +108,28 @@ QString PluginList::getColumnToolTip(int column) } } +void PluginList::highlightPlugins(const QItemSelection &selected, const MOShared::DirectoryEntry &directoryEntry) +{ + for (auto &esp : m_ESPs) { + esp.m_ModSelected = false; + } + for (QModelIndex idx : selected.indexes()) { + ModInfo::Ptr selectedMod = ModInfo::getByIndex(idx.data(Qt::UserRole + 1).toInt()); + if (!selectedMod.isNull()) { + QDir dir(selectedMod->absolutePath()); + QStringList plugins = dir.entryList(QStringList() << "*.esp" << "*.esm" << "*.esl"); + if (plugins.size() > 0) { + for (auto plugin : plugins) { + std::map::iterator iter = m_ESPsByName.find(plugin.toLower()); + if (iter != m_ESPsByName.end()) { + m_ESPs[iter->second].m_ModSelected = true; + } + } + } + } + } + emit dataChanged(this->index(0, 0), this->index(m_ESPs.size() - 1, this->columnCount() - 1)); +} void PluginList::refresh(const QString &profileName , const DirectoryEntry &baseDirectory @@ -752,9 +775,16 @@ QVariant PluginList::data(const QModelIndex &modelIndex, int role) const } } else if (role == Qt::ForegroundRole) { if ((modelIndex.column() == COL_NAME) && - m_ESPs[index].m_ForceEnabled) { + m_ESPs[index].m_ForceEnabled) { return QBrush(Qt::gray); } + } else if (role == Qt::BackgroundRole + || (role == ViewMarkingScrollBar::DEFAULT_ROLE)) { + if (m_ESPs[index].m_ModSelected) { + return QColor(0, 0, 255, 32); + } else { + return QVariant(); + } } else if (role == Qt::FontRole) { QFont result; if (m_ESPs[index].m_IsMaster) { @@ -1134,7 +1164,7 @@ PluginList::ESPInfo::ESPInfo(const QString &name, bool enabled, const QString &originName, const QString &fullPath, bool hasIni) : m_Name(name), m_FullPath(fullPath), m_Enabled(enabled), m_ForceEnabled(enabled), - m_Priority(0), m_LoadOrder(-1), m_OriginName(originName), m_HasIni(hasIni) + m_Priority(0), m_LoadOrder(-1), m_OriginName(originName), m_HasIni(hasIni), m_ModSelected(false) { try { ESP::File file(ToWString(fullPath)); diff --git a/src/pluginlist.h b/src/pluginlist.h index e98f5c41..19e98989 100644 --- a/src/pluginlist.h +++ b/src/pluginlist.h @@ -200,6 +200,8 @@ public: static QString getColumnName(int column); static QString getColumnToolTip(int column); + void highlightPlugins(const QItemSelection &selected, const MOShared::DirectoryEntry &directoryEntry); + void refreshLoadOrder(); void disconnectSlots(); @@ -277,6 +279,7 @@ private: QString m_OriginName; bool m_IsMaster; bool m_IsLight; + bool m_ModSelected; QString m_Author; QString m_Description; bool m_HasIni; diff --git a/src/pluginlistview.cpp b/src/pluginlistview.cpp new file mode 100644 index 00000000..0fcf8183 --- /dev/null +++ b/src/pluginlistview.cpp @@ -0,0 +1,58 @@ +#include "pluginlistview.h" +#include +#include +#include + + +class PluginListViewStyle : public QProxyStyle { +public: + PluginListViewStyle(QStyle *style, int indentation); + + void drawPrimitive(PrimitiveElement element, const QStyleOption *option, + QPainter *painter, const QWidget *widget = 0) const; +private: + int m_Indentation; +}; + +PluginListViewStyle::PluginListViewStyle(QStyle *style, int indentation) + : QProxyStyle(style), m_Indentation(indentation) +{ +} + +void PluginListViewStyle::drawPrimitive(PrimitiveElement element, const QStyleOption *option, + QPainter *painter, const QWidget *widget) const +{ + if (element == QStyle::PE_IndicatorItemViewItemDrop && !option->rect.isNull()) { + QStyleOption opt(*option); + opt.rect.setLeft(m_Indentation); + if (widget) { + opt.rect.setRight(widget->width() - 5); // 5 is an arbitrary value that seems to work ok + } + QProxyStyle::drawPrimitive(element, &opt, painter, widget); + } + else { + QProxyStyle::drawPrimitive(element, option, painter, widget); + } +} + +PluginListView::PluginListView(QWidget *parent) + : QTreeView(parent) + , m_Scrollbar(new ViewMarkingScrollBar(this->model(), this)) +{ + setVerticalScrollBar(m_Scrollbar); +} + +void PluginListView::dragEnterEvent(QDragEnterEvent *event) +{ + emit dropModeUpdate(event->mimeData()->hasUrls()); + + QTreeView::dragEnterEvent(event); +} + +void PluginListView::setModel(QAbstractItemModel *model) +{ + QTreeView::setModel(model); + setVerticalScrollBar(new ViewMarkingScrollBar(model, this)); +} + +#pragma once diff --git a/src/pluginlistview.h b/src/pluginlistview.h new file mode 100644 index 00000000..bdd4ee61 --- /dev/null +++ b/src/pluginlistview.h @@ -0,0 +1,24 @@ +#ifndef PLUGINLISTVIEW_H +#define PLUGINLISTVIEW_H + +#include +#include +#include "viewmarkingscrollbar.h" + +class PluginListView : public QTreeView +{ + Q_OBJECT +public: + explicit PluginListView(QWidget *parent = 0); + virtual void dragEnterEvent(QDragEnterEvent *event); + virtual void setModel(QAbstractItemModel *model); +signals: + void dropModeUpdate(bool dropOnRows); + + public slots: +private: + + ViewMarkingScrollBar *m_Scrollbar; +}; + +#endif // PLUGINLISTVIEW_H -- cgit v1.3.1 From 7b45d807d6c2c8b5663ec53183e81e16a5baf739 Mon Sep 17 00:00:00 2001 From: Jeremy Rimpo Date: Fri, 15 Dec 2017 15:01:39 -0600 Subject: Restore archive tab and partial functionality --- src/iuserinterface.h | 4 + src/mainwindow.cpp | 191 ++++++++++++++++++++++++++++++++++++++++++++++- src/mainwindow.h | 13 ++++ src/mainwindow.ui | 107 ++++++++++++++++++++++++++ src/modinfo.cpp | 2 +- src/modinfooverwrite.cpp | 2 +- src/modinforegular.cpp | 2 +- src/modlist.cpp | 2 +- src/organizercore.cpp | 13 ++++ src/organizercore.h | 1 + 10 files changed, 331 insertions(+), 6 deletions(-) (limited to 'src/mainwindow.ui') diff --git a/src/iuserinterface.h b/src/iuserinterface.h index 255c7ac0..7ce71c24 100644 --- a/src/iuserinterface.h +++ b/src/iuserinterface.h @@ -28,6 +28,10 @@ public: virtual void displayModInformation(ModInfo::Ptr modInfo, unsigned int index, int tab) = 0; + virtual void updateBSAList(const QStringList &defaultArchives, const QStringList &activeArchives) = 0; + + virtual MOBase::DelayedFileWriterBase &archivesWriter() = 0; + virtual ILockedWaitingForProcess* lock() = 0; virtual void unlock() = 0; }; diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 85808e8d..141bcf2a 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -200,6 +200,7 @@ MainWindow::MainWindow(QSettings &initSettings , m_OrganizerCore(organizerCore) , m_PluginContainer(pluginContainer) , m_DidUpdateMasterList(false) + , m_ArchiveListWriter(std::bind(&MainWindow::saveArchiveList, this)) { QWebEngineProfile::defaultProfile()->setPersistentCookiesPolicy(QWebEngineProfile::NoPersistentCookies); QWebEngineProfile::defaultProfile()->setHttpCacheMaximumSize(52428800); @@ -278,6 +279,8 @@ MainWindow::MainWindow(QSettings &initSettings ui->espList->setItemDelegateForColumn(PluginList::COL_FLAGS, new GenericIconDelegate(ui->espList)); 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(), @@ -358,6 +361,9 @@ MainWindow::MainWindow(QSettings &initSettings connect(this, SIGNAL(styleChanged(QString)), this, SLOT(updateStyle(QString))); + 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))); @@ -1378,6 +1384,147 @@ static QStringList toStringList(InputIterator current, InputIterator end) return result; } +void MainWindow::updateBSAList(const QStringList &defaultArchives, const QStringList &activeArchives) +{ + m_DefaultArchives = defaultArchives; + ui->bsaList->clear(); + ui->bsaList->header()->setSectionResizeMode(QHeaderView::ResizeToContents); + std::vector> items; + + BSAInvalidation * invalidation = m_OrganizerCore.managedGame()->feature(); + std::vector files = m_OrganizerCore.directoryStructure()->getFiles(); + + QStringList plugins = m_OrganizerCore.findFiles("", [](const QString &fileName) -> bool { + return fileName.endsWith(".esp", Qt::CaseInsensitive) + || fileName.endsWith(".esm", 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)) { + return true; + } + } + return false; + }; + + for (FileEntry::Ptr current : files) { + QFileInfo fileInfo(ToQString(current->getName().c_str())); + + if (fileInfo.suffix().toLower() == "bsa" || fileInfo.suffix().toLower() == "ba2") { + int index = activeArchives.indexOf(fileInfo.fileName()); + if (index == -1) { + index = 0xFFFF; + } + else { + index += 2; + } + + if ((invalidation != nullptr) && invalidation->isInvalidationBSA(fileInfo.fileName())) { + index = 1; + } + + int originId = current->getOrigin(); + FilesOrigin & origin = m_OrganizerCore.directoryStructure()->getOriginByID(originId); + + 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->setCheckState(0, (index != -1) ? Qt::Checked : Qt::Unchecked); + newItem->setData(0, Qt::UserRole, false); + if (m_OrganizerCore.settings().forceEnableCoreFiles() + && defaultArchives.contains(fileInfo.fileName())) { + newItem->setCheckState(0, Qt::Checked); + newItem->setDisabled(true); + newItem->setData(0, Qt::UserRole, true); + } else if (fileInfo.fileName().compare("update.bsa", Qt::CaseInsensitive) == 0) { + newItem->setCheckState(0, Qt::Checked); + newItem->setDisabled(true); + } else if (hasAssociatedPlugin(fileInfo.fileName())) { + newItem->setCheckState(0, Qt::Checked); + 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) { + int originID = iter->second->data(1, Qt::UserRole).toInt(); + + FilesOrigin origin = m_OrganizerCore.directoryStructure()->getOriginByID(originID); + QString modName("data"); + unsigned int modIndex = ModInfo::getIndex(ToQString(origin.getName())); + if (modIndex != UINT_MAX) { + ModInfo::Ptr modInfo = ModInfo::getByIndex(modIndex); + modName = modInfo->name(); + } + QList items = ui->bsaList->findItems(modName, Qt::MatchFixedString); + QTreeWidgetItem * subItem = nullptr; + if (items.length() > 0) { + subItem = items.at(0); + } + else { + subItem = new QTreeWidgetItem(QStringList(modName)); + subItem->setFlags(subItem->flags() & ~Qt::ItemIsDragEnabled); + ui->bsaList->addTopLevelItem(subItem); + } + subItem->addChild(iter->second); + subItem->setExpanded(true); + } + checkBSAList(); +} + +void MainWindow::checkBSAList() +{ + DataArchives * archives = m_OrganizerCore.managedGame()->feature(); + + if (archives != nullptr) { + ui->bsaList->blockSignals(true); + ON_BLOCK_EXIT([&]() { ui->bsaList->blockSignals(false); }); + + QStringList defaultArchives = archives->archives(m_OrganizerCore.currentProfile()); + + bool warning = false; + + for (int i = 0; i < ui->bsaList->topLevelItemCount(); ++i) { + bool modWarning = false; + QTreeWidgetItem * tlItem = ui->bsaList->topLevelItem(i); + for (int j = 0; j < tlItem->childCount(); ++j) { + QTreeWidgetItem * item = tlItem->child(j); + QString filename = item->text(0); + item->setIcon(0, QIcon()); + item->setToolTip(0, QString()); + + if (item->checkState(0) == Qt::Unchecked) { + if (defaultArchives.contains(filename)) { + item->setIcon(0, QIcon(":/MO/gui/warning")); + item->setToolTip(0, tr("This bsa is enabled in the ini file so it may be required!")); + modWarning = true; + } + } + } + if (modWarning) { + ui->bsaList->expandItem(ui->bsaList->topLevelItem(i)); + warning = true; + } + } + if (warning) { + ui->tabWidget->setTabIcon(1, QIcon(":/MO/gui/warning")); + } else { + ui->tabWidget->setTabIcon(1, QIcon()); + } + } +} + void MainWindow::saveModMetas() { for (unsigned int i = 0; i < ModInfo::getNumMods(); ++i) { @@ -1524,10 +1671,12 @@ void MainWindow::on_tabWidget_currentChanged(int index) if (index == 0) { m_OrganizerCore.refreshESPList(); } else if (index == 1) { - refreshDataTree(); + m_OrganizerCore.refreshBSAList(); } else if (index == 2) { - refreshSaveList(); + refreshDataTree(); } else if (index == 3) { + refreshSaveList(); + } else if (index == 4) { ui->downloadView->scrollToBottom(); } } @@ -1806,6 +1955,7 @@ void MainWindow::modorder_changed() } m_OrganizerCore.refreshBSAList(); m_OrganizerCore.currentProfile()->modlistWriter().write(); + m_ArchiveListWriter.write(); m_OrganizerCore.directoryStructure()->getFileRegister()->sortOrigins(); { // refresh selection @@ -2741,6 +2891,31 @@ void MainWindow::replaceCategories_MenuHandler() { refreshFilters(); } +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); + for (int j = 0; j < tlItem->childCount(); ++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")); + } + } + } + } + if (archiveFile.commitIfDifferent(m_ArchiveListHash)) { + qDebug("%s saved", qPrintable(QDir::toNativeSeparators(m_OrganizerCore.currentProfile()->getArchivesFileName()))); + } + } else { + qWarning("archive list not initialised"); + } +} + void MainWindow::checkModsForUpdates() { statusBar()->show(); @@ -3957,6 +4132,12 @@ void MainWindow::displayColumnSelection(const QPoint &pos) } } +void MainWindow::on_bsaList_itemChanged(QTreeWidgetItem*, int) +{ + m_ArchiveListWriter.write(); + m_CheckBSATimer.start(500); +} + void MainWindow::on_actionProblems_triggered() { ProblemsDialog problems(m_PluginContainer.plugins(), this); @@ -4543,6 +4724,12 @@ void MainWindow::on_categoriesOrBtn_toggled(bool checked) } } +void MainWindow::on_managedArchiveLabel_linkHovered(const QString&) +{ + QToolTip::showText(QCursor::pos(), + ui->managedArchiveLabel->toolTip()); +} + void MainWindow::dragEnterEvent(QDragEnterEvent *event) { //Accept copy or move drags to the download window. Link drags are not diff --git a/src/mainwindow.h b/src/mainwindow.h index 575bf020..45a41137 100644 --- a/src/mainwindow.h +++ b/src/mainwindow.h @@ -120,12 +120,15 @@ public: virtual void unlock() override; bool addProfile(); + void updateBSAList(const QStringList &defaultArchives, const QStringList &activeArchives); void refreshDataTree(); void refreshSaveList(); void setModListSorting(int index); void setESPListSorting(int index); + void saveArchiveList(); + void registerPluginTool(MOBase::IPluginTool *tool); void registerModPage(MOBase::IPluginModPage *modPage); @@ -148,6 +151,8 @@ public: virtual bool closeWindow(); virtual void setWindowEnabled(bool enabled); + virtual MOBase::DelayedFileWriterBase &archivesWriter() override { return m_ArchiveListWriter; } + public slots: void displayColumnSelection(const QPoint &pos); @@ -346,6 +351,8 @@ private: std::vector m_RemoveWidget; + QByteArray m_ArchiveListHash; + bool m_DidUpdateMasterList; LockedDialogBase *m_LockDialog { nullptr }; @@ -355,6 +362,8 @@ private: std::vector> m_PersistedGeometry; + MOBase::DelayedFileWriter m_ArchiveListWriter; + enum class ShortcutType { Toolbar, Desktop, @@ -478,6 +487,8 @@ private slots: void startExeAction(); + void checkBSAList(); + void updateProblemsButton(); void saveModMetas(); @@ -552,6 +563,7 @@ private slots: // ui slots void on_categoriesList_itemSelectionChanged(); void on_linkButton_pressed(); void on_showHiddenBox_toggled(bool checked); + void on_bsaList_itemChanged(QTreeWidgetItem *item, int column); void on_bossButton_clicked(); void on_saveButton_clicked(); @@ -561,6 +573,7 @@ private slots: // ui slots void on_actionCopy_Log_to_Clipboard_triggered(); void on_categoriesAndBtn_toggled(bool checked); void on_categoriesOrBtn_toggled(bool checked); + void on_managedArchiveLabel_linkHovered(const QString &link); }; diff --git a/src/mainwindow.ui b/src/mainwindow.ui index 26b9e375..1e7339b8 100644 --- a/src/mainwindow.ui +++ b/src/mainwindow.ui @@ -902,6 +902,113 @@ p, li { white-space: pre-wrap; } + + + Archives + + + + 6 + + + + 6 + + + 6 + + + 6 + + + + + + + + + + true + + + + + + + <html><head/><body><p>BSAs are bundles of game assets (textures, scripts, ...). By default, the engine loads these bundles in a separate step from loose files. MO can manage those archives to align their load order with that of loose files:</p><p>If archives are <span style=" font-weight:600;">managed</span>, their load order is specified by the priority of the corresponding mod (left pane), the same as the loose files. You can manually enable any BSA that has no corresponding plugin active.<br/></p><p>If archives are <span style=" font-weight:600;">not managed</span> their load order is specified by the priority of the corresponding plugin (right pane, plugins tab). You can then not manually enable BSAs where the plugin isn't active.</p><p>In either case you can not disable archives if there is a matching plugin, the game will load them no matter what.</p></body></html> + + + <html><head/><body><p>Have MO manage archives (<a href="#"><span style=" text-decoration: underline; color:#0000ff;">read more</span></a>)</p></body></html> + + + true + + + + + + + + + Qt::CustomContextMenu + + + List of available BS Archives. Archives not checked here are not managed by MO and ignore installation order. + + + BSA files are archives (comparable to .zip files) that contain data assets (meshes, textures, ...) to be used by the game. As such they "compete" with loose files in your data directory over which is loaded. + By default, BSAs that share their base name with an enabled ESP (i.e. plugin.esp and plugin.bsa) are automatically loaded and will have precedence over all loose files, the installation order you set up to the left is then ignored! + + BSAs checked here are loaded in such a way that your installation order is obeyed properly. + + + QAbstractItemView::NoEditTriggers + + + true + + + false + + + false + + + QAbstractItemView::DragDrop + + + Qt::MoveAction + + + QAbstractItemView::SingleSelection + + + QAbstractItemView::SelectRows + + + 20 + + + true + + + 1 + + + false + + + 200 + + + + File + + + + + + Data diff --git a/src/modinfo.cpp b/src/modinfo.cpp index 4f74086f..d3687d31 100644 --- a/src/modinfo.cpp +++ b/src/modinfo.cpp @@ -94,7 +94,7 @@ QString ModInfo::getContentTypeName(int contentType) case CONTENT_PLUGIN: return tr("Plugins"); case CONTENT_TEXTURE: return tr("Textures"); case CONTENT_MESH: return tr("Meshes"); - case CONTENT_BSA: return tr("BSA"); + case CONTENT_BSA: return tr("Bethesda Archive"); case CONTENT_INTERFACE: return tr("UI Changes"); case CONTENT_SOUND: return tr("Sound Effects"); case CONTENT_SCRIPT: return tr("Scripts"); diff --git a/src/modinfooverwrite.cpp b/src/modinfooverwrite.cpp index 6b8c9bd9..360212c0 100644 --- a/src/modinfooverwrite.cpp +++ b/src/modinfooverwrite.cpp @@ -53,7 +53,7 @@ QStringList ModInfoOverwrite::archives() const { QStringList result; QDir dir(this->absolutePath()); - for (const QString &archive : dir.entryList(QStringList("*.bsa"))) { + for (const QString &archive : dir.entryList(QStringList({ "*.bsa", "*.ba2" }))) { result.append(this->absolutePath() + "/" + archive); } return result; diff --git a/src/modinforegular.cpp b/src/modinforegular.cpp index 9d94002b..5486bb2c 100644 --- a/src/modinforegular.cpp +++ b/src/modinforegular.cpp @@ -551,7 +551,7 @@ QStringList ModInfoRegular::archives() const { QStringList result; QDir dir(this->absolutePath()); - for (const QString &archive : dir.entryList(QStringList("*.bsa"))) { + for (const QString &archive : dir.entryList(QStringList({ "*.bsa", "*.ba2" }))) { result.append(this->absolutePath() + "/" + archive); } return result; diff --git a/src/modlist.cpp b/src/modlist.cpp index 53350c59..d7b5f471 100644 --- a/src/modlist.cpp +++ b/src/modlist.cpp @@ -64,7 +64,7 @@ ModList::ModList(QObject *parent) m_ContentIcons[ModInfo::CONTENT_PLUGIN] = std::make_tuple(":/MO/gui/content/plugin", tr("Game Plugins (ESP/ESM/ESL)")); m_ContentIcons[ModInfo::CONTENT_INTERFACE] = std::make_tuple(":/MO/gui/content/interface", tr("Interface")); m_ContentIcons[ModInfo::CONTENT_MESH] = std::make_tuple(":/MO/gui/content/mesh", tr("Meshes")); - m_ContentIcons[ModInfo::CONTENT_BSA] = std::make_tuple(":/MO/gui/content/bsa", tr("BSA")); + m_ContentIcons[ModInfo::CONTENT_BSA] = std::make_tuple(":/MO/gui/content/bsa", tr("Bethesda Archive")); m_ContentIcons[ModInfo::CONTENT_SCRIPT] = std::make_tuple(":/MO/gui/content/script", tr("Scripts (Papyrus)")); m_ContentIcons[ModInfo::CONTENT_SKSE] = std::make_tuple(":/MO/gui/content/skse", tr("Script Extender Plugin")); m_ContentIcons[ModInfo::CONTENT_SKYPROC] = std::make_tuple(":/MO/gui/content/skyproc", tr("SkyProc Patcher")); diff --git a/src/organizercore.cpp b/src/organizercore.cpp index dd77f19a..1a336d91 100644 --- a/src/organizercore.cpp +++ b/src/organizercore.cpp @@ -1494,6 +1494,10 @@ void OrganizerCore::refreshBSAList() if (m_ActiveArchives.isEmpty()) { m_ActiveArchives = m_DefaultArchives; } + + if (m_UserInterface != nullptr) { + m_UserInterface->updateBSAList(m_DefaultArchives, m_ActiveArchives); + } m_ArchivesInit = true; } @@ -1572,6 +1576,9 @@ void OrganizerCore::updateModInDirectoryStructure(unsigned int index, // now we need to refresh the bsa list and save it so there is no confusion // about what archives are avaiable and active refreshBSAList(); + if (m_UserInterface != nullptr) { + m_UserInterface->archivesWriter().writeImmediately(false); + } std::vector archives = enabledArchives(); m_DirectoryRefresher.setMods( @@ -1729,6 +1736,9 @@ void OrganizerCore::modStatusChanged(unsigned int index) = m_DirectoryStructure->getOriginByName(ToWString(modInfo->name())); origin.enable(false); } + if (m_UserInterface != nullptr) { + m_UserInterface->archivesWriter().write(); + } } modInfo->clearCaches(); @@ -1885,6 +1895,9 @@ bool OrganizerCore::saveCurrentLists() try { savePluginList(); + if (m_UserInterface != nullptr) { + m_UserInterface->archivesWriter().write(); + } } catch (const std::exception &e) { reportError(tr("failed to save load order: %1").arg(e.what())); } diff --git a/src/organizercore.h b/src/organizercore.h index cf030e0a..decb3d01 100644 --- a/src/organizercore.h +++ b/src/organizercore.h @@ -315,6 +315,7 @@ private: ModList m_ModList; PluginList m_PluginList; + QList> m_PostLoginTasks; QList> m_PostRefreshTasks; -- cgit v1.3.1 From 385a888c0bc8e5b4d4a6791e46eed3b5963c403a Mon Sep 17 00:00:00 2001 From: Jeremy Rimpo Date: Sun, 17 Dec 2017 21:33:04 -0600 Subject: Implement file priority for loose files > archives --- src/mainwindow.cpp | 24 +++++++-------- src/mainwindow.ui | 30 +++++++++--------- src/modinfo.cpp | 3 +- src/modinfodialog.cpp | 10 +++--- src/modinfowithconflictinfo.cpp | 10 +++--- src/modlist.cpp | 11 +++---- src/organizercore.cpp | 8 ++--- src/pluginlist.cpp | 26 ++++++++-------- src/shared/directoryentry.cpp | 68 ++++++++++++++++++++++------------------- src/shared/directoryentry.h | 6 ++-- src/syncoverwritedialog.cpp | 6 ++-- 11 files changed, 103 insertions(+), 99 deletions(-) (limited to 'src/mainwindow.ui') diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 141bcf2a..22e99e37 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -1148,17 +1148,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 alternatives = current->getAlternatives(); + std::vector> alternatives = current->getAlternatives(); if (!alternatives.empty()) { std::wostringstream altString; altString << ToWString(tr("Also in:
")); - for (std::vector::iterator altIter = alternatives.begin(); + for (std::vector>::iterator altIter = alternatives.begin(); altIter != alternatives.end(); ++altIter) { if (altIter != alternatives.begin()) { altString << " , "; } - altString << "" << m_OrganizerCore.directoryStructure()->getOriginByID(*altIter).getName() << ""; + altString << "" << m_OrganizerCore.directoryStructure()->getOriginByID(altIter->first).getName() << ""; } fileChild->setToolTip(1, QString("%1").arg(ToQString(altString.str()))); fileChild->setForeground(1, QBrush(Qt::red)); @@ -1396,7 +1396,8 @@ void MainWindow::updateBSAList(const QStringList &defaultArchives, const QString 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 { @@ -1434,7 +1435,7 @@ void MainWindow::updateBSAList(const QStringList &defaultArchives, const QString << 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() @@ -1448,6 +1449,9 @@ void MainWindow::updateBSAList(const QStringList &defaultArchives, const QString } else if (hasAssociatedPlugin(fileInfo.fileName())) { newItem->setCheckState(0, Qt::Checked); newItem->setDisabled(true); + } else { + newItem->setCheckState(0, Qt::Unchecked); + newItem->setDisabled(true); } if (index < 0) index = 0; @@ -2900,11 +2904,7 @@ void MainWindow::saveArchiveList() for (int j = 0; j < tlItem->childCount(); ++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")); } } } @@ -3763,8 +3763,8 @@ void MainWindow::previewDataFile() }; addFunc(file->getOrigin()); - for (int i : file->getAlternatives()) { - addFunc(i); + for (auto alt : file->getAlternatives()) { + addFunc(alt.first); } if (preview.numVariants() > 0) { preview.exec(); diff --git a/src/mainwindow.ui b/src/mainwindow.ui index 1e7339b8..d8fa1432 100644 --- a/src/mainwindow.ui +++ b/src/mainwindow.ui @@ -922,23 +922,23 @@ p, li { white-space: pre-wrap; } - - - - - - - true - - - + + + + + + + + + + - <html><head/><body><p>BSAs are bundles of game assets (textures, scripts, ...). By default, the engine loads these bundles in a separate step from loose files. MO can manage those archives to align their load order with that of loose files:</p><p>If archives are <span style=" font-weight:600;">managed</span>, their load order is specified by the priority of the corresponding mod (left pane), the same as the loose files. You can manually enable any BSA that has no corresponding plugin active.<br/></p><p>If archives are <span style=" font-weight:600;">not managed</span> their load order is specified by the priority of the corresponding plugin (right pane, plugins tab). You can then not manually enable BSAs where the plugin isn't active.</p><p>In either case you can not disable archives if there is a matching plugin, the game will load them no matter what.</p></body></html> + <html><head/><body><p>BSAs / BA2s are bundles of game assets (textures, scripts, etc.). By default, the engine loads these bundles in a separate step from loose files. <p>Their load order is specified by the priority of the corresponding plugin (right pane, plugins tab).</p><p>If there is a matching plugin, the game will load them no matter what.</p></body></html> - <html><head/><body><p>Have MO manage archives (<a href="#"><span style=" text-decoration: underline; color:#0000ff;">read more</span></a>)</p></body></html> + <html><head/><body><p>Currently detected archives. (<a href="#"><span style=" text-decoration: underline; color:#0000ff;">What is an archive?</span></a>)</p></body></html> true @@ -965,7 +965,7 @@ p, li { white-space: pre-wrap; } QAbstractItemView::NoEditTriggers - true + false false @@ -974,10 +974,10 @@ p, li { white-space: pre-wrap; } false - QAbstractItemView::DragDrop + QAbstractItemView::NoDragDrop - Qt::MoveAction + Qt::IgnoreAction QAbstractItemView::SingleSelection diff --git a/src/modinfo.cpp b/src/modinfo.cpp index d3687d31..c14eedb7 100644 --- a/src/modinfo.cpp +++ b/src/modinfo.cpp @@ -123,9 +123,10 @@ ModInfo::Ptr ModInfo::getByIndex(unsigned int index) { QMutexLocker locker(&s_Mutex); - if (index >= s_Collection.size()) { + if (index >= s_Collection.size() && index != ULONG_MAX) { throw MyException(tr("invalid mod index %1").arg(index)); } + if (index == ULONG_MAX) return s_Collection[ModInfo::getIndex("Overwrite")]; return s_Collection[index]; } diff --git a/src/modinfodialog.cpp b/src/modinfodialog.cpp index d43808b6..ccd2a122 100644 --- a/src/modinfodialog.cpp +++ b/src/modinfodialog.cpp @@ -266,22 +266,22 @@ void ModInfoDialog::refreshLists() QString fileName = relativeName.mid(0).prepend(m_RootPath); bool archive; if ((*iter)->getOrigin(archive) == m_Origin->getID()) { - std::vector alternatives = (*iter)->getAlternatives(); + std::vector> alternatives = (*iter)->getAlternatives(); if (!alternatives.empty()) { std::wostringstream altString; - for (std::vector::iterator altIter = alternatives.begin(); + for (std::vector>::iterator altIter = alternatives.begin(); altIter != alternatives.end(); ++altIter) { if (altIter != alternatives.begin()) { altString << ", "; } - altString << m_Directory->getOriginByID(*altIter).getName(); + altString << m_Directory->getOriginByID(altIter->first).getName(); } QStringList fields(relativeName.prepend("...")); fields.append(ToQString(altString.str())); QTreeWidgetItem *item = new QTreeWidgetItem(fields); item->setData(0, Qt::UserRole, fileName); - item->setData(1, Qt::UserRole, ToQString(m_Directory->getOriginByID(alternatives[0]).getName())); - item->setData(1, Qt::UserRole + 1, alternatives[0]); + item->setData(1, Qt::UserRole, ToQString(m_Directory->getOriginByID(alternatives.begin()->first).getName())); + item->setData(1, Qt::UserRole + 1, alternatives.begin()->first); item->setData(1, Qt::UserRole + 2, archive); ui->overwriteTree->addTopLevelItem(item); ++numOverwrite; diff --git a/src/modinfowithconflictinfo.cpp b/src/modinfowithconflictinfo.cpp index fbf2345f..b8ece783 100644 --- a/src/modinfowithconflictinfo.cpp +++ b/src/modinfowithconflictinfo.cpp @@ -57,8 +57,8 @@ void ModInfoWithConflictInfo::doConflictCheck() const std::vector files = origin.getFiles(); // for all files in this origin for (FileEntry::Ptr file : files) { - const std::vector &alternatives = file->getAlternatives(); - if ((alternatives.size() == 0) || (alternatives[0] == dataID)) { + const std::vector> &alternatives = file->getAlternatives(); + if ((alternatives.size() == 0) || (alternatives.begin()->first == dataID)) { // no alternatives -> no conflict providesAnything = true; } else { @@ -71,9 +71,9 @@ void ModInfoWithConflictInfo::doConflictCheck() const } // for all non-providing alternative origins - for (int altId : alternatives) { - if ((altId != dataID) && (altId != origin.getID())) { - FilesOrigin &altOrigin = (*m_DirectoryStructure)->getOriginByID(altId); + for (auto altInfo : alternatives) { + if ((altInfo.first != dataID) && (altInfo.first != origin.getID())) { + FilesOrigin &altOrigin = (*m_DirectoryStructure)->getOriginByID(altInfo.first); unsigned int altIndex = ModInfo::getIndex(ToQString(altOrigin.getName())); if (origin.getPriority() > altOrigin.getPriority()) { m_OverwriteList.insert(altIndex); diff --git a/src/modlist.cpp b/src/modlist.cpp index d7b5f471..3afa94b5 100644 --- a/src/modlist.cpp +++ b/src/modlist.cpp @@ -701,14 +701,13 @@ void ModList::highlightMods(const QItemSelection &selected, const MOShared::Dire if (fileEntry.get() != nullptr) { QString fileName; bool archive = false; - std::vector origins; + std::vector> origins; { - std::vector alternatives = fileEntry->getAlternatives(); - origins.push_back(fileEntry->getOrigin(archive)); - origins.insert(origins.end(), alternatives.begin(), alternatives.end()); + std::vector> alternatives = fileEntry->getAlternatives(); + origins.insert(origins.end(), std::pair(fileEntry->getOrigin(archive), fileEntry->getArchive())); } - for (int originId : origins) { - MOShared::FilesOrigin &origin = directoryEntry.getOriginByID(originId); + for (auto originInfo : origins) { + MOShared::FilesOrigin &origin = directoryEntry.getOriginByID(originInfo.first); for (unsigned int i = 0; i < ModInfo::getNumMods(); ++i) { if (ModInfo::getByIndex(i)->internalName() == QString::fromStdWString(origin.getName())) { ModInfo::getByIndex(i)->setPluginSelected(true); diff --git a/src/organizercore.cpp b/src/organizercore.cpp index 1a336d91..98920479 100644 --- a/src/organizercore.cpp +++ b/src/organizercore.cpp @@ -1002,9 +1002,9 @@ QStringList OrganizerCore::getFileOrigins(const QString &fileName) const if (file.get() != nullptr) { result.append(ToQString( m_DirectoryStructure->getOriginByID(file->getOrigin()).getName())); - foreach (int i, file->getAlternatives()) { + foreach (auto i, file->getAlternatives()) { result.append( - ToQString(m_DirectoryStructure->getOriginByID(i).getName())); + ToQString(m_DirectoryStructure->getOriginByID(i.first).getName())); } } else { qDebug("%s not found", qPrintable(fileName)); @@ -1030,9 +1030,9 @@ QList OrganizerCore::findFileInfos( m_DirectoryStructure->getOriginByID(file->getOrigin(fromArchive)) .getName())); info.archive = fromArchive ? ToQString(file->getArchive()) : ""; - foreach (int idx, file->getAlternatives()) { + foreach (auto idx, file->getAlternatives()) { info.origins.append( - ToQString(m_DirectoryStructure->getOriginByID(idx).getName())); + ToQString(m_DirectoryStructure->getOriginByID(idx.first).getName())); } if (filter(info)) { diff --git a/src/pluginlist.cpp b/src/pluginlist.cpp index 6392d44b..775086fd 100644 --- a/src/pluginlist.cpp +++ b/src/pluginlist.cpp @@ -115,23 +115,23 @@ void PluginList::highlightPlugins(const QItemSelection &selected, const MOShared } for (QModelIndex idx : selected.indexes()) { ModInfo::Ptr selectedMod = ModInfo::getByIndex(idx.data(Qt::UserRole + 1).toInt()); - if (!selectedMod.isNull() && profile.modEnabled(idx.data(Qt::UserRole + 1).toInt())) { - QDir dir(selectedMod->absolutePath()); - QStringList plugins = dir.entryList(QStringList() << "*.esp" << "*.esm" << "*.esl"); - MOShared::FilesOrigin origin = directoryEntry.getOriginByName(selectedMod->internalName().toStdWString()); - if (plugins.size() > 0) { - for (auto plugin : plugins) { + if (!selectedMod.isNull() && profile.modEnabled(idx.data(Qt::UserRole + 1).toInt())) { + QDir dir(selectedMod->absolutePath()); + QStringList plugins = dir.entryList(QStringList() << "*.esp" << "*.esm" << "*.esl"); + MOShared::FilesOrigin origin = directoryEntry.getOriginByName(selectedMod->internalName().toStdWString()); + if (plugins.size() > 0) { + for (auto plugin : plugins) { MOShared::FileEntry::Ptr file = directoryEntry.findFile(plugin.toStdWString()); if (file->getOrigin() != origin.getID()) { - const std::vector alternatives = file->getAlternatives(); - if (std::find(alternatives.begin(), alternatives.end(), origin.getID()) == alternatives.end()) + const std::vector> alternatives = file->getAlternatives(); + if (std::find_if(alternatives.begin(), alternatives.end(), [&](const std::pair& element) { return element.first == origin.getID(); }) == alternatives.end()) continue; } - std::map::iterator iter = m_ESPsByName.find(plugin.toLower()); - if (iter != m_ESPsByName.end()) { - m_ESPs[iter->second].m_ModSelected = true; - } - } + std::map::iterator iter = m_ESPsByName.find(plugin.toLower()); + if (iter != m_ESPsByName.end()) { + m_ESPs[iter->second].m_ModSelected = true; + } + } } } } diff --git a/src/shared/directoryentry.cpp b/src/shared/directoryentry.cpp index df6a7b5a..e1cba08c 100644 --- a/src/shared/directoryentry.cpp +++ b/src/shared/directoryentry.cpp @@ -236,9 +236,10 @@ void FileEntry::addOrigin(int origin, FILETIME fileTime, const std::wstring &arc m_FileTime = fileTime; m_Archive = archive; } else if ((m_Parent != nullptr) - && (m_Parent->getOriginByID(origin).getPriority() > m_Parent->getOriginByID(m_Origin).getPriority())) { - if (std::find(m_Alternatives.begin(), m_Alternatives.end(), m_Origin) == m_Alternatives.end()) { - m_Alternatives.push_back(m_Origin); + && (m_Parent->getOriginByID(origin).getPriority() > m_Parent->getOriginByID(m_Origin).getPriority()) + && (archive.size() == 0 || m_Archive.size() > 0 )) { + if (std::find_if(m_Alternatives.begin(), m_Alternatives.end(), [&](const std::pair &i) -> bool { return i.first == m_Origin; }) == m_Alternatives.end()) { + m_Alternatives.push_back(std::pair(m_Origin, m_Archive)); } m_Origin = origin; m_FileTime = fileTime; @@ -249,20 +250,20 @@ void FileEntry::addOrigin(int origin, FILETIME fileTime, const std::wstring &arc // already an origin return; } - for (std::vector::iterator iter = m_Alternatives.begin(); iter != m_Alternatives.end(); ++iter) { - if (*iter == origin) { + for (std::vector>::iterator iter = m_Alternatives.begin(); iter != m_Alternatives.end(); ++iter) { + if (iter->first == origin) { // already an origin return; } if ((m_Parent != nullptr) - && (m_Parent->getOriginByID(*iter).getPriority() < m_Parent->getOriginByID(origin).getPriority())) { - m_Alternatives.insert(iter, origin); + && (m_Parent->getOriginByID(iter->first).getPriority() < m_Parent->getOriginByID(origin).getPriority())) { + m_Alternatives.insert(iter, std::pair(origin, archive)); found = true; break; } } if (!found) { - m_Alternatives.push_back(origin); + m_Alternatives.push_back(std::pair(origin, archive)); } } } @@ -272,14 +273,14 @@ bool FileEntry::removeOrigin(int origin) if (m_Origin == origin) { if (!m_Alternatives.empty()) { // find alternative with the highest priority - std::vector::iterator currentIter = m_Alternatives.begin(); - for (std::vector::iterator iter = m_Alternatives.begin(); iter != m_Alternatives.end(); ++iter) { - if ((m_Parent->getOriginByID(*iter).getPriority() > m_Parent->getOriginByID(*currentIter).getPriority()) && - (*iter != origin)) { + std::vector>::iterator currentIter = m_Alternatives.begin(); + for (std::vector>::iterator iter = m_Alternatives.begin(); iter != m_Alternatives.end(); ++iter) { + if ((m_Parent->getOriginByID(iter->first).getPriority() > m_Parent->getOriginByID(currentIter->first).getPriority()) && + (iter->first != origin)) { currentIter = iter; } } - int currentID = *currentIter; + int currentID = currentIter->first; m_Alternatives.erase(currentIter); m_Origin = currentID; @@ -303,23 +304,13 @@ bool FileEntry::removeOrigin(int origin) return true; } } else { - std::vector::iterator newEnd = std::remove(m_Alternatives.begin(), m_Alternatives.end(), origin); - m_Alternatives.erase(newEnd, m_Alternatives.end()); + std::vector>::iterator newEnd = std::find_if(m_Alternatives.begin(), m_Alternatives.end(), [&](const std::pair &i) -> bool { return i.first == origin; }); + if (newEnd != m_Alternatives.end()) + m_Alternatives.erase(newEnd, m_Alternatives.end()); } return false; } - -// sorted by priority descending -static bool ByOriginPriority(DirectoryEntry *entry, int LHS, int RHS) -{ - int l = entry->getOriginByID(LHS).getPriority(); if (l < 0) l = INT_MAX; - int r = entry->getOriginByID(RHS).getPriority(); if (r < 0) r = INT_MAX; - - return l < r; -} - - FileEntry::FileEntry() : m_Index(UINT_MAX), m_Name(), m_Origin(-1), m_Parent(nullptr), m_LastAccessed(time(nullptr)) { @@ -339,10 +330,23 @@ FileEntry::~FileEntry() void FileEntry::sortOrigins() { - m_Alternatives.push_back(m_Origin); - std::sort(m_Alternatives.begin(), m_Alternatives.end(), boost::bind(ByOriginPriority, m_Parent, _1, _2)); - m_Origin = m_Alternatives[m_Alternatives.size() - 1]; - m_Alternatives.pop_back(); + m_Alternatives.push_back(std::pair(m_Origin, m_Archive)); + std::sort(m_Alternatives.begin(), m_Alternatives.end(), [&](const std::pair &LHS, const std::pair &RHS) -> bool { + if ((!LHS.second.size() && !RHS.second.size()) || (LHS.second.size() && RHS.second.size())) { + int l = m_Parent->getOriginByID(LHS.first).getPriority(); if (l < 0) l = INT_MAX; + int r = m_Parent->getOriginByID(RHS.first).getPriority(); if (r < 0) r = INT_MAX; + + return l < r; + } + + if (RHS.second.size()) return false; + return true; + }); + if (!m_Alternatives.empty()) { + m_Origin = m_Alternatives.back().first; + m_Archive = m_Alternatives.back().second; + m_Alternatives.pop_back(); + } } @@ -886,9 +890,9 @@ void FileRegister::unregisterFile(FileEntry::Ptr file) // unregister from origin int originID = file->getOrigin(ignore); m_OriginConnection->getByID(originID).removeFile(file->getIndex()); - const std::vector &alternatives = file->getAlternatives(); + const std::vector> &alternatives = file->getAlternatives(); for (auto iter = alternatives.begin(); iter != alternatives.end(); ++iter) { - m_OriginConnection->getByID(*iter).removeFile(file->getIndex()); + m_OriginConnection->getByID(iter->first).removeFile(file->getIndex()); } // unregister from directory diff --git a/src/shared/directoryentry.h b/src/shared/directoryentry.h index 04b8782b..8dbedaf4 100644 --- a/src/shared/directoryentry.h +++ b/src/shared/directoryentry.h @@ -72,7 +72,7 @@ public: // gets the list of alternative origins (origins with lower priority than the primary one). // if sortOrigins has been called, it is sorted by priority (ascending) - const std::vector &getAlternatives() const { return m_Alternatives; } + const std::vector> &getAlternatives() const { return m_Alternatives; } const std::wstring &getName() const { return m_Name; } int getOrigin() const { return m_Origin; } @@ -96,9 +96,9 @@ private: Index m_Index; std::wstring m_Name; - int m_Origin; + int m_Origin = -1; std::wstring m_Archive; - std::vector m_Alternatives; + std::vector> m_Alternatives; DirectoryEntry *m_Parent; mutable FILETIME m_FileTime; diff --git a/src/syncoverwritedialog.cpp b/src/syncoverwritedialog.cpp index aeed0a55..f03e29c5 100644 --- a/src/syncoverwritedialog.cpp +++ b/src/syncoverwritedialog.cpp @@ -98,9 +98,9 @@ void SyncOverwriteDialog::readTree(const QString &path, DirectoryEntry *director bool ignore; int origin = entry->getOrigin(ignore); addToComboBox(combo, ToQString(m_DirectoryStructure->getOriginByID(origin).getName()), origin); - const std::vector &alternatives = entry->getAlternatives(); - for (std::vector::const_iterator iter = alternatives.begin(); iter != alternatives.end(); ++iter) { - addToComboBox(combo, ToQString(m_DirectoryStructure->getOriginByID(*iter).getName()), *iter); + const std::vector> &alternatives = entry->getAlternatives(); + for (std::vector>::const_iterator iter = alternatives.begin(); iter != alternatives.end(); ++iter) { + addToComboBox(combo, ToQString(m_DirectoryStructure->getOriginByID(iter->first).getName()), iter->first); } combo->setCurrentIndex(combo->count() - 1); } else { -- cgit v1.3.1 From 2ea23c41299fa22b0ade479d7e8451bccff4278e Mon Sep 17 00:00:00 2001 From: LePresidente Date: Mon, 25 Dec 2017 07:04:55 +0200 Subject: Disable the bsa tab for release Version bump to 2.1.0 Updated about window --- src/aboutdialog.ui | 45 +++++++++++++++++++++++++++++++++++++++++++-- src/mainwindow.ui | 4 +++- src/version.rc | 2 +- 3 files changed, 47 insertions(+), 4 deletions(-) (limited to 'src/mainwindow.ui') diff --git a/src/aboutdialog.ui b/src/aboutdialog.ui index 618077ed..50a9de5f 100644 --- a/src/aboutdialog.ui +++ b/src/aboutdialog.ui @@ -154,8 +154,44 @@ Thanks
- + + + Current Maintainers + + + + + + QAbstractItemView::NoSelection + + + + LePresidente + + + + + Silarn + + + + + erasmux + + + + + Diana + + + + + + + + + Translators @@ -237,7 +273,7 @@ - + Other Supporter @@ -247,6 +283,11 @@ QAbstractItemView::NoSelection + + + Al12 (Discord) + + blacksol diff --git a/src/mainwindow.ui b/src/mainwindow.ui index d8fa1432..d9667ed7 100644 --- a/src/mainwindow.ui +++ b/src/mainwindow.ui @@ -906,11 +906,13 @@ p, li { white-space: pre-wrap; } Archives + + true + 6 - 6 diff --git a/src/version.rc b/src/version.rc index f8b62a2f..9de492f6 100644 --- a/src/version.rc +++ b/src/version.rc @@ -1,7 +1,7 @@ #include "Winver.h" #define VER_FILEVERSION 2,1,0 -#define VER_FILEVERSION_STR "2.1.0beta\0" +#define VER_FILEVERSION_STR "2.1.0\0" VS_VERSION_INFO VERSIONINFO FILEVERSION VER_FILEVERSION -- cgit v1.3.1 From f7374a8525fa163fe04c0849c933318a8d7008f7 Mon Sep 17 00:00:00 2001 From: Al12rs Date: Thu, 15 Feb 2018 01:56:40 +0100 Subject: - Added "Clear all Filters" button with red outline that only shows up if one or more filters are selected. - Fixed a bug that would not allow the already present "Clear" button under the filters tab to clear "contains" type of filters. - Fixed a bug that enabled the "Clear" button at the start even if there were no filters selected. --- src/mainwindow.cpp | 18 ++++++++++-------- src/mainwindow.h | 1 + src/mainwindow.ui | 49 +++++++++++++++++++++++++++++++++++++++++++++---- 3 files changed, 56 insertions(+), 12 deletions(-) (limited to 'src/mainwindow.ui') diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index abad054b..abac9317 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -3063,8 +3063,6 @@ void MainWindow::exportModListCSV() //selection.addChoice(tr("Visible"), tr("All mods visible in the mod list are included"), 2); QDialog selection(this); - //QLabel descriptionLabel("Choose what to export"); - //selection->(descriptionLabel); QGridLayout *grid = new QGridLayout; selection.setWindowTitle(tr("Export to csv")); @@ -3132,8 +3130,6 @@ void MainWindow::exportModListCSV() selection.setLayout(grid); - //connect(ok, SIGNAL(released()), this, SLOT(accept())); - //connect(cancel, SIGNAL(released()), this, SLOT(reject())); if (selection.exec() == QDialog::Accepted) { @@ -3165,9 +3161,6 @@ void MainWindow::exportModListCSV() if (download_File_Name->isChecked()) fields.push_back(std::make_pair(QString("#Download_File_Name"), CSVBuilder::TYPE_STRING)); - - - // fields.push_back(std::make_pair(QString("file_category"), CSVBuilder::TYPE_INTEGER)); builder.setFields(fields); builder.writeHeader(); @@ -3403,7 +3396,10 @@ void MainWindow::on_categoriesList_itemSelectionChanged() m_ModListSortProxy->setCategoryFilter(categories); m_ModListSortProxy->setContentFilter(content); - ui->clickBlankButton->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(""))); } else if (indices.count() > 1) { @@ -5028,3 +5024,9 @@ void MainWindow::on_clickBlankButton_clicked() { deselectFilters(); } + +void MainWindow::on_clearFiltersButton_clicked() +{ + deselectFilters(); +} + diff --git a/src/mainwindow.h b/src/mainwindow.h index d7708da6..b7eca72e 100644 --- a/src/mainwindow.h +++ b/src/mainwindow.h @@ -549,6 +549,7 @@ private slots: // ui slots void on_actionUpdate_triggered(); void on_actionEndorseMO_triggered(); + void on_clearFiltersButton_clicked(); void on_btnRefreshData_clicked(); void on_categoriesList_customContextMenuRequested(const QPoint &pos); void on_conflictsCheckBox_toggled(bool checked); diff --git a/src/mainwindow.ui b/src/mainwindow.ui index d9667ed7..49f313ca 100644 --- a/src/mainwindow.ui +++ b/src/mainwindow.ui @@ -96,6 +96,9 @@ + + false + 0 @@ -485,6 +488,44 @@ p, li { white-space: pre-wrap; } + + + + + 0 + 0 + + + + + 0 + 25 + + + + false + + + Qt::RightToLeft + + + border:2px solid #ff0000; + + + Clear all Filters + + + + :/MO/gui/edit_clear:/MO/gui/edit_clear + + + + 12 + 12 + + + + @@ -729,12 +770,12 @@ p, li { white-space: pre-wrap; } + + true + Sort - - - true - + :/MO/gui/sort:/MO/gui/sort -- cgit v1.3.1 From 61898074fe87fc97b399fba67006339bbedf6950 Mon Sep 17 00:00:00 2001 From: Al12rs Date: Sun, 18 Feb 2018 16:43:16 +0100 Subject: Changed switch instance icon and tooltip --- src/mainwindow.ui | 4 ++-- src/resources.qrc | 2 ++ src/resources/switch-instance-icon.png | Bin 0 -> 57516 bytes 3 files changed, 4 insertions(+), 2 deletions(-) create mode 100644 src/resources/switch-instance-icon.png (limited to 'src/mainwindow.ui') diff --git a/src/mainwindow.ui b/src/mainwindow.ui index 49f313ca..0f7560c3 100644 --- a/src/mainwindow.ui +++ b/src/mainwindow.ui @@ -1540,13 +1540,13 @@ Right now this has very limited functionality - :/MO/gui/app_icon:/MO/gui/app_icon + :/MO/gui/instance_switch:/MO/gui/instance_switch Change Game - Open the game selection dialog + Open the Instance selection dialog to manage a different Game diff --git a/src/resources.qrc b/src/resources.qrc index e88eda06..9b66a38c 100644 --- a/src/resources.qrc +++ b/src/resources.qrc @@ -15,6 +15,7 @@ resources/document-properties.png resources/go-up.png resources/go-down.png + resources/switch-instance-icon.png resources/contact-new.png resources/preferences-system.png resources/application-x-executable.png @@ -69,6 +70,7 @@ resources/status_inactive.png resources/mo_icon.png resources/package.png + resources/switch-instance-icon.png resources/contents/jigsaw-piece.png diff --git a/src/resources/switch-instance-icon.png b/src/resources/switch-instance-icon.png new file mode 100644 index 00000000..b992babe Binary files /dev/null and b/src/resources/switch-instance-icon.png differ -- cgit v1.3.1 From 8ebd79ee71c42152a58364b1f37b42efb5b3b644 Mon Sep 17 00:00:00 2001 From: Al12rs Date: Mon, 26 Feb 2018 21:34:14 +0100 Subject: Reduced Clear filter red border to one pixel instead of two. --- src/mainwindow.ui | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/mainwindow.ui') diff --git a/src/mainwindow.ui b/src/mainwindow.ui index 0f7560c3..f9e64349 100644 --- a/src/mainwindow.ui +++ b/src/mainwindow.ui @@ -509,7 +509,7 @@ p, li { white-space: pre-wrap; } Qt::RightToLeft - border:2px solid #ff0000; + border:1px solid #ff0000; Clear all Filters -- cgit v1.3.1 From c1421d07345617e7776dd8bdf0aec4dbef52a72a Mon Sep 17 00:00:00 2001 From: Al12rs Date: Wed, 28 Feb 2018 20:57:08 +0100 Subject: - Added Open Folders drop-down menu over the modlist (using new custom icon) and moved there all previuolsy added "open <> folder" menu options. - Added "Open MO install folder" option. --- src/mainwindow.cpp | 52 ++++++++++++++++++++++++------------- src/mainwindow.h | 3 +++ src/mainwindow.ui | 31 ++++++++++++++++++++-- src/resources.qrc | 3 ++- src/resources/open-Folder-Icon.png | Bin 0 -> 17646 bytes 5 files changed, 68 insertions(+), 21 deletions(-) create mode 100644 src/resources/open-Folder-Icon.png (limited to 'src/mainwindow.ui') diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index abac9317..fe93b546 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -301,6 +301,8 @@ MainWindow::MainWindow(QSettings &initSettings ui->listOptionsBtn->setMenu(modListContextMenu()); + ui->openFolderMenu->setMenu(openFolderMenu()); + updateDownloadListDelegate(); ui->savegameList->installEventFilter(this); @@ -3033,6 +3035,11 @@ 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); @@ -3219,6 +3226,30 @@ 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); @@ -3237,24 +3268,6 @@ QMenu *MainWindow::modListContextMenu() menu->addAction(tr("Export to csv..."), this, SLOT(exportModListCSV())); - menu->addSeparator(); - - QMenu *openSubMenu = new QMenu(this); - - - openSubMenu->addAction(tr("Open Instance folder"), this, SLOT(openInstanceFolder())); - - openSubMenu->addAction(tr("Open Profile folder"), this, SLOT(openProfileFolder())); - - openSubMenu->addAction(tr("Open Downloads folder"), this, SLOT(openDownloadsFolder())); - - openSubMenu->addAction(tr("Open Game folder"), this, SLOT(openGameFolder())); - - openSubMenu->addAction(tr("Open MyGames folder"), this, SLOT(openMyGamesFolder())); - - openSubMenu->setTitle(tr("Open Folder...")); - - menu->addMenu(openSubMenu); return menu; } @@ -3698,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) diff --git a/src/mainwindow.h b/src/mainwindow.h index b7eca72e..2c2e2723 100644 --- a/src/mainwindow.h +++ b/src/mainwindow.h @@ -277,6 +277,8 @@ private: QMenu *modListContextMenu(); + QMenu *openFolderMenu(); + std::set enabledArchives(); void scheduleUpdateButton(); @@ -485,6 +487,7 @@ private slots: void disableVisibleMods(); void exportModListCSV(); void openInstanceFolder(); + void openInstallFolder(); void openDownloadsFolder(); void openProfileFolder(); void openGameFolder(); diff --git a/src/mainwindow.ui b/src/mainwindow.ui index f9e64349..31522c03 100644 --- a/src/mainwindow.ui +++ b/src/mainwindow.ui @@ -176,7 +176,7 @@ 2 - + @@ -247,10 +247,34 @@ p, li { white-space: pre-wrap; } 16 16 + + + + + + + Quickly open in Explorer relevant Folders... + + + + + + + :/MO/gui/open_folder:/MO/gui/open_folder + + + + + + + + + + Restore Backup... @@ -439,7 +463,7 @@ p, li { white-space: pre-wrap; } - + @@ -944,6 +968,9 @@ p, li { white-space: pre-wrap; } + + + Archives diff --git a/src/resources.qrc b/src/resources.qrc index 9b66a38c..618d3cfc 100644 --- a/src/resources.qrc +++ b/src/resources.qrc @@ -70,7 +70,8 @@ resources/status_inactive.png resources/mo_icon.png resources/package.png - resources/switch-instance-icon.png + resources/switch-instance-icon.png + resources/open-Folder-Icon.png resources/contents/jigsaw-piece.png diff --git a/src/resources/open-Folder-Icon.png b/src/resources/open-Folder-Icon.png new file mode 100644 index 00000000..345671f7 Binary files /dev/null and b/src/resources/open-Folder-Icon.png differ -- cgit v1.3.1
Game plugins (esp/esm)
Game plugins (esp/esm/esl)
Interface
Meshes
BSA