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
QtWS25 Last Chance

QTreeview Custom model and QSortFilterProxyModel

Scheduled Pinned Locked Moved General and Desktop
5 Posts 2 Posters 3.2k Views
  • 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