Make QMacMime::canConvert a non-virtual helper for other virtuals

Implementors are expected to return whether the converter can convert
both ways between a mime and a uti. However, this is implied in the
mimeForUti and utiForMime functions, and almost all converter implemented
canConvert by returning mimeForUti(uti) == mime.

A notable exception is the QMacMimeTypeName implementation, which can
only convert from from mime to uti using hard-coded special format names
and dummy data to provide place holders for drag'n'drop operations that
originate in Qt. That converter returned always false from canConvert,
but mapped the special "application/x-qt-mime-type-name" mime type to
the special "com.trolltech.qt.MimeTypeName" uti. Since nobody ever
requests data as "com.trolltech.qt.MimeTypeName", we still always ignore
that converter. The uti is then special-cased in the QMacClipboard code.

Lower-level code where only mime type or UTI are known can still call
the virtuals directly and check whether the returned string is empty,
which indicates that the converter does not support the conversion.

As a drive-by, fix coding style and variable naming.

Change-Id: I3d5d60faa82f8b31d9873c9da0097a308b9eeb50
Reviewed-by: Richard Moe Gustavsen <richard.gustavsen@qt.io>
Reviewed-by: Timur Pocheptsov <timur.pocheptsov@qt.io>
This commit is contained in:
Volker Hilsheimer 2022-11-07 15:35:05 +01:00
parent 2bdc027f5c
commit 7cc0a8741c
5 changed files with 39 additions and 108 deletions

View File

@ -69,10 +69,10 @@ using namespace Qt::StringLiterals;
\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
When working with MIME data, Qt will iterate through all instances of QMacMime to find
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().
mimeForUti() or utiForMime() on each instance, starting with (and choosing) the last created
instance first. The actual conversions will be done by using convertToMime() and convertFromMime().
*/
/*!
@ -117,35 +117,32 @@ int QMacMime::count(const QMimeData *mimeData) const
return 1;
}
/*
\fn bool QMacMime::canConvert(const QString &mime, QString uti)
/*!
\fn bool QMacMime::canConvert(const QString &mime, const QString &uti) const
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.
Returns the MIME type used for Mac UTI \a uti, or an empty string if
this converter does not support converting from \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.
this converter does not support converting from \a mime.
All subclasses must reimplement this pure virtual function.
*/
/*
/*!
\fn QVariant QMacMime::convertToMime(const QString &mime,
const QList<QByteArray> &data, const QString &uti)
@ -157,7 +154,7 @@ int QMacMime::count(const QMimeData *mimeData) const
All subclasses must reimplement this pure virtual function.
*/
/*
/*!
\fn QList<QByteArray> QMacMime::convertFromMime(const QString &mime,
const QVariant &data, const QString & uti)
@ -176,7 +173,6 @@ public:
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,
@ -200,11 +196,6 @@ QString QMacMimeAny::mimeForUti(const QString &uti) const
return QString();
}
bool QMacMimeAny::canConvert(const QString &mime, const QString &uti) const
{
return mimeForUti(uti) == mime;
}
QVariant QMacMimeAny::convertToMime(const QString &mime, const QList<QByteArray> &data,
const QString &) const
{
@ -237,7 +228,6 @@ public:
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;
};
@ -254,11 +244,6 @@ QString QMacMimeTypeName::mimeForUti(const QString &) const
return QString();
}
bool QMacMimeTypeName::canConvert(const QString &, const QString &) const
{
return false;
}
QVariant QMacMimeTypeName::convertToMime(const QString &, const QList<QByteArray> &, const QString &) const
{
QVariant ret;
@ -277,7 +262,6 @@ class QMacMimePlainTextFallback : public QMacMime
public:
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,
@ -298,11 +282,6 @@ QString QMacMimePlainTextFallback::mimeForUti(const QString &uti) const
return QString();
}
bool QMacMimePlainTextFallback::canConvert(const QString &mime, const QString &uti) const
{
return mime == mimeForUti(uti);
}
QVariant
QMacMimePlainTextFallback::convertToMime(const QString &mimetype,
const QList<QByteArray> &data, const QString &uti) const
@ -339,7 +318,6 @@ class QMacMimeUnicodeText : public QMacMime
public:
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,
@ -350,11 +328,10 @@ QString QMacMimeUnicodeText::utiForMime(const QString &mime) const
{
if (mime == "text/plain"_L1)
return "public.utf16-plain-text"_L1;
int i = mime.indexOf("charset="_L1);
if (i >= 0) {
QString cs(mime.mid(i+8).toLower());
if (qsizetype i = mime.indexOf("charset="_L1); i >= 0) {
QString cs(mime.mid(i + 8).toLower());
i = cs.indexOf(u';');
if (i>=0)
if (i >= 0)
cs = cs.left(i);
if (cs == "system"_L1)
return "public.utf8-plain-text"_L1;
@ -371,12 +348,6 @@ QString QMacMimeUnicodeText::mimeForUti(const QString &uti) const
return QString();
}
bool QMacMimeUnicodeText::canConvert(const QString &mime, const QString &uti) const
{
return (mime == "text/plain"_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 &uti) const
@ -430,7 +401,6 @@ class QMacMimeHTMLText : public QMacMime
public:
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,
@ -451,11 +421,6 @@ QString QMacMimeHTMLText::mimeForUti(const QString &uti) const
return QString();
}
bool QMacMimeHTMLText::canConvert(const QString &mime, const QString &uti) const
{
return utiForMime(mime) == uti;
}
QVariant
QMacMimeHTMLText::convertToMime(const QString &mimeType,
const QList<QByteArray> &data, const QString &uti) const
@ -483,7 +448,6 @@ class QMacMimeRtfText : public QMacMime
public:
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,
@ -504,11 +468,6 @@ QString QMacMimeRtfText::mimeForUti(const QString &uti) const
return QString();
}
bool QMacMimeRtfText::canConvert(const QString &mime, const QString &uti) const
{
return mime == mimeForUti(uti);
}
QVariant
QMacMimeRtfText::convertToMime(const QString &mimeType,
const QList<QByteArray> &data, const QString &uti) const
@ -557,7 +516,6 @@ class QMacMimeFileUri : public QMacMime
public:
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,
@ -579,11 +537,6 @@ QString QMacMimeFileUri::mimeForUti(const QString &uti) const
return QString();
}
bool QMacMimeFileUri::canConvert(const QString &mime, const QString &uti) const
{
return mime == "text/uri-list"_L1 && uti == "public.file-url"_L1;
}
QVariant
QMacMimeFileUri::convertToMime(const QString &mime,
const QList<QByteArray> &data, const QString &uti) const
@ -646,7 +599,6 @@ class QMacMimeUrl : public QMacMime
public:
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,
@ -667,12 +619,6 @@ QString QMacMimeUrl::mimeForUti(const QString &uti) const
return QString();
}
bool QMacMimeUrl::canConvert(const QString &mime, const QString &uti) const
{
return uti == "public.url"_L1
&& mime == "text/uri-list"_L1;
}
QVariant QMacMimeUrl::convertToMime(const QString &mime,
const QList<QByteArray> &data, const QString &uti) const
{
@ -717,18 +663,12 @@ class QMacMimeVCard : public QMacMime
public:
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 &uti) const
{
return mimeForUti(uti) == mime;
}
QString QMacMimeVCard::utiForMime(const QString &mime) const
{
if (mime.startsWith("text/vcard"_L1))
@ -744,10 +684,12 @@ QString QMacMimeVCard::mimeForUti(const QString &uti) const
}
QVariant QMacMimeVCard::convertToMime(const QString &mime,
const QList<QByteArray> &data, const QString &) const
const QList<QByteArray> &data, const QString &uti) const
{
if (!canConvert(mime, uti))
return QVariant();
QByteArray cards;
if (mime == "text/vcard"_L1) {
if (uti == "public.vcard"_L1) {
for (int i=0; i<data.size(); ++i)
cards += data[i];
}
@ -755,9 +697,12 @@ QVariant QMacMimeVCard::convertToMime(const QString &mime,
}
QList<QByteArray> QMacMimeVCard::convertFromMime(const QString &mime,
const QVariant &data, const QString &) const
const QVariant &data, const QString &uti) const
{
QList<QByteArray> ret;
if (!canConvert(mime, uti))
return ret;
if (mime == "text/vcard"_L1)
ret.append(data.toString().toUtf8());
return ret;
@ -771,7 +716,6 @@ class QMacMimeTiff : public QMacMime
public:
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,
@ -792,11 +736,6 @@ QString QMacMimeTiff::mimeForUti(const QString &uti) const
return QString();
}
bool QMacMimeTiff::canConvert(const QString &mime, const QString &uti) const
{
return uti == "public.tiff"_L1 && mime == "application/x-qt-image"_L1;
}
QVariant QMacMimeTiff::convertToMime(const QString &mime,
const QList<QByteArray> &data, const QString &uti) const
{

View File

@ -40,8 +40,8 @@ public:
virtual ~QMacMime();
HandlerScope scope() const { return m_scope; }
bool canConvert(const QString &mime, const QString &uti) const { return mimeForUti(uti) == mime; }
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 &uti) const = 0;
virtual QString utiForMime(const QString &mime) const = 0;

View File

@ -16,7 +16,6 @@ class QMacMimeTraditionalMacPlainText : public QMacMime {
public:
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,
@ -37,12 +36,6 @@ QString QMacMimeTraditionalMacPlainText::mimeForUti(const QString &uti) const
return QString();
}
bool QMacMimeTraditionalMacPlainText::canConvert(const QString &mime,
const QString &uti) const
{
return utiForMime(mime) == uti;
}
QVariant
QMacMimeTraditionalMacPlainText::convertToMime(const QString &mimetype,
const QList<QByteArray> &data,

View File

@ -130,9 +130,8 @@ OSStatus QMacPasteboard::promiseKeeper(PasteboardRef paste, PasteboardItemID id,
const long promise_id = (long)id;
// Find the kept promise
QList<QMacMime*> availableConverters
= QMacMimeRegistry::all(QMacMime::HandlerScope::All);
const QString flavorAsQString = QString::fromCFString(uti);
const QList<QMacMime*> availableConverters = QMacMimeRegistry::all(QMacMime::HandlerScope::All);
const QString utiAsQString = QString::fromCFString(uti);
QMacPasteboard::Promise promise;
for (int i = 0; i < qpaste->promises.size(); i++){
const QMacPasteboard::Promise tmp = qpaste->promises[i];
@ -146,13 +145,13 @@ OSStatus QMacPasteboard::promiseKeeper(PasteboardRef paste, PasteboardItemID id,
continue;
}
if (tmp.itemId == promise_id && tmp.converter->canConvert(tmp.mime, flavorAsQString)){
if (tmp.itemId == promise_id && tmp.converter->canConvert(tmp.mime, utiAsQString)) {
promise = tmp;
break;
}
}
if (!promise.itemId && flavorAsQString == "com.trolltech.qt.MimeTypeName"_L1) {
if (!promise.itemId && utiAsQString == "com.trolltech.qt.MimeTypeName"_L1) {
// we have promised this data, but won't be able to convert, so return null data.
// This helps in making the application/x-qt-mime-type-name hidden from normal use.
QByteArray ba;
@ -164,12 +163,12 @@ OSStatus QMacPasteboard::promiseKeeper(PasteboardRef paste, PasteboardItemID id,
if (!promise.itemId) {
// There was no promise that could deliver data for the
// given id and uti. This should not happen.
qDebug("Pasteboard: %d: Request for %ld, %s, but no promise found!", __LINE__, promise_id, qPrintable(flavorAsQString));
qDebug("Pasteboard: %d: Request for %ld, %s, but no promise found!", __LINE__, promise_id, qPrintable(utiAsQString));
return cantGetFlavorErr;
}
qCDebug(lcQpaClipboard, "PasteBoard: Calling in promise for %s[%ld] [%s] [%d]", qPrintable(promise.mime), promise_id,
qPrintable(flavorAsQString), promise.offset);
qPrintable(utiAsQString), promise.offset);
// Get the promise data. If this is a "lazy" promise call variantData()
// to request the data from the application.
@ -187,7 +186,7 @@ OSStatus QMacPasteboard::promiseKeeper(PasteboardRef paste, PasteboardItemID id,
promiseData = promise.variantData;
}
const QList<QByteArray> md = promise.converter->convertFromMime(promise.mime, promiseData, flavorAsQString);
const QList<QByteArray> md = promise.converter->convertFromMime(promise.mime, promiseData, utiAsQString);
if (md.size() <= promise.offset)
return cantGetFlavorErr;
const QByteArray &ba = md[promise.offset];

View File

@ -130,13 +130,11 @@ QVariant QIOSMimeData::retrieveData(const QString &mimeType, QMetaType) const
UIPasteboard *pb = [UIPasteboard pasteboardWithQClipboardMode:m_mode];
NSArray<NSString *> *pasteboardTypes = [pb pasteboardTypes];
foreach (QMacMime *converter, QMacMimeRegistry::all(QMacMime::HandlerScope::All)) {
if (!converter->canConvert(mimeType, converter->utiForMime(mimeType)))
continue;
const auto converters = QMacMimeRegistry::all(QMacMime::HandlerScope::All);
for (QMacMime *converter : converters) {
for (NSUInteger i = 0; i < [pasteboardTypes count]; ++i) {
NSString *availableUtiNSString = [pasteboardTypes objectAtIndex:i];
QString availableUti = QString::fromNSString(availableUtiNSString);
const QString availableUti = QString::fromNSString(availableUtiNSString);
if (!converter->canConvert(mimeType, availableUti))
continue;
@ -183,10 +181,12 @@ void QIOSClipboard::setMimeData(QMimeData *mimeData, QClipboard::Mode mode)
mimeData->deleteLater();
NSMutableDictionary<NSString *, id> *pbItem = [NSMutableDictionary<NSString *, id> dictionaryWithCapacity:mimeData->formats().size()];
foreach (const QString &mimeType, mimeData->formats()) {
foreach (QMacMime *converter, QMacMimeRegistry::all(QMacMime::HandlerScope::All)) {
const auto formats = mimeData->formats();
for (const QString &mimeType : formats) {
const auto converters = QMacMimeRegistry::all(QMacMime::HandlerScope::All);
for (const QMacMime *converter : converters) {
const QString uti = converter->utiForMime(mimeType);
if (uti.isEmpty() || !converter->canConvert(mimeType, uti))
if (uti.isEmpty())
continue;
QVariant mimeDataAsVariant;