diff options
| author | Jonathan Feenstra <26406078+JonathanFeenstra@users.noreply.github.com> | 2025-08-18 07:55:52 +0200 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2025-08-18 07:55:52 +0200 |
| commit | d52fcccb831b63dc1add068084369543d0a45246 (patch) | |
| tree | 3d3009a7e0ad3b477b64b349a1bdc7fd1e0d5f62 /src | |
| parent | 6c64236e2e7a8e2883b7656657e0fac329d5621b (diff) | |
Add author and uploader columns to mod list (#2269)
Diffstat (limited to 'src')
| -rw-r--r-- | src/downloadlistview.cpp | 13 | ||||
| -rw-r--r-- | src/downloadlistview.h | 2 | ||||
| -rw-r--r-- | src/downloadmanager.cpp | 46 | ||||
| -rw-r--r-- | src/downloadmanager.h | 2 | ||||
| -rw-r--r-- | src/downloadstab.cpp | 2 | ||||
| -rw-r--r-- | src/mainwindow.cpp | 6 | ||||
| -rw-r--r-- | src/modinfo.h | 30 | ||||
| -rw-r--r-- | src/modinfobackup.h | 6 | ||||
| -rw-r--r-- | src/modinfoforeign.h | 6 | ||||
| -rw-r--r-- | src/modinfooverwrite.h | 6 | ||||
| -rw-r--r-- | src/modinforegular.cpp | 45 | ||||
| -rw-r--r-- | src/modinforegular.h | 33 | ||||
| -rw-r--r-- | src/modinfoseparator.h | 6 | ||||
| -rw-r--r-- | src/modlist.cpp | 12 | ||||
| -rw-r--r-- | src/modlist.h | 2 | ||||
| -rw-r--r-- | src/modlistcontextmenu.cpp | 12 | ||||
| -rw-r--r-- | src/modlistsortproxy.cpp | 44 | ||||
| -rw-r--r-- | src/modlistview.cpp | 1 | ||||
| -rw-r--r-- | src/modlistviewactions.cpp | 70 | ||||
| -rw-r--r-- | src/modlistviewactions.h | 7 | ||||
| -rw-r--r-- | src/nexusinterface.cpp | 20 |
21 files changed, 336 insertions, 35 deletions
diff --git a/src/downloadlistview.cpp b/src/downloadlistview.cpp index a895d2e2..f2677523 100644 --- a/src/downloadlistview.cpp +++ b/src/downloadlistview.cpp @@ -231,14 +231,18 @@ void DownloadListView::onCustomContextMenu(const QPoint& point) menu.addAction(tr("Install"), [=] { issueInstall(row); }); - if (m_Manager->isInfoIncomplete(row)) + if (m_Manager->isInfoIncomplete(row)) { menu.addAction(tr("Query Info"), [=] { issueQueryInfoMd5(row); }); - else + } else { menu.addAction(tr("Visit on Nexus"), [=] { issueVisitOnNexus(row); }); + menu.addAction(tr("Visit the uploader's profile"), [=] { + issueVisitUploaderProfile(row); + }); + } menu.addAction(tr("Open File"), [=] { issueOpenFile(row); }); @@ -408,6 +412,11 @@ void DownloadListView::issueVisitOnNexus(int index) emit visitOnNexus(index); } +void DownloadListView::issueVisitUploaderProfile(int index) +{ + emit visitUploaderProfile(index); +} + void DownloadListView::issueOpenFile(int index) { emit openFile(index); diff --git a/src/downloadlistview.h b/src/downloadlistview.h index 65d98849..9fccdbc5 100644 --- a/src/downloadlistview.h +++ b/src/downloadlistview.h @@ -87,6 +87,7 @@ signals: void pauseDownload(int index); void resumeDownload(int index); void visitOnNexus(int index); + void visitUploaderProfile(int index); void openFile(int index); void openMetaFile(int index); void openInDownloadsFolder(int index); @@ -105,6 +106,7 @@ private slots: void issueRestoreToView(int index); void issueRestoreToViewAll(); void issueVisitOnNexus(int index); + void issueVisitUploaderProfile(int index); void issueOpenFile(int index); void issueOpenMetaFile(int index); void issueOpenInDownloadsFolder(int index); diff --git a/src/downloadmanager.cpp b/src/downloadmanager.cpp index 52eb8c8e..ce6ba665 100644 --- a/src/downloadmanager.cpp +++ b/src/downloadmanager.cpp @@ -148,6 +148,9 @@ DownloadManager::DownloadInfo::createFromMeta(const QString& filePath, bool show info->m_FileInfo->fileCategory = metaFile.value("fileCategory", 0).toInt(); info->m_FileInfo->repository = metaFile.value("repository", "Nexus").toString(); info->m_FileInfo->userData = metaFile.value("userData").toMap(); + info->m_FileInfo->author = metaFile.value("author", "").toString(); + info->m_FileInfo->uploader = metaFile.value("uploader", "").toString(); + info->m_FileInfo->uploaderUrl = metaFile.value("uploaderUrl", "").toString(); info->m_Reply = nullptr; return info; @@ -1217,6 +1220,27 @@ void DownloadManager::visitOnNexus(int index) } } +void DownloadManager::visitUploaderProfile(int index) +{ + if ((index < 0) || (index >= m_ActiveDownloads.size())) { + reportError(tr("VisitUploaderProfile: invalid download index %1").arg(index)); + return; + } + DownloadInfo* info = m_ActiveDownloads[index]; + + if (info->m_State < DownloadManager::STATE_READY) { + // UI shouldn't allow this + return; + } + + const auto& uploaderUrl = info->m_FileInfo->uploaderUrl; + if (!uploaderUrl.isEmpty()) { + shell::Open(QUrl(uploaderUrl)); + } else { + emit showMessage(tr("Uploader for this Mod is unknown")); + } +} + void DownloadManager::openFile(int index) { if ((index < 0) || (index >= m_ActiveDownloads.size())) { @@ -1724,6 +1748,9 @@ void DownloadManager::createMetaFile(DownloadInfo* info) metaFile.setValue("category", info->m_FileInfo->categoryID); metaFile.setValue("repository", info->m_FileInfo->repository); metaFile.setValue("userData", info->m_FileInfo->userData); + metaFile.setValue("author", info->m_FileInfo->author); + metaFile.setValue("uploader", info->m_FileInfo->uploader); + metaFile.setValue("uploaderUrl", info->m_FileInfo->uploaderUrl); metaFile.setValue("installed", info->m_State == DownloadManager::STATE_INSTALLED); metaFile.setValue("uninstalled", info->m_State == DownloadManager::STATE_UNINSTALLED); metaFile.setValue("paused", (info->m_State == DownloadManager::STATE_PAUSED) || @@ -1753,7 +1780,10 @@ void DownloadManager::nxmDescriptionAvailable(QString, int, QVariant userData, DownloadInfo* info = downloadInfoByID(userData.toInt()); if (info == nullptr) return; - info->m_FileInfo->categoryID = result["category_id"].toInt(); + info->m_FileInfo->categoryID = result["category_id"].toInt(); + info->m_FileInfo->author = result["author"].toString(); + info->m_FileInfo->uploader = result["uploaded_by"].toString(); + info->m_FileInfo->uploaderUrl = result["uploaded_users_profile_url"].toString(); QTextDocument doc; doc.setHtml(result["name"].toString().trimmed()); info->m_FileInfo->modName = doc.toPlainText(); @@ -1813,7 +1843,10 @@ void DownloadManager::nxmFilesAvailable(QString, int, QVariant userData, info->m_FileInfo->fileName = fileInfo["file_name"].toString(); info->m_FileInfo->description = BBCode::convertToHTML(fileInfo["description"].toString()); - found = true; + info->m_FileInfo->author = fileInfo["author"].toString(); + info->m_FileInfo->uploader = fileInfo["uploaded_by"].toString(); + info->m_FileInfo->uploaderUrl = fileInfo["uploaded_users_profile_url"].toString(); + found = true; break; } } @@ -2116,9 +2149,12 @@ void DownloadManager::nxmFileInfoFromMd5Available(QString gameName, QVariant use info->m_FileInfo->version.parse(fileDetails["mod_version"].toString()); info->m_FileInfo->fileCategory = fileDetails["category_id"].toInt(); - info->m_FileInfo->modID = modDetails["mod_id"].toInt(); - info->m_FileInfo->modName = modDetails["name"].toString(); - info->m_FileInfo->categoryID = modDetails["category_id"].toInt(); + info->m_FileInfo->modID = modDetails["mod_id"].toInt(); + info->m_FileInfo->modName = modDetails["name"].toString(); + info->m_FileInfo->categoryID = modDetails["category_id"].toInt(); + info->m_FileInfo->author = modDetails["author"].toString(); + info->m_FileInfo->uploader = modDetails["uploaded_by"].toString(); + info->m_FileInfo->uploaderUrl = modDetails["uploaded_users_profile_url"].toString(); QString gameShortName = gameName; QStringList games(m_ManagedGame->validShortNames()); diff --git a/src/downloadmanager.h b/src/downloadmanager.h index 7ff7752d..abf909c8 100644 --- a/src/downloadmanager.h +++ b/src/downloadmanager.h @@ -503,6 +503,8 @@ public slots: void visitOnNexus(int index); + void visitUploaderProfile(int index); + void openFile(int index); void openMetaFile(int index); diff --git a/src/downloadstab.cpp b/src/downloadstab.cpp index 958efbd5..4f988bf0 100644 --- a/src/downloadstab.cpp +++ b/src/downloadstab.cpp @@ -37,6 +37,8 @@ DownloadsTab::DownloadsTab(OrganizerCore& core, Ui::MainWindow* mwui) SLOT(queryInfoMd5(int))); connect(ui.list, SIGNAL(visitOnNexus(int)), m_core.downloadManager(), SLOT(visitOnNexus(int))); + connect(ui.list, SIGNAL(visitUploaderProfile(int)), m_core.downloadManager(), + SLOT(visitUploaderProfile(int))); connect(ui.list, SIGNAL(openFile(int)), m_core.downloadManager(), SLOT(openFile(int))); connect(ui.list, SIGNAL(openMetaFile(int)), m_core.downloadManager(), diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 90c7dec7..ce432196 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -3357,6 +3357,12 @@ void MainWindow::nxmModInfoAvailable(QString gameName, int modID, QVariant userD mod->setNexusCategory(result["category_id"].toInt()); + mod->setAuthor(result["author"].toString()); + + mod->setUploader(result["uploaded_by"].toString()); + + mod->setUploaderUrl(result["uploaded_users_profile_url"].toString()); + if ((mod->endorsedState() != EndorsedState::ENDORSED_NEVER) && (result.contains("endorsement"))) { QVariantMap endorsement = result["endorsement"].toMap(); diff --git a/src/modinfo.h b/src/modinfo.h index bbb1aae3..b73073ed 100644 --- a/src/modinfo.h +++ b/src/modinfo.h @@ -352,6 +352,21 @@ public: // IModInterface implementations / Re-declaration virtual QStringList categories() const override; /** + * @return the author of the mod. + */ + virtual QString author() const = 0; + + /** + * @return the name of the uploader of this mod. + */ + virtual QString uploader() const = 0; + + /** + * @return the URL of the uploader of this mod's profile. + */ + virtual QString uploaderUrl() const = 0; + + /** * @return the tracked state of this mod. */ virtual MOBase::TrackedState trackedState() const override @@ -486,6 +501,21 @@ public: // Mutable operations: */ virtual bool setName(const QString& name) = 0; + /** + * @brief Set the author of the mod. + */ + virtual void setAuthor(const QString& author) = 0; + + /** + * @brief Set the name of the uploader of this mod. + */ + virtual void setUploader(const QString& uploader) = 0; + + /** + * @brief Set the URL of the uploader of this mod's profile. + */ + virtual void setUploaderUrl(const QString& uploaderUrl) = 0; + public: // Methods after this do not come from IModInterface: /** * @return true if this mod is empty, false otherwise. diff --git a/src/modinfobackup.h b/src/modinfobackup.h index 0c3c29d7..620359b9 100644 --- a/src/modinfobackup.h +++ b/src/modinfobackup.h @@ -40,6 +40,12 @@ public: virtual QString getNexusDescription() const override { return QString(); } virtual void setNexusCategory(int) override {} virtual int getNexusCategory() const override { return 0; } + virtual QString author() const override { return QString(); } + virtual void setAuthor(const QString&) override {} + virtual QString uploader() const override { return QString(); } + virtual void setUploader(const QString&) override {} + virtual QString uploaderUrl() const override { return QString(); } + virtual void setUploaderUrl(const QString&) override {} virtual bool isBackup() const override { return true; } virtual void addInstalledFile(int, int) override {} diff --git a/src/modinfoforeign.h b/src/modinfoforeign.h index fa57e378..813725d5 100644 --- a/src/modinfoforeign.h +++ b/src/modinfoforeign.h @@ -67,6 +67,12 @@ public: virtual QDateTime getNexusLastModified() const override { return QDateTime(); } virtual void setNexusLastModified(QDateTime) override {} virtual QString getNexusDescription() const override { return QString(); } + virtual QString author() const override { return QString(); } + virtual void setAuthor(const QString&) override {} + virtual QString uploader() const override { return QString(); } + virtual void setUploader(const QString&) override {} + virtual QString uploaderUrl() const override { return QString(); } + virtual void setUploaderUrl(const QString&) override {} virtual QStringList archives(bool = false) override { return m_Archives; } virtual QStringList stealFiles() const override { diff --git a/src/modinfooverwrite.h b/src/modinfooverwrite.h index 45b5bbdd..dda7d388 100644 --- a/src/modinfooverwrite.h +++ b/src/modinfooverwrite.h @@ -70,6 +70,12 @@ public: virtual QString getNexusDescription() const override { return QString(); } virtual void setNexusCategory(int) override {} virtual int getNexusCategory() const override { return 0; } + virtual QString author() const override { return QString(); } + virtual void setAuthor(const QString&) override {} + virtual QString uploader() const override { return QString(); } + virtual void setUploader(const QString&) override {} + virtual QString uploaderUrl() const override { return QString(); } + virtual void setUploaderUrl(const QString&) override {} virtual QStringList archives(bool checkOnDisk = false) override; virtual void addInstalledFile(int, int) override {} virtual std::set<std::pair<int, int>> installedFiles() const override { return {}; } diff --git a/src/modinforegular.cpp b/src/modinforegular.cpp index b33bbc44..c529c054 100644 --- a/src/modinforegular.cpp +++ b/src/modinforegular.cpp @@ -98,6 +98,9 @@ void ModInfoRegular::readMeta() m_NexusDescription = metaFile.value("nexusDescription", "").toString(); m_NexusFileStatus = metaFile.value("nexusFileStatus", "1").toInt(); m_NexusCategory = metaFile.value("nexusCategory", 0).toInt(); + m_Author = metaFile.value("author", "").toString(); + m_Uploader = metaFile.value("uploader", "").toString(); + m_UploaderUrl = metaFile.value("uploaderUrl", "").toString(); m_Repository = metaFile.value("repository", "Nexus").toString(); m_Converted = metaFile.value("converted", false).toBool(); m_Validated = metaFile.value("validated", false).toBool(); @@ -270,6 +273,9 @@ void ModInfoRegular::saveMeta() metaFile.setValue("lastNexusUpdate", m_LastNexusUpdate.toString(Qt::ISODate)); metaFile.setValue("nexusLastModified", m_NexusLastModified.toString(Qt::ISODate)); metaFile.setValue("nexusCategory", m_NexusCategory); + metaFile.setValue("author", m_Author); + metaFile.setValue("uploader", m_Uploader); + metaFile.setValue("uploaderUrl", m_UploaderUrl); metaFile.setValue("converted", m_Converted); metaFile.setValue("validated", m_Validated); metaFile.setValue("color", m_Color); @@ -855,6 +861,45 @@ void ModInfoRegular::setNexusCategory(int category) saveMeta(); } +QString ModInfoRegular::author() const +{ + return m_Author; +} + +void ModInfoRegular::setAuthor(const QString& author) +{ + m_Author = author; + m_MetaInfoChanged = true; + saveMeta(); + emit modDetailsUpdated(true); +} + +QString ModInfoRegular::uploader() const +{ + return m_Uploader; +} + +void ModInfoRegular::setUploader(const QString& uploader) +{ + m_Uploader = uploader; + m_MetaInfoChanged = true; + saveMeta(); + emit modDetailsUpdated(true); +} + +QString ModInfoRegular::uploaderUrl() const +{ + return m_UploaderUrl; +} + +void ModInfoRegular::setUploaderUrl(const QString& uploaderUrl) +{ + m_UploaderUrl = uploaderUrl; + m_MetaInfoChanged = true; + saveMeta(); + emit modDetailsUpdated(true); +} + void ModInfoRegular::setCustomURL(QString const& url) { m_CustomURL = url; diff --git a/src/modinforegular.h b/src/modinforegular.h index a408d966..062f3dd8 100644 --- a/src/modinforegular.h +++ b/src/modinforegular.h @@ -389,6 +389,36 @@ public: */ virtual void setNexusCategory(int category) override; + /** + * @return the author of the mod. + */ + virtual QString author() const override; + + /** + * @brief Set the author of the mod. + */ + virtual void setAuthor(const QString&) override; + + /** + * @return the name of the uploader of this mod. + */ + virtual QString uploader() const override; + + /** + * @brief Set the name of the uploader of this mod. + */ + virtual void setUploader(const QString&) override; + + /** + * @return the URL of the uploader of this mod's profile. + */ + virtual QString uploaderUrl() const override; + + /** + * @brief Set the URL of the uploader of this mod's profile. + */ + virtual void setUploaderUrl(const QString&) override; + virtual QStringList archives(bool checkOnDisk = false) override; virtual void setColor(QColor color) override; @@ -468,6 +498,9 @@ private: QDateTime m_LastNexusUpdate; QDateTime m_NexusLastModified; int m_NexusCategory; + QString m_Author; + QString m_Uploader; + QString m_UploaderUrl; QColor m_Color; diff --git a/src/modinfoseparator.h b/src/modinfoseparator.h index 67bc3d56..ef966a8f 100644 --- a/src/modinfoseparator.h +++ b/src/modinfoseparator.h @@ -49,6 +49,12 @@ public: virtual void setNexusCategory(int) override {} virtual QDateTime creationTime() const override { return QDateTime(); } virtual QString getNexusDescription() const override { return QString(); } + virtual QString author() const override { return QString(); } + virtual void setAuthor(const QString&) override {} + virtual QString uploader() const override { return QString(); } + virtual void setUploader(const QString&) override {} + virtual QString uploaderUrl() const override { return QString(); } + virtual void setUploaderUrl(const QString&) override {} virtual void addInstalledFile(int /*modId*/, int /*fileId*/) override {} virtual bool isSeparator() const override { return true; } diff --git a/src/modlist.cpp b/src/modlist.cpp index 4ef3afbc..d3552c73 100644 --- a/src/modlist.cpp +++ b/src/modlist.cpp @@ -250,6 +250,10 @@ QVariant ModList::data(const QModelIndex& modelIndex, int role) const return QVariant(); } } + } else if (column == COL_AUTHOR) { + return modInfo->author(); + } else if (column == COL_UPLOADER) { + return modInfo->uploader(); } else if (column == COL_INSTALLTIME) { // display installation time for mods that can be updated if (modInfo->creationTime().isValid()) { @@ -1317,6 +1321,10 @@ QString ModList::getColumnName(int column) return tr("Priority"); case COL_CATEGORY: return tr("Category"); + case COL_AUTHOR: + return tr("Author"); + case COL_UPLOADER: + return tr("Uploader"); case COL_GAME: return tr("Source Game"); case COL_MODID: @@ -1343,6 +1351,10 @@ QString ModList::getColumnToolTip(int column) const "overwrites files from mods with lower priority."); case COL_CATEGORY: return tr("Primary category of the mod."); + case COL_AUTHOR: + return tr("Author(s) of the mod."); + case COL_UPLOADER: + return tr("Uploader of the mod. This is not necessarily the same as the author."); case COL_GAME: return tr("The source game which was the origin of this mod."); case COL_MODID: diff --git a/src/modlist.h b/src/modlist.h index 112070e1..1da74fa8 100644 --- a/src/modlist.h +++ b/src/modlist.h @@ -85,6 +85,8 @@ public: COL_FLAGS, COL_CONTENT, COL_CATEGORY, + COL_AUTHOR, + COL_UPLOADER, COL_MODID, COL_GAME, COL_VERSION, diff --git a/src/modlistcontextmenu.cpp b/src/modlistcontextmenu.cpp index fefb1d73..d2c8e2a1 100644 --- a/src/modlistcontextmenu.cpp +++ b/src/modlistcontextmenu.cpp @@ -443,6 +443,12 @@ void ModListContextMenu::addBackupActions(ModInfo::Ptr mod) }); } + if (!mod->uploaderUrl().isEmpty()) { + addAction(tr("Visit the uploader's profile"), [=]() { + m_actions.visitUploaderProfile(m_selected); + }); + } + const auto url = mod->parseCustomURL(); if (url.isValid()) { addAction(tr("Visit on %1").arg(url.host()), [=]() { @@ -612,6 +618,12 @@ void ModListContextMenu::addRegularActions(ModInfo::Ptr mod) }); } + if (!mod->uploaderUrl().isEmpty()) { + addAction(tr("Visit the uploader's profile"), [=]() { + m_actions.visitUploaderProfile(m_selected); + }); + } + const auto url = mod->parseCustomURL(); if (url.isValid()) { addAction(tr("Visit on %1").arg(url.host()), [=]() { diff --git a/src/modlistsortproxy.cpp b/src/modlistsortproxy.cpp index 3cc7de40..2fb854c4 100644 --- a/src/modlistsortproxy.cpp +++ b/src/modlistsortproxy.cpp @@ -183,6 +183,26 @@ bool ModListSortProxy::lessThan(const QModelIndex& left, const QModelIndex& righ } } } break; + case ModList::COL_AUTHOR: { + if (leftMod->author() != rightMod->author()) { + lt = leftMod->author() < rightMod->author(); + } else { + int comp = QString::compare(leftMod->uploader(), rightMod->uploader(), + Qt::CaseInsensitive); + if (comp != 0) + lt = comp < 0; + } + } break; + case ModList::COL_UPLOADER: { + if (leftMod->uploader() != rightMod->uploader()) { + lt = leftMod->uploader() < rightMod->uploader(); + } else { + int comp = QString::compare(leftMod->uploader(), rightMod->uploader(), + Qt::CaseInsensitive); + if (comp != 0) + lt = comp < 0; + } + } break; case ModList::COL_MODID: { if (leftMod->nexusId() != rightMod->nexusId()) lt = leftMod->nexusId() < rightMod->nexusId(); @@ -447,8 +467,8 @@ bool ModListSortProxy::filterMatchesMod(ModInfo::Ptr info, bool enabled) const segmentGood = true; bool foundKeyword = false; - // check each word in the segment for match, each word needs to be matched but it - // doesn't matter where. + // check each word in the segment for match, each word needs to be matched but + // it doesn't matter where. for (auto& currentKeyword : ANDKeywords) { foundKeyword = false; @@ -458,6 +478,18 @@ bool ModListSortProxy::filterMatchesMod(ModInfo::Ptr info, bool enabled) const foundKeyword = true; } + // Search by author + if (!foundKeyword && m_EnabledColumns[ModList::COL_AUTHOR] && + info->author().contains(currentKeyword, Qt::CaseInsensitive)) { + foundKeyword = true; + } + + // Search by uploader + if (!foundKeyword && m_EnabledColumns[ModList::COL_UPLOADER] && + info->uploader().contains(currentKeyword, Qt::CaseInsensitive)) { + foundKeyword = true; + } + // Search by notes if (!foundKeyword && m_EnabledColumns[ModList::COL_NOTES] && (info->notes().contains(currentKeyword, Qt::CaseInsensitive) || @@ -601,8 +633,8 @@ bool ModListSortProxy::canDropMimeData(const QMimeData* data, Qt::DropAction act // disable drop install with group proxy, except the one for collapsible separator // - it would be nice to be able to "install to category" or something like that but - // it's a bit more complicated since the drop position is based on the category, so - // just disabling for now + // it's a bit more complicated since the drop position is based on the category, + // so just disabling for now if (dropInfo.isDownloadDrop()) { // maybe there is a cleaner way? if (qobject_cast<QtGroupingProxy*>(sourceModel())) { @@ -675,8 +707,8 @@ void ModListSortProxy::aboutToChangeData() void ModListSortProxy::postDataChanged() { // if the filter is re-activated right away the editor can't be deleted but becomes - // invisible or at least the view continues to think it's being edited. As a result no - // new editor can be opened + // invisible or at least the view continues to think it's being edited. As a result + // no new editor can be opened QTimer::singleShot(10, [this]() { setCriteria(m_PreChangeCriteria); m_PreChangeCriteria.clear(); diff --git a/src/modlistview.cpp b/src/modlistview.cpp index 7b3669fd..6091021b 100644 --- a/src/modlistview.cpp +++ b/src/modlistview.cpp @@ -817,6 +817,7 @@ void ModListView::setup(OrganizerCore& core, CategoryFactory& factory, MainWindo // hide these columns by default header()->setSectionHidden(ModList::COL_CONTENT, true); header()->setSectionHidden(ModList::COL_MODID, true); + header()->setSectionHidden(ModList::COL_UPLOADER, true); header()->setSectionHidden(ModList::COL_GAME, true); header()->setSectionHidden(ModList::COL_INSTALLTIME, true); header()->setSectionHidden(ModList::COL_NOTES, true); diff --git a/src/modlistviewactions.cpp b/src/modlistviewactions.cpp index efe48c31..6b26a1e3 100644 --- a/src/modlistviewactions.cpp +++ b/src/modlistviewactions.cpp @@ -378,8 +378,11 @@ void ModListViewActions::exportModListCSV() const QCheckBox* mod_Status = new QCheckBox(tr("Mod_Status")); mod_Status->setChecked(true); QCheckBox* primary_Category = new QCheckBox(tr("Primary_Category")); + QCheckBox* mod_Author = new QCheckBox(tr("Mod_Author")); + QCheckBox* mod_Uploader = new QCheckBox(tr("Mod_Uploader")); QCheckBox* nexus_ID = new QCheckBox(tr("Nexus_ID")); QCheckBox* mod_Nexus_URL = new QCheckBox(tr("Mod_Nexus_URL")); + QCheckBox* mod_Uploader_URL = new QCheckBox(tr("Mod_Uploader_URL")); QCheckBox* mod_Version = new QCheckBox(tr("Mod_Version")); QCheckBox* install_Date = new QCheckBox(tr("Install_Date")); QCheckBox* download_File_Name = new QCheckBox(tr("Download_File_Name")); @@ -390,8 +393,11 @@ void ModListViewActions::exportModListCSV() const vbox1->addWidget(mod_Status); vbox1->addWidget(mod_Note); vbox1->addWidget(primary_Category); + vbox1->addWidget(mod_Author); + vbox1->addWidget(mod_Uploader); vbox1->addWidget(nexus_ID); vbox1->addWidget(mod_Nexus_URL); + vbox1->addWidget(mod_Uploader_URL); vbox1->addWidget(mod_Version); vbox1->addWidget(install_Date); vbox1->addWidget(download_File_Name); @@ -435,12 +441,21 @@ void ModListViewActions::exportModListCSV() const if (primary_Category->isChecked()) fields.push_back( std::make_pair(QString("#Primary_Category"), CSVBuilder::TYPE_STRING)); + if (mod_Author->isChecked()) + fields.push_back( + std::make_pair(QString("#Mod_Author"), CSVBuilder::TYPE_STRING)); + if (mod_Uploader->isChecked()) + fields.push_back( + std::make_pair(QString("#Mod_Uploader"), CSVBuilder::TYPE_STRING)); if (nexus_ID->isChecked()) fields.push_back( std::make_pair(QString("#Nexus_ID"), CSVBuilder::TYPE_INTEGER)); if (mod_Nexus_URL->isChecked()) fields.push_back( std::make_pair(QString("#Mod_Nexus_URL"), CSVBuilder::TYPE_STRING)); + if (mod_Uploader_URL->isChecked()) + fields.push_back( + std::make_pair(QString("#Mod_Uploader_URL"), CSVBuilder::TYPE_STRING)); if (mod_Version->isChecked()) fields.push_back( std::make_pair(QString("#Mod_Version"), CSVBuilder::TYPE_STRING)); @@ -485,6 +500,10 @@ void ModListViewActions::exportModListCSV() const (m_categories.categoryExists(info->primaryCategory())) ? m_categories.getCategoryNameByID(info->primaryCategory()) : ""); + if (mod_Author->isChecked()) + builder.setRowField("#Mod_Author", info->author()); + if (mod_Uploader->isChecked()) + builder.setRowField("#Mod_Uploader", info->uploader()); if (nexus_ID->isChecked()) builder.setRowField("#Nexus_ID", info->nexusId()); if (mod_Nexus_URL->isChecked()) @@ -493,6 +512,8 @@ void ModListViewActions::exportModListCSV() const ? NexusInterface::instance().getModURL( info->nexusId(), info->gameName()) : ""); + if (mod_Uploader_URL->isChecked()) + builder.setRowField("#Mod_Uploader_URL", info->uploaderUrl()); if (mod_Version->isChecked()) builder.setRowField("#Mod_Version", info->version().canonicalString()); if (install_Date->isChecked()) @@ -887,11 +908,7 @@ void ModListViewActions::markConverted(const QModelIndexList& indices) const void ModListViewActions::visitOnNexus(const QModelIndexList& indices) const { if (indices.size() > 10) { - if (QMessageBox::question(m_parent, tr("Opening Nexus Links"), - tr("You are trying to open %1 links to Nexus Mods. Are " - "you sure you want to do this?") - .arg(indices.size()), - QMessageBox::Yes | QMessageBox::No) != QMessageBox::Yes) { + if (!askOpenLinksConfirmation(indices.size(), tr("Nexus Links"))) { return; } } @@ -911,11 +928,7 @@ void ModListViewActions::visitOnNexus(const QModelIndexList& indices) const void ModListViewActions::visitWebPage(const QModelIndexList& indices) const { if (indices.size() > 10) { - if (QMessageBox::question(m_parent, tr("Opening Web Pages"), - tr("You are trying to open %1 Web Pages. Are you sure " - "you want to do this?") - .arg(indices.size()), - QMessageBox::Yes | QMessageBox::No) != QMessageBox::Yes) { + if (!askOpenLinksConfirmation(indices.size(), tr("Web Pages"))) { return; } } @@ -933,11 +946,7 @@ void ModListViewActions::visitWebPage(const QModelIndexList& indices) const void ModListViewActions::visitNexusOrWebPage(const QModelIndexList& indices) const { if (indices.size() > 10) { - if (QMessageBox::question(m_parent, tr("Opening Web Pages"), - tr("You are trying to open %1 Web Pages. Are you sure " - "you want to do this?") - .arg(indices.size()), - QMessageBox::Yes | QMessageBox::No) != QMessageBox::Yes) { + if (!askOpenLinksConfirmation(indices.size(), tr("Web Pages"))) { return; } } @@ -963,6 +972,37 @@ void ModListViewActions::visitNexusOrWebPage(const QModelIndexList& indices) con } } +void ModListViewActions::visitUploaderProfile(const QModelIndexList& indices) const +{ + if (indices.size() > 10) { + if (!askOpenLinksConfirmation(indices.size(), tr("Uploader Profiles"))) { + return; + } + } + + for (auto& idx : indices) { + ModInfo::Ptr info = ModInfo::getByIndex(idx.data(ModList::IndexRole).toInt()); + const auto uploaderUrl = info->uploaderUrl(); + + if (!uploaderUrl.isEmpty()) { + shell::Open(QUrl(uploaderUrl)); + } else { + log::error("mod '{}' has no uploader url", info->name()); + } + } +} + +bool ModListViewActions::askOpenLinksConfirmation(std::size_t numberOfLinks, + const QString& nameOfLinks) const +{ + return QMessageBox::question(m_parent, tr("Opening %1").arg(nameOfLinks), + tr("You are trying to open %1 %2. Are you sure " + "you want to do this?") + .arg(numberOfLinks) + .arg(nameOfLinks), + QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes; +} + void ModListViewActions::reinstallMod(const QModelIndex& index) const { ModInfo::Ptr modInfo = ModInfo::getByIndex(index.data(ModList::IndexRole).toInt()); diff --git a/src/modlistviewactions.h b/src/modlistviewactions.h index ad20e784..fb834a90 100644 --- a/src/modlistviewactions.h +++ b/src/modlistviewactions.h @@ -92,6 +92,7 @@ public: void visitOnNexus(const QModelIndexList& indices) const; void visitWebPage(const QModelIndexList& indices) const; void visitNexusOrWebPage(const QModelIndexList& indices) const; + void visitUploaderProfile(const QModelIndexList& indices) const; void reinstallMod(const QModelIndex& index) const; void createBackup(const QModelIndex& index) const; void restoreHiddenFiles(const QModelIndexList& indices) const; @@ -174,6 +175,12 @@ private: // void checkModsForUpdates(std::multimap<QString, int> const& IDs) const; + // ask the user for confirmation for opening many links at once. + // returns true if the user confirmed, false otherwise. + // + bool askOpenLinksConfirmation(std::size_t numberOfLinks, + const QString& nameOfLinks) const; + private: OrganizerCore& m_core; FilterList& m_filters; diff --git a/src/nexusinterface.cpp b/src/nexusinterface.cpp index ecd33cb6..fa4dd729 100644 --- a/src/nexusinterface.cpp +++ b/src/nexusinterface.cpp @@ -131,6 +131,9 @@ void NexusBridge::nxmFilesAvailable(QString gameName, int modID, QVariant userDa temp.categoryID = fileInfo["category_id"].toInt(); temp.fileID = fileInfo["file_id"].toInt(); temp.fileSize = fileInfo["size"].toInt(); + temp.author = fileInfo["author"].toString(); + temp.uploader = fileInfo["uploaded_by"].toString(); + temp.uploaderUrl = fileInfo["uploaded_users_profile_url"].toString(); fileInfoList.append(&temp); } @@ -575,13 +578,16 @@ void NexusInterface::fakeFiles() QVariantList result; QVariantMap fileMap; - fileMap["uri"] = "fakeURI"; - fileMap["name"] = "fakeName"; - fileMap["description"] = "fakeDescription"; - fileMap["version"] = "1.0.0"; - fileMap["category_id"] = "1"; - fileMap["id"] = "1"; - fileMap["size"] = "512"; + fileMap["uri"] = "fakeURI"; + fileMap["name"] = "fakeName"; + fileMap["description"] = "fakeDescription"; + fileMap["version"] = "1.0.0"; + fileMap["category_id"] = "1"; + fileMap["id"] = "1"; + fileMap["size"] = "512"; + fileMap["author"] = "fakeAuthor"; + fileMap["uploaded_by"] = "fakeUploader"; + fileMap["uploaded_users_profile_url"] = "https://fakeuploader.com"; result.append(fileMap); emit nxmFilesAvailable("fakeGame", 1234, "fake", result, id++); |
