drag/drop sample tree entries

portability/boost
zetaPRIME 2019-06-25 14:57:43 -04:00
parent 7d525d482b
commit 70898e33a1
5 changed files with 93 additions and 49 deletions

View File

@ -635,7 +635,7 @@
<bool>true</bool>
</property>
<property name="dragDropMode">
<enum>QAbstractItemView::DropOnly</enum>
<enum>QAbstractItemView::DragDrop</enum>
</property>
<attribute name="headerVisible">
<bool>false</bool>

View File

@ -63,6 +63,16 @@ QString DirectoryNode::path() {
return parent->path() % "/" % name;
}
DirectoryNode* DirectoryNode::findPath(QString path) {
if (path.isEmpty()) return this;
QString first = path.section('/', 0, 0, QString::SectionSkipEmpty);
QString rest = path.section('/', 1, -1, QString::SectionSkipEmpty);
DirectoryNode* sd = nullptr;
for (auto c : children) if (c->name == first) { sd = c; break; }
if (!sd) return nullptr;
return sd->findPath(rest);
}
DirectoryNode* DirectoryNode::findData(const QVariant& d) {
if (data == d) return this;
for (auto c : children) {

View File

@ -30,7 +30,7 @@ namespace Xybrid::UI {
//void placeData(const QVector<std::pair<QString, QVariant>>&);
QString path();
//DirectoryNode* findPath(QString path);
DirectoryNode* findPath(QString path);
DirectoryNode* findData(const QVariant&);
inline bool isDirectory() const { return data.isNull(); }

View File

@ -70,7 +70,7 @@ void SampleListModel::refresh() {
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
hold = root; // hold old tree alive until layout change goes through
root = std::make_shared<DirectoryNode>();
auto* project = window->getProject().get();
if (!project) return;
@ -81,34 +81,21 @@ void SampleListModel::refresh() {
emit layoutChanged();
if (dn && !dn->data.isNull()) {
// TODO: do this by path instead
if (dn) {
if (auto f = root->findPath(dn->path()); f) view->setCurrentIndex(createIndex(f->index, 0, f));
}
/*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;
displayOrder.clear();
auto* project = window->getProject().get();
if (!project) return;
displayOrder.reserve(static_cast<size_t>(project->samples.size()));
for (auto s : project->samples) displayOrder.push_back(s);
std::sort(displayOrder.begin(), displayOrder.end(), [](std::shared_ptr<Sample> a, std::shared_ptr<Sample> b) {
if (a->name == b->name) return a->uuid < b->uuid;
return a->name < b->name;
});
emit layoutChanged();
// keep selected sample
view->setCurrentIndex(index(-1, -1));
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; }
}*/
auto ii = view->currentIndex();
while (ii.isValid()) { // expand down to selected
view->expand(ii);
ii = ii.parent();
}
}
int SampleListModel::rowCount(const QModelIndex& parent [[maybe_unused]]) const {
@ -132,21 +119,31 @@ QVariant SampleListModel::data(const QModelIndex &index, int role) const {
return c;
}
if (role == Qt::EditRole) {
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();
}
void SampleListModel::propagateSampleNames(DirectoryNode* dn) {
if (!dn->data.isNull()) {
auto* project = window->getProject().get();
project->samples[dn->data.toUuid()]->name = dn->path();
} else for (auto c : dn->children) propagateSampleNames(c);
}
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) {
auto dn = static_cast<DirectoryNode*>(index.internalPointer());
dn->name = value.toString();
propagateSampleNames(dn);
refresh();
/*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();
@ -159,7 +156,7 @@ bool SampleListModel::setData(const QModelIndex& index, const QVariant& value, i
}
Qt::ItemFlags SampleListModel::flags(const QModelIndex &index) const {
return Qt::ItemIsEditable | Qt::ItemIsDropEnabled | QAbstractItemModel::flags(index);
return Qt::ItemIsEditable | Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled | QAbstractItemModel::flags(index);
}
QModelIndex SampleListModel::index(int row, int column, const QModelIndex& parent) const {
@ -189,36 +186,70 @@ QStringList SampleListModel::mimeTypes() const {
return types;
}
QMimeData *SampleListModel::mimeData(const QModelIndexList &/*indexes*/) const {
QMimeData* SampleListModel::mimeData(const QModelIndexList& indexes) const {
if (indexes.empty()) return new QMimeData();
auto dn = static_cast<DirectoryNode*>(indexes.first().internalPointer());
if (!dn) return new QMimeData();
auto d = new QMimeData();
// no
QByteArray b;
b.resize(sizeof(void*)*2);
QDataStream s(&b, QIODevice::WriteOnly);
s << reinterpret_cast<qintptr>(this);
s << reinterpret_cast<qintptr>(dn);
d->setData("xybrid-internal/x-sample-entry-move", b);
return d;
}
bool SampleListModel::canDropMimeData(const QMimeData *data, Qt::DropAction action [[maybe_unused]], int row [[maybe_unused]], int column [[maybe_unused]], const QModelIndex &parent [[maybe_unused]]) const {
return data->hasUrls();
return data->hasUrls() || data->hasFormat("xybrid-internal/x-sample-entry-move");
}
bool SampleListModel::dropMimeData(const QMimeData *data, Qt::DropAction action, int row [[maybe_unused]], int column [[maybe_unused]], const QModelIndex &parent [[maybe_unused]]) {
if (!data->hasUrls()) return false;
if (action == Qt::IgnoreAction) return true; // can accept type
if (data->hasUrls()) {
if (action == Qt::IgnoreAction) return true; // can accept type
QList<QUrl> urls = data->urls();
bool success = false;
for (auto u : urls) {
if (!u.isLocalFile()) continue;
auto smp = Sample::fromFile(u.toLocalFile());
if (smp) { // valid sample returned
//qDebug() << "sample successfully imported:" << smp->name << "channels" << smp->numChannels() << "len" << smp->length();
auto prj = window->getProject();
smp->project = prj.get();
prj->samples[smp->uuid] = smp;
QList<QUrl> urls = data->urls();
bool success = false;
for (auto u : urls) {
if (!u.isLocalFile()) continue;
auto smp = Sample::fromFile(u.toLocalFile());
if (smp) { // valid sample returned
//qDebug() << "sample successfully imported:" << smp->name << "channels" << smp->numChannels() << "len" << smp->length();
auto prj = window->getProject();
smp->project = prj.get();
prj->samples[smp->uuid] = smp;
success = true;
success = true;
}
}
if (success) refresh();
return success;
} else if (data->hasFormat("xybrid-internal/x-sample-entry-move")) {
if (action == Qt::IgnoreAction) return true; // can accept type
QByteArray b = data->data("xybrid-internal/x-sample-entry-move");
QDataStream s(&b, QIODevice::ReadOnly);
qintptr p;
s >> p;
if (p != reinterpret_cast<qintptr>(this)) return false;
s >> p;
auto dn = reinterpret_cast<DirectoryNode*>(p);
if (!dn) return false;
//auto ti = index(row, column, parent);
auto tdn = reinterpret_cast<DirectoryNode*>(parent.internalPointer());
if (!tdn) tdn = root.get();
if (!tdn->isDirectory()) tdn = tdn->parent;
dn->parent = tdn;
propagateSampleNames(dn);
refresh();
return true;
}
if (success) refresh();
return success;
return false;
}

View File

@ -21,6 +21,9 @@ namespace Xybrid::UI {
MainWindow* window;
std::shared_ptr<DirectoryNode> root;
std::shared_ptr<DirectoryNode> hold;
void propagateSampleNames(DirectoryNode*);
public:
SampleListModel(QObject* parent, MainWindow* window);