Reputation: 7974
I have a simple file handling widget which can copy/cut/paste selected files from/to clipboard. I would like to be able to exchange files using these commands between this widget and Windows Explorer (potentially other file managers such as Total Commander or Free Commander). I already found that I can store the file names to the clipboard as QList<QUrl>
using QMimeData::setUrls()
and restore them similarly. This way I am able to copy and paste between my widget and the above mentioned file managers because they seem to use the same format for storing file names. But I do not know how to cut items to clipboard (i.e. delete after the file is pasted). I assume that the receiver (the application which pastes the data) is responsible for deleting the cut files. In that case it must be somehow encoded in the clipboard data, that the files have been cut rather than copied, this information can be retrieved by the receiving application. How is this done? Or is there any other way? I know this is possible because this works perfectly between Windows Explorer and Free Commander. I.e. when you cut files in Window Explorer and paste them to Free Commander, the original file is deleted and vice versa.
UPDATE:
I found there is also another part of MIME data "Preferred DropEffect"
which can have value of 5
(copy) or 2
(cut). When I set the QByteArray
to 4 bytes which correspond to an integer of value 5
or 2
, I can distinguish whether Windows Explorer initiated cut or copy. If it is cut, then I can move the file rather than copy. It works well. Unfortunately this still works one way only from Windows Explorer to Qt application. I still have not found why the opposite direction does not work. There are also some other MIME data which are however hard to decode for me. Maybe there is the key.
UPDATE 2: Mimimal code to reproduce the behvaiour is here. Make sure the file hardcoded in the program exists. Try to run the program and after closing the window open open Windows Explorer go to arbitrary folder where you can write and press Ctrl+V... Then the copy of the file should appear in that directory but it is not deleted from the source directory. The program below uses constant 2 which means cut rather than copy which means the original file should disappear.
#include <QApplication>
#include <QClipboard>
#include <QDataStream>
#include <QMimeData>
#include <QUrl>
#include <QWidget>
int main(int argc, char *argv[])
{
QApplication application(argc, argv);
auto mimeData = new QMimeData;
// store the URL to files which I want to cut
QList<QUrl> urls;
urls.append(QUrl::fromLocalFile("C:/mypath/myfile.txt")); // use your path or make sure this file exist
mimeData->setUrls(urls);
// store drop effect indicating whether I want to cut or copy
int dropEffect = 2; // 2 for cut and 5 for copy
QByteArray data;
QDataStream stream(&data, QIODevice::WriteOnly);
stream << dropEffect;
mimeData->setData("Preferred DropEffect", data);
QApplication::clipboard()->setMimeData(mimeData);
QWidget window;
window.show();
return application.exec();
}
See also How to programmatically cut/copy/get files to/from the Windows clipboard in a system standard compliant form? and https://msdn.microsoft.com/en-us/library/windows/desktop/bb776904(v=vs.85).aspx#delete_on_paste
Upvotes: 4
Views: 2411
Reputation: 7974
It seems I found the answer. The byte order was wrong, it has to be little Endian for some reason (the default order in Qt is big Endian). So the code in the example should be:
QByteArray data;
QDataStream stream(&data, QIODevice::WriteOnly);
stream.setByteOrder(QDataStream::LittleEndian);
stream << dropEffect;
This way other file managers are able to interoperate using copy/cut and paste with my Qt application. The reversal process of decoding the clipboard contents is left to the reader (it is not difficult, just reverse the operations done to encode the data to clipboard). Of course it is also necessary to handle copying or moving/deleting of the files which is much more work but it is straightforward.
So I was wrong, I was actually looking for a bug... Thanks to scopchanov for forcing me to write the minimal code! :)
Upvotes: 2