From be0d6aef00891286f33242073627611413ad79c4 Mon Sep 17 00:00:00 2001 From: Mikaƫl Capelle Date: Sat, 26 Dec 2020 20:48:38 +0100 Subject: Start working on collapsible separators. --- src/CMakeLists.txt | 1 + src/mainwindow.cpp | 8 +- src/modlist.h | 2 + src/modlistbypriorityproxy.cpp | 214 +++++++++++++++++++++++++++++++++++++++++ src/modlistbypriorityproxy.h | 56 +++++++++++ src/modlistsortproxy.cpp | 4 +- src/profile.h | 2 +- 7 files changed, 282 insertions(+), 5 deletions(-) create mode 100644 src/modlistbypriorityproxy.cpp create mode 100644 src/modlistbypriorityproxy.h (limited to 'src') diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 98bbe05f..0a913649 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -135,6 +135,7 @@ add_filter(NAME src/modinfo/dialog GROUPS add_filter(NAME src/modlist GROUPS modlist modlistsortproxy + modlistbypriorityproxy modlistview ) diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index cfce9bef..ddde1d9b 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -87,6 +87,7 @@ along with Mod Organizer. If not, see . #include "listdialog.h" #include "envshortcut.h" #include "browserdialog.h" +#include "modlistbypriorityproxy.h" #include "directoryrefresher.h" #include "shared/directoryentry.h" @@ -543,6 +544,8 @@ MainWindow::MainWindow(Settings &settings processUpdates(); ui->statusBar->updateNormalMessage(m_OrganizerCore); + + on_groupCombo_currentIndexChanged(0); } void MainWindow::setupModList() @@ -5935,7 +5938,7 @@ void MainWindow::on_groupCombo_currentIndexChanged(int index) Qt::UserRole + 2); } break; default: { - newModel = nullptr; + newModel = nullptr; } break; } @@ -5948,7 +5951,8 @@ void MainWindow::on_groupCombo_currentIndexChanged(int index) connect(ui->modList, SIGNAL(collapsed(QModelIndex)), newModel, SLOT(collapsed(QModelIndex))); connect(newModel, SIGNAL(expandItem(QModelIndex)), this, SLOT(expandModList(QModelIndex))); } else { - m_ModListSortProxy->setSourceModel(m_OrganizerCore.modList()); + m_ModListSortProxy->setSourceModel(new ModListByPriorityProxy(m_OrganizerCore.modList(), this)); + // m_ModListSortProxy->setSourceModel(m_OrganizerCore.modList()); } modFilterActive(m_ModListSortProxy->isFilterActive()); } diff --git a/src/modlist.h b/src/modlist.h index 21a19fab..fad53755 100644 --- a/src/modlist.h +++ b/src/modlist.h @@ -369,6 +369,8 @@ private: private: + friend class ModListByPriorityProxy; + OrganizerCore *m_Organizer; Profile *m_Profile; diff --git a/src/modlistbypriorityproxy.cpp b/src/modlistbypriorityproxy.cpp new file mode 100644 index 00000000..69c6ff88 --- /dev/null +++ b/src/modlistbypriorityproxy.cpp @@ -0,0 +1,214 @@ +#include "modlistbypriorityproxy.h" + +#include "modinfo.h" +#include "modlist.h" + +ModListByPriorityProxy::ModListByPriorityProxy(ModList* modList, QObject* parent) : + QAbstractProxyModel(parent), m_ModList(modList) +{ + setSourceModel(modList); +} + +ModListByPriorityProxy::~ModListByPriorityProxy() +{ +} + +void ModListByPriorityProxy::setSourceModel(QAbstractItemModel* model) +{ + QAbstractProxyModel::setSourceModel(model); + // connect(sourceModel(), &QAbstractItemModel::layoutChanged, this, &ModListByPriorityProxy::buildTree); +} + +void ModListByPriorityProxy::buildTree() +{ + if (!sourceModel()) return; + + beginResetModel(); + + endResetModel(); + +} + +std::vector ModListByPriorityProxy::topLevelItems() const +{ + std::vector items; + bool separator = false; + for (auto& [priority, index] : m_ModList->m_Profile->getAllIndexesByPriority()) { + ModInfo::Ptr modInfo = ModInfo::getByIndex(index); + if (modInfo->isSeparator()) { + items.emplace_back(modInfo, priority); + separator = true; + } + else if (modInfo->isOverwrite() || !separator) { + items.emplace_back(modInfo, priority); + } + } + + return items; +} + +std::vector ModListByPriorityProxy::childItems(int priority) const +{ + std::vector children; + for (auto& [p, index] : m_ModList->m_Profile->getAllIndexesByPriority()) { + if (p > priority) { + ModInfo::Ptr modInfo = ModInfo::getByIndex(index); + if (modInfo->isSeparator()) { + break; + } + children.emplace_back(modInfo, p); + } + } + return children; +} + +std::optional ModListByPriorityProxy::separator(int priority) const +{ + // overwrites + if (priority == ULONG_MAX) { + return {}; + } + + auto& indexByPriority = m_ModList->m_Profile->getAllIndexesByPriority(); + + auto it = indexByPriority.find(priority); + if (it == std::end(indexByPriority)) { + return {}; + } + + { + ModInfo::Ptr modInfo = ModInfo::getByIndex(it->second); + if (modInfo->isSeparator() || modInfo->isOverwrite()) { + return {}; + } + } + + auto rit = std::reverse_iterator{ it }; + for (; rit != std::rend(indexByPriority); ++rit) { + ModInfo::Ptr modInfo = ModInfo::getByIndex(rit->second); + if (modInfo->isSeparator()) { + return ModInfoWithPriority{ modInfo, rit->first }; + } + } + + return {}; +} + +QModelIndex ModListByPriorityProxy::mapFromSource(const QModelIndex& sourceIndex) const +{ + if (!sourceIndex.isValid()) { + return QModelIndex(); + } + + auto topItems = topLevelItems(); + ModInfo::Ptr modInfo = ModInfo::getByIndex(sourceIndex.row()); + + for (std::size_t i = 0; i < topItems.size(); ++i) { + if (topItems[i].mod == modInfo) { + return createIndex(i, sourceIndex.column(), modInfo.get()); + } + } + + auto sep = separator(m_ModList->priority(modInfo->name())); + auto children = childItems(sep->priority); + for (std::size_t i = 0; i < children.size(); ++i) { + if (children[i].mod == modInfo) { + return createIndex(i, sourceIndex.column(), modInfo.get()); + } + } + + return QModelIndex(); +} + +QModelIndex ModListByPriorityProxy::mapToSource(const QModelIndex& proxyIndex) const +{ + if (!proxyIndex.isValid()) { + return QModelIndex(); + } + auto topItems = topLevelItems(); + ModInfo::Ptr modInfo; + if (proxyIndex.parent().isValid()) { + ModInfo::Ptr parentInfo = topItems[proxyIndex.parent().row()].mod; + modInfo = childItems(m_ModList->priority(parentInfo->name()))[proxyIndex.row()].mod; + } + else { + modInfo = topItems[proxyIndex.row()].mod; + } + return sourceModel()->index(ModInfo::getIndex(modInfo->name()), proxyIndex.column(), mapToSource(proxyIndex.parent())); +} + +int ModListByPriorityProxy::rowCount(const QModelIndex& parent) const +{ + auto topItems = topLevelItems(); + if (!parent.isValid()) { + return topItems.size(); + } + + ModInfo::Ptr modInfo = topItems[parent.row()].mod; + if (!modInfo->isSeparator()) { + return 0; + } + + auto priority = m_ModList->priority(modInfo->name()); + return childItems(priority).size(); +} + +int ModListByPriorityProxy::columnCount(const QModelIndex& index) const +{ + return sourceModel()->columnCount(mapToSource(index)); +} + + +QModelIndex ModListByPriorityProxy::parent(const QModelIndex& child) const +{ + + auto topItems = topLevelItems(); + ModInfo::Ptr modInfo; + if (child.parent().isValid()) { + ModInfo::Ptr parentInfo = topItems[child.parent().row()].mod; + modInfo = childItems(m_ModList->priority(parentInfo->name()))[child.row()].mod; + } + else { + modInfo = topItems[child.row()].mod; + } + + auto sep = separator(m_ModList->priority(modInfo->name())); + + if (!sep) { + return QModelIndex(); + } + + for (std::size_t i = 0; i < topItems.size(); ++i) { + if (topItems[i].mod == sep->mod) { + return createIndex(i, child.column(), sep->mod.get()); + } + } + + return QModelIndex(); +} + +bool ModListByPriorityProxy::hasChildren(const QModelIndex& parent) const +{ + if (!parent.isValid()) { + return false; + } + ModInfo* modInfo = static_cast(parent.internalPointer()); + for (auto& item : topLevelItems()) { + if (modInfo == item.mod) { + return modInfo->isSeparator() && !childItems(item.priority).empty(); + } + } + return false; +} + +QModelIndex ModListByPriorityProxy::index(int row, int column, const QModelIndex& parent) const +{ + auto topItems = topLevelItems(); + if (!parent.isValid()) { + return createIndex(row, column, topItems[row].mod.get()); + } + else { + auto children = childItems(topItems[parent.row()].priority); + return createIndex(row, column, children[row].mod.get()); + } +} diff --git a/src/modlistbypriorityproxy.h b/src/modlistbypriorityproxy.h new file mode 100644 index 00000000..6ec04b9b --- /dev/null +++ b/src/modlistbypriorityproxy.h @@ -0,0 +1,56 @@ +#ifndef MODLISBYPRIORITYPROXY_H +#define MODLISBYPRIORITYPROXY_H + +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "modinfo.h" + +class ModList; + +class ModListByPriorityProxy : public QAbstractProxyModel +{ + Q_OBJECT + +public: + explicit ModListByPriorityProxy(ModList* modList, QObject* parent = nullptr); + ~ModListByPriorityProxy(); + + void setSourceModel(QAbstractItemModel* sourceModel) override; + + int rowCount(const QModelIndex& parent = QModelIndex()) const override; + QModelIndex parent(const QModelIndex& child) const override; + QModelIndex index(int row, int column, const QModelIndex& parent = QModelIndex()) const override; + int columnCount(const QModelIndex& index) const override; + bool hasChildren(const QModelIndex& parent) const override; + + QModelIndex mapFromSource(const QModelIndex& sourceIndex) const override; + QModelIndex mapToSource(const QModelIndex& proxyIndex) const override; + +private: + + void buildTree(); + + struct ModInfoWithPriority { + const ModInfo::Ptr mod; + const int priority; + }; + + std::vector topLevelItems() const; + std::vector childItems(int priority) const; + std::optional separator(int priority) const; + +private: + + ModList* m_ModList; + +}; + +#endif //GROUPINGPROXY_H diff --git a/src/modlistsortproxy.cpp b/src/modlistsortproxy.cpp index ca0f3bb1..f54f3b7a 100644 --- a/src/modlistsortproxy.cpp +++ b/src/modlistsortproxy.cpp @@ -383,7 +383,7 @@ bool ModListSortProxy::categoryMatchesMod( b = (hasConflictFlag(info->getConflictFlags())); break; } - + case CategoryFactory::HasHiddenFiles: { b = (info->hasFlag(ModInfo::FLAG_HIDDEN_FILES)); @@ -645,7 +645,7 @@ bool ModListSortProxy::dropMimeData(const QMimeData *data, Qt::DropAction action void ModListSortProxy::setSourceModel(QAbstractItemModel *sourceModel) { QSortFilterProxyModel::setSourceModel(sourceModel); - QtGroupingProxy *proxy = qobject_cast(sourceModel); + QAbstractProxyModel *proxy = qobject_cast(sourceModel); if (proxy != nullptr) { sourceModel = proxy->sourceModel(); } diff --git a/src/profile.h b/src/profile.h index b8628276..04452ff6 100644 --- a/src/profile.h +++ b/src/profile.h @@ -250,7 +250,7 @@ public: * * @return map of indexes by priority **/ - std::map getAllIndexesByPriority() { return m_ModIndexByPriority; } + const std::map& getAllIndexesByPriority() { return m_ModIndexByPriority; } /** * retrieve the number of mods for which this object has status information. -- cgit v1.3.1