mostly working sample tree
parent
2db0f5b4ee
commit
7d525d482b
|
@ -629,7 +629,7 @@
|
|||
</size>
|
||||
</property>
|
||||
<property name="editTriggers">
|
||||
<set>QAbstractItemView::DoubleClicked|QAbstractItemView::EditKeyPressed</set>
|
||||
<set>QAbstractItemView::EditKeyPressed|QAbstractItemView::SelectedClicked</set>
|
||||
</property>
|
||||
<property name="dragEnabled">
|
||||
<bool>true</bool>
|
||||
|
|
|
@ -4,6 +4,7 @@ using Xybrid::UI::DirectoryNode;
|
|||
#include <algorithm>
|
||||
#include <functional>
|
||||
|
||||
#include <QStringBuilder>
|
||||
#include <QCollator>
|
||||
#include <QHash>
|
||||
|
||||
|
@ -11,13 +12,21 @@ DirectoryNode::DirectoryNode(DirectoryNode* parent, QString name, QVariant data)
|
|||
this->parent = parent;
|
||||
this->name = name;
|
||||
this->data = data;
|
||||
if (parent) parent->children.push_back(this);
|
||||
if (parent) {
|
||||
index = parent->children.size();
|
||||
parent->children.push_back(this);
|
||||
}
|
||||
}
|
||||
|
||||
DirectoryNode::~DirectoryNode() {
|
||||
qDeleteAll(children);
|
||||
}
|
||||
|
||||
void DirectoryNode::clear() {
|
||||
qDeleteAll(children);
|
||||
children.clear();
|
||||
}
|
||||
|
||||
void DirectoryNode::sortChildren() {
|
||||
QCollator col;
|
||||
col.setNumericMode(true);
|
||||
|
@ -25,6 +34,7 @@ void DirectoryNode::sortChildren() {
|
|||
if (a->isDirectory() != b->isDirectory()) return a->isDirectory();
|
||||
return col.compare(a->name, b->name) < 0;
|
||||
});
|
||||
for (int i = 0; i < children.size(); i++) children[i]->index = i;
|
||||
}
|
||||
|
||||
void DirectoryNode::sortTree() {
|
||||
|
@ -42,10 +52,23 @@ DirectoryNode* DirectoryNode::subdir(QString name) {
|
|||
return sd->subdir(rest);
|
||||
}
|
||||
|
||||
void DirectoryNode::placeData(QString name, QVariant data) {
|
||||
DirectoryNode* DirectoryNode::placeData(QString name, QVariant data) {
|
||||
QString dir = name.section('/', 0, -2, QString::SectionSkipEmpty);
|
||||
QString file = name.section('/', -1, -1, QString::SectionSkipEmpty);
|
||||
new DirectoryNode(subdir(dir), file, data);
|
||||
return new DirectoryNode(subdir(dir), file, data);
|
||||
}
|
||||
|
||||
QString DirectoryNode::path() {
|
||||
if (!parent || parent->name.isEmpty()) return name;
|
||||
return parent->path() % "/" % name;
|
||||
}
|
||||
|
||||
DirectoryNode* DirectoryNode::findData(const QVariant& d) {
|
||||
if (data == d) return this;
|
||||
for (auto c : children) {
|
||||
if (auto cd = c->findData(d); cd) return cd;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/*void DirectoryNode::placeData(const QVector<std::pair<QString, QVariant>>& data) {
|
||||
|
|
|
@ -14,18 +14,25 @@ namespace Xybrid::UI {
|
|||
|
||||
DirectoryNode* parent;
|
||||
QVector<DirectoryNode*> children;
|
||||
int index = 0;
|
||||
|
||||
DirectoryNode(DirectoryNode* parent = nullptr, QString name = QString(), QVariant data = QVariant());
|
||||
~DirectoryNode();
|
||||
|
||||
void clear();
|
||||
|
||||
void sortChildren();
|
||||
void sortTree();
|
||||
|
||||
DirectoryNode* subdir(QString name);
|
||||
|
||||
void placeData(QString name, QVariant data);
|
||||
DirectoryNode* placeData(QString name, QVariant data);
|
||||
//void placeData(const QVector<std::pair<QString, QVariant>>&);
|
||||
|
||||
QString path();
|
||||
//DirectoryNode* findPath(QString path);
|
||||
DirectoryNode* findData(const QVariant&);
|
||||
|
||||
inline bool isDirectory() const { return data.isNull(); }
|
||||
};
|
||||
}
|
||||
|
|
|
@ -12,9 +12,10 @@ using Xybrid::Data::Sample;
|
|||
#include "editing/patterncommands.h"
|
||||
using namespace Xybrid::Editing;
|
||||
|
||||
#include <QListView>
|
||||
#include <QTreeView>
|
||||
|
||||
#include <QDebug>
|
||||
#include <QTimer>
|
||||
#include <QMimeData>
|
||||
#include <QUrl>
|
||||
|
||||
|
@ -25,14 +26,15 @@ using namespace Xybrid::Editing;
|
|||
|
||||
SampleListModel::SampleListModel(QObject* parent, MainWindow* window) : QAbstractItemModel (parent) {
|
||||
this->window = window;
|
||||
auto view = static_cast<QListView*>(parent);
|
||||
root = std::make_shared<DirectoryNode>();
|
||||
auto view = static_cast<QTreeView*>(parent);
|
||||
|
||||
connect(window, &MainWindow::projectLoaded, this, [this, view] {
|
||||
view->setCurrentIndex(index(-1, -1)); // select none
|
||||
refresh();
|
||||
});
|
||||
|
||||
view->setContextMenuPolicy(Qt::CustomContextMenu);
|
||||
/*view->setContextMenuPolicy(Qt::CustomContextMenu);
|
||||
connect(view, &QListView::customContextMenuRequested, this, [this, view](const QPoint& pt) {
|
||||
size_t idx = static_cast<size_t>(view->indexAt(pt).row());
|
||||
if (idx >= displayOrder.size()) return;
|
||||
|
@ -49,18 +51,43 @@ SampleListModel::SampleListModel(QObject* parent, MainWindow* window) : QAbstrac
|
|||
menu->setAttribute(Qt::WA_DeleteOnClose);
|
||||
menu->popup(view->mapToGlobal(pt));
|
||||
|
||||
});
|
||||
});*/
|
||||
|
||||
connect(window->uiSocket(), &UISocket::updatePatternLists, this, [this] { refresh(); });
|
||||
}
|
||||
|
||||
std::shared_ptr<Sample> SampleListModel::itemAt(const QModelIndex& ind) {
|
||||
if (!ind.isValid() || ind.model() != this) return nullptr;
|
||||
return displayOrder[static_cast<size_t>(ind.row())];
|
||||
std::shared_ptr<Sample> SampleListModel::itemAt(const QModelIndex& index) {
|
||||
if (!index.isValid() || index.model() != this || !index.internalPointer()) return nullptr;
|
||||
auto dn = static_cast<DirectoryNode*>(index.internalPointer());
|
||||
if (dn->isDirectory()) return nullptr;
|
||||
auto* project = window->getProject().get();
|
||||
if (!project) return nullptr;
|
||||
return project->samples[dn->data.toUuid()];
|
||||
}
|
||||
|
||||
void SampleListModel::refresh() {
|
||||
auto view = static_cast<QListView*>(QObject::parent());
|
||||
DirectoryNode* dn = nullptr;
|
||||
auto view = static_cast<QTreeView*>(QObject::parent());
|
||||
if (auto ind = view->currentIndex(); ind.isValid()) dn = static_cast<DirectoryNode*>(ind.internalPointer());
|
||||
|
||||
auto hold = root; // hold old tree alive until layout change goes through
|
||||
root = std::make_shared<DirectoryNode>();
|
||||
auto* project = window->getProject().get();
|
||||
if (!project) return;
|
||||
for (auto s : project->samples) root->placeData(s->name, s->uuid);
|
||||
root->sortTree();
|
||||
|
||||
view->setCurrentIndex(QModelIndex());
|
||||
|
||||
emit layoutChanged();
|
||||
|
||||
if (dn && !dn->data.isNull()) {
|
||||
if (auto f = root->findData(dn->data); f) {
|
||||
view->setCurrentIndex(createIndex(f->index, 0, f));
|
||||
}
|
||||
}
|
||||
|
||||
/*auto view = static_cast<QListView*>(QObject::parent());
|
||||
auto ind = view->currentIndex();
|
||||
QUuid uuid;
|
||||
if (ind.isValid()) uuid = displayOrder[static_cast<size_t>(ind.row())]->uuid;
|
||||
|
@ -81,14 +108,13 @@ void SampleListModel::refresh() {
|
|||
for (size_t i = 0; i < displayOrder.size(); i++) {
|
||||
auto s = displayOrder[i];
|
||||
if (s->uuid == uuid) { view->setCurrentIndex(index(static_cast<int>(i), 0)); break; }
|
||||
}
|
||||
}*/
|
||||
}
|
||||
|
||||
int SampleListModel::rowCount(const QModelIndex &parent [[maybe_unused]]) const {
|
||||
if (parent.isValid()) return 0;
|
||||
auto* project = window->getProject().get();
|
||||
if (!project) return 0;
|
||||
return static_cast<int>(project->samples.size());
|
||||
int SampleListModel::rowCount(const QModelIndex& parent [[maybe_unused]]) const {
|
||||
auto dn = const_cast<DirectoryNode*>(root.get());
|
||||
if (parent.isValid()) dn = static_cast<DirectoryNode*>(parent.internalPointer());
|
||||
return dn->children.size();
|
||||
}
|
||||
|
||||
int SampleListModel::columnCount(const QModelIndex &parent [[maybe_unused]]) const {
|
||||
|
@ -98,27 +124,37 @@ int SampleListModel::columnCount(const QModelIndex &parent [[maybe_unused]]) con
|
|||
QVariant SampleListModel::data(const QModelIndex &index, int role) const {
|
||||
auto* project = window->getProject().get();
|
||||
if (!project) return QVariant();
|
||||
if (!index.internalPointer()) return QVariant();
|
||||
if (role == Qt::DisplayRole) {
|
||||
auto c = displayOrder[static_cast<size_t>(index.row())]->name;
|
||||
auto dn = static_cast<DirectoryNode*>(index.internalPointer());
|
||||
auto c = dn->name;
|
||||
if (c.isEmpty()) return "(unnamed)";
|
||||
return c;
|
||||
}
|
||||
if (role == Qt::EditRole) {
|
||||
return displayOrder[static_cast<size_t>(index.row())]->name;
|
||||
if (auto smp = const_cast<SampleListModel*>(this)->itemAt(index); smp) return smp->name;
|
||||
auto dn = static_cast<DirectoryNode*>(index.internalPointer());
|
||||
return dn->name;
|
||||
}
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
bool SampleListModel::setData(const QModelIndex &index, const QVariant &value, int role) {
|
||||
bool SampleListModel::setData(const QModelIndex& index, const QVariant& value, int role) {
|
||||
if (role == Qt::EditRole) {
|
||||
if (auto smp = const_cast<SampleListModel*>(this)->itemAt(index); smp) {
|
||||
smp->name = value.toString();
|
||||
refresh();
|
||||
} else { // directory
|
||||
// TODO
|
||||
}
|
||||
}
|
||||
/*if (role == Qt::EditRole) {
|
||||
auto* project = window->getProject().get();
|
||||
if (!project) return true;
|
||||
auto smp = displayOrder[static_cast<size_t>(index.row())];
|
||||
auto smp = itemAt(index);
|
||||
smp->name = value.toString();
|
||||
refresh();
|
||||
/*auto pattern = project->patterns[static_cast<size_t>(index.row())];
|
||||
return (new PatternRenameCommand(pattern, value.toString().toStdString()))->commit();*/
|
||||
}
|
||||
}*/
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -126,12 +162,21 @@ Qt::ItemFlags SampleListModel::flags(const QModelIndex &index) const {
|
|||
return Qt::ItemIsEditable | Qt::ItemIsDropEnabled | QAbstractItemModel::flags(index);
|
||||
}
|
||||
|
||||
QModelIndex SampleListModel::index(int row, int column, const QModelIndex &parent) const {
|
||||
return createIndex(row, column);
|
||||
QModelIndex SampleListModel::index(int row, int column, const QModelIndex& parent) const {
|
||||
DirectoryNode* dn = nullptr;
|
||||
if (parent.isValid()) dn = static_cast<DirectoryNode*>(parent.internalPointer());
|
||||
if (!dn) dn = const_cast<DirectoryNode*>(root.get());
|
||||
|
||||
if (row >= 0 && row < dn->children.size()) return createIndex(row, column, dn->children[row]);
|
||||
|
||||
return QModelIndex();
|
||||
}
|
||||
|
||||
QModelIndex SampleListModel::parent(const QModelIndex& index) const {
|
||||
return this->index(-1, -1);
|
||||
if (!index.isValid()) return QModelIndex();
|
||||
auto dn = static_cast<DirectoryNode*>(index.internalPointer());
|
||||
if (!dn->parent || dn->parent == root.get()) return QModelIndex();
|
||||
return createIndex(dn->parent->index, 0, dn->parent);
|
||||
}
|
||||
|
||||
Qt::DropActions SampleListModel::supportedDropActions() const {
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
#include "ui/directorynode.h"
|
||||
|
||||
#include <QAbstractItemModel>
|
||||
|
||||
#include "data/project.h"
|
||||
|
@ -18,7 +20,7 @@ namespace Xybrid::UI {
|
|||
// raw pointer because the model's lifetime is dependent on the window
|
||||
MainWindow* window;
|
||||
|
||||
std::vector<std::shared_ptr<Data::Sample>> displayOrder;
|
||||
std::shared_ptr<DirectoryNode> root;
|
||||
public:
|
||||
SampleListModel(QObject* parent, MainWindow* window);
|
||||
|
||||
|
|
Loading…
Reference in New Issue