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. QFileSystemModel - iterating through current index children
Forum Updated to NodeBB v4.3 + New Features

QFileSystemModel - iterating through current index children

Scheduled Pinned Locked Moved General and Desktop
68 Posts 7 Posters 48.5k 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
    phamtv
    wrote on last edited by
    #1

    I subclass QFileSystemModel to populate a root directory and display a checkbox in front of column 0 node. I want to interate through the current node´s children and set the check value based on its parent´s value but QModelIndex does not contain a children´s objectlist. Is there a way to do this?

    @
    bool JibeFileSystemModel::setData(const QModelIndex& index, const QVariant& value, int role)
    {
    if (index.isValid() && index.column() == 0 && role == Qt::CheckStateRole)
    {
    if (isDir(index))
    {
    if (value == Qt::Checked)
    checklist.insert(index);
    else
    checklist.remove(index);

            emit dataChanged(index, index);
            
            if (hasChildren(index))  // do recursive to check all child node
            {
                Q_FOREACH( QObject* obj, index.children) // does not exist!!!
                {
                    setData(, value, role);
                }
            }
        }
        else 
        {
            if (value == Qt::Checked)
                checklist.insert(index);
            else
                checklist.remove(index);
    
            emit dataChanged(index, index);
        }
        return true;
    }
    return QFileSystemModel::setData(index, value, role);
    

    }
    @

    1 Reply Last reply
    0
    • G Offline
      G Offline
      goetz
      wrote on last edited by
      #2

      Replace line 14 to 20 with this:

      @
      for(int childRow = 0; childRow < rowCount(index); ++childRow) {
      QModelIndex childIndex = index(r, 0); // or whatever column you need
      setData(childIndex, ....);
      emit dataChanged(childIndex, childIndex);
      }
      @

      You might want to put that into a separate method so that you can recurse into the child tree unlimitedly.

      http://www.catb.org/~esr/faqs/smart-questions.html

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

        Thanks Volker... however, this does not automatically check non-expanded child nodes? Any ideas?

        1 Reply Last reply
        0
        • G Offline
          G Offline
          goetz
          wrote on last edited by
          #4

          Expanded/collapsed is a property of the view, not the model. You can have the very same model on different views with the same index expanded in one and collapsed in another.

          You can call "canFetchMore() ":http://doc.qt.nokia.com/4.7/qabstractitemmodel.html#canFetchMore to check if there are possibly children on this index and if so call "fetchMore() ":http://doc.qt.nokia.com/4.7/qabstractitemmodel.html#fetchMore to actually load the data. Once this is done, rowCount() gives you the correct value.

          But watch out! This loads all files and dirs below your parent if you do it recursively, which can be a huge amount of data (or the entire file system if you're on the root directory)!

          http://www.catb.org/~esr/faqs/smart-questions.html

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

            hi volker... i tried the following but canFetchMore alway return false.

            @
            bool JibeFileSystemModel::setData(const QModelIndex& index, const QVariant& value, int role)
            {
            if (index.isValid() && index.column() == 0 && role == Qt::CheckStateRole)
            {
            if (value == Qt::Checked)
            checklist.insert(index);
            else
            checklist.remove(index);

                emit dataChanged(index, index);
            
                if (canFetchMore(index))
                    fetchMore(index);
            
                for(int childRow = 0; childRow < rowCount(index); ++childRow)
                {
                    QModelIndex childIndex = index.child(childRow, 0); // or whatever column you need
                    setData(childIndex, value, role);
                }
            
                return true;
            }
            return QFileSystemModel::setData(index, value, role);
            

            }
            @

            1 Reply Last reply
            0
            • P Offline
              P Offline
              phamtv
              wrote on last edited by
              #6

              nevermind Volker... I had to override the canFetchMore function to get it to work. However, can you explain my why I am getting inconsistent results from fetchMore. I placed some debug code to test my code as below. However, eventhough I click on the same node to execute my test, I get different results printed to the output screen.

              @
              bool JibeFileSystemModel::canFetchMore ( const QModelIndex& index ) const
              {
              return hasChildren(index);
              }

              bool JibeFileSystemModel::setData(const QModelIndex& index, const QVariant& value, int role)
              {
              if (index.isValid() && index.column() == 0 && role == Qt::CheckStateRole)
              {
              if (value == Qt::Checked)
              checklist.insert(index);
              else
              checklist.remove(index);

                  emit dataChanged(index, index);
              
                  qDebug() << fileName(index);    ///  test code!!!!!!!!!
                  
                  if (canFetchMore(index))
                      fetchMore(index);
              
                  for(int childRow = 0; childRow < rowCount(index); ++childRow)
                  {
                      QModelIndex childIndex = index.child(childRow, 0); // or whatever column you need
                      setData(childIndex, value, role);
                  }
              
                  return true;
              }
              return QFileSystemModel::setData(index, value, role);
              

              }
              @

              1 Reply Last reply
              0
              • G Offline
                G Offline
                goetz
                wrote on last edited by
                #7

                If you do not implement fetchMore() and its buddies, then you shall not implement canFetchMore() as it's not you who decides this things.

                hasChildren() returns true if the node represents a directory, which is true regardless wether the children have been loaded or not.

                You can safely call fetchMore(index), if there children are already loaded it does nothing, if not it loads them.

                http://www.catb.org/~esr/faqs/smart-questions.html

                1 Reply Last reply
                0
                • P Offline
                  P Offline
                  phamtv
                  wrote on last edited by
                  #8

                  based on your response, if I comment line 19 from above code, I should be able to simply use fetchMore(index) to get the correct rowCount(index) despite the index being expanded or not, right? However, I commented the code as below but still get inconsistent result for rowCount(index).

                  @
                  if (index.isValid() && index.column() == 0 && role == Qt::CheckStateRole)
                  {
                  if (value == Qt::Checked)
                  checklist.insert(index);
                  else
                  checklist.remove(index);

                      emit dataChanged(index, index);
                  
                      qDebug() << fileName(index);
                  
                      //if (canFetchMore(index))
                      fetchMore(index);
                  
                      for(int childRow = 0; childRow < rowCount(index); ++childRow)
                      {
                          QModelIndex childIndex = index.child(childRow, 0); // or whatever column you need
                          setData(childIndex, value, role);
                      }
                  
                      return true;
                  }
                  return QFileSystemModel::setData(index, value, role);
                  

                  @

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

                    The problem may be, that AFAIK, QFileSystemModel does its fetching of nodes in a background thread. That could mean that while fetchMore(index) triggers such a background scan, the model is not actually modified until that background thread is done doing its magic. The call to fetchMore(index) would simply return immediately, and rowCount(index) on line 15 would not be updated yet.

                    Note that the above is just conjecture. I did not try this myself, nor did I take a peek at the source code.

                    1 Reply Last reply
                    0
                    • G Offline
                      G Offline
                      giesbert
                      wrote on last edited by
                      #10

                      [quote author="Andre" date="1302679754"]The problem may be, that AFAIK, QFileSystemModel does its fetching of nodes in a background thread. That could mean that while fetchMore(index) triggers such a background scan, the model is not actually modified until that background thread is done doing its magic. The call to fetchMore(index) would simply return immediately, and rowCount(index) on line 15 would not be updated yet.

                      Note that the above is just conjecture. I did not try this myself, nor did I take a peek at the source code. [/quote]

                      I think it works exactly this way.
                      If you have a QFileSystemModel connected to a QTreeView and open folders on slow drives, the content comes in part by part.

                      Nokia Certified Qt Specialist.
                      Programming Is Like Sex: One mistake and you have to support it for the rest of your life. (Michael Sinz)

                      1 Reply Last reply
                      0
                      • P Offline
                        P Offline
                        phamtv
                        wrote on last edited by
                        #11

                        this seems to be what is happening because over time, there are more and more nodes being displayed. Is there an indication to when the fetch is complete? Better yet, what would be a better methodology for accomplishing my task? As you can see, I am trying to recursively check/uncheck all children nodes when the parent node is checked/unchecked. Also, there will be logic to uncheck any parent node if any of its child is unchecked. Thanks!

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

                          I would start to re-think your logic, I think. Think if you can come up with a method that does not require that every node is loaded.

                          You could, for instance, do something like this:
                          Each leaf node can have three states:

                          Checked

                          Unchecked

                          Determined by parent

                          A fourth state is added for each branch-node: Determined by children

                          The default, implicit state for each node with the exception of the root node would be that it is determined by its parent. Note that if a branch-node's state is determined by its children, it can get the "partially checked" ambivalent value.

                          If your user checks or unchecks a branch node that was determined by its parent before, you only need to do three things:

                          Set the state for this branch to the appropriate explicit new state checked or unchecked

                          Set the state of the siblings of this branch to reflect the (common) parents' state

                          Set the parents to the "determined by children" state

                          If your user checks or unchecks a branch node that was determined by its children before, you need to:

                          Set the new state on the branch node

                          Set iteratively set each (existing!) child node state to "Determined by parent" (or, dump that part of your data, keeping in mind that we agreed that "Determined by parent" is the default state anyway.

                          For determining the actual visualized state of a check box, you end up with something like this:

                          • If the state is "determined by parent", the state is the same as for the parent node
                          • If the state is one of the explicit states, then the state is clear
                          • If the state is "determined by children", then iterate over the (existing!) child nodes. If they are all the same, then the state is that state, otherwise the state is the ambivalent PartlyChecked state.

                          Of course, the above picture is not complete. It is just to illustrate a way you can add check boxes to a tree without having to have access to the full tree. Observe that in the case of your QFileSystemModel tree model, you will probably only need to keep track of the states of just a few nodes. The rest of them will be determined implicitly. Still, to the user, checking a single directory will appear to check perhaps thousands of files under it, without the code actually having to iterate into the complete directory structure under it.

                          1 Reply Last reply
                          0
                          • P Offline
                            P Offline
                            phamtv
                            wrote on last edited by
                            #13

                            bq. If the state is “determined by children”, then iterate over the (existing!) child nodes. If they are all the same, then the state is that state, otherwise the state is the ambivalent PartlyChecked state.

                            Thanks for your response. However, a concern I have is that I will still have to fetchMore (an indefinite procedure) to iterate over the (existing) child nodes.

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

                              No, you don't. That's the whole beauty of the idea. :-)

                              You only need to iterate over the children that you already have. Potential children that have not been loaded yet, will have the default Determined by parent state.

                              Edit:
                              Perhaps there could be a slight snag though, if you are in a large directory, perhaps it could occur that not all files in that directory are loaded yet when you start modifying check boxes in it. That might be a point of breakdown. That could be solved by introducing something like a "default state for child nodes" for all branch nodes. Set that, and have nodes that have just been added take over that state.

                              1 Reply Last reply
                              0
                              • P Offline
                                P Offline
                                phamtv
                                wrote on last edited by
                                #15

                                Can you provide code snippets to resolve this issue? I cannot get this to work... I´ve also been searching the web for sample but have not had any luck... Thanks!

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

                                  I could in principle, but I don't think I will have time to provide one within the next two days.

                                  1 Reply Last reply
                                  0
                                  • P Offline
                                    P Offline
                                    phamtv
                                    wrote on last edited by
                                    #17

                                    any help would greatly be appreciated!!! I´ve tried but cannot seem to get things to work properly. Thank you for your continual support!

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

                                      Please do remind me (by replying in this topic) if I don't respond before the end of the week. In the meantime, of course everyone else is welcome to pitch in as well ;-)

                                      1 Reply Last reply
                                      0
                                      • P Offline
                                        P Offline
                                        phamtv
                                        wrote on last edited by
                                        #19

                                        Just so that we are on the same page because the topic doesn´t describe my issue in details. I am using a QTreeView populated with a subclassed QFileSystemModel. I´ve been successful at integrating a checkbox in column 0 of each tree node (a row) and have also added another column to my treeview. I am running into the issue of propagating the state of the parent node to the children when it´s state change as well as propagating the state of the parent node to uncheck if any of its child is unchecked or to check if all of its child is checked. Eventually, my goal will be to iterate through all of the check nodes (files) in the treeview and process them.

                                        1 Reply Last reply
                                        0
                                        • P Offline
                                          P Offline
                                          phamtv
                                          wrote on last edited by
                                          #20

                                          Andre... this is a reminder to respond on request for code snippets for propagating QTreeView using subclassed QFileSystemModel with checkboxes. Thanks!

                                          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