Merge branch 'master' of scm.dev.nokia.troll.no:creator/mainline

This commit is contained in:
con
2011-03-02 11:50:08 +01:00
34 changed files with 2547 additions and 152 deletions

View File

@@ -31,6 +31,9 @@
** **
**************************************************************************/ **************************************************************************/
// WARNING: This code is shared with the qmlplugindump tool code in Qt.
// Modifications to this file need to be applied there.
#include <QtDeclarative/QtDeclarative> #include <QtDeclarative/QtDeclarative>
#include <QtDeclarative/private/qdeclarativemetatype_p.h> #include <QtDeclarative/private/qdeclarativemetatype_p.h>
#include <QtDeclarative/private/qdeclarativeopenmetaobject_p.h> #include <QtDeclarative/private/qdeclarativeopenmetaobject_p.h>

View File

@@ -31,6 +31,9 @@
** **
**************************************************************************/ **************************************************************************/
// WARNING: This code is shared with the qmlplugindump tool code in Qt.
// Modifications to this file need to be applied there.
#include "qmlstreamwriter.h" #include "qmlstreamwriter.h"
#include <QtCore/QBuffer> #include <QtCore/QBuffer>

View File

@@ -31,6 +31,9 @@
** **
**************************************************************************/ **************************************************************************/
// WARNING: This code is shared with the qmlplugindump tool code in Qt.
// Modifications to this file need to be applied there.
#ifndef QMLSTREAMWRITER_H #ifndef QMLSTREAMWRITER_H
#define QMLSTREAMWRITER_H #define QMLSTREAMWRITER_H

View File

@@ -56,11 +56,11 @@ leave room for the Qt 4 target page.
<!-- Create a 2nd wizard page with parameters --> <!-- Create a 2nd wizard page with parameters -->
<fieldpagetitle>Custom QML Extension Plugin Parameters</fieldpagetitle> <fieldpagetitle>Custom QML Extension Plugin Parameters</fieldpagetitle>
<fields> <fields>
<field mandatory="false" name="ObjectName"> <field mandatory="true" name="ObjectName">
<fieldcontrol class="QLineEdit" validator='^[A-Za-z0-9_]+$' defaulttext="MyItem"/> <fieldcontrol class="QLineEdit" validator='^[A-Za-z0-9_]+$' defaulttext="MyItem"/>
<fielddescription>Object Class-name:</fielddescription> <fielddescription>Object Class-name:</fielddescription>
</field> </field>
<field mandatory="false" name="Uri"> <field mandatory="true" name="Uri">
<fieldcontrol class="QLineEdit" validator='^[A-Za-z0-9]+([A-Za-z0-9-]*[A-Za-z0-9]+)?(\.[A-Za-z0-9]+([-A-Za-z0-9]*[A-Za-z0-9]+)?)*$' defaulttext="com.mycompany.qmlcomponents"/> <fieldcontrol class="QLineEdit" validator='^[A-Za-z0-9]+([A-Za-z0-9-]*[A-Za-z0-9]+)?(\.[A-Za-z0-9]+([-A-Za-z0-9]*[A-Za-z0-9]+)?)*$' defaulttext="com.mycompany.qmlcomponents"/>
<fielddescription>URI:</fielddescription> <fielddescription>URI:</fielddescription>
</field> </field>

View File

@@ -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";

View File

@@ -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)
void CorePlugin::extensionsInitialized() void CorePlugin::extensionsInitialized()
{ {
m_mainWindow->mimeDatabase()->syncUserModifiedMimeTypes();
m_mainWindow->extensionsInitialized(); m_mainWindow->extensionsInitialized();
} }

View File

@@ -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 \
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 \
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

View File

@@ -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

View File

@@ -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() :
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()
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()
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)
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()
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,
} }
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;
}
}

View File

@@ -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:
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:
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

View File

@@ -33,6 +33,7 @@
#include "mimedatabase.h" #include "mimedatabase.h"
#include "coreconstants.h" #include "coreconstants.h"
#include "icore.h"
#include <utils/qtcassert.h> #include <utils/qtcassert.h>
@@ -40,9 +41,11 @@
#include <QtCore/QCoreApplication> #include <QtCore/QCoreApplication>
#include <QtCore/QDebug> #include <QtCore/QDebug>
#include <QtCore/QFile> #include <QtCore/QFile>
#include <QtCore/QDir>
#include <QtCore/QFileInfo> #include <QtCore/QFileInfo>
#include <QtCore/QLocale> #include <QtCore/QLocale>
#include <QtCore/QMap> #include <QtCore/QMap>
#include <QtCore/QHash>
#include <QtCore/QMultiHash> #include <QtCore/QMultiHash>
#include <QtCore/QRegExp> #include <QtCore/QRegExp>
#include <QtCore/QSharedData> #include <QtCore/QSharedData>
@@ -50,10 +53,11 @@
#include <QtCore/QStringList> #include <QtCore/QStringList>
#include <QtCore/QTextStream> #include <QtCore/QTextStream>
#include <QtCore/QMutexLocker> #include <QtCore/QMutexLocker>
#include <QtCore/QXmlStreamReader>
#include <QtXml/QXmlStreamReader> #include <QtCore/QXmlStreamWriter>
#include <algorithm> #include <algorithm>
#include <functional>
enum { debugMimeDB = 0 }; enum { debugMimeDB = 0 };
@@ -211,6 +215,8 @@ bool HeuristicTextMagicMatcher::matches(const QByteArray &data) const
} // namespace Internal } // namespace Internal
// MagicRule // MagicRule
const QChar MagicRule::kColon(QLatin1Char(':'));
MagicRule::MagicRule(int startPos, int endPos) : m_startPos(startPos), m_endPos(endPos) MagicRule::MagicRule(int startPos, int endPos) : m_startPos(startPos), m_endPos(endPos)
{ {
} }
@@ -229,6 +235,20 @@ int MagicRule::endPos() const
return m_endPos; 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) : MagicStringRule::MagicStringRule(const QString &s, int startPos, int endPos) :
MagicRule(startPos, endPos), m_pattern(s.toUtf8()) 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 bool MagicStringRule::matches(const QByteArray &data) const
{ {
// Quick check // Quick check
@@ -254,28 +284,51 @@ bool MagicStringRule::matches(const QByteArray &data) const
return rc; return rc;
} }
const QString MagicByteRule::kMatchType(QLatin1String("byte"));
MagicByteRule::MagicByteRule(const QString &s, int startPos, int endPos) : 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 if (validateByteSequence(s, &m_bytes))
const QStringList &bytes = s.split(QLatin1Char('\\'), QString::SkipEmptyParts); m_bytesSize = m_bytes.size();
foreach (const QString &byte, bytes) { else
bool ok; m_bytes.clear();
const int hex = byte.toInt(&ok, 16);
if (ok) {
m_bytes.push_back(hex);
} else {
m_bytes.clear();
break;
}
}
m_bytesSize = m_bytes.size();
} }
MagicByteRule::~MagicByteRule() 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 bool MagicByteRule::matches(const QByteArray &data) const
{ {
if (m_bytesSize == 0) if (m_bytesSize == 0)
@@ -307,7 +360,17 @@ MagicRuleMatcher::MagicRuleMatcher() :
void MagicRuleMatcher::add(const MagicRuleSharedPointer &rule) 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 bool MagicRuleMatcher::matches(const QByteArray &data) const
@@ -329,6 +392,20 @@ void MagicRuleMatcher::setPriority(int p)
m_priority = 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 // GlobPattern
MimeGlobPattern::MimeGlobPattern(const QRegExp &regExp, unsigned weight) : MimeGlobPattern::MimeGlobPattern(const QRegExp &regExp, unsigned weight) :
m_regExp(regExp), m_weight(weight) m_regExp(regExp), m_weight(weight)
@@ -353,9 +430,16 @@ unsigned MimeGlobPattern::weight() const
class MimeTypeData : public QSharedData { class MimeTypeData : public QSharedData {
public: public:
typedef QHash<QString,QString> LocaleHash; typedef QHash<QString,QString> LocaleHash;
MimeTypeData();
void clear(); void clear();
void assignSuffix(const QString &pattern);
void assignSuffixes(const QStringList &patterns);
void debug(QTextStream &str, int indent = 0) const; void debug(QTextStream &str, int indent = 0) const;
const QRegExp suffixPattern;
QString type; QString type;
QString comment; QString comment;
@@ -365,12 +449,17 @@ public:
QStringList subClassesOf; QStringList subClassesOf;
QString preferredSuffix; QString preferredSuffix;
QStringList suffixes; QStringList suffixes;
IMagicMatcher::IMagicMatcherList magicMatchers;
typedef QSharedPointer<IMagicMatcher> IMagicMatcherSharedPointer;
typedef QList<IMagicMatcherSharedPointer> IMagicMatcherList;
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() void MimeTypeData::clear()
{ {
type.clear(); type.clear();
@@ -383,6 +472,22 @@ void MimeTypeData::clear()
magicMatchers.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 void MimeTypeData::debug(QTextStream &str, int indent) const
{ {
const QString indentS = QString(indent, QLatin1Char(' ')); const QString indentS = QString(indent, QLatin1Char(' '));
@@ -516,6 +621,13 @@ QList<MimeGlobPattern> MimeType::globPatterns() const
void MimeType::setGlobPatterns(const QList<MimeGlobPattern> &g) void MimeType::setGlobPatterns(const QList<MimeGlobPattern> &g)
{ {
m_d->globPatterns = 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 QStringList MimeType::subClassesOf() const
@@ -608,7 +720,7 @@ unsigned MimeType::matchesFileByContent(Internal::FileMatchContext &c) const
const QByteArray data = c.data(); const QByteArray data = c.data();
if (!data.isEmpty()) { if (!data.isEmpty()) {
foreach (const MimeTypeData::IMagicMatcherSharedPointer &matcher, m_d->magicMatchers) { foreach (const IMagicMatcher::IMagicMatcherSharedPointer &matcher, m_d->magicMatchers) {
if (matcher->matches(data)) { if (matcher->matches(data)) {
const unsigned magicPriority = matcher->priority(); const unsigned magicPriority = matcher->priority();
if (magicPriority > priority) if (magicPriority > priority)
@@ -624,16 +736,52 @@ QStringList MimeType::suffixes() const
return m_d->suffixes; return m_d->suffixes;
} }
void MimeType::setSuffixes(const QStringList &s) void MimeType::addMagicMatcher(const IMagicMatcherSharedPointer &matcher)
{
m_d->suffixes = s;
}
void MimeType::addMagicMatcher(const QSharedPointer<IMagicMatcher> &matcher)
{ {
m_d->magicMatchers.push_back(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) QDebug operator<<(QDebug d, const MimeType &mt)
{ {
QString s; QString s;
@@ -652,7 +800,7 @@ namespace Internal {
class BaseMimeTypeParser { class BaseMimeTypeParser {
Q_DISABLE_COPY(BaseMimeTypeParser) Q_DISABLE_COPY(BaseMimeTypeParser)
public: public:
BaseMimeTypeParser(); BaseMimeTypeParser() {}
virtual ~BaseMimeTypeParser() {} virtual ~BaseMimeTypeParser() {}
bool parse(QIODevice *dev, const QString &fileName, QString *errorMessage); bool parse(QIODevice *dev, const QString &fileName, QString *errorMessage);
@@ -676,18 +824,8 @@ private:
ParseError }; ParseError };
static ParseStage nextStage(ParseStage currentStage, const QStringRef &startElement); 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 void BaseMimeTypeParser::addGlobPattern(const QString &pattern, const QString &weight, MimeTypeData *d) const
{ {
if (pattern.isEmpty()) if (pattern.isEmpty())
@@ -706,12 +844,7 @@ void BaseMimeTypeParser::addGlobPattern(const QString &pattern, const QString &w
else else
d->globPatterns.push_back(MimeGlobPattern(wildCard, weight.toInt())); d->globPatterns.push_back(MimeGlobPattern(wildCard, weight.toInt()));
if (m_suffixPattern.exactMatch(pattern)) { d->assignSuffix(pattern);
const QString suffix = pattern.right(pattern.size() - 2);
d->suffixes.push_back(suffix);
if (d->preferredSuffix.isEmpty())
d->preferredSuffix = suffix;
}
} }
BaseMimeTypeParser::ParseStage BaseMimeTypeParser::nextStage(ParseStage currentStage, const QStringRef &startElement) 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. * - Provide quick lookup by file type.
* This basically rules out some pointer-based tree, so the structure chosen * This basically rules out some pointer-based tree, so the structure chosen
* is: * is:
* - An alias map <QString->QString> for mapping aliases to types * - An alias map QString->QString for mapping aliases to types
* - A Map <QString-MimeMapEntry> for the types (MimeMapEntry being a pair of * - A Map QString->MimeMapEntry for the types (MimeMapEntry being a pair of
* MimeType and (hierarchy) level. * 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) * recursing over children)
* Using strings avoids dangling pointers. * Using strings avoids dangling pointers.
* The hierarchy level is used for mapping by file types. When findByFile() * The hierarchy level is used for mapping by file types. When findByFile()
@@ -958,16 +1091,31 @@ public:
bool addMimeTypes(QIODevice *device, QString *errorMessage); bool addMimeTypes(QIODevice *device, QString *errorMessage);
bool addMimeType(MimeType mt); bool addMimeType(MimeType mt);
// Returns a mime type or Null one if none found
MimeType findByType(const QString &type) const; MimeType findByType(const QString &type) const;
// Returns a mime type or Null one if none found
MimeType findByFile(const QFileInfo &f) const; MimeType findByFile(const QFileInfo &f) const;
QStringList filterStrings() const;
QStringList suffixes() const;
bool setPreferredSuffix(const QString &typeOrAlias, const QString &suffix); bool setPreferredSuffix(const QString &typeOrAlias, const QString &suffix);
// Return all known suffixes QList<MimeGlobPattern> globPatterns() const;
QStringList suffixes() const; void setGlobPatterns(const QString &typeOrAlias, const QList<MimeGlobPattern> &globPatterns);
QStringList filterStrings() const;
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; void debug(QTextStream &str) const;
@@ -976,6 +1124,11 @@ private:
typedef QHash<QString, QString> AliasMap; typedef QHash<QString, QString> AliasMap;
typedef QMultiHash<QString, QString> ParentChildrenMap; 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); bool addMimeTypes(QIODevice *device, const QString &fileName, QString *errorMessage);
inline const QString &resolveAlias(const QString &name) const; inline const QString &resolveAlias(const QString &name) const;
MimeType findByFile(const QFileInfo &f, unsigned *priority) const; MimeType findByFile(const QFileInfo &f, unsigned *priority) const;
@@ -988,9 +1141,15 @@ private:
int m_maxLevel; int m_maxLevel;
}; };
const QChar MimeDatabasePrivate::kSemiColon(QLatin1Char(';'));
const QString MimeDatabasePrivate::kModifiedMimeTypesFile(QLatin1String("modifiedmimetypes.xml"));
QString MimeDatabasePrivate::kModifiedMimeTypesPath;
MimeDatabasePrivate::MimeDatabasePrivate() : MimeDatabasePrivate::MimeDatabasePrivate() :
m_maxLevel(-1) m_maxLevel(-1)
{ {
// Assign here to avoid non-local static data initialization issues.
kModifiedMimeTypesPath = ICore::instance()->userResourcePath() + QLatin1String("/mimetypes/");
} }
namespace Internal { namespace Internal {
@@ -1230,6 +1389,197 @@ QStringList MimeDatabasePrivate::filterStrings() const
return rc; 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 void MimeDatabasePrivate::debug(QTextStream &str) const
{ {
str << ">MimeDatabase\n"; str << ">MimeDatabase\n";
@@ -1308,7 +1658,7 @@ QStringList MimeDatabase::suffixes() const
QStringList MimeDatabase::filterStrings() const QStringList MimeDatabase::filterStrings() const
{ {
m_mutex.lock(); m_mutex.lock();
const QStringList rc = m_d->filterStrings(); const QStringList rc = m_d->filterStrings();
m_mutex.unlock(); m_mutex.unlock();
return rc; return rc;
} }
@@ -1336,6 +1686,70 @@ QString MimeDatabase::allFiltersString(QString *allFilesFilter) const
return filters.join(QLatin1String(";;")); 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 QString MimeDatabase::preferredSuffixByType(const QString &type) const
{ {
if (const MimeType mt = findByType(type)) if (const MimeType mt = findByType(type))
@@ -1358,6 +1772,16 @@ bool MimeDatabase::setPreferredSuffix(const QString &typeOrAlias, const QString
return rc; 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) QDebug operator<<(QDebug d, const MimeDatabase &mt)
{ {
QString s; QString s;

View File

@@ -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
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:
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:
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:
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
{ {
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:
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:
// 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:
// 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
{ {
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:
// 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;

View File

@@ -0,0 +1,109 @@
/**************************************************************************
**
** 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()))) {
QMessageBox::critical(0, tr("Error"), tr("Not a valid byte pattern."));
return;
}
accept();
}
void MimeTypeMagicDialog::setMagicData(const MagicData &data)
{
ui.valueLineEdit->setText(data.m_value);
if (data.m_type == Core::MagicStringRule::kMatchType)
ui.stringRadioButton->setChecked(true);
else
ui.byteRadioButton->setChecked(true);
ui.startRangeSpinBox->setValue(data.m_start);
ui.endRangeSpinBox->setValue(data.m_end);
ui.prioritySpinBox->setValue(data.m_priority);
}
MagicData MimeTypeMagicDialog::magicData() const
{
MagicData data;
data.m_value = ui.valueLineEdit->text();
if (ui.stringRadioButton->isChecked())
data.m_type = Core::MagicStringRule::kMatchType;
else
data.m_type = Core::MagicByteRule::kMatchType;
data.m_start = ui.startRangeSpinBox->value();
data.m_end = ui.endRangeSpinBox->value();
data.m_priority = ui.prioritySpinBox->value();
return data;
}

View File

@@ -0,0 +1,83 @@
/**************************************************************************
**
** 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.
**
**************************************************************************/
#ifndef MIMETYPEMAGICDIALOG_H
#define MIMETYPEMAGICDIALOG_H
#include "ui_mimetypemagicdialog.h"
namespace Core {
namespace Internal {
struct MagicData
{
MagicData() {}
MagicData(const QString &value, const QString &type, int start, int end, int p)
: m_value(value)
, m_type(type)
, m_start(start)
, m_end(end)
, m_priority(p) {}
QString m_value;
QString m_type;
int m_start;
int m_end;
int m_priority;
};
class MimeTypeMagicDialog : public QDialog
{
Q_OBJECT
public:
explicit MimeTypeMagicDialog(QWidget *parent = 0);
void setMagicData(const MagicData &data);
MagicData magicData() const;
protected:
void changeEvent(QEvent *e);
private slots:
void applyRecommended(bool checked);
void validateAccept();
private:
Ui::MimeTypeMagicDialog ui;
};
} // Internal
} // Core
#endif // MIMETYPEMAGICDIALOG_H

View File

@@ -0,0 +1,318 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MimeTypeMagicDialog</class>
<widget class="QDialog" name="MimeTypeMagicDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>480</width>
<height>286</height>
</rect>
</property>
<property name="windowTitle">
<string>Dialog</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QLabel" name="valueLabel">
<property name="text">
<string>Value:</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="valueLineEdit"/>
</item>
</layout>
</item>
<item>
<widget class="QGroupBox" name="typeGroupBox">
<property name="title">
<string>Type</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QRadioButton" name="stringRadioButton">
<property name="text">
<string>String</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QRadioButton" name="byteRadioButton">
<property name="text">
<string>Byte</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="useRecommendedGroupBox">
<property name="title">
<string>Use Recommended</string>
</property>
<property name="checkable">
<bool>true</bool>
</property>
<layout class="QGridLayout" name="gridLayout_2">
<item row="0" column="0">
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<widget class="QLabel" name="startRangeLabel">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>Start range:</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="endRangeLabel">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>End range:</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="priorityLabel">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>Priority:</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QSpinBox" name="prioritySpinBox">
<property name="enabled">
<bool>false</bool>
</property>
<property name="minimum">
<number>1</number>
</property>
<property name="value">
<number>50</number>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QSpinBox" name="startRangeSpinBox">
<property name="enabled">
<bool>false</bool>
</property>
<property name="maximum">
<number>9999</number>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QSpinBox" name="endRangeSpinBox">
<property name="enabled">
<bool>false</bool>
</property>
<property name="maximum">
<number>9999</number>
</property>
</widget>
</item>
</layout>
</item>
<item row="0" column="1">
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>233</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="1" column="0">
<widget class="QLabel" name="noteLabel">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>&lt;i&gt;Note: Wide range values might impact on Qt Creator's performance when opening files.&lt;/i&gt;</string>
</property>
<property name="textFormat">
<enum>Qt::RichText</enum>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>11</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>MimeTypeMagicDialog</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>295</x>
<y>297</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>useRecommendedGroupBox</sender>
<signal>clicked(bool)</signal>
<receiver>prioritySpinBox</receiver>
<slot>setDisabled(bool)</slot>
<hints>
<hint type="sourcelabel">
<x>48</x>
<y>171</y>
</hint>
<hint type="destinationlabel">
<x>105</x>
<y>249</y>
</hint>
</hints>
</connection>
<connection>
<sender>useRecommendedGroupBox</sender>
<signal>clicked(bool)</signal>
<receiver>startRangeSpinBox</receiver>
<slot>setDisabled(bool)</slot>
<hints>
<hint type="sourcelabel">
<x>195</x>
<y>169</y>
</hint>
<hint type="destinationlabel">
<x>107</x>
<y>149</y>
</hint>
</hints>
</connection>
<connection>
<sender>useRecommendedGroupBox</sender>
<signal>clicked(bool)</signal>
<receiver>endRangeSpinBox</receiver>
<slot>setDisabled(bool)</slot>
<hints>
<hint type="sourcelabel">
<x>195</x>
<y>169</y>
</hint>
<hint type="destinationlabel">
<x>107</x>
<y>175</y>
</hint>
</hints>
</connection>
<connection>
<sender>useRecommendedGroupBox</sender>
<signal>clicked(bool)</signal>
<receiver>priorityLabel</receiver>
<slot>setDisabled(bool)</slot>
<hints>
<hint type="sourcelabel">
<x>225</x>
<y>178</y>
</hint>
<hint type="destinationlabel">
<x>99</x>
<y>201</y>
</hint>
</hints>
</connection>
<connection>
<sender>useRecommendedGroupBox</sender>
<signal>clicked(bool)</signal>
<receiver>startRangeLabel</receiver>
<slot>setDisabled(bool)</slot>
<hints>
<hint type="sourcelabel">
<x>225</x>
<y>178</y>
</hint>
<hint type="destinationlabel">
<x>99</x>
<y>149</y>
</hint>
</hints>
</connection>
<connection>
<sender>useRecommendedGroupBox</sender>
<signal>clicked(bool)</signal>
<receiver>endRangeLabel</receiver>
<slot>setDisabled(bool)</slot>
<hints>
<hint type="sourcelabel">
<x>225</x>
<y>178</y>
</hint>
<hint type="destinationlabel">
<x>99</x>
<y>175</y>
</hint>
</hints>
</connection>
<connection>
<sender>useRecommendedGroupBox</sender>
<signal>clicked(bool)</signal>
<receiver>noteLabel</receiver>
<slot>setDisabled(bool)</slot>
<hints>
<hint type="sourcelabel">
<x>225</x>
<y>178</y>
</hint>
<hint type="destinationlabel">
<x>182</x>
<y>225</y>
</hint>
</hints>
</connection>
</connections>
</ui>

View File

@@ -0,0 +1,605 @@
/**************************************************************************
**
** 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 "mimetypesettings.h"
#include "ui_mimetypesettingspage.h"
#include "mimetypemagicdialog.h"
#include "mimedatabase.h"
#include "coreconstants.h"
#include "editormanager.h"
#include "icore.h"
#include "ieditorfactory.h"
#include "iexternaleditor.h"
#include <extensionsystem/pluginmanager.h>
#include <QtCore/QCoreApplication>
#include <QtCore/QLatin1String>
#include <QtCore/QStringList>
#include <QtCore/QVector>
#include <QtCore/QSet>
#include <QtCore/QScopedPointer>
#include <QtCore/QAbstractTableModel>
#include <QtCore/QHash>
#include <QtGui/QIcon>
#include <QtGui/QTableWidgetItem>
#include <QtGui/QMessageBox>
#include <QtAlgorithms>
#include <algorithm>
namespace Core {
namespace Internal {
struct MimeTypeComp
{
bool operator()(const MimeType &a, const MimeType &b)
{ return a.type().compare(b.type(), Qt::CaseInsensitive) < 0; }
};
// MimeTypeSettingsModel
class MimeTypeSettingsModel : public QAbstractTableModel
{
Q_OBJECT
public:
MimeTypeSettingsModel(QObject *parent = 0)
: QAbstractTableModel(parent), m_core(ICore::instance()) {}
virtual ~MimeTypeSettingsModel() {}
virtual int rowCount(const QModelIndex &parent = QModelIndex()) const;
virtual int columnCount(const QModelIndex &parent = QModelIndex()) const;
virtual QVariant headerData(int section, Qt::Orientation orientation,
int role = Qt::DisplayRole) const;
virtual QVariant data(const QModelIndex &modelIndex, int role = Qt::DisplayRole) const;
void load();
void validatePatterns(QStringList *candidates, const MimeType &mimeType) const;
void updateKnownPatterns(const QStringList &oldPatterns, const QStringList &newPatterns);
ICore *m_core;
QList<MimeType> m_mimeTypes;
QSet<QString> m_knownPatterns;
QHash<QString, QString> m_handlersByMimeType;
};
int MimeTypeSettingsModel::rowCount(const QModelIndex &) const
{
return m_mimeTypes.size();
}
int MimeTypeSettingsModel::columnCount(const QModelIndex &) const
{
return 2;
}
QVariant MimeTypeSettingsModel::headerData(int section, Qt::Orientation orientation, int role) const
{
if (role != Qt::DisplayRole || orientation != Qt::Horizontal)
return QVariant();
if (section == 0)
return tr("MIME Type");
else
return tr("Handler");
}
QVariant MimeTypeSettingsModel::data(const QModelIndex &modelIndex, int role) const
{
if (!modelIndex.isValid())
return QVariant();
const int column = modelIndex.column();
if (role == Qt::DisplayRole) {
const QString &type = m_mimeTypes.at(modelIndex.row()).type();
if (column == 0)
return type;
else
return m_handlersByMimeType.value(type);
} else if (role == Qt::TextAlignmentRole) {
if (column == 1)
return Qt::AlignCenter;
}
return QVariant();
}
void MimeTypeSettingsModel::load()
{
m_mimeTypes = m_core->mimeDatabase()->mimeTypes();
qSort(m_mimeTypes.begin(), m_mimeTypes.end(), MimeTypeComp());
m_knownPatterns = QSet<QString>::fromList(
MimeDatabase::fromGlobPatterns(m_core->mimeDatabase()->globPatterns()));
foreach (const MimeType &mimeType, m_mimeTypes) {
QString value;
const QList<IEditorFactory *> factories =
m_core->editorManager()->editorFactories(mimeType);
if (!factories.isEmpty()) {
value = factories.front()->displayName();
} else {
const QList<IExternalEditor *> externalEditors =
m_core->editorManager()->externalEditors(mimeType);
if (!externalEditors.isEmpty())
value = externalEditors.front()->displayName();
else
value = tr("Undefined");
}
m_handlersByMimeType.insert(mimeType.type(), value);
}
}
void MimeTypeSettingsModel::validatePatterns(QStringList *candidates,
const MimeType &mimeType) const
{
QSet<QString> oldPatterns =
QSet<QString>::fromList(MimeDatabase::fromGlobPatterns(mimeType.globPatterns()));
QStringList duplicates;
QStringList::iterator it = candidates->begin();
while (it != candidates->end()) {
const QString &current = *it;
if (!oldPatterns.contains(current) && m_knownPatterns.contains(current)) {
duplicates.append(current);
it = candidates->erase(it);
} else {
++it;
}
}
if (!duplicates.isEmpty()) {
QMessageBox msgBox;
msgBox.setWindowTitle(tr("Invalid MIME Type"));
msgBox.setText(tr("Conflicting pattern(s) will be discarded."));
msgBox.setInformativeText(tr("%n pattern(s) already in use.", 0, duplicates.size()));
msgBox.setDetailedText(duplicates.join(QLatin1String("\n")));
msgBox.exec();
}
}
void MimeTypeSettingsModel::updateKnownPatterns(const QStringList &oldPatterns,
const QStringList &newPatterns)
{
QStringList all = oldPatterns;
all.append(newPatterns);
all.removeDuplicates();
foreach (const QString &pattern, all) {
QSet<QString>::iterator it = m_knownPatterns.find(pattern);
if (it == m_knownPatterns.end()) {
// A pattern was added.
m_knownPatterns.insert(pattern);
} else {
// A pattern was removed.
m_knownPatterns.erase(it);
}
}
}
// MimeTypeSettingsPagePrivate
class MimeTypeSettingsPrivate : public QObject
{
Q_OBJECT
public:
MimeTypeSettingsPrivate();
virtual ~MimeTypeSettingsPrivate();
void configureUi(QWidget *w);
static void configureTable(QTableView *tableView);
bool checkSelectedMimeType() const;
bool checkSelectedMagicHeader() const;
void markMimeForPatternSync(int index);
void markMimeForMagicSync(int index);
void syncMimePattern();
void syncMimeMagic();
void clearSyncData();
void markAsModified(int index);
void addMagicHeaderRow(const MagicData &data);
MagicData getMagicHeaderRowData(const int row) const;
void editMagicHeaderRowData(const int row, const MagicData &data);
void updateMimeDatabase();
public slots:
void syncData(const QModelIndex &current, const QModelIndex &previous);
void handlePatternEdited();
void addMagicHeader();
void removeMagicHeader();
void editMagicHeader();
void resetMimeTypes();
public:
static const QChar kSemiColon;
QString m_keywords;
MimeDatabase *m_mimeDatabase;
QScopedPointer<MimeTypeSettingsModel> m_model;
int m_mimeForPatternSync;
int m_mimeForMagicSync;
bool m_reset;
QList<int> m_modifiedMimeTypes;
Ui::MimeTypeSettingsPage m_ui;
};
const QChar MimeTypeSettingsPrivate::kSemiColon(QLatin1Char(';'));
MimeTypeSettingsPrivate::MimeTypeSettingsPrivate()
: m_mimeDatabase(ICore::instance()->mimeDatabase())
, m_model(new MimeTypeSettingsModel)
, m_mimeForPatternSync(-1)
, m_mimeForMagicSync(-1)
, m_reset(false)
{}
MimeTypeSettingsPrivate::~MimeTypeSettingsPrivate()
{}
void MimeTypeSettingsPrivate::configureUi(QWidget *w)
{
m_ui.setupUi(w);
m_model->load();
m_ui.mimeTypesTableView->setModel(m_model.data());
configureTable(m_ui.mimeTypesTableView);
configureTable(m_ui.magicHeadersTableWidget);
connect(m_ui.mimeTypesTableView->selectionModel(),
SIGNAL(currentChanged(QModelIndex,QModelIndex)),
this,
SLOT(syncData(QModelIndex,QModelIndex)));
connect(m_ui.patternsLineEdit, SIGNAL(textEdited(QString)),
this, SLOT(handlePatternEdited()));
connect(m_ui.addMagicButton, SIGNAL(clicked()), this, SLOT(addMagicHeader()));
connect(m_ui.removeMagicButton, SIGNAL(clicked()), this, SLOT(removeMagicHeader()));
connect(m_ui.editMagicButton, SIGNAL(clicked()), this, SLOT(editMagicHeader()));
connect(m_ui.resetButton, SIGNAL(clicked()), this, SLOT(resetMimeTypes()));
}
void MimeTypeSettingsPrivate::configureTable(QTableView *tableView)
{
tableView->setSelectionBehavior(QAbstractItemView::SelectRows);
tableView->setSelectionMode(QAbstractItemView::SingleSelection);
tableView->verticalHeader()->setVisible(false);
tableView->verticalHeader()->setDefaultSectionSize(20);
tableView->horizontalHeader()->setResizeMode(QHeaderView::Stretch);
tableView->horizontalHeader()->setResizeMode(0, QHeaderView::Interactive);
tableView->horizontalHeader()->resizeSection(
0, 4 * tableView->horizontalHeader()->defaultSectionSize());
tableView->horizontalHeader()->setHighlightSections(false);
tableView->setEditTriggers(QAbstractItemView::NoEditTriggers);
}
bool MimeTypeSettingsPrivate::checkSelectedMimeType() const
{
const QModelIndex &modelIndex = m_ui.mimeTypesTableView->selectionModel()->currentIndex();
if (!modelIndex.isValid()) {
QMessageBox::critical(0, tr("Error"), tr("No MIME type selected."));
return false;
}
return true;
}
bool MimeTypeSettingsPrivate::checkSelectedMagicHeader() const
{
const QModelIndex &modelIndex = m_ui.magicHeadersTableWidget->selectionModel()->currentIndex();
if (!modelIndex.isValid()) {
QMessageBox::critical(0, tr("Error"), tr("No magic header selected."));
return false;
}
return true;
}
void MimeTypeSettingsPrivate::markMimeForPatternSync(int index)
{
if (m_mimeForPatternSync != index) {
m_mimeForPatternSync = index;
markAsModified(index);
}
}
void MimeTypeSettingsPrivate::markMimeForMagicSync(int index)
{
if (m_mimeForMagicSync != index) {
m_mimeForMagicSync = index;
markAsModified(index);
}
}
void MimeTypeSettingsPrivate::markAsModified(int index)
{
// Duplicates are handled later.
m_modifiedMimeTypes.append(index);
}
void MimeTypeSettingsPrivate::syncMimePattern()
{
MimeType &mimeType = m_model->m_mimeTypes[m_mimeForPatternSync];
QStringList patterns = m_ui.patternsLineEdit->text().split(kSemiColon);
patterns.removeDuplicates();
m_model->validatePatterns(&patterns, mimeType);
m_model->updateKnownPatterns(MimeDatabase::fromGlobPatterns(mimeType.globPatterns()), patterns);
mimeType.setGlobPatterns(MimeDatabase::toGlobPatterns(patterns));
}
void MimeTypeSettingsPrivate::syncMimeMagic()
{
typedef MagicRuleMatcher::MagicRuleList MagicRuleList;
typedef MagicRuleMatcher::MagicRuleSharedPointer MagicRuleSharedPointer;
// Gather the magic rules.
QHash<int, MagicRuleList> rulesByPriority;
for (int row = 0; row < m_ui.magicHeadersTableWidget->rowCount(); ++row) {
const MagicData &data = getMagicHeaderRowData(row);
// @TODO: Validate magic rule?
MagicRule *magicRule;
if (data.m_type == MagicStringRule::kMatchType)
magicRule = new MagicStringRule(data.m_value, data.m_start, data.m_end);
else
magicRule = new MagicByteRule(data.m_value, data.m_start, data.m_end);
rulesByPriority[data.m_priority].append(MagicRuleSharedPointer(magicRule));
}
const QList<QSharedPointer<IMagicMatcher> > &matchers =
MagicRuleMatcher::createMatchers(rulesByPriority);
m_model->m_mimeTypes[m_mimeForMagicSync].setMagicRuleMatchers(matchers);
}
void MimeTypeSettingsPrivate::clearSyncData()
{
m_mimeForPatternSync = -1;
m_mimeForMagicSync = -1;
}
void MimeTypeSettingsPrivate::syncData(const QModelIndex &current,
const QModelIndex &previous)
{
if (previous.isValid()) {
if (m_mimeForPatternSync == previous.row())
syncMimePattern();
if (m_mimeForMagicSync == previous.row())
syncMimeMagic();
clearSyncData();
m_ui.patternsLineEdit->clear();
m_ui.magicHeadersTableWidget->clearContents();
m_ui.magicHeadersTableWidget->setRowCount(0);
}
if (current.isValid()) {
const MimeType &currentMimeType = m_model->m_mimeTypes.at(current.row());
QStringList formatedPatterns;
foreach (const MimeGlobPattern &pattern, currentMimeType.globPatterns())
formatedPatterns.append(pattern.regExp().pattern());
m_ui.patternsLineEdit->setText(formatedPatterns.join(kSemiColon));
// Consider only rule-based matchers.
const QList<QSharedPointer<IMagicMatcher> > &matchers = currentMimeType.magicRuleMatchers();
foreach (const QSharedPointer<IMagicMatcher> &matcher, matchers) {
MagicRuleMatcher *ruleMatcher = static_cast<MagicRuleMatcher *>(matcher.data());
const int priority = ruleMatcher->priority();
const MagicRuleMatcher::MagicRuleList &rules = ruleMatcher->magicRules();
foreach (const MagicRuleMatcher::MagicRuleSharedPointer &rule, rules)
addMagicHeaderRow(MagicData(rule->matchValue(),
rule->matchType(),
rule->startPos(),
rule->endPos(),
priority));
}
}
}
void MimeTypeSettingsPrivate::handlePatternEdited()
{
if (m_mimeForPatternSync == -1) {
const QModelIndex &modelIndex = m_ui.mimeTypesTableView->selectionModel()->currentIndex();
if (modelIndex.isValid())
markMimeForPatternSync(modelIndex.row());
}
}
void MimeTypeSettingsPrivate::addMagicHeaderRow(const MagicData &data)
{
const int row = m_ui.magicHeadersTableWidget->rowCount();
m_ui.magicHeadersTableWidget->insertRow(row);
editMagicHeaderRowData(row, data);
}
MagicData MimeTypeSettingsPrivate::getMagicHeaderRowData(const int row) const
{
MagicData data;
data.m_value = m_ui.magicHeadersTableWidget->item(row, 0)->text();
data.m_type = m_ui.magicHeadersTableWidget->item(row, 1)->text();
QPair<int, int> startEnd =
MagicRule::fromOffset(m_ui.magicHeadersTableWidget->item(row, 2)->text());
data.m_start = startEnd.first;
data.m_end = startEnd.second;
data.m_priority = m_ui.magicHeadersTableWidget->item(row, 3)->text().toInt();
return data;
}
void MimeTypeSettingsPrivate::editMagicHeaderRowData(const int row, const MagicData &data)
{
for (int col = 0; col < m_ui.magicHeadersTableWidget->columnCount(); ++col) {
QTableWidgetItem *item = new QTableWidgetItem;
if (col == 0) {
item->setText(data.m_value);
} else {
item->setTextAlignment(Qt::AlignCenter);
if (col == 1)
item->setText(data.m_type);
else if (col == 2)
item->setText(MagicRule::toOffset(qMakePair(data.m_start, data.m_end)));
else
item->setText(QString::number(data.m_priority));
}
m_ui.magicHeadersTableWidget->setItem(row, col, item);
}
}
void MimeTypeSettingsPrivate::addMagicHeader()
{
if (!checkSelectedMimeType())
return;
MimeTypeMagicDialog dlg;
if (dlg.exec()) {
addMagicHeaderRow(dlg.magicData());
markMimeForMagicSync(m_ui.mimeTypesTableView->selectionModel()->currentIndex().row());
}
}
void MimeTypeSettingsPrivate::removeMagicHeader()
{
if (!checkSelectedMagicHeader())
return;
m_ui.magicHeadersTableWidget->removeRow(m_ui.magicHeadersTableWidget->currentRow());
markMimeForMagicSync(m_ui.mimeTypesTableView->selectionModel()->currentIndex().row());
}
void MimeTypeSettingsPrivate::editMagicHeader()
{
if (!checkSelectedMagicHeader())
return;
MimeTypeMagicDialog dlg;
dlg.setMagicData(getMagicHeaderRowData(m_ui.magicHeadersTableWidget->currentRow()));
if (dlg.exec()) {
editMagicHeaderRowData(m_ui.magicHeadersTableWidget->currentRow(), dlg.magicData());
markMimeForMagicSync(m_ui.mimeTypesTableView->selectionModel()->currentIndex().row());
}
}
void MimeTypeSettingsPrivate::updateMimeDatabase()
{
MimeDatabase *db = ICore::instance()->mimeDatabase();
// For this case it is a better approach to simply use a list and to remove duplicates
// afterwards than to keep a more complex data structure like a hash table.
qSort(m_modifiedMimeTypes.begin(), m_modifiedMimeTypes.end());
m_modifiedMimeTypes.erase(std::unique(m_modifiedMimeTypes.begin(), m_modifiedMimeTypes.end()),
m_modifiedMimeTypes.end());
if (!m_modifiedMimeTypes.isEmpty()) {
QList<MimeType> allModified;
foreach (int index, m_modifiedMimeTypes) {
const MimeType &mimeType = m_model->m_mimeTypes.at(index);
db->setGlobPatterns(mimeType.type(), mimeType.globPatterns());
db->setMagicMatchers(mimeType.type(), mimeType.magicMatchers());
allModified.append(mimeType);
}
db->writeUserModifiedMimeTypes(allModified);
}
}
void MimeTypeSettingsPrivate::resetMimeTypes()
{
QMessageBox::information(0,
tr("MIME Types"),
tr("Changes will take effect in the next time you start Qt Creator."));
m_reset = true;
}
// MimeTypeSettingsPage
MimeTypeSettings::MimeTypeSettings(QObject *parent)
: IOptionsPage(parent)
, m_d(new MimeTypeSettingsPrivate)
{}
MimeTypeSettings::~MimeTypeSettings()
{}
QString MimeTypeSettings::id() const
{
return QLatin1String(Core::Constants::SETTINGS_ID_MIMETYPES);
}
QString MimeTypeSettings::displayName() const
{
return tr("MIME Types");
}
QString MimeTypeSettings::category() const
{
return QLatin1String(Core::Constants::SETTINGS_CATEGORY_CORE);
}
QString MimeTypeSettings::displayCategory() const
{
return QCoreApplication::translate("Core", Core::Constants::SETTINGS_TR_CATEGORY_CORE);
}
QIcon MimeTypeSettings::categoryIcon() const
{
return QIcon(QLatin1String(Core::Constants::SETTINGS_CATEGORY_CORE_ICON));
}
bool MimeTypeSettings::matches(const QString &s) const
{
return m_d->m_keywords.contains(s, Qt::CaseInsensitive);
}
QWidget *MimeTypeSettings::createPage(QWidget *parent)
{
QWidget *w = new QWidget(parent);
m_d->configureUi(w);
return w;
}
void MimeTypeSettings::apply()
{
if (m_d->m_reset) {
ICore::instance()->mimeDatabase()->clearUserModifiedMimeTypes();
} else if (!m_d->m_modifiedMimeTypes.isEmpty()) {
const QModelIndex &modelIndex =
m_d->m_ui.mimeTypesTableView->selectionModel()->currentIndex();
if (modelIndex.isValid()) {
if (m_d->m_mimeForPatternSync == modelIndex.row())
m_d->syncMimePattern();
if (m_d->m_mimeForMagicSync == modelIndex.row())
m_d->syncMimeMagic();
}
m_d->updateMimeDatabase();
}
}
void MimeTypeSettings::finish()
{}
} // Internal
} // Core
#include "mimetypesettings.moc"

View File

@@ -0,0 +1,72 @@
/**************************************************************************
**
** 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.
**
**************************************************************************/
#ifndef MIMETYPESETTINGSPAGE_H
#define MIMETYPESETTINGSPAGE_H
#include "ioptionspage.h"
#include <QtCore/QScopedPointer>
namespace Core {
namespace Internal {
class MimeTypeSettingsPrivate;
class MimeTypeSettings : public IOptionsPage
{
Q_OBJECT
public:
MimeTypeSettings(QObject *parent = 0);
virtual ~MimeTypeSettings();
virtual QString id() const;
virtual QString displayName() const;
virtual QString category() const;
virtual QString displayCategory() const;
virtual QIcon categoryIcon() const;
virtual bool matches(const QString &s) const;
virtual QWidget *createPage(QWidget *parent);
virtual void apply();
virtual void finish();
private:
QScopedPointer<MimeTypeSettingsPrivate> m_d;
};
} // Internal
} // Core
#endif // MIMETYPESETTINGSPAGE_H

View File

@@ -0,0 +1,169 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MimeTypeSettingsPage</class>
<widget class="QWidget" name="MimeTypeSettingsPage">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>666</width>
<height>407</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<layout class="QVBoxLayout" name="verticalLayout_3">
<item>
<widget class="QTableView" name="mimeTypesTableView"/>
</item>
<item>
<widget class="QGroupBox" name="detailsGroupBox">
<property name="title">
<string>Details</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_4">
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QLabel" name="patternsLabel">
<property name="text">
<string>Patterns:</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="patternsLineEdit"/>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QTableWidget" name="magicHeadersTableWidget">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Maximum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>100</height>
</size>
</property>
<column>
<property name="text">
<string>Magic Header</string>
</property>
</column>
<column>
<property name="text">
<string>Type</string>
</property>
</column>
<column>
<property name="text">
<string>Range</string>
</property>
</column>
<column>
<property name="text">
<string>Priority</string>
</property>
</column>
</widget>
</item>
<item>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QPushButton" name="addMagicButton">
<property name="text">
<string>Add</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="editMagicButton">
<property name="text">
<string>Edit</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="removeMagicButton">
<property name="text">
<string>Remove</string>
</property>
</widget>
</item>
<item>
<spacer name="verticalSpacer_2">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>72</width>
<height>18</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
</layout>
</item>
</layout>
</widget>
</item>
</layout>
</item>
<item row="0" column="1">
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<widget class="QPushButton" name="resetButton">
<property name="toolTip">
<string>Reset all to default</string>
</property>
<property name="text">
<string>Reset All</string>
</property>
</widget>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>18</width>
<height>17</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item row="1" column="0">
<spacer name="verticalSpacer_3">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>504</width>
<height>16</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>

View File

@@ -1043,7 +1043,7 @@ void CodaGdbAdapter::startAdapter()
m_codaSocketIODevice = codaSocket; m_codaSocketIODevice = codaSocket;
} else { } else {
m_codaDevice = SymbianUtils::SymbianDeviceManager::instance() m_codaDevice = SymbianUtils::SymbianDeviceManager::instance()
->getTcfPort(parameters.remoteChannel); ->getCodaDevice(parameters.remoteChannel);
bool ok = m_codaDevice && m_codaDevice->device()->isOpen(); bool ok = m_codaDevice && m_codaDevice->device()->isOpen();
if (!ok) { if (!ok) {
@@ -1233,7 +1233,7 @@ void CodaGdbAdapter::cleanup()
// Ensure process is stopped after being suspended. // Ensure process is stopped after being suspended.
sendRunControlTerminateCommand(); sendRunControlTerminateCommand();
disconnect(m_codaDevice.data(), 0, this, 0); disconnect(m_codaDevice.data(), 0, this, 0);
SymbianUtils::SymbianDeviceManager::instance()->releaseTcfPort(m_codaDevice); SymbianUtils::SymbianDeviceManager::instance()->releaseCodaDevice(m_codaDevice);
} }
} }

View File

@@ -55,9 +55,9 @@ namespace Internal {
void RegisterPostMortemAction::registerNow(const QVariant &value) void RegisterPostMortemAction::registerNow(const QVariant &value)
{ {
const bool boolValue = value.toBool(); const bool boolValue = value.toBool();
const QString debuggerExe = QCoreApplication::applicationDirPath() + QLatin1Char('/') const QString debuggerExe = QDir::toNativeSeparators(QCoreApplication::applicationDirPath() + QLatin1Char('/')
+ debuggerApplicationFileC + QLatin1String(".exe"); + debuggerApplicationFileC + QLatin1String(".exe"));
const std::wstring debuggerWString = QDir::toNativeSeparators(debuggerExe).toStdWString(); const ushort *debuggerWString = debuggerExe.utf16();
CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE); CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE);
SHELLEXECUTEINFO shExecInfo; SHELLEXECUTEINFO shExecInfo;
@@ -65,7 +65,7 @@ void RegisterPostMortemAction::registerNow(const QVariant &value)
shExecInfo.fMask = SEE_MASK_NOCLOSEPROCESS; shExecInfo.fMask = SEE_MASK_NOCLOSEPROCESS;
shExecInfo.hwnd = NULL; shExecInfo.hwnd = NULL;
shExecInfo.lpVerb = L"runas"; shExecInfo.lpVerb = L"runas";
shExecInfo.lpFile = debuggerWString.data(); shExecInfo.lpFile = reinterpret_cast<LPCWSTR>(debuggerWString);
shExecInfo.lpParameters = boolValue ? L"-register" : L"-unregister"; shExecInfo.lpParameters = boolValue ? L"-register" : L"-unregister";
shExecInfo.lpDirectory = NULL; shExecInfo.lpDirectory = NULL;
shExecInfo.nShow = SW_SHOWNORMAL; shExecInfo.nShow = SW_SHOWNORMAL;

View File

@@ -3755,7 +3755,7 @@ void FakeVimHandler::Private::highlightMatches(const QString &needle0)
QString needle = needle0; QString needle = needle0;
vimPatternToQtPattern(&needle, &flags); vimPatternToQtPattern(&needle, &flags);
QRegExp needleExp(needle); QRegExp needleExp(needle);
while (1) { while (!tc.atEnd()) {
tc = tc.document()->find(needleExp, tc.position(), flags); tc = tc.document()->find(needleExp, tc.position(), flags);
if (tc.isNull()) if (tc.isNull())
break; break;

View File

@@ -117,7 +117,7 @@ bool CodaRunControl::setupLauncher()
if (m_serialPort.length()) { if (m_serialPort.length()) {
// We get the port from SymbianDeviceManager // We get the port from SymbianDeviceManager
appendMessage(tr("Connecting to '%1'...").arg(m_serialPort), NormalMessageFormat); appendMessage(tr("Connecting to '%1'...").arg(m_serialPort), NormalMessageFormat);
m_codaDevice = SymbianUtils::SymbianDeviceManager::instance()->getTcfPort(m_serialPort); m_codaDevice = SymbianUtils::SymbianDeviceManager::instance()->getCodaDevice(m_serialPort);
bool ok = m_codaDevice && m_codaDevice->device()->isOpen(); bool ok = m_codaDevice && m_codaDevice->device()->isOpen();
if (!ok) { if (!ok) {
@@ -333,7 +333,7 @@ void CodaRunControl::finishRunControl()
m_runningProcessId.clear(); m_runningProcessId.clear();
if (m_codaDevice) { if (m_codaDevice) {
disconnect(m_codaDevice.data(), 0, this, 0); disconnect(m_codaDevice.data(), 0, this, 0);
SymbianUtils::SymbianDeviceManager::instance()->releaseTcfPort(m_codaDevice); SymbianUtils::SymbianDeviceManager::instance()->releaseCodaDevice(m_codaDevice);
} }
m_state = StateUninit; m_state = StateUninit;
emit finished(); emit finished();
@@ -344,7 +344,7 @@ QMessageBox *CodaRunControl::createCodaWaitingMessageBox(QWidget *parent)
const QString title = tr("Waiting for CODA"); const QString title = tr("Waiting for CODA");
const QString text = tr("Qt Creator is waiting for the CODA application to connect.<br>" const QString text = tr("Qt Creator is waiting for the CODA application to connect.<br>"
"Please make sure the application is running on " "Please make sure the application is running on "
"your mobile phone and the right IP address and port are " "your mobile phone and the right IP address and/or port are "
"configured in the project settings."); "configured in the project settings.");
QMessageBox *mb = new QMessageBox(QMessageBox::Information, title, text, QMessageBox::Cancel, parent); QMessageBox *mb = new QMessageBox(QMessageBox::Information, title, text, QMessageBox::Cancel, parent);
return mb; return mb;

View File

@@ -357,7 +357,10 @@ char S60DeployConfiguration::installationDrive() const
void S60DeployConfiguration::setInstallationDrive(char drive) void S60DeployConfiguration::setInstallationDrive(char drive)
{ {
if (m_installationDrive == drive)
return;
m_installationDrive = drive; m_installationDrive = drive;
emit installationDriveChanged();
} }
bool S60DeployConfiguration::silentInstall() const bool S60DeployConfiguration::silentInstall() const
@@ -412,6 +415,17 @@ void S60DeployConfiguration::setCommunicationChannel(CommunicationChannel channe
} }
} }
void S60DeployConfiguration::setAvailableDeviceDrives(QList<DeviceDrive> drives)
{
m_availableDeviceDrives = drives;
emit availableDeviceDrivesChanged();
}
const QList<S60DeployConfiguration::DeviceDrive> &S60DeployConfiguration::availableDeviceDrives() const
{
return m_availableDeviceDrives;
}
// ======== S60DeployConfigurationFactory // ======== S60DeployConfigurationFactory
S60DeployConfigurationFactory::S60DeployConfigurationFactory(QObject *parent) : S60DeployConfigurationFactory::S60DeployConfigurationFactory(QObject *parent) :

View File

@@ -63,6 +63,8 @@ public:
CommunicationCodaTcpConnection CommunicationCodaTcpConnection
}; };
typedef QPair<char, int> DeviceDrive;
explicit S60DeployConfiguration(ProjectExplorer::Target *parent); explicit S60DeployConfiguration(ProjectExplorer::Target *parent);
virtual ~S60DeployConfiguration(); virtual ~S60DeployConfiguration();
@@ -92,6 +94,9 @@ public:
void setCommunicationChannel(CommunicationChannel channel); void setCommunicationChannel(CommunicationChannel channel);
S60DeployConfiguration::CommunicationChannel communicationChannel() const; S60DeployConfiguration::CommunicationChannel communicationChannel() const;
void setAvailableDeviceDrives(QList<DeviceDrive> drives);
const QList<DeviceDrive> &availableDeviceDrives() const;
QStringList signedPackages() const; QStringList signedPackages() const;
QStringList packageFileNamesWithTargetInfo() const; QStringList packageFileNamesWithTargetInfo() const;
QStringList packageTemplateFileNames() const; QStringList packageTemplateFileNames() const;
@@ -107,6 +112,8 @@ signals:
void communicationChannelChanged(); void communicationChannelChanged();
void deviceAddressChanged(); void deviceAddressChanged();
void devicePortChanged(); void devicePortChanged();
void availableDeviceDrivesChanged();
void installationDriveChanged();
private slots: private slots:
void updateActiveBuildConfiguration(ProjectExplorer::BuildConfiguration *buildConfiguration); void updateActiveBuildConfiguration(ProjectExplorer::BuildConfiguration *buildConfiguration);
@@ -134,6 +141,8 @@ private:
QString m_deviceAddress; QString m_deviceAddress;
QString m_devicePort; QString m_devicePort;
CommunicationChannel m_communicationChannel; CommunicationChannel m_communicationChannel;
QList<DeviceDrive> m_availableDeviceDrives;
}; };
class S60DeployConfigurationFactory : public ProjectExplorer::DeployConfigurationFactory class S60DeployConfigurationFactory : public ProjectExplorer::DeployConfigurationFactory

View File

@@ -41,6 +41,7 @@
#include <symbianutils/launcher.h> #include <symbianutils/launcher.h>
#include <symbianutils/bluetoothlistener.h> #include <symbianutils/bluetoothlistener.h>
#include <symbianutils/symbiandevicemanager.h> #include <symbianutils/symbiandevicemanager.h>
#include <codadevice.h>
#include "trkruncontrol.h" #include "trkruncontrol.h"
@@ -74,6 +75,51 @@ namespace Internal {
const char STARTING_DRIVE_LETTER = 'C'; const char STARTING_DRIVE_LETTER = 'C';
const char LAST_DRIVE_LETTER = 'Z'; const char LAST_DRIVE_LETTER = 'Z';
static const quint32 CODA_UID = 0x20021f96;
QString formatDriveText(const S60DeployConfiguration::DeviceDrive &drive)
{
char driveLetter = QChar::toUpper(static_cast<ushort>(drive.first));
if (drive.second <= 0)
return QString("%1:").arg(driveLetter);
if (drive.second >= 1024)
return QString("%1:%2 MB").arg(driveLetter).arg(drive.second);
return QString("%1:%2 kB").arg(driveLetter).arg(drive.second);
}
void startTable(QString &text)
{
const char startTableC[] = "<html></head><body><table>";
if (text.contains(startTableC))
return;
text.append(startTableC);
}
void finishTable(QString &text)
{
const char stopTableC[] = "</table></body></html>";
text.replace(stopTableC, QLatin1String(""));
text.append(stopTableC);
}
void addToTable(QTextStream &stream, const QString &key, const QString &value)
{
const char tableRowStartC[] = "<tr><td><b>";
const char tableRowSeparatorC[] = "</b></td><td>";
const char tableRowEndC[] = "</td></tr>";
stream << tableRowStartC << key << tableRowSeparatorC << value << tableRowEndC;
}
void addErrorToTable(QTextStream &stream, const QString &key, const QString &value)
{
const char tableRowStartC[] = "<tr><td><b>";
const char tableRowSeparatorC[] = "</b></td><td>";
const char tableRowEndC[] = "</td></tr>";
const char errorSpanStartC[] = "<span style=\"font-weight:600; color:red; \">";
const char errorSpanEndC[] = "</span>";
stream << tableRowStartC << errorSpanStartC << key << tableRowSeparatorC << value << errorSpanEndC << tableRowEndC;
}
S60DeployConfigurationWidget::S60DeployConfigurationWidget(QWidget *parent) S60DeployConfigurationWidget::S60DeployConfigurationWidget(QWidget *parent)
: ProjectExplorer::DeployConfigurationWidget(parent), : ProjectExplorer::DeployConfigurationWidget(parent),
m_detailsWidget(new Utils::DetailsWidget), m_detailsWidget(new Utils::DetailsWidget),
@@ -178,6 +224,7 @@ void S60DeployConfigurationWidget::init(ProjectExplorer::DeployConfiguration *dc
QHBoxLayout *infoHBoxLayout = new QHBoxLayout; QHBoxLayout *infoHBoxLayout = new QHBoxLayout;
m_deviceInfoLabel->setWordWrap(true); m_deviceInfoLabel->setWordWrap(true);
m_deviceInfoLabel->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Preferred); m_deviceInfoLabel->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Preferred);
m_deviceInfoLabel->setTextInteractionFlags(Qt::TextBrowserInteraction);
infoHBoxLayout->addWidget(m_deviceInfoLabel); infoHBoxLayout->addWidget(m_deviceInfoLabel);
infoHBoxLayout->addWidget(m_deviceInfoButton); infoHBoxLayout->addWidget(m_deviceInfoButton);
m_deviceInfoButton->setIcon(qApp->style()->standardIcon(QStyle::SP_MessageBoxInformation)); m_deviceInfoButton->setIcon(qApp->style()->standardIcon(QStyle::SP_MessageBoxInformation));
@@ -187,6 +234,8 @@ void S60DeployConfigurationWidget::init(ProjectExplorer::DeployConfiguration *dc
updateTargetInformation(); updateTargetInformation();
connect(m_deployConfiguration, SIGNAL(targetInformationChanged()), connect(m_deployConfiguration, SIGNAL(targetInformationChanged()),
this, SLOT(updateTargetInformation())); this, SLOT(updateTargetInformation()));
connect(m_deployConfiguration, SIGNAL(availableDeviceDrivesChanged()),
this, SLOT(updateInstallationDrives()));
} }
QWidget *S60DeployConfigurationWidget::createCommunicationChannel() QWidget *S60DeployConfigurationWidget::createCommunicationChannel()
@@ -240,14 +289,28 @@ QWidget *S60DeployConfigurationWidget::createCommunicationChannel()
void S60DeployConfigurationWidget::updateInstallationDrives() void S60DeployConfigurationWidget::updateInstallationDrives()
{ {
m_installationDriveCombo->clear(); m_installationDriveCombo->clear();
for (int i = STARTING_DRIVE_LETTER; i <= LAST_DRIVE_LETTER; ++i) { const QList<S60DeployConfiguration::DeviceDrive> &availableDrives(m_deployConfiguration->availableDeviceDrives());
m_installationDriveCombo->addItem(QString("%1:").arg(static_cast<char>(i)), qVariantFromValue(i)); int index = 0;
char currentDrive = QChar::toUpper(static_cast<ushort>(m_deployConfiguration->installationDrive()));
if (availableDrives.isEmpty()) {
for (int i = STARTING_DRIVE_LETTER; i <= LAST_DRIVE_LETTER; ++i) {
m_installationDriveCombo->addItem(QString("%1:").arg(static_cast<char>(i)), QChar(i));
}
index = currentDrive - STARTING_DRIVE_LETTER;
} else {
for (int i = 0; i < availableDrives.count(); ++i) {
const S60DeployConfiguration::DeviceDrive& drive(availableDrives.at(i));
char driveLetter = QChar::toUpper(static_cast<ushort>(drive.first));
m_installationDriveCombo->addItem(formatDriveText(drive),
QChar(driveLetter));
if (currentDrive == driveLetter)
index = i;
}
} }
int index = QChar::toUpper(static_cast<ushort>(m_deployConfiguration->installationDrive())) - STARTING_DRIVE_LETTER; QTC_ASSERT(index >= 0 && index <= m_installationDriveCombo->count(), return);
Q_ASSERT(index >= 0 && index <= LAST_DRIVE_LETTER-STARTING_DRIVE_LETTER);
m_installationDriveCombo->setCurrentIndex(index); m_installationDriveCombo->setCurrentIndex(index);
setInstallationDrive(index);
} }
void S60DeployConfigurationWidget::silentInstallChanged(int state) void S60DeployConfigurationWidget::silentInstallChanged(int state)
@@ -280,7 +343,8 @@ void S60DeployConfigurationWidget::updateSerialDevices()
const QString newPortName = device(newIndex).portName(); const QString newPortName = device(newIndex).portName();
m_deployConfiguration->setSerialPortName(newPortName); m_deployConfiguration->setSerialPortName(newPortName);
} }
if (m_deployConfiguration->communicationChannel() != S60DeployConfiguration::CommunicationTrkSerialConnection) if (m_deployConfiguration->communicationChannel() != S60DeployConfiguration::CommunicationTrkSerialConnection
&& m_deployConfiguration->communicationChannel() != S60DeployConfiguration::CommunicationCodaSerialConnection)
m_deviceInfoButton->setEnabled(false); m_deviceInfoButton->setEnabled(false);
} }
@@ -309,7 +373,11 @@ void S60DeployConfigurationWidget::updateTargetInformation()
void S60DeployConfigurationWidget::setInstallationDrive(int index) void S60DeployConfigurationWidget::setInstallationDrive(int index)
{ {
m_deployConfiguration->setInstallationDrive(static_cast<char>(STARTING_DRIVE_LETTER + index)); QTC_ASSERT(index >= 0, return);
QTC_ASSERT(index < m_installationDriveCombo->count(), return);
QChar driveLetter(m_installationDriveCombo->itemData(index).toChar());
m_deployConfiguration->setInstallationDrive(driveLetter.toAscii());
} }
void S60DeployConfigurationWidget::setSerialPort(int index) void S60DeployConfigurationWidget::setSerialPort(int index)
@@ -425,10 +493,10 @@ void S60DeployConfigurationWidget::slotWaitingForTrkClosed()
void S60DeployConfigurationWidget::updateDeviceInfo() void S60DeployConfigurationWidget::updateDeviceInfo()
{ {
//TODO: No CODA device info! Implement it when it is available
if (m_deployConfiguration->communicationChannel() == S60DeployConfiguration::CommunicationTrkSerialConnection) { if (m_deployConfiguration->communicationChannel() == S60DeployConfiguration::CommunicationTrkSerialConnection) {
QTC_ASSERT(!m_infoLauncher, return) QTC_ASSERT(!m_infoLauncher, return)
setDeviceInfoLabel(tr("Connecting..."));
setDeviceInfoLabel(tr("Connecting..."));
// Do a launcher run with the ping protocol. Prompt to connect and // Do a launcher run with the ping protocol. Prompt to connect and
// go asynchronous afterwards to pop up launch trk box if a timeout occurs. // go asynchronous afterwards to pop up launch trk box if a timeout occurs.
QString message; QString message;
@@ -466,9 +534,185 @@ void S60DeployConfigurationWidget::updateDeviceInfo()
} }
// Wait for either timeout or results // Wait for either timeout or results
m_deviceInfoButton->setEnabled(false); m_deviceInfoButton->setEnabled(false);
} else if (m_deployConfiguration->communicationChannel() == S60DeployConfiguration::CommunicationCodaSerialConnection) {
setDeviceInfoLabel(tr("Connecting..."));
const SymbianUtils::SymbianDevice commDev = currentDevice();
m_codaInfoDevice = SymbianUtils::SymbianDeviceManager::instance()->getCodaDevice(commDev.portName());
if (!m_codaInfoDevice->device()->isOpen()) {
setDeviceInfoLabel(m_codaInfoDevice->device()->errorString(), true);
return;
}
//TODO error handling - for now just throw the command at coda
m_codaInfoDevice->sendSymbianOsDataGetQtVersionCommand(Coda::CodaCallback(this, &S60DeployConfigurationWidget::getQtVersionCommandResult));
m_deviceInfoButton->setEnabled(false);
} else } else
setDeviceInfoLabel(tr("Information about the device is not available when using CODA."), true); setDeviceInfoLabel(tr("Currently there is no information about device for this connection type."), true);
} }
void S60DeployConfigurationWidget::getQtVersionCommandResult(const Coda::CodaCommandResult &result)
{
if (result.type == Coda::CodaCommandResult::FailReply) {
setDeviceInfoLabel(tr("No device information available"), true);
m_deviceInfoButton->setEnabled(true);
return;
} else if (result.type == Coda::CodaCommandResult::CommandErrorReply){
QString message;
startTable(message);
QTextStream str(&message);
addErrorToTable(str, tr("Qt version: "), tr("Not installed on device"));
finishTable(message);
setDeviceInfoLabel(message, false);
} else {
QString resultString;
if (result.values.count()) {
QHash<QString, QVariant> obj = result.values[0].toVariant().toHash();
QString ver = obj.value("qVersion").toString();
startTable(resultString);
QTextStream str(&resultString);
addToTable(str, tr("Qt version: "), ver);
QString systemVersion;
int symVer = obj.value("symbianVersion").toInt();
// Ugh why won't QSysInfo define these on non-symbian builds...
switch (symVer) {
case 10:
systemVersion.append("Symbian OS v9.2");
break;
case 20:
systemVersion.append("Symbian OS v9.3");
break;
case 30:
systemVersion.append("Symbian OS v9.4 / Symbian^1");
break;
case 40:
systemVersion.append("Symbian^2");
break;
case 50:
systemVersion.append("Symbian^3");
break;
case 60:
systemVersion.append("Symbian^4");
break;
default:
systemVersion.append(tr("Unrecognised Symbian version 0x%1").arg(symVer, 0, 16));
break;
}
systemVersion.append(", ");
int s60Ver = obj.value("s60Version").toInt();
switch (s60Ver) {
case 10:
systemVersion.append("S60 3rd Edition Feature Pack 1");
break;
case 20:
systemVersion.append("S60 3rd Edition Feature Pack 2");
break;
case 30:
systemVersion.append("S60 5th Edition");
break;
case 40:
systemVersion.append("S60 5th Edition Feature Pack 1");
break;
case 50:
systemVersion.append("S60 5th Edition Feature Pack 2");
break;
default:
systemVersion.append(tr("Unrecognised S60 version 0x%1").arg(symVer, 0, 16));
break;
}
addToTable(str, tr("OS version: "), systemVersion);
finishTable(resultString);
}
setDeviceInfoLabel(resultString);
}
m_codaInfoDevice->sendSymbianOsDataGetRomInfoCommand(Coda::CodaCallback(this, &S60DeployConfigurationWidget::getRomInfoResult));
}
void S60DeployConfigurationWidget::getRomInfoResult(const Coda::CodaCommandResult &result)
{
if (result.type == Coda::CodaCommandResult::SuccessReply && result.values.count()) {
QString resultString = m_deviceInfoLabel->text();
startTable(resultString);
QTextStream str(&resultString);
QVariantHash obj = result.values[0].toVariant().toHash();
QString romVersion = obj.value("romVersion", tr("unknown")).toString();
romVersion.replace('\n', " "); // The ROM string is split across multiple lines, for some reason.
addToTable(str, tr("ROM version: "), romVersion);
QString pr = obj.value("prInfo").toString();
if (pr.length())
addToTable(str, tr("Release:"), pr);
finishTable(resultString);
setDeviceInfoLabel(resultString);
}
QList<quint32> packagesOfInterest;
packagesOfInterest.append(CODA_UID);
m_codaInfoDevice->sendSymbianInstallGetPackageInfoCommand(Coda::CodaCallback(this, &S60DeployConfigurationWidget::getInstalledPackagesResult), packagesOfInterest);
}
void S60DeployConfigurationWidget::getInstalledPackagesResult(const Coda::CodaCommandResult &result)
{
if (result.type == Coda::CodaCommandResult::SuccessReply && result.values.count()) {
QString resultString = m_deviceInfoLabel->text();
startTable(resultString);
QTextStream str(&resultString);
QVariantList resultsList = result.values[0].toVariant().toList();
foreach (const QVariant& var, resultsList) {
QVariantHash obj = var.toHash();
if (obj.value("uid").toString().toUInt(0, 16) == CODA_UID) {
if (!obj.value("error").isNull()) {
// How can coda not be installed? Presumably some UID wrongness...
addErrorToTable(str, tr("CODA version: "), tr("Error reading CODA version"));
} else {
QVariantList version = obj.value("version").toList();
addToTable(str, tr("CODA version: "),
QString("%1.%2.%3").arg(version[0].toInt())
.arg(version[1].toInt())
.arg(version[2].toInt()));
}
}
}
finishTable(resultString);
setDeviceInfoLabel(resultString);
}
QStringList keys;
keys << QLatin1String("EDisplayXPixels");
keys << QLatin1String("EDisplayYPixels");
//keys << "EMemoryRAMFree";
m_codaInfoDevice->sendSymbianOsDataGetHalInfoCommand(Coda::CodaCallback(this, &S60DeployConfigurationWidget::getHalResult), keys);
}
void S60DeployConfigurationWidget::getHalResult(const Coda::CodaCommandResult &result)
{
if (result.type == Coda::CodaCommandResult::SuccessReply && result.values.count()) {
QString resultString = m_deviceInfoLabel->text();
QVariantList resultsList = result.values[0].toVariant().toList();
int x = 0;
int y = 0;
foreach (const QVariant& var, resultsList) {
QVariantHash obj = var.toHash();
if (obj.value("name").toString() == "EDisplayXPixels")
x = obj.value("value").toInt();
else if (obj.value("name").toString() == "EDisplayYPixels")
y = obj.value("value").toInt();
}
if (x && y) {
startTable(resultString);
QTextStream str(&resultString);
addToTable(str, tr("Screen size: "), QString("%1x%2").arg(x).arg(y));
finishTable(resultString);
setDeviceInfoLabel(resultString);
}
}
// Done with collecting info
m_deviceInfoButton->setEnabled(true);
SymbianUtils::SymbianDeviceManager::instance()->releaseCodaDevice(m_codaInfoDevice);
}
} // namespace Internal } // namespace Internal
} // namespace Qt4ProjectManager } // namespace Qt4ProjectManager

View File

@@ -61,6 +61,11 @@ namespace SymbianUtils {
class SymbianDevice; class SymbianDevice;
} }
namespace Coda {
class CodaDevice;
struct CodaCommandResult;
}
namespace Qt4ProjectManager { namespace Qt4ProjectManager {
namespace Internal { namespace Internal {
@@ -102,6 +107,11 @@ private:
QWidget * createCommunicationChannel(); QWidget * createCommunicationChannel();
void getQtVersionCommandResult(const Coda::CodaCommandResult &result);
void getRomInfoResult(const Coda::CodaCommandResult &result);
void getInstalledPackagesResult(const Coda::CodaCommandResult &result);
void getHalResult(const Coda::CodaCommandResult &result);
S60DeployConfiguration *m_deployConfiguration; S60DeployConfiguration *m_deployConfiguration;
Utils::DetailsWidget *m_detailsWidget; Utils::DetailsWidget *m_detailsWidget;
QComboBox *m_serialPortsCombo; QComboBox *m_serialPortsCombo;
@@ -117,6 +127,7 @@ private:
Utils::IpAddressLineEdit *m_ipAddress; Utils::IpAddressLineEdit *m_ipAddress;
QRadioButton *m_trkRadioButton; QRadioButton *m_trkRadioButton;
QRadioButton *m_codaRadioButton; QRadioButton *m_codaRadioButton;
QSharedPointer<Coda::CodaDevice> m_codaInfoDevice;
}; };
} // namespace Internal } // namespace Internal

View File

@@ -317,7 +317,7 @@ void S60DeployStep::stop()
} else { } else {
if (m_codaDevice) { if (m_codaDevice) {
disconnect(m_codaDevice.data(), 0, this, 0); disconnect(m_codaDevice.data(), 0, this, 0);
SymbianUtils::SymbianDeviceManager::instance()->releaseTcfPort(m_codaDevice); SymbianUtils::SymbianDeviceManager::instance()->releaseCodaDevice(m_codaDevice);
} }
} }
emit finished(false); emit finished(false);
@@ -384,7 +384,7 @@ void S60DeployStep::startDeployment()
} }
} else if (m_channel == S60DeployConfiguration::CommunicationCodaSerialConnection) { } else if (m_channel == S60DeployConfiguration::CommunicationCodaSerialConnection) {
appendMessage(tr("Deploying application to '%1'...").arg(m_serialPortFriendlyName), false); appendMessage(tr("Deploying application to '%1'...").arg(m_serialPortFriendlyName), false);
m_codaDevice = SymbianUtils::SymbianDeviceManager::instance()->getTcfPort(m_serialPortName); m_codaDevice = SymbianUtils::SymbianDeviceManager::instance()->getCodaDevice(m_serialPortName);
bool ok = m_codaDevice && m_codaDevice->device()->isOpen(); bool ok = m_codaDevice && m_codaDevice->device()->isOpen();
if (!ok) { if (!ok) {
QString deviceError = tr("No such port"); QString deviceError = tr("No such port");
@@ -442,7 +442,7 @@ void S60DeployStep::run(QFutureInterface<bool> &fi)
if (m_codaDevice) { if (m_codaDevice) {
disconnect(m_codaDevice.data(), 0, this, 0); disconnect(m_codaDevice.data(), 0, this, 0);
SymbianUtils::SymbianDeviceManager::instance()->releaseTcfPort(m_codaDevice); SymbianUtils::SymbianDeviceManager::instance()->releaseCodaDevice(m_codaDevice);
} }
delete m_eventLoop; delete m_eventLoop;

View File

@@ -184,6 +184,11 @@ void Manager::gatherDefinitionsMimeTypes(QFutureInterface<Core::MimeType> &futur
Core::MimeDatabase *mimeDatabase = Core::ICore::instance()->mimeDatabase(); Core::MimeDatabase *mimeDatabase = Core::ICore::instance()->mimeDatabase();
QSet<QString> knownSuffixes = QSet<QString>::fromList(mimeDatabase->suffixes()); QSet<QString> knownSuffixes = QSet<QString>::fromList(mimeDatabase->suffixes());
QHash<QString, Core::MimeType> userModified;
const QList<Core::MimeType> &userMimeTypes = mimeDatabase->readUserModifiedMimeTypes();
foreach (const Core::MimeType &userMimeType, userMimeTypes)
userModified.insert(userMimeType.type(), userMimeType);
foreach (const QString &path, definitionsPaths) { foreach (const QString &path, definitionsPaths) {
if (path.isEmpty()) if (path.isEmpty())
continue; continue;
@@ -227,25 +232,35 @@ void Manager::gatherDefinitionsMimeTypes(QFutureInterface<Core::MimeType> &futur
m_idByMimeType.insert(type, id); m_idByMimeType.insert(type, id);
Core::MimeType mimeType = mimeDatabase->findByType(type); Core::MimeType mimeType = mimeDatabase->findByType(type);
if (mimeType.isNull()) { if (mimeType.isNull()) {
if (globPatterns.isEmpty()) {
foreach (const QString &pattern, metaData->patterns()) {
static const QLatin1String mark("*.");
if (pattern.startsWith(mark)) {
const QString &suffix = pattern.right(pattern.length() - 2);
if (!knownSuffixes.contains(suffix))
knownSuffixes.insert(suffix);
else
continue;
}
QRegExp regExp(pattern, Qt::CaseSensitive, QRegExp::Wildcard);
globPatterns.append(Core::MimeGlobPattern(regExp, 50));
}
}
mimeType.setType(type); mimeType.setType(type);
mimeType.setSubClassesOf(textPlain); mimeType.setSubClassesOf(textPlain);
mimeType.setComment(metaData->name()); mimeType.setComment(metaData->name());
mimeType.setGlobPatterns(globPatterns);
// If there's a user modification for this mime type, we want to use the
// modified patterns and rule-based matchers. If not, just consider what
// is specified in the definition file.
QHash<QString, Core::MimeType>::const_iterator it =
userModified.find(mimeType.type());
if (it == userModified.end()) {
if (globPatterns.isEmpty()) {
foreach (const QString &pattern, metaData->patterns()) {
static const QLatin1String mark("*.");
if (pattern.startsWith(mark)) {
const QString &suffix = pattern.right(pattern.length() - 2);
if (!knownSuffixes.contains(suffix))
knownSuffixes.insert(suffix);
else
continue;
}
QRegExp regExp(pattern, Qt::CaseSensitive, QRegExp::Wildcard);
globPatterns.append(Core::MimeGlobPattern(regExp, 50));
}
}
mimeType.setGlobPatterns(globPatterns);
} else {
mimeType.setGlobPatterns(it.value().globPatterns());
mimeType.setMagicRuleMatchers(it.value().magicRuleMatchers());
}
mimeDatabase->addMimeType(mimeType); mimeDatabase->addMimeType(mimeType);
future.reportResult(mimeType); future.reportResult(mimeType);
@@ -275,6 +290,8 @@ void Manager::registerMimeTypesFinished()
QSharedPointer<HighlightDefinitionMetaData> Manager::parseMetadata(const QFileInfo &fileInfo) QSharedPointer<HighlightDefinitionMetaData> Manager::parseMetadata(const QFileInfo &fileInfo)
{ {
static const QLatin1Char kSemiColon(';'); static const QLatin1Char kSemiColon(';');
static const QLatin1Char kSpace(' ');
static const QLatin1Char kDash('-');
static const QLatin1String kLanguage("language"); static const QLatin1String kLanguage("language");
static const QLatin1String kArtificial("text/x-artificial-"); static const QLatin1String kArtificial("text/x-artificial-");
@@ -304,7 +321,7 @@ QSharedPointer<HighlightDefinitionMetaData> Manager::parseMetadata(const QFileIn
// There are definitions which do not specify a MIME type, but specify file // There are definitions which do not specify a MIME type, but specify file
// patterns. Creating an artificial MIME type is a workaround. // patterns. Creating an artificial MIME type is a workaround.
QString artificialType(kArtificial); QString artificialType(kArtificial);
artificialType.append(metaData->name()); artificialType.append(metaData->name().trimmed().replace(kSpace, kDash));
mimeTypes.append(artificialType); mimeTypes.append(artificialType);
} }
metaData->setMimeTypes(mimeTypes); metaData->setMimeTypes(mimeTypes);

View File

@@ -936,8 +936,6 @@ void CodaDevice::sendProcessStartCommand(const CodaCallback &callBack,
const QString sysBin = QLatin1String("c:/sys/bin"); const QString sysBin = QLatin1String("c:/sys/bin");
const QString binaryFileName = slashPos == -1 ? binaryIn : binaryIn.mid(slashPos + 1); const QString binaryFileName = slashPos == -1 ? binaryIn : binaryIn.mid(slashPos + 1);
// Fixup: Does argv[0] convention exist on Symbian?
arguments.push_front(binaryFileName);
if (workingDirectory.isEmpty()) if (workingDirectory.isEmpty())
workingDirectory = sysBin; workingDirectory = sysBin;
@@ -968,6 +966,20 @@ void CodaDevice::sendProcessStartCommand(const CodaCallback &callBack,
sendCodaMessage(MessageWithReply, ProcessesService, "start", startData, callBack, cookie); sendCodaMessage(MessageWithReply, ProcessesService, "start", startData, callBack, cookie);
} }
void CodaDevice::sendRunProcessCommand(const CodaCallback &callBack,
const QString &processName,
QStringList arguments,
const QVariant &cookie)
{
QByteArray startData;
JsonInputStream startStr(startData);
startStr << "" //We don't really know the drive of the working dir
<< '\0' << processName << '\0' << arguments << '\0'
<< QStringList() << '\0' // Env is an array ["PATH=value"] (non-standard)
<< false; // Don't attach debugger
sendCodaMessage(MessageWithReply, ProcessesService, "start", startData, callBack, cookie);
}
void CodaDevice::sendSettingsEnableLogCommand() void CodaDevice::sendSettingsEnableLogCommand()
{ {
@@ -1302,8 +1314,7 @@ void CodaDevice::sendRegistersSetCommand(const CodaCallback &callBack,
value, cookie); value, cookie);
} }
//static const char outputListenerIDC[] = "org.eclipse.cdt.debug.edc.ui.ProgramOutputConsoleLogger"; static const char outputListenerIDC[] = "ProgramOutputConsoleLogger";
static const char outputListenerIDC[] = "ProgramOutputConsoleLogger"; //TODO: this one might be the correct one
void CodaDevice::sendLoggingAddListenerCommand(const CodaCallback &callBack, void CodaDevice::sendLoggingAddListenerCommand(const CodaCallback &callBack,
const QVariant &cookie) const QVariant &cookie)
@@ -1332,6 +1343,34 @@ void CodaDevice::sendSymbianOsDataFindProcessesCommand(const CodaCallback &callB
sendCodaMessage(MessageWithReply, SymbianOSData, "findRunningProcesses", data, callBack, cookie); sendCodaMessage(MessageWithReply, SymbianOSData, "findRunningProcesses", data, callBack, cookie);
} }
void CodaDevice::sendSymbianOsDataGetQtVersionCommand(const CodaCallback &callBack,
const QVariant &cookie)
{
sendCodaMessage(MessageWithReply, SymbianOSData, "getQtVersion", QByteArray(), callBack, cookie);
}
void CodaDevice::sendSymbianOsDataGetRomInfoCommand(const CodaCallback &callBack,
const QVariant &cookie)
{
sendCodaMessage(MessageWithReply, SymbianOSData, "getRomInfo", QByteArray(), callBack, cookie);
}
void CodaDevice::sendSymbianOsDataGetHalInfoCommand(const CodaCallback &callBack,
const QStringList &keys,
const QVariant &cookie)
{
QByteArray data;
JsonInputStream str(data);
str << '[';
for (int i = 0; i < keys.count(); ++i) {
if (i)
str << ',';
str << keys[i];
}
str << ']';
sendCodaMessage(MessageWithReply, SymbianOSData, "getHalInfo", data, callBack, cookie);
}
void Coda::CodaDevice::sendFileSystemOpenCommand(const Coda::CodaCallback &callBack, void Coda::CodaDevice::sendFileSystemOpenCommand(const Coda::CodaCallback &callBack,
const QByteArray &name, const QByteArray &name,
unsigned flags, unsigned flags,
@@ -1395,4 +1434,24 @@ void Coda::CodaDevice::sendSymbianInstallUIInstallCommand(const Coda::CodaCallba
str << file; str << file;
sendCodaMessage(MessageWithReply, SymbianInstallService, "installWithUI", data, callBack, cookie); sendCodaMessage(MessageWithReply, SymbianInstallService, "installWithUI", data, callBack, cookie);
} }
void Coda::CodaDevice::sendSymbianInstallGetPackageInfoCommand(const Coda::CodaCallback &callBack,
const QList<quint32> &packages,
const QVariant &cookie)
{
QByteArray data;
JsonInputStream str(data);
str << '[';
for (int i = 0; i < packages.count(); ++i) {
if (i)
str << ',';
QString pkgString;
pkgString.setNum(packages[i], 16);
str << pkgString;
}
str << ']';
sendCodaMessage(MessageWithReply, SymbianInstallService, "getPackageInfo", data, callBack, cookie);
}
} // namespace Coda } // namespace Coda

View File

@@ -131,11 +131,6 @@ http://dev.eclipse.org/svnroot/dsdp/org.eclipse.tm.tcf/trunk/docs/TCF%20Services
* Commands can be sent along with callbacks that are passed a * Commands can be sent along with callbacks that are passed a
* CodaCommandResult and an opaque QVariant cookie. In addition, events are emitted. * CodaCommandResult and an opaque QVariant cookie. In addition, events are emitted.
* *
* Note: As of 11.8.2010, TCF Trk 4.0.5 does not currently support 'Registers::getm'
* (get multiple registers). So, CodaDevice emulates it by sending a sequence of
* single commands. As soon as 'Registers::getm' is natively supported, all code
* related to 'FakeRegisterGetm' should be removed. The workaround requires that
* the register name is known.
* CODA notes: * CODA notes:
* - Commands are accepted only after receiving the Locator Hello event * - Commands are accepted only after receiving the Locator Hello event
* - Serial communication initiation sequence: * - Serial communication initiation sequence:
@@ -213,6 +208,12 @@ public:
const QStringList &additionalLibraries = QStringList(), const QStringList &additionalLibraries = QStringList(),
const QVariant &cookie = QVariant()); const QVariant &cookie = QVariant());
// Just launch a process, don't attempt to attach the debugger to it
void sendRunProcessCommand(const CodaCallback &callBack,
const QString &processName,
QStringList arguments = QStringList(),
const QVariant &cookie = QVariant());
// Preferred over Processes:Terminate by TCF TRK. // Preferred over Processes:Terminate by TCF TRK.
void sendRunControlTerminateCommand(const CodaCallback &callBack, void sendRunControlTerminateCommand(const CodaCallback &callBack,
const QByteArray &id, const QByteArray &id,
@@ -345,6 +346,10 @@ public:
const QByteArray &file, const QByteArray &file,
const QVariant &cookie = QVariant()); const QVariant &cookie = QVariant());
void sendSymbianInstallGetPackageInfoCommand(const Coda::CodaCallback &callBack,
const QList<quint32> &packages,
const QVariant &cookie = QVariant());
void sendLoggingAddListenerCommand(const CodaCallback &callBack, void sendLoggingAddListenerCommand(const CodaCallback &callBack,
const QVariant &cookie = QVariant()); const QVariant &cookie = QVariant());
@@ -357,6 +362,16 @@ public:
const QByteArray &uid, const QByteArray &uid,
const QVariant &cookie = QVariant()); const QVariant &cookie = QVariant());
void sendSymbianOsDataGetQtVersionCommand(const CodaCallback &callBack,
const QVariant &cookie = QVariant());
void sendSymbianOsDataGetRomInfoCommand(const CodaCallback &callBack,
const QVariant &cookie = QVariant());
void sendSymbianOsDataGetHalInfoCommand(const CodaCallback &callBack,
const QStringList &keys = QStringList(),
const QVariant &cookie = QVariant());
// Settings // Settings
void sendSettingsEnableLogCommand(); void sendSettingsEnableLogCommand();

View File

@@ -41,6 +41,7 @@
#include <QtCore/QTextStream> #include <QtCore/QTextStream>
#include <QtCore/QDebug> #include <QtCore/QDebug>
#include <QtCore/QStringList> #include <QtCore/QStringList>
#include <QtCore/QVariant>
#include <ctype.h> #include <ctype.h>
@@ -415,6 +416,45 @@ QByteArray JsonValue::toString(bool multiline, int indent) const
return result; return result;
} }
QVariant JsonValue::toVariant() const
{
switch (m_type) {
case String:
return QString(m_data);
case Number: {
bool ok;
qint64 val = QString(m_data).toLongLong(&ok);
if (ok)
return val;
return QVariant();
}
case Object: {
QHash<QString, QVariant> hash;
for (int i = 0; i < m_children.size(); ++i) {
QString name(m_children[i].name());
QVariant val = m_children[i].toVariant();
hash.insert(name, val);
}
return hash;
}
case Array: {
QList<QVariant> list;
for (int i = 0; i < m_children.size(); ++i) {
list.append(m_children[i].toVariant());
}
return list;
}
case Boolean:
return data() == QByteArray("true");
case Invalid:
case NullObject:
default:
return QVariant();
}
}
void JsonValue::fromString(const QByteArray &ba) void JsonValue::fromString(const QByteArray &ba)
{ {
const char *from = ba.constBegin(); const char *from = ba.constBegin();

View File

@@ -87,6 +87,8 @@ public:
void fromString(const QByteArray &str); void fromString(const QByteArray &str);
void setStreamOutput(const QByteArray &name, const QByteArray &content); void setStreamOutput(const QByteArray &name, const QByteArray &content);
QVariant toVariant() const;
private: private:
static QByteArray parseCString(const char *&from, const char *to); static QByteArray parseCString(const char *&from, const char *to);
static QByteArray parseNumber(const char *&from, const char *to); static QByteArray parseNumber(const char *&from, const char *to);

View File

@@ -355,7 +355,7 @@ SymbianDeviceManager::TrkDevicePtr
return rc; return rc;
} }
CodaDevicePtr SymbianDeviceManager::getTcfPort(const QString &port) CodaDevicePtr SymbianDeviceManager::getCodaDevice(const QString &port)
{ {
ensureInitialized(); ensureInitialized();
const int idx = findByPortName(port); const int idx = findByPortName(port);
@@ -419,7 +419,7 @@ void SymbianDeviceManager::customEvent(QEvent *event)
} }
} }
void SymbianDeviceManager::releaseTcfPort(CodaDevicePtr &port) void SymbianDeviceManager::releaseCodaDevice(CodaDevicePtr &port)
{ {
if (port) { if (port) {
// Check if this was the last reference to the port, if so close it after a short delay // Check if this was the last reference to the port, if so close it after a short delay
@@ -613,4 +613,106 @@ SYMBIANUTILS_EXPORT QDebug operator<<(QDebug d, const SymbianDeviceManager &sdm)
return d; return d;
} }
} // namespace SymbianUtilsInternal OstChannel *SymbianDeviceManager::getOstChannel(const QString &port, uchar channelId)
{
CodaDevicePtr coda = getCodaDevice(port);
if (coda.isNull() || !coda->device()->isOpen())
return 0;
return new OstChannel(coda, channelId);
}
struct OstChannelPrivate
{
CodaDevicePtr m_codaPtr;
QByteArray m_dataBuffer;
uchar m_channelId;
bool m_hasReceivedData;
};
OstChannel::OstChannel(const CodaDevicePtr &codaPtr, uchar channelId)
: d(new OstChannelPrivate)
{
d->m_codaPtr = codaPtr;
d->m_channelId = channelId;
d->m_hasReceivedData = false;
connect(codaPtr.data(), SIGNAL(unknownEvent(uchar, QByteArray)), this, SLOT(ostDataReceived(uchar,QByteArray)));
connect(codaPtr->device().data(), SIGNAL(aboutToClose()), this, SLOT(deviceAboutToClose()));
QIODevice::open(ReadWrite|Unbuffered);
}
void OstChannel::close()
{
QIODevice::close();
if (d && d->m_codaPtr.data()) {
disconnect(d->m_codaPtr.data(), 0, this, 0);
SymbianDeviceManager::instance()->releaseCodaDevice(d->m_codaPtr);
}
}
OstChannel::~OstChannel()
{
close();
delete d;
}
void OstChannel::flush()
{
//TODO d->m_codaPtr->device()-
}
qint64 OstChannel::bytesAvailable() const
{
return d->m_dataBuffer.size();
}
bool OstChannel::isSequential() const
{
return true;
}
qint64 OstChannel::readData(char *data, qint64 maxSize)
{
qint64 amount = qMin(maxSize, (qint64)d->m_dataBuffer.size());
qMemCopy(data, d->m_dataBuffer.constData(), amount);
d->m_dataBuffer.remove(0, amount);
return amount;
}
qint64 OstChannel::writeData(const char *data, qint64 maxSize)
{
static const qint64 KMaxOstPayload = 1022;
// If necessary, split the packet up
while (maxSize) {
QByteArray dataBuf = QByteArray::fromRawData(data, qMin(KMaxOstPayload, maxSize));
d->m_codaPtr->writeCustomData(d->m_channelId, dataBuf);
data += dataBuf.length();
maxSize -= dataBuf.length();
}
return maxSize;
}
void OstChannel::ostDataReceived(uchar channelId, const QByteArray &aData)
{
if (channelId == d->m_channelId) {
d->m_hasReceivedData = true;
d->m_dataBuffer.append(aData);
emit readyRead();
}
}
Coda::CodaDevice& OstChannel::codaDevice() const
{
return *d->m_codaPtr;
}
bool OstChannel::hasReceivedData() const
{
return isOpen() && d->m_hasReceivedData;
}
void OstChannel::deviceAboutToClose()
{
close();
}
} // namespace SymbianUtils

View File

@@ -36,7 +36,7 @@
#include "symbianutils_global.h" #include "symbianutils_global.h"
#include <QtCore/QObject> #include <QtCore/QIODevice>
#include <QtCore/QExplicitlySharedDataPointer> #include <QtCore/QExplicitlySharedDataPointer>
#include <QtCore/QSharedPointer> #include <QtCore/QSharedPointer>
@@ -56,6 +56,7 @@ namespace SymbianUtils {
struct SymbianDeviceManagerPrivate; struct SymbianDeviceManagerPrivate;
class SymbianDeviceData; class SymbianDeviceData;
class OstChannel;
enum DeviceCommunicationType { enum DeviceCommunicationType {
SerialPortCommunication = 0, SerialPortCommunication = 0,
@@ -152,11 +153,15 @@ public:
// Gets the CodaDevice, which may or may not be open depending on what other clients have already acquired it. // Gets the CodaDevice, which may or may not be open depending on what other clients have already acquired it.
// Therefore once clients have set up any signals and slots they required, they should check CodaDevice::device()->isOpen() // Therefore once clients have set up any signals and slots they required, they should check CodaDevice::device()->isOpen()
// and if false, the open failed and they should check device()->errorString() if required. // and if false, the open failed and they should check device()->errorString() if required.
// Caller should call releaseTcfPort if they want the port to auto-close itself // Caller should call releaseCodaDevice if they want the port to auto-close itself
CodaDevicePtr getTcfPort(const QString &port); CodaDevicePtr getCodaDevice(const QString &port);
// Note this function makes no guarantee that someone else isn't already listening on this channel id, or that there is anything on the other end
// Returns NULL if the port couldn't be opened
OstChannel *getOstChannel(const QString &port, uchar channelId);
// Caller is responsible for disconnecting any signals from aPort - do not assume the CodaDevice will be deleted as a result of this call. On return aPort will be clear()ed. // Caller is responsible for disconnecting any signals from aPort - do not assume the CodaDevice will be deleted as a result of this call. On return aPort will be clear()ed.
void releaseTcfPort(CodaDevicePtr &aPort); void releaseCodaDevice(CodaDevicePtr &aPort);
int findByPortName(const QString &p) const; int findByPortName(const QString &p) const;
QString friendlyNameForPort(const QString &port) const; QString friendlyNameForPort(const QString &port) const;
@@ -188,6 +193,38 @@ private:
SYMBIANUTILS_EXPORT QDebug operator<<(QDebug d, const SymbianDeviceManager &); SYMBIANUTILS_EXPORT QDebug operator<<(QDebug d, const SymbianDeviceManager &);
struct OstChannelPrivate;
class SYMBIANUTILS_EXPORT OstChannel : public QIODevice
{
Q_OBJECT
public:
void close();
~OstChannel();
void flush();
qint64 bytesAvailable() const;
bool isSequential() const;
bool hasReceivedData() const;
Coda::CodaDevice &codaDevice() const;
private slots:
void ostDataReceived(uchar channelId, const QByteArray &aData);
void deviceAboutToClose();
private:
OstChannel(const CodaDevicePtr &codaPtr, uchar channelId);
Q_DISABLE_COPY(OstChannel)
qint64 readData(char *data, qint64 maxSize);
qint64 writeData(const char *data, qint64 maxSize);
private:
OstChannelPrivate *d;
friend class SymbianDeviceManager;
};
} // namespace SymbianUtils } // namespace SymbianUtils
#endif // SYMBIANDEVICEMANAGER_H #endif // SYMBIANDEVICEMANAGER_H