MIME types: Introduce user extensions feature

Creates a new page in the options dialog which allows
the user to modify MIME type's globl patterns and rule-based
magic matchers.

As a side-effect of this feature our MIME database (and related
components) got some improvements.

Reviewed-by: Friedemann Kleint
This commit is contained in:
Leandro Melo
2011-02-22 15:11:50 +01:00
parent c8f19854f9
commit 3db53206c2
15 changed files with 1964 additions and 111 deletions

View File

@@ -33,6 +33,7 @@
#include "mimedatabase.h"
#include "coreconstants.h"
#include "icore.h"
#include <utils/qtcassert.h>
@@ -40,9 +41,11 @@
#include <QtCore/QCoreApplication>
#include <QtCore/QDebug>
#include <QtCore/QFile>
#include <QtCore/QDir>
#include <QtCore/QFileInfo>
#include <QtCore/QLocale>
#include <QtCore/QMap>
#include <QtCore/QHash>
#include <QtCore/QMultiHash>
#include <QtCore/QRegExp>
#include <QtCore/QSharedData>
@@ -50,10 +53,11 @@
#include <QtCore/QStringList>
#include <QtCore/QTextStream>
#include <QtCore/QMutexLocker>
#include <QtXml/QXmlStreamReader>
#include <QtCore/QXmlStreamReader>
#include <QtCore/QXmlStreamWriter>
#include <algorithm>
#include <functional>
enum { debugMimeDB = 0 };
@@ -211,6 +215,8 @@ bool HeuristicTextMagicMatcher::matches(const QByteArray &data) const
} // namespace Internal
// MagicRule
const QChar MagicRule::kColon(QLatin1Char(':'));
MagicRule::MagicRule(int startPos, int endPos) : m_startPos(startPos), m_endPos(endPos)
{
}
@@ -229,6 +235,20 @@ int MagicRule::endPos() const
return m_endPos;
}
QString MagicRule::toOffset(const QPair<int, int> &startEnd)
{
return QString(QLatin1String("%1:%2")).arg(startEnd.first).arg(startEnd.second);
}
QPair<int, int> MagicRule::fromOffset(const QString &offset)
{
const QStringList &startEnd = offset.split(kColon);
Q_ASSERT(startEnd.size() == 2);
return qMakePair(startEnd.at(0).toInt(), startEnd.at(1).toInt());
}
const QString MagicStringRule::kMatchType("string");
MagicStringRule::MagicStringRule(const QString &s, int startPos, int endPos) :
MagicRule(startPos, endPos), m_pattern(s.toUtf8())
{
@@ -238,6 +258,16 @@ MagicStringRule::~MagicStringRule()
{
}
QString MagicStringRule::matchType() const
{
return kMatchType;
}
QString MagicStringRule::matchValue() const
{
return m_pattern;
}
bool MagicStringRule::matches(const QByteArray &data) const
{
// Quick check
@@ -254,28 +284,51 @@ bool MagicStringRule::matches(const QByteArray &data) const
return rc;
}
const QString MagicByteRule::kMatchType(QLatin1String("byte"));
MagicByteRule::MagicByteRule(const QString &s, int startPos, int endPos) :
MagicRule(startPos, endPos)
MagicRule(startPos, endPos), m_bytesSize(0)
{
// Expect an hex format value like this: \0x7f\0x45\0x4c\0x46
const QStringList &bytes = s.split(QLatin1Char('\\'), QString::SkipEmptyParts);
foreach (const QString &byte, bytes) {
bool ok;
const int hex = byte.toInt(&ok, 16);
if (ok) {
m_bytes.push_back(hex);
} else {
m_bytes.clear();
break;
}
}
m_bytesSize = m_bytes.size();
if (validateByteSequence(s, &m_bytes))
m_bytesSize = m_bytes.size();
else
m_bytes.clear();
}
MagicByteRule::~MagicByteRule()
{
}
bool MagicByteRule::validateByteSequence(const QString &sequence, QList<int> *bytes)
{
// Expect an hex format value like this: \0x7f\0x45\0x4c\0x46
const QStringList &byteSequence = sequence.split(QLatin1Char('\\'), QString::SkipEmptyParts);
foreach (const QString &byte, byteSequence) {
bool ok;
const int hex = byte.toInt(&ok, 16);
if (ok) {
if (bytes)
bytes->push_back(hex);
} else {
return false;
}
}
return true;
}
QString MagicByteRule::matchType() const
{
return kMatchType;
}
QString MagicByteRule::matchValue() const
{
QString value;
foreach (int byte, m_bytes)
value.append(QString(QLatin1String("\\0x%1")).arg(byte, 0, 16));
return value;
}
bool MagicByteRule::matches(const QByteArray &data) const
{
if (m_bytesSize == 0)
@@ -307,7 +360,17 @@ MagicRuleMatcher::MagicRuleMatcher() :
void MagicRuleMatcher::add(const MagicRuleSharedPointer &rule)
{
m_list.push_back(rule);
m_list.append(rule);
}
void MagicRuleMatcher::add(const MagicRuleList &ruleList)
{
m_list.append(ruleList);
}
MagicRuleMatcher::MagicRuleList MagicRuleMatcher::magicRules() const
{
return m_list;
}
bool MagicRuleMatcher::matches(const QByteArray &data) const
@@ -329,6 +392,20 @@ void MagicRuleMatcher::setPriority(int p)
m_priority = p;
}
IMagicMatcher::IMagicMatcherList MagicRuleMatcher::createMatchers(
const QHash<int, MagicRuleList> &rulesByPriority)
{
IMagicMatcher::IMagicMatcherList matchers;
QHash<int, MagicRuleList>::const_iterator ruleIt = rulesByPriority.begin();
for (; ruleIt != rulesByPriority.end(); ++ruleIt) {
MagicRuleMatcher *magicRuleMatcher = new MagicRuleMatcher();
magicRuleMatcher->setPriority(ruleIt.key());
magicRuleMatcher->add(ruleIt.value());
matchers.append(IMagicMatcher::IMagicMatcherSharedPointer(magicRuleMatcher));
}
return matchers;
}
// GlobPattern
MimeGlobPattern::MimeGlobPattern(const QRegExp &regExp, unsigned weight) :
m_regExp(regExp), m_weight(weight)
@@ -353,9 +430,16 @@ unsigned MimeGlobPattern::weight() const
class MimeTypeData : public QSharedData {
public:
typedef QHash<QString,QString> LocaleHash;
MimeTypeData();
void clear();
void assignSuffix(const QString &pattern);
void assignSuffixes(const QStringList &patterns);
void debug(QTextStream &str, int indent = 0) const;
const QRegExp suffixPattern;
QString type;
QString comment;
@@ -365,12 +449,17 @@ public:
QStringList subClassesOf;
QString preferredSuffix;
QStringList suffixes;
typedef QSharedPointer<IMagicMatcher> IMagicMatcherSharedPointer;
typedef QList<IMagicMatcherSharedPointer> IMagicMatcherList;
IMagicMatcherList magicMatchers;
IMagicMatcher::IMagicMatcherList magicMatchers;
};
MimeTypeData::MimeTypeData()
// RE to match a suffix glob pattern: "*.ext" (and not sth like "Makefile" or
// "*.log[1-9]"
: suffixPattern(QLatin1String("^\\*\\.[\\w+]+$"))
{
QTC_ASSERT(suffixPattern.isValid(), /**/);
}
void MimeTypeData::clear()
{
type.clear();
@@ -383,6 +472,22 @@ void MimeTypeData::clear()
magicMatchers.clear();
}
void MimeTypeData::assignSuffix(const QString &pattern)
{
if (suffixPattern.exactMatch(pattern)) {
const QString suffix = pattern.right(pattern.size() - 2);
suffixes.push_back(suffix);
if (preferredSuffix.isEmpty())
preferredSuffix = suffix;
}
}
void MimeTypeData::assignSuffixes(const QStringList &patterns)
{
foreach (const QString &pattern, patterns)
assignSuffix(pattern);
}
void MimeTypeData::debug(QTextStream &str, int indent) const
{
const QString indentS = QString(indent, QLatin1Char(' '));
@@ -516,6 +621,13 @@ QList<MimeGlobPattern> MimeType::globPatterns() const
void MimeType::setGlobPatterns(const QList<MimeGlobPattern> &g)
{
m_d->globPatterns = g;
QString oldPrefferedSuffix = m_d->preferredSuffix;
m_d->suffixes.clear();
m_d->preferredSuffix.clear();
m_d->assignSuffixes(MimeDatabase::fromGlobPatterns(g));
if (m_d->preferredSuffix != oldPrefferedSuffix && m_d->suffixes.contains(oldPrefferedSuffix))
m_d->preferredSuffix = oldPrefferedSuffix;
}
QStringList MimeType::subClassesOf() const
@@ -608,7 +720,7 @@ unsigned MimeType::matchesFileByContent(Internal::FileMatchContext &c) const
const QByteArray data = c.data();
if (!data.isEmpty()) {
foreach (const MimeTypeData::IMagicMatcherSharedPointer &matcher, m_d->magicMatchers) {
foreach (const IMagicMatcher::IMagicMatcherSharedPointer &matcher, m_d->magicMatchers) {
if (matcher->matches(data)) {
const unsigned magicPriority = matcher->priority();
if (magicPriority > priority)
@@ -624,16 +736,52 @@ QStringList MimeType::suffixes() const
return m_d->suffixes;
}
void MimeType::setSuffixes(const QStringList &s)
{
m_d->suffixes = s;
}
void MimeType::addMagicMatcher(const QSharedPointer<IMagicMatcher> &matcher)
void MimeType::addMagicMatcher(const IMagicMatcherSharedPointer &matcher)
{
m_d->magicMatchers.push_back(matcher);
}
const MimeType::IMagicMatcherList &MimeType::magicMatchers() const
{
return m_d->magicMatchers;
}
void MimeType::setMagicMatchers(const IMagicMatcherList &matchers)
{
m_d->magicMatchers = matchers;
}
namespace {
struct RemovePred : std::unary_function<MimeType::IMagicMatcherSharedPointer, bool>
{
RemovePred(bool keepRuleBased) : m_keepRuleBase(keepRuleBased) {}
bool m_keepRuleBase;
bool operator()(const MimeType::IMagicMatcherSharedPointer &matcher) {
if ((m_keepRuleBase && !dynamic_cast<MagicRuleMatcher *>(matcher.data()))
|| (!m_keepRuleBase && dynamic_cast<MagicRuleMatcher *>(matcher.data())))
return true;
return false;
}
};
} // Anonymous
MimeType::IMagicMatcherList MimeType::magicRuleMatchers() const
{
IMagicMatcherList ruleMatchers = m_d->magicMatchers;
ruleMatchers.erase(std::remove_if(ruleMatchers.begin(), ruleMatchers.end(), RemovePred(true)),
ruleMatchers.end());
return ruleMatchers;
}
void MimeType::setMagicRuleMatchers(const IMagicMatcherList &matchers)
{
m_d->magicMatchers.erase(std::remove_if(m_d->magicMatchers.begin(), m_d->magicMatchers.end(),
RemovePred(false)),
m_d->magicMatchers.end());
m_d->magicMatchers.append(matchers);
}
QDebug operator<<(QDebug d, const MimeType &mt)
{
QString s;
@@ -652,7 +800,7 @@ namespace Internal {
class BaseMimeTypeParser {
Q_DISABLE_COPY(BaseMimeTypeParser)
public:
BaseMimeTypeParser();
BaseMimeTypeParser() {}
virtual ~BaseMimeTypeParser() {}
bool parse(QIODevice *dev, const QString &fileName, QString *errorMessage);
@@ -676,18 +824,8 @@ private:
ParseError };
static ParseStage nextStage(ParseStage currentStage, const QStringRef &startElement);
const QRegExp m_suffixPattern;
};
BaseMimeTypeParser:: BaseMimeTypeParser() :
// RE to match a suffix glob pattern: "*.ext" (and not sth like "Makefile" or
// "*.log[1-9]"
m_suffixPattern(QLatin1String("^\\*\\.[\\w+]+$"))
{
QTC_ASSERT(m_suffixPattern.isValid(), /**/);
}
void BaseMimeTypeParser::addGlobPattern(const QString &pattern, const QString &weight, MimeTypeData *d) const
{
if (pattern.isEmpty())
@@ -706,12 +844,7 @@ void BaseMimeTypeParser::addGlobPattern(const QString &pattern, const QString &w
else
d->globPatterns.push_back(MimeGlobPattern(wildCard, weight.toInt()));
if (m_suffixPattern.exactMatch(pattern)) {
const QString suffix = pattern.right(pattern.size() - 2);
d->suffixes.push_back(suffix);
if (d->preferredSuffix.isEmpty())
d->preferredSuffix = suffix;
}
d->assignSuffix(pattern);
}
BaseMimeTypeParser::ParseStage BaseMimeTypeParser::nextStage(ParseStage currentStage, const QStringRef &startElement)
@@ -934,10 +1067,10 @@ MimeMapEntry::MimeMapEntry(const MimeType &t, int aLevel) :
* - Provide quick lookup by file type.
* This basically rules out some pointer-based tree, so the structure chosen
* is:
* - An alias map <QString->QString> for mapping aliases to types
* - A Map <QString-MimeMapEntry> for the types (MimeMapEntry being a pair of
* - An alias map QString->QString for mapping aliases to types
* - A Map QString->MimeMapEntry for the types (MimeMapEntry being a pair of
* MimeType and (hierarchy) level.
* - A map <QString->QString> representing parent->child relations (enabling
* - A map QString->QString representing parent->child relations (enabling
* recursing over children)
* Using strings avoids dangling pointers.
* The hierarchy level is used for mapping by file types. When findByFile()
@@ -958,16 +1091,31 @@ public:
bool addMimeTypes(QIODevice *device, QString *errorMessage);
bool addMimeType(MimeType mt);
// Returns a mime type or Null one if none found
MimeType findByType(const QString &type) const;
// Returns a mime type or Null one if none found
MimeType findByFile(const QFileInfo &f) const;
QStringList filterStrings() const;
QStringList suffixes() const;
bool setPreferredSuffix(const QString &typeOrAlias, const QString &suffix);
// Return all known suffixes
QStringList suffixes() const;
QStringList filterStrings() const;
QList<MimeGlobPattern> globPatterns() const;
void setGlobPatterns(const QString &typeOrAlias, const QList<MimeGlobPattern> &globPatterns);
QList<QSharedPointer<IMagicMatcher> > magicMatchers() const;
void setMagicMatchers(const QString &typeOrAlias,
const QList<QSharedPointer<IMagicMatcher> > &matchers);
QList<MimeType> mimeTypes() const;
void syncUserModifiedMimeTypes();
static QList<MimeType> readUserModifiedMimeTypes();
static void writeUserModifiedMimeTypes(const QList<MimeType> &mimeTypes);
void clearUserModifiedMimeTypes();
static QList<MimeGlobPattern> toGlobPatterns(const QStringList &patterns,
int weight = MimeGlobPattern::MaxWeight);
static QStringList fromGlobPatterns(const QList<MimeGlobPattern> &globPatterns);
void debug(QTextStream &str) const;
@@ -976,6 +1124,11 @@ private:
typedef QHash<QString, QString> AliasMap;
typedef QMultiHash<QString, QString> ParentChildrenMap;
static const QChar kSemiColon;
static const QString kModifiedMimeTypesFile;
static QString kModifiedMimeTypesPath;
bool addMimeTypes(QIODevice *device, const QString &fileName, QString *errorMessage);
inline const QString &resolveAlias(const QString &name) const;
MimeType findByFile(const QFileInfo &f, unsigned *priority) const;
@@ -988,9 +1141,15 @@ private:
int m_maxLevel;
};
const QChar MimeDatabasePrivate::kSemiColon(QLatin1Char(';'));
const QString MimeDatabasePrivate::kModifiedMimeTypesFile(QLatin1String("modifiedmimetypes.xml"));
QString MimeDatabasePrivate::kModifiedMimeTypesPath;
MimeDatabasePrivate::MimeDatabasePrivate() :
m_maxLevel(-1)
{
// Assign here to avoid non-local static data initialization issues.
kModifiedMimeTypesPath = ICore::instance()->userResourcePath() + QLatin1String("/mimetypes/");
}
namespace Internal {
@@ -1230,6 +1389,197 @@ QStringList MimeDatabasePrivate::filterStrings() const
return rc;
}
QList<MimeGlobPattern> MimeDatabasePrivate::globPatterns() const
{
QList<MimeGlobPattern> globPatterns;
const TypeMimeTypeMap::const_iterator cend = m_typeMimeTypeMap.constEnd();
for (TypeMimeTypeMap::const_iterator it = m_typeMimeTypeMap.constBegin(); it != cend; ++it)
globPatterns.append(it.value().type.globPatterns());
return globPatterns;
}
void MimeDatabasePrivate::setGlobPatterns(const QString &typeOrAlias,
const QList<MimeGlobPattern> &globPatterns)
{
TypeMimeTypeMap::iterator tit = m_typeMimeTypeMap.find(resolveAlias(typeOrAlias));
if (tit != m_typeMimeTypeMap.end())
tit.value().type.setGlobPatterns(globPatterns);
}
QList<QSharedPointer<IMagicMatcher> > MimeDatabasePrivate::magicMatchers() const
{
QList<QSharedPointer<IMagicMatcher> > magicMatchers;
const TypeMimeTypeMap::const_iterator cend = m_typeMimeTypeMap.constEnd();
for (TypeMimeTypeMap::const_iterator it = m_typeMimeTypeMap.constBegin(); it != cend; ++it)
magicMatchers.append(it.value().type.magicMatchers());
return magicMatchers;
}
void MimeDatabasePrivate::setMagicMatchers(const QString &typeOrAlias,
const QList<QSharedPointer<IMagicMatcher> > &matchers)
{
TypeMimeTypeMap::iterator tit = m_typeMimeTypeMap.find(resolveAlias(typeOrAlias));
if (tit != m_typeMimeTypeMap.end())
tit.value().type.setMagicMatchers(matchers);
}
QList<MimeType> MimeDatabasePrivate::mimeTypes() const
{
QList<MimeType> mimeTypes;
const TypeMimeTypeMap::const_iterator cend = m_typeMimeTypeMap.constEnd();
for (TypeMimeTypeMap::const_iterator it = m_typeMimeTypeMap.constBegin(); it != cend; ++it)
mimeTypes.append(it.value().type);
return mimeTypes;
}
void MimeDatabasePrivate::syncUserModifiedMimeTypes()
{
QHash<QString, MimeType> userModified;
const QList<MimeType> &userMimeTypes = readUserModifiedMimeTypes();
foreach (const MimeType &userMimeType, userMimeTypes)
userModified.insert(userMimeType.type(), userMimeType);
TypeMimeTypeMap::iterator end = m_typeMimeTypeMap.end();
QHash<QString, MimeType>::const_iterator userMimeEnd = userModified.end();
for (TypeMimeTypeMap::iterator it = m_typeMimeTypeMap.begin(); it != end; ++it) {
QHash<QString, MimeType>::const_iterator userMimeIt =
userModified.find(it.value().type.type());
if (userMimeIt != userMimeEnd) {
it.value().type.setGlobPatterns(userMimeIt.value().globPatterns());
it.value().type.setMagicRuleMatchers(userMimeIt.value().magicRuleMatchers());
}
}
}
QList<MimeType> MimeDatabasePrivate::readUserModifiedMimeTypes()
{
typedef MagicRuleMatcher::MagicRuleList MagicRuleList;
typedef MagicRuleMatcher::MagicRuleSharedPointer MagicRuleSharedPointer;
QList<MimeType> mimeTypes;
QFile file(kModifiedMimeTypesPath + kModifiedMimeTypesFile);
if (file.open(QFile::ReadOnly)) {
MimeType mimeType;
QHash<int, MagicRuleList> rules;
QXmlStreamReader reader(&file);
QXmlStreamAttributes atts;
while (!reader.atEnd()) {
switch (reader.readNext()) {
case QXmlStreamReader::StartElement:
atts = reader.attributes();
if (reader.name() == mimeTypeTagC) {
mimeType.setType(atts.value(mimeTypeAttributeC).toString());
const QString &patterns = atts.value(patternAttributeC).toString();
mimeType.setGlobPatterns(toGlobPatterns(patterns.split(kSemiColon)));
} else if (reader.name() == matchTagC) {
const QString &value = atts.value(matchValueAttributeC).toString();
const QString &type = atts.value(matchTypeAttributeC).toString();
const QString &offset = atts.value(matchOffsetAttributeC).toString();
QPair<int, int> range = MagicRule::fromOffset(offset);
const int priority = atts.value(priorityAttributeC).toString().toInt();
MagicRule *magicRule;
if (type == MagicStringRule::kMatchType)
magicRule = new MagicStringRule(value, range.first, range.second);
else
magicRule = new MagicByteRule(value, range.first, range.second);
rules[priority].append(MagicRuleSharedPointer(magicRule));
}
break;
case QXmlStreamReader::EndElement:
if (reader.name() == mimeTypeTagC) {
mimeType.setMagicRuleMatchers(MagicRuleMatcher::createMatchers(rules));
mimeTypes.append(mimeType);
mimeType.clear();
rules.clear();
}
break;
default:
break;
}
}
if (reader.hasError())
qWarning() << kModifiedMimeTypesFile << reader.errorString() << reader.lineNumber()
<< reader.columnNumber();
file.close();
}
return mimeTypes;
}
void MimeDatabasePrivate::writeUserModifiedMimeTypes(const QList<MimeType> &mimeTypes)
{
// Keep mime types modified which are already on file.
QList<MimeType> allModifiedMimeTypes = mimeTypes;
allModifiedMimeTypes.append(readUserModifiedMimeTypes());
if (QFile::exists(kModifiedMimeTypesPath) || QDir().mkpath(kModifiedMimeTypesPath)) {
QFile file(kModifiedMimeTypesPath + kModifiedMimeTypesFile);
if (file.open(QFile::WriteOnly | QFile::Truncate)) {
// Notice this file only represents user modifications. It is writen in a
// convienient way for synchronization, which is similar to but not exactly the
// same format we use for the embedded mime type files.
QXmlStreamWriter writer(&file);
writer.setAutoFormatting(true);
writer.writeStartDocument();
writer.writeStartElement(QLatin1String(mimeInfoTagC));
foreach (const MimeType &mimeType, allModifiedMimeTypes) {
writer.writeStartElement(mimeTypeTagC);
writer.writeAttribute(mimeTypeAttributeC, mimeType.type());
writer.writeAttribute(patternAttributeC,
fromGlobPatterns(mimeType.globPatterns()).join(kSemiColon));
const QList<QSharedPointer<IMagicMatcher> > &matchers = mimeType.magicMatchers();
foreach (const QSharedPointer<IMagicMatcher> &matcher, matchers) {
// Only care about rule-based matchers.
if (MagicRuleMatcher *ruleMatcher =
dynamic_cast<MagicRuleMatcher *>(matcher.data())) {
const MagicRuleMatcher::MagicRuleList &rules = ruleMatcher->magicRules();
foreach (const MagicRuleMatcher::MagicRuleSharedPointer &rule, rules) {
writer.writeStartElement(matchTagC);
writer.writeAttribute(matchValueAttributeC, rule->matchValue());
writer.writeAttribute(matchTypeAttributeC, rule->matchType());
writer.writeAttribute(matchOffsetAttributeC,
MagicRule::toOffset(
qMakePair(rule->startPos(), rule->endPos())));
writer.writeAttribute(priorityAttributeC,
QString::number(ruleMatcher->priority()));
writer.writeEndElement();
}
}
}
writer.writeEndElement();
}
writer.writeEndElement();
writer.writeEndDocument();
file.close();
}
}
}
void MimeDatabasePrivate::clearUserModifiedMimeTypes()
{
// This removes the user's file. However, the operation will actually take place the next time
// Creator starts, since we currently don't support removing stuff from the mime database.
QFile::remove(kModifiedMimeTypesPath + kModifiedMimeTypesFile);
}
QList<MimeGlobPattern> MimeDatabasePrivate::toGlobPatterns(const QStringList &patterns, int weight)
{
QList<MimeGlobPattern> globPatterns;
foreach (const QString &pattern, patterns) {
QRegExp regExp(pattern, Qt::CaseSensitive, QRegExp::Wildcard);
globPatterns.append(Core::MimeGlobPattern(regExp, weight));
}
return globPatterns;
}
QStringList MimeDatabasePrivate::fromGlobPatterns(const QList<MimeGlobPattern> &globPatterns)
{
QStringList patterns;
foreach (const MimeGlobPattern &globPattern, globPatterns)
patterns.append(globPattern.regExp().pattern());
return patterns;
}
void MimeDatabasePrivate::debug(QTextStream &str) const
{
str << ">MimeDatabase\n";
@@ -1308,7 +1658,7 @@ QStringList MimeDatabase::suffixes() const
QStringList MimeDatabase::filterStrings() const
{
m_mutex.lock();
const QStringList rc = m_d->filterStrings();
const QStringList rc = m_d->filterStrings();
m_mutex.unlock();
return rc;
}
@@ -1336,6 +1686,70 @@ QString MimeDatabase::allFiltersString(QString *allFilesFilter) const
return filters.join(QLatin1String(";;"));
}
QList<MimeGlobPattern> MimeDatabase::globPatterns() const
{
m_mutex.lock();
const QList<MimeGlobPattern> rc = m_d->globPatterns();
m_mutex.unlock();
return rc;
}
void MimeDatabase::setGlobPatterns(const QString &typeOrAlias,
const QList<MimeGlobPattern> &globPatterns)
{
m_mutex.lock();
m_d->setGlobPatterns(typeOrAlias, globPatterns);
m_mutex.unlock();
}
MimeDatabase::IMagicMatcherList MimeDatabase::magicMatchers() const
{
m_mutex.lock();
const IMagicMatcherList rc = m_d->magicMatchers();
m_mutex.unlock();
return rc;
}
void MimeDatabase::setMagicMatchers(const QString &typeOrAlias,
const IMagicMatcherList &matchers)
{
m_mutex.lock();
m_d->setMagicMatchers(typeOrAlias, matchers);
m_mutex.unlock();
}
QList<MimeType> MimeDatabase::mimeTypes() const
{
m_mutex.lock();
const QList<MimeType> &mimeTypes = m_d->mimeTypes();
m_mutex.unlock();
return mimeTypes;
}
void MimeDatabase::syncUserModifiedMimeTypes()
{
m_mutex.lock();
m_d->syncUserModifiedMimeTypes();
m_mutex.unlock();
}
void MimeDatabase::clearUserModifiedMimeTypes()
{
m_mutex.lock();
m_d->clearUserModifiedMimeTypes();
m_mutex.unlock();
}
QList<MimeType> MimeDatabase::readUserModifiedMimeTypes()
{
return MimeDatabasePrivate::readUserModifiedMimeTypes();
}
void MimeDatabase::writeUserModifiedMimeTypes(const QList<MimeType> &mimeTypes)
{
MimeDatabasePrivate::writeUserModifiedMimeTypes(mimeTypes);
}
QString MimeDatabase::preferredSuffixByType(const QString &type) const
{
if (const MimeType mt = findByType(type))
@@ -1358,6 +1772,16 @@ bool MimeDatabase::setPreferredSuffix(const QString &typeOrAlias, const QString
return rc;
}
QList<MimeGlobPattern> MimeDatabase::toGlobPatterns(const QStringList &patterns, int weight)
{
return MimeDatabasePrivate::toGlobPatterns(patterns, weight);
}
QStringList MimeDatabase::fromGlobPatterns(const QList<MimeGlobPattern> &globPatterns)
{
return MimeDatabasePrivate::fromGlobPatterns(globPatterns);
}
QDebug operator<<(QDebug d, const MimeDatabase &mt)
{
QString s;