Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. Custom sortable columns in QFileSystemModel

Custom sortable columns in QFileSystemModel

Scheduled Pinned Locked Moved Unsolved General and Desktop
23 Posts 3 Posters 1.2k Views
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • J Offline
    J Offline
    Jo Jo
    wrote on 27 Mar 2025, 12:51 last edited by
    #1

    Hi, I am using QTreeView together with QFileSystemModel and my task is to add a new column (Date Created) to the QFileSystemModel. It should also be possible to sort data by this column. For this, I have implemented the code that I provide below.

    My question is, have I implemented the solution correctly? Can any problems arise? For example, after "moving" columns?

    Here is implementation (I am using Windows 11 with Qt 6.6.2):

    #include <QApplication>
    #include <QTreeView>
    #include <QFileSystemModel>
    #include <QSortFilterProxyModel>
     
    class CustomSortFilterProxyModel : public QSortFilterProxyModel
    {
    public:
        explicit CustomSortFilterProxyModel(QObject *parent = nullptr) : QSortFilterProxyModel(parent) {}
     
    protected:
        bool lessThan(const QModelIndex &left, const QModelIndex &right) const override
        {
            if (sortColumn() == 4)
            {
                QString leftDate = left.data(Qt::DisplayRole).toString();
                QString rightDate = right.data(Qt::DisplayRole).toString();
     
                return QDateTime::fromString(leftDate, Qt::ISODate) < QDateTime::fromString(rightDate, Qt::ISODate);
            }
     
            return QSortFilterProxyModel::lessThan(left, right);
        }
    };
     
    class Model : public QFileSystemModel
    {
    public:
        void sort(int column, Qt::SortOrder order = Qt::AscendingOrder) override
        {
            // prevent model from sorting due to setSortingEnabled(true) called first time
            if (!m_doSort) {
                m_doSort = true;
                return;
            }
     
            QFileSystemModel::sort(column, order);
        }
     
        int columnCount(const QModelIndex& parent = QModelIndex()) const override
        {
            int cc = QFileSystemModel::columnCount(parent);
     
            if (cc == 0)
            {
                return 0;
            }
     
            return cc + 1;
        }
     
        QVariant data(const QModelIndex& index,int role) const override
        {
            if(index.isValid() && index.column() == 4)
            {
                QModelIndex sibling = index.siblingAtColumn(3);
     
                switch(role)
                {
                    case(Qt::DisplayRole):
                    {
                        return fileInfo(sibling).birthTime();
                    }
                    default:
                    {
                        // return same role as in fourth (Date Modified) column at the current row
                        return QFileSystemModel::data(sibling, role);
                    }
                }
            }
     
            return QFileSystemModel::data(index, role);
        }
     
        QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override
        {
            if (role == Qt::DisplayRole && orientation == Qt::Horizontal)
            {
                if (section == 4)
                {
                    return QStringLiteral("Date Created");
                }
            }
     
            return QFileSystemModel::headerData(section, orientation, role);
        }
     
    private:
        bool m_doSort = false;
    };
     
    int main(int argc, char *argv[])
    {
        QApplication app(argc, argv);
     
        Model *model = new Model;
        model->setRootPath(QDir::rootPath());
     
        CustomSortFilterProxyModel* proxyModel = new CustomSortFilterProxyModel;
        proxyModel->setSourceModel(model);
     
        QTreeView *treeView = new QTreeView;
        treeView->setSortingEnabled(true);
        treeView->setModel(proxyModel);
        treeView->setRootIndex(model->index("C:\\Users\\Username\\Desktop\\BOOK"));
        treeView->setColumnWidth(0, 250);
        treeView->setWindowTitle("QFileSystemModel Example");
        treeView->resize(600, 400);
        treeView->show();
     
        return app.exec();
    }
    
    J 1 Reply Last reply 27 Mar 2025, 13:03
    0
    • J Jo Jo
      27 Mar 2025, 12:51

      Hi, I am using QTreeView together with QFileSystemModel and my task is to add a new column (Date Created) to the QFileSystemModel. It should also be possible to sort data by this column. For this, I have implemented the code that I provide below.

      My question is, have I implemented the solution correctly? Can any problems arise? For example, after "moving" columns?

      Here is implementation (I am using Windows 11 with Qt 6.6.2):

      #include <QApplication>
      #include <QTreeView>
      #include <QFileSystemModel>
      #include <QSortFilterProxyModel>
       
      class CustomSortFilterProxyModel : public QSortFilterProxyModel
      {
      public:
          explicit CustomSortFilterProxyModel(QObject *parent = nullptr) : QSortFilterProxyModel(parent) {}
       
      protected:
          bool lessThan(const QModelIndex &left, const QModelIndex &right) const override
          {
              if (sortColumn() == 4)
              {
                  QString leftDate = left.data(Qt::DisplayRole).toString();
                  QString rightDate = right.data(Qt::DisplayRole).toString();
       
                  return QDateTime::fromString(leftDate, Qt::ISODate) < QDateTime::fromString(rightDate, Qt::ISODate);
              }
       
              return QSortFilterProxyModel::lessThan(left, right);
          }
      };
       
      class Model : public QFileSystemModel
      {
      public:
          void sort(int column, Qt::SortOrder order = Qt::AscendingOrder) override
          {
              // prevent model from sorting due to setSortingEnabled(true) called first time
              if (!m_doSort) {
                  m_doSort = true;
                  return;
              }
       
              QFileSystemModel::sort(column, order);
          }
       
          int columnCount(const QModelIndex& parent = QModelIndex()) const override
          {
              int cc = QFileSystemModel::columnCount(parent);
       
              if (cc == 0)
              {
                  return 0;
              }
       
              return cc + 1;
          }
       
          QVariant data(const QModelIndex& index,int role) const override
          {
              if(index.isValid() && index.column() == 4)
              {
                  QModelIndex sibling = index.siblingAtColumn(3);
       
                  switch(role)
                  {
                      case(Qt::DisplayRole):
                      {
                          return fileInfo(sibling).birthTime();
                      }
                      default:
                      {
                          // return same role as in fourth (Date Modified) column at the current row
                          return QFileSystemModel::data(sibling, role);
                      }
                  }
              }
       
              return QFileSystemModel::data(index, role);
          }
       
          QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override
          {
              if (role == Qt::DisplayRole && orientation == Qt::Horizontal)
              {
                  if (section == 4)
                  {
                      return QStringLiteral("Date Created");
                  }
              }
       
              return QFileSystemModel::headerData(section, orientation, role);
          }
       
      private:
          bool m_doSort = false;
      };
       
      int main(int argc, char *argv[])
      {
          QApplication app(argc, argv);
       
          Model *model = new Model;
          model->setRootPath(QDir::rootPath());
       
          CustomSortFilterProxyModel* proxyModel = new CustomSortFilterProxyModel;
          proxyModel->setSourceModel(model);
       
          QTreeView *treeView = new QTreeView;
          treeView->setSortingEnabled(true);
          treeView->setModel(proxyModel);
          treeView->setRootIndex(model->index("C:\\Users\\Username\\Desktop\\BOOK"));
          treeView->setColumnWidth(0, 250);
          treeView->setWindowTitle("QFileSystemModel Example");
          treeView->resize(600, 400);
          treeView->show();
       
          return app.exec();
      }
      
      J Offline
      J Offline
      JonB
      wrote on 27 Mar 2025, 13:03 last edited by
      #2

      @Jo-Jo
      Just a couple of minor observations:

      • Your data() returns a fileInfo(sibling).birthTime(), which is a QDateTime. So why does your lessThan() convert that to a string and then parse that string back to a datetime in order to compare? That is both slow and error prone?

      • Your literal string in model->index("C:\\Users\\Username\\Desktop\\BOOK") is a Windows native path. Normally one uses the Qt OS-agnostic representation with /s instead of \s. Do other QFileSystemModel methods deal with (e.g. return) paths with backslashes or forward slashes? It may not matter, I don't know.

      J 1 Reply Last reply 27 Mar 2025, 13:12
      1
      • J JonB
        27 Mar 2025, 13:03

        @Jo-Jo
        Just a couple of minor observations:

        • Your data() returns a fileInfo(sibling).birthTime(), which is a QDateTime. So why does your lessThan() convert that to a string and then parse that string back to a datetime in order to compare? That is both slow and error prone?

        • Your literal string in model->index("C:\\Users\\Username\\Desktop\\BOOK") is a Windows native path. Normally one uses the Qt OS-agnostic representation with /s instead of \s. Do other QFileSystemModel methods deal with (e.g. return) paths with backslashes or forward slashes? It may not matter, I don't know.

        J Offline
        J Offline
        Jo Jo
        wrote on 27 Mar 2025, 13:12 last edited by
        #3

        @JonB

        1. You are right, it should be like this:
            bool lessThan(const QModelIndex &left, const QModelIndex &right) const override
            {
                if (sortColumn() == 4)
                {
                    QDateTime leftDate = left.data(Qt::DisplayRole).toDateTime();
                    QDateTime rightDate = right.data(Qt::DisplayRole).toDateTime();
        
                    return leftDate < rightDate;
                }
        
                return QSortFilterProxyModel::lessThan(left, right);
            }
        
        1. I got you, thanks

        One problem I have now is when I launch the program, in theory, first there should be only folders, and then files. However, my files and folders are mixed up. How can I fix this problem?

        J 1 Reply Last reply 27 Mar 2025, 13:32
        0
        • J Jo Jo
          27 Mar 2025, 13:12

          @JonB

          1. You are right, it should be like this:
              bool lessThan(const QModelIndex &left, const QModelIndex &right) const override
              {
                  if (sortColumn() == 4)
                  {
                      QDateTime leftDate = left.data(Qt::DisplayRole).toDateTime();
                      QDateTime rightDate = right.data(Qt::DisplayRole).toDateTime();
          
                      return leftDate < rightDate;
                  }
          
                  return QSortFilterProxyModel::lessThan(left, right);
              }
          
          1. I got you, thanks

          One problem I have now is when I launch the program, in theory, first there should be only folders, and then files. However, my files and folders are mixed up. How can I fix this problem?

          J Offline
          J Offline
          JonB
          wrote on 27 Mar 2025, 13:32 last edited by JonB
          #4

          @Jo-Jo
          Not quite sure exactly what you see or want for the order/visibility of various entries, but are you aware of:

          • The default QFileSystemModel::filter() includes all entries via QDir::AllEntries | QDir::NoDotAndDotDot | QDir::AllDirs. You can change that if e.g. you want to exclude non-directories.

          • Or you can control which nodes/leaves are initially expanded/contracted on the QTreeView.

          • If you want Windows File Explorer-type ordering where directories are sorted and displayed in separate sections even when e.g. sorted by creation time, I'm not seeing anything in QFileSystemModel for this(?). For example, Linux default sorting does not treat directories separately from files. So you may have to do this in your sorting functions themselves by looking at the file info during lessThan() and including directory versus non-directory as first priority and then creation datetime as second priority?

          J 1 Reply Last reply 27 Mar 2025, 13:43
          1
          • J JonB
            27 Mar 2025, 13:32

            @Jo-Jo
            Not quite sure exactly what you see or want for the order/visibility of various entries, but are you aware of:

            • The default QFileSystemModel::filter() includes all entries via QDir::AllEntries | QDir::NoDotAndDotDot | QDir::AllDirs. You can change that if e.g. you want to exclude non-directories.

            • Or you can control which nodes/leaves are initially expanded/contracted on the QTreeView.

            • If you want Windows File Explorer-type ordering where directories are sorted and displayed in separate sections even when e.g. sorted by creation time, I'm not seeing anything in QFileSystemModel for this(?). For example, Linux default sorting does not treat directories separately from files. So you may have to do this in your sorting functions themselves by looking at the file info during lessThan() and including directory versus non-directory as first priority and then creation datetime as second priority?

            J Offline
            J Offline
            Jo Jo
            wrote on 27 Mar 2025, 13:43 last edited by Jo Jo
            #5

            @JonB said in Custom sortable columns in QFileSystemModel:

            Not quite sure exactly what you see or want for the order/visibility of various entries

            Let me make this clear. When I launch the program first time, I want the folders to be shown first, then the files. This is the default behavior when using QTreeView + QFileSystemModel and I want to keep it. However, after using QSortFilterProxyModel this default behavior is broken (please see screenshot).

            alt text

            J 1 Reply Last reply 27 Mar 2025, 13:56
            0
            • J Jo Jo
              27 Mar 2025, 13:43

              @JonB said in Custom sortable columns in QFileSystemModel:

              Not quite sure exactly what you see or want for the order/visibility of various entries

              Let me make this clear. When I launch the program first time, I want the folders to be shown first, then the files. This is the default behavior when using QTreeView + QFileSystemModel and I want to keep it. However, after using QSortFilterProxyModel this default behavior is broken (please see screenshot).

              alt text

              J Offline
              J Offline
              JonB
              wrote on 27 Mar 2025, 13:56 last edited by
              #6

              @Jo-Jo
              Because QSortFilterProxyModel has no knowledge that you are dealing with file system entries, where you want different sort order for folders versus files. Whereas, presumably, the default QFileSystemModel sorter, whatever that is, does, or does for Windows or whatever. So it seems to me that like I said it is your job to make your QSortFilterProxyModel::lessThan() look at the entry types and use whether the items compared are folders or files as the first priority in your comparison code, and only if the two items are the same type (folder/file) then look at the sort column, like creation date or name, as the secondary priority.

              You can Google for something like qfilesystemmodel sort. There are various hits, e.g. https://forum.qt.io/topic/113138/sorting-folders-first-qfilesystemmodel-with-directory-filter, where I have previously referenced a couple of topics.

              J 1 Reply Last reply 27 Mar 2025, 14:02
              1
              • J JonB
                27 Mar 2025, 13:56

                @Jo-Jo
                Because QSortFilterProxyModel has no knowledge that you are dealing with file system entries, where you want different sort order for folders versus files. Whereas, presumably, the default QFileSystemModel sorter, whatever that is, does, or does for Windows or whatever. So it seems to me that like I said it is your job to make your QSortFilterProxyModel::lessThan() look at the entry types and use whether the items compared are folders or files as the first priority in your comparison code, and only if the two items are the same type (folder/file) then look at the sort column, like creation date or name, as the secondary priority.

                You can Google for something like qfilesystemmodel sort. There are various hits, e.g. https://forum.qt.io/topic/113138/sorting-folders-first-qfilesystemmodel-with-directory-filter, where I have previously referenced a couple of topics.

                J Offline
                J Offline
                Jo Jo
                wrote on 27 Mar 2025, 14:02 last edited by
                #7

                @JonB
                Thank you! Do I understand correctly that in QSortFilterProxyModel::lessThan we have no way to delegate the call to the QFileSystemModel comparison function and we have to implement it ourselves?

                J 1 Reply Last reply 27 Mar 2025, 14:10
                0
                • J Jo Jo
                  27 Mar 2025, 14:02

                  @JonB
                  Thank you! Do I understand correctly that in QSortFilterProxyModel::lessThan we have no way to delegate the call to the QFileSystemModel comparison function and we have to implement it ourselves?

                  J Offline
                  J Offline
                  JonB
                  wrote on 27 Mar 2025, 14:10 last edited by JonB
                  #8

                  @Jo-Jo
                  That is my understanding, unless you find better by searching.
                  You might also take heed of https://forum.qt.io/post/569839, where the author states/claims:

                  In order to use QFileSystemModel, you can as well re-implement the "sort" function since the base implementation does nothing:

                  https://doc.qt.io/qt-5/qfilesystemmodel.html#sort

                  If you want to sort like the one in the right, I would recommend using the QSortFilterProxyModel as is. If you want something more customizable then re-implementing the QFileSystemModel would be a better option.

                  While you are looking at that thread, note that it appears Windows File Explorer has further "customized" rules for file name sorting, such as where the file names contains digits where @Christian-Ehrlicher refers to void QCollator::setNumericMode(bool on).

                  J 1 Reply Last reply 27 Mar 2025, 14:29
                  1
                  • J JonB
                    27 Mar 2025, 14:10

                    @Jo-Jo
                    That is my understanding, unless you find better by searching.
                    You might also take heed of https://forum.qt.io/post/569839, where the author states/claims:

                    In order to use QFileSystemModel, you can as well re-implement the "sort" function since the base implementation does nothing:

                    https://doc.qt.io/qt-5/qfilesystemmodel.html#sort

                    If you want to sort like the one in the right, I would recommend using the QSortFilterProxyModel as is. If you want something more customizable then re-implementing the QFileSystemModel would be a better option.

                    While you are looking at that thread, note that it appears Windows File Explorer has further "customized" rules for file name sorting, such as where the file names contains digits where @Christian-Ehrlicher refers to void QCollator::setNumericMode(bool on).

                    J Offline
                    J Offline
                    Jo Jo
                    wrote on 27 Mar 2025, 14:29 last edited by
                    #9

                    @JonB Thank you! Now I am fixed this problem and full implementation currently looks like this (see below) and I would be glad to receive any feedback.

                    #include <QApplication>
                    #include <QTreeView>
                    #include <QHeaderView>
                    #include <QFileSystemModel>
                    #include <QSortFilterProxyModel>
                    
                    class CustomSortFilterProxyModel : public QSortFilterProxyModel
                    {
                    public:
                        explicit CustomSortFilterProxyModel(QObject *parent = nullptr) : QSortFilterProxyModel(parent) {}
                    
                    protected:
                        bool lessThan(const QModelIndex &left, const QModelIndex &right) const override
                        {
                            auto model = (QFileSystemModel*)sourceModel();
                            bool isLeftDir = model->isDir(left);
                            bool isRightDir = model->isDir(right);
                    
                            if ((isLeftDir && isRightDir) || (!isLeftDir && !isRightDir))
                            {
                                QString const leftName  = model->data(left,  Qt::DisplayRole).toString();
                                QString const rightName = model->data(right, Qt::DisplayRole).toString();
                    
                                const int compare = QString::localeAwareCompare(leftName, rightName);
                                if(compare != 0) {
                                    return compare < 0;
                                }
                            }
                            else if (isLeftDir)
                            {
                                return true;
                            }
                    
                            return false;
                        }
                    };
                    
                    class Model : public QFileSystemModel
                    {
                    public:
                    
                        int columnCount(const QModelIndex& parent = QModelIndex()) const override
                        {
                            int cc = QFileSystemModel::columnCount(parent);
                    
                            if (cc == 0)
                            {
                                return 0;
                            }
                    
                            return cc + 1;
                        }
                    
                        QVariant data(const QModelIndex& index,int role) const override
                        {
                            if(index.isValid() && index.column() == 4)
                            {
                                QModelIndex sibling = index.siblingAtColumn(3);
                    
                                switch(role)
                                {
                                    case(Qt::DisplayRole):
                                    {
                                        return fileInfo(sibling).birthTime();
                                    }
                                    default:
                                    {
                                        // return same role as in fourth (Date Modified) column at the current row
                                        return QFileSystemModel::data(sibling, role);
                                    }
                                }
                            }
                    
                            return QFileSystemModel::data(index, role);
                        }
                    
                        QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override
                        {
                            if (role == Qt::DisplayRole && orientation == Qt::Horizontal)
                            {
                                if (section == 4)
                                {
                                    return QStringLiteral("Date Created");
                                }
                            }
                    
                            return QFileSystemModel::headerData(section, orientation, role);
                        }
                    };
                    
                    int main(int argc, char *argv[])
                    {
                        QApplication app(argc, argv);
                    
                        Model *model = new Model;
                        model->setRootPath(QDir::rootPath());
                    
                        CustomSortFilterProxyModel* proxyModel = new CustomSortFilterProxyModel;
                    
                        proxyModel->setSourceModel(model);
                        proxyModel->setSortRole(Qt::DisplayRole);
                    
                        QTreeView *treeView = new QTreeView;
                        treeView->setSortingEnabled(true);
                        treeView->setModel(proxyModel);
                        treeView->setRootIndex(model->index("C:\\Users\\Username\\Desktop\\BOOK"));
                        treeView->setColumnWidth(0, 250);
                        treeView->setWindowTitle("QFileSystemModel Example");
                        treeView->resize(600, 400);
                        treeView->show();
                    
                        treeView->header()->setSortIndicator(0, Qt::AscendingOrder);
                    
                        return app.exec();
                    }
                    
                    
                    J 1 Reply Last reply 27 Mar 2025, 14:44
                    0
                    • J Jo Jo
                      27 Mar 2025, 14:29

                      @JonB Thank you! Now I am fixed this problem and full implementation currently looks like this (see below) and I would be glad to receive any feedback.

                      #include <QApplication>
                      #include <QTreeView>
                      #include <QHeaderView>
                      #include <QFileSystemModel>
                      #include <QSortFilterProxyModel>
                      
                      class CustomSortFilterProxyModel : public QSortFilterProxyModel
                      {
                      public:
                          explicit CustomSortFilterProxyModel(QObject *parent = nullptr) : QSortFilterProxyModel(parent) {}
                      
                      protected:
                          bool lessThan(const QModelIndex &left, const QModelIndex &right) const override
                          {
                              auto model = (QFileSystemModel*)sourceModel();
                              bool isLeftDir = model->isDir(left);
                              bool isRightDir = model->isDir(right);
                      
                              if ((isLeftDir && isRightDir) || (!isLeftDir && !isRightDir))
                              {
                                  QString const leftName  = model->data(left,  Qt::DisplayRole).toString();
                                  QString const rightName = model->data(right, Qt::DisplayRole).toString();
                      
                                  const int compare = QString::localeAwareCompare(leftName, rightName);
                                  if(compare != 0) {
                                      return compare < 0;
                                  }
                              }
                              else if (isLeftDir)
                              {
                                  return true;
                              }
                      
                              return false;
                          }
                      };
                      
                      class Model : public QFileSystemModel
                      {
                      public:
                      
                          int columnCount(const QModelIndex& parent = QModelIndex()) const override
                          {
                              int cc = QFileSystemModel::columnCount(parent);
                      
                              if (cc == 0)
                              {
                                  return 0;
                              }
                      
                              return cc + 1;
                          }
                      
                          QVariant data(const QModelIndex& index,int role) const override
                          {
                              if(index.isValid() && index.column() == 4)
                              {
                                  QModelIndex sibling = index.siblingAtColumn(3);
                      
                                  switch(role)
                                  {
                                      case(Qt::DisplayRole):
                                      {
                                          return fileInfo(sibling).birthTime();
                                      }
                                      default:
                                      {
                                          // return same role as in fourth (Date Modified) column at the current row
                                          return QFileSystemModel::data(sibling, role);
                                      }
                                  }
                              }
                      
                              return QFileSystemModel::data(index, role);
                          }
                      
                          QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override
                          {
                              if (role == Qt::DisplayRole && orientation == Qt::Horizontal)
                              {
                                  if (section == 4)
                                  {
                                      return QStringLiteral("Date Created");
                                  }
                              }
                      
                              return QFileSystemModel::headerData(section, orientation, role);
                          }
                      };
                      
                      int main(int argc, char *argv[])
                      {
                          QApplication app(argc, argv);
                      
                          Model *model = new Model;
                          model->setRootPath(QDir::rootPath());
                      
                          CustomSortFilterProxyModel* proxyModel = new CustomSortFilterProxyModel;
                      
                          proxyModel->setSourceModel(model);
                          proxyModel->setSortRole(Qt::DisplayRole);
                      
                          QTreeView *treeView = new QTreeView;
                          treeView->setSortingEnabled(true);
                          treeView->setModel(proxyModel);
                          treeView->setRootIndex(model->index("C:\\Users\\Username\\Desktop\\BOOK"));
                          treeView->setColumnWidth(0, 250);
                          treeView->setWindowTitle("QFileSystemModel Example");
                          treeView->resize(600, 400);
                          treeView->show();
                      
                          treeView->header()->setSortIndicator(0, Qt::AscendingOrder);
                      
                          return app.exec();
                      }
                      
                      
                      J Offline
                      J Offline
                      JonB
                      wrote on 27 Mar 2025, 14:44 last edited by
                      #10

                      @Jo-Jo
                      Well, I could rewrite your lessThan() to use fewer lines and smaller expressions, becaue I am like that :) But it's not a big deal.

                      You started out with a lessThan which had special code for data comparison in a column. Now you seem to have an implementation which does not look at column data type and just does string comparisons on everything. Is the sufficient? Do you need a more complex "merger" of various approaches depending on data type? Depends what you want.

                      J 1 Reply Last reply 27 Mar 2025, 15:01
                      0
                      • J JonB
                        27 Mar 2025, 14:44

                        @Jo-Jo
                        Well, I could rewrite your lessThan() to use fewer lines and smaller expressions, becaue I am like that :) But it's not a big deal.

                        You started out with a lessThan which had special code for data comparison in a column. Now you seem to have an implementation which does not look at column data type and just does string comparisons on everything. Is the sufficient? Do you need a more complex "merger" of various approaches depending on data type? Depends what you want.

                        J Offline
                        J Offline
                        Jo Jo
                        wrote on 27 Mar 2025, 15:01 last edited by
                        #11

                        @JonB I'm thinking about how to correctly implement comparison taking into account types but have some problems. Currently my code looks like this but not workiing properly. Maybe you can suggest solution?

                        class CustomSortFilterProxyModel : public QSortFilterProxyModel
                        {
                            QList<int> m_dtCols{3,4};
                        public:
                            explicit CustomSortFilterProxyModel(QObject *parent = nullptr) : QSortFilterProxyModel(parent) {}
                        
                        protected:
                            bool lessThan(const QModelIndex &left, const QModelIndex &right) const override
                            {
                                auto model = (QFileSystemModel*)sourceModel();
                                bool isLeftDir = model->isDir(left);
                                bool isRightDir = model->isDir(right);
                        
                                if ((isLeftDir && isRightDir) || (!isLeftDir && !isRightDir))
                                {
                                    auto leftName  = model->data(left,  Qt::DisplayRole);
                                    auto rightName = model->data(right, Qt::DisplayRole);
                                    const int compare = m_dtCols.contains(sortColumn()) ?
                                        leftName.toDateTime() < rightName.toDateTime() :
                                        QString::localeAwareCompare(leftName.toString(), rightName.toString());
                        
                                    if(compare != 0) {
                                        return compare < 0;
                                    }
                                }
                                else if (isLeftDir)
                                {
                                    return true;
                                }
                        
                                return false;
                            }
                        };
                        
                        1 Reply Last reply
                        0
                        • J Offline
                          J Offline
                          JonB
                          wrote on 27 Mar 2025, 15:06 last edited by
                          #12

                          I'm not sure what "not workiing properly" means? What does not work right? Have you put a break or qDebug() statements here to see/verify what it is comparing and returning?

                          J 1 Reply Last reply 27 Mar 2025, 15:14
                          0
                          • J JonB
                            27 Mar 2025, 15:06

                            I'm not sure what "not workiing properly" means? What does not work right? Have you put a break or qDebug() statements here to see/verify what it is comparing and returning?

                            J Offline
                            J Offline
                            Jo Jo
                            wrote on 27 Mar 2025, 15:14 last edited by Jo Jo
                            #13

                            @JonB Sorry, sorting by "Date Modified" and "Date Created" columns does not work properly (yes, i use qDebug() for tests)

                            UPDATE:
                            I think it should be implemented like this

                            class CustomSortFilterProxyModel : public QSortFilterProxyModel
                            {
                                QList<int> m_dtCols{3,4};
                            public:
                                explicit CustomSortFilterProxyModel(QObject *parent = nullptr) : QSortFilterProxyModel(parent) {}
                            
                            protected:
                                bool lessThan(const QModelIndex &left, const QModelIndex &right) const override
                                {
                                    auto model = (QFileSystemModel*)sourceModel();
                                    bool isLeftDir = model->isDir(left);
                                    bool isRightDir = model->isDir(right);
                            
                                    if ((isLeftDir && isRightDir) || (!isLeftDir && !isRightDir))
                                    {
                                        auto leftName  = model->data(left,  Qt::DisplayRole);
                                        auto rightName = model->data(right, Qt::DisplayRole);
                            
                                        if (m_dtCols.contains(sortColumn()))
                                        {
                                            return (leftName.toDateTime() < rightName.toDateTime());
                                        }
                            
                                        const int compare = QString::localeAwareCompare(leftName.toString(), rightName.toString());
                            
                                        if(compare != 0) {
                                            return compare < 0;
                                        }
                                    }
                                    else if (isLeftDir)
                                    {
                                        return true;
                                    }
                            
                                    return false;
                                }
                            };
                            

                            But any improvement is appreciated

                            J 1 Reply Last reply 27 Mar 2025, 15:18
                            0
                            • J Jo Jo
                              27 Mar 2025, 15:14

                              @JonB Sorry, sorting by "Date Modified" and "Date Created" columns does not work properly (yes, i use qDebug() for tests)

                              UPDATE:
                              I think it should be implemented like this

                              class CustomSortFilterProxyModel : public QSortFilterProxyModel
                              {
                                  QList<int> m_dtCols{3,4};
                              public:
                                  explicit CustomSortFilterProxyModel(QObject *parent = nullptr) : QSortFilterProxyModel(parent) {}
                              
                              protected:
                                  bool lessThan(const QModelIndex &left, const QModelIndex &right) const override
                                  {
                                      auto model = (QFileSystemModel*)sourceModel();
                                      bool isLeftDir = model->isDir(left);
                                      bool isRightDir = model->isDir(right);
                              
                                      if ((isLeftDir && isRightDir) || (!isLeftDir && !isRightDir))
                                      {
                                          auto leftName  = model->data(left,  Qt::DisplayRole);
                                          auto rightName = model->data(right, Qt::DisplayRole);
                              
                                          if (m_dtCols.contains(sortColumn()))
                                          {
                                              return (leftName.toDateTime() < rightName.toDateTime());
                                          }
                              
                                          const int compare = QString::localeAwareCompare(leftName.toString(), rightName.toString());
                              
                                          if(compare != 0) {
                                              return compare < 0;
                                          }
                                      }
                                      else if (isLeftDir)
                                      {
                                          return true;
                                      }
                              
                                      return false;
                                  }
                              };
                              

                              But any improvement is appreciated

                              J Offline
                              J Offline
                              JonB
                              wrote on 27 Mar 2025, 15:18 last edited by JonB
                              #14

                              @Jo-Jo
                              Well, start by checking that goes through the toDateTime() path, what their values are and that is getting it right. I don't know what is wrong just by looking at it.

                              Btw, check whether the QString::localeAwareCompare(0 is case insensitive or case sensitive? Windows, but not Linux, sorts case insensitively, yours might not.

                              You have just updated your code: I'm not sure it is any different from what you first wrote, but if it is and works that's fine.

                              J 1 Reply Last reply 27 Mar 2025, 16:02
                              0
                              • J JonB
                                27 Mar 2025, 15:18

                                @Jo-Jo
                                Well, start by checking that goes through the toDateTime() path, what their values are and that is getting it right. I don't know what is wrong just by looking at it.

                                Btw, check whether the QString::localeAwareCompare(0 is case insensitive or case sensitive? Windows, but not Linux, sorts case insensitively, yours might not.

                                You have just updated your code: I'm not sure it is any different from what you first wrote, but if it is and works that's fine.

                                J Offline
                                J Offline
                                Jo Jo
                                wrote on 27 Mar 2025, 16:02 last edited by Jo Jo
                                #15

                                @JonB Everything worked except for the "Date Modified" column. It turned out that Qt returns this date as a QString. I had to convert this string to QDateTime. Now the code looks like this:

                                class CustomSortFilterProxyModel : public QSortFilterProxyModel
                                {
                                    QList<int> m_dtCols{3,4};
                                public:
                                    explicit CustomSortFilterProxyModel(QObject *parent = nullptr) : QSortFilterProxyModel(parent) {}
                                
                                protected:
                                    bool lessThan(const QModelIndex &left, const QModelIndex &right) const override
                                    {
                                        auto model = (QFileSystemModel*)sourceModel();
                                        bool isLeftDir = model->isDir(left);
                                        bool isRightDir = model->isDir(right);
                                
                                        if ((isLeftDir && isRightDir) || (!isLeftDir && !isRightDir))
                                        {
                                            auto leftName  = model->data(left,  Qt::DisplayRole);
                                            auto rightName = model->data(right, Qt::DisplayRole);
                                
                                            //return (leftName.toDateTime() < rightName.toDateTime()); // OK, works fine for dates
                                
                                            if (m_dtCols.contains(sortColumn()))
                                            {
                                                if (sortColumn() == 3)
                                                {
                                                    QDateTime dt1 = QDateTime::fromString(leftName.toString(), "M/d/yyyy h:mm AP");
                                                    QDateTime dt2 = QDateTime::fromString(rightName.toString(), "M/d/yyyy h:mm AP");
                                                    return dt1 < dt2;
                                                }
                                
                                                return (leftName.toDateTime() < rightName.toDateTime());
                                            }
                                
                                            const int compare = QString::localeAwareCompare(leftName.toString(), rightName.toString());
                                
                                            if(compare != 0) {
                                                return compare < 0;
                                            }
                                        }
                                        else if (isLeftDir)
                                        {
                                            return true;
                                        }
                                
                                        return false;
                                    }
                                };
                                

                                However, I'm not sure that I'm setting the date format correctly. It can change depending on the OS settings, or am I wrong?

                                Christian EhrlicherC J 2 Replies Last reply 27 Mar 2025, 16:05
                                0
                                • J Jo Jo
                                  27 Mar 2025, 16:02

                                  @JonB Everything worked except for the "Date Modified" column. It turned out that Qt returns this date as a QString. I had to convert this string to QDateTime. Now the code looks like this:

                                  class CustomSortFilterProxyModel : public QSortFilterProxyModel
                                  {
                                      QList<int> m_dtCols{3,4};
                                  public:
                                      explicit CustomSortFilterProxyModel(QObject *parent = nullptr) : QSortFilterProxyModel(parent) {}
                                  
                                  protected:
                                      bool lessThan(const QModelIndex &left, const QModelIndex &right) const override
                                      {
                                          auto model = (QFileSystemModel*)sourceModel();
                                          bool isLeftDir = model->isDir(left);
                                          bool isRightDir = model->isDir(right);
                                  
                                          if ((isLeftDir && isRightDir) || (!isLeftDir && !isRightDir))
                                          {
                                              auto leftName  = model->data(left,  Qt::DisplayRole);
                                              auto rightName = model->data(right, Qt::DisplayRole);
                                  
                                              //return (leftName.toDateTime() < rightName.toDateTime()); // OK, works fine for dates
                                  
                                              if (m_dtCols.contains(sortColumn()))
                                              {
                                                  if (sortColumn() == 3)
                                                  {
                                                      QDateTime dt1 = QDateTime::fromString(leftName.toString(), "M/d/yyyy h:mm AP");
                                                      QDateTime dt2 = QDateTime::fromString(rightName.toString(), "M/d/yyyy h:mm AP");
                                                      return dt1 < dt2;
                                                  }
                                  
                                                  return (leftName.toDateTime() < rightName.toDateTime());
                                              }
                                  
                                              const int compare = QString::localeAwareCompare(leftName.toString(), rightName.toString());
                                  
                                              if(compare != 0) {
                                                  return compare < 0;
                                              }
                                          }
                                          else if (isLeftDir)
                                          {
                                              return true;
                                          }
                                  
                                          return false;
                                      }
                                  };
                                  

                                  However, I'm not sure that I'm setting the date format correctly. It can change depending on the OS settings, or am I wrong?

                                  Christian EhrlicherC Offline
                                  Christian EhrlicherC Offline
                                  Christian Ehrlicher
                                  Lifetime Qt Champion
                                  wrote on 27 Mar 2025, 16:05 last edited by
                                  #16

                                  @Jo-Jo said in Custom sortable columns in QFileSystemModel:

                                  I had to convert this string to QDateTime

                                  You already converted the QVariant to a QDateTime above - so why do you use the way through QString now again?

                                  Qt Online Installer direct download: https://download.qt.io/official_releases/online_installers/
                                  Visit the Qt Academy at https://academy.qt.io/catalog

                                  J 1 Reply Last reply 27 Mar 2025, 16:16
                                  0
                                  • Christian EhrlicherC Christian Ehrlicher
                                    27 Mar 2025, 16:05

                                    @Jo-Jo said in Custom sortable columns in QFileSystemModel:

                                    I had to convert this string to QDateTime

                                    You already converted the QVariant to a QDateTime above - so why do you use the way through QString now again?

                                    J Offline
                                    J Offline
                                    Jo Jo
                                    wrote on 27 Mar 2025, 16:16 last edited by Jo Jo
                                    #17

                                    @Christian-Ehrlicher said in Custom sortable columns in QFileSystemModel:

                                    You already converted the QVariant to a QDateTime above - so why do you use the way through QString now again?

                                    Because "Date Modified" column is created by Qt and Qt using QString for this column. If I convert QVariant to QDateTime, in this case comparison does not work properly

                                    1 Reply Last reply
                                    0
                                    • Christian EhrlicherC Offline
                                      Christian EhrlicherC Offline
                                      Christian Ehrlicher
                                      Lifetime Qt Champion
                                      wrote on 27 Mar 2025, 16:23 last edited by
                                      #18

                                      Then you should debug why ... e.g. with a qDebug() statement as @JonB already wrote some time ago....

                                      Qt Online Installer direct download: https://download.qt.io/official_releases/online_installers/
                                      Visit the Qt Academy at https://academy.qt.io/catalog

                                      1 Reply Last reply
                                      0
                                      • J Jo Jo
                                        27 Mar 2025, 16:02

                                        @JonB Everything worked except for the "Date Modified" column. It turned out that Qt returns this date as a QString. I had to convert this string to QDateTime. Now the code looks like this:

                                        class CustomSortFilterProxyModel : public QSortFilterProxyModel
                                        {
                                            QList<int> m_dtCols{3,4};
                                        public:
                                            explicit CustomSortFilterProxyModel(QObject *parent = nullptr) : QSortFilterProxyModel(parent) {}
                                        
                                        protected:
                                            bool lessThan(const QModelIndex &left, const QModelIndex &right) const override
                                            {
                                                auto model = (QFileSystemModel*)sourceModel();
                                                bool isLeftDir = model->isDir(left);
                                                bool isRightDir = model->isDir(right);
                                        
                                                if ((isLeftDir && isRightDir) || (!isLeftDir && !isRightDir))
                                                {
                                                    auto leftName  = model->data(left,  Qt::DisplayRole);
                                                    auto rightName = model->data(right, Qt::DisplayRole);
                                        
                                                    //return (leftName.toDateTime() < rightName.toDateTime()); // OK, works fine for dates
                                        
                                                    if (m_dtCols.contains(sortColumn()))
                                                    {
                                                        if (sortColumn() == 3)
                                                        {
                                                            QDateTime dt1 = QDateTime::fromString(leftName.toString(), "M/d/yyyy h:mm AP");
                                                            QDateTime dt2 = QDateTime::fromString(rightName.toString(), "M/d/yyyy h:mm AP");
                                                            return dt1 < dt2;
                                                        }
                                        
                                                        return (leftName.toDateTime() < rightName.toDateTime());
                                                    }
                                        
                                                    const int compare = QString::localeAwareCompare(leftName.toString(), rightName.toString());
                                        
                                                    if(compare != 0) {
                                                        return compare < 0;
                                                    }
                                                }
                                                else if (isLeftDir)
                                                {
                                                    return true;
                                                }
                                        
                                                return false;
                                            }
                                        };
                                        

                                        However, I'm not sure that I'm setting the date format correctly. It can change depending on the OS settings, or am I wrong?

                                        J Offline
                                        J Offline
                                        JonB
                                        wrote on 27 Mar 2025, 18:50 last edited by
                                        #19

                                        @Jo-Jo said in Custom sortable columns in QFileSystemModel:

                                        Everything worked except for the "Date Modified" column. It turned out that Qt returns this date as a QString.

                                        I am surprised at this, but untested. You are now talking about a "Date Modified" column inbuilt into QFileSystemModel, and not the "creation date" column you added for your birthTime()? But that is QDateTime QFileSystemModel::lastModified(). So I don't understand where you are getting any string for a datetime which you need to convert.

                                        J 1 Reply Last reply 28 Mar 2025, 10:45
                                        0
                                        • J JonB
                                          27 Mar 2025, 18:50

                                          @Jo-Jo said in Custom sortable columns in QFileSystemModel:

                                          Everything worked except for the "Date Modified" column. It turned out that Qt returns this date as a QString.

                                          I am surprised at this, but untested. You are now talking about a "Date Modified" column inbuilt into QFileSystemModel, and not the "creation date" column you added for your birthTime()? But that is QDateTime QFileSystemModel::lastModified(). So I don't understand where you are getting any string for a datetime which you need to convert.

                                          J Offline
                                          J Offline
                                          Jo Jo
                                          wrote on 28 Mar 2025, 10:45 last edited by
                                          #20

                                          @JonB said in Custom sortable columns in QFileSystemModel:

                                          You are now talking about a "Date Modified" column inbuilt into QFileSystemModel, and not the "creation date" column you added for your birthTime()?

                                          Yes. This column value is QString, not QDateTime. You may check sources: https://codebrowser.dev/qt5/qtbase/src/widgets/dialogs/qfilesystemmodel.cpp.html#808

                                          J 1 Reply Last reply 28 Mar 2025, 14:49
                                          0

                                          5/23

                                          27 Mar 2025, 13:43

                                          topic:navigator.unread, 18
                                          • Login

                                          • Login or register to search.
                                          5 out of 23
                                          • First post
                                            5/23
                                            Last post
                                          0
                                          • Categories
                                          • Recent
                                          • Tags
                                          • Popular
                                          • Users
                                          • Groups
                                          • Search
                                          • Get Qt Extensions
                                          • Unsolved