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