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