0

I want to show only mounted drives sorted by drive letter in windows using Qt 5.10. Here is my test code:

#include <QtWidgets>
#include <QDebug>

QStringList mountedDrives;

class FSFilter : public QSortFilterProxyModel
{
public:
    FSFilter(QObject *parent)  : QSortFilterProxyModel(parent) {}
protected:
    bool filterAcceptsRow(int row, const QModelIndex &par) const override
    {
        QModelIndex idx = sourceModel()->index(row, 0, par);
        QString path = idx.data(QFileSystemModel::FilePathRole).toString();
        QString path2 = idx.data(Qt::DisplayRole).toString();
        bool mounted = mountedDrives.contains(path);
        if (mounted) {
            qDebug() << "QFileSystemModel::FilePathRole =" << path
                     << "  Qt::DisplayRole =" << path2;
            return true;
        }
        else return false;
    }
};

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);

    // get mounted drives only
    foreach (const QStorageInfo &storage, QStorageInfo::mountedVolumes()) {
        if (storage.isValid() && storage.isReady()) {
            if (!storage.isReadOnly()) {
                mountedDrives << storage.rootPath();
            }
        }
    }

    QFileSystemModel *fsModel = new QFileSystemModel;
    fsModel->setRootPath("");

    FSFilter *fsFilter = new FSFilter(fsModel);
    fsFilter->setSourceModel(fsModel);
    fsFilter->setSortRole(QFileSystemModel::FilePathRole); // now it works
    fsModel->fetchMore(fsModel->index(0,0));

    QTreeView tree;
    tree.setModel(fsFilter);  // different sort if use  
    tree.setModel(fsFilter);
    tree.setSortingEnabled(true);
    tree.sortByColumn(0, Qt::AscendingOrder);

    tree.resize(800, 400);
    tree.setColumnWidth(0, 300);
    tree.setWindowTitle(QObject::tr("File System Test"));
    tree.show();

    return app.exec();
}

This works fine, producing this output, except it is not sorted by drive letter:

Mounted Drives using QSortFilterProxyModelfilter

Running the same code, but setting the treeview model as

tree.setModel(fsModel);  // use QFileSystemModel, not QSortFilterProxyModel

results in the following, where the items are sorting the way I want: All drives using QFileSystemModel without proxy

I thought this might be a role issue. Here is the output from my qDebug statements:

QFileSystemModel::FilePathRole = "C:/" Qt::DisplayRole = "C:"

QFileSystemModel::FilePathRole = "D:/" Qt::DisplayRole = "Data (D:)"

QFileSystemModel::FilePathRole = "E:/" Qt::DisplayRole = "Photos (E:)"

QFileSystemModel::FilePathRole = "F:/" Qt::DisplayRole = "Archive (F:)"

QFileSystemModel::FilePathRole = "H:/" Qt::DisplayRole = "Old D (H:)"

QFileSystemModel::FilePathRole = "I:/" Qt::DisplayRole = "Old C (I:)"

So I included this line

fsFilter->setFilterRole(QFileSystemModel::FilePathRole);

but this did not help.

Solution (corrected in code listing above):

fsFilter->setSortRole(QFileSystemModel::FilePathRole);
Rory
  • 113
  • 8
  • The QSortFilterProxyModel screenshot shows that QSortFilterProxyModel is sorting the strings alphabetically, presumably because it doesn't use the customized compare algorithm that QFileSystemModel uses. If you want to see what QFileSystemModel is doing, have a look in qfilesystemmodel.cpp in the Qt sources, there is a class there called QFileSystemModelSorter which might be of interest. – Jeremy Friesner Mar 22 '18 at 01:28
  • It turns out it was pretty simple. I was close with setFilterRole. I replaced fsFilter->setFilterRole(QFileSystemModel::FilePathRole); with fsFilter->setSortRole(QFileSystemModel::FilePathRole); – Rory Mar 22 '18 at 02:35

1 Answers1

1

You should reimplement virtual function lessThan in FSFilter, by default it sort alphabetically, but in this case you need take into account first and last letters in drive name.

Yuriy Rusinov
  • 61
  • 2
  • 5