QSortFilterProxyModel subclass for readonly columns columns with checkboxes and password columns
[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 <code>QList<int></code> 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:
<br />CheckableSortFilterProxyModel *cfpm = new CheckableSortFilterProxyModel(this);<br />QList&lt;int&gt; boolCols;<br />boolCols.append( usrModel->fieldIndex("isActive&quot;) );<br />boolCols.append( usrModel->fieldIndex("isOk&quot;) );
QList&lt;int&gt; readonlyCols;<br />readonlyCols.append( usrModel->fieldIndex("id&quot;) );
QList&lt;int&gt; pwdCols;<br />pwdCols.append( usrModel->fieldIndex("passwordFld&quot;));
cfpm->setParameters(boolCols, readonlyCols, pwdCols);
cfpm->setSourceModel( mySqlTableModel );<br />myTableView->setModel(cfpm);
QList&lt;int&gt; nullCols;<br />QList&lt;int&gt; notNullCols;<br />notNullCols.append( usrModel->fieldIndex("isActive&quot;);<br />cfpm->setNotNullColumns(nullCols, notNullCols);
Code
So here is the code:
checkablesortfilterproxymodel.h
<br />#ifndef CHECKABLESORTFILTERPROXYMODEL_H<br />#define CHECKABLESORTFILTERPROXYMODEL_H
#include <QSortFilterProxyModel&gt;
class CheckableSortFilterProxyModel : public QSortFilterProxyModel<br />{<br /> Q_OBJECT<br />public:<br /> explicit CheckableSortFilterProxyModel(QObject *parent = 0);
void setParameters(QList&lt;int&gt; boolCols, QList&lt;int&gt; readonlyCols, QList&lt;int&gt; passwordCols);<br /> void setNullAndNotNullColumns(QList&lt;int&gt; nullCols, QList&lt;int&gt; notNullCols);
QVariant data(const QModelIndex &index, int role=Qt::DisplayRole) const;<br /> bool setData(const QModelIndex &index, const QVariant &value, int role=Qt::EditRole);<br /> Qt::ItemFlags flags ( const QModelIndex & index ) const;
protected:<br /> bool filterAcceptsRow ( int source_row, const QModelIndex & source_parent ) const;
signals:
public slots:
private:<br /> QList&lt;int&gt; booleanSet;<br /> QList&lt;int&gt; passwordSet;<br /> QList&lt;int&gt; readonlySet;<br /> QList&lt;int&gt; notNullSet;<br /> QList&lt;int&gt; nullSet;
};<br />
checkablesortfilterproxymodel.cpp
<br />#include "checkablesortfilterproxymodel.h&quot;
CheckableSortFilterProxyModel::CheckableSortFilterProxyModel(QObject *parent) :<br /> QSortFilterProxyModel(parent)<br />{<br />}
void CheckableSortFilterProxyModel::setParameters(QList&lt;int&gt; boolCols, QList&lt;int&gt; readonlyCols, QList&lt;int&gt; passwordCols) {<br /> booleanSet.clear();<br /> readonlySet.clear();<br /> passwordSet.clear();
if (!boolCols.isEmpty()) { foreach(int column , boolCols) { booleanSet.append(column); } }<br /> if (!readonlyCols.isEmpty()) { foreach(int column , readonlyCols) { readonlySet.append(column); } }<br /> if (!passwordCols.isEmpty()) { foreach(int column , passwordCols) { passwordSet.append(column); } }
}
void CheckableSortFilterProxyModel::setNullAndNotNullColumns(QList&lt;int&gt; nullCols, QList&lt;int&gt; notNullCols) {<br /> notNullSet.clear();<br /> nullSet.clear();
if (!notNullCols.isEmpty()) {<br /> // this only works when our model is a QSqlQueryModel subclass<br /> if (sourceModel()<s>>inherits("QSqlQueryModel&quot;)) {<br /> foreach(int column , notNullCols) { notNullSet.append(column); }<br /> }<br /> invalidateFilter();<br /> }
<br /> if (!nullCols.isEmpty()) {<br /> // this only works when our model is a QSqlQueryModel subclass<br /> if (sourceModel()</s>>inherits("QSqlQueryModel&quot;)) {<br /> foreach(int column , nullCols) { nullSet.append(column); }<br /> }<br /> invalidateFilter();<br /> }<br />}
bool CheckableSortFilterProxyModel::filterAcceptsRow ( int source_row, const QModelIndex & source_parent ) const {<br /> Q_UNUSED(source_parent);<br /> if (!notNullSet.isEmpty()) {<br /> QSqlQueryModel '''m = static_cast&lt;QSqlQueryModel'''>(sourceModel());<br /> foreach (int column, notNullSet)<br /> if (m->record(source_row).isNull(column))<br /> return false;
bool CheckableSortFilterProxyModel::filterAcceptsRow ( int source_row, const QModelIndex & source_parent ) const {<br /> Q_UNUSED(source_parent);
if (!notNullSet.isEmpty()) {<br /> QSqlQueryModel '''m = static_cast&lt;QSqlQueryModel'''>(sourceModel());<br /> foreach (int column, notNullSet)<br /> if (m->record(source_row).isNull(column))<br /> return false;<br /> }
if (!nullSet.isEmpty()) {<br /> QSqlQueryModel '''m = static_cast&lt;QSqlQueryModel'''>(sourceModel());<br /> foreach (int column, nullSet)<br /> if (!m->record(source_row).isNull(column))<br /> return false;<br /> }<br /> return true;<br />}
QVariant CheckableSortFilterProxyModel::data(const QModelIndex &index, int role) const {<br /> if (!index.isValid())<br /> return QVariant();
if (booleanSet.contains(index.column()) && (role Qt::CheckStateRole || role Qt::DisplayRole)) {<br /> if (role Qt::CheckStateRole)
return index.data(Qt::EditRole).toBool() ? QVariant(Qt::Checked) : QVariant(Qt::Unchecked);
else if (role Qt::DisplayRole)<br /> return QVariant();<br /> } else if (passwordSet.contains(index.column()) && (role == Qt::DisplayRole)) {<br /> return QVariant("''''''*");<br /> } else<br /> return QSortFilterProxyModel::data(index,role);
return QVariant();<br />}
bool CheckableSortFilterProxyModel::setData(const QModelIndex &index, const QVariant &value, int role) {<br /> if(!index.isValid())<br /> return false;
if(booleanSet.contains(index.column()) && roleQt::CheckStateRole)
&#123;
QVariant data = (value.toInt()Qt::Checked) ? QVariant(1) : QVariant (0);<br /> return QSortFilterProxyModel::setData(index, data, Qt::EditRole);<br /> }<br /> else<br /> return QSortFilterProxyModel::setData(index,value,role);
}
Qt::ItemFlags CheckableSortFilterProxyModel::flags ( const QModelIndex & index ) const {<br /> if(!index.isValid())<br /> return Qt::ItemIsEnabled;
if (booleanSet.contains(index.column()))<br /> return Qt::ItemIsUserCheckable | Qt::ItemIsSelectable | Qt::ItemIsEnabled;<br /> else if (readonlySet.contains(index.column()))<br /> return Qt::ItemIsSelectable;<br /> else<br /> return QSortFilterProxyModel::flags(index);
}<br />