diff options
author | Leandro Melo <leandro.melo@nokia.com> | 2010-10-27 17:38:22 +0200 |
---|---|---|
committer | Leandro Melo <leandro.melo@nokia.com> | 2010-12-08 17:22:07 +0100 |
commit | 7528c6d617c60acfdc2d82e2a7f8d1ec2de87a02 (patch) | |
tree | 48a2dc39d8653aa8653998f6513fd06d183e7097 /src/plugins | |
parent | 27bab4e811bf5a3fd476738c35769573cd7b5ef3 (diff) | |
download | qt-creator-7528c6d617c60acfdc2d82e2a7f8d1ec2de87a02.tar.gz |
Snippets: Feature enhancement start...
Provide an interface so users can create/edit/remove snippets.
Diffstat (limited to 'src/plugins')
41 files changed, 2569 insertions, 224 deletions
diff --git a/src/plugins/cppeditor/cppeditor.cpp b/src/plugins/cppeditor/cppeditor.cpp index b132895f06..10672b0e8d 100644 --- a/src/plugins/cppeditor/cppeditor.cpp +++ b/src/plugins/cppeditor/cppeditor.cpp @@ -1735,22 +1735,7 @@ void CPPEditor::setFontSettings(const TextEditor::FontSettings &fs) if (!highlighter) return; - static QVector<QString> categories; - if (categories.isEmpty()) { - categories << QLatin1String(TextEditor::Constants::C_NUMBER) - << QLatin1String(TextEditor::Constants::C_STRING) - << QLatin1String(TextEditor::Constants::C_TYPE) - << QLatin1String(TextEditor::Constants::C_KEYWORD) - << QLatin1String(TextEditor::Constants::C_OPERATOR) - << QLatin1String(TextEditor::Constants::C_PREPROCESSOR) - << QLatin1String(TextEditor::Constants::C_LABEL) - << QLatin1String(TextEditor::Constants::C_COMMENT) - << QLatin1String(TextEditor::Constants::C_DOXYGEN_COMMENT) - << QLatin1String(TextEditor::Constants::C_DOXYGEN_TAG) - << QLatin1String(TextEditor::Constants::C_VISUAL_WHITESPACE); - } - - const QVector<QTextCharFormat> formats = fs.toTextCharFormats(categories); + const QVector<QTextCharFormat> formats = fs.toTextCharFormats(highlighterFormatCategories()); highlighter->setFormats(formats.constBegin(), formats.constEnd()); m_occurrencesFormat = fs.toTextCharFormat(QLatin1String(TextEditor::Constants::C_OCCURRENCES)); @@ -2175,4 +2160,23 @@ QModelIndex CPPEditor::indexForPosition(int line, int column, const QModelIndex return lastIndex; } +QVector<QString> CPPEditor::highlighterFormatCategories() +{ + static QVector<QString> categories; + if (categories.isEmpty()) { + categories << QLatin1String(TextEditor::Constants::C_NUMBER) + << QLatin1String(TextEditor::Constants::C_STRING) + << QLatin1String(TextEditor::Constants::C_TYPE) + << QLatin1String(TextEditor::Constants::C_KEYWORD) + << QLatin1String(TextEditor::Constants::C_OPERATOR) + << QLatin1String(TextEditor::Constants::C_PREPROCESSOR) + << QLatin1String(TextEditor::Constants::C_LABEL) + << QLatin1String(TextEditor::Constants::C_COMMENT) + << QLatin1String(TextEditor::Constants::C_DOXYGEN_COMMENT) + << QLatin1String(TextEditor::Constants::C_DOXYGEN_TAG) + << QLatin1String(TextEditor::Constants::C_VISUAL_WHITESPACE); + } + return categories; +} + #include "cppeditor.moc" diff --git a/src/plugins/cppeditor/cppeditor.h b/src/plugins/cppeditor/cppeditor.h index a781e57362..ed0708132b 100644 --- a/src/plugins/cppeditor/cppeditor.h +++ b/src/plugins/cppeditor/cppeditor.h @@ -43,6 +43,7 @@ #include <QtCore/QWaitCondition> #include <QtCore/QFutureWatcher> #include <QtCore/QModelIndex> +#include <QtCore/QVector> QT_BEGIN_NAMESPACE class QComboBox; @@ -184,6 +185,8 @@ public: static Link linkToSymbol(CPlusPlus::Symbol *symbol); + static QVector<QString> highlighterFormatCategories(); + Q_SIGNALS: void outlineModelIndexChanged(const QModelIndex &index); diff --git a/src/plugins/cppeditor/cppeditor.pro b/src/plugins/cppeditor/cppeditor.pro index 0e6aa03ffd..a9bd9296ff 100644 --- a/src/plugins/cppeditor/cppeditor.pro +++ b/src/plugins/cppeditor/cppeditor.pro @@ -25,7 +25,9 @@ HEADERS += cppplugin.h \ cppquickfixcollector.h \ cppqtstyleindenter.h \ cppautocompleter.h \ - cppcompleteswitch.h + cppcompleteswitch.h \ + cppsnippeteditordecorator.h + SOURCES += cppplugin.cpp \ cppeditor.cpp \ cpphighlighter.cpp \ @@ -44,6 +46,8 @@ SOURCES += cppplugin.cpp \ cppquickfixcollector.cpp \ cppqtstyleindenter.cpp \ cppautocompleter.cpp \ - cppcompleteswitch.cpp + cppcompleteswitch.cpp \ + cppsnippeteditordecorator.cpp + RESOURCES += cppeditor.qrc OTHER_FILES += CppEditor.mimetypes.xml diff --git a/src/plugins/cppeditor/cppplugin.cpp b/src/plugins/cppeditor/cppplugin.cpp index c5923c3b18..a33a151aee 100644 --- a/src/plugins/cppeditor/cppplugin.cpp +++ b/src/plugins/cppeditor/cppplugin.cpp @@ -38,6 +38,7 @@ #include "cppoutline.h" #include "cppquickfixcollector.h" #include "cpptypehierarchy.h" +#include "cppsnippeteditordecorator.h" #include <coreplugin/icore.h> #include <coreplugin/coreconstants.h> @@ -211,6 +212,7 @@ bool CppPlugin::initialize(const QStringList & /*arguments*/, QString *errorMess addAutoReleasedObject(new CppHoverHandler); addAutoReleasedObject(new CppOutlineWidgetFactory); addAutoReleasedObject(new CppTypeHierarchyFactory); + addAutoReleasedObject(new CppSnippetEditorDecorator); m_quickFixCollector = new CppQuickFixCollector; addAutoReleasedObject(m_quickFixCollector); diff --git a/src/plugins/cppeditor/cppsnippeteditordecorator.cpp b/src/plugins/cppeditor/cppsnippeteditordecorator.cpp new file mode 100644 index 0000000000..2cf2936a02 --- /dev/null +++ b/src/plugins/cppeditor/cppsnippeteditordecorator.cpp @@ -0,0 +1,64 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** Commercial Usage +** +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://qt.nokia.com/contact. +** +**************************************************************************/ + +#include "cppsnippeteditordecorator.h" +#include "cpphighlighter.h" +#include "cppeditor.h" + +#include <texteditor/texteditorsettings.h> +#include <texteditor/fontsettings.h> +#include <texteditor/texteditorconstants.h> +#include <texteditor/snippets/snippeteditor.h> + +using namespace CppEditor; +using namespace Internal; + +CppSnippetEditorDecorator::CppSnippetEditorDecorator() : + TextEditor::ISnippetEditorDecorator() +{} + +CppSnippetEditorDecorator::~CppSnippetEditorDecorator() +{} + +bool CppSnippetEditorDecorator::supports(TextEditor::Snippet::Group group) const +{ + if (group == TextEditor::Snippet::Cpp) + return true; + return false; +} + +void CppSnippetEditorDecorator::apply(TextEditor::SnippetEditor *editor) const +{ + CppHighlighter *highlighter = new CppHighlighter; + const TextEditor::FontSettings &fs = TextEditor::TextEditorSettings::instance()->fontSettings(); + const QVector<QTextCharFormat> &formats = + fs.toTextCharFormats(CPPEditor::highlighterFormatCategories()); + highlighter->setFormats(formats.constBegin(), formats.constEnd()); + editor->installSyntaxHighlighter(highlighter); +} diff --git a/src/plugins/cppeditor/cppsnippeteditordecorator.h b/src/plugins/cppeditor/cppsnippeteditordecorator.h new file mode 100644 index 0000000000..605099e19c --- /dev/null +++ b/src/plugins/cppeditor/cppsnippeteditordecorator.h @@ -0,0 +1,52 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** Commercial Usage +** +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://qt.nokia.com/contact. +** +**************************************************************************/ + +#ifndef CPPSNIPPETEDITORDECORATOR_H +#define CPPSNIPPETEDITORDECORATOR_H + +#include <texteditor/snippets/isnippeteditordecorator.h> + +namespace CppEditor { +namespace Internal { + +class CppSnippetEditorDecorator : public TextEditor::ISnippetEditorDecorator +{ +public: + CppSnippetEditorDecorator(); + virtual ~CppSnippetEditorDecorator(); + +public: + virtual bool supports(TextEditor::Snippet::Group group) const; + virtual void apply(TextEditor::SnippetEditor *editor) const; +}; + +} // Internal +} // CppEditor + +#endif // CPPSNIPPETEDITORDECORATOR_H diff --git a/src/plugins/cpptools/cppcodecompletion.cpp b/src/plugins/cpptools/cppcodecompletion.cpp index 81636c71b6..479de433d1 100644 --- a/src/plugins/cpptools/cppcodecompletion.cpp +++ b/src/plugins/cpptools/cppcodecompletion.cpp @@ -59,6 +59,7 @@ #include <texteditor/itexteditor.h> #include <texteditor/itexteditable.h> #include <texteditor/basetexteditor.h> +#include <texteditor/snippets/snippet.h> #include <projectexplorer/projectexplorer.h> #include <utils/faketooltip.h> @@ -462,7 +463,8 @@ CppCodeCompletion::CppCodeCompletion(CppModelManager *manager) m_automaticCompletion(false), m_completionOperator(T_EOF_SYMBOL), m_objcEnabled(true), - m_snippetsParser(Core::ICore::instance()->resourcePath() + QLatin1String("/snippets/cpp.xml")) + m_snippetProvider(TextEditor::Snippet::Cpp, + QIcon(QLatin1String(":/texteditor/images/snippet.png"))) { } @@ -751,12 +753,12 @@ void CppCodeCompletion::completeObjCMsgSend(ClassOrNamespace *binding, Symbol *arg = method->argumentAt(i); text += selectorName->nameAt(i)->identifier()->chars(); text += QLatin1Char(':'); - text += QChar::ObjectReplacementCharacter; + text += TextEditor::Snippet::kVariableDelimiter; text += QLatin1Char('('); text += oo(arg->type()); text += QLatin1Char(')'); text += oo(arg->name()); - text += QChar::ObjectReplacementCharacter; + text += TextEditor::Snippet::kVariableDelimiter; } } else { text = selectorName->identifier()->chars(); @@ -2058,8 +2060,7 @@ bool CppCodeCompletion::objcKeywordsWanted() const void CppCodeCompletion::addSnippets() { - static const QIcon icon(QLatin1String(":/texteditor/images/snippet.png")); - m_completions.append(m_snippetsParser.execute(this, icon)); + m_completions.append(m_snippetProvider.getSnippets(this)); } #include "cppcodecompletion.moc" diff --git a/src/plugins/cpptools/cppcodecompletion.h b/src/plugins/cpptools/cppcodecompletion.h index 49317eb096..483bf3358b 100644 --- a/src/plugins/cpptools/cppcodecompletion.h +++ b/src/plugins/cpptools/cppcodecompletion.h @@ -37,7 +37,7 @@ #include <cplusplus/TypeOfExpression.h> #include <texteditor/icompletioncollector.h> -#include <texteditor/snippetsparser.h> +#include <texteditor/snippets/snippetprovider.h> #include <QtCore/QObject> #include <QtCore/QPointer> @@ -153,7 +153,7 @@ private: unsigned m_completionOperator; bool m_objcEnabled; - TextEditor::SnippetsParser m_snippetsParser; + TextEditor::SnippetProvider m_snippetProvider; CPlusPlus::Icons m_icons; CPlusPlus::Overview overview; diff --git a/src/plugins/qmljseditor/qmljscodecompletion.cpp b/src/plugins/qmljseditor/qmljscodecompletion.cpp index 68e0ab28f6..8dc714dc80 100644 --- a/src/plugins/qmljseditor/qmljscodecompletion.cpp +++ b/src/plugins/qmljseditor/qmljscodecompletion.cpp @@ -487,7 +487,7 @@ CodeCompletion::CodeCompletion(ModelManagerInterface *modelManager, QObject *par m_editor(0), m_startPosition(0), m_restartCompletion(false), - m_snippetsParser(Core::ICore::instance()->resourcePath() + QLatin1String("/snippets/qml.xml")) + m_snippetProvider(TextEditor::Snippet::Qml, iconForColor(Qt::red), SnippetOrder) { Q_ASSERT(modelManager); } @@ -952,7 +952,7 @@ int CodeCompletion::startCompletion(TextEditor::ITextEditable *editor) } if (isQmlFile && (completionOperator.isNull() || completionOperator.isSpace() || isDelimiter(completionOperator))) { - m_completions.append(m_snippetsParser.execute(this, iconForColor(Qt::red), SnippetOrder)); + m_completions.append(m_snippetProvider.getSnippets(this)); } if (! m_completions.isEmpty()) diff --git a/src/plugins/qmljseditor/qmljscodecompletion.h b/src/plugins/qmljseditor/qmljscodecompletion.h index 6aced15ca6..d3448c4c72 100644 --- a/src/plugins/qmljseditor/qmljscodecompletion.h +++ b/src/plugins/qmljseditor/qmljscodecompletion.h @@ -32,7 +32,7 @@ #include <qmljs/qmljsdocument.h> #include <texteditor/icompletioncollector.h> -#include <texteditor/snippetsparser.h> +#include <texteditor/snippets/snippetprovider.h> #include <QtCore/QDateTime> #include <QtCore/QPointer> @@ -97,7 +97,7 @@ private: TextEditor::ITextEditable *m_editor; int m_startPosition; bool m_restartCompletion; - TextEditor::SnippetsParser m_snippetsParser; + TextEditor::SnippetProvider m_snippetProvider; QList<TextEditor::CompletionItem> m_completions; QPointer<FunctionArgumentWidget> m_functionArgumentWidget; }; diff --git a/src/plugins/qmljseditor/qmljseditor.cpp b/src/plugins/qmljseditor/qmljseditor.cpp index d7e3d2add5..ba9392b336 100644 --- a/src/plugins/qmljseditor/qmljseditor.cpp +++ b/src/plugins/qmljseditor/qmljseditor.cpp @@ -1187,27 +1187,7 @@ void QmlJSTextEditor::setFontSettings(const TextEditor::FontSettings &fs) if (!highlighter) return; - /* - NumberFormat, - StringFormat, - TypeFormat, - KeywordFormat, - LabelFormat, - CommentFormat, - VisualWhitespace, - */ - static QVector<QString> categories; - if (categories.isEmpty()) { - categories << QLatin1String(TextEditor::Constants::C_NUMBER) - << QLatin1String(TextEditor::Constants::C_STRING) - << QLatin1String(TextEditor::Constants::C_TYPE) - << QLatin1String(TextEditor::Constants::C_KEYWORD) - << QLatin1String(TextEditor::Constants::C_FIELD) - << QLatin1String(TextEditor::Constants::C_COMMENT) - << QLatin1String(TextEditor::Constants::C_VISUAL_WHITESPACE); - } - - highlighter->setFormats(fs.toTextCharFormats(categories)); + highlighter->setFormats(fs.toTextCharFormats(highlighterFormatCategories())); highlighter->rehighlight(); m_occurrencesFormat = fs.toTextCharFormat(QLatin1String(TextEditor::Constants::C_OCCURRENCES)); @@ -1571,6 +1551,30 @@ bool QmlJSTextEditor::hideContextPane() return b; } +QVector<QString> QmlJSTextEditor::highlighterFormatCategories() +{ + /* + NumberFormat, + StringFormat, + TypeFormat, + KeywordFormat, + LabelFormat, + CommentFormat, + VisualWhitespace, + */ + static QVector<QString> categories; + if (categories.isEmpty()) { + categories << QLatin1String(TextEditor::Constants::C_NUMBER) + << QLatin1String(TextEditor::Constants::C_STRING) + << QLatin1String(TextEditor::Constants::C_TYPE) + << QLatin1String(TextEditor::Constants::C_KEYWORD) + << QLatin1String(TextEditor::Constants::C_FIELD) + << QLatin1String(TextEditor::Constants::C_COMMENT) + << QLatin1String(TextEditor::Constants::C_VISUAL_WHITESPACE); + } + return categories; +} + SemanticHighlighterSource QmlJSTextEditor::currentSource(bool force) { int line = 0, column = 0; diff --git a/src/plugins/qmljseditor/qmljseditor.h b/src/plugins/qmljseditor/qmljseditor.h index f40ce7e652..d0ac90101a 100644 --- a/src/plugins/qmljseditor/qmljseditor.h +++ b/src/plugins/qmljseditor/qmljseditor.h @@ -155,6 +155,8 @@ public: void renameId(const QString &oldId, const QString &newId); + static QVector<QString> highlighterFormatCategories(); + public slots: void followSymbolUnderCursor(); void findUsages(); diff --git a/src/plugins/qmljseditor/qmljseditor.pro b/src/plugins/qmljseditor/qmljseditor.pro index c237d122c6..24e6caf03d 100644 --- a/src/plugins/qmljseditor/qmljseditor.pro +++ b/src/plugins/qmljseditor/qmljseditor.pro @@ -34,7 +34,8 @@ HEADERS += \ qmljssemantichighlighter.h \ qmljsindenter.h \ qmljsautocompleter.h \ - jsfilewizard.h + jsfilewizard.h \ + qmljssnippeteditordecorator.h SOURCES += \ qmljscodecompletion.cpp \ @@ -62,7 +63,8 @@ SOURCES += \ qmljssemantichighlighter.cpp \ qmljsindenter.cpp \ qmljsautocompleter.cpp \ - jsfilewizard.cpp + jsfilewizard.cpp \ + qmljssnippeteditordecorator.cpp RESOURCES += qmljseditor.qrc OTHER_FILES += QmlJSEditor.mimetypes.xml diff --git a/src/plugins/qmljseditor/qmljseditorplugin.cpp b/src/plugins/qmljseditor/qmljseditorplugin.cpp index e03b1370a5..1d394e6201 100644 --- a/src/plugins/qmljseditor/qmljseditorplugin.cpp +++ b/src/plugins/qmljseditor/qmljseditorplugin.cpp @@ -39,6 +39,7 @@ #include "qmljsoutline.h" #include "qmljspreviewrunner.h" #include "qmljsquickfix.h" +#include "qmljssnippeteditordecorator.h" #include "qmltaskmanager.h" #include "quicktoolbar.h" #include "quicktoolbarsettingspage.h" @@ -128,6 +129,7 @@ bool QmlJSEditorPlugin::initialize(const QStringList & /*arguments*/, QString *e return false; m_modelManager = QmlJS::ModelManagerInterface::instance(); + addAutoReleasedObject(new QmlJSSnippetEditorDecorator); Core::Context context(QmlJSEditor::Constants::C_QMLJSEDITOR_ID); diff --git a/src/plugins/qmljseditor/qmljssnippeteditordecorator.cpp b/src/plugins/qmljseditor/qmljssnippeteditordecorator.cpp new file mode 100644 index 0000000000..f2ca0b07ca --- /dev/null +++ b/src/plugins/qmljseditor/qmljssnippeteditordecorator.cpp @@ -0,0 +1,62 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** Commercial Usage +** +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://qt.nokia.com/contact. +** +**************************************************************************/ + +#include "qmljssnippeteditordecorator.h" +#include "qmljshighlighter.h" +#include "qmljseditor.h" + +#include <texteditor/texteditorsettings.h> +#include <texteditor/fontsettings.h> +#include <texteditor/texteditorconstants.h> +#include <texteditor/snippets/snippeteditor.h> + +using namespace QmlJSEditor; +using namespace Internal; + +QmlJSSnippetEditorDecorator::QmlJSSnippetEditorDecorator() : + TextEditor::ISnippetEditorDecorator() +{} + +QmlJSSnippetEditorDecorator::~QmlJSSnippetEditorDecorator() +{} + +bool QmlJSSnippetEditorDecorator::supports(TextEditor::Snippet::Group group) const +{ + if (group == TextEditor::Snippet::Qml) + return true; + return false; +} + +void QmlJSSnippetEditorDecorator::apply(TextEditor::SnippetEditor *editor) const +{ + Highlighter *highlighter = new Highlighter; + const TextEditor::FontSettings &fs = TextEditor::TextEditorSettings::instance()->fontSettings(); + highlighter->setFormats(fs.toTextCharFormats(QmlJSTextEditor::highlighterFormatCategories())); + editor->installSyntaxHighlighter(highlighter); +} diff --git a/src/plugins/qmljseditor/qmljssnippeteditordecorator.h b/src/plugins/qmljseditor/qmljssnippeteditordecorator.h new file mode 100644 index 0000000000..d22a478564 --- /dev/null +++ b/src/plugins/qmljseditor/qmljssnippeteditordecorator.h @@ -0,0 +1,52 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** Commercial Usage +** +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://qt.nokia.com/contact. +** +**************************************************************************/ + +#ifndef QMLJSSNIPPETEDITORDECORATOR_H +#define QMLJSSNIPPETEDITORDECORATOR_H + +#include <texteditor/snippets/isnippeteditordecorator.h> + +namespace QmlJSEditor { +namespace Internal { + +class QmlJSSnippetEditorDecorator : public TextEditor::ISnippetEditorDecorator +{ +public: + QmlJSSnippetEditorDecorator(); + virtual ~QmlJSSnippetEditorDecorator(); + +public: + virtual bool supports(TextEditor::Snippet::Group group) const; + virtual void apply(TextEditor::SnippetEditor *editor) const; +}; + +} // Internal +} // QmlJSEditor + +#endif // QMLJSSNIPPETEDITORDECORATOR_H diff --git a/src/plugins/texteditor/basetexteditor.cpp b/src/plugins/texteditor/basetexteditor.cpp index 7fcea6ccda..d429277205 100644 --- a/src/plugins/texteditor/basetexteditor.cpp +++ b/src/plugins/texteditor/basetexteditor.cpp @@ -44,6 +44,7 @@ #include "tipcontents.h" #include "indenter.h" #include "autocompleter.h" +#include "snippet.h" #include <aggregation/aggregate.h> #include <coreplugin/actionmanager/actionmanager.h> @@ -1848,7 +1849,7 @@ void BaseTextEditor::_q_requestAutoCompletion() void BaseTextEditor::insertCodeSnippet(const QTextCursor &cursor_arg, const QString &snippet) { - if ((snippet.count('$') % 2) != 0) { + if ((snippet.count(Snippet::kVariableDelimiter) % 2) != 0) { qWarning() << "invalid snippet"; return; } @@ -1864,21 +1865,21 @@ void BaseTextEditor::insertCodeSnippet(const QTextCursor &cursor_arg, const QStr QMap<int, int> positions; while (pos < snippet.size()) { - if (snippet.at(pos) != QChar::ObjectReplacementCharacter) { + if (snippet.at(pos) != Snippet::kVariableDelimiter) { const int start = pos; do { ++pos; } - while (pos < snippet.size() && snippet.at(pos) != QChar::ObjectReplacementCharacter); + while (pos < snippet.size() && snippet.at(pos) != Snippet::kVariableDelimiter); cursor.insertText(snippet.mid(start, pos - start)); } else { // the start of a place holder. const int start = ++pos; for (; pos < snippet.size(); ++pos) { - if (snippet.at(pos) == QChar::ObjectReplacementCharacter) + if (snippet.at(pos) == Snippet::kVariableDelimiter) break; } Q_ASSERT(pos < snippet.size()); - Q_ASSERT(snippet.at(pos) == QChar::ObjectReplacementCharacter); + Q_ASSERT(snippet.at(pos) == Snippet::kVariableDelimiter); const QString textToInsert = snippet.mid(start, pos - start); diff --git a/src/plugins/texteditor/snippets/isnippeteditordecorator.cpp b/src/plugins/texteditor/snippets/isnippeteditordecorator.cpp new file mode 100644 index 0000000000..5c94c6ec65 --- /dev/null +++ b/src/plugins/texteditor/snippets/isnippeteditordecorator.cpp @@ -0,0 +1,38 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** Commercial Usage +** +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://qt.nokia.com/contact. +** +**************************************************************************/ + +#include "isnippeteditordecorator.h" + +using namespace TextEditor; + +ISnippetEditorDecorator::ISnippetEditorDecorator() : QObject() +{} + +ISnippetEditorDecorator::~ISnippetEditorDecorator() +{} diff --git a/src/plugins/texteditor/snippets/isnippeteditordecorator.h b/src/plugins/texteditor/snippets/isnippeteditordecorator.h new file mode 100644 index 0000000000..945461f308 --- /dev/null +++ b/src/plugins/texteditor/snippets/isnippeteditordecorator.h @@ -0,0 +1,58 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** Commercial Usage +** +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://qt.nokia.com/contact. +** +**************************************************************************/ + +#ifndef ISNIPPETEDITORDECORATOR_H +#define ISNIPPETEDITORDECORATOR_H + +#include "snippet.h" + +#include <texteditor/texteditor_global.h> + +#include <QtCore/QObject> + +namespace TextEditor { + +class SnippetEditor; + +class TEXTEDITOR_EXPORT ISnippetEditorDecorator : public QObject +{ + Q_OBJECT +public: + virtual ~ISnippetEditorDecorator(); + + virtual bool supports(Snippet::Group group) const = 0; + virtual void apply(SnippetEditor *editor) const = 0; + +protected: + ISnippetEditorDecorator(); +}; + +} // TextEditor + +#endif // ISNIPPETEDITORDECORATOR_H diff --git a/src/plugins/texteditor/snippets/reuse.h b/src/plugins/texteditor/snippets/reuse.h new file mode 100644 index 0000000000..5ab7b403ec --- /dev/null +++ b/src/plugins/texteditor/snippets/reuse.h @@ -0,0 +1,85 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** Commercial Usage +** +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://qt.nokia.com/contact. +** +**************************************************************************/ + +#ifndef REUSE_H +#define REUSE_H + +#include "snippet.h" + +#include <QtCore/QString> +#include <QtCore/QLatin1String> + +namespace TextEditor { +namespace Internal { + +const QLatin1String kCpp("C++"); +const QLatin1String kQml("QML"); +const QLatin1String kText("Text"); +const QLatin1String kTrue("true"); +const QLatin1String kFalse("false"); + +inline Snippet::Group toSnippetGroup(const QString &s) +{ + const QString &upper = s.toUpper(); + if (upper == kCpp) + return Snippet::Cpp; + else if (upper == kQml) + return Snippet::Qml; + else + return Snippet::PlainText; +} + +inline QString fromSnippetGroup(Snippet::Group group) +{ + if (group == Snippet::Cpp) + return kCpp; + else if (group == Snippet::Qml) + return kQml; + else + return kText; +} + +inline bool toBool(const QString &s) +{ + if (s == kTrue) + return true; + return false; +} + +inline QString fromBool(bool b) +{ + if (b) + return kTrue; + return kFalse; +} + +} // Internal +} // TextEditor + +#endif // REUSE_H diff --git a/src/plugins/texteditor/snippets/snippet.cpp b/src/plugins/texteditor/snippets/snippet.cpp new file mode 100644 index 0000000000..b00056110c --- /dev/null +++ b/src/plugins/texteditor/snippets/snippet.cpp @@ -0,0 +1,148 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** Commercial Usage +** +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://qt.nokia.com/contact. +** +**************************************************************************/ + +#include "snippet.h" + +#include <QtCore/QLatin1Char> +#include <QtCore/QLatin1String> +#include <QtGui/QTextDocument> + +using namespace TextEditor; + +const QChar Snippet::kVariableDelimiter(QLatin1Char('$')); + +Snippet::Snippet(const QString &id) : m_isRemoved(false), m_isModified(false), m_id(id) +{} + +Snippet::~Snippet() +{} + +const QString &Snippet::id() const +{ + return m_id; +} + +bool Snippet::isBuiltIn() const +{ + return !m_id.isEmpty(); +} + +void Snippet::setTrigger(const QString &trigger) +{ + m_trigger = trigger; +} + +const QString &Snippet::trigger() const +{ + return m_trigger; +} + +void Snippet::setContent(const QString &content) +{ + m_content = content; +} + +const QString &Snippet::content() const +{ + return m_content; +} + +void Snippet::setComplement(const QString &complement) +{ + m_complement = complement; +} + +const QString &Snippet::complement() const +{ + return m_complement; +} + +void Snippet::setIsRemoved(bool removed) +{ + m_isRemoved = removed; +} + +bool Snippet::isRemoved() const +{ + return m_isRemoved; +} + +void Snippet::setIsModified(bool modified) +{ + m_isModified = modified; +} + +bool Snippet::isModified() const +{ + return m_isModified; +} + +void Snippet::setGroup(Group group) +{ + m_group = group; +} + +Snippet::Group Snippet::group() const +{ + return m_group; +} + +QString Snippet::generateTip() const +{ + static const QLatin1Char kNewLine('\n'); + static const QLatin1Char kSpace(' '); + static const QLatin1String kBr("<br>"); + static const QLatin1String kNbsp(" "); + static const QLatin1String kNoBr("<nobr>"); + static const QLatin1String kOpenBold("<b>"); + static const QLatin1String kCloseBold("</b>"); + static const QLatin1String kEllipsis("..."); + + QString escapedContent(Qt::escape(m_content)); + escapedContent.replace(kNewLine, kBr); + escapedContent.replace(kSpace, kNbsp); + + QString tip(kNoBr); + int count = 0; + for (int i = 0; i < escapedContent.count(); ++i) { + if (escapedContent.at(i) != kVariableDelimiter) { + tip += escapedContent.at(i); + continue; + } + if (++count % 2) { + tip += kOpenBold; + } else { + if (escapedContent.at(i-1) == kVariableDelimiter) + tip += kEllipsis; + tip += kCloseBold; + } + } + + return tip; +} diff --git a/src/plugins/texteditor/snippets/snippet.h b/src/plugins/texteditor/snippets/snippet.h new file mode 100644 index 0000000000..d9d6c42245 --- /dev/null +++ b/src/plugins/texteditor/snippets/snippet.h @@ -0,0 +1,98 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** Commercial Usage +** +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://qt.nokia.com/contact. +** +**************************************************************************/ + +#ifndef SNIPPET_H +#define SNIPPET_H + +#include <texteditor/texteditor_global.h> + +#include <QtCore/QChar> +#include <QtCore/QString> + +namespace TextEditor { + +class TEXTEDITOR_EXPORT Snippet +{ +public: + Snippet(const QString &id = QString()); + ~Snippet(); + + // Values from this enumeration need to be contiguous (they are used as indexes). + enum Group { + Cpp = 0, + Qml, + PlainText, + GroupSize + }; + + const QString &id() const; + + bool isBuiltIn() const; + + void setTrigger(const QString &trigger); + const QString &trigger() const; + + void setContent(const QString &content); + const QString &content() const; + + void setComplement(const QString &complement); + const QString &complement() const; + + void setIsRemoved(bool removed); + bool isRemoved() const; + + void setIsModified(bool modified); + bool isModified() const; + + void setGroup(Group group); + Group group() const; + + QString generateTip() const; + + static const QChar kVariableDelimiter; + +private: + bool m_isRemoved; + bool m_isModified; + QString m_id; + QString m_trigger; + QString m_content; + QString m_complement; + Group m_group; +}; + +inline Snippet::Group& operator++(Snippet::Group& group) +{ + group = Snippet::Group(group + 1); + return group; +} + +} // TextEditor + +#endif // SNIPPET_H diff --git a/src/plugins/texteditor/snippets/snippeteditor.cpp b/src/plugins/texteditor/snippets/snippeteditor.cpp new file mode 100644 index 0000000000..cf40373bfe --- /dev/null +++ b/src/plugins/texteditor/snippets/snippeteditor.cpp @@ -0,0 +1,92 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** Commercial Usage +** +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://qt.nokia.com/contact. +** +**************************************************************************/ + +#include "snippeteditor.h" + +#include <texteditor/basetextdocument.h> +#include <texteditor/texteditorconstants.h> +#include <texteditor/normalindenter.h> + +#include <QtGui/QTextDocument> + +using namespace TextEditor; + +SnippetEditorEditable::SnippetEditorEditable(SnippetEditor *editor) : + BaseTextEditorEditable(editor), + m_context(Constants::SNIPPET_EDITOR_ID, Constants::C_TEXTEDITOR) +{} + +SnippetEditorEditable::~SnippetEditorEditable() +{} + +QString SnippetEditorEditable::id() const +{ + return Constants::SNIPPET_EDITOR_ID; +} + +SnippetEditor::SnippetEditor(QWidget *parent) : + BaseTextEditor(parent), + m_indenter(new NormalIndenter) +{ + setFrameStyle(QFrame::StyledPanel | QFrame::Sunken); + + setHighlightCurrentLine(false); + setLineNumbersVisible(false); +} + +SnippetEditor::~SnippetEditor() +{} + +void SnippetEditor::installSyntaxHighlighter(TextEditor::SyntaxHighlighter *highlighter) +{ + baseTextDocument()->setSyntaxHighlighter(highlighter); +} + +void SnippetEditor::installIndenter(Indenter *indenter) +{ + m_indenter.reset(indenter); +} + +void SnippetEditor::focusOutEvent(QFocusEvent *event) +{ + Q_UNUSED(event); + if (document()->isModified()) + emit snippetContentChanged(); +} + +BaseTextEditorEditable *SnippetEditor::createEditableInterface() +{ + return new SnippetEditorEditable(this); +} + +void SnippetEditor::indentBlock(QTextDocument *doc, QTextBlock block, QChar typedChar) +{ + if (!m_indenter.isNull()) + m_indenter->indentBlock(doc, block, typedChar, tabSettings()); +} diff --git a/src/plugins/texteditor/snippets/snippeteditor.h b/src/plugins/texteditor/snippets/snippeteditor.h new file mode 100644 index 0000000000..a4273f5e66 --- /dev/null +++ b/src/plugins/texteditor/snippets/snippeteditor.h @@ -0,0 +1,92 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** Commercial Usage +** +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://qt.nokia.com/contact. +** +**************************************************************************/ + +#ifndef SNIPPETEDITOR_H +#define SNIPPETEDITOR_H + +#include <texteditor/texteditor_global.h> +#include <texteditor/basetexteditor.h> + +#include <QtCore/QScopedPointer> + +QT_FORWARD_DECLARE_CLASS(QFocusEvent) + +namespace TextEditor { + +class SnippetEditor; +class SyntaxHighlighter; +class Indenter; + +// Should not be necessary in this case, but the base text editor assumes a +// valid editable interface. +class TEXTEDITOR_EXPORT SnippetEditorEditable : public BaseTextEditorEditable +{ + Q_OBJECT +public: + SnippetEditorEditable(SnippetEditor *editor); + virtual ~SnippetEditorEditable(); + + Core::Context context() const { return m_context; } + + bool duplicateSupported() const { return false; } + Core::IEditor *duplicate(QWidget * /* parent */ ) { return 0; } + bool isTemporary() const { return false; } + virtual QString id() const; + +private: + const Core::Context m_context; +}; + +class TEXTEDITOR_EXPORT SnippetEditor : public BaseTextEditor +{ + Q_OBJECT +public: + SnippetEditor(QWidget *parent); + virtual ~SnippetEditor(); + + void installSyntaxHighlighter(SyntaxHighlighter *highlighter); + void installIndenter(Indenter *indenter); + +signals: + void snippetContentChanged(); + +protected: + virtual void focusOutEvent(QFocusEvent *event); + + virtual int extraAreaWidth(int * /* markWidthPtr */ = 0) const { return 0; } + virtual BaseTextEditorEditable *createEditableInterface(); + virtual void indentBlock(QTextDocument *doc, QTextBlock block, QChar typedChar); + +private: + QScopedPointer<Indenter> m_indenter; +}; + +} // TextEditor + +#endif // SNIPPETEDITOR_H diff --git a/src/plugins/texteditor/snippets/snippetprovider.cpp b/src/plugins/texteditor/snippets/snippetprovider.cpp new file mode 100644 index 0000000000..26361d1989 --- /dev/null +++ b/src/plugins/texteditor/snippets/snippetprovider.cpp @@ -0,0 +1,62 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** Commercial Usage +** +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://qt.nokia.com/contact. +** +**************************************************************************/ + +#include "snippetprovider.h" +#include "snippetsmanager.h" +#include "snippetscollection.h" + +using namespace TextEditor; +using namespace Internal; + +SnippetProvider::SnippetProvider(Snippet::Group group, const QIcon &icon, int order) : + m_group(group), m_icon(icon), m_order(order) +{} + +SnippetProvider::~SnippetProvider() +{} + +QList<CompletionItem> SnippetProvider::getSnippets(ICompletionCollector *collector) const +{ + QList<CompletionItem> completionItems; + QSharedPointer<SnippetsCollection> collection = + SnippetsManager::instance()->snippetsCollection(); + const int size = collection->totalActiveSnippets(m_group); + for (int i = 0; i < size; ++i) { + const Snippet &snippet = collection->snippet(i, m_group); + CompletionItem item(collector); + item.text = snippet.trigger() + QLatin1Char(' ') + snippet.complement(); + item.data = snippet.content(); + item.details = snippet.generateTip(); + item.icon = m_icon; + item.order = m_order; + + completionItems.append(item); + } + return completionItems; +} diff --git a/src/plugins/texteditor/snippetsparser.h b/src/plugins/texteditor/snippets/snippetprovider.h index 90cb6c18cf..486ebcf165 100644 --- a/src/plugins/texteditor/snippetsparser.h +++ b/src/plugins/texteditor/snippets/snippetprovider.h @@ -27,34 +27,33 @@ ** **************************************************************************/ -#ifndef SNIPPETSPARSER_H -#define SNIPPETSPARSER_H +#ifndef SNIPPETPROVIDER_H +#define SNIPPETPROVIDER_H -#include "texteditor_global.h" -#include "icompletioncollector.h" +#include "snippet.h" + +#include <texteditor/texteditor_global.h> +#include <texteditor/icompletioncollector.h> -#include <QtCore/QString> #include <QtCore/QList> -#include <QtCore/QDateTime> #include <QtGui/QIcon> namespace TextEditor { -class TEXTEDITOR_EXPORT SnippetsParser +class TEXTEDITOR_EXPORT SnippetProvider { public: - SnippetsParser(const QString &fileName); + SnippetProvider(Snippet::Group group, const QIcon &icon, int order = 0); + ~SnippetProvider(); - const QList<CompletionItem> &execute(ICompletionCollector *collector, - const QIcon &icon, - int order = 0); + QList<CompletionItem> getSnippets(ICompletionCollector *collector) const; private: - QString m_fileName; - QDateTime m_lastTrackedFileChange; - QList<CompletionItem> m_snippets; + Snippet::Group m_group; + QIcon m_icon; + int m_order; }; -} // namespace TextEditor +} // TextEditor -#endif // SNIPPETSPARSER_H +#endif // SNIPPETPROVIDER_H diff --git a/src/plugins/texteditor/snippets/snippets.xml b/src/plugins/texteditor/snippets/snippets.xml new file mode 100644 index 0000000000..0d511a8d41 --- /dev/null +++ b/src/plugins/texteditor/snippets/snippets.xml @@ -0,0 +1,120 @@ +<?xml version="1.0" encoding="utf-8"?> +<snippets> +<snippet group="C++" trigger="class" id="genericclass">class $name$ +{ +public: + $name$() {} +};</snippet> +<snippet group="C++" trigger="class" id="qobjectclass" complement="derived from QObject">class $name$ : public QObject +{ + Q_OBJECT +public: + $name$() {} + virtual ~$name$() {} +};</snippet> +<snippet group="C++" trigger="class" id="qwidgetclass" complement="derived from QWidget">class $name$ : public QWidget +{ + Q_OBJECT +public: + $name$() {} + virtual ~$name$() {} +};</snippet> +<snippet group="C++" trigger="class" id="classtemplate" complement="template">template <typename $T$> +class $name$ +{ +public: + $name$() {} +};</snippet> +<snippet group="C++" trigger="do" id="do">do { + +} while ($condition$);</snippet> +<snippet group="C++" trigger="else" id="else" >else { + +}</snippet> +<snippet group="C++" trigger="else" id="elsewithif" complement="with if">else if ($condition$) { + +}</snippet> +<snippet group="C++" trigger="for" id="for">for (int $var$ = 0; $var$ < $total$; ++$var$) { + +}</snippet> +<snippet group="C++" trigger="foreach" id="foreach">foreach ($var$, $container$) { + +}</snippet> +<snippet group="C++" trigger="if" id="if">if ($condition$) { + +}</snippet> +<snippet group="C++" trigger="if" id="ifandelse" complement="and else">if ($condition$) { + +} else { + +}</snippet> +<snippet group="C++" trigger="namespace" id="namespace">namespace $name$ { + +}</snippet> +<snippet group="C++" trigger="try" id="trycatch" complement="and catch">try { + +} catch (...) { + +}</snippet> +<snippet group="C++" trigger="using" id="usingnamespace" complement="namespace">using namespace $name$;</snippet> +<snippet group="C++" trigger="while" id="while">while ($condition$) { + +}</snippet> +<snippet group="QML" trigger="property" id="property">property $type$ $name$: $value$</snippet> +<snippet group="QML" trigger="Item" id="item">Item { + id: $name$ +}</snippet> +<snippet group="QML" trigger="BorderImage" id="borderimage">BorderImage { + id: $name$ + source: "$file$" + width: $100$; height: $100$ + border.left: $5$; border.top: $5$ + border.right: $5$; border.bottom: $5$ +}</snippet> +<snippet group="QML" trigger="Image" id="image">Image { + id: $name$ + source: "$file$" +}</snippet> +<snippet group="QML" trigger="Text" id="text">Text { + id: $name$ + text: "$text$" +}</snippet> +<snippet group="QML" trigger="states" id="states">states: [ + State { + name: "$name$" + PropertyChanges { + target: $name$ + $$ + } + } +]</snippet> +<snippet group="QML" trigger="State" id="state">State { + name: "$name$" + PropertyChanges { + target: $name$ + $$ + } +}</snippet> +<snippet group="QML" trigger="transitions" id="transitions">transitions: [ + Transition { + from: "$name$" + to: "$name$" + $$ + } +]</snippet> +<snippet group="QML" trigger="Transition" id="transition">Transition { + from: "$name$" + to: "$name$" + $$ +}</snippet> +<snippet group="QML" trigger="PropertyChanges" id="propertychanges">PropertyChanges { + target: $name$ + $$ +}</snippet> +<snippet group="QML" trigger="NumberAnimation" id="numberanimationwithtargets" complement="with targets">NumberAnimation { targets: [$name$]; properties: "$name$"; duration: $200$ }</snippet> +<snippet group="QML" trigger="NumberAnimation" id="numberanimationwithtarget" complement="with target">NumberAnimation { target: $name$; property: "$name$"; to: $value$; duration: $200$ }</snippet> +<snippet group="QML" trigger="PropertyAction" id="propertyactionwithtargets" complement="with targets">PropertyAction { targets: [$name$]; properties: "$name$" }</snippet> +<snippet group="QML" trigger="PropertyAction" id="propertyactionwithtarget" complement="with target">PropertyAction { target: $name$; property: "$name$"; value: $value$ }</snippet> +<snippet group="QML" trigger="PauseAnimation" id="pauseanimation">PauseAnimation { duration: $200$ }</snippet> +<snippet group="QML" trigger="ColorAnimation" id="coloranimation">ColorAnimation { from: $"white"$; to: $"black"$; duration: $200$ }</snippet> +</snippets> diff --git a/src/plugins/texteditor/snippets/snippetscollection.cpp b/src/plugins/texteditor/snippets/snippetscollection.cpp new file mode 100644 index 0000000000..a2f7320cf0 --- /dev/null +++ b/src/plugins/texteditor/snippets/snippetscollection.cpp @@ -0,0 +1,212 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** Commercial Usage +** +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://qt.nokia.com/contact. +** +**************************************************************************/ + +#include "snippetscollection.h" + +#include <QtAlgorithms> + +#include <iterator> +#include <algorithm> + +using namespace TextEditor; +using namespace Internal; + +namespace { + +struct SnippetComp +{ + bool operator()(const Snippet &a, const Snippet &b) const + { + const int comp = a.trigger().toLower().localeAwareCompare(b.trigger().toLower()); + if (comp < 0) + return true; + else if (comp == 0 && + a.complement().toLower().localeAwareCompare(b.complement().toLower()) < 0) + return true; + return false; + } +}; +SnippetComp snippetComp; + +struct RemovedSnippetPred +{ + bool operator()(const Snippet &s) const + { + return s.isRemoved(); + } +}; +RemovedSnippetPred removedSnippetPred; + +} // Anonymous + +// Hint +SnippetsCollection::Hint::Hint(int index) : m_index(index) +{} + +SnippetsCollection::Hint::Hint(int index, QList<Snippet>::iterator it) : m_index(index), m_it(it) +{} + +int SnippetsCollection::Hint::index() const +{ + return m_index; +} + +// SnippetsCollection +SnippetsCollection::SnippetsCollection() : + m_snippets(Snippet::GroupSize), + m_activeSnippetsEnd(Snippet::GroupSize) +{ + for (Snippet::Group group = Snippet::Cpp; group < Snippet::GroupSize; ++group) + m_activeSnippetsEnd[group] = m_snippets[group].end(); +} + +SnippetsCollection::~SnippetsCollection() +{} + +void SnippetsCollection::insertSnippet(const Snippet &snippet, Snippet::Group group) +{ + insertSnippet(snippet, group, computeInsertionHint(snippet, group)); +} + +void SnippetsCollection::insertSnippet(const Snippet &snippet, + Snippet::Group group, + const Hint &hint) +{ + if (snippet.isBuiltIn() && snippet.isRemoved()) { + m_activeSnippetsEnd[group] = m_snippets[group].insert(m_activeSnippetsEnd[group], snippet); + } else { + m_snippets[group].insert(hint.m_it, snippet); + updateActiveSnippetsEnd(group); + } +} + +SnippetsCollection::Hint SnippetsCollection::computeInsertionHint(const Snippet &snippet, + Snippet::Group group) +{ + QList<Snippet> &snippets = m_snippets[group]; + QList<Snippet>::iterator it = qUpperBound( + snippets.begin(), m_activeSnippetsEnd.at(group), snippet, snippetComp); + return Hint(static_cast<int>(std::distance(snippets.begin(), it)), it); +} + +void SnippetsCollection::replaceSnippet(int index, const Snippet &snippet, Snippet::Group group) +{ + replaceSnippet(index, snippet, group, computeReplacementHint(index, snippet, group)); +} + +void SnippetsCollection::replaceSnippet(int index, + const Snippet &snippet, + Snippet::Group group, + const Hint &hint) +{ + Snippet replacement(snippet); + if (replacement.isBuiltIn() && !replacement.isModified()) + replacement.setIsModified(true); + + if (index == hint.index()) { + m_snippets[group][index] = replacement; + } else { + insertSnippet(replacement, group, hint); + // Consider whether the row moved up towards the beginning or down towards the end. + if (index < hint.index()) + m_snippets[group].removeAt(index); + else + m_snippets[group].removeAt(index + 1); + updateActiveSnippetsEnd(group); + } +} + +SnippetsCollection::Hint SnippetsCollection::computeReplacementHint(int index, + const Snippet &snippet, + Snippet::Group group) +{ + QList<Snippet> &snippets = m_snippets[group]; + QList<Snippet>::iterator it = qLowerBound( + snippets.begin(), m_activeSnippetsEnd.at(group), snippet, snippetComp); + int hintIndex = static_cast<int>(std::distance(snippets.begin(), it)); + if (index < hintIndex - 1) + return Hint(hintIndex - 1, it); + it = qUpperBound(it, m_activeSnippetsEnd.at(group), snippet, snippetComp); + hintIndex = static_cast<int>(std::distance(snippets.begin(), it)); + if (index > hintIndex) + return Hint(hintIndex, it); + // Even if the snipet is at a different index it is still inside a valid range. + return Hint(index); +} + +void SnippetsCollection::removeSnippet(int index, Snippet::Group group) +{ + Snippet snippet(m_snippets.at(group).at(index)); + m_snippets[group].removeAt(index); + if (snippet.isBuiltIn()) { + snippet.setIsRemoved(true); + m_activeSnippetsEnd[group] = m_snippets[group].insert(m_activeSnippetsEnd[group], snippet); + } else { + updateActiveSnippetsEnd(group); + } +} + +const Snippet &SnippetsCollection::snippet(int index, Snippet::Group group) const +{ + return m_snippets.at(group).at(index); +} + +void SnippetsCollection::setSnippetContent(int index, Snippet::Group group, const QString &content) +{ + Snippet &snippet = m_snippets[group][index]; + snippet.setContent(content); + if (snippet.isBuiltIn() && !snippet.isModified()) + snippet.setIsModified(true); +} + +int SnippetsCollection::totalActiveSnippets(Snippet::Group group) const +{ + return std::distance<QList<Snippet>::const_iterator>(m_snippets.at(group).begin(), + m_activeSnippetsEnd.at(group)); +} + +int SnippetsCollection::totalSnippets(Snippet::Group group) const +{ + return m_snippets.at(group).size(); +} + +void SnippetsCollection::clear() +{ + for (Snippet::Group group = Snippet::Cpp; group < Snippet::GroupSize; ++group) { + m_snippets[group].clear(); + m_activeSnippetsEnd[group] = m_snippets[group].end(); + } +} + +void SnippetsCollection::updateActiveSnippetsEnd(Snippet::Group group) +{ + m_activeSnippetsEnd[group] = std::find_if(m_snippets[group].begin(), + m_snippets[group].end(), + removedSnippetPred); +} diff --git a/src/plugins/texteditor/snippets/snippetscollection.h b/src/plugins/texteditor/snippets/snippetscollection.h new file mode 100644 index 0000000000..88546db929 --- /dev/null +++ b/src/plugins/texteditor/snippets/snippetscollection.h @@ -0,0 +1,97 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** Commercial Usage +** +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://qt.nokia.com/contact. +** +**************************************************************************/ + +#ifndef SNIPPETSCOLLECTION_H +#define SNIPPETSCOLLECTION_H + +#include "snippet.h" + +#include <QtCore/QVector> +#include <QtCore/QList> + +namespace TextEditor { +namespace Internal { + +// Characteristics of this collection: +// - Store snippets by group. +// - Keep groups of snippets sorted. +// - Allow snippet insertion/replacement based on a hint. +// - Allow modification of snippet members that are not sorting keys. +// - Track removed/modified built-in snippets. +// - Provide fast index access. +// - Not thread-safe. + +class SnippetsCollection +{ +public: + SnippetsCollection(); + ~SnippetsCollection(); + + class Hint + { + friend class SnippetsCollection; + public: + int index() const; + private: + Hint(int index); + Hint(int index, QList<Snippet>::iterator it); + int m_index; + QList<Snippet>::iterator m_it; + }; + + void insertSnippet(const Snippet &snippet, Snippet::Group group); + void insertSnippet(const Snippet &snippet, Snippet::Group group, const Hint &hint); + Hint computeInsertionHint(const Snippet &snippet, Snippet::Group group); + + void replaceSnippet(int index, const Snippet &snippet, Snippet::Group group); + void replaceSnippet(int index, const Snippet &snippet, Snippet::Group group, const Hint &hint); + Hint computeReplacementHint(int index, const Snippet &snippet, Snippet::Group group); + + void removeSnippet(int index, Snippet::Group group); + + void setSnippetContent(int index, Snippet::Group group, const QString &content); + + const Snippet &snippet(int index, Snippet::Group group) const; + + int totalActiveSnippets(Snippet::Group group) const; + int totalSnippets(Snippet::Group group) const; + + void clear(); + +private: + void updateActiveSnippetsEnd(Snippet::Group group); + + QVector<QList<Snippet> > m_snippets; + QVector<QList<Snippet>::iterator> m_activeSnippetsEnd; +}; + +} // Internal +} // TextEditor + +#endif // SNIPPETSCOLLECTION_H diff --git a/src/plugins/texteditor/snippets/snippetsmanager.cpp b/src/plugins/texteditor/snippets/snippetsmanager.cpp new file mode 100644 index 0000000000..8c0b9c099c --- /dev/null +++ b/src/plugins/texteditor/snippets/snippetsmanager.cpp @@ -0,0 +1,192 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** Commercial Usage +** +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://qt.nokia.com/contact. +** +**************************************************************************/ + +#include "snippetsmanager.h" +#include "isnippeteditordecorator.h" +#include "snippetscollection.h" +#include "reuse.h" + +#include <coreplugin/icore.h> + +#include <QtCore/QLatin1String> +#include <QtCore/QFile> +#include <QtCore/QFileInfo> +#include <QtCore/QDir> +#include <QtCore/QHash> +#include <QtCore/QDebug> +#include <QtCore/QXmlStreamReader> +#include <QtCore/QXmlStreamWriter> + +using namespace TextEditor; +using namespace Internal; + +const QLatin1String SnippetsManager::kSnippet("snippet"); +const QLatin1String SnippetsManager::kSnippets("snippets"); +const QLatin1String SnippetsManager::kTrigger("trigger"); +const QLatin1String SnippetsManager::kId("id"); +const QLatin1String SnippetsManager::kComplement("complement"); +const QLatin1String SnippetsManager::kGroup("group"); +const QLatin1String SnippetsManager::kRemoved("removed"); +const QLatin1String SnippetsManager::kModified("modified"); + +SnippetsManager::SnippetsManager() : + m_collectionLoaded(false), + m_collection(new SnippetsCollection), + m_builtInSnippetsPath(QLatin1String(":/texteditor/snippets/")), + m_userSnippetsPath(Core::ICore::instance()->userResourcePath() + QLatin1String("/snippets/")), + m_snippetsFileName(QLatin1String("snippets.xml")) +{} + +SnippetsManager::~SnippetsManager() +{} + +SnippetsManager *SnippetsManager::instance() +{ + static SnippetsManager manager; + return &manager; +} + +void SnippetsManager::loadSnippetsCollection() +{ + QHash<QString, Snippet> activeBuiltInSnippets; + const QList<Snippet> &builtInSnippets = readXML(m_builtInSnippetsPath + m_snippetsFileName); + foreach (const Snippet &snippet, builtInSnippets) + activeBuiltInSnippets.insert(snippet.id(), snippet); + + const QList<Snippet> &userSnippets = readXML(m_userSnippetsPath + m_snippetsFileName); + foreach (const Snippet &snippet, userSnippets) { + if (snippet.isBuiltIn()) + // This user snippet overrides the corresponding built-in snippet. + activeBuiltInSnippets.remove(snippet.id()); + m_collection->insertSnippet(snippet, snippet.group()); + } + + foreach (const Snippet &snippet, activeBuiltInSnippets) + m_collection->insertSnippet(snippet, snippet.group()); +} + +void SnippetsManager::reloadSnippetsCollection() +{ + m_collection->clear(); + loadSnippetsCollection(); +} + +void SnippetsManager::persistSnippetsCollection() +{ + if (QFile::exists(m_userSnippetsPath) || QDir().mkpath(m_userSnippetsPath)) { + QFile file(m_userSnippetsPath + m_snippetsFileName); + if (file.open(QFile::WriteOnly | QFile::Truncate)) { + QXmlStreamWriter writer(&file); + writer.setAutoFormatting(true); + writer.writeStartDocument(); + writer.writeStartElement(kSnippets); + for (Snippet::Group group = Snippet::Cpp; group < Snippet::GroupSize; ++group) { + const int size = m_collection->totalSnippets(group); + for (int i = 0; i < size; ++i) { + const Snippet &snippet = m_collection->snippet(i, group); + if (!snippet.isBuiltIn() || + (snippet.isBuiltIn() && (snippet.isRemoved() || snippet.isModified()))) { + writeSnippetXML(snippet, &writer); + } + } + } + writer.writeEndElement(); + writer.writeEndDocument(); + file.close(); + } + } +} + +void SnippetsManager::writeSnippetXML(const Snippet &snippet, QXmlStreamWriter *writer) +{ + writer->writeStartElement(kSnippet); + writer->writeAttribute(kGroup, fromSnippetGroup(snippet.group())); + writer->writeAttribute(kTrigger, snippet.trigger()); + writer->writeAttribute(kId, snippet.id()); + writer->writeAttribute(kComplement, snippet.complement()); + writer->writeAttribute(kRemoved, fromBool(snippet.isRemoved())); + writer->writeAttribute(kModified, fromBool(snippet.isModified())); + writer->writeCharacters(snippet.content()); + writer->writeEndElement(); +} + +QList<Snippet> SnippetsManager::readXML(const QString &fileName) +{ + QList<Snippet> snippets; + QFile file(fileName); + if (file.exists() && file.open(QIODevice::ReadOnly)) { + QXmlStreamReader xml(&file); + if (xml.readNextStartElement()) { + if (xml.name() == kSnippets) { + while (xml.readNextStartElement()) { + if (xml.name() == kSnippet) { + const QXmlStreamAttributes &atts = xml.attributes(); + + Snippet snippet(atts.value(kId).toString()); + snippet.setTrigger(atts.value(kTrigger).toString()); + snippet.setComplement(atts.value(kComplement).toString()); + snippet.setGroup(toSnippetGroup(atts.value(kGroup).toString())); + snippet.setIsRemoved(toBool(atts.value(kRemoved).toString())); + snippet.setIsModified(toBool(atts.value(kModified).toString())); + + QString content; + while (!xml.atEnd()) { + xml.readNext(); + if (xml.isCharacters()) { + content += xml.text(); + } else if (xml.isEndElement()) { + snippet.setContent(content); + snippets.append(snippet); + break; + } + } + } else { + xml.skipCurrentElement(); + } + } + } else { + xml.skipCurrentElement(); + } + } + if (xml.hasError()) + qWarning() << fileName << xml.errorString() << xml.lineNumber() << xml.columnNumber(); + file.close(); + } + + return snippets; +} + +QSharedPointer<SnippetsCollection> SnippetsManager::snippetsCollection() +{ + if (!m_collectionLoaded) { + loadSnippetsCollection(); + m_collectionLoaded = true; + } + return m_collection; +} diff --git a/src/plugins/texteditor/snippets/snippetsmanager.h b/src/plugins/texteditor/snippets/snippetsmanager.h new file mode 100644 index 0000000000..6a07c72843 --- /dev/null +++ b/src/plugins/texteditor/snippets/snippetsmanager.h @@ -0,0 +1,86 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** Commercial Usage +** +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://qt.nokia.com/contact. +** +**************************************************************************/ + +#ifndef SNIPPETSMANAGER_H +#define SNIPPETSMANAGER_H + +#include "snippet.h" + +#include <QtCore/QString> +#include <QtCore/QSharedPointer> +#include <QtCore/QList> + +QT_FORWARD_DECLARE_CLASS(QXmlStreamWriter) + +namespace TextEditor { +namespace Internal { + +class SnippetsCollection; + +class SnippetsManager +{ +private: + SnippetsManager(); + Q_DISABLE_COPY(SnippetsManager) + +public: + ~SnippetsManager(); + + static SnippetsManager *instance(); + + void reloadSnippetsCollection(); + void persistSnippetsCollection(); + QSharedPointer<SnippetsCollection> snippetsCollection(); + +private: + void loadSnippetsCollection(); + + static QList<Snippet> readXML(const QString &fileName); + static void writeSnippetXML(const Snippet &snippet, QXmlStreamWriter *writer); + + static const QLatin1String kSnippet; + static const QLatin1String kSnippets; + static const QLatin1String kTrigger; + static const QLatin1String kId; + static const QLatin1String kComplement; + static const QLatin1String kGroup; + static const QLatin1String kRemoved; + static const QLatin1String kModified; + + bool m_collectionLoaded; + QSharedPointer<SnippetsCollection> m_collection; + QString m_builtInSnippetsPath; + QString m_userSnippetsPath; + QString m_snippetsFileName; +}; + +} // Internal +} // TextEditor + +#endif // SNIPPETSMANAGER_H diff --git a/src/plugins/texteditor/snippets/snippetssettings.cpp b/src/plugins/texteditor/snippets/snippetssettings.cpp new file mode 100644 index 0000000000..e99cbaf59e --- /dev/null +++ b/src/plugins/texteditor/snippets/snippetssettings.cpp @@ -0,0 +1,78 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** Commercial Usage +** +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://qt.nokia.com/contact. +** +**************************************************************************/ + +#include "snippetssettings.h" +#include "reuse.h" + +#include <QtCore/QSettings> + +namespace { + +static const QLatin1String kGroupPostfix("SnippetsSettings"); +static const QLatin1String kLastUsedSnippetGroup("LastUsedSnippetGroup"); + +} // Anonymous + +using namespace TextEditor; +using namespace Internal; + +SnippetsSettings::SnippetsSettings() +{} + +void SnippetsSettings::toSettings(const QString &category, QSettings *s) const +{ + const QString &group = category + kGroupPostfix; + s->beginGroup(group); + s->setValue(kLastUsedSnippetGroup, m_lastUsedSnippetGroup); + s->endGroup(); +} + +void SnippetsSettings::fromSettings(const QString &category, QSettings *s) +{ + const QString &group = category + kGroupPostfix; + s->beginGroup(group); + m_lastUsedSnippetGroup = + s->value(kLastUsedSnippetGroup, fromSnippetGroup(Snippet::Cpp)).toString(); + s->endGroup(); +} + +void SnippetsSettings::setLastUsedSnippetGroup(const QString &lastUsed) +{ + m_lastUsedSnippetGroup = lastUsed; +} + +const QString &SnippetsSettings::lastUsedSnippetGroup() const +{ + return m_lastUsedSnippetGroup; +} + +bool SnippetsSettings::equals(const SnippetsSettings &snippetsSettings) const +{ + return m_lastUsedSnippetGroup == snippetsSettings.m_lastUsedSnippetGroup; +} diff --git a/src/plugins/texteditor/snippets/snippetssettings.h b/src/plugins/texteditor/snippets/snippetssettings.h new file mode 100644 index 0000000000..9699d47f08 --- /dev/null +++ b/src/plugins/texteditor/snippets/snippetssettings.h @@ -0,0 +1,66 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** Commercial Usage +** +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://qt.nokia.com/contact. +** +**************************************************************************/ + +#ifndef SNIPPETSSETTINGS_H +#define SNIPPETSSETTINGS_H + +#include <QtCore/QString> + +QT_BEGIN_NAMESPACE +class QSettings; +QT_END_NAMESPACE + +namespace TextEditor { + +class SnippetsSettings +{ +public: + SnippetsSettings(); + + void toSettings(const QString &category, QSettings *s) const; + void fromSettings(const QString &category, QSettings *s); + + void setLastUsedSnippetGroup(const QString &lastUsed); + const QString &lastUsedSnippetGroup() const; + + bool equals(const SnippetsSettings &snippetsSettings) const; + +private: + QString m_lastUsedSnippetGroup; +}; + +inline bool operator==(const SnippetsSettings &a, const SnippetsSettings &b) +{ return a.equals(b); } + +inline bool operator!=(const SnippetsSettings &a, const SnippetsSettings &b) +{ return !a.equals(b); } + +} // TextEditor + +#endif // SNIPPETSSETTINGS_H diff --git a/src/plugins/texteditor/snippets/snippetssettingspage.cpp b/src/plugins/texteditor/snippets/snippetssettingspage.cpp new file mode 100644 index 0000000000..3302e1298c --- /dev/null +++ b/src/plugins/texteditor/snippets/snippetssettingspage.cpp @@ -0,0 +1,512 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** Commercial Usage +** +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://qt.nokia.com/contact. +** +**************************************************************************/ + +#include "snippetssettingspage.h" +#include "snippetsmanager.h" +#include "snippeteditor.h" +#include "isnippeteditordecorator.h" +#include "snippet.h" +#include "snippetscollection.h" +#include "snippetssettings.h" +#include "reuse.h" +#include "ui_snippetssettingspage.h" + +#include <coreplugin/icore.h> +#include <extensionsystem/pluginmanager.h> + +#include <QtCore/QSharedPointer> +#include <QtCore/QModelIndex> +#include <QtCore/QAbstractTableModel> +#include <QtCore/QList> +#include <QtCore/QSettings> +#include <QtCore/QTextStream> +#include <QtGui/QMessageBox> + +namespace TextEditor { +namespace Internal { + +// SnippetsTableModel +class SnippetsTableModel : public QAbstractTableModel +{ + Q_OBJECT +public: + SnippetsTableModel(QObject *parent); + virtual ~SnippetsTableModel() {} + + virtual int rowCount(const QModelIndex &parent = QModelIndex()) const; + virtual int columnCount(const QModelIndex &parent = QModelIndex()) const; + virtual Qt::ItemFlags flags(const QModelIndex &modelIndex) const; + virtual QVariant data(const QModelIndex &modelIndex, int role = Qt::DisplayRole) const; + virtual bool setData(const QModelIndex &modelIndex, const QVariant &value, + int role = Qt::EditRole); + virtual QVariant headerData(int section, Qt::Orientation orientation, + int role = Qt::DisplayRole) const; + + void load(Snippet::Group group); + + QModelIndex createSnippet(); + QModelIndex insertSnippet(const Snippet &snippet); + void removeSnippet(const QModelIndex &modelIndex); + const Snippet &snippetAt(const QModelIndex &modelIndex) const; + void setSnippetContent(const QModelIndex &modelIndex, const QString &content); + +private: + static bool isValidTrigger(const QString &s); + + Snippet::Group m_activeGroup; + QSharedPointer<SnippetsCollection> m_collection; +}; + +SnippetsTableModel::SnippetsTableModel(QObject *parent) : + QAbstractTableModel(parent), + m_activeGroup(Snippet::Cpp), + m_collection(SnippetsManager::instance()->snippetsCollection()) +{} + +int SnippetsTableModel::rowCount(const QModelIndex &) const +{ + if (m_collection.isNull()) + return 0; + return m_collection->totalActiveSnippets(m_activeGroup); +} + +int SnippetsTableModel::columnCount(const QModelIndex &) const +{ + if (m_collection.isNull()) + return 0; + return 2; +} + +Qt::ItemFlags SnippetsTableModel::flags(const QModelIndex &index) const +{ + Qt::ItemFlags itemFlags = QAbstractTableModel::flags(index); + if (index.isValid()) + itemFlags |= Qt::ItemIsEditable; + return itemFlags; +} + +QVariant SnippetsTableModel::data(const QModelIndex &modelIndex, int role) const +{ + if (!modelIndex.isValid()) + return QVariant(); + + if (role == Qt::DisplayRole || role == Qt::EditRole) { + const Snippet &snippet = m_collection->snippet(modelIndex.row(), m_activeGroup); + if (modelIndex.column() == 0) + return snippet.trigger(); + else + return snippet.complement(); + } else { + return QVariant(); + } +} + +bool SnippetsTableModel::setData(const QModelIndex &modelIndex, const QVariant &value, int role) +{ + if (modelIndex.isValid() && role == Qt::EditRole) { + const int row = modelIndex.row(); + Snippet snippet(m_collection->snippet(row, m_activeGroup)); + if (modelIndex.column() == 0) { + const QString &s = value.toString(); + if (!isValidTrigger(s)) { + QMessageBox::critical(0, tr("Error"), tr("Not a valid trigger.")); + if (snippet.trigger().isEmpty()) + removeSnippet(modelIndex); + return false; + } + snippet.setTrigger(s); + } else { + snippet.setComplement(value.toString()); + } + + const SnippetsCollection::Hint &hint = + m_collection->computeReplacementHint(row, snippet, m_activeGroup); + if (modelIndex.row() == hint.index()) { + m_collection->replaceSnippet(row, snippet, m_activeGroup, hint); + emit dataChanged(modelIndex, modelIndex); + } else { + if (row < hint.index()) + // Rows will be moved down. + beginMoveRows(QModelIndex(), row, row, QModelIndex(), hint.index() + 1); + else + beginMoveRows(QModelIndex(), row, row, QModelIndex(), hint.index()); + m_collection->replaceSnippet(row, snippet, m_activeGroup, hint); + endMoveRows(); + } + + return true; + } + return false; +} + +QVariant SnippetsTableModel::headerData(int section, Qt::Orientation orientation, int role) const +{ + if (role != Qt::DisplayRole || orientation != Qt::Horizontal) + return QVariant(); + + if (section == 0) + return tr("Trigger"); + else + return tr("Complement"); +} + +void SnippetsTableModel::load(Snippet::Group group) +{ + m_activeGroup = group; + reset(); +} + +QModelIndex SnippetsTableModel::createSnippet() +{ + Snippet snippet; + snippet.setGroup(m_activeGroup); + return insertSnippet(snippet); +} + +QModelIndex SnippetsTableModel::insertSnippet(const Snippet &snippet) +{ + const SnippetsCollection::Hint &hint = + m_collection->computeInsertionHint(snippet, m_activeGroup); + beginInsertRows(QModelIndex(), hint.index(), hint.index()); + m_collection->insertSnippet(snippet, m_activeGroup, hint); + endInsertRows(); + + return index(hint.index(), 0); +} + +void SnippetsTableModel::removeSnippet(const QModelIndex &modelIndex) +{ + beginRemoveRows(QModelIndex(), modelIndex.row(), modelIndex.row()); + m_collection->removeSnippet(modelIndex.row(), m_activeGroup); + endRemoveRows(); +} + +const Snippet &SnippetsTableModel::snippetAt(const QModelIndex &modelIndex) const +{ + return m_collection->snippet(modelIndex.row(), m_activeGroup); +} + +void SnippetsTableModel::setSnippetContent(const QModelIndex &modelIndex, const QString &content) +{ + m_collection->setSnippetContent(modelIndex.row(), m_activeGroup, content); +} + +bool SnippetsTableModel::isValidTrigger(const QString &s) +{ + if (s.isEmpty()) + return false; + for (int i = 0; i < s.length(); ++i) + if (!s.at(i).isLetter()) + return false; + return true; +} + +// SnippetsSettingsPagePrivate +class SnippetsSettingsPagePrivate : public QObject +{ + Q_OBJECT +public: + SnippetsSettingsPagePrivate(const QString &id); + ~SnippetsSettingsPagePrivate() { delete m_model; } + + const QString &id() const { return m_id; } + const QString &displayName() const { return m_displayName; } + bool isKeyword(const QString &s) const { return m_keywords.contains(s, Qt::CaseInsensitive); } + void configureUi(QWidget *parent); + + void apply(); + void finish(); + +private slots: + void loadSnippetGroup(int index); + void markSnippetsCollection(); + void addSnippet(); + void removeSnippet(); + void selectSnippet(const QModelIndex &parent, int row); + void selectMovedSnippet(const QModelIndex &, int, int, const QModelIndex &, int row); + void previewSnippet(const QModelIndex &modelIndex); + void updateSnippetContent(); + +private: + SnippetEditor *currentEditor() const; + SnippetEditor *editorAt(int i) const; + + static void decorateEditor(SnippetEditor *editor, Snippet::Group group); + + void loadSettings(); + bool settingsChanged() const; + void writeSettings(); + + const QString m_id; + const QString m_displayName; + const QString m_settingsPrefix; + SnippetsTableModel *m_model; + bool m_snippetsCollectionChanged; + QString m_keywords; + SnippetsSettings m_settings; + Ui::SnippetsSettingsPage m_ui; +}; + +SnippetsSettingsPagePrivate::SnippetsSettingsPagePrivate(const QString &id) : + m_id(id), + m_displayName(tr("Snippets")), + m_settingsPrefix(QLatin1String("Text")), + m_model(new SnippetsTableModel(0)), + m_snippetsCollectionChanged(false) +{} + +SnippetEditor *SnippetsSettingsPagePrivate::currentEditor() const +{ + return editorAt(m_ui.snippetsEditorStack->currentIndex()); +} + +SnippetEditor *SnippetsSettingsPagePrivate::editorAt(int i) const +{ + return static_cast<SnippetEditor *>(m_ui.snippetsEditorStack->widget(i)); +} + +void SnippetsSettingsPagePrivate::configureUi(QWidget *w) +{ + m_ui.setupUi(w); + + m_ui.groupCombo->insertItem(Snippet::Cpp, fromSnippetGroup(Snippet::Cpp)); + m_ui.groupCombo->insertItem(Snippet::Qml, fromSnippetGroup(Snippet::Qml)); + m_ui.groupCombo->insertItem(Snippet::PlainText, fromSnippetGroup(Snippet::PlainText)); + + m_ui.snippetsTable->setSelectionBehavior(QAbstractItemView::SelectRows); + m_ui.snippetsTable->setSelectionMode(QAbstractItemView::SingleSelection); + m_ui.snippetsTable->horizontalHeader()->setStretchLastSection(true); + m_ui.snippetsTable->horizontalHeader()->setHighlightSections(false); + m_ui.snippetsTable->verticalHeader()->setVisible(false); + m_ui.snippetsTable->verticalHeader()->setDefaultSectionSize(20); + m_ui.snippetsTable->setModel(m_model); + + m_ui.snippetsEditorStack->insertWidget(Snippet::Cpp, new SnippetEditor(w)); + m_ui.snippetsEditorStack->insertWidget(Snippet::Qml, new SnippetEditor(w)); + m_ui.snippetsEditorStack->insertWidget(Snippet::PlainText, new SnippetEditor(w)); + decorateEditor(editorAt(Snippet::Cpp), Snippet::Cpp); + decorateEditor(editorAt(Snippet::Qml), Snippet::Qml); + decorateEditor(editorAt(Snippet::PlainText), Snippet::PlainText); + + QTextStream(&m_keywords) << m_displayName; + + loadSettings(); + loadSnippetGroup(m_ui.groupCombo->currentIndex()); + + connect(editorAt(Snippet::Cpp), SIGNAL(snippetContentChanged()), + this, SLOT(updateSnippetContent())); + connect(editorAt(Snippet::Qml), SIGNAL(snippetContentChanged()), + this, SLOT(updateSnippetContent())); + connect(editorAt(Snippet::PlainText), SIGNAL(snippetContentChanged()), + this, SLOT(updateSnippetContent())); + + connect(m_model, SIGNAL(rowsInserted(QModelIndex, int, int)), + this, SLOT(selectSnippet(QModelIndex,int))); + connect(m_model, SIGNAL(rowsInserted(QModelIndex, int, int)), + this, SLOT(markSnippetsCollection())); + connect(m_model, SIGNAL(rowsRemoved(QModelIndex, int, int)), + this, SLOT(markSnippetsCollection())); + connect(m_model, SIGNAL(rowsMoved(QModelIndex, int, int, QModelIndex, int)), + this, SLOT(selectMovedSnippet(QModelIndex,int,int,QModelIndex,int))); + connect(m_model, SIGNAL(rowsMoved(QModelIndex, int, int, QModelIndex, int)), + this, SLOT(markSnippetsCollection())); + connect(m_model, SIGNAL(dataChanged(QModelIndex,QModelIndex)), + this, SLOT(markSnippetsCollection())); + + connect(m_ui.groupCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(loadSnippetGroup(int))); + connect(m_ui.addButton, SIGNAL(clicked()), this, SLOT(addSnippet())); + connect(m_ui.removeButton, SIGNAL(clicked()), this, SLOT(removeSnippet())); + connect(m_ui.snippetsTable->selectionModel(), SIGNAL(currentChanged(QModelIndex,QModelIndex)), + this, SLOT(previewSnippet(QModelIndex))); +} + +void SnippetsSettingsPagePrivate::decorateEditor(SnippetEditor *editor, Snippet::Group group) +{ + const QList<ISnippetEditorDecorator *> &decorators = + ExtensionSystem::PluginManager::instance()->getObjects<ISnippetEditorDecorator>(); + foreach (ISnippetEditorDecorator *decorator, decorators) + if (decorator->supports(group)) + decorator->apply(editor); +} + +void SnippetsSettingsPagePrivate::apply() +{ + if (settingsChanged()) + writeSettings(); + + if (m_snippetsCollectionChanged) + SnippetsManager::instance()->persistSnippetsCollection(); +} + +void SnippetsSettingsPagePrivate::finish() +{ + if (m_snippetsCollectionChanged) { + SnippetsManager::instance()->reloadSnippetsCollection(); + m_snippetsCollectionChanged = false; + } +} + +void SnippetsSettingsPagePrivate::loadSettings() +{ + if (QSettings *s = Core::ICore::instance()->settings()) { + m_settings.fromSettings(m_settingsPrefix, s); + m_ui.groupCombo->setCurrentIndex(toSnippetGroup(m_settings.lastUsedSnippetGroup())); + } +} + +void SnippetsSettingsPagePrivate::writeSettings() +{ + if (QSettings *s = Core::ICore::instance()->settings()) { + m_settings.setLastUsedSnippetGroup(m_ui.groupCombo->currentText()); + m_settings.toSettings(m_settingsPrefix, s); + } +} + +bool SnippetsSettingsPagePrivate::settingsChanged() const +{ + if (m_settings.lastUsedSnippetGroup() != m_ui.groupCombo->currentText()) + return true; + return false; +} + +void SnippetsSettingsPagePrivate::loadSnippetGroup(int index) +{ + m_ui.snippetsEditorStack->setCurrentIndex(index); + currentEditor()->clear(); + m_model->load(Snippet::Group(index)); +} + +void SnippetsSettingsPagePrivate::markSnippetsCollection() +{ + if (!m_snippetsCollectionChanged) + m_snippetsCollectionChanged = true; +} + +void SnippetsSettingsPagePrivate::addSnippet() +{ + const QModelIndex &modelIndex = m_model->createSnippet(); + selectSnippet(QModelIndex(), modelIndex.row()); + m_ui.snippetsTable->edit(modelIndex); +} + +void SnippetsSettingsPagePrivate::removeSnippet() +{ + const QModelIndex &modelIndex = m_ui.snippetsTable->selectionModel()->currentIndex(); + if (!modelIndex.isValid()) { + QMessageBox::critical(0, tr("Error"), tr("No snippet selected.")); + return; + } + m_model->removeSnippet(modelIndex); +} + +void SnippetsSettingsPagePrivate::selectSnippet(const QModelIndex &parent, int row) +{ + QModelIndex topLeft = m_model->index(row, 0, parent); + QModelIndex bottomRight = m_model->index(row, 1, parent); + QItemSelection selection(topLeft, bottomRight); + m_ui.snippetsTable->selectionModel()->select(selection, QItemSelectionModel::SelectCurrent); + m_ui.snippetsTable->setCurrentIndex(topLeft); + m_ui.snippetsTable->scrollTo(topLeft); +} + +void SnippetsSettingsPagePrivate::selectMovedSnippet(const QModelIndex &, + int sourceRow, + int, + const QModelIndex &destinationParent, + int destinationRow) +{ + QModelIndex modelIndex; + if (sourceRow < destinationRow) + modelIndex = m_model->index(destinationRow - 1, 0, destinationParent); + else + modelIndex = m_model->index(destinationRow, 0, destinationParent); + m_ui.snippetsTable->scrollTo(modelIndex); +} + +void SnippetsSettingsPagePrivate::previewSnippet(const QModelIndex &modelIndex) +{ + currentEditor()->setPlainText(m_model->snippetAt(modelIndex).content()); +} + +void SnippetsSettingsPagePrivate::updateSnippetContent() +{ + const QModelIndex &modelIndex = m_ui.snippetsTable->selectionModel()->currentIndex(); + if (modelIndex.isValid()) { + m_model->setSnippetContent(modelIndex, currentEditor()->toPlainText()); + markSnippetsCollection(); + } +} + +// SnippetsSettingsPage +SnippetsSettingsPage::SnippetsSettingsPage(const QString &id, QObject *parent) : + TextEditorOptionsPage(parent), + m_d(new SnippetsSettingsPagePrivate(id)) +{} + +SnippetsSettingsPage::~SnippetsSettingsPage() +{ + delete m_d; +} + +QString SnippetsSettingsPage::id() const +{ + return m_d->id(); +} + +QString SnippetsSettingsPage::displayName() const +{ + return m_d->displayName(); +} + +bool SnippetsSettingsPage::matches(const QString &s) const +{ + return m_d->isKeyword(s); +} + +QWidget *SnippetsSettingsPage::createPage(QWidget *parent) +{ + QWidget *w = new QWidget(parent); + m_d->configureUi(w); + return w; +} + +void SnippetsSettingsPage::apply() +{ + m_d->apply(); +} + +void SnippetsSettingsPage::finish() +{ + m_d->finish(); +} + +} // Internal +} // TextEditor + +#include "snippetssettingspage.moc" diff --git a/src/plugins/texteditor/snippets/snippetssettingspage.h b/src/plugins/texteditor/snippets/snippetssettingspage.h new file mode 100644 index 0000000000..485d602592 --- /dev/null +++ b/src/plugins/texteditor/snippets/snippetssettingspage.h @@ -0,0 +1,61 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** Commercial Usage +** +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://qt.nokia.com/contact. +** +**************************************************************************/ + +#ifndef SNIPPETSSETTINGSPAGE_H +#define SNIPPETSSETTINGSPAGE_H + +#include "texteditoroptionspage.h" + +namespace TextEditor { +namespace Internal { + +class SnippetsSettingsPagePrivate; + +class SnippetsSettingsPage : public TextEditorOptionsPage +{ + Q_OBJECT +public: + SnippetsSettingsPage(const QString &id, QObject *parent); + virtual ~SnippetsSettingsPage(); + + virtual QString id() const; + virtual QString displayName() const; + virtual bool matches(const QString &s) const; + virtual QWidget *createPage(QWidget *parent); + virtual void apply(); + virtual void finish(); + +private: + SnippetsSettingsPagePrivate *m_d; +}; + +} // Internal +} // TextEditor + +#endif // SNIPPETSSETTINGSPAGE_H diff --git a/src/plugins/texteditor/snippets/snippetssettingspage.ui b/src/plugins/texteditor/snippets/snippetssettingspage.ui new file mode 100644 index 0000000000..df9917d9d9 --- /dev/null +++ b/src/plugins/texteditor/snippets/snippetssettingspage.ui @@ -0,0 +1,109 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>SnippetsSettingsPage</class> + <widget class="QWidget" name="SnippetsSettingsPage"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>684</width> + <height>554</height> + </rect> + </property> + <property name="windowTitle"> + <string>Form</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout_3"> + <item> + <layout class="QHBoxLayout" name="horizontalLayout"> + <item> + <widget class="QLabel" name="groupLabel"> + <property name="text"> + <string>Group: </string> + </property> + </widget> + </item> + <item> + <widget class="QComboBox" name="groupCombo"/> + </item> + <item> + <spacer name="horizontalSpacer"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + </layout> + </item> + <item> + <layout class="QHBoxLayout" name="horizontalLayout_2"> + <item> + <layout class="QVBoxLayout" name="verticalLayout"> + <item> + <widget class="QTableView" name="snippetsTable"> + <property name="editTriggers"> + <set>QAbstractItemView::DoubleClicked|QAbstractItemView::EditKeyPressed</set> + </property> + </widget> + </item> + <item> + <widget class="QStackedWidget" name="snippetsEditorStack"> + <property name="currentIndex"> + <number>1</number> + </property> + <widget class="QWidget" name="page"/> + <widget class="QWidget" name="page_2"/> + </widget> + </item> + </layout> + </item> + <item> + <layout class="QVBoxLayout" name="verticalLayout_2"> + <item> + <widget class="QPushButton" name="addButton"> + <property name="text"> + <string>Add</string> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="removeButton"> + <property name="text"> + <string>Remove</string> + </property> + </widget> + </item> + <item> + <spacer name="verticalSpacer"> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>20</width> + <height>40</height> + </size> + </property> + </spacer> + </item> + </layout> + </item> + </layout> + </item> + </layout> + </widget> + <tabstops> + <tabstop>groupCombo</tabstop> + <tabstop>addButton</tabstop> + <tabstop>removeButton</tabstop> + <tabstop>snippetsTable</tabstop> + </tabstops> + <resources/> + <connections/> +</ui> diff --git a/src/plugins/texteditor/snippetsparser.cpp b/src/plugins/texteditor/snippetsparser.cpp deleted file mode 100644 index ce3cf21704..0000000000 --- a/src/plugins/texteditor/snippetsparser.cpp +++ /dev/null @@ -1,144 +0,0 @@ -/************************************************************************** -** -** This file is part of Qt Creator -** -** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies). -** -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** Commercial Usage -** -** Licensees holding valid Qt Commercial licenses may use this file in -** accordance with the Qt Commercial License Agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and Nokia. -** -** 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. -** -** If you are unsure which license is appropriate for your use, please -** contact the sales department at http://qt.nokia.com/contact. -** -**************************************************************************/ - -#include "snippetsparser.h" - -#include <QtCore/QFile> -#include <QtCore/QFileInfo> -#include <QtCore/QLatin1String> -#include <QtCore/QLatin1Char> -#include <QtCore/QVariant> -#include <QtCore/QXmlStreamReader> -#include <QtCore/QDebug> -#include <QtGui/QTextDocument> - -using namespace TextEditor; - -SnippetsParser::SnippetsParser(const QString &fileName) : m_fileName(fileName) -{} - -const QList<CompletionItem> &SnippetsParser::execute(ICompletionCollector *collector, - const QIcon &icon, - int order) -{ - if (!QFile::exists(m_fileName)) { - m_snippets.clear(); - } else { - const QDateTime &lastModified = QFileInfo(m_fileName).lastModified(); - if (m_lastTrackedFileChange.isNull() || m_lastTrackedFileChange != lastModified) { - m_snippets.clear(); - QFile file(m_fileName); - file.open(QIODevice::ReadOnly); - QXmlStreamReader xml(&file); - if (xml.readNextStartElement()) { - if (xml.name() == QLatin1String("snippets")) { - while (xml.readNextStartElement()) { - if (xml.name() == QLatin1String("snippet")) { - TextEditor::CompletionItem item(collector); - QString title; - QString data; - QString description = xml.attributes().value("description").toString(); - - while (!xml.atEnd()) { - xml.readNext(); - if (xml.isEndElement()) { - int i = 0; - while (i < data.size() && data.at(i).isLetterOrNumber()) - ++i; - title = data.left(i); - item.text = title; - if (!description.isEmpty()) { - item.text += QLatin1Char(' '); - item.text += description; - } - item.data = QVariant::fromValue(data.trimmed()); - - QString infotip = data; - while (infotip.size() && infotip.at(infotip.size()-1).isSpace()) - infotip.chop(1); - infotip = Qt::escape(infotip); - infotip.replace(QLatin1Char('\n'), QLatin1String("<br>")); - infotip.replace(QLatin1Char(' '), QLatin1String(" ")); - { - QString s = QLatin1String("<nobr>"); - int count = 0; - for (int i = 0; i < infotip.count(); ++i) { - if (infotip.at(i) != QChar::ObjectReplacementCharacter) { - s += infotip.at(i); - continue; - } - if (++count % 2) { - s += QLatin1String("<b>"); - } else { - if (infotip.at(i-1) == QChar::ObjectReplacementCharacter) - s += QLatin1String("..."); - s += QLatin1String("</b>"); - } - } - infotip = s; - } - item.details = infotip; - - item.icon = icon; - item.order = order; - item.isSnippet = true; - m_snippets.append(item); - break; - } - - if (xml.isCharacters()) - data += xml.text(); - else if (xml.isStartElement()) { - if (xml.name() != QLatin1String("tab")) - xml.raiseError(QLatin1String("invalid snippets file")); - else { - data += QChar::ObjectReplacementCharacter; - data += xml.readElementText(); - data += QChar::ObjectReplacementCharacter; - } - } - } - } else { - xml.skipCurrentElement(); - } - } - } else { - xml.skipCurrentElement(); - } - } - if (xml.hasError()) - qWarning() << m_fileName << xml.errorString() << xml.lineNumber() << xml.columnNumber(); - file.close(); - - m_lastTrackedFileChange = lastModified; - } - } - - return m_snippets; -} diff --git a/src/plugins/texteditor/texteditor.pro b/src/plugins/texteditor/texteditor.pro index 43ba19013a..fbc8b67cd4 100644 --- a/src/plugins/texteditor/texteditor.pro +++ b/src/plugins/texteditor/texteditor.pro @@ -5,9 +5,11 @@ QT += xml network include(../../qtcreatorplugin.pri) include(texteditor_dependencies.pri) INCLUDEPATH += generichighlighter \ - tooltip + tooltip \ + snippets DEPENDPATH += generichighlighter \ - tooltip + tooltip \ + snippets SOURCES += texteditorplugin.cpp \ textfilewizard.cpp \ plaintexteditor.cpp \ @@ -70,8 +72,15 @@ SOURCES += texteditorplugin.cpp \ tooltip/tipfactory.cpp \ basehoverhandler.cpp \ helpitem.cpp \ - snippetsparser.cpp \ - autocompleter.cpp + autocompleter.cpp \ + snippets/snippetssettingspage.cpp \ + snippets/snippet.cpp \ + snippets/snippetsmanager.cpp \ + snippets/snippeteditor.cpp \ + snippets/isnippeteditordecorator.cpp \ + snippets/snippetscollection.cpp \ + snippets/snippetssettings.cpp \ + snippets/snippetprovider.cpp HEADERS += texteditorplugin.h \ textfilewizard.h \ @@ -145,14 +154,23 @@ HEADERS += texteditorplugin.h \ tooltip/tipfactory.h \ basehoverhandler.h \ helpitem.h \ - snippetsparser.h \ - autocompleter.h + autocompleter.h \ + snippets/snippetssettingspage.h \ + snippets/snippet.h \ + snippets/snippetsmanager.h \ + snippets/snippeteditor.h \ + snippets/isnippeteditordecorator.h \ + snippets/snippetscollection.h \ + snippets/reuse.h \ + snippets/snippetssettings.h \ + snippets/snippetprovider.h FORMS += behaviorsettingspage.ui \ displaysettingspage.ui \ fontsettingspage.ui \ colorschemeedit.ui \ generichighlighter/highlightersettingspage.ui \ - generichighlighter/managedefinitionsdialog.ui + generichighlighter/managedefinitionsdialog.ui \ + snippets/snippetssettingspage.ui RESOURCES += texteditor.qrc OTHER_FILES += TextEditor.mimetypes.xml diff --git a/src/plugins/texteditor/texteditor.qrc b/src/plugins/texteditor/texteditor.qrc index 86fa6638cb..bba57a2fe6 100644 --- a/src/plugins/texteditor/texteditor.qrc +++ b/src/plugins/texteditor/texteditor.qrc @@ -5,5 +5,6 @@ <file>TextEditor.mimetypes.xml</file> <file>images/refactormarker.png</file> <file>images/snippet.png</file> + <file>snippets/snippets.xml</file> </qresource> </RCC> diff --git a/src/plugins/texteditor/texteditorconstants.h b/src/plugins/texteditor/texteditorconstants.h index 83b4261e02..a22917d2cd 100644 --- a/src/plugins/texteditor/texteditorconstants.h +++ b/src/plugins/texteditor/texteditorconstants.h @@ -140,6 +140,9 @@ const char * const TEXT_EDITOR_FONT_SETTINGS = "A.FontSettings"; const char * const TEXT_EDITOR_BEHAVIOR_SETTINGS = "B.BehaviourSettings"; const char * const TEXT_EDITOR_DISPLAY_SETTINGS = "D.DisplaySettings"; const char * const TEXT_EDITOR_HIGHLIGHTER_SETTINGS = "E.HighlighterSettings"; +const char * const TEXT_EDITOR_SNIPPETS_SETTINGS = "F.SnippetsSettings"; + +const char * const SNIPPET_EDITOR_ID = "TextEditor.SnippetEditor"; } // namespace Constants } // namespace TextEditor diff --git a/src/plugins/texteditor/texteditorsettings.cpp b/src/plugins/texteditor/texteditorsettings.cpp index da0d8965ce..fcd5c4f969 100644 --- a/src/plugins/texteditor/texteditorsettings.cpp +++ b/src/plugins/texteditor/texteditorsettings.cpp @@ -41,6 +41,7 @@ #include "tabsettings.h" #include "texteditorplugin.h" #include "highlightersettingspage.h" +#include "snippetssettingspage.h" #include <extensionsystem/pluginmanager.h> #include <coreplugin/icore.h> @@ -62,6 +63,7 @@ public: BehaviorSettingsPage *m_behaviorSettingsPage; DisplaySettingsPage *m_displaySettingsPage; HighlighterSettingsPage *m_highlighterSettingsPage; + SnippetsSettingsPage *m_snippetsSettingsPage; CompletionSettings m_completionSettings; @@ -174,6 +176,10 @@ TextEditorSettings::TextEditorSettings(QObject *parent) new HighlighterSettingsPage(QLatin1String(Constants::TEXT_EDITOR_HIGHLIGHTER_SETTINGS), this); pm->addObject(m_d->m_highlighterSettingsPage); + m_d->m_snippetsSettingsPage = + new SnippetsSettingsPage(QLatin1String(Constants::TEXT_EDITOR_SNIPPETS_SETTINGS), this); + pm->addObject(m_d->m_snippetsSettingsPage); + connect(m_d->m_fontSettingsPage, SIGNAL(changed(TextEditor::FontSettings)), this, SIGNAL(fontSettingsChanged(TextEditor::FontSettings))); connect(m_d->m_behaviorSettingsPage, SIGNAL(tabSettingsChanged(TextEditor::TabSettings)), @@ -197,6 +203,7 @@ TextEditorSettings::~TextEditorSettings() pm->removeObject(m_d->m_behaviorSettingsPage); pm->removeObject(m_d->m_displaySettingsPage); pm->removeObject(m_d->m_highlighterSettingsPage); + pm->removeObject(m_d->m_snippetsSettingsPage); delete m_d; |