summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/mainwindow.cpp29
-rw-r--r--src/mainwindow.h2
-rw-r--r--src/modinfo.h10
-rw-r--r--src/modinfoseparator.h2
-rw-r--r--src/modlist.cpp2
-rw-r--r--src/modlistbypriorityproxy.cpp236
-rw-r--r--src/modlistbypriorityproxy.h49
7 files changed, 178 insertions, 152 deletions
diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp
index ddde1d9b..be879dc6 100644
--- a/src/mainwindow.cpp
+++ b/src/mainwindow.cpp
@@ -544,14 +544,22 @@ MainWindow::MainWindow(Settings &settings
processUpdates();
ui->statusBar->updateNormalMessage(m_OrganizerCore);
-
- on_groupCombo_currentIndexChanged(0);
}
void MainWindow::setupModList()
{
- m_ModListSortProxy = m_OrganizerCore.createModListProxyModel();
+ m_ModListByPriorityProxy = new ModListByPriorityProxy(m_OrganizerCore.currentProfile(), &m_OrganizerCore);
+ connect(ui->modList, SIGNAL(expanded(QModelIndex)), m_ModListByPriorityProxy, SLOT(expanded(QModelIndex)));
+ connect(ui->modList, SIGNAL(collapsed(QModelIndex)), m_ModListByPriorityProxy, SLOT(collapsed(QModelIndex)));
+ connect(m_ModListByPriorityProxy, SIGNAL(expandItem(QModelIndex)), this, SLOT(expandModList(QModelIndex)));
+
+ m_ModListSortProxy = new ModListSortProxy(m_OrganizerCore.currentProfile(), &m_OrganizerCore);
ui->modList->setModel(m_ModListSortProxy);
+
+ m_ModListByPriorityProxy->setSourceModel(m_OrganizerCore.modList());
+ m_ModListSortProxy->setSourceModel(m_ModListByPriorityProxy);
+ emit m_OrganizerCore.modList()->layoutChanged();
+
ui->modList->sortByColumn(ModList::COL_PRIORITY, Qt::AscendingOrder);
@@ -1267,15 +1275,7 @@ void MainWindow::espFilterChanged(const QString &filter)
void MainWindow::expandModList(const QModelIndex &index)
{
- QAbstractItemModel *model = ui->modList->model();
-
- for (int i = 0; i < model->rowCount(); ++i) {
- QModelIndex targetIdx = model->index(i, 0);
- if (model->data(targetIdx).toString() == index.data().toString()) {
- ui->modList->expand(targetIdx);
- break;
- }
- }
+ ui->modList->expand(m_ModListSortProxy->mapFromSource(index));
}
@@ -1679,6 +1679,7 @@ void MainWindow::activateSelectedProfile()
m_OrganizerCore.setCurrentProfile(ui->profileBox->currentText());
m_ModListSortProxy->setProfile(m_OrganizerCore.currentProfile());
+ m_ModListByPriorityProxy->setProfile(m_OrganizerCore.currentProfile());
m_SavesTab->refreshSaveList();
m_OrganizerCore.refresh();
@@ -5951,8 +5952,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(new ModListByPriorityProxy(m_OrganizerCore.modList(), this));
- // m_ModListSortProxy->setSourceModel(m_OrganizerCore.modList());
+ m_ModListSortProxy->setSourceModel(m_ModListByPriorityProxy);
+ emit m_OrganizerCore.modList()->layoutChanged();
}
modFilterActive(m_ModListSortProxy->isFilterActive());
}
diff --git a/src/mainwindow.h b/src/mainwindow.h
index f8910361..19a1b179 100644
--- a/src/mainwindow.h
+++ b/src/mainwindow.h
@@ -26,6 +26,7 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
#include "imoinfo.h"
#include "iuserinterface.h"
#include "modinfo.h"
+#include "modlistbypriorityproxy.h"
#include "modlistsortproxy.h"
#include "tutorialcontrol.h"
#include "plugincontainer.h" //class PluginContainer;
@@ -297,6 +298,7 @@ private:
QStringList m_DefaultArchives;
ModListSortProxy *m_ModListSortProxy;
+ ModListByPriorityProxy *m_ModListByPriorityProxy;
PluginListSortProxy *m_PluginListSortProxy;
diff --git a/src/modinfo.h b/src/modinfo.h
index 42abe51e..d04f6657 100644
--- a/src/modinfo.h
+++ b/src/modinfo.h
@@ -379,6 +379,11 @@ public: // IModInterface implementations / Re-declaration
virtual std::shared_ptr<const MOBase::IFileTree> fileTree() const = 0;
/**
+ * @return true if this object represents a regular mod.
+ */
+ virtual bool isRegular() const { return false; }
+
+ /**
* @return true if this object represents the overwrite mod.
*/
virtual bool isOverwrite() const { return false; }
@@ -492,11 +497,6 @@ public: // Mutable operations:
public: // Methods after this do not come from IModInterface:
/**
- * @return true if this mod is a regular mod, false otherwise.
- */
- virtual bool isRegular() const { return false; }
-
- /**
* @return true if this mod is empty, false otherwise.
*/
virtual bool isEmpty() const { return false; }
diff --git a/src/modinfoseparator.h b/src/modinfoseparator.h
index 88262f37..c7df7184 100644
--- a/src/modinfoseparator.h
+++ b/src/modinfoseparator.h
@@ -55,7 +55,7 @@ protected:
private:
ModInfoSeparator(
- PluginContainer* pluginContainer,
+ PluginContainer* pluginContainer,
const MOBase::IPluginGame* game, const QDir& path,
MOShared::DirectoryEntry** directoryStructure);
};
diff --git a/src/modlist.cpp b/src/modlist.cpp
index c8056140..4191e2db 100644
--- a/src/modlist.cpp
+++ b/src/modlist.cpp
@@ -1236,8 +1236,8 @@ void ModList::removeRowForce(int row, const QModelIndex &parent)
m_Profile->cancelModlistWrite();
beginRemoveRows(parent, row, row);
ModInfo::removeMod(row);
- endRemoveRows();
m_Profile->refreshModStatus(); // removes the mod from the status list
+ endRemoveRows();
m_Profile->writeModlist(); // this ensures the modified list gets written back before new mods can be installed
notifyModRemoved(modInfo->name());
diff --git a/src/modlistbypriorityproxy.cpp b/src/modlistbypriorityproxy.cpp
index 69c6ff88..77b7262a 100644
--- a/src/modlistbypriorityproxy.cpp
+++ b/src/modlistbypriorityproxy.cpp
@@ -1,12 +1,13 @@
#include "modlistbypriorityproxy.h"
#include "modinfo.h"
+#include "profile.h"
#include "modlist.h"
+#include "log.h"
-ModListByPriorityProxy::ModListByPriorityProxy(ModList* modList, QObject* parent) :
- QAbstractProxyModel(parent), m_ModList(modList)
+ModListByPriorityProxy::ModListByPriorityProxy(Profile* profile, QObject* parent) :
+ QAbstractProxyModel(parent), m_Profile(profile)
{
- setSourceModel(modList);
}
ModListByPriorityProxy::~ModListByPriorityProxy()
@@ -16,7 +17,14 @@ ModListByPriorityProxy::~ModListByPriorityProxy()
void ModListByPriorityProxy::setSourceModel(QAbstractItemModel* model)
{
QAbstractProxyModel::setSourceModel(model);
- // connect(sourceModel(), &QAbstractItemModel::layoutChanged, this, &ModListByPriorityProxy::buildTree);
+
+ if (sourceModel()) {
+ m_CollapsedItems.clear();
+ connect(sourceModel(), &QAbstractItemModel::layoutChanged, this, &ModListByPriorityProxy::buildTree, Qt::UniqueConnection);
+ connect(sourceModel(), &QAbstractItemModel::rowsRemoved, this, [this]() { buildTree(); }, Qt::UniqueConnection);
+ connect(sourceModel(), &QAbstractItemModel::modelReset, this, &ModListByPriorityProxy::buildTree, Qt::UniqueConnection);
+ buildTree();
+ }
}
void ModListByPriorityProxy::buildTree()
@@ -25,73 +33,48 @@ void ModListByPriorityProxy::buildTree()
beginResetModel();
- endResetModel();
-
-}
+ // reset the root
+ m_Root = { };
+ m_IndexToItem.clear();
-std::vector<ModListByPriorityProxy::ModInfoWithPriority> ModListByPriorityProxy::topLevelItems() const
-{
- std::vector<ModListByPriorityProxy::ModInfoWithPriority> items;
- bool separator = false;
- for (auto& [priority, index] : m_ModList->m_Profile->getAllIndexesByPriority()) {
+ TreeItem* root = &m_Root;
+ for (auto& [priority, index] : m_Profile->getAllIndexesByPriority()) {
ModInfo::Ptr modInfo = ModInfo::getByIndex(index);
+
+ TreeItem* item;
+
if (modInfo->isSeparator()) {
- items.emplace_back(modInfo, priority);
- separator = true;
+ m_Root.children.push_back(std::make_unique<TreeItem>(modInfo, index, &m_Root));
+ item = m_Root.children.back().get();
+ root = item;
}
- else if (modInfo->isOverwrite() || !separator) {
- items.emplace_back(modInfo, priority);
+ else if (modInfo->isOverwrite()) {
+ m_Root.children.push_back(std::make_unique<TreeItem>(modInfo, index, &m_Root));
+ item = m_Root.children.back().get();
}
- }
-
- return items;
-}
-
-std::vector<ModListByPriorityProxy::ModInfoWithPriority> ModListByPriorityProxy::childItems(int priority) const
-{
- std::vector<ModListByPriorityProxy::ModInfoWithPriority> 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);
+ else {
+ root->children.push_back(std::make_unique<TreeItem>(modInfo, index, root));
+ item = root->children.back().get();
}
- }
- return children;
-}
+ m_IndexToItem[index] = item;
-std::optional<ModListByPriorityProxy::ModInfoWithPriority> 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 {};
- }
+ endResetModel();
- {
- ModInfo::Ptr modInfo = ModInfo::getByIndex(it->second);
- if (modInfo->isSeparator() || modInfo->isOverwrite()) {
- return {};
- }
- }
+ // restore expand-state
+ expandItems(QModelIndex());
+}
- 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 };
+void ModListByPriorityProxy::expandItems(const QModelIndex& index)
+{
+ for (int row = 0; row < rowCount(index); row++) {
+ QModelIndex idx = this->index(row, 0, QModelIndex());
+ if (!m_CollapsedItems.contains(idx.data(Qt::DisplayRole).toString())) {
+ emit expandItem(idx);
}
+ expandItems(idx);
}
-
- return {};
}
QModelIndex ModListByPriorityProxy::mapFromSource(const QModelIndex& sourceIndex) const
@@ -100,24 +83,8 @@ QModelIndex ModListByPriorityProxy::mapFromSource(const QModelIndex& sourceIndex
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();
+ auto* item = m_IndexToItem.at(sourceIndex.row());
+ return createIndex(item->parent->childIndex(item), sourceIndex.column(), item);
}
QModelIndex ModListByPriorityProxy::mapToSource(const QModelIndex& proxyIndex) const
@@ -125,32 +92,23 @@ QModelIndex ModListByPriorityProxy::mapToSource(const QModelIndex& proxyIndex) c
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()));
+ auto* item = static_cast<TreeItem*>(proxyIndex.internalPointer());
+ return sourceModel()->index(item->index, proxyIndex.column());
}
int ModListByPriorityProxy::rowCount(const QModelIndex& parent) const
{
- auto topItems = topLevelItems();
if (!parent.isValid()) {
- return topItems.size();
+ return m_Root.children.size();
}
- ModInfo::Ptr modInfo = topItems[parent.row()].mod;
- if (!modInfo->isSeparator()) {
- return 0;
+ auto* item = static_cast<TreeItem*>(parent.internalPointer());
+
+ if (item->mod->isSeparator()) {
+ return item->children.size();
}
- auto priority = m_ModList->priority(modInfo->name());
- return childItems(priority).size();
+ return 0;
}
int ModListByPriorityProxy::columnCount(const QModelIndex& index) const
@@ -161,54 +119,90 @@ int ModListByPriorityProxy::columnCount(const QModelIndex& index) const
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;
+ if (!child.isValid()) {
+ return QModelIndex();
}
- auto sep = separator(m_ModList->priority(modInfo->name()));
+ auto* item = static_cast<TreeItem*>(child.internalPointer());
- if (!sep) {
+ if (!item->parent || item->parent == &m_Root) {
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();
+ return createIndex(item->parent->parent->childIndex(item->parent), 0, item->parent);
}
bool ModListByPriorityProxy::hasChildren(const QModelIndex& parent) const
{
if (!parent.isValid()) {
- return false;
+ return m_Root.children.size() > 0;
}
- ModInfo* modInfo = static_cast<ModInfo*>(parent.internalPointer());
- for (auto& item : topLevelItems()) {
- if (modInfo == item.mod) {
- return modInfo->isSeparator() && !childItems(item.priority).empty();
+ auto* item = static_cast<TreeItem*>(parent.internalPointer());
+ return item->children.size() > 0;
+}
+
+bool ModListByPriorityProxy::setData(const QModelIndex& index, const QVariant& value, int role)
+{
+ // only care about the "name" column
+ if (index.column() == 0 && role == Qt::EditRole) {
+ QString oldValue = data(index, role).toString();
+ if (m_CollapsedItems.contains(oldValue)) {
+ m_CollapsedItems.erase(oldValue);
+ m_CollapsedItems.insert(value.toString());
}
}
- return false;
+ return QAbstractProxyModel::setData(index, value, role);
+}
+
+
+Qt::ItemFlags ModListByPriorityProxy::flags(const QModelIndex& idx) const
+{
+ if (!idx.isValid()) {
+ return sourceModel()->flags(QModelIndex());
+ }
+
+ // we check the flags of the root node and if drop is not enabled, it
+ // means we are dragging files.
+ Qt::ItemFlags rootFlags = sourceModel()->flags(QModelIndex());
+ if (!rootFlags.testFlag(Qt::ItemIsDropEnabled)) {
+ return sourceModel()->flags(mapToSource(idx));
+ }
+
+ auto flags = sourceModel()->flags(mapToSource(idx));
+ auto* item = static_cast<TreeItem*>(idx.internalPointer());
+
+ if (item->mod->isSeparator()) {
+ flags |= Qt::ItemIsDropEnabled;
+ }
+
+ return flags;
}
QModelIndex ModListByPriorityProxy::index(int row, int column, const QModelIndex& parent) const
{
- auto topItems = topLevelItems();
+ if (!hasIndex(row, column, parent)) {
+ return QModelIndex();
+ }
+
+ const TreeItem* parentItem;
if (!parent.isValid()) {
- return createIndex(row, column, topItems[row].mod.get());
+ parentItem = &m_Root;
}
else {
- auto children = childItems(topItems[parent.row()].priority);
- return createIndex(row, column, children[row].mod.get());
+ parentItem = static_cast<TreeItem*>(parent.internalPointer());
+ }
+ return createIndex(row, column, parentItem->children[row].get());
+}
+
+void ModListByPriorityProxy::expanded(const QModelIndex& index)
+{
+ auto it = m_CollapsedItems.find(index.data(Qt::DisplayRole).toString());
+ if (it != m_CollapsedItems.end()) {
+ m_CollapsedItems.erase(it);
}
}
+
+void ModListByPriorityProxy::collapsed(const QModelIndex& index)
+{
+ m_CollapsedItems.insert(index.data(Qt::DisplayRole).toString());
+}
diff --git a/src/modlistbypriorityproxy.h b/src/modlistbypriorityproxy.h
index 6ec04b9b..d5f59f4c 100644
--- a/src/modlistbypriorityproxy.h
+++ b/src/modlistbypriorityproxy.h
@@ -2,6 +2,7 @@
#define MODLISBYPRIORITYPROXY_H
#include <optional>
+#include <set>
#include <vector>
#include <QAbstractProxyModel>
@@ -14,43 +15,71 @@
#include "modinfo.h"
class ModList;
+class Profile;
class ModListByPriorityProxy : public QAbstractProxyModel
{
Q_OBJECT
public:
- explicit ModListByPriorityProxy(ModList* modList, QObject* parent = nullptr);
+ explicit ModListByPriorityProxy(Profile* profile, QObject* parent = nullptr);
~ModListByPriorityProxy();
+ void setProfile(Profile* profile) { m_Profile = profile; }
+
void setSourceModel(QAbstractItemModel* sourceModel) override;
int rowCount(const QModelIndex& parent = QModelIndex()) const override;
QModelIndex parent(const QModelIndex& child) const override;
+ Qt::ItemFlags flags(const QModelIndex& idx) 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;
+ bool setData(const QModelIndex& index, const QVariant& value, int role) override;
+
QModelIndex mapFromSource(const QModelIndex& sourceIndex) const override;
QModelIndex mapToSource(const QModelIndex& proxyIndex) const override;
+signals:
+ void expandItem(const QModelIndex& index);
+
+public slots:
+
+ void expanded(const QModelIndex& index);
+ void collapsed(const QModelIndex& index);
+
private:
void buildTree();
+ void expandItems(const QModelIndex& index);
- struct ModInfoWithPriority {
- const ModInfo::Ptr mod;
- const int priority;
- };
+ struct TreeItem {
+ ModInfo::Ptr mod;
+ unsigned int index;
+ std::vector<std::unique_ptr<TreeItem>> children;
+ TreeItem* parent;
- std::vector<ModInfoWithPriority> topLevelItems() const;
- std::vector<ModInfoWithPriority> childItems(int priority) const;
- std::optional<ModInfoWithPriority> separator(int priority) const;
+ std::size_t childIndex(TreeItem* child) const {
+ for (std::size_t i = 0; i < children.size(); ++i) {
+ if (children[i].get() == child) {
+ return i;
+ }
+ }
+ return -1;
+ }
-private:
+ TreeItem() : TreeItem(nullptr, -1) { }
+ TreeItem(ModInfo::Ptr mod, unsigned int index, TreeItem* parent = nullptr) :
+ mod(mod), index(index), parent(parent) { }
+ };
- ModList* m_ModList;
+ TreeItem m_Root;
+ std::map<unsigned int, TreeItem*> m_IndexToItem;
+ std::set<QString> m_CollapsedItems;
+private:
+ Profile* m_Profile;
};
#endif //GROUPINGPROXY_H