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.
  • 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 Online
      JonBJ Online
      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 Online
                JonBJ Online
                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 Online
                      JonBJ Online
                      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