title: QFileSystemModel() / QTreeView(): traverse model filesystem tree prior to view expansion
body: <p>I wish to create a widget for an app created with PyQt5.  I want the user to be able to select any subset of the files within a filesystem hierarchy below a specified directory.  I have extended the QFileSystemModel to allow checking the elements in the model roughly following this </p>
  
  <p><a href="https://stackoverflow.com/questions/40446187/pyqt-qfilesystemmodel-checkbox-filter">example</a>.</p>
  
  <p>I wish the user to be able to modify the checked state of the contents of a directory when the directory is checked - even before the subdirectory has been expanded.  </p>
  
  <p>So that this:</p>
  
  <p><img src="https://i.stack.imgur.com/mmjTm.png" alt="image 1"></p>
  
  <p>...does this 'under the hood' of the collapsed node in the tree view:</p>
  
  <p><img src="https://i.stack.imgur.com/dFeE4.png" alt="image 2"></p>
  
  <p>The problem I am facing is that the QTreeView - and seemingly the QFileSystemModel - are each, or together optimizing performance by only reporting model items which have been viewed already.  Until I manually expand the subdirectories in the View, I cannot traverse the data in the Model.</p>
  
  <p>To illustrate, I have added a print callback, and passed it to my (recursive) tree-traversal routine - to print how many children any index has. (See attached code.)  Before I expand a subdir in the Tree View by double-clicking on it, it reports no children:  <strong>Image 1</strong> reports the following when I click on 'one':</p>
  
  <pre><code>tree clicked: /Users/caleb/dev/ML/cloudburst-ml/data/test_dir/one
  traverseDirectory():
  model printIndex(): /Users/caleb/dev/ML/cloudburst-ml/data/test_dir/one
  |children|: 0
  </code></pre>
  
  <p>...but if I expand the view - as in <strong>Image 2</strong>, Then I see all the children, like this:</p>
  
  <pre><code>tree clicked: /Users/caleb/dev/ML/cloudburst-ml/data/test_dir/one
  traverseDirectory():
  model printIndex(): /Users/caleb/dev/ML/cloudburst-ml/data/test_dir/one
  |children|: 7
  child[0]: recursing
  traverseDirectory():
  model printIndex(): /Users/caleb/dev/ML/cloudburst-ml/data/test_dir/one/one_f
  |children|: 0
  child[1]: recursing
  traverseDirectory():
  model printIndex(): /Users/caleb/dev/ML/cloudburst-ml/data/test_dir/one/one_e
  |children|: 0
  child[2]: recursing
  traverseDirectory():
  model printIndex(): /Users/caleb/dev/ML/cloudburst-ml/data/test_dir/one/one_d
  |children|: 0
  child[3]: recursing
  traverseDirectory():
  model printIndex(): /Users/caleb/dev/ML/cloudburst-ml/data/test_dir/one/one_c
  |children|: 0
  child[4]: recursing
  traverseDirectory():
  model printIndex(): /Users/caleb/dev/ML/cloudburst-ml/data/test_dir/one/one_b
  |children|: 0
  child[5]: recursing
  traverseDirectory():
  model printIndex(): /Users/caleb/dev/ML/cloudburst-ml/data/test_dir/one/one_a
  |children|: 6
  child[0]: recursing
  traverseDirectory():
  model printIndex(): /Users/caleb/dev/ML/cloudburst-ml/data/test_dir/one/one_a/tfd
  |children|: 0
  child[1]: recursing
  traverseDirectory():
  model printIndex(): /Users/caleb/dev/ML/cloudburst-ml/data/test_dir/one/one_a/sgl
  |children|: 0
  child[2]: recursing
  traverseDirectory():
  model printIndex(): /Users/caleb/dev/ML/cloudburst-ml/data/test_dir/one/one_a/kjh
  |children|: 0
  child[3]: recursing
  traverseDirectory():
  model printIndex(): /Users/caleb/dev/ML/cloudburst-ml/data/test_dir/one/one_a/jyk
  |children|: 0
  child[4]: recursing
  traverseDirectory():
  model printIndex(): /Users/caleb/dev/ML/cloudburst-ml/data/test_dir/one/one_a/dgj
  |children|: 0
  child[5]: recursing
  traverseDirectory():
  model printIndex(): /Users/caleb/dev/ML/cloudburst-ml/data/test_dir/one/one_a/..
  |children|: 0
  child[6]: recursing
  traverseDirectory():
  model printIndex(): /Users/caleb/dev/ML/cloudburst-ml/data/test_dir/one/..
  |children|: 0
  </code></pre>
  
  <p>How may I induce the loading of the subdirectories, or the expansion of the model's reflection of the actual filesystem?  How do I traverse the root path of the QFileSystemModel before the user clicks on the view widget?</p>
  
  <p>Here is my code:</p>
  
  <pre><code>import sys
  from PyQt5 import QtWidgets, QtCore, QtGui
  
  
  class FileTreeSelectorModel(QtWidgets.QFileSystemModel):
      def __init__(self, parent=None, rootpath='/'):
          QtWidgets.QFileSystemModel.__init__(self, None)
          self.root_path      = rootpath
          self.checks         = {}
          self.nodestack      = []
          self.parent_index   = self.setRootPath(self.root_path)
          self.root_index     = self.index(self.root_path)
  
          self.setFilter(QtCore.QDir.AllEntries | QtCore.QDir.Hidden | QtCore.QDir.NoDot)
          self.directoryLoaded.connect(self._loaded)
  
      def _loaded(self, path):
          print('_loaded', self.root_path, self.rowCount(self.parent_index))
  
      def data(self, index, role=QtCore.Qt.DisplayRole):
          if role != QtCore.Qt.CheckStateRole:
              return QtWidgets.QFileSystemModel.data(self, index, role)
          else:
              if index.column() == 0:
                  return self.checkState(index)
  
      def flags(self, index):
          return QtWidgets.QFileSystemModel.flags(self, index) | QtCore.Qt.ItemIsUserCheckable
  
      def checkState(self, index):
          if index in self.checks:
              return self.checks[index]
          else:
              return QtCore.Qt.Checked
  
      def setData(self, index, value, role):
          if (role == QtCore.Qt.CheckStateRole and index.column() == 0):
              self.checks[index] = value
              print('setData(): {}'.format(value))
              return True
          return QtWidgets.QFileSystemModel.setData(self, index, value, role)
  
      def traverseDirectory(self, parentindex, callback=None):
          print('traverseDirectory():')
          callback(parentindex)
          if self.hasChildren(parentindex):
              print('|children|: {}'.format(self.rowCount(parentindex)))
              for childRow in range(self.rowCount(parentindex)):
                  childIndex = parentindex.child(childRow, 0)
                  print('child[{}]: recursing'.format(childRow))
                  self.traverseDirectory(childIndex, callback=callback)
          else:
              print('no children')
  
      def printIndex(self, index):
          print('model printIndex(): {}'.format(self.filePath(index)))
  
  
  class FileTreeSelectorDialog(QtWidgets.QWidget):
      def __init__(self):
          super().__init__()
  
          self.root_path      = '/Users/caleb/dev/ML/cloudburst-ml/data/test_dir/'
  
          # Widget
          self.title          = "Application Window"
          self.left           = 10
          self.top            = 10
          self.width          = 1080
          self.height         = 640
  
          self.setWindowTitle(self.title)         #TODO:  Whilch title?
          self.setGeometry(self.left, self.top, self.width, self.height)
  
          # Model
          self.model          = FileTreeSelectorModel(rootpath=self.root_path)
          # self.model          = QtWidgets.QFileSystemModel()
  
          # View
          self.view           = QtWidgets.QTreeView()
  
          self.view.setObjectName('treeView_fileTreeSelector')
          self.view.setWindowTitle("Dir View")    #TODO:  Which title?
          self.view.setAnimated(False)
          self.view.setIndentation(20)
          self.view.setSortingEnabled(True)
          self.view.setColumnWidth(0,150)
          self.view.resize(1080, 640)
  
          # Attach Model to View
          self.view.setModel(self.model)
          self.view.setRootIndex(self.model.parent_index)
  
          # Misc
          self.node_stack     = []
  
          # GUI
          windowlayout = QtWidgets.QVBoxLayout()
          windowlayout.addWidget(self.view)
          self.setLayout(windowlayout)
  
          QtCore.QMetaObject.connectSlotsByName(self)
  
          self.show()
  
      @QtCore.pyqtSlot(QtCore.QModelIndex)
      def on_treeView_fileTreeSelector_clicked(self, index):
          print('tree clicked: {}'.format(self.model.filePath(index)))
          self.model.traverseDirectory(index, callback=self.model.printIndex)
  
  
  if __name__ == '__main__':
      app = QtWidgets.QApplication(sys.argv)
      ex = FileTreeSelectorDialog()
      sys.exit(app.exec_())
  </code></pre>
  
  <p>I have looked at several links here</p>
  
  <p><a href="https://stackoverflow.com/questions/43816264/pyqt-qfilesystemmodel-rowcount">[1]</a> - This did not change the behaviour</p>
  
  <p><a href="https://stackoverflow.com/questions/48048644/qfilesystemmodel-and-qtreeview">[2]</a> - This posed an alternative solution which doesn't work for my purposes</p>
  
  <p><a href="https://stackoverflow.com/questions/20444701/qtreewidget-and-qfilesystemmodel">[3]</a> - This dealt with the same classes, but not the same issue</p>