Qt Forum

    • Login
    • Search
    • Categories
    • Recent
    • Tags
    • Popular
    • Users
    • Groups
    • Search
    • Unsolved

    QSortFilterProxyModel: inconsistent changes reported by source model

    General and Desktop
    3
    17
    11619
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • K
      kunashir last edited by

      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?

      1 Reply Last reply Reply Quote 0
      • Z
        ZapB last edited by

        You'll need to post some code in order for people to be able to help you with this. Can you make a small compilable example that reproduces the problem please?

        Nokia Certified Qt Specialist
        Interested in hearing about Qt related work

        1 Reply Last reply Reply Quote 0
        • K
          kunashir last edited by

          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
          };
          @

          1 Reply Last reply Reply Quote 0
          • K
            kunashir last edited by

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

            @

            1 Reply Last reply Reply Quote 0
            • K
              kunashir last edited by

              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.

              1 Reply Last reply Reply Quote 0
              • K
                kunashir last edited by

                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
                }

                1 Reply Last reply Reply Quote 0
                • Z
                  ZapB last edited by

                  Are you correctly calling beginRemoveRows() and endRemoveRows() in your model implementation? These are needed to notify any connected proxies and views that the source model is changing.

                  Nokia Certified Qt Specialist
                  Interested in hearing about Qt related work

                  1 Reply Last reply Reply Quote 0
                  • K
                    kunashir last edited by

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

                    1 Reply Last reply Reply Quote 0
                    • Z
                      ZapB last edited by

                      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.

                      Nokia Certified Qt Specialist
                      Interested in hearing about Qt related work

                      1 Reply Last reply Reply Quote 0
                      • K
                        kunashir last edited by

                        With out emit the layoutChanged() programm to crash!
                        Maybe link between source model and proxy is not correct?

                        1 Reply Last reply Reply Quote 0
                        • Z
                          ZapB last edited by

                          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.

                          Nokia Certified Qt Specialist
                          Interested in hearing about Qt related work

                          1 Reply Last reply Reply Quote 0
                          • K
                            kunashir last edited by

                            Let's me stupid question - gitotious of model test have pro-file, but wiki article say about pri-file. How I can get pri file?

                            1 Reply Last reply Reply Quote 0
                            • Z
                              ZapB last edited by

                              Ah the instructions must be slightly out of date wrt the code. It used to be in it's own repository on Qt-labs. I think you can just copy the modeltest.{h,cpp} files to a little test project and instatiate them as shown in the above wiki article.

                              Nokia Certified Qt Specialist
                              Interested in hearing about Qt related work

                              1 Reply Last reply Reply Quote 0
                              • K
                                kunashir last edited by

                                I use modeltest and have next message:

                                ratbr QModelIndex(-1,-1,0x0,QObject(0x0) ) 73 73
                                rr QModelIndex(-1,-1,0x0,QObject(0x0) ) 73 73

                                and other simular.
                                Is it Ok? I check mapping index from proxy to source - it ok.
                                What else I may do?

                                1 Reply Last reply Reply Quote 0
                                • Z
                                  ZapB last edited by

                                  Debug your removeRows() function to make sure it is working properly. Step through it in a debugger to see where it crashes and why.

                                  Nokia Certified Qt Specialist
                                  Interested in hearing about Qt related work

                                  1 Reply Last reply Reply Quote 0
                                  • K
                                    kunashir last edited by

                                    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
                                    

                                    @

                                    1 Reply Last reply Reply Quote 0
                                    • G
                                      gonzomcgraw last edited by

                                      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,
                                      Thomas

                                      Edit: Uuups, little bit late ...

                                      1 Reply Last reply Reply Quote 0
                                      • First post
                                        Last post