QSortFilterProxyModel: inconsistent changes reported by source model
-
Good day!
There is a table model of the heir QAbstractTableModel. It displays on a QTableView via QSortFilterProxyModel.
All works fine and is even deleted, but the process in creators (in debug mode) is displayed - QSortFilterProxyModel: inconsistent changes reported by source model.
And removal about 1000 lines ccontinue for about 1 minute - it is long, i think , I suppose maybe because of this error.Prompt where to look?
-
I think the message is a simple problem.
Excerpt from the code:
catalogTableModel.h
@
class CatalogTableModel : public QAbstractTableModel
{
Q_OBJECT
public:
explicit CatalogTableModel(TlsPrices *lsItem, QObject *parent);
~CatalogTableModel ();int rowCount (const QModelIndex &parent = QModelIndex ()) const; int columnCount (const QModelIndex &parent = QModelIndex ()) const; QVariant headerData (int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const; Qt::ItemFlags flags (const QModelIndex &index) const; QVariant data (const QModelIndex &index, int role = Qt::DisplayRole) const; bool hasChildren (const QModelIndex &parent = QModelIndex ()) const; bool setData (const QModelIndex &index, const QVariant &value, int role = Qt::EditRole); bool removeRows (int row, int count, const QModelIndex &parent = QModelIndex ()); bool removeRowsWithCondition(int column, QString value); bool insertRows (int row, int count, const QModelIndex &parent = QModelIndex ()); TlsPrices* getPointerToData () { return listItem;} void setHeaderList (QList<QString> ls) { keys = ls;}
private:
TlsPrices *listItem;
QList <QString> lsNameAttr;
QList <QString> keys; //list with names of columns
};
@ -
catalogTableModel.cpp
@
#include <QSize>
#include <QFont>
#include <QFontMetrics>
#include "catalogtablemodel.h"CatalogTableModel::CatalogTableModel(TlsPrices *lsItem, QObject *parent) :
QAbstractTableModel(parent)
{
listItem = lsItem;
}CatalogTableModel::~CatalogTableModel()
{}
int CatalogTableModel::rowCount(const QModelIndex &parent) const
{
if (parent.isValid())
return 0;
return listItem->count() ;
}int CatalogTableModel::columnCount(const QModelIndex &parent) const
{
return keys.count();//7;//lsNameAttr.count() ;
}QVariant CatalogTableModel::headerData(int section, Qt::Orientation orientation, int role) const
{
if (orientation == Qt::Horizontal && role == Qt::DisplayRole)
{
return keys.at(section);
}
return QAbstractItemModel::headerData(section, orientation, role);
}Qt::ItemFlags CatalogTableModel::flags(const QModelIndex &index) const
{
bool isSpec = false;
if (keys.count() < 6)
isSpec = true;
if (index.column() == 6 || (index.column() == 2 && isSpec))
return QAbstractItemModel::flags(index) | Qt::ItemIsEditable;return QAbstractItemModel::flags(index);
}
QVariant CatalogTableModel::data(const QModelIndex &index, int role) const
{
if (!index.isValid() || !listItem->count())
return QVariant ();
if (role == Qt::FontRole)
{
return QFont ("Helvetica");
}
if (role == Qt::SizeHintRole)
{
//deside best size
QFont f ("Helvetica");
QFontMetrics fm (f);
if (index.column() == 0 || index.column() == 1
|| index.column() == 3)
{
int w = fm.width (listItem->at(index.row())->getData(index.column()).toString());
int h = fm.height() - 2;
if ( (w/200) > 1)
{
double ost = w/double (200);
h = h*ost; //(w/200);
w = 200;
}
return QSize (w, h);
}
return QSize (50, 25);
//QFont
//listItem->at(index.row())->getData(index.column()).toString().;
}
// QList <QString> keys = listItem->keys();
if (role == Qt::DisplayRole || role == Qt::EditRole)
{
bool isSpec = false;
if (keys.count() < 6)
{
isSpec = true;
if (index.column() == 4)
{
double summa = listItem->at(index.row())->getData(2, isSpec).toDouble()*listItem->at(index.row())->getData(3, isSpec).toDouble();
return summa;
}
}
return listItem->at(index.row())->getData(index.column(), isSpec);} else if ( role == Qt::UserRole) { } return QVariant ();
}
bool CatalogTableModel::setData(const QModelIndex &index, const QVariant &value, int role)
{
if (index.column() == 6)
{
listItem->at(index.row())->order = value.toInt();return true; }
// bool isSpec = false;
if (keys.count() < 6)
{
//isSpec = true;
if (index.column() == 2)
{
listItem->at(index.row())->price = value.toDouble();
reset ();//for updating views
return true;
}} return false;
}
bool CatalogTableModel::insertRows (int row, int count, const QModelIndex &parent)
{
return true;
}bool CatalogTableModel::removeRows (int row, int count, const QModelIndex &parent)
{
//TODO:
Q_UNUSED (parent);
beginRemoveRows(QModelIndex(), row, row + count - 1);
//int column = row + count;
for (int i = 0; i < count; ++i)
{
delete listItem->at(row);
listItem->removeAt(row);
}
emit layoutChanged();
endRemoveRows();
return true;
}bool CatalogTableModel::hasChildren(const QModelIndex &parent) const
{
return !parent.isValid();
}bool CatalogTableModel::removeRowsWithCondition(int column, QString value)
{
//int i = 0;
int sizeOfList = listItem->count()-1;
//while (i < sizeOfList)
for (int i = sizeOfList; i >= 0; --i)
{
if (listItem->at(i)->getData(column).toString() == value)
{
removeRows(i, 1);
}
}
}@
section of mainwindows.cpp
@
void MainWindow::setHierarhy()
{
if (ui->checkBox->isChecked())
{
tableProxyModel->setSourceModel(model.getTableModel());//вот с этой моделью работаю
ui->treeView->setVisible(false);
}
else
{
tableProxyModel->setSourceModel(&model);
ui->treeView->setVisible(true);
}
}void MainWindow::delRowPrice()
{
//model.getTableModel()->removeRows( tableProxyModel->mapToSource(ui->tableView->currentIndex()).row(), 1);
int row = ui->tableView->currentIndex().row();
if (ui->tableView->currentIndex().isValid())
tableProxyModel->removeRows(ui->tableView->currentIndex().row(), 1);
//tableProxyModel->removeRow(ui->tableView->currentIndex().row());
ui->tableView->setCurrentIndex(tableProxyModel->index(row, 0));
}@
-
I find this:
@int proxy_count = proxy_to_source.size();
if (proxy_count > source_to_proxy.size()) {
// mapping is in an inconsistent state -- redo the whole mapping
qWarning("QSortFilterProxyModel: inconsistent changes reported by source model");
remove_from_mapping(source_parent);
Q_Q(QSortFilterProxyModel);
q->reset();
return;
}@
but i don't know how right set size of proxy model.
unless of course this is the case. -
While using the following decision:
@
void MainWindow::cancelLoadPrice ()
{
tableProxyModel->setSourceModel( NULL ); //reset proxy model
for (int i = 0; i < lsProperty.count(); ++i)
{
if (lsProperty.at(i)->isMarked)
{model.delPricePosition(3, lsProperty.at(i)->contra); lsProperty.at(i)->isLoad = false; } } tableProxyModel->setSourceModel(model.getTableModel()); //again use proxy ui->tableView->resizeColumnsToContents(); ui->tableView->resizeRowsToContents();
@
Removing move very fast. But I think it is not right resolving
} -
In source model:
@
bool CatalogTableModel::removeRows (int row, int count, const QModelIndex &parent)
{
//TODO:
Q_UNUSED (parent);
beginRemoveRows(QModelIndex(), row, row + count - 1);
//int column = row + count;
for (int i = 0; i < count; ++i)
{
delete listItem->at(row);
listItem->removeAt(row);
}
emit layoutChanged();
endRemoveRows();
return true;
}
@
I don't sure correctly it is or not.. -
I don't think that you need to emit the layoutChanged() signal. The {begin|end}RemoveRows() functions do everything that is needed for you. Try removing that emit end see if it works then.
I suspect what is happening is that the proxy and views are receiving signals from you and from {begin|end}RemoveRows() in an unexpected order which causes them to misbehave.
-
Setting a proxy is a one-liner so I doubt it is that. I suspect you have a problem in your model. I suggest that you run your model with the qmodeltest helper which diagnoses common model implementation problems. This "wiki article":http://developer.qt.nokia.com/wiki/Model_Test describes how to use qmodeltest and the source can be downloaded from "gitorious":https://qt.gitorious.org/qt/qt/trees/4.7/tests/auto/modeltest.
-
I get error:
@
void QSortFilterProxyModelPrivate::source_items_removed(
const QModelIndex &source_parent, int start, int end, Qt::Orientation orient)
{
if ((start < 0) || (end < 0))
return;
IndexMap::const_iterator it = source_index_mapping.constFind(source_parent);
if (it == source_index_mapping.constEnd()) {
// Don't care, since we don't have mapping for this index
return;
}Mapping *m = it.value(); QVector<int> &source_to_proxy = (orient == Qt::Vertical) ? m->proxy_rows : m->proxy_columns; QVector<int> &proxy_to_source = (orient == Qt::Vertical) ? m->source_rows : m->source_columns; if (end >= source_to_proxy.size()) end = source_to_proxy.size() - 1; // Shrink the source-to-proxy mapping to reflect the new item count int delta_item_count = end - start + 1; source_to_proxy.remove(start, delta_item_count); //This crash
@
-
As ZapB said
[quote author="ZapB" date="1310123242"]Setting a proxy is a one-liner[/quote]unless you must overwrite a standard function of QSortFilterProxyModel.Normally removing rows will be done in the sourcemodel. As you do a selection in the view you have to map the indexes getting from the view to the source with
@// single selection
QModelIndex SourceIndex = tableProxyModel->mapToSource(viewIndex);// multiple selection
QModelIndexList SourceIndexList;
for (int i=0; i<viewIndexList.length(); i++)
{
SourceIndexList.append(tableProxyModel->mapToSource(viewIndexList[i]));
}
@Also, if you have multiple selection you must sort the indexlist before removing like this:
@void CatalogTableModel::removeSelectedRows(const QModelIndexList &indexlist)
{
QList<int> rows;
foreach(const QModelIndex & index, indexlist)
{
rows.append(index.row());
}qSort(rows); int prev = -1; for(int i=rows.count()-1; i>=0; i-=1 ) { int current = rows[i]; if(current != prev) { QModelIndex _index = createIndex(current, 0); removeLabel(_index); prev = current; } }
}
@Cheers,
ThomasEdit: Uuups, little bit late ...