diff options
author | Jarek Kobus <jkobus@trolltech.com> | 2010-11-08 14:01:50 +0100 |
---|---|---|
committer | Jarek Kobus <jkobus@trolltech.com> | 2010-11-08 14:03:49 +0100 |
commit | 371665446fcbf78fe4a4e395597e9cfaf52f6fc3 (patch) | |
tree | 65288e823c1ae75b1c4332849322b56655abab6b /src/plugins/qt4projectmanager | |
parent | a6e1c200dda155f5f6ee5ba16c4f8651ba0bc322 (diff) | |
download | qt-creator-371665446fcbf78fe4a4e395597e9cfaf52f6fc3.tar.gz |
Support completion in profile editor
Task-number: QTCREATORBUG-2110
Diffstat (limited to 'src/plugins/qt4projectmanager')
-rw-r--r-- | src/plugins/qt4projectmanager/profilecompletion.cpp | 189 | ||||
-rw-r--r-- | src/plugins/qt4projectmanager/profilecompletion.h | 45 | ||||
-rw-r--r-- | src/plugins/qt4projectmanager/profileeditor.h | 2 | ||||
-rw-r--r-- | src/plugins/qt4projectmanager/profileeditorfactory.cpp | 11 | ||||
-rw-r--r-- | src/plugins/qt4projectmanager/profilehighlighter.cpp | 128 | ||||
-rw-r--r-- | src/plugins/qt4projectmanager/profilekeywords.cpp | 167 | ||||
-rw-r--r-- | src/plugins/qt4projectmanager/profilekeywords.h | 24 | ||||
-rw-r--r-- | src/plugins/qt4projectmanager/qt4projectmanager.pro | 8 | ||||
-rw-r--r-- | src/plugins/qt4projectmanager/qt4projectmanagerplugin.cpp | 10 |
9 files changed, 456 insertions, 128 deletions
diff --git a/src/plugins/qt4projectmanager/profilecompletion.cpp b/src/plugins/qt4projectmanager/profilecompletion.cpp new file mode 100644 index 0000000000..9d3f706d8a --- /dev/null +++ b/src/plugins/qt4projectmanager/profilecompletion.cpp @@ -0,0 +1,189 @@ +#include "profilecompletion.h" +#include "profileeditor.h" +#include "profilekeywords.h" +#include <texteditor/itexteditor.h> +#include <texteditor/completionsettings.h> +#include <cplusplus/Icons.h> +#include <QDebug> + +using namespace Qt4ProjectManager::Internal; + +ProFileCompletion::ProFileCompletion(QObject *parent) : + TextEditor::ICompletionCollector(parent), + m_editor(0), + m_startPosition(-1), + m_variableIcon(CPlusPlus::Icons().iconForType(CPlusPlus::Icons::VarPublicIconType)), + m_functionIcon(CPlusPlus::Icons().iconForType(CPlusPlus::Icons::FuncPublicIconType)) +{ +} + +ProFileCompletion::~ProFileCompletion() +{ + +} + +QList<TextEditor::CompletionItem> ProFileCompletion::getCompletions() +{ + QList<TextEditor::CompletionItem> completionItems; + completions(&completionItems); + + return completionItems; +} + +bool ProFileCompletion::shouldRestartCompletion() +{ + return false; +} + +TextEditor::ITextEditable *ProFileCompletion::editor() const +{ + return m_editor; +} + +int ProFileCompletion::startPosition() const +{ + return m_startPosition; +} + +bool ProFileCompletion::supportsEditor(TextEditor::ITextEditable *editor) +{ + if (qobject_cast<ProFileEditorEditable *>(editor)) + return true; + return false; +} + +bool ProFileCompletion::triggersCompletion(TextEditor::ITextEditable *editor) +{ + m_editor = editor; + const int pos = editor->position(); + + if (completionSettings().m_completionTrigger == TextEditor::AutomaticCompletion) { + QChar characterUnderCursor = editor->characterAt(pos); + if (!characterUnderCursor.isLetterOrNumber()) { + m_startPosition = findStartOfName(); + if (pos - m_startPosition >= 3 && !isInComment()) + return true; + } + } + return false; +} + +int ProFileCompletion::findStartOfName(int pos) const +{ + if (pos == -1) + pos = m_editor->position(); + QChar chr; + + // Skip to the start of a name + do { + chr = m_editor->characterAt(--pos); + } while (chr.isLetterOrNumber() || chr == QLatin1Char('_')); + + return pos + 1; +} + +bool ProFileCompletion::isInComment() const +{ + const int beginOfLinePosition = m_editor->position(TextEditor::ITextEditor::StartOfLine); + const QString lineBeginning = m_editor->textAt(beginOfLinePosition, + m_startPosition - beginOfLinePosition); + if (lineBeginning.contains(QLatin1Char('#'))) + return true; + return false; +} + +int ProFileCompletion::startCompletion(TextEditor::ITextEditable *editor) +{ + m_editor = editor; + m_startPosition = findStartOfName(); + + return m_startPosition; +} + +void ProFileCompletion::completions(QList<TextEditor::CompletionItem> *completions) +{ + const int length = m_editor->position() - m_startPosition; + if (length < 0) + return; + + if (isInComment()) + return; + + const QString key = m_editor->textAt(m_startPosition, length); + + QList<TextEditor::CompletionItem> items; + QStringList keywords = ProFileKeywords::variables() + + ProFileKeywords::functions(); +// qSort(keywords); + for (int i = 0; i < keywords.count(); i++) { + TextEditor::CompletionItem item(this); + item.text = keywords[i]; + item.data = QVariant::fromValue(item.text); + item.icon = ProFileKeywords::isFunction(item.text) + ? m_functionIcon : m_variableIcon; + items.append(item); + } + + filter(items, completions, key); +} + +bool ProFileCompletion::typedCharCompletes(const TextEditor::CompletionItem &item, QChar typedChar) +{ + // only '(' in case of a function + if (typedChar == QLatin1Char('(') && ProFileKeywords::isFunction(item.text)) + return true; + return false; +} + +void ProFileCompletion::complete(const TextEditor::CompletionItem &item, QChar typedChar) +{ + Q_UNUSED(typedChar) + + int replaceLength = m_editor->position() - m_startPosition; + if (replaceLength < 0) + return; + + QString toInsert = item.text; + int cursorOffset = 0; + if (ProFileKeywords::isFunction(toInsert) + && completionSettings().m_autoInsertBrackets) { + if (completionSettings().m_spaceAfterFunctionName) { + if (m_editor->textAt(m_editor->position(), 2) == QLatin1String(" (")) { + cursorOffset = 2; + } else if (m_editor->characterAt(m_editor->position()) == QLatin1Char('(') + || m_editor->characterAt(m_editor->position()) == QLatin1Char(' ')) { + replaceLength += 1; + toInsert += QLatin1String(" ("); + } else { + toInsert += QLatin1String(" ()"); + cursorOffset = -1; + } + } else { + if (m_editor->characterAt(m_editor->position()) == QLatin1Char('(')) { + cursorOffset = 1; + } else { + toInsert += QLatin1String("()"); + cursorOffset = -1; + } + } + } + + m_editor->setCurPos(m_startPosition); + m_editor->replace(replaceLength, toInsert); + if (cursorOffset) + m_editor->setCurPos(m_editor->position() + cursorOffset); +} + +bool ProFileCompletion::partiallyComplete(const QList<TextEditor::CompletionItem> &completionItems) +{ + if (completionItems.count() == 1) { + complete(completionItems.first(), QChar()); + return true; + } + + return TextEditor::ICompletionCollector::partiallyComplete(completionItems); +} + +void ProFileCompletion::cleanup() +{ +} diff --git a/src/plugins/qt4projectmanager/profilecompletion.h b/src/plugins/qt4projectmanager/profilecompletion.h new file mode 100644 index 0000000000..cdbec85adf --- /dev/null +++ b/src/plugins/qt4projectmanager/profilecompletion.h @@ -0,0 +1,45 @@ +#ifndef PROFILECOMPLETION_H +#define PROFILECOMPLETION_H + +#include <texteditor/icompletioncollector.h> + +namespace Qt4ProjectManager { + +namespace Internal { + +class ProFileCompletion : public TextEditor::ICompletionCollector +{ + Q_OBJECT +public: + ProFileCompletion(QObject *parent = 0); + + virtual ~ProFileCompletion(); + + virtual QList<TextEditor::CompletionItem> getCompletions(); + virtual bool shouldRestartCompletion(); + + virtual TextEditor::ITextEditable *editor() const; + virtual int startPosition() const; + + virtual bool supportsEditor(TextEditor::ITextEditable *editor); + virtual bool triggersCompletion(TextEditor::ITextEditable *editor); + virtual int startCompletion(TextEditor::ITextEditable *editor); + virtual void completions(QList<TextEditor::CompletionItem> *completions); + virtual bool typedCharCompletes(const TextEditor::CompletionItem &item, QChar typedChar); + virtual void complete(const TextEditor::CompletionItem &item, QChar typedChar); + virtual bool partiallyComplete(const QList<TextEditor::CompletionItem> &completionItems); + virtual void cleanup(); +private: + int findStartOfName(int pos = -1) const; + bool isInComment() const; + + TextEditor::ITextEditable *m_editor; + int m_startPosition; + const QIcon m_variableIcon; + const QIcon m_functionIcon; +}; + +} // namespace Internal +} // namespace Qt4ProjectManager + +#endif // PROFILECOMPLETION_H diff --git a/src/plugins/qt4projectmanager/profileeditor.h b/src/plugins/qt4projectmanager/profileeditor.h index 1dc9733e23..1ef4beb0d0 100644 --- a/src/plugins/qt4projectmanager/profileeditor.h +++ b/src/plugins/qt4projectmanager/profileeditor.h @@ -53,6 +53,8 @@ class ProFileEditor; class ProFileEditorEditable : public TextEditor::BaseTextEditorEditable { + Q_OBJECT + public: ProFileEditorEditable(ProFileEditor *); Core::Context context() const; diff --git a/src/plugins/qt4projectmanager/profileeditorfactory.cpp b/src/plugins/qt4projectmanager/profileeditorfactory.cpp index c2e5e02889..031adfc398 100644 --- a/src/plugins/qt4projectmanager/profileeditorfactory.cpp +++ b/src/plugins/qt4projectmanager/profileeditorfactory.cpp @@ -37,6 +37,7 @@ #include <coreplugin/editormanager/editormanager.h> #include <texteditor/texteditoractionhandler.h> #include <texteditor/texteditorsettings.h> +#include <texteditor/completionsupport.h> #include <QtCore/QFileInfo> #include <QtGui/QAction> @@ -83,9 +84,13 @@ Core::IFile *ProFileEditorFactory::open(const QString &fileName) Core::IEditor *ProFileEditorFactory::createEditor(QWidget *parent) { - ProFileEditor *rc = new ProFileEditor(parent, this, m_actionHandler); - TextEditor::TextEditorSettings::instance()->initializeEditor(rc); - return rc->editableInterface(); + ProFileEditor *editor = new ProFileEditor(parent, this, m_actionHandler); + TextEditor::TextEditorSettings::instance()->initializeEditor(editor); + + // auto completion + connect(editor, SIGNAL(requestAutoCompletion(TextEditor::ITextEditable*, bool)), + TextEditor::Internal::CompletionSupport::instance(), SLOT(autoComplete(TextEditor::ITextEditable*, bool))); + return editor->editableInterface(); } QStringList ProFileEditorFactory::mimeTypes() const diff --git a/src/plugins/qt4projectmanager/profilehighlighter.cpp b/src/plugins/qt4projectmanager/profilehighlighter.cpp index 14daeee9f6..55a00f70aa 100644 --- a/src/plugins/qt4projectmanager/profilehighlighter.cpp +++ b/src/plugins/qt4projectmanager/profilehighlighter.cpp @@ -28,6 +28,7 @@ **************************************************************************/ #include "profilehighlighter.h" +#include "profilekeywords.h" #include <QtCore/QRegExp> #include <QtGui/QColor> @@ -36,125 +37,6 @@ using namespace Qt4ProjectManager::Internal; -const char *const variables[] = { - "CCFLAG", - "CONFIG", - "DEFINES", - "DEF_FILE", - "DEPENDPATH", - "DEPLOYMENT", - "DESTDIR", - "DESTDIR_TARGET", - "DISTFILES", - "DLLDESTDIR", - "FORMS", - "HEADERS", - "ICON", - "INCLUDEPATH", - "INSTALLS", - "LEXSOURCES", - "LIBS", - "MAKEFILE", - "MOBILITY", - "MOC_DIR", - "OBJECTIVE_HEADERS", - "OBJECTIVE_SOURCES", - "OBJECTS", - "OBJECTS_DIR", - "OBJMOC", - "OTHER_FILES", - "PKGCONFIG", - "POST_TARGETDEPS", - "PRECOMPILED_HEADER", - "PRE_TARGETDEPS", - "QMAKE", - "QMAKESPEC", - "QT", - "RCC_DIR", - "RC_FILE", - "REQUIRES", - "RESOURCES", - "RES_FILE", - "SOURCES", - "SRCMOC", - "STATECHARTS", - "SUBDIRS", - "TARGET", - "TARGET.CAPABILITY", - "TARGET.EPOCHEAPSIZE", - "TARGET.UID3", - "TARGET_EXT", - "TARGET_x", - "TARGET_x.y.z", - "TEMPLATE", - "TRANSLATIONS", - "UI_DIR", - "UI_HEADERS_DIR", - "UI_SOURCES_DIR", - "VER_MAJ", - "VER_MIN", - "VER_PAT", - "VERSION", - "VPATH", - "YACCSOURCES", - 0 -}; - -const char *const functions[] = { - "basename", - "contains", - "count", - "dirname", - "error", - "exists", - "find", - "for", - "include", - "infile", - "isEmpty", - "join", - "member", - "message", - "prompt", - "quote", - "sprintf", - "system", - "unique", - "warning", - 0 -}; - -struct KeywordHelper -{ - inline KeywordHelper(const QString &word) : needle(word) {} - const QString needle; -}; - -static bool operator<(const KeywordHelper &helper, const char *kw) -{ - return helper.needle < QLatin1String(kw); -} - -static bool operator<(const char *kw, const KeywordHelper &helper) -{ - return QLatin1String(kw) < helper.needle; -} - -static bool isVariable(const QString &word) -{ - const char *const *start = &variables[0]; - const char *const *end = &variables[sizeof variables / sizeof variables[0] - 1]; - const char *const *kw = qBinaryFind(start, end, KeywordHelper(word)); - return *kw != 0; -} - -static bool isFunction(const QString &word) -{ - const char *const *start = &functions[0]; - const char *const *end = &functions[sizeof functions / sizeof functions[0] - 1]; - const char *const *kw = qBinaryFind(start, end, KeywordHelper(word)); - return *kw != 0; -} ProFileHighlighter::ProFileHighlighter(QTextDocument *document) : TextEditor::SyntaxHighlighter(document) @@ -179,12 +61,12 @@ void ProFileHighlighter::highlightBlock(const QString &text) if (c.isLetter() || c == '_' || c == '.' || c.isDigit()) { buf += c; setFormat(i - buf.length()+1, buf.length(), emptyFormat); - if (!buf.isEmpty() && isFunction(buf)) + if (!buf.isEmpty() && ProFileKeywords::isFunction(buf)) setFormat(i - buf.length()+1, buf.length(), m_formats[ProfileFunctionFormat]); - else if (!buf.isEmpty() && isVariable(buf)) + else if (!buf.isEmpty() && ProFileKeywords::isVariable(buf)) setFormat(i - buf.length()+1, buf.length(), m_formats[ProfileVariableFormat]); } else if (c == '(') { - if (!buf.isEmpty() && isFunction(buf)) + if (!buf.isEmpty() && ProFileKeywords::isFunction(buf)) setFormat(i - buf.length(), buf.length(), m_formats[ProfileFunctionFormat]); buf.clear(); } else if (c == '#') { @@ -192,7 +74,7 @@ void ProFileHighlighter::highlightBlock(const QString &text) setFormat(i, 1, m_formats[ProfileCommentFormat]); buf.clear(); } else { - if (!buf.isEmpty() && isVariable(buf)) + if (!buf.isEmpty() && ProFileKeywords::isVariable(buf)) setFormat(i - buf.length(), buf.length(), m_formats[ProfileVariableFormat]); buf.clear(); } diff --git a/src/plugins/qt4projectmanager/profilekeywords.cpp b/src/plugins/qt4projectmanager/profilekeywords.cpp new file mode 100644 index 0000000000..1e0ee9b65d --- /dev/null +++ b/src/plugins/qt4projectmanager/profilekeywords.cpp @@ -0,0 +1,167 @@ +#include "profilekeywords.h" + +using namespace Qt4ProjectManager::Internal; + +static const char *const variableKeywords[] = { + "CCFLAG", + "CONFIG", + "DEFINES", + "DEF_FILE", + "DEPENDPATH", + "DEPLOYMENT", + "DESTDIR", + "DESTDIR_TARGET", + "DISTFILES", + "DLLDESTDIR", + "FORMS", + "HEADERS", + "ICON", + "INCLUDEPATH", + "INSTALLS", + "LEXSOURCES", + "LIBS", + "MAKEFILE", + "MOBILITY", + "MOC_DIR", + "OBJECTIVE_HEADERS", + "OBJECTIVE_SOURCES", + "OBJECTS", + "OBJECTS_DIR", + "OBJMOC", + "OTHER_FILES", + "PKGCONFIG", + "POST_TARGETDEPS", + "PRECOMPILED_HEADER", + "PRE_TARGETDEPS", + "QMAKE", + "QMAKESPEC", + "QT", + "RCC_DIR", + "RC_FILE", + "REQUIRES", + "RESOURCES", + "RES_FILE", + "SOURCES", + "SRCMOC", + "STATECHARTS", + "SUBDIRS", + "TARGET", + "TARGET.CAPABILITY", + "TARGET.EPOCHEAPSIZE", + "TARGET.UID3", + "TARGET_EXT", + "TARGET_x", + "TARGET_x.y.z", + "TEMPLATE", + "TRANSLATIONS", + "UI_DIR", + "UI_HEADERS_DIR", + "UI_SOURCES_DIR", + "VER_MAJ", + "VER_MIN", + "VER_PAT", + "VERSION", + "VPATH", + "YACCSOURCES", + 0 +}; + +static const char *const functionKeywords[] = { + "basename", + "contains", + "count", + "dirname", + "error", + "exists", + "find", + "for", + "include", + "infile", + "isEmpty", + "join", + "member", + "message", + "prompt", + "quote", + "sprintf", + "system", + "unique", + "warning", + 0 +}; + +class ProFileKeywordsImplementation +{ +public: + static ProFileKeywordsImplementation *instance(); + QStringList variables(); + QStringList functions(); + bool isVariable(const QString &word); + bool isFunction(const QString &word); +private: + ProFileKeywordsImplementation(); + static ProFileKeywordsImplementation *m_instance; + QStringList m_variables; + QStringList m_functions; +}; + +ProFileKeywordsImplementation *ProFileKeywordsImplementation::m_instance = 0; + +ProFileKeywordsImplementation *ProFileKeywordsImplementation::instance() +{ + if (!m_instance) + m_instance = new ProFileKeywordsImplementation(); + return m_instance; +} + +QStringList ProFileKeywordsImplementation::variables() +{ + return m_variables; +} + +QStringList ProFileKeywordsImplementation::functions() +{ + return m_functions; +} + +bool ProFileKeywordsImplementation::isVariable(const QString &word) +{ + return m_variables.contains(word); +} + +bool ProFileKeywordsImplementation::isFunction(const QString &word) +{ + return m_functions.contains(word); +} + +ProFileKeywordsImplementation::ProFileKeywordsImplementation() +{ + for (uint i = 0; i < sizeof variableKeywords / sizeof variableKeywords[0] - 1; i++) + m_variables.append(QLatin1String(variableKeywords[i])); + for (uint i = 0; i < sizeof functionKeywords / sizeof functionKeywords[0] - 1; i++) + m_functions.append(QLatin1String(functionKeywords[i])); +} + +ProFileKeywords::ProFileKeywords() +{ +} + +QStringList ProFileKeywords::variables() +{ + return ProFileKeywordsImplementation::instance()->variables(); +} + +QStringList ProFileKeywords::functions() +{ + return ProFileKeywordsImplementation::instance()->functions(); +} + +bool ProFileKeywords::isVariable(const QString &word) +{ + return ProFileKeywordsImplementation::instance()->isVariable(word); +} + +bool ProFileKeywords::isFunction(const QString &word) +{ + return ProFileKeywordsImplementation::instance()->isFunction(word); +} diff --git a/src/plugins/qt4projectmanager/profilekeywords.h b/src/plugins/qt4projectmanager/profilekeywords.h new file mode 100644 index 0000000000..411d98d348 --- /dev/null +++ b/src/plugins/qt4projectmanager/profilekeywords.h @@ -0,0 +1,24 @@ +#ifndef PROFILEKEYWORDS_H +#define PROFILEKEYWORDS_H + +#include <QtCore/QStringList> + +namespace Qt4ProjectManager { + +namespace Internal { + +class ProFileKeywords +{ +public: + static QStringList variables(); + static QStringList functions(); + static bool isVariable(const QString &word); + static bool isFunction(const QString &word); +private: + ProFileKeywords(); +}; + +} // namespace Internal +} // namespace Qt4ProjectManager + +#endif // PROFILEKEYWORDS_H diff --git a/src/plugins/qt4projectmanager/qt4projectmanager.pro b/src/plugins/qt4projectmanager/qt4projectmanager.pro index 78fa9e4a0b..d0a823d5a9 100644 --- a/src/plugins/qt4projectmanager/qt4projectmanager.pro +++ b/src/plugins/qt4projectmanager/qt4projectmanager.pro @@ -63,7 +63,9 @@ HEADERS += qt4deployconfiguration.h \ findqt4profiles.h \ qt4projectmanager_global.h \ qmldumptool.h \ - qmlobservertool.h + qmlobservertool.h \ + profilecompletion.h \ + profilekeywords.h SOURCES += qt4projectmanagerplugin.cpp \ qt4deployconfiguration.cpp \ qtparser.cpp \ @@ -121,7 +123,9 @@ SOURCES += qt4projectmanagerplugin.cpp \ librarydetailscontroller.cpp \ findqt4profiles.cpp \ qmldumptool.cpp \ - qmlobservertool.cpp + qmlobservertool.cpp \ + profilecompletion.cpp \ + profilekeywords.cpp FORMS += makestep.ui \ qmakestep.ui \ qt4projectconfigwidget.ui \ diff --git a/src/plugins/qt4projectmanager/qt4projectmanagerplugin.cpp b/src/plugins/qt4projectmanager/qt4projectmanagerplugin.cpp index 1b629887c2..fd670e6a46 100644 --- a/src/plugins/qt4projectmanager/qt4projectmanagerplugin.cpp +++ b/src/plugins/qt4projectmanager/qt4projectmanagerplugin.cpp @@ -50,6 +50,7 @@ #include "qtoptionspage.h" #include "externaleditors.h" #include "gettingstartedwelcomepage.h" +#include "profilecompletion.h" #include "qt-maemo/maemomanager.h" #include "qt-s60/s60manager.h" @@ -70,6 +71,7 @@ #include <coreplugin/editormanager/editormanager.h> #include <texteditor/texteditoractionhandler.h> #include <texteditor/texteditorconstants.h> +#include <texteditor/texteditorsettings.h> #ifdef WITH_TESTS # include <QTest> @@ -164,6 +166,14 @@ bool Qt4ProjectManagerPlugin::initialize(const QStringList &arguments, QString * addAutoReleasedObject(new S60Manager); addAutoReleasedObject(new MaemoManager); + ProFileCompletion *completion = new ProFileCompletion; + addAutoReleasedObject(completion); + // Set completion settings and keep them up to date + TextEditor::TextEditorSettings *textEditorSettings = TextEditor::TextEditorSettings::instance(); + completion->setCompletionSettings(textEditorSettings->completionSettings()); + connect(textEditorSettings, SIGNAL(completionSettingsChanged(TextEditor::CompletionSettings)), + completion, SLOT(setCompletionSettings(TextEditor::CompletionSettings))); + new ProFileCacheManager(this); // TODO reenable |