Qt Forum

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

    QTreeview Custom model and QSortFilterProxyModel

    General and Desktop
    2
    5
    3040
    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.
    • P
      prady_80 last edited by

      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 Reply Quote 0
      • A
        andre last edited by

        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 Reply Quote 0
        • P
          prady_80 last edited by

          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 Reply Quote 0
          • P
            prady_80 last edited by

            Any one has any ideas on the above?

            1 Reply Last reply Reply Quote 0
            • P
              prady_80 last edited by

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

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