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:
=QSortFilterProxyModel subclass for readonly, checkboxes and password columns=
[[Category:Snippets]]<br />[toc align_right=&quot;yes&amp;quot; depth=&quot;3&amp;quot;]


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


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


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


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


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


==Usage==
* '''EDIT:''' Since I discovered another problem with the handling of NULL values, I have added the possibility to this class to address it.


The subclass usage is as follows:<br />
== Usage ==


==Code==
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;) );
 
QList&amp;lt;int&amp;gt; readonlyCols;<br />readonlyCols.append( usrModel-&gt;fieldIndex(&quot;id&amp;quot;) );
 
QList&amp;lt;int&amp;gt; pwdCols;<br />pwdCols.append( usrModel-&gt;fieldIndex(&quot;passwordFld&amp;quot;));
 
cfpm-&gt;setParameters(boolCols, readonlyCols, pwdCols);
 
cfpm-&gt;setSourceModel( mySqlTableModel );<br />myTableView-&gt;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);
 
</code>
 
== Code ==


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


===checkablesortfilterproxymodel.h===
=== checkablesortfilterproxymodel.h ===
 
<code><br />#ifndef CHECKABLESORTFILTERPROXYMODEL_H<br />#define CHECKABLESORTFILTERPROXYMODEL_H
 
#include &lt;QSortFilterProxyModel&amp;gt;
 
class CheckableSortFilterProxyModel : public QSortFilterProxyModel<br />{<br /> Q_OBJECT<br />public:<br /> 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);
 
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;
 
protected:<br /> bool filterAcceptsRow ( int source_row, const QModelIndex &amp; source_parent ) const;
 
signals:
 
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;
 
};<br /></code>
 
=== checkablesortfilterproxymodel.cpp ===
 
<code><br />#include &quot;checkablesortfilterproxymodel.h&amp;quot;
 
CheckableSortFilterProxyModel::CheckableSortFilterProxyModel(QObject *parent) :<br /> QSortFilterProxyModel(parent)<br />{<br />}
 
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();
 
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&amp;lt;int&amp;gt; nullCols, QList&amp;lt;int&amp;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>&gt;inherits(&quot;QSqlQueryModel&amp;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>&gt;inherits(&quot;QSqlQueryModel&amp;quot;)) {<br /> foreach(int column , nullCols) { nullSet.append(column); }<br /> }<br /> invalidateFilter();<br /> }<br />}
 
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 {<br /> 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 (!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 />}
 
QVariant CheckableSortFilterProxyModel::data(const QModelIndex &amp;index, int role) const {<br /> if (!index.isValid())<br /> return QVariant();
 
if (booleanSet.contains(index.column()) &amp;&amp; (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()) &amp;&amp; (role == Qt::DisplayRole)) {<br /> return QVariant(&quot;''''''*&quot;);<br /> } else<br /> return QSortFilterProxyModel::data(index,role);
 
return QVariant();<br />}
 
bool CheckableSortFilterProxyModel::setData(const QModelIndex &amp;index, const QVariant &amp;value, int role) {<br /> if(!index.isValid())<br /> return false;
 
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);
 
}


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


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


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

Revision as of 09:54, 24 February 2015


[toc align_right="yes&quot; depth="3&quot;]

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

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

QList&amp;lt;int&amp;gt; readonlyCols;<br />readonlyCols.append( usrModel-&gt;fieldIndex(&quot;id&amp;quot;) );

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

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

cfpm-&gt;setSourceModel( mySqlTableModel );<br />myTableView-&gt;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);

Code

So here is the code:

checkablesortfilterproxymodel.h

<br />#ifndef CHECKABLESORTFILTERPROXYMODEL_H<br />#define CHECKABLESORTFILTERPROXYMODEL_H

#include &lt;QSortFilterProxyModel&amp;gt;

class CheckableSortFilterProxyModel : public QSortFilterProxyModel<br />{<br /> Q_OBJECT<br />public:<br /> 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);

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;

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

signals:

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;

};<br />

checkablesortfilterproxymodel.cpp

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

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

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

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&amp;lt;int&amp;gt; nullCols, QList&amp;lt;int&amp;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>&gt;inherits(&quot;QSqlQueryModel&amp;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>&gt;inherits(&quot;QSqlQueryModel&amp;quot;)) {<br /> foreach(int column , nullCols) { nullSet.append(column); }<br /> }<br /> invalidateFilter();<br /> }<br />}

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 {<br /> 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 (!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 />}

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

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

return QVariant();<br />}

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

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

}

Qt::ItemFlags CheckableSortFilterProxyModel::flags ( const QModelIndex &amp; 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 />