QSortFilterProxyModel subclass for readonly columns columns with checkboxes and password columns: Difference between revisions
No edit summary |
No edit summary |
||
Line 1: | Line 1: | ||
[[Category:Snippets]] | [[Category:Snippets]] | ||
[toc align_right="yes" depth="3"] | |||
= QSortFilterProxyModel subclass for readonly, checkboxes and password columns = | = QSortFilterProxyModel subclass for readonly, checkboxes and password columns = | ||
Line 9: | Line 10: | ||
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 [[QSortFilterProxyModel_subclass_to_add_a_checkbox|CheckableProxyModel]]. | 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 [[QSortFilterProxyModel_subclass_to_add_a_checkbox|CheckableProxyModel]]. | ||
You should create three | 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 ([[QSqlRelationalDelegate_subclass_that_works_with_QSqlRelationalTableModel|mySqlRelationalDelegate]]) that you can use. | * '''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 ([[QSqlRelationalDelegate_subclass_that_works_with_QSqlRelationalTableModel|mySqlRelationalDelegate]]) that you can use. | ||
Line 17: | Line 18: | ||
== Usage == | == Usage == | ||
The subclass usage is as follows: | The subclass usage is as follows: | ||
<code> | |||
CheckableSortFilterProxyModel *cfpm = new CheckableSortFilterProxyModel(this); | |||
QList<int> boolCols; | |||
boolCols.append( usrModel->fieldIndex("isActive") ); | |||
boolCols.append( usrModel->fieldIndex("isOk") ); | |||
QList | QList<int> readonlyCols; | ||
readonlyCols.append( usrModel->fieldIndex("id") ); | |||
QList | QList<int> pwdCols; | ||
pwdCols.append( usrModel->fieldIndex("passwordFld")); | |||
cfpm- | cfpm->setParameters(boolCols, readonlyCols, pwdCols); | ||
cfpm- | cfpm->setSourceModel( mySqlTableModel ); | ||
myTableView->setModel(cfpm); | |||
QList | QList<int> nullCols; | ||
QList<int> notNullCols; | |||
notNullCols.append( usrModel->fieldIndex("isActive"); | |||
cfpm->setNotNullColumns(nullCols, notNullCols); | |||
</code> | </code> | ||
Line 37: | Line 49: | ||
=== checkablesortfilterproxymodel.h === | === checkablesortfilterproxymodel.h === | ||
<code> | <code> | ||
#ifndef CHECKABLESORTFILTERPROXYMODEL_H | |||
#define CHECKABLESORTFILTERPROXYMODEL_H | |||
#include | #include <QSortFilterProxyModel> | ||
class CheckableSortFilterProxyModel : public QSortFilterProxyModel | class CheckableSortFilterProxyModel : public QSortFilterProxyModel | ||
{ | |||
Q_OBJECT | |||
public: | |||
explicit CheckableSortFilterProxyModel(QObject *parent = 0); | |||
void setParameters(QList | 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; | 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: | protected: | ||
bool filterAcceptsRow ( int source_row, const QModelIndex & source_parent ) const; | |||
signals: | signals: | ||
Line 53: | Line 75: | ||
public slots: | public slots: | ||
private:< | private: | ||
QList<int> booleanSet; | |||
QList<int> passwordSet; | |||
QList<int> readonlySet; | |||
QList<int> notNullSet; | |||
QList<int> nullSet; | |||
}; | }; | ||
</code> | |||
=== checkablesortfilterproxymodel.cpp === | === checkablesortfilterproxymodel.cpp === | ||
<code> | <code> | ||
#include "checkablesortfilterproxymodel.h" | |||
CheckableSortFilterProxyModel::CheckableSortFilterProxyModel(QObject *parent) : | CheckableSortFilterProxyModel::CheckableSortFilterProxyModel(QObject *parent) : | ||
QSortFilterProxyModel(parent) | |||
{ | |||
} | |||
void CheckableSortFilterProxyModel::setParameters(QList | 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 (!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 | 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 (! | 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 { | 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 { | bool CheckableSortFilterProxyModel::filterAcceptsRow ( int source_row, const QModelIndex & source_parent ) const { | ||
Q_UNUSED(source_parent); | |||
if (!notNullSet.isEmpty()) { | 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()) { | 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 { | 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 (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); | return index.data(Qt::EditRole).toBool() ? QVariant(Qt::Checked) : QVariant(Qt::Unchecked); | ||
else if (role Qt::DisplayRole) | 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(); | return QVariant(); | ||
} | |||
bool CheckableSortFilterProxyModel::setData(const QModelIndex &index, const QVariant &value, int role) { | bool CheckableSortFilterProxyModel::setData(const QModelIndex &index, const QVariant &value, int role) { | ||
if(!index.isValid()) | |||
return false; | |||
if(booleanSet.contains(index.column()) && roleQt::CheckStateRole) | if(booleanSet.contains(index.column()) && roleQt::CheckStateRole) | ||
{ | |||
QVariant data = (value.toInt()Qt::Checked) ? QVariant(1) : QVariant (0); | 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 { | Qt::ItemFlags CheckableSortFilterProxyModel::flags ( const QModelIndex & index ) const { | ||
if(!index.isValid()) | |||
return Qt::ItemIsEnabled; | |||
if (booleanSet.contains(index.column())) | 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); | |||
} | } | ||
</code> |
Revision as of 10:15, 25 February 2015
[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);
}