Improvements
This commit is contained in:
@ -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 \
|
||||
|
19
djwidget.cpp
19
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);
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
};
|
||||
|
16
djwidget.ui
16
djwidget.ui
@ -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>
|
||||
|
@ -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)));
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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 = {};
|
||||
}
|
||||
|
||||
|
196
trackdeck.ui
196
trackdeck.ui
@ -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
324
treetotableproxymodel.cpp
Normal 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
49
treetotableproxymodel.h
Normal 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;
|
||||
};
|
Reference in New Issue
Block a user