Commit 3db53206 authored by Leandro Melo's avatar Leandro Melo
Browse files

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
parent c8f19854
...@@ -253,7 +253,9 @@ const char * const SETTINGS_CATEGORY_CORE = "A.Core"; ...@@ -253,7 +253,9 @@ const char * const SETTINGS_CATEGORY_CORE = "A.Core";
const char * const SETTINGS_CATEGORY_CORE_ICON = ":/core/images/category_core.png"; const char * const SETTINGS_CATEGORY_CORE_ICON = ":/core/images/category_core.png";
const char * const SETTINGS_TR_CATEGORY_CORE = QT_TRANSLATE_NOOP("Core", "Environment"); const char * const SETTINGS_TR_CATEGORY_CORE = QT_TRANSLATE_NOOP("Core", "Environment");
const char * const SETTINGS_ID_ENVIRONMENT = "A.General"; const char * const SETTINGS_ID_ENVIRONMENT = "A.General";
const char * const SETTINGS_ID_TOOLS = "G.ExternalTools"; const char * const SETTINGS_ID_SHORTCUTS = "B.Keyboard";
const char * const SETTINGS_ID_TOOLS = "C.ExternalTools";
const char * const SETTINGS_ID_MIMETYPES = "D.MimeTypes";
const char * const SETTINGS_DEFAULTTEXTENCODING = "General/DefaultFileEncoding"; const char * const SETTINGS_DEFAULTTEXTENCODING = "General/DefaultFileEncoding";
......
...@@ -38,6 +38,7 @@ ...@@ -38,6 +38,7 @@
#include "modemanager.h" #include "modemanager.h"
#include "fileiconprovider.h" #include "fileiconprovider.h"
#include "designmode.h" #include "designmode.h"
#include "mimedatabase.h"
#include <extensionsystem/pluginmanager.h> #include <extensionsystem/pluginmanager.h>
...@@ -99,6 +100,7 @@ bool CorePlugin::initialize(const QStringList &arguments, QString *errorMessage) ...@@ -99,6 +100,7 @@ bool CorePlugin::initialize(const QStringList &arguments, QString *errorMessage)
void CorePlugin::extensionsInitialized() void CorePlugin::extensionsInitialized()
{ {
m_mainWindow->mimeDatabase()->syncUserModifiedMimeTypes();
m_mainWindow->extensionsInitialized(); m_mainWindow->extensionsInitialized();
} }
......
...@@ -91,7 +91,9 @@ SOURCES += mainwindow.cpp \ ...@@ -91,7 +91,9 @@ SOURCES += mainwindow.cpp \
externaltool.cpp \ externaltool.cpp \
dialogs/externaltoolconfig.cpp \ dialogs/externaltoolconfig.cpp \
toolsettings.cpp \ toolsettings.cpp \
variablechooser.cpp variablechooser.cpp \
mimetypemagicdialog.cpp \
mimetypesettings.cpp
HEADERS += mainwindow.h \ HEADERS += mainwindow.h \
editmode.h \ editmode.h \
...@@ -180,7 +182,9 @@ HEADERS += mainwindow.h \ ...@@ -180,7 +182,9 @@ HEADERS += mainwindow.h \
externaltool.h \ externaltool.h \
dialogs/externaltoolconfig.h \ dialogs/externaltoolconfig.h \
toolsettings.h \ toolsettings.h \
variablechooser.h variablechooser.h \
mimetypemagicdialog.h \
mimetypesettings.h
FORMS += dialogs/newdialog.ui \ FORMS += dialogs/newdialog.ui \
actionmanager/commandmappings.ui \ actionmanager/commandmappings.ui \
...@@ -189,7 +193,10 @@ FORMS += dialogs/newdialog.ui \ ...@@ -189,7 +193,10 @@ FORMS += dialogs/newdialog.ui \
editormanager/openeditorsview.ui \ editormanager/openeditorsview.ui \
generalsettings.ui \ generalsettings.ui \
dialogs/externaltoolconfig.ui \ dialogs/externaltoolconfig.ui \
variablechooser.ui variablechooser.ui \
mimetypesettingspage.ui \
mimetypemagicdialog.ui
RESOURCES += core.qrc \ RESOURCES += core.qrc \
fancyactionbar.qrc fancyactionbar.qrc
......
...@@ -75,7 +75,7 @@ ShortcutSettings::~ShortcutSettings() ...@@ -75,7 +75,7 @@ ShortcutSettings::~ShortcutSettings()
QString ShortcutSettings::id() const QString ShortcutSettings::id() const
{ {
return QLatin1String("D.Keyboard"); return QLatin1String(Core::Constants::SETTINGS_ID_SHORTCUTS);
} }
QString ShortcutSettings::displayName() const QString ShortcutSettings::displayName() const
......
...@@ -40,6 +40,7 @@ ...@@ -40,6 +40,7 @@
#include "editormanager.h" #include "editormanager.h"
#include "externaltool.h" #include "externaltool.h"
#include "toolsettings.h" #include "toolsettings.h"
#include "mimetypesettings.h"
#include "fancytabwidget.h" #include "fancytabwidget.h"
#include "filemanager.h" #include "filemanager.h"
#include "generalsettings.h" #include "generalsettings.h"
...@@ -152,6 +153,7 @@ MainWindow::MainWindow() : ...@@ -152,6 +153,7 @@ MainWindow::MainWindow() :
m_generalSettings(new GeneralSettings), m_generalSettings(new GeneralSettings),
m_shortcutSettings(new ShortcutSettings), m_shortcutSettings(new ShortcutSettings),
m_toolSettings(new ToolSettings), m_toolSettings(new ToolSettings),
m_mimeTypeSettings(new MimeTypeSettings),
m_systemEditor(new SystemEditor), m_systemEditor(new SystemEditor),
m_focusToEditor(0), m_focusToEditor(0),
m_newAction(0), m_newAction(0),
...@@ -256,6 +258,7 @@ MainWindow::~MainWindow() ...@@ -256,6 +258,7 @@ MainWindow::~MainWindow()
pm->removeObject(m_shortcutSettings); pm->removeObject(m_shortcutSettings);
pm->removeObject(m_generalSettings); pm->removeObject(m_generalSettings);
pm->removeObject(m_toolSettings); pm->removeObject(m_toolSettings);
pm->removeObject(m_mimeTypeSettings);
pm->removeObject(m_systemEditor); pm->removeObject(m_systemEditor);
delete m_externalToolManager; delete m_externalToolManager;
m_externalToolManager = 0; m_externalToolManager = 0;
...@@ -267,6 +270,8 @@ MainWindow::~MainWindow() ...@@ -267,6 +270,8 @@ MainWindow::~MainWindow()
m_generalSettings = 0; m_generalSettings = 0;
delete m_toolSettings; delete m_toolSettings;
m_toolSettings = 0; m_toolSettings = 0;
delete m_mimeTypeSettings;
m_mimeTypeSettings = 0;
delete m_systemEditor; delete m_systemEditor;
m_systemEditor = 0; m_systemEditor = 0;
delete m_settings; delete m_settings;
...@@ -325,9 +330,9 @@ bool MainWindow::init(QString *errorMessage) ...@@ -325,9 +330,9 @@ bool MainWindow::init(QString *errorMessage)
pm->addObject(m_generalSettings); pm->addObject(m_generalSettings);
pm->addObject(m_shortcutSettings); pm->addObject(m_shortcutSettings);
pm->addObject(m_toolSettings); pm->addObject(m_toolSettings);
pm->addObject(m_mimeTypeSettings);
pm->addObject(m_systemEditor); pm->addObject(m_systemEditor);
// Add widget to the bottom, we create the view here instead of inside the // Add widget to the bottom, we create the view here instead of inside the
// OutputPaneManager, since the StatusBarManager needs to be initialized before // OutputPaneManager, since the StatusBarManager needs to be initialized before
m_outputView = new Core::StatusBarWidget; m_outputView = new Core::StatusBarWidget;
...@@ -352,8 +357,6 @@ void MainWindow::extensionsInitialized() ...@@ -352,8 +357,6 @@ void MainWindow::extensionsInitialized()
readSettings(); readSettings();
updateContext(); updateContext();
registerUserMimeTypes();
emit m_coreImpl->coreAboutToOpen(); emit m_coreImpl->coreAboutToOpen();
show(); show();
emit m_coreImpl->coreOpened(); emit m_coreImpl->coreOpened();
...@@ -1397,15 +1400,3 @@ bool MainWindow::showWarningWithOptions(const QString &title, ...@@ -1397,15 +1400,3 @@ bool MainWindow::showWarningWithOptions(const QString &title,
} }
return false; return false;
} }
void MainWindow::registerUserMimeTypes() const
{
// This is to temporarily allow user specific MIME types (without recompilation).
// Be careful with the file contents. Otherwise unpredictable behavior might arise.
const QString &fileName = m_coreImpl->userResourcePath() + QLatin1String("/mimetypes.xml");
if (QFile::exists(fileName)) {
QString error;
if (!m_coreImpl->mimeDatabase()->addMimeTypes(fileName, &error))
qWarning() << error;
}
}
...@@ -78,6 +78,7 @@ class GeneralSettings; ...@@ -78,6 +78,7 @@ class GeneralSettings;
class ProgressManagerPrivate; class ProgressManagerPrivate;
class ShortcutSettings; class ShortcutSettings;
class ToolSettings; class ToolSettings;
class MimeTypeSettings;
class StatusBarManager; class StatusBarManager;
class VersionDialog; class VersionDialog;
class SystemEditor; class SystemEditor;
...@@ -179,8 +180,6 @@ private: ...@@ -179,8 +180,6 @@ private:
void readSettings(); void readSettings();
void writeSettings(); void writeSettings();
void registerUserMimeTypes() const;
CoreImpl *m_coreImpl; CoreImpl *m_coreImpl;
UniqueIDManager *m_uniqueIDManager; UniqueIDManager *m_uniqueIDManager;
Context m_additionalContexts; Context m_additionalContexts;
...@@ -214,6 +213,7 @@ private: ...@@ -214,6 +213,7 @@ private:
GeneralSettings *m_generalSettings; GeneralSettings *m_generalSettings;
ShortcutSettings *m_shortcutSettings; ShortcutSettings *m_shortcutSettings;
ToolSettings *m_toolSettings; ToolSettings *m_toolSettings;
MimeTypeSettings *m_mimeTypeSettings;
SystemEditor *m_systemEditor; SystemEditor *m_systemEditor;
// actions // actions
......
This diff is collapsed.
...@@ -41,6 +41,7 @@ ...@@ -41,6 +41,7 @@
#include <QtCore/QByteArray> #include <QtCore/QByteArray>
#include <QtCore/QMutex> #include <QtCore/QMutex>
#include <QtCore/QFileInfo> #include <QtCore/QFileInfo>
#include <QtCore/QPair>
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
class QIODevice; class QIODevice;
...@@ -66,6 +67,9 @@ class CORE_EXPORT IMagicMatcher ...@@ -66,6 +67,9 @@ class CORE_EXPORT IMagicMatcher
protected: protected:
IMagicMatcher() {} IMagicMatcher() {}
public: public:
typedef QSharedPointer<IMagicMatcher> IMagicMatcherSharedPointer;
typedef QList<IMagicMatcherSharedPointer> IMagicMatcherList;
// Check for a match on contents of a file // Check for a match on contents of a file
virtual bool matches(const QByteArray &data) const = 0; virtual bool matches(const QByteArray &data) const = 0;
// Return a priority value from 1..100 // Return a priority value from 1..100
...@@ -83,13 +87,19 @@ public: ...@@ -83,13 +87,19 @@ public:
MagicRule(int startPos, int endPos); MagicRule(int startPos, int endPos);
virtual ~MagicRule(); virtual ~MagicRule();
virtual QString matchType() const = 0;
virtual QString matchValue() const = 0;
virtual bool matches(const QByteArray &data) const = 0; virtual bool matches(const QByteArray &data) const = 0;
protected:
int startPos() const; int startPos() const;
int endPos() const; int endPos() const;
static QString toOffset(const QPair<int, int> &startEnd);
static QPair<int, int> fromOffset(const QString &offset);
private: private:
static const QChar kColon;
const int m_startPos; const int m_startPos;
const int m_endPos; const int m_endPos;
}; };
...@@ -100,8 +110,12 @@ public: ...@@ -100,8 +110,12 @@ public:
MagicStringRule(const QString &s, int startPos, int endPos); MagicStringRule(const QString &s, int startPos, int endPos);
virtual ~MagicStringRule(); virtual ~MagicStringRule();
virtual QString matchType() const;
virtual QString matchValue() const;
virtual bool matches(const QByteArray &data) const; virtual bool matches(const QByteArray &data) const;
static const QString kMatchType;
private: private:
const QByteArray m_pattern; const QByteArray m_pattern;
}; };
...@@ -112,11 +126,17 @@ public: ...@@ -112,11 +126,17 @@ public:
MagicByteRule(const QString &s, int startPos, int endPos); MagicByteRule(const QString &s, int startPos, int endPos);
virtual ~MagicByteRule(); virtual ~MagicByteRule();
virtual QString matchType() const;
virtual QString matchValue() const;
virtual bool matches(const QByteArray &data) const; virtual bool matches(const QByteArray &data) const;
static bool validateByteSequence(const QString &sequence, QList<int> *bytes = 0);
static const QString kMatchType;
private: private:
QList<int> m_bytes;
int m_bytesSize; int m_bytesSize;
QList<int> m_bytes;
}; };
/* Utility class: A Magic matcher that checks a number of rules based on /* Utility class: A Magic matcher that checks a number of rules based on
...@@ -125,17 +145,24 @@ class CORE_EXPORT MagicRuleMatcher : public IMagicMatcher ...@@ -125,17 +145,24 @@ class CORE_EXPORT MagicRuleMatcher : public IMagicMatcher
{ {
Q_DISABLE_COPY(MagicRuleMatcher) Q_DISABLE_COPY(MagicRuleMatcher)
public: public:
typedef QSharedPointer<MagicRule> MagicRuleSharedPointer; typedef QSharedPointer<MagicRule> MagicRuleSharedPointer;
typedef QList<MagicRuleSharedPointer> MagicRuleList;
MagicRuleMatcher(); MagicRuleMatcher();
void add(const MagicRuleSharedPointer &rule); void add(const MagicRuleSharedPointer &rule);
void add(const MagicRuleList &ruleList);
MagicRuleList magicRules() const;
virtual bool matches(const QByteArray &data) const; virtual bool matches(const QByteArray &data) const;
virtual int priority() const; virtual int priority() const;
void setPriority(int p); void setPriority(int p);
// Create a list of MagicRuleMatchers from a hash of rules indexed by priorities.
static IMagicMatcher::IMagicMatcherList createMatchers(const QHash<int, MagicRuleList> &);
private: private:
typedef QList<MagicRuleSharedPointer> MagicRuleList;
MagicRuleList m_list; MagicRuleList m_list;
int m_priority; int m_priority;
}; };
...@@ -169,6 +196,9 @@ private: ...@@ -169,6 +196,9 @@ private:
class CORE_EXPORT MimeType class CORE_EXPORT MimeType
{ {
public: public:
typedef IMagicMatcher::IMagicMatcherList IMagicMatcherList;
typedef IMagicMatcher::IMagicMatcherSharedPointer IMagicMatcherSharedPointer;
MimeType(); MimeType();
MimeType(const MimeType&); MimeType(const MimeType&);
MimeType &operator=(const MimeType&); MimeType &operator=(const MimeType&);
...@@ -200,9 +230,6 @@ public: ...@@ -200,9 +230,6 @@ public:
// Extension over standard mime data // Extension over standard mime data
QStringList suffixes() const; QStringList suffixes() const;
void setSuffixes(const QStringList &);
// Extension over standard mime data
QString preferredSuffix() const; QString preferredSuffix() const;
bool setPreferredSuffix(const QString&); bool setPreferredSuffix(const QString&);
...@@ -216,12 +243,19 @@ public: ...@@ -216,12 +243,19 @@ public:
// Return a filter string usable for a file dialog // Return a filter string usable for a file dialog
QString filterString() const; QString filterString() const;
// Add magic matcher void addMagicMatcher(const IMagicMatcherSharedPointer &matcher);
void addMagicMatcher(const QSharedPointer<IMagicMatcher> &matcher);
const IMagicMatcherList &magicMatchers() const;
void setMagicMatchers(const IMagicMatcherList &matchers);
// Convenience for rule-base matchers.
IMagicMatcherList magicRuleMatchers() const;
void setMagicRuleMatchers(const IMagicMatcherList &matchers);
friend QDebug operator<<(QDebug d, const MimeType &mt); friend QDebug operator<<(QDebug d, const MimeType &mt);
static QString formatFilterString(const QString &description, const QList<MimeGlobPattern> &globs); static QString formatFilterString(const QString &description,
const QList<MimeGlobPattern> &globs);
private: private:
explicit MimeType(const MimeTypeData &d); explicit MimeType(const MimeTypeData &d);
...@@ -243,8 +277,10 @@ class CORE_EXPORT MimeDatabase ...@@ -243,8 +277,10 @@ class CORE_EXPORT MimeDatabase
{ {
Q_DISABLE_COPY(MimeDatabase) Q_DISABLE_COPY(MimeDatabase)
public: public:
MimeDatabase(); typedef IMagicMatcher::IMagicMatcherList IMagicMatcherList;
typedef IMagicMatcher::IMagicMatcherSharedPointer IMagicMatcherSharedPointer;
MimeDatabase();
~MimeDatabase(); ~MimeDatabase();
bool addMimeTypes(const QString &fileName, QString *errorMessage); bool addMimeTypes(const QString &fileName, QString *errorMessage);
...@@ -256,27 +292,45 @@ public: ...@@ -256,27 +292,45 @@ public:
// Returns a mime type or Null one if none found // Returns a mime type or Null one if none found
MimeType findByFile(const QFileInfo &f) const; MimeType findByFile(const QFileInfo &f) const;
// Convenience that mutex-locks the DB and calls a function // Convenience that mutex-locks the DB and calls a function
// of the signature 'void f(const MimeType &, const QFileInfo &, const QString &)' // of the signature 'void f(const MimeType &, const QFileInfo &, const QString &)'
// for each filename of a sequence. This avoids locking the DB for each // for each filename of a sequence. This avoids locking the DB for each
// single file. // single file.
template <class Iterator, typename Function> template <class Iterator, typename Function>
inline void findByFile(Iterator i1, const Iterator &i2, Function f) const; inline void findByFile(Iterator i1, const Iterator &i2, Function f) const;
// Convenience
QString preferredSuffixByType(const QString &type) const;
QString preferredSuffixByFile(const QFileInfo &f) const;
// Return all known suffixes // Return all known suffixes
QStringList suffixes() const; QStringList suffixes() const;
bool setPreferredSuffix(const QString &typeOrAlias, const QString &suffix); bool setPreferredSuffix(const QString &typeOrAlias, const QString &suffix);
QString preferredSuffixByType(const QString &type) const;
QString preferredSuffixByFile(const QFileInfo &f) const;
QStringList filterStrings() const; QStringList filterStrings() const;
// Return a string with all the possible file filters, for use with file dialogs
QString allFiltersString(QString *allFilesFilter = 0) const;
QList<MimeGlobPattern> globPatterns() const;
void setGlobPatterns(const QString &typeOrAlias, const QList<MimeGlobPattern> &globPatterns);
IMagicMatcherList magicMatchers() const;
void setMagicMatchers(const QString &typeOrAlias, const IMagicMatcherList &matchers);
QList<MimeType> mimeTypes() const;
// The mime types from the functions bellow are considered only in regard to
// their glob patterns and rule-based magic matchers.
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);
friend QDebug operator<<(QDebug d, const MimeDatabase &mt); friend QDebug operator<<(QDebug d, const MimeDatabase &mt);
// returns a string with all the possible file filters, for use with file dialogs
QString allFiltersString(QString *allFilesFilter = 0) const;
private: private:
MimeType findByFileUnlocked(const QFileInfo &f) const; MimeType findByFileUnlocked(const QFileInfo &f) const;
......
/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** No Commercial Usage
**
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the Technology Preview License Agreement accompanying
** this package.
**
** GNU Lesser General Public License Usage
**
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**************************************************************************/
#include "mimetypemagicdialog.h"
#include "mimedatabase.h"
#include <QtCore/QLatin1String>
#include <QtGui/QMessageBox>
using namespace Core;
using namespace Internal;
MimeTypeMagicDialog::MimeTypeMagicDialog(QWidget *parent) :
QDialog(parent)
{
ui.setupUi(this);
setWindowTitle(tr("Magic Header"));
connect(ui.useRecommendedGroupBox, SIGNAL(clicked(bool)),
this, SLOT(applyRecommended(bool)));
connect(ui.buttonBox, SIGNAL(accepted()), this, SLOT(validateAccept()));
}
void MimeTypeMagicDialog::changeEvent(QEvent *e)
{
QDialog::changeEvent(e);
switch (e->type()) {
case QEvent::LanguageChange:
ui.retranslateUi(this);
break;
default:
break;
}
}
void MimeTypeMagicDialog::applyRecommended(bool checked)
{
if (checked) {
ui.startRangeSpinBox->setValue(0);
ui.endRangeSpinBox->setValue(0);
ui.prioritySpinBox->setValue(50);
}
}
void MimeTypeMagicDialog::validateAccept()
{
if (ui.valueLineEdit->text().isEmpty()
|| (ui.byteRadioButton->isChecked()
&& !Core::MagicByteRule::validateByteSequence(ui.valueLineEdit->text()))) {