forked from qt-creator/qt-creator
Merge branch 'master' of scm.dev.nokia.troll.no:creator/mainline
This commit is contained in:
@@ -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/private/qdeclarativemetatype_p.h>
|
||||
#include <QtDeclarative/private/qdeclarativeopenmetaobject_p.h>
|
||||
|
@@ -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 <QtCore/QBuffer>
|
||||
|
@@ -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
|
||||
#define QMLSTREAMWRITER_H
|
||||
|
||||
|
@@ -56,11 +56,11 @@ leave room for the Qt 4 target page.
|
||||
<!-- Create a 2nd wizard page with parameters -->
|
||||
<fieldpagetitle>Custom QML Extension Plugin Parameters</fieldpagetitle>
|
||||
<fields>
|
||||
<field mandatory="false" name="ObjectName">
|
||||
<field mandatory="true" name="ObjectName">
|
||||
<fieldcontrol class="QLineEdit" validator='^[A-Za-z0-9_]+$' defaulttext="MyItem"/>
|
||||
<fielddescription>Object Class-name:</fielddescription>
|
||||
</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"/>
|
||||
<fielddescription>URI:</fielddescription>
|
||||
</field>
|
||||
|
@@ -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_TR_CATEGORY_CORE = QT_TRANSLATE_NOOP("Core", "Environment");
|
||||
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";
|
||||
|
||||
|
@@ -38,6 +38,7 @@
|
||||
#include "modemanager.h"
|
||||
#include "fileiconprovider.h"
|
||||
#include "designmode.h"
|
||||
#include "mimedatabase.h"
|
||||
|
||||
#include <extensionsystem/pluginmanager.h>
|
||||
|
||||
@@ -99,6 +100,7 @@ bool CorePlugin::initialize(const QStringList &arguments, QString *errorMessage)
|
||||
|
||||
void CorePlugin::extensionsInitialized()
|
||||
{
|
||||
m_mainWindow->mimeDatabase()->syncUserModifiedMimeTypes();
|
||||
m_mainWindow->extensionsInitialized();
|
||||
}
|
||||
|
||||
|
@@ -91,7 +91,9 @@ SOURCES += mainwindow.cpp \
|
||||
externaltool.cpp \
|
||||
dialogs/externaltoolconfig.cpp \
|
||||
toolsettings.cpp \
|
||||
variablechooser.cpp
|
||||
variablechooser.cpp \
|
||||
mimetypemagicdialog.cpp \
|
||||
mimetypesettings.cpp
|
||||
|
||||
HEADERS += mainwindow.h \
|
||||
editmode.h \
|
||||
@@ -180,7 +182,9 @@ HEADERS += mainwindow.h \
|
||||
externaltool.h \
|
||||
dialogs/externaltoolconfig.h \
|
||||
toolsettings.h \
|
||||
variablechooser.h
|
||||
variablechooser.h \
|
||||
mimetypemagicdialog.h \
|
||||
mimetypesettings.h
|
||||
|
||||
FORMS += dialogs/newdialog.ui \
|
||||
actionmanager/commandmappings.ui \
|
||||
@@ -189,7 +193,10 @@ FORMS += dialogs/newdialog.ui \
|
||||
editormanager/openeditorsview.ui \
|
||||
generalsettings.ui \
|
||||
dialogs/externaltoolconfig.ui \
|
||||
variablechooser.ui
|
||||
variablechooser.ui \
|
||||
mimetypesettingspage.ui \
|
||||
mimetypemagicdialog.ui
|
||||
|
||||
RESOURCES += core.qrc \
|
||||
fancyactionbar.qrc
|
||||
|
||||
|
@@ -75,7 +75,7 @@ ShortcutSettings::~ShortcutSettings()
|
||||
|
||||
QString ShortcutSettings::id() const
|
||||
{
|
||||
return QLatin1String("D.Keyboard");
|
||||
return QLatin1String(Core::Constants::SETTINGS_ID_SHORTCUTS);
|
||||
}
|
||||
|
||||
QString ShortcutSettings::displayName() const
|
||||
|
@@ -40,6 +40,7 @@
|
||||
#include "editormanager.h"
|
||||
#include "externaltool.h"
|
||||
#include "toolsettings.h"
|
||||
#include "mimetypesettings.h"
|
||||
#include "fancytabwidget.h"
|
||||
#include "filemanager.h"
|
||||
#include "generalsettings.h"
|
||||
@@ -152,6 +153,7 @@ MainWindow::MainWindow() :
|
||||
m_generalSettings(new GeneralSettings),
|
||||
m_shortcutSettings(new ShortcutSettings),
|
||||
m_toolSettings(new ToolSettings),
|
||||
m_mimeTypeSettings(new MimeTypeSettings),
|
||||
m_systemEditor(new SystemEditor),
|
||||
m_focusToEditor(0),
|
||||
m_newAction(0),
|
||||
@@ -256,6 +258,7 @@ MainWindow::~MainWindow()
|
||||
pm->removeObject(m_shortcutSettings);
|
||||
pm->removeObject(m_generalSettings);
|
||||
pm->removeObject(m_toolSettings);
|
||||
pm->removeObject(m_mimeTypeSettings);
|
||||
pm->removeObject(m_systemEditor);
|
||||
delete m_externalToolManager;
|
||||
m_externalToolManager = 0;
|
||||
@@ -267,6 +270,8 @@ MainWindow::~MainWindow()
|
||||
m_generalSettings = 0;
|
||||
delete m_toolSettings;
|
||||
m_toolSettings = 0;
|
||||
delete m_mimeTypeSettings;
|
||||
m_mimeTypeSettings = 0;
|
||||
delete m_systemEditor;
|
||||
m_systemEditor = 0;
|
||||
delete m_settings;
|
||||
@@ -325,9 +330,9 @@ bool MainWindow::init(QString *errorMessage)
|
||||
pm->addObject(m_generalSettings);
|
||||
pm->addObject(m_shortcutSettings);
|
||||
pm->addObject(m_toolSettings);
|
||||
pm->addObject(m_mimeTypeSettings);
|
||||
pm->addObject(m_systemEditor);
|
||||
|
||||
|
||||
// Add widget to the bottom, we create the view here instead of inside the
|
||||
// OutputPaneManager, since the StatusBarManager needs to be initialized before
|
||||
m_outputView = new Core::StatusBarWidget;
|
||||
@@ -352,8 +357,6 @@ void MainWindow::extensionsInitialized()
|
||||
readSettings();
|
||||
updateContext();
|
||||
|
||||
registerUserMimeTypes();
|
||||
|
||||
emit m_coreImpl->coreAboutToOpen();
|
||||
show();
|
||||
emit m_coreImpl->coreOpened();
|
||||
@@ -1397,15 +1400,3 @@ bool MainWindow::showWarningWithOptions(const QString &title,
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void MainWindow::registerUserMimeTypes() const
|
||||
{
|
||||
// This is to temporarily allow user specific MIME types (without recompilation).
|
||||
// Be careful with the file contents. Otherwise unpredictable behavior might arise.
|
||||
const QString &fileName = m_coreImpl->userResourcePath() + QLatin1String("/mimetypes.xml");
|
||||
if (QFile::exists(fileName)) {
|
||||
QString error;
|
||||
if (!m_coreImpl->mimeDatabase()->addMimeTypes(fileName, &error))
|
||||
qWarning() << error;
|
||||
}
|
||||
}
|
||||
|
@@ -78,6 +78,7 @@ class GeneralSettings;
|
||||
class ProgressManagerPrivate;
|
||||
class ShortcutSettings;
|
||||
class ToolSettings;
|
||||
class MimeTypeSettings;
|
||||
class StatusBarManager;
|
||||
class VersionDialog;
|
||||
class SystemEditor;
|
||||
@@ -179,8 +180,6 @@ private:
|
||||
void readSettings();
|
||||
void writeSettings();
|
||||
|
||||
void registerUserMimeTypes() const;
|
||||
|
||||
CoreImpl *m_coreImpl;
|
||||
UniqueIDManager *m_uniqueIDManager;
|
||||
Context m_additionalContexts;
|
||||
@@ -214,6 +213,7 @@ private:
|
||||
GeneralSettings *m_generalSettings;
|
||||
ShortcutSettings *m_shortcutSettings;
|
||||
ToolSettings *m_toolSettings;
|
||||
MimeTypeSettings *m_mimeTypeSettings;
|
||||
SystemEditor *m_systemEditor;
|
||||
|
||||
// actions
|
||||
|
@@ -33,6 +33,7 @@
|
||||
|
||||
#include "mimedatabase.h"
|
||||
#include "coreconstants.h"
|
||||
#include "icore.h"
|
||||
|
||||
#include <utils/qtcassert.h>
|
||||
|
||||
@@ -40,9 +41,11 @@
|
||||
#include <QtCore/QCoreApplication>
|
||||
#include <QtCore/QDebug>
|
||||
#include <QtCore/QFile>
|
||||
#include <QtCore/QDir>
|
||||
#include <QtCore/QFileInfo>
|
||||
#include <QtCore/QLocale>
|
||||
#include <QtCore/QMap>
|
||||
#include <QtCore/QHash>
|
||||
#include <QtCore/QMultiHash>
|
||||
#include <QtCore/QRegExp>
|
||||
#include <QtCore/QSharedData>
|
||||
@@ -50,10 +53,11 @@
|
||||
#include <QtCore/QStringList>
|
||||
#include <QtCore/QTextStream>
|
||||
#include <QtCore/QMutexLocker>
|
||||
|
||||
#include <QtXml/QXmlStreamReader>
|
||||
#include <QtCore/QXmlStreamReader>
|
||||
#include <QtCore/QXmlStreamWriter>
|
||||
|
||||
#include <algorithm>
|
||||
#include <functional>
|
||||
|
||||
enum { debugMimeDB = 0 };
|
||||
|
||||
@@ -211,6 +215,8 @@ bool HeuristicTextMagicMatcher::matches(const QByteArray &data) const
|
||||
} // namespace Internal
|
||||
|
||||
// MagicRule
|
||||
const QChar MagicRule::kColon(QLatin1Char(':'));
|
||||
|
||||
MagicRule::MagicRule(int startPos, int endPos) : m_startPos(startPos), m_endPos(endPos)
|
||||
{
|
||||
}
|
||||
@@ -229,6 +235,20 @@ int MagicRule::endPos() const
|
||||
return m_endPos;
|
||||
}
|
||||
|
||||
QString MagicRule::toOffset(const QPair<int, int> &startEnd)
|
||||
{
|
||||
return QString(QLatin1String("%1:%2")).arg(startEnd.first).arg(startEnd.second);
|
||||
}
|
||||
|
||||
QPair<int, int> MagicRule::fromOffset(const QString &offset)
|
||||
{
|
||||
const QStringList &startEnd = offset.split(kColon);
|
||||
Q_ASSERT(startEnd.size() == 2);
|
||||
return qMakePair(startEnd.at(0).toInt(), startEnd.at(1).toInt());
|
||||
}
|
||||
|
||||
const QString MagicStringRule::kMatchType("string");
|
||||
|
||||
MagicStringRule::MagicStringRule(const QString &s, int startPos, int endPos) :
|
||||
MagicRule(startPos, endPos), m_pattern(s.toUtf8())
|
||||
{
|
||||
@@ -238,6 +258,16 @@ MagicStringRule::~MagicStringRule()
|
||||
{
|
||||
}
|
||||
|
||||
QString MagicStringRule::matchType() const
|
||||
{
|
||||
return kMatchType;
|
||||
}
|
||||
|
||||
QString MagicStringRule::matchValue() const
|
||||
{
|
||||
return m_pattern;
|
||||
}
|
||||
|
||||
bool MagicStringRule::matches(const QByteArray &data) const
|
||||
{
|
||||
// Quick check
|
||||
@@ -254,28 +284,51 @@ bool MagicStringRule::matches(const QByteArray &data) const
|
||||
return rc;
|
||||
}
|
||||
|
||||
const QString MagicByteRule::kMatchType(QLatin1String("byte"));
|
||||
|
||||
MagicByteRule::MagicByteRule(const QString &s, int startPos, int endPos) :
|
||||
MagicRule(startPos, endPos)
|
||||
MagicRule(startPos, endPos), m_bytesSize(0)
|
||||
{
|
||||
// Expect an hex format value like this: \0x7f\0x45\0x4c\0x46
|
||||
const QStringList &bytes = s.split(QLatin1Char('\\'), QString::SkipEmptyParts);
|
||||
foreach (const QString &byte, bytes) {
|
||||
bool ok;
|
||||
const int hex = byte.toInt(&ok, 16);
|
||||
if (ok) {
|
||||
m_bytes.push_back(hex);
|
||||
} else {
|
||||
m_bytes.clear();
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (validateByteSequence(s, &m_bytes))
|
||||
m_bytesSize = m_bytes.size();
|
||||
else
|
||||
m_bytes.clear();
|
||||
}
|
||||
|
||||
MagicByteRule::~MagicByteRule()
|
||||
{
|
||||
}
|
||||
|
||||
bool MagicByteRule::validateByteSequence(const QString &sequence, QList<int> *bytes)
|
||||
{
|
||||
// Expect an hex format value like this: \0x7f\0x45\0x4c\0x46
|
||||
const QStringList &byteSequence = sequence.split(QLatin1Char('\\'), QString::SkipEmptyParts);
|
||||
foreach (const QString &byte, byteSequence) {
|
||||
bool ok;
|
||||
const int hex = byte.toInt(&ok, 16);
|
||||
if (ok) {
|
||||
if (bytes)
|
||||
bytes->push_back(hex);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
QString MagicByteRule::matchType() const
|
||||
{
|
||||
return kMatchType;
|
||||
}
|
||||
|
||||
QString MagicByteRule::matchValue() const
|
||||
{
|
||||
QString value;
|
||||
foreach (int byte, m_bytes)
|
||||
value.append(QString(QLatin1String("\\0x%1")).arg(byte, 0, 16));
|
||||
return value;
|
||||
}
|
||||
|
||||
bool MagicByteRule::matches(const QByteArray &data) const
|
||||
{
|
||||
if (m_bytesSize == 0)
|
||||
@@ -307,7 +360,17 @@ MagicRuleMatcher::MagicRuleMatcher() :
|
||||
|
||||
void MagicRuleMatcher::add(const MagicRuleSharedPointer &rule)
|
||||
{
|
||||
m_list.push_back(rule);
|
||||
m_list.append(rule);
|
||||
}
|
||||
|
||||
void MagicRuleMatcher::add(const MagicRuleList &ruleList)
|
||||
{
|
||||
m_list.append(ruleList);
|
||||
}
|
||||
|
||||
MagicRuleMatcher::MagicRuleList MagicRuleMatcher::magicRules() const
|
||||
{
|
||||
return m_list;
|
||||
}
|
||||
|
||||
bool MagicRuleMatcher::matches(const QByteArray &data) const
|
||||
@@ -329,6 +392,20 @@ void MagicRuleMatcher::setPriority(int p)
|
||||
m_priority = p;
|
||||
}
|
||||
|
||||
IMagicMatcher::IMagicMatcherList MagicRuleMatcher::createMatchers(
|
||||
const QHash<int, MagicRuleList> &rulesByPriority)
|
||||
{
|
||||
IMagicMatcher::IMagicMatcherList matchers;
|
||||
QHash<int, MagicRuleList>::const_iterator ruleIt = rulesByPriority.begin();
|
||||
for (; ruleIt != rulesByPriority.end(); ++ruleIt) {
|
||||
MagicRuleMatcher *magicRuleMatcher = new MagicRuleMatcher();
|
||||
magicRuleMatcher->setPriority(ruleIt.key());
|
||||
magicRuleMatcher->add(ruleIt.value());
|
||||
matchers.append(IMagicMatcher::IMagicMatcherSharedPointer(magicRuleMatcher));
|
||||
}
|
||||
return matchers;
|
||||
}
|
||||
|
||||
// GlobPattern
|
||||
MimeGlobPattern::MimeGlobPattern(const QRegExp ®Exp, unsigned weight) :
|
||||
m_regExp(regExp), m_weight(weight)
|
||||
@@ -353,9 +430,16 @@ unsigned MimeGlobPattern::weight() const
|
||||
class MimeTypeData : public QSharedData {
|
||||
public:
|
||||
typedef QHash<QString,QString> LocaleHash;
|
||||
|
||||
MimeTypeData();
|
||||
|
||||
void clear();
|
||||
void assignSuffix(const QString &pattern);
|
||||
void assignSuffixes(const QStringList &patterns);
|
||||
void debug(QTextStream &str, int indent = 0) const;
|
||||
|
||||
const QRegExp suffixPattern;
|
||||
|
||||
QString type;
|
||||
QString comment;
|
||||
|
||||
@@ -365,12 +449,17 @@ public:
|
||||
QStringList subClassesOf;
|
||||
QString preferredSuffix;
|
||||
QStringList suffixes;
|
||||
|
||||
typedef QSharedPointer<IMagicMatcher> IMagicMatcherSharedPointer;
|
||||
typedef QList<IMagicMatcherSharedPointer> IMagicMatcherList;
|
||||
IMagicMatcherList magicMatchers;
|
||||
IMagicMatcher::IMagicMatcherList magicMatchers;
|
||||
};
|
||||
|
||||
MimeTypeData::MimeTypeData()
|
||||
// RE to match a suffix glob pattern: "*.ext" (and not sth like "Makefile" or
|
||||
// "*.log[1-9]"
|
||||
: suffixPattern(QLatin1String("^\\*\\.[\\w+]+$"))
|
||||
{
|
||||
QTC_ASSERT(suffixPattern.isValid(), /**/);
|
||||
}
|
||||
|
||||
void MimeTypeData::clear()
|
||||
{
|
||||
type.clear();
|
||||
@@ -383,6 +472,22 @@ void MimeTypeData::clear()
|
||||
magicMatchers.clear();
|
||||
}
|
||||
|
||||
void MimeTypeData::assignSuffix(const QString &pattern)
|
||||
{
|
||||
if (suffixPattern.exactMatch(pattern)) {
|
||||
const QString suffix = pattern.right(pattern.size() - 2);
|
||||
suffixes.push_back(suffix);
|
||||
if (preferredSuffix.isEmpty())
|
||||
preferredSuffix = suffix;
|
||||
}
|
||||
}
|
||||
|
||||
void MimeTypeData::assignSuffixes(const QStringList &patterns)
|
||||
{
|
||||
foreach (const QString &pattern, patterns)
|
||||
assignSuffix(pattern);
|
||||
}
|
||||
|
||||
void MimeTypeData::debug(QTextStream &str, int indent) const
|
||||
{
|
||||
const QString indentS = QString(indent, QLatin1Char(' '));
|
||||
@@ -516,6 +621,13 @@ QList<MimeGlobPattern> MimeType::globPatterns() const
|
||||
void MimeType::setGlobPatterns(const QList<MimeGlobPattern> &g)
|
||||
{
|
||||
m_d->globPatterns = g;
|
||||
|
||||
QString oldPrefferedSuffix = m_d->preferredSuffix;
|
||||
m_d->suffixes.clear();
|
||||
m_d->preferredSuffix.clear();
|
||||
m_d->assignSuffixes(MimeDatabase::fromGlobPatterns(g));
|
||||
if (m_d->preferredSuffix != oldPrefferedSuffix && m_d->suffixes.contains(oldPrefferedSuffix))
|
||||
m_d->preferredSuffix = oldPrefferedSuffix;
|
||||
}
|
||||
|
||||
QStringList MimeType::subClassesOf() const
|
||||
@@ -608,7 +720,7 @@ unsigned MimeType::matchesFileByContent(Internal::FileMatchContext &c) const
|
||||
|
||||
const QByteArray data = c.data();
|
||||
if (!data.isEmpty()) {
|
||||
foreach (const MimeTypeData::IMagicMatcherSharedPointer &matcher, m_d->magicMatchers) {
|
||||
foreach (const IMagicMatcher::IMagicMatcherSharedPointer &matcher, m_d->magicMatchers) {
|
||||
if (matcher->matches(data)) {
|
||||
const unsigned magicPriority = matcher->priority();
|
||||
if (magicPriority > priority)
|
||||
@@ -624,16 +736,52 @@ QStringList MimeType::suffixes() const
|
||||
return m_d->suffixes;
|
||||
}
|
||||
|
||||
void MimeType::setSuffixes(const QStringList &s)
|
||||
{
|
||||
m_d->suffixes = s;
|
||||
}
|
||||
|
||||
void MimeType::addMagicMatcher(const QSharedPointer<IMagicMatcher> &matcher)
|
||||
void MimeType::addMagicMatcher(const IMagicMatcherSharedPointer &matcher)
|
||||
{
|
||||
m_d->magicMatchers.push_back(matcher);
|
||||
}
|
||||
|
||||
const MimeType::IMagicMatcherList &MimeType::magicMatchers() const
|
||||
{
|
||||
return m_d->magicMatchers;
|
||||
}
|
||||
|
||||
void MimeType::setMagicMatchers(const IMagicMatcherList &matchers)
|
||||
{
|
||||
m_d->magicMatchers = matchers;
|
||||
}
|
||||
|
||||
namespace {
|
||||
struct RemovePred : std::unary_function<MimeType::IMagicMatcherSharedPointer, bool>
|
||||
{
|
||||
RemovePred(bool keepRuleBased) : m_keepRuleBase(keepRuleBased) {}
|
||||
bool m_keepRuleBase;
|
||||
|
||||
bool operator()(const MimeType::IMagicMatcherSharedPointer &matcher) {
|
||||
if ((m_keepRuleBase && !dynamic_cast<MagicRuleMatcher *>(matcher.data()))
|
||||
|| (!m_keepRuleBase && dynamic_cast<MagicRuleMatcher *>(matcher.data())))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
};
|
||||
} // Anonymous
|
||||
|
||||
MimeType::IMagicMatcherList MimeType::magicRuleMatchers() const
|
||||
{
|
||||
IMagicMatcherList ruleMatchers = m_d->magicMatchers;
|
||||
ruleMatchers.erase(std::remove_if(ruleMatchers.begin(), ruleMatchers.end(), RemovePred(true)),
|
||||
ruleMatchers.end());
|
||||
return ruleMatchers;
|
||||
}
|
||||
|
||||
void MimeType::setMagicRuleMatchers(const IMagicMatcherList &matchers)
|
||||
{
|
||||
m_d->magicMatchers.erase(std::remove_if(m_d->magicMatchers.begin(), m_d->magicMatchers.end(),
|
||||
RemovePred(false)),
|
||||
m_d->magicMatchers.end());
|
||||
m_d->magicMatchers.append(matchers);
|
||||
}
|
||||
|
||||
QDebug operator<<(QDebug d, const MimeType &mt)
|
||||
{
|
||||
QString s;
|
||||
@@ -652,7 +800,7 @@ namespace Internal {
|
||||
class BaseMimeTypeParser {
|
||||
Q_DISABLE_COPY(BaseMimeTypeParser)
|
||||
public:
|
||||
BaseMimeTypeParser();
|
||||
BaseMimeTypeParser() {}
|
||||
virtual ~BaseMimeTypeParser() {}
|
||||
|
||||
bool parse(QIODevice *dev, const QString &fileName, QString *errorMessage);
|
||||
@@ -676,18 +824,8 @@ private:
|
||||
ParseError };
|
||||
|
||||
static ParseStage nextStage(ParseStage currentStage, const QStringRef &startElement);
|
||||
|
||||
const QRegExp m_suffixPattern;
|
||||
};
|
||||
|
||||
BaseMimeTypeParser:: BaseMimeTypeParser() :
|
||||
// RE to match a suffix glob pattern: "*.ext" (and not sth like "Makefile" or
|
||||
// "*.log[1-9]"
|
||||
m_suffixPattern(QLatin1String("^\\*\\.[\\w+]+$"))
|
||||
{
|
||||
QTC_ASSERT(m_suffixPattern.isValid(), /**/);
|
||||
}
|
||||
|
||||
void BaseMimeTypeParser::addGlobPattern(const QString &pattern, const QString &weight, MimeTypeData *d) const
|
||||
{
|
||||
if (pattern.isEmpty())
|
||||
@@ -706,12 +844,7 @@ void BaseMimeTypeParser::addGlobPattern(const QString &pattern, const QString &w
|
||||
else
|
||||
d->globPatterns.push_back(MimeGlobPattern(wildCard, weight.toInt()));
|
||||
|
||||
if (m_suffixPattern.exactMatch(pattern)) {
|
||||
const QString suffix = pattern.right(pattern.size() - 2);
|
||||
d->suffixes.push_back(suffix);
|
||||
if (d->preferredSuffix.isEmpty())
|
||||
d->preferredSuffix = suffix;
|
||||
}
|
||||
d->assignSuffix(pattern);
|
||||
}
|
||||
|
||||
BaseMimeTypeParser::ParseStage BaseMimeTypeParser::nextStage(ParseStage currentStage, const QStringRef &startElement)
|
||||
@@ -934,10 +1067,10 @@ MimeMapEntry::MimeMapEntry(const MimeType &t, int aLevel) :
|
||||
* - Provide quick lookup by file type.
|
||||
* This basically rules out some pointer-based tree, so the structure chosen
|
||||
* is:
|
||||
* - An alias map <QString->QString> for mapping aliases to types
|
||||
* - A Map <QString-MimeMapEntry> for the types (MimeMapEntry being a pair of
|
||||
* - An alias map QString->QString for mapping aliases to types
|
||||
* - A Map QString->MimeMapEntry for the types (MimeMapEntry being a pair of
|
||||
* MimeType and (hierarchy) level.
|
||||
* - A map <QString->QString> representing parent->child relations (enabling
|
||||
* - A map QString->QString representing parent->child relations (enabling
|
||||
* recursing over children)
|
||||
* Using strings avoids dangling pointers.
|
||||
* The hierarchy level is used for mapping by file types. When findByFile()
|
||||
@@ -958,16 +1091,31 @@ public:
|
||||
bool addMimeTypes(QIODevice *device, QString *errorMessage);
|
||||
bool addMimeType(MimeType mt);
|
||||
|
||||
// Returns a mime type or Null one if none found
|
||||
MimeType findByType(const QString &type) const;
|
||||
// Returns a mime type or Null one if none found
|
||||
MimeType findByFile(const QFileInfo &f) const;
|
||||
|
||||
QStringList filterStrings() const;
|
||||
|
||||
QStringList suffixes() const;
|
||||
bool setPreferredSuffix(const QString &typeOrAlias, const QString &suffix);
|
||||
|
||||
// Return all known suffixes
|
||||
QStringList suffixes() const;
|
||||
QStringList filterStrings() const;
|
||||
QList<MimeGlobPattern> globPatterns() const;
|
||||
void setGlobPatterns(const QString &typeOrAlias, const QList<MimeGlobPattern> &globPatterns);
|
||||
|
||||
QList<QSharedPointer<IMagicMatcher> > magicMatchers() const;
|
||||
void setMagicMatchers(const QString &typeOrAlias,
|
||||
const QList<QSharedPointer<IMagicMatcher> > &matchers);
|
||||
|
||||
QList<MimeType> mimeTypes() const;
|
||||
|
||||
void syncUserModifiedMimeTypes();
|
||||
static QList<MimeType> readUserModifiedMimeTypes();
|
||||
static void writeUserModifiedMimeTypes(const QList<MimeType> &mimeTypes);
|
||||
void clearUserModifiedMimeTypes();
|
||||
|
||||
static QList<MimeGlobPattern> toGlobPatterns(const QStringList &patterns,
|
||||
int weight = MimeGlobPattern::MaxWeight);
|
||||
static QStringList fromGlobPatterns(const QList<MimeGlobPattern> &globPatterns);
|
||||
|
||||
void debug(QTextStream &str) const;
|
||||
|
||||
@@ -976,6 +1124,11 @@ private:
|
||||
typedef QHash<QString, QString> AliasMap;
|
||||
typedef QMultiHash<QString, QString> ParentChildrenMap;
|
||||
|
||||
static const QChar kSemiColon;
|
||||
static const QString kModifiedMimeTypesFile;
|
||||
static QString kModifiedMimeTypesPath;
|
||||
|
||||
|
||||
bool addMimeTypes(QIODevice *device, const QString &fileName, QString *errorMessage);
|
||||
inline const QString &resolveAlias(const QString &name) const;
|
||||
MimeType findByFile(const QFileInfo &f, unsigned *priority) const;
|
||||
@@ -988,9 +1141,15 @@ private:
|
||||
int m_maxLevel;
|
||||
};
|
||||
|
||||
const QChar MimeDatabasePrivate::kSemiColon(QLatin1Char(';'));
|
||||
const QString MimeDatabasePrivate::kModifiedMimeTypesFile(QLatin1String("modifiedmimetypes.xml"));
|
||||
QString MimeDatabasePrivate::kModifiedMimeTypesPath;
|
||||
|
||||
MimeDatabasePrivate::MimeDatabasePrivate() :
|
||||
m_maxLevel(-1)
|
||||
{
|
||||
// Assign here to avoid non-local static data initialization issues.
|
||||
kModifiedMimeTypesPath = ICore::instance()->userResourcePath() + QLatin1String("/mimetypes/");
|
||||
}
|
||||
|
||||
namespace Internal {
|
||||
@@ -1230,6 +1389,197 @@ QStringList MimeDatabasePrivate::filterStrings() const
|
||||
return rc;
|
||||
}
|
||||
|
||||
QList<MimeGlobPattern> MimeDatabasePrivate::globPatterns() const
|
||||
{
|
||||
QList<MimeGlobPattern> globPatterns;
|
||||
const TypeMimeTypeMap::const_iterator cend = m_typeMimeTypeMap.constEnd();
|
||||
for (TypeMimeTypeMap::const_iterator it = m_typeMimeTypeMap.constBegin(); it != cend; ++it)
|
||||
globPatterns.append(it.value().type.globPatterns());
|
||||
return globPatterns;
|
||||
}
|
||||
|
||||
void MimeDatabasePrivate::setGlobPatterns(const QString &typeOrAlias,
|
||||
const QList<MimeGlobPattern> &globPatterns)
|
||||
{
|
||||
TypeMimeTypeMap::iterator tit = m_typeMimeTypeMap.find(resolveAlias(typeOrAlias));
|
||||
if (tit != m_typeMimeTypeMap.end())
|
||||
tit.value().type.setGlobPatterns(globPatterns);
|
||||
}
|
||||
|
||||
QList<QSharedPointer<IMagicMatcher> > MimeDatabasePrivate::magicMatchers() const
|
||||
{
|
||||
QList<QSharedPointer<IMagicMatcher> > magicMatchers;
|
||||
const TypeMimeTypeMap::const_iterator cend = m_typeMimeTypeMap.constEnd();
|
||||
for (TypeMimeTypeMap::const_iterator it = m_typeMimeTypeMap.constBegin(); it != cend; ++it)
|
||||
magicMatchers.append(it.value().type.magicMatchers());
|
||||
return magicMatchers;
|
||||
}
|
||||
|
||||
void MimeDatabasePrivate::setMagicMatchers(const QString &typeOrAlias,
|
||||
const QList<QSharedPointer<IMagicMatcher> > &matchers)
|
||||
{
|
||||
TypeMimeTypeMap::iterator tit = m_typeMimeTypeMap.find(resolveAlias(typeOrAlias));
|
||||
if (tit != m_typeMimeTypeMap.end())
|
||||
tit.value().type.setMagicMatchers(matchers);
|
||||
}
|
||||
|
||||
QList<MimeType> MimeDatabasePrivate::mimeTypes() const
|
||||
{
|
||||
QList<MimeType> mimeTypes;
|
||||
const TypeMimeTypeMap::const_iterator cend = m_typeMimeTypeMap.constEnd();
|
||||
for (TypeMimeTypeMap::const_iterator it = m_typeMimeTypeMap.constBegin(); it != cend; ++it)
|
||||
mimeTypes.append(it.value().type);
|
||||
return mimeTypes;
|
||||
}
|
||||
|
||||
void MimeDatabasePrivate::syncUserModifiedMimeTypes()
|
||||
{
|
||||
QHash<QString, MimeType> userModified;
|
||||
const QList<MimeType> &userMimeTypes = readUserModifiedMimeTypes();
|
||||
foreach (const MimeType &userMimeType, userMimeTypes)
|
||||
userModified.insert(userMimeType.type(), userMimeType);
|
||||
|
||||
TypeMimeTypeMap::iterator end = m_typeMimeTypeMap.end();
|
||||
QHash<QString, MimeType>::const_iterator userMimeEnd = userModified.end();
|
||||
for (TypeMimeTypeMap::iterator it = m_typeMimeTypeMap.begin(); it != end; ++it) {
|
||||
QHash<QString, MimeType>::const_iterator userMimeIt =
|
||||
userModified.find(it.value().type.type());
|
||||
if (userMimeIt != userMimeEnd) {
|
||||
it.value().type.setGlobPatterns(userMimeIt.value().globPatterns());
|
||||
it.value().type.setMagicRuleMatchers(userMimeIt.value().magicRuleMatchers());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QList<MimeType> MimeDatabasePrivate::readUserModifiedMimeTypes()
|
||||
{
|
||||
typedef MagicRuleMatcher::MagicRuleList MagicRuleList;
|
||||
typedef MagicRuleMatcher::MagicRuleSharedPointer MagicRuleSharedPointer;
|
||||
|
||||
QList<MimeType> mimeTypes;
|
||||
QFile file(kModifiedMimeTypesPath + kModifiedMimeTypesFile);
|
||||
if (file.open(QFile::ReadOnly)) {
|
||||
MimeType mimeType;
|
||||
QHash<int, MagicRuleList> rules;
|
||||
QXmlStreamReader reader(&file);
|
||||
QXmlStreamAttributes atts;
|
||||
while (!reader.atEnd()) {
|
||||
switch (reader.readNext()) {
|
||||
case QXmlStreamReader::StartElement:
|
||||
atts = reader.attributes();
|
||||
if (reader.name() == mimeTypeTagC) {
|
||||
mimeType.setType(atts.value(mimeTypeAttributeC).toString());
|
||||
const QString &patterns = atts.value(patternAttributeC).toString();
|
||||
mimeType.setGlobPatterns(toGlobPatterns(patterns.split(kSemiColon)));
|
||||
} else if (reader.name() == matchTagC) {
|
||||
const QString &value = atts.value(matchValueAttributeC).toString();
|
||||
const QString &type = atts.value(matchTypeAttributeC).toString();
|
||||
const QString &offset = atts.value(matchOffsetAttributeC).toString();
|
||||
QPair<int, int> range = MagicRule::fromOffset(offset);
|
||||
const int priority = atts.value(priorityAttributeC).toString().toInt();
|
||||
|
||||
MagicRule *magicRule;
|
||||
if (type == MagicStringRule::kMatchType)
|
||||
magicRule = new MagicStringRule(value, range.first, range.second);
|
||||
else
|
||||
magicRule = new MagicByteRule(value, range.first, range.second);
|
||||
rules[priority].append(MagicRuleSharedPointer(magicRule));
|
||||
}
|
||||
break;
|
||||
case QXmlStreamReader::EndElement:
|
||||
if (reader.name() == mimeTypeTagC) {
|
||||
mimeType.setMagicRuleMatchers(MagicRuleMatcher::createMatchers(rules));
|
||||
mimeTypes.append(mimeType);
|
||||
mimeType.clear();
|
||||
rules.clear();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (reader.hasError())
|
||||
qWarning() << kModifiedMimeTypesFile << reader.errorString() << reader.lineNumber()
|
||||
<< reader.columnNumber();
|
||||
file.close();
|
||||
}
|
||||
return mimeTypes;
|
||||
}
|
||||
|
||||
void MimeDatabasePrivate::writeUserModifiedMimeTypes(const QList<MimeType> &mimeTypes)
|
||||
{
|
||||
// Keep mime types modified which are already on file.
|
||||
QList<MimeType> allModifiedMimeTypes = mimeTypes;
|
||||
allModifiedMimeTypes.append(readUserModifiedMimeTypes());
|
||||
|
||||
if (QFile::exists(kModifiedMimeTypesPath) || QDir().mkpath(kModifiedMimeTypesPath)) {
|
||||
QFile file(kModifiedMimeTypesPath + kModifiedMimeTypesFile);
|
||||
if (file.open(QFile::WriteOnly | QFile::Truncate)) {
|
||||
// Notice this file only represents user modifications. It is writen in a
|
||||
// convienient way for synchronization, which is similar to but not exactly the
|
||||
// same format we use for the embedded mime type files.
|
||||
QXmlStreamWriter writer(&file);
|
||||
writer.setAutoFormatting(true);
|
||||
writer.writeStartDocument();
|
||||
writer.writeStartElement(QLatin1String(mimeInfoTagC));
|
||||
foreach (const MimeType &mimeType, allModifiedMimeTypes) {
|
||||
writer.writeStartElement(mimeTypeTagC);
|
||||
writer.writeAttribute(mimeTypeAttributeC, mimeType.type());
|
||||
writer.writeAttribute(patternAttributeC,
|
||||
fromGlobPatterns(mimeType.globPatterns()).join(kSemiColon));
|
||||
const QList<QSharedPointer<IMagicMatcher> > &matchers = mimeType.magicMatchers();
|
||||
foreach (const QSharedPointer<IMagicMatcher> &matcher, matchers) {
|
||||
// Only care about rule-based matchers.
|
||||
if (MagicRuleMatcher *ruleMatcher =
|
||||
dynamic_cast<MagicRuleMatcher *>(matcher.data())) {
|
||||
const MagicRuleMatcher::MagicRuleList &rules = ruleMatcher->magicRules();
|
||||
foreach (const MagicRuleMatcher::MagicRuleSharedPointer &rule, rules) {
|
||||
writer.writeStartElement(matchTagC);
|
||||
writer.writeAttribute(matchValueAttributeC, rule->matchValue());
|
||||
writer.writeAttribute(matchTypeAttributeC, rule->matchType());
|
||||
writer.writeAttribute(matchOffsetAttributeC,
|
||||
MagicRule::toOffset(
|
||||
qMakePair(rule->startPos(), rule->endPos())));
|
||||
writer.writeAttribute(priorityAttributeC,
|
||||
QString::number(ruleMatcher->priority()));
|
||||
writer.writeEndElement();
|
||||
}
|
||||
}
|
||||
}
|
||||
writer.writeEndElement();
|
||||
}
|
||||
writer.writeEndElement();
|
||||
writer.writeEndDocument();
|
||||
file.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MimeDatabasePrivate::clearUserModifiedMimeTypes()
|
||||
{
|
||||
// This removes the user's file. However, the operation will actually take place the next time
|
||||
// Creator starts, since we currently don't support removing stuff from the mime database.
|
||||
QFile::remove(kModifiedMimeTypesPath + kModifiedMimeTypesFile);
|
||||
}
|
||||
|
||||
QList<MimeGlobPattern> MimeDatabasePrivate::toGlobPatterns(const QStringList &patterns, int weight)
|
||||
{
|
||||
QList<MimeGlobPattern> globPatterns;
|
||||
foreach (const QString &pattern, patterns) {
|
||||
QRegExp regExp(pattern, Qt::CaseSensitive, QRegExp::Wildcard);
|
||||
globPatterns.append(Core::MimeGlobPattern(regExp, weight));
|
||||
}
|
||||
return globPatterns;
|
||||
}
|
||||
|
||||
QStringList MimeDatabasePrivate::fromGlobPatterns(const QList<MimeGlobPattern> &globPatterns)
|
||||
{
|
||||
QStringList patterns;
|
||||
foreach (const MimeGlobPattern &globPattern, globPatterns)
|
||||
patterns.append(globPattern.regExp().pattern());
|
||||
return patterns;
|
||||
}
|
||||
|
||||
void MimeDatabasePrivate::debug(QTextStream &str) const
|
||||
{
|
||||
str << ">MimeDatabase\n";
|
||||
@@ -1336,6 +1686,70 @@ QString MimeDatabase::allFiltersString(QString *allFilesFilter) const
|
||||
return filters.join(QLatin1String(";;"));
|
||||
}
|
||||
|
||||
QList<MimeGlobPattern> MimeDatabase::globPatterns() const
|
||||
{
|
||||
m_mutex.lock();
|
||||
const QList<MimeGlobPattern> rc = m_d->globPatterns();
|
||||
m_mutex.unlock();
|
||||
return rc;
|
||||
}
|
||||
|
||||
void MimeDatabase::setGlobPatterns(const QString &typeOrAlias,
|
||||
const QList<MimeGlobPattern> &globPatterns)
|
||||
{
|
||||
m_mutex.lock();
|
||||
m_d->setGlobPatterns(typeOrAlias, globPatterns);
|
||||
m_mutex.unlock();
|
||||
}
|
||||
|
||||
MimeDatabase::IMagicMatcherList MimeDatabase::magicMatchers() const
|
||||
{
|
||||
m_mutex.lock();
|
||||
const IMagicMatcherList rc = m_d->magicMatchers();
|
||||
m_mutex.unlock();
|
||||
return rc;
|
||||
}
|
||||
|
||||
void MimeDatabase::setMagicMatchers(const QString &typeOrAlias,
|
||||
const IMagicMatcherList &matchers)
|
||||
{
|
||||
m_mutex.lock();
|
||||
m_d->setMagicMatchers(typeOrAlias, matchers);
|
||||
m_mutex.unlock();
|
||||
}
|
||||
|
||||
QList<MimeType> MimeDatabase::mimeTypes() const
|
||||
{
|
||||
m_mutex.lock();
|
||||
const QList<MimeType> &mimeTypes = m_d->mimeTypes();
|
||||
m_mutex.unlock();
|
||||
return mimeTypes;
|
||||
}
|
||||
|
||||
void MimeDatabase::syncUserModifiedMimeTypes()
|
||||
{
|
||||
m_mutex.lock();
|
||||
m_d->syncUserModifiedMimeTypes();
|
||||
m_mutex.unlock();
|
||||
}
|
||||
|
||||
void MimeDatabase::clearUserModifiedMimeTypes()
|
||||
{
|
||||
m_mutex.lock();
|
||||
m_d->clearUserModifiedMimeTypes();
|
||||
m_mutex.unlock();
|
||||
}
|
||||
|
||||
QList<MimeType> MimeDatabase::readUserModifiedMimeTypes()
|
||||
{
|
||||
return MimeDatabasePrivate::readUserModifiedMimeTypes();
|
||||
}
|
||||
|
||||
void MimeDatabase::writeUserModifiedMimeTypes(const QList<MimeType> &mimeTypes)
|
||||
{
|
||||
MimeDatabasePrivate::writeUserModifiedMimeTypes(mimeTypes);
|
||||
}
|
||||
|
||||
QString MimeDatabase::preferredSuffixByType(const QString &type) const
|
||||
{
|
||||
if (const MimeType mt = findByType(type))
|
||||
@@ -1358,6 +1772,16 @@ bool MimeDatabase::setPreferredSuffix(const QString &typeOrAlias, const QString
|
||||
return rc;
|
||||
}
|
||||
|
||||
QList<MimeGlobPattern> MimeDatabase::toGlobPatterns(const QStringList &patterns, int weight)
|
||||
{
|
||||
return MimeDatabasePrivate::toGlobPatterns(patterns, weight);
|
||||
}
|
||||
|
||||
QStringList MimeDatabase::fromGlobPatterns(const QList<MimeGlobPattern> &globPatterns)
|
||||
{
|
||||
return MimeDatabasePrivate::fromGlobPatterns(globPatterns);
|
||||
}
|
||||
|
||||
QDebug operator<<(QDebug d, const MimeDatabase &mt)
|
||||
{
|
||||
QString s;
|
||||
|
@@ -41,6 +41,7 @@
|
||||
#include <QtCore/QByteArray>
|
||||
#include <QtCore/QMutex>
|
||||
#include <QtCore/QFileInfo>
|
||||
#include <QtCore/QPair>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
class QIODevice;
|
||||
@@ -66,6 +67,9 @@ class CORE_EXPORT IMagicMatcher
|
||||
protected:
|
||||
IMagicMatcher() {}
|
||||
public:
|
||||
typedef QSharedPointer<IMagicMatcher> IMagicMatcherSharedPointer;
|
||||
typedef QList<IMagicMatcherSharedPointer> IMagicMatcherList;
|
||||
|
||||
// Check for a match on contents of a file
|
||||
virtual bool matches(const QByteArray &data) const = 0;
|
||||
// Return a priority value from 1..100
|
||||
@@ -83,13 +87,19 @@ public:
|
||||
MagicRule(int startPos, int endPos);
|
||||
virtual ~MagicRule();
|
||||
|
||||
virtual QString matchType() const = 0;
|
||||
virtual QString matchValue() const = 0;
|
||||
virtual bool matches(const QByteArray &data) const = 0;
|
||||
|
||||
protected:
|
||||
int startPos() const;
|
||||
int endPos() const;
|
||||
|
||||
static QString toOffset(const QPair<int, int> &startEnd);
|
||||
static QPair<int, int> fromOffset(const QString &offset);
|
||||
|
||||
private:
|
||||
static const QChar kColon;
|
||||
|
||||
const int m_startPos;
|
||||
const int m_endPos;
|
||||
};
|
||||
@@ -100,8 +110,12 @@ public:
|
||||
MagicStringRule(const QString &s, int startPos, int endPos);
|
||||
virtual ~MagicStringRule();
|
||||
|
||||
virtual QString matchType() const;
|
||||
virtual QString matchValue() const;
|
||||
virtual bool matches(const QByteArray &data) const;
|
||||
|
||||
static const QString kMatchType;
|
||||
|
||||
private:
|
||||
const QByteArray m_pattern;
|
||||
};
|
||||
@@ -112,11 +126,17 @@ public:
|
||||
MagicByteRule(const QString &s, int startPos, int endPos);
|
||||
virtual ~MagicByteRule();
|
||||
|
||||
virtual QString matchType() const;
|
||||
virtual QString matchValue() const;
|
||||
virtual bool matches(const QByteArray &data) const;
|
||||
|
||||
static bool validateByteSequence(const QString &sequence, QList<int> *bytes = 0);
|
||||
|
||||
static const QString kMatchType;
|
||||
|
||||
private:
|
||||
QList<int> m_bytes;
|
||||
int m_bytesSize;
|
||||
QList<int> m_bytes;
|
||||
};
|
||||
|
||||
/* Utility class: A Magic matcher that checks a number of rules based on
|
||||
@@ -126,16 +146,23 @@ class CORE_EXPORT MagicRuleMatcher : public IMagicMatcher
|
||||
Q_DISABLE_COPY(MagicRuleMatcher)
|
||||
public:
|
||||
typedef QSharedPointer<MagicRule> MagicRuleSharedPointer;
|
||||
typedef QList<MagicRuleSharedPointer> MagicRuleList;
|
||||
|
||||
MagicRuleMatcher();
|
||||
|
||||
void add(const MagicRuleSharedPointer &rule);
|
||||
void add(const MagicRuleList &ruleList);
|
||||
MagicRuleList magicRules() const;
|
||||
|
||||
virtual bool matches(const QByteArray &data) const;
|
||||
|
||||
virtual int priority() const;
|
||||
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:
|
||||
typedef QList<MagicRuleSharedPointer> MagicRuleList;
|
||||
MagicRuleList m_list;
|
||||
int m_priority;
|
||||
};
|
||||
@@ -169,6 +196,9 @@ private:
|
||||
class CORE_EXPORT MimeType
|
||||
{
|
||||
public:
|
||||
typedef IMagicMatcher::IMagicMatcherList IMagicMatcherList;
|
||||
typedef IMagicMatcher::IMagicMatcherSharedPointer IMagicMatcherSharedPointer;
|
||||
|
||||
MimeType();
|
||||
MimeType(const MimeType&);
|
||||
MimeType &operator=(const MimeType&);
|
||||
@@ -200,9 +230,6 @@ public:
|
||||
|
||||
// Extension over standard mime data
|
||||
QStringList suffixes() const;
|
||||
void setSuffixes(const QStringList &);
|
||||
|
||||
// Extension over standard mime data
|
||||
QString preferredSuffix() const;
|
||||
bool setPreferredSuffix(const QString&);
|
||||
|
||||
@@ -216,12 +243,19 @@ public:
|
||||
// Return a filter string usable for a file dialog
|
||||
QString filterString() const;
|
||||
|
||||
// Add magic matcher
|
||||
void addMagicMatcher(const QSharedPointer<IMagicMatcher> &matcher);
|
||||
void addMagicMatcher(const IMagicMatcherSharedPointer &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);
|
||||
|
||||
static QString formatFilterString(const QString &description, const QList<MimeGlobPattern> &globs);
|
||||
static QString formatFilterString(const QString &description,
|
||||
const QList<MimeGlobPattern> &globs);
|
||||
|
||||
private:
|
||||
explicit MimeType(const MimeTypeData &d);
|
||||
@@ -243,8 +277,10 @@ class CORE_EXPORT MimeDatabase
|
||||
{
|
||||
Q_DISABLE_COPY(MimeDatabase)
|
||||
public:
|
||||
MimeDatabase();
|
||||
typedef IMagicMatcher::IMagicMatcherList IMagicMatcherList;
|
||||
typedef IMagicMatcher::IMagicMatcherSharedPointer IMagicMatcherSharedPointer;
|
||||
|
||||
MimeDatabase();
|
||||
~MimeDatabase();
|
||||
|
||||
bool addMimeTypes(const QString &fileName, QString *errorMessage);
|
||||
@@ -256,6 +292,7 @@ public:
|
||||
|
||||
// Returns a mime type or Null one if none found
|
||||
MimeType findByFile(const QFileInfo &f) const;
|
||||
|
||||
// Convenience that mutex-locks the DB and calls a function
|
||||
// of the signature 'void f(const MimeType &, const QFileInfo &, const QString &)'
|
||||
// for each filename of a sequence. This avoids locking the DB for each
|
||||
@@ -263,20 +300,37 @@ public:
|
||||
template <class Iterator, typename Function>
|
||||
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
|
||||
QStringList suffixes() const;
|
||||
bool setPreferredSuffix(const QString &typeOrAlias, const QString &suffix);
|
||||
QString preferredSuffixByType(const QString &type) const;
|
||||
QString preferredSuffixByFile(const QFileInfo &f) 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);
|
||||
|
||||
// returns a string with all the possible file filters, for use with file dialogs
|
||||
QString allFiltersString(QString *allFilesFilter = 0) const;
|
||||
private:
|
||||
MimeType findByFileUnlocked(const QFileInfo &f) const;
|
||||
|
||||
|
109
src/plugins/coreplugin/mimetypemagicdialog.cpp
Normal file
109
src/plugins/coreplugin/mimetypemagicdialog.cpp
Normal 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;
|
||||
}
|
83
src/plugins/coreplugin/mimetypemagicdialog.h
Normal file
83
src/plugins/coreplugin/mimetypemagicdialog.h
Normal 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
|
318
src/plugins/coreplugin/mimetypemagicdialog.ui
Normal file
318
src/plugins/coreplugin/mimetypemagicdialog.ui
Normal 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><i>Note: Wide range values might impact on Qt Creator's performance when opening files.</i></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>
|
605
src/plugins/coreplugin/mimetypesettings.cpp
Normal file
605
src/plugins/coreplugin/mimetypesettings.cpp
Normal 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 ¤t = *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 ¤t, 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 ¤t,
|
||||
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 ¤tMimeType = 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"
|
72
src/plugins/coreplugin/mimetypesettings.h
Normal file
72
src/plugins/coreplugin/mimetypesettings.h
Normal 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
|
169
src/plugins/coreplugin/mimetypesettingspage.ui
Normal file
169
src/plugins/coreplugin/mimetypesettingspage.ui
Normal 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>
|
@@ -1043,7 +1043,7 @@ void CodaGdbAdapter::startAdapter()
|
||||
m_codaSocketIODevice = codaSocket;
|
||||
} else {
|
||||
m_codaDevice = SymbianUtils::SymbianDeviceManager::instance()
|
||||
->getTcfPort(parameters.remoteChannel);
|
||||
->getCodaDevice(parameters.remoteChannel);
|
||||
bool ok = m_codaDevice && m_codaDevice->device()->isOpen();
|
||||
|
||||
if (!ok) {
|
||||
@@ -1233,7 +1233,7 @@ void CodaGdbAdapter::cleanup()
|
||||
// Ensure process is stopped after being suspended.
|
||||
sendRunControlTerminateCommand();
|
||||
disconnect(m_codaDevice.data(), 0, this, 0);
|
||||
SymbianUtils::SymbianDeviceManager::instance()->releaseTcfPort(m_codaDevice);
|
||||
SymbianUtils::SymbianDeviceManager::instance()->releaseCodaDevice(m_codaDevice);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -55,9 +55,9 @@ namespace Internal {
|
||||
void RegisterPostMortemAction::registerNow(const QVariant &value)
|
||||
{
|
||||
const bool boolValue = value.toBool();
|
||||
const QString debuggerExe = QCoreApplication::applicationDirPath() + QLatin1Char('/')
|
||||
+ debuggerApplicationFileC + QLatin1String(".exe");
|
||||
const std::wstring debuggerWString = QDir::toNativeSeparators(debuggerExe).toStdWString();
|
||||
const QString debuggerExe = QDir::toNativeSeparators(QCoreApplication::applicationDirPath() + QLatin1Char('/')
|
||||
+ debuggerApplicationFileC + QLatin1String(".exe"));
|
||||
const ushort *debuggerWString = debuggerExe.utf16();
|
||||
|
||||
CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE);
|
||||
SHELLEXECUTEINFO shExecInfo;
|
||||
@@ -65,7 +65,7 @@ void RegisterPostMortemAction::registerNow(const QVariant &value)
|
||||
shExecInfo.fMask = SEE_MASK_NOCLOSEPROCESS;
|
||||
shExecInfo.hwnd = NULL;
|
||||
shExecInfo.lpVerb = L"runas";
|
||||
shExecInfo.lpFile = debuggerWString.data();
|
||||
shExecInfo.lpFile = reinterpret_cast<LPCWSTR>(debuggerWString);
|
||||
shExecInfo.lpParameters = boolValue ? L"-register" : L"-unregister";
|
||||
shExecInfo.lpDirectory = NULL;
|
||||
shExecInfo.nShow = SW_SHOWNORMAL;
|
||||
|
@@ -3755,7 +3755,7 @@ void FakeVimHandler::Private::highlightMatches(const QString &needle0)
|
||||
QString needle = needle0;
|
||||
vimPatternToQtPattern(&needle, &flags);
|
||||
QRegExp needleExp(needle);
|
||||
while (1) {
|
||||
while (!tc.atEnd()) {
|
||||
tc = tc.document()->find(needleExp, tc.position(), flags);
|
||||
if (tc.isNull())
|
||||
break;
|
||||
|
@@ -117,7 +117,7 @@ bool CodaRunControl::setupLauncher()
|
||||
if (m_serialPort.length()) {
|
||||
// We get the port from SymbianDeviceManager
|
||||
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();
|
||||
if (!ok) {
|
||||
@@ -333,7 +333,7 @@ void CodaRunControl::finishRunControl()
|
||||
m_runningProcessId.clear();
|
||||
if (m_codaDevice) {
|
||||
disconnect(m_codaDevice.data(), 0, this, 0);
|
||||
SymbianUtils::SymbianDeviceManager::instance()->releaseTcfPort(m_codaDevice);
|
||||
SymbianUtils::SymbianDeviceManager::instance()->releaseCodaDevice(m_codaDevice);
|
||||
}
|
||||
m_state = StateUninit;
|
||||
emit finished();
|
||||
@@ -344,7 +344,7 @@ QMessageBox *CodaRunControl::createCodaWaitingMessageBox(QWidget *parent)
|
||||
const QString title = tr("Waiting for CODA");
|
||||
const QString text = tr("Qt Creator is waiting for the CODA application to connect.<br>"
|
||||
"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.");
|
||||
QMessageBox *mb = new QMessageBox(QMessageBox::Information, title, text, QMessageBox::Cancel, parent);
|
||||
return mb;
|
||||
|
@@ -357,7 +357,10 @@ char S60DeployConfiguration::installationDrive() const
|
||||
|
||||
void S60DeployConfiguration::setInstallationDrive(char drive)
|
||||
{
|
||||
if (m_installationDrive == drive)
|
||||
return;
|
||||
m_installationDrive = drive;
|
||||
emit installationDriveChanged();
|
||||
}
|
||||
|
||||
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(QObject *parent) :
|
||||
|
@@ -63,6 +63,8 @@ public:
|
||||
CommunicationCodaTcpConnection
|
||||
};
|
||||
|
||||
typedef QPair<char, int> DeviceDrive;
|
||||
|
||||
explicit S60DeployConfiguration(ProjectExplorer::Target *parent);
|
||||
virtual ~S60DeployConfiguration();
|
||||
|
||||
@@ -92,6 +94,9 @@ public:
|
||||
void setCommunicationChannel(CommunicationChannel channel);
|
||||
S60DeployConfiguration::CommunicationChannel communicationChannel() const;
|
||||
|
||||
void setAvailableDeviceDrives(QList<DeviceDrive> drives);
|
||||
const QList<DeviceDrive> &availableDeviceDrives() const;
|
||||
|
||||
QStringList signedPackages() const;
|
||||
QStringList packageFileNamesWithTargetInfo() const;
|
||||
QStringList packageTemplateFileNames() const;
|
||||
@@ -107,6 +112,8 @@ signals:
|
||||
void communicationChannelChanged();
|
||||
void deviceAddressChanged();
|
||||
void devicePortChanged();
|
||||
void availableDeviceDrivesChanged();
|
||||
void installationDriveChanged();
|
||||
|
||||
private slots:
|
||||
void updateActiveBuildConfiguration(ProjectExplorer::BuildConfiguration *buildConfiguration);
|
||||
@@ -134,6 +141,8 @@ private:
|
||||
QString m_deviceAddress;
|
||||
QString m_devicePort;
|
||||
CommunicationChannel m_communicationChannel;
|
||||
|
||||
QList<DeviceDrive> m_availableDeviceDrives;
|
||||
};
|
||||
|
||||
class S60DeployConfigurationFactory : public ProjectExplorer::DeployConfigurationFactory
|
||||
|
@@ -41,6 +41,7 @@
|
||||
#include <symbianutils/launcher.h>
|
||||
#include <symbianutils/bluetoothlistener.h>
|
||||
#include <symbianutils/symbiandevicemanager.h>
|
||||
#include <codadevice.h>
|
||||
|
||||
#include "trkruncontrol.h"
|
||||
|
||||
@@ -74,6 +75,51 @@ namespace Internal {
|
||||
const char STARTING_DRIVE_LETTER = 'C';
|
||||
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)
|
||||
: ProjectExplorer::DeployConfigurationWidget(parent),
|
||||
m_detailsWidget(new Utils::DetailsWidget),
|
||||
@@ -178,6 +224,7 @@ void S60DeployConfigurationWidget::init(ProjectExplorer::DeployConfiguration *dc
|
||||
QHBoxLayout *infoHBoxLayout = new QHBoxLayout;
|
||||
m_deviceInfoLabel->setWordWrap(true);
|
||||
m_deviceInfoLabel->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Preferred);
|
||||
m_deviceInfoLabel->setTextInteractionFlags(Qt::TextBrowserInteraction);
|
||||
infoHBoxLayout->addWidget(m_deviceInfoLabel);
|
||||
infoHBoxLayout->addWidget(m_deviceInfoButton);
|
||||
m_deviceInfoButton->setIcon(qApp->style()->standardIcon(QStyle::SP_MessageBoxInformation));
|
||||
@@ -187,6 +234,8 @@ void S60DeployConfigurationWidget::init(ProjectExplorer::DeployConfiguration *dc
|
||||
updateTargetInformation();
|
||||
connect(m_deployConfiguration, SIGNAL(targetInformationChanged()),
|
||||
this, SLOT(updateTargetInformation()));
|
||||
connect(m_deployConfiguration, SIGNAL(availableDeviceDrivesChanged()),
|
||||
this, SLOT(updateInstallationDrives()));
|
||||
}
|
||||
|
||||
QWidget *S60DeployConfigurationWidget::createCommunicationChannel()
|
||||
@@ -240,14 +289,28 @@ QWidget *S60DeployConfigurationWidget::createCommunicationChannel()
|
||||
void S60DeployConfigurationWidget::updateInstallationDrives()
|
||||
{
|
||||
m_installationDriveCombo->clear();
|
||||
const QList<S60DeployConfiguration::DeviceDrive> &availableDrives(m_deployConfiguration->availableDeviceDrives());
|
||||
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)), qVariantFromValue(i));
|
||||
m_installationDriveCombo->addItem(QString("%1:").arg(static_cast<char>(i)), QChar(i));
|
||||
}
|
||||
int index = QChar::toUpper(static_cast<ushort>(m_deployConfiguration->installationDrive())) - STARTING_DRIVE_LETTER;
|
||||
|
||||
Q_ASSERT(index >= 0 && index <= LAST_DRIVE_LETTER-STARTING_DRIVE_LETTER);
|
||||
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;
|
||||
}
|
||||
}
|
||||
QTC_ASSERT(index >= 0 && index <= m_installationDriveCombo->count(), return);
|
||||
|
||||
m_installationDriveCombo->setCurrentIndex(index);
|
||||
setInstallationDrive(index);
|
||||
}
|
||||
|
||||
void S60DeployConfigurationWidget::silentInstallChanged(int state)
|
||||
@@ -280,7 +343,8 @@ void S60DeployConfigurationWidget::updateSerialDevices()
|
||||
const QString newPortName = device(newIndex).portName();
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -309,7 +373,11 @@ void S60DeployConfigurationWidget::updateTargetInformation()
|
||||
|
||||
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)
|
||||
@@ -425,9 +493,9 @@ void S60DeployConfigurationWidget::slotWaitingForTrkClosed()
|
||||
|
||||
void S60DeployConfigurationWidget::updateDeviceInfo()
|
||||
{
|
||||
//TODO: No CODA device info! Implement it when it is available
|
||||
if (m_deployConfiguration->communicationChannel() == S60DeployConfiguration::CommunicationTrkSerialConnection) {
|
||||
QTC_ASSERT(!m_infoLauncher, return)
|
||||
|
||||
setDeviceInfoLabel(tr("Connecting..."));
|
||||
// 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.
|
||||
@@ -466,9 +534,185 @@ void S60DeployConfigurationWidget::updateDeviceInfo()
|
||||
}
|
||||
// Wait for either timeout or results
|
||||
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
|
||||
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 Qt4ProjectManager
|
||||
|
@@ -61,6 +61,11 @@ namespace SymbianUtils {
|
||||
class SymbianDevice;
|
||||
}
|
||||
|
||||
namespace Coda {
|
||||
class CodaDevice;
|
||||
struct CodaCommandResult;
|
||||
}
|
||||
|
||||
namespace Qt4ProjectManager {
|
||||
namespace Internal {
|
||||
|
||||
@@ -102,6 +107,11 @@ private:
|
||||
|
||||
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;
|
||||
Utils::DetailsWidget *m_detailsWidget;
|
||||
QComboBox *m_serialPortsCombo;
|
||||
@@ -117,6 +127,7 @@ private:
|
||||
Utils::IpAddressLineEdit *m_ipAddress;
|
||||
QRadioButton *m_trkRadioButton;
|
||||
QRadioButton *m_codaRadioButton;
|
||||
QSharedPointer<Coda::CodaDevice> m_codaInfoDevice;
|
||||
};
|
||||
|
||||
} // namespace Internal
|
||||
|
@@ -317,7 +317,7 @@ void S60DeployStep::stop()
|
||||
} else {
|
||||
if (m_codaDevice) {
|
||||
disconnect(m_codaDevice.data(), 0, this, 0);
|
||||
SymbianUtils::SymbianDeviceManager::instance()->releaseTcfPort(m_codaDevice);
|
||||
SymbianUtils::SymbianDeviceManager::instance()->releaseCodaDevice(m_codaDevice);
|
||||
}
|
||||
}
|
||||
emit finished(false);
|
||||
@@ -384,7 +384,7 @@ void S60DeployStep::startDeployment()
|
||||
}
|
||||
} else if (m_channel == S60DeployConfiguration::CommunicationCodaSerialConnection) {
|
||||
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();
|
||||
if (!ok) {
|
||||
QString deviceError = tr("No such port");
|
||||
@@ -442,7 +442,7 @@ void S60DeployStep::run(QFutureInterface<bool> &fi)
|
||||
|
||||
if (m_codaDevice) {
|
||||
disconnect(m_codaDevice.data(), 0, this, 0);
|
||||
SymbianUtils::SymbianDeviceManager::instance()->releaseTcfPort(m_codaDevice);
|
||||
SymbianUtils::SymbianDeviceManager::instance()->releaseCodaDevice(m_codaDevice);
|
||||
}
|
||||
|
||||
delete m_eventLoop;
|
||||
|
@@ -184,6 +184,11 @@ void Manager::gatherDefinitionsMimeTypes(QFutureInterface<Core::MimeType> &futur
|
||||
Core::MimeDatabase *mimeDatabase = Core::ICore::instance()->mimeDatabase();
|
||||
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) {
|
||||
if (path.isEmpty())
|
||||
continue;
|
||||
@@ -227,6 +232,16 @@ void Manager::gatherDefinitionsMimeTypes(QFutureInterface<Core::MimeType> &futur
|
||||
m_idByMimeType.insert(type, id);
|
||||
Core::MimeType mimeType = mimeDatabase->findByType(type);
|
||||
if (mimeType.isNull()) {
|
||||
mimeType.setType(type);
|
||||
mimeType.setSubClassesOf(textPlain);
|
||||
mimeType.setComment(metaData->name());
|
||||
|
||||
// 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("*.");
|
||||
@@ -241,11 +256,11 @@ void Manager::gatherDefinitionsMimeTypes(QFutureInterface<Core::MimeType> &futur
|
||||
globPatterns.append(Core::MimeGlobPattern(regExp, 50));
|
||||
}
|
||||
}
|
||||
|
||||
mimeType.setType(type);
|
||||
mimeType.setSubClassesOf(textPlain);
|
||||
mimeType.setComment(metaData->name());
|
||||
mimeType.setGlobPatterns(globPatterns);
|
||||
} else {
|
||||
mimeType.setGlobPatterns(it.value().globPatterns());
|
||||
mimeType.setMagicRuleMatchers(it.value().magicRuleMatchers());
|
||||
}
|
||||
|
||||
mimeDatabase->addMimeType(mimeType);
|
||||
future.reportResult(mimeType);
|
||||
@@ -275,6 +290,8 @@ void Manager::registerMimeTypesFinished()
|
||||
QSharedPointer<HighlightDefinitionMetaData> Manager::parseMetadata(const QFileInfo &fileInfo)
|
||||
{
|
||||
static const QLatin1Char kSemiColon(';');
|
||||
static const QLatin1Char kSpace(' ');
|
||||
static const QLatin1Char kDash('-');
|
||||
static const QLatin1String kLanguage("language");
|
||||
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
|
||||
// patterns. Creating an artificial MIME type is a workaround.
|
||||
QString artificialType(kArtificial);
|
||||
artificialType.append(metaData->name());
|
||||
artificialType.append(metaData->name().trimmed().replace(kSpace, kDash));
|
||||
mimeTypes.append(artificialType);
|
||||
}
|
||||
metaData->setMimeTypes(mimeTypes);
|
||||
|
@@ -936,8 +936,6 @@ void CodaDevice::sendProcessStartCommand(const CodaCallback &callBack,
|
||||
const QString sysBin = QLatin1String("c:/sys/bin");
|
||||
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())
|
||||
workingDirectory = sysBin;
|
||||
|
||||
@@ -968,6 +966,20 @@ void CodaDevice::sendProcessStartCommand(const CodaCallback &callBack,
|
||||
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()
|
||||
{
|
||||
|
||||
@@ -1302,8 +1314,7 @@ void CodaDevice::sendRegistersSetCommand(const CodaCallback &callBack,
|
||||
value, cookie);
|
||||
}
|
||||
|
||||
//static const char outputListenerIDC[] = "org.eclipse.cdt.debug.edc.ui.ProgramOutputConsoleLogger";
|
||||
static const char outputListenerIDC[] = "ProgramOutputConsoleLogger"; //TODO: this one might be the correct one
|
||||
static const char outputListenerIDC[] = "ProgramOutputConsoleLogger";
|
||||
|
||||
void CodaDevice::sendLoggingAddListenerCommand(const CodaCallback &callBack,
|
||||
const QVariant &cookie)
|
||||
@@ -1332,6 +1343,34 @@ void CodaDevice::sendSymbianOsDataFindProcessesCommand(const CodaCallback &callB
|
||||
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,
|
||||
const QByteArray &name,
|
||||
unsigned flags,
|
||||
@@ -1395,4 +1434,24 @@ void Coda::CodaDevice::sendSymbianInstallUIInstallCommand(const Coda::CodaCallba
|
||||
str << file;
|
||||
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
|
||||
|
@@ -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
|
||||
* 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:
|
||||
* - Commands are accepted only after receiving the Locator Hello event
|
||||
* - Serial communication initiation sequence:
|
||||
@@ -213,6 +208,12 @@ public:
|
||||
const QStringList &additionalLibraries = QStringList(),
|
||||
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.
|
||||
void sendRunControlTerminateCommand(const CodaCallback &callBack,
|
||||
const QByteArray &id,
|
||||
@@ -345,6 +346,10 @@ public:
|
||||
const QByteArray &file,
|
||||
const QVariant &cookie = QVariant());
|
||||
|
||||
void sendSymbianInstallGetPackageInfoCommand(const Coda::CodaCallback &callBack,
|
||||
const QList<quint32> &packages,
|
||||
const QVariant &cookie = QVariant());
|
||||
|
||||
void sendLoggingAddListenerCommand(const CodaCallback &callBack,
|
||||
const QVariant &cookie = QVariant());
|
||||
|
||||
@@ -357,6 +362,16 @@ public:
|
||||
const QByteArray &uid,
|
||||
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
|
||||
void sendSettingsEnableLogCommand();
|
||||
|
||||
|
@@ -41,6 +41,7 @@
|
||||
#include <QtCore/QTextStream>
|
||||
#include <QtCore/QDebug>
|
||||
#include <QtCore/QStringList>
|
||||
#include <QtCore/QVariant>
|
||||
|
||||
#include <ctype.h>
|
||||
|
||||
@@ -415,6 +416,45 @@ QByteArray JsonValue::toString(bool multiline, int indent) const
|
||||
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)
|
||||
{
|
||||
const char *from = ba.constBegin();
|
||||
|
@@ -87,6 +87,8 @@ public:
|
||||
void fromString(const QByteArray &str);
|
||||
void setStreamOutput(const QByteArray &name, const QByteArray &content);
|
||||
|
||||
QVariant toVariant() const;
|
||||
|
||||
private:
|
||||
static QByteArray parseCString(const char *&from, const char *to);
|
||||
static QByteArray parseNumber(const char *&from, const char *to);
|
||||
|
@@ -355,7 +355,7 @@ SymbianDeviceManager::TrkDevicePtr
|
||||
return rc;
|
||||
}
|
||||
|
||||
CodaDevicePtr SymbianDeviceManager::getTcfPort(const QString &port)
|
||||
CodaDevicePtr SymbianDeviceManager::getCodaDevice(const QString &port)
|
||||
{
|
||||
ensureInitialized();
|
||||
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) {
|
||||
// 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;
|
||||
}
|
||||
|
||||
} // 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
|
||||
|
@@ -36,7 +36,7 @@
|
||||
|
||||
#include "symbianutils_global.h"
|
||||
|
||||
#include <QtCore/QObject>
|
||||
#include <QtCore/QIODevice>
|
||||
#include <QtCore/QExplicitlySharedDataPointer>
|
||||
#include <QtCore/QSharedPointer>
|
||||
|
||||
@@ -56,6 +56,7 @@ namespace SymbianUtils {
|
||||
|
||||
struct SymbianDeviceManagerPrivate;
|
||||
class SymbianDeviceData;
|
||||
class OstChannel;
|
||||
|
||||
enum DeviceCommunicationType {
|
||||
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.
|
||||
// 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.
|
||||
// Caller should call releaseTcfPort if they want the port to auto-close itself
|
||||
CodaDevicePtr getTcfPort(const QString &port);
|
||||
// Caller should call releaseCodaDevice if they want the port to auto-close itself
|
||||
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.
|
||||
void releaseTcfPort(CodaDevicePtr &aPort);
|
||||
void releaseCodaDevice(CodaDevicePtr &aPort);
|
||||
|
||||
int findByPortName(const QString &p) const;
|
||||
QString friendlyNameForPort(const QString &port) const;
|
||||
@@ -188,6 +193,38 @@ private:
|
||||
|
||||
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
|
||||
|
||||
#endif // SYMBIANDEVICEMANAGER_H
|
||||
|
Reference in New Issue
Block a user