Commit d64e17ad authored by Eike Ziller's avatar Eike Ziller

Move mimetype definitions to plugin specs

- Avoids the hassle of QRC files and manually registering mime types
- Avoids performance regressions because of mime types that are
  registered after mime database has been used
- Makes it technically possible to detect that a disabled plugin could
  handle a mime type if it was enabled

Change-Id: I373008b1b56e9c6b4853055f20b3eeb112a6eff9
Reviewed-by: Christian Stenger's avatarChristian Stenger <christian.stenger@qt.io>
Reviewed-by: default avatarhjk <hjk@qt.io>
parent ca1d1dfb
......@@ -55,12 +55,6 @@ QtcProduct {
fileTags: ["pluginJsonIn"]
}
Group {
name: "MimeTypes"
prefix: product.sourceDirectory + '/'
files: [ "*.mimetypes.xml" ]
}
Export {
Depends { name: "ExtensionSystem" }
Depends { name: "cpp" }
......
......@@ -360,6 +360,11 @@ QVector<PluginDependency> PluginSpec::dependencies() const
return d->dependencies;
}
QJsonObject PluginSpec::metaData() const
{
return d->metaData;
}
/*!
Returns a list of descriptions of command line arguments the plugin processes.
*/
......@@ -539,6 +544,7 @@ bool PluginSpecPrivate::read(const QString &fileName)
hasError = false;
errorString.clear();
dependencies.clear();
metaData = QJsonObject();
QFileInfo fileInfo(fileName);
location = fileInfo.absolutePath();
filePath = fileInfo.absoluteFilePath();
......@@ -650,11 +656,11 @@ static inline bool readMultiLineString(const QJsonValue &value, QString *out)
/*!
\internal
*/
bool PluginSpecPrivate::readMetaData(const QJsonObject &metaData)
bool PluginSpecPrivate::readMetaData(const QJsonObject &pluginMetaData)
{
qCDebug(pluginLog) << "MetaData:" << QJsonDocument(metaData).toJson();
qCDebug(pluginLog) << "MetaData:" << QJsonDocument(pluginMetaData).toJson();
QJsonValue value;
value = metaData.value(QLatin1String("IID"));
value = pluginMetaData.value(QLatin1String("IID"));
if (!value.isString()) {
qCDebug(pluginLog) << "Not a plugin (no string IID found)";
return false;
......@@ -664,19 +670,19 @@ bool PluginSpecPrivate::readMetaData(const QJsonObject &metaData)
return false;
}
value = metaData.value(QLatin1String(PLUGIN_METADATA));
value = pluginMetaData.value(QLatin1String(PLUGIN_METADATA));
if (!value.isObject())
return reportError(tr("Plugin meta data not found"));
QJsonObject pluginInfo = value.toObject();
metaData = value.toObject();
value = pluginInfo.value(QLatin1String(PLUGIN_NAME));
value = metaData.value(QLatin1String(PLUGIN_NAME));
if (value.isUndefined())
return reportError(msgValueMissing(PLUGIN_NAME));
if (!value.isString())
return reportError(msgValueIsNotAString(PLUGIN_NAME));
name = value.toString();
value = pluginInfo.value(QLatin1String(PLUGIN_VERSION));
value = metaData.value(QLatin1String(PLUGIN_VERSION));
if (value.isUndefined())
return reportError(msgValueMissing(PLUGIN_VERSION));
if (!value.isString())
......@@ -685,32 +691,32 @@ bool PluginSpecPrivate::readMetaData(const QJsonObject &metaData)
if (!isValidVersion(version))
return reportError(msgInvalidFormat(PLUGIN_VERSION, version));
value = pluginInfo.value(QLatin1String(PLUGIN_COMPATVERSION));
value = metaData.value(QLatin1String(PLUGIN_COMPATVERSION));
if (!value.isUndefined() && !value.isString())
return reportError(msgValueIsNotAString(PLUGIN_COMPATVERSION));
compatVersion = value.toString(version);
if (!value.isUndefined() && !isValidVersion(compatVersion))
return reportError(msgInvalidFormat(PLUGIN_COMPATVERSION, compatVersion));
value = pluginInfo.value(QLatin1String(PLUGIN_REQUIRED));
value = metaData.value(QLatin1String(PLUGIN_REQUIRED));
if (!value.isUndefined() && !value.isBool())
return reportError(msgValueIsNotABool(PLUGIN_REQUIRED));
required = value.toBool(false);
qCDebug(pluginLog) << "required =" << required;
value = pluginInfo.value(QLatin1String(PLUGIN_HIDDEN_BY_DEFAULT));
value = metaData.value(QLatin1String(PLUGIN_HIDDEN_BY_DEFAULT));
if (!value.isUndefined() && !value.isBool())
return reportError(msgValueIsNotABool(PLUGIN_HIDDEN_BY_DEFAULT));
hiddenByDefault = value.toBool(false);
qCDebug(pluginLog) << "hiddenByDefault =" << hiddenByDefault;
value = pluginInfo.value(QLatin1String(PLUGIN_EXPERIMENTAL));
value = metaData.value(QLatin1String(PLUGIN_EXPERIMENTAL));
if (!value.isUndefined() && !value.isBool())
return reportError(msgValueIsNotABool(PLUGIN_EXPERIMENTAL));
experimental = value.toBool(false);
qCDebug(pluginLog) << "experimental =" << experimental;
value = pluginInfo.value(QLatin1String(PLUGIN_DISABLED_BY_DEFAULT));
value = metaData.value(QLatin1String(PLUGIN_DISABLED_BY_DEFAULT));
if (!value.isUndefined() && !value.isBool())
return reportError(msgValueIsNotABool(PLUGIN_DISABLED_BY_DEFAULT));
enabledByDefault = !value.toBool(false);
......@@ -720,35 +726,35 @@ bool PluginSpecPrivate::readMetaData(const QJsonObject &metaData)
enabledByDefault = false;
enabledBySettings = enabledByDefault;
value = pluginInfo.value(QLatin1String(VENDOR));
value = metaData.value(QLatin1String(VENDOR));
if (!value.isUndefined() && !value.isString())
return reportError(msgValueIsNotAString(VENDOR));
vendor = value.toString();
value = pluginInfo.value(QLatin1String(COPYRIGHT));
value = metaData.value(QLatin1String(COPYRIGHT));
if (!value.isUndefined() && !value.isString())
return reportError(msgValueIsNotAString(COPYRIGHT));
copyright = value.toString();
value = pluginInfo.value(QLatin1String(DESCRIPTION));
value = metaData.value(QLatin1String(DESCRIPTION));
if (!value.isUndefined() && !readMultiLineString(value, &description))
return reportError(msgValueIsNotAString(DESCRIPTION));
value = pluginInfo.value(QLatin1String(URL));
value = metaData.value(QLatin1String(URL));
if (!value.isUndefined() && !value.isString())
return reportError(msgValueIsNotAString(URL));
url = value.toString();
value = pluginInfo.value(QLatin1String(CATEGORY));
value = metaData.value(QLatin1String(CATEGORY));
if (!value.isUndefined() && !value.isString())
return reportError(msgValueIsNotAString(CATEGORY));
category = value.toString();
value = pluginInfo.value(QLatin1String(LICENSE));
value = metaData.value(QLatin1String(LICENSE));
if (!value.isUndefined() && !readMultiLineString(value, &license))
return reportError(msgValueIsNotAMultilineString(LICENSE));
value = pluginInfo.value(QLatin1String(PLATFORM));
value = metaData.value(QLatin1String(PLATFORM));
if (!value.isUndefined() && !value.isString())
return reportError(msgValueIsNotAString(PLATFORM));
const QString platformSpec = value.toString().trimmed();
......@@ -759,7 +765,7 @@ bool PluginSpecPrivate::readMetaData(const QJsonObject &metaData)
.arg(platformSpec, platformSpecification.errorString()));
}
value = pluginInfo.value(QLatin1String(DEPENDENCIES));
value = metaData.value(QLatin1String(DEPENDENCIES));
if (!value.isUndefined() && !value.isArray())
return reportError(msgValueIsNotAObjectArray(DEPENDENCIES));
if (!value.isUndefined()) {
......@@ -806,7 +812,7 @@ bool PluginSpecPrivate::readMetaData(const QJsonObject &metaData)
}
}
value = pluginInfo.value(QLatin1String(ARGUMENTS));
value = metaData.value(QLatin1String(ARGUMENTS));
if (!value.isUndefined() && !value.isArray())
return reportError(msgValueIsNotAObjectArray(ARGUMENTS));
if (!value.isUndefined()) {
......
......@@ -104,6 +104,7 @@ public:
bool isForceEnabled() const;
bool isForceDisabled() const;
QVector<PluginDependency> dependencies() const;
QJsonObject metaData() const;
typedef QVector<PluginArgumentDescription> PluginArgumentDescriptions;
PluginArgumentDescriptions argumentDescriptions() const;
......
......@@ -82,6 +82,7 @@ public:
QString category;
QRegExp platformSpecification;
QVector<PluginDependency> dependencies;
QJsonObject metaData;
bool enabledBySettings = true;
bool enabledIndirectly = false;
bool forceEnabled = false;
......@@ -104,7 +105,7 @@ public:
void enableDependenciesIndirectly();
bool readMetaData(const QJsonObject &metaData);
bool readMetaData(const QJsonObject &pluginMetaData);
private:
PluginSpec *q;
......
......@@ -331,7 +331,7 @@ MimeDatabase::~MimeDatabase()
d = 0;
}
void MimeDatabase::addMimeTypes(const QString &fileName)
void MimeDatabase::addMimeTypes(const QString &fileName, const QByteArray &data)
{
auto d = MimeDatabasePrivate::instance();
QMutexLocker locker(&d->mutex);
......@@ -341,7 +341,7 @@ void MimeDatabase::addMimeTypes(const QString &fileName)
qPrintable(fileName));
auto xmlProvider = static_cast<MimeXMLProvider *>(d->provider());
xmlProvider->addFile(fileName);
xmlProvider->addData(fileName, data);
}
QString MimeDatabase::allFiltersString(QString *allFilesFilter)
......
......@@ -89,7 +89,7 @@ public:
QList<MimeType> allMimeTypes() const;
// Qt Creator additions
static void addMimeTypes(const QString &fileName);
static void addMimeTypes(const QString &id, const QByteArray &data);
static QString allFiltersString(QString *allFilesFilter = 0);
static QString allFilesFilterString();
static QStringList allGlobPatterns();
......
......@@ -782,16 +782,16 @@ void MimeXMLProvider::setMagicRulesForMimeType(const MimeType &mimeType, const Q
void MimeXMLProvider::ensureLoaded()
{
if (!m_loaded /*|| shouldCheck()*/) {
m_loaded = true;
// bool fdoXmlFound = false;
// add custom mime types first, which overrides any default from freedesktop.org.xml
QStringList allFiles = m_additionalFiles;
QStringList allFiles;
// const QStringList packageDirs = QStandardPaths::locateAll(QStandardPaths::GenericDataLocation, QLatin1String("mime/packages"), QStandardPaths::LocateDirectory);
// //qDebug() << "packageDirs=" << packageDirs;
// foreach (const QString &packageDir, packageDirs) {
// for (const QString &packageDir : packageDirs) {
// QDir dir(packageDir);
// const QStringList files = dir.entryList(QDir::Files | QDir::NoDotAndDotDot);
// //qDebug() << static_cast<const void *>(this) << Q_FUNC_INFO << packageDir << files;
// //qDebug() << static_cast<const void *>(this) << packageDir << files;
// if (!fdoXmlFound)
// fdoXmlFound = files.contains(QLatin1String("freedesktop.org.xml"));
// QStringList::const_iterator endIt(files.constEnd());
......@@ -802,13 +802,9 @@ void MimeXMLProvider::ensureLoaded()
// if (!fdoXmlFound) {
// // We could instead install the file as part of installing Qt?
allFiles.append(QLatin1String(":/qt-project.org/qmime/freedesktop.org.xml"));
allFiles.prepend(QLatin1String(":/qt-project.org/qmime/freedesktop.org.xml"));
// }
if (m_allFiles == allFiles)
return;
m_allFiles = allFiles;
m_nameMimeTypeMap.clear();
m_aliases.clear();
m_parents.clear();
......@@ -817,6 +813,17 @@ void MimeXMLProvider::ensureLoaded()
//qDebug() << "Loading" << m_allFiles;
// add custom mime types first, which override any default from freedesktop.org.xml
MimeTypeParser parser(*this);
QHashIterator<QString, QByteArray> it(m_additionalData);
while (it.hasNext()) {
it.next();
QString errorMessage;
if (!parser.parse(it.value(), it.key(), &errorMessage)) {
qWarning("MimeDatabase: Error loading %s\n%s", qPrintable(it.key()),
qPrintable(errorMessage));
}
}
foreach (const QString &file, allFiles)
load(file);
}
......@@ -904,8 +911,10 @@ void MimeXMLProvider::addMagicMatcher(const MimeMagicRuleMatcher &matcher)
m_magicMatchers.append(matcher);
}
void MimeXMLProvider::addFile(const QString &filePath)
void MimeXMLProvider::addData(const QString &id, const QByteArray &data)
{
m_additionalFiles.append(filePath);
if (m_additionalData.contains(id))
qWarning("Overwriting data in mime database, id '%s'", qPrintable(id));
m_additionalData.insert(id, data);
m_loaded = false; // force reload to ensure correct load order for overridden mime types
}
......@@ -160,7 +160,7 @@ public:
void addMagicMatcher(const MimeMagicRuleMatcher &matcher);
// Qt Creator additions
void addFile(const QString &filePath);
void addData(const QString &id, const QByteArray &data);
QMap<int, QList<MimeMagicRule> > magicRulesForMimeType(const MimeType &mimeType);
void setGlobPatternsForMimeType(const MimeType &mimeType, const QStringList &patterns);
void setMagicRulesForMimeType(const MimeType &mimeType, const QMap<int, QList<MimeMagicRule> > &rules);
......@@ -182,10 +182,9 @@ private:
MimeAllGlobPatterns m_mimeTypeGlobs;
QList<MimeMagicRuleMatcher> m_magicMatchers;
QStringList m_allFiles;
// Qt Creator additions
QStringList m_additionalFiles;
QHash<QString, QByteArray> m_additionalData; // id -> data
};
} // Internal
......
......@@ -15,5 +15,16 @@
\"Category\" : \"Device Support\",
\"Description\" : \"Support for deployment to and execution on Android Devices.\",
\"Url\" : \"http://necessitas.kde.org\",
$$dependencyList
$$dependencyList,
\"Mimetypes\" : \"
<?xml version=\'1.0\'?>
<mime-info xmlns=\'http://www.freedesktop.org/standards/shared-mime-info\'>
<mime-type type=\'application/vnd.google.android.android_manifest\'>
<comment>Android manifest file</comment>
<sub-class-of type=\'application/xml\'/>
<glob pattern=\'AndroidManifest.xml\'/>
</mime-type>
</mime-info>
\"
}
<?xml version="1.0"?>
<mime-info xmlns='http://www.freedesktop.org/standards/shared-mime-info'>
<mime-type type="application/vnd.google.android.android_manifest">
<comment>Android manifest file</comment>
<sub-class-of type="application/xml"/>
<glob pattern="AndroidManifest.xml"/>
</mime-type>
</mime-info>
......@@ -5,6 +5,5 @@
<file>images/androiddevicesmall.png</file>
<file>images/androiddevicesmall@2x.png</file>
<file>images/download.png</file>
<file>Android.mimetypes.xml</file>
</qresource>
</RCC>
......@@ -52,8 +52,6 @@
#include <qtsupport/qtversionmanager.h>
#include <utils/mimetypes/mimedatabase.h>
#include <QtPlugin>
using namespace ProjectExplorer;
......@@ -81,8 +79,6 @@ bool AndroidPlugin::initialize(const QStringList &arguments, QString *errorMessa
addAutoReleasedObject(new Internal::JavaEditorFactory);
KitManager::registerKitInformation(new Internal::AndroidGdbServerKitInformation);
Utils::MimeDatabase::addMimeTypes(QLatin1String(":/android/Android.mimetypes.xml"));
addAutoReleasedObject(new Internal::AndroidManifestEditorFactory);
connect(KitManager::instance(), &KitManager::kitsLoaded,
......
......@@ -16,5 +16,15 @@
\"Category\" : \"Version Control\",
\"Description\" : \"ClearCase integration.\",
\"Url\" : \"http://www.qt.io\",
$$dependencyList
$$dependencyList,
\"Mimetypes\" : \"
<?xml version=\'1.0\'?>
<mime-info xmlns=\'http://www.freedesktop.org/standards/shared-mime-info\'>
<mime-type type=\'application/vnd.audc.text.clearcase.submit\'>
<comment>ClearCase submit template</comment>
<sub-class-of type=\'text/plain\'/>
</mime-type>
</mime-info>
\"
}
......@@ -31,5 +31,3 @@ FORMS += checkoutdialog.ui \
settingspage.ui \
undocheckout.ui \
versionselector.ui
RESOURCES += clearcase.qrc
......@@ -21,7 +21,6 @@ QtcPlugin {
"checkoutdialog.cpp",
"checkoutdialog.h",
"checkoutdialog.ui",
"clearcase.qrc",
"clearcaseconstants.h",
"clearcasecontrol.cpp",
"clearcasecontrol.h",
......
<RCC>
<qresource prefix="/clearcase">
<file>ClearCase.mimetypes.xml</file>
</qresource>
</RCC>
......@@ -54,7 +54,6 @@
#include <projectexplorer/project.h>
#include <projectexplorer/iprojectmanager.h>
#include <utils/algorithm.h>
#include <utils/mimetypes/mimedatabase.h>
#include <utils/synchronousprocess.h>
#include <utils/temporarydirectory.h>
#include <utils/parameteraction.h>
......@@ -418,8 +417,6 @@ bool ClearCasePlugin::initialize(const QStringList & /*arguments */, QString *er
connect(ProgressManager::instance(), &ProgressManager::allTasksFinished,
this, &ClearCasePlugin::tasksFinished);
Utils::MimeDatabase::addMimeTypes(QLatin1String(":/clearcase/ClearCase.mimetypes.xml"));
m_settings.fromSettings(ICore::settings());
// update view name when changing active project
......
......@@ -15,5 +15,21 @@
\"Category\" : \"Build Systems\",
\"Description\" : \"CMake support.\",
\"Url\" : \"http://www.qt.io\",
$$dependencyList
$$dependencyList,
\"Mimetypes\" : \"
<?xml version=\'1.0\'?>
<mime-info xmlns=\'http://www.freedesktop.org/standards/shared-mime-info\'>
<mime-type type=\'text/x-cmake\'>
<sub-class-of type=\'text/plain\'/>
<comment>CMake Project file</comment>
<glob pattern=\'*.cmake\'/>
</mime-type>
<mime-type type=\'text/x-cmake-project\'>
<sub-class-of type=\'text/x-cmake\'/>
<comment>CMake Project file</comment>
<glob pattern=\'CMakeLists.txt\'/>
</mime-type>
</mime-info>
\"
}
<?xml version="1.0"?>
<mime-info xmlns='http://www.freedesktop.org/standards/shared-mime-info'>
<mime-type type="text/x-cmake">
<sub-class-of type="text/plain"/>
<comment>CMake Project file</comment>
<glob pattern="*.cmake"/>
</mime-type>
<mime-type type="text/x-cmake-project">
<sub-class-of type="text/x-cmake"/>
<comment>CMake Project file</comment>
<glob pattern="CMakeLists.txt"/>
</mime-type>
</mime-info>
<RCC>
<qresource prefix="/cmakeproject">
<file>CMakeProjectManager.mimetypes.xml</file>
<file>images/fileoverlay_cmake.png</file>
<file>images/fileoverlay_cmake@2x.png</file>
</qresource>
......
......@@ -47,7 +47,6 @@
#include <projectexplorer/kitmanager.h>
#include <projectexplorer/projecttree.h>
#include <utils/mimetypes/mimedatabase.h>
#include <utils/parameteraction.h>
using namespace CMakeProjectManager::Internal;
......@@ -59,8 +58,6 @@ bool CMakeProjectPlugin::initialize(const QStringList & /*arguments*/, QString *
Q_UNUSED(errorMessage)
const Context projectContext(Constants::PROJECTCONTEXT);
Utils::MimeDatabase::addMimeTypes(QLatin1String(":cmakeproject/CMakeProjectManager.mimetypes.xml"));
Core::FileIconProvider::registerIconOverlayForSuffix(Constants::FILEOVERLAY_CMAKE, "cmake");
Core::FileIconProvider::registerIconOverlayForFilename(Constants::FILEOVERLAY_CMAKE, "CMakeLists.txt");
......
......@@ -46,9 +46,11 @@
#include <extensionsystem/pluginerroroverview.h>
#include <extensionsystem/pluginmanager.h>
#include <extensionsystem/pluginspec.h>
#include <utils/algorithm.h>
#include <utils/pathchooser.h>
#include <utils/macroexpander.h>
#include <utils/mimetypes/mimedatabase.h>
#include <utils/savefile.h>
#include <utils/stringutils.h>
#include <utils/theme/theme.h>
......@@ -123,6 +125,17 @@ CoreArguments parseArguments(const QStringList &arguments)
bool CorePlugin::initialize(const QStringList &arguments, QString *errorMessage)
{
// register all mime types from all plugins
Utils::MimeDatabase mdb;
for (ExtensionSystem::PluginSpec *plugin : ExtensionSystem::PluginManager::plugins()) {
if (!plugin->isEffectivelyEnabled())
continue;
const QJsonObject metaData = plugin->metaData();
const QJsonValue mimetypes = metaData.value("Mimetypes");
if (mimetypes.isString())
mdb.addMimeTypes(plugin->name() + ".mimetypes", mimetypes.toString().trimmed().toUtf8());
}
if (ThemeEntry::availableThemes().isEmpty()) {
*errorMessage = tr("No themes found in installation.");
return false;
......
......@@ -264,7 +264,6 @@ else:unix {
INSTALLS += image$${imagesize}
}
}
DISTFILES += editormanager/BinFiles.mimetypes.xml
equals(TEST, 1) {
SOURCES += testdatadir.cpp
......
......@@ -16,5 +16,103 @@
\"Category\" : \"C++\",
\"Description\" : \"Tools for analyzing C/C++ code.\",
\"Url\" : \"http://www.qt.io\",
$$dependencyList
$$dependencyList,
\"Mimetypes\" : \"
<?xml version=\'1.0\' encoding=\'UTF-8\'?>
<mime-info xmlns=\'http://www.freedesktop.org/standards/shared-mime-info\'>
<mime-type type=\'text/x-csrc\'>
<comment>C source code</comment>
<sub-class-of type=\'text/plain\'/>
<alias type=\'text/x-c\'/>
<glob pattern=\'*.c\' case-sensitive=\'true\' weight=\'70\'/>
</mime-type>
<mime-type type=\'text/vnd.nvidia.cuda.csrc\'>
<sub-class-of type=\'text/x-csrc\'/>
<comment>NVIDIA CUDA C source code</comment>
<glob pattern=\'*.cu\'/>
</mime-type>
<mime-type type=\'text/x-chdr\'>
<comment>C header</comment>
<sub-class-of type=\'text/x-csrc\'/>
<!-- reduce weight from freedesktop to avoid conflict with text/x-c++hdr -->
<glob pattern=\'*.h\' weight=\'30\'/>
</mime-type>
<!-- Those are used to find matching headers by the CppTools plugin,
so, they should match -->
<mime-type type=\'text/x-c++hdr\'>
<sub-class-of type=\'text/x-chdr\'/>
<comment>C++ header</comment>
<glob pattern=\'*.hh\' weight=\'70\'/>
<glob pattern=\'*.hxx\' weight=\'70\'/>
<glob pattern=\'*.h++\' weight=\'70\'/>
<glob pattern=\'*.hpp\' weight=\'70\'/>
<glob pattern=\'*.hp\' weight=\'70\'/>
<!-- Additions to freedesktop: -->
<glob pattern=\'*.h\' weight=\'70\'/>
<glob pattern=\'*.H\' weight=\'70\'/>
<!-- Find include guards of header files without extension, for
example, STL ones like <string>. Those can have a big initial
comment exceeding 1000 chars, though. -->
<magic priority=\'50\'>
<match value=\'#ifndef \' type=\'string\' offset=\'0:2000\'/>
<match value=\'#if \' type=\'string\' offset=\'0:2000\'/>
<match value=\'#include \' type=\'string\' offset=\'0:2000\'/>
</magic>
</mime-type>
<mime-type type=\'text/x-c++src\'>
<comment>C++ source code</comment>
<sub-class-of type=\'text/x-csrc\'/>
<glob pattern=\'*.cpp\' weight=\'70\'/>
<glob pattern=\'*.cxx\' weight=\'70\'/>
<glob pattern=\'*.cc\' weight=\'70\'/>
<glob pattern=\'*.C\' case-sensitive=\'true\' weight=\'70\'/>
<glob pattern=\'*.c++\' weight=\'70\'/>
<!-- Additions to freedesktop: -->
<glob pattern=\'*.cp\' weight=\'70\'/>
<glob pattern=\'*.inl\' weight=\'70\'/>