Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qmimetype.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// Copyright (C) 2015 Klaralvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author David Faure <david.faure@kdab.com>
3// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
4
5#include "qmimetype.h"
6
7#include "qmimetype_p.h"
9
10#include <QtCore/QCoreApplication>
11#include <QtCore/QDebug>
12#include <QtCore/QLocale>
13#include <QtCore/QHashFunctions>
14
15#include <memory>
16
18
19using namespace Qt::StringLiterals;
20
21/*!
22 \class QMimeType
23 \inmodule QtCore
24 \ingroup shared
25 \brief The QMimeType class describes types of file or data, represented by a MIME type string.
26
27 \since 5.0
28 \compares equality
29
30 For instance a file named "readme.txt" has the MIME type "text/plain".
31 The MIME type can be determined from the file name, or from the file
32 contents, or from both. MIME type determination can also be done on
33 buffers of data not coming from files.
34
35 Determining the MIME type of a file can be useful to make sure your
36 application supports it. It is also useful in file-manager-like applications
37 or widgets, in order to display an appropriate \l {QMimeType::iconName}{icon} for the file, or even
38 the descriptive \l {QMimeType::comment()}{comment} in detailed views.
39
40 To check if a file has the expected MIME type, you should use inherits()
41 rather than a simple string comparison based on the name(). This is because
42 MIME types can inherit from each other: for instance a C source file is
43 a specific type of plain text file, so text/x-csrc inherits text/plain.
44
45 \sa QMimeDatabase, {MIME Type Browser}
46 */
47
48/*!
49 \fn QMimeType &QMimeType::operator=(QMimeType &&other)
50
51 Move-assigns \a other to this QMimeType instance.
52
53 \since 5.2
54*/
55
56/*!
57 \fn QMimeType::QMimeType();
58 Constructs this QMimeType object initialized with default property values that indicate an invalid MIME type.
59 */
60QMimeType::QMimeType() :
61 d(new QMimeTypePrivate())
62{
63}
64
65/*!
66 \fn QMimeType::QMimeType(const QMimeType &other);
67 Constructs this QMimeType object as a copy of \a other.
68 */
69QMimeType::QMimeType(const QMimeType &other) :
70 d(other.d)
71{
72}
73
74/*!
75 \fn QMimeType &QMimeType::operator=(const QMimeType &other);
76 Assigns the data of \a other to this QMimeType object, and returns a reference to this object.
77 */
78QMimeType &QMimeType::operator=(const QMimeType &other)
79{
80 if (d != other.d)
81 d = other.d;
82 return *this;
83}
84
85/*!
86 \fn QMimeType::QMimeType(const QMimeTypePrivate &dd);
87 Assigns the data of the QMimeTypePrivate \a dd to this QMimeType object, and returns a reference to this object.
88 \internal
89 */
90QMimeType::QMimeType(const QMimeTypePrivate &dd) :
91 d(new QMimeTypePrivate(dd))
92{
93}
94
95/*!
96 \fn void QMimeType::swap(QMimeType &other);
97 \memberswap{mime type}
98
99 The swap() method helps with the implementation of assignment
100 operators in an exception-safe way. For more information consult
101 \l {http://en.wikibooks.org/wiki/More_C++_Idioms/Copy-and-swap}
102 {More C++ Idioms - Copy-and-swap}.
103 */
104
105/*!
106 \fn QMimeType::~QMimeType();
107 Destroys the QMimeType object, and releases the d pointer.
108 */
109QMimeType::~QMimeType()
110{
111}
112
113/*!
114 \fn bool QMimeType::operator==(const QMimeType &lhs, const QMimeType &rhs);
115 Returns \c true if \a lhs equals to the \a rhs QMimeType object, otherwise
116 returns \c false.
117 The name is the unique identifier for a mimetype, so two mimetypes with
118 the same name, are equal.
119 */
120bool comparesEqual(const QMimeType &lhs, const QMimeType &rhs) noexcept
121{
122 return lhs.d == rhs.d || lhs.d->name == rhs.d->name;
123}
124
125/*!
126 \since 5.6
127 \qhashold{QMimeType}
128 */
129size_t qHash(const QMimeType &key, size_t seed) noexcept
130{
131 return qHash(key.d->name, seed);
132}
133
134/*!
135 \fn bool QMimeType::operator!=(const QMimeType &lhs, const QMimeType &rhs);
136 Returns \c true if QMimeType \a lhs is not equal to QMimeType \a rhs,
137 otherwise returns \c false.
138 */
139
140/*!
141 \property QMimeType::valid
142 \brief \c true if the QMimeType object contains valid data, \c false otherwise
143
144 A valid MIME type has a non-empty name().
145 The invalid MIME type is the default-constructed QMimeType.
146
147 While this property was introduced in 5.10, the
148 corresponding accessor method has always been there.
149 */
150bool QMimeType::isValid() const
151{
152 return !d->name.isEmpty();
153}
154
155/*!
156 \property QMimeType::isDefault
157 \brief \c true if this MIME type is the default MIME type which
158 applies to all files: application/octet-stream.
159
160 While this property was introduced in 5.10, the
161 corresponding accessor method has always been there.
162 */
163bool QMimeType::isDefault() const
164{
165 return d->name == QMimeDatabasePrivate::instance()->defaultMimeType();
166}
167
168/*!
169 \property QMimeType::name
170 \brief the name of the MIME type
171
172 While this property was introduced in 5.10, the
173 corresponding accessor method has always been there.
174 */
175QString QMimeType::name() const
176{
177 return d->name;
178}
179
180/*!
181 \property QMimeType::comment
182 \brief the description of the MIME type to be displayed on user interfaces
183
184 Returns a description for a MIME type, localized to the user's
185 current language settings.
186
187 While this property was introduced in 5.10, the
188 corresponding accessor method has always been there.
189 */
190QString QMimeType::comment() const
191{
192 const auto isEnUs = [](QStringView lang) {
193 // All synonyms of en_US, according to CLDR likely subtag rules:
194 static constexpr QLatin1StringView usaIsh[] =
195 { "en_Latn_US"_L1, "en_US"_L1, "en_Latn"_L1, "en"_L1 };
196 return std::find(std::begin(usaIsh), std::end(usaIsh), lang) != std::end(usaIsh);
197 };
198 const auto localeComments = QMimeDatabasePrivate::instance()->localeComments(d->name);
199 const QStringList languageList = QLocale().uiLanguages(QLocale::TagSeparator::Underscore);
200 QString comment = localeComments.value(u"default"_s);
201
202 for (const QString &language : std::as_const(languageList)) {
203 const QString lang = language == "C"_L1 ? u"en_US"_s : language;
204 QString translated = localeComments.value(lang);
205 if (!translated.isEmpty())
206 return translated;
207 if (!comment.isEmpty() && isEnUs(lang))
208 return comment; // The default entry is assumed to be in en-US
209 }
210 QString translated =
211 QCoreApplication::translate("QMimeType", comment.toUtf8().constData());
212 if (!translated.isEmpty())
213 return translated;
214
215 // Use the mimetype name as fallback
216 return d->name;
217}
218
219/*!
220 \property QMimeType::genericIconName
221 \brief the file name of a generic icon that represents the MIME type
222
223 This should be used if the icon returned by iconName() cannot be found on
224 the system. It is used for categories of similar types (like spreadsheets
225 or archives) that can use a common icon.
226 The freedesktop.org Icon Naming Specification lists a set of such icon names.
227
228 The icon name can be given to QIcon::fromTheme() in order to load the icon.
229
230 While this property was introduced in 5.10, the
231 corresponding accessor method has always been there.
232 */
233QString QMimeType::genericIconName() const
234{
235 QString genericIconName = QMimeDatabasePrivate::instance()->genericIcon(d->name);
236 if (genericIconName.isEmpty()) {
237 // From the spec:
238 // If the generic icon name is empty (not specified by the mimetype definition)
239 // then the mimetype is used to generate the generic icon by using the top-level
240 // media type (e.g. "video" in "video/ogg") and appending "-x-generic"
241 // (i.e. "video-x-generic" in the previous example).
242 const QString group = name();
243 QStringView groupRef(group);
244 const qsizetype slashindex = groupRef.indexOf(u'/');
245 if (slashindex != -1)
246 groupRef = groupRef.left(slashindex);
247 return groupRef + "-x-generic"_L1;
248 }
249 return genericIconName;
250}
251
253{
254 const qsizetype slashindex = iconName.indexOf(u'/');
255 if (slashindex != -1)
256 iconName[slashindex] = u'-';
257 return iconName;
258}
259
260/*!
261 \property QMimeType::iconName
262 \brief the file name of an icon image that represents the MIME type
263
264 The icon name can be given to QIcon::fromTheme() in order to load the icon.
265
266 While this property was introduced in 5.10, the
267 corresponding accessor method has always been there.
268 */
269QString QMimeType::iconName() const
270{
271 QString iconName = QMimeDatabasePrivate::instance()->icon(d->name);
272 if (iconName.isEmpty()) {
273 return make_default_icon_name_from_mimetype_name(name());
274 }
275 return iconName;
276}
277
278/*!
279 \property QMimeType::globPatterns
280 \brief the list of glob matching patterns
281
282 While this property was introduced in 5.10, the
283 corresponding accessor method has always been there.
284 */
285QStringList QMimeType::globPatterns() const
286{
287 return QMimeDatabasePrivate::instance()->globPatterns(d->name);
288}
289
290/*!
291 \property QMimeType::parentMimeTypes
292 \brief the names of parent MIME types
293
294 A type is a subclass of another type if any instance of the first type is
295 also an instance of the second. For example, all image/svg+xml files are also
296 text/xml, text/plain and application/octet-stream files. Subclassing is about
297 the format, rather than the category of the data (for example, there is no
298 'generic spreadsheet' class that all spreadsheets inherit from).
299 Conversely, the parent mimetype of image/svg+xml is text/xml.
300
301 A mimetype can have multiple parents. For instance application/x-perl
302 has two parents: application/x-executable and text/plain. This makes
303 it possible to both execute perl scripts, and to open them in text editors.
304
305 While this property was introduced in 5.10, the
306 corresponding accessor method has always been there.
307*/
308QStringList QMimeType::parentMimeTypes() const
309{
310 return QMimeDatabasePrivate::instance()->mimeParents(d->name);
311}
312
313static void collectParentMimeTypes(const QString &mime, QStringList &allParents)
314{
315 const QStringList parents = QMimeDatabasePrivate::instance()->mimeParents(mime);
316 QStringList newParents;
317 for (const QString &parent : parents) {
318 // I would use QSet, but since order matters I better not
319 if (!allParents.contains(parent)) {
320 allParents.append(parent);
321 newParents.append(parent);
322 }
323 }
324 // We want a breadth-first search, so that the least-specific parent (octet-stream) is last
325 // This means iterating twice, unfortunately.
326 for (const QString &parent : newParents)
327 collectParentMimeTypes(parent, allParents);
328}
329
330/*!
331 \property QMimeType::allAncestors
332 \brief the names of direct and indirect parent MIME types
333
334 Return all the parent mimetypes of this mimetype, direct and indirect.
335 This includes the parent(s) of its parent(s), etc.
336
337 For instance, for image/svg+xml the list would be:
338 application/xml, text/plain, application/octet-stream.
339
340 Note that application/octet-stream is the ultimate parent for all types
341 of files (but not directories).
342
343 While this property was introduced in 5.10, the
344 corresponding accessor method has always been there.
345*/
346QStringList QMimeType::allAncestors() const
347{
348 QStringList allParents;
349 collectParentMimeTypes(d->name, allParents);
350 return allParents;
351}
352
353/*!
354 \property QMimeType::aliases
355 \brief the list of aliases of this mimetype
356
357 For instance, for text/csv, the returned list would be:
358 text/x-csv, text/x-comma-separated-values.
359
360 Note that all QMimeType instances refer to proper mimetypes,
361 never to aliases directly.
362
363 The order of the aliases in the list is undefined.
364
365 While this property was introduced in 5.10, the
366 corresponding accessor method has always been there.
367*/
368QStringList QMimeType::aliases() const
369{
370 return QMimeDatabasePrivate::instance()->listAliases(d->name);
371}
372
373/*!
374 \property QMimeType::suffixes
375 \brief the known suffixes for the MIME type
376
377 No leading dot is included, so for instance this would return "jpg", "jpeg" for image/jpeg.
378
379 While this property was introduced in 5.10, the
380 corresponding accessor method has always been there.
381 */
382QStringList QMimeType::suffixes() const
383{
384 const QStringList patterns = globPatterns();
385
386 QStringList result;
387 result.reserve(patterns.size());
388 for (const QString &pattern : patterns) {
389 // Not a simple suffix if it looks like: README or *. or *.* or *.JP*G or *.JP?
390 if (pattern.startsWith("*."_L1) &&
391 pattern.size() > 2 &&
392 pattern.indexOf(u'*', 2) < 0 && pattern.indexOf(u'?', 2) < 0) {
393 const QString suffix = pattern.mid(2);
394 result.append(suffix);
395 }
396 }
397
398 return result;
399}
400
401/*!
402 \property QMimeType::preferredSuffix
403 \brief the preferred suffix for the MIME type
404
405 No leading dot is included, so for instance this would return "pdf" for application/pdf.
406 The return value can be empty, for mime types which do not have any suffixes associated.
407
408 While this property was introduced in 5.10, the
409 corresponding accessor method has always been there.
410 */
411QString QMimeType::preferredSuffix() const
412{
413 if (isDefault()) // workaround for unwanted *.bin suffix for octet-stream, https://bugs.freedesktop.org/show_bug.cgi?id=101667, fixed upstream in 1.10
414 return QString();
415 const QStringList suffixList = suffixes();
416 return suffixList.isEmpty() ? QString() : suffixList.at(0);
417}
418
419/*!
420 \property QMimeType::filterString
421 \brief a filter string usable for a file dialog
422
423 While this property was introduced in 5.10, the
424 corresponding accessor method has always been there.
425*/
426QString QMimeType::filterString() const
427{
428 const QStringList patterns = globPatterns();
429 QString filter;
430
431 if (!patterns.isEmpty()) {
432 filter = comment() + " ("_L1 + patterns.join(u' ') + u')';
433 }
434
435 return filter;
436}
437
438/*!
439 \fn bool QMimeType::inherits(const QString &mimeTypeName) const;
440 Returns \c true if this mimetype is \a mimeTypeName,
441 or inherits \a mimeTypeName (see parentMimeTypes()),
442 or \a mimeTypeName is an alias for this mimetype.
443
444 This method has been made invokable from QML since 5.10.
445 */
446bool QMimeType::inherits(const QString &mimeTypeName) const
447{
448 if (d->name == mimeTypeName)
449 return true;
450 return QMimeDatabasePrivate::instance()->mimeInherits(d->name, mimeTypeName);
451}
452
453#ifndef QT_NO_DEBUG_STREAM
454QDebug operator<<(QDebug debug, const QMimeType &mime)
455{
456 QDebugStateSaver saver(debug);
457 if (!mime.isValid()) {
458 debug.nospace() << "QMimeType(invalid)";
459 } else {
460 debug.nospace() << "QMimeType(" << mime.name() << ")";
461 }
462 return debug;
463}
464#endif
465
466QT_END_NAMESPACE
467
468#include "moc_qmimetype.cpp"
static QMimeDatabasePrivate * instance()
static QString make_default_icon_name_from_mimetype_name(QString iconName)
bool comparesEqual(const QMimeType &lhs, const QMimeType &rhs) noexcept
size_t qHash(const QMimeType &key, size_t seed) noexcept
static void collectParentMimeTypes(const QString &mime, QStringList &allParents)