Handling drag'n'drop of files in Qt under OS X

November 2015 · 2 minute read

If you ever tried to handle drag’n’drop files in your Qt application, you would usually come up with the code like the following.

First of all you will need a Drop Area somewhere in your application, which will handle drops

DropArea {
  anchors.fill: parent
  onDropped: {
    if (drop.hasUrls) {
      var filesCount = yourCppModel.dropFiles(drop.urls)
      console.log(filesCount + ' files added via drag&drop')
    }
 }
}

Where yourCppModel is a model exposed to Qml in main.cpp or wherever like this:

QQmlContext *rootContext = engine.rootContext();
rootContext->setContextProperty("yourCppModel", &myCppModel);

and int dropFiles(const QList<QUrl> &urls) is just an ordinary method exposed to QML via Q_INVOKABLE attribute.

You will sure notice everything works fine unless you’re working under OS X. In OS X instead of QUrls to local files you will get something like this: _ file:///.file/id=6571367.2773272/_. There’s a bug in Qt for that and it even looks closed, but it still doesn’t work for me that’s why I’ve implemented my own helper using mixing of Objective-C and Qt-C++ code.

I’ve added a osxnshelper.h and osxnshelper.mm source file with helper method to my project:

#include <Foundation/Foundation.h>
#include <QUrl>

QUrl fromNSUrl(const QUrl &url) {
    NSURL *nsUrl = url.toNSURL();
    NSString *path = nsUrl.path;

    QString qtString = QString::fromNSString(path);
    return QUrl::fromLocalFile(qtString);
}

and added it into the .pro file with conditional define:

macx {
OBJECTIVE_SOURCES += \
    osxnsurlhelper.mm

LIBS += -framework Foundation
HEADERS += osxnsurlhelper.h
}

Now I’m able to use this helper in my actual dropFiles() method:

int MySuperCppModel::dropFiles(const QList<QString> &urls)
{
    QList<QString> localUrls;

#ifdef Q_OS_MAC
    foreach (const QUrl &url, urls) {
        QUrl localUrl = fromNSUrl(url);
        localUrls.append(localUrl);
    }
#else
    localUrls = urls;
#endif
    // ......
}

That’s it. Now it works perfectly.

Share: 
Buy me a coffeeBuy me a coffee
comments powered by Disqus