1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
5 **
6 ** This file is part of the QtCore module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser General Public
11 ** License version 2.1 as published by the Free Software Foundation and
12 ** appearing in the file LICENSE.LGPL included in the packaging of this
13 ** file. Please review the following information to ensure the GNU Lesser
14 ** General Public License version 2.1 requirements will be met:
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
16 **
17 ** In addition, as a special exception, Nokia gives you certain additional
18 ** rights. These rights are described in the Nokia Qt LGPL Exception
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
20 **
21 ** GNU General Public License Usage
22 ** Alternatively, this file may be used under the terms of the GNU General
23 ** Public License version 3.0 as published by the Free Software Foundation
24 ** and appearing in the file LICENSE.GPL included in the packaging of this
25 ** file. Please review the following information to ensure the GNU General
26 ** Public License version 3.0 requirements will be met:
27 ** http://www.gnu.org/copyleft/gpl.html.
28 **
29 ** Other Usage
30 ** Alternatively, this file may be used in accordance with the terms and
31 ** conditions contained in a signed written agreement between you and Nokia.
32 **
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include <NBMimeType.hpp>
43 #include <NBMimeType_p.hpp>
44 #include <NBMimeDatabase_p.hpp>
45 #include <NBMimeProvider_p.hpp>
46 #include <NBMimeGlobPattern_p.hpp>
47
48 #include <QDebug>
49 #include <QLocale>
50
51 #include <memory>
52
53 bool qt_isQMimeTypeDebuggingActivated (false);
54
55 #ifndef QT_NO_DEBUG_OUTPUT
56 #define DBG() if (qt_isQMimeTypeDebuggingActivated) qDebug() << static_cast<const void *>(this) << Q_FUNC_INFO
57 #else
58 #define DBG() if (0) qDebug() << static_cast<const void *>(this) << Q_FUNC_INFO
59 #endif
60
QMimeTypePrivate()61 QMimeTypePrivate::QMimeTypePrivate()
62 {}
63
QMimeTypePrivate(const QMimeType & other)64 QMimeTypePrivate::QMimeTypePrivate(const QMimeType &other)
65 : name(other.d->name),
66 localeComments(other.d->localeComments),
67 genericIconName(other.d->genericIconName),
68 iconName(other.d->iconName),
69 globPatterns(other.d->globPatterns)
70 {}
71
clear()72 void QMimeTypePrivate::clear()
73 {
74 name.clear();
75 localeComments.clear();
76 genericIconName.clear();
77 iconName.clear();
78 globPatterns.clear();
79 }
80
81 /*!
82 \fn bool QMimeTypePrivate::operator==(const QMimeTypePrivate &other) const;
83 Returns true if \a other equals this QMimeTypePrivate object, otherwise returns false.
84 */
operator ==(const QMimeTypePrivate & other) const85 bool QMimeTypePrivate::operator==(const QMimeTypePrivate &other) const
86 {
87 DBG();
88 if (name == other.name &&
89 localeComments == other.localeComments &&
90 genericIconName == other.genericIconName &&
91 iconName == other.iconName &&
92 globPatterns == other.globPatterns) {
93 return true;
94 }
95
96 DBG() << name << other.name << (name == other.name);
97 //DBG() << comment << other.comment << (comment == other.comment);
98 DBG() << localeComments << other.localeComments << (localeComments == other.localeComments);
99 DBG() << genericIconName << other.genericIconName << (genericIconName == other.genericIconName);
100 DBG() << iconName << other.iconName << (iconName == other.iconName);
101 DBG() << globPatterns << other.globPatterns << (globPatterns == other.globPatterns);
102 return false;
103 }
104
addGlobPattern(const QString & pattern)105 void QMimeTypePrivate::addGlobPattern(const QString &pattern)
106 {
107 globPatterns.append(pattern);
108 }
109
110 /*!
111 \class QMimeType
112 \brief The QMimeType class describes types of file or data, represented by a MIME type string.
113
114 \since 5.0
115
116 For instance a file named "readme.txt" has the MIME type "text/plain".
117 The MIME type can be determined from the file name, or from the file
118 contents, or from both. MIME type determination can also be done on
119 buffers of data not coming from files.
120
121 Determining the MIME type of a file can be useful to make sure your
122 application supports it. It is also useful in file-manager-like applications
123 or widgets, in order to display an appropriate icon() for the file, or even
124 the descriptive comment() in detailed views.
125
126 To check if a file has the expected MIME type, you should use inherits()
127 rather than a simple string comparison based on the name(). This is because
128 MIME types can inherit from each other: for instance a C source file is
129 a specific type of plain text file, so text/x-csrc inherits text/plain.
130
131 \sa QMimeDatabase
132 */
133
134 /*!
135 \fn QMimeType::QMimeType();
136 Constructs this QMimeType object initialized with default property values that indicate an invalid MIME type.
137 */
QMimeType()138 QMimeType::QMimeType() :
139 d(new QMimeTypePrivate())
140 {
141 DBG() << "name():" << name();
142 //DBG() << "aliases():" << aliases();
143 //DBG() << "comment():" << comment();
144 DBG() << "genericIconName():" << genericIconName();
145 DBG() << "iconName():" << iconName();
146 DBG() << "globPatterns():" << globPatterns();
147 DBG() << "suffixes():" << suffixes();
148 DBG() << "preferredSuffix():" << preferredSuffix();
149 }
150
151 /*!
152 \fn QMimeType::QMimeType(const QMimeType &other);
153 Constructs this QMimeType object as a copy of \a other.
154 */
QMimeType(const QMimeType & other)155 QMimeType::QMimeType(const QMimeType &other) :
156 d(other.d)
157 {
158 DBG() << "name():" << name();
159 //DBG() << "aliases():" << aliases();
160 //DBG() << "comment():" << comment();
161 DBG() << "genericIconName():" << genericIconName();
162 DBG() << "iconName():" << iconName();
163 DBG() << "globPatterns():" << globPatterns();
164 DBG() << "suffixes():" << suffixes();
165 DBG() << "preferredSuffix():" << preferredSuffix();
166 }
167
168 /*!
169 \fn QMimeType &QMimeType::operator=(const QMimeType &other);
170 Assigns the data of \a other to this QMimeType object, and returns a reference to this object.
171 */
operator =(const QMimeType & other)172 QMimeType &QMimeType::operator=(const QMimeType &other)
173 {
174 if (d != other.d)
175 d = other.d;
176 return *this;
177 }
178
179 /*!
180 \fn QMimeType::QMimeType(const QMimeTypePrivate &dd);
181 Assigns the data of the QMimeTypePrivate \a dd to this QMimeType object, and returns a reference to this object.
182 */
QMimeType(const QMimeTypePrivate & dd)183 QMimeType::QMimeType(const QMimeTypePrivate &dd) :
184 d(new QMimeTypePrivate(dd))
185 {
186 DBG() << "name():" << name();
187 //DBG() << "aliases():" << aliases();
188 //DBG() << "comment():" << comment();
189 DBG() << "genericIconName():" << genericIconName();
190 DBG() << "iconName():" << iconName();
191 DBG() << "globPatterns():" << globPatterns();
192 DBG() << "suffixes():" << suffixes();
193 DBG() << "preferredSuffix():" << preferredSuffix();
194 }
195
196 /*!
197 \fn void QMimeType::swap(QMimeType &other);
198 Swaps QMimeType \a other with this QMimeType object.
199
200 This operation is very fast and never fails.
201
202 The swap() method helps with the implementation of assignment
203 operators in an exception-safe way. For more information consult
204 \l {http://en.wikibooks.org/wiki/More_C++_Idioms/Copy-and-swap}
205 {More C++ Idioms - Copy-and-swap}.
206 */
207
208 /*!
209 \fn QMimeType::~QMimeType();
210 Destroys the QMimeType object, and releases the d pointer.
211 */
~QMimeType()212 QMimeType::~QMimeType()
213 {
214 DBG() << "name():" << name();
215 //DBG() << "aliases():" << aliases();
216 //DBG() << "comment():" << comment();
217 DBG() << "genericIconName():" << genericIconName();
218 DBG() << "iconName():" << iconName();
219 DBG() << "globPatterns():" << globPatterns();
220 DBG() << "suffixes():" << suffixes();
221 DBG() << "preferredSuffix():" << preferredSuffix();
222 }
223
224 /*!
225 \fn bool QMimeType::operator==(const QMimeType &other) const;
226 Returns true if \a other equals this QMimeType object, otherwise returns false.
227 */
operator ==(const QMimeType & other) const228 bool QMimeType::operator==(const QMimeType &other) const
229 {
230 return d == other.d || *d == *other.d;
231 }
232
233 /*!
234 \fn bool QMimeType::operator!=(const QMimeType &other) const;
235 Returns true if \a other does not equal this QMimeType object, otherwise returns false.
236 */
237
238 /*!
239 \fn bool QMimeType::isValid() const;
240 Returns true if the QMimeType object contains valid data, otherwise returns false.
241 A valid MIME type has a non-empty name().
242 The invalid MIME type is the default-constructed QMimeType.
243 */
isValid() const244 bool QMimeType::isValid() const
245 {
246 return !d->name.isEmpty();
247 }
248
249 /*!
250 \fn bool QMimeType::isDefault() const;
251 Returns true if this MIME type is the default MIME type which
252 applies to all files: application/octet-stream.
253 */
isDefault() const254 bool QMimeType::isDefault() const
255 {
256 return d->name == QMimeDatabasePrivate::instance()->defaultMimeType();
257 }
258
259 /*!
260 \fn QString QMimeType::name() const;
261 Returns the name of the MIME type.
262 */
name() const263 QString QMimeType::name() const
264 {
265 return d->name;
266 }
267
268 /*!
269 Returns the description of the MIME type to be displayed on user interfaces.
270
271 The system language (QLocale::system().name()) is used to select the appropriate translation.
272 */
comment() const273 QString QMimeType::comment() const
274 {
275 QMimeDatabasePrivate::instance()->provider()->loadMimeTypePrivate(*d);
276
277 QStringList languageList;
278 languageList << QLocale::system().name();
279 /*temporally workaround until i learn the code behind the qt 4.8 api for locales */
280 #if QT_VERSION >= 0x040800
281 languageList << QLocale::system().uiLanguages();
282 #endif
283 Q_FOREACH (const QString &language, languageList) {
284 const QString lang = language == QLatin1String("C") ? QLatin1String("en_US") : language;
285 const QString comm = d->localeComments.value(lang);
286 if (!comm.isEmpty())
287 return comm;
288 const int pos = lang.indexOf(QLatin1Char('_'));
289 if (pos != -1) {
290 // "pt_BR" not found? try just "pt"
291 const QString shortLang = lang.left(pos);
292 const QString commShort = d->localeComments.value(shortLang);
293 if (!commShort.isEmpty())
294 return commShort;
295 }
296 }
297
298 // Use the mimetype name as fallback
299 return d->name;
300 }
301
302 /*!
303 \fn QString QMimeType::genericIconName() const;
304 Returns the file name of a generic icon that represents the MIME type.
305
306 This should be used if the icon returned by iconName() cannot be found on
307 the system. It is used for categories of similar types (like spreadsheets
308 or archives) that can use a common icon.
309 The freedesktop.org Icon Naming Specification lists a set of such icon names.
310
311 The icon name can be given to QIcon::fromTheme() in order to load the icon.
312 */
genericIconName() const313 QString QMimeType::genericIconName() const
314 {
315 QMimeDatabasePrivate::instance()->provider()->loadGenericIcon(*d);
316 if (d->genericIconName.isEmpty()) {
317 // From the spec:
318 // If the generic icon name is empty (not specified by the mimetype definition)
319 // then the mimetype is used to generate the generic icon by using the top-level
320 // media type (e.g. "video" in "video/ogg") and appending "-x-generic"
321 // (i.e. "video-x-generic" in the previous example).
322 QString group = name();
323 const int slashindex = group.indexOf(QLatin1Char('/'));
324 if (slashindex != -1)
325 group = group.left(slashindex);
326 return group + QLatin1String("-x-generic");
327 }
328 return d->genericIconName;
329 }
330
331 /*!
332 \fn QString QMimeType::iconName() const;
333 Returns the file name of an icon image that represents the MIME type.
334
335 The icon name can be given to QIcon::fromTheme() in order to load the icon.
336 */
iconName() const337 QString QMimeType::iconName() const
338 {
339 QMimeDatabasePrivate::instance()->provider()->loadIcon(*d);
340 if (d->iconName.isEmpty()) {
341 // Make default icon name from the mimetype name
342 d->iconName = name();
343 const int slashindex = d->iconName.indexOf(QLatin1Char('/'));
344 if (slashindex != -1)
345 d->iconName[slashindex] = QLatin1Char('-');
346 }
347 return d->iconName;
348 }
349
350 /*!
351 \fn QStringList QMimeType::globPatterns() const;
352 Returns the list of glob matching patterns.
353 */
globPatterns() const354 QStringList QMimeType::globPatterns() const
355 {
356 QMimeDatabasePrivate::instance()->provider()->loadMimeTypePrivate(*d);
357 return d->globPatterns;
358 }
359
360 /*!
361 A type is a subclass of another type if any instance of the first type is
362 also an instance of the second. For example, all image/svg+xml files are also
363 text/xml, text/plain and application/octet-stream files. Subclassing is about
364 the format, rather than the category of the data (for example, there is no
365 'generic spreadsheet' class that all spreadsheets inherit from).
366 Conversely, the parent mimetype of image/svg+xml is text/xml.
367
368 A mimetype can have multiple parents. For instance application/x-perl
369 has two parents: application/x-executable and text/plain. This makes
370 it possible to both execute perl scripts, and to open them in text editors.
371 */
parentMimeTypes() const372 QStringList QMimeType::parentMimeTypes() const
373 {
374 return QMimeDatabasePrivate::instance()->provider()->parents(d->name);
375 }
376
collectParentMimeTypes(const QString & mime,QStringList & allParents)377 static void collectParentMimeTypes(const QString &mime, QStringList &allParents)
378 {
379 QStringList parents = QMimeDatabasePrivate::instance()->provider()->parents(mime);
380 foreach (const QString &parent, parents) {
381 // I would use QSet, but since order matters I better not
382 if (!allParents.contains(parent))
383 allParents.append(parent);
384 }
385 // We want a breadth-first search, so that the least-specific parent (octet-stream) is last
386 // This means iterating twice, unfortunately.
387 foreach (const QString &parent, parents) {
388 collectParentMimeTypes(parent, allParents);
389 }
390 }
391
392 /*!
393 Return all the parent mimetypes of this mimetype, direct and indirect.
394 This includes the parent(s) of its parent(s), etc.
395
396 For instance, for image/svg+xml the list would be:
397 application/xml, text/plain, application/octet-stream.
398
399 Note that application/octet-stream is the ultimate parent for all types
400 of files (but not directories).
401 */
allAncestors() const402 QStringList QMimeType::allAncestors() const
403 {
404 QStringList allParents;
405 collectParentMimeTypes(d->name, allParents);
406 return allParents;
407 }
408
409 /*!
410 \fn QStringList QMimeType::suffixes() const;
411 Returns the known suffixes for the MIME type.
412 */
suffixes() const413 QStringList QMimeType::suffixes() const
414 {
415 QMimeDatabasePrivate::instance()->provider()->loadMimeTypePrivate(*d);
416
417 QStringList result;
418 foreach (const QString &pattern, d->globPatterns) {
419 // Not a simple suffix if if looks like: README or *. or *.* or *.JP*G or *.JP?
420 if (pattern.startsWith(QLatin1String("*.")) &&
421 pattern.length() > 2 &&
422 pattern.indexOf(QLatin1Char('*'), 2) < 0 && pattern.indexOf(QLatin1Char('?'), 2) < 0) {
423 const QString suffix = pattern.mid(2);
424 result.append(suffix);
425 }
426 }
427
428 return result;
429 }
430
431 /*!
432 \fn QString QMimeType::preferredSuffix() const;
433 Returns the preferred suffix for the MIME type.
434 */
preferredSuffix() const435 QString QMimeType::preferredSuffix() const
436 {
437 const QStringList suffixList = suffixes();
438 return suffixList.isEmpty() ? QString() : suffixList.at(0);
439 }
440
441 /*!
442 \fn QString QMimeType::filterString() const;
443 Returns a filter string usable for a file dialog.
444 */
filterString() const445 QString QMimeType::filterString() const
446 {
447 QMimeDatabasePrivate::instance()->provider()->loadMimeTypePrivate(*d);
448 QString filter;
449
450 if (!d->globPatterns.empty()) {
451 filter += comment() + QLatin1String(" (");
452 for (int i = 0; i < d->globPatterns.size(); ++i) {
453 if (i != 0)
454 filter += QLatin1Char(' ');
455 filter += d->globPatterns.at(i);
456 }
457 filter += QLatin1Char(')');
458 }
459
460 return filter;
461 }
462
463 /*!
464 \fn bool QMimeType::inherits(const QString &mimeTypeName) const;
465 Returns true if this mimetype is \a mimeTypeName,
466 or inherits \a mimeTypeName (see parentMimeTypes()),
467 or \a mimeTypeName is an alias for this mimetype.
468 */
inherits(const QString & mimeTypeName) const469 bool QMimeType::inherits(const QString &mimeTypeName) const
470 {
471 if (d->name == mimeTypeName)
472 return true;
473 return QMimeDatabasePrivate::instance()->inherits(d->name, mimeTypeName);
474 }
475
476 #undef DBG
477
478 QT_END_NAMESPACE
479