QMacMime API cleanup: use uti instead of flavor

Update documentation.

Task-number: QTBUG-93632
Change-Id: I69a57608ba2a06211e89fcf511bc582509c00dc4
Reviewed-by: Timur Pocheptsov <timur.pocheptsov@qt.io>
bb10
Volker Hilsheimer 2022-11-03 12:57:42 +01:00
parent 9f35db2a8a
commit 2c54086317
6 changed files with 306 additions and 284 deletions

View File

@ -34,58 +34,55 @@ using namespace Qt::StringLiterals;
//#define DEBUG_MIME_MAPS
/*!
\class QMacMime
\internal
\brief The QMacMime class converts between a MIME type and a
\l{http://developer.apple.com/macosx/uniformtypeidentifiers.html}{Uniform
Type Identifier (UTI)} format.
\since 4.2
\class QMacMime
\internal
\brief The QMacMime class converts between a MIME type and a
\l{https://developer.apple.com/documentation/uniformtypeidentifiers}
{Uniform Type Identifier (UTI)} format.
\since 4.2
\ingroup draganddrop
\inmodule QtWidgets
\ingroup draganddrop
\inmodule QtGui
Qt's drag and drop and clipboard facilities use the MIME
standard. On X11, this maps trivially to the Xdnd protocol. On
Mac, although some applications use MIME to describe clipboard
contents, it is more common to use Apple's UTI format.
Qt's drag and drop and clipboard facilities use the MIME
standard. On X11, this maps trivially to the Xdnd protocol. On
Mac, although some applications use MIME to describe clipboard
contents, it is more common to use Apple's UTI format.
QMacMime's role is to bridge the gap between MIME and UTI;
By subclasses this class, one can extend Qt's drag and drop
and clipboard handling to convert to and from unsupported, or proprietary, UTI formats.
QMacMime's role is to bridge the gap between MIME and UTI;
By subclasses this class, one can extend Qt's drag and drop
and clipboard handling to convert to and from unsupported, or proprietary, UTI formats.
A subclass of QMacMime will automatically be registered, and active, upon instantiation.
A subclass of QMacMime will automatically be registered, and active, upon instantiation.
Qt has predefined support for the following UTIs:
\list
\li public.utf8-plain-text - converts to "text/plain"
\li public.utf16-plain-text - converts to "text/plain"
\li public.text - converts to "text/plain"
\li public.html - converts to "text/html"
\li public.url - converts to "text/uri-list"
\li public.file-url - converts to "text/uri-list"
\li public.tiff - converts to "application/x-qt-image"
\li public.vcard - converts to "text/plain"
\li com.apple.traditional-mac-plain-text - converts to "text/plain"
\li com.apple.pict - converts to "application/x-qt-image"
\endlist
Qt has predefined support for the following UTIs:
\list
\li public.utf8-plain-text - converts to "text/plain"
\li public.utf16-plain-text - converts to "text/plain"
\li public.text - converts to "text/plain"
\li public.html - converts to "text/html"
\li public.url - converts to "text/uri-list"
\li public.file-url - converts to "text/uri-list"
\li public.tiff - converts to "application/x-qt-image"
\li public.vcard - converts to "text/plain"
\li com.apple.traditional-mac-plain-text - converts to "text/plain"
\li com.apple.pict - converts to "application/x-qt-image"
\endlist
When working with MIME data, Qt will iterate through all instances of QMacMime to
find an instance that can convert to, or from, a specific MIME type. It will do this by calling
canConvert() on each instance, starting with (and choosing) the last created instance first.
The actual conversions will be done by using convertToMime() and convertFromMime().
\note The API uses the term "flavor" in some cases. This is for backwards
compatibility reasons, and should now be understood as UTIs.
When working with MIME data, Qt will iterate through all instances of QMacMime to
find an instance that can convert to, or from, a specific MIME type. It will do this by calling
canConvert() on each instance, starting with (and choosing) the last created instance first.
The actual conversions will be done by using convertToMime() and convertFromMime().
*/
/*
\enum QMacMime::QMacMimeType
/*!
\enum QMacMime::HandlerScope
\internal
*/
/*
Constructs a new conversion object of type \a scope, adding it to the
globally accessed list of available converters.
/*!
Constructs a new conversion object of type \a scope, adding it to the
globally accessed list of available converters.
*/
QMacMime::QMacMime(HandlerScope scope)
: m_scope(scope)
@ -93,26 +90,26 @@ QMacMime::QMacMime(HandlerScope scope)
QMacMimeRegistry::registerMimeConverter(this);
}
/*
Constructs a new conversion object and adds it to the
globally accessed list of available converters.
/*!
Constructs a new conversion object and adds it to the
globally accessed list of available converters.
*/
QMacMime::QMacMime()
: QMacMime(HandlerScope::All)
{
}
/*
Destroys a conversion object, removing it from the global
list of available converters.
/*!
Destroys a conversion object, removing it from the global
list of available converters.
*/
QMacMime::~QMacMime()
{
QMacMimeRegistry::unregisterMimeConverter(this);
}
/*
Returns the item count for the given \a mimeData
/*!
Returns the item count for the given \a mimeData
*/
int QMacMime::count(const QMimeData *mimeData) const
{
@ -120,18 +117,73 @@ int QMacMime::count(const QMimeData *mimeData) const
return 1;
}
/*
\fn bool QMacMime::canConvert(const QString &mime, QString uti)
Returns \c true if the converter can convert (both ways) between
\a mime and \a uti; otherwise returns \c false.
All subclasses must reimplement this pure virtual function.
*/
/*
\fn QString QMacMime::mimeForUti(QString uti)
Returns the MIME UTI used for Mac uti \a uti, or an empty string if
this converter does not support \a uti.
All subclasses must reimplement this pure virtual function.
*/
/*
\fn QString QMacMime::utiForMime(const QString &mime)
Returns the Mac UTI used for MIME type \a mime, or an empty string if
this converter does not support \a mime.
All subclasses must reimplement this pure virtual function.
*/
/*
\fn QVariant QMacMime::convertToMime(const QString &mime,
const QList<QByteArray> &data, const QString &uti)
Returns \a data converted from Mac UTI \a uti to MIME type \a mime.
Note that Mac UTIs must all be self-terminating. The input \a data
may contain trailing data.
All subclasses must reimplement this pure virtual function.
*/
/*
\fn QList<QByteArray> QMacMime::convertFromMime(const QString &mime,
const QVariant &data, const QString & uti)
Returns \a data converted from MIME type \a mime to Mac UTI \a uti.
Note that Mac UTIs must all be self-terminating. The return
value may contain trailing data.
All subclasses must reimplement this pure virtual function.
*/
class QMacMimeAny : public QMacMime {
public:
QMacMimeAny() : QMacMime(HandlerScope::AllCompatible) {}
QString flavorForMime(const QString &mime) const override;
QString mimeForFlavor(const QString &flav) const override;
bool canConvert(const QString &mime, const QString &flav) const override;
QVariant convertToMime(const QString &mime, const QList<QByteArray> &data, const QString &flav) const override;
QList<QByteArray> convertFromMime(const QString &mime, const QVariant &data, const QString &flav) const override;
QString utiForMime(const QString &mime) const override;
QString mimeForUti(const QString &uti) const override;
bool canConvert(const QString &mime, const QString &uti) const override;
QVariant convertToMime(const QString &mime, const QList<QByteArray> &data,
const QString &uti) const override;
QList<QByteArray> convertFromMime(const QString &mime, const QVariant &data,
const QString &uti) const override;
};
QString QMacMimeAny::flavorForMime(const QString &mime) const
QString QMacMimeAny::utiForMime(const QString &mime) const
{
// do not handle the mime type name in the drag pasteboard
if (mime == "application/x-qt-mime-type-name"_L1)
@ -140,20 +192,21 @@ QString QMacMimeAny::flavorForMime(const QString &mime) const
return ret.replace(u'/', "--"_L1);
}
QString QMacMimeAny::mimeForFlavor(const QString &flav) const
QString QMacMimeAny::mimeForUti(const QString &uti) const
{
const QString any_prefix = "com.trolltech.anymime."_L1;
if (flav.size() > any_prefix.length() && flav.startsWith(any_prefix))
return flav.mid(any_prefix.length()).replace("--"_L1, "/"_L1);
if (uti.size() > any_prefix.length() && uti.startsWith(any_prefix))
return uti.mid(any_prefix.length()).replace("--"_L1, "/"_L1);
return QString();
}
bool QMacMimeAny::canConvert(const QString &mime, const QString &flav) const
bool QMacMimeAny::canConvert(const QString &mime, const QString &uti) const
{
return mimeForFlavor(flav) == mime;
return mimeForUti(uti) == mime;
}
QVariant QMacMimeAny::convertToMime(const QString &mime, const QList<QByteArray> &data, const QString &) const
QVariant QMacMimeAny::convertToMime(const QString &mime, const QList<QByteArray> &data,
const QString &) const
{
if (data.count() > 1)
qWarning("QMacMimeAny: Cannot handle multiple member data");
@ -165,7 +218,8 @@ QVariant QMacMimeAny::convertToMime(const QString &mime, const QList<QByteArray>
return ret;
}
QList<QByteArray> QMacMimeAny::convertFromMime(const QString &mime, const QVariant &data, const QString &) const
QList<QByteArray> QMacMimeAny::convertFromMime(const QString &mime, const QVariant &data,
const QString &) const
{
QList<QByteArray> ret;
if (mime == "text/plain"_L1)
@ -181,21 +235,21 @@ private:
public:
QMacMimeTypeName(): QMacMime(HandlerScope::AllCompatible) {}
QString flavorForMime(const QString &mime) const override;
QString mimeForFlavor(const QString &flav) const override;
bool canConvert(const QString &mime, const QString &flav) const override;
QVariant convertToMime(const QString &mime, const QList<QByteArray> &data, const QString &flav) const override;
QList<QByteArray> convertFromMime(const QString &mime, const QVariant &data, const QString &flav) const override;
QString utiForMime(const QString &mime) const override;
QString mimeForUti(const QString &uti) const override;
bool canConvert(const QString &mime, const QString &uti) const override;
QVariant convertToMime(const QString &mime, const QList<QByteArray> &data, const QString &uti) const override;
QList<QByteArray> convertFromMime(const QString &mime, const QVariant &data, const QString &uti) const override;
};
QString QMacMimeTypeName::flavorForMime(const QString &mime) const
QString QMacMimeTypeName::utiForMime(const QString &mime) const
{
if (mime == "application/x-qt-mime-type-name"_L1)
return u"com.trolltech.qt.MimeTypeName"_s;
return QString();
}
QString QMacMimeTypeName::mimeForFlavor(const QString &) const
QString QMacMimeTypeName::mimeForUti(const QString &) const
{
return QString();
}
@ -221,40 +275,42 @@ QList<QByteArray> QMacMimeTypeName::convertFromMime(const QString &, const QVari
class QMacMimePlainTextFallback : public QMacMime
{
public:
QString flavorForMime(const QString &mime) const override;
QString mimeForFlavor(const QString &flav) const override;
bool canConvert(const QString &mime, const QString &flav) const override;
QVariant convertToMime(const QString &mime, const QList<QByteArray> &data, const QString &flav) const override;
QList<QByteArray> convertFromMime(const QString &mime, const QVariant &data, const QString &flav) const override;
QString utiForMime(const QString &mime) const override;
QString mimeForUti(const QString &uti) const override;
bool canConvert(const QString &mime, const QString &uti) const override;
QVariant convertToMime(const QString &mime, const QList<QByteArray> &data,
const QString &uti) const override;
QList<QByteArray> convertFromMime(const QString &mime, const QVariant &data,
const QString &uti) const override;
};
QString QMacMimePlainTextFallback::flavorForMime(const QString &mime) const
QString QMacMimePlainTextFallback::utiForMime(const QString &mime) const
{
if (mime == "text/plain"_L1)
return "public.text"_L1;
return QString();
}
QString QMacMimePlainTextFallback::mimeForFlavor(const QString &flav) const
QString QMacMimePlainTextFallback::mimeForUti(const QString &uti) const
{
if (flav == "public.text"_L1)
if (uti == "public.text"_L1)
return "text/plain"_L1;
return QString();
}
bool QMacMimePlainTextFallback::canConvert(const QString &mime, const QString &flav) const
bool QMacMimePlainTextFallback::canConvert(const QString &mime, const QString &uti) const
{
return mime == mimeForFlavor(flav);
return mime == mimeForUti(uti);
}
QVariant
QMacMimePlainTextFallback::convertToMime(const QString &mimetype,
const QList<QByteArray> &data, const QString &flavor) const
const QList<QByteArray> &data, const QString &uti) const
{
if (data.count() > 1)
qWarning("QMacMimePlainTextFallback: Cannot handle multiple member data");
if (flavor == "public.text"_L1) {
if (uti == "public.text"_L1) {
// Note that public.text is documented by Apple to have an undefined encoding. From
// testing it seems that utf8 is normally used, at least by Safari on iOS.
const QByteArray &firstData = data.first();
@ -269,11 +325,11 @@ QMacMimePlainTextFallback::convertToMime(const QString &mimetype,
QList<QByteArray>
QMacMimePlainTextFallback::convertFromMime(const QString &, const QVariant &data,
const QString &flavor) const
const QString &uti) const
{
QList<QByteArray> ret;
QString string = data.toString();
if (flavor == "public.text"_L1)
if (uti == "public.text"_L1)
ret.append(string.toUtf8());
return ret;
}
@ -281,14 +337,16 @@ QMacMimePlainTextFallback::convertFromMime(const QString &, const QVariant &data
class QMacMimeUnicodeText : public QMacMime
{
public:
QString flavorForMime(const QString &mime) const override;
QString mimeForFlavor(const QString &flav) const override;
bool canConvert(const QString &mime, const QString &flav) const override;
QVariant convertToMime(const QString &mime, const QList<QByteArray> &data, const QString &flav) const override;
QList<QByteArray> convertFromMime(const QString &mime, const QVariant &data, const QString &flav) const override;
QString utiForMime(const QString &mime) const override;
QString mimeForUti(const QString &uti) const override;
bool canConvert(const QString &mime, const QString &uti) const override;
QVariant convertToMime(const QString &mime, const QList<QByteArray> &data,
const QString &uti) const override;
QList<QByteArray> convertFromMime(const QString &mime, const QVariant &data,
const QString &uti) const override;
};
QString QMacMimeUnicodeText::flavorForMime(const QString &mime) const
QString QMacMimeUnicodeText::utiForMime(const QString &mime) const
{
if (mime == "text/plain"_L1)
return "public.utf16-plain-text"_L1;
@ -306,31 +364,31 @@ QString QMacMimeUnicodeText::flavorForMime(const QString &mime) const
return QString();
}
QString QMacMimeUnicodeText::mimeForFlavor(const QString &flav) const
QString QMacMimeUnicodeText::mimeForUti(const QString &uti) const
{
if (flav == "public.utf16-plain-text"_L1 || flav == "public.utf8-plain-text"_L1)
if (uti == "public.utf16-plain-text"_L1 || uti == "public.utf8-plain-text"_L1)
return "text/plain"_L1;
return QString();
}
bool QMacMimeUnicodeText::canConvert(const QString &mime, const QString &flav) const
bool QMacMimeUnicodeText::canConvert(const QString &mime, const QString &uti) const
{
return (mime == "text/plain"_L1
&& (flav == "public.utf8-plain-text"_L1 || (flav == "public.utf16-plain-text"_L1)));
&& (uti == "public.utf8-plain-text"_L1 || (uti == "public.utf16-plain-text"_L1)));
}
QVariant
QMacMimeUnicodeText::convertToMime(const QString &mimetype,
const QList<QByteArray> &data, const QString &flavor) const
const QList<QByteArray> &data, const QString &uti) const
{
if (data.count() > 1)
qWarning("QMacMimeUnicodeText: Cannot handle multiple member data");
const QByteArray &firstData = data.first();
// I can only handle two types (system and unicode) so deal with them that way
QVariant ret;
if (flavor == "public.utf8-plain-text"_L1) {
if (uti == "public.utf8-plain-text"_L1) {
ret = QString::fromUtf8(firstData);
} else if (flavor == "public.utf16-plain-text"_L1) {
} else if (uti == "public.utf16-plain-text"_L1) {
QString str = QStringDecoder(QStringDecoder::Utf16)(firstData);
ret = str;
} else {
@ -340,13 +398,14 @@ QMacMimeUnicodeText::convertToMime(const QString &mimetype,
}
QList<QByteArray>
QMacMimeUnicodeText::convertFromMime(const QString &, const QVariant &data, const QString &flavor) const
QMacMimeUnicodeText::convertFromMime(const QString &, const QVariant &data,
const QString &uti) const
{
QList<QByteArray> ret;
QString string = data.toString();
if (flavor == "public.utf8-plain-text"_L1)
if (uti == "public.utf8-plain-text"_L1)
ret.append(string.toUtf8());
else if (flavor == "public.utf16-plain-text"_L1) {
else if (uti == "public.utf16-plain-text"_L1) {
QStringEncoder::Flags f;
#if defined(Q_OS_MACOS)
// Some applications such as Microsoft Excel, don't deal well with
@ -369,37 +428,39 @@ QMacMimeUnicodeText::convertFromMime(const QString &, const QVariant &data, cons
class QMacMimeHTMLText : public QMacMime
{
public:
QString flavorForMime(const QString &mime) const override;
QString mimeForFlavor(const QString &flav) const override;
bool canConvert(const QString &mime, const QString &flav) const override;
QVariant convertToMime(const QString &mime, const QList<QByteArray> &data, const QString &flav) const override;
QList<QByteArray> convertFromMime(const QString &mime, const QVariant &data, const QString &flav) const override;
QString utiForMime(const QString &mime) const override;
QString mimeForUti(const QString &uti) const override;
bool canConvert(const QString &mime, const QString &uti) const override;
QVariant convertToMime(const QString &mime, const QList<QByteArray> &data,
const QString &uti) const override;
QList<QByteArray> convertFromMime(const QString &mime, const QVariant &data,
const QString &uti) const override;
};
QString QMacMimeHTMLText::flavorForMime(const QString &mime) const
QString QMacMimeHTMLText::utiForMime(const QString &mime) const
{
if (mime == "text/html"_L1)
return "public.html"_L1;
return QString();
}
QString QMacMimeHTMLText::mimeForFlavor(const QString &flav) const
QString QMacMimeHTMLText::mimeForUti(const QString &uti) const
{
if (flav == "public.html"_L1)
if (uti == "public.html"_L1)
return "text/html"_L1;
return QString();
}
bool QMacMimeHTMLText::canConvert(const QString &mime, const QString &flav) const
bool QMacMimeHTMLText::canConvert(const QString &mime, const QString &uti) const
{
return flavorForMime(mime) == flav;
return utiForMime(mime) == uti;
}
QVariant
QMacMimeHTMLText::convertToMime(const QString &mimeType,
const QList<QByteArray> &data, const QString &flavor) const
const QList<QByteArray> &data, const QString &uti) const
{
if (!canConvert(mimeType, flavor))
if (!canConvert(mimeType, uti))
return QVariant();
if (data.count() > 1)
qWarning("QMacMimeHTMLText: Cannot handle multiple member data");
@ -408,10 +469,10 @@ QMacMimeHTMLText::convertToMime(const QString &mimeType,
QList<QByteArray>
QMacMimeHTMLText::convertFromMime(const QString &mime,
const QVariant &data, const QString &flavor) const
const QVariant &data, const QString &uti) const
{
QList<QByteArray> ret;
if (!canConvert(mime, flavor))
if (!canConvert(mime, uti))
return ret;
ret.append(data.toByteArray());
return ret;
@ -420,37 +481,39 @@ QMacMimeHTMLText::convertFromMime(const QString &mime,
class QMacMimeRtfText : public QMacMime
{
public:
QString flavorForMime(const QString &mime) const override;
QString mimeForFlavor(const QString &flav) const override;
bool canConvert(const QString &mime, const QString &flav) const override;
QVariant convertToMime(const QString &mime, const QList<QByteArray> &data, const QString &flav) const override;
QList<QByteArray> convertFromMime(const QString &mime, const QVariant &data, const QString &flav) const override;
QString utiForMime(const QString &mime) const override;
QString mimeForUti(const QString &uti) const override;
bool canConvert(const QString &mime, const QString &uti) const override;
QVariant convertToMime(const QString &mime, const QList<QByteArray> &data,
const QString &uti) const override;
QList<QByteArray> convertFromMime(const QString &mime, const QVariant &data,
const QString &uti) const override;
};
QString QMacMimeRtfText::flavorForMime(const QString &mime) const
QString QMacMimeRtfText::utiForMime(const QString &mime) const
{
if (mime == "text/html"_L1)
return "public.rtf"_L1;
return QString();
}
QString QMacMimeRtfText::mimeForFlavor(const QString &flav) const
QString QMacMimeRtfText::mimeForUti(const QString &uti) const
{
if (flav == "public.rtf"_L1)
if (uti == "public.rtf"_L1)
return "text/html"_L1;
return QString();
}
bool QMacMimeRtfText::canConvert(const QString &mime, const QString &flav) const
bool QMacMimeRtfText::canConvert(const QString &mime, const QString &uti) const
{
return mime == mimeForFlavor(flav);
return mime == mimeForUti(uti);
}
QVariant
QMacMimeRtfText::convertToMime(const QString &mimeType,
const QList<QByteArray> &data, const QString &flavor) const
const QList<QByteArray> &data, const QString &uti) const
{
if (!canConvert(mimeType, flavor))
if (!canConvert(mimeType, uti))
return QVariant();
if (data.count() > 1)
qWarning("QMacMimeHTMLText: Cannot handle multiple member data");
@ -470,10 +533,10 @@ QMacMimeRtfText::convertToMime(const QString &mimeType,
QList<QByteArray>
QMacMimeRtfText::convertFromMime(const QString &mime,
const QVariant &data, const QString &flavor) const
const QVariant &data, const QString &uti) const
{
QList<QByteArray> ret;
if (!canConvert(mime, flavor))
if (!canConvert(mime, uti))
return ret;
NSAttributedString *string = [[NSAttributedString alloc] initWithData:data.toByteArray().toNSData()
@ -492,38 +555,40 @@ QMacMimeRtfText::convertFromMime(const QString &mime,
class QMacMimeFileUri : public QMacMime
{
public:
QString flavorForMime(const QString &mime) const override;
QString mimeForFlavor(const QString &flav) const override;
bool canConvert(const QString &mime, const QString &flav) const override;
QVariant convertToMime(const QString &mime, const QList<QByteArray> &data, const QString &flav) const override;
QList<QByteArray> convertFromMime(const QString &mime, const QVariant &data, const QString &flav) const override;
QString utiForMime(const QString &mime) const override;
QString mimeForUti(const QString &uti) const override;
bool canConvert(const QString &mime, const QString &uti) const override;
QVariant convertToMime(const QString &mime, const QList<QByteArray> &data,
const QString &uti) const override;
QList<QByteArray> convertFromMime(const QString &mime, const QVariant &data,
const QString &uti) const override;
int count(const QMimeData *mimeData) const override;
};
QString QMacMimeFileUri::flavorForMime(const QString &mime) const
QString QMacMimeFileUri::utiForMime(const QString &mime) const
{
if (mime == "text/uri-list"_L1)
return "public.file-url"_L1;
return QString();
}
QString QMacMimeFileUri::mimeForFlavor(const QString &flav) const
QString QMacMimeFileUri::mimeForUti(const QString &uti) const
{
if (flav == "public.file-url"_L1)
if (uti == "public.file-url"_L1)
return "text/uri-list"_L1;
return QString();
}
bool QMacMimeFileUri::canConvert(const QString &mime, const QString &flav) const
bool QMacMimeFileUri::canConvert(const QString &mime, const QString &uti) const
{
return mime == "text/uri-list"_L1 && flav == "public.file-url"_L1;
return mime == "text/uri-list"_L1 && uti == "public.file-url"_L1;
}
QVariant
QMacMimeFileUri::convertToMime(const QString &mime,
const QList<QByteArray> &data, const QString &flav) const
const QList<QByteArray> &data, const QString &uti) const
{
if (!canConvert(mime, flav))
if (!canConvert(mime, uti))
return QVariant();
QList<QVariant> ret;
for (int i = 0; i < data.size(); ++i) {
@ -550,10 +615,10 @@ QMacMimeFileUri::convertToMime(const QString &mime,
QList<QByteArray>
QMacMimeFileUri::convertFromMime(const QString &mime,
const QVariant &data, const QString &flav) const
const QVariant &data, const QString &uti) const
{
QList<QByteArray> ret;
if (!canConvert(mime, flav))
if (!canConvert(mime, uti))
return ret;
QList<QVariant> urls = data.toList();
for (int i = 0; i < urls.size(); ++i) {
@ -579,37 +644,39 @@ int QMacMimeFileUri::count(const QMimeData *mimeData) const
class QMacMimeUrl : public QMacMime
{
public:
QString flavorForMime(const QString &mime) const override;
QString mimeForFlavor(const QString &flav) const override;
bool canConvert(const QString &mime, const QString &flav) const override;
QVariant convertToMime(const QString &mime, const QList<QByteArray> &data, const QString &flav) const override;
QList<QByteArray> convertFromMime(const QString &mime, const QVariant &data, const QString &flav) const override;
QString utiForMime(const QString &mime) const override;
QString mimeForUti(const QString &uti) const override;
bool canConvert(const QString &mime, const QString &uti) const override;
QVariant convertToMime(const QString &mime, const QList<QByteArray> &data,
const QString &uti) const override;
QList<QByteArray> convertFromMime(const QString &mime, const QVariant &data,
const QString &uti) const override;
};
QString QMacMimeUrl::flavorForMime(const QString &mime) const
QString QMacMimeUrl::utiForMime(const QString &mime) const
{
if (mime.startsWith("text/uri-list"_L1))
return "public.url"_L1;
return QString();
}
QString QMacMimeUrl::mimeForFlavor(const QString &flav) const
QString QMacMimeUrl::mimeForUti(const QString &uti) const
{
if (flav == "public.url"_L1)
if (uti == "public.url"_L1)
return "text/uri-list"_L1;
return QString();
}
bool QMacMimeUrl::canConvert(const QString &mime, const QString &flav) const
bool QMacMimeUrl::canConvert(const QString &mime, const QString &uti) const
{
return flav == "public.url"_L1
return uti == "public.url"_L1
&& mime == "text/uri-list"_L1;
}
QVariant QMacMimeUrl::convertToMime(const QString &mime,
const QList<QByteArray> &data, const QString &flav) const
const QList<QByteArray> &data, const QString &uti) const
{
if (!canConvert(mime, flav))
if (!canConvert(mime, uti))
return QVariant();
QList<QVariant> ret;
@ -624,10 +691,10 @@ QVariant QMacMimeUrl::convertToMime(const QString &mime,
}
QList<QByteArray> QMacMimeUrl::convertFromMime(const QString &mime,
const QVariant &data, const QString &flav) const
const QVariant &data, const QString &uti) const
{
QList<QByteArray> ret;
if (!canConvert(mime, flav))
if (!canConvert(mime, uti))
return ret;
QList<QVariant> urls = data.toList();
@ -648,34 +715,36 @@ QList<QByteArray> QMacMimeUrl::convertFromMime(const QString &mime,
class QMacMimeVCard : public QMacMime
{
public:
QString flavorForMime(const QString &mime) const override;
QString mimeForFlavor(const QString &flav) const override;
bool canConvert(const QString &mime, const QString &flav) const override;
QVariant convertToMime(const QString &mime, const QList<QByteArray> &data, const QString &flav) const override;
QList<QByteArray> convertFromMime(const QString &mime, const QVariant &data, const QString &flav) const override;
QString utiForMime(const QString &mime) const override;
QString mimeForUti(const QString &uti) const override;
bool canConvert(const QString &mime, const QString &uti) const override;
QVariant convertToMime(const QString &mime, const QList<QByteArray> &data,
const QString &uti) const override;
QList<QByteArray> convertFromMime(const QString &mime, const QVariant &data,
const QString &uti) const override;
};
bool QMacMimeVCard::canConvert(const QString &mime, const QString &flav) const
bool QMacMimeVCard::canConvert(const QString &mime, const QString &uti) const
{
return mimeForFlavor(flav) == mime;
return mimeForUti(uti) == mime;
}
QString QMacMimeVCard::flavorForMime(const QString &mime) const
QString QMacMimeVCard::utiForMime(const QString &mime) const
{
if (mime.startsWith("text/vcard"_L1))
return "public.vcard"_L1;
return QString();
}
QString QMacMimeVCard::mimeForFlavor(const QString &flav) const
QString QMacMimeVCard::mimeForUti(const QString &uti) const
{
if (flav == "public.vcard"_L1)
if (uti == "public.vcard"_L1)
return "text/vcard"_L1;
return QString();
}
QVariant QMacMimeVCard::convertToMime(const QString &mime,
const QList<QByteArray> &data, const QString &) const
const QList<QByteArray> &data, const QString &) const
{
QByteArray cards;
if (mime == "text/vcard"_L1) {
@ -686,7 +755,7 @@ QVariant QMacMimeVCard::convertToMime(const QString &mime,
}
QList<QByteArray> QMacMimeVCard::convertFromMime(const QString &mime,
const QVariant &data, const QString &) const
const QVariant &data, const QString &) const
{
QList<QByteArray> ret;
if (mime == "text/vcard"_L1)
@ -700,39 +769,41 @@ extern CGImageRef qt_mac_toCGImage(const QImage &qImage);
class QMacMimeTiff : public QMacMime
{
public:
QString flavorForMime(const QString &mime) const override;
QString mimeForFlavor(const QString &flav) const override;
bool canConvert(const QString &mime, const QString &flav) const override;
QVariant convertToMime(const QString &mime, const QList<QByteArray> &data, const QString &flav) const override;
QList<QByteArray> convertFromMime(const QString &mime, const QVariant &data, const QString &flav) const override;
QString utiForMime(const QString &mime) const override;
QString mimeForUti(const QString &uti) const override;
bool canConvert(const QString &mime, const QString &uti) const override;
QVariant convertToMime(const QString &mime, const QList<QByteArray> &data,
const QString &uti) const override;
QList<QByteArray> convertFromMime(const QString &mime, const QVariant &data,
const QString &uti) const override;
};
QString QMacMimeTiff::flavorForMime(const QString &mime) const
QString QMacMimeTiff::utiForMime(const QString &mime) const
{
if (mime.startsWith("application/x-qt-image"_L1))
return "public.tiff"_L1;
return QString();
}
QString QMacMimeTiff::mimeForFlavor(const QString &flav) const
QString QMacMimeTiff::mimeForUti(const QString &uti) const
{
if (flav == "public.tiff"_L1)
if (uti == "public.tiff"_L1)
return "application/x-qt-image"_L1;
return QString();
}
bool QMacMimeTiff::canConvert(const QString &mime, const QString &flav) const
bool QMacMimeTiff::canConvert(const QString &mime, const QString &uti) const
{
return flav == "public.tiff"_L1 && mime == "application/x-qt-image"_L1;
return uti == "public.tiff"_L1 && mime == "application/x-qt-image"_L1;
}
QVariant QMacMimeTiff::convertToMime(const QString &mime,
const QList<QByteArray> &data, const QString &flav) const
const QList<QByteArray> &data, const QString &uti) const
{
if (data.count() > 1)
qWarning("QMacMimeTiff: Cannot handle multiple member data");
if (!canConvert(mime, flav))
if (!canConvert(mime, uti))
return QVariant();
QCFType<CFDataRef> tiffData = data.first().toRawCFData();
@ -745,13 +816,14 @@ QVariant QMacMimeTiff::convertToMime(const QString &mime,
}
QList<QByteArray> QMacMimeTiff::convertFromMime(const QString &mime,
const QVariant &variant, const QString &flav) const
const QVariant &variant, const QString &uti) const
{
if (!canConvert(mime, flav))
if (!canConvert(mime, uti))
return QList<QByteArray>();
QCFType<CFMutableDataRef> data = CFDataCreateMutable(0, 0);
QCFType<CGImageDestinationRef> imageDestination = CGImageDestinationCreateWithData(data, kUTTypeTIFF, 1, 0);
QCFType<CGImageDestinationRef> imageDestination = CGImageDestinationCreateWithData(data,
kUTTypeTIFF, 1, 0);
if (!imageDestination)
return QList<QByteArray>();
@ -762,7 +834,8 @@ QList<QByteArray> QMacMimeTiff::convertFromMime(const QString &mime,
static_cast<NSString *>(kCGImagePropertyPixelHeight): @(img.height())
};
CGImageDestinationAddImage(imageDestination, qt_mac_toCGImage(img), static_cast<CFDictionaryRef>(props));
CGImageDestinationAddImage(imageDestination, qt_mac_toCGImage(img),
static_cast<CFDictionaryRef>(props));
CGImageDestinationFinalize(imageDestination);
return QList<QByteArray>() << QByteArray::fromCFData(data);
@ -790,55 +863,4 @@ void registerBuiltInTypes()
}
/*
\fn bool QMacMime::canConvert(const QString &mime, QString flav)
Returns \c true if the converter can convert (both ways) between
\a mime and \a flav; otherwise returns \c false.
All subclasses must reimplement this pure virtual function.
*/
/*
\fn QString QMacMime::mimeForFlavor(QString flav)
Returns the MIME UTI used for Mac flavor \a flav, or 0 if this
converter does not support \a flav.
All subclasses must reimplement this pure virtual function.
*/
/*
\fn QString QMacMime::flavorForMime(const QString &mime)
Returns the Mac UTI used for MIME type \a mime, or 0 if this
converter does not support \a mime.
All subclasses must reimplement this pure virtual function.
*/
/*
\fn QVariant QMacMime::convertToMime(const QString &mime, QList<QByteArray> data, QString flav)
Returns \a data converted from Mac UTI \a flav to MIME type \a
mime.
Note that Mac flavors must all be self-terminating. The input \a
data may contain trailing data.
All subclasses must reimplement this pure virtual function.
*/
/*
\fn QList<QByteArray> QMacMime::convertFromMime(const QString &mime, const QVariant &data, const QString & flav)
Returns \a data converted from MIME type \a mime
to Mac UTI \a flav.
Note that Mac flavors must all be self-terminating. The return
value may contain trailing data.
All subclasses must reimplement this pure virtual function.
*/
QT_END_NAMESPACE

View File

@ -41,14 +41,14 @@ public:
HandlerScope scope() const { return m_scope; }
virtual bool canConvert(const QString &mime, const QString &flav) const = 0;
virtual bool canConvert(const QString &mime, const QString &uti) const = 0;
// for converting from Qt
virtual QList<QByteArray> convertFromMime(const QString &mime, const QVariant &data, const QString &flav) const = 0;
virtual QString flavorForMime(const QString &mime) const = 0;
virtual QList<QByteArray> convertFromMime(const QString &mime, const QVariant &data, const QString &uti) const = 0;
virtual QString utiForMime(const QString &mime) const = 0;
// for converting to Qt
virtual QString mimeForFlavor(const QString &flav) const = 0;
virtual QVariant convertToMime(const QString &mime, const QList<QByteArray> &data, const QString &flav) const = 0;
virtual QString mimeForUti(const QString &uti) const = 0;
virtual QVariant convertToMime(const QString &mime, const QList<QByteArray> &data, const QString &uti) const = 0;
virtual int count(const QMimeData *mimeData) const;
private:

View File

@ -78,19 +78,19 @@ void destroyMimeTypes()
}
/*
Returns a MIME type of for scope \a scope for \a flav, or \nullptr if none exists.
Returns a MIME type of for scope \a scope for \a uti, or \nullptr if none exists.
*/
QString flavorToMime(QMacMime::HandlerScope scope, const QString &flav)
QString flavorToMime(QMacMime::HandlerScope scope, const QString &uti)
{
MimeList *mimes = globalMimeList();
for (MimeList::const_iterator it = mimes->constBegin(); it != mimes->constEnd(); ++it) {
const bool relevantScope = uchar((*it)->scope()) & uchar(scope);
#ifdef DEBUG_MIME_MAPS
qDebug("QMacMimeRegistry::flavorToMime: attempting (%d) for flavor %s [%s]",
relevantScope, qPrintable(flav), qPrintable((*it)->mimeForFlavor(flav)));
qDebug("QMacMimeRegistry::flavorToMime: attempting (%d) for uti %s [%s]",
relevantScope, qPrintable(uti), qPrintable((*it)->mimeForUti(uti)));
#endif
if (relevantScope) {
QString mimeType = (*it)->mimeForFlavor(flav);
QString mimeType = (*it)->mimeForUti(uti);
if (!mimeType.isNull())
return mimeType;
}

View File

@ -14,45 +14,45 @@ using namespace Qt::StringLiterals;
class QMacMimeTraditionalMacPlainText : public QMacMime {
public:
QString flavorForMime(const QString &mime) const override;
QString mimeForFlavor(const QString &flav) const override;
bool canConvert(const QString &mime, const QString &flav) const override;
QString utiForMime(const QString &mime) const override;
QString mimeForUti(const QString &uti) const override;
bool canConvert(const QString &mime, const QString &uti) const override;
QVariant convertToMime(const QString &mime, const QList<QByteArray> &data,
const QString &flav) const override;
const QString &uti) const override;
QList<QByteArray> convertFromMime(const QString &mime, const QVariant &data,
const QString &flav) const override;
const QString &uti) const override;
};
QString QMacMimeTraditionalMacPlainText::flavorForMime(const QString &mime) const
QString QMacMimeTraditionalMacPlainText::utiForMime(const QString &mime) const
{
if (mime == "text/plain"_L1)
return "com.apple.traditional-mac-plain-text"_L1;
return QString();
}
QString QMacMimeTraditionalMacPlainText::mimeForFlavor(const QString &flav) const
QString QMacMimeTraditionalMacPlainText::mimeForUti(const QString &uti) const
{
if (flav == "com.apple.traditional-mac-plain-text"_L1)
if (uti == "com.apple.traditional-mac-plain-text"_L1)
return "text/plain"_L1;
return QString();
}
bool QMacMimeTraditionalMacPlainText::canConvert(const QString &mime,
const QString &flav) const
const QString &uti) const
{
return flavorForMime(mime) == flav;
return utiForMime(mime) == uti;
}
QVariant
QMacMimeTraditionalMacPlainText::convertToMime(const QString &mimetype,
const QList<QByteArray> &data,
const QString &flavor) const
const QString &uti) const
{
if (data.count() > 1)
qWarning("QMacMimeTraditionalMacPlainText: Cannot handle multiple member data");
const QByteArray &firstData = data.first();
QVariant ret;
if (flavor == "com.apple.traditional-mac-plain-text"_L1) {
if (uti == "com.apple.traditional-mac-plain-text"_L1) {
return QString(QCFString(CFStringCreateWithBytes(kCFAllocatorDefault,
reinterpret_cast<const UInt8 *>(firstData.constData()),
firstData.size(), CFStringGetSystemEncoding(), false)));
@ -65,11 +65,11 @@ QMacMimeTraditionalMacPlainText::convertToMime(const QString &mimetype,
QList<QByteArray>
QMacMimeTraditionalMacPlainText::convertFromMime(const QString &,
const QVariant &data,
const QString &flavor) const
const QString &uti) const
{
QList<QByteArray> ret;
QString string = data.toString();
if (flavor == "com.apple.traditional-mac-plain-text"_L1)
if (uti == "com.apple.traditional-mac-plain-text"_L1)
ret.append(string.toLatin1());
return ret;
}

View File

@ -125,7 +125,7 @@ QMacPasteboard::pasteBoard() const
return paste;
}
OSStatus QMacPasteboard::promiseKeeper(PasteboardRef paste, PasteboardItemID id, CFStringRef flavor, void *_qpaste)
OSStatus QMacPasteboard::promiseKeeper(PasteboardRef paste, PasteboardItemID id, CFStringRef uti, void *_qpaste)
{
QMacPasteboard *qpaste = (QMacPasteboard*)_qpaste;
const long promise_id = (long)id;
@ -133,7 +133,7 @@ OSStatus QMacPasteboard::promiseKeeper(PasteboardRef paste, PasteboardItemID id,
// Find the kept promise
QList<QMacMime*> availableConverters
= QMacMimeRegistry::all(QMacMime::HandlerScope::All);
const QString flavorAsQString = QString::fromCFString(flavor);
const QString flavorAsQString = QString::fromCFString(uti);
QMacPasteboard::Promise promise;
for (int i = 0; i < qpaste->promises.size(); i++){
QMacPasteboard::Promise tmp = qpaste->promises[i];
@ -158,13 +158,13 @@ OSStatus QMacPasteboard::promiseKeeper(PasteboardRef paste, PasteboardItemID id,
// This helps in making the application/x-qt-mime-type-name hidden from normal use.
QByteArray ba;
QCFType<CFDataRef> data = CFDataCreate(nullptr, (UInt8*)ba.constData(), ba.size());
PasteboardPutItemFlavor(paste, id, flavor, data, kPasteboardFlavorNoFlags);
PasteboardPutItemFlavor(paste, id, uti, data, kPasteboardFlavorNoFlags);
return noErr;
}
if (!promise.itemId) {
// There was no promise that could deliver data for the
// given id and flavor. This should not happen.
// given id and uti. This should not happen.
qDebug("Pasteboard: %d: Request for %ld, %s, but no promise found!", __LINE__, promise_id, qPrintable(flavorAsQString));
return cantGetFlavorErr;
}
@ -193,7 +193,7 @@ OSStatus QMacPasteboard::promiseKeeper(PasteboardRef paste, PasteboardItemID id,
return cantGetFlavorErr;
const QByteArray &ba = md[promise.offset];
QCFType<CFDataRef> data = CFDataCreate(nullptr, (UInt8*)ba.constData(), ba.size());
PasteboardPutItemFlavor(paste, id, flavor, data, kPasteboardFlavorNoFlags);
PasteboardPutItemFlavor(paste, id, uti, data, kPasteboardFlavorNoFlags);
return noErr;
}
@ -223,8 +223,8 @@ QMacPasteboard::hasOSType(int c_flavor) const
const int type_count = CFArrayGetCount(types);
for (int i = 0; i < type_count; ++i) {
CFStringRef flavor = (CFStringRef)CFArrayGetValueAtIndex(types, i);
CFStringRef preferredTag = UTTypeCopyPreferredTagWithClass(flavor, kUTTagClassOSType);
CFStringRef uti = (CFStringRef)CFArrayGetValueAtIndex(types, i);
CFStringRef preferredTag = UTTypeCopyPreferredTagWithClass(uti, kUTTagClassOSType);
const int os_flavor = UTGetOSTypeFromString(preferredTag);
if (preferredTag)
CFRelease(preferredTag);
@ -320,10 +320,10 @@ QMacPasteboard::setMimeData(QMimeData *mime_src, DataRequestType dataRequestType
// Hack: The Rtf handler converts incoming Rtf to Html. We do
// not want to convert outgoing Html to Rtf but instead keep
// posting it as Html. Skip the Rtf handler here.
if (c->flavorForMime("text/html"_L1) == "public.rtf"_L1)
if (c->utiForMime("text/html"_L1) == "public.rtf"_L1)
continue;
QString flavor(c->flavorForMime(mimeType));
if (!flavor.isEmpty()) {
QString uti(c->utiForMime(mimeType));
if (!uti.isEmpty()) {
QMacMimeData *mimeData = static_cast<QMacMimeData*>(mime_src);
int numItems = c->count(mime_src);
@ -335,9 +335,9 @@ QMacPasteboard::setMimeData(QMimeData *mime_src, DataRequestType dataRequestType
QMacPasteboard::Promise promise(itemID, c, mimeType, mimeData, item, dataRequestType);
promises.append(promise);
PasteboardPutItemFlavor(paste, reinterpret_cast<PasteboardItemID>(itemID), QCFString(flavor), 0, kPasteboardFlavorNoFlags);
PasteboardPutItemFlavor(paste, reinterpret_cast<PasteboardItemID>(itemID), QCFString(uti), 0, kPasteboardFlavorNoFlags);
qCDebug(lcQpaClipboard, " - adding %ld %s [%s] [%d]",
itemID, qPrintable(mimeType), qPrintable(flavor), item);
itemID, qPrintable(mimeType), qPrintable(uti), item);
}
}
}
@ -371,11 +371,11 @@ QMacPasteboard::formats() const
const int type_count = CFArrayGetCount(types);
for (int i = 0; i < type_count; ++i) {
const QString flavor = QString::fromCFString((CFStringRef)CFArrayGetValueAtIndex(types, i));
qCDebug(lcQpaClipboard, " -%s", qPrintable(QString(flavor)));
const QString mimeType = QMacMimeRegistry::flavorToMime(scope, flavor);
const QString uti = QString::fromCFString((CFStringRef)CFArrayGetValueAtIndex(types, i));
qCDebug(lcQpaClipboard, " -%s", qPrintable(QString(uti)));
const QString mimeType = QMacMimeRegistry::flavorToMime(scope, uti);
if (!mimeType.isEmpty() && !ret.contains(mimeType)) {
qCDebug(lcQpaClipboard, " -<%lld> %s [%s]", ret.size(), qPrintable(mimeType), qPrintable(QString(flavor)));
qCDebug(lcQpaClipboard, " -<%lld> %s [%s]", ret.size(), qPrintable(mimeType), qPrintable(QString(uti)));
ret << mimeType;
}
}
@ -408,9 +408,9 @@ QMacPasteboard::hasFormat(const QString &format) const
const int type_count = CFArrayGetCount(types);
for (int i = 0; i < type_count; ++i) {
const QString flavor = QString::fromCFString((CFStringRef)CFArrayGetValueAtIndex(types, i));
qCDebug(lcQpaClipboard, " -%s [0x%x]", qPrintable(flavor), uchar(scope));
QString mimeType = QMacMimeRegistry::flavorToMime(scope, flavor);
const QString uti = QString::fromCFString((CFStringRef)CFArrayGetValueAtIndex(types, i));
qCDebug(lcQpaClipboard, " -%s [0x%x]", qPrintable(uti), uchar(scope));
QString mimeType = QMacMimeRegistry::flavorToMime(scope, uti);
if (!mimeType.isEmpty())
qCDebug(lcQpaClipboard, " - %s", qPrintable(mimeType));
if (mimeType == format)
@ -435,7 +435,7 @@ QMacPasteboard::retrieveData(const QString &format, QMetaType) const
qCDebug(lcQpaClipboard, "Pasteboard: retrieveData [%s]", qPrintable(format));
const QList<QMacMime *> availableConverters = QMacMimeRegistry::all(scope);
for (const auto *c : availableConverters) {
QString c_flavor = c->flavorForMime(format);
QString c_flavor = c->utiForMime(format);
if (!c_flavor.isEmpty()) {
// Converting via PasteboardCopyItemFlavorData below will for some UITs result
// in newlines mapping to '\r' instead of '\n'. To work around this we shortcut
@ -461,10 +461,10 @@ QMacPasteboard::retrieveData(const QString &format, QMetaType) const
const int type_count = CFArrayGetCount(types);
for (int i = 0; i < type_count; ++i) {
CFStringRef flavor = static_cast<CFStringRef>(CFArrayGetValueAtIndex(types, i));
if (c_flavor == QString::fromCFString(flavor)) {
CFStringRef uti = static_cast<CFStringRef>(CFArrayGetValueAtIndex(types, i));
if (c_flavor == QString::fromCFString(uti)) {
QCFType<CFDataRef> macBuffer;
if (PasteboardCopyItemFlavorData(paste, id, flavor, &macBuffer) == noErr) {
if (PasteboardCopyItemFlavorData(paste, id, uti, &macBuffer) == noErr) {
QByteArray buffer((const char *)CFDataGetBytePtr(macBuffer), CFDataGetLength(macBuffer));
if (!buffer.isEmpty()) {
qCDebug(lcQpaClipboard, " - %s [%s]", qPrintable(format), qPrintable(c_flavor));
@ -474,7 +474,7 @@ QMacPasteboard::retrieveData(const QString &format, QMetaType) const
}
}
} else {
qCDebug(lcQpaClipboard, " - NoMatch %s [%s]", qPrintable(c_flavor), qPrintable(QString::fromCFString(flavor)));
qCDebug(lcQpaClipboard, " - NoMatch %s [%s]", qPrintable(c_flavor), qPrintable(QString::fromCFString(uti)));
}
}
}

View File

@ -131,7 +131,7 @@ QVariant QIOSMimeData::retrieveData(const QString &mimeType, QMetaType) const
NSArray<NSString *> *pasteboardTypes = [pb pasteboardTypes];
foreach (QMacMime *converter, QMacMimeRegistry::all(QMacMime::HandlerScope::All)) {
if (!converter->canConvert(mimeType, converter->flavorForMime(mimeType)))
if (!converter->canConvert(mimeType, converter->utiForMime(mimeType)))
continue;
for (NSUInteger i = 0; i < [pasteboardTypes count]; ++i) {
@ -185,7 +185,7 @@ void QIOSClipboard::setMimeData(QMimeData *mimeData, QClipboard::Mode mode)
foreach (const QString &mimeType, mimeData->formats()) {
foreach (QMacMime *converter, QMacMimeRegistry::all(QMacMime::HandlerScope::All)) {
const QString uti = converter->flavorForMime(mimeType);
const QString uti = converter->utiForMime(mimeType);
if (uti.isEmpty() || !converter->canConvert(mimeType, uti))
continue;