1

If I call removeRows on records which were read from the database a ! will be displayed in the first column of the tableView.

enter image description here

The only thing which I would like to achieve is that this row will not be displayed in the view. I tried it with QSortFilterProxyModel but I don't know where I can get the flag which is used to display the ! in the first column. Is there a way to set a filter in QSortFilterProxyModel that it only contains the rows which don't have this flag?

From where does the view take the information, that the removed row is marked with a "!" ? This information might be hidden somewhere in the model, but I cannot find out where.

MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent),
    m_ui(new Ui::MainWindow),
    m_model(new QSqlTableModel(this)),
    m_proxyModel(new QSortFilterProxyModel(this))
{
    m_ui->setupUi(this);
    m_model->setTable("test");
    m_model->setEditStrategy(QSqlTableModel::OnManualSubmit);
    m_model->select();

    m_proxyModel->setSourceModel(m_model);

    m_ui->tableView->setModel(m_proxyModel);

    qDebug() << "Select       : Row count:" << m_model->rowCount();

    connect(m_ui->tableView->selectionModel(), &QItemSelectionModel::selectionChanged,
            this, &MainWindow::on_selectionChanged);
}

MainWindow::~MainWindow()
{
    delete m_ui;
}

void MainWindow::on_pushButtonNewRecord_clicked()
{
    qDebug() << "New Record";

    m_record = m_model->record();
    m_record.setValue("firstname", "john");
    m_record.setValue("lastname", "doe");
    m_record.setValue("email", "john.doe@email.com");

    m_model->insertRecord(-1, m_record);

    qDebug() << "New Record   : Row count:" << m_model->rowCount();
}

void MainWindow::on_pushButtonRemoveRow_clicked()
{
    qDebug() << "Remove Row";

    if (m_row >= 0) {
        m_proxyModel->removeRow(m_row);

        qDebug() << "Remove Record: Row count:" << m_model->rowCount();
    }

    for (int i = 0; i < m_model->rowCount(); i++) {
        qDebug() << "\n";
        qDebug() << "Remove Row: index  :" << m_model->index(i, 0);
        qDebug() << "Remove Row: isValid:" << m_model->index(i, 0).isValid();
        qDebug() << "Remove Row: isDirty:" << m_model->isDirty(m_model->index(i, 0));
        qDebug() << "Remove Row: flags  :" << m_model->index(i, 0).flags();
        qDebug() << "Remove Row: data   :" << m_model->index(i, 0).data(Qt::DisplayRole);
        qDebug() << "Remove Row: heaader:" << m_model->headerData(i, Qt::Vertical);
        QVariant verticalHeader = m_model->headerData(i, Qt::Vertical);
        if (verticalHeader == "!") {
            qDebug() << "Deleted";
        }
        //qDebug() << m_model->record(i);
    }
}

void MainWindow::on_pushButtonSubmit_clicked()
{
    qDebug() << "Submit";

    m_model->submitAll();
    m_model->select();
}


void MainWindow::on_selectionChanged(const QItemSelection &selected, const QItemSelection &deselected)
{
    Q_UNUSED(deselected)

    if (!selected.isEmpty()) {
        m_row = selected.indexes().first().row();
    }
}
Bumblebee
  • 513
  • 2
  • 4
  • 15

1 Answers1

1

You have to implement a QSortFilterProxyModel that filters the rows that are Dirty and whose vertical header text is "!", You must also call the invalidate() method to force the application of the filter.

dirtyfilterproxymodel.h

#ifndef DIRTYFILTERPROXYMODEL_H
#define DIRTYFILTERPROXYMODEL_H

#include <QSortFilterProxyModel>
#include <QSqlTableModel>

class DirtyFilterProxyModel : public QSortFilterProxyModel
{
public:
    using QSortFilterProxyModel::QSortFilterProxyModel;
protected:
    bool filterAcceptsRow(int source_row, const QModelIndex &source_parent) const
    {
        if(QSqlTableModel *source_model = qobject_cast<QSqlTableModel *>(sourceModel())){
            QModelIndex ix = source_model->index(source_row, 0, source_parent);
            QString row_header_item = source_model->headerData(source_row, Qt::Vertical, Qt::DisplayRole).toString();
            return !(source_model->isDirty(ix) && row_header_item == QLatin1String("!"));
        }
        return QSortFilterProxyModel::filterAcceptsRow(source_row, source_parent);
    }
};

#endif // DIRTYFILTERPROXYMODEL_H

mainwindow.h

// ...
class DirtyFilterProxyModel;
// ...
class MainWindow : public QMainWindow
{
    // ...
private:
    Ui::MainWindow *m_ui;
    DirtyFilterProxyModel *m_proxyModel;
    // ...

mainwindow.cpp

#include "dirtyfilterproxymodel.h"
// ...
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent),
    m_ui(new Ui::MainWindow),
    m_model(new QSqlTableModel(this)),
    m_proxyModel(new DirtyFilterProxyModel(this))
{
    // ...
}

void MainWindow::on_pushButtonNewRecord_clicked()
{
    // ...
    m_model->insertRecord(-1, m_record);
    m_proxyModel->invalidate();
}
// ...
void MainWindow::on_pushButtonRemoveRow_clicked()
{    if (m_row >= 0) {
        m_proxyModel->removeRow(m_row);
        m_proxyModel->invalidate();
    }
}
eyllanesc
  • 235,170
  • 19
  • 170
  • 241
  • Perfect! That is exactly what I was looking for. Thank you very much – Bumblebee Dec 23 '19 at 18:05
  • But there is still one thing I would like to know. Where does QSqlTableModel get the information which triggers the "!" in the vertical header? – Bumblebee Dec 23 '19 at 18:07
  • @Bumblebee mmm, I do not understand your question but I will explain how QSqlTableModel works: the model has items that reflect the DB table + implemented modifications made by the user (new rows or remove rows) and for that the model has a **cache** so for differentiating it adds symbols in the headerData ("*" and "!"), you can see that in the source code: https://github.com/qt/qtbase/blob/58c69df4d38324644bc49ec5f42ee8343a454b2d/src/sql/models/qsqltablemodel.cpp#L490 – eyllanesc Dec 23 '19 at 18:12