qwindowsmime.cpp: support dropping multiple mail attachments

Only the data for the first file could be reached with the mimetype
application/x-qt-windows-mime;value="FileContents"

To get the data for the other files, setting the lindex field of
the FORMATETC struct is necessary. Provide support for that by
appending ;index=N to the mimetype string.

The Windows API provides no generic way to find out how many of these
are available (the app has to find out by looking into the FILEGROUPDESCRIPTORW
structure, for this particular use case), so these additional mimetypes
are not listed in QMimeData::formats(). However this patch extends
the documentation to mention the feature.

[ChangeLog][Platform Specific Changes][Windows][QMimeData] Add support
for handling dropping of multiple mail attachments, adding ;index=N to
the mimetype string application/x-qt-windows-mime;value="FileContents"

Task-number: QTBUG-17373
Change-Id: I031e477d2357b4e5135d2dcd3e3cf991025715a5
Reviewed-by: Andy Shaw <andy.shaw@digia.com>
Reviewed-by: Friedemann Kleint <Friedemann.Kleint@theqtcompany.com>
This commit is contained in:
David Faure 2014-11-05 16:53:46 +01:00
parent 4c1ea8f72c
commit efbc538587
3 changed files with 32 additions and 6 deletions

View File

@ -106,3 +106,9 @@ if (event->mimeData()->hasColor()) {
... ...
} }
//! [7] //! [7]
//! [8]
application/x-qt-windows-mime;value="FileContents";index=0
application/x-qt-windows-mime;value="FileContents";index=1
//! [8]

View File

@ -286,6 +286,11 @@ QVariant QMimeDataPrivate::retrieveTypedData(const QString &format, QVariant::Ty
The \c value declaration of each format describes the way in which the The \c value declaration of each format describes the way in which the
data is encoded. data is encoded.
In some cases (e.g. dropping multiple email attachments), multiple data
values are available. They can be accessed by adding an \c index value:
\snippet code/src_corelib_kernel_qmimedata.cpp 8
On Windows, the MIME format does not always map directly to the On Windows, the MIME format does not always map directly to the
clipboard formats. Qt provides QWinMime to map clipboard clipboard formats. Qt provides QWinMime to map clipboard
formats to open-standard MIME formats. Similarly, the formats to open-standard MIME formats. Similarly, the

View File

@ -343,10 +343,11 @@ static bool setData(const QByteArray &data, STGMEDIUM *pmedium)
return true; return true;
} }
static QByteArray getData(int cf, IDataObject *pDataObj) static QByteArray getData(int cf, IDataObject *pDataObj, int lindex = -1)
{ {
QByteArray data; QByteArray data;
FORMATETC formatetc = setCf(cf); FORMATETC formatetc = setCf(cf);
formatetc.lindex = lindex;
STGMEDIUM s; STGMEDIUM s;
if (pDataObj->GetData(&formatetc, &s) == S_OK) { if (pDataObj->GetData(&formatetc, &s) == S_OK) {
DWORD * val = (DWORD*)GlobalLock(s.hGlobal); DWORD * val = (DWORD*)GlobalLock(s.hGlobal);
@ -1339,16 +1340,29 @@ static bool isCustomMimeType(const QString &mimeType)
return mimeType.startsWith(QLatin1String(x_qt_windows_mime), Qt::CaseInsensitive); return mimeType.startsWith(QLatin1String(x_qt_windows_mime), Qt::CaseInsensitive);
} }
static QString customMimeType(const QString &mimeType) static QString customMimeType(const QString &mimeType, int *lindex = 0)
{ {
int len = sizeof(x_qt_windows_mime) - 1; int len = sizeof(x_qt_windows_mime) - 1;
int n = mimeType.lastIndexOf(QLatin1Char('\"'))-len; int n = mimeType.lastIndexOf(QLatin1Char('\"')) - len;
return mimeType.mid(len, n); QString ret = mimeType.mid(len, n);
const int beginPos = mimeType.indexOf(QLatin1String(";index="));
if (beginPos > -1) {
const int endPos = mimeType.indexOf(QLatin1Char(';'), beginPos + 1);
const int indexStartPos = beginPos + 7;
if (lindex)
*lindex = mimeType.midRef(indexStartPos, endPos == -1 ? endPos : endPos - indexStartPos).toInt();
} else {
if (lindex)
*lindex = -1;
}
return ret;
} }
bool QLastResortMimes::canConvertToMime(const QString &mimeType, IDataObject *pDataObj) const bool QLastResortMimes::canConvertToMime(const QString &mimeType, IDataObject *pDataObj) const
{ {
if (isCustomMimeType(mimeType)) { if (isCustomMimeType(mimeType)) {
// MSDN documentation for QueryGetData says only -1 is supported, so ignore lindex here.
QString clipFormat = customMimeType(mimeType); QString clipFormat = customMimeType(mimeType);
int cf = RegisterClipboardFormat(reinterpret_cast<const wchar_t *> (clipFormat.utf16())); int cf = RegisterClipboardFormat(reinterpret_cast<const wchar_t *> (clipFormat.utf16()));
return canGetData(cf, pDataObj); return canGetData(cf, pDataObj);
@ -1369,9 +1383,10 @@ QVariant QLastResortMimes::convertToMime(const QString &mimeType, IDataObject *p
if (canConvertToMime(mimeType, pDataObj)) { if (canConvertToMime(mimeType, pDataObj)) {
QByteArray data; QByteArray data;
if (isCustomMimeType(mimeType)) { if (isCustomMimeType(mimeType)) {
QString clipFormat = customMimeType(mimeType); int lindex;
QString clipFormat = customMimeType(mimeType, &lindex);
int cf = RegisterClipboardFormat(reinterpret_cast<const wchar_t *> (clipFormat.utf16())); int cf = RegisterClipboardFormat(reinterpret_cast<const wchar_t *> (clipFormat.utf16()));
data = getData(cf, pDataObj); data = getData(cf, pDataObj, lindex);
} else if (formats.keys(mimeType).isEmpty()) { } else if (formats.keys(mimeType).isEmpty()) {
int cf = QWindowsMime::registerMimeType(mimeType); int cf = QWindowsMime::registerMimeType(mimeType);
data = getData(cf, pDataObj); data = getData(cf, pDataObj);