Search code examples
qtrecursionqtreewidget

Populate QTreeWidget with hierarchic structure from absolute filepaths


I have a file which has absolute filepaths listed, 1 per line. The listed files are in order, so all files in e.g. the /Documents/ dir will be listed after eachother in the file.

What I want to do is to place all these files in a QTreeWidget in a nice hierarchic structure, just like a normal filesystem. How would I do that from my file of absolute paths I have?

This is how far I've gotten with my coding on this:

QFile file(FILENAME_ENCRYPTED);
QString line;
QDir dir;

QTreeWidgetItem *item;
if (file.open(QIODevice::ReadOnly)) {
    QTextStream stream( &file );
    do {
        line = stream.readLine();
        if (!line.isNull()) {
            dir = QDir(line);
            item = new QTreeWidgetItem();
            item->setText(0, dir.dirName());
            this->ui->treeWidget->addTopLevelItem(item);
        }
    } while (!line.isNull());
}
file.close();

This works fine, but it only lists all the filenames after eachother. I guess I have to do some recursive function but recursion is not my best friend, I prefer iteration! Could someone give me a push in the right direction? :)


Solution

  • No recursion should be necessary. You can use QString::split() to split the file path into separate QStrings in a QStringList based on a separator (i.e., "/"), then iterate through each QString to determine the file structure.

    EDIT: Here is an example:

    #include <QtGui>
    
    const QString s1 = "Docs/Testing/textFile1.txt";
    const QString s2 = "Docs/Testing/textFile2.txt";
    const QString s3 = "Docs/Testing/textFile3.txt";
    const QString s4 = "Docs/Testing/AnotherFolder/textFile4.txt";
    const QString s5 = "ThisIsGonnaBeCrazy/WholeNewFolder/AndAnother/file.pdf";
    const QString s6 = "ThisIsGonnaBeCrazy/file.doc";
    
    class MainWindow : public QMainWindow
    {
    public:
        MainWindow()
        {
            QTreeWidget *treeWidget = new QTreeWidget;
    
            QStringList fileNames;
            fileNames << s1 << s2 << s3 << s4 << s5 << s6;
    
            QTreeWidgetItem *topLevelItem = NULL;
            foreach (const QString &fileName, fileNames)
            {
                QStringList splitFileName = fileName.split("/");
    
                // add root folder as top level item if treeWidget doesn't already have it
                if (treeWidget->findItems(splitFileName[0], Qt::MatchFixedString).isEmpty())
                {
                    topLevelItem = new QTreeWidgetItem;
                    topLevelItem->setText(0, splitFileName[0]);
                    treeWidget->addTopLevelItem(topLevelItem);
                }
    
                QTreeWidgetItem *parentItem = topLevelItem;
    
                // iterate through non-root directories (file name comes after)
                for (int i = 1; i < splitFileName.size() - 1; ++i)
                {
                    // iterate through children of parentItem to see if this directory exists
                    bool thisDirectoryExists = false;
                    for (int j = 0; j < parentItem->childCount(); ++j)
                    {
                        if (splitFileName[i] == parentItem->child(j)->text(0))
                        {
                            thisDirectoryExists = true;
                            parentItem = parentItem->child(j);
                            break;
                        }
                    }
    
                    if (!thisDirectoryExists)
                    {
                        parentItem = new QTreeWidgetItem(parentItem);
                        parentItem->setText(0, splitFileName[i]);
                    }
                }
    
                QTreeWidgetItem *childItem = new QTreeWidgetItem(parentItem);
                childItem->setText(0, splitFileName.last());
            }
    
            setCentralWidget(treeWidget);
        }
    };
    
    int main(int argc, char *argv[])
    {
        QApplication a(argc, argv);
        MainWindow w;
        w.show();
        return a.exec();
    }
    

    Note that you can use QTreeWidgetItem::setData() to set the file name for each file if you like. My example does not do that, though.