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

QFileSystemModel drop items issue

Scheduled Pinned Locked Moved Solved General and Desktop
9 Posts 2 Posters 628 Views 1 Watching
  • 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.
  • Cobra91151C Offline
    Cobra91151C Offline
    Cobra91151
    wrote on last edited by
    #1

    Hello! I have a QTreeView and QListView which uses QFileSystemModels and I want to implement drag and drop between those views. I already implemented dropMimeData between those views only for QClipboard operations. I have some questions.

    1. Any ideas how to implement it for drag and drops (what exactly should be reimplemented, some example)?
    2. When move or copy files from one location to another (names are unique) dropMimeData returns false (and I think no operation is done), the same for QFile::copy and CopyFile (WinAPI) methods. How to fix it?
    3. Coping big files using dropMimeData freezes main GUI, the same for deleting big files using model->remove. Is there any option to enable threading or other techniques?
    4. dropMimeData return false for Qt::CopyAction the dirs. How to fix it?

    Thanks in advance for your help.

    1 Reply Last reply
    0
    • Cobra91151C Offline
      Cobra91151C Offline
      Cobra91151
      wrote on last edited by
      #9

      Hello!

      I have fixed the issue by reimplementing the QFileSystemModel and using the native Win API method - SHFileOperationW. It displays the progress dialog and allows to transfer big files without program freeze.
      The issue is resolved.

      1 Reply Last reply
      2
      • SGaistS Offline
        SGaistS Offline
        SGaist
        Lifetime Qt Champion
        wrote on last edited by
        #2

        Hi,

        There's a whole chapter of that here

        Interested in AI ? www.idiap.ch
        Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

        Cobra91151C 1 Reply Last reply
        1
        • SGaistS SGaist

          Hi,

          There's a whole chapter of that here

          Cobra91151C Offline
          Cobra91151C Offline
          Cobra91151
          wrote on last edited by
          #3

          @SGaist

          Ok. I will check it. Thanks.

          1 Reply Last reply
          0
          • Cobra91151C Offline
            Cobra91151C Offline
            Cobra91151
            wrote on last edited by Cobra91151
            #4

            Hello!

            I have reimplemented QFileSystemModel class to add the drag and drop feature between QTreeView and QListView but it still does not work. It displays the following dialog:

            image1

            #ifndef EXPLORERMODEL_H
            #define EXPLORERMODEL_H
            
            #include <QObject>
            #include <QFileSystemModel>
            #include <QMimeData>
            #include <QBrush>
            #include <QDebug>
            
            class ExplorerModel : public QFileSystemModel
            {
                Q_OBJECT
            public:
                using QFileSystemModel::QFileSystemModel;
                Qt::DropActions supportedDragActions() const;
                Qt::DropActions supportedDropActions() const;
                Qt::ItemFlags flags(const QModelIndex &index) const;
                QStringList mimeTypes() const;
                QMimeData *mimeData(const QModelIndexList &indexes) const;
                bool dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent);
            
            private:
                bool canDropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent);
            };
            
            #endif // EXPLORERMODEL_H
            
            #include "explorermodel.h"
            
            Qt::DropActions ExplorerModel::supportedDragActions() const
            {
               return Qt::CopyAction | Qt::MoveAction;
            }
            
            Qt::DropActions ExplorerModel::supportedDropActions() const
            {
                return Qt::CopyAction | Qt::MoveAction;
            }
            
            Qt::ItemFlags ExplorerModel::flags(const QModelIndex &index) const
            {
                Qt::ItemFlags defaultFlags = QFileSystemModel::flags(index);
            
                if (index.isValid()) {
                    return Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled | defaultFlags;
                } else {
                    return Qt::ItemIsDropEnabled | defaultFlags;
                }
            }
            
            QStringList ExplorerModel::mimeTypes() const
            {
                QStringList types;
                types << "application/octet-stream";
                return types;
            }
            
            QMimeData *ExplorerModel::mimeData(const QModelIndexList &indexes) const
            {
                QMimeData *mimeData = new QMimeData;
                QByteArray encodedData;
                QDataStream stream(&encodedData, QIODevice::WriteOnly);
            
                for (const QModelIndex &index : indexes) {
                    if (index.isValid()) {
                        QString text = data(index, Qt::DisplayRole).toString();
                        stream << text;
                    }
                }
            
                mimeData->setData("application/octet-stream", encodedData);
                return mimeData;
            }
            
            bool ExplorerModel::canDropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent)
            {
                Q_UNUSED(action);
                Q_UNUSED(row);
                Q_UNUSED(parent);
            
                qDebug() << data->formats();
            
                if (!data->hasFormat("application/octet-stream")) {
                    return false;
                }
            
                if (column > 0) {
                    return false;
                }
            
                return true;
            }
            
            bool ExplorerModel::dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent)
            {
                if (!canDropMimeData(data, action, row, column, parent)) {
                    qDebug() << "Test...";
                    return false;
                }
            
                if (action == Qt::IgnoreAction) {
                    return true;
                }
            
                int beginRow;
            
                if (row != -1) {
                    beginRow = row;
                } else if (parent.isValid()) {
                    beginRow = parent.row();
                } else {
                    beginRow = rowCount(QModelIndex());
                }
            
                QByteArray encodedData = data->data("application/octet-stream");
                QDataStream stream(&encodedData, QIODevice::ReadOnly);
                QStringList newItems;
                int rows = 0;
            
                while (!stream.atEnd()) {
                   QString text;
                   stream >> text;
                   newItems << text;
                   ++rows;
                }
            
                insertRows(beginRow, rows, QModelIndex());
            
                for (const QString &text : qAsConst(newItems)) {
                    QModelIndex idx = index(beginRow, 0, QModelIndex());
                    setData(idx, text);
                    beginRow++;
                }
            
                return true;
            }
            

            When droping simple .txt file from TreeView to the ListView.

            ("application/octet-stream")
            QModelIndex(2,0,0x2ad605a4350,ExplorerModel(0x2ad604e4cd0))  |  "New Text Document.txt"
            QModelIndex(3,0,0x2ad605a41c0,ExplorerModel(0x2ad604e4cd0))  |  "17 bytes"
            QModelIndex(-1,-1,0x0,QObject(0x0))  |  "txt File"
            QModelIndex(-1,-1,0x0,QObject(0x0))  |  "2/10/2021 10:57 PM"
            

            It does not copy or move items. Any ideas how to fix it? Thanks.

            1 Reply Last reply
            0
            • Cobra91151C Offline
              Cobra91151C Offline
              Cobra91151
              wrote on last edited by Cobra91151
              #5

              I have found out that the problem is in the dropMimeData method. So, I have changed it to:

              bool ExplorerModel::dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent)
              {
                  if (!canDropMimeData(data, action, row, column, parent)) {
                      return false;
                  }
              
                  if (action == Qt::IgnoreAction) {
                      return true;
                  }
              
                  int beginRow;
              
                  if (row != -1) {
                      beginRow = row;
                  } else if (parent.isValid()) {
                      beginRow = parent.row();
                  } else {
                      beginRow = rowCount(QModelIndex());
                  }
              
                  removeRow(row, parent);
                  insertRow(beginRow, parent);
                  QModelIndex idx = index(beginRow, 0, QModelIndex());
                  setData(idx, data);
                  return true;
              }
              

              Now, it displays:
              2021-02-11_005901.png

              1 Reply Last reply
              0
              • Cobra91151C Offline
                Cobra91151C Offline
                Cobra91151
                wrote on last edited by
                #6

                So, now I changed 2 methods:

                QMimeData *ExplorerModel::mimeData(const QModelIndexList &indexes) const
                {
                    QMimeData *mimeData = new QMimeData;
                    QByteArray encodedData;
                    QDataStream stream(&encodedData, QIODevice::WriteOnly);
                
                    if (indexes.first().isValid()) {
                        QString text = data(indexes.first(), Qt::DisplayRole).toString();
                        qDebug() << text;
                        stream << text;
                    }
                
                    mimeData->setData("application/octet-stream", encodedData);
                    return mimeData;
                }
                
                bool ExplorerModel::dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent)
                {
                    if (!canDropMimeData(data, action, row, column, parent)) {
                        return false;
                    }
                
                    if (action == Qt::IgnoreAction) {
                        return true;
                    }
                
                    int beginRow;
                
                    if (row != -1) {
                        beginRow = row;
                    } else if (parent.isValid()) {
                        beginRow = parent.row();
                    } else {
                        beginRow = rowCount(QModelIndex());
                    }
                
                    QByteArray encodedData = data->data("application/octet-stream");
                    QDataStream stream(&encodedData, QIODevice::ReadOnly);
                    QString text;
                
                    while (!stream.atEnd()) {
                        stream >> text;
                    }
                
                    //removeRow(row, parent);
                    insertRow(beginRow, parent);
                    QModelIndex idx = index(beginRow, 0, QModelIndex());
                    setData(idx, text);
                    return true;
                }
                

                It fixed the issue with the wrong indexes which lead to the incorrect name. But it still displays this notification:

                invalid_filename.gif

                Any ideas what could cause such issue? Thanks.

                1 Reply Last reply
                0
                • Cobra91151C Offline
                  Cobra91151C Offline
                  Cobra91151
                  wrote on last edited by
                  #7

                  I have added the setData method:

                  bool ExplorerModel::setData(const QModelIndex &index, const QVariant &value, int role)
                  {
                      qDebug() << "setData....";
                      emit dataChanged(index, index, {Qt::UserRole});
                      return QFileSystemModel::setData(index, value, role);
                  }
                  

                  Now, it does not display any message, but still the file is not copied/moved.

                  1 Reply Last reply
                  0
                  • Cobra91151C Offline
                    Cobra91151C Offline
                    Cobra91151
                    wrote on last edited by
                    #8

                    I have found the solution. There is no need to override all those methods, but only one.

                    Code:

                    Qt::ItemFlags ExplorerModel::flags(const QModelIndex &index) const
                    {
                        Qt::ItemFlags defaultFlags = QFileSystemModel::flags(index);
                    
                        if (!index.isValid()) {
                            return defaultFlags;
                        }
                    
                        const QFileInfo &fileInfo = this->fileInfo(index);
                    
                        if (fileInfo.isDir()) { // The target
                            // allowed drop
                            return Qt::ItemIsDropEnabled | defaultFlags;
                        } else if (fileInfo.isFile()) { // The source: should be directory (in that case)
                            // allowed drag
                            return Qt::ItemIsDragEnabled | defaultFlags;
                        }
                    
                        return defaultFlags;
                    }
                    

                    Screenshot:
                    example_1.gif

                    Now, it copies the files successfully. But there is another issue, when the file size is >= 1 GB the program freezes. Is there any way to enable the threading for copy/cut operation or display the progress dialog in the model? Thank you.

                    1 Reply Last reply
                    2
                    • Cobra91151C Offline
                      Cobra91151C Offline
                      Cobra91151
                      wrote on last edited by
                      #9

                      Hello!

                      I have fixed the issue by reimplementing the QFileSystemModel and using the native Win API method - SHFileOperationW. It displays the progress dialog and allows to transfer big files without program freeze.
                      The issue is resolved.

                      1 Reply Last reply
                      2

                      • Login

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