Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. QTreeview Custom model and QSortFilterProxyModel
Forum Updated to NodeBB v4.3 + New Features

QTreeview Custom model and QSortFilterProxyModel

Scheduled Pinned Locked Moved General and Desktop
5 Posts 2 Posters 3.3k Views 1 Watching
  • 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.
  • P Offline
    P Offline
    prady_80
    wrote on last edited by
    #1

    I have a custom Hierarchical model Implemented which is basically displayed in a QtreeView. My requirement is to filter data on multiple columns. The code of the model is as follows:
    model:

    @namespace {
    const int ColumnCount = 7;
    enum Column {Application=0, StartTime, AccountedTime,Activity,Purpose,OffLine,MachineName};
    }

    QVariant CSapActvtyTreeModel::data(const QModelIndex &index, int role) const
    {
    qDebug()<<"CSapActvtyTreeModel::data ... start"<<endl;
    if (!m_pObjRootItem || !index.isValid() || index.column() < 0 ||
    index.column() >= ColumnCount) {
    return QVariant();
    }

    //This is the data display role
    if (COnlineSapActvtyItem *item = itemForIndex(index)) {
        if (role == Qt::DisplayRole) {
            switch (index.column()) {
            //Application, StartTime, AccountedTime,Activity,Purpose
            case Application: return item->GetTaskName();
            case StartTime: return item->GetStartTimeStr();
            case AccountedTime: return item->GetAccountedTimeStr();
            case Activity: return item->GetActivityType();
            case Purpose: return item->GetActivityPurpose();
            case OffLine: return (item->IsOnline() ? "1" : "0");
            case MachineName: return item->GetMachineName();
            default: return QVariant();
            }
        }
    }
    return QVariant();
    

    }

    int CSapActvtyTreeModel::rowCount(const QModelIndex &parent) const
    {
    qDebug() << "CSapActvtyTreeModel::rowCount" << endl;
    if (parent.isValid() && parent.column() != 0)
    return 0;
    COnlineSapActvtyItem *parentItem = itemForIndex(parent);
    int irowCount = (parentItem ? parentItem->childCount() : 0);
    qDebug()<<"Returning row count: "<<irowCount <<endl;
    return irowCount;
    }

    int CSapActvtyTreeModel::columnCount(const QModelIndex &parent) const
    {
    qDebug() << "CSapActvtyTreeModel::columnCount" << endl;
    int iColCount = (parent.isValid() && parent.column() != 0 ? 0 : ColumnCount);
    qDebug()<<"Returning Col count: "<<iColCount <<endl;
    return iColCount;
    }

    QModelIndex CSapActvtyTreeModel::index(int row, int column,
    const QModelIndex &parent) const
    {
    qDebug() << "CSapActvtyTreeModel::index" << endl;
    if (!m_pObjRootItem || row < 0 || column < 0 || column >= ColumnCount
    || (parent.isValid() && parent.column() != 0))
    return QModelIndex();
    COnlineSapActvtyItem *parentItem = itemForIndex(parent);
    if(parentItem) {
    if (COnlineSapActvtyItem *item = parentItem->childAt(row))
    return createIndex(row, column, item);
    }
    return QModelIndex();
    }

    COnlineSapActvtyItem* CSapActvtyTreeModel::itemForIndex(const QModelIndex &index) const
    {
    qDebug() << "CSapActvtyTreeModel::itemForIndex" << endl;
    if (index.isValid()) {
    if (COnlineSapActvtyItem item = static_cast<COnlineSapActvtyItem>(
    index.internalPointer())) {
    return item;
    }
    }
    return m_pObjRootItem;
    }

    QStringList CSapActvtyTreeModel::pathForIndex(const QModelIndex &index) const
    {
    qDebug() << "CSapActvtyTreeModel::pathForIndex" << endl;
    QStringList path;
    QModelIndex thisIndex = index;
    while (thisIndex.isValid()) {
    path.prepend(data(thisIndex).toString());
    thisIndex = thisIndex.parent();
    }
    return path;
    }

    QModelIndex CSapActvtyTreeModel::indexForPath(const QStringList &path) const
    {
    qDebug() << "CSapActvtyTreeModel::indexForPath" << endl;
    return indexForPath(QModelIndex(), path);
    }

    QModelIndex CSapActvtyTreeModel::indexForPath(const QModelIndex &parent,
    const QStringList &path) const
    {
    qDebug() << "CSapActvtyTreeModel::indexForPath2" << endl;
    if (path.isEmpty())
    return QModelIndex();
    for (int row = 0; row < rowCount(parent); ++row) {
    QModelIndex thisIndex = index(row, 0, parent);
    if (data(thisIndex).toString() == path.at(0)) {
    if (path.count() == 1)
    return thisIndex;
    thisIndex = indexForPath(thisIndex, path.mid(1));
    if (thisIndex.isValid())
    return thisIndex;
    }
    }
    return QModelIndex();
    }@

    These are the major overloaded functions implemented for my model. When I use this model, the treeView displays data correct. But When I changed the treeview to use a custom proxy model which just overrides filterAcceptRows the tree view does not display anything. Also, I added a debug trace in the filterAcceptRows. The filterAcceptRows is not getting called.

    The way I set up the treeView and models is:

    @m_pFilterProxyModel = new CSapFilterProxyModel(); //Derived from QSortFilterProxyModel
    treeView->setModel(m_pFilterProxyModel);

    m_pMainTreeModel = new CSapActvtyTreeModel(); //My Main model

    PopulateMainModel();
    m_pFilterProxyModel->setSourceModel(m_pMainTreeModel);
    @

    Sample Xml using which I build the tree
    @
    <TA NM="Qt Creator" OL="1" MN="PRADY-LP">

            <TA NM="SapienceTray" OL="1" MN="PRADY-LP">
    
                <TM ST="2013-03-29T04:47:02" TT="2100"/>
    
                <AC AT="Development" AP="Sapience Multi Client"/>
    
            </TA>
    

    </TA>
    <TA NM="Ms Visual Studio" OL="1" MN="PRADY-LP">

        <TA NM="Test" OL="1" MN="PRADY-LP">
    
            <TM ST="2013-03-29T02:47:02" TT="3000"/>
    
            <AC AT="Development" AP="Sapience Multi Client"/>
    
        </TA>
    
        <TA NM="Number Crunching" OL="1" MN="PRADY-LP">
    
            <TM ST="2013-03-29T01:47:02" TT="2000"/>
    
            <AC AT="Development" AP="Sapience Multi Client"/>
    
        </TA>
    

    </TA>
    @

    This is how the proxymodel is implemented.

    FilterAcceptsRow is not getting called. What could be the problem???

    1 Reply Last reply
    0
    • A Offline
      A Offline
      andre
      wrote on last edited by
      #2

      Are you positive that your overloaded filterAcceptsRow is really an overload? I mean: does the signature match the one from the base class exactly? Look for a missing const, for instance...

      1 Reply Last reply
      0
      • P Offline
        P Offline
        prady_80
        wrote on last edited by
        #3

        Andre, yes my function overload is correct.
        My trimmed down derivation of QSortFilterProxyModel is as follows:
        ////.h
        @
        #include <QDate>
        #include <QSortFilterProxyModel>

        class CSapFilterProxyModel : public QSortFilterProxyModel {
        Q_OBJECT

        public:
        CSapFilterProxyModel(QObject* parent = 0);
        virtual ~CSapFilterProxyModel();

        //All the filtering criteria go in here...
        

        protected:
        bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const;

        private:
        //Data members and helper functions here
        };
        @

        and the .cpp file is :
        @
        bool CSapFilterProxyModel::filterAcceptsRow(int sourceRow,
        const QModelIndex &sourceParent) const {
        qDebug() << "filterAcceptsRow called" << endl;
        bool bIsAccepted = true;
        bIsAccepted = bIsAccepted && MatchMe(1,sourceRow,sourceParent);
        return bIsAccepted;

        }

        bool CSapFilterProxyModel::MatchMe(int iCol,int sourceRow,
        const QModelIndex &sourceParent) const {
        //return true or false based on matching criteria
        }
        @

        Also the way I load the XML into my data structure (for reference just in case),
        where pObjTask contains the root item pointer.
        @
        void CSapActvtyTreeModel::readTasks(QXmlStreamReader *reader, COnlineSapActvtyItem *pObjTask)
        {
        qDebug() << "CSapActvtyTreeModel::readTasks" << endl;
        while ((reader && !reader->atEnd())) {
        reader->readNext();
        if (reader->isStartElement()) {
        if (reader->name() == TaskTag) { //TA
        QString strName = reader->attributes()
        .value(NameAttribute).toString();

                    bool bIsOnLine = reader->attributes()
                            .value(OnLineAttribute)
                            == "1";
        
                    QString strMachineName = reader->attributes()
                            .value(MachinNameAttribute).toString();
                    pObjTask = new COnlineSapActvtyItem(NULL,pObjTask);
                    pObjTask->SetTaskName(strName);
                    pObjTask->SetOnlineFlag(bIsOnLine);
                    pObjTask->SetMachineName(strMachineName);
        
                } else if(reader->name() == TimeTag) { //TM
                    Q_ASSERT(pObjTask);
        
                    QDateTime objStartTime = QDateTime::fromString(
                                reader->attributes().value(StartTimeAttribute)
                                .toString(), Qt::ISODate);
                    int iTotalTime =
                            reader->attributes().value(TotalTimeAttribute)
                            .toString().toInt();
                    pObjTask->SetStartTime(objStartTime);
                    pObjTask->SetAccountedTime(iTotalTime);
                }
                else if (reader->name() == ActvtyTag) { //AC
                    Q_ASSERT(pObjTask);
                    QString strActvtyType =
                            reader->attributes().value(ActvtyTypeAttribute)
                            .toString();
                    QString strActvtyPurpose =
                            reader->attributes().value(ActvtyPurposeAttribute)
                            .toString();
                    pObjTask->SetActvtyType(strActvtyType);
                    pObjTask->SetActvtyPurpose(strActvtyPurpose);
                }
            }
            else if (reader->isEndElement()) {
                if (reader->name() == TaskTag) { //TA end
                    Q_ASSERT(pObjTask);
                    pObjTask = pObjTask->parent();
                    Q_ASSERT(pObjTask);
                }
            }
        }
        

        }
        @

        Please let me know. Thanks

        1 Reply Last reply
        0
        • P Offline
          P Offline
          prady_80
          wrote on last edited by
          #4

          Any one has any ideas on the above?

          1 Reply Last reply
          0
          • P Offline
            P Offline
            prady_80
            wrote on last edited by
            #5

            I have been able to solve this using the QDomModel example from Qt examples which works very well with QSortFilterProxyModel.

            1 Reply Last reply
            0

            • Login

            • Login or register to search.
            • First post
              Last post
            0
            • Categories
            • Recent
            • Tags
            • Popular
            • Users
            • Groups
            • Search
            • Get Qt Extensions
            • Unsolved