Improvements

This commit is contained in:
2020-04-30 21:06:17 +02:00
parent 81cc81fe3a
commit 96167220ca
13 changed files with 589 additions and 136 deletions

View File

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

View File

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

View File

@ -2,10 +2,12 @@
#include <QWidget>
#include <QFileSystemModel>
#include <QSortFilterProxyModel>
#include <memory>
#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;
};

View File

@ -100,6 +100,13 @@
<layout class="QVBoxLayout">
<item>
<layout class="QHBoxLayout">
<item>
<widget class="QLineEdit" name="lineEditSearch">
<property name="clearButtonEnabled">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="pushButtonLoadDeckA">
<property name="text">
@ -121,15 +128,6 @@
<property name="dragEnabled">
<bool>true</bool>
</property>
<property name="rootIsDecorated">
<bool>false</bool>
</property>
<property name="itemsExpandable">
<bool>false</bool>
</property>
<property name="sortingEnabled">
<bool>true</bool>
</property>
</widget>
</item>
</layout>

View File

@ -6,40 +6,72 @@
#include <QPainter>
#include <QPalette>
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<frame_t, frame_t> 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<frame_t, frame_t> *begin, std::pair<frame_t, frame_t> *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<frame_t, frame_t> *outputBegin, std::pair<frame_t, frame_t> *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)));
}
}

View File

@ -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<frame_t, frame_t> *begin, std::pair<frame_t, frame_t> *end, QPainter &painter);
void reduceSamples(const frame_t *inputBegin, const frame_t *inputEnd, std::pair<frame_t, frame_t> *outputBegin, std::pair<frame_t, frame_t> *outputEnd);
}

View File

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

View File

@ -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<frame_t>(), m_buffer.constData<frame_t>() + m_buffer.frameCount(), painter, palette());
GraphRenderer::render(m_graphCache.rect(), m_buffer.constData<frame_t>(), m_buffer.constData<frame_t>() + m_buffer.frameCount(), painter);
painter.end();
}

View File

@ -120,9 +120,23 @@ QPixmap ScratchWidget::getPixmap(int index)
}
const auto *begin = m_buffer.constData<frame_t>() + (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;
}

View File

@ -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 = {};
}

View File

@ -6,8 +6,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>752</width>
<height>500</height>
<width>567</width>
<height>275</height>
</rect>
</property>
<property name="sizePolicy">
@ -86,89 +86,6 @@
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="pushButtonLoopOff">
<property name="maximumSize">
<size>
<width>16</width>
<height>16777215</height>
</size>
</property>
<property name="text">
<string>-</string>
</property>
<property name="checkable">
<bool>true</bool>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="pushButtonLoop1">
<property name="maximumSize">
<size>
<width>16</width>
<height>16777215</height>
</size>
</property>
<property name="text">
<string>1</string>
</property>
<property name="checkable">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="pushButtonLoop2">
<property name="maximumSize">
<size>
<width>16</width>
<height>16777215</height>
</size>
</property>
<property name="text">
<string>2</string>
</property>
<property name="checkable">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="pushButtonLoop4">
<property name="maximumSize">
<size>
<width>16</width>
<height>16777215</height>
</size>
</property>
<property name="text">
<string>4</string>
</property>
<property name="checkable">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="pushButtonLoop8">
<property name="maximumSize">
<size>
<width>16</width>
<height>16777215</height>
</size>
</property>
<property name="text">
<string>8</string>
</property>
<property name="checkable">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QSlider" name="sliderZoom">
<property name="maximumSize">
@ -228,7 +145,7 @@
<item>
<layout class="QHBoxLayout" name="horizontalLayout_3" stretch="1,0">
<item>
<layout class="QVBoxLayout" name="verticalLayout">
<layout class="QVBoxLayout" name="verticalLayout" stretch="1,1,0">
<item>
<widget class="PreviewWidget" name="previewWidget" native="true">
<property name="sizePolicy">
@ -273,6 +190,113 @@
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_6">
<item>
<widget class="QLabel" name="labelLoop">
<property name="text">
<string>Loop:</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="pushButtonLoopOff">
<property name="maximumSize">
<size>
<width>16</width>
<height>16777215</height>
</size>
</property>
<property name="text">
<string>-</string>
</property>
<property name="checkable">
<bool>true</bool>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="pushButtonLoop2">
<property name="maximumSize">
<size>
<width>16</width>
<height>16777215</height>
</size>
</property>
<property name="text">
<string>2</string>
</property>
<property name="checkable">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="pushButtonLoop1">
<property name="maximumSize">
<size>
<width>16</width>
<height>16777215</height>
</size>
</property>
<property name="text">
<string>1</string>
</property>
<property name="checkable">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="pushButtonLoop4">
<property name="maximumSize">
<size>
<width>16</width>
<height>16777215</height>
</size>
</property>
<property name="text">
<string>4</string>
</property>
<property name="checkable">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="pushButtonLoop8">
<property name="maximumSize">
<size>
<width>16</width>
<height>16777215</height>
</size>
</property>
<property name="text">
<string>8</string>
</property>
<property name="checkable">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_4">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
</layout>
</item>
<item>

324
treetotableproxymodel.cpp Normal file
View File

@ -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<int> &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)
{
}

49
treetotableproxymodel.h Normal file
View File

@ -0,0 +1,49 @@
#pragma once
#include <QAbstractTableModel>
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<int> &roles = QVector<int>());
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;
};