From c4636d891f94f3af6664a82d1f6757a386431fde Mon Sep 17 00:00:00 2001 From: Al12rs Date: Sat, 25 Aug 2018 14:30:27 +0200 Subject: Added ModGroups contents icon and flag. --- src/modlist.cpp | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src/modlist.cpp') diff --git a/src/modlist.cpp b/src/modlist.cpp index afed2241..bcd087bc 100644 --- a/src/modlist.cpp +++ b/src/modlist.cpp @@ -74,6 +74,7 @@ ModList::ModList(PluginContainer *pluginContainer, QObject *parent) m_ContentIcons[ModInfo::CONTENT_TEXTURE] = std::make_tuple(":/MO/gui/content/texture", tr("Textures")); m_ContentIcons[ModInfo::CONTENT_MCM] = std::make_tuple(":/MO/gui/content/menu", tr("MCM Configuration")); m_ContentIcons[ModInfo::CONTENT_INI] = std::make_tuple(":/MO/gui/content/inifile", tr("INI files")); + m_ContentIcons[ModInfo::CONTENT_MODGROUP] = std::make_tuple(":/MO/gui/content/modgroup", tr("ModGroup files")); m_LastCheck.start(); } @@ -1119,6 +1120,8 @@ QString ModList::getColumnToolTip(int column) "SkyProc Patcher" "Mod Configuration Menu" "INI files" + "ModGroup files" + ""); case COL_INSTALLTIME: return tr("Time this mod was installed"); default: return tr("unknown"); -- cgit v1.3.1 From 15ab8d5c5e9b5a06ad61247aa81f4673a42595e6 Mon Sep 17 00:00:00 2001 From: Al12rs Date: Sat, 29 Sep 2018 15:07:24 +0200 Subject: Changed "ignore missing game data" to not create an empty Texture folder and instead save the choice in meta.ini --- src/mainwindow.cpp | 6 ++++-- src/modinfo.h | 5 +++++ src/modinforegular.cpp | 16 +++++++++++++--- src/modinforegular.h | 7 +++++++ src/modlist.cpp | 4 +++- 5 files changed, 32 insertions(+), 6 deletions(-) (limited to 'src/modlist.cpp') diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 04491c3e..9d0c37c0 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -2684,16 +2684,18 @@ void MainWindow::ignoreMissingData_clicked() for (QModelIndex idx : selection->selectedRows()) { int row_idx = idx.data(Qt::UserRole + 1).toInt(); ModInfo::Ptr info = ModInfo::getByIndex(row_idx); - QDir(info->absolutePath()).mkdir("textures"); + //QDir(info->absolutePath()).mkdir("textures"); info->testValid(); + info->markValidated(true); connect(this, SIGNAL(modListDataChanged(QModelIndex, QModelIndex)), m_OrganizerCore.modList(), SIGNAL(dataChanged(QModelIndex, QModelIndex))); emit modListDataChanged(m_OrganizerCore.modList()->index(row_idx, 0), m_OrganizerCore.modList()->index(row_idx, m_OrganizerCore.modList()->columnCount() - 1)); } } else { ModInfo::Ptr info = ModInfo::getByIndex(m_ContextRow); - QDir(info->absolutePath()).mkdir("textures"); + //QDir(info->absolutePath()).mkdir("textures"); info->testValid(); + info->markValidated(true); connect(this, SIGNAL(modListDataChanged(QModelIndex, QModelIndex)), m_OrganizerCore.modList(), SIGNAL(dataChanged(QModelIndex, QModelIndex))); emit modListDataChanged(m_OrganizerCore.modList()->index(m_ContextRow, 0), m_OrganizerCore.modList()->index(m_ContextRow, m_OrganizerCore.modList()->columnCount() - 1)); diff --git a/src/modinfo.h b/src/modinfo.h index 919d1a5b..895105df 100644 --- a/src/modinfo.h +++ b/src/modinfo.h @@ -577,6 +577,11 @@ public: */ virtual void markConverted(bool converted) {} + /** + * @brief updates the mod to flag it as valid in order to ignore the invalid game data flag + */ + virtual void markValidated(bool validated) {} + /** * @brief reads meta information from disk */ diff --git a/src/modinforegular.cpp b/src/modinforegular.cpp index 1e77e050..1d84e2c8 100644 --- a/src/modinforegular.cpp +++ b/src/modinforegular.cpp @@ -31,6 +31,7 @@ ModInfoRegular::ModInfoRegular(PluginContainer *pluginContainer, const IPluginGa , m_GameName(game->gameShortName()) , m_IsAlternate(false) , m_Converted(false) + , m_Validated(false) , m_MetaInfoChanged(false) , m_EndorsedState(ENDORSED_UNKNOWN) , m_NexusBridge(pluginContainer) @@ -86,6 +87,7 @@ void ModInfoRegular::readMeta() m_NexusDescription = metaFile.value("nexusDescription", "").toString(); m_Repository = metaFile.value("repository", "Nexus").toString(); m_Converted = metaFile.value("converted", false).toBool(); + m_Validated = metaFile.value("validated", false).toBool(); m_URL = metaFile.value("url", "").toString(); m_LastNexusQuery = QDateTime::fromString(metaFile.value("lastNexusQuery", "").toString(), Qt::ISODate); if (metaFile.contains("endorsed")) { @@ -150,6 +152,7 @@ void ModInfoRegular::saveMeta() metaFile.setValue("url", m_URL); metaFile.setValue("lastNexusQuery", m_LastNexusQuery.toString(Qt::ISODate)); metaFile.setValue("converted", m_Converted); + metaFile.setValue("validated", m_Validated); if (m_EndorsedState != ENDORSED_UNKNOWN) { metaFile.setValue("endorsed", m_EndorsedState); } @@ -415,6 +418,13 @@ void ModInfoRegular::markConverted(bool converted) emit modDetailsUpdated(true); } +void ModInfoRegular::markValidated(bool validated) +{ + m_Validated = validated; + m_MetaInfoChanged = true; + saveMeta(); + emit modDetailsUpdated(true); +} QString ModInfoRegular::absolutePath() const { @@ -438,7 +448,7 @@ std::vector ModInfoRegular::getFlags() const if ((m_NexusID > 0) && (endorsedState() == ENDORSED_FALSE)) { result.push_back(ModInfo::FLAG_NOTENDORSED); } - if (!isValid()) { + if (!isValid() && !m_Validated) { result.push_back(ModInfo::FLAG_INVALID); } if (m_Notes.length() != 0) { @@ -514,7 +524,7 @@ std::vector ModInfoRegular::getContents() const int ModInfoRegular::getHighlight() const { - if (!isValid()) + if (!isValid() && !m_Validated) return HIGHLIGHT_INVALID; auto flags = getFlags(); if (std::find(flags.begin(), flags.end(), ModInfo::FLAG_PLUGIN_SELECTED) != flags.end()) @@ -525,7 +535,7 @@ int ModInfoRegular::getHighlight() const QString ModInfoRegular::getDescription() const { - if (!isValid()) { + if (!isValid() && !m_Validated) { return tr("%1 contains no esp/esm/esl and no asset (textures, meshes, interface, ...) directory").arg(name()); } else { const std::set &categories = getCategories(); diff --git a/src/modinforegular.h b/src/modinforegular.h index 3abaded4..2f3eb941 100644 --- a/src/modinforegular.h +++ b/src/modinforegular.h @@ -28,6 +28,7 @@ public: bool isAlternate() { return m_IsAlternate; } bool isConverted() { return m_Converted; } + bool isValidated() { return m_Validated; } /** * @brief test if there is a newer version of the mod @@ -188,6 +189,11 @@ public: */ virtual void markConverted(bool converted) override; + /** + * @brief updates the mod to flag it as valid in order to ignore the invalid game data flag + */ + virtual void markValidated(bool validated) override; + /** * @brief getter for the mod name * @@ -358,6 +364,7 @@ private: bool m_MetaInfoChanged; bool m_IsAlternate; bool m_Converted; + bool m_Validated; MOBase::VersionInfo m_NewestVersion; MOBase::VersionInfo m_IgnoredVersion; diff --git a/src/modlist.cpp b/src/modlist.cpp index bcd087bc..c7f6a53b 100644 --- a/src/modlist.cpp +++ b/src/modlist.cpp @@ -768,6 +768,8 @@ IModList::ModStates ModList::state(unsigned int modIndex) const QSharedPointer modInfoRegular = modInfo.staticCast(); if (modInfoRegular->isAlternate() && !modInfoRegular->isConverted()) result |= IModList::STATE_ALTERNATE; + if (!modInfo->isValid() && modInfoRegular->isValidated()) + result |= IModList::STATE_VALID; } if (modInfo->canBeEnabled()) { if (m_Profile->modEnabled(modIndex)) { @@ -1263,4 +1265,4 @@ void ModList::disableSelected(const QItemSelectionModel *selectionModel) } } } -} \ No newline at end of file +} -- cgit v1.3.1 From 42d2344f0b81cb1cf8dbe83e8f480b84ed0c3114 Mon Sep 17 00:00:00 2001 From: Al12rs Date: Sun, 28 Oct 2018 02:16:20 +0200 Subject: Added modlist Separators feature: *New modType separator. *Bold, italic and centralized name without _separator at the end. *Added "create separator" option to context menu. *Added "rename separator" option. *Fixed rename separator issue with priority resetting. --- src/mainwindow.cpp | 42 +++++++++++++++++++++++--- src/mainwindow.h | 1 + src/modinfo.cpp | 8 +++-- src/modinfo.h | 3 +- src/modinfodialog.cpp | 17 ++++++++++- src/modinfoseparator.cpp | 36 ++++++++++++++++++++++ src/modinfoseparator.h | 77 ++++++++++++++++++++++++++++++++++++++++++++++++ src/modlist.cpp | 29 ++++++++++++++++-- 8 files changed, 202 insertions(+), 11 deletions(-) create mode 100644 src/modinfoseparator.cpp create mode 100644 src/modinfoseparator.h (limited to 'src/modlist.cpp') diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 04bd96c7..bc25ab70 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -2629,8 +2629,9 @@ void MainWindow::modOpenNext(int tab) ModInfo::Ptr mod = ModInfo::getByIndex(m_ContextRow); std::vector flags = mod->getFlags(); if ((std::find(flags.begin(), flags.end(), ModInfo::FLAG_OVERWRITE) != flags.end()) || - (std::find(flags.begin(), flags.end(), ModInfo::FLAG_BACKUP) != flags.end())) { - // skip overwrite and backups + (std::find(flags.begin(), flags.end(), ModInfo::FLAG_BACKUP) != flags.end()) || + (std::find(flags.begin(), flags.end(), ModInfo::FLAG_SEPARATOR) != flags.end())) { + // skip overwrite and backups and separators modOpenNext(tab); } else { displayModInformation(m_ContextRow,tab); @@ -2649,8 +2650,9 @@ void MainWindow::modOpenPrev(int tab) ModInfo::Ptr mod = ModInfo::getByIndex(m_ContextRow); std::vector flags = mod->getFlags(); if ((std::find(flags.begin(), flags.end(), ModInfo::FLAG_OVERWRITE) != flags.end()) || - (std::find(flags.begin(), flags.end(), ModInfo::FLAG_BACKUP) != flags.end())) { - // skip overwrite and backups + (std::find(flags.begin(), flags.end(), ModInfo::FLAG_BACKUP) != flags.end()) || + (std::find(flags.begin(), flags.end(), ModInfo::FLAG_SEPARATOR) != flags.end())) { + // skip overwrite and backups and separators modOpenPrev(tab); } else { displayModInformation(m_ContextRow,tab); @@ -2839,6 +2841,33 @@ void MainWindow::createEmptyMod_clicked() m_OrganizerCore.refreshModList(); } +void MainWindow::createSeparator_clicked() +{ + GuessedValue name; + name.setFilter(&fixDirectoryName); + while (name->isEmpty()) + { + bool ok; + name.update(QInputDialog::getText(this, tr("Create Separator..."), + tr("This will create a new separator.\n" + "Please enter a name:"), QLineEdit::Normal, "", &ok), + GUESS_USER); + if (!ok) { return; } + } + if (m_OrganizerCore.getMod(name) != nullptr) + { + reportError(tr("A separator with this name already exists")); + return; + } + name->append("_separator"); + if (m_OrganizerCore.getMod(name) != nullptr) + { + return; + } + if (m_OrganizerCore.createMod(name) == nullptr) { return; } + m_OrganizerCore.refreshModList(); +} + void MainWindow::createModFromOverwrite() { GuessedValue name; @@ -3579,6 +3608,8 @@ QMenu *MainWindow::modListContextMenu() menu->addAction(tr("Create empty mod"), this, SLOT(createEmptyMod_clicked())); + menu->addAction(tr("Create separator"), this, SLOT(createSeparator_clicked())); + menu->addSeparator(); menu->addAction(tr("Enable all visible"), this, SLOT(enableVisibleMods())); @@ -3623,6 +3654,9 @@ void MainWindow::on_modList_customContextMenuRequested(const QPoint &pos) } 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())); + } else if (std::find(flags.begin(), flags.end(), ModInfo::FLAG_SEPARATOR) != flags.end()){ + menu->addAction(tr("Rename Separator..."), this, SLOT(renameMod_clicked())); + menu->addAction(tr("Remove Separator..."), this, SLOT(removeMod_clicked())); } else if (std::find(flags.begin(), flags.end(), ModInfo::FLAG_FOREIGN) != flags.end()) { // nop, nothing to do with this mod } else { diff --git a/src/mainwindow.h b/src/mainwindow.h index 0bf3d3c8..78d374e6 100644 --- a/src/mainwindow.h +++ b/src/mainwindow.h @@ -404,6 +404,7 @@ private slots: // modlist context menu void installMod_clicked(); void createEmptyMod_clicked(); + void createSeparator_clicked(); void restoreBackup_clicked(); void renameMod_clicked(); void removeMod_clicked(); diff --git a/src/modinfo.cpp b/src/modinfo.cpp index 8ce40da3..4c41a114 100644 --- a/src/modinfo.cpp +++ b/src/modinfo.cpp @@ -23,6 +23,7 @@ along with Mod Organizer. If not, see . #include "modinforegular.h" #include "modinfoforeign.h" #include "modinfooverwrite.h" +#include "modinfoseparator.h" #include "installationtester.h" #include "categories.h" @@ -64,11 +65,14 @@ bool ModInfo::ByName(const ModInfo::Ptr &LHS, const ModInfo::Ptr &RHS) ModInfo::Ptr ModInfo::createFrom(PluginContainer *pluginContainer, const MOBase::IPluginGame *game, const QDir &dir, DirectoryEntry **directoryStructure) { QMutexLocker locker(&s_Mutex); -// int id = s_NextID++; + // int id = s_NextID++; static QRegExp backupExp(".*backup[0-9]*"); + static QRegExp separatorExp(".*_separator"); ModInfo::Ptr result; if (backupExp.exactMatch(dir.dirName())) { result = ModInfo::Ptr(new ModInfoBackup(pluginContainer, game, dir, directoryStructure)); + } else if(separatorExp.exactMatch(dir.dirName())){ + result = Ptr(new ModInfoSeparator(pluginContainer, game, dir, directoryStructure)); } else { result = ModInfo::Ptr(new ModInfoRegular(pluginContainer, game, dir, directoryStructure)); } @@ -418,4 +422,4 @@ void ModInfo::testValid() while (dirIter.hasNext()) { dirIter.next(); } -} \ No newline at end of file +} diff --git a/src/modinfo.h b/src/modinfo.h index 895105df..9f6c2fbc 100644 --- a/src/modinfo.h +++ b/src/modinfo.h @@ -62,6 +62,7 @@ public: enum EFlag { FLAG_INVALID, FLAG_BACKUP, + FLAG_SEPARATOR, FLAG_OVERWRITE, FLAG_FOREIGN, FLAG_NOTENDORSED, @@ -560,7 +561,7 @@ public: /** * @return true if this mod is considered "valid", that is: it contains data used by the game **/ - bool isValid() const { return m_Valid; } + virtual bool isValid() const { return m_Valid; } /** * @return true if the file has been endorsed on nexus diff --git a/src/modinfodialog.cpp b/src/modinfodialog.cpp index fedddd6c..54910e41 100644 --- a/src/modinfodialog.cpp +++ b/src/modinfodialog.cpp @@ -134,7 +134,22 @@ ModInfoDialog::ModInfoDialog(ModInfo::Ptr modInfo, const DirectoryEntry *directo refreshLists(); - if (unmanaged) { + if (modInfo->hasFlag(ModInfo::FLAG_SEPARATOR)) + { + ui->tabWidget->setTabEnabled(TAB_TEXTFILES, false); + ui->tabWidget->setTabEnabled(TAB_INIFILES, false); + ui->tabWidget->setTabEnabled(TAB_IMAGES, false); + ui->tabWidget->setTabEnabled(TAB_ESPS, false); + ui->tabWidget->setTabEnabled(TAB_CONFLICTS, false); + //ui->tabWidget->setTabEnabled(TAB_CATEGORIES, false); + addCategories(CategoryFactory::instance(), modInfo->getCategories(), ui->categoriesTree->invisibleRootItem(), 0); + refreshPrimaryCategoriesBox(); + ui->tabWidget->setTabEnabled(TAB_NEXUS, false); + //ui->tabWidget->setTabEnabled(TAB_NOTES, false); + ui->tabWidget->setTabEnabled(TAB_FILETREE, false); + } + else if (unmanaged) + { ui->tabWidget->setTabEnabled(TAB_INIFILES, false); ui->tabWidget->setTabEnabled(TAB_CATEGORIES, false); ui->tabWidget->setTabEnabled(TAB_NEXUS, false); diff --git a/src/modinfoseparator.cpp b/src/modinfoseparator.cpp new file mode 100644 index 00000000..60014f66 --- /dev/null +++ b/src/modinfoseparator.cpp @@ -0,0 +1,36 @@ +#include "modinfoseparator.h" + +bool ModInfoSeparator::setName(const QString& name) +{ + return ModInfoRegular::setName(name); +} + +std::vector ModInfoSeparator::getFlags() const +{ + { + auto result = ModInfoRegular::getFlags(); + result.insert(result.begin(), FLAG_SEPARATOR); + return result; + } +} + +int ModInfoSeparator::getHighlight() const +{ + return HIGHLIGHT_CENTER; +} + +QString ModInfoSeparator::getDescription() const +{ + return tr("This is a Separator"); +} + +QString ModInfoSeparator::name() const +{ + return ModInfoRegular::name(); +} + + +ModInfoSeparator::ModInfoSeparator(PluginContainer *pluginContainer, const MOBase::IPluginGame *game, const QDir &path, MOShared::DirectoryEntry **directoryStructure) + : ModInfoRegular(pluginContainer, game, path, directoryStructure) +{ +} diff --git a/src/modinfoseparator.h b/src/modinfoseparator.h new file mode 100644 index 00000000..f215fb17 --- /dev/null +++ b/src/modinfoseparator.h @@ -0,0 +1,77 @@ +#ifndef MODINFOSEPARATOR_H +#define MODINFOSEPARATOR_H + +#include "modinforegular.h" + +class ModInfoSeparator: + public ModInfoRegular +{ + friend class ModInfo; + +public: + + virtual bool updateAvailable() const { return false; } + virtual bool updateIgnored() const { return false; } + virtual bool downgradeAvailable() const { return false; } + virtual bool updateNXMInfo() { return false; } + virtual bool isValid() const { return true; } + //TODO: Fix renaming method to avoid priority reset + virtual bool setName(const QString& name); + + virtual int getNexusID() const { return -1; } + + virtual void setGameName(QString /*gameName*/) + { + } + + virtual void setNexusID(int /*modID*/) + { + } + + virtual void endorse(bool /*doEndorse*/) + { + } + + virtual void ignoreUpdate(bool /*ignore*/) + { + } + + virtual bool canBeUpdated() const { return false; } + virtual bool canBeEnabled() const { return false; } + virtual std::vector getIniTweaks() const { return std::vector(); } + + virtual std::vector getFlags() const; + virtual int getHighlight() const; + + virtual QString getDescription() const; + virtual QString name() const; + virtual QString getGameName() const { return ""; } + virtual QString getInstallationFile() const { return ""; } + virtual QString getURL() const { return ""; } + virtual QString repository() const { return ""; } + + virtual QDateTime getLastNexusQuery() const { return QDateTime(); } + virtual QDateTime creationTime() const { return QDateTime(); } + + virtual void getNexusFiles + ( + QList::const_iterator& /*unused*/, + QList::const_iterator& /*unused*/) + { + } + + virtual QString getNexusDescription() const { return QString(); } + + virtual void addInstalledFile(int /*modId*/, int /*fileId*/) + { + } + +private: + + ModInfoSeparator + ( + PluginContainer* pluginContainer, const MOBase::IPluginGame* game, const QDir& path, + MOShared::DirectoryEntry** directoryStructure); +}; + +#endif diff --git a/src/modlist.cpp b/src/modlist.cpp index c7f6a53b..31ef9ddc 100644 --- a/src/modlist.cpp +++ b/src/modlist.cpp @@ -45,6 +45,7 @@ along with Mod Organizer. If not, see . #include #include #include +#include #include #include @@ -145,6 +146,7 @@ QString ModList::getFlagText(ModInfo::EFlag flag, ModInfo::Ptr modInfo) const { switch (flag) { case ModInfo::FLAG_BACKUP: return tr("Backup"); + case ModInfo::FLAG_SEPARATOR: return tr("Separator"); case ModInfo::FLAG_INVALID: return tr("No valid game data"); case ModInfo::FLAG_NOTENDORSED: return tr("Not endorsed yet"); case ModInfo::FLAG_NOTES: return QString("%1").arg(modInfo->notes().replace("\n", "
")); @@ -203,7 +205,13 @@ QVariant ModList::data(const QModelIndex &modelIndex, int role) const || (column == COL_CONTENT)) { return QVariant(); } else if (column == COL_NAME) { - return modInfo->name(); + auto flags = modInfo->getFlags(); + if (std::find(flags.begin(), flags.end(), ModInfo::FLAG_SEPARATOR) != flags.end()) + { + return modInfo->name().replace("_separator", ""); + } + else + return modInfo->name(); } else if (column == COL_VERSION) { VersionInfo verInfo = modInfo->getVersion(); QString version = verInfo.displayString(); @@ -277,6 +285,7 @@ QVariant ModList::data(const QModelIndex &modelIndex, int role) const return QVariant(); } } else if (role == Qt::TextAlignmentRole) { + auto flags = modInfo->getFlags(); if (column == COL_NAME) { if (modInfo->getHighlight() & ModInfo::HIGHLIGHT_CENTER) { return QVariant(Qt::AlignCenter | Qt::AlignVCenter); @@ -327,8 +336,15 @@ QVariant ModList::data(const QModelIndex &modelIndex, int role) const return modInfo->getGameName(); } else if (role == Qt::FontRole) { QFont result; + auto flags = modInfo->getFlags(); if (column == COL_NAME) { - if (modInfo->getHighlight() & ModInfo::HIGHLIGHT_INVALID) { + if (std::find(flags.begin(), flags.end(), ModInfo::FLAG_SEPARATOR) != flags.end()) + { + //result.setCapitalization(QFont::AllUppercase); + result.setItalic(true); + //result.setUnderline(true); + result.setBold(true); + } else if (modInfo->getHighlight() & ModInfo::HIGHLIGHT_INVALID) { result.setItalic(true); } } else if ((column == COL_CATEGORY) && (modInfo->hasFlag(ModInfo::FLAG_FOREIGN))) { @@ -476,6 +492,7 @@ bool ModList::setData(const QModelIndex &index, const QVariant &value, int role) ModInfo::Ptr info = ModInfo::getByIndex(modID); IModList::ModStates oldState = state(modID); + bool result = false; emit aboutToChangeData(); @@ -493,7 +510,13 @@ bool ModList::setData(const QModelIndex &index, const QVariant &value, int role) } else if (role == Qt::EditRole) { switch (index.column()) { case COL_NAME: { - result = renameMod(modID, value.toString()); + auto flags = info->getFlags(); + if (std::find(flags.begin(), flags.end(), ModInfo::FLAG_SEPARATOR) != flags.end()) + { + result = renameMod(modID, value.toString() + "_separator"); + } + else + result = renameMod(modID, value.toString()); } break; case COL_PRIORITY: { bool ok = false; -- cgit v1.3.1 From dce6507dad1ff7d76a5c0497d516c79bacd08477 Mon Sep 17 00:00:00 2001 From: Al12rs Date: Sun, 28 Oct 2018 15:04:50 +0100 Subject: Added Color costumization for Separators. --- src/mainwindow.cpp | 28 +++++++++++++++++++++++++++- src/mainwindow.h | 1 + src/modinfo.h | 11 +++++++++++ src/modinforegular.cpp | 13 +++++++++++++ src/modinforegular.h | 7 +++++++ src/modlist.cpp | 6 +++++- 6 files changed, 64 insertions(+), 2 deletions(-) (limited to 'src/modlist.cpp') diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index bc25ab70..438ba037 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -154,6 +154,8 @@ along with Mod Organizer. If not, see . #include #include #include +#include +#include #include #include @@ -2868,6 +2870,26 @@ void MainWindow::createSeparator_clicked() m_OrganizerCore.refreshModList(); } +void MainWindow::setColor_clicked() +{ + ModInfo::Ptr modInfo = ModInfo::getByIndex(m_ContextRow); + QColor color = QColorDialog::getColor(modInfo->getColor(),this); + QItemSelectionModel *selection = ui->modList->selectionModel(); + if (selection->hasSelection() && selection->selectedRows().count() > 1) { + for (QModelIndex idx : selection->selectedRows()) { + ModInfo::Ptr info = ModInfo::getByIndex(idx.data(Qt::UserRole + 1).toInt()); + auto flags = info->getFlags(); + if (std::find(flags.begin(), flags.end(), ModInfo::FLAG_SEPARATOR) != flags.end()) + { + info->setColor(color); + } + } + } + else { + modInfo->setColor(color); + } +} + void MainWindow::createModFromOverwrite() { GuessedValue name; @@ -3608,7 +3630,7 @@ QMenu *MainWindow::modListContextMenu() menu->addAction(tr("Create empty mod"), this, SLOT(createEmptyMod_clicked())); - menu->addAction(tr("Create separator"), this, SLOT(createSeparator_clicked())); + menu->addAction(tr("Create Separator"), this, SLOT(createSeparator_clicked())); menu->addSeparator(); @@ -3655,8 +3677,12 @@ void MainWindow::on_modList_customContextMenuRequested(const QPoint &pos) menu->addAction(tr("Restore Backup"), this, SLOT(restoreBackup_clicked())); menu->addAction(tr("Remove Backup..."), this, SLOT(removeMod_clicked())); } else if (std::find(flags.begin(), flags.end(), ModInfo::FLAG_SEPARATOR) != flags.end()){ + menu->addSeparator(); menu->addAction(tr("Rename Separator..."), this, SLOT(renameMod_clicked())); menu->addAction(tr("Remove Separator..."), this, SLOT(removeMod_clicked())); + menu->addSeparator(); + menu->addAction(tr("Select Color..."), this, SLOT(setColor_clicked())); + menu->addSeparator(); } else if (std::find(flags.begin(), flags.end(), ModInfo::FLAG_FOREIGN) != flags.end()) { // nop, nothing to do with this mod } else { diff --git a/src/mainwindow.h b/src/mainwindow.h index 78d374e6..02e368d7 100644 --- a/src/mainwindow.h +++ b/src/mainwindow.h @@ -408,6 +408,7 @@ private slots: void restoreBackup_clicked(); void renameMod_clicked(); void removeMod_clicked(); + void setColor_clicked(); void backupMod_clicked(); void reinstallMod_clicked(); void endorse_clicked(); diff --git a/src/modinfo.h b/src/modinfo.h index 9f6c2fbc..235fb50c 100644 --- a/src/modinfo.h +++ b/src/modinfo.h @@ -31,6 +31,7 @@ class QDir; #include #include #include +#include #include @@ -524,6 +525,16 @@ public: */ virtual QStringList archives() const = 0; + /* + *@return the color choosen by the user for the mod/separator + */ + virtual QColor getColor() { return QColor(); } + + /* + *@return true if the color has been set successfully. + */ + virtual void setColor(QColor color) { } + /** * @brief adds the information that a file has been installed into this mod * @param modId id of the mod installed diff --git a/src/modinforegular.cpp b/src/modinforegular.cpp index 1d84e2c8..d0f56a52 100644 --- a/src/modinforegular.cpp +++ b/src/modinforegular.cpp @@ -90,6 +90,7 @@ void ModInfoRegular::readMeta() m_Validated = metaFile.value("validated", false).toBool(); m_URL = metaFile.value("url", "").toString(); m_LastNexusQuery = QDateTime::fromString(metaFile.value("lastNexusQuery", "").toString(), Qt::ISODate); + m_Color = metaFile.value("color",QColor()).value(); if (metaFile.contains("endorsed")) { if (metaFile.value("endorsed").canConvert()) { switch (metaFile.value("endorsed").toInt()) { @@ -153,6 +154,7 @@ void ModInfoRegular::saveMeta() metaFile.setValue("lastNexusQuery", m_LastNexusQuery.toString(Qt::ISODate)); metaFile.setValue("converted", m_Converted); metaFile.setValue("validated", m_Validated); + metaFile.setValue("color", m_Color); if (m_EndorsedState != ENDORSED_UNKNOWN) { metaFile.setValue("endorsed", m_EndorsedState); } @@ -397,6 +399,17 @@ void ModInfoRegular::setNeverEndorse() } +void ModInfoRegular::setColor(QColor color) +{ + m_Color = color; + m_MetaInfoChanged = true; +} + +QColor ModInfoRegular::getColor() +{ + return m_Color; +} + bool ModInfoRegular::remove() { m_MetaInfoChanged = false; diff --git a/src/modinforegular.h b/src/modinforegular.h index 2f3eb941..78a6e58a 100644 --- a/src/modinforegular.h +++ b/src/modinforegular.h @@ -311,6 +311,10 @@ public: virtual QStringList archives() const; + virtual void setColor(QColor color); + + virtual QColor getColor(); + virtual void addInstalledFile(int modId, int fileId); /** @@ -355,9 +359,12 @@ private: QString m_URL; QString m_GameName; + QDateTime m_CreationTime; QDateTime m_LastNexusQuery; + QColor m_Color; + int m_NexusID; std::set> m_InstalledFileIDs; diff --git a/src/modlist.cpp b/src/modlist.cpp index 31ef9ddc..6caafeb2 100644 --- a/src/modlist.cpp +++ b/src/modlist.cpp @@ -383,12 +383,16 @@ QVariant ModList::data(const QModelIndex &modelIndex, int role) const return QVariant(); } else if ((role == Qt::BackgroundRole) || (role == ViewMarkingScrollBar::DEFAULT_ROLE)) { + auto flags = modInfo->getFlags(); if (modInfo->getHighlight() & ModInfo::HIGHLIGHT_PLUGIN) { return QColor(0, 0, 255, 64); } else if (m_Overwrite.find(modIndex) != m_Overwrite.end()) { return QColor(0, 255, 0, 64); - } else if (m_Overwritten.find(modIndex) != m_Overwritten.end()) { + } + else if (m_Overwritten.find(modIndex) != m_Overwritten.end()) { return QColor(255, 0, 0, 64); + } else if (std::find(flags.begin(), flags.end(), ModInfo::FLAG_SEPARATOR) != flags.end() && modInfo->getColor().isValid()) { + return modInfo->getColor(); } else { return QVariant(); } -- cgit v1.3.1 From 122744454c9befc06b582a8f0feb03bfbb85aa71 Mon Sep 17 00:00:00 2001 From: LostDragonist Date: Wed, 31 Oct 2018 20:00:20 -0500 Subject: Improve changing mod and plugin priorities --- src/modlist.cpp | 44 +++++++++++++++++++++++-------- src/organizercore.cpp | 6 +++-- src/pluginlist.cpp | 32 ++++++++++++++++++----- src/profile.cpp | 71 ++++++++++++++++++++++++--------------------------- src/profile.h | 6 +++-- 5 files changed, 100 insertions(+), 59 deletions(-) (limited to 'src/modlist.cpp') diff --git a/src/modlist.cpp b/src/modlist.cpp index 6caafeb2..7b57eeda 100644 --- a/src/modlist.cpp +++ b/src/modlist.cpp @@ -654,26 +654,48 @@ void ModList::changeModPriority(std::vector sourceIndices, int newPriority) emit layoutAboutToBeChanged(); Profile *profile = m_Profile; - // sort rows to insert by their old priority (ascending) and insert them move them in that order + + // sort the moving mods by ascending priorities std::sort(sourceIndices.begin(), sourceIndices.end(), - [profile](const int &LHS, const int &RHS) { - return profile->getModPriority(LHS) < profile->getModPriority(RHS); - }); + [profile](const int &LHS, const int &RHS) { + return profile->getModPriority(LHS) > profile->getModPriority(RHS); + }); - // odd stuff: if any of the dragged sources has priority lower than the destination then the - // target idx is that of the row BELOW the dropped location, otherwise it's the one above. why? + // move mods that are decreasing in priority for (std::vector::const_iterator iter = sourceIndices.begin(); iter != sourceIndices.end(); ++iter) { - if (profile->getModPriority(*iter) < newPriority) { + int oldPriority = profile->getModPriority(*iter); + if (oldPriority > newPriority) { + profile->setModPriority(*iter, newPriority); + m_ModMoved(ModInfo::getByIndex(*iter)->name(), oldPriority, newPriority); + } + } + + // sort the moving mods by descending priorities + std::sort(sourceIndices.begin(), sourceIndices.end(), + [profile](const int &LHS, const int &RHS) { + return profile->getModPriority(LHS) < profile->getModPriority(RHS); + }); + + // if at least one mod is increasing in priority, the target index is + // that of the row BELOW the dropped location, otherwise it's the one above + for (std::vector::const_iterator iter = sourceIndices.begin(); + iter != sourceIndices.end(); ++iter) { + int oldPriority = profile->getModPriority(*iter); + if (oldPriority < newPriority) { --newPriority; break; } } + + // move mods that are increasing in priority for (std::vector::const_iterator iter = sourceIndices.begin(); - iter != sourceIndices.end(); ++iter) { - int oldPriority = m_Profile->getModPriority(*iter); - m_Profile->setModPriority(*iter, newPriority); - m_ModMoved(ModInfo::getByIndex(*iter)->name(), oldPriority, newPriority); + iter != sourceIndices.end(); ++iter) { + int oldPriority = profile->getModPriority(*iter); + if (oldPriority < newPriority) { + profile->setModPriority(*iter, newPriority); + m_ModMoved(ModInfo::getByIndex(*iter)->name(), oldPriority, newPriority); + } } emit layoutChanged(); diff --git a/src/organizercore.cpp b/src/organizercore.cpp index 5c85e323..1fafd4c1 100644 --- a/src/organizercore.cpp +++ b/src/organizercore.cpp @@ -1183,7 +1183,9 @@ ModList *OrganizerCore::modList() QStringList OrganizerCore::modsSortedByProfilePriority() const { QStringList res; - for (unsigned int i = 0; i < currentProfile()->numRegularMods(); ++i) { + for (int i = currentProfile()->getPriorityMinimum(); + i < currentProfile()->getPriorityMinimum() + currentProfile()->numRegularMods(); + ++i) { int modIndex = currentProfile()->modIndexByPriority(i); res.push_back(ModInfo::getByIndex(modIndex)->name()); } @@ -2304,4 +2306,4 @@ std::vector OrganizerCore::fileMapping( result.insert(result.end(), subRes.begin(), subRes.end()); } return result; -} \ No newline at end of file +} diff --git a/src/pluginlist.cpp b/src/pluginlist.cpp index 4097ba98..8f714afd 100644 --- a/src/pluginlist.cpp +++ b/src/pluginlist.cpp @@ -1183,17 +1183,35 @@ void PluginList::setPluginPriority(int row, int &newPriority) void PluginList::changePluginPriority(std::vector rows, int newPriority) { ChangeBracket layoutChange(this); - // sort rows to insert by their old priority (ascending) and insert them move them in that order const std::vector &esp = m_ESPs; + + int minPriority = INT_MAX; + int maxPriority = INT_MIN; + + // don't try to move plugins before force-enabled plugins + for (std::vector::const_iterator iter = m_ESPs.begin(); + iter != m_ESPs.end(); ++iter) { + if (iter->m_ForceEnabled) { + newPriority = std::max(newPriority, iter->m_Priority+1); + } + maxPriority = std::max(maxPriority, iter->m_Priority+1); + minPriority = std::min(minPriority, iter->m_Priority); + } + + // limit the new priority to existing priorities + newPriority = std::min(newPriority, maxPriority); + newPriority = std::max(newPriority, minPriority); + + // sort the moving plugins by ascending priorities std::sort(rows.begin(), rows.end(), - [&esp](const int &LHS, const int &RHS) { - return esp[LHS].m_Priority < esp[RHS].m_Priority; - }); + [&esp](const int &LHS, const int &RHS) { + return esp[LHS].m_Priority < esp[RHS].m_Priority; + }); - // odd stuff: if any of the dragged sources has priority lower than the destination then the - // target idx is that of the row BELOW the dropped location, otherwise it's the one above. why? + // if at least on plugin is increasing in priority, the target index is + // that of the row BELOW the dropped location, otherwise it's the one above for (std::vector::const_iterator iter = rows.begin(); - iter != rows.end(); ++iter) { + iter != rows.end(); ++iter) { if (m_ESPs[*iter].m_Priority < newPriority) { --newPriority; break; diff --git a/src/profile.cpp b/src/profile.cpp index 7f10bd02..00818d0b 100644 --- a/src/profile.cpp +++ b/src/profile.cpp @@ -184,9 +184,10 @@ void Profile::doWriteModlist() return; } - for (int i = static_cast(m_ModStatus.size()) - 1; i >= 0; --i) { + for (std::map::const_reverse_iterator iter = m_ModIndexByPriority.crbegin(); iter != m_ModIndexByPriority.crend(); iter++ ) { + //qDebug(QString("write mod %1 to priority %2").arg(iter->first).arg(iter->second).toLocal8Bit()); // the priority order was inverted on load so it has to be inverted again - unsigned int index = m_ModIndexByPriority[i]; + unsigned int index = iter->second; if (index != UINT_MAX) { ModInfo::Ptr modInfo = ModInfo::getByIndex(index); std::vector flags = modInfo->getFlags(); @@ -223,9 +224,9 @@ void Profile::createTweakedIniFile() return; } - for (unsigned int i = 0; i < m_ModStatus.size(); ++i) { + for (int i = getPriorityMinimum(); i < getPriorityMinimum() + (int)numRegularMods(); ++i) { unsigned int idx = modIndexByPriority(i); - if ((idx != UINT_MAX) && m_ModStatus[idx].m_Enabled) { + if (m_ModStatus[idx].m_Enabled) { ModInfo::Ptr modInfo = ModInfo::getByIndex(idx); mergeTweaks(modInfo, tweakedIni); } @@ -454,18 +455,14 @@ void Profile::updateIndices() { m_NumRegularMods = 0; m_ModIndexByPriority.clear(); - m_ModIndexByPriority.resize(m_ModStatus.size(), UINT_MAX); for (unsigned int i = 0; i < m_ModStatus.size(); ++i) { int priority = m_ModStatus[i].m_Priority; - if (priority < 0) { + if (priority == INT_MIN) { // don't assign this to mapping at all, it's probably the overwrite mod continue; - } else if (priority >= static_cast(m_ModIndexByPriority.size())) { - qCritical("invalid priority %d for mod", priority); - continue; } else { ++m_NumRegularMods; - m_ModIndexByPriority.at(priority) = i; + m_ModIndexByPriority[priority] = i; } } } @@ -474,11 +471,10 @@ void Profile::updateIndices() std::vector > Profile::getActiveMods() { std::vector > result; - for (std::vector::const_iterator iter = m_ModIndexByPriority.begin(); - iter != m_ModIndexByPriority.end(); ++iter) { - if ((*iter != UINT_MAX) && m_ModStatus[*iter].m_Enabled) { - ModInfo::Ptr modInfo = ModInfo::getByIndex(*iter); - result.push_back(std::make_tuple(modInfo->internalName(), modInfo->absolutePath(), m_ModStatus[*iter].m_Priority)); + for (std::map::const_iterator iter = m_ModIndexByPriority.begin(); iter != m_ModIndexByPriority.end(); iter++ ) { + if ((iter->second != UINT_MAX) && m_ModStatus[iter->second].m_Enabled) { + ModInfo::Ptr modInfo = ModInfo::getByIndex(iter->second); + result.push_back(std::make_tuple(modInfo->internalName(), modInfo->absolutePath(), m_ModStatus[iter->second].m_Priority)); } } @@ -496,13 +492,13 @@ std::vector > Profile::getActiveMods() } -unsigned int Profile::modIndexByPriority(unsigned int priority) const +unsigned int Profile::modIndexByPriority(int priority) const { - if (priority >= m_ModStatus.size()) { + try { + return m_ModIndexByPriority.at(priority); + } catch (std::out_of_range) { throw MyException(tr("invalid priority %1").arg(priority)); } - - return m_ModIndexByPriority[priority]; } @@ -552,30 +548,26 @@ void Profile::setModPriority(unsigned int index, int &newPriority) return; } - int newPriorityTemp = - (std::max)(0, (std::min)(static_cast(m_ModStatus.size()) - 1, - newPriority)); + int oldPriority = m_ModStatus.at(index).m_Priority; + int lastPriority = INT_MIN; - // don't try to place below overwrite - while ((m_ModIndexByPriority.at(newPriorityTemp) >= m_ModStatus.size()) || - m_ModStatus.at(m_ModIndexByPriority.at(newPriorityTemp)).m_Overwrite) { - --newPriorityTemp; + if (newPriority == oldPriority) { + // nothing to do + return; } - int oldPriority = m_ModStatus.at(index).m_Priority; - if (newPriorityTemp > oldPriority) { - // priority is higher than the old, so the gap we left is in lower priorities - for (int i = oldPriority + 1; i <= newPriorityTemp; ++i) { - --m_ModStatus.at(m_ModIndexByPriority.at(i)).m_Priority; + for (std::map::iterator iter = m_ModIndexByPriority.begin(); iter != m_ModIndexByPriority.end(); iter++) { + if (newPriority < oldPriority && iter->first >= newPriority && iter->first < oldPriority) { + m_ModStatus.at(iter->second).m_Priority += 1; } - } else { - for (int i = newPriorityTemp; i < oldPriority; ++i) { - ++m_ModStatus.at(m_ModIndexByPriority.at(i)).m_Priority; + else if (newPriority > oldPriority && iter->first <= newPriority && iter->first > oldPriority) { + m_ModStatus.at(iter->second).m_Priority -= 1; } - ++newPriority; + lastPriority = std::max(lastPriority, iter->first); } - m_ModStatus.at(index).m_Priority = newPriorityTemp; + newPriority = std::min(newPriority, lastPriority); + m_ModStatus.at(index).m_Priority = std::min(newPriority, lastPriority); updateIndices(); m_ModListWriter.write(); @@ -839,4 +831,9 @@ void Profile::storeSetting(const QString §ion, const QString &name, void Profile::removeSetting(const QString §ion, const QString &name) { m_Settings->remove(section + "/" + name); -} \ No newline at end of file +} + +int Profile::getPriorityMinimum() const +{ + return m_ModIndexByPriority.begin()->first; +} diff --git a/src/profile.h b/src/profile.h index 1fcad046..9ddd5b89 100644 --- a/src/profile.h +++ b/src/profile.h @@ -247,7 +247,7 @@ public: * @return the index of the mod * @throw std::exception an exception is thrown if there is no mod with the specified priority **/ - unsigned int modIndexByPriority(unsigned int priority) const; + unsigned int modIndexByPriority(int priority) const; /** * @brief enable or disable a mod @@ -294,6 +294,8 @@ public: const QVariant &value); void removeSetting(const QString §ion, const QString &name); + int getPriorityMinimum() const; + signals: /** @@ -347,7 +349,7 @@ private: mutable QByteArray m_LastModlistHash; std::vector m_ModStatus; - std::vector m_ModIndexByPriority; + std::map m_ModIndexByPriority; unsigned int m_NumRegularMods; MOBase::DelayedFileWriter m_ModListWriter; -- cgit v1.3.1 From 73842ee245a09fe4ead0e1a2a5f778d89f0a8039 Mon Sep 17 00:00:00 2001 From: Al12rs Date: Thu, 1 Nov 2018 16:20:53 +0100 Subject: Added ability to change color of conflict and plugin highlighting from the settings. --- src/modlist.cpp | 6 +- src/organizer_en.ts | 1417 ++++++++++++++++++++++++++---------------------- src/pluginlist.cpp | 2 +- src/settings.cpp | 86 ++- src/settings.h | 18 +- src/settingsdialog.cpp | 104 ++++ src/settingsdialog.h | 27 + src/settingsdialog.ui | 88 ++- 8 files changed, 1065 insertions(+), 683 deletions(-) (limited to 'src/modlist.cpp') diff --git a/src/modlist.cpp b/src/modlist.cpp index 7b57eeda..3f8fa0c0 100644 --- a/src/modlist.cpp +++ b/src/modlist.cpp @@ -385,12 +385,12 @@ QVariant ModList::data(const QModelIndex &modelIndex, int role) const || (role == ViewMarkingScrollBar::DEFAULT_ROLE)) { auto flags = modInfo->getFlags(); if (modInfo->getHighlight() & ModInfo::HIGHLIGHT_PLUGIN) { - return QColor(0, 0, 255, 64); + return Settings::instance().modlistContainsPluginColor(); } else if (m_Overwrite.find(modIndex) != m_Overwrite.end()) { - return QColor(0, 255, 0, 64); + return Settings::instance().modlistOverwrittenLooseColor(); } else if (m_Overwritten.find(modIndex) != m_Overwritten.end()) { - return QColor(255, 0, 0, 64); + return Settings::instance().modlistOverwritingLooseColor(); } else if (std::find(flags.begin(), flags.end(), ModInfo::FLAG_SEPARATOR) != flags.end() && modInfo->getColor().isValid()) { return modInfo->getColor(); } else { diff --git a/src/organizer_en.ts b/src/organizer_en.ts index 9a7e0713..3d2f1744 100644 --- a/src/organizer_en.ts +++ b/src/organizer_en.ts @@ -1386,58 +1386,58 @@ p, li { white-space: pre-wrap; } - + File format "%1" not supported - + None of the available installer plugins were able to handle that archive. This is likely due to a corrupted or incompatible download or unrecognized archive format. - + no error - + 7z.dll not found - + 7z.dll isn't valid - + archive not found - + failed to open archive - + unsupported archive type - + internal library error - + archive invalid - + unknown archive error @@ -1534,47 +1534,47 @@ This is likely due to a corrupted or incompatible download or unrecognized archi MainWindow - + Categories - + Clear - + If checked, only mods that match all selected categories are displayed. - + And - + If checked, all mods that match at least one of the selected categories are displayed. - + Or - + Profile - + Pick a module collection - + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } @@ -1584,77 +1584,77 @@ p, li { white-space: pre-wrap; } - + Open list options... - + Refresh list. This is usually not necessary unless you modified data outside the program. - + Show Open Folders menu... - - + + Restore Backup... - - - + + + Create Backup - + List of available mods. - + This is a list of installed mods. Use the checkboxes to activate/deactivate mods and drag & drop mods to change their "installation" orders. - + Filter - + Clear all Filters - + No groups - + Nexus IDs - - - + + + Namefilter - + Pick a program to run. - + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } @@ -1664,12 +1664,12 @@ p, li { white-space: pre-wrap; } - + Run program - + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } @@ -1678,17 +1678,17 @@ p, li { white-space: pre-wrap; } - + Run - + Create a shortcut in your start menu or on the desktop to the specified program - + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } @@ -1697,27 +1697,27 @@ p, li { white-space: pre-wrap; } - + Shortcut - + Plugins - + Sort - + List of available esp/esm files - + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } @@ -1726,27 +1726,27 @@ p, li { white-space: pre-wrap; } - + Archives - + <html><head/><body><p>BSAs / BA2s are bundles of game assets (textures, scripts, etc.). By default, the engine loads these bundles in a separate step from loose files. <p>Their load order is specified by the priority of the corresponding plugin (right pane, plugins tab).</p><p>If there is a matching plugin, the game will load them no matter what.</p></body></html> - + <html><head/><body><p>Currently detected archives. (<a href="#"><span style=" text-decoration: underline; color:#0000ff;">What is an archive?</span></a>)</p></body></html> - + List of available BS Archives. Archives not checked here are not managed by MO and ignore installation order. - + BSA files are archives (comparable to .zip files) that contain data assets (meshes, textures, ...) to be used by the game. As such they "compete" with loose files in your data directory over which is loaded. By default, BSAs that share their base name with an enabled ESP (i.e. plugin.esp and plugin.bsa) are automatically loaded and will have precedence over all loose files, the installation order you set up to the left is then ignored! @@ -1754,61 +1754,61 @@ p, li { white-space: pre-wrap; } - + Data - + refresh data-directory overview - + Refresh the overview. This may take a moment. - - - - + + + + Refresh - + This is an overview of your data directory as visible to the game (and tools). - + File - + Mod - - + + Filter the above list so that only conflicts are displayed. - + Show only conflicts - + Saves - + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } @@ -1819,160 +1819,160 @@ p, li { white-space: pre-wrap; } - + Downloads - + Refresh downloads view - + This is a list of mods you downloaded from Nexus. Double click one to install it. You can also drag an archive into here. - + Show Hidden - + Tool Bar - + Install Mod - + Install &Mod - + Install a new mod from an archive - + Ctrl+M - + Profiles - + &Profiles - + Configure Profiles - + Ctrl+P - + Executables - + &Executables - + Configure the executables that can be started through Mod Organizer - + Ctrl+E - - + + Tools - + &Tools - + Ctrl+I - + Settings - + &Settings - + Configure settings and workarounds - + Ctrl+S - + Nexus - + Search nexus network for more mods - + Ctrl+N - - + + Update - + Mod Organizer is up-to-date - - + + No Problems - + This button will be highlighted if MO discovered potential problems in your setup and provide tips on how to fix them. !Work in progress! @@ -1980,758 +1980,813 @@ Right now this has very limited functionality - - + + Help - + Ctrl+H - + Endorse MO - - + + Endorse Mod Organizer - + Copy Log to Clipboard - + Change Game - + Open the Instance selection dialog to manage a different Game - + Toolbar - + Desktop - + Start Menu - + There is no supported sort mechanism for this game. You will probably have to use a third-party tool. - + Problems - + There are potential problems with your setup - + Everything seems to be in order - + Help on UI - + Documentation Wiki - + Report Issue - + Tutorials - + About - + About Qt - + Name - + Please enter a name for the new profile - + failed to create profile: %1 - + Show tutorial? - + You are starting Mod Organizer for the first time. Do you want to show a tutorial of its basic features? If you choose no you can always start the tutorial from the "Help"-menu. - + Downloads in progress - + There are still downloads in progress, do you really want to quit? - + Plugin "%1" failed: %2 - + Plugin "%1" failed - + Browse Mod Page - + Also in: <br> - + No conflict - + <Edit...> - + This bsa is enabled in the ini file so it may be required! - + Activating Network Proxy - + Notice: Your current MO version (%1) is lower than the previous version (%2).<br>The GUI may not downgrade gracefully, so you may experience oddities.<br>However, there should be no serious issues. - + Choose Mod - + Mod Archive - + Start Tutorial? - + You're about to start a tutorial. For technical reasons it's not possible to end the tutorial early. Continue? - + failed to spawn notepad.exe: %1 - + failed to change origin name: %1 - + failed to move "%1" from mod "%2" to "%3": %4 - + <Contains %1> - + <Checked> - + <Unchecked> - + <Update> - + <Mod Backup> - + <Managed by MO> - + <Managed outside MO> - + <No category> - + <Conflicted> - + <Not Endorsed> - + failed to rename mod: %1 - + Overwrite? - + This will replace the existing mod "%1". Continue? - + failed to remove mod "%1" - - - + + + failed to rename "%1" to "%2" - - - - + + + + Confirm - + Remove the following mods?<br><ul>%1</ul> - + failed to remove mod: %1 - - - + + + Failed - + Installation file no longer exists - + Mods installed with old versions of MO can't be reinstalled in this way. - + Failed to create backup. - + You need to be logged in with Nexus to resume a download - - + + You need to be logged in with Nexus to endorse - + Failed to display overwrite dialog: %1 - + Nexus ID for this Mod is unknown - + Web page for this mod is unknown - - - + + + Create Mod... - + This will create an empty mod. Please enter a name: - - + + A mod with this name already exists - + + Create Separator... + + + + + This will create a new separator. +Please enter a name: + + + + + A separator with this name already exists + + + + This will move all files from overwrite into a new, regular mod. Please enter a name: - - + + Are you sure? - + About to recursively delete: - + Not logged in, endorsement information will be wrong - + Continue? - + The versioning scheme decides which version is considered newer than another. This function will guess the versioning scheme under the assumption that the installed version is outdated. - - + + Sorry - + I don't know a versioning scheme where %1 is newer than %2. - + Really enable all visible mods? - + Really disable all visible mods? - + Export to csv - + CSV (Comma Separated Values) is a format that can be imported in programs like Excel to create a spreadsheet. You can also use online editors and converters instead. - + Select what mods you want export: - + All installed mods - + Only active (checked) mods from your current profile - + All currently visible mods in the mod list - + Choose what Columns to export: - + Mod_Priority - + Mod_Name - + Mod_Status - + Primary_Category - + Nexus_ID - + Mod_Nexus_URL - + Mod_Version - + Install_Date - + Download_File_Name - + export failed: %1 - + Open Game folder - + Open MyGames folder - + Open Instance folder - + Open Mods folder - + Open Profile folder - + Open Downloads folder - + Open MO2 Install folder - + Open MO2 Plugins folder - + Open MO2 Logs folder - + Install Mod... - + Create empty mod - + + Create Separator + + + + Enable all visible - + Disable all visible - + Check all for update - + Export to csv... - + All Mods - + Sync to Mods... - + Clear Overwrite... - - + + Open in Explorer - + Restore Backup - + Remove Backup... - + + Rename Separator... + + + + + Remove Separator... + + + + + + + Send to Top + + + + + + + Send to Bottom + + + + + Select Color... + + + + + Reset Color + + + + Change Categories - + Primary Category - + Change versioning scheme - + Un-ignore update - + Ignore update - - + + Enable selected - - + + Disable selected - + Rename Mod... - + Reinstall Mod - + Remove Mod... - + Un-Endorse - - + + Endorse - + Won't endorse - + Endorsement state unknown - + Ignore missing data - + Mark as converted/working - + Visit on Nexus - + Visit web page - + Information... - - + + Exception: - - + + Unknown exception - + <All> - + <Multiple> - + %1 more - + Are you sure you want to remove the following %n save(s)?<br><ul>%1</ul><br>Removed saves will be sent to the Recycle Bin. @@ -2739,12 +2794,12 @@ You can also use online editors and converters instead. - + Enable Mods... - + Delete %n save(s) @@ -2752,319 +2807,329 @@ You can also use online editors and converters instead. - + failed to remove %1 - + failed to create %1 - + Can't change download directory while downloads are in progress! - + failed to write to file %1 - + %1 written - + Select binary - + Binary - + Enter Name - + Please enter a name for the executable - + Not an executable - + This is not a recognized executable. - - + + Replace file? - + There already is a hidden version of this file. Replace it? - - + + File operation failed - - + + Failed to remove "%1". Maybe you lack the required file permissions? - + There already is a visible version of this file. Replace it? - + file not found: %1 - + failed to generate preview for %1 - + Sorry, can't preview anything. This function currently does not support extracting from bsas. - + Update available - + Open/Execute - + Add as Executable - + Preview - + Un-Hide - + Hide - + Write To File... - + Do you want to endorse Mod Organizer on %1 now? - + Thank you! - + Thank you for your endorsement! - + Request to Nexus failed: %1 - - + + failed to read %1: %2 - - + + Error - + failed to extract %1 (errorcode %2) - + Extract BSA - + This archive contains invalid hashes. Some files may be broken. - + Extract... - + This will restart MO, continue? - + Edit Categories... - + Deselect filter - + Remove - + Enable all - + Disable all - + + Send to top + + + + + Send to bottom + + + + Unlock load order - + Lock load order - + depends on missing "%1" - + incompatible with "%1" - + Please wait while LOOT is running - + loot failed. Exit code was: %1 - + failed to start loot - + failed to run loot: %1 - + Errors occured - + Backup of load order created - + Choose backup to restore - + No Backups - + There are no backups to restore - - + + Restore failed - - + + Failed to restore the backup. Errorcode: %1 - + Backup of modlist created - + A file with the same name has already been downloaded. What would you like to do? - + Overwrite - + Rename new file - + Ignore file @@ -3081,82 +3146,82 @@ You can also use online editors and converters instead. ModInfo - + Plugins - + Textures - + Meshes - + Bethesda Archive - + UI Changes - + Sound Effects - + Scripts - + Script Extender - + Script Extender Files - + SkyProc Tools - + MCM Data - + INI files - + ModGroup files - + invalid content type %1 - + invalid mod index %1 - + remove: invalid mod index %1 @@ -3481,273 +3546,273 @@ p, li { white-space: pre-wrap; } - + &Delete - + &Rename - + &Hide - + &Unhide - + &Open - + &New Folder - + Save changes? - + Save changes to "%1"? - + File Exists - + A file with that name exists, please enter a new one - + failed to move file - + failed to create directory "optional" - - + + Info requested, please wait - + Main - + Update - + Optional - + Old - + Misc - + Unknown - + Current Version: %1 - + No update available - + (description incomplete, please visit nexus) - + <a href="%1">Visit on Nexus</a> - + Failed to delete %1 - - - - + + + + Confirm - - + + Are sure you want to delete "%1"? - - + + Are sure you want to delete the selected files? - - + + New Folder - + Failed to create "%1" - - + + Replace file? - + There already is a hidden version of this file. Replace it? - - + + File operation failed - - + + Failed to remove "%1". Maybe you lack the required file permissions? - - + + failed to rename %1 to %2 - + There already is a visible version of this file. Replace it? - + Select binary - + Binary - + file not found: %1 - + failed to generate preview for %1 - + Sorry - + Sorry, can't preview anything. This function currently does not support extracting from bsas. - + Un-Hide - + Hide - - + + Open/Execute - - + + Preview - + Name - + Please enter a name - - + + Error - + Invalid name. Must be a valid file name - + A tweak by that name exists - + Create Tweak @@ -3786,272 +3851,285 @@ p, li { white-space: pre-wrap; } ModInfoRegular - - + + failed to write %1/meta.ini: error %2 - + %1 contains no esp/esm/esl and no asset (textures, meshes, interface, ...) directory - + Categories: <br> + + ModInfoSeparator + + + This is a Separator + + + ModList - + Game Plugins (ESP/ESM/ESL) - + Interface - + Meshes - + Bethesda Archive - + Scripts (Papyrus) - + Script Extender Plugin - + SkyProc Patcher - + Sound or Music - + Textures - + MCM Configuration - + INI files - + ModGroup files - + This entry contains files that have been created inside the virtual data tree (i.e. by the construction kit) - + Backup - + + Separator + + + + No valid game data - + Not endorsed yet - + Overwrites files - + Overwritten files - + Overwrites & Overwritten - + Redundant - + Alternate game source - + Non-MO - + invalid - + installed version: "%1", newest version: "%2" - + The newest version on Nexus seems to be older than the one you have installed. This could either mean the version you have has been withdrawn (i.e. due to a bug) or the author uses a non-standard versioning scheme and that newest version is actually newer. Either way you may want to "upgrade". - + Categories: <br> - + Invalid name - + Name is already in use by another mod - + drag&drop failed: %1 - + Confirm - + Are you sure you want to remove "%1"? - + Flags - + Content - + Mod Name - + Version - + Priority - + Category - + Source Game - + Nexus ID - + Installation - - + + unknown - + Name of your mods - + Version of the mod (if available) - + Installation priority of your mod. The higher, the more "important" it is and thus overwrites files from mods with lower priority. - + Category of the mod. - + The source game which was the origin of this mod. - + Id of the mod as used on Nexus. - + Emblemes to highlight things that might require attention. - + Depicts the content of the mod:<br><table cellspacing=7><tr><td><img src=":/MO/gui/content/plugin" width=32/></td><td>Game plugins (esp/esm/esl)</td></tr><tr><td><img src=":/MO/gui/content/interface" width=32/></td><td>Interface</td></tr><tr><td><img src=":/MO/gui/content/mesh" width=32/></td><td>Meshes</td></tr><tr><td><img src=":/MO/gui/content/bsa" width=32/></td><td>BSA</td></tr><tr><td><img src=":/MO/gui/content/texture" width=32/></td><td>Textures</td></tr><tr><td><img src=":/MO/gui/content/sound" width=32/></td><td>Sounds</td></tr><tr><td><img src=":/MO/gui/content/music" width=32/></td><td>Music</td></tr><tr><td><img src=":/MO/gui/content/string" width=32/></td><td>Strings</td></tr><tr><td><img src=":/MO/gui/content/script" width=32/></td><td>Scripts (Papyrus)</td></tr><tr><td><img src=":/MO/gui/content/skse" width=32/></td><td>Script Extender plugins</td></tr><tr><td><img src=":/MO/gui/content/skyproc" width=32/></td><td>SkyProc Patcher</td></tr><tr><td><img src=":/MO/gui/content/menu" width=32/></td><td>Mod Configuration Menu</td></tr><tr><td><img src=":/MO/gui/content/inifile" width=32/></td><td>INI files</td></tr><tr><td><img src=":/MO/gui/content/modgroup" width=32/></td><td>ModGroup files</td></tr></table> - + Time this mod was installed @@ -4225,123 +4303,123 @@ p, li { white-space: pre-wrap; } - + Executable "%1" not found - + Start Steam? - + Steam is required to be running already to correctly start the game. Should MO try to start steam now? - + Error - + Windows Event Log Error - + The Windows Event Log service is disabled and/or not running. This prevents USVFS from running properly. Your mods may not be working in the executable that you are launching. Note that you may have to restart MO and/or your PC after the service is fixed. Continue launching %1? - + No profile set - + Failed to refresh list of esps: %1 - + Multiple esps/esls activated, please check that they don't conflict. - + Download? - + A download has been started but no installed page plugin recognizes it. If you download anyway no information (i.e. version) will be associated with the download. Continue? - + failed to update mod list: %1 - - + + login successful - + Login failed - + Login failed, try again? - + login failed: %1. Download will not be associated with an account - + login failed: %1 - + login failed: %1. You need to log-in with Nexus to update MO. - + MO1 "Script Extender" load mechanism has left hook.dll in your game folder - - + + Description missing - + <a href="%1">hook.dll</a> has been found in your game folder (right click to copy the full path). This is most likely a leftover of setting the ModOrganizer 1 load mechanism to "Script Extender", in which case you must remove this file either by changing the load mechanism in ModOrganizer 1 or manually removing the file, otherwise the game is likely to crash and burn. - + failed to save load order: %1 - + The designated write target "%1" is not enabled. @@ -4514,68 +4592,68 @@ Continue? - + The file containing locked plugin indices is broken - - + + <b>Origin</b>: %1 - + <br><b><i>This plugin can't be disabled (enforced by the game).</i></b> - + Author - + Description - + Missing Masters - + Enabled Masters - + Loads Archives - + There are Archives connected to this plugin. Their assets will be added to your game, overwriting in case of conflicts following the plugin order. Loose files will always overwrite assets from Archives. (This flag only checks for Archives from the same mod as the plugin) - + Loads INI settings - + There is an ini file connected to this plugin. Its settings will be added to your game settings, overwriting in case of conflicts. - + This ESP is flagged as an ESL. It will adhere to the ESP load order but the records will be loaded in ESL space. - + failed to restore load order for %1 @@ -4647,56 +4725,56 @@ p, li { white-space: pre-wrap; } - + failed to write mod list: %1 - + failed to update tweaked ini file, wrong settings may be used: %1 - + failed to create tweaked ini: %1 - + failed to open %1 - + "%1" is missing or inaccessible - - - - - + + + + + invalid index %1 - + Overwrite directory couldn't be parsed - + invalid priority %1 - + Delete savegames? - + Do you want to delete local savegames? (If you select "No", the save games will show up again if you re-enable local savegames) @@ -5302,7 +5380,7 @@ If the folder was still in use, restart MO and try again. - + Mod Organizer @@ -5317,18 +5395,18 @@ If the folder was still in use, restart MO and try again. - + Please use "Help" from the toolbar to get usage instructions to all elements - - + + <Manage...> - + failed to parse profile %1: %2 @@ -5364,12 +5442,12 @@ If the folder was still in use, restart MO and try again. - + failed to access %1 - + failed to set file time %1 @@ -5379,12 +5457,12 @@ If the folder was still in use, restart MO and try again. - + Script Extender - + Proxy DLL @@ -5588,28 +5666,28 @@ Select Show Details option to see the full change-log. Settings - + Failed - + Sorry, failed to start the helper application - - + + attempt to store setting for unknown plugin "%1" - + Error - + Failed to create "%1", you may not have the necessary permission. path remains unchanged. @@ -5686,136 +5764,167 @@ If you use pre-releases, never contact me directly by e-mail or via private mess + Colors + + + + + Plugin is Contained in selected Mod + + + + + Reset Colors + + + + If checked, the download interface will be more compact. - + Compact Download Interface - + If checked, the download list will display meta information instead of file names. - + Download Meta Information - + Reset stored information from dialogs. - + + Mod Contains selected Plugin + Is contained in selected Mod + + + + This will make all dialogs show up again where you checked the "Remember selection"-box. - + Reset Dialogs - - + + Modify the categories available to arrange your mods. - + Configure Mod Categories - + + Is overwriting (loose files) + + + + + Is overwritten (loose files) + + + + Paths - - - + + + ... - + Caches - + Overwrite - - + + Directory where downloads are stored. - + Downloads - + Profiles - + Directory where mods are stored. - + Directory where mods are stored. Please note that changing this will break all associations of profiles with mods that don't exist in the new location (with the same name). - + Mods - + Managed Game - + Base Directory - + Use %BASE_DIR% to refer to the Base Directory. - + Important: All directories have to be writeable! - - + + Nexus - + Allows automatic log-in when the Nexus-Page for the game is clicked. - + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } @@ -5824,144 +5933,144 @@ p, li { white-space: pre-wrap; } - + If checked and if correct credentials are entered below, log-in to Nexus (for browsing and downloading) is automatic. - + Automatically Log-In to Nexus - - + + Username - - + + Password - + Remove cache and cookies. Forces a new login. - + Clear Cache - + Disable automatic internet features - + Disable automatic internet features. This does not affect features that are explicitly invoked by the user (like checking mods for updates, endorsing, opening the web browser) - + Offline Mode - + Use a proxy for network connections. - + Use a proxy for network connections. This uses the system-wide settings which can be configured in Internet Explorer. Please note that MO will start up a few seconds slower on some systems when using a proxy. - + Use HTTP Proxy (Uses System Settings) - + Associate with "Download with manager" links - + Known Servers (updated on download) - + Preferred Servers (Drag & Drop) - + Steam - + If you save your steam user ID and password here, they will be used when logging into steam. Note, however, your password will be stored unencrypted, so make sure your computer is secure. - + Plugins - + Author: - + Version: - + Description: - + Key - + Value - + Blacklisted Plugins (use <del> to remove): - + Workarounds - + Steam App ID - + The Steam AppID for your game - + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } @@ -5977,17 +6086,17 @@ p, li { white-space: pre-wrap; } - + Load Mechanism - + Select loading mechanism. See help for details. - + Mod Organizer needs a dll to be injected into the game so all mods are visible to it. There are several means to do this: *Mod Organizer* (default) In this mode the Mod Organizer itself injects the dll. The disadvantage is that you always have to start the game through MO or a link created by it. @@ -5998,17 +6107,17 @@ If you use the Steam version of Oblivion the default will NOT work. In this case - + NMM Version - + The Version of Nexus Mod Manager to impersonate. - + Mod Organizer uses an API provided by the Nexus to provide features like checking for updates and downloading files. Unfortunately this API has not been made available officially to third party tools like MO so we have to impersonate the Nexus Mod Manager to be allowed in. On top of this Nexus has used the client identification to lock out outdated versions of NMM to force users to update. This means that MO also needs to impersonate the new version of NMM even if MO doesn't need an update. Therefore you can configure the version to identify as here. Please note that MO does identify itself as MO to the webserver, it's not lying about what it is. It is merely adding a "compatible" NMM version to the user agent. @@ -6017,44 +6126,44 @@ tl;dr-version: If Nexus-features don't work, insert the current version num - + Enforces that inactive ESPs and ESMs are never loaded. - + It seems that the Games occasionally load ESP or ESM files even if they haven't been activated as plugins. I don't yet know what the circumstances are, but user reports imply it is in some cases unwanted. If this is checked, ESPs and ESMs not checked in the List are invisible to the game and can not be loaded. - + Hide inactive ESPs/ESMs - + If checked, files (i.e. esps, esms and bsas) belonging to the core game can not be disabled in the UI. (default: on) - + If checked, files (i.e. esps, esms and bsas) belonging to the core game can not be disabled in the UI. (default: on) Uncheck this if you want to use Mod Organizer with total conversions (like Nehrim) but be aware that the game will crash if required files are not enabled. - + Force-enable game files - + Disable this to no longer display mods installed outside MO in the mod list (left pane). Assets from those mods will then be treated as having lowest mod priority together with the original game content. - + By default Mod Organizer will display esp+bsa bundles installed with foreign tools as mods (left pane). This allows you to control their priority in relation to other mods. This is particularly useful if you also use Steam Workshop to install mods. However, if you installed loose file mods outside MO which conflict with BSAs also installed outside MO those conflicts can't be resolved correctly. @@ -6062,44 +6171,44 @@ If you disable this feature, MO will only display official DLCs this way. Please - + Display mods installed outside MO - - + + For Skyrim, this can be used instead of Archive Invalidation. It should make AI redundant for all Profiles. For the other games this is not a sufficient replacement for AI! - + Back-date BSAs - + These are workarounds for problems with Mod Organizer. Please make sure you read the help text before changing anything here. - + Diagnostics - + Log Level - + Decides the amount of data printed to "ModOrganizer.log" - + Decides the amount of data printed to "ModOrganizer.log". "Debug" produces very useful information for finding problems. There is usually no noteworthy performance impact but the file may become rather large. If this is a problem you may prefer the "Info" level for regluar use. On the "Error" level the log file usually remains empty. @@ -6107,37 +6216,37 @@ For the other games this is not a sufficient replacement for AI! - + Debug - + Info (recommended) - + Warning - + Error - + Crash Dumps - + Decides which type of crash dumps are collected when injected processes crash. - + Decides which type of crash dumps are collected when injected processes crash. "None" Disables the generation of crash dumps by MO. @@ -6148,37 +6257,37 @@ For the other games this is not a sufficient replacement for AI! - + None - + Mini (recommended) - + Data - + Full - + Max Dumps To Keep - + Maximum number of crash dumps to keep on disk. Use 0 for unlimited. - + Maximum number of crash dumps to keep on disk. Use 0 for unlimited. Set "Crash Dumps" above to None to disable crash dump collection. @@ -6186,12 +6295,12 @@ For the other games this is not a sufficient replacement for AI! - + Hint: right click link and copy link location - + Logs and crash dumps are stored under your current instance in the <a href="LOGS_FULL_PATH">LOGS_DIR</a> and <a href="DUMPS_FULL_PATH">DUMPS_DIR</a> folders. @@ -6201,52 +6310,52 @@ For the other games this is not a sufficient replacement for AI! - + Confirm - + Changing the mod directory affects all your profiles! Mods not present (or named differently) in the new location will be disabled in all profiles. There is no way to undo this unless you backed up your profiles manually. Proceed? - + Select base directory - + Select download directory - + Select mod directory - + Select cache directory - + Select profiles directory - + Select overwrite directory - + Confirm? - + This will make all dialogs show up again where you checked the "Remember selection"-box. Continue? diff --git a/src/pluginlist.cpp b/src/pluginlist.cpp index 8f714afd..d56a4bde 100644 --- a/src/pluginlist.cpp +++ b/src/pluginlist.cpp @@ -936,7 +936,7 @@ QVariant PluginList::data(const QModelIndex &modelIndex, int role) const } else if (role == Qt::BackgroundRole || (role == ViewMarkingScrollBar::DEFAULT_ROLE)) { if (m_ESPs[index].m_ModSelected) { - return QColor(0, 0, 255, 64); + return Settings::instance().pluginListContainedColor(); } else { return QVariant(); } diff --git a/src/settings.cpp b/src/settings.cpp index 2dbca0eb..0ecbaa23 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -50,6 +50,8 @@ along with Mod Organizer. If not, see . #include #include #include +#include +#include #include // for Qt::UserRole, etc #include // for qDebug, qWarning @@ -62,6 +64,7 @@ along with Mod Organizer. If not, see . #include #include // for pair, make_pair + using namespace MOBase; template @@ -189,6 +192,14 @@ QString Settings::deObfuscate(const QString &password) return QString::fromUtf8(buffer.constData()); } +QColor Settings::getIdealTextColor(const QColor& rBackgroundColor) +{ + const int THRESHOLD = 105; + int BackgroundDelta = (rBackgroundColor.red() * 0.299) + (rBackgroundColor.green() * 0.587) + (rBackgroundColor.blue() * 0.114); + return QColor((255 - BackgroundDelta < THRESHOLD) ? Qt::black : Qt::white); +} + + bool Settings::hideUncheckedPlugins() const { return m_Settings.value("Settings/hide_unchecked_plugins", false).toBool(); @@ -355,6 +366,26 @@ int Settings::crashDumpsMax() const return m_Settings.value("Settings/crash_dumps_max", 5).toInt(); } +QColor Settings::modlistOverwrittenLooseColor() const +{ + return m_Settings.value("Settings/overwrittenLooseFilesColor", QColor(0, 255, 0, 64)).value(); +} + +QColor Settings::modlistOverwritingLooseColor() const +{ + return m_Settings.value("Settings/overwritingLooseFilesColor", QColor(255, 0, 0, 64)).value(); +} + +QColor Settings::modlistContainsPluginColor() const +{ + return m_Settings.value("Settings/containsPluginColor", QColor(0, 0, 255, 64)).value(); +} + +QColor Settings::pluginListContainedColor() const +{ + return m_Settings.value("Settings/containedColor", QColor(0, 0, 255, 64)).value(); +} + void Settings::setNexusLogin(QString username, QString password) { m_Settings.setValue("Settings/nexus_login", true); @@ -587,13 +618,14 @@ void Settings::resetDialogs() QuestionBoxMemory::resetDialogs(); } - void Settings::query(PluginContainer *pluginContainer, QWidget *parent) { SettingsDialog dialog(pluginContainer, parent); connect(&dialog, SIGNAL(resetDialogs()), this, SLOT(resetDialogs())); + connect(&dialog, SIGNAL(resetColorSettings()), this, SLOT(resetColorSettings())); + std::vector> tabs; tabs.push_back(std::unique_ptr(new GeneralTab(this, dialog))); @@ -658,6 +690,10 @@ Settings::GeneralTab::GeneralTab(Settings *m_parent, SettingsDialog &m_dialog) , m_compactBox(m_dialog.findChild("compactBox")) , m_showMetaBox(m_dialog.findChild("showMetaBox")) , m_usePrereleaseBox(m_dialog.findChild("usePrereleaseBox")) + , m_overwritingBtn(m_dialog.findChild("overwritingBtn")) + , m_overwrittenBtn(m_dialog.findChild("overwrittenBtn")) + , m_containsBtn(m_dialog.findChild("containsBtn")) + , m_containedBtn(m_dialog.findChild("containedBtn")) { // FIXME I think 'addLanguages' lives in here not in parent m_parent->addLanguages(m_languageBox); @@ -685,6 +721,50 @@ Settings::GeneralTab::GeneralTab(Settings *m_parent, SettingsDialog &m_dialog) m_styleBox->setCurrentIndex(currentID); } } + /* verision using palette only works with fusion theme for some stupid reason... + m_overwritingBtn->setAutoFillBackground(true); + m_overwrittenBtn->setAutoFillBackground(true); + m_containsBtn->setAutoFillBackground(true); + m_containedBtn->setAutoFillBackground(true); + m_overwritingBtn->setPalette(QPalette(m_parent->modlistOverwritingLooseColor())); + m_overwrittenBtn->setPalette(QPalette(m_parent->modlistOverwrittenLooseColor())); + m_containsBtn->setPalette(QPalette(m_parent->modlistContainsPluginColor())); + m_containedBtn->setPalette(QPalette(m_parent->pluginListContainedColor())); + QPalette palette1 = m_overwritingBtn->palette(); + QPalette palette2 = m_overwrittenBtn->palette(); + QPalette palette3 = m_containsBtn->palette(); + QPalette palette4 = m_containedBtn->palette(); + palette1.setColor(QPalette::Background, m_parent->modlistOverwritingLooseColor()); + palette2.setColor(QPalette::Background, m_parent->modlistOverwrittenLooseColor()); + palette3.setColor(QPalette::Background, m_parent->modlistContainsPluginColor()); + palette4.setColor(QPalette::Background, m_parent->pluginListContainedColor()); + m_overwritingBtn->setPalette(palette1); + m_overwrittenBtn->setPalette(palette2); + m_containsBtn->setPalette(palette3); + m_containedBtn->setPalette(palette4); + */ + + //version with stylesheet + QString COLOR_STYLE("QPushButton { background-color : %1; color : %2; }"); + + + m_overwritingBtn->setStyleSheet(COLOR_STYLE.arg( + m_parent->modlistOverwritingLooseColor().name()).arg(getIdealTextColor( + m_parent->modlistOverwritingLooseColor()).name())); + m_overwrittenBtn->setStyleSheet(COLOR_STYLE.arg( + m_parent->modlistOverwrittenLooseColor().name()).arg(getIdealTextColor( + m_parent->modlistOverwrittenLooseColor()).name())); + m_containsBtn->setStyleSheet(COLOR_STYLE.arg( + m_parent->modlistContainsPluginColor().name()).arg(getIdealTextColor( + m_parent->modlistContainsPluginColor()).name())); + m_containedBtn->setStyleSheet(COLOR_STYLE.arg( + m_parent->pluginListContainedColor().name()).arg(getIdealTextColor( + m_parent->pluginListContainedColor()).name())); + + m_dialog.setOverwritingColor(m_parent->modlistOverwritingLooseColor()); + m_dialog.setOverwrittenColor(m_parent->modlistOverwrittenLooseColor()); + m_dialog.setContainsColor(m_parent->modlistContainsPluginColor()); + m_dialog.setContainedColor(m_parent->pluginListContainedColor()); m_compactBox->setChecked(m_parent->compactDownloads()); m_showMetaBox->setChecked(m_parent->metaDownloads()); @@ -707,6 +787,10 @@ void Settings::GeneralTab::update() emit m_parent->styleChanged(newStyle); } + m_Settings.setValue("Settings/overwritingLooseFilesColor", m_dialog.getOverwritingColor()); + m_Settings.setValue("Settings/overwrittenLooseFilesColor", m_dialog.getOverwrittenColor()); + m_Settings.setValue("Settings/containsPluginColor", m_dialog.getContainsColor()); + m_Settings.setValue("Settings/containedColor", m_dialog.getContainedColor()); m_Settings.setValue("Settings/compact_downloads", m_compactBox->isChecked()); m_Settings.setValue("Settings/meta_downloads", m_showMetaBox->isChecked()); m_Settings.setValue("Settings/use_prereleases", m_usePrereleaseBox->isChecked()); diff --git a/src/settings.h b/src/settings.h index c49edfcb..8fe053e8 100644 --- a/src/settings.h +++ b/src/settings.h @@ -29,6 +29,7 @@ along with Mod Organizer. If not, see . #include #include #include +#include #include //for uint @@ -42,6 +43,7 @@ class QSpinBox; class QListWidget; class QWidget; class QLabel; +class QPushButton; struct ServerInfo; @@ -217,6 +219,15 @@ public: */ int crashDumpsMax() const; + QColor modlistOverwrittenLooseColor() const; + + QColor modlistOverwritingLooseColor() const; + + QColor modlistContainsPluginColor() const; + + QColor pluginListContainedColor() const; + + /** * @brief set the nexus login information * @@ -346,7 +357,8 @@ public: public slots: void managedGameChanged(MOBase::IPluginGame const *gamePlugin); - +public: + static QColor getIdealTextColor(const QColor& rBackgroundColor); private: static QString obfuscate(const QString &password); @@ -387,6 +399,10 @@ private: QCheckBox *m_compactBox; QCheckBox *m_showMetaBox; QCheckBox *m_usePrereleaseBox; + QPushButton *m_overwritingBtn; + QPushButton *m_overwrittenBtn; + QPushButton *m_containsBtn; + QPushButton *m_containedBtn; }; class PathsTab : public SettingsTab diff --git a/src/settingsdialog.cpp b/src/settingsdialog.cpp index 058d082a..7f484830 100644 --- a/src/settingsdialog.cpp +++ b/src/settingsdialog.cpp @@ -33,6 +33,7 @@ along with Mod Organizer. If not, see . #include #include #include +#include #define WIN32_LEAN_AND_MEAN #include @@ -177,6 +178,109 @@ void SettingsDialog::on_browseOverwriteDirBtn_clicked() } } +void SettingsDialog::on_containsBtn_clicked() +{ + QColor result = QColorDialog::getColor(m_ContainsColor, this); + if (result.isValid()) { + m_ContainsColor = result; + + QString COLOR_STYLE("QPushButton { background-color : %1; color : %2; }"); + ui->containsBtn->setStyleSheet(COLOR_STYLE.arg( + result.name()).arg(Settings::getIdealTextColor( + result).name())); + + /*ui->containsBtn->setAutoFillBackground(true); + ui->containsBtn->setPalette(QPalette(result)); + QPalette palette = ui->containsBtn->palette(); + palette.setColor(QPalette::Background, result); + ui->containsBtn->setPalette(palette);*/ + } +} + +void SettingsDialog::on_containedBtn_clicked() +{ + QColor result = QColorDialog::getColor(m_ContainedColor, this); + if (result.isValid()) { + m_ContainedColor = result; + + QString COLOR_STYLE("QPushButton { background-color : %1; color : %2; }"); + ui->containedBtn->setStyleSheet(COLOR_STYLE.arg( + result.name()).arg(Settings::getIdealTextColor( + result).name())); + + /*ui->containedBtn->setAutoFillBackground(true); + ui->containedBtn->setPalette(QPalette(result)); + QPalette palette = ui->containedBtn->palette(); + palette.setColor(QPalette::Background, result); + ui->containedBtn->setPalette(palette);*/ + } +} + +void SettingsDialog::on_overwrittenBtn_clicked() +{ + QColor result = QColorDialog::getColor(m_OverwrittenColor, this); + if (result.isValid()) { + m_OverwrittenColor = result; + + QString COLOR_STYLE("QPushButton { background-color : %1; color : %2; }"); + ui->overwrittenBtn->setStyleSheet(COLOR_STYLE.arg( + result.name()).arg(Settings::getIdealTextColor( + result).name())); + + /*ui->overwrittenBtn->setAutoFillBackground(true); + ui->overwrittenBtn->setPalette(QPalette(result)); + QPalette palette = ui->overwrittenBtn->palette(); + palette.setColor(QPalette::Background, result); + ui->overwrittenBtn->setPalette(palette);*/ + } +} + +void SettingsDialog::on_overwritingBtn_clicked() +{ + QColor result = QColorDialog::getColor(m_OverwritingColor, this); + if (result.isValid()) { + m_OverwritingColor = result; + + QString COLOR_STYLE("QPushButton { background-color : %1; color : %2; }"); + ui->overwritingBtn->setStyleSheet(COLOR_STYLE.arg( + result.name()).arg(Settings::getIdealTextColor( + result).name())); + + /*ui->overwritingBtn->setAutoFillBackground(true); + ui->overwritingBtn->setPalette(QPalette(result)); + QPalette palette = ui->overwritingBtn->palette(); + palette.setColor(QPalette::Background, result); + ui->overwritingBtn->setPalette(palette);*/ + } +} + +void SettingsDialog::on_resetColorsBtn_clicked() +{ + m_OverwritingColor = QColor(255, 0, 0, 64); + m_OverwrittenColor = QColor(0, 255, 0, 64); + m_ContainsColor = QColor(0, 0, 255, 64); + m_ContainedColor = QColor(0, 0, 255, 64); + + QString COLOR_STYLE("QPushButton { background-color : %1; color : %2; }"); + + ui->overwritingBtn->setStyleSheet(COLOR_STYLE.arg( + QColor(255, 0, 0, 64).name()).arg(Settings::getIdealTextColor( + QColor(255, 0, 0, 64)).name())); + + ui->overwrittenBtn->setStyleSheet(COLOR_STYLE.arg( + QColor(0, 255, 0, 64).name()).arg(Settings::getIdealTextColor( + QColor(0, 255, 0, 64)).name())); + + ui->containsBtn->setStyleSheet(COLOR_STYLE.arg( + QColor(0, 0, 255, 64).name()).arg(Settings::getIdealTextColor( + QColor(0, 0, 255, 64)).name())); + + ui->containedBtn->setStyleSheet(COLOR_STYLE.arg( + QColor(0, 0, 255, 64).name()).arg(Settings::getIdealTextColor( + QColor(0, 0, 255, 64)).name())); + +} + void SettingsDialog::on_resetDialogsButton_clicked() { if (QMessageBox::question(this, tr("Confirm?"), diff --git a/src/settingsdialog.h b/src/settingsdialog.h index 2e270131..c678ec78 100644 --- a/src/settingsdialog.h +++ b/src/settingsdialog.h @@ -56,6 +56,18 @@ private: void storeSettings(QListWidgetItem *pluginItem); +public: + + QColor getOverwritingColor() { return m_OverwritingColor; } + QColor getOverwrittenColor() { return m_OverwrittenColor; } + QColor getContainsColor() { return m_ContainsColor; } + QColor getContainedColor() { return m_ContainedColor; } + + void setOverwritingColor(QColor col) { m_OverwritingColor = col; } + void setOverwrittenColor(QColor col) { m_OverwrittenColor = col; } + void setContainsColor(QColor col) { m_ContainsColor = col; } + void setContainedColor(QColor col) { m_ContainedColor = col; } + private slots: void on_loginCheckBox_toggled(bool checked); @@ -85,9 +97,24 @@ private slots: void on_browseProfilesDirBtn_clicked(); + void on_overwritingBtn_clicked(); + + void on_overwrittenBtn_clicked(); + + void on_containsBtn_clicked(); + + void on_containedBtn_clicked(); + + void on_resetColorsBtn_clicked(); + private: Ui::SettingsDialog *ui; PluginContainer *m_PluginContainer; + + QColor m_OverwritingColor; + QColor m_OverwrittenColor; + QColor m_ContainsColor; + QColor m_ContainedColor; }; diff --git a/src/settingsdialog.ui b/src/settingsdialog.ui index 05814091..4d6535dc 100644 --- a/src/settingsdialog.ui +++ b/src/settingsdialog.ui @@ -92,28 +92,65 @@ If you use pre-releases, never contact me directly by e-mail or via private mess User interface - - - - - If checked, the download interface will be more compact. - - - Compact Download Interface + + + + + Colors + + + + + Mod Contains selected Plugin + + + + + + + Plugin is Contained in selected Mod + + + + + + + Reset Colors + + + + + + + Is overwritten (loose files) + + + + + + + Is overwriting (loose files) + + + + - - + + - If checked, the download list will display meta information instead of file names. + Modify the categories available to arrange your mods. + + + Modify the categories available to arrange your mods. - Download Meta Information + Configure Mod Categories - + @@ -132,7 +169,17 @@ If you use pre-releases, never contact me directly by e-mail or via private mess - + + + + If checked, the download interface will be more compact. + + + Compact Download Interface + + + + Qt::Vertical @@ -145,16 +192,13 @@ If you use pre-releases, never contact me directly by e-mail or via private mess - - + + - Modify the categories available to arrange your mods. - - - Modify the categories available to arrange your mods. + If checked, the download list will display meta information instead of file names. - Configure Mod Categories + Download Meta Information @@ -1217,8 +1261,6 @@ For the other games this is not a sufficient replacement for AI! logLevelBox usePrereleaseBox compactBox - showMetaBox - resetDialogsButton categoriesBtn baseDirEdit browseBaseDirBtn -- cgit v1.3.1 From 2c57899cf611056a8c5bae1f7f27c9a157df6f41 Mon Sep 17 00:00:00 2001 From: LostDragonist Date: Thu, 1 Nov 2018 17:58:49 -0500 Subject: Fix matching highlights for mod and plugin selections The selectionChanged event used before requires subtractive/additive logic to work correctly. A separate event is fired for each row and each column for each row that is selected or deselected. The previous logic assumed all of the selection was passed in at once. The logic has been changed to recalculate all highlights each time the event is fired. This is poorly optimized in regards to performance but makes the function work. --- src/mainwindow.cpp | 4 ++-- src/modlist.cpp | 5 +++-- src/modlist.h | 2 +- src/pluginlist.cpp | 11 +++++++---- src/pluginlist.h | 2 +- 5 files changed, 14 insertions(+), 10 deletions(-) (limited to 'src/modlist.cpp') diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 5b257977..752c5c76 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -2341,13 +2341,13 @@ void MainWindow::modlistSelectionChanged(const QModelIndex ¤t, const QMode void MainWindow::modlistSelectionsChanged(const QItemSelection &selected) { - m_OrganizerCore.pluginList()->highlightPlugins(selected, *m_OrganizerCore.directoryStructure(), *m_OrganizerCore.currentProfile()); + m_OrganizerCore.pluginList()->highlightPlugins(ui->modList->selectionModel(), *m_OrganizerCore.directoryStructure(), *m_OrganizerCore.currentProfile()); ui->espList->verticalScrollBar()->repaint(); } void MainWindow::esplistSelectionsChanged(const QItemSelection &selected) { - m_OrganizerCore.modList()->highlightMods(selected, *m_OrganizerCore.directoryStructure()); + m_OrganizerCore.modList()->highlightMods(ui->espList->selectionModel(), *m_OrganizerCore.directoryStructure()); ui->modList->verticalScrollBar()->repaint(); } diff --git a/src/modlist.cpp b/src/modlist.cpp index 3f8fa0c0..539ba6fc 100644 --- a/src/modlist.cpp +++ b/src/modlist.cpp @@ -24,6 +24,7 @@ along with Mod Organizer. If not, see . #include "qtgroupingproxy.h" #include "viewmarkingscrollbar.h" #include "modlistsortproxy.h" +#include "pluginlist.h" #include "settings.h" #include "modinforegular.h" #include @@ -768,12 +769,12 @@ int ModList::timeElapsedSinceLastChecked() const return m_LastCheck.elapsed(); } -void ModList::highlightMods(const QItemSelection &selected, const MOShared::DirectoryEntry &directoryEntry) +void ModList::highlightMods(const QItemSelectionModel *selection, const MOShared::DirectoryEntry &directoryEntry) { for (unsigned int i = 0; i < ModInfo::getNumMods(); ++i) { ModInfo::getByIndex(i)->setPluginSelected(false); } - for (QModelIndex idx : selected.indexes()) { + for (QModelIndex idx : selection->selectedRows(PluginList::COL_NAME)) { QString modName = idx.data().toString(); const MOShared::FileEntry::Ptr fileEntry = directoryEntry.findFile(modName.toStdWString()); diff --git a/src/modlist.h b/src/modlist.h index caad8c61..8de08da3 100644 --- a/src/modlist.h +++ b/src/modlist.h @@ -118,7 +118,7 @@ public: int timeElapsedSinceLastChecked() const; - void highlightMods(const QItemSelection &selected, const MOShared::DirectoryEntry &directoryEntry); + void highlightMods(const QItemSelectionModel *selection, const MOShared::DirectoryEntry &directoryEntry); public: diff --git a/src/pluginlist.cpp b/src/pluginlist.cpp index d56a4bde..21e716d3 100644 --- a/src/pluginlist.cpp +++ b/src/pluginlist.cpp @@ -21,6 +21,7 @@ along with Mod Organizer. If not, see . #include "settings.h" #include "scopeguard.h" #include "modinfo.h" +#include "modlist.h" #include "viewmarkingscrollbar.h" #include #include @@ -119,14 +120,16 @@ QString PluginList::getColumnToolTip(int column) } } -void PluginList::highlightPlugins(const QItemSelection &selected, const MOShared::DirectoryEntry &directoryEntry, const Profile &profile) +void PluginList::highlightPlugins(const QItemSelectionModel *selection, const MOShared::DirectoryEntry &directoryEntry, const Profile &profile) { for (auto &esp : m_ESPs) { esp.m_ModSelected = false; } - for (QModelIndex idx : selected.indexes()) { - ModInfo::Ptr selectedMod = ModInfo::getByIndex(idx.data(Qt::UserRole + 1).toInt()); - if (!selectedMod.isNull() && profile.modEnabled(idx.data(Qt::UserRole + 1).toInt())) { + for (QModelIndex idx : selection->selectedRows(ModList::COL_PRIORITY)) { + int modPriority = idx.data().toInt(); + int modIndex = profile.modIndexByPriority(modPriority); + ModInfo::Ptr selectedMod = ModInfo::getByIndex(modIndex); + if (!selectedMod.isNull() && profile.modEnabled(modIndex)) { QDir dir(selectedMod->absolutePath()); QStringList plugins = dir.entryList(QStringList() << "*.esp" << "*.esm" << "*.esl"); MOShared::FilesOrigin origin = directoryEntry.getOriginByName(selectedMod->internalName().toStdWString()); diff --git a/src/pluginlist.h b/src/pluginlist.h index 009c9153..f7817c37 100644 --- a/src/pluginlist.h +++ b/src/pluginlist.h @@ -206,7 +206,7 @@ public: static QString getColumnName(int column); static QString getColumnToolTip(int column); - void highlightPlugins(const QItemSelection &selected, const MOShared::DirectoryEntry &directoryEntry, const Profile &profile); + void highlightPlugins(const QItemSelectionModel *selection, const MOShared::DirectoryEntry &directoryEntry, const Profile &profile); void refreshLoadOrder(); -- cgit v1.3.1 From 4cae1397e7e54a2b4f5593d6ad74c969471c3055 Mon Sep 17 00:00:00 2001 From: LostDragonist Date: Mon, 26 Nov 2018 07:44:26 -0600 Subject: Prevent the user from setting a negative mod priority --- src/modlist.cpp | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src/modlist.cpp') diff --git a/src/modlist.cpp b/src/modlist.cpp index 539ba6fc..6c04738a 100644 --- a/src/modlist.cpp +++ b/src/modlist.cpp @@ -526,6 +526,9 @@ bool ModList::setData(const QModelIndex &index, const QVariant &value, int role) case COL_PRIORITY: { bool ok = false; int newPriority = value.toInt(&ok); + if (ok && newPriority < 0) { + newPriority = 0; + } if (ok) { m_Profile->setModPriority(modID, newPriority); -- cgit v1.3.1 From 6142872620983a2bdd352d4e9e391ddb11c40305 Mon Sep 17 00:00:00 2001 From: LostDragonist Date: Mon, 26 Nov 2018 07:51:45 -0600 Subject: Prevent the user from renaming unmanaged and DLC mods --- src/modlist.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'src/modlist.cpp') diff --git a/src/modlist.cpp b/src/modlist.cpp index 6c04738a..7ca0667a 100644 --- a/src/modlist.cpp +++ b/src/modlist.cpp @@ -616,17 +616,20 @@ Qt::ItemFlags ModList::flags(const QModelIndex &modelIndex) const } if (modelIndex.isValid()) { ModInfo::Ptr modInfo = ModInfo::getByIndex(modelIndex.row()); + std::vector flags = modInfo->getFlags(); if (modInfo->getFixedPriority() == INT_MIN) { result |= Qt::ItemIsDragEnabled; result |= Qt::ItemIsUserCheckable; - if ((modelIndex.column() == COL_NAME) || - (modelIndex.column() == COL_PRIORITY) || + if ((modelIndex.column() == COL_PRIORITY) || (modelIndex.column() == COL_VERSION) || (modelIndex.column() == COL_MODID)) { result |= Qt::ItemIsEditable; } + if ((modelIndex.column() == COL_NAME) + && (std::find(flags.begin(), flags.end(), ModInfo::FLAG_FOREIGN) == flags.end())) { + result |= Qt::ItemIsEditable; + } } - std::vector flags = modInfo->getFlags(); if (m_DropOnItems && (std::find(flags.begin(), flags.end(), ModInfo::FLAG_OVERWRITE) == flags.end())) { result |= Qt::ItemIsDropEnabled; -- cgit v1.3.1 From c501b5cca081e1b3697904a3b4e1e236ea9c4e69 Mon Sep 17 00:00:00 2001 From: LostDragonist Date: Sat, 8 Dec 2018 10:37:46 -0600 Subject: Add notes column to mod list --- src/mainwindow.cpp | 4 ++++ src/modinfo.cpp | 2 +- src/modinfo.h | 17 ++++++++++++++--- src/modinfodialog.cpp | 2 ++ src/modinfodialog.ui | 25 ++++++++++++++++++++++++- src/modinfoforeign.h | 2 ++ src/modinfooverwrite.h | 2 ++ src/modinforegular.cpp | 17 +++++++++++++++-- src/modinforegular.h | 12 ++++++++++++ src/modlist.cpp | 24 ++++++++++++++++++++++-- src/modlist.h | 3 ++- 11 files changed, 100 insertions(+), 10 deletions(-) (limited to 'src/modlist.cpp') diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 84b77945..9a40ce2e 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -299,6 +299,7 @@ MainWindow::MainWindow(QSettings &initSettings ui->modList->header()->setSectionHidden(ModList::COL_MODID, true); ui->modList->header()->setSectionHidden(ModList::COL_GAME, true); ui->modList->header()->setSectionHidden(ModList::COL_INSTALLTIME, true); + ui->modList->header()->setSectionHidden(ModList::COL_NOTES, true); } ui->modList->header()->setSectionHidden(ModList::COL_NAME, false); // prevent the name-column from being hidden @@ -1726,6 +1727,9 @@ void MainWindow::processUpdates() { lastHidden = hidden; } } + if (lastVersion < QVersionNumber(2,1,6)) { + ui->modList->header()->setSectionHidden(ModList::COL_NOTES, true); + } } if (currentVersion > lastVersion) diff --git a/src/modinfo.cpp b/src/modinfo.cpp index 4c41a114..1c6139f6 100644 --- a/src/modinfo.cpp +++ b/src/modinfo.cpp @@ -104,7 +104,7 @@ QString ModInfo::getContentTypeName(int contentType) case CONTENT_SOUND: return tr("Sound Effects"); case CONTENT_SCRIPT: return tr("Scripts"); case CONTENT_SKSE: return tr("Script Extender"); - case CONTENT_SKSEFILES: return tr("Script Extender Files"); + case CONTENT_SKSEFILES: return tr("Script Extender Files"); case CONTENT_SKYPROC: return tr("SkyProc Tools"); case CONTENT_MCM: return tr("MCM Data"); case CONTENT_INI: return tr("INI files"); diff --git a/src/modinfo.h b/src/modinfo.h index 235fb50c..5a69185d 100644 --- a/src/modinfo.h +++ b/src/modinfo.h @@ -44,7 +44,7 @@ namespace MOShared { class DirectoryEntry; } /** * @brief Represents meta information about a single mod. - * + * * Represents meta information about a single mod. The class interface is used * to manage the mod collection * @@ -85,7 +85,7 @@ public: CONTENT_SOUND, CONTENT_SCRIPT, CONTENT_SKSE, - CONTENT_SKSEFILES, + CONTENT_SKSEFILES, CONTENT_SKYPROC, CONTENT_MCM, CONTENT_INI, @@ -268,6 +268,12 @@ public: **/ virtual void setCategory(int categoryID, bool active) = 0; + /** + * @brief changes the comments (manually set information displayed in the mod list) for this mod + * @param comments new comments + */ + virtual void setComments(const QString &comments) = 0; + /** * @brief change the notes (manually set information) for this mod * @param notes new notes @@ -495,6 +501,11 @@ public: */ virtual QString getDescription() const = 0; + /** + * @return comments for this mod + */ + virtual QString comments() const = 0; + /** * @return notes for this mod */ @@ -526,7 +537,7 @@ public: virtual QStringList archives() const = 0; /* - *@return the color choosen by the user for the mod/separator + *@return the color choosen by the user for the mod/separator */ virtual QColor getColor() { return QColor(); } diff --git a/src/modinfodialog.cpp b/src/modinfodialog.cpp index 54910e41..416eca58 100644 --- a/src/modinfodialog.cpp +++ b/src/modinfodialog.cpp @@ -112,6 +112,7 @@ ModInfoDialog::ModInfoDialog(ModInfo::Ptr modInfo, const DirectoryEntry *directo } ui->sourceGameEdit->setCurrentIndex(ui->sourceGameEdit->findData(gameName)); + ui->commentsEdit->setText(modInfo->comments()); ui->notesEdit->setText(modInfo->notes()); ui->descriptionView->setPage(new DescriptionPage); @@ -189,6 +190,7 @@ ModInfoDialog::ModInfoDialog(ModInfo::Ptr modInfo, const DirectoryEntry *directo ModInfoDialog::~ModInfoDialog() { + m_ModInfo->setComments(ui->commentsEdit->text()); m_ModInfo->setNotes(ui->notesEdit->toPlainText()); saveCategories(ui->categoriesTree->invisibleRootItem()); saveIniTweaks(); // ini tweaks are written to the ini file directly. This is the only information not managed by ModInfo diff --git a/src/modinfodialog.ui b/src/modinfodialog.ui index b3873bf3..671c7f31 100644 --- a/src/modinfodialog.ui +++ b/src/modinfodialog.ui @@ -782,7 +782,30 @@ p, li { white-space: pre-wrap; } - + + + Enter comments about the mod here. These are displayed in the notes column of the mod list. + + + Enter comments about the mod here. These are displayed in the notes column of the mod list. + + + Enter comments about the mod here. These are displayed in the notes column of the mod list. + + + + + + + Enter notes about the mod here. These can be viewed in the mod list by hovering over the notes column or the flags column. + + + Enter notes about the mod here. These can be viewed in the mod list by hovering over the notes column or the flags column. + + + Enter notes about the mod here. These can be viewed in the mod list by hovering over the notes column or the flags column. + + diff --git a/src/modinfoforeign.h b/src/modinfoforeign.h index 0d7b3847..93061294 100644 --- a/src/modinfoforeign.h +++ b/src/modinfoforeign.h @@ -18,6 +18,7 @@ public: virtual bool updateNXMInfo() { return false; } virtual void setCategory(int, bool) {} virtual bool setName(const QString&) { return false; } + virtual void setComments(const QString&) {} virtual void setNotes(const QString&) {} virtual void setGameName(QString) {} virtual void setNexusID(int) {} @@ -33,6 +34,7 @@ public: virtual bool isEmpty() const { return false; } virtual QString name() const; virtual QString internalName() const { return name(); } + virtual QString comments() const { return ""; } virtual QString notes() const { return ""; } virtual QDateTime creationTime() const; virtual QString absolutePath() const; diff --git a/src/modinfooverwrite.h b/src/modinfooverwrite.h index 5681dc6f..4b98d715 100644 --- a/src/modinfooverwrite.h +++ b/src/modinfooverwrite.h @@ -20,6 +20,7 @@ public: virtual bool updateNXMInfo() { return false; } virtual void setCategory(int, bool) {} virtual bool setName(const QString&) { return false; } + virtual void setComments(const QString&) {} virtual void setNotes(const QString&) {} virtual void setGameName(QString) {} virtual void setNexusID(int) {} @@ -35,6 +36,7 @@ public: virtual bool alwaysEnabled() const { return true; } virtual bool isEmpty() const; virtual QString name() const { return "Overwrite"; } + virtual QString comments() const { return ""; } virtual QString notes() const { return ""; } virtual QDateTime creationTime() const { return QDateTime(); } virtual QString absolutePath() const; diff --git a/src/modinforegular.cpp b/src/modinforegular.cpp index d0f56a52..6a52d3df 100644 --- a/src/modinforegular.cpp +++ b/src/modinforegular.cpp @@ -76,6 +76,7 @@ bool ModInfoRegular::isEmpty() const void ModInfoRegular::readMeta() { QSettings metaFile(m_Path + "/meta.ini", QSettings::IniFormat); + m_Comments = metaFile.value("comments", "").toString(); m_Notes = metaFile.value("notes", "").toString(); QString tempGameName = metaFile.value("gameName", m_GameName).toString(); if (tempGameName.size()) m_GameName = tempGameName; @@ -148,6 +149,7 @@ void ModInfoRegular::saveMeta() metaFile.setValue("repository", m_Repository); metaFile.setValue("gameName", m_GameName); metaFile.setValue("modid", m_NexusID); + metaFile.setValue("comments", m_Comments); metaFile.setValue("notes", m_Notes); metaFile.setValue("nexusDescription", m_NexusDescription); metaFile.setValue("url", m_URL); @@ -324,6 +326,12 @@ bool ModInfoRegular::setName(const QString &name) return true; } +void ModInfoRegular::setComments(const QString &comments) +{ + m_Comments = comments; + m_MetaInfoChanged = true; +} + void ModInfoRegular::setNotes(const QString ¬es) { m_Notes = notes; @@ -405,7 +413,7 @@ void ModInfoRegular::setColor(QColor color) m_MetaInfoChanged = true; } -QColor ModInfoRegular::getColor() +QColor ModInfoRegular::getColor() { return m_Color; } @@ -510,7 +518,7 @@ std::vector ModInfoRegular::getContents() const if (sePluginDir.entryList(QStringList() << "*.dll").size() > 0) { m_CachedContent.push_back(CONTENT_SKSE); } - } + } } if (dir.exists("textures") || dir.exists("icons") || dir.exists("bookart")) m_CachedContent.push_back(CONTENT_TEXTURE); @@ -567,6 +575,11 @@ QString ModInfoRegular::getDescription() const } } +QString ModInfoRegular::comments() const +{ + return m_Comments; +} + QString ModInfoRegular::notes() const { return m_Notes; diff --git a/src/modinforegular.h b/src/modinforegular.h index 78a6e58a..33b26998 100644 --- a/src/modinforegular.h +++ b/src/modinforegular.h @@ -90,6 +90,12 @@ public: **/ bool setName(const QString &name); + /** + * @brief changes the comments (manually set information displayed in the mod list) for this mod + * @param comments new comments + */ + void setComments(const QString &comments); + /** * @brief change the notes (manually set information) for this mod * @param notes new notes @@ -279,6 +285,11 @@ public: */ virtual QString getDescription() const; + /** + * @return comments for this mod + */ + virtual QString comments() const; + /** * @return manually set notes for this mod */ @@ -353,6 +364,7 @@ private: QString m_Name; QString m_Path; QString m_InstallationFile; + QString m_Comments; QString m_Notes; QString m_NexusDescription; QString m_Repository; diff --git a/src/modlist.cpp b/src/modlist.cpp index 7ca0667a..547cc853 100644 --- a/src/modlist.cpp +++ b/src/modlist.cpp @@ -150,7 +150,14 @@ QString ModList::getFlagText(ModInfo::EFlag flag, ModInfo::Ptr modInfo) const case ModInfo::FLAG_SEPARATOR: return tr("Separator"); case ModInfo::FLAG_INVALID: return tr("No valid game data"); case ModInfo::FLAG_NOTENDORSED: return tr("Not endorsed yet"); - case ModInfo::FLAG_NOTES: return QString("%1").arg(modInfo->notes().replace("\n", "
")); + case ModInfo::FLAG_NOTES: { + QStringList output; + if (!modInfo->comments().isEmpty()) + output << QString("%1").arg(modInfo->comments()); + if (!modInfo->notes().isEmpty()) + output << QString("%1").arg(modInfo->notes()).replace("\n", "
"); + return output.join("
"); + } case ModInfo::FLAG_CONFLICT_OVERWRITE: return tr("Overwrites files"); case ModInfo::FLAG_CONFLICT_OVERWRITTEN: return tr("Overwritten files"); case ModInfo::FLAG_CONFLICT_MIXED: return tr("Overwrites & Overwritten"); @@ -276,6 +283,8 @@ QVariant ModList::data(const QModelIndex &modelIndex, int role) const } else { return QVariant(); } + } else if (column == COL_NOTES) { + return modInfo->comments(); } else { return tr("invalid"); } @@ -295,6 +304,8 @@ QVariant ModList::data(const QModelIndex &modelIndex, int role) const } } else if (column == COL_VERSION) { return QVariant(Qt::AlignRight | Qt::AlignVCenter); + } else if (column == COL_NOTES) { + return QVariant(Qt::AlignLeft | Qt::AlignVCenter); } else { return QVariant(Qt::AlignCenter | Qt::AlignVCenter); } @@ -443,6 +454,8 @@ QVariant ModList::data(const QModelIndex &modelIndex, int role) const } return ToQString(categoryString.str()); + } else if (column == COL_NOTES) { + return getFlagText(ModInfo::FLAG_NOTES, modInfo); } else { return QVariant(); } @@ -559,6 +572,10 @@ bool ModList::setData(const QModelIndex &index, const QVariant &value, int role) result = false; } } break; + case COL_NOTES: { + info->setComments(value.toString()); + result = true; + } break; default: { qWarning("edit on column \"%s\" not supported", getColumnName(index.column()).toUtf8().constData()); @@ -625,7 +642,8 @@ Qt::ItemFlags ModList::flags(const QModelIndex &modelIndex) const (modelIndex.column() == COL_MODID)) { result |= Qt::ItemIsEditable; } - if ((modelIndex.column() == COL_NAME) + if (((modelIndex.column() == COL_NAME) || + (modelIndex.column() == COL_NOTES)) && (std::find(flags.begin(), flags.end(), ModInfo::FLAG_FOREIGN) == flags.end())) { result |= Qt::ItemIsEditable; } @@ -1147,6 +1165,7 @@ QString ModList::getColumnName(int column) case COL_GAME: return tr("Source Game"); case COL_MODID: return tr("Nexus ID"); case COL_INSTALLTIME: return tr("Installation"); + case COL_NOTES: return tr("Notes"); default: return tr("unknown"); } } @@ -1182,6 +1201,7 @@ QString ModList::getColumnToolTip(int column) ""); case COL_INSTALLTIME: return tr("Time this mod was installed"); + case COL_NOTES: return tr("User notes about the mod"); default: return tr("unknown"); } } diff --git a/src/modlist.h b/src/modlist.h index 8de08da3..42269386 100644 --- a/src/modlist.h +++ b/src/modlist.h @@ -65,8 +65,9 @@ public: COL_VERSION, COL_INSTALLTIME, COL_PRIORITY, + COL_NOTES, - COL_LASTCOLUMN = COL_PRIORITY + COL_LASTCOLUMN = COL_NOTES }; typedef boost::signals2::signal SignalModStateChanged; -- cgit v1.3.1 From 5335188e635c8c1b1cb2529e2a921d15c7d02058 Mon Sep 17 00:00:00 2001 From: LostDragonist Date: Tue, 11 Dec 2018 14:47:50 -0600 Subject: Add option to remove column colors for mod list separators --- src/modlist.cpp | 8 +++++--- src/settings.cpp | 8 ++++++++ src/settings.h | 7 +++++++ src/settingsdialog.ui | 40 ++++++++++++++++++++++++++++------------ 4 files changed, 48 insertions(+), 15 deletions(-) (limited to 'src/modlist.cpp') diff --git a/src/modlist.cpp b/src/modlist.cpp index 547cc853..dfe2efd3 100644 --- a/src/modlist.cpp +++ b/src/modlist.cpp @@ -395,7 +395,6 @@ QVariant ModList::data(const QModelIndex &modelIndex, int role) const return QVariant(); } else if ((role == Qt::BackgroundRole) || (role == ViewMarkingScrollBar::DEFAULT_ROLE)) { - auto flags = modInfo->getFlags(); if (modInfo->getHighlight() & ModInfo::HIGHLIGHT_PLUGIN) { return Settings::instance().modlistContainsPluginColor(); } else if (m_Overwrite.find(modIndex) != m_Overwrite.end()) { @@ -403,8 +402,11 @@ QVariant ModList::data(const QModelIndex &modelIndex, int role) const } else if (m_Overwritten.find(modIndex) != m_Overwritten.end()) { return Settings::instance().modlistOverwritingLooseColor(); - } else if (std::find(flags.begin(), flags.end(), ModInfo::FLAG_SEPARATOR) != flags.end() && modInfo->getColor().isValid()) { - return modInfo->getColor(); + } else if (modInfo->hasFlag(ModInfo::FLAG_SEPARATOR) + && modInfo->getColor().isValid() + && ((role != ViewMarkingScrollBar::DEFAULT_ROLE) + || Settings::instance().colorSeparatorScrollbar())) { + return modInfo->getColor(); } else { return QVariant(); } diff --git a/src/settings.cpp b/src/settings.cpp index 5db656d8..18e893cb 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -148,6 +148,11 @@ void Settings::registerAsNXMHandler(bool force) } } +bool Settings::colorSeparatorScrollbar() const +{ + return m_Settings.value("Settings/colorSeparatorScrollbars", true).toBool(); +} + void Settings::managedGameChanged(IPluginGame const *gamePlugin) { m_GamePlugin = gamePlugin; @@ -716,6 +721,7 @@ Settings::GeneralTab::GeneralTab(Settings *m_parent, SettingsDialog &m_dialog) , m_overwrittenBtn(m_dialog.findChild("overwrittenBtn")) , m_containsBtn(m_dialog.findChild("containsBtn")) , m_containedBtn(m_dialog.findChild("containedBtn")) + , m_colorSeparatorsBox(m_dialog.findChild("colorSeparatorsBox")) { // FIXME I think 'addLanguages' lives in here not in parent m_parent->addLanguages(m_languageBox); @@ -788,6 +794,7 @@ Settings::GeneralTab::GeneralTab(Settings *m_parent, SettingsDialog &m_dialog) m_compactBox->setChecked(m_parent->compactDownloads()); m_showMetaBox->setChecked(m_parent->metaDownloads()); m_usePrereleaseBox->setChecked(m_parent->usePrereleases()); + m_colorSeparatorsBox->setChecked(m_parent->colorSeparatorScrollbar()); } void Settings::GeneralTab::update() @@ -813,6 +820,7 @@ void Settings::GeneralTab::update() m_Settings.setValue("Settings/compact_downloads", m_compactBox->isChecked()); m_Settings.setValue("Settings/meta_downloads", m_showMetaBox->isChecked()); m_Settings.setValue("Settings/use_prereleases", m_usePrereleaseBox->isChecked()); + m_Settings.setValue("Settings/colorSeparatorScrollbars", m_colorSeparatorsBox->isChecked()); } Settings::PathsTab::PathsTab(Settings *parent, SettingsDialog &dialog) diff --git a/src/settings.h b/src/settings.h index 4009d4a3..912864e2 100644 --- a/src/settings.h +++ b/src/settings.h @@ -365,6 +365,12 @@ public: */ void registerAsNXMHandler(bool force); + /** + * @brief color the scrollbar of the mod list for custom separator colors? + * @return the state of the setting + */ + bool colorSeparatorScrollbar() const; + public slots: void managedGameChanged(MOBase::IPluginGame const *gamePlugin); @@ -414,6 +420,7 @@ private: QPushButton *m_overwrittenBtn; QPushButton *m_containsBtn; QPushButton *m_containedBtn; + QCheckBox *m_colorSeparatorsBox; }; class PathsTab : public SettingsTab diff --git a/src/settingsdialog.ui b/src/settingsdialog.ui index 80a6a0e7..6557bbcc 100644 --- a/src/settingsdialog.ui +++ b/src/settingsdialog.ui @@ -99,31 +99,31 @@ If you use pre-releases, never contact me directly by e-mail or via private mess Colors - - + + - Mod Contains selected Plugin + Reset Colors - - + + - Plugin is Contained in selected Mod + Is overwritten (loose files) - - + + - Reset Colors + Mod Contains selected Plugin - - + + - Is overwritten (loose files) + Plugin is Contained in selected Mod @@ -134,6 +134,22 @@ If you use pre-releases, never contact me directly by e-mail or via private mess + + + + When this is enabled, the color defined for a separator will be shown on the mod list scrollbar at the location of the separator. This can be useful for quick navigation between separator sections or to a specific separator section. + + + When this is enabled, the color defined for a separator will be shown on the mod list scrollbar at the location of the separator. This can be useful for quick navigation between separator sections or to a specific separator section. + + + Show mod list separator colors on the scrollbar + + + true + + + -- cgit v1.3.1 From f6cd53e9327316b68520ddd0e4e607b22ac5fbd1 Mon Sep 17 00:00:00 2001 From: LostDragonist Date: Tue, 11 Dec 2018 15:24:25 -0600 Subject: Change color of separator text based on the configured color of the separator --- src/modlist.cpp | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'src/modlist.cpp') diff --git a/src/modlist.cpp b/src/modlist.cpp index dfe2efd3..ee7db894 100644 --- a/src/modlist.cpp +++ b/src/modlist.cpp @@ -378,6 +378,11 @@ QVariant ModList::data(const QModelIndex &modelIndex, int role) const } } return QVariant(); + } else if (role == Qt::TextColorRole) { + if (modInfo->hasFlag(ModInfo::FLAG_SEPARATOR) && modInfo->getColor().isValid()) { + return Settings::getIdealTextColor(modInfo->getColor()); + } + return QVariant(); } else if (role == Qt::ForegroundRole) { if (column == COL_NAME) { int highlight = modInfo->getHighlight(); -- cgit v1.3.1 From 68a1afed49a204268e5b1ca374f3989766d75706 Mon Sep 17 00:00:00 2001 From: LostDragonist Date: Tue, 11 Dec 2018 20:31:17 -0600 Subject: Implement separator text color in a way that doesn't break everything else --- src/modlist.cpp | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) (limited to 'src/modlist.cpp') diff --git a/src/modlist.cpp b/src/modlist.cpp index ee7db894..16d2cd07 100644 --- a/src/modlist.cpp +++ b/src/modlist.cpp @@ -378,16 +378,15 @@ QVariant ModList::data(const QModelIndex &modelIndex, int role) const } } return QVariant(); - } else if (role == Qt::TextColorRole) { + } else if (role == Qt::ForegroundRole) { if (modInfo->hasFlag(ModInfo::FLAG_SEPARATOR) && modInfo->getColor().isValid()) { return Settings::getIdealTextColor(modInfo->getColor()); - } - return QVariant(); - } else if (role == Qt::ForegroundRole) { - if (column == COL_NAME) { + } else if (column == COL_NAME) { int highlight = modInfo->getHighlight(); - if (highlight & ModInfo::HIGHLIGHT_IMPORTANT) return QBrush(Qt::darkRed); - else if (highlight & ModInfo::HIGHLIGHT_INVALID) return QBrush(Qt::darkGray); + if (highlight & ModInfo::HIGHLIGHT_IMPORTANT) + return QBrush(Qt::darkRed); + else if (highlight & ModInfo::HIGHLIGHT_INVALID) + return QBrush(Qt::darkGray); } else if (column == COL_VERSION) { if (!modInfo->getNewestVersion().isValid()) { return QVariant(); -- cgit v1.3.1