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
No edit summary
Line 1: Line 1:
[[Category:Snippets]]<br />[toc align_right=&quot;yes&amp;quot; depth=&quot;3&amp;quot;]
[[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 &lt;code&amp;gt;QList&amp;lt;int&amp;gt;&lt;/code&amp;gt; container classes, one each to hold the column indexes of the fields you want checkboxes for, to be displayed as passwords, or be readonly.
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:<br /><code><br />CheckableSortFilterProxyModel *cfpm = new CheckableSortFilterProxyModel(this);<br />QList&amp;lt;int&amp;gt; boolCols;<br />boolCols.append( usrModel-&gt;fieldIndex(&quot;isActive&amp;quot;) );<br />boolCols.append( usrModel-&gt;fieldIndex(&quot;isOk&amp;quot;) );
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&amp;lt;int&amp;gt; readonlyCols;<br />readonlyCols.append( usrModel-&gt;fieldIndex(&quot;id&amp;quot;) );
QList<int> readonlyCols;
readonlyCols.append( usrModel->fieldIndex("id") );


QList&amp;lt;int&amp;gt; pwdCols;<br />pwdCols.append( usrModel-&gt;fieldIndex(&quot;passwordFld&amp;quot;));
QList<int> pwdCols;
pwdCols.append( usrModel->fieldIndex("passwordFld"));


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


cfpm-&gt;setSourceModel( mySqlTableModel );<br />myTableView-&gt;setModel(cfpm);
cfpm->setSourceModel( mySqlTableModel );
myTableView->setModel(cfpm);


QList&amp;lt;int&amp;gt; nullCols;<br />QList&amp;lt;int&amp;gt; notNullCols;<br />notNullCols.append( usrModel-&gt;fieldIndex(&quot;isActive&amp;quot;);<br />cfpm-&gt;setNotNullColumns(nullCols, notNullCols);
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><br />#ifndef CHECKABLESORTFILTERPROXYMODEL_H<br />#define CHECKABLESORTFILTERPROXYMODEL_H
<code>
#ifndef CHECKABLESORTFILTERPROXYMODEL_H
#define CHECKABLESORTFILTERPROXYMODEL_H


#include &lt;QSortFilterProxyModel&amp;gt;
#include <QSortFilterProxyModel>


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


void setParameters(QList&amp;lt;int&amp;gt; boolCols, QList&amp;lt;int&amp;gt; readonlyCols, QList&amp;lt;int&amp;gt; passwordCols);<br /> void setNullAndNotNullColumns(QList&amp;lt;int&amp;gt; nullCols, QList&amp;lt;int&amp;gt; notNullCols);
void setParameters(QList<int> boolCols, QList<int> readonlyCols, QList<int> passwordCols);
void setNullAndNotNullColumns(QList<int> nullCols, QList<int> notNullCols);


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


protected:<br /> bool filterAcceptsRow ( int source_row, const QModelIndex &amp; source_parent ) const;
protected:
bool filterAcceptsRow ( int source_row, const QModelIndex &amp; source_parent ) const;


signals:
signals:
Line 53: Line 75:
public slots:
public slots:


private:<br /> QList&amp;lt;int&amp;gt; booleanSet;<br /> QList&amp;lt;int&amp;gt; passwordSet;<br /> QList&amp;lt;int&amp;gt; readonlySet;<br /> QList&amp;lt;int&amp;gt; notNullSet;<br /> QList&amp;lt;int&amp;gt; nullSet;
private:
QList<int> booleanSet;
QList<int> passwordSet;
QList<int> readonlySet;
QList<int> notNullSet;
QList<int> nullSet;


};<br /></code>
};
</code>


=== checkablesortfilterproxymodel.cpp ===
=== checkablesortfilterproxymodel.cpp ===


<code><br />#include &quot;checkablesortfilterproxymodel.h&amp;quot;
<code>
#include "checkablesortfilterproxymodel.h"


CheckableSortFilterProxyModel::CheckableSortFilterProxyModel(QObject *parent) :<br /> QSortFilterProxyModel(parent)<br />{<br />}
CheckableSortFilterProxyModel::CheckableSortFilterProxyModel(QObject *parent) :
QSortFilterProxyModel(parent)
{
}


void CheckableSortFilterProxyModel::setParameters(QList&amp;lt;int&amp;gt; boolCols, QList&amp;lt;int&amp;gt; readonlyCols, QList&amp;lt;int&amp;gt; passwordCols) {<br /> booleanSet.clear();<br /> readonlySet.clear();<br /> passwordSet.clear();
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); } }<br /> if (!readonlyCols.isEmpty()) { foreach(int column , readonlyCols) { readonlySet.append(column); } }<br /> if (!passwordCols.isEmpty()) { foreach(int column , passwordCols) { passwordSet.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&amp;lt;int&amp;gt; nullCols, QList&amp;lt;int&amp;gt; notNullCols) {<br /> notNullSet.clear();<br /> nullSet.clear();
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 (!notNullCols.isEmpty()) {<br /> // this only works when our model is a QSqlQueryModel subclass<br /> if (sourceModel()<s>&gt;inherits(&quot;QSqlQueryModel&amp;quot;)) {<br /> foreach(int column , notNullCols) { notNullSet.append(column); }<br /> }<br /> invalidateFilter();<br /> }
if (!nullCols.isEmpty()) {
<br /> if (!nullCols.isEmpty()) {<br /> // this only works when our model is a QSqlQueryModel subclass<br /> if (sourceModel()</s>&gt;inherits(&quot;QSqlQueryModel&amp;quot;)) {<br /> foreach(int column , nullCols) { nullSet.append(column); }<br /> }<br /> invalidateFilter();<br /> }<br />}
// 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 &amp; source_parent ) const {<br /> Q_UNUSED(source_parent);<br /> if (!notNullSet.isEmpty()) {<br /> QSqlQueryModel '''m = static_cast&amp;lt;QSqlQueryModel'''&gt;(sourceModel());<br /> foreach (int column, notNullSet)<br /> if (m-&gt;record(source_row).isNull(column))<br /> return false;
bool CheckableSortFilterProxyModel::filterAcceptsRow ( int source_row, const QModelIndex &amp; 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 &amp; source_parent ) const {<br /> Q_UNUSED(source_parent);
bool CheckableSortFilterProxyModel::filterAcceptsRow ( int source_row, const QModelIndex &amp; source_parent ) const {
Q_UNUSED(source_parent);


if (!notNullSet.isEmpty()) {<br /> QSqlQueryModel '''m = static_cast&amp;lt;QSqlQueryModel'''&gt;(sourceModel());<br /> foreach (int column, notNullSet)<br /> if (m-&gt;record(source_row).isNull(column))<br /> return false;<br /> }
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()) {<br /> QSqlQueryModel '''m = static_cast&amp;lt;QSqlQueryModel'''&gt;(sourceModel());<br /> foreach (int column, nullSet)<br /> if (!m-&gt;record(source_row).isNull(column))<br /> return false;<br /> }<br /> return true;<br />}
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 &amp;index, int role) const {<br /> if (!index.isValid())<br /> return QVariant();
QVariant CheckableSortFilterProxyModel::data(const QModelIndex &amp;index, int role) const {
if (!index.isValid())
return QVariant();


if (booleanSet.contains(index.column()) &amp;&amp; (role  Qt::CheckStateRole || role  Qt::DisplayRole)) {<br /> if (role  Qt::CheckStateRole)
if (booleanSet.contains(index.column()) &amp;&amp; (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)<br /> return QVariant();<br /> } else if (passwordSet.contains(index.column()) &amp;&amp; (role == Qt::DisplayRole)) {<br /> return QVariant(&quot;''''''*&quot;);<br /> } else<br /> return QSortFilterProxyModel::data(index,role);
         else if (role  Qt::DisplayRole)
return QVariant();
} else if (passwordSet.contains(index.column()) &amp;&amp; (role == Qt::DisplayRole)) {
return QVariant("''''''*");
} else
return QSortFilterProxyModel::data(index,role);


return QVariant();<br />}
return QVariant();
}


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


if(booleanSet.contains(index.column()) &amp;&amp; roleQt::CheckStateRole)
if(booleanSet.contains(index.column()) &amp;&amp; roleQt::CheckStateRole)
     &amp;#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);
         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 &amp; index ) const {<br /> if(!index.isValid())<br /> return Qt::ItemIsEnabled;
Qt::ItemFlags CheckableSortFilterProxyModel::flags ( const QModelIndex &amp; index ) const {
if(!index.isValid())
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);
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);


}<br /></code>
}
</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 &amp;index, int role=Qt::DisplayRole) const;
 bool setData(const QModelIndex &amp;index, const QVariant &amp;value, int role=Qt::EditRole);
 Qt::ItemFlags flags ( const QModelIndex &amp; index ) const;

protected:
 bool filterAcceptsRow ( int source_row, const QModelIndex &amp; 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 &amp; 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 &amp; 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 &amp;index, int role) const {
 if (!index.isValid())
 return QVariant();

if (booleanSet.contains(index.column()) &amp;&amp; (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()) &amp;&amp; (role == Qt::DisplayRole)) {
 return QVariant("''''''*");
 } else
 return QSortFilterProxyModel::data(index,role);

return QVariant();
}

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

if(booleanSet.contains(index.column()) &amp;&amp; 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 &amp; 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);

}