2

I've been struggling with this for a while.

Qt's QFileSystemModel is really slow when fetching several hundred files because of a really bad icon fetching algorithm.

I want to completely disable icons. They are fetched in QFileSystemModel::data method which is not virtual (the source of QFileSystemModel is available here: http://qt.gitorious.org/qt/qt/blobs/4.7/src/gui/dialogs/qfilesystemmodel.cpp)

This is the code I'm trying to run:

class FileModel : public QFileSystemModel {
    using QFileSystemModel::data;
public:
    QVariant QFileSystemModel::data(const QModelIndex &index, int role) const
    {
     // my own implementation here
    }
}

but it fails with

cannot define member function QFileSystemModel::data witin FileModel

UPDATE

I've managed to override the function and this is what I have now:

class FileModel : public QFileSystemModel {
public:
    QVariant data(const QModelIndex &index, int role) const
    {
    // Here goes Qt's implementation
    Q_D(const QFileSystemModel);
    if (!index.isValid() || index.model() != this)
        return QVariant();
    switch (role) {
    case Qt::EditRole:
    case Qt::DisplayRole:
        switch (index.column()) {
        case 0: return d->name(index);
        case 1: return d->size(index);
        case 2: return d->type(index);
        case 3: return d->time(index);
        default:
            qWarning("data: invalid display value column %d", index.column());
            break;
        }
        break;
    case FilePathRole:
        return filePath(index);
    case FileNameRole:
        return d->name(index);
    case Qt::DecorationRole:
        if (index.column() == 0) {
            QIcon icon = d->icon(index); // This is the part I need to change
            if (icon.isNull()) {
                if (d->node(index)->isDir())
                    icon = d->fileInfoGatherer.iconProvider()->icon(QFileIconProvider::Folder);
                else
                    icon = d->fileInfoGatherer.iconProvider()->icon(QFileIconProvider::File);
            }
            return icon;
        }
        break;
    case Qt::TextAlignmentRole:
        if (index.column() == 1)
            return Qt::AlignRight;
        break;
    case FilePermissions:
        int p = permissions(index);
        return p;
    }
    return QVariant();
}
};

However this code doesn't compile. This is the error I get: 'const QFileSystemModelPrivate* QFileSystemModel::d_func() const' is private

Alex
  • 34,581
  • 26
  • 91
  • 135
  • 2
    remove QFileSystemModel:: part from your declaration, also don't put using part. It is not required here – Kamil Klimek Apr 20 '12 at 13:17
  • `data` must be virtual. `QFileSystemModel` derives from `QAbstractItemModel`, and in that class `data` is a pure virtual function. See http://qt-project.org/doc/qt-4.8/qabstractitemmodel.html#data – Moritz Bunkus Apr 20 '12 at 14:15
  • What Kamil says. Moritz: you don't need virtual keyword if the base already declares a function virtual, pure or otherwise. – Stephen Chu Apr 20 '12 at 14:25

2 Answers2

5

Looks like this was anticipated, as there is a method for setting the "icon provider":

http://doc.qt.io/archives/qt-4.7/qfilesystemmodel.html#setIconProvider

The parameter, a QFileIconProvider, looks to be a fairly simple class that you can implement an instance of yourself, with a method that fetches an icon from a QFileInfo (basically, a file name):

http://doc.qt.io/archives/qt-4.7/qfileinfo.html

You could implement one of these that just returns the same icon for everything. If you find that doesn't address your problem, the following compiled fine for me...FWIW:

class FileModel : public QFileSystemModel {
public:
    QVariant data(const QModelIndex &index, int role) const
    {
        if (role == Qt::DecorationRole) {
            return QVariant (QIcon ());
        }    

        return QFileSystemModel::data(index, role);
    }
};
Christophe Weis
  • 2,518
  • 4
  • 28
  • 32
  • Thanks, but that doesn't work. QFileSystemModel uses QFileIconProvider only to build icons for folders and general files and only if calling `QFileSystemNode::icon()` failed. I couldn't find the `QFileSystemNode ` class, even if I did, changing it would be a lot harder than changing the `QFileSystemModel` class. – Alex Apr 20 '12 at 14:24
  • Looking at the source...are you saying in getting the decoration role that it is going through the `d->icon` path here (which is slow for you) and not calling the provider? Or do you think it's something else? This is in the source of the method you are trying to override: http://qt.gitorious.org/qt/qt/blobs/4.8/src/gui/dialogs/qfilesystemmodel.cpp#line708 – HostileFork says dont trust SE Apr 20 '12 at 14:59
  • Yes, d->icon() calls `QFileSystemNode::icon` which takes about 2 milliseconds to run. Multiply it by 5000 files and you get 10 seconds of a UI freeze since QIcon can only be used in a main UI thread. – Alex Apr 20 '12 at 17:27
  • @Alex `QFileSystemNode::icon` is initially populated by `QFileIconProvider` too: http://qt.gitorious.org/qt/qt/blobs/4.8/src/gui/dialogs/qfileinfogatherer.cpp#line233 – alexisdm Apr 20 '12 at 17:35
  • @Alex If what @alexisdm says isn't the case then what you're describing sounds like some kind of weird bug, Qt is not usually that brain-dead. :) In any case, if you do have to override `data()` I added code that compiles fine on my system...you could special case the decoration/icon case and pass through to the base for the rest. – HostileFork says dont trust SE Apr 20 '12 at 17:38
  • This is actually how it works, and I saw some users rage on the mailing lists about that. I also don't understand why it's like that. Thanks, I'll try your code. – Alex Apr 20 '12 at 18:10
  • Okay, your code compiles. But when I paste the actual implementation (the line I need to change is in the middle of it), I a get compilation error. This class is using this weird Q_D macro, I'm sure that it's causing the trouble. – Alex Apr 20 '12 at 18:20
  • 1
    That's due to the "pimpl idiom"...there's some private implementation stuff that doesn't make it into the public header set. You shouldn't need to worry about reaching into the implementation of QFileSystemModel though, can't you just test the parameters and handle it if they are the case you want, otherwise pass through to the base...? See updated code. – HostileFork says dont trust SE Apr 20 '12 at 18:30
2

If a function in a base class is virtual then it is virtual in derived classes as well. The following will print "C":

#include <iostream>

class A {
public:
  virtual void data() = 0;
};

class B: public A {
public:
  void data() { std::cout << "B\n"; }
};

class C: public B {
public:
  void data() { std::cout << "C\n"; }
};

int
main() {
  C c;
  A *a = &c;
  a->data();

  return 0;
}

QFileSystemDialog is derived from QAbstractItemModel in which data() is pure virtual. You couldn't even instatiate the former if it didn't override data() with its own implementation.

See http://qt-project.org/doc/qt-4.8/qabstractitemmodel.html#data

Moritz Bunkus
  • 11,592
  • 3
  • 37
  • 49
  • You are right, it's virtual. However I'm getting this error: `invalid use of incomplete type 'const struct QFileSystemModelPrivate'` – Alex Apr 20 '12 at 14:39
  • Why don't you post the full source code to your class somewhere so that we can look at actual code and don't have to mind read what you've written? – Moritz Bunkus Apr 20 '12 at 16:45