diff options
| author | Jeremy Rimpo <jeremy.rimpo@servermonkey.com> | 2023-09-25 17:39:41 -0500 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2023-09-25 17:39:41 -0500 |
| commit | 79d457f598bcfa7a8d094a87033a31f370c9c4c1 (patch) | |
| tree | 3674e6b1223ac104422ce77b06d020c50ad31cc0 /src/categories.cpp | |
| parent | 70509275405d2a5c5e94743786f03b17ef2051f2 (diff) | |
| parent | 74668b9363d877d055a5e8b8c7d001ba448dc832 (diff) | |
Merge pull request #1880 from ModOrganizer2/qt6-category
WIP: Category Revamp
Diffstat (limited to 'src/categories.cpp')
| -rw-r--r-- | src/categories.cpp | 341 |
1 files changed, 217 insertions, 124 deletions
diff --git a/src/categories.cpp b/src/categories.cpp index 70efd706..c1aa756f 100644 --- a/src/categories.cpp +++ b/src/categories.cpp @@ -29,6 +29,8 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. #include <QList> #include <QObject> +#include "nexusinterface.h" + using namespace MOBase; CategoryFactory* CategoryFactory::s_Instance = nullptr; @@ -38,30 +40,33 @@ QString CategoryFactory::categoriesFilePath() return qApp->property("dataPath").toString() + "/categories.dat"; } -CategoryFactory::CategoryFactory() +CategoryFactory::CategoryFactory() : QObject() { atexit(&cleanup); } +QString CategoryFactory::nexusMappingFilePath() +{ + return qApp->property("dataPath").toString() + "/nexuscatmap.dat"; +} + void CategoryFactory::loadCategories() { reset(); QFile categoryFile(categoriesFilePath()); + bool needLoad = false; if (!categoryFile.open(QIODevice::ReadOnly)) { - loadDefaultCategories(); + needLoad = true; } else { int lineNum = 0; while (!categoryFile.atEnd()) { QByteArray line = categoryFile.readLine(); ++lineNum; QList<QByteArray> cells = line.split('|'); - if (cells.count() != 4) { - log::error("invalid category line {}: {} ({} cells)", lineNum, line.constData(), - cells.count()); - } else { - std::vector<int> nexusIDs; + if (cells.count() == 4) { + std::vector<NexusCategory> nexusCats; if (cells[2].length() > 0) { QList<QByteArray> nexusIDStrings = cells[2].split(','); for (QList<QByteArray>::iterator iter = nexusIDStrings.begin(); @@ -69,9 +74,9 @@ void CategoryFactory::loadCategories() bool ok = false; int temp = iter->toInt(&ok); if (!ok) { - log::error("invalid category id {}", iter->constData()); + log::error(tr("invalid category id {}").toStdString(), iter->constData()); } - nexusIDs.push_back(temp); + nexusCats.push_back(NexusCategory("Unknown", temp)); } } bool cell0Ok = true; @@ -79,50 +84,94 @@ void CategoryFactory::loadCategories() int id = cells[0].toInt(&cell0Ok); int parentID = cells[3].trimmed().toInt(&cell3Ok); if (!cell0Ok || !cell3Ok) { - log::error("invalid category line {}: {}", lineNum, line.constData()); + log::error(tr("invalid category line {}: {}").toStdString(), lineNum, + line.constData()); } - addCategory(id, QString::fromUtf8(cells[1].constData()), nexusIDs, parentID); + addCategory(id, QString::fromUtf8(cells[1].constData()), nexusCats, parentID); + } else if (cells.count() == 3) { + bool cell0Ok = true; + bool cell3Ok = true; + int id = cells[0].toInt(&cell0Ok); + int parentID = cells[2].trimmed().toInt(&cell3Ok); + if (!cell0Ok || !cell3Ok) { + log::error(tr("invalid category line {}: {}").toStdString(), lineNum, + line.constData()); + } + + addCategory(id, QString::fromUtf8(cells[1].constData()), + std::vector<NexusCategory>(), parentID); + } else { + log::error(tr("invalid category line {}: {} ({} cells)").toStdString(), lineNum, + line.constData(), cells.count()); } } categoryFile.close(); + + QFile nexusMapFile(nexusMappingFilePath()); + if (!nexusMapFile.open(QIODevice::ReadOnly)) { + needLoad = true; + } else { + int nexLineNum = 0; + while (!nexusMapFile.atEnd()) { + QByteArray nexLine = nexusMapFile.readLine(); + ++nexLineNum; + QList<QByteArray> nexCells = nexLine.split('|'); + if (nexCells.count() == 3) { + std::vector<NexusCategory> nexusCats; + QString nexName = nexCells[1]; + bool ok = false; + int nexID = nexCells[2].toInt(&ok); + if (!ok) { + log::error(tr("invalid nexus ID {}").toStdString(), + nexCells[2].constData()); + } + int catID = nexCells[0].toInt(&ok); + if (!ok) { + log::error(tr("invalid category id {}").toStdString(), + nexCells[0].constData()); + } + m_NexusMap.insert_or_assign(nexID, NexusCategory(nexName, nexID)); + m_NexusMap.at(nexID).setCategoryID(catID); + } else { + log::error(tr("invalid nexus category line {}: {} ({} cells)").toStdString(), + lineNum, nexLine.constData(), nexCells.count()); + } + } + } + nexusMapFile.close(); } std::sort(m_Categories.begin(), m_Categories.end()); setParents(); + if (needLoad) + loadDefaultCategories(); } CategoryFactory& CategoryFactory::instance() { - if (s_Instance == nullptr) { - s_Instance = new CategoryFactory; - } - return *s_Instance; + static CategoryFactory s_Instance; + return s_Instance; } void CategoryFactory::reset() { m_Categories.clear(); + m_NexusMap.clear(); m_IDMap.clear(); - // 28 = - // 43 = Savegames (makes no sense to install them through MO) - // 45 = Videos and trailers - // 87 = Miscelanous - addCategory(0, "None", {4, 28, 43, 45, 87}, 0); + addCategory(0, "None", std::vector<NexusCategory>(), 0); } void CategoryFactory::setParents() { - for (std::vector<Category>::iterator iter = m_Categories.begin(); - iter != m_Categories.end(); ++iter) { - iter->m_HasChildren = false; + for (auto& category : m_Categories) { + category.setHasChildren(false); } - for (std::vector<Category>::const_iterator categoryIter = m_Categories.begin(); - categoryIter != m_Categories.end(); ++categoryIter) { - if (categoryIter->m_ParentID != 0) { + for (const auto& category : m_Categories) { + if (category.parentID() != 0) { std::map<int, unsigned int>::const_iterator iter = - m_IDMap.find(categoryIter->m_ParentID); + m_IDMap.find(category.parentID()); if (iter != m_IDMap.end()) { - m_Categories[iter->second].m_HasChildren = true; + m_Categories[iter->second].setHasChildren(true); } } } @@ -139,28 +188,44 @@ void CategoryFactory::saveCategories() QFile categoryFile(categoriesFilePath()); if (!categoryFile.open(QIODevice::WriteOnly)) { - reportError(QObject::tr("Failed to save custom categories")); + reportError(tr("Failed to save custom categories")); return; } categoryFile.resize(0); - for (std::vector<Category>::const_iterator iter = m_Categories.begin(); - iter != m_Categories.end(); ++iter) { - if (iter->m_ID == 0) { + for (const auto& category : m_Categories) { + if (category.ID() == 0) { continue; } QByteArray line; - line.append(QByteArray::number(iter->m_ID)) + line.append(QByteArray::number(category.ID())) .append("|") - .append(iter->m_Name.toUtf8()) + .append(category.name().toUtf8()) .append("|") - .append(VectorJoin(iter->m_NexusIDs, ",").toUtf8()) - .append("|") - .append(QByteArray::number(iter->m_ParentID)) + .append(QByteArray::number(category.parentID())) .append("\n"); categoryFile.write(line); } categoryFile.close(); + + QFile nexusMapFile(nexusMappingFilePath()); + + if (!nexusMapFile.open(QIODevice::WriteOnly)) { + reportError(tr("Failed to save nexus category mappings")); + return; + } + + nexusMapFile.resize(0); + for (const auto& nexMap : m_NexusMap) { + QByteArray line; + line.append(QByteArray::number(nexMap.second.categoryID())).append("|"); + line.append(nexMap.second.name().toUtf8()).append("|"); + line.append(QByteArray::number(nexMap.second.ID())).append("\n"); + nexusMapFile.write(line); + } + nexusMapFile.close(); + + emit categoriesSaved(); } unsigned int @@ -175,100 +240,126 @@ CategoryFactory::countCategories(std::function<bool(const Category& category)> f return result; } -int CategoryFactory::addCategory(const QString& name, const std::vector<int>& nexusIDs, +int CategoryFactory::addCategory(const QString& name, + const std::vector<NexusCategory>& nexusCats, int parentID) { int id = 1; while (m_IDMap.find(id) != m_IDMap.end()) { ++id; } - addCategory(id, name, nexusIDs, parentID); + addCategory(id, name, nexusCats, parentID); saveCategories(); return id; } -void CategoryFactory::addCategory(int id, const QString& name, - const std::vector<int>& nexusIDs, int parentID) +void CategoryFactory::addCategory(int id, const QString& name, int parentID) { int index = static_cast<int>(m_Categories.size()); - m_Categories.push_back(Category(index, id, name, nexusIDs, parentID)); - for (int nexusID : nexusIDs) { - m_NexusMap[nexusID] = index; + m_Categories.push_back( + Category(index, id, name, parentID, std::vector<NexusCategory>())); + m_IDMap[id] = index; +} + +void CategoryFactory::addCategory(int id, const QString& name, + const std::vector<NexusCategory>& nexusCats, + int parentID) +{ + for (const auto& nexusCat : nexusCats) { + m_NexusMap.insert_or_assign(nexusCat.ID(), nexusCat); + m_NexusMap.at(nexusCat.ID()).setCategoryID(id); } + int index = static_cast<int>(m_Categories.size()); + m_Categories.push_back(Category(index, id, name, parentID, nexusCats)); m_IDMap[id] = index; } +void CategoryFactory::setNexusCategories( + const std::vector<CategoryFactory::NexusCategory>& nexusCats) +{ + for (const auto& nexusCat : nexusCats) { + m_NexusMap.emplace(nexusCat.ID(), nexusCat); + } + + saveCategories(); +} + +void CategoryFactory::refreshNexusCategories(CategoriesDialog* dialog) +{ + emit nexusCategoryRefresh(dialog); +} + void CategoryFactory::loadDefaultCategories() { // the order here is relevant as it defines the order in which the // mods appear in the combo box - addCategory(1, "Animations", {2, 4, 51}, 0); - addCategory(52, "Poses", {1, 29}, 1); - addCategory(2, "Armour", {2, 5, 54}, 0); - addCategory(53, "Power Armor", {1, 53}, 2); - addCategory(3, "Audio", {3, 33, 35, 106}, 0); - addCategory(38, "Music", {2, 34, 61}, 0); - addCategory(39, "Voice", {2, 36, 107}, 0); - addCategory(5, "Clothing", {2, 9, 60}, 0); - addCategory(41, "Jewelry", {1, 102}, 5); - addCategory(42, "Backpacks", {1, 49}, 5); - addCategory(6, "Collectables", {2, 10, 92}, 0); - addCategory(28, "Companions", {3, 11, 66, 96}, 0); - addCategory(7, "Creatures, Mounts, & Vehicles", {4, 12, 65, 83, 101}, 0); - addCategory(8, "Factions", {2, 16, 25}, 0); - addCategory(9, "Gameplay", {2, 15, 24}, 0); - addCategory(27, "Combat", {1, 77}, 9); - addCategory(43, "Crafting", {2, 50, 100}, 9); - addCategory(48, "Overhauls", {2, 24, 79}, 9); - addCategory(49, "Perks", {1, 27}, 9); - addCategory(54, "Radio", {1, 31}, 9); - addCategory(55, "Shouts", {1, 104}, 9); - addCategory(22, "Skills & Levelling", {2, 46, 73}, 9); - addCategory(58, "Weather & Lighting", {1, 56}, 9); - addCategory(44, "Equipment", {1, 44}, 43); - addCategory(45, "Home/Settlement", {1, 45}, 43); - addCategory(10, "Body, Face, & Hair", {2, 17, 26}, 0); - addCategory(56, "Tattoos", {1, 57}, 10); - addCategory(40, "Character Presets", {1, 58}, 0); - addCategory(11, "Items", {2, 27, 85}, 0); - addCategory(32, "Mercantile", {2, 23, 69}, 0); - addCategory(37, "Ammo", {1, 3}, 11); - addCategory(19, "Weapons", {2, 41, 55}, 11); - addCategory(36, "Weapon & Armour Sets", {1, 42}, 11); - addCategory(23, "Player Homes", {2, 28, 67}, 0); - addCategory(25, "Castles & Mansions", {1, 68}, 23); - addCategory(51, "Settlements", {1, 48}, 23); - addCategory(12, "Locations", {10, 20, 21, 22, 30, 47, 70, 88, 89, 90, 91}, 0); - addCategory(4, "Cities", {1, 53}, 12); - addCategory(31, "Landscape Changes", {1, 58}, 0); - addCategory(29, "Environment", {2, 14, 74}, 0); - addCategory(30, "Immersion", {2, 51, 78}, 0); - addCategory(20, "Magic", {3, 75, 93, 94}, 0); - addCategory(21, "Models & Textures", {2, 19, 29}, 0); - addCategory(33, "Modders resources", {2, 18, 82}, 0); - addCategory(13, "NPCs", {3, 22, 33, 99}, 0); - addCategory(24, "Bugfixes", {2, 6, 95}, 0); - addCategory(14, "Patches", {2, 25, 84}, 24); - addCategory(35, "Utilities", {2, 38, 39}, 0); - addCategory(26, "Cheats", {1, 8}, 0); - addCategory(15, "Quests", {2, 30, 35}, 0); - addCategory(16, "Races & Classes", {1, 34}, 0); - addCategory(34, "Stealth", {1, 76}, 0); - addCategory(17, "UI", {2, 37, 42}, 0); - addCategory(18, "Visuals", {2, 40, 62}, 0); - addCategory(50, "Pip-Boy", {1, 52}, 18); - addCategory(46, "Shader Presets", {3, 13, 97, 105}, 0); - addCategory(47, "Miscellaneous", {2, 2, 28}, 0); + addCategory(1, "Animations", 0); + addCategory(52, "Poses", 1); + addCategory(2, "Armour", 0); + addCategory(53, "Power Armor", 2); + addCategory(3, "Audio", 0); + addCategory(38, "Music", 0); + addCategory(39, "Voice", 0); + addCategory(5, "Clothing", 0); + addCategory(41, "Jewelry", 5); + addCategory(42, "Backpacks", 5); + addCategory(6, "Collectables", 0); + addCategory(28, "Companions", 0); + addCategory(7, "Creatures, Mounts, & Vehicles", 0); + addCategory(8, "Factions", 0); + addCategory(9, "Gameplay", 0); + addCategory(27, "Combat", 9); + addCategory(43, "Crafting", 9); + addCategory(48, "Overhauls", 9); + addCategory(49, "Perks", 9); + addCategory(54, "Radio", 9); + addCategory(55, "Shouts", 9); + addCategory(22, "Skills & Levelling", 9); + addCategory(58, "Weather & Lighting", 9); + addCategory(44, "Equipment", 43); + addCategory(45, "Home/Settlement", 43); + addCategory(10, "Body, Face, & Hair", 0); + addCategory(39, "Tattoos", 10); + addCategory(40, "Character Presets", 0); + addCategory(11, "Items", 0); + addCategory(32, "Mercantile", 0); + addCategory(37, "Ammo", 11); + addCategory(19, "Weapons", 11); + addCategory(36, "Weapon & Armour Sets", 11); + addCategory(23, "Player Homes", 0); + addCategory(25, "Castles & Mansions", 23); + addCategory(51, "Settlements", 23); + addCategory(12, "Locations", 0); + addCategory(4, "Cities", 12); + addCategory(31, "Landscape Changes", 0); + addCategory(29, "Environment", 0); + addCategory(30, "Immersion", 0); + addCategory(20, "Magic", 0); + addCategory(21, "Models & Textures", 0); + addCategory(33, "Modders resources", 0); + addCategory(13, "NPCs", 0); + addCategory(24, "Bugfixes", 0); + addCategory(14, "Patches", 24); + addCategory(35, "Utilities", 0); + addCategory(26, "Cheats", 0); + addCategory(15, "Quests", 0); + addCategory(16, "Races & Classes", 0); + addCategory(34, "Stealth", 0); + addCategory(17, "UI", 0); + addCategory(18, "Visuals", 0); + addCategory(50, "Pip-Boy", 18); + addCategory(46, "Shader Presets", 0); + addCategory(47, "Miscellaneous", 0); } int CategoryFactory::getParentID(unsigned int index) const { if (index >= m_Categories.size()) { - throw MyException(QObject::tr("invalid category index: %1").arg(index)); + throw MyException(tr("invalid category index: %1").arg(index)); } - return m_Categories[index].m_ParentID; + return m_Categories[index].parentID(); } bool CategoryFactory::categoryExists(int id) const @@ -295,15 +386,15 @@ bool CategoryFactory::isDescendantOfImpl(int id, int parentID, if (iter != m_IDMap.end()) { unsigned int index = iter->second; - if (m_Categories[index].m_ParentID == 0) { + if (m_Categories[index].parentID() == 0) { return false; - } else if (m_Categories[index].m_ParentID == parentID) { + } else if (m_Categories[index].parentID() == parentID) { return true; } else { - return isDescendantOfImpl(m_Categories[index].m_ParentID, parentID, seen); + return isDescendantOfImpl(m_Categories[index].parentID(), parentID, seen); } } else { - log::warn("{} is no valid category id", id); + log::warn(tr("{} is no valid category id").toStdString(), id); return false; } } @@ -311,19 +402,19 @@ bool CategoryFactory::isDescendantOfImpl(int id, int parentID, bool CategoryFactory::hasChildren(unsigned int index) const { if (index >= m_Categories.size()) { - throw MyException(QObject::tr("invalid category index: %1").arg(index)); + throw MyException(tr("invalid category index: %1").arg(index)); } - return m_Categories[index].m_HasChildren; + return m_Categories[index].hasChildren(); } QString CategoryFactory::getCategoryName(unsigned int index) const { if (index >= m_Categories.size()) { - throw MyException(QObject::tr("invalid category index: %1").arg(index)); + throw MyException(tr("invalid category index: %1").arg(index)); } - return m_Categories[index].m_Name; + return m_Categories[index].name(); } QString CategoryFactory::getSpecialCategoryName(SpecialCategories type) const @@ -381,24 +472,24 @@ QString CategoryFactory::getCategoryNameByID(int id) const return {}; } - return m_Categories[index].m_Name; + return m_Categories[index].name(); } } int CategoryFactory::getCategoryID(unsigned int index) const { if (index >= m_Categories.size()) { - throw MyException(QObject::tr("invalid category index: %1").arg(index)); + throw MyException(tr("invalid category index: %1").arg(index)); } - return m_Categories[index].m_ID; + return m_Categories[index].ID(); } int CategoryFactory::getCategoryIndex(int ID) const { std::map<int, unsigned int>::const_iterator iter = m_IDMap.find(ID); if (iter == m_IDMap.end()) { - throw MyException(QObject::tr("invalid category id: %1").arg(ID)); + throw MyException(tr("invalid category id: %1").arg(ID)); } return iter->second; } @@ -407,11 +498,11 @@ int CategoryFactory::getCategoryID(const QString& name) const { auto iter = std::find_if(m_Categories.begin(), m_Categories.end(), [name](const Category& cat) -> bool { - return cat.m_Name == name; + return cat.name() == name; }); if (iter != m_Categories.end()) { - return iter->m_ID; + return iter->ID(); } else { return -1; } @@ -419,12 +510,14 @@ int CategoryFactory::getCategoryID(const QString& name) const unsigned int CategoryFactory::resolveNexusID(int nexusID) const { - std::map<int, unsigned int>::const_iterator iter = m_NexusMap.find(nexusID); - if (iter != m_NexusMap.end()) { - log::debug("nexus category id {} maps to internal {}", nexusID, iter->second); - return iter->second; - } else { - log::debug("nexus category id {} not mapped", nexusID); - return 0U; + auto result = m_NexusMap.find(nexusID); + if (result != m_NexusMap.end()) { + if (m_IDMap.count(result->second.categoryID())) { + log::debug(tr("nexus category id {} maps to internal {}").toStdString(), nexusID, + m_IDMap.at(result->second.categoryID())); + return m_IDMap.at(result->second.categoryID()); + } } + log::debug(tr("nexus category id {} not mapped").toStdString(), nexusID); + return 0U; } |
