diff options
Diffstat (limited to 'src/plugins/cpptools')
-rw-r--r-- | src/plugins/cpptools/CppTools.pluginspec.in (renamed from src/plugins/cpptools/CppTools.pluginspec) | 10 | ||||
-rw-r--r-- | src/plugins/cpptools/completionsettingspage.cpp | 13 | ||||
-rw-r--r-- | src/plugins/cpptools/completionsettingspage.h | 2 | ||||
-rw-r--r-- | src/plugins/cpptools/cppcodecompletion.cpp | 45 | ||||
-rw-r--r-- | src/plugins/cpptools/cppcodecompletion.h | 4 | ||||
-rw-r--r-- | src/plugins/cpptools/cppcodeformatter.cpp | 74 | ||||
-rw-r--r-- | src/plugins/cpptools/cppcodeformatter.h | 5 | ||||
-rw-r--r-- | src/plugins/cpptools/cppfilesettingspage.cpp | 17 | ||||
-rw-r--r-- | src/plugins/cpptools/cpptools.pri | 2 | ||||
-rw-r--r-- | src/plugins/cpptools/cpptools.pro | 4 | ||||
-rw-r--r-- | src/plugins/cpptools/cpptoolsplugin.cpp | 3 | ||||
-rw-r--r-- | src/plugins/cpptools/insertionpointlocator.h | 2 | ||||
-rw-r--r-- | src/plugins/cpptools/uicodecompletionsupport.cpp | 197 | ||||
-rw-r--r-- | src/plugins/cpptools/uicodecompletionsupport.h | 70 |
14 files changed, 405 insertions, 43 deletions
diff --git a/src/plugins/cpptools/CppTools.pluginspec b/src/plugins/cpptools/CppTools.pluginspec.in index c7bd234c28..704a64f450 100644 --- a/src/plugins/cpptools/CppTools.pluginspec +++ b/src/plugins/cpptools/CppTools.pluginspec.in @@ -1,4 +1,4 @@ -<plugin name="CppTools" version="2.0.95" compatVersion="2.0.95"> +<plugin name=\"CppTools\" version=\"$$QTCREATOR_VERSION\" compatVersion=\"$$QTCREATOR_VERSION\"> <vendor>Nokia Corporation</vendor> <copyright>(C) 2010 Nokia Corporation</copyright> <license> @@ -14,9 +14,9 @@ Alternatively, this plugin may be used under the terms of the GNU Lesser General <description>Tools for analyzing C/C++ code.</description> <url>http://qt.nokia.com</url> <dependencyList> - <dependency name="TextEditor" version="2.0.95"/> - <dependency name="ProjectExplorer" version="2.0.95"/> - <dependency name="Locator" version="2.0.95"/> - <dependency name="Find" version="2.0.95"/> + <dependency name=\"TextEditor\" version=\"$$QTCREATOR_VERSION\"/> + <dependency name=\"ProjectExplorer\" version=\"$$QTCREATOR_VERSION\"/> + <dependency name=\"Locator\" version=\"$$QTCREATOR_VERSION\"/> + <dependency name=\"Find\" version=\"$$QTCREATOR_VERSION\"/> </dependencyList> </plugin> diff --git a/src/plugins/cpptools/completionsettingspage.cpp b/src/plugins/cpptools/completionsettingspage.cpp index 8e74bfed09..5df367d82f 100644 --- a/src/plugins/cpptools/completionsettingspage.cpp +++ b/src/plugins/cpptools/completionsettingspage.cpp @@ -44,7 +44,7 @@ using namespace CppTools::Internal; CompletionSettingsPage::CompletionSettingsPage() - : m_page(new Ui_CompletionSettingsPage) + : m_page(0) { } @@ -66,6 +66,7 @@ QString CompletionSettingsPage::displayName() const QWidget *CompletionSettingsPage::createPage(QWidget *parent) { QWidget *w = new QWidget(parent); + m_page = new Ui_CompletionSettingsPage; m_page->setupUi(w); const TextEditor::CompletionSettings &settings = @@ -117,6 +118,8 @@ QWidget *CompletionSettingsPage::createPage(QWidget *parent) void CompletionSettingsPage::apply() { + if (!m_page) // page was never shown + return; TextEditor::CompletionSettings settings; settings.m_caseSensitivity = caseSensitivity(); settings.m_completionTrigger = completionTrigger(); @@ -155,3 +158,11 @@ TextEditor::CompletionTrigger CompletionSettingsPage::completionTrigger() const return TextEditor::AutomaticCompletion; } } + +void CompletionSettingsPage::finish() +{ + if (!m_page) // page was never shown + return; + delete m_page; + m_page = 0; +} diff --git a/src/plugins/cpptools/completionsettingspage.h b/src/plugins/cpptools/completionsettingspage.h index 4cf2135f1d..f2927677cf 100644 --- a/src/plugins/cpptools/completionsettingspage.h +++ b/src/plugins/cpptools/completionsettingspage.h @@ -59,7 +59,7 @@ public: QWidget *createPage(QWidget *parent); void apply(); - void finish() { } + void finish(); virtual bool matches(const QString &) const; private: diff --git a/src/plugins/cpptools/cppcodecompletion.cpp b/src/plugins/cpptools/cppcodecompletion.cpp index 7e0d2502d2..9e3a5a534f 100644 --- a/src/plugins/cpptools/cppcodecompletion.cpp +++ b/src/plugins/cpptools/cppcodecompletion.cpp @@ -56,6 +56,8 @@ #include <cplusplus/BackwardsScanner.h> #include <cplusplus/LookupContext.h> +#include <cppeditor/cppeditorconstants.h> + #include <coreplugin/icore.h> #include <coreplugin/mimedatabase.h> #include <coreplugin/editormanager/editormanager.h> @@ -63,6 +65,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> @@ -466,7 +469,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(CppEditor::Constants::CPP_SNIPPETS_GROUP_ID, + QIcon(QLatin1String(":/texteditor/images/snippet.png"))) { } @@ -715,6 +719,31 @@ int CppCodeCompletion::startCompletion(TextEditor::ITextEditable *editor) { int index = startCompletionHelper(editor); if (index != -1) { + if (m_automaticCompletion) { + const int pos = editor->position(); + const QChar ch = editor->characterAt(pos); + if (! (ch.isLetterOrNumber() || ch == QLatin1Char('_'))) { + for (int i = pos - 1;; --i) { + const QChar ch = editor->characterAt(i); + if (ch.isLetterOrNumber() || ch == QLatin1Char('_')) { + const QString wordUnderCursor = editor->textAt(i, pos - i); + if (wordUnderCursor.at(0).isLetter() || wordUnderCursor.at(0) == QLatin1Char('_')) { + foreach (const TextEditor::CompletionItem &i, m_completions) { + if (i.text == wordUnderCursor) { + cleanup(); + return -1; + } + } + } else { + cleanup(); + return -1; + } + } else + break; + } + } + } + if (m_completionOperator != T_EOF_SYMBOL) qSort(m_completions.begin(), m_completions.end(), completionItemLessThan); @@ -755,12 +784,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(); @@ -1922,6 +1951,11 @@ void CppCodeCompletion::complete(const TextEditor::CompletionItem &item, QChar t } #endif } else if (! function->isAmbiguous()) { + // When the user typed the opening parenthesis, he'll likely also type the closing one, + // in which case it would be annoying if we put the cursor after the already automatically + // inserted closing parenthesis. + const bool skipClosingParenthesis = typedChar != QLatin1Char('('); + if (completionSettings().m_spaceAfterFunctionName) extraChars += QLatin1Char(' '); extraChars += QLatin1Char('('); @@ -1941,7 +1975,7 @@ void CppCodeCompletion::complete(const TextEditor::CompletionItem &item, QChar t } // If the function takes no arguments, automatically place the closing parenthesis - if (item.duplicateCount == 0 && ! function->hasArguments()) { + if (item.duplicateCount == 0 && ! function->hasArguments() && skipClosingParenthesis) { extraChars += QLatin1Char(')'); if (endWithSemicolon) { extraChars += semicolon; @@ -2062,8 +2096,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 7ac11c2821..46bb3945d8 100644 --- a/src/plugins/cpptools/cppcodecompletion.h +++ b/src/plugins/cpptools/cppcodecompletion.h @@ -41,7 +41,7 @@ #include <cplusplus/TypeOfExpression.h> #include <texteditor/icompletioncollector.h> -#include <texteditor/snippetsparser.h> +#include <texteditor/snippets/snippetcollector.h> #include <QtCore/QObject> #include <QtCore/QPointer> @@ -157,7 +157,7 @@ private: unsigned m_completionOperator; bool m_objcEnabled; - TextEditor::SnippetsParser m_snippetsParser; + TextEditor::SnippetCollector m_snippetProvider; CPlusPlus::Icons m_icons; CPlusPlus::Overview overview; diff --git a/src/plugins/cpptools/cppcodeformatter.cpp b/src/plugins/cpptools/cppcodeformatter.cpp index 281ce0c943..fdb179f3a4 100644 --- a/src/plugins/cpptools/cppcodeformatter.cpp +++ b/src/plugins/cpptools/cppcodeformatter.cpp @@ -386,6 +386,12 @@ void CodeFormatter::recalculateStateAfter(const QTextBlock &block) default: leave(); continue; } break; + case label: + switch (kind) { + case T_COLON: leave(); break; + default: leave(); continue; // shouldn't happen + } break; + case multiline_comment_start: case multiline_comment_cont: if (kind != T_COMMENT && kind != T_DOXY_COMMENT) { @@ -714,6 +720,10 @@ bool CodeFormatter::tryDeclaration() enter(qt_like_macro); return true; } + if (m_tokens.size() > 1 && m_tokens.at(1).kind() == T_COLON) { + enter(label); + return true; + } } // fallthrough case T_CHAR: @@ -1042,12 +1052,13 @@ void QtStyleCodeFormatter::onEnter(int newState, int *indentDepth, int *savedInd { const State &parentState = state(); const Token &tk = currentToken(); - const int tokenPosition = column(tk.begin()); const bool firstToken = (tokenIndex() == 0); const bool lastToken = (tokenIndex() == tokenCount() - 1); - int nextTokenStart = 0; - if (!lastToken) - nextTokenStart = column(tokenAt(tokenIndex() + 1).begin()); + const int tokenPosition = column(tk.begin()); + const int nextTokenPosition = lastToken ? tokenPosition + tk.length() + : column(tokenAt(tokenIndex() + 1).begin()); + const int spaceOrNextTokenPosition = lastToken ? tokenPosition + tk.length() + 1 + : nextTokenPosition; if (shouldClearPaddingOnEnter(newState)) *paddingDepth = 0; @@ -1071,7 +1082,7 @@ void QtStyleCodeFormatter::onEnter(int newState, int *indentDepth, int *savedInd case template_param: if (!lastToken) - *paddingDepth = tokenPosition-*indentDepth + tk.length(); + *paddingDepth = nextTokenPosition-*indentDepth; else { if (*paddingDepth == 0) *paddingDepth = 2*m_indentSize; @@ -1108,24 +1119,24 @@ void QtStyleCodeFormatter::onEnter(int newState, int *indentDepth, int *savedInd case arglist_open: case condition_paren_open: if (!lastToken) - *paddingDepth = tokenPosition-*indentDepth + 1; + *paddingDepth = nextTokenPosition-*indentDepth; else *paddingDepth += m_indentSize; break; case ternary_op: if (!lastToken) - *paddingDepth = tokenPosition-*indentDepth + tk.length() + 1; + *paddingDepth = spaceOrNextTokenPosition-*indentDepth; else *paddingDepth += m_indentSize; break; case stream_op: - *paddingDepth = tokenPosition-*indentDepth + tk.length() + 1; + *paddingDepth = spaceOrNextTokenPosition-*indentDepth; break; case stream_op_cont: if (firstToken) - *savedPaddingDepth = *paddingDepth = tokenPosition-*indentDepth + tk.length() + 1; + *savedPaddingDepth = *paddingDepth = spaceOrNextTokenPosition-*indentDepth; break; case member_init_open: @@ -1163,7 +1174,7 @@ void QtStyleCodeFormatter::onEnter(int newState, int *indentDepth, int *savedInd *indentDepth += m_indentSize; if (followedByData) { - *paddingDepth = column(tokenAt(tokenIndex() + 1).begin()) - *indentDepth; + *paddingDepth = nextTokenPosition-*indentDepth; } break; } @@ -1192,7 +1203,7 @@ void QtStyleCodeFormatter::onEnter(int newState, int *indentDepth, int *savedInd if (!lastToken) { if (parentState.type == initializer) *savedPaddingDepth = tokenPosition-*indentDepth; - *paddingDepth = nextTokenStart-*indentDepth; + *paddingDepth = nextTokenPosition-*indentDepth; } else { // avoid existing continuation indents if (parentState.type == initializer) @@ -1202,7 +1213,11 @@ void QtStyleCodeFormatter::onEnter(int newState, int *indentDepth, int *savedInd break; case block_open: - if (parentState.type != case_cont) + // case_cont already adds some indent, revert it for a block + if (parentState.type == case_cont && !m_indentSubstatementBraces) + *indentDepth = *savedIndentDepth = parentState.savedIndentDepth; + + if (m_indentSubstatementStatements) *indentDepth += m_indentSize; break; @@ -1212,10 +1227,10 @@ void QtStyleCodeFormatter::onEnter(int newState, int *indentDepth, int *savedInd *savedPaddingDepth = *paddingDepth; // fixed extra indent when continuing 'if (', but not for 'else if (' - if (tokenPosition <= *indentDepth + m_indentSize) + if (nextTokenPosition-*indentDepth <= m_indentSize) *paddingDepth = 2*m_indentSize; else - *paddingDepth = tokenPosition-*indentDepth + 1; + *paddingDepth = nextTokenPosition-*indentDepth; break; case substatement: @@ -1235,11 +1250,11 @@ void QtStyleCodeFormatter::onEnter(int newState, int *indentDepth, int *savedInd } break; case for_statement_paren_open: - *paddingDepth = tokenPosition + 1 - *indentDepth; + *paddingDepth = nextTokenPosition - *indentDepth; break; case multiline_comment_start: - *indentDepth = tokenPosition + 2; + *indentDepth = tokenPosition + 2; // nextTokenPosition won't work break; case multiline_comment_cont: @@ -1306,6 +1321,8 @@ void QtStyleCodeFormatter::adjustIndent(const QList<CPlusPlus::Token> &tokens, i case T_LBRACE: { if (topState.type == case_cont) { *indentDepth = topState.savedIndentDepth; + if (m_indentSubstatementBraces) + *indentDepth += m_indentSize; *paddingDepth = 0; // function definition - argument list is expression state } else if (topState.type == expression && previousState.type == declaration_start) { @@ -1336,8 +1353,8 @@ void QtStyleCodeFormatter::adjustIndent(const QList<CPlusPlus::Token> &tokens, i } case T_RBRACE: { if (topState.type == block_open && previousState.type == case_cont) { - *indentDepth = previousState.savedIndentDepth; - *paddingDepth = previousState.savedPaddingDepth; + *indentDepth = topState.savedIndentDepth; + *paddingDepth = topState.savedPaddingDepth; break; } for (int i = 0; state(i).type != topmost_intro; ++i) { @@ -1369,10 +1386,16 @@ void QtStyleCodeFormatter::adjustIndent(const QList<CPlusPlus::Token> &tokens, i // } // break; case T_DEFAULT: - case T_CASE: + case T_CASE: { + int lastSubstatementIndent = 0; for (int i = 0; state(i).type != topmost_intro; ++i) { const int type = state(i).type; - if (type == switch_statement || type == case_cont) { + if (type == substatement_open) { + lastSubstatementIndent = state(i).savedIndentDepth; + } else if (type == switch_statement) { + *indentDepth = lastSubstatementIndent; + break; + } else if (type == case_cont) { *indentDepth = state(i).savedIndentDepth; break; } else if (type == topmost_intro) { @@ -1380,6 +1403,7 @@ void QtStyleCodeFormatter::adjustIndent(const QList<CPlusPlus::Token> &tokens, i } } break; + } case T_PUBLIC: case T_PRIVATE: case T_PROTECTED: @@ -1418,6 +1442,16 @@ void QtStyleCodeFormatter::adjustIndent(const QList<CPlusPlus::Token> &tokens, i *indentDepth = 0; } break; + case T_IDENTIFIER: + if (topState.type == substatement + || topState.type == substatement_open + || topState.type == case_cont + || topState.type == block_open + || topState.type == defun_open) { + if (tokens.size() > 1 && tokens.at(1).kind() == T_COLON) // label? + *indentDepth = 0; + } + break; } } diff --git a/src/plugins/cpptools/cppcodeformatter.h b/src/plugins/cpptools/cppcodeformatter.h index 2034d8771d..a556ced7d5 100644 --- a/src/plugins/cpptools/cppcodeformatter.h +++ b/src/plugins/cpptools/cppcodeformatter.h @@ -54,7 +54,7 @@ namespace TextEditor { class TabSettings; } -namespace CppTools { +namespace CppTools { namespace Internal { class CppCodeFormatterData; } @@ -116,6 +116,7 @@ public: // must be public to make Q_GADGET introspection work cpp_macro_cont, // Subsequent lines of a multi-line C preprocessor macro definition. cpp_macro_conditional, // Special marker used for separating saved from current state when dealing with #ifdef qt_like_macro, // after an identifier starting with Q_ or QT_ at the beginning of the line + label, // after an identifier followed by a colon defun_open, // Brace that opens a top-level function definition. using_start, // right after the "using" token @@ -173,7 +174,7 @@ public: // must be public to make Q_GADGET introspection work assign_open, // after an assignment token expression, // after a '=' in a declaration_start once we're sure it's not '= {' - initializer, // after a '=' in a declaration start + initializer // after a '=' in a declaration start }; Q_ENUMS(StateType) diff --git a/src/plugins/cpptools/cppfilesettingspage.cpp b/src/plugins/cpptools/cppfilesettingspage.cpp index 401c6bcb47..35f74d672a 100644 --- a/src/plugins/cpptools/cppfilesettingspage.cpp +++ b/src/plugins/cpptools/cppfilesettingspage.cpp @@ -49,6 +49,7 @@ #include <QtCore/QCoreApplication> #include <QtCore/QDate> #include <QtCore/QLocale> +#include <QtCore/QTextCodec> #include <QtCore/QTextStream> #include <QtGui/QFileDialog> @@ -120,6 +121,14 @@ static bool keyWordReplacement(const QString &keyWord, *value = QString::number(QDate::currentDate().year()); return true; } + if (keyWord == QLatin1String("%MONTH%")) { + *value = QString::number(QDate::currentDate().month()); + return true; + } + if (keyWord == QLatin1String("%DAY%")) { + *value = QString::number(QDate::currentDate().day()); + return true; + } if (keyWord == QLatin1String("%CLASS%")) { *value = className; return true; @@ -204,7 +213,13 @@ QString CppFileSettings::licenseTemplate(const QString &fileName, const QString qWarning("Unable to open the license template %s: %s", qPrintable(path), qPrintable(file.errorString())); return QString(); } - QString license = QString::fromUtf8(file.readAll()); + + QTextCodec *codec = Core::EditorManager::instance()->defaultTextEncoding(); + QTextStream licenseStream(&file); + licenseStream.setCodec(codec); + licenseStream.setAutoDetectUnicode(true); + QString license = licenseStream.readAll(); + parseLicenseTemplatePlaceholders(&license, fileName, className); // Ensure exactly one additional new line separating stuff const QChar newLine = QLatin1Char('\n'); diff --git a/src/plugins/cpptools/cpptools.pri b/src/plugins/cpptools/cpptools.pri index 1dffbfc556..5732e896e7 100644 --- a/src/plugins/cpptools/cpptools.pri +++ b/src/plugins/cpptools/cpptools.pri @@ -1,3 +1,3 @@ include(cpptools_dependencies.pri) -LIBS *= -l$$qtLibraryTarget(CppTools) +LIBS *= -l$$qtLibraryName(CppTools) diff --git a/src/plugins/cpptools/cpptools.pro b/src/plugins/cpptools/cpptools.pro index 8062333db7..57507f3612 100644 --- a/src/plugins/cpptools/cpptools.pro +++ b/src/plugins/cpptools/cpptools.pro @@ -26,6 +26,7 @@ HEADERS += completionsettingspage.h \ cppfindreferences.h \ cppcodeformatter.h \ symbolsfindfilter.h \ + uicodecompletionsupport.h \ insertionpointlocator.h \ cpprefactoringchanges.h @@ -45,10 +46,9 @@ SOURCES += completionsettingspage.cpp \ cppfindreferences.cpp \ cppcodeformatter.cpp \ symbolsfindfilter.cpp \ + uicodecompletionsupport.cpp \ insertionpointlocator.cpp \ cpprefactoringchanges.cpp FORMS += completionsettingspage.ui \ cppfilesettingspage.ui - -OTHER_FILES += CppTools.pluginspec diff --git a/src/plugins/cpptools/cpptoolsplugin.cpp b/src/plugins/cpptools/cpptoolsplugin.cpp index 22419d23dd..947675e624 100644 --- a/src/plugins/cpptools/cpptoolsplugin.cpp +++ b/src/plugins/cpptools/cpptoolsplugin.cpp @@ -51,6 +51,7 @@ #include <coreplugin/actionmanager/actionmanager.h> #include <coreplugin/actionmanager/actioncontainer.h> #include <coreplugin/actionmanager/command.h> +#include <coreplugin/uniqueidmanager.h> #include <coreplugin/editormanager/editormanager.h> #include <coreplugin/progressmanager/progressmanager.h> #include <coreplugin/vcsmanager.h> @@ -105,7 +106,7 @@ bool CppToolsPlugin::initialize(const QStringList &arguments, QString *error) // Objects m_modelManager = new CppModelManager(this); - Core::VCSManager *vcsManager = core->vcsManager(); + Core::VcsManager *vcsManager = core->vcsManager(); Core::FileManager *fileManager = core->fileManager(); connect(vcsManager, SIGNAL(repositoryChanged(QString)), m_modelManager, SLOT(updateModifiedSourceFiles())); diff --git a/src/plugins/cpptools/insertionpointlocator.h b/src/plugins/cpptools/insertionpointlocator.h index bc250fcb8e..f475041fa2 100644 --- a/src/plugins/cpptools/insertionpointlocator.h +++ b/src/plugins/cpptools/insertionpointlocator.h @@ -98,7 +98,7 @@ public: PublicSlot = Public | SlotBit, ProtectedSlot = Protected | SlotBit, - PrivateSlot = Private | SlotBit, + PrivateSlot = Private | SlotBit }; public: diff --git a/src/plugins/cpptools/uicodecompletionsupport.cpp b/src/plugins/cpptools/uicodecompletionsupport.cpp new file mode 100644 index 0000000000..dc226b09a3 --- /dev/null +++ b/src/plugins/cpptools/uicodecompletionsupport.cpp @@ -0,0 +1,197 @@ +/************************************************************************** +** +** 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 "uicodecompletionsupport.h" +#include <QtCore/QProcess> + +enum { debug = 0 }; + +using namespace CppTools; + +UiCodeModelSupport::UiCodeModelSupport(CppTools::CppModelManagerInterface *modelmanager, + const QString &source, + const QString &uiHeaderFile) + : CppTools::AbstractEditorSupport(modelmanager), + m_sourceName(source), + m_fileName(uiHeaderFile), + m_updateIncludingFiles(false), + m_initialized(false) +{ + if (debug) + qDebug()<<"ctor UiCodeModelSupport for"<<m_sourceName<<uiHeaderFile; +} + +UiCodeModelSupport::~UiCodeModelSupport() +{ + if (debug) + qDebug()<<"dtor ~UiCodeModelSupport for"<<m_sourceName; +} + +void UiCodeModelSupport::init() const +{ + m_initialized = true; + QDateTime sourceTime = QFileInfo(m_sourceName).lastModified(); + QFileInfo uiHeaderFileInfo(m_fileName); + QDateTime uiHeaderTime = uiHeaderFileInfo.exists() ? uiHeaderFileInfo.lastModified() : QDateTime(); + if (uiHeaderTime.isValid() && (uiHeaderTime > sourceTime)) { + QFile file(m_fileName); + if (file.open(QFile::ReadOnly)) { + if (debug) + qDebug()<<"ui*h file is more recent then source file, using information from ui*h file"<<m_fileName; + QTextStream stream(&file); + m_contents = stream.readAll().toUtf8(); + m_cacheTime = uiHeaderTime; + return; + } + } + + if (debug) + qDebug()<<"ui*h file not found, or not recent enough, trying to create it on the fly"; + QFile file(m_sourceName); + if (file.open(QFile::ReadOnly)) { + QTextStream stream(&file); + const QString contents = stream.readAll(); + if (runUic(contents)) { + if (debug) + qDebug()<<"created on the fly"; + return; + } else { + // uic run was unsuccesfull + if (debug) + qDebug()<<"uic run wasn't succesfull"; + m_cacheTime = QDateTime (); + m_contents = QByteArray(); + // and if the header file wasn't there, next time we need to update + // all of the files that include this header + if (!uiHeaderFileInfo.exists()) + m_updateIncludingFiles = true; + return; + } + } else { + if (debug) + qDebug()<<"Could open "<<m_sourceName<<"needed for the cpp model"; + m_contents = QByteArray(); + } +} + +QByteArray UiCodeModelSupport::contents() const +{ + if (!m_initialized) + init(); + + return m_contents; +} + +QString UiCodeModelSupport::fileName() const +{ + return m_fileName; +} + +void UiCodeModelSupport::setFileName(const QString &name) +{ + if (m_fileName == name && m_cacheTime.isValid()) + return; + + if (debug) + qDebug() << "UiCodeModelSupport::setFileName"<<name; + + m_fileName = name; + m_contents.clear(); + m_cacheTime = QDateTime(); + init(); +} + +bool UiCodeModelSupport::runUic(const QString &ui) const +{ + QProcess process; + const QString uic = uicCommand(); + process.setEnvironment(environment()); + + if (debug) + qDebug() << "UiCodeModelSupport::runUic " << uic << " on " << ui.size() << " bytes"; + process.start(uic, QStringList(), QIODevice::ReadWrite); + if (!process.waitForStarted()) + return false; + process.write(ui.toUtf8()); + process.closeWriteChannel(); + if (process.waitForFinished() && process.exitStatus() == QProcess::NormalExit && process.exitCode() == 0) { + m_contents = process.readAllStandardOutput(); + m_cacheTime = QDateTime::currentDateTime(); + if (debug) + qDebug() << "ok" << m_contents.size() << "bytes."; + return true; + } else { + if (debug) + qDebug() << "failed" << process.readAllStandardError(); + process.kill(); + } + return false; +} + +void UiCodeModelSupport::updateFromEditor(const QString &formEditorContents) +{ + if (runUic(formEditorContents)) { + updateDocument(); + } +} + +void UiCodeModelSupport::updateFromBuild() +{ + if (debug) + qDebug()<<"UiCodeModelSupport::updateFromBuild() for file"<<m_sourceName; + // This is mostly a fall back for the cases when uic couldn't be run + // it pays special attention to the case where a ui_*h was newly created + QDateTime sourceTime = QFileInfo(m_sourceName).lastModified(); + if (m_cacheTime.isValid() && m_cacheTime >= sourceTime) { + if (debug) + qDebug()<<"Cache is still more recent then source"; + return; + } else { + QFileInfo fi(m_fileName); + QDateTime uiHeaderTime = fi.exists() ? fi.lastModified() : QDateTime(); + if (uiHeaderTime.isValid() && (uiHeaderTime > sourceTime)) { + if (m_cacheTime >= uiHeaderTime) + return; + if (debug) + qDebug()<<"found ui*h updating from it"; + + QFile file(m_fileName); + if (file.open(QFile::ReadOnly)) { + QTextStream stream(&file); + m_contents = stream.readAll().toUtf8(); + m_cacheTime = uiHeaderTime; + updateDocument(); + return; + } + } + if (debug) + qDebug()<<"ui*h not found or not more recent then source not changing anything"; + } +} + diff --git a/src/plugins/cpptools/uicodecompletionsupport.h b/src/plugins/cpptools/uicodecompletionsupport.h new file mode 100644 index 0000000000..b03294960d --- /dev/null +++ b/src/plugins/cpptools/uicodecompletionsupport.h @@ -0,0 +1,70 @@ +/************************************************************************** +** +** 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 UICODECOMPLETIONSUPPORT_H +#define UICODECOMPLETIONSUPPORT_H + +#include "cppmodelmanagerinterface.h" +#include "cpptools_global.h" + +#include <QtCore/QDateTime> + +namespace CppTools { + +class CPPTOOLS_EXPORT UiCodeModelSupport : public CppTools::AbstractEditorSupport +{ +public: + UiCodeModelSupport(CppTools::CppModelManagerInterface *modelmanager, + const QString &sourceFile, + const QString &uiHeaderFile); + ~UiCodeModelSupport(); + void setFileName(const QString &name); + void setSourceName(const QString &name); + virtual QByteArray contents() const; + virtual QString fileName() const; + void updateFromEditor(const QString &formEditorContents); + void updateFromBuild(); +protected: + virtual QString uicCommand() const = 0; + virtual QStringList environment() const = 0; +private: + void init() const; + bool runUic(const QString &ui) const; + QString m_sourceName; + QString m_fileName; + mutable bool m_updateIncludingFiles; + mutable bool m_initialized; + mutable QByteArray m_contents; + mutable QDateTime m_cacheTime; +}; + +} // CppTools + +#endif // UICODECOMPLETIONSUPPORT_H |