Tutorial :Qt 4.x: how to implement drag-and-drop onto the desktop or into a folder?



Question:

I've written a little file-transfer application written in C++ using Qt 4.x ... it logs into a server, shows the user a list of files available on the server, and lets the user upload or download files.

This all works fine; you can even drag a file in from the desktop (or from an open folder), and when you drop the file icon into the server-files-list-view, the dropped file gets uploaded to the server.

Now I have a request for the opposite action as well... my users would like to be able to drag a file out of the server-files-list-view and onto the desktop, or into an open folder window, and have that file get downloaded into that location.

That seems like a reasonable request, but I don't know how to implement it. Is there a way for a Qt application to find out the directory corresponding to where "drop event" occurred, when the icon was dropped onto the desktop or into an open folder window? Ideally this would be a Qt-based platform-neutral mechanism, but if that doesn't exist, then platform-specific mechanisms for MacOS/X and Windows (XP or higher) would suffice.

Any ideas?


Solution:1

Look at QMimeData and its documentation, it has a virtual function

virtual QVariant retrieveData  ( const QString & mimetype, QVariant::Type type ) const  

this means to do you drag to the outside you implement this functions accordingly

class DeferredMimeData : public QMimeData  {    DeferredMimeData(QString downloadFilename) : m_filename(downloadFilename)      virtual QVariant retrieveData (const QString & mimetype, QVariant::Type type) const     {      if (mimetype matches expected && type matches expected)      {         perform download with m_filename      }    }  }  

The delayed encoding examples shows this principle.

You will probably also have to override hasFormat and formats to provide the appropriate types, application/octet-stream probably being the one that might get you the most play, you will probably have to read up on how windows specifically handles drag and drop using mime types.

I don't know how you will supply the file name under which the file is saved, but you will probably have to get into the windows side of things. Looking at the source of QWindowsMime might also help. There might me a multiple step process where you will get requests for text/uri-list data for the filenames and then application/octet-stream for the data.

Hope this helps


Solution:2

I think you are going about that in the wrong way.

You don't care where the drop goes to, you just know it was dropped. In the DropEvent, download the file to a temporary location and then set the mime data to be what was downloaded. Granted this may end up with a second copy to the hard drive, it will be cross platform from the start. You may be able to optimize it afterward with platform specific calls.

Take a look at Dropsite example to see how the mime data works from other sources...

Edit:

It looks like the double copy method is the standard if you don't write a shell extension (for windows at least). Filezilla and 7zip both do that, they return a "text/uri-list" mime type with a temp location. This way explorer copies the data from the temp location to the real one. Your application can do the same, create a temp file (or just the name) with no data. Using the delayed encoding example, create the data on the drop. This whole operation is very platform specific it appears. On Linux (running KDE) I can drag and drop just based on mime type. It appears that windows is not as flexible.


Solution:3

You just implement the drag part. You don't need to know where the drop happen because the application receiving it will handle it and decide where to store your file.

You create a QMimeData, not sure which type but from what i saw here and here, maybe "application/octet-stream" with your file as data in a QByteArray or "text/uri-list" with url to your file.

You create a QDrag, and use its setMimeData() method and exec() (not sure about which QT::DropAction to choose).

Here is an example (disclamer : i did it with color not files) :

void DraggedWidget::mousePressEvent(QMouseEvent *event)  {      if (event->button() == Qt::LeftButton)          start_pos = event->pos();  }    void DraggedWidget::mouseMoveEvent(QMouseEvent *event)  {          if (event->buttons() & Qt::LeftButton) {          int distance = (event->pos() - start_pos).manhattanLength();          if (distance >= QApplication::startDragDistance())          {              /* Drag */              QMimeData *mime_data = new QMimeData;                mime_data->setData( ... );                QDrag *drag = new QDrag(this);              drag->setMimeData(mime_data);              drag->exec(Qt::CopyAction);          }      }  }  

Sorry it's quite incomplete, i hope it helps a little.


Note:If u also have question or solution just comment us below or mail us on toontricks1994@gmail.com
Previous
Next Post »