179 lines
5.7 KiB
C++
179 lines
5.7 KiB
C++
#include "samplelistmodel.h"
|
|
using Xybrid::UI::SampleListModel;
|
|
|
|
#include "data/sample.h"
|
|
using Xybrid::Data::Project;
|
|
using Xybrid::Data::Pattern;
|
|
using Xybrid::Data::Sample;
|
|
|
|
#include "uisocket.h"
|
|
|
|
#include "editing/projectcommands.h"
|
|
#include "editing/patterncommands.h"
|
|
using namespace Xybrid::Editing;
|
|
|
|
#include <QListView>
|
|
|
|
#include <QDebug>
|
|
#include <QMimeData>
|
|
#include <QUrl>
|
|
|
|
#include <QMenu>
|
|
#include <QMessageBox>
|
|
|
|
#include "mainwindow.h"
|
|
|
|
SampleListModel::SampleListModel(QObject* parent, MainWindow* window) : QAbstractListModel (parent) {
|
|
this->window = window;
|
|
auto view = static_cast<QListView*>(parent);
|
|
|
|
connect(window, &MainWindow::projectLoaded, this, [this, view] {
|
|
view->setCurrentIndex(index(-1, -1)); // select none
|
|
refresh();
|
|
});
|
|
|
|
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;
|
|
auto smp = displayOrder[idx];
|
|
|
|
auto menu = new QMenu(view);
|
|
menu->addAction("Delete Sample", this, [this, smp, view] {
|
|
if (QMessageBox::warning(view, "Are you sure?", QString("Remove sample \"%1\"?\n(This cannot be undone!)").arg(smp->name), QMessageBox::Yes | QMessageBox::No, QMessageBox::No) != QMessageBox::Yes) return;
|
|
smp->project->samples.remove(smp->uuid);
|
|
smp->project = nullptr;
|
|
refresh();
|
|
});
|
|
|
|
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())];
|
|
}
|
|
|
|
void SampleListModel::refresh() {
|
|
auto view = static_cast<QListView*>(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))); break; }
|
|
}
|
|
}
|
|
|
|
int SampleListModel::rowCount(const QModelIndex &parent [[maybe_unused]]) const {
|
|
auto* project = window->getProject().get();
|
|
if (!project) return 0;
|
|
return static_cast<int>(project->samples.size());
|
|
}
|
|
|
|
int SampleListModel::columnCount(const QModelIndex &parent [[maybe_unused]]) const {
|
|
return 1;
|
|
}
|
|
|
|
QVariant SampleListModel::data(const QModelIndex &index, int role) const {
|
|
auto* project = window->getProject().get();
|
|
if (!project) return QVariant();
|
|
if (role == Qt::DisplayRole) {
|
|
auto c = displayOrder[static_cast<size_t>(index.row())]->name;
|
|
if (c.isEmpty()) return "(unnamed)";
|
|
return c;
|
|
}
|
|
if (role == Qt::EditRole) {
|
|
return displayOrder[static_cast<size_t>(index.row())]->name;
|
|
}
|
|
return QVariant();
|
|
}
|
|
|
|
bool SampleListModel::setData(const QModelIndex &index, const QVariant &value, int role) {
|
|
if (role == Qt::EditRole) {
|
|
auto* project = window->getProject().get();
|
|
if (!project) return true;
|
|
auto smp = displayOrder[static_cast<size_t>(index.row())];
|
|
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;
|
|
}
|
|
|
|
Qt::ItemFlags SampleListModel::flags(const QModelIndex &index) const {
|
|
return Qt::ItemIsEditable | Qt::ItemIsDropEnabled | QAbstractListModel::flags(index);
|
|
}
|
|
|
|
Qt::DropActions SampleListModel::supportedDropActions() const {
|
|
return Qt::CopyAction;
|
|
}
|
|
|
|
QStringList SampleListModel::mimeTypes() const {
|
|
QStringList types;
|
|
//types << "xybrid-internal/x-pattern-index";
|
|
return types;
|
|
}
|
|
|
|
QMimeData *SampleListModel::mimeData(const QModelIndexList &/*indexes*/) const {
|
|
auto d = new QMimeData();
|
|
// no
|
|
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();
|
|
}
|
|
|
|
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
|
|
|
|
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;
|
|
}
|
|
}
|
|
if (success) refresh();
|
|
return success;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//
|