From 99156abc6e0779ed3de437c0005b6de8293c7a15 Mon Sep 17 00:00:00 2001 From: LePresidente Date: Wed, 4 Jan 2017 14:22:18 +0200 Subject: First attempt to update to QT5.7 --- src/CMakeLists.txt | 8 ++++---- src/browserdialog.cpp | 32 ++++++++++++++++---------------- src/browserdialog.h | 2 +- src/browserview.cpp | 35 ++++++++++++++++++----------------- src/browserview.h | 8 ++++---- src/modinfodialog.cpp | 3 ++- src/modinfodialog.ui | 6 +++--- 7 files changed, 48 insertions(+), 46 deletions(-) (limited to 'src') diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 500dc56b..0d330d72 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -233,10 +233,10 @@ SET(CMAKE_INCLUDE_CURRENT_DIR ON) SET(CMAKE_AUTOMOC ON) SET(CMAKE_AUTOUIC ON) FIND_PACKAGE(Qt5Widgets REQUIRED) -FIND_PACKAGE(Qt5Declarative REQUIRED) +FIND_PACKAGE(Qt5QuickWidgets REQUIRED) FIND_PACKAGE(Qt5Network REQUIRED) FIND_PACKAGE(Qt5WinExtras REQUIRED) -FIND_PACKAGE(Qt5WebKitWidgets REQUIRED) +FIND_PACKAGE(Qt5WebEngineWidgets REQUIRED) FIND_PACKAGE(Qt5LinguistTools) QT5_WRAP_UI(organizer_UIHDRS ${organizer_UIS}) QT5_ADD_RESOURCES(organizer_RCCPPS ${organizer_QRCS}) @@ -299,7 +299,7 @@ ENDIF() ADD_EXECUTABLE(ModOrganizer WIN32 ${organizer_HDRS} ${organizer_SRCS} ${organizer_UIHDRS} ${organizer_RCS} ${organizer_RCCPPS} ${organizer_translations_qm}) TARGET_LINK_LIBRARIES(ModOrganizer - Qt5::Widgets Qt5::WinExtras Qt5::WebKitWidgets + Qt5::Widgets Qt5::WinExtras Qt5::WebEngineWidgets ${Boost_LIBRARIES} zlibstatic uibase esptk bsatk githubpp @@ -313,7 +313,7 @@ SET_TARGET_PROPERTIES(ModOrganizer PROPERTIES LINK_FLAGS_RELWITHDEBINFO "/LARGEADDRESSAWARE ${OPTIMIZE_LINK_FLAGS}") -QT5_USE_MODULES(ModOrganizer Widgets Declarative Network WebKitWidgets) +QT5_USE_MODULES(ModOrganizer Widgets Script Qml QuickWidgets Network WebEngineWidgets) ############### diff --git a/src/browserdialog.cpp b/src/browserdialog.cpp index e5f0f21d..c2c65acc 100644 --- a/src/browserdialog.cpp +++ b/src/browserdialog.cpp @@ -28,13 +28,13 @@ along with Mod Organizer. If not, see . #include #include "settings.h" +#include #include #include #include #include -#include +#include #include -#include #include #include @@ -77,8 +77,8 @@ void BrowserDialog::closeEvent(QCloseEvent *event) void BrowserDialog::initTab(BrowserView *newView) { - newView->page()->setNetworkAccessManager(m_AccessManager); - newView->page()->setForwardUnsupportedContent(true); + //newView->page()->setNetworkAccessManager(m_AccessManager); + //newView->page()->setForwardUnsupportedContent(true); connect(newView, SIGNAL(loadProgress(int)), this, SLOT(progress(int))); connect(newView, SIGNAL(titleChanged(QString)), this, SLOT(titleChanged(QString))); @@ -86,14 +86,14 @@ void BrowserDialog::initTab(BrowserView *newView) connect(newView, SIGNAL(startFind()), this, SLOT(startSearch())); connect(newView, SIGNAL(urlChanged(QUrl)), this, SLOT(urlChanged(QUrl))); connect(newView, SIGNAL(openUrlInNewTab(QUrl)), this, SLOT(openInNewTab(QUrl))); - connect(newView->page(), SIGNAL(downloadRequested(QNetworkRequest)), this, SLOT(downloadRequested(QNetworkRequest))); - connect(newView->page(), SIGNAL(unsupportedContent(QNetworkReply*)), this, SLOT(unsupportedContent(QNetworkReply*))); + connect(newView, SIGNAL(downloadRequested(QNetworkRequest)), this, SLOT(downloadRequested(QNetworkRequest))); + connect(newView, SIGNAL(unsupportedContent(QNetworkReply*)), this, SLOT(unsupportedContent(QNetworkReply*))); ui->backBtn->setEnabled(false); ui->fwdBtn->setEnabled(false); m_Tabs->addTab(newView, tr("new")); - newView->settings()->setAttribute(QWebSettings::PluginsEnabled, true); - newView->settings()->setAttribute(QWebSettings::AutoLoadImages, true); + newView->settings()->setAttribute(QWebEngineSettings::PluginsEnabled, true); + newView->settings()->setAttribute(QWebEngineSettings::AutoLoadImages, true); } @@ -133,10 +133,10 @@ void BrowserDialog::openUrl(const QUrl &url) void BrowserDialog::maximizeWidth() { - int viewportWidth = getCurrentView()->page()->viewportSize().width(); + int viewportWidth = getCurrentView()->page()->contentsSize ().width(); int frameWidth = width() - viewportWidth; - int contentWidth = getCurrentView()->page()->mainFrame()->contentsSize().width(); + int contentWidth = getCurrentView()->page()->contentsSize().width(); QDesktopWidget screen; int currentScreen = screen.screenNumber(this); @@ -190,7 +190,7 @@ QString BrowserDialog::guessFileName(const QString &url) void BrowserDialog::unsupportedContent(QNetworkReply *reply) { try { - QWebPage *page = qobject_cast(sender()); + QWebEnginePage *page = qobject_cast(sender()); if (page == nullptr) { qCritical("sender not a page"); return; @@ -252,10 +252,10 @@ void BrowserDialog::startSearch() void BrowserDialog::on_searchEdit_returnPressed() { - BrowserView *currentView = getCurrentView(); - if (currentView != nullptr) { - currentView->findText(ui->searchEdit->text(), QWebPage::FindWrapsAroundDocument); - } +// BrowserView *currentView = getCurrentView(); +// if (currentView != nullptr) { +// currentView->findText(ui->searchEdit->text(), QWebEnginePage::FindWrapsAroundDocument); +// } } void BrowserDialog::on_refreshBtn_clicked() @@ -274,7 +274,7 @@ void BrowserDialog::on_browserTabWidget_currentChanged(int index) void BrowserDialog::on_urlEdit_returnPressed() { - QWebView *currentView = getCurrentView(); + QWebEngineView *currentView = getCurrentView(); if (currentView != nullptr) { currentView->setUrl(QUrl(ui->urlEdit->text())); } diff --git a/src/browserdialog.h b/src/browserdialog.h index 04567f5f..354a377b 100644 --- a/src/browserdialog.h +++ b/src/browserdialog.h @@ -24,7 +24,7 @@ along with Mod Organizer. If not, see . #include #include #include -#include +#include #include #include #include diff --git a/src/browserview.cpp b/src/browserview.cpp index aeb16520..0b871e23 100644 --- a/src/browserview.cpp +++ b/src/browserview.cpp @@ -21,23 +21,23 @@ along with Mod Organizer. If not, see . #include #include -#include -#include #include +#include +#include #include #include #include "utility.h" BrowserView::BrowserView(QWidget *parent) - : QWebView(parent) + : QWebEngineView(parent) { installEventFilter(this); - page()->settings()->setMaximumPagesInCache(10); + //page()->settings()->setMaximumPagesInCache(10); } -QWebView *BrowserView::createWindow(QWebPage::WebWindowType) +QWebEngineView *BrowserView::createWindow(QWebEnginePage::WebWindowType) { BrowserView *newView = new BrowserView(parentWidget()); emit initTab(newView); @@ -59,17 +59,18 @@ bool BrowserView::eventFilter(QObject *obj, QEvent *event) mouseEvent->ignore(); return true; } - } else if (event->type() == QEvent::MouseButtonRelease) { - QMouseEvent *mouseEvent = static_cast(event); - if (mouseEvent->button() == Qt::MidButton) { - QWebHitTestResult hitTest = page()->frameAt(mouseEvent->pos())->hitTestContent(mouseEvent->pos()); - if (hitTest.linkUrl().isValid()) { - emit openUrlInNewTab(hitTest.linkUrl()); - } - mouseEvent->ignore(); - - return true; - } +// TODO This is due to that QTWebEnginePage doesn't support QWebFrame anymore +// } else if (event->type() == QEvent::MouseButtonRelease) { +// QMouseEvent *mouseEvent = static_cast(event); +// if (mouseEvent->button() == Qt::MidButton) { +// QWebEngineContextMenuData hitTest = page()->hitTestContent(mouseEvent->pos()); +// if (hitTest.linkUrl().isValid()) { +// emit openUrlInNewTab(hitTest.linkUrl()); +// } +// mouseEvent->ignore(); +// +// return true; +// } } - return QWebView::eventFilter(obj, event); + return QWebEngineView::eventFilter(obj, event); } diff --git a/src/browserview.h b/src/browserview.h index 6a89752a..24be21c1 100644 --- a/src/browserview.h +++ b/src/browserview.h @@ -24,13 +24,13 @@ along with Mod Organizer. If not, see . class QEvent; class QUrl; class QWidget; -#include -#include +#include +#include /** * @brief web view used to display a nexus page **/ -class BrowserView : public QWebView +class BrowserView : public QWebEngineView { Q_OBJECT @@ -66,7 +66,7 @@ signals: protected: - virtual QWebView *createWindow(QWebPage::WebWindowType type); + virtual QWebEngineView *createWindow(QWebEnginePage::WebWindowType type); virtual bool eventFilter(QObject *obj, QEvent *event); diff --git a/src/modinfodialog.cpp b/src/modinfodialog.cpp index e1a2183c..0e77859a 100644 --- a/src/modinfodialog.cpp +++ b/src/modinfodialog.cpp @@ -89,7 +89,8 @@ ModInfoDialog::ModInfoDialog(ModInfo::Ptr modInfo, const DirectoryEntry *directo connect(this, SIGNAL(thumbnailClickedSignal(const QString&)), this, SLOT(thumbnailClicked(const QString&))); connect(m_ModInfo.data(), SIGNAL(modDetailsUpdated(bool)), this, SLOT(modDetailsUpdated(bool))); connect(ui->descriptionView, SIGNAL(linkClicked(QUrl)), this, SLOT(linkClicked(QUrl))); - ui->descriptionView->page()->setLinkDelegationPolicy(QWebPage::DelegateAllLinks); + //TODO: No easy way to delegate links + //ui->descriptionView->page()->acceptNavigationRequest(QWebEnginePage::DelegateAllLinks); if (directory->originExists(ToWString(modInfo->name()))) { m_Origin = &directory->getOriginByName(ToWString(modInfo->name())); diff --git a/src/modinfodialog.ui b/src/modinfodialog.ui index a03edef7..a452bc59 100644 --- a/src/modinfodialog.ui +++ b/src/modinfodialog.ui @@ -678,7 +678,7 @@ p, li { white-space: pre-wrap; } - + about:blank @@ -807,9 +807,9 @@ p, li { white-space: pre-wrap; } - QWebView + QQuickWidget QWidget -
QtWebKitWidgets/QWebView
+
QtQuickWidgets/QQuickWidget
-- cgit v1.3.1 From 91eaba8b44417fdf8f0210a658d49cc97b6e395c Mon Sep 17 00:00:00 2001 From: LePresidente Date: Mon, 1 May 2017 20:23:53 +0200 Subject: Updated manifest to use new dll's. --- src/dlls.manifest.qt5 | 26 ++++++++++---------------- 1 file changed, 10 insertions(+), 16 deletions(-) (limited to 'src') diff --git a/src/dlls.manifest.qt5 b/src/dlls.manifest.qt5 index 80af4e5f..dd0b4ea9 100644 --- a/src/dlls.manifest.qt5 +++ b/src/dlls.manifest.qt5 @@ -1,31 +1,25 @@ - - - + + + + + - + - - - - - - - - + - - + + - - + \ No newline at end of file -- cgit v1.3.1 From 8bea68564007432d225175201eb8a41277d3574e Mon Sep 17 00:00:00 2001 From: LePresidente Date: Fri, 5 May 2017 08:39:51 +0200 Subject: windeployqt doesn't automatically detect the requirement for qtwebenginewidgets, so we force it. --- src/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 0d330d72..448f47e5 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -337,7 +337,7 @@ INSTALL( CODE "EXECUTE_PROCESS( COMMAND - ${qt5bin}/windeployqt.exe ModOrganizer.exe ${windeploy_parameters} + ${qt5bin}/windeployqt.exe ModOrganizer.exe --webenginewidgets ${windeploy_parameters} COMMAND ${qt5bin}/windeployqt.exe uibase.dll ${windeploy_parameters} WORKING_DIRECTORY ${CMAKE_INSTALL_PREFIX}/bin -- 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') 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 b16a0ab3d94fad599347098e79e4a8131de08efa Mon Sep 17 00:00:00 2001 From: Jeremy Rimpo Date: Fri, 20 Oct 2017 23:16:04 -0500 Subject: Add ESL flag type detection * ESL files can be sorted like ESMs * ESL files are displayed italicized but not bold --- src/pluginlist.cpp | 24 ++++++++++++++++++++---- src/pluginlist.h | 2 ++ 2 files changed, 22 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/pluginlist.cpp b/src/pluginlist.cpp index f2c52d5b..2a252d27 100644 --- a/src/pluginlist.cpp +++ b/src/pluginlist.cpp @@ -593,6 +593,16 @@ bool PluginList::isMaster(const QString &name) const } } +bool PluginList::isLight(const QString &name) const +{ + auto iter = m_ESPsByName.find(name.toLower()); + if (iter == m_ESPsByName.end()) { + return false; + } else { + return m_ESPs[iter->second].m_IsLight; + } +} + QStringList PluginList::masters(const QString &name) const { auto iter = m_ESPsByName.find(name.toLower()); @@ -736,6 +746,8 @@ QVariant PluginList::data(const QModelIndex &modelIndex, int role) const if (m_ESPs[index].m_IsMaster) { result.setItalic(true); result.setWeight(QFont::Bold); + } else if (m_ESPs[index].m_IsLight) { + result.setItalic(true); } return result; } else if (role == Qt::TextAlignmentRole) { @@ -895,16 +907,18 @@ void PluginList::setPluginPriority(int row, int &newPriority) { int newPriorityTemp = newPriority; - if (!m_ESPs[row].m_IsMaster) { + if (!m_ESPs[row].m_IsMaster && !m_ESPs[row].m_IsLight) { // don't allow esps to be moved above esms while ((newPriorityTemp < static_cast(m_ESPsByPriority.size() - 1)) && - m_ESPs.at(m_ESPsByPriority.at(newPriorityTemp)).m_IsMaster) { + (m_ESPs.at(m_ESPsByPriority.at(newPriorityTemp)).m_IsMaster || + m_ESPs.at(m_ESPsByPriority.at(newPriorityTemp)).m_IsLight)) { ++newPriorityTemp; } } else { // don't allow esms to be moved below esps while ((newPriorityTemp > 0) && - !m_ESPs.at(m_ESPsByPriority.at(newPriorityTemp)).m_IsMaster) { + !m_ESPs.at(m_ESPsByPriority.at(newPriorityTemp)).m_IsMaster && + !m_ESPs.at(m_ESPsByPriority.at(newPriorityTemp)).m_IsLight) { --newPriorityTemp; } // also don't allow "regular" esms to be moved above primary plugins @@ -1110,7 +1124,8 @@ PluginList::ESPInfo::ESPInfo(const QString &name, bool enabled, { try { ESP::File file(ToWString(fullPath)); - m_IsMaster = file.isMaster(); + m_IsMaster = file.isMaster() && !file.isLight(); + m_IsLight = file.isMaster() && file.isLight(); m_Author = QString::fromLatin1(file.author().c_str()); m_Description = QString::fromLatin1(file.description().c_str()); std::set masters = file.masters(); @@ -1120,6 +1135,7 @@ PluginList::ESPInfo::ESPInfo(const QString &name, bool enabled, } catch (const std::exception &e) { qCritical("failed to parse esp file %s: %s", qPrintable(fullPath), e.what()); m_IsMaster = false; + m_IsLight = false; } } diff --git a/src/pluginlist.h b/src/pluginlist.h index 78623cae..aaa45bc1 100644 --- a/src/pluginlist.h +++ b/src/pluginlist.h @@ -213,6 +213,7 @@ public: virtual int loadOrder(const QString &name) const; virtual bool onRefreshed(const std::function &callback); virtual bool isMaster(const QString &name) const; + virtual bool isLight(const QString &name) const; virtual QStringList masters(const QString &name) const; virtual QString origin(const QString &name) const; virtual void setLoadOrder(const QStringList &pluginList) override; @@ -275,6 +276,7 @@ private: FILETIME m_Time; QString m_OriginName; bool m_IsMaster; + bool m_IsLight; QString m_Author; QString m_Description; bool m_HasIni; -- cgit v1.3.1 From eaeb48d745d74857d47da5d66d82fea005a16555 Mon Sep 17 00:00:00 2001 From: Jeremy Rimpo Date: Sat, 21 Oct 2017 22:43:45 -0500 Subject: Correctly render the modindex for ESLs --- src/pluginlist.cpp | 20 +++++++++++++++++--- src/pluginlist.h | 4 ++++ 2 files changed, 21 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/pluginlist.cpp b/src/pluginlist.cpp index 2a252d27..f1e28cb2 100644 --- a/src/pluginlist.cpp +++ b/src/pluginlist.cpp @@ -102,7 +102,7 @@ QString PluginList::getColumnToolTip(int column) case COL_NAME: return tr("Name of your mods"); case COL_PRIORITY: return tr("Load priority of your mod. The higher, the more \"important\" it is and thus " "overwrites data from plugins with lower priority."); - case COL_MODINDEX: return tr("The modindex determins the formids of objects originating from this mods."); + case COL_MODINDEX: return tr("The modindex determines the formids of objects originating from this mods."); default: return tr("unknown"); } } @@ -713,7 +713,7 @@ QVariant PluginList::data(const QModelIndex &modelIndex, int role) const if ((role == Qt::DisplayRole) || (role == Qt::EditRole)) { switch (modelIndex.column()) { - case COL_NAME: { + case COL_NAME: { return m_ESPs[index].m_Name; } break; case COL_PRIORITY: { @@ -723,7 +723,21 @@ QVariant PluginList::data(const QModelIndex &modelIndex, int role) const if (m_ESPs[index].m_LoadOrder == -1) { return QString(); } else { - return QString("%1").arg(m_ESPs[index].m_LoadOrder, 2, 16, QChar('0')).toUpper(); + int numESLs = 0; + std::vector sortESPs(m_ESPs); + std::sort(sortESPs.begin(), sortESPs.end()); + for (auto sortedESP: sortESPs) { + if (sortedESP.m_LoadOrder == m_ESPs[index].m_LoadOrder) + break; + if (sortedESP.m_IsLight && sortedESP.m_LoadOrder != -1) + ++numESLs; + } + if (m_ESPs[index].m_IsLight) { + int ESLpos = 254 + (numESLs+1 / 4096); + return QString("%1").arg(ESLpos, 2, 16, QChar('0')).toUpper(); + } else { + return QString("%1").arg(m_ESPs[index].m_LoadOrder - numESLs, 2, 16, QChar('0')).toUpper(); + } } } break; default: { diff --git a/src/pluginlist.h b/src/pluginlist.h index aaa45bc1..e98f5c41 100644 --- a/src/pluginlist.h +++ b/src/pluginlist.h @@ -282,6 +282,10 @@ private: bool m_HasIni; std::set m_Masters; mutable std::set m_MasterUnset; + bool operator < (const ESPInfo& str) const + { + return (m_LoadOrder < str.m_LoadOrder); + } }; struct AdditionalInfo { -- cgit v1.3.1 From e4d431fe2111134ec38f69a1924a2730e89767fc Mon Sep 17 00:00:00 2001 From: Jeremy Rimpo Date: Sat, 21 Oct 2017 23:00:32 -0500 Subject: Display the index of the ESL in the mod index space to differentiate ESLs --- src/organizer_en.ts | 159 +++++++++++++++++++++++++++------------------------- src/pluginlist.cpp | 2 +- 2 files changed, 83 insertions(+), 78 deletions(-) (limited to 'src') diff --git a/src/organizer_en.ts b/src/organizer_en.ts index f73717f2..535c16a5 100644 --- a/src/organizer_en.ts +++ b/src/organizer_en.ts @@ -3019,197 +3019,197 @@ p, li { white-space: pre-wrap; } - - + + 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 @@ -3240,7 +3240,8 @@ p, li { white-space: pre-wrap; } - %1 contains no esp/esm and no asset (textures, meshes, interface, ...) directory + %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 @@ -3253,7 +3254,8 @@ p, li { white-space: pre-wrap; } ModList - Game plugins (esp/esm) + Game plugins (esp/esm/esl) + Game plugins (esp/esm) @@ -3459,7 +3461,8 @@ p, li { white-space: pre-wrap; } - 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> + 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> @@ -3659,81 +3662,81 @@ p, li { white-space: pre-wrap; } - - Multiple esps activated, please check that they don't conflict. + + 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. @@ -3902,37 +3905,37 @@ Continue? - + 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 @@ -5670,7 +5673,8 @@ On Windows XP: - I told you in the "First Steps" tutorial how the esp/esm 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. + 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. + I told you in the "First Steps" tutorial how the esp/esm 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. @@ -5977,7 +5981,8 @@ Please open the "Nexus"-tab - Plugins (esp/esm files) of the mods in the current profile. They need to be checked to be loaded. + Plugins (esp/esm/esl files) of the mods in the current profile. They need to be checked to be loaded. + Plugins (esp/esm files) of the mods in the current profile. They need to be checked to be loaded. diff --git a/src/pluginlist.cpp b/src/pluginlist.cpp index f1e28cb2..d2ffad91 100644 --- a/src/pluginlist.cpp +++ b/src/pluginlist.cpp @@ -734,7 +734,7 @@ QVariant PluginList::data(const QModelIndex &modelIndex, int role) const } if (m_ESPs[index].m_IsLight) { int ESLpos = 254 + (numESLs+1 / 4096); - return QString("%1").arg(ESLpos, 2, 16, QChar('0')).toUpper(); + return QString("%1:%2").arg(ESLpos, 2, 16, QChar('0')).arg((numESLs+1)%4096).toUpper(); } else { return QString("%1").arg(m_ESPs[index].m_LoadOrder - numESLs, 2, 16, QChar('0')).toUpper(); } -- cgit v1.3.1 From b09f8ce7b40a64fa6ac6cdf2dd1a8acdfb736204 Mon Sep 17 00:00:00 2001 From: LePresidente Date: Sun, 22 Oct 2017 21:05:06 +0200 Subject: Updated version to 2.1.0beta Added QtQuick to cmake to try address tutorial issue [Untested] --- src/CMakeLists.txt | 5 +++-- src/version.rc | 4 ++-- 2 files changed, 5 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 448f47e5..833f7504 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -234,6 +234,7 @@ SET(CMAKE_AUTOMOC ON) SET(CMAKE_AUTOUIC ON) FIND_PACKAGE(Qt5Widgets REQUIRED) FIND_PACKAGE(Qt5QuickWidgets REQUIRED) +FIND_PACKAGE(Qt5Quick REQUIRED) FIND_PACKAGE(Qt5Network REQUIRED) FIND_PACKAGE(Qt5WinExtras REQUIRED) FIND_PACKAGE(Qt5WebEngineWidgets REQUIRED) @@ -299,7 +300,7 @@ ENDIF() ADD_EXECUTABLE(ModOrganizer WIN32 ${organizer_HDRS} ${organizer_SRCS} ${organizer_UIHDRS} ${organizer_RCS} ${organizer_RCCPPS} ${organizer_translations_qm}) TARGET_LINK_LIBRARIES(ModOrganizer - Qt5::Widgets Qt5::WinExtras Qt5::WebEngineWidgets + Qt5::Widgets Qt5::WinExtras Qt5::WebEngineWidgets Qt5::Quick ${Boost_LIBRARIES} zlibstatic uibase esptk bsatk githubpp @@ -313,7 +314,7 @@ SET_TARGET_PROPERTIES(ModOrganizer PROPERTIES LINK_FLAGS_RELWITHDEBINFO "/LARGEADDRESSAWARE ${OPTIMIZE_LINK_FLAGS}") -QT5_USE_MODULES(ModOrganizer Widgets Script Qml QuickWidgets Network WebEngineWidgets) +QT5_USE_MODULES(ModOrganizer Widgets Script Qml QuickWidgets Quick Network WebEngineWidgets) ############### diff --git a/src/version.rc b/src/version.rc index e3a2c832..f8b62a2f 100644 --- a/src/version.rc +++ b/src/version.rc @@ -1,7 +1,7 @@ #include "Winver.h" -#define VER_FILEVERSION 2,0,8,3 -#define VER_FILEVERSION_STR "2.0.8.3beta\0" +#define VER_FILEVERSION 2,1,0 +#define VER_FILEVERSION_STR "2.1.0beta\0" VS_VERSION_INFO VERSIONINFO FILEVERSION VER_FILEVERSION -- cgit v1.3.1 From fe44deb765775107da3e4fbd52d5e04574753566 Mon Sep 17 00:00:00 2001 From: Jeremy Rimpo Date: Mon, 23 Oct 2017 02:31:22 -0500 Subject: Update QtQuick import to 2.7 (for Qt 5.7) - works with 5.9 Requires update to uibase --- src/tutorials/Highlight.qml | 2 +- src/tutorials/Tooltip.qml | 2 +- src/tutorials/TooltipArea.qml | 2 +- src/tutorials/TutorialDescription.qml | 2 +- src/tutorials/TutorialOverlay.qml | 2 +- src/tutorials/tutorials_installdialog.qml | 2 +- src/tutorials/tutorials_mainwindow.qml | 2 +- src/tutorials/tutorials_modinfodialog.qml | 2 +- src/tutorials/tutorials_nexusdialog.qml | 2 +- src/tutorials/tutorials_settingsdialog.qml | 2 +- 10 files changed, 10 insertions(+), 10 deletions(-) (limited to 'src') diff --git a/src/tutorials/Highlight.qml b/src/tutorials/Highlight.qml index 55474c91..b6fb7676 100644 --- a/src/tutorials/Highlight.qml +++ b/src/tutorials/Highlight.qml @@ -1,4 +1,4 @@ -import QtQuick 1.1 +import QtQuick 2.7 Rectangle { radius: 10 diff --git a/src/tutorials/Tooltip.qml b/src/tutorials/Tooltip.qml index 6424d9ab..cca71efa 100644 --- a/src/tutorials/Tooltip.qml +++ b/src/tutorials/Tooltip.qml @@ -1,4 +1,4 @@ -import QtQuick 1.1 +import QtQuick 2.7 Rectangle { diff --git a/src/tutorials/TooltipArea.qml b/src/tutorials/TooltipArea.qml index 48a50f76..b6b3d073 100644 --- a/src/tutorials/TooltipArea.qml +++ b/src/tutorials/TooltipArea.qml @@ -1,4 +1,4 @@ -import QtQuick 1.1 +import QtQuick 2.7 Rectangle { radius: 2 diff --git a/src/tutorials/TutorialDescription.qml b/src/tutorials/TutorialDescription.qml index 498573d2..4079b70d 100644 --- a/src/tutorials/TutorialDescription.qml +++ b/src/tutorials/TutorialDescription.qml @@ -1,4 +1,4 @@ -import QtQuick 1.1 +import QtQuick 2.7 // rectangle for description texts Rectangle { diff --git a/src/tutorials/TutorialOverlay.qml b/src/tutorials/TutorialOverlay.qml index 15fe9603..47e5065d 100644 --- a/src/tutorials/TutorialOverlay.qml +++ b/src/tutorials/TutorialOverlay.qml @@ -1,4 +1,4 @@ -import QtQuick 1.1 +import QtQuick 2.7 import "tutorials.js" as Logic Rectangle { diff --git a/src/tutorials/tutorials_installdialog.qml b/src/tutorials/tutorials_installdialog.qml index 33f0a660..9cc21097 100644 --- a/src/tutorials/tutorials_installdialog.qml +++ b/src/tutorials/tutorials_installdialog.qml @@ -1,4 +1,4 @@ -import QtQuick 1.1 +import QtQuick 2.7 TutorialOverlay { id: tutorial diff --git a/src/tutorials/tutorials_mainwindow.qml b/src/tutorials/tutorials_mainwindow.qml index 0012b686..0d660a29 100644 --- a/src/tutorials/tutorials_mainwindow.qml +++ b/src/tutorials/tutorials_mainwindow.qml @@ -1,4 +1,4 @@ -import QtQuick 1.1 +import QtQuick 2.7 TutorialOverlay { id: tutorial diff --git a/src/tutorials/tutorials_modinfodialog.qml b/src/tutorials/tutorials_modinfodialog.qml index e9a56cb3..74f6adfa 100644 --- a/src/tutorials/tutorials_modinfodialog.qml +++ b/src/tutorials/tutorials_modinfodialog.qml @@ -1,4 +1,4 @@ -import QtQuick 1.1 +import QtQuick 2.7 TutorialOverlay { id: tutorial diff --git a/src/tutorials/tutorials_nexusdialog.qml b/src/tutorials/tutorials_nexusdialog.qml index 6a7af6d6..9fb9aafd 100644 --- a/src/tutorials/tutorials_nexusdialog.qml +++ b/src/tutorials/tutorials_nexusdialog.qml @@ -1,4 +1,4 @@ -import QtQuick 1.1 +import QtQuick 2.7 TutorialOverlay { id: tutorial diff --git a/src/tutorials/tutorials_settingsdialog.qml b/src/tutorials/tutorials_settingsdialog.qml index e9a56cb3..74f6adfa 100644 --- a/src/tutorials/tutorials_settingsdialog.qml +++ b/src/tutorials/tutorials_settingsdialog.qml @@ -1,4 +1,4 @@ -import QtQuick 1.1 +import QtQuick 2.7 TutorialOverlay { id: tutorial -- cgit v1.3.1 From 03608230acd0faa7d5fefdc11c75713a0b6c733e Mon Sep 17 00:00:00 2001 From: LePresidente Date: Mon, 23 Oct 2017 18:33:42 +0200 Subject: added a catch all for the remote version check when checking for updates. Should stop a hard crash but should probably be reviewed at a date. --- src/selfupdater.cpp | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'src') diff --git a/src/selfupdater.cpp b/src/selfupdater.cpp index d78b020b..273e9b45 100644 --- a/src/selfupdater.cpp +++ b/src/selfupdater.cpp @@ -124,6 +124,7 @@ void SelfUpdater::testForUpdate() { // TODO: if prereleases are disabled we could just request the latest release // directly + try { m_GitHub.releases(GitHub::Repository("LePresidente", "modorganizer"), [this](const QJsonArray &releases) { QJsonObject newest; @@ -155,6 +156,11 @@ void SelfUpdater::testForUpdate() } } }); + } + //Catch all is bad by design, should be improved + catch (...) { + qDebug("Unable to connect to github.com to check version"); + } } void SelfUpdater::startUpdate() -- cgit v1.3.1 From ac3953030df11f8c9356fa8998c795608f3180e0 Mon Sep 17 00:00:00 2001 From: Jeremy Rimpo Date: Mon, 23 Oct 2017 16:09:27 -0500 Subject: Fix the nexus description link handler --- src/CMakeLists.txt | 1 + src/descriptionpage.h | 28 ++++++++++ src/modinfodialog.cpp | 14 +++-- src/organizer_en.ts | 147 ++++++++++++++++++++++++++------------------------ 4 files changed, 117 insertions(+), 73 deletions(-) create mode 100644 src/descriptionpage.h (limited to 'src') diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 833f7504..d5ebf6ae 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -171,6 +171,7 @@ SET(organizer_HDRS instancemanager.h usvfsconnector.h eventfilter.h + descriptionpage.h shared/windows_error.h shared/error_report.h diff --git a/src/descriptionpage.h b/src/descriptionpage.h new file mode 100644 index 00000000..f6158ee0 --- /dev/null +++ b/src/descriptionpage.h @@ -0,0 +1,28 @@ +#include + +#ifndef DESCRIPTIONPAGE_H +#define DESCRIPTIONPAGE_H + +class DescriptionPage : public QWebEnginePage +{ + Q_OBJECT + +public: + DescriptionPage(QObject* parent = 0) : QWebEnginePage(parent){} + + bool acceptNavigationRequest(const QUrl & url, QWebEnginePage::NavigationType type, bool isMainFrame) + { + if (type == QWebEnginePage::NavigationTypeLinkClicked) + { + emit linkClicked(url); + return false; + } + return true; + } + +signals: + void linkClicked(const QUrl&); + +}; + +#endif //DESCRIPTIONPAGE_H diff --git a/src/modinfodialog.cpp b/src/modinfodialog.cpp index c96c2b4a..c586c6b6 100644 --- a/src/modinfodialog.cpp +++ b/src/modinfodialog.cpp @@ -19,6 +19,7 @@ along with Mod Organizer. If not, see . #include "modinfodialog.h" #include "ui_modinfodialog.h" +#include "descriptionpage.h" #include "iplugingame.h" #include "nexusinterface.h" @@ -38,6 +39,7 @@ along with Mod Organizer. If not, see . #include #include #include +#include #include @@ -85,10 +87,12 @@ ModInfoDialog::ModInfoDialog(ModInfo::Ptr modInfo, const DirectoryEntry *directo ui->notesEdit->setText(modInfo->notes()); + ui->descriptionView->setPage(new DescriptionPage); + connect(&m_ThumbnailMapper, SIGNAL(mapped(const QString&)), this, SIGNAL(thumbnailClickedSignal(const QString&))); connect(this, SIGNAL(thumbnailClickedSignal(const QString&)), this, SLOT(thumbnailClicked(const QString&))); connect(m_ModInfo.data(), SIGNAL(modDetailsUpdated(bool)), this, SLOT(modDetailsUpdated(bool))); - connect(ui->descriptionView, SIGNAL(linkClicked(QUrl)), this, SLOT(linkClicked(QUrl))); + connect(ui->descriptionView->page(), SIGNAL(linkClicked(QUrl)), this, SLOT(linkClicked(QUrl))); //TODO: No easy way to delegate links //ui->descriptionView->page()->acceptNavigationRequest(QWebEnginePage::DelegateAllLinks); @@ -826,11 +830,13 @@ void ModInfoDialog::modDetailsUpdated(bool success) "%1" "").arg(BBCode::convertToHTML(nexusDescription)); + ui->descriptionView->page()->setHtml(descriptionAsHTML); + // QString descriptionAsHTML = BBCode::convertToHTML(result["description"].toString()); - ui->descriptionView->setHtml(descriptionAsHTML); + // ui->descriptionView->setHtml(descriptionAsHTML); } else { // ui->descriptionView->setHtml(result["summary"].toString().append(QString("\r\n") + tr("(description incomplete, please visit nexus)"))); - ui->descriptionView->setHtml(tr("(description incomplete, please visit nexus)")); + ui->descriptionView->page()->setHtml(tr("(description incomplete, please visit nexus)")); } updateVersionColor(); @@ -876,7 +882,7 @@ void ModInfoDialog::on_modIDEdit_editingFinished() if (oldID != modID){ m_ModInfo->setNexusID(modID); - ui->descriptionView->setHtml(""); + ui->descriptionView->page()->setHtml(""); if (modID != 0) { m_RequestStarted = false; refreshNexusData(modID); diff --git a/src/organizer_en.ts b/src/organizer_en.ts index 535c16a5..15785d1f 100644 --- a/src/organizer_en.ts +++ b/src/organizer_en.ts @@ -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 @@ -3870,7 +3870,8 @@ Continue? - The modindex determins the formids of objects originating from this mods. + The modindex determines the formids of objects originating from this mods. + The modindex determins the formids of objects originating from this mods. @@ -3905,37 +3906,37 @@ Continue? - + 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 @@ -5628,22 +5629,26 @@ On Windows XP: - <img src=":/MO/gui/emblem_conflict_overwrite" /> indicates that the mod overwrites files that are also available in another mod. + <img src="qrc:///MO/gui/emblem_conflict_overwrite" /> indicates that the mod overwrites files that are also available in another mod. + <img src=":/MO/gui/emblem_conflict_overwrite" /> indicates that the mod overwrites files that are also available in another mod. - <img src=":/MO/gui/emblem_conflict_overwritten" /> indicates that the mod is <b>partially</b> overwritten by another. + <img src="qrc:///MO/gui/emblem_conflict_overwritten" /> indicates that the mod is <b>partially</b> overwritten by another. + <img src=":/MO/gui/emblem_conflict_overwritten" /> indicates that the mod is <b>partially</b> overwritten by another. - <img src=":/MO/gui/emblem_conflict_mixed" /> indicates that both of the above is true. + <img src="qrc:///MO/gui/emblem_conflict_mixed" /> indicates that both of the above is true. + <img src=":/MO/gui/emblem_conflict_mixed" /> indicates that both of the above is true. - <img src=":/MO/gui/emblem_conflict_redundant" /> indicates that the mod is completely overwrtten by another. You could as well disable it. + <img src="qrc:///MO/gui/emblem_conflict_redundant" /> indicates that the mod is completely overwrtten by another. You could as well disable it. + <img src=":/MO/gui/emblem_conflict_redundant" /> indicates that the mod is completely overwrtten by another. You could as well disable it. @@ -5684,7 +5689,8 @@ On Windows XP: - Please open the "ESPs"-tab... + Please open the "Plugins"-tab... + Please open the "ESPs"-tab... @@ -5694,17 +5700,20 @@ On Windows XP: - Unlike with file conflicts, MO does not provide help on finding conflicts. The good news is, there already is a perfect tool for that called BOSS. BOSS is available on the Nexus and integrates neatly with MO. Basically, if you don't have BOSS yet, install it once this tutorial is over. + Unlike with file conflicts, MO does not provide help on finding conflicts. The good news is, there already is a perfect tool for that called LOOT. LOOT is available on the Nexus and integrates neatly with MO. Basically, if you don't have LOOT yet, install it once this tutorial is over. + Unlike with file conflicts, MO does not provide help on finding conflicts. The good news is, there already is a perfect tool for that called BOSS. BOSS is available on the Nexus and integrates neatly with MO. Basically, if you don't have BOSS yet, install it once this tutorial is over. - After you installed BOSS in the default location (follow its instructions), start MO again and BOSS should automatically appear as an Executable... + After you installed LOOT in the default location (follow its instructions), start MO again and LOOT should automatically appear as an Executable... + After you installed BOSS in the default location (follow its instructions), start MO again and BOSS should automatically appear as an Executable... - When you run BOSS, it will automatically re-organize plugins for best compatibility (overwriting your manual changes). It will also open a report in your browser that warns about incompatibilities. You should read the report, at least for new mods. + When you run LOOT, it will automatically re-organize plugins for best compatibility (overwriting your manual changes). It will also open a report in your browser that warns about incompatibilities. You should read the report, at least for new mods. + When you run BOSS, it will automatically re-organize plugins for best compatibility (overwriting your manual changes). It will also open a report in your browser that warns about incompatibilities. You should read the report, at least for new mods. -- cgit v1.3.1 From 0c6f9831489840bdb3e74f1cdaa1e6f970d8d428 Mon Sep 17 00:00:00 2001 From: Jeremy Rimpo Date: Mon, 23 Oct 2017 16:11:38 -0500 Subject: Fix up tutorial scripts * Patches for QtQuick 2.x * Fix up tab refs, names, and other out-of-date info --- src/tutorials/TooltipArea.qml | 2 +- src/tutorials/tutorial_conflictresolution_main.js | 20 +++---- src/tutorials/tutorial_firststeps_settings.js | 2 +- src/tutorials/tutorial_primer_main.js | 65 +++++++++++++---------- 4 files changed, 50 insertions(+), 39 deletions(-) (limited to 'src') diff --git a/src/tutorials/TooltipArea.qml b/src/tutorials/TooltipArea.qml index b6b3d073..8d404beb 100644 --- a/src/tutorials/TooltipArea.qml +++ b/src/tutorials/TooltipArea.qml @@ -17,7 +17,7 @@ Rectangle { anchors.fill: parent hoverEnabled: true - onMousePositionChanged: { + onPositionChanged: { if (parent.parent.width - (parent.x + mouseX) < tooltip.width + 50) { tooltip.x = parent.x + mouseX - 15 - tooltip.width } else { diff --git a/src/tutorials/tutorial_conflictresolution_main.js b/src/tutorials/tutorial_conflictresolution_main.js index 00ca8d67..a60a5c8d 100644 --- a/src/tutorials/tutorial_conflictresolution_main.js +++ b/src/tutorials/tutorial_conflictresolution_main.js @@ -44,19 +44,19 @@ function getTutorialSteps() { }, function() { unhighlight() - tutorial.text = qsTr(" indicates that the mod overwrites files that are also available in another mod.") + tutorial.text = qsTr(" indicates that the mod overwrites files that are also available in another mod.") waitForClick() }, function() { - tutorial.text = qsTr(" indicates that the mod is partially overwritten by another.") + tutorial.text = qsTr(" indicates that the mod is partially overwritten by another.") waitForClick() }, function() { - tutorial.text = qsTr(" indicates that both of the above is true.") + tutorial.text = qsTr(" indicates that both of the above is true.") waitForClick() }, function() { - tutorial.text = qsTr(" indicates that the mod is completely overwrtten by another. You could as well disable it."); + tutorial.text = qsTr(" indicates that the mod is completely overwrtten by another. You could as well disable it."); waitForClick() }, function() { @@ -65,7 +65,7 @@ function getTutorialSteps() { }, function() { tutorial.text = qsTr("Option A: Switch to the \"Data\"-tab if necessary") - if (!tutorialControl.waitForTabOpen("tabWidget", 2)) { + if (!tutorialControl.waitForTabOpen("tabWidget", 1)) { highlightItem("tabWidget", false) waitForClick() } else { @@ -105,7 +105,7 @@ function getTutorialSteps() { waitForClick() }, function() { - tutorial.text = qsTr("Please open the \"ESPs\"-tab...") + tutorial.text = qsTr("Please open the \"Plugins\"-tab...") highlightItem("tabWidget", true) if (!tutorialControl.waitForTabOpen("tabWidget", 0)) { nextStep() @@ -120,17 +120,17 @@ function getTutorialSteps() { function() { unhighlight() tutorial.text = qsTr("Unlike with file conflicts, MO does not provide help on finding conflicts. The good news is, there " - +"already is a perfect tool for that called BOSS. BOSS is available on the Nexus and integrates " - +"neatly with MO. Basically, if you don't have BOSS yet, install it once this tutorial is over.") + +"already is a perfect tool for that called LOOT. LOOT is available on the Nexus and integrates " + +"neatly with MO. Basically, if you don't have LOOT yet, install it once this tutorial is over.") waitForClick() }, function() { - tutorial.text = qsTr("After you installed BOSS in the default location (follow its instructions), start MO again and BOSS should automatically appear as an Executable...") + tutorial.text = qsTr("After you installed LOOT in the default location (follow its instructions), start MO again and LOOT should automatically appear as an Executable...") highlightItem("startGroup", false) waitForClick() }, function() { - tutorial.text = qsTr("When you run BOSS, it will automatically re-organize plugins for best compatibility (overwriting your manual changes). " + tutorial.text = qsTr("When you run LOOT, it will automatically re-organize plugins for best compatibility (overwriting your manual changes). " +"It will also open a report in your browser that warns about incompatibilities. You should read the report, at least " +"for new mods.") waitForClick() diff --git a/src/tutorials/tutorial_firststeps_settings.js b/src/tutorials/tutorial_firststeps_settings.js index dd5c6e9c..1dd77d2e 100644 --- a/src/tutorials/tutorial_firststeps_settings.js +++ b/src/tutorials/tutorial_firststeps_settings.js @@ -4,7 +4,7 @@ function getTutorialSteps() function() { highlightItem("tabWidget", true) tutorial.text = qsTr("You can use your regular browser to download from Nexus.\nPlease open the \"Nexus\"-tab") - tutorialControl.waitForTabOpen("tabWidget", 1) + tutorialControl.waitForTabOpen("tabWidget", 2) }, function() { diff --git a/src/tutorials/tutorial_primer_main.js b/src/tutorials/tutorial_primer_main.js index 7ef65df9..5d5597c1 100644 --- a/src/tutorials/tutorial_primer_main.js +++ b/src/tutorials/tutorial_primer_main.js @@ -4,29 +4,40 @@ var tooltips = [] function tooltipWidget(widgetName, explanation, maxheight, clickable) { - var rect = tutorialControl.getRect(widgetName) - var component = Qt.createComponent("TooltipArea.qml") - if (component.status === Component.Error) { - console.log("b" + component.errorString()) - } - if (typeof clickable === 'undefined') { - clickable = false - } - if ((typeof maxheight === 'undefined') || maxheight === 0) { - maxheight = rect.height - } - - var obj = component.createObject(tutToplevel, - { "x" : rect.x, - "y" : rect.y, - "width" : rect.width, - "height" : maxheight - }) - obj.tooltipText = explanation - obj.clickable = clickable - obj.visible = true + var component = Qt.createComponent("TooltipArea.qml") + if (component.status === Component.Ready) + finishCreation(component, widgetName, explanation, maxheight, clickable); + else + component.statusChanged.connect(function() { + finishCreation(component, widgetName, explanation, maxheight, clickable); + }); +} - tooltips.push(obj) +function finishCreation(component, widgetName, explanation, maxheight, clickable) { + if (component.status === Component.Ready) { + var rect = tutorialControl.getRect(widgetName) + if (typeof clickable === 'undefined') { + clickable = false + } + if ((typeof maxheight === 'undefined') || maxheight === 0) { + maxheight = rect.height + } + + var obj = component.createObject(tutToplevel, + { + "x": rect.x, + "y": rect.y, + "width": rect.width, + "height": maxheight + }) + obj.tooltipText = explanation + obj.clickable = clickable + obj.visible = true + + tooltips.push(obj) + } else if (component.status === Component.Error) { + console.log("Error loading component: " + component.errorString()) + } } function tooltipAction(actionName, explanation, maxheight, clickable) { @@ -79,16 +90,16 @@ function setupTooptips() { tooltipWidget("bossButton", qsTr("Automatically sort plugins using the bundled LOOT application.")) tooltipWidget("espFilterEdit", qsTr("Quickly filter plugin list as you type.")) break + // case 1: + // tooltipWidget("bsaList", qsTr("All the asset archives (.bsa files) for all active mods.")) + // break case 1: - tooltipWidget("bsaList", qsTr("All the asset archives (.bsa files) for all active mods.")) - break - case 2: tooltipWidget("dataTree", qsTr("The directory tree and all files that the program will see.")) break - case 3: + case 2: tooltipWidget("savegameList", qsTr("Save game browser. Shows all the saves for the current profile and whether or not the current mod-load status is correct.")) break - case 4: + case 3: tooltipWidget("downloadView", qsTr("Shows the mods that have been downloaded and if they’ve been installed.")) break } -- cgit v1.3.1 From 56a3dd46247bc1ef1ccc9d2f213c48041f1669a1 Mon Sep 17 00:00:00 2001 From: Jeremy Rimpo Date: Tue, 24 Oct 2017 01:45:29 -0500 Subject: Fix minor ESL issues and set a useful URL for issue reporting --- src/mainwindow.cpp | 2 +- src/pluginlist.cpp | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 7c853578..79be617b 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -1684,7 +1684,7 @@ void MainWindow::wikiTriggered() void MainWindow::issueTriggered() { - ::ShellExecuteW(nullptr, L"open", L"http://issue.tannin.eu/tbg", nullptr, nullptr, SW_SHOWNORMAL); + ::ShellExecuteW(nullptr, L"open", L"http://github.com/LePresidente/modorganizer/issues", nullptr, nullptr, SW_SHOWNORMAL); } void MainWindow::tutorialTriggered() diff --git a/src/pluginlist.cpp b/src/pluginlist.cpp index d2ffad91..a66a2fb4 100644 --- a/src/pluginlist.cpp +++ b/src/pluginlist.cpp @@ -733,8 +733,8 @@ QVariant PluginList::data(const QModelIndex &modelIndex, int role) const ++numESLs; } if (m_ESPs[index].m_IsLight) { - int ESLpos = 254 + (numESLs+1 / 4096); - return QString("%1:%2").arg(ESLpos, 2, 16, QChar('0')).arg((numESLs+1)%4096).toUpper(); + int ESLpos = 254 + ((numESLs+1) / 4096); + return QString("%1:%2").arg(ESLpos, 2, 16, QChar('0')).arg((numESLs)%4096).toUpper(); } else { return QString("%1").arg(m_ESPs[index].m_LoadOrder - numESLs, 2, 16, QChar('0')).toUpper(); } @@ -1139,7 +1139,7 @@ PluginList::ESPInfo::ESPInfo(const QString &name, bool enabled, try { ESP::File file(ToWString(fullPath)); m_IsMaster = file.isMaster() && !file.isLight(); - m_IsLight = file.isMaster() && file.isLight(); + m_IsLight = file.isLight(); m_Author = QString::fromLatin1(file.author().c_str()); m_Description = QString::fromLatin1(file.description().c_str()); std::set masters = file.masters(); -- cgit v1.3.1 From 643477de2fc0a5e66e0254d86f753101c3ca7335 Mon Sep 17 00:00:00 2001 From: LePresidente Date: Tue, 24 Oct 2017 13:56:06 +0200 Subject: Updated dll manifest. --- src/dlls.manifest.qt5 | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/dlls.manifest.qt5 b/src/dlls.manifest.qt5 index dd0b4ea9..2a3cfeb0 100644 --- a/src/dlls.manifest.qt5 +++ b/src/dlls.manifest.qt5 @@ -3,11 +3,12 @@ - - - + + + + @@ -16,10 +17,12 @@ - + + + - + \ No newline at end of file -- cgit v1.3.1 From 139ee36a3f0cc8b628d93edc890df19170adeac6 Mon Sep 17 00:00:00 2001 From: LePresidente Date: Thu, 26 Oct 2017 15:50:35 +0200 Subject: Fixes https://github.com/LePresidente/modorganizer/issues/108 --- src/mainwindow.cpp | 1 + 1 file changed, 1 insertion(+) (limited to 'src') diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 79be617b..158e32d1 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -840,6 +840,7 @@ void MainWindow::showEvent(QShowEvent *event) m_OrganizerCore.settings().registerAsNXMHandler(false); m_WasVisible = true; + updateProblemsButton(); } } -- cgit v1.3.1 From d659ad7294af2bc67a3b569dc90a7920f5469b07 Mon Sep 17 00:00:00 2001 From: Jeremy Rimpo Date: Thu, 26 Oct 2017 16:28:15 -0500 Subject: Update master parsing and detect ESLs by extension --- src/organizer_en.ts | 173 +++++++++++++++++++++++++--------------------------- src/pluginlist.cpp | 26 ++++---- 2 files changed, 98 insertions(+), 101 deletions(-) (limited to 'src') diff --git a/src/organizer_en.ts b/src/organizer_en.ts index 15785d1f..f8e6ffaa 100644 --- a/src/organizer_en.ts +++ b/src/organizer_en.ts @@ -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 @@ -4769,52 +4769,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 @@ -5919,113 +5919,108 @@ Please open the "Nexus"-tab tutorial_primer_main - + This window shows all the mods that are installed. The column headers can be used for sorting. Only checked mods are active in the current profile. - + Each profile is a separate set of enabled mods and ini settings. - + The dropdown allows various ways of grouping the mods shown in the mod list. - + Show/hide the category pane. - + Quickly filter the mod list as you type. - + Switch between information views. - + This shows mod categories and some meta categories (in angle-brackets). Select some to filter the mod list. For example select "<Checked>" to show only active mods. - + Customizable list for choosing the program to run. - + When this button is clicked, Mod Organizer creates a virtual directory structure then runs the program selected to the left. - + Will create a shortcut for quick access. The shortcut can be placed in the toolbar at the top, in the Start Menu or on the Windows Desktop. - + Log messages produced by MO. Please note that messages with a light bulb usually don't require your attention. - + Configure Mod Organizer. - + Reports potential Problems about the current setup. - + Activates if there is an update for MO. Please note that if, for any reason, MO can't communicate with NMM, this will not work either. - + Plugins (esp/esm/esl files) of the mods in the current profile. They need to be checked to be loaded. Plugins (esp/esm files) of the mods in the current profile. They need to be checked to be loaded. - + Automatically sort plugins using the bundled LOOT application. - + Quickly filter plugin list as you type. - - All the asset archives (.bsa files) for all active mods. - - - - + The directory tree and all files that the program will see. - + Save game browser. Shows all the saves for the current profile and whether or not the current mod-load status is correct. - + Shows the mods that have been downloaded and if they’ve been installed. - + Click to quit diff --git a/src/pluginlist.cpp b/src/pluginlist.cpp index a66a2fb4..4420bf17 100644 --- a/src/pluginlist.cpp +++ b/src/pluginlist.cpp @@ -686,18 +686,18 @@ void PluginList::testMasters() // emit layoutAboutToBeChanged(); std::set enabledMasters; - for (auto iter = m_ESPs.begin(); iter != m_ESPs.end(); ++iter) { - if (iter->m_Enabled) { - enabledMasters.insert(iter->m_Name.toLower()); + for (const auto& iter: m_ESPs) { + if (iter.m_Enabled) { + enabledMasters.insert(iter.m_Name.toLower()); } } - for (auto iter = m_ESPs.begin(); iter != m_ESPs.end(); ++iter) { - iter->m_MasterUnset.clear(); - if (iter->m_Enabled) { - for (auto master = iter->m_Masters.begin(); master != iter->m_Masters.end(); ++master) { - if (enabledMasters.find(master->toLower()) == enabledMasters.end()) { - iter->m_MasterUnset.insert(*master); + for (auto& iter: m_ESPs) { + iter.m_MasterUnset.clear(); + if (iter.m_Enabled) { + for (const auto& master: iter.m_Masters) { + if (enabledMasters.find(master.toLower()) == enabledMasters.end()) { + iter.m_MasterUnset.insert(master); } } } @@ -1138,8 +1138,10 @@ PluginList::ESPInfo::ESPInfo(const QString &name, bool enabled, { try { ESP::File file(ToWString(fullPath)); - m_IsMaster = file.isMaster() && !file.isLight(); - m_IsLight = file.isLight(); + m_IsMaster = file.isMaster(); + auto extension = name.right(3).toLower(); + m_IsLight = (extension == "esl"); // The .isLight() header is apparently meaningless. + m_Author = QString::fromLatin1(file.author().c_str()); m_Description = QString::fromLatin1(file.description().c_str()); std::set masters = file.masters(); @@ -1147,7 +1149,7 @@ PluginList::ESPInfo::ESPInfo(const QString &name, bool enabled, m_Masters.insert(QString(iter->c_str())); } } catch (const std::exception &e) { - qCritical("failed to parse esp file %s: %s", qPrintable(fullPath), e.what()); + qCritical("failed to parse plugin file %s: %s", qPrintable(fullPath), e.what()); m_IsMaster = false; m_IsLight = false; } -- cgit v1.3.1 From ebe6011174767687f3b575c08132a720ecccbf55 Mon Sep 17 00:00:00 2001 From: LePresidente Date: Sat, 28 Oct 2017 08:30:23 +0200 Subject: Fixes the handle leak in the OrganizerCore::waitForProcessCompletion --- src/organizercore.cpp | 103 +++++++++++++++++++++++++------------------------- 1 file changed, 52 insertions(+), 51 deletions(-) (limited to 'src') diff --git a/src/organizercore.cpp b/src/organizercore.cpp index c55504a8..9ae8beae 100644 --- a/src/organizercore.cpp +++ b/src/organizercore.cpp @@ -1239,7 +1239,7 @@ bool OrganizerCore::waitForApplication(HANDLE handle, LPDWORD exitCode) bool OrganizerCore::waitForProcessCompletion(HANDLE handle, LPDWORD exitCode) { HANDLE processHandle = handle; - + static const DWORD maxCount = 5; size_t numProcesses = maxCount; LPDWORD processes = new DWORD[maxCount]; @@ -1250,62 +1250,63 @@ 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), - ((res != WAIT_FAILED) || (res != WAIT_OBJECT_0)) && - ((m_UserInterface == nullptr) || !m_UserInterface->unlockClicked())) { - - if (!::GetVFSProcessList(&numProcesses, processes)) { - break; - } - - bool found = false; - size_t count = - std::min(static_cast(maxCount), numProcesses); - for (size_t i = 0; i < count; ++i) { - std::wstring processName = getProcessName(processes[i]); - if (!boost::starts_with(processName, L"ModOrganizer.exe")) { - currentProcess = processes[i]; - m_UserInterface->setProcessName(QString::fromStdWString(processName)); - processHandle = ::OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, currentProcess); - found = true; + res = ::MsgWaitForMultipleObjects(1, &handle, false, 500, + QS_KEY | QS_MOUSE), + ((res != WAIT_FAILED) || (res != WAIT_OBJECT_0)) && + ((m_UserInterface == nullptr) || !m_UserInterface->unlockClicked())) { + + if (!::GetVFSProcessList(&numProcesses, processes)) { + break; + } + bool found = false; + size_t count = + std::min(static_cast(maxCount), numProcesses); + for (size_t i = 0; i < count; ++i) { + std::wstring processName = getProcessName(processes[i]); + if (!boost::starts_with(processName, L"ModOrganizer.exe")){ + currentProcess = processes[i]; + m_UserInterface->setProcessName(QString::fromStdWString(processName)); + processHandle = ::OpenProcess(SYNCHRONIZE, FALSE, currentProcess); + found = true; + ::CloseHandle(processHandle); + } } - } - if (!found) { - // it's possible the previous process has deregistered before - // the new one has registered, so we should try one more time - // with a little delay - if (tryAgain) { - tryAgain = false; - QThread::msleep(500); - continue; + if (!found) { + // it's possible the previous process has deregistered before + // the new one has registered, so we should try one more time + // with a little delay + if (tryAgain) { + tryAgain = false; + QThread::msleep(500); + continue; + } else { + break; + } } else { - break; + tryAgain = true; + } + // keep processing events so the app doesn't appear dead + + QCoreApplication::processEvents(); + + + if (exitCode != nullptr) { + //This is actually wrong if the process we started finished before we + //got the event and so we end up with a job handle. + if (! ::GetExitCodeProcess(processHandle, exitCode)) + { + DWORD error = ::GetLastError(); + qDebug() << "Failed to get process exit code: Error " << error; + } } - } else { - tryAgain = true; - } - - // keep processing events so the app doesn't appear dead - QCoreApplication::processEvents(); - } - if (exitCode != nullptr) { - //This is actually wrong if the process we started finished before we - //got the event and so we end up with a job handle. - if (! ::GetExitCodeProcess(processHandle, exitCode)) - { - DWORD error = ::GetLastError(); - qDebug() << "Failed to get process exit code: Error " << error; + ::CloseHandle(processHandle); + if (handle != processHandle) { + ::CloseHandle(handle); + } } - } - - ::CloseHandle(processHandle); - if (handle != processHandle) { - ::CloseHandle(handle); - } - return res == WAIT_OBJECT_0; } -- cgit v1.3.1 From cabffa23a9b1ec053a7a573ed71883c44d7a5b6a Mon Sep 17 00:00:00 2001 From: LePresidente Date: Sun, 29 Oct 2017 11:38:06 +0200 Subject: Use ScriptExtender PluginPath instead of appending "/plugin" to the old script extender name variable. --- src/loadmechanism.cpp | 4 ++-- src/modinforegular.cpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/loadmechanism.cpp b/src/loadmechanism.cpp index e476c56d..35aedfed 100644 --- a/src/loadmechanism.cpp +++ b/src/loadmechanism.cpp @@ -129,7 +129,7 @@ void LoadMechanism::deactivateScriptExtender() throw MyException(QObject::tr("game doesn't support a script extender")); } - QDir pluginsDir(game->gameDirectory().absolutePath() + "/data/" + extender->name() + "/plugins"); + QDir pluginsDir(game->gameDirectory().absolutePath() + "/data/" + extender->PluginPath()); #pragma message("implement this for usvfs") @@ -188,7 +188,7 @@ void LoadMechanism::activateScriptExtender() throw MyException(QObject::tr("game doesn't support a script extender")); } - QDir pluginsDir(game->gameDirectory().absolutePath() + "/data/" + extender->name() + "/plugins"); + QDir pluginsDir(game->gameDirectory().absolutePath() + "/data/" + extender->PluginPath()); if (!pluginsDir.exists()) { pluginsDir.mkpath("."); diff --git a/src/modinforegular.cpp b/src/modinforegular.cpp index bacc21f7..1194f604 100644 --- a/src/modinforegular.cpp +++ b/src/modinforegular.cpp @@ -442,7 +442,7 @@ std::vector ModInfoRegular::getContents() const ->feature(); if (extender != nullptr) { - QString sePluginPath = extender->name() + "/plugins"; + QString sePluginPath = extender->PluginPath(); if (dir.exists(sePluginPath)) m_CachedContent.push_back(CONTENT_SKSE); } -- cgit v1.3.1 From 88452e5d76467fc687a9c4d6b6aaf7381d2463e1 Mon Sep 17 00:00:00 2001 From: Jeremy Rimpo Date: Sun, 29 Oct 2017 19:34:35 -0500 Subject: Reimplement ScriptExtender handling by detecting USVFS arch --- src/loadmechanism.cpp | 45 ++++++++++++++++++++++++++++++++------------- src/shared/appconfig.inc | 2 ++ 2 files changed, 34 insertions(+), 13 deletions(-) (limited to 'src') diff --git a/src/loadmechanism.cpp b/src/loadmechanism.cpp index e476c56d..a9d444d1 100644 --- a/src/loadmechanism.cpp +++ b/src/loadmechanism.cpp @@ -133,17 +133,23 @@ void LoadMechanism::deactivateScriptExtender() #pragma message("implement this for usvfs") - /* - QString hookDLLName = ToQString(AppConfig::hookDLLName()); - if (QFile(pluginsDir.absoluteFilePath(hookDLLName)).exists()) { + QString vfsDLLName = ""; + if (extender->getArch() == IMAGE_FILE_MACHINE_I386) { + vfsDLLName = ToQString(AppConfig::vfs32DLLName()); + } + else if (extender->getArch() == IMAGE_FILE_MACHINE_AMD64) + { + vfsDLLName = ToQString(AppConfig::vfs64DLLName()); + } + qDebug("USVFS DLL Name: " + vfsDLLName.toLatin1()); + if (QFile(pluginsDir.absoluteFilePath(vfsDLLName)).exists()) { // remove dll from SE plugins directory - if (!pluginsDir.remove(hookDLLName)) { - throw MyException(QObject::tr("Failed to delete %1").arg(pluginsDir.absoluteFilePath(hookDLLName))); + if (!pluginsDir.remove(vfsDLLName)) { + throw MyException(QObject::tr("Failed to delete %1").arg(pluginsDir.absoluteFilePath(vfsDLLName))); } } removeHintFile(pluginsDir); - */ } catch (const std::exception &e) { QMessageBox::critical(nullptr, QObject::tr("Failed to deactivate script extender loading"), e.what()); } @@ -195,27 +201,37 @@ void LoadMechanism::activateScriptExtender() } #pragma message("implement this for usvfs") -/* - QString targetPath = pluginsDir.absoluteFilePath(ToQString(AppConfig::hookDLLName())); - QString hookDLLPath = qApp->applicationDirPath() + "/" + QString::fromStdWString(AppConfig::hookDLLName()); + QString targetPath; + QString vfsDLLPath; + if (extender->getArch() == IMAGE_FILE_MACHINE_I386) { + targetPath = pluginsDir.absoluteFilePath(ToQString(AppConfig::vfs32DLLName())); + vfsDLLPath = qApp->applicationDirPath() + "/" + QString::fromStdWString(AppConfig::vfs32DLLName()); + } + else if (extender->getArch() == IMAGE_FILE_MACHINE_AMD64) + { + targetPath = pluginsDir.absoluteFilePath(ToQString(AppConfig::vfs64DLLName())); + vfsDLLPath = qApp->applicationDirPath() + "/" + QString::fromStdWString(AppConfig::vfs64DLLName()); + } + + qDebug("DLL USVFS Target Path: " + targetPath.toLatin1()); + qDebug("DLL USVFS VFS DLL Path: " + vfsDLLPath.toLatin1()); QFile dllFile(targetPath); if (dllFile.exists()) { // may be outdated - if (!hashIdentical(targetPath, hookDLLPath)) { + if (!hashIdentical(targetPath, vfsDLLPath)) { dllFile.remove(); } } if (!dllFile.exists()) { // install dll to SE plugins - if (!QFile::copy(hookDLLPath, targetPath)) { - throw MyException(QObject::tr("Failed to copy %1 to %2").arg(hookDLLPath, targetPath)); + if (!QFile::copy(vfsDLLPath, targetPath)) { + throw MyException(QObject::tr("Failed to copy %1 to %2").arg(vfsDLLPath, targetPath)); } } writeHintFile(pluginsDir); -*/ } catch (const std::exception &e) { QMessageBox::critical(nullptr, QObject::tr("Failed to set up script extender loading"), e.what()); } @@ -278,14 +294,17 @@ void LoadMechanism::activate(EMechanism mechanism) { switch (mechanism) { case LOAD_MODORGANIZER: { + qDebug("Load Mechanism: Mod Organizer"); deactivateProxyDLL(); deactivateScriptExtender(); } break; case LOAD_SCRIPTEXTENDER: { + qDebug("Load Mechanism: ScriptExtender"); deactivateProxyDLL(); activateScriptExtender(); } break; case LOAD_PROXYDLL: { + qDebug("Load Mechanism: Proxy DLL"); deactivateScriptExtender(); activateProxyDLL(); } break; diff --git a/src/shared/appconfig.inc b/src/shared/appconfig.inc index ac6c210f..e98757d3 100644 --- a/src/shared/appconfig.inc +++ b/src/shared/appconfig.inc @@ -14,6 +14,8 @@ APPPARAM(std::wstring, iniFileName, L"ModOrganizer.ini") APPPARAM(std::wstring, proxyDLLTarget, L"steam_api.dll") APPPARAM(std::wstring, proxyDLLOrig, L"steam_api_orig.dll") // needs to be identical to the value used in proxydll-project APPPARAM(std::wstring, proxyDLLSource, L"proxy.dll") +APPPARAM(std::wstring, vfs32DLLName, L"usvfs_x86.dll") +APPPARAM(std::wstring, vfs64DLLName, L"usvfs_x64.dll") APPPARAM(const wchar_t*, localSavePlaceholder, L"__MOProfileSave__\\") APPPARAM(std::wstring, firstStepsTutorial, L"tutorial_firststeps_main.js") -- cgit v1.3.1 From 701e6e4927ed887fc569aab97a1a6850e0f3dbdf Mon Sep 17 00:00:00 2001 From: LePresidente Date: Mon, 30 Oct 2017 15:30:28 +0200 Subject: Close the handle that is created by FindFirstFileW correctly. --- src/mainwindow.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 158e32d1..ace7dbd8 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -1944,9 +1944,10 @@ void MainWindow::fileMoved(const QString &filePath, const QString &oldOriginName QString fullNewPath = ToQString(newOrigin.getPath()) + "\\" + filePath; WIN32_FIND_DATAW findData; - ::FindFirstFileW(ToWString(fullNewPath).c_str(), &findData); - + HANDLE hFind; + hFind = ::FindFirstFileW(ToWString(fullNewPath).c_str(), &findData); filePtr->addOrigin(newOrigin.getID(), findData.ftCreationTime, L""); + FindClose(hFind); } if (m_OrganizerCore.directoryStructure()->originExists(ToWString(oldOriginName))) { FilesOrigin &oldOrigin = m_OrganizerCore.directoryStructure()->getOriginByName(ToWString(oldOriginName)); -- cgit v1.3.1 From 2f1d270c08eb43f043e342accc64b1cd1bbff25f Mon Sep 17 00:00:00 2001 From: LePresidente Date: Tue, 31 Oct 2017 12:13:25 +0200 Subject: multiple fixes to waitForProcessCompletion. --- src/organizercore.cpp | 87 +++++++++++++++++++++++++++------------------------ 1 file changed, 46 insertions(+), 41 deletions(-) (limited to 'src') diff --git a/src/organizercore.cpp b/src/organizercore.cpp index 9ae8beae..cba92d8f 100644 --- a/src/organizercore.cpp +++ b/src/organizercore.cpp @@ -1265,48 +1265,53 @@ bool OrganizerCore::waitForProcessCompletion(HANDLE handle, LPDWORD exitCode) std::min(static_cast(maxCount), numProcesses); for (size_t i = 0; i < count; ++i) { std::wstring processName = getProcessName(processes[i]); - if (!boost::starts_with(processName, L"ModOrganizer.exe")){ - currentProcess = processes[i]; - m_UserInterface->setProcessName(QString::fromStdWString(processName)); - processHandle = ::OpenProcess(SYNCHRONIZE, FALSE, currentProcess); - found = true; - ::CloseHandle(processHandle); - } - } - if (!found) { - // it's possible the previous process has deregistered before - // the new one has registered, so we should try one more time - // with a little delay - if (tryAgain) { - tryAgain = false; - QThread::msleep(500); - continue; - } else { - break; - } - } else { - tryAgain = true; - } - // keep processing events so the app doesn't appear dead - - QCoreApplication::processEvents(); - - - if (exitCode != nullptr) { - //This is actually wrong if the process we started finished before we - //got the event and so we end up with a job handle. - if (! ::GetExitCodeProcess(processHandle, exitCode)) - { - DWORD error = ::GetLastError(); - qDebug() << "Failed to get process exit code: Error " << error; - } - } + if (!boost::starts_with(processName, L"ModOrganizer.exe")) { + currentProcess = processes[i]; + m_UserInterface->setProcessName(QString::fromStdWString(processName)); + processHandle = ::OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, currentProcess); + found = true; + } + } + if (!found) { + // it's possible the previous process has deregistered before + // the new one has registered, so we should try one more time + // with a little delay + if (tryAgain) { + tryAgain = false; + QThread::msleep(500); + continue; + } + else { + break; + } + } + else { + tryAgain = true; + } + //Cleanup + if (processHandle != INVALID_HANDLE_VALUE) { + if (exitCode != nullptr) { + //This is actually wrong if the process we started finished before we + //got the event and so we end up with a job handle. + if (!::GetExitCodeProcess(processHandle, exitCode)) + { + DWORD error = ::GetLastError(); + qDebug() << "Failed to get process exit code: Error " << error; + } + } + if (handle != processHandle) { + ::CloseHandle(processHandle); + } + } - ::CloseHandle(processHandle); - if (handle != processHandle) { - ::CloseHandle(handle); - } - } + // keep processing events so the app doesn't appear dead + QCoreApplication::processEvents(); + } + //Final Cleanup + if (handle != INVALID_HANDLE_VALUE) { + ::CloseHandle(handle); + } + delete[] processes; return res == WAIT_OBJECT_0; } -- cgit v1.3.1 From 6c54ef5ec2a1b5395f4292fd33e4dcddf748a145 Mon Sep 17 00:00:00 2001 From: LePresidente Date: Tue, 31 Oct 2017 16:00:58 +0200 Subject: More fixes to waitForProcessCompletion --- src/organizercore.cpp | 73 +++++++++++++++++++++++++++------------------------ 1 file changed, 38 insertions(+), 35 deletions(-) (limited to 'src') diff --git a/src/organizercore.cpp b/src/organizercore.cpp index cba92d8f..48e2f98a 100644 --- a/src/organizercore.cpp +++ b/src/organizercore.cpp @@ -1254,7 +1254,7 @@ bool OrganizerCore::waitForProcessCompletion(HANDLE handle, LPDWORD exitCode) while ( res = ::MsgWaitForMultipleObjects(1, &handle, false, 500, QS_KEY | QS_MOUSE), - ((res != WAIT_FAILED) || (res != WAIT_OBJECT_0)) && + ((res != WAIT_FAILED) && (res != WAIT_OBJECT_0)) && ((m_UserInterface == nullptr) || !m_UserInterface->unlockClicked())) { if (!::GetVFSProcessList(&numProcesses, processes)) { @@ -1263,47 +1263,50 @@ bool OrganizerCore::waitForProcessCompletion(HANDLE handle, LPDWORD exitCode) bool found = false; size_t count = std::min(static_cast(maxCount), numProcesses); - for (size_t i = 0; i < count; ++i) { - std::wstring processName = getProcessName(processes[i]); - if (!boost::starts_with(processName, L"ModOrganizer.exe")) { - currentProcess = processes[i]; - m_UserInterface->setProcessName(QString::fromStdWString(processName)); - processHandle = ::OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, currentProcess); - found = true; + if (count > 0) { + for (size_t i = 0; i < count; ++i) { + std::wstring processName = getProcessName(processes[i]); + if (!boost::starts_with(processName, L"ModOrganizer.exe")) { + if (!boost::starts_with(processName, L"unknown")) { + currentProcess = processes[i]; + m_UserInterface->setProcessName(QString::fromStdWString(processName)); + processHandle = ::OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, currentProcess); + found = true; + } + } } - } - if (!found) { - // it's possible the previous process has deregistered before - // the new one has registered, so we should try one more time - // with a little delay - if (tryAgain) { - tryAgain = false; - QThread::msleep(500); - continue; + if (!found) { + // it's possible the previous process has deregistered before + // the new one has registered, so we should try one more time + // with a little delay + if (tryAgain) { + tryAgain = false; + QThread::msleep(500); + continue; + } + else { + break; + } } else { - break; + tryAgain = true; } - } - else { - tryAgain = true; - } - //Cleanup - if (processHandle != INVALID_HANDLE_VALUE) { - if (exitCode != nullptr) { - //This is actually wrong if the process we started finished before we - //got the event and so we end up with a job handle. - if (!::GetExitCodeProcess(processHandle, exitCode)) - { - DWORD error = ::GetLastError(); - qDebug() << "Failed to get process exit code: Error " << error; + //Cleanup + if (processHandle != INVALID_HANDLE_VALUE) { + if (exitCode != nullptr) { + //This is actually wrong if the process we started finished before we + //got the event and so we end up with a job handle. + if (!::GetExitCodeProcess(processHandle, exitCode)) + { + DWORD error = ::GetLastError(); + qDebug() << "Failed to get process exit code: Error " << error; + } + } + if (handle != processHandle) { + ::CloseHandle(processHandle); } - } - if (handle != processHandle) { - ::CloseHandle(processHandle); } } - // keep processing events so the app doesn't appear dead QCoreApplication::processEvents(); } -- cgit v1.3.1 From 0825cd0f203af00a074203dde469bf40102e821d Mon Sep 17 00:00:00 2001 From: Al12rs Date: Tue, 31 Oct 2017 23:20:06 +0100 Subject: Added !found condition to for loop to ensure that a valid processHandle can't be overwritten to avoid handle leaks. --- src/organizercore.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/organizercore.cpp b/src/organizercore.cpp index 48e2f98a..05da9f83 100644 --- a/src/organizercore.cpp +++ b/src/organizercore.cpp @@ -1264,7 +1264,7 @@ bool OrganizerCore::waitForProcessCompletion(HANDLE handle, LPDWORD exitCode) size_t count = std::min(static_cast(maxCount), numProcesses); if (count > 0) { - for (size_t i = 0; i < count; ++i) { + for (size_t i = 0; i < count && !found; ++i) { std::wstring processName = getProcessName(processes[i]); if (!boost::starts_with(processName, L"ModOrganizer.exe")) { if (!boost::starts_with(processName, L"unknown")) { -- cgit v1.3.1 From 087f3841f3dbf92936ac30e935520c728fef1776 Mon Sep 17 00:00:00 2001 From: Jeremy Rimpo Date: Tue, 31 Oct 2017 21:29:12 -0500 Subject: If architecture is not detected, skip handling --- src/loadmechanism.cpp | 65 +++++++++++++++++++++++++++------------------------ 1 file changed, 34 insertions(+), 31 deletions(-) (limited to 'src') diff --git a/src/loadmechanism.cpp b/src/loadmechanism.cpp index a2050512..7ad36ac7 100644 --- a/src/loadmechanism.cpp +++ b/src/loadmechanism.cpp @@ -142,12 +142,14 @@ void LoadMechanism::deactivateScriptExtender() vfsDLLName = ToQString(AppConfig::vfs64DLLName()); } qDebug("USVFS DLL Name: " + vfsDLLName.toLatin1()); - if (QFile(pluginsDir.absoluteFilePath(vfsDLLName)).exists()) { - // remove dll from SE plugins directory - if (!pluginsDir.remove(vfsDLLName)) { - throw MyException(QObject::tr("Failed to delete %1").arg(pluginsDir.absoluteFilePath(vfsDLLName))); - } - } + if (vfsDLLName != "") { + if (QFile(pluginsDir.absoluteFilePath(vfsDLLName)).exists()) { + // remove dll from SE plugins directory + if (!pluginsDir.remove(vfsDLLName)) { + throw MyException(QObject::tr("Failed to delete %1").arg(pluginsDir.absoluteFilePath(vfsDLLName))); + } + } + } removeHintFile(pluginsDir); } catch (const std::exception &e) { @@ -201,36 +203,37 @@ void LoadMechanism::activateScriptExtender() } #pragma message("implement this for usvfs") - QString targetPath; - QString vfsDLLPath; + std::wstring vfsDLL = L""; if (extender->getArch() == IMAGE_FILE_MACHINE_I386) { - targetPath = pluginsDir.absoluteFilePath(ToQString(AppConfig::vfs32DLLName())); - vfsDLLPath = qApp->applicationDirPath() + "/" + QString::fromStdWString(AppConfig::vfs32DLLName()); + vfsDLL = AppConfig::vfs32DLLName(); } else if (extender->getArch() == IMAGE_FILE_MACHINE_AMD64) { - targetPath = pluginsDir.absoluteFilePath(ToQString(AppConfig::vfs64DLLName())); - vfsDLLPath = qApp->applicationDirPath() + "/" + QString::fromStdWString(AppConfig::vfs64DLLName()); + vfsDLL = AppConfig::vfs64DLLName(); + } + if (vfsDLL != L"") { + QString targetPath = pluginsDir.absoluteFilePath(ToQString(vfsDLL)); + QString vfsDLLPath = qApp->applicationDirPath() + "/" + QString::fromStdWString(vfsDLL); + + qDebug("DLL USVFS Target Path: " + targetPath.toLatin1()); + qDebug("DLL USVFS VFS DLL Path: " + vfsDLLPath.toLatin1()); + + QFile dllFile(targetPath); + + if (dllFile.exists()) { + // may be outdated + if (!hashIdentical(targetPath, vfsDLLPath)) { + dllFile.remove(); + } + } + + if (!dllFile.exists()) { + // install dll to SE plugins + if (!QFile::copy(vfsDLLPath, targetPath)) { + throw MyException(QObject::tr("Failed to copy %1 to %2").arg(vfsDLLPath, targetPath)); + } + } } - - qDebug("DLL USVFS Target Path: " + targetPath.toLatin1()); - qDebug("DLL USVFS VFS DLL Path: " + vfsDLLPath.toLatin1()); - - QFile dllFile(targetPath); - - if (dllFile.exists()) { - // may be outdated - if (!hashIdentical(targetPath, vfsDLLPath)) { - dllFile.remove(); - } - } - - if (!dllFile.exists()) { - // install dll to SE plugins - if (!QFile::copy(vfsDLLPath, targetPath)) { - throw MyException(QObject::tr("Failed to copy %1 to %2").arg(vfsDLLPath, targetPath)); - } - } writeHintFile(pluginsDir); } catch (const std::exception &e) { QMessageBox::critical(nullptr, QObject::tr("Failed to set up script extender loading"), e.what()); -- cgit v1.3.1 From 51ad72c74d89b630e3091e7cb7d6e7dfdcb7b78b Mon Sep 17 00:00:00 2001 From: Jeremy Rimpo Date: Thu, 2 Nov 2017 01:41:11 -0500 Subject: Process completion fixes * Closes all old handles * Hides 'unknown' processes * Correctly detects process chains --- src/organizercore.cpp | 154 +++++++++++++++++++++++++------------------------- 1 file changed, 76 insertions(+), 78 deletions(-) (limited to 'src') diff --git a/src/organizercore.cpp b/src/organizercore.cpp index 05da9f83..f77d7356 100644 --- a/src/organizercore.cpp +++ b/src/organizercore.cpp @@ -1238,84 +1238,82 @@ bool OrganizerCore::waitForApplication(HANDLE handle, LPDWORD exitCode) bool OrganizerCore::waitForProcessCompletion(HANDLE handle, LPDWORD exitCode) { - HANDLE processHandle = handle; - - static const DWORD maxCount = 5; - size_t numProcesses = maxCount; - LPDWORD processes = new DWORD[maxCount]; - - DWORD currentProcess = 0UL; - bool tryAgain = true; - - 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), - ((res != WAIT_FAILED) && (res != WAIT_OBJECT_0)) && - ((m_UserInterface == nullptr) || !m_UserInterface->unlockClicked())) { - - if (!::GetVFSProcessList(&numProcesses, processes)) { - break; - } - bool found = false; - size_t count = - std::min(static_cast(maxCount), numProcesses); - if (count > 0) { - for (size_t i = 0; i < count && !found; ++i) { - std::wstring processName = getProcessName(processes[i]); - if (!boost::starts_with(processName, L"ModOrganizer.exe")) { - if (!boost::starts_with(processName, L"unknown")) { - currentProcess = processes[i]; - m_UserInterface->setProcessName(QString::fromStdWString(processName)); - processHandle = ::OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, currentProcess); - found = true; - } - } - } - if (!found) { - // it's possible the previous process has deregistered before - // the new one has registered, so we should try one more time - // with a little delay - if (tryAgain) { - tryAgain = false; - QThread::msleep(500); - continue; - } - else { - break; - } - } - else { - tryAgain = true; - } - //Cleanup - if (processHandle != INVALID_HANDLE_VALUE) { - if (exitCode != nullptr) { - //This is actually wrong if the process we started finished before we - //got the event and so we end up with a job handle. - if (!::GetExitCodeProcess(processHandle, exitCode)) - { - DWORD error = ::GetLastError(); - qDebug() << "Failed to get process exit code: Error " << error; - } - } - if (handle != processHandle) { - ::CloseHandle(processHandle); - } - } - } - // keep processing events so the app doesn't appear dead - QCoreApplication::processEvents(); - } - //Final Cleanup - if (handle != INVALID_HANDLE_VALUE) { - ::CloseHandle(handle); - } - delete[] processes; - return res == WAIT_OBJECT_0; + HANDLE processHandle = handle; + + static const DWORD maxCount = 5; + size_t numProcesses = maxCount; + LPDWORD processes = new DWORD[maxCount]; + + DWORD currentProcess = 0UL; + bool tryAgain = true; + + 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), + ((res != WAIT_FAILED) || (res != WAIT_OBJECT_0)) && + ((m_UserInterface == nullptr) || !m_UserInterface->unlockClicked())) { + + if (!::GetVFSProcessList(&numProcesses, processes)) { + break; + } + + bool found = false; + size_t count = + std::min(static_cast(maxCount), numProcesses); + for (size_t i = 0; i < count; ++i) { + std::wstring processName = getProcessName(processes[i]); + if (!boost::starts_with(processName, L"ModOrganizer.exe")) { + currentProcess = processes[i]; + if (processHandle != INVALID_HANDLE_VALUE) + ::CloseHandle(processHandle); + processHandle = ::OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, currentProcess); + found = true; + if (!boost::starts_with(processName, L"unknown")) { + m_UserInterface->setProcessName(QString::fromStdWString(processName)); + } + } + } + if (!found) { + // it's possible the previous process has deregistered before + // the new one has registered, so we should try one more time + // with a little delay + if (tryAgain) { + tryAgain = false; + QThread::msleep(500); + continue; + } else { + break; + } + } else { + tryAgain = true; + } + + // keep processing events so the app doesn't appear dead + QCoreApplication::processEvents(); + } + + if (exitCode != nullptr) { + //This is actually wrong if the process we started finished before we + //got the event and so we end up with a job handle. + if (! ::GetExitCodeProcess(processHandle, exitCode)) + { + DWORD error = ::GetLastError(); + qDebug() << "Failed to get process exit code: Error " << error; + } + } + + //Cleanup + if (processHandle != INVALID_HANDLE_VALUE) { + ::CloseHandle(processHandle); + } + if (handle != processHandle) { + ::CloseHandle(handle); + } + + return res == WAIT_OBJECT_0; } bool OrganizerCore::onAboutToRun( -- cgit v1.3.1 From 00af56f7c7e8b233ba6a466b23bb907ba9ca4648 Mon Sep 17 00:00:00 2001 From: Jeremy Rimpo Date: Thu, 2 Nov 2017 16:01:55 -0500 Subject: Fix remaining handle leaks --- src/organizercore.cpp | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/organizercore.cpp b/src/organizercore.cpp index f77d7356..26b726e9 100644 --- a/src/organizercore.cpp +++ b/src/organizercore.cpp @@ -104,17 +104,20 @@ static std::wstring getProcessName(DWORD processId) HANDLE process = ::OpenProcess(PROCESS_QUERY_INFORMATION, false, processId); wchar_t buffer[MAX_PATH]; + wchar_t *fileName = L"unknown"; + + if (process == nullptr) return fileName; + if (::GetProcessImageFileNameW(process, buffer, MAX_PATH) != 0) { - wchar_t *fileName = wcsrchr(buffer, L'\\'); + fileName = wcsrchr(buffer, L'\\'); if (fileName == nullptr) { fileName = buffer; } else { fileName += 1; } - return fileName; - } else { - return std::wstring(L"unknown"); } + ::CloseHandle(process); + return fileName; } static void startSteam(QWidget *widget) @@ -363,6 +366,12 @@ bool OrganizerCore::testForSteam() PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, processIDs[i]); if (process != nullptr) { + + ON_BLOCK_EXIT([&]() { + if (process != INVALID_HANDLE_VALUE) + ::CloseHandle(process); + }); + HMODULE module; DWORD ignore; @@ -1267,7 +1276,7 @@ bool OrganizerCore::waitForProcessCompletion(HANDLE handle, LPDWORD exitCode) std::wstring processName = getProcessName(processes[i]); if (!boost::starts_with(processName, L"ModOrganizer.exe")) { currentProcess = processes[i]; - if (processHandle != INVALID_HANDLE_VALUE) + if (processHandle != INVALID_HANDLE_VALUE && processHandle != handle) ::CloseHandle(processHandle); processHandle = ::OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, currentProcess); found = true; -- cgit v1.3.1 From 901bf0059d68c0c84039a3bf248a308c243e4664 Mon Sep 17 00:00:00 2001 From: LePresidente Date: Sat, 4 Nov 2017 09:54:47 +0200 Subject: processes should be deleted at end of waitForProcessCompletion --- src/organizercore.cpp | 1 + 1 file changed, 1 insertion(+) (limited to 'src') diff --git a/src/organizercore.cpp b/src/organizercore.cpp index 26b726e9..76fc3eef 100644 --- a/src/organizercore.cpp +++ b/src/organizercore.cpp @@ -1321,6 +1321,7 @@ bool OrganizerCore::waitForProcessCompletion(HANDLE handle, LPDWORD exitCode) if (handle != processHandle) { ::CloseHandle(handle); } + delete[] processes; return res == WAIT_OBJECT_0; } -- cgit v1.3.1 From 853c42081d9c7f14bea2ffe8ee076724fd5e3946 Mon Sep 17 00:00:00 2001 From: Jeremy Rimpo Date: Sun, 5 Nov 2017 01:45:57 -0600 Subject: Rework waitForProcessCompletion - reduce handle use and add delay --- src/organizercore.cpp | 202 +++++++++++++++++++++++++++----------------------- 1 file changed, 110 insertions(+), 92 deletions(-) (limited to 'src') diff --git a/src/organizercore.cpp b/src/organizercore.cpp index 76fc3eef..deb47d74 100644 --- a/src/organizercore.cpp +++ b/src/organizercore.cpp @@ -99,25 +99,24 @@ static bool renameFile(const QString &oldName, const QString &newName, return QFile::rename(oldName, newName); } -static std::wstring getProcessName(DWORD processId) +static std::wstring getProcessName(HANDLE process) { - HANDLE process = ::OpenProcess(PROCESS_QUERY_INFORMATION, false, processId); + wchar_t buffer[MAX_PATH]; + wchar_t *fileName = L"unknown"; - wchar_t buffer[MAX_PATH]; - wchar_t *fileName = L"unknown"; + if (process == nullptr) return fileName; - if (process == nullptr) return fileName; + if (::GetProcessImageFileNameW(process, buffer, MAX_PATH) != 0) { + fileName = wcsrchr(buffer, L'\\'); + if (fileName == nullptr) { + fileName = buffer; + } + else { + fileName += 1; + } + } - if (::GetProcessImageFileNameW(process, buffer, MAX_PATH) != 0) { - fileName = wcsrchr(buffer, L'\\'); - if (fileName == nullptr) { - fileName = buffer; - } else { - fileName += 1; - } - } - ::CloseHandle(process); - return fileName; + return fileName; } static void startSteam(QWidget *widget) @@ -1247,83 +1246,102 @@ bool OrganizerCore::waitForApplication(HANDLE handle, LPDWORD exitCode) bool OrganizerCore::waitForProcessCompletion(HANDLE handle, LPDWORD exitCode) { - HANDLE processHandle = handle; - - static const DWORD maxCount = 5; - size_t numProcesses = maxCount; - LPDWORD processes = new DWORD[maxCount]; - - DWORD currentProcess = 0UL; - bool tryAgain = true; - - 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), - ((res != WAIT_FAILED) || (res != WAIT_OBJECT_0)) && - ((m_UserInterface == nullptr) || !m_UserInterface->unlockClicked())) { - - if (!::GetVFSProcessList(&numProcesses, processes)) { - break; - } - - bool found = false; - size_t count = - std::min(static_cast(maxCount), numProcesses); - for (size_t i = 0; i < count; ++i) { - std::wstring processName = getProcessName(processes[i]); - if (!boost::starts_with(processName, L"ModOrganizer.exe")) { - currentProcess = processes[i]; - if (processHandle != INVALID_HANDLE_VALUE && processHandle != handle) - ::CloseHandle(processHandle); - processHandle = ::OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, currentProcess); - found = true; - if (!boost::starts_with(processName, L"unknown")) { - m_UserInterface->setProcessName(QString::fromStdWString(processName)); - } - } - } - if (!found) { - // it's possible the previous process has deregistered before - // the new one has registered, so we should try one more time - // with a little delay - if (tryAgain) { - tryAgain = false; - QThread::msleep(500); - continue; - } else { - break; - } - } else { - tryAgain = true; - } - - // keep processing events so the app doesn't appear dead - QCoreApplication::processEvents(); - } - - if (exitCode != nullptr) { - //This is actually wrong if the process we started finished before we - //got the event and so we end up with a job handle. - if (! ::GetExitCodeProcess(processHandle, exitCode)) - { - DWORD error = ::GetLastError(); - qDebug() << "Failed to get process exit code: Error " << error; - } - } - - //Cleanup - if (processHandle != INVALID_HANDLE_VALUE) { - ::CloseHandle(processHandle); - } - if (handle != processHandle) { - ::CloseHandle(handle); - } + DWORD startPID = ::GetProcessId(handle); + + static const DWORD maxCount = 5; + size_t numProcesses = maxCount; + LPDWORD processes = new DWORD[maxCount]; + std::map handles; + + DWORD currentProcess = 0UL; + bool tryAgain = true; + DWORD moProcess = -1; + + 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), + ((m_UserInterface == nullptr) || !m_UserInterface->unlockClicked())) { + + if (!::GetVFSProcessList(&numProcesses, processes)) { + break; + } + + // Get USvFS processes, build a handle map, and allow to continue if invalid PIDs are supplied + bool found = false; + size_t count = + std::min(static_cast(maxCount), numProcesses); + for (size_t i = 0; i < count; ++i) { + DWORD currentProcess = processes[i]; + if (currentProcess != moProcess && handles.count(currentProcess) == 0) { + HANDLE currentHandle = ::OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, currentProcess); + std::wstring processName = getProcessName(currentHandle); + if (!boost::starts_with(processName, L"ModOrganizer.exe")) { + found = true; + if (currentHandle == nullptr || currentHandle == INVALID_HANDLE_VALUE) continue; + handles.insert(std::pair(currentProcess, currentHandle)); + } + else + { + moProcess = processes[i]; + ::CloseHandle(currentHandle); + } + } + } + + // Clean up tracked handles + for (std::map::iterator checkHandle = handles.begin(); checkHandle != handles.end(); ++checkHandle) { + if (checkHandle->second != nullptr && checkHandle->second != INVALID_HANDLE_VALUE) { + DWORD processExit; + BOOL codeCheck = ::GetExitCodeProcess(checkHandle->second, &processExit); + if (!codeCheck || processExit != STILL_ACTIVE) { + if (!codeCheck) qDebug() << "Checking the process failed: Error Code " << ::GetLastError(); + ::CloseHandle(checkHandle->second); + checkHandle = handles.erase(checkHandle); + } + } + } + + if (handles.size() > 0) + m_UserInterface->setProcessName(QString::fromStdWString(getProcessName(handles.begin()->second))); + + if ((res == WAIT_FAILED) || (res == WAIT_OBJECT_0)) { + if (handles.size() > 0) { + QThread::msleep(500); + } + } + + // If process handle is still closed, let's give it one more try... + if (handles.size() == 0 && !found) { + // it's possible the previous process has deregistered before + // the new one has registered, so we should try one more time + // with a little delay + if (tryAgain) { + tryAgain = false; + QThread::msleep(500); + continue; + } + else { + break; + } + } + else { + tryAgain = true; + } + + // keep processing events so the app doesn't appear dead + QCoreApplication::processEvents(); + } + + //Cleanup + if (handle != INVALID_HANDLE_VALUE) { + ::CloseHandle(handle); + } delete[] processes; - return res == WAIT_OBJECT_0; + return res == WAIT_OBJECT_0; } bool OrganizerCore::onAboutToRun( @@ -1676,8 +1694,8 @@ void OrganizerCore::loginSuccessful(bool necessary) task(); } - m_PostLoginTasks.clear(); - NexusInterface::instance()->loginCompleted(); + m_PostLoginTasks.clear(); + NexusInterface::instance()->loginCompleted(); } void OrganizerCore::loginSuccessfulUpdate(bool necessary) -- cgit v1.3.1 From a92fc98246f351ed6657788b9b12aca7cce4771a Mon Sep 17 00:00:00 2001 From: Jeremy Rimpo Date: Sun, 5 Nov 2017 13:47:00 -0600 Subject: Remove cruft and reapply input event listening on subprocess delay --- src/organizercore.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/organizercore.cpp b/src/organizercore.cpp index deb47d74..d12b77b9 100644 --- a/src/organizercore.cpp +++ b/src/organizercore.cpp @@ -1253,13 +1253,11 @@ bool OrganizerCore::waitForProcessCompletion(HANDLE handle, LPDWORD exitCode) LPDWORD processes = new DWORD[maxCount]; std::map handles; - DWORD currentProcess = 0UL; bool tryAgain = true; DWORD moProcess = -1; 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), @@ -1304,20 +1302,22 @@ bool OrganizerCore::waitForProcessCompletion(HANDLE handle, LPDWORD exitCode) } } + // Update the lock process name with the name of the lowest active PID - though this may not actually be the main process if (handles.size() > 0) m_UserInterface->setProcessName(QString::fromStdWString(getProcessName(handles.begin()->second))); + // If the main wait process dies, we need a backup wait process until the subprocesses close if ((res == WAIT_FAILED) || (res == WAIT_OBJECT_0)) { if (handles.size() > 0) { - QThread::msleep(500); + // By the time we get here, the main wait function should always immediately continue + // Passing in a handle doesn't seem to work for subprocesses + ::MsgWaitForMultipleObjects(0, NULL, FALSE, 500, QS_KEY | QS_MOUSE); } } - // If process handle is still closed, let's give it one more try... + // Give the process list a short time to populate + // Required for initial USVFS boot and process switching if (handles.size() == 0 && !found) { - // it's possible the previous process has deregistered before - // the new one has registered, so we should try one more time - // with a little delay if (tryAgain) { tryAgain = false; QThread::msleep(500); -- cgit v1.3.1 From 4cd09a2f3b25c1af5939f5de0153b1438241a874 Mon Sep 17 00:00:00 2001 From: Jeremy Rimpo Date: Sun, 5 Nov 2017 14:03:02 -0600 Subject: Wait for mousebutton to reduce MO cpu use while waiting --- src/organizercore.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/organizercore.cpp b/src/organizercore.cpp index d12b77b9..f8a368c9 100644 --- a/src/organizercore.cpp +++ b/src/organizercore.cpp @@ -1260,7 +1260,7 @@ bool OrganizerCore::waitForProcessCompletion(HANDLE handle, LPDWORD exitCode) // Wait for a an event on the handle, a key press, mouse click or timeout while ( res = ::MsgWaitForMultipleObjects(1, &handle, false, 500, - QS_KEY | QS_MOUSE), + QS_KEY | QS_MOUSEBUTTON), ((m_UserInterface == nullptr) || !m_UserInterface->unlockClicked())) { if (!::GetVFSProcessList(&numProcesses, processes)) { @@ -1311,7 +1311,7 @@ bool OrganizerCore::waitForProcessCompletion(HANDLE handle, LPDWORD exitCode) if (handles.size() > 0) { // By the time we get here, the main wait function should always immediately continue // Passing in a handle doesn't seem to work for subprocesses - ::MsgWaitForMultipleObjects(0, NULL, FALSE, 500, QS_KEY | QS_MOUSE); + ::MsgWaitForMultipleObjects(0, NULL, FALSE, 500, QS_KEY | QS_MOUSEBUTTON); } } -- cgit v1.3.1 From 836e550dd0bc2b20d99f222865cfe1a0cb069187 Mon Sep 17 00:00:00 2001 From: Helidoc65 Date: Tue, 7 Nov 2017 10:42:43 -0700 Subject: Add files via upload Fixed to get rid of WindowsWindow::setGeometry: Unable to set geometry bug. --- src/editexecutablesdialog.ui | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'src') diff --git a/src/editexecutablesdialog.ui b/src/editexecutablesdialog.ui index b3543c95..bdbb8bd1 100644 --- a/src/editexecutablesdialog.ui +++ b/src/editexecutablesdialog.ui @@ -10,6 +10,12 @@ 460 + + + 200 + 200 + + Modify Executables -- cgit v1.3.1 From 8d5c67296f7e8b87a8feb70e32c3a89713f80fbe Mon Sep 17 00:00:00 2001 From: Jeremy Rimpo Date: Tue, 7 Nov 2017 22:18:55 -0600 Subject: Forcing the progress window to resize seems to hang the extraction process --- src/installationmanager.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/installationmanager.cpp b/src/installationmanager.cpp index 9be4cdd9..d2d131fd 100644 --- a/src/installationmanager.cpp +++ b/src/installationmanager.cpp @@ -420,7 +420,12 @@ void InstallationManager::updateProgress(float percentage) void InstallationManager::updateProgressFile(QString const &fileName) { if (m_InstallationProgress != nullptr) { - m_InstallationProgress->setLabelText(fileName); + if (fileName.size() > 30) { + m_InstallationProgress->setLabelText("..." + fileName.right(27)); + } + else { + m_InstallationProgress->setLabelText(fileName); + } } } -- cgit v1.3.1 From 092596f57afe6c44a11465d1df5522e48d185297 Mon Sep 17 00:00:00 2001 From: Jeremy Rimpo Date: Tue, 7 Nov 2017 23:31:07 -0600 Subject: Don't truncate, bypass the issue by fixing the progress window size --- src/installationmanager.cpp | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/src/installationmanager.cpp b/src/installationmanager.cpp index d2d131fd..9a70f8bd 100644 --- a/src/installationmanager.cpp +++ b/src/installationmanager.cpp @@ -187,6 +187,7 @@ bool InstallationManager::unpackSingleFile(const QString &fileName) m_InstallationProgress->setWindowTitle(tr("Extracting files")); m_InstallationProgress->setWindowModality(Qt::WindowModal); + m_InstallationProgress->setFixedSize(600, 100); m_InstallationProgress->show(); bool res = m_ArchiveHandler->extract(QDir::tempPath(), @@ -274,6 +275,7 @@ QStringList InstallationManager::extractFiles(const QStringList &filesOrig, bool m_InstallationProgress->windowFlags() & (~Qt::WindowContextHelpButtonHint)); m_InstallationProgress->setWindowTitle(tr("Extracting files")); m_InstallationProgress->setWindowModality(Qt::WindowModal); + m_InstallationProgress->setFixedSize(600, 100); m_InstallationProgress->show(); // unpack only the files we need for the installer @@ -419,14 +421,10 @@ void InstallationManager::updateProgress(float percentage) void InstallationManager::updateProgressFile(QString const &fileName) { - if (m_InstallationProgress != nullptr) { - if (fileName.size() > 30) { - m_InstallationProgress->setLabelText("..." + fileName.right(27)); - } - else { - m_InstallationProgress->setLabelText(fileName); - } - } + if (m_InstallationProgress != nullptr) { + m_InstallationProgress->setLabelText(fileName); + QCoreApplication::processEvents(); + } } @@ -568,6 +566,7 @@ bool InstallationManager::doInstall(GuessedValue &modName, int modID, m_InstallationProgress->setWindowFlags( m_InstallationProgress->windowFlags() & (~Qt::WindowContextHelpButtonHint)); m_InstallationProgress->setWindowModality(Qt::WindowModal); + m_InstallationProgress->setFixedSize(600, 100); m_InstallationProgress->show(); if (!m_ArchiveHandler->extract(targetDirectory, new MethodCallback(this, &InstallationManager::updateProgress), -- cgit v1.3.1 From 9ec913945a42b33f1cfd4f7389539c25895adb34 Mon Sep 17 00:00:00 2001 From: Jeremy Rimpo Date: Wed, 8 Nov 2017 19:29:10 -0600 Subject: Add missing Nexus categories --- src/categories.cpp | 87 ++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 55 insertions(+), 32 deletions(-) (limited to 'src') diff --git a/src/categories.cpp b/src/categories.cpp index be6af9ae..02ebbd8a 100644 --- a/src/categories.cpp +++ b/src/categories.cpp @@ -205,42 +205,65 @@ void CategoryFactory::loadDefaultCategories() { // the order here is relevant as it defines the order in which the // mods appear in the combo box - addCategory(1, "Animations", MakeVector(1, 51), 0); - addCategory(2, "Armour", MakeVector(1, 54), 0); - addCategory(3, "Sound & Music", MakeVector(1, 61), 0); - addCategory(5, "Clothing", MakeVector(1, 60), 0); - addCategory(6, "Collectables", MakeVector(1, 92), 0); - addCategory(28, "Companions", MakeVector(2, 66, 96), 0); - addCategory(7, "Creatures & Mounts", MakeVector(2, 83, 65), 0); - addCategory(8, "Factions", MakeVector(1, 25), 0); - addCategory(9, "Gameplay", MakeVector(1, 24), 0); - addCategory(10, "Hair", MakeVector(1, 26), 0); - addCategory(11, "Items", MakeVector(2, 27, 85), 0); - addCategory(32, "Mercantile", MakeVector(1, 69), 0); - addCategory(19, "Weapons", MakeVector(1, 55), 11); - addCategory(36, "Weapon & Armour Sets", MakeVector(1, 39), 11); - addCategory(12, "Locations", MakeVector(7, 22, 30, 70, 88, 89, 90, 91), 0); - addCategory(31, "Landscape Changes", MakeVector(1, 58), 0); - addCategory(4, "Cities", MakeVector(1, 53), 12); - addCategory(29, "Environment", MakeVector(1, 74), 0); - addCategory(30, "Immersion", MakeVector(1, 78), 0); + addCategory(1, "Animations", MakeVector(2, 4, 51), 0); + addCategory(52, "Poses", MakeVector(1, 29), 1); + addCategory(2, "Armour", MakeVector(2, 5, 54), 0); + addCategory(53, "Power Armor", MakeVector(1, 53), 2); + addCategory(3, "Audio", MakeVector(3, 33, 35, 106), 0); + addCategory(38, "Music", MakeVector(2, 34, 61), 0); + addCategory(39, "Voice", MakeVector(2, 36, 107), 0); + addCategory(5, "Clothing", MakeVector(2, 9, 60), 0); + addCategory(41, "Jewelry", MakeVector(1, 102), 5); + addCategory(42, "Backpacks", MakeVector(1, 49), 5); + addCategory(6, "Collectables", MakeVector(2, 10, 92), 0); + addCategory(28, "Companions", MakeVector(3, 11, 66, 96), 0); + addCategory(7, "Creatures, Mounts, & Vehicles", MakeVector(4, 12, 39, 83, 65), 0); + addCategory(8, "Factions", MakeVector(2, 16, 25), 0); + addCategory(9, "Gameplay", MakeVector(2, 15, 24), 0); + addCategory(27, "Combat", MakeVector(1, 77), 9); + addCategory(43, "Crafting", MakeVector(2, 50, 100), 9); + addCategory(48, "Overhauls", MakeVector(2, 24, 79), 9); + addCategory(49, "Perks", MakeVector(1, 27), 9); + addCategory(54, "Radio", MakeVector(1, 31), 9); + addCategory(55, "Shouts", MakeVector(1, 104), 9); + addCategory(22, "Skills & Levelling", MakeVector(2, 46, 73), 9); + addCategory(58, "Weather & Lighting", MakeVector(1, 56), 9); + addCategory(44, "Equipment", MakeVector(1, 44), 43); + addCategory(45, "Home/Settlement", MakeVector(1, 45), 43); + addCategory(10, "Body, Face, & Hair", MakeVector(2, 17, 26), 0); + addCategory(56, "Tattoos", MakeVector(1, 57), 10); + addCategory(40, "Character Presets", MakeVector(1, 58), 0); + addCategory(11, "Items", MakeVector(3, 27, 85), 0); + addCategory(32, "Mercantile", MakeVector(2, 23, 69), 0); + addCategory(37, "Ammo", MakeVector(1, 3), 11); + addCategory(19, "Weapons", MakeVector(2, 41, 55), 11); + addCategory(36, "Weapon & Armour Sets", MakeVector(2, 39, 42), 11); + addCategory(23, "Player Homes", MakeVector(1, 28, 67), 0); addCategory(25, "Castles & Mansions", MakeVector(1, 68), 23); + addCategory(51, "Settlements", MakeVector(1, 48), 23); + addCategory(57, "Blueprints", MakeVector(1, 61), 51); + addCategory(12, "Locations", MakeVector(10, 20, 21, 22, 30, 47, 70, 88, 89, 90, 91), 0); + addCategory(4, "Cities", MakeVector(1, 53), 12); + addCategory(31, "Landscape Changes", MakeVector(1, 58), 0); + addCategory(29, "Environment", MakeVector(1, 14, 74), 0); + addCategory(30, "Immersion", MakeVector(2, 51, 78), 0); addCategory(20, "Magic", MakeVector(3, 75, 93, 94), 0); - addCategory(21, "Models & Textures", MakeVector(1, 29), 0); - addCategory(33, "Modders resources", MakeVector(1, 82), 0); - addCategory(13, "NPCs", MakeVector(1, 33), 0); - addCategory(14, "Patches", MakeVector(2, 79, 84), 0); - addCategory(24, "Bugfixes", MakeVector(1, 95), 0); - addCategory(35, "Utilities", MakeVector(1, 39), 0); - addCategory(26, "Cheats", MakeVector(1, 40), 0); - addCategory(23, "Player Homes", MakeVector(1, 67), 0); - addCategory(15, "Quests", MakeVector(1, 35), 0); + addCategory(21, "Models & Textures", MakeVector(2, 19, 29), 0); + addCategory(33, "Modders resources", MakeVector(2, 18, 82), 0); + addCategory(13, "NPCs", MakeVector(3, 22, 33, 99), 0); + addCategory(24, "Bugfixes", MakeVector(2, 6, 95), 0); + addCategory(14, "Patches", MakeVector(2, 25, 84), 24); + addCategory(39, "Performance", MakeVector(1, 26), 24); + addCategory(35, "Utilities", MakeVector(2, 38, 39), 0); + addCategory(26, "Cheats", MakeVector(1, 8, 40), 0); + addCategory(15, "Quests", MakeVector(2, 30, 35), 0); addCategory(16, "Races & Classes", MakeVector(1, 34), 0); - addCategory(27, "Combat", MakeVector(1, 77), 0); - addCategory(22, "Skills", MakeVector(1, 73), 0); addCategory(34, "Stealth", MakeVector(1, 76), 0); - addCategory(17, "UI", MakeVector(1, 42), 0); - addCategory(18, "Visuals", MakeVector(1, 62), 0); + addCategory(17, "UI", MakeVector(2, 37, 42), 0); + addCategory(18, "Visuals", MakeVector(2, 40, 62), 0); + addCategory(50, "Pip-Boy", MakeVector(1, 52), 18); + addCategory(46, "Shader Presets", MakeVector(3, 13, 97, 105), 0); + addCategory(47, "Miscellaneous", MakeVector(2, 2, 28), 0); } -- cgit v1.3.1 From 3cf3de700eeac08867d509e478449e46d7ff9f12 Mon Sep 17 00:00:00 2001 From: Jeremy Rimpo Date: Wed, 8 Nov 2017 19:30:20 -0600 Subject: Add MCM detection (but doesn't fix loading issues :() --- src/modinfo.cpp | 1 + src/modinfo.h | 3 ++- src/modinforegular.cpp | 2 ++ src/modlist.cpp | 3 ++- src/resources.qrc | 1 + 5 files changed, 8 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/modinfo.cpp b/src/modinfo.cpp index 7cb4b4ba..5d3c1e41 100644 --- a/src/modinfo.cpp +++ b/src/modinfo.cpp @@ -99,6 +99,7 @@ QString ModInfo::getContentTypeName(int contentType) case CONTENT_SCRIPT: return tr("Scripts"); case CONTENT_SKSE: return tr("SKSE Plugins"); case CONTENT_SKYPROC: return tr("SkyProc Tools"); + case CONTENT_MCM: return tr("MCM Data"); default: throw MyException(tr("invalid content type %1").arg(contentType)); } } diff --git a/src/modinfo.h b/src/modinfo.h index 501588ec..1485a4b3 100644 --- a/src/modinfo.h +++ b/src/modinfo.h @@ -79,7 +79,8 @@ public: CONTENT_SOUND, CONTENT_SCRIPT, CONTENT_SKSE, - CONTENT_SKYPROC + CONTENT_SKYPROC, + CONTENT_MCM }; static const int NUM_CONTENT_TYPES = CONTENT_SKYPROC + 1; diff --git a/src/modinforegular.cpp b/src/modinforegular.cpp index 1194f604..c296d792 100644 --- a/src/modinforegular.cpp +++ b/src/modinforegular.cpp @@ -458,6 +458,8 @@ std::vector ModInfoRegular::getContents() const m_CachedContent.push_back(CONTENT_SCRIPT); if (dir.exists("SkyProc Patchers")) m_CachedContent.push_back(CONTENT_SKYPROC); + if (dir.exists("MCM")) + m_CachedContent.push_back(CONTENT_MCM); m_LastContentCheck = QTime::currentTime(); } diff --git a/src/modlist.cpp b/src/modlist.cpp index 0aea7a98..ffbdee95 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/esl)")); + 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")); @@ -69,6 +69,7 @@ ModList::ModList(QObject *parent) m_ContentIcons[ModInfo::CONTENT_SKYPROC] = std::make_tuple(":/MO/gui/content/skyproc", tr("SkyProc Patcher")); m_ContentIcons[ModInfo::CONTENT_SOUND] = std::make_tuple(":/MO/gui/content/sound", tr("Sound or Music")); m_ContentIcons[ModInfo::CONTENT_TEXTURE] = std::make_tuple(":/MO/gui/content/texture", tr("Textures")); + m_ContentIcons[ModInfo::CONTENT_MCM] = std::make_tuple(":/MO/gui/content/menu", tr("MCM Configuration")); m_LastCheck.start(); } diff --git a/src/resources.qrc b/src/resources.qrc index d357801c..e88eda06 100644 --- a/src/resources.qrc +++ b/src/resources.qrc @@ -82,6 +82,7 @@ resources/contents/breastplate.png resources/contents/conversation.png resources/contents/locked-chest.png + resources/contents/config.png qt.conf -- cgit v1.3.1 From 3974ddced4e02866c6548066d0c546f3cf6d77db Mon Sep 17 00:00:00 2001 From: Al12rs Date: Fri, 10 Nov 2017 21:00:24 +0100 Subject: Fix for MO finding the wrong game to manage. Commented out code that tried to deduce game and found wrong one. Now, if not already set in INI, file MO will ask the user which one to manage. --- src/main.cpp | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'src') diff --git a/src/main.cpp b/src/main.cpp index d14641a4..526563a2 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -318,6 +318,9 @@ MOBase::IPluginGame *determineCurrentGame(QString const &moPath, QSettings &sett } } + //The following code would try to determine the right game to mange but it would usually find the wrong one + //so it was commented out. + /* //OK, we are in a new setup or existing info is useless. //See if MO has been installed inside a game directory for (IPluginGame * const game : plugins.plugins()) { @@ -341,6 +344,7 @@ MOBase::IPluginGame *determineCurrentGame(QString const &moPath, QSettings &sett //OK, chop off the last directory and try again } while (gameDir.cdUp()); } + */ //Then try a selection dialogue. if (!gamePath.isEmpty() || !gameName.isEmpty()) { -- cgit v1.3.1 From 53a54230eb017878cd186ba4723e01c521278de9 Mon Sep 17 00:00:00 2001 From: Jeremy Rimpo Date: Mon, 13 Nov 2017 08:47:44 -0600 Subject: Add resource image for MCM detection --- src/resources/contents/config.png | Bin 0 -> 552 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 src/resources/contents/config.png (limited to 'src') diff --git a/src/resources/contents/config.png b/src/resources/contents/config.png new file mode 100644 index 00000000..3896d885 Binary files /dev/null and b/src/resources/contents/config.png differ -- cgit v1.3.1 From 581a8871c62a05d48a45059e6e611871be3f6361 Mon Sep 17 00:00:00 2001 From: Jeremy Rimpo Date: Wed, 15 Nov 2017 18:33:54 -0600 Subject: Category fixes --- src/categories.cpp | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) (limited to 'src') diff --git a/src/categories.cpp b/src/categories.cpp index 02ebbd8a..d8cd49fb 100644 --- a/src/categories.cpp +++ b/src/categories.cpp @@ -217,7 +217,7 @@ void CategoryFactory::loadDefaultCategories() addCategory(42, "Backpacks", MakeVector(1, 49), 5); addCategory(6, "Collectables", MakeVector(2, 10, 92), 0); addCategory(28, "Companions", MakeVector(3, 11, 66, 96), 0); - addCategory(7, "Creatures, Mounts, & Vehicles", MakeVector(4, 12, 39, 83, 65), 0); + addCategory(7, "Creatures, Mounts, & Vehicles", MakeVector(4, 12, 65, 83, 101), 0); addCategory(8, "Factions", MakeVector(2, 16, 25), 0); addCategory(9, "Gameplay", MakeVector(2, 15, 24), 0); addCategory(27, "Combat", MakeVector(1, 77), 9); @@ -231,21 +231,20 @@ void CategoryFactory::loadDefaultCategories() addCategory(44, "Equipment", MakeVector(1, 44), 43); addCategory(45, "Home/Settlement", MakeVector(1, 45), 43); addCategory(10, "Body, Face, & Hair", MakeVector(2, 17, 26), 0); - addCategory(56, "Tattoos", MakeVector(1, 57), 10); + addCategory(39, "Tattoos", MakeVector(1, 57), 10); addCategory(40, "Character Presets", MakeVector(1, 58), 0); - addCategory(11, "Items", MakeVector(3, 27, 85), 0); + addCategory(11, "Items", MakeVector(2, 27, 85), 0); addCategory(32, "Mercantile", MakeVector(2, 23, 69), 0); addCategory(37, "Ammo", MakeVector(1, 3), 11); addCategory(19, "Weapons", MakeVector(2, 41, 55), 11); - addCategory(36, "Weapon & Armour Sets", MakeVector(2, 39, 42), 11); - addCategory(23, "Player Homes", MakeVector(1, 28, 67), 0); + addCategory(36, "Weapon & Armour Sets", MakeVector(1, 42), 11); + addCategory(23, "Player Homes", MakeVector(2, 28, 67), 0); addCategory(25, "Castles & Mansions", MakeVector(1, 68), 23); addCategory(51, "Settlements", MakeVector(1, 48), 23); - addCategory(57, "Blueprints", MakeVector(1, 61), 51); addCategory(12, "Locations", MakeVector(10, 20, 21, 22, 30, 47, 70, 88, 89, 90, 91), 0); addCategory(4, "Cities", MakeVector(1, 53), 12); addCategory(31, "Landscape Changes", MakeVector(1, 58), 0); - addCategory(29, "Environment", MakeVector(1, 14, 74), 0); + addCategory(29, "Environment", MakeVector(2, 14, 74), 0); addCategory(30, "Immersion", MakeVector(2, 51, 78), 0); addCategory(20, "Magic", MakeVector(3, 75, 93, 94), 0); addCategory(21, "Models & Textures", MakeVector(2, 19, 29), 0); @@ -253,9 +252,8 @@ void CategoryFactory::loadDefaultCategories() addCategory(13, "NPCs", MakeVector(3, 22, 33, 99), 0); addCategory(24, "Bugfixes", MakeVector(2, 6, 95), 0); addCategory(14, "Patches", MakeVector(2, 25, 84), 24); - addCategory(39, "Performance", MakeVector(1, 26), 24); addCategory(35, "Utilities", MakeVector(2, 38, 39), 0); - addCategory(26, "Cheats", MakeVector(1, 8, 40), 0); + addCategory(26, "Cheats", MakeVector(1, 8), 0); addCategory(15, "Quests", MakeVector(2, 30, 35), 0); addCategory(16, "Races & Classes", MakeVector(1, 34), 0); addCategory(34, "Stealth", MakeVector(1, 76), 0); -- cgit v1.3.1 From 977d562976a06b9d98e08197d28dfca7cb3d229e Mon Sep 17 00:00:00 2001 From: Jeremy Rimpo Date: Thu, 30 Nov 2017 00:36:10 -0600 Subject: Set the default WebEngineProfile settings to webcache --- src/mainwindow.cpp | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'src') diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index ace7dbd8..0a6e32c3 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -145,6 +145,7 @@ along with Mod Organizer. If not, see . #include #include #include +#include #include #include @@ -199,6 +200,10 @@ MainWindow::MainWindow(QSettings &initSettings , m_PluginContainer(pluginContainer) , m_DidUpdateMasterList(false) { + QWebEngineProfile::defaultProfile()->setPersistentCookiesPolicy(QWebEngineProfile::NoPersistentCookies); + QWebEngineProfile::defaultProfile()->setHttpCacheMaximumSize(52428800); + QWebEngineProfile::defaultProfile()->setCachePath(m_OrganizerCore.settings().getCacheDirectory()); + QWebEngineProfile::defaultProfile()->setPersistentStoragePath(m_OrganizerCore.settings().getCacheDirectory()); ui->setupUi(this); updateWindowTitle(QString(), false); @@ -868,6 +873,7 @@ void MainWindow::cleanup() ui->logList->setModel(nullptr); } + QWebEngineProfile::defaultProfile()->clearAllVisitedLinks(); m_IntegratedBrowser.close(); } -- 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') 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 797a007eab2695c231a00240225d77b3a9928992 Mon Sep 17 00:00:00 2001 From: Jeremy Rimpo Date: Thu, 30 Nov 2017 17:34:28 -0600 Subject: Add unmanaged mods and fix plugin identification --- src/modinfoforeign.cpp | 6 +++++- src/pluginlist.cpp | 9 ++++++++- 2 files changed, 13 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/modinfoforeign.cpp b/src/modinfoforeign.cpp index 4ba16bb1..6ad8b6d8 100644 --- a/src/modinfoforeign.cpp +++ b/src/modinfoforeign.cpp @@ -30,12 +30,16 @@ std::vector ModInfoForeign::getFlags() const std::vector result = ModInfoWithConflictInfo::getFlags(); result.push_back(FLAG_FOREIGN); + if (m_PluginSelected) { + result.push_back(ModInfo::FLAG_PLUGIN_SELECTED); + } + return result; } int ModInfoForeign::getHighlight() const { - return 0; + return m_PluginSelected ? ModInfo::HIGHLIGHT_PLUGIN : ModInfo::HIGHLIGHT_NONE; } QString ModInfoForeign::getDescription() const diff --git a/src/pluginlist.cpp b/src/pluginlist.cpp index a215b9d3..add34b3f 100644 --- a/src/pluginlist.cpp +++ b/src/pluginlist.cpp @@ -118,8 +118,15 @@ void PluginList::highlightPlugins(const QItemSelection &selected, const MOShared if (!selectedMod.isNull()) { 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) { + 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()) + continue; + } std::map::iterator iter = m_ESPsByName.find(plugin.toLower()); if (iter != m_ESPsByName.end()) { m_ESPs[iter->second].m_ModSelected = true; -- cgit v1.3.1 From e19597ee4e8d045d61bd6c4a85e280e500475ed6 Mon Sep 17 00:00:00 2001 From: Jeremy Rimpo Date: Sat, 2 Dec 2017 13:36:33 -0600 Subject: Final highlighting changes --- src/mainwindow.cpp | 2 +- src/pluginlist.cpp | 4 ++-- src/pluginlist.h | 3 ++- 3 files changed, 5 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 84860767..cdc32918 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -2126,7 +2126,7 @@ void MainWindow::modlistSelectionChanged(const QModelIndex ¤t, const QMode void MainWindow::modlistSelectionsChanged(const QItemSelection &selected) { - m_OrganizerCore.pluginList()->highlightPlugins(selected, *m_OrganizerCore.directoryStructure()); + m_OrganizerCore.pluginList()->highlightPlugins(selected, *m_OrganizerCore.directoryStructure(), *m_OrganizerCore.currentProfile()); ui->espList->verticalScrollBar()->repaint(); } diff --git a/src/pluginlist.cpp b/src/pluginlist.cpp index add34b3f..61d33fe9 100644 --- a/src/pluginlist.cpp +++ b/src/pluginlist.cpp @@ -108,14 +108,14 @@ QString PluginList::getColumnToolTip(int column) } } -void PluginList::highlightPlugins(const QItemSelection &selected, const MOShared::DirectoryEntry &directoryEntry) +void PluginList::highlightPlugins(const QItemSelection &selected, const MOShared::DirectoryEntry &directoryEntry, const Profile &profile) { 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()) { + 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()); diff --git a/src/pluginlist.h b/src/pluginlist.h index 19e98989..8d1a5491 100644 --- a/src/pluginlist.h +++ b/src/pluginlist.h @@ -22,6 +22,7 @@ along with Mod Organizer. If not, see . #include #include +#include "profile.h" namespace MOBase { class IPluginGame; } #include @@ -200,7 +201,7 @@ public: static QString getColumnName(int column); static QString getColumnToolTip(int column); - void highlightPlugins(const QItemSelection &selected, const MOShared::DirectoryEntry &directoryEntry); + void highlightPlugins(const QItemSelection &selected, const MOShared::DirectoryEntry &directoryEntry, const Profile &profile); void refreshLoadOrder(); -- cgit v1.3.1
Game plugins (esp/esm)
Game plugins (esp/esm/esl)
Interface
Meshes
BSA