Using QFileSystemModel to synchronise two views with different elements

575 views Asked by At

I'm building a explorer like view with a directory tree / navigation pane using a QTreeView on the left side and an icon view on the right/main side using a QListView. The tree side should only show directories (preferable non empty directories…but that's a different story) and the icon view only files with a specific name filter and no directories. And I'm struggling how to do this right.

First: I don't know if I should use one or two QFileSystemModels for that. Using one I've to filter with two attached QSortFilterProxyModels for each view—but I don't have file system properties anymore .... and using only RegEx for that is kind of limiting. And using two models have been proven hard cause I can't really map a QModelIndex from one model into the other cause the models contain not the same items. For example when I click on a directory on the left the root path of the right should get updated. But the directory is not included in the model ...so this doesn't work.

Any ideas on how to do this right? Thank you!

1

There are 1 answers

0
Alexander V On BEST ANSWER

How can the file directory tree view and the file navigation view interact?

Not insisting that is the only way but works for me:

  • One view model filters only directories and the other only files
  • Each view (directory tree and file navigation) uses separate file model object of the same type pointing to some root
  • Synchronize views using the path in the file system: when either of views changes selection (in your case tree view) by the user click the other is picking up from the same path
  • Mind that having QSortFilterProxyModel we first have to obtain the current view position from there

void MyFileSystemWidget::startViews()
{
    // First, initialize QTreeView and QTableView each with own
    // QFileSystemModel/QSortFilterProxyModel(MySortFilterProxyModel)
    // with individual selection e.g. QDir::Files or QDir::Dirs
    //// //// ////

    // Make models to point at the same root to start
    const QModelIndex rootTreeViewIdx = m_pTreeSortFilterProxyModel->mapFromSource( m_pTreeDataModel->index(rootDir.path()) );
    m_pTreeView->setRootIndex(rootTreeViewIdx);
    m_pTreeView->setCurrentIndex(rootTreeViewIdx);

    const QModelIndex rootFileViewIdx = m_pListSortFilterProxyModel->mapFromSource( m_pListDataModel->index(rootDir.path()) );
    m_pTableView->setRootIndex(rootFileViewIdx);

    // now connect tree view clicked signal 
    connect(m_pTreeView, SIGNAL(clicked(QModelIndex)),  SLOT(onTreeViewClicked(QModelIndex)));
}


void MyFileSystemWidget::onTreeViewClicked(const QModelIndex& treeIndex)
{
        // see MySortFilterProxyModel::sourceFileInfo
        QString modelPath = m_pTreeSortFilterProxyModel->sourceFileInfo( treeIndex ).absoluteFilePath();
        if (modelPath.isEmpty())
            return;
        // see MySortFilterProxyModel::setSourceModelRootPath
        const QModelIndex proxyIndex = m_pListSortFilterProxyModel->setSourceModelRootPath(modelPath);
        m_pTableView->setRootIndex(proxyIndex);
}


QFileInfo MySortFilterProxyModel::sourceFileInfo(const QModelIndex& index)
{
    if (!index.isValid())
        return QFileInfo();
    const QModelIndex proxyIndex = mapToSource( index );
    if (!proxyIndex.isValid())
        return QFileInfo();
    return static_cast<QFileSystemModel*>(sourceModel())->fileInfo(proxyIndex);
}


QModelIndex MySortFilterProxyModel::setSourceModelRootPath(const QString& modelPath)
{
    const QModelIndex fmIndex = static_cast<QFileSystemModel*>(sourceModel())->setRootPath(modelPath);
    return mapFromSource( fmIndex );
}