From 977b4075254ca79e68bbdec2e689eccb291fe701 Mon Sep 17 00:00:00 2001 From: Tannin Date: Tue, 13 May 2014 21:20:44 +0200 Subject: - mod list context menu split into two menus (one for whole list, one for selected mods) - added option to combine category filters using "or" - added context menu option for deselecting category filters - slightly changed ui on the category filters - added a sample plugin for cpp that can be built without building the rest of MO - simple installer can now be configured to run without any user interaction - extended interface for python plugins - iorganizer implementation moved out of the main window - nexus requests from plugins will now be identified in the user agent - bugfix: shortcuts created from MO used the wrong working directory - bugfix: deactivation of bsas didn't stick - bugfix: file hiding mechanism wasn't active - bugfix: executables linked on the toolbar couldn't be removed if the executable was removed first - bugfix: the endorsement-filter couldn't be combined with other filters - bugfix: python interface to repository bridge was broken --- src/bbcode.cpp | 4 +- src/downloadmanager.cpp | 8 +- src/logbuffer.cpp | 7 +- src/main.cpp | 3 +- src/mainwindow.cpp | 689 ++++++++++++++++++++--------------------------- src/mainwindow.h | 59 ++-- src/mainwindow.ui | 85 +++++- src/modinfo.cpp | 2 +- src/modlistsortproxy.cpp | 66 ++++- src/modlistsortproxy.h | 12 + src/nexusinterface.cpp | 139 ++++++++-- src/nexusinterface.h | 36 +-- src/nxmaccessmanager.cpp | 13 +- src/nxmaccessmanager.h | 5 + src/organizer.pro | 6 +- src/organizerproxy.cpp | 185 +++++++++++++ src/organizerproxy.h | 48 ++++ src/pluginlist.cpp | 12 +- src/pluginlist.h | 1 - src/selfupdater.cpp | 2 +- 20 files changed, 870 insertions(+), 512 deletions(-) create mode 100644 src/organizerproxy.cpp create mode 100644 src/organizerproxy.h (limited to 'src') 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: "\\1"); m_TagMap["url="] = std::make_pair(QRegExp("\\[url=([^\\]]*)\\](.*)\\[/url\\]"), "\\2"); - 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\\]"), "\\2"); 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 . #include "browserdialog.h" #include "aboutdialog.h" #include "safewritefile.h" +#include "organizerproxy.h" #include #include #include @@ -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 &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 &LHS, const std::pair &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 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(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::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 &filter) const -{ - QStringList result; - DirectoryEntry *dir = m_DirectoryStructure->findSubDirectoryRecursive(ToWString(path)); - if (dir != NULL) { - std::vector 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 MainWindow::findFileInfos(const QString &path, const std::function &filter) const -{ - QList result; - DirectoryEntry *dir = m_DirectoryStructure->findSubDirectoryRecursive(ToWString(path)); - if (dir != NULL) { - std::vector 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 &func) -{ - auto conn = m_AboutToRun.connect(func); - return conn.connected(); -} - std::vector MainWindow::activeProblems() const { std::vector problems; @@ -2495,6 +2197,109 @@ void MainWindow::installMod() } } +IModInterface *MainWindow::installMod(const QString &fileName) +{ + if (m_CurrentProfile == NULL) { + return NULL; + } + + bool hasIniTweaks = false; + GuessedValue 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(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 &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 MainWindow::findFileInfos(const QString &path, const std::function &filter) const +{ + QList result; + DirectoryEntry *dir = m_DirectoryStructure->findSubDirectoryRecursive(ToWString(path)); + if (dir != NULL) { + std::vector 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("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("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 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 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 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(""))); } 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 &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 &filter) const; - virtual QList findFileInfos(const QString &path, const std::function &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 &func); - virtual void refreshModList(bool saveChanges = true); - virtual std::vector 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 &name); + bool removeMod(MOBase::IModInterface *mod); + + QList findFileInfos(const QString &path, const std::function &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 @@ QAbstractItemView::ExtendedSelection + + 0 + false @@ -85,6 +88,54 @@ + + + + false + + + Click blank area to deselect + + + + + + + + + + false + + + false + + + + + + If checked, only mods that match all selected categories are displayed. + + + And + + + true + + + + + + + If checked, all mods that match one of the selected categories are displayed. + + + Or + + + + + + @@ -140,10 +191,23 @@ p, li { white-space: pre-wrap; } - + + + Qt::Horizontal + + + + 40 + 20 + + + + + + - 24 + 16777215 16777215 @@ -158,22 +222,15 @@ p, li { white-space: pre-wrap; } - :/MO/gui/resources/view-refresh.png:/MO/gui/resources/view-refresh.png - - - - - - - Qt::Horizontal + :/MO/gui/settings:/MO/gui/settings - + - 40 - 20 + 16 + 16 - + 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 &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 &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 @@ -30,6 +30,13 @@ class ModListSortProxy : public QSortFilterProxyModel { Q_OBJECT +public: + + enum FilterMode { + FILTER_AND, + FILTER_OR + }; + public: explicit ModListSortProxy(Profile *profile, QObject *parent = 0); @@ -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 &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 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 &modIDs, QObject *receiver, QVariant userData, const QString &url) +int NexusInterface::requestUpdates(const std::vector &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,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::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 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 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 &modIDs, QObject *receiver, QVariant userData, + int requestUpdates(const std::vector &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 &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 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 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::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 +#include + + +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 &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 &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::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 &filter) const +{ + QStringList result; + DirectoryEntry *dir = m_Proxied->m_DirectoryStructure->findSubDirectoryRecursive(ToWString(path)); + if (dir != NULL) { + std::vector 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 OrganizerProxy::findFileInfos(const QString &path, const std::function &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 +#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 &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 &filter) const; + virtual QList findFileInfos(const QString &path, const std::function &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 &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())); } } -- cgit v1.3.1