summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/bbcode.cpp4
-rw-r--r--src/downloadmanager.cpp8
-rw-r--r--src/logbuffer.cpp7
-rw-r--r--src/main.cpp3
-rw-r--r--src/mainwindow.cpp689
-rw-r--r--src/mainwindow.h59
-rw-r--r--src/mainwindow.ui85
-rw-r--r--src/modinfo.cpp2
-rw-r--r--src/modlistsortproxy.cpp66
-rw-r--r--src/modlistsortproxy.h12
-rw-r--r--src/nexusinterface.cpp139
-rw-r--r--src/nexusinterface.h36
-rw-r--r--src/nxmaccessmanager.cpp13
-rw-r--r--src/nxmaccessmanager.h5
-rw-r--r--src/organizer.pro6
-rw-r--r--src/organizerproxy.cpp185
-rw-r--r--src/organizerproxy.h48
-rw-r--r--src/pluginlist.cpp12
-rw-r--r--src/pluginlist.h1
-rw-r--r--src/selfupdater.cpp2
20 files changed, 870 insertions, 512 deletions
diff --git a/src/bbcode.cpp b/src/bbcode.cpp
index 80721cd2..455f4767 100644
--- a/src/bbcode.cpp
+++ b/src/bbcode.cpp
@@ -153,8 +153,8 @@ private:
"<a href=\"\\1\">\\1</a>");
m_TagMap["url="] = std::make_pair(QRegExp("\\[url=([^\\]]*)\\](.*)\\[/url\\]"),
"<a href=\"\\1\">\\2</a>");
- m_TagMap["img"] = std::make_pair(QRegExp("\\[img\\](.*)\\[/img\\]"), "");
- m_TagMap["img="] = std::make_pair(QRegExp("\\[img=([^\\]]*)\\](.*)\\[/img\\]"), "");
+ m_TagMap["img"] = std::make_pair(QRegExp("\\[img\\](.*)\\[/img\\]"), " ");
+ m_TagMap["img="] = std::make_pair(QRegExp("\\[img=([^\\]]*)\\](.*)\\[/img\\]"), " ");
m_TagMap["email="] = std::make_pair(QRegExp("\\[email=\"?([^\\]]*)\"?\\](.*)\\[/email\\]"),
"<a href=\"mailto:\\1\">\\2</a>");
m_TagMap["youtube"] = std::make_pair(QRegExp("\\[youtube\\](.*)\\[/youtube\\]"),
diff --git a/src/downloadmanager.cpp b/src/downloadmanager.cpp
index 03c282f0..ae53a819 100644
--- a/src/downloadmanager.cpp
+++ b/src/downloadmanager.cpp
@@ -448,7 +448,7 @@ void DownloadManager::addNXMDownload(const QString &url)
emit update(-1);
emit downloadAdded();
- m_RequestIDs.insert(m_NexusInterface->requestFileInfo(nxmInfo.modId(), nxmInfo.fileId(), this, nxmInfo.fileId()));
+ m_RequestIDs.insert(m_NexusInterface->requestFileInfo(nxmInfo.modId(), nxmInfo.fileId(), this, nxmInfo.fileId(), ""));
}
@@ -919,10 +919,10 @@ void DownloadManager::setState(DownloadManager::DownloadInfo *info, DownloadMana
info->m_Reply->abort();
} break;
case STATE_FETCHINGMODINFO: {
- m_RequestIDs.insert(m_NexusInterface->requestDescription(info->m_FileInfo->modID, this, info->m_DownloadID));
+ m_RequestIDs.insert(m_NexusInterface->requestDescription(info->m_FileInfo->modID, this, info->m_DownloadID, QString()));
} break;
case STATE_FETCHINGFILEINFO: {
- m_RequestIDs.insert(m_NexusInterface->requestFiles(info->m_FileInfo->modID, this, info->m_DownloadID));
+ m_RequestIDs.insert(m_NexusInterface->requestFiles(info->m_FileInfo->modID, this, info->m_DownloadID, QString()));
} break;
case STATE_READY: {
createMetaFile(info);
@@ -1167,7 +1167,7 @@ void DownloadManager::nxmFileInfoAvailable(int modID, int fileID, QVariant userD
info->fileID = fileID;
QObject *test = info;
- m_RequestIDs.insert(m_NexusInterface->requestDownloadURL(modID, fileID, this, qVariantFromValue(test)));
+ m_RequestIDs.insert(m_NexusInterface->requestDownloadURL(modID, fileID, this, qVariantFromValue(test), QString()));
}
diff --git a/src/logbuffer.cpp b/src/logbuffer.cpp
index b9fa9417..1bf9cd85 100644
--- a/src/logbuffer.cpp
+++ b/src/logbuffer.cpp
@@ -168,7 +168,12 @@ QVariant LogBuffer::data(const QModelIndex &index, int role) const
if (index.column() == 0) {
return m_Messages.at(msgIndex).time;
} else if (index.column() == 1) {
- return m_Messages.at(msgIndex).message;
+ const QString &msg = m_Messages.at(msgIndex).message;
+ if (msg.length() < 200) {
+ return msg;
+ } else {
+ return msg.mid(0, 200) + "...";
+ }
}
} break;
case Qt::DecorationRole: {
diff --git a/src/main.cpp b/src/main.cpp
index 3d00b10a..05dc54d7 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -310,6 +310,7 @@ bool HaveWriteAccess(const std::wstring &path)
return writable;
}
+
int main(int argc, char *argv[])
{
MOApplication application(argc, argv);
@@ -328,7 +329,7 @@ int main(int argc, char *argv[])
, ToWString(QDir::currentPath()).c_str(), SW_SHOWNORMAL);
return 1;
}
- LogBuffer::init(200, QtDebugMsg, application.applicationDirPath() + "/logs/mo_interface.log");
+ LogBuffer::init(100, QtDebugMsg, application.applicationDirPath() + "/logs/mo_interface.log");
qDebug("Working directory: %s", qPrintable(QDir::toNativeSeparators(QDir::currentPath())));
qDebug("MO at: %s", qPrintable(QDir::toNativeSeparators(application.applicationDirPath())));
diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp
index 5dc2eb2a..a524be61 100644
--- a/src/mainwindow.cpp
+++ b/src/mainwindow.cpp
@@ -60,6 +60,7 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
#include "browserdialog.h"
#include "aboutdialog.h"
#include "safewritefile.h"
+#include "organizerproxy.h"
#include <gameinfo.h>
#include <appconfig.h>
#include <utility.h>
@@ -161,13 +162,12 @@ MainWindow::MainWindow(const QString &exeName, QSettings &initSettings, QWidget
m_PluginList(this), m_OldExecutableIndex(-1), m_GamePath(ToQString(GameInfo::instance().getGameDirectory())),
m_DownloadManager(NexusInterface::instance(), this), m_InstallationManager(this),
m_Updater(NexusInterface::instance(), this), m_CategoryFactory(CategoryFactory::instance()),
- m_CurrentProfile(NULL), m_AskForNexusPW(false), m_LoginAttempted(false),
+ m_CurrentProfile(NULL), m_AskForNexusPW(false),
m_ArchivesInit(false), m_ContextItem(NULL), m_ContextAction(NULL), m_CurrentSaveView(NULL),
m_GameInfo(new GameInfoImpl()), m_AboutToRun()
{
ui->setupUi(this);
this->setWindowTitle(ToQString(GameInfo::instance().getGameName()) + " Mod Organizer v" + m_Updater.getVersion().displayString());
-
ui->logList->setModel(LogBuffer::instance());
ui->logList->setColumnWidth(0, 100);
ui->logList->setAutoScroll(true);
@@ -246,6 +246,8 @@ MainWindow::MainWindow(const QString &exeName, QSettings &initSettings, QWidget
linkMenu->addAction(QIcon(":/MO/gui/link"), tr("Start Menu"), this, SLOT(linkMenu()));
ui->linkButton->setMenu(linkMenu);
+ ui->listOptionsBtn->setMenu(modListContextMenu());
+
m_DownloadManager.setOutputDirectory(m_Settings.getDownloadDirectory());
m_DownloadManager.setPreferredServers(m_Settings.getPreferredServers());
@@ -306,6 +308,7 @@ MainWindow::MainWindow(const QString &exeName, QSettings &initSettings, QWidget
connect(NexusInterface::instance()->getAccessManager(), SIGNAL(loginFailed(QString)), this, SLOT(loginFailed(QString)));
connect(NexusInterface::instance(), SIGNAL(requestNXMDownload(QString)), this, SLOT(downloadRequestedNXM(QString)));
connect(NexusInterface::instance(), SIGNAL(nxmDownloadURLsAvailable(int,int,QVariant,QVariant,int)), this, SLOT(nxmDownloadURLs(int,int,QVariant,QVariant,int)));
+ connect(NexusInterface::instance(), SIGNAL(needLogin()), this, SLOT(nexusLogin()));
connect(&TutorialManager::instance(), SIGNAL(windowTutorialFinished(QString)), this, SLOT(windowTutorialFinished(QString)));
@@ -995,7 +998,7 @@ bool MainWindow::verifyPlugin(IPlugin *plugin)
{
if (plugin == NULL) {
return false;
- } else if (!plugin->init(this)) {
+ } else if (!plugin->init(new OrganizerProxy(this, plugin->name()))) {
qWarning("plugin failed to initialize");
return false;
}
@@ -1253,131 +1256,6 @@ void MainWindow::loadPlugins()
m_DiagnosisPlugins.push_back(this);
}
-IGameInfo &MainWindow::gameInfo() const
-{
- return *m_GameInfo;
-}
-
-
-IModRepositoryBridge *MainWindow::createNexusBridge() const
-{
- return new NexusBridge();
-}
-
-
-QString MainWindow::profileName() const
-{
- if (m_CurrentProfile != NULL) {
- return m_CurrentProfile->getName();
- } else {
- return "";
- }
-}
-
-QString MainWindow::profilePath() const
-{
- if (m_CurrentProfile != NULL) {
- return m_CurrentProfile->getPath();
- } else {
- return "";
- }
-}
-
-QString MainWindow::downloadsPath() const
-{
- return QDir::fromNativeSeparators(m_Settings.getDownloadDirectory());
-}
-
-VersionInfo MainWindow::appVersion() const
-{
- return m_Updater.getVersion();
-}
-
-
-IModInterface *MainWindow::getMod(const QString &name)
-{
- unsigned int index = ModInfo::getIndex(name);
- if (index == UINT_MAX) {
- return NULL;
- } else {
- return ModInfo::getByIndex(index).data();
- }
-}
-
-
-IModInterface *MainWindow::createMod(GuessedValue<QString> &name)
-{
- if (!m_InstallationManager.testOverwrite(name)) {
- return NULL;
- }
-
- m_InstallationManager.setModsDirectory(m_Settings.getModDirectory());
-
-/* QString fixedName = name;
- fixDirectoryName(fixedName);
- unsigned int index = ModInfo::getIndex(fixedName);
- if (index != UINT_MAX) {
- ModInfo::Ptr result = ModInfo::getByIndex(index);
- if (!result->isEmpty()) {
- throw MyException(tr("The mod \"%1\" already exists!").arg(fixedName));
- }
- return result.data();
- } else {*/
- QString targetDirectory = QDir::fromNativeSeparators(m_Settings.getModDirectory()).append("/").append(name);
-
- QSettings settingsFile(targetDirectory.mid(0).append("/meta.ini"), QSettings::IniFormat);
-
- settingsFile.setValue("modid", 0);
- settingsFile.setValue("version", "");
- settingsFile.setValue("newestVersion", "");
- settingsFile.setValue("category", 0);
- settingsFile.setValue("installationFile", "");
- return ModInfo::createFrom(QDir(targetDirectory), &m_DirectoryStructure).data();
-// }
-}
-
-bool MainWindow::removeMod(IModInterface *mod)
-{
- unsigned int index = ModInfo::getIndex(mod->name());
- if (index == UINT_MAX) {
- return mod->remove();
- } else {
- return ModInfo::removeMod(index);
- }
-}
-
-
-void MainWindow::modDataChanged(IModInterface*)
-{
- refreshModList();
-}
-
-QVariant MainWindow::pluginSetting(const QString &pluginName, const QString &key) const
-{
- return m_Settings.pluginSetting(pluginName, key);
-}
-
-void MainWindow::setPluginSetting(const QString &pluginName, const QString &key, const QVariant &value)
-{
- m_Settings.setPluginSetting(pluginName, key, value);
-}
-
-QVariant MainWindow::persistent(const QString &pluginName, const QString &key, const QVariant &def) const
-{
- return m_Settings.pluginPersistent(pluginName, key, def);
-}
-
-void MainWindow::setPersistent(const QString &pluginName, const QString &key, const QVariant &value, bool sync)
-{
- m_Settings.setPluginPersistent(pluginName, key, value, sync);
-}
-
-QString MainWindow::pluginDataPath() const
-{
- QString pluginPath = QDir::fromNativeSeparators(ToQString(GameInfo::instance().getOrganizerDirectory())) + "/" + ToQString(AppConfig::pluginPath());
- return pluginPath + "/data";
-}
-
void MainWindow::startSteam()
{
@@ -1496,21 +1374,6 @@ void MainWindow::startExeAction()
}
-void MainWindow::refreshModList(bool saveChanges)
-{
- // don't lose changes!
- if (saveChanges) {
- m_CurrentProfile->writeModlistNow(true);
- }
- ModInfo::updateFromDisc(m_Settings.getModDirectory(), &m_DirectoryStructure);
- m_CurrentProfile->refreshModStatus();
-
- m_ModList.notifyChange(-1);
-
- refreshDirectoryStructure();
-}
-
-
void MainWindow::setExecutablesList(const ExecutablesList &executablesList)
{
m_ExecutablesList = executablesList;
@@ -1892,6 +1755,20 @@ void MainWindow::refreshESPList()
}
}
+void MainWindow::refreshModList(bool saveChanges)
+{
+ // don't lose changes!
+ if (saveChanges) {
+ m_CurrentProfile->writeModlistNow(true);
+ }
+ ModInfo::updateFromDisc(m_Settings.getModDirectory(), &m_DirectoryStructure);
+ m_CurrentProfile->refreshModStatus();
+
+ m_ModList.notifyChange(-1);
+
+ refreshDirectoryStructure();
+}
+
static bool BySortValue(const std::pair<UINT32, QTreeWidgetItem*> &LHS, const std::pair<UINT32, QTreeWidgetItem*> &RHS)
{
@@ -1931,6 +1808,7 @@ void MainWindow::refreshBSAList()
for (int i = 0; i < m_DefaultArchives.count(); ++i) {
m_DefaultArchives[i] = m_DefaultArchives[i].trimmed();
}
+
m_ActiveArchives.clear();
QFile archiveFile(m_CurrentProfile->getArchivesFileName());
@@ -1978,7 +1856,7 @@ void MainWindow::refreshBSAList()
newItem->setCheckState(0, Qt::Checked);
newItem->setDisabled(true);
} else {
- newItem->setCheckState(0, (index != -1) ? Qt::Checked : Qt::Unchecked);
+ newItem->setCheckState(0, (index != 0xFFFF) ? Qt::Checked : Qt::Unchecked);
}
if (index < 0) index = 0;
@@ -2003,7 +1881,6 @@ void MainWindow::refreshBSAList()
ui->bsaList->addTopLevelItem(subItem);
}
subItem->addChild(iter->second);
- //ui->bsaList->addTopLevelItem(iter->second);
}
checkBSAList();
@@ -2242,181 +2119,6 @@ void MainWindow::on_tabWidget_currentChanged(int index)
}
}
-
-IModInterface *MainWindow::installMod(const QString &fileName)
-{
- if (m_CurrentProfile == NULL) {
- return NULL;
- }
-
- bool hasIniTweaks = false;
- GuessedValue<QString> modName;
- m_CurrentProfile->writeModlistNow();
- m_InstallationManager.setModsDirectory(m_Settings.getModDirectory());
- if (m_InstallationManager.install(fileName, modName, hasIniTweaks)) {
- MessageDialog::showMessage(tr("Installation successful"), this);
- refreshModList();
-
- QModelIndexList posList = m_ModList.match(m_ModList.index(0, 0), Qt::DisplayRole, static_cast<const QString&>(modName));
- if (posList.count() == 1) {
- ui->modList->scrollTo(posList.at(0));
- }
- int modIndex = ModInfo::getIndex(modName);
- if (modIndex != UINT_MAX) {
- ModInfo::Ptr modInfo = ModInfo::getByIndex(modIndex);
- if (hasIniTweaks &&
- (QMessageBox::question(this, tr("Configure Mod"),
- tr("This mod contains ini tweaks. Do you want to configure them now?"),
- QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes)) {
- displayModInformation(modInfo, modIndex, ModInfoDialog::TAB_INIFILES);
- }
- testExtractBSA(modIndex);
- return modInfo.data();
- } else {
- reportError(tr("mod \"%1\" not found").arg(modName));
- }
- } else if (m_InstallationManager.wasCancelled()) {
- QMessageBox::information(this, tr("Installation cancelled"), tr("The mod was not installed completely."), QMessageBox::Ok);
- }
- return NULL;
-}
-
-QString MainWindow::resolvePath(const QString &fileName) const
-{
- if (m_DirectoryStructure == NULL) {
- return QString();
- }
- const FileEntry::Ptr file = m_DirectoryStructure->searchFile(ToWString(fileName), NULL);
- if (file.get() != NULL) {
- return ToQString(file->getFullPath());
- } else {
- return QString();
- }
-}
-
-QStringList MainWindow::listDirectories(const QString &directoryName) const
-{
- QStringList result;
- DirectoryEntry *dir = m_DirectoryStructure->findSubDirectoryRecursive(ToWString(directoryName));
- if (dir != NULL) {
- std::vector<DirectoryEntry*>::iterator current, end;
- dir->getSubDirectories(current, end);
- for (; current != end; ++current) {
- result.append(ToQString((*current)->getName()));
- }
- }
- return result;
-}
-
-QStringList MainWindow::findFiles(const QString &path, const std::function<bool(const QString&)> &filter) const
-{
- QStringList result;
- DirectoryEntry *dir = m_DirectoryStructure->findSubDirectoryRecursive(ToWString(path));
- if (dir != NULL) {
- std::vector<FileEntry::Ptr> files = dir->getFiles();
- foreach (FileEntry::Ptr file, files) {
- if (filter(ToQString(file->getFullPath()))) {
- result.append(ToQString(file->getFullPath()));
- }
- }
- } else {
- qWarning("directory %s not found", qPrintable(path));
- }
- return result;
-}
-
-QList<IOrganizer::FileInfo> MainWindow::findFileInfos(const QString &path, const std::function<bool (const IOrganizer::FileInfo &)> &filter) const
-{
- QList<IOrganizer::FileInfo> result;
- DirectoryEntry *dir = m_DirectoryStructure->findSubDirectoryRecursive(ToWString(path));
- if (dir != NULL) {
- std::vector<FileEntry::Ptr> files = dir->getFiles();
- foreach (FileEntry::Ptr file, files) {
- FileInfo info;
- info.filePath = ToQString(file->getFullPath());
- bool fromArchive = false;
- info.origins.append(ToQString(m_DirectoryStructure->getOriginByID(file->getOrigin(fromArchive)).getName()));
- info.archive = fromArchive ? ToQString(file->getArchive()) : "";
- foreach (int idx, file->getAlternatives()) {
- info.origins.append(ToQString(m_DirectoryStructure->getOriginByID(idx).getName()));
- }
-
- if (filter(info)) {
- result.append(info);
- }
- }
- } else {
- qDebug("directory %s not found", qPrintable(path));
- }
- return result;
-}
-
-IDownloadManager *MainWindow::downloadManager()
-{
- return &m_DownloadManager;
-}
-
-IPluginList *MainWindow::pluginList()
-{
- return &m_PluginList;
-}
-
-IModList *MainWindow::modList()
-{
- return &m_ModList;
-}
-
-HANDLE MainWindow::startApplication(const QString &executable, const QStringList &args, const QString &cwd, const QString &profile)
-{
- QFileInfo binary;
- QString arguments = args.join(" ");
- QString currentDirectory = cwd;
- QString profileName = profile;
- if (profile.length() == 0) {
- if (m_CurrentProfile != NULL) {
- profileName = m_CurrentProfile->getName();
- } else {
- throw MyException(tr("No profile set"));
- }
- }
- QString steamAppID;
- if (executable.contains('\\') || executable.contains('/')) {
- // file path
- binary = QFileInfo(executable);
- if (binary.isRelative()) {
- // relative path, should be relative to game directory
- binary = QFileInfo(QDir::fromNativeSeparators(ToQString(GameInfo::instance().getGameDirectory())) + "/" + executable);
- }
- if (cwd.length() == 0) {
- currentDirectory = binary.absolutePath();
- }
- } else {
- // only a file name, search executables list
- try {
- const Executable &exe = m_ExecutablesList.find(executable);
- steamAppID = exe.m_SteamAppID;
- if (arguments == "") {
- arguments = exe.m_Arguments;
- }
- binary = exe.m_BinaryInfo;
- if (cwd.length() == 0) {
- currentDirectory = exe.m_WorkingDirectory;
- }
- } catch (const std::runtime_error&) {
- qWarning("\"%s\" not set up as executable", executable.toUtf8().constData());
- binary = QFileInfo(executable);
- }
- }
-
- return spawnBinaryDirect(binary, arguments, profileName, currentDirectory, steamAppID);
-}
-
-bool MainWindow::onAboutToRun(const std::function<bool (const QString &)> &func)
-{
- auto conn = m_AboutToRun.connect(func);
- return conn.connected();
-}
-
std::vector<unsigned int> MainWindow::activeProblems() const
{
std::vector<unsigned int> problems;
@@ -2495,6 +2197,109 @@ void MainWindow::installMod()
}
}
+IModInterface *MainWindow::installMod(const QString &fileName)
+{
+ if (m_CurrentProfile == NULL) {
+ return NULL;
+ }
+
+ bool hasIniTweaks = false;
+ GuessedValue<QString> modName;
+ m_CurrentProfile->writeModlistNow();
+ m_InstallationManager.setModsDirectory(m_Settings.getModDirectory());
+ if (m_InstallationManager.install(fileName, modName, hasIniTweaks)) {
+ MessageDialog::showMessage(tr("Installation successful"), this);
+ refreshModList();
+
+ QModelIndexList posList = m_ModList.match(m_ModList.index(0, 0), Qt::DisplayRole, static_cast<const QString&>(modName));
+ if (posList.count() == 1) {
+ ui->modList->scrollTo(posList.at(0));
+ }
+ int modIndex = ModInfo::getIndex(modName);
+ if (modIndex != UINT_MAX) {
+ ModInfo::Ptr modInfo = ModInfo::getByIndex(modIndex);
+ if (hasIniTweaks &&
+ (QMessageBox::question(this, tr("Configure Mod"),
+ tr("This mod contains ini tweaks. Do you want to configure them now?"),
+ QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes)) {
+ displayModInformation(modInfo, modIndex, ModInfoDialog::TAB_INIFILES);
+ }
+ testExtractBSA(modIndex);
+ return modInfo.data();
+ } else {
+ reportError(tr("mod \"%1\" not found").arg(modName));
+ }
+ } else if (m_InstallationManager.wasCancelled()) {
+ QMessageBox::information(this, tr("Installation cancelled"), tr("The mod was not installed completely."), QMessageBox::Ok);
+ }
+ return NULL;
+}
+
+IModInterface *MainWindow::getMod(const QString &name)
+{
+ unsigned int index = ModInfo::getIndex(name);
+ if (index == UINT_MAX) {
+ return NULL;
+ } else {
+ return ModInfo::getByIndex(index).data();
+ }
+}
+
+IModInterface *MainWindow::createMod(GuessedValue<QString> &name)
+{
+ if (!m_InstallationManager.testOverwrite(name)) {
+ return NULL;
+ }
+
+ m_InstallationManager.setModsDirectory(m_Settings.getModDirectory());
+
+ QString targetDirectory = QDir::fromNativeSeparators(m_Settings.getModDirectory()).append("/").append(name);
+
+ QSettings settingsFile(targetDirectory.mid(0).append("/meta.ini"), QSettings::IniFormat);
+
+ settingsFile.setValue("modid", 0);
+ settingsFile.setValue("version", "");
+ settingsFile.setValue("newestVersion", "");
+ settingsFile.setValue("category", 0);
+ settingsFile.setValue("installationFile", "");
+ return ModInfo::createFrom(QDir(targetDirectory), &m_DirectoryStructure).data();
+}
+
+bool MainWindow::removeMod(IModInterface *mod)
+{
+ unsigned int index = ModInfo::getIndex(mod->name());
+ if (index == UINT_MAX) {
+ return mod->remove();
+ } else {
+ return ModInfo::removeMod(index);
+ }
+}
+
+QList<IOrganizer::FileInfo> MainWindow::findFileInfos(const QString &path, const std::function<bool (const IOrganizer::FileInfo &)> &filter) const
+{
+ QList<IOrganizer::FileInfo> result;
+ DirectoryEntry *dir = m_DirectoryStructure->findSubDirectoryRecursive(ToWString(path));
+ if (dir != NULL) {
+ std::vector<FileEntry::Ptr> files = dir->getFiles();
+ foreach (FileEntry::Ptr file, files) {
+ IOrganizer::FileInfo info;
+ info.filePath = ToQString(file->getFullPath());
+ bool fromArchive = false;
+ info.origins.append(ToQString(m_DirectoryStructure->getOriginByID(file->getOrigin(fromArchive)).getName()));
+ info.archive = fromArchive ? ToQString(file->getArchive()) : "";
+ foreach (int idx, file->getAlternatives()) {
+ info.origins.append(ToQString(m_DirectoryStructure->getOriginByID(idx).getName()));
+ }
+
+ if (filter(info)) {
+ result.append(info);
+ }
+ }
+ } else {
+ qDebug("directory %s not found", qPrintable(path));
+ }
+ return result;
+}
void MainWindow::on_startButton_clicked()
{
@@ -2753,10 +2558,10 @@ void MainWindow::refresher_progress(int percent)
void MainWindow::directory_refreshed()
{
DirectoryEntry *newStructure = m_DirectoryRefresher.getDirectoryStructure();
+ Q_ASSERT(newStructure != m_DirectoryStructure);
if (newStructure != NULL) {
- DirectoryEntry *oldStructure = m_DirectoryStructure;
- m_DirectoryStructure = newStructure;
- delete oldStructure;
+ std::swap(m_DirectoryStructure, newStructure);
+ delete newStructure;
refreshDataTree();
} else {
// TODO: don't know why this happens, this slot seems to get called twice with only one emit
@@ -2853,11 +2658,10 @@ void MainWindow::procFinished(int, QProcess::ExitStatus)
}
-void MainWindow::on_profileRefreshBtn_clicked()
+void MainWindow::profileRefresh()
{
m_CurrentProfile->writeModlist();
-// m_ModList.updateModCollection();
refreshModList();
}
@@ -3897,102 +3701,113 @@ void addMenuAsPushButton(QMenu *menu, QMenu *subMenu)
menu->addAction(action);
}
-void MainWindow::on_modList_customContextMenuRequested(const QPoint &pos)
+QMenu *MainWindow::modListContextMenu()
{
- try {
- QTreeView *modList = findChild<QTreeView*>("modList");
+ QMenu *menu = new QMenu();
+ menu->addAction(tr("Install Mod..."), this, SLOT(installMod_clicked()));
- m_ContextIdx = mapToModel(&m_ModList, modList->indexAt(pos));
- m_ContextRow = m_ContextIdx.row();
-
- QMenu menu;
+ menu->addAction(tr("Enable all visible"), this, SLOT(enableVisibleMods()));
+ menu->addAction(tr("Disable all visible"), this, SLOT(disableVisibleMods()));
- menu.addAction(tr("Install Mod..."), this, SLOT(installMod_clicked()));
+ menu->addAction(tr("Check all for update"), this, SLOT(checkModsForUpdates()));
- menu.addAction(tr("Enable all visible"), this, SLOT(enableVisibleMods()));
- menu.addAction(tr("Disable all visible"), this, SLOT(disableVisibleMods()));
+ menu->addAction(tr("Refresh"), this, SLOT(profileRefresh()));
- menu.addAction(tr("Check all for update"), this, SLOT(checkModsForUpdates()));
+ menu->addAction(tr("Export to csv..."), this, SLOT(exportModListCSV()));
+ return menu;
+}
- menu.addAction(tr("Refresh"), this, SLOT(on_profileRefreshBtn_clicked()));
+void MainWindow::on_modList_customContextMenuRequested(const QPoint &pos)
+{
+ try {
+ QTreeView *modList = findChild<QTreeView*>("modList");
- menu.addAction(tr("Export to csv..."), this, SLOT(exportModListCSV()));
+ m_ContextIdx = mapToModel(&m_ModList, modList->indexAt(pos));
+ m_ContextRow = m_ContextIdx.row();
- if (m_ContextRow != -1) {
- menu.addSeparator();
+ QMenu *menu = NULL;
+ QMenu *allMods = modListContextMenu();
+ if (m_ContextRow == -1) {
+ // no selection
+ menu = allMods;
+ menu->setParent(this);
+ } else {
+ menu = new QMenu(this);
+ allMods->setTitle(tr("All Mods"));
+ menu->addMenu(allMods);
ModInfo::Ptr info = ModInfo::getByIndex(m_ContextRow);
std::vector<ModInfo::EFlag> flags = info->getFlags();
if (std::find(flags.begin(), flags.end(), ModInfo::FLAG_OVERWRITE) != flags.end()) {
if (QDir(info->absolutePath()).count() > 2) {
- menu.addAction(tr("Sync to Mods..."), this, SLOT(syncOverwrite()));
- menu.addAction(tr("Create Mod..."), this, SLOT(createModFromOverwrite()));
+ menu->addAction(tr("Sync to Mods..."), this, SLOT(syncOverwrite()));
+ menu->addAction(tr("Create Mod..."), this, SLOT(createModFromOverwrite()));
}
} else if (std::find(flags.begin(), flags.end(), ModInfo::FLAG_BACKUP) != flags.end()) {
- menu.addAction(tr("Restore Backup"), this, SLOT(restoreBackup_clicked()));
- menu.addAction(tr("Remove Backup..."), this, SLOT(removeMod_clicked()));
+ menu->addAction(tr("Restore Backup"), this, SLOT(restoreBackup_clicked()));
+ menu->addAction(tr("Remove Backup..."), this, SLOT(removeMod_clicked()));
} else {
QMenu *addRemoveCategoriesMenu = new QMenu(tr("Add/Remove Categories"));
populateMenuCategories(addRemoveCategoriesMenu, 0);
connect(addRemoveCategoriesMenu, SIGNAL(aboutToHide()), this, SLOT(addRemoveCategories_MenuHandler()));
- addMenuAsPushButton(&menu, addRemoveCategoriesMenu);
+ addMenuAsPushButton(menu, addRemoveCategoriesMenu);
QMenu *replaceCategoriesMenu = new QMenu(tr("Replace Categories"));
populateMenuCategories(replaceCategoriesMenu, 0);
connect(replaceCategoriesMenu, SIGNAL(aboutToHide()), this, SLOT(replaceCategories_MenuHandler()));
- addMenuAsPushButton(&menu, replaceCategoriesMenu);
+ addMenuAsPushButton(menu, replaceCategoriesMenu);
QMenu *primaryCategoryMenu = new QMenu(tr("Primary Category"));
connect(primaryCategoryMenu, SIGNAL(aboutToShow()), this, SLOT(addPrimaryCategoryCandidates()));
connect(primaryCategoryMenu, SIGNAL(aboutToHide()), this, SLOT(savePrimaryCategory()));
- addMenuAsPushButton(&menu, primaryCategoryMenu);
+ addMenuAsPushButton(menu, primaryCategoryMenu);
- menu.addSeparator();
+ menu->addSeparator();
if (info->downgradeAvailable()) {
- menu.addAction(tr("Change versioning scheme"), this, SLOT(changeVersioningScheme()));
+ menu->addAction(tr("Change versioning scheme"), this, SLOT(changeVersioningScheme()));
}
if (info->updateAvailable() || info->downgradeAvailable()) {
if (info->updateIgnored()) {
- menu.addAction(tr("Un-ignore update"), this, SLOT(unignoreUpdate()));
+ menu->addAction(tr("Un-ignore update"), this, SLOT(unignoreUpdate()));
} else {
- menu.addAction(tr("Ignore update"), this, SLOT(ignoreUpdate()));
+ menu->addAction(tr("Ignore update"), this, SLOT(ignoreUpdate()));
}
}
- menu.addSeparator();
+ menu->addSeparator();
- menu.addAction(tr("Rename Mod..."), this, SLOT(renameMod_clicked()));
- menu.addAction(tr("Remove Mod..."), this, SLOT(removeMod_clicked()));
- menu.addAction(tr("Reinstall Mod"), this, SLOT(reinstallMod_clicked()));
+ menu->addAction(tr("Rename Mod..."), this, SLOT(renameMod_clicked()));
+ menu->addAction(tr("Remove Mod..."), this, SLOT(removeMod_clicked()));
+ menu->addAction(tr("Reinstall Mod"), this, SLOT(reinstallMod_clicked()));
switch (info->endorsedState()) {
case ModInfo::ENDORSED_TRUE: {
- menu.addAction(tr("Un-Endorse"), this, SLOT(unendorse_clicked()));
+ menu->addAction(tr("Un-Endorse"), this, SLOT(unendorse_clicked()));
} break;
case ModInfo::ENDORSED_FALSE: {
- menu.addAction(tr("Endorse"), this, SLOT(endorse_clicked()));
- menu.addAction(tr("Won't endorse"), this, SLOT(dontendorse_clicked()));
+ menu->addAction(tr("Endorse"), this, SLOT(endorse_clicked()));
+ menu->addAction(tr("Won't endorse"), this, SLOT(dontendorse_clicked()));
} break;
case ModInfo::ENDORSED_NEVER: {
- menu.addAction(tr("Endorse"), this, SLOT(endorse_clicked()));
+ menu->addAction(tr("Endorse"), this, SLOT(endorse_clicked()));
} break;
default: {
- QAction *action = new QAction(tr("Endorsement state unknown"), &menu);
+ QAction *action = new QAction(tr("Endorsement state unknown"), menu);
action->setEnabled(false);
- menu.addAction(action);
+ menu->addAction(action);
} break;
}
std::vector<ModInfo::EFlag> flags = info->getFlags();
if (std::find(flags.begin(), flags.end(), ModInfo::FLAG_INVALID) != flags.end()) {
- menu.addAction(tr("Ignore missing data"), this, SLOT(ignoreMissingData_clicked()));
+ menu->addAction(tr("Ignore missing data"), this, SLOT(ignoreMissingData_clicked()));
}
- menu.addAction(tr("Visit on Nexus"), this, SLOT(visitOnNexus_clicked()));
- menu.addAction(tr("Open in explorer"), this, SLOT(openExplorer_clicked()));
+ menu->addAction(tr("Visit on Nexus"), this, SLOT(visitOnNexus_clicked()));
+ menu->addAction(tr("Open in explorer"), this, SLOT(openExplorer_clicked()));
}
- QAction *infoAction = menu.addAction(tr("Information..."), this, SLOT(information_clicked()));
- menu.setDefaultAction(infoAction);
+ QAction *infoAction = menu->addAction(tr("Information..."), this, SLOT(information_clicked()));
+ menu->setDefaultAction(infoAction);
}
- menu.exec(modList->mapToGlobal(pos));
+ menu->exec(modList->mapToGlobal(pos));
} catch (const std::exception &e) {
reportError(tr("Exception: ").arg(e.what()));
} catch (...) {
@@ -4003,7 +3818,6 @@ void MainWindow::on_modList_customContextMenuRequested(const QPoint &pos)
void MainWindow::on_categoriesList_itemSelectionChanged()
{
-// int filter = current->data(0, Qt::UserRole).toInt();
QModelIndexList indices = ui->categoriesList->selectionModel()->selectedRows();
std::vector<int> categories;
foreach (const QModelIndex &index, indices) {
@@ -4014,7 +3828,7 @@ void MainWindow::on_categoriesList_itemSelectionChanged()
}
m_ModListSortProxy->setCategoryFilter(categories);
-// ui->currentCategoryLabel->setText(QString("(%1)").arg(current->text(0)));
+ ui->clickBlankLabel->setEnabled(categories.size() > 0);
if (indices.count() == 0) {
ui->currentCategoryLabel->setText(QString("(%1)").arg(tr("<All>")));
} else if (indices.count() > 1) {
@@ -4174,16 +3988,18 @@ void MainWindow::linkDesktop()
reportError(tr("failed to remove %1").arg(linkName));
}
} else {
- QFileInfo exeInfo(m_ExeName);
+ QFileInfo exeInfo(qApp->arguments().at(0));
// create link
std::wstring targetFile = ToWString(exeInfo.absoluteFilePath());
- std::wstring parameter = ToWString(QString("\"") + selectedExecutable.m_BinaryInfo.absoluteFilePath() + "\" " + selectedExecutable.m_Arguments);
+ std::wstring parameter = ToWString(QString("\"%1\" %2").arg(QDir::toNativeSeparators(selectedExecutable.m_BinaryInfo.absoluteFilePath()))
+ .arg(selectedExecutable.m_Arguments));
std::wstring description = ToWString(selectedExecutable.m_BinaryInfo.fileName());
- std::wstring currentDirectory = ToWString(selectedExecutable.m_BinaryInfo.absolutePath());
-
- if (CreateShortcut(targetFile.c_str(), parameter.c_str(),
- linkName.toUtf8().constData(),
- description.c_str(), currentDirectory.c_str()) != E_INVALIDARG) {
+ std::wstring currentDirectory = ToWString(QDir::toNativeSeparators(exeInfo.absolutePath()));
+ if (CreateShortcut(targetFile.c_str()
+ , parameter.c_str()
+ , linkName.toUtf8().constData()
+ , description.c_str()
+ , currentDirectory.c_str()) != E_INVALIDARG) {
ui->linkButton->menu()->actions().at(0)->setIcon(QIcon(":/MO/gui/remove"));
} else {
reportError(tr("failed to create %1").arg(linkName));
@@ -4205,12 +4021,13 @@ void MainWindow::linkMenu()
reportError(tr("failed to remove %1").arg(linkName));
}
} else {
- QFileInfo exeInfo(m_ExeName);
+ QFileInfo exeInfo(qApp->arguments().at(0));
// create link
std::wstring targetFile = ToWString(exeInfo.absoluteFilePath());
- std::wstring parameter = ToWString(QString("\"") + selectedExecutable.m_BinaryInfo.absoluteFilePath() + "\" " + selectedExecutable.m_Arguments);
+ std::wstring parameter = ToWString(QString("\"%1\" %2").arg(QDir::toNativeSeparators(selectedExecutable.m_BinaryInfo.absoluteFilePath()))
+ .arg(selectedExecutable.m_Arguments));
std::wstring description = ToWString(selectedExecutable.m_BinaryInfo.fileName());
- std::wstring currentDirectory = ToWString(selectedExecutable.m_BinaryInfo.absolutePath());
+ std::wstring currentDirectory = ToWString(QDir::toNativeSeparators(exeInfo.absolutePath()));
if (CreateShortcut(targetFile.c_str(), parameter.c_str(),
linkName.toUtf8().constData(),
@@ -4285,17 +4102,30 @@ void MainWindow::linkClicked(const QString &url)
}
-void MainWindow::downloadRequestedNXM(const QString &url)
+bool MainWindow::nexusLogin()
{
QString username, password;
- qDebug("download requested: %s", qPrintable(url));
- if (!m_LoginAttempted && !NexusInterface::instance()->getAccessManager()->loggedIn() &&
- (m_Settings.getNexusLogin(username, password) ||
- (m_AskForNexusPW && queryLogin(username, password)))) {
+ NXMAccessManager *accessManager = NexusInterface::instance()->getAccessManager();
+
+ if (!accessManager->loginAttempted()
+ && !accessManager->loggedIn()
+ && (m_Settings.getNexusLogin(username, password)
+ || (m_AskForNexusPW
+ && queryLogin(username, password)))) {
+ accessManager->login(username, password);
+ return true;
+ } else {
+ return false;
+ }
+}
+
+
+void MainWindow::downloadRequestedNXM(const QString &url)
+{
+ qDebug("download requested: %s", qPrintable(url));
+ if (nexusLogin()) {
m_PendingDownloads.append(url);
- NexusInterface::instance()->getAccessManager()->login(username, password);
- m_LoginAttempted = true;
} else {
m_DownloadManager.addNXMDownload(url);
}
@@ -4754,13 +4584,7 @@ void MainWindow::on_conflictsCheckBox_toggled(bool)
void MainWindow::on_actionUpdate_triggered()
{
- QString username, password;
-
- if (!m_LoginAttempted && !NexusInterface::instance()->getAccessManager()->loggedIn() &&
- (m_Settings.getNexusLogin(username, password) ||
- (m_AskForNexusPW && queryLogin(username, password)))) {
- NexusInterface::instance()->getAccessManager()->login(username, password);
- m_LoginAttempted = true;
+ if (nexusLogin()) {
m_PostLoginTasks.push_back([&](MainWindow*) { m_Updater.startUpdate(); });
} else {
m_Updater.startUpdate();
@@ -4773,7 +4597,7 @@ void MainWindow::on_actionEndorseMO_triggered()
if (QMessageBox::question(this, tr("Endorse Mod Organizer"),
tr("Do you want to endorse Mod Organizer on %1 now?").arg(ToQString(GameInfo::instance().getNexusPage())),
QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) {
- NexusInterface::instance()->requestToggleEndorsement(GameInfo::instance().getNexusModID(), true, this, QVariant());
+ NexusInterface::instance()->requestToggleEndorsement(GameInfo::instance().getNexusModID(), true, this, QVariant(), QString());
}
}
@@ -4908,6 +4732,7 @@ void MainWindow::loginSuccessful(bool necessary)
}
m_PostLoginTasks.clear();
+ NexusInterface::instance()->loginCompleted();
}
@@ -4933,6 +4758,7 @@ void MainWindow::loginFailed(const QString &message)
m_PostLoginTasks.clear();
statusBar()->hide();
}
+ NexusInterface::instance()->loginCompleted();
}
@@ -5119,10 +4945,16 @@ void MainWindow::editCategories()
}
}
+void MainWindow::deselectFilters()
+{
+ ui->categoriesList->clearSelection();
+}
+
void MainWindow::on_categoriesList_customContextMenuRequested(const QPoint &pos)
{
QMenu menu;
menu.addAction(tr("Edit Categories..."), this, SLOT(editCategories()));
+ menu.addAction(tr("Deselect filter"), this, SLOT(deselectFilters()));
menu.exec(ui->categoriesList->mapToGlobal(pos));
}
@@ -5155,8 +4987,13 @@ void MainWindow::unlockESPIndex()
void MainWindow::removeFromToolbar()
{
- Executable &exe = m_ExecutablesList.find(m_ContextAction->text());
- exe.m_Toolbar = false;
+ try {
+ Executable &exe = m_ExecutablesList.find(m_ContextAction->text());
+ exe.m_Toolbar = false;
+ } catch (const std::runtime_error&) {
+ qDebug("executable doesn't exist any more");
+ }
+
updateToolBar();
}
@@ -5328,6 +5165,52 @@ void MainWindow::processLOOTOut(const std::string &lootOut, std::string &reportU
}
}
+
+HANDLE MainWindow::startApplication(const QString &executable, const QStringList &args, const QString &cwd, const QString &profile)
+{
+ QFileInfo binary;
+ QString arguments = args.join(" ");
+ QString currentDirectory = cwd;
+ QString profileName = profile;
+ if (profile.length() == 0) {
+ if (m_CurrentProfile != NULL) {
+ profileName = m_CurrentProfile->getName();
+ } else {
+ throw MyException(tr("No profile set"));
+ }
+ }
+ QString steamAppID;
+ if (executable.contains('\\') || executable.contains('/')) {
+ // file path
+ binary = QFileInfo(executable);
+ if (binary.isRelative()) {
+ // relative path, should be relative to game directory
+ binary = QFileInfo(QDir::fromNativeSeparators(ToQString(GameInfo::instance().getGameDirectory())) + "/" + executable);
+ }
+ if (cwd.length() == 0) {
+ currentDirectory = binary.absolutePath();
+ }
+ } else {
+ // only a file name, search executables list
+ try {
+ const Executable &exe = m_ExecutablesList.find(executable);
+ steamAppID = exe.m_SteamAppID;
+ if (arguments == "") {
+ arguments = exe.m_Arguments;
+ }
+ binary = exe.m_BinaryInfo;
+ if (cwd.length() == 0) {
+ currentDirectory = exe.m_WorkingDirectory;
+ }
+ } catch (const std::runtime_error&) {
+ qWarning("\"%s\" not set up as executable", executable.toUtf8().constData());
+ binary = QFileInfo(executable);
+ }
+ }
+
+ return spawnBinaryDirect(binary, arguments, profileName, currentDirectory, steamAppID);
+}
+
void MainWindow::on_bossButton_clicked()
{
std::string reportURL;
@@ -5521,3 +5404,17 @@ void MainWindow::on_actionCopy_Log_to_Clipboard_triggered()
}
QApplication::clipboard()->setText(lines.join("\n"));
}
+
+void MainWindow::on_categoriesAndBtn_toggled(bool checked)
+{
+ if (checked) {
+ m_ModListSortProxy->setFilterMode(ModListSortProxy::FILTER_AND);
+ }
+}
+
+void MainWindow::on_categoriesOrBtn_toggled(bool checked)
+{
+ if (checked) {
+ m_ModListSortProxy->setFilterMode(ModListSortProxy::FILTER_OR);
+ }
+}
diff --git a/src/mainwindow.h b/src/mainwindow.h
index 3aaf62a5..910e243a 100644
--- a/src/mainwindow.h
+++ b/src/mainwindow.h
@@ -64,11 +64,13 @@ class ModListSortProxy;
class ModListGroupCategoriesProxy;
-class MainWindow : public QMainWindow, public MOBase::IOrganizer, public MOBase::IPluginDiagnose
+class MainWindow : public QMainWindow, public MOBase::IPluginDiagnose
{
Q_OBJECT
Q_INTERFACES(MOBase::IPluginDiagnose)
+ friend class OrganizerProxy;
+
private:
struct SignalCombinerAnd
@@ -97,7 +99,6 @@ public:
bool addProfile();
void refreshLists();
- void refreshESPList();
void refreshBSAList();
void refreshDataTree();
void refreshSaveList();
@@ -117,34 +118,6 @@ public:
void loadPlugins();
- virtual MOBase::IGameInfo &gameInfo() const;
- virtual MOBase::IModRepositoryBridge *createNexusBridge() const;
- virtual QString profileName() const;
- virtual QString profilePath() const;
- virtual QString downloadsPath() const;
- virtual MOBase::VersionInfo appVersion() const;
- virtual MOBase::IModInterface *getMod(const QString &name);
- virtual MOBase::IModInterface *createMod(MOBase::GuessedValue<QString> &name);
- virtual bool removeMod(MOBase::IModInterface *mod);
- virtual void modDataChanged(MOBase::IModInterface *mod);
- virtual QVariant pluginSetting(const QString &pluginName, const QString &key) const;
- virtual void setPluginSetting(const QString &pluginName, const QString &key, const QVariant &value);
- virtual QVariant persistent(const QString &pluginName, const QString &key, const QVariant &def = QVariant()) const;
- virtual void setPersistent(const QString &pluginName, const QString &key, const QVariant &value, bool sync = true);
- virtual QString pluginDataPath() const;
- virtual MOBase::IModInterface *installMod(const QString &fileName);
- virtual QString resolvePath(const QString &fileName) const;
- virtual QStringList listDirectories(const QString &directoryName) const;
- virtual QStringList findFiles(const QString &path, const std::function<bool(const QString &)> &filter) const;
- virtual QList<FileInfo> findFileInfos(const QString &path, const std::function<bool(const FileInfo&)> &filter) const;
-
- virtual MOBase::IDownloadManager *downloadManager();
- virtual MOBase::IPluginList *pluginList();
- virtual MOBase::IModList *modList();
- virtual HANDLE startApplication(const QString &executable, const QStringList &args = QStringList(), const QString &cwd = "", const QString &profile = "");
- virtual bool onAboutToRun(const std::function<bool(const QString&)> &func);
- virtual void refreshModList(bool saveChanges = true);
-
virtual std::vector<unsigned int> activeProblems() const;
virtual QString shortDescription(unsigned int key) const;
virtual QString fullDescription(unsigned int key) const;
@@ -158,6 +131,9 @@ public:
void createStdoutPipe(HANDLE *stdOutRead, HANDLE *stdOutWrite);
std::string readFromPipe(HANDLE stdOutRead);
void processLOOTOut(const std::string &lootOut, std::string &reportURL, std::string &errorMessages, QProgressDialog &dialog);
+
+ HANDLE startApplication(const QString &executable, const QStringList &args = QStringList(), const QString &cwd = "", const QString &profile = "");
+
public slots:
void displayColumnSelection(const QPoint &pos);
@@ -200,6 +176,9 @@ protected:
private:
+ void refreshESPList();
+ void refreshModList(bool saveChanges = true);
+
void actionToToolButton(QAction *&sourceAction);
bool verifyPlugin(MOBase::IPlugin *plugin);
void registerPluginTool(MOBase::IPluginTool *tool);
@@ -211,8 +190,6 @@ private:
void setExecutableIndex(int index);
- bool nexusLogin();
-
bool testForSteam();
void startSteam();
@@ -224,6 +201,13 @@ private:
bool refreshProfiles(bool selectProfile = true);
void refreshExecutablesList();
void installMod();
+ MOBase::IModInterface *installMod(const QString &fileName);
+ MOBase::IModInterface *getMod(const QString &name);
+ MOBase::IModInterface *createMod(MOBase::GuessedValue<QString> &name);
+ bool removeMod(MOBase::IModInterface *mod);
+
+ QList<MOBase::IOrganizer::FileInfo> findFileInfos(const QString &path, const std::function<bool (const MOBase::IOrganizer::FileInfo &)> &filter) const;
+
bool modifyExecutablesDialog();
void displayModInformation(ModInfo::Ptr modInfo, unsigned int index, int tab);
void displayModInformation(int row, int tab = 0);
@@ -298,6 +282,8 @@ private:
bool createBackup(const QString &filePath, const QDateTime &time);
QString queryRestore(const QString &filePath);
+ QMenu *modListContextMenu();
+
private:
static const unsigned int PROBLEM_PLUGINSNOTLOADED = 1;
@@ -458,6 +444,8 @@ private slots:
void linkClicked(const QString &url);
+ bool nexusLogin();
+
void loginSuccessful(bool necessary);
void loginSuccessfulUpdate(bool necessary);
void loginFailed(const QString &message);
@@ -489,6 +477,7 @@ private slots:
void nxmRequestFailed(int modID, int fileID, QVariant userData, int requestID, const QString &errorString);
void editCategories();
+ void deselectFilters();
void displayModInformation(const QString &modName, int tab);
void modOpenNext();
@@ -556,6 +545,7 @@ private slots:
void delayedRemove();
void requestDownload(const QUrl &url, QNetworkReply *reply);
+ void profileRefresh();
private slots: // ui slots
// actions
@@ -578,7 +568,6 @@ private slots: // ui slots
void on_modList_customContextMenuRequested(const QPoint &pos);
void on_modList_doubleClicked(const QModelIndex &index);
void on_profileBox_currentIndexChanged(int index);
- void on_profileRefreshBtn_clicked();
void on_savegameList_customContextMenuRequested(const QPoint &pos);
void on_startButton_clicked();
void on_tabWidget_currentChanged(int index);
@@ -597,6 +586,10 @@ private slots: // ui slots
void on_restoreModsButton_clicked();
void on_saveModsButton_clicked();
void on_actionCopy_Log_to_Clipboard_triggered();
+ void on_categoriesAndBtn_toggled(bool checked);
+ void on_categoriesOrBtn_toggled(bool checked);
};
+
+
#endif // MAINWINDOW_H
diff --git a/src/mainwindow.ui b/src/mainwindow.ui
index 7ad3a90d..c607a8e6 100644
--- a/src/mainwindow.ui
+++ b/src/mainwindow.ui
@@ -75,6 +75,9 @@
<property name="selectionMode">
<enum>QAbstractItemView::ExtendedSelection</enum>
</property>
+ <property name="indentation">
+ <number>0</number>
+ </property>
<attribute name="headerVisible">
<bool>false</bool>
</attribute>
@@ -85,6 +88,54 @@
</column>
</widget>
</item>
+ <item>
+ <widget class="QLabel" name="clickBlankLabel">
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string>Click blank area to deselect</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QGroupBox" name="groupBox">
+ <property name="title">
+ <string/>
+ </property>
+ <property name="flat">
+ <bool>false</bool>
+ </property>
+ <property name="checkable">
+ <bool>false</bool>
+ </property>
+ <layout class="QHBoxLayout" name="horizontalLayout_11">
+ <item>
+ <widget class="QRadioButton" name="categoriesAndBtn">
+ <property name="toolTip">
+ <string>If checked, only mods that match all selected categories are displayed.</string>
+ </property>
+ <property name="text">
+ <string>And</string>
+ </property>
+ <property name="checked">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QRadioButton" name="categoriesOrBtn">
+ <property name="toolTip">
+ <string>If checked, all mods that match one of the selected categories are displayed.</string>
+ </property>
+ <property name="text">
+ <string>Or</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
</layout>
</widget>
</item>
@@ -140,10 +191,23 @@ p, li { white-space: pre-wrap; }
</widget>
</item>
<item>
- <widget class="QPushButton" name="profileRefreshBtn">
+ <spacer name="horizontalSpacer">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QPushButton" name="listOptionsBtn">
<property name="maximumSize">
<size>
- <width>24</width>
+ <width>16777215</width>
<height>16777215</height>
</size>
</property>
@@ -158,22 +222,15 @@ p, li { white-space: pre-wrap; }
</property>
<property name="icon">
<iconset resource="resources.qrc">
- <normaloff>:/MO/gui/resources/view-refresh.png</normaloff>:/MO/gui/resources/view-refresh.png</iconset>
- </property>
- </widget>
- </item>
- <item>
- <spacer name="horizontalSpacer">
- <property name="orientation">
- <enum>Qt::Horizontal</enum>
+ <normaloff>:/MO/gui/settings</normaloff>:/MO/gui/settings</iconset>
</property>
- <property name="sizeHint" stdset="0">
+ <property name="iconSize">
<size>
- <width>40</width>
- <height>20</height>
+ <width>16</width>
+ <height>16</height>
</size>
</property>
- </spacer>
+ </widget>
</item>
<item>
<widget class="QPushButton" name="restoreModsButton">
diff --git a/src/modinfo.cpp b/src/modinfo.cpp
index bd244852..12463559 100644
--- a/src/modinfo.cpp
+++ b/src/modinfo.cpp
@@ -219,7 +219,7 @@ ModInfo::ModInfo()
void ModInfo::checkChunkForUpdate(const std::vector<int> &modIDs, QObject *receiver)
{
if (modIDs.size() != 0) {
- NexusInterface::instance()->requestUpdates(modIDs, receiver, QVariant());
+ NexusInterface::instance()->requestUpdates(modIDs, receiver, QVariant(), QString());
}
}
diff --git a/src/modlistsortproxy.cpp b/src/modlistsortproxy.cpp
index 49f37726..052e65b2 100644
--- a/src/modlistsortproxy.cpp
+++ b/src/modlistsortproxy.cpp
@@ -33,6 +33,7 @@ ModListSortProxy::ModListSortProxy(Profile* profile, QObject *parent)
, m_CategoryFilter()
, m_CurrentFilter()
, m_FilterActive(false)
+ , m_FilterMode(FILTER_AND)
{
m_EnabledColumns.set(ModList::COL_FLAGS);
m_EnabledColumns.set(ModList::COL_NAME);
@@ -224,13 +225,8 @@ bool ModListSortProxy::hasConflictFlag(const std::vector<ModInfo::EFlag> &flags)
}
-bool ModListSortProxy::filterMatchesMod(ModInfo::Ptr info, bool enabled) const
+bool ModListSortProxy::filterMatchesModAnd(ModInfo::Ptr info, bool enabled) const
{
- if (!m_CurrentFilter.isEmpty() &&
- !info->name().contains(m_CurrentFilter, Qt::CaseInsensitive)) {
- return false;
- }
-
for (auto iter = m_CategoryFilter.begin(); iter != m_CategoryFilter.end(); ++iter) {
switch (*iter) {
case CategoryFactory::CATEGORY_SPECIAL_CHECKED: {
@@ -250,17 +246,71 @@ bool ModListSortProxy::filterMatchesMod(ModInfo::Ptr info, bool enabled) const
} break;
case CategoryFactory::CATEGORY_SPECIAL_NOTENDORSED: {
ModInfo::EEndorsedState state = info->endorsedState();
- return (state == ModInfo::ENDORSED_FALSE) || (state == ModInfo::ENDORSED_NEVER);
+ if (state != ModInfo::ENDORSED_FALSE) return false;
} break;
default: {
if (!info->categorySet(*iter)) return false;
} break;
}
}
-
return true;
}
+bool ModListSortProxy::filterMatchesModOr(ModInfo::Ptr info, bool enabled) const
+{
+ for (auto iter = m_CategoryFilter.begin(); iter != m_CategoryFilter.end(); ++iter) {
+ switch (*iter) {
+ case CategoryFactory::CATEGORY_SPECIAL_CHECKED: {
+ if (enabled) return true;
+ } break;
+ case CategoryFactory::CATEGORY_SPECIAL_UNCHECKED: {
+ if (!enabled) return true;
+ } break;
+ case CategoryFactory::CATEGORY_SPECIAL_UPDATEAVAILABLE: {
+ if (info->updateAvailable() || info->downgradeAvailable()) return true;
+ } break;
+ case CategoryFactory::CATEGORY_SPECIAL_NOCATEGORY: {
+ if (info->getCategories().size() == 0) return true;
+ } break;
+ case CategoryFactory::CATEGORY_SPECIAL_CONFLICT: {
+ if (hasConflictFlag(info->getFlags())) return true;
+ } break;
+ case CategoryFactory::CATEGORY_SPECIAL_NOTENDORSED: {
+ ModInfo::EEndorsedState state = info->endorsedState();
+ if ((state == ModInfo::ENDORSED_FALSE) && (state != ModInfo::ENDORSED_NEVER)) return true;
+ } break;
+ default: {
+ if (info->categorySet(*iter)) return true;
+ } break;
+ }
+ }
+ return false;
+}
+
+
+
+bool ModListSortProxy::filterMatchesMod(ModInfo::Ptr info, bool enabled) const
+{
+ if (!m_CurrentFilter.isEmpty() &&
+ !info->name().contains(m_CurrentFilter, Qt::CaseInsensitive)) {
+ return false;
+ }
+
+ if (m_FilterMode == FILTER_AND) {
+ return filterMatchesModAnd(info, enabled);
+ } else {
+ return (m_CategoryFilter.size() == 0) || filterMatchesModOr(info, enabled);
+ }
+}
+
+void ModListSortProxy::setFilterMode(ModListSortProxy::FilterMode mode)
+{
+ if (m_FilterMode != mode) {
+ m_FilterMode = mode;
+ this->invalidate();
+ }
+}
+
bool ModListSortProxy::filterAcceptsRow(int row, const QModelIndex &parent) const
{
diff --git a/src/modlistsortproxy.h b/src/modlistsortproxy.h
index f1b01c7e..c04ba28d 100644
--- a/src/modlistsortproxy.h
+++ b/src/modlistsortproxy.h
@@ -32,6 +32,13 @@ class ModListSortProxy : public QSortFilterProxyModel
public:
+ enum FilterMode {
+ FILTER_AND,
+ FILTER_OR
+ };
+
+public:
+
explicit ModListSortProxy(Profile *profile, QObject *parent = 0);
void setProfile(Profile *profile);
@@ -65,6 +72,8 @@ public:
*/
bool isFilterActive() const { return m_FilterActive; }
+ void setFilterMode(FilterMode mode);
+
/**
* @brief tests if the specified index has child nodes
* @param parent the node to test
@@ -93,6 +102,8 @@ private:
bool hasConflictFlag(const std::vector<ModInfo::EFlag> &flags) const;
void updateFilterActive();
+ bool filterMatchesModAnd(ModInfo::Ptr info, bool enabled) const;
+ bool filterMatchesModOr(ModInfo::Ptr info, bool enabled) const;
private:
@@ -103,6 +114,7 @@ private:
QString m_CurrentFilter;
bool m_FilterActive;
+ FilterMode m_FilterMode;
};
diff --git a/src/nexusinterface.cpp b/src/nexusinterface.cpp
index d6cf8d8f..1f95fcd7 100644
--- a/src/nexusinterface.cpp
+++ b/src/nexusinterface.cpp
@@ -32,36 +32,37 @@ using namespace MOBase;
using namespace MOShared;
-NexusBridge::NexusBridge()
+NexusBridge::NexusBridge(const QString &subModule)
: m_Interface(NexusInterface::instance())
, m_Url(MOBase::ToQString(MOShared::GameInfo::instance().getNexusInfoUrl()))
+ , m_SubModule(subModule)
{
}
void NexusBridge::requestDescription(int modID, QVariant userData)
{
- m_RequestIDs.insert(m_Interface->requestDescription(modID, this, userData, m_Url));
+ m_RequestIDs.insert(m_Interface->requestDescription(modID, this, userData, m_SubModule, m_Url));
}
void NexusBridge::requestFiles(int modID, QVariant userData)
{
- m_RequestIDs.insert(m_Interface->requestFiles(modID, this, userData, m_Url));
+ m_RequestIDs.insert(m_Interface->requestFiles(modID, this, userData, m_SubModule, m_Url));
}
void NexusBridge::requestFileInfo(int modID, int fileID, QVariant userData)
{
- m_RequestIDs.insert(m_Interface->requestFileInfo(modID, fileID, this, userData, m_Url));
+ m_RequestIDs.insert(m_Interface->requestFileInfo(modID, fileID, this, userData, m_SubModule, m_Url));
}
void NexusBridge::requestDownloadURL(int modID, int fileID, QVariant userData)
{
- m_RequestIDs.insert(m_Interface->requestDownloadURL(modID, fileID, this, userData, m_Url));
+ m_RequestIDs.insert(m_Interface->requestDownloadURL(modID, fileID, this, userData, m_SubModule, m_Url));
}
void NexusBridge::requestToggleEndorsement(int modID, bool endorse, QVariant userData)
{
- m_RequestIDs.insert(m_Interface->requestToggleEndorsement(modID, endorse, this, userData, m_Url));
+ m_RequestIDs.insert(m_Interface->requestToggleEndorsement(modID, endorse, this, userData, m_SubModule, m_Url));
}
void NexusBridge::nxmDescriptionAvailable(int modID, QVariant userData, QVariant resultData, int requestID)
@@ -170,9 +171,6 @@ NXMAccessManager *NexusInterface::getAccessManager()
}
-//NexusInterface *NexusInterface::s_Instance = NULL;
-
-
NexusInterface *NexusInterface::instance()
{
static NexusInterface s_Instance;
@@ -192,13 +190,17 @@ void NexusInterface::setNMMVersion(const QString &nmmVersion)
m_NMMVersion = nmmVersion;
}
+void NexusInterface::loginCompleted()
+{
+ nextRequest();
+}
+
void NexusInterface::interpretNexusFileName(const QString &fileName, QString &modName, int &modID, bool query)
{
static std::tr1::regex exp("^([a-zA-Z0-9_\\- ]*?)([-_ ][VvRr]?[0-9_]+)?-([1-9][0-9]+).*");
static std::tr1::regex simpleexp("^([a-zA-Z0-9_]+)");
-// std::tr1::match_results<std::string::const_iterator> result;
QByteArray fileNameUTF8 = fileName.toUtf8();
std::tr1::cmatch result;
if (std::tr1::regex_search(fileNameUTF8.constData(), result, exp)) {
@@ -245,9 +247,10 @@ void NexusInterface::interpretNexusFileName(const QString &fileName, QString &mo
}
-int NexusInterface::requestDescription(int modID, QObject *receiver, QVariant userData, const QString &url)
+int NexusInterface::requestDescription(int modID, QObject *receiver, QVariant userData,
+ const QString &subModule, const QString &url)
{
- NXMRequestInfo requestInfo(modID, NXMRequestInfo::TYPE_DESCRIPTION, userData, url);
+ NXMRequestInfo requestInfo(modID, NXMRequestInfo::TYPE_DESCRIPTION, userData, subModule, url);
m_RequestQueue.enqueue(requestInfo);
connect(this, SIGNAL(nxmDescriptionAvailable(int,QVariant,QVariant,int)),
@@ -261,9 +264,10 @@ int NexusInterface::requestDescription(int modID, QObject *receiver, QVariant us
}
-int NexusInterface::requestUpdates(const std::vector<int> &modIDs, QObject *receiver, QVariant userData, const QString &url)
+int NexusInterface::requestUpdates(const std::vector<int> &modIDs, QObject *receiver, QVariant userData,
+ const QString &subModule, const QString &url)
{
- NXMRequestInfo requestInfo(modIDs, NXMRequestInfo::TYPE_GETUPDATES, userData, url);
+ NXMRequestInfo requestInfo(modIDs, NXMRequestInfo::TYPE_GETUPDATES, userData, subModule, url);
m_RequestQueue.enqueue(requestInfo);
connect(this, SIGNAL(nxmUpdatesAvailable(std::vector<int>,QVariant,QVariant,int)),
@@ -296,9 +300,10 @@ void NexusInterface::fakeFiles()
}
-int NexusInterface::requestFiles(int modID, QObject *receiver, QVariant userData, const QString &url)
+int NexusInterface::requestFiles(int modID, QObject *receiver, QVariant userData,
+ const QString &subModule, const QString &url)
{
- NXMRequestInfo requestInfo(modID, NXMRequestInfo::TYPE_FILES, userData, url);
+ NXMRequestInfo requestInfo(modID, NXMRequestInfo::TYPE_FILES, userData, subModule, url);
m_RequestQueue.enqueue(requestInfo);
connect(this, SIGNAL(nxmFilesAvailable(int,QVariant,QVariant,int)),
receiver, SLOT(nxmFilesAvailable(int,QVariant,QVariant,int)), Qt::UniqueConnection);
@@ -315,9 +320,10 @@ int NexusInterface::requestFiles(int modID, QObject *receiver, QVariant userData
}
-int NexusInterface::requestFileInfo(int modID, int fileID, QObject *receiver, QVariant userData, const QString &url)
+int NexusInterface::requestFileInfo(int modID, int fileID, QObject *receiver, QVariant userData, const QString &subModule,
+ const QString &url)
{
- NXMRequestInfo requestInfo(modID, fileID, NXMRequestInfo::TYPE_FILEINFO, userData, url);
+ NXMRequestInfo requestInfo(modID, fileID, NXMRequestInfo::TYPE_FILEINFO, userData, subModule, url);
m_RequestQueue.enqueue(requestInfo);
connect(this, SIGNAL(nxmFileInfoAvailable(int,int,QVariant,QVariant,int)),
@@ -331,9 +337,10 @@ int NexusInterface::requestFileInfo(int modID, int fileID, QObject *receiver, QV
}
-int NexusInterface::requestDownloadURL(int modID, int fileID, QObject *receiver, QVariant userData, const QString &url)
+int NexusInterface::requestDownloadURL(int modID, int fileID, QObject *receiver, QVariant userData,
+ const QString &subModule, const QString &url)
{
- NXMRequestInfo requestInfo(modID, fileID, NXMRequestInfo::TYPE_DOWNLOADURL, userData, url);
+ NXMRequestInfo requestInfo(modID, fileID, NXMRequestInfo::TYPE_DOWNLOADURL, userData, subModule, url);
m_RequestQueue.enqueue(requestInfo);
connect(this, SIGNAL(nxmDownloadURLsAvailable(int,int,QVariant,QVariant,int)),
@@ -347,9 +354,10 @@ int NexusInterface::requestDownloadURL(int modID, int fileID, QObject *receiver,
}
-int NexusInterface::requestToggleEndorsement(int modID, bool endorse, QObject *receiver, QVariant userData, const QString &url)
+int NexusInterface::requestToggleEndorsement(int modID, bool endorse, QObject *receiver, QVariant userData,
+ const QString &subModule, const QString &url)
{
- NXMRequestInfo requestInfo(modID, NXMRequestInfo::TYPE_TOGGLEENDORSEMENT, userData, url);
+ NXMRequestInfo requestInfo(modID, NXMRequestInfo::TYPE_TOGGLEENDORSEMENT, userData, subModule, url);
requestInfo.m_Endorse = endorse;
m_RequestQueue.enqueue(requestInfo);
@@ -363,13 +371,29 @@ int NexusInterface::requestToggleEndorsement(int modID, bool endorse, QObject *r
return requestInfo.m_ID;
}
+bool NexusInterface::requiresLogin(const NXMRequestInfo &info)
+{
+ return (info.m_Type == NXMRequestInfo::TYPE_TOGGLEENDORSEMENT)
+ || (info.m_Type == NXMRequestInfo::TYPE_DOWNLOADURL);
+}
void NexusInterface::nextRequest()
{
- if ((m_ActiveRequest.size() >= MAX_ACTIVE_DOWNLOADS) || (m_RequestQueue.isEmpty())) {
+ if ((m_ActiveRequest.size() >= MAX_ACTIVE_DOWNLOADS)
+ || m_RequestQueue.isEmpty()) {
return;
}
+ if (!getAccessManager()->loggedIn()
+ && requiresLogin(m_RequestQueue.head())) {
+ if (!getAccessManager()->loginAttempted()) {
+ emit needLogin();
+ return;
+ } else if (getAccessManager()->loginWaiting()) {
+ return;
+ }
+ }
+
NXMRequestInfo info = m_RequestQueue.dequeue();
info.m_Timeout = new QTimer(this);
info.m_Timeout->setInterval(60000);
@@ -407,10 +431,16 @@ void NexusInterface::nextRequest()
}
QNetworkRequest request(url);
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/xml");
- request.setRawHeader("User-Agent",
- QString("Mod Organizer v%1 (compatible to Nexus Client v%2)")
- .arg(m_MOVersion.displayString())
- .arg(m_NMMVersion).toUtf8());
+ QStringList comments;
+ comments << "compatible to Nexus Client v" + m_NMMVersion;
+ if (!info.m_SubModule.isEmpty()) {
+ comments << "module: " + info.m_SubModule;
+ }
+
+ QString userAgent = QString("Mod Organizer v%1 (%2)")
+ .arg(m_MOVersion.displayString())
+ .arg(comments.join("; "));
+ request.setRawHeader("User-Agent", userAgent.toUtf8());
info.m_Reply = m_AccessManager->get(request);
@@ -450,6 +480,7 @@ void NexusInterface::requestFinished(std::list<NXMRequestInfo>::iterator iter)
if (nexusError.length() == 0) {
nexusError = tr("empty response");
}
+ qDebug("nexus error: %s", qPrintable(nexusError));
emit nxmRequestFailed(iter->m_ModID, iter->m_FileID, iter->m_UserData, iter->m_ID, nexusError);
} else {
bool ok;
@@ -528,3 +559,57 @@ void NexusInterface::requestTimeout()
}
}
}
+
+
+NexusInterface::NXMRequestInfo::NXMRequestInfo(int modID
+ , NexusInterface::NXMRequestInfo::Type type
+ , QVariant userData
+ , const QString &subModule
+ , const QString &url)
+ : m_ModID(modID)
+ , m_FileID(0)
+ , m_Reply(NULL)
+ , m_Type(type)
+ , m_UserData(userData)
+ , m_Timeout(NULL)
+ , m_Reroute(false)
+ , m_ID(s_NextID.fetchAndAddAcquire(1))
+ , m_URL(url)
+ , m_SubModule(subModule)
+{}
+
+NexusInterface::NXMRequestInfo::NXMRequestInfo(std::vector<int> modIDList
+ , NexusInterface::NXMRequestInfo::Type type
+ , QVariant userData
+ , const QString &subModule
+ , const QString &url)
+ : m_ModID(-1)
+ , m_ModIDList(modIDList)
+ , m_FileID(0)
+ , m_Reply(NULL)
+ , m_Type(type)
+ , m_UserData(userData)
+ , m_Timeout(NULL)
+ , m_Reroute(false)
+ , m_ID(s_NextID.fetchAndAddAcquire(1))
+ , m_URL(url)
+ , m_SubModule(subModule)
+{}
+
+NexusInterface::NXMRequestInfo::NXMRequestInfo(int modID
+ , int fileID
+ , NexusInterface::NXMRequestInfo::Type type
+ , QVariant userData
+ , const QString &subModule
+ , const QString &url)
+ : m_ModID(modID)
+ , m_FileID(fileID)
+ , m_Reply(NULL)
+ , m_Type(type)
+ , m_UserData(userData)
+ , m_Timeout(NULL)
+ , m_Reroute(false)
+ , m_ID(s_NextID.fetchAndAddAcquire(1))
+ , m_URL(url)
+ , m_SubModule(subModule)
+{}
diff --git a/src/nexusinterface.h b/src/nexusinterface.h
index 6067d027..c4427474 100644
--- a/src/nexusinterface.h
+++ b/src/nexusinterface.h
@@ -54,7 +54,7 @@ class NexusBridge : public MOBase::IModRepositoryBridge
public:
- NexusBridge();
+ NexusBridge(const QString &subModule = "");
/**
* @brief request description for a mod
@@ -111,6 +111,7 @@ private:
NexusInterface *m_Interface;
QString m_Url;
+ QString m_SubModule;
std::set<int> m_RequestIDs;
};
@@ -145,7 +146,7 @@ public:
* @param url the url to request from
* @return int an id to identify the request
**/
- int requestDescription(int modID, QObject *receiver, QVariant userData,
+ int requestDescription(int modID, QObject *receiver, QVariant userData, const QString &subModule,
const QString &url = MOBase::ToQString(MOShared::GameInfo::instance().getNexusInfoUrl()));
/**
@@ -156,7 +157,7 @@ public:
* @param url the url to request from
* @return int an id to identify the request
*/
- int requestUpdates(const std::vector<int> &modIDs, QObject *receiver, QVariant userData,
+ int requestUpdates(const std::vector<int> &modIDs, QObject *receiver, QVariant userData, const QString &subModule,
const QString &url = MOBase::ToQString(MOShared::GameInfo::instance().getNexusInfoUrl()));
/**
@@ -168,7 +169,7 @@ public:
* @param url the url to request from
* @return int an id to identify the request
**/
- int requestFiles(int modID, QObject *receiver, QVariant userData,
+ int requestFiles(int modID, QObject *receiver, QVariant userData, const QString &subModule,
const QString &url = MOBase::ToQString(MOShared::GameInfo::instance().getNexusInfoUrl()));
/**
@@ -181,7 +182,7 @@ public:
* @param url the url to request from
* @return int an id to identify the request
**/
- int requestFileInfo(int modID, int fileID, QObject *receiver, QVariant userData,
+ int requestFileInfo(int modID, int fileID, QObject *receiver, QVariant userData, const QString &subModule,
const QString &url = MOBase::ToQString(MOShared::GameInfo::instance().getNexusInfoUrl()));
/**
@@ -194,7 +195,7 @@ public:
* @param url the url to request from
* @return int an id to identify the request
**/
- int requestDownloadURL(int modID, int fileID, QObject *receiver, QVariant userData,
+ int requestDownloadURL(int modID, int fileID, QObject *receiver, QVariant userData, const QString &subModule,
const QString &url = MOBase::ToQString(MOShared::GameInfo::instance().getNexusInfoUrl()));
/**
@@ -206,7 +207,7 @@ public:
* @param url the url to request from
* @return int an id to identify the request
*/
- int requestToggleEndorsement(int modID, bool endorse, QObject *receiver, QVariant userData,
+ int requestToggleEndorsement(int modID, bool endorse, QObject *receiver, QVariant userData, const QString &subModule,
const QString &url = MOBase::ToQString(MOShared::GameInfo::instance().getNexusInfoUrl()));
/**
@@ -220,6 +221,11 @@ public:
**/
void setNMMVersion(const QString &nmmVersion);
+ /**
+ * @brief called when the log-in completes. This was, requests waiting for the log-in can be run
+ */
+ void loginCompleted();
+
public:
/**
@@ -234,6 +240,8 @@ signals:
void requestNXMDownload(const QString &url);
+ void needLogin();
+
void nxmDescriptionAvailable(int modID, QVariant userData, QVariant resultData, int requestID);
void nxmUpdatesAvailable(const std::vector<int> &modIDs, QVariant userData, QVariant resultData, int requestID);
void nxmFilesAvailable(int modID, QVariant userData, QVariant resultData, int requestID);
@@ -270,19 +278,14 @@ private:
QVariant m_UserData;
QTimer *m_Timeout;
QString m_URL;
+ QString m_SubModule;
bool m_Reroute;
int m_ID;
int m_Endorse;
- NXMRequestInfo(int modID, Type type, QVariant userData, const QString &url)
- : m_ModID(modID), m_FileID(0), m_Reply(NULL), m_Type(type), m_UserData(userData),
- m_Timeout(NULL), m_Reroute(false), m_ID(s_NextID.fetchAndAddAcquire(1)), m_URL(url) {}
- NXMRequestInfo(std::vector<int> modIDList, Type type, QVariant userData, const QString &url)
- : m_ModID(-1), m_ModIDList(modIDList), m_FileID(0), m_Reply(NULL), m_Type(type), m_UserData(userData),
- m_Timeout(NULL), m_Reroute(false), m_ID(s_NextID.fetchAndAddAcquire(1)), m_URL(url) {}
- NXMRequestInfo(int modID, int fileID, Type type, QVariant userData, const QString &url)
- : m_ModID(modID), m_FileID(fileID), m_Reply(NULL), m_Type(type), m_UserData(userData),
- m_Timeout(NULL), m_Reroute(false), m_ID(s_NextID.fetchAndAddAcquire(1)), m_URL(url) {}
+ NXMRequestInfo(int modID, Type type, QVariant userData, const QString &subModule, const QString &url);
+ NXMRequestInfo(std::vector<int> modIDList, Type type, QVariant userData, const QString &subModule, const QString &url);
+ NXMRequestInfo(int modID, int fileID, Type type, QVariant userData, const QString &subModule, const QString &url);
private:
static QAtomicInt s_NextID;
@@ -295,6 +298,7 @@ private:
NexusInterface();
void nextRequest();
void requestFinished(std::list<NXMRequestInfo>::iterator iter);
+ bool requiresLogin(const NXMRequestInfo &info);
static void cleanup();
private:
diff --git a/src/nxmaccessmanager.cpp b/src/nxmaccessmanager.cpp
index 3df34de1..b65ff082 100644
--- a/src/nxmaccessmanager.cpp
+++ b/src/nxmaccessmanager.cpp
@@ -42,7 +42,10 @@ using namespace MOShared;
NXMAccessManager::NXMAccessManager(QObject *parent)
- : QNetworkAccessManager(parent), m_LoginReply(NULL), m_ProgressDialog()
+ : QNetworkAccessManager(parent)
+ , m_LoginReply(NULL)
+ , m_ProgressDialog()
+ , m_LoginAttempted(false)
{
setCookieJar(new PersistentCookieJar(
QDir::fromNativeSeparators(MOBase::ToQString(MOShared::GameInfo::instance().getCacheDir())) + "/nexus_cookies.dat", this));
@@ -92,6 +95,11 @@ bool NXMAccessManager::loggedIn() const
return hasLoginCookies();
}
+bool NXMAccessManager::loginWaiting() const
+{
+ return m_LoginReply != NULL;
+}
+
void NXMAccessManager::login(const QString &username, const QString &password)
{
@@ -104,6 +112,8 @@ void NXMAccessManager::login(const QString &username, const QString &password)
return;
}
+ m_LoginAttempted = true;
+
m_Username = username;
m_Password = password;
pageLogin();
@@ -149,6 +159,7 @@ void NXMAccessManager::loginTimeout()
emit loginFailed(tr("timeout"));
m_LoginReply->deleteLater();
m_LoginReply = NULL;
+ m_LoginAttempted = false; // this usually means we might have usccess later
m_LoginTimeout.stop();
m_Username.clear();
m_Password.clear();
diff --git a/src/nxmaccessmanager.h b/src/nxmaccessmanager.h
index 1d8d36ab..6c0dedb9 100644
--- a/src/nxmaccessmanager.h
+++ b/src/nxmaccessmanager.h
@@ -41,6 +41,9 @@ public:
bool loggedIn() const;
+ bool loginAttempted() const { return m_LoginAttempted; }
+ bool loginWaiting() const;
+
void login(const QString &username, const QString &password);
void showCookies();
@@ -93,6 +96,8 @@ private:
QString m_Username;
QString m_Password;
+ bool m_LoginAttempted;
+
};
#endif // NXMACCESSMANAGER_H
diff --git a/src/organizer.pro b/src/organizer.pro
index 8875ec05..95f5d753 100644
--- a/src/organizer.pro
+++ b/src/organizer.pro
@@ -88,7 +88,8 @@ SOURCES += \
json.cpp \
safewritefile.cpp \
modflagicondelegate.cpp \
- pluginflagicondelegate.cpp
+ pluginflagicondelegate.cpp \
+ organizerproxy.cpp
HEADERS += \
@@ -166,7 +167,8 @@ HEADERS += \
safewritefile.h\
pdll.h \
modflagicondelegate.h \
- pluginflagicondelegate.h
+ pluginflagicondelegate.h \
+ organizerproxy.h
FORMS += \
transfersavesdialog.ui \
diff --git a/src/organizerproxy.cpp b/src/organizerproxy.cpp
new file mode 100644
index 00000000..f17d7cd9
--- /dev/null
+++ b/src/organizerproxy.cpp
@@ -0,0 +1,185 @@
+#include "organizerproxy.h"
+#include <gameinfo.h>
+#include <appconfig.h>
+
+
+using namespace MOBase;
+using namespace MOShared;
+
+
+OrganizerProxy::OrganizerProxy(MainWindow *window, const QString &pluginName)
+ : m_Proxied(window)
+ , m_PluginName(pluginName)
+{
+}
+
+IGameInfo &OrganizerProxy::gameInfo() const
+{
+ return *m_Proxied->m_GameInfo;
+}
+
+
+IModRepositoryBridge *OrganizerProxy::createNexusBridge() const
+{
+ return new NexusBridge(m_PluginName);
+}
+
+
+QString OrganizerProxy::profileName() const
+{
+ if (m_Proxied->m_CurrentProfile != NULL) {
+ return m_Proxied->m_CurrentProfile->getName();
+ } else {
+ return "";
+ }
+}
+
+QString OrganizerProxy::profilePath() const
+{
+ if (m_Proxied->m_CurrentProfile != NULL) {
+ return m_Proxied->m_CurrentProfile->getPath();
+ } else {
+ return "";
+ }
+}
+
+QString OrganizerProxy::downloadsPath() const
+{
+ return QDir::fromNativeSeparators(m_Proxied->m_Settings.getDownloadDirectory());
+}
+
+VersionInfo OrganizerProxy::appVersion() const
+{
+ return m_Proxied->m_Updater.getVersion();
+}
+
+IModInterface *OrganizerProxy::getMod(const QString &name)
+{
+ return m_Proxied->getMod(name);
+}
+
+IModInterface *OrganizerProxy::createMod(MOBase::GuessedValue<QString> &name)
+{
+ return m_Proxied->createMod(name);
+}
+
+bool OrganizerProxy::removeMod(IModInterface *mod)
+{
+ return m_Proxied->removeMod(mod);
+}
+
+void OrganizerProxy::modDataChanged(IModInterface*)
+{
+ m_Proxied->refreshModList();
+}
+
+QVariant OrganizerProxy::pluginSetting(const QString &pluginName, const QString &key) const
+{
+ return m_Proxied->m_Settings.pluginSetting(pluginName, key);
+}
+
+void OrganizerProxy::setPluginSetting(const QString &pluginName, const QString &key, const QVariant &value)
+{
+ m_Proxied->m_Settings.setPluginSetting(pluginName, key, value);
+}
+
+QVariant OrganizerProxy::persistent(const QString &pluginName, const QString &key, const QVariant &def) const
+{
+ return m_Proxied->m_Settings.pluginPersistent(pluginName, key, def);
+}
+
+void OrganizerProxy::setPersistent(const QString &pluginName, const QString &key, const QVariant &value, bool sync)
+{
+ m_Proxied->m_Settings.setPluginPersistent(pluginName, key, value, sync);
+}
+
+QString OrganizerProxy::pluginDataPath() const
+{
+ QString pluginPath = QDir::fromNativeSeparators(ToQString(GameInfo::instance().getOrganizerDirectory())) + "/" + ToQString(AppConfig::pluginPath());
+ return pluginPath + "/data";
+}
+
+HANDLE OrganizerProxy::startApplication(const QString &executable, const QStringList &args, const QString &cwd, const QString &profile)
+{
+ return m_Proxied->startApplication(executable, args, cwd, profile);
+}
+
+bool OrganizerProxy::onAboutToRun(const std::function<bool (const QString &)> &func)
+{
+ auto conn = m_Proxied->m_AboutToRun.connect(func);
+ return conn.connected();
+}
+
+void OrganizerProxy::refreshModList(bool saveChanges)
+{
+ m_Proxied->refreshModList(saveChanges);
+}
+
+IModInterface *OrganizerProxy::installMod(const QString &fileName)
+{
+ return m_Proxied->installMod(fileName);
+}
+
+QString OrganizerProxy::resolvePath(const QString &fileName) const
+{
+ if (m_Proxied->m_DirectoryStructure == NULL) {
+ return QString();
+ }
+ const FileEntry::Ptr file = m_Proxied->m_DirectoryStructure->searchFile(ToWString(fileName), NULL);
+ if (file.get() != NULL) {
+ return ToQString(file->getFullPath());
+ } else {
+ return QString();
+ }
+}
+
+QStringList OrganizerProxy::listDirectories(const QString &directoryName) const
+{
+ QStringList result;
+ DirectoryEntry *dir = m_Proxied->m_DirectoryStructure->findSubDirectoryRecursive(ToWString(directoryName));
+ if (dir != NULL) {
+ std::vector<DirectoryEntry*>::iterator current, end;
+ dir->getSubDirectories(current, end);
+ for (; current != end; ++current) {
+ result.append(ToQString((*current)->getName()));
+ }
+ }
+ return result;
+}
+
+QStringList OrganizerProxy::findFiles(const QString &path, const std::function<bool(const QString&)> &filter) const
+{
+ QStringList result;
+ DirectoryEntry *dir = m_Proxied->m_DirectoryStructure->findSubDirectoryRecursive(ToWString(path));
+ if (dir != NULL) {
+ std::vector<FileEntry::Ptr> files = dir->getFiles();
+ foreach (FileEntry::Ptr file, files) {
+ if (filter(ToQString(file->getFullPath()))) {
+ result.append(ToQString(file->getFullPath()));
+ }
+ }
+ } else {
+ qWarning("directory %s not found", qPrintable(path));
+ }
+ return result;
+}
+
+QList<MOBase::IOrganizer::FileInfo> OrganizerProxy::findFileInfos(const QString &path, const std::function<bool (const MOBase::IOrganizer::FileInfo &)> &filter) const
+{
+ return m_Proxied->findFileInfos(path, filter);
+}
+
+MOBase::IDownloadManager *OrganizerProxy::downloadManager()
+{
+ return &m_Proxied->m_DownloadManager;
+}
+
+MOBase::IPluginList *OrganizerProxy::pluginList()
+{
+ return &m_Proxied->m_PluginList;
+}
+
+MOBase::IModList *OrganizerProxy::modList()
+{
+ return &m_Proxied->m_ModList;
+}
diff --git a/src/organizerproxy.h b/src/organizerproxy.h
new file mode 100644
index 00000000..fd9dd56a
--- /dev/null
+++ b/src/organizerproxy.h
@@ -0,0 +1,48 @@
+#ifndef ORGANIZERPROXY_H
+#define ORGANIZERPROXY_H
+
+
+#include <imoinfo.h>
+#include "mainwindow.h"
+
+class OrganizerProxy : public MOBase::IOrganizer
+{
+public:
+ OrganizerProxy(MainWindow *window, const QString &pluginName);
+
+ virtual MOBase::IGameInfo &gameInfo() const;
+ virtual MOBase::IModRepositoryBridge *createNexusBridge() const;
+ virtual QString profileName() const;
+ virtual QString profilePath() const;
+ virtual QString downloadsPath() const;
+ virtual MOBase::VersionInfo appVersion() const;
+ virtual MOBase::IModInterface *getMod(const QString &name);
+ virtual MOBase::IModInterface *createMod(MOBase::GuessedValue<QString> &name);
+ virtual bool removeMod(MOBase::IModInterface *mod);
+ virtual void modDataChanged(MOBase::IModInterface *mod);
+ virtual QVariant pluginSetting(const QString &pluginName, const QString &key) const;
+ virtual void setPluginSetting(const QString &pluginName, const QString &key, const QVariant &value);
+ virtual QVariant persistent(const QString &pluginName, const QString &key, const QVariant &def = QVariant()) const;
+ virtual void setPersistent(const QString &pluginName, const QString &key, const QVariant &value, bool sync = true);
+ virtual QString pluginDataPath() const;
+ virtual MOBase::IModInterface *installMod(const QString &fileName);
+ virtual QString resolvePath(const QString &fileName) const;
+ virtual QStringList listDirectories(const QString &directoryName) const;
+ virtual QStringList findFiles(const QString &path, const std::function<bool(const QString &)> &filter) const;
+ virtual QList<FileInfo> findFileInfos(const QString &path, const std::function<bool(const FileInfo&)> &filter) const;
+
+ virtual MOBase::IDownloadManager *downloadManager();
+ virtual MOBase::IPluginList *pluginList();
+ virtual MOBase::IModList *modList();
+ virtual HANDLE startApplication(const QString &executable, const QStringList &args = QStringList(), const QString &cwd = "", const QString &profile = "");
+ virtual bool onAboutToRun(const std::function<bool(const QString&)> &func);
+ virtual void refreshModList(bool saveChanges);
+
+private:
+ MainWindow *m_Proxied;
+ const QString &m_PluginName;
+
+};
+
+
+#endif // ORGANIZERPROXY_H
diff --git a/src/pluginlist.cpp b/src/pluginlist.cpp
index 929e0476..24504f92 100644
--- a/src/pluginlist.cpp
+++ b/src/pluginlist.cpp
@@ -397,7 +397,7 @@ void PluginList::writePlugins(const QString &fileName, bool writeUnchecked) cons
int writtenCount = 0;
for (size_t i = 0; i < m_ESPs.size(); ++i) {
int priority = m_ESPsByPriority[i];
- if ((m_ESPs[priority].m_Enabled || writeUnchecked) && !m_ESPs[priority].m_Removed) {
+ if (m_ESPs[priority].m_Enabled || writeUnchecked) {
//file.write(m_ESPs[priority].m_Name.toUtf8());
if (!textCodec->canEncode(m_ESPs[priority].m_Name)) {
invalidFileNames = true;
@@ -435,7 +435,11 @@ void PluginList::writeLockedOrder(const QString &fileName) const
}
-void PluginList::saveTo(const QString &pluginFileName, const QString &loadOrderFileName, const QString &lockedOrderFileName, const QString& deleterFileName, bool hideUnchecked) const
+void PluginList::saveTo(const QString &pluginFileName
+ , const QString &loadOrderFileName
+ , const QString &lockedOrderFileName
+ , const QString& deleterFileName
+ , bool hideUnchecked) const
{
writePlugins(pluginFileName, false);
writePlugins(loadOrderFileName, true);
@@ -449,7 +453,7 @@ void PluginList::saveTo(const QString &pluginFileName, const QString &loadOrderF
for (size_t i = 0; i < m_ESPs.size(); ++i) {
int priority = m_ESPsByPriority[i];
- if (m_ESPs[priority].m_Removed) {
+ if (!m_ESPs[priority].m_Enabled) {
deleterFile.write(m_ESPs[priority].m_Name.toUtf8());
deleterFile.write("\r\n");
}
@@ -1082,7 +1086,7 @@ bool PluginList::eventFilter(QObject *obj, QEvent *event)
PluginList::ESPInfo::ESPInfo(const QString &name, bool enabled, FILETIME time,
const QString &originName, const QString &fullPath,
bool hasIni)
- : m_Name(name), m_Enabled(enabled), m_ForceEnabled(enabled), m_Removed(false),
+ : m_Name(name), m_Enabled(enabled), m_ForceEnabled(enabled),
m_Priority(0), m_LoadOrder(-1), m_Time(time), m_OriginName(originName), m_HasIni(hasIni)
{
try {
diff --git a/src/pluginlist.h b/src/pluginlist.h
index b7e7e2b4..ecd9c654 100644
--- a/src/pluginlist.h
+++ b/src/pluginlist.h
@@ -238,7 +238,6 @@ private:
QString m_Name;
bool m_Enabled;
bool m_ForceEnabled;
- bool m_Removed;
int m_Priority;
int m_LoadOrder;
FILETIME m_Time;
diff --git a/src/selfupdater.cpp b/src/selfupdater.cpp
index 14df8566..0895c5ab 100644
--- a/src/selfupdater.cpp
+++ b/src/selfupdater.cpp
@@ -99,7 +99,7 @@ void SelfUpdater::testForUpdate()
if (m_UpdateRequestID == -1) {
m_UpdateRequestID = m_Interface->requestDescription(
SkyrimInfo::getNexusModIDStatic(), this, QVariant(),
- ToQString(SkyrimInfo::getNexusInfoUrlStatic()));
+ QString(), ToQString(SkyrimInfo::getNexusInfoUrlStatic()));
}
}