QSortFilterProxyModel subclass for readonly columns columns with checkboxes and password columns

From Qt Wiki
Revision as of 17:33, 12 March 2015 by AutoSpider (talk | contribs) (Decode HTML entity names)
Jump to navigation Jump to search
The printable version is no longer supported and may have rendering errors. Please update your browser bookmarks and please use the default browser print function instead.
This article may require cleanup to meet the Qt Wiki's quality standards. Reason: Auto-imported from ExpressionEngine.
Please improve this article if you can. Remove the {{cleanup}} tag and add this page to Updated pages list after it's clean.

[toc align_right="yes" depth="3"]

QSortFilterProxyModel subclass for readonly, checkboxes and password columns

When you try to use a QTableView with QSql*' model classes, it is difficult to make boolean column appear as check boxes or make columns readonly.

This is a QSortFilterProxyModel subclass that is designed to be generic enough to easily accomplish these tasks. It also includes some primitive 'password' field support.

If you want to add a check box to a model but you don't want to use a boolean field in the source model to keep track of the value of the check box, you can take a look at CheckableProxyModel.

You should create three

QList<int>

container classes, one each to hold the column indexes of the fields you want checkboxes for, to be displayed as passwords, or be readonly.

  • NOTE: If you are using a QSqlRelationalTableModel, there are issues with the QSortFilterProxyModel (the combo box). To resolve that, I have created another wiki article about a QSqlRelationalDelegate subclass (mySqlRelationalDelegate) that you can use.
  • EDIT: Since I discovered another problem with the handling of NULL values, I have added the possibility to this class to address it.

Usage

The subclass usage is as follows:

CheckableSortFilterProxyModel *cfpm = new CheckableSortFilterProxyModel(this);
QList<int> boolCols;
boolCols.append( usrModel->fieldIndex("isActive") );
boolCols.append( usrModel->fieldIndex("isOk") );

QList<int> readonlyCols;
readonlyCols.append( usrModel->fieldIndex("id") );

QList<int> pwdCols;
pwdCols.append( usrModel->fieldIndex("passwordFld"));

cfpm->setParameters(boolCols, readonlyCols, pwdCols);

cfpm->setSourceModel( mySqlTableModel );
myTableView->setModel(cfpm);

QList<int> nullCols;
QList<int> notNullCols;
notNullCols.append( usrModel->fieldIndex("isActive");
cfpm->setNotNullColumns(nullCols, notNullCols);

Code

So here is the code:

checkablesortfilterproxymodel.h

#ifndef CHECKABLESORTFILTERPROXYMODEL_H
#define CHECKABLESORTFILTERPROXYMODEL_H

#include <QSortFilterProxyModel>

class CheckableSortFilterProxyModel : public QSortFilterProxyModel
{
 Q_OBJECT
public:
 explicit CheckableSortFilterProxyModel(QObject *parent = 0);

void setParameters(QList<int> boolCols, QList<int> readonlyCols, QList<int> passwordCols);
 void setNullAndNotNullColumns(QList<int> nullCols, QList<int> notNullCols);

QVariant data(const QModelIndex &index, int role=Qt::DisplayRole) const;
 bool setData(const QModelIndex &index, const QVariant &value, int role=Qt::EditRole);
 Qt::ItemFlags flags ( const QModelIndex & index ) const;

protected:
 bool filterAcceptsRow ( int source_row, const QModelIndex & source_parent ) const;

signals:

public slots:

private:
 QList<int> booleanSet;
 QList<int> passwordSet;
 QList<int> readonlySet;
 QList<int> notNullSet;
 QList<int> nullSet;

};

checkablesortfilterproxymodel.cpp

#include "checkablesortfilterproxymodel.h"

CheckableSortFilterProxyModel::CheckableSortFilterProxyModel(QObject *parent) :
 QSortFilterProxyModel(parent)
{
}

void CheckableSortFilterProxyModel::setParameters(QList<int> boolCols, QList<int> readonlyCols, QList<int> passwordCols) {
 booleanSet.clear();
 readonlySet.clear();
 passwordSet.clear();

if (!boolCols.isEmpty()) { foreach(int column , boolCols) { booleanSet.append(column); } }
 if (!readonlyCols.isEmpty()) { foreach(int column , readonlyCols) { readonlySet.append(column); } }
 if (!passwordCols.isEmpty()) { foreach(int column , passwordCols) { passwordSet.append(column); } }

}

void CheckableSortFilterProxyModel::setNullAndNotNullColumns(QList<int> nullCols, QList<int> notNullCols) {
 notNullSet.clear();
 nullSet.clear();

if (!notNullCols.isEmpty()) {
 // this only works when our model is a QSqlQueryModel subclass
 if (sourceModel()->inherits("QSqlQueryModel")) {
 foreach(int column , notNullCols) { notNullSet.append(column); }
 }
 invalidateFilter();
 }

 if (!nullCols.isEmpty()) {
 // this only works when our model is a QSqlQueryModel subclass
 if (sourceModel()->inherits("QSqlQueryModel")) {
 foreach(int column , nullCols) { nullSet.append(column); }
 }
 invalidateFilter();
 }
}

bool CheckableSortFilterProxyModel::filterAcceptsRow ( int source_row, const QModelIndex & source_parent ) const {
 Q_UNUSED(source_parent);
 if (!notNullSet.isEmpty()) {
 QSqlQueryModel '''m = static_cast<QSqlQueryModel'''>(sourceModel());
 foreach (int column, notNullSet)
 if (m->record(source_row).isNull(column))
 return false;

bool CheckableSortFilterProxyModel::filterAcceptsRow ( int source_row, const QModelIndex & source_parent ) const {
 Q_UNUSED(source_parent);

if (!notNullSet.isEmpty()) {
 QSqlQueryModel '''m = static_cast<QSqlQueryModel'''>(sourceModel());
 foreach (int column, notNullSet)
 if (m->record(source_row).isNull(column))
 return false;
 }

if (!nullSet.isEmpty()) {
 QSqlQueryModel '''m = static_cast<QSqlQueryModel'''>(sourceModel());
 foreach (int column, nullSet)
 if (!m->record(source_row).isNull(column))
 return false;
 }
 return true;
}

QVariant CheckableSortFilterProxyModel::data(const QModelIndex &index, int role) const {
 if (!index.isValid())
 return QVariant();

if (booleanSet.contains(index.column()) && (role  Qt::CheckStateRole || role  Qt::DisplayRole)) {
 if (role  Qt::CheckStateRole)
            return index.data(Qt::EditRole).toBool() ? QVariant(Qt::Checked) : QVariant(Qt::Unchecked);
        else if (role  Qt::DisplayRole)
 return QVariant();
 } else if (passwordSet.contains(index.column()) && (role == Qt::DisplayRole)) {
 return QVariant("''''''*");
 } else
 return QSortFilterProxyModel::data(index,role);

return QVariant();
}

bool CheckableSortFilterProxyModel::setData(const QModelIndex &index, const QVariant &value, int role) {
 if(!index.isValid())
 return false;

if(booleanSet.contains(index.column()) && roleQt::CheckStateRole)
    {
        QVariant data = (value.toInt()Qt::Checked) ? QVariant(1) : QVariant (0);
 return QSortFilterProxyModel::setData(index, data, Qt::EditRole);
 }
 else
 return QSortFilterProxyModel::setData(index,value,role);

}

Qt::ItemFlags CheckableSortFilterProxyModel::flags ( const QModelIndex & index ) const {
 if(!index.isValid())
 return Qt::ItemIsEnabled;

if (booleanSet.contains(index.column()))
 return Qt::ItemIsUserCheckable | Qt::ItemIsSelectable | Qt::ItemIsEnabled;
 else if (readonlySet.contains(index.column()))
 return Qt::ItemIsSelectable;
 else
 return QSortFilterProxyModel::flags(index);

}