aboutsummaryrefslogtreecommitdiff
path: root/libs/installer_bsplugins/src/BSPluginInfo/RecordStructureModel.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'libs/installer_bsplugins/src/BSPluginInfo/RecordStructureModel.cpp')
-rw-r--r--libs/installer_bsplugins/src/BSPluginInfo/RecordStructureModel.cpp167
1 files changed, 167 insertions, 0 deletions
diff --git a/libs/installer_bsplugins/src/BSPluginInfo/RecordStructureModel.cpp b/libs/installer_bsplugins/src/BSPluginInfo/RecordStructureModel.cpp
new file mode 100644
index 0000000..a28d714
--- /dev/null
+++ b/libs/installer_bsplugins/src/BSPluginInfo/RecordStructureModel.cpp
@@ -0,0 +1,167 @@
+#include "RecordStructureModel.h"
+#include "TESData/SingleRecordParser.h"
+#include "TESFile/Reader.h"
+
+#include <log.h>
+
+#include <boost/container/flat_map.hpp>
+
+namespace BSPluginInfo
+{
+
+RecordStructureModel::RecordStructureModel(TESData::PluginList* pluginList,
+ TESData::Record* record,
+ const TESData::RecordPath& path,
+ MOBase::IOrganizer* organizer)
+ : m_Organizer{organizer}, m_PluginList{pluginList}, m_Record{record}, m_Path{path},
+ m_Root{std::make_shared<Item>()}
+{
+ refresh();
+}
+
+void RecordStructureModel::refresh()
+{
+ boost::container::flat_map<int, const TESData::FileEntry*> entries;
+ for (const auto handle : m_Record->alternatives()) {
+ const auto entry = m_PluginList->findEntryByHandle(handle);
+ const auto info =
+ m_PluginList->getPluginByName(QString::fromStdString(entry->name()));
+ if (info && info->enabled()) {
+ entries.emplace(info->priority(), entry);
+ }
+ }
+
+ m_Files.resize(entries.size());
+
+ for (int index = static_cast<int>(entries.size()) - 1; index >= 0; --index) {
+ const auto entry = entries.nth(index)->second;
+ const auto name = QString::fromStdString(entry->name());
+ const auto vfsEntry =
+ m_Organizer->virtualFileTree()->find(name, MOBase::FileTreeEntry::FILE);
+
+ const auto filePath = m_Organizer->resolvePath(name);
+ m_Files[index] = QFileInfo(filePath).fileName();
+
+ readFile(m_Path, filePath, index);
+ }
+}
+
+void RecordStructureModel::readFile(const TESData::RecordPath& path,
+ const QString& filePath, int index)
+try {
+ const auto fileName = QFileInfo(filePath).fileName().toStdString();
+ const auto gameName = m_Organizer->managedGame()->gameName();
+ TESData::SingleRecordParser handler(gameName, path, fileName, m_Root.get(), index);
+ TESFile::Reader<TESData::SingleRecordParser> reader{};
+ reader.parse(std::filesystem::path(filePath.toStdWString()), handler);
+} catch (const std::exception& e) {
+ MOBase::log::error("Error parsing \"{}\": {}", filePath, e.what());
+}
+
+QModelIndex RecordStructureModel::index(int row, int column,
+ const QModelIndex& parent) const
+{
+ if (row < 0 || column < 0) {
+ return QModelIndex();
+ }
+
+ const auto parentItem = parent.isValid()
+ ? static_cast<const Item*>(parent.internalPointer())
+ : m_Root.get();
+ if (parentItem && row < parentItem->numChildren()) {
+ const auto childItem = parentItem->childAt(row);
+ return createIndex(row, column, childItem);
+ }
+
+ return QModelIndex();
+}
+
+QModelIndex RecordStructureModel::parent(const QModelIndex& index) const
+{
+ const auto item =
+ index.isValid() ? static_cast<const Item*>(index.internalPointer()) : nullptr;
+ const auto parentItem = item ? item->parent() : nullptr;
+ if (!parentItem) {
+ return QModelIndex();
+ }
+
+ const int row = parentItem->index();
+ return createIndex(row, 0, parentItem);
+}
+
+int RecordStructureModel::rowCount(const QModelIndex& parent) const
+{
+ const auto item = parent.isValid()
+ ? static_cast<const Item*>(parent.internalPointer())
+ : m_Root.get();
+ return item ? item->numChildren() : 0;
+}
+
+int RecordStructureModel::columnCount([[maybe_unused]] const QModelIndex& parent) const
+{
+ return 1 + static_cast<int>(m_Files.size());
+}
+
+QVariant RecordStructureModel::data(const QModelIndex& index, int role) const
+{
+ const auto item =
+ index.isValid() ? static_cast<const Item*>(index.internalPointer()) : nullptr;
+ if (!item) {
+ return QVariant();
+ }
+
+ switch (role) {
+ case Qt::DisplayRole:
+ case Qt::EditRole:
+ if (index.column() == 0) {
+ return item->rowHeader();
+ } else {
+ return item->displayData(index.column() - 1);
+ }
+
+ case Qt::BackgroundRole: {
+ if (index.column() == 0) {
+ return QVariant();
+ }
+
+ const int count = columnCount() - 1;
+ const int fileIndex = index.column() - 1;
+ if (item->isLosingConflict(fileIndex, count)) {
+ return QColor(255, 0, 0, 64);
+ } else if (item->isOverriding(fileIndex)) {
+ return QColor(0, 255, 0, 64);
+ }
+
+ return QVariant();
+ }
+
+ case Qt::UserRole:
+ return QVariant::fromValue(item);
+ }
+
+ return QVariant();
+}
+
+QVariant RecordStructureModel::headerData(int section, Qt::Orientation orientation,
+ int role) const
+{
+ if (orientation != Qt::Horizontal)
+ return QVariant();
+
+ switch (role) {
+ case Qt::DisplayRole: {
+ if (section == 0) {
+ // Name
+ return QVariant();
+ }
+
+ if (section - 1 < m_Files.length()) {
+ return m_Files[section - 1];
+ }
+ }
+ }
+
+ return QVariant();
+}
+
+} // namespace BSPluginInfo