PDA

View Full Version : Draging a non-existing file to the Windows Desktop



klaus1111
23rd March 2006, 23:34
Hi,
I have a somewhat sophisticated problem. I want to drag a file out of my application to the windows desktop. This is normally done by setting the drag type to “text/uri-ist” and passing the filename. Fine.

My problem is that in the moment where I start the drag the file does not exist. I want it to create it *after* releasing the mouse button. Why? Because my application is somewhat like a ftp-client. So my application has to download the file, which - depending on the file size - can take a moment. So I can not prepare the file before the user drag it of.

In the first moment this is something witch seems impossible, but there are a number of applications like smartFTP, or WinZIP (they have the same problem - unzipping of a file takes to long to prepare it…) witch solves the problem.

Can someone give me a hint how to start a possible solution?

As the solution are very much related to the Windows Operating System - Perhaps you could also point me to a good Windows related c++ Forum ?

Many thanks in advance,
Klaus

Protocol
4th April 2006, 00:24
During the drag operation, you have to signal to windows to create a temp file. Once the temp file is created (after the user releases the mouse button). Copy the temp file to the location they dropped the file to.

klaus1111
4th April 2006, 09:08
hi,
thanks for your answer. My problem with it is, that I don't know how to find out the location where the file is dropped to. Could you give me a hint how you think I can do that?
Thanks,
Klaus

Protocol
4th April 2006, 19:09
Sure... Luckily windows reconizes certain drag & drop events. So just make sure that you make the drag event trigger a copy || move file command and windows should handle the rest. So you can disregard my last post.

Let me know how it goes. I do MFC programming at work (amongst other TKs).

Chicken Blood Machine
4th April 2006, 20:17
You don't need to create a temporary file and you should be able to implement the solution in a platform transparent way.

You need to subclass QMimeSource and override QMimeData::retrieveData ( const QString & mimetype, QVariant::Type type ).

Use this object when you set the data for your QDrag object.

The method retrieveData() should automatically be called only when the drop is complete. Your override of this method is where you should implement your FTP ('get' it into a QByteArray) and provide the data (return a QVariant created from the QByteArray). The OS should take care of creating the file.

Qt drag and drop has changed quite a lot since Qt3, but in Qt3, what you are proposing is quite easy. I apologize if this turns out to be incorrect, but the instructions above should, (in theory) do what you require.

wysota
4th April 2006, 20:47
The problem is Windows doesn't allow a drop when using uri-list as contents (it shown the "no-drop" stop sign). What contents to put there then for Windows desktop or explorer to allow it?

Chicken Blood Machine
4th April 2006, 22:20
The problem is Windows doesn't allow a drop when using uri-list as contents (it shown the "no-drop" stop sign). What contents to put there then for Windows desktop or explorer to allow it?

Just checking with Drag Queen...you're right. So it does need a platform-specific solution. Take a look at QWindowsMime. I think you may need to provide CF_HDROP as the format.

Protocol
5th April 2006, 15:41
You don't need to create a temporary file and you should be able to implement the solution in a platform transparent way.




So you can disregard my last post.


FYI: The above means to disregard the statement about the temp file.

wysota
5th April 2006, 16:11
Take a look at QWindowsMime. I think you may need to provide CF_HDROP as the format.

Looks promising, but how does one use it?

EDIT:
In our situation it would probably be better to use CF_INETURL as the data dragged is an http url. Anyway we use text/uri-list (as QWindowsMime suggests) but Windows doesn't accept it. Should the conversion be done manually? And if so, then when? On the other hand if the conversion is done automatically by Qt D&D mechanism (and it probably is), why doesn't Explorer accept it? Maybe it just doesn't like remote files? But if so, then we go back to the fact that we can't use a local resource because it doesn't exist yet.

BTW. I think Klaus should continue that discussion and not me :) It works fine under KDE ;)

klaus1111
5th April 2006, 17:41
hey - thanks for everyone. In fact this is a difficult subject.

When I use drop Site (one of the troll examples) to check the mime-type, I see that a normal drag from the explorer is a text/uri-list, which will only work if the file is allready existing, that means, that the pointer in text/uri-list start with file:////....

Nevertheless, when I use SmartFTP, (which has the feature I need), I see that it also draging a text/uri-list, pointing to a temporary file (file:////c:...../temp/SFTPDROP) which does not exist. The mechanism also works if I create this SFTPDROP file in the temp folder.

@protocoll: You said, that you see a possibilty to catch the drop event. Is this a Qt-event or are you talking about an Windows event? Would you be so friendly to give me a little bit more information about how to catch this event?

@chicken blood machine: as far as I understand CF_HDROP has a double \0\0 terminated list of strings with the names of the files. I'm not sure if this helps me, as also this file names has to point somewhere - but perhaps I make a mistake.
In windows there is also the format CFSTR_FILECONTENTS where I could pass a stream to another application, but I'm not shure what happens if I would like to drag more than one file.

Thanks a lot for your time,
Klaus

spud
19th September 2007, 16:57
If anybody's still interested, I think I've found a solution to this problem. For me explorer accepts a uri list, as long as it isn't empty. The problem was finding out when the drag operation has ended. retrieveData() is not only called after the drop.



#include <QtGui>
#include <windows.h>

class WinMimeData : public QMimeData
{
public:
WinMimeData()
: runOnce(true)
{
setUrls(QList<QUrl>()<<QUrl("tmp"));
}

QVariant retrieveData(const QString& mimeType, QVariant::Type type)const
{
// This is surely a hack, but how else do we find out that the drag operation has completed?
if(((unsigned short)GetAsyncKeyState(VK_LBUTTON))>1)
return QMimeData::retrieveData(mimeType, type);

if(runOnce)
{
// Now we create the file:
if(file.open())
{
file.write("Hello!");
file.flush();
}
runOnce=false;
}
return QUrl("/"+file.fileName());
}
private:
// these need to be mutable since retrieveData() is const
mutable QTemporaryFile file;
mutable bool runOnce;
};

class Widget : public QWidget
{
void mousePressEvent(QMouseEvent* event)
{
QDrag *drag = new QDrag(this);
drag->setMimeData(new WinMimeData);
drag->start(Qt::CopyAction);
}
};

int main(int argc, char *argv[])
{
QApplication app(argc, argv);
Widget window;
window.show();
return app.exec();
}

wysota
19th September 2007, 17:21
As far as I remember for me explorer was forbidding dropping an uri-list (containing http data) on the desktop. But it would be nice if the solution you propose worked. I think your solution won't work for files which have to be for example downloaded after the drop (or extracted from some archive). So really this isn't much different to providing an URI to an already existing file - you won't be able to implement unzipping this way, right?

spud
20th September 2007, 01:14
As far as I remember for me explorer was forbidding dropping an uri-list (containing http data) on the desktop. But it would be nice if the solution you propose worked. I think your solution won't work for files which have to be for example downloaded after the drop (or extracted from some archive). So really this isn't much different to providing an URI to an already existing file - you won't be able to implement unzipping this way, right?

I don't think so. In my example the file is actually only created after the drag action has finished. Go ahead and try it if you want. I got the idea by trying to pull a file from winrar to the "drop site" example. During the drag, the drop site reports only an empty list. After you let go of the mouse button winrar starts creating a temporary file and when it's finished drop site reports the newly created temporary file.
Of course it is kind of a hack, and I can't guarantee it will always work. Eventually Qt will have to provide this functionality, but for now I think it could work. It would be nice if somebody tried it out.

wysota
20th September 2007, 12:47
I don't think so. In my example the file is actually only created after the drag action has finished. Go ahead and try it if you want. I got the idea by trying to pull a file from winrar to the "drop site" example. During the drag, the drop site reports only an empty list. After you let go of the mouse button winrar starts creating a temporary file and when it's finished drop site reports the newly created temporary file.

The point is how the file is created. Could you try to check it out with a drop that starts a http download and downloads the file which is then transfered to explorer (I can't do it myself now)?