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
Forum Updated to NodeBB v4.3 + New Features

Custom sortable columns in QFileSystemModel

Scheduled Pinned Locked Moved Unsolved General and Desktop
23 Posts 3 Posters 1.4k 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 Jo Jo

    @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?

    JonBJ Offline
    JonBJ Offline
    JonB
    wrote on 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
    1
    • JonBJ JonB

      @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 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

      JonBJ 1 Reply Last reply
      0
      • J Jo Jo

        @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

        JonBJ Offline
        JonBJ Offline
        JonB
        wrote on 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
        1
        • JonBJ JonB

          @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 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?

          JonBJ 1 Reply Last reply
          0
          • J Jo Jo

            @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?

            JonBJ Offline
            JonBJ Offline
            JonB
            wrote on 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
            1
            • JonBJ JonB

              @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 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();
              }
              
              
              JonBJ 1 Reply Last reply
              0
              • J Jo Jo

                @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();
                }
                
                
                JonBJ Offline
                JonBJ Offline
                JonB
                wrote on 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
                0
                • JonBJ JonB

                  @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 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
                  • JonBJ Offline
                    JonBJ Offline
                    JonB
                    wrote on 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
                    0
                    • JonBJ JonB

                      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 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

                      JonBJ 1 Reply Last reply
                      0
                      • J Jo Jo

                        @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

                        JonBJ Offline
                        JonBJ Offline
                        JonB
                        wrote on 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
                        0
                        • JonBJ JonB

                          @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 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 JonBJ 2 Replies Last reply
                          0
                          • J Jo Jo

                            @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 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
                            0
                            • Christian EhrlicherC Christian Ehrlicher

                              @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 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 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

                                  @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?

                                  JonBJ Offline
                                  JonBJ Offline
                                  JonB
                                  wrote on 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
                                  0
                                  • JonBJ JonB

                                    @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 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

                                    JonBJ 1 Reply Last reply
                                    0
                                    • Christian EhrlicherC Offline
                                      Christian EhrlicherC Offline
                                      Christian Ehrlicher
                                      Lifetime Qt Champion
                                      wrote on last edited by
                                      #21

                                      Thast's why https://doc.qt.io/qt-6/qfilesystemmodel.html#lastModified is there.

                                      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
                                      2
                                      • J Jo Jo

                                        @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

                                        JonBJ Offline
                                        JonBJ Offline
                                        JonB
                                        wrote on last edited by
                                        #22

                                        @Jo-Jo
                                        I now see that, and see from https://codebrowser.dev/qt5/qtbase/src/widgets/dialogs/qfilesystemmodel.cpp.html#737 that it is called in the implementation of QFileSystemModel::data() for column #3, which is what I needed to know.

                                        I also see it is formatted as a string with QLocale::ShortFormat. I don't know what that looks like, I don't know how "precise" it is (e.g. down to, say, milliseconds or likely not?), I don't know what the locale-aware formatting does with it. Putting all these together it would not surprise me if it is unsuitable for sorting, and/or for converting back (accurately) to a datetime/comparing. Whereas the birthTime() you use for your extra column is indeed a datetime type and is suitable.

                                        Hence, as both I and @Christian-Ehrlicher have said, I would use lastModified() just as you use birthDate() for this column in your own code for data() method.

                                        1 Reply Last reply
                                        1
                                        • J Offline
                                          J Offline
                                          Jo Jo
                                          wrote on last edited by
                                          #23

                                          @Christian-Ehrlicher @JonB agree with you guys about lastModified, thanks!

                                          1 Reply Last reply
                                          1

                                          • Login

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