mostly working sample tree

portability/boost
zetaPRIME 2019-06-25 04:31:57 -04:00
parent 2db0f5b4ee
commit 7d525d482b
5 changed files with 107 additions and 30 deletions

View File

@ -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>

View File

@ -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) {

View File

@ -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(); }
};
}

View File

@ -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 {

View File

@ -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);