QSortFilterProxyModel not mapping properly



  • I'm having an issue with calls to a QSortFilterProxyModel's mapFromSource function always returning an invalid QModelIndex, regardless of the index provided. In my test case, the model has exactly 1 valid entry, but regardless of what QModelIndex I provide, it always returns invalid. Below is some of the test code I've been using.

                auto src = _sorted_view->sourceModel();
                for (int i = 0; i < src->rowCount(QModelIndex()); ++i) {
                    for (int j = 0; j < src->columnCount(QModelIndex()); ++j) {
                        QModelIndex s = src->index(i, j);
                        QModelIndex m = _meta_model->index(i, j);
                        QModelIndex v = _sorted_view->mapFromSource(s);
                        QModelIndex t = _sorted_view->mapFromSource(m);
    
                        std::string st = src->data(s).toString().toStdString();
                        std::string mt = _meta_model->data(m).toString().toStdString();
                        if (v.isValid()) { //Always invalid
                            std::string vt = _sorted_view->data(v).toString().toStdString();
                        }    
                        if (t.isValid()) { //Always invalid
                            std::string tt = _sorted_view->data(t).toString().toStdString();
                        }    
                    }    
                }
    

    In this case, _sorted_view is the QSortFilterProxyModel and _meta_model is a subclass of QAbstractItemModel. Would anyone with a better understanding of QT's model-view setup be able to tell me why the mapping here is not working? As a note, calls to mapToSource generate perfectly valid QModelIndexes, but trying to go the other way does not.


  • Lifetime Qt Champion

    Hi and welcome to devnet,

    Why are you using indexes from two different models and map them with _sorted_view ?



  • In this case src and _meta_model point to the same object. It's just some leftover from when I was trying to track down the issue and wanted to make sure that the view was using the model I thought it was.


  • Lifetime Qt Champion

    Are you sure of that ? Because if they point to the same object, then the index returned should be the same. If not, then your custom model does something wrong.



  • Yes, the indexes returned from src and _meta_model are the same. The issue is that none of the indexes returned by _sorted_view->mapFromSource are valid even though I know there is 1 valid entry and I'm iterating over every entry.


  • Lifetime Qt Champion

    Can you show how the source model is implemented ?



  • Yes, here's the top level class. There's a handful of subclasses but I don't believe they do interactions with the Model/View aspects.

    class CxFVariableItemModel : public QAbstractItemModel {
    
    public:
    
        CxFVariableItemModel () : QAbstractItemModel ()
        {   
        }   
        virtual ~CxFVariableItemModel () {}
    
        const QList <QString> &headers () const { return _headers; }
    
        virtual const QList <QString> &possibleHeaders () const = 0;
    
        void setHeaders (const QList <QString> &headers) { 
            emit layoutAboutToBeChanged (); 
            _headers = headers; 
            emit layoutChanged (); 
        }
    
        virtual const bool useLabels (int whichSensor) = 0;
    
        virtual const QList <LabelReturnType> &getUsefulStrings (bool returnLabels, int whichSensor) = 0;
    
        virtual const char *getVariableName (int whichSensor) = 0;
    
        virtual const int getWhichRow (const char *name) = 0;
    
        virtual const int depVarSize (int whichSensor, int i) = 0;
    
        virtual const char *getRealDependName (const int whichSensor, const int whichDependSensor) = 0;
    
    /// Will return a list of all possible timing variable names
        virtual const QList <QString> getListOfTimingVariableNames () = 0;
    
    /// Will return a list of all possible variable names
        virtual const QList <QString> getListOfVariableNames () = 0;
    
        QModelIndex index (int row, int column, const QModelIndex &parent = QModelIndex ()) const
        {   
            if (!hasIndex (row, column, parent)) {
                return QModelIndex ();
            }   
            if (parent == QModelIndex ()) {
                return createIndex(row, column);
            }   
            if (_headers [column] == "Other") {
                return createIndex (row, column, reinterpret_cast <void *> (parent.row () + 1));
            }   
    
            return QModelIndex ();
        }   
    
        QModelIndex parent (const QModelIndex &index) const
        {   
    // We used to have index.parent ().row () but that causes an issue when we only had one variable in the GUI.
            long parentRow = index.row ();
            if (parentRow == 0) return QModelIndex ();
            else {
                return createIndex (parentRow - 1, 0);
            }
        }
    
        virtual int rowCount (const QModelIndex &parent) const = 0;
        int columnCount (const QModelIndex &) const { return _headers.size (); }
    
        virtual QVariant data (const QModelIndex &index, int role = Qt::DisplayRole) const = 0;
    
        QVariant headerData (int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const
        {
            if (role == Qt::DisplayRole) {
                if (orientation == Qt::Horizontal) {
                    return QVariant (_headers [section]);
                } else { // vertical
                    return (QVariant (section));
                }
            }
            return (QVariant ());
        }
    
    protected :
    
        QList <QString> _headers;
    };
    

    Some of this code is quite old so it may not necessarily be correct according to current Qt Model/View standards which is where I think the problem lies.


  • Lifetime Qt Champion

    You can check you model implementation with the QAbstractItemModelTester. See this wiki entry.