Qt World Summit: Submit your Presentation

QModelIndex is invalid in QTreeView based on Qt SimpleTreeModel example (source code pasted)

  • I'm creating a file browser based on the Qt4.8 example SimpleTree
    And I rewrote my own setUpModelData as shown in the function FileTreeModel::setupModelData below (totally less than 60 lines)

    Basically, the argument root contains the user-specified root path, like "D:\qt_project\prj1", and setUpModelData will create a tree model from the real root directory D:\ to this user-specified path, with all sibling items added.

    The problem is, whenever I expanded any directory under D:, I got a segment fault.
    With all the addresses dumped, I could see that the childItem in the function TreeModel::parent is none of the dumped address, i.e., such childItem retrieved from index.internalPointer is invalid.

    How come internalPointer returns an invalid TreeItem pointer ?

    QModelIndex TreeModel::parent(const QModelIndex &index) const
        if (!index.isValid())
            return QModelIndex();
        TreeItem *childItem = static_cast<TreeItem*>(index.internalPointer());
        TreeItem *parentItem = childItem->parent();
        if (parentItem == rootItem)
            return QModelIndex();
        return createIndex(parentItem->row(), 0, parentItem);
    QModelIndex FileTreeModel::setupModelData(TreeItem *root) {
        QFileInfo fi_root = QFileInfo(root->data().toString());
        TreeItem *activeItem = root;    // always points to the current child
        QDir it_dir = fi_root.dir();    // check with the locating dir
        QList<TreeItem *> lstParents;     // to calculate the model index
        bool rootDirNotMet = true;
        do {
            TreeItem *startItem = new TreeItem(it_dir.dirName());      // create the father node
            QString addr; addr.setNum((long)(void *)activeItem, 16);
            qDebug() << (activeItem->data().toString() + " @@ " + addr);    // dump all address for each path
            this->listSubDir(it_dir, startItem, activeItem);
            activeItem = startItem;
            if (!rootDirNotMet) break;   // ensure the root dir is also processed when cdUp failed
            rootDirNotMet = it_dir.cdUp();
        }  while(1);
        qDebug() << it_dir.absolutePath();
        activeItem->setParent(rootItem);             // setParent sets parentItem in the TreeItem
        QModelIndex itemIndex = QModelIndex(); // index(0, 0, QModelIndex());        // calculate from root index
        do {
            itemIndex = this->index(lstParents.takeLast()->row(), 0, itemIndex);
        } while (!lstParents.isEmpty());
        return itemIndex;   // return the index of the user-specified root
    }   // setupModelData
    void FileTreeModel::listSubDir(QDir &dir, TreeItem *parent, TreeItem *registered_child = 0) {
        if (parent->childCount() > 1) return;       // this dir has already been listed
        if (parent->hasChildren() && parent->child(0)->text().compare("")) return;  // the only child is not dummy
        QDirIterator it(dir.path(), QDirIterator::NoIteratorFlags);      // check this parent node
        while (it.hasNext()) {      // check each child
            QString full_path;
            QFileInfo fi = QFileInfo(full_path = it.next());
            if (!fi.fileName().compare(".") || !fi.fileName().compare("..")) continue;        // ignore "." and ".."
            TreeItem *siblingItem;
            if (registered_child && registered_child->data().toString() == full_path) {     // this is registered child
                siblingItem = registered_child;
            } else if (parent->childCount() == 1 && parent->child(0)->text().compare("") == 0) { // can reuse the dummy item
                siblingItem = parent->child(0);
            } else {    // need a new node for the item
                siblingItem = new TreeItem(fi.fileName());
            }   // else for a new node
            if (fi.isDir()) {  // is directory
                TreeItem *dummyItem = new TreeItem("");     // dummy child to mark the folder to expand
            } else {    // a file
            } // else of if dir
            QString addr; addr.setNum((long)(void *)siblingItem, 16);
            qDebug() << (siblingItem->data().toString() + " ## " + addr);    // dump all address for each found child
        }   // while it.hasNext
    }   // listSubDir

  • The reason that I added dummy child is to make all directories expandable, a lazy expansion.

  • The dummy child is the culprit. It did not set the parent so the parent is invalid.