From 96167220ca65c48a7feec6fc55ad0f83f7d9caec Mon Sep 17 00:00:00 2001 From: 0xFEEDC0DE64 Date: Thu, 30 Apr 2020 21:06:17 +0200 Subject: [PATCH] Improvements --- DrumMachine.pro | 6 +- djwidget.cpp | 19 ++- djwidget.h | 4 + djwidget.ui | 16 +- graphrenderer.cpp | 67 +++++--- graphrenderer.h | 6 +- mainwindow.cpp | 4 +- previewwidget.cpp | 6 +- scratchwidget.cpp | 20 ++- trackdeck.cpp | 8 +- trackdeck.ui | 196 +++++++++++++---------- treetotableproxymodel.cpp | 324 ++++++++++++++++++++++++++++++++++++++ treetotableproxymodel.h | 49 ++++++ 13 files changed, 589 insertions(+), 136 deletions(-) create mode 100644 treetotableproxymodel.cpp create mode 100644 treetotableproxymodel.h diff --git a/DrumMachine.pro b/DrumMachine.pro index 6cf1bad..4e9ce6e 100755 --- a/DrumMachine.pro +++ b/DrumMachine.pro @@ -31,7 +31,8 @@ SOURCES += \ scratchwidget.cpp \ sequencerwidget.cpp \ synthisizer.cpp \ - trackdeck.cpp + trackdeck.cpp \ + treetotableproxymodel.cpp HEADERS += \ audiodecoder.h \ @@ -53,7 +54,8 @@ HEADERS += \ scratchwidget.h \ sequencerwidget.h \ synthisizer.h \ - trackdeck.h + trackdeck.h \ + treetotableproxymodel.h FORMS += \ djwidget.ui \ diff --git a/djwidget.cpp b/djwidget.cpp index 97870b9..cb4e626 100644 --- a/djwidget.cpp +++ b/djwidget.cpp @@ -15,7 +15,7 @@ DjWidget::DjWidget(QWidget *parent) : const auto index = m_ui->treeViewFiles->currentIndex(); if (!index.isValid()) return; - trackDeck.loadTrack(m_filesModel.filePath(index)); + trackDeck.loadTrack(m_filesModel.filePath(m_filesTableModel.mapToSource(m_sortFilterProxyModel.mapToSource(index)))); }; }; @@ -31,16 +31,22 @@ DjWidget::DjWidget(QWidget *parent) : connect(m_ui->treeViewDirectories->selectionModel(), &QItemSelectionModel::currentRowChanged, this, &DjWidget::directorySelected); - m_filesModel.setFilter(QDir::AllEntries|QDir::NoDotAndDotDot); - m_ui->treeViewFiles->setModel(&m_filesModel); + m_filesModel.setFilter(QDir::Files); + m_filesTableModel.setSourceModel(&m_filesModel); + m_sortFilterProxyModel.setFilterCaseSensitivity(Qt::CaseInsensitive); + m_sortFilterProxyModel.setSourceModel(&m_filesTableModel); + m_ui->treeViewFiles->setModel(&m_sortFilterProxyModel); if (const auto locations = QStandardPaths::standardLocations(QStandardPaths::MusicLocation); !locations.isEmpty()) { const auto index = m_directoryModel.index(locations.first()); m_ui->treeViewDirectories->selectionModel()->select(index, QItemSelectionModel::Clear|QItemSelectionModel::Select|QItemSelectionModel::Current|QItemSelectionModel::Rows); - m_ui->treeViewFiles->setRootIndex(m_filesModel.setRootPath(m_directoryModel.filePath(index))); + const auto rootIndex = m_filesModel.setRootPath(m_directoryModel.filePath(index)); + m_filesTableModel.setRootIndex(rootIndex); } + + connect(m_ui->lineEditSearch, &QLineEdit::textChanged, &m_sortFilterProxyModel, &QSortFilterProxyModel::setFilterFixedString); } DjWidget::~DjWidget() = default; @@ -73,5 +79,8 @@ void DjWidget::directorySelected() { const auto selected = m_ui->treeViewDirectories->currentIndex(); if (selected.isValid()) - m_ui->treeViewFiles->setRootIndex(m_filesModel.setRootPath(m_directoryModel.filePath(selected))); + { + const auto rootIndex = m_filesModel.setRootPath(m_directoryModel.filePath(selected)); + m_filesTableModel.setRootIndex(rootIndex); + } } diff --git a/djwidget.h b/djwidget.h index 405818e..41b9d27 100644 --- a/djwidget.h +++ b/djwidget.h @@ -2,10 +2,12 @@ #include #include +#include #include #include "audioformat.h" +#include "treetotableproxymodel.h" namespace Ui { class DjWidget; } @@ -29,4 +31,6 @@ private: QFileSystemModel m_directoryModel; QFileSystemModel m_filesModel; + TreeToTableProxyModel m_filesTableModel; + QSortFilterProxyModel m_sortFilterProxyModel; }; diff --git a/djwidget.ui b/djwidget.ui index f73e2f9..de64781 100644 --- a/djwidget.ui +++ b/djwidget.ui @@ -100,6 +100,13 @@ + + + + true + + + @@ -121,15 +128,6 @@ true - - false - - - false - - - true - diff --git a/graphrenderer.cpp b/graphrenderer.cpp index 752ecd2..5b16533 100644 --- a/graphrenderer.cpp +++ b/graphrenderer.cpp @@ -6,40 +6,72 @@ #include #include -QPixmap GraphRenderer::render(const QSize &size, const frame_t *frameBegin, const frame_t *frameEnd, const QPalette &palette) +QPixmap GraphRenderer::render(const QSize &size, const frame_t *begin, const frame_t *end, const QPalette &palette) { QPixmap pixmap{size}; - QPainter painter; - painter.begin(&pixmap); + { + QPainter painter; + painter.begin(&pixmap); - painter.fillRect(pixmap.rect(), palette.base()); + painter.setPen({}); + painter.setBrush(palette.base()); + painter.drawRect(pixmap.rect()); - painter.setBrush(palette.base()); + painter.setPen(QPen{palette.color(QPalette::Text)}); + painter.setBrush(palette.text()); + render(pixmap.rect(), begin, end, painter); - painter.drawRect(pixmap.rect()); + painter.end(); + } - render(pixmap.rect(), frameBegin, frameEnd, painter, palette); - painter.end(); return pixmap; } -void GraphRenderer::render(const QRect &rect, const frame_t *frameBegin, const frame_t *frameEnd, QPainter &painter, const QPalette &palette) +void GraphRenderer::render(const QRect &rect, const frame_t *begin, const frame_t *end, QPainter &painter) { - if (frameEnd == frameBegin) + if (end == begin) return; - painter.setPen(QPen{palette.color(QPalette::Text)}); - painter.setBrush(palette.text()); + std::pair arr[rect.width()]; - const auto framesPerPixel = std::distance(frameBegin, frameEnd) / rect.width(); + reduceSamples(begin, end, arr, arr+rect.width()); - for (int x = 0; x < rect.width(); x++) + render(rect.topLeft(), rect.height(), arr, arr+rect.width(), painter); +} + +void GraphRenderer::render(const QPoint &pos, int height, std::pair *begin, std::pair *end, QPainter &painter) +{ + int x = pos.x(); + for (auto iter = begin; iter != end; iter++) { - const frame_t *begin = frameBegin + (x * framesPerPixel); + const frame_t &min = iter->first; + const frame_t &max = iter->second; + + painter.drawLine(x, pos.y() + (height / 2) - (min[0] * (height / 2)), + x, pos.y() + (height / 2) + (max[0] * (height / 2))); + x++; + } +} + +void GraphRenderer::reduceSamples(const frame_t *inputBegin, const frame_t *inputEnd, std::pair *outputBegin, std::pair *outputEnd) +{ + const auto inputLength = std::distance(inputBegin, inputEnd); + const auto outputLength = std::distance(outputBegin, outputEnd); + + const auto framesPerPixel = inputLength / outputLength; + + for (int i = 0; i < outputLength; i++) + { + frame_t &min = outputBegin[i].first; + frame_t &max = outputBegin[i].second; + + min = {1.f, 1.f}; + max = {-1.f, -1.f}; + + const frame_t *begin = inputBegin + (i * framesPerPixel); const frame_t *end = begin + framesPerPixel; - frame_t min{1.f, 1.f}, max{-1.f, -1.f}; for (auto iter = begin; iter != end; iter++) { if ((*iter)[0] < min[0]) @@ -51,8 +83,5 @@ void GraphRenderer::render(const QRect &rect, const frame_t *frameBegin, const f if ((*iter)[1] > max[1]) max[1] = (*iter)[1]; } - - painter.drawLine(rect.x() + x, rect.y() + (rect.height() / 2) - (min[0] * (rect.height() / 2)), - rect.x() + x, rect.y() + (rect.height() / 2) + (max[0] * (rect.height() / 2))); } } diff --git a/graphrenderer.h b/graphrenderer.h index 0e4dcef..00eff2b 100644 --- a/graphrenderer.h +++ b/graphrenderer.h @@ -9,6 +9,8 @@ class QPalette; namespace GraphRenderer { - QPixmap render(const QSize &size, const frame_t *frameBegin, const frame_t *frameEnd, const QPalette &palette); - void render(const QRect &rect, const frame_t *frameBegin, const frame_t *frameEnd, QPainter &painter, const QPalette &palette); + QPixmap render(const QSize &size, const frame_t *begin, const frame_t *end, const QPalette &palette); + void render(const QRect &rect, const frame_t *begin, const frame_t *end, QPainter &painter); + void render(const QPoint &pos, int height, std::pair *begin, std::pair *end, QPainter &painter); + void reduceSamples(const frame_t *inputBegin, const frame_t *inputEnd, std::pair *outputBegin, std::pair *outputEnd); } diff --git a/mainwindow.cpp b/mainwindow.cpp index c66928b..15355be 100755 --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -106,9 +106,7 @@ MainWindow::MainWindow(const presets::PresetsConfig &presetsConfig, QWidget *par m_presetsProxyModel.setFilterKeyColumn(1); - connect(m_ui->lineEdit, &QLineEdit::textChanged, this, [=](){ - m_presetsProxyModel.setFilterFixedString(m_ui->lineEdit->text()); - }); + connect(m_ui->lineEdit, &QLineEdit::textChanged, &m_presetsProxyModel, &QSortFilterProxyModel::setFilterFixedString); m_ui->filesView->setModel(&m_filesModel); diff --git a/previewwidget.cpp b/previewwidget.cpp index 8d86c31..5fef09d 100644 --- a/previewwidget.cpp +++ b/previewwidget.cpp @@ -23,11 +23,13 @@ void PreviewWidget::paintEvent(QPaintEvent *event) painter.begin(&m_graphCache); painter.setBrush(palette().base()); - painter.drawRect(m_graphCache.rect()); + painter.setPen(QPen{palette().color(QPalette::Text)}); + painter.setBrush(palette().text()); + if (m_buffer.isValid()) - GraphRenderer::render(m_graphCache.rect(), m_buffer.constData(), m_buffer.constData() + m_buffer.frameCount(), painter, palette()); + GraphRenderer::render(m_graphCache.rect(), m_buffer.constData(), m_buffer.constData() + m_buffer.frameCount(), painter); painter.end(); } diff --git a/scratchwidget.cpp b/scratchwidget.cpp index f00f109..f2d10e9 100644 --- a/scratchwidget.cpp +++ b/scratchwidget.cpp @@ -120,9 +120,23 @@ QPixmap ScratchWidget::getPixmap(int index) } const auto *begin = m_buffer.constData() + (index*m_framesPerBeat); - const auto pixmap = GraphRenderer::render(QSize{m_beatWidth, height()}, begin, begin+m_framesPerBeat, palette()); - m_graphCache.insert(index, new QPixmap{pixmap}); + const auto pixmap = new QPixmap{QSize{m_beatWidth, height()}}; - return pixmap; + { + QPainter painter; + painter.begin(pixmap); + + painter.setPen(Qt::blue); + painter.setBrush(palette().base()); + painter.drawRect(pixmap->rect()); + + painter.setPen(QPen{palette().color(QPalette::Text)}); + painter.setBrush(palette().text()); + GraphRenderer::render(pixmap->rect(), begin, begin+m_framesPerBeat, painter); + } + + m_graphCache.insert(index, pixmap); + + return *pixmap; } diff --git a/trackdeck.cpp b/trackdeck.cpp index 020ca7a..e1dc9b5 100644 --- a/trackdeck.cpp +++ b/trackdeck.cpp @@ -179,7 +179,7 @@ void TrackDeck::decodingFinished(const QAudioBuffer &buffer) m_ui->labelTitle->setText(QFileInfo{m_filename}.fileName()); for (auto *btn : m_loopGroup.buttons()) - btn->setEnabled(false); + btn->setEnabled(true); m_ui->previewWidget->setBuffer(buffer); m_ui->scratchWidget->setBuffer(buffer); @@ -233,9 +233,9 @@ void TrackDeck::bpmTap() std::get<1>(*m_bpmTap) = position; std::get<2>(*m_bpmTap)++; const auto framesPerBeat = (std::get<1>(*m_bpmTap)-std::get<0>(*m_bpmTap))/std::get<2>(*m_bpmTap); + m_ui->scratchWidget->setFramesPerBeat(framesPerBeat); const auto beatsPerSecond = frameRate/framesPerBeat; const auto bpm = 60.*beatsPerSecond; - qDebug() << "framesPerBeat =" << framesPerBeat << "beatsPerSecond =" << beatsPerSecond << "bpm =" << bpm; m_ui->doubleSpinBoxBpm->setValue(bpm); } else @@ -250,13 +250,11 @@ void TrackDeck::bpmTap() void TrackDeck::timeout() { const auto framesPerBeat = (std::get<1>(*m_bpmTap)-std::get<0>(*m_bpmTap))/std::get<2>(*m_bpmTap); + m_ui->scratchWidget->setFramesPerBeat(framesPerBeat); const auto beatsPerSecond = frameRate/framesPerBeat; const auto bpm = 60.*beatsPerSecond; - qDebug() << "framesPerBeat =" << framesPerBeat << "beatsPerSecond =" << beatsPerSecond << "bpm =" << bpm; m_ui->pushButtonBpm->setText(tr("BPM tap")); m_ui->doubleSpinBoxBpm->setValue(bpm); - for (auto *btn : m_loopGroup.buttons()) - btn->setEnabled(true); m_bpmTap = {}; } diff --git a/trackdeck.ui b/trackdeck.ui index 018a757..846e3bd 100644 --- a/trackdeck.ui +++ b/trackdeck.ui @@ -6,8 +6,8 @@ 0 0 - 752 - 500 + 567 + 275 @@ -86,89 +86,6 @@ - - - - - 16 - 16777215 - - - - - - - - true - - - true - - - - - - - - 16 - 16777215 - - - - 1 - - - true - - - - - - - - 16 - 16777215 - - - - 2 - - - true - - - - - - - - 16 - 16777215 - - - - 4 - - - true - - - - - - - - 16 - 16777215 - - - - 8 - - - true - - - @@ -228,7 +145,7 @@ - + @@ -273,6 +190,113 @@ + + + + + + Loop: + + + + + + + + 16 + 16777215 + + + + - + + + true + + + true + + + + + + + + 16 + 16777215 + + + + 2 + + + true + + + + + + + + 16 + 16777215 + + + + 1 + + + true + + + + + + + + 16 + 16777215 + + + + 4 + + + true + + + + + + + + 16 + 16777215 + + + + 8 + + + true + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + diff --git a/treetotableproxymodel.cpp b/treetotableproxymodel.cpp new file mode 100644 index 0000000..3f949d6 --- /dev/null +++ b/treetotableproxymodel.cpp @@ -0,0 +1,324 @@ +#include "treetotableproxymodel.h" + +void TreeToTableProxyModel::setSourceModel(QAbstractItemModel *sourceModel) +{ + if (m_sourceModel) + { + disconnect(m_sourceModel, &QAbstractItemModel::dataChanged, this, &TreeToTableProxyModel::sourceDataChanged); + disconnect(m_sourceModel, &QAbstractItemModel::headerDataChanged, this, &QAbstractItemModel::headerDataChanged); + + disconnect(m_sourceModel, &QAbstractItemModel::rowsAboutToBeInserted, this, &TreeToTableProxyModel::sourceRowsAboutToBeInserted); + disconnect(m_sourceModel, &QAbstractItemModel::rowsInserted, this, &TreeToTableProxyModel::sourceRowsInserted); + + disconnect(m_sourceModel, &QAbstractItemModel::rowsAboutToBeRemoved, this, &TreeToTableProxyModel::sourceRowsAboutToBeRemoved); + disconnect(m_sourceModel, &QAbstractItemModel::rowsRemoved, this, &TreeToTableProxyModel::sourceRowsRemoved); + + disconnect(m_sourceModel, &QAbstractItemModel::columnsAboutToBeInserted, this, &TreeToTableProxyModel::sourceColumnsAboutToBeInserted); + disconnect(m_sourceModel, &QAbstractItemModel::columnsInserted, this, &TreeToTableProxyModel::sourceColumnsInserted); + + disconnect(m_sourceModel, &QAbstractItemModel::columnsAboutToBeRemoved, this, &TreeToTableProxyModel::sourceColumnsAboutToBeRemoved); + disconnect(m_sourceModel, &QAbstractItemModel::columnsRemoved, this, &TreeToTableProxyModel::sourceColumnsRemoved); + + disconnect(m_sourceModel, &QAbstractItemModel::modelAboutToBeReset, this, &QAbstractItemModel::modelAboutToBeReset); + disconnect(m_sourceModel, &QAbstractItemModel::modelReset, this, &QAbstractItemModel::modelReset); + + disconnect(m_sourceModel, &QAbstractItemModel::rowsAboutToBeMoved, this, &TreeToTableProxyModel::sourceRowsAboutToBeMoved); + disconnect(m_sourceModel, &QAbstractItemModel::rowsMoved, this, &TreeToTableProxyModel::sourceRowsMoved); + + disconnect(m_sourceModel, &QAbstractItemModel::columnsAboutToBeMoved, this, &TreeToTableProxyModel::sourceColumnsAboutToBeMoved); + disconnect(m_sourceModel, &QAbstractItemModel::columnsMoved, this, &TreeToTableProxyModel::sourceColumnsMoved); + } + + beginResetModel(); + m_sourceModel = sourceModel; + m_rootIndex = {}; + endResetModel(); + + if (m_sourceModel) + { + connect(m_sourceModel, &QAbstractItemModel::dataChanged, this, &TreeToTableProxyModel::sourceDataChanged); + connect(m_sourceModel, &QAbstractItemModel::headerDataChanged, this, &QAbstractItemModel::headerDataChanged); + + connect(m_sourceModel, &QAbstractItemModel::rowsAboutToBeInserted, this, &TreeToTableProxyModel::sourceRowsAboutToBeInserted); + connect(m_sourceModel, &QAbstractItemModel::rowsInserted, this, &TreeToTableProxyModel::sourceRowsInserted); + + connect(m_sourceModel, &QAbstractItemModel::rowsAboutToBeRemoved, this, &TreeToTableProxyModel::sourceRowsAboutToBeRemoved); + connect(m_sourceModel, &QAbstractItemModel::rowsRemoved, this, &TreeToTableProxyModel::sourceRowsRemoved); + + connect(m_sourceModel, &QAbstractItemModel::columnsAboutToBeInserted, this, &TreeToTableProxyModel::sourceColumnsAboutToBeInserted); + connect(m_sourceModel, &QAbstractItemModel::columnsInserted, this, &TreeToTableProxyModel::sourceColumnsInserted); + + connect(m_sourceModel, &QAbstractItemModel::columnsAboutToBeRemoved, this, &TreeToTableProxyModel::sourceColumnsAboutToBeRemoved); + connect(m_sourceModel, &QAbstractItemModel::columnsRemoved, this, &TreeToTableProxyModel::sourceColumnsRemoved); + + connect(m_sourceModel, &QAbstractItemModel::modelAboutToBeReset, this, &QAbstractItemModel::modelAboutToBeReset); + connect(m_sourceModel, &QAbstractItemModel::modelReset, this, &QAbstractItemModel::modelReset); + + connect(m_sourceModel, &QAbstractItemModel::rowsAboutToBeMoved, this, &TreeToTableProxyModel::sourceRowsAboutToBeMoved); + connect(m_sourceModel, &QAbstractItemModel::rowsMoved, this, &TreeToTableProxyModel::sourceRowsMoved); + + connect(m_sourceModel, &QAbstractItemModel::columnsAboutToBeMoved, this, &TreeToTableProxyModel::sourceColumnsAboutToBeMoved); + connect(m_sourceModel, &QAbstractItemModel::columnsMoved, this, &TreeToTableProxyModel::sourceColumnsMoved); + } +} + +void TreeToTableProxyModel::setSourceModelAndRootIndex(QAbstractItemModel *sourceModel, const QModelIndex &index) +{ + Q_ASSERT(index.model() == sourceModel); + + if (m_sourceModel) + { + disconnect(m_sourceModel, &QAbstractItemModel::dataChanged, this, &TreeToTableProxyModel::sourceDataChanged); + disconnect(m_sourceModel, &QAbstractItemModel::headerDataChanged, this, &QAbstractItemModel::headerDataChanged); + + disconnect(m_sourceModel, &QAbstractItemModel::rowsAboutToBeInserted, this, &TreeToTableProxyModel::sourceRowsAboutToBeInserted); + disconnect(m_sourceModel, &QAbstractItemModel::rowsInserted, this, &TreeToTableProxyModel::sourceRowsInserted); + + disconnect(m_sourceModel, &QAbstractItemModel::rowsAboutToBeRemoved, this, &TreeToTableProxyModel::sourceRowsAboutToBeRemoved); + disconnect(m_sourceModel, &QAbstractItemModel::rowsRemoved, this, &TreeToTableProxyModel::sourceRowsRemoved); + + disconnect(m_sourceModel, &QAbstractItemModel::columnsAboutToBeInserted, this, &TreeToTableProxyModel::sourceColumnsAboutToBeInserted); + disconnect(m_sourceModel, &QAbstractItemModel::columnsInserted, this, &TreeToTableProxyModel::sourceColumnsInserted); + + disconnect(m_sourceModel, &QAbstractItemModel::columnsAboutToBeRemoved, this, &TreeToTableProxyModel::sourceColumnsAboutToBeRemoved); + disconnect(m_sourceModel, &QAbstractItemModel::columnsRemoved, this, &TreeToTableProxyModel::sourceColumnsRemoved); + + disconnect(m_sourceModel, &QAbstractItemModel::modelAboutToBeReset, this, &QAbstractItemModel::modelAboutToBeReset); + disconnect(m_sourceModel, &QAbstractItemModel::modelReset, this, &QAbstractItemModel::modelReset); + + disconnect(m_sourceModel, &QAbstractItemModel::rowsAboutToBeMoved, this, &TreeToTableProxyModel::sourceRowsAboutToBeMoved); + disconnect(m_sourceModel, &QAbstractItemModel::rowsMoved, this, &TreeToTableProxyModel::sourceRowsMoved); + + disconnect(m_sourceModel, &QAbstractItemModel::columnsAboutToBeMoved, this, &TreeToTableProxyModel::sourceColumnsAboutToBeMoved); + disconnect(m_sourceModel, &QAbstractItemModel::columnsMoved, this, &TreeToTableProxyModel::sourceColumnsMoved); + } + + beginResetModel(); + m_sourceModel = sourceModel; + m_rootIndex = index; + endResetModel(); + + if (m_sourceModel) + { + connect(m_sourceModel, &QAbstractItemModel::dataChanged, this, &TreeToTableProxyModel::sourceDataChanged); + connect(m_sourceModel, &QAbstractItemModel::headerDataChanged, this, &QAbstractItemModel::headerDataChanged); + + connect(m_sourceModel, &QAbstractItemModel::rowsAboutToBeInserted, this, &TreeToTableProxyModel::sourceRowsAboutToBeInserted); + connect(m_sourceModel, &QAbstractItemModel::rowsInserted, this, &TreeToTableProxyModel::sourceRowsInserted); + + connect(m_sourceModel, &QAbstractItemModel::rowsAboutToBeRemoved, this, &TreeToTableProxyModel::sourceRowsAboutToBeRemoved); + connect(m_sourceModel, &QAbstractItemModel::rowsRemoved, this, &TreeToTableProxyModel::sourceRowsRemoved); + + connect(m_sourceModel, &QAbstractItemModel::columnsAboutToBeInserted, this, &TreeToTableProxyModel::sourceColumnsAboutToBeInserted); + connect(m_sourceModel, &QAbstractItemModel::columnsInserted, this, &TreeToTableProxyModel::sourceColumnsInserted); + + connect(m_sourceModel, &QAbstractItemModel::columnsAboutToBeRemoved, this, &TreeToTableProxyModel::sourceColumnsAboutToBeRemoved); + connect(m_sourceModel, &QAbstractItemModel::columnsRemoved, this, &TreeToTableProxyModel::sourceColumnsRemoved); + + connect(m_sourceModel, &QAbstractItemModel::modelAboutToBeReset, this, &QAbstractItemModel::modelAboutToBeReset); + connect(m_sourceModel, &QAbstractItemModel::modelReset, this, &QAbstractItemModel::modelReset); + + connect(m_sourceModel, &QAbstractItemModel::rowsAboutToBeMoved, this, &TreeToTableProxyModel::sourceRowsAboutToBeMoved); + connect(m_sourceModel, &QAbstractItemModel::rowsMoved, this, &TreeToTableProxyModel::sourceRowsMoved); + + connect(m_sourceModel, &QAbstractItemModel::columnsAboutToBeMoved, this, &TreeToTableProxyModel::sourceColumnsAboutToBeMoved); + connect(m_sourceModel, &QAbstractItemModel::columnsMoved, this, &TreeToTableProxyModel::sourceColumnsMoved); + } +} + +void TreeToTableProxyModel::setRootIndex(const QModelIndex &index) +{ + Q_ASSERT(index.model() == m_sourceModel); + + beginResetModel(); + m_rootIndex = index; + endResetModel(); +} + +QModelIndex TreeToTableProxyModel::mapFromSource(const QModelIndex &index) const +{ + Q_ASSERT(m_sourceModel); + Q_ASSERT(m_rootIndex.isValid()); + Q_ASSERT(index.parent() == m_rootIndex); + + return createIndex(index.row(), index.column()); +} + +QModelIndex TreeToTableProxyModel::mapToSource(const QModelIndex &index) const +{ + Q_ASSERT(m_sourceModel); + Q_ASSERT(m_rootIndex.isValid()); + Q_ASSERT(index.model() == this); + + return m_sourceModel->index(index.row(), index.column(), m_rootIndex); +} + +int TreeToTableProxyModel::rowCount(const QModelIndex &parent) const +{ + Q_ASSERT(!parent.isValid()); + + if (m_sourceModel && m_rootIndex.isValid()) + return m_sourceModel->rowCount(m_rootIndex); + else + return 0; +} + +int TreeToTableProxyModel::columnCount(const QModelIndex &parent) const +{ + Q_ASSERT(!parent.isValid()); + + if (m_sourceModel && m_rootIndex.isValid()) + return m_sourceModel->columnCount(m_rootIndex); + else + return 0; +} + +QVariant TreeToTableProxyModel::data(const QModelIndex &index, int role) const +{ + Q_ASSERT(index.model() == this); + + if (m_sourceModel && m_rootIndex.isValid()) + return m_sourceModel->data(mapToSource(index), role); + else + return {}; +} + +QVariant TreeToTableProxyModel::headerData(int section, Qt::Orientation orientation, int role) const +{ + if (m_sourceModel) + return m_sourceModel->headerData(section, orientation, role); + else + return {}; +} + +void TreeToTableProxyModel::fetchMore(const QModelIndex &parent) +{ + Q_ASSERT(!parent.isValid()); + + if (m_sourceModel && m_rootIndex.isValid()) + m_sourceModel->data(m_rootIndex); +} + +bool TreeToTableProxyModel::canFetchMore(const QModelIndex &parent) const +{ + Q_ASSERT(!parent.isValid()); + + if (m_sourceModel && m_rootIndex.isValid()) + return m_sourceModel->canFetchMore(m_rootIndex); + else + return {}; +} + +Qt::ItemFlags TreeToTableProxyModel::flags(const QModelIndex &index) const +{ + Q_ASSERT(index.model() == this); + + if (m_sourceModel && m_rootIndex.isValid()) + return m_sourceModel->flags(mapToSource(index)); + else + return QAbstractTableModel::flags(index); +} + +void TreeToTableProxyModel::sourceDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QVector &roles) +{ + if (topLeft.parent() != m_rootIndex) + return; + + emit dataChanged(mapFromSource(topLeft), mapFromSource(bottomRight), roles); +} + +void TreeToTableProxyModel::sourceRowsAboutToBeInserted(const QModelIndex &parent, int first, int last) +{ + if (parent != m_rootIndex) + return; + + beginInsertRows({}, first, last); +} + +void TreeToTableProxyModel::sourceRowsInserted(const QModelIndex &parent, int first, int last) +{ + Q_UNUSED(first) + Q_UNUSED(last) + + if (parent != m_rootIndex) + return; + + endInsertRows(); +} + +void TreeToTableProxyModel::sourceRowsAboutToBeRemoved(const QModelIndex &parent, int first, int last) +{ + if (parent != m_rootIndex) + return; + + beginRemoveRows({}, first, last); +} + +void TreeToTableProxyModel::sourceRowsRemoved(const QModelIndex &parent, int first, int last) +{ + Q_UNUSED(first) + Q_UNUSED(last) + + if (parent != m_rootIndex) + return; + + endRemoveRows(); +} + +void TreeToTableProxyModel::sourceColumnsAboutToBeInserted(const QModelIndex &parent, int first, int last) +{ + if (parent != m_rootIndex) + return; + + beginInsertColumns({}, first, last); +} + +void TreeToTableProxyModel::sourceColumnsInserted(const QModelIndex &parent, int first, int last) +{ + Q_UNUSED(first) + Q_UNUSED(last) + + if (parent != m_rootIndex) + return; + + endInsertColumns(); +} + +void TreeToTableProxyModel::sourceColumnsAboutToBeRemoved(const QModelIndex &parent, int first, int last) +{ + if (parent != m_rootIndex) + return; + + beginRemoveColumns({}, first, last); +} + +void TreeToTableProxyModel::sourceColumnsRemoved(const QModelIndex &parent, int first, int last) +{ + Q_UNUSED(first) + Q_UNUSED(last) + + if (parent != m_rootIndex) + return; + + endRemoveColumns(); +} + +void TreeToTableProxyModel::sourceRowsAboutToBeMoved(const QModelIndex &sourceParent, int sourceStart, int sourceEnd, const QModelIndex &destinationParent, int destinationRow) +{ + +} + +void TreeToTableProxyModel::sourceRowsMoved(const QModelIndex &parent, int start, int end, const QModelIndex &destination, int row) +{ + +} + +void TreeToTableProxyModel::sourceColumnsAboutToBeMoved(const QModelIndex &sourceParent, int sourceStart, int sourceEnd, const QModelIndex &destinationParent, int destinationColumn) +{ + +} + +void TreeToTableProxyModel::sourceColumnsMoved(const QModelIndex &parent, int start, int end, const QModelIndex &destination, int column) +{ + +} diff --git a/treetotableproxymodel.h b/treetotableproxymodel.h new file mode 100644 index 0000000..6e0b7cd --- /dev/null +++ b/treetotableproxymodel.h @@ -0,0 +1,49 @@ +#pragma once + +#include + +class TreeToTableProxyModel : public QAbstractTableModel +{ +public: + using QAbstractTableModel::QAbstractTableModel; + + void setSourceModel(QAbstractItemModel *sourceModel); + void setSourceModelAndRootIndex(QAbstractItemModel *sourceModel, const QModelIndex &index); + void setRootIndex(const QModelIndex &index); + + QModelIndex mapFromSource(const QModelIndex &index) const; + QModelIndex mapToSource(const QModelIndex &index) const; + + int rowCount(const QModelIndex &parent) const override; + int columnCount(const QModelIndex &parent) const override; + QVariant data(const QModelIndex &index, int role) const override; + QVariant headerData(int section, Qt::Orientation orientation, int role) const override; + void fetchMore(const QModelIndex &parent) override; + bool canFetchMore(const QModelIndex &parent) const override; + Qt::ItemFlags flags(const QModelIndex &index) const override; + +private slots: + void sourceDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QVector &roles = QVector()); + + void sourceRowsAboutToBeInserted(const QModelIndex &parent, int first, int last); + void sourceRowsInserted(const QModelIndex &parent, int first, int last); + + void sourceRowsAboutToBeRemoved(const QModelIndex &parent, int first, int last); + void sourceRowsRemoved(const QModelIndex &parent, int first, int last); + + void sourceColumnsAboutToBeInserted(const QModelIndex &parent, int first, int last); + void sourceColumnsInserted(const QModelIndex &parent, int first, int last); + + void sourceColumnsAboutToBeRemoved(const QModelIndex &parent, int first, int last); + void sourceColumnsRemoved(const QModelIndex &parent, int first, int last); + + void sourceRowsAboutToBeMoved( const QModelIndex &sourceParent, int sourceStart, int sourceEnd, const QModelIndex &destinationParent, int destinationRow); + void sourceRowsMoved(const QModelIndex &parent, int start, int end, const QModelIndex &destination, int row); + + void sourceColumnsAboutToBeMoved( const QModelIndex &sourceParent, int sourceStart, int sourceEnd, const QModelIndex &destinationParent, int destinationColumn); + void sourceColumnsMoved(const QModelIndex &parent, int start, int end, const QModelIndex &destination, int column); + +private: + const QAbstractItemModel *m_sourceModel{}; + QModelIndex m_rootIndex; +};