QSortFilterProxyModel subclass for readonly columns columns with checkboxes and password columns: Difference between revisions

From Qt Wiki
Jump to navigation Jump to search
No edit summary
 
(Remove non-functioning "toc" command)
 
(4 intermediate revisions by 2 users not shown)
Line 1: Line 1:
=QSortFilterProxyModel subclass for readonly, checkboxes and password columns=
{{Cleanup | reason=Auto-imported from ExpressionEngine.}}


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.
[[Category:Snippets]]


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.
= QSortFilterProxyModel subclass for readonly, checkboxes and password columns =


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]].
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.


You should create three <code>QList&lt;int&gt;</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.
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.


* '''<span class="caps">NOTE</span>:''' 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.
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]].


* '''<span class="caps">EDIT</span>:''' Since I discovered another problem with the handling of <span class="caps">NULL</span> values, I have added the possibility to this class to address it.
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.


==Usage==
* '''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.


The subclass usage is as follows:<br />
* '''EDIT:''' Since I discovered another problem with the handling of NULL values, I have added the possibility to this class to address it.


==Code==
== Usage ==
 
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<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>
 
== Code ==


So here is the code:
So here is the code:


===checkablesortfilterproxymodel.h===
=== checkablesortfilterproxymodel.h ===
 
<code>
#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;
 
};
</code>
 
=== checkablesortfilterproxymodel.cpp ===
 
<code>
#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);
 
}


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


===Categories:===
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);


* [[:Category:snippets|snippets]]
}
</code>

Latest revision as of 12:28, 17 April 2015

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.

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);

}