QTreeview Custom model and QSortFilterProxyModel



  • 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???



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



  • 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



  • Any one has any ideas on the above?



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


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.