diff --git a/.gitignore b/.gitignore index 0f3b119423db74e21ab8914f97c254e51436f672..f140cb47ca629d575e58f819b212b4340d137f7b 100644 --- a/.gitignore +++ b/.gitignore @@ -68,8 +68,8 @@ src/corelib/lib src/network/lib src/xml/lib/ -# Files copied by syncIde -# ----------------------- +# Binaries +# -------- bin/Aggregation.dll bin/CodeModel.dll bin/ExtensionSystem.dll @@ -77,24 +77,4 @@ bin/QtConcurrent.dll bin/Utils.dll bin/qtcreator bin/qtcreator.exe -shared/help/bookmarkdialog.ui -shared/help/bookmarkmanager.cpp -shared/help/bookmarkmanager.h -shared/help/contentwindow.cpp -shared/help/contentwindow.h -shared/help/filternamedialog.cpp -shared/help/filternamedialog.h -shared/help/filternamedialog.ui -shared/help/helpviewer.cpp -shared/help/helpviewer.h -shared/help/indexwindow.cpp -shared/help/indexwindow.h -shared/help/topicchooser.cpp -shared/help/topicchooser.h -shared/help/topicchooser.ui -shared/proparser/abstractproitemvisitor.h -shared/proparser/profileevaluator.cpp -shared/proparser/profileevaluator.h -shared/proparser/proitems.cpp -shared/proparser/proitems.h -shared/proparser/proparserutils.h +tests/manual/cplusplus/cplusplus0 diff --git a/shared/cplusplus/Parser.cpp b/shared/cplusplus/Parser.cpp index 46618dd112b8c653b33652ba41100a4109d31538..13fbaa0160b6185e3a9609085d10c13f708fa97c 100644 --- a/shared/cplusplus/Parser.cpp +++ b/shared/cplusplus/Parser.cpp @@ -1191,6 +1191,11 @@ bool Parser::parseClassSpecifier(SpecifierAST *&node) NameAST *name = 0; parseName(name); + bool parsed = false; + + const bool previousInFunctionBody = _inFunctionBody; + _inFunctionBody = false; + if (LA() == T_COLON || LA() == T_LBRACE) { BaseSpecifierAST *base_clause = 0; if (LA() == T_COLON) { @@ -1233,9 +1238,12 @@ bool Parser::parseClassSpecifier(SpecifierAST *&node) } } node = ast; - return true; + parsed = true; } - return false; + + _inFunctionBody = previousInFunctionBody; + + return parsed; } bool Parser::parseAccessSpecifier(SpecifierAST *&node) diff --git a/shared/cplusplus/Scope.cpp b/shared/cplusplus/Scope.cpp index 2c1b986b2c9f48d5afc19a08f5bcb0fc7b90f629..47221da121f58bd39c596bdba6e6b7f69d0067cb 100644 --- a/shared/cplusplus/Scope.cpp +++ b/shared/cplusplus/Scope.cpp @@ -292,6 +292,7 @@ Use *Scope::useAt(unsigned index) const void Scope::addUse(unsigned sourceOffset, Name *name) { +#ifdef CPLUSPLUS_WITH_USES if (++_useCount == _allocatedUses) { _allocatedUses += 4; _uses = reinterpret_cast<Use *>(realloc(_uses, _allocatedUses * sizeof(Use))); @@ -303,6 +304,7 @@ void Scope::addUse(unsigned sourceOffset, Name *name) else lastVisibleSymbol = _symbols[_symbolCount]; _uses[_useCount].init(sourceOffset, name, lastVisibleSymbol); +#endif } CPLUSPLUS_END_NAMESPACE diff --git a/shared/help/help.pri b/shared/help/help.pri index 9503d085938b6ae619b5d2567fa3fe8a163ec88a..dff0ae7699b673175d3571ba8d4ffa952340805e 100644 --- a/shared/help/help.pri +++ b/shared/help/help.pri @@ -9,7 +9,8 @@ HEADERS += \ $$PWD/helpviewer.h \ $$PWD/contentwindow.h \ $$PWD/bookmarkmanager.h \ - $$PWD/../namespace_global.h + $$PWD/../namespace_global.h \ + $$PWD/indexwindow.h SOURCES += \ $$PWD/filternamedialog.cpp \ @@ -19,7 +20,7 @@ SOURCES += \ $$PWD/contentwindow.cpp \ $$PWD/bookmarkmanager.cpp -FORMS += \ +FORMS += \ $$PWD/filternamedialog.ui \ $$PWD/topicchooser.ui \ $$PWD/bookmarkdialog.ui diff --git a/src/libs/cplusplus/CppDocument.cpp b/src/libs/cplusplus/CppDocument.cpp index 782c14ff6d556ecac284d71a567d619d1e52d145..3a280416d9b881631dac42e8486f7a9834a1ec0d 100644 --- a/src/libs/cplusplus/CppDocument.cpp +++ b/src/libs/cplusplus/CppDocument.cpp @@ -153,6 +153,11 @@ void Document::appendMacro(const QByteArray ¯oName, const QByteArray &text) _definedMacros += text; } +void Document::addMacroUse(unsigned offset, unsigned length) +{ + _macroUses.append(Block(offset, offset + length)); +} + TranslationUnit *Document::translationUnit() const { return _translationUnit; diff --git a/src/libs/cplusplus/CppDocument.h b/src/libs/cplusplus/CppDocument.h index 17762200fa03c99fdde3871c5c9398c07720f411..e952913a07b7d75e37648b7af0117e180845f4cb 100644 --- a/src/libs/cplusplus/CppDocument.h +++ b/src/libs/cplusplus/CppDocument.h @@ -68,6 +68,8 @@ public: void appendMacro(const QByteArray ¯oName, const QByteArray &text); + void addMacroUse(unsigned offset, unsigned length); + Control *control() const; TranslationUnit *translationUnit() const; @@ -176,6 +178,9 @@ public: QList<Block> skippedBlocks() const { return _skippedBlocks; } + QList<Block> macroUses() const + { return _macroUses; } + private: Symbol *findSymbolAt(unsigned line, unsigned column, Scope *scope) const; @@ -189,6 +194,7 @@ private: QByteArray _definedMacros; QSet<QByteArray> _macroNames; QList<Block> _skippedBlocks; + QList<Block> _macroUses; }; } // end of namespace CPlusPlus diff --git a/src/libs/cplusplus/ResolveExpression.cpp b/src/libs/cplusplus/ResolveExpression.cpp index 019cbfff1ff1656321b595a49c702992ced15950..cfcd06cacd7067b55000916460c59aa08dcb5c83 100644 --- a/src/libs/cplusplus/ResolveExpression.cpp +++ b/src/libs/cplusplus/ResolveExpression.cpp @@ -235,9 +235,9 @@ bool ResolveExpression::visit(ExpressionListAST *) return false; } -bool ResolveExpression::visit(BinaryExpressionAST *) +bool ResolveExpression::visit(BinaryExpressionAST *ast) { - // nothing to do. + accept(ast->left_expression); return false; } diff --git a/src/libs/cplusplus/TypeOfExpression.cpp b/src/libs/cplusplus/TypeOfExpression.cpp index 2672bfb105f1422b8d39f3da2941d0ee280d2dfa..7dd669365fc3ec8bf3be89b6cf5e7c8ca8210759 100644 --- a/src/libs/cplusplus/TypeOfExpression.cpp +++ b/src/libs/cplusplus/TypeOfExpression.cpp @@ -91,7 +91,8 @@ Document::Ptr TypeOfExpression::documentForExpression(const QString &expression) { // create the expression's AST. Document::Ptr doc = Document::create(QLatin1String("<completion>")); - doc->setSource(expression.toUtf8()); + const QByteArray bytes = expression.toUtf8(); + doc->setSource(bytes); doc->parse(Document::ParseExpression); return doc; } diff --git a/src/libs/utils/filesearch.cpp b/src/libs/utils/filesearch.cpp index 6286b780d30db94e67f85d7f1cafe87c2c2712d4..153b9531742b3f5f5345d57e8b7844e050f650da 100644 --- a/src/libs/utils/filesearch.cpp +++ b/src/libs/utils/filesearch.cpp @@ -165,7 +165,7 @@ void runFileSearchRegExp(QFutureInterface<FileSearchResult> &future, int numFilesSearched = 0; int numMatches = 0; if (flags & QTextDocument::FindWholeWords) - searchTerm = QString("\b%1\b").arg(searchTerm); + searchTerm = QString("\\b%1\\b").arg(searchTerm); Qt::CaseSensitivity caseSensitivity = (flags & QTextDocument::FindCaseSensitively) ? Qt::CaseSensitive : Qt::CaseInsensitive; QRegExp expression(searchTerm, caseSensitivity); diff --git a/src/libs/utils/filewizarddialog.cpp b/src/libs/utils/filewizarddialog.cpp index 8608fed73ec6a0ed0bba88bce98cca01dcb29d9b..8441cdb86380e7add0b1f572296e5bd79d723f70 100644 --- a/src/libs/utils/filewizarddialog.cpp +++ b/src/libs/utils/filewizarddialog.cpp @@ -44,6 +44,8 @@ FileWizardDialog::FileWizardDialog(QWidget *parent) : m_filePage(new FileWizardPage) { setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint); + setOption(QWizard::NoCancelButton, false); + setOption(QWizard::NoDefaultButton, false); setPixmap(QWizard::WatermarkPixmap, QPixmap(QLatin1String(":/qworkbench/images/qtwatermark.png"))); addPage(m_filePage); connect(m_filePage, SIGNAL(activated()), button(QWizard::FinishButton), SLOT(animateClick())); diff --git a/src/libs/utils/synchronousprocess.cpp b/src/libs/utils/synchronousprocess.cpp index 078373aa20837842dc505edbf791703539c73a06..6a1b2efa8403d49a73c39712b054a1396717edff 100644 --- a/src/libs/utils/synchronousprocess.cpp +++ b/src/libs/utils/synchronousprocess.cpp @@ -125,6 +125,7 @@ struct SynchronousProcessPrivate { SynchronousProcessResponse m_result; int m_hangTimerCount; int m_maxHangTimerCount; + bool m_startFailure; ChannelBuffer m_stdOut; ChannelBuffer m_stdErr; @@ -133,7 +134,8 @@ struct SynchronousProcessPrivate { SynchronousProcessPrivate::SynchronousProcessPrivate() : m_stdOutCodec(0), m_hangTimerCount(0), - m_maxHangTimerCount(defaultMaxHangTimerCount) + m_maxHangTimerCount(defaultMaxHangTimerCount), + m_startFailure(false) { } @@ -143,6 +145,7 @@ void SynchronousProcessPrivate::clearForRun() m_stdOut.clearForRun(); m_stdErr.clearForRun(); m_result.clear(); + m_startFailure = false; } // ----------- SynchronousProcess @@ -221,22 +224,26 @@ SynchronousProcessResponse SynchronousProcess::run(const QString &binary, qDebug() << '>' << Q_FUNC_INFO << binary << args; m_d->clearForRun(); - m_d->m_timer.start(); - - QApplication::setOverrideCursor(Qt::WaitCursor); + // On Windows, start failure is triggered immediately if the + // executable cannot be found in the path. Do not start the + // event loop in that case. m_d->m_process.start(binary, args, QIODevice::ReadOnly); - m_d->m_eventLoop.exec(QEventLoop::ExcludeUserInputEvents); - if (m_d->m_result.result == SynchronousProcessResponse::Finished || m_d->m_result.result == SynchronousProcessResponse::FinishedError) { - processStdOut(false); - processStdErr(false); - } + if (!m_d->m_startFailure) { + m_d->m_timer.start(); + QApplication::setOverrideCursor(Qt::WaitCursor); + m_d->m_eventLoop.exec(QEventLoop::ExcludeUserInputEvents); + if (m_d->m_result.result == SynchronousProcessResponse::Finished || m_d->m_result.result == SynchronousProcessResponse::FinishedError) { + processStdOut(false); + processStdErr(false); + } - m_d->m_result.stdOut = convertStdOut(m_d->m_stdOut.data); - m_d->m_result.stdErr = convertStdErr(m_d->m_stdErr.data); + m_d->m_result.stdOut = convertStdOut(m_d->m_stdOut.data); + m_d->m_result.stdErr = convertStdErr(m_d->m_stdErr.data); - m_d->m_timer.stop(); - QApplication::restoreOverrideCursor(); + m_d->m_timer.stop(); + QApplication::restoreOverrideCursor(); + } if (debug) qDebug() << '<' << Q_FUNC_INFO << binary << m_d->m_result; @@ -246,12 +253,14 @@ SynchronousProcessResponse SynchronousProcess::run(const QString &binary, void SynchronousProcess::slotTimeout() { if (++m_d->m_hangTimerCount > m_d->m_maxHangTimerCount) { + if (debug) + qDebug() << Q_FUNC_INFO << "HANG detected, killing"; m_d->m_process.kill(); m_d->m_result.result = SynchronousProcessResponse::Hang; + } else { + if (debug) + qDebug() << Q_FUNC_INFO << m_d->m_hangTimerCount; } - - if (debug) - qDebug() << Q_FUNC_INFO << m_d->m_hangTimerCount; } void SynchronousProcess::finished(int exitCode, QProcess::ExitStatus e) @@ -265,7 +274,9 @@ void SynchronousProcess::finished(int exitCode, QProcess::ExitStatus e) m_d->m_result.exitCode = exitCode; break; case QProcess::CrashExit: - m_d->m_result.result = SynchronousProcessResponse::TerminatedAbnormally; + // Was hang detected before and killed? + if (m_d->m_result.result != SynchronousProcessResponse::Hang) + m_d->m_result.result = SynchronousProcessResponse::TerminatedAbnormally; m_d->m_result.exitCode = -1; break; } @@ -277,7 +288,10 @@ void SynchronousProcess::error(QProcess::ProcessError e) m_d->m_hangTimerCount = 0; if (debug) qDebug() << Q_FUNC_INFO << e; - m_d->m_result.result = SynchronousProcessResponse::StartFailed; + // Was hang detected before and killed? + if (m_d->m_result.result != SynchronousProcessResponse::Hang) + m_d->m_result.result = SynchronousProcessResponse::StartFailed; + m_d->m_startFailure = true; m_d->m_eventLoop.quit(); } diff --git a/src/plugins/cmakeprojectmanager/cmakeprojectconstants.h b/src/plugins/cmakeprojectmanager/cmakeprojectconstants.h index 516e3e61754d8d31ea41eea7ee5985a3e3407cfb..4832f17f26383d9deab8e48d2f9820068e95fa0e 100644 --- a/src/plugins/cmakeprojectmanager/cmakeprojectconstants.h +++ b/src/plugins/cmakeprojectmanager/cmakeprojectconstants.h @@ -40,6 +40,7 @@ namespace Constants { const char * const PROJECTCONTEXT = "CMakeProject.ProjectContext"; const char * const CMAKEMIMETYPE = "text/x-cmake"; // TOOD check that this is correct const char * const CMAKESTEP = "CMakeProjectManager.CMakeStep"; +const char * const MAKESTEP = "CMakeProjectManager.MakeStep"; } // namespace Constants diff --git a/src/plugins/cmakeprojectmanager/cmakeprojectmanager.pro b/src/plugins/cmakeprojectmanager/cmakeprojectmanager.pro index 3d427a93d8b4b2237610dcf529ccfad2b442daa9..afca26b265b2d355d643d0c9c3f4ad7d385372da 100644 --- a/src/plugins/cmakeprojectmanager/cmakeprojectmanager.pro +++ b/src/plugins/cmakeprojectmanager/cmakeprojectmanager.pro @@ -7,10 +7,12 @@ HEADERS = cmakeproject.h \ cmakeprojectmanager.h \ cmakeprojectconstants.h \ cmakeprojectnodes.h \ - cmakestep.h + cmakestep.h \ + makestep.h SOURCES = cmakeproject.cpp \ cmakeprojectplugin.cpp \ cmakeprojectmanager.cpp \ cmakeprojectnodes.cpp \ - cmakestep.cpp + cmakestep.cpp \ + makestep.cpp RESOURCES += cmakeproject.qrc diff --git a/src/plugins/cmakeprojectmanager/cmakestep.cpp b/src/plugins/cmakeprojectmanager/cmakestep.cpp index 821bf6b1beca5b1b356adfa8d12430eaa7626325..523741c92ba9e16d838f4747f3dbcf8e1096eed5 100644 --- a/src/plugins/cmakeprojectmanager/cmakestep.cpp +++ b/src/plugins/cmakeprojectmanager/cmakestep.cpp @@ -1,3 +1,36 @@ +/*************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Qt Software Information (qt-info@nokia.com) +** +** +** Non-Open Source Usage +** +** Licensees may use this file in accordance with the Qt Beta Version +** License Agreement, Agreement version 2.2 provided with the Software or, +** alternatively, in accordance with the terms contained in a written +** agreement between you and Nokia. +** +** GNU General Public License Usage +** +** Alternatively, this file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the packaging +** of this file. Please review the following information to ensure GNU +** General Public Licensing requirements will be met: +** +** http://www.fsf.org/licensing/licenses/info/GPLv2.html and +** http://www.gnu.org/copyleft/gpl.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt GPL Exception +** version 1.2, included in the file GPL_EXCEPTION.txt in this package. +** +***************************************************************************/ + #include "cmakestep.h" #include "cmakeprojectconstants.h" #include "cmakeproject.h" @@ -6,7 +39,7 @@ using namespace CMakeProjectManager; using namespace CMakeProjectManager::Internal; CMakeStep::CMakeStep(CMakeProject *pro) - : BuildStep(pro), m_pro(pro) + : AbstractProcessStep(pro), m_pro(pro) { } @@ -18,14 +51,17 @@ CMakeStep::~CMakeStep() bool CMakeStep::init(const QString &buildConfiguration) { - // TODO - return true; + setEnabled(buildConfiguration, true); + setWorkingDirectory(buildConfiguration, m_pro->buildDirectory(buildConfiguration)); + setCommand(buildConfiguration, "cmake"); // TODO give full path here? + setArguments(buildConfiguration, QStringList()); // TODO + setEnvironment(buildConfiguration, m_pro->environment(buildConfiguration)); + return AbstractProcessStep::init(buildConfiguration); } void CMakeStep::run(QFutureInterface<bool> &fi) { - // TODO - fi.reportResult(true); + AbstractProcessStep::run(fi); } QString CMakeStep::name() diff --git a/src/plugins/cmakeprojectmanager/cmakestep.h b/src/plugins/cmakeprojectmanager/cmakestep.h index dea4499efc4fc3c6b05abc9d6772f6d5554528b4..75cc0d6ba3804b8eef0a51b810121097a0ba174c 100644 --- a/src/plugins/cmakeprojectmanager/cmakestep.h +++ b/src/plugins/cmakeprojectmanager/cmakestep.h @@ -1,7 +1,41 @@ +/*************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Qt Software Information (qt-info@nokia.com) +** +** +** Non-Open Source Usage +** +** Licensees may use this file in accordance with the Qt Beta Version +** License Agreement, Agreement version 2.2 provided with the Software or, +** alternatively, in accordance with the terms contained in a written +** agreement between you and Nokia. +** +** GNU General Public License Usage +** +** Alternatively, this file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the packaging +** of this file. Please review the following information to ensure GNU +** General Public Licensing requirements will be met: +** +** http://www.fsf.org/licensing/licenses/info/GPLv2.html and +** http://www.gnu.org/copyleft/gpl.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt GPL Exception +** version 1.2, included in the file GPL_EXCEPTION.txt in this package. +** +***************************************************************************/ + #ifndef CMAKESTEP_H #define CMAKESTEP_H #include <projectexplorer/buildstep.h> +#include <projectexplorer/abstractprocessstep.h> namespace CMakeProjectManager { namespace Internal { @@ -10,7 +44,7 @@ class CMakeProject; class CMakeBuildStepConfigWidget; -class CMakeStep : public ProjectExplorer::BuildStep +class CMakeStep : public ProjectExplorer::AbstractProcessStep { public: CMakeStep(CMakeProject *pro); diff --git a/src/plugins/cmakeprojectmanager/makestep.cpp b/src/plugins/cmakeprojectmanager/makestep.cpp new file mode 100644 index 0000000000000000000000000000000000000000..6bb5b59cdf81833ee87147501c118ae408083753 --- /dev/null +++ b/src/plugins/cmakeprojectmanager/makestep.cpp @@ -0,0 +1,127 @@ +/*************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Qt Software Information (qt-info@nokia.com) +** +** +** Non-Open Source Usage +** +** Licensees may use this file in accordance with the Qt Beta Version +** License Agreement, Agreement version 2.2 provided with the Software or, +** alternatively, in accordance with the terms contained in a written +** agreement between you and Nokia. +** +** GNU General Public License Usage +** +** Alternatively, this file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the packaging +** of this file. Please review the following information to ensure GNU +** General Public Licensing requirements will be met: +** +** http://www.fsf.org/licensing/licenses/info/GPLv2.html and +** http://www.gnu.org/copyleft/gpl.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt GPL Exception +** version 1.2, included in the file GPL_EXCEPTION.txt in this package. +** +***************************************************************************/ + +#include "makestep.h" +#include "cmakeprojectconstants.h" +#include "cmakeproject.h" + +using namespace CMakeProjectManager; +using namespace CMakeProjectManager::Internal; + +MakeStep::MakeStep(CMakeProject *pro) + : AbstractProcessStep(pro), m_pro(pro) +{ + +} + +MakeStep::~MakeStep() +{ + +} + +bool MakeStep::init(const QString &buildConfiguration) +{ + setEnabled(buildConfiguration, true); + setWorkingDirectory(buildConfiguration, m_pro->buildDirectory(buildConfiguration)); + setCommand(buildConfiguration, "make"); // TODO give full path here? + setArguments(buildConfiguration, QStringList()); // TODO + setEnvironment(buildConfiguration, m_pro->environment(buildConfiguration)); + return AbstractProcessStep::init(buildConfiguration); +} + +void MakeStep::run(QFutureInterface<bool> &fi) +{ + AbstractProcessStep::run(fi); +} + +QString MakeStep::name() +{ + return "Make"; +} + +QString MakeStep::displayName() +{ + return Constants::CMAKESTEP; +} + +ProjectExplorer::BuildStepConfigWidget *MakeStep::createConfigWidget() +{ + return new MakeBuildStepConfigWidget(); +} + +bool MakeStep::immutable() const +{ + return true; +} + +// +// CMakeBuildStepConfigWidget +// + +QString MakeBuildStepConfigWidget::displayName() const +{ + return "Make"; +} + +void MakeBuildStepConfigWidget::init(const QString &buildConfiguration) +{ + // TODO +} + +// +// MakeBuildStepFactory +// + +bool MakeBuildStepFactory::canCreate(const QString &name) const +{ + return (Constants::MAKESTEP == name); +} + +ProjectExplorer::BuildStep *MakeBuildStepFactory::create(ProjectExplorer::Project *project, const QString &name) const +{ + Q_ASSERT(name == Constants::MAKESTEP); + CMakeProject *pro = qobject_cast<CMakeProject *>(project); + Q_ASSERT(pro); + return new MakeStep(pro); +} + +QStringList MakeBuildStepFactory::canCreateForProject(ProjectExplorer::Project *pro) const +{ + return QStringList(); +} + +QString MakeBuildStepFactory::displayNameForName(const QString &name) const +{ + return "Make"; +} + diff --git a/src/plugins/cmakeprojectmanager/makestep.h b/src/plugins/cmakeprojectmanager/makestep.h new file mode 100644 index 0000000000000000000000000000000000000000..f0ef530b42f912b921e35c01f6d62c624c5d53ba --- /dev/null +++ b/src/plugins/cmakeprojectmanager/makestep.h @@ -0,0 +1,79 @@ +/*************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Qt Software Information (qt-info@nokia.com) +** +** +** Non-Open Source Usage +** +** Licensees may use this file in accordance with the Qt Beta Version +** License Agreement, Agreement version 2.2 provided with the Software or, +** alternatively, in accordance with the terms contained in a written +** agreement between you and Nokia. +** +** GNU General Public License Usage +** +** Alternatively, this file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the packaging +** of this file. Please review the following information to ensure GNU +** General Public Licensing requirements will be met: +** +** http://www.fsf.org/licensing/licenses/info/GPLv2.html and +** http://www.gnu.org/copyleft/gpl.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt GPL Exception +** version 1.2, included in the file GPL_EXCEPTION.txt in this package. +** +***************************************************************************/ + +#ifndef MAKESTEP_H +#define MAKESTEP_H + +#include <projectexplorer/abstractprocessstep.h> + +namespace CMakeProjectManager { +namespace Internal { + +class CMakeProject; + +class MakeStep : public ProjectExplorer::AbstractProcessStep +{ +public: + MakeStep(CMakeProject *pro); + ~MakeStep(); + virtual bool init(const QString &buildConfiguration); + + virtual void run(QFutureInterface<bool> &fi); + + virtual QString name(); + virtual QString displayName(); + virtual ProjectExplorer::BuildStepConfigWidget *createConfigWidget(); + virtual bool immutable() const; +private: + CMakeProject *m_pro; +}; + +class MakeBuildStepConfigWidget :public ProjectExplorer::BuildStepConfigWidget +{ +public: + virtual QString displayName() const; + virtual void init(const QString &buildConfiguration); +}; + +class MakeBuildStepFactory : public ProjectExplorer::IBuildStepFactory +{ + virtual bool canCreate(const QString &name) const; + virtual ProjectExplorer::BuildStep *create(ProjectExplorer::Project *pro, const QString &name) const; + virtual QStringList canCreateForProject(ProjectExplorer::Project *pro) const; + virtual QString displayNameForName(const QString &name) const; +}; + +} +} + +#endif // MAKESTEP_H diff --git a/src/plugins/coreplugin/basefilewizard.cpp b/src/plugins/coreplugin/basefilewizard.cpp index f72353743b8852ec1b30750bc3aeb9e807020446..58030ba20c9ad8e0c7aaef03c266ff694fbbc3d6 100644 --- a/src/plugins/coreplugin/basefilewizard.cpp +++ b/src/plugins/coreplugin/basefilewizard.cpp @@ -509,6 +509,8 @@ QPixmap BaseFileWizard::watermark() void BaseFileWizard::setupWizard(QWizard *w) { w->setPixmap(QWizard::WatermarkPixmap, watermark()); + w->setOption(QWizard::NoCancelButton, false); + w->setOption(QWizard::NoDefaultButton, false); } bool BaseFileWizard::postGenerateFiles(const GeneratedFiles &l, QString *errorMessage) diff --git a/src/plugins/coreplugin/coreconstants.h b/src/plugins/coreplugin/coreconstants.h index ee1488d40dc0097a8d6ce2857775f406931cd2a5..c2a703a2d6f66bb1633be393637b5ec53071f287 100644 --- a/src/plugins/coreplugin/coreconstants.h +++ b/src/plugins/coreplugin/coreconstants.h @@ -94,6 +94,7 @@ const char * const C_WELCOME_MODE = "Core.WelcomeMode"; const char * const C_EDIT_MODE = "Core.EditMode"; const char * const C_EDITORMANAGER = "Core.EditorManager"; const char * const C_NAVIGATION_PANE = "Core.NavigationPane"; +const char * const C_PROBLEM_PANE = "Core.ProblemPane"; //default editor kind const char * const K_DEFAULT_TEXT_EDITOR = "Plain Text Editor"; diff --git a/src/plugins/coreplugin/editormanager/editormanager.cpp b/src/plugins/coreplugin/editormanager/editormanager.cpp index 0092513693b467b42690e2c86e5157e932c827fa..29798b25c010e9202f09cd2c27d38e6278ff9900 100644 --- a/src/plugins/coreplugin/editormanager/editormanager.cpp +++ b/src/plugins/coreplugin/editormanager/editormanager.cpp @@ -74,20 +74,6 @@ using namespace Core::Internal; enum { debugEditorManager=0 }; -QString EditorManager::defaultExternalEditor() const -{ -#ifdef Q_OS_MAC - return m_d->m_core->resourcePath() - +QLatin1String("/runInTerminal.command vi %f %l %c %W %H %x %y"); -#elif defined(Q_OS_UNIX) - return QLatin1String("xterm -geom %Wx%H+%x+%y -e vi %f +%l +\"normal %c|\""); -#elif defined (Q_OS_WIN) - return QLatin1String("notepad %f"); -#else - return QString(); -#endif -} - //===================EditorManager===================== EditorManagerPlaceHolder *EditorManagerPlaceHolder::m_current = 0; @@ -388,6 +374,20 @@ QSize EditorManager::minimumSizeHint() const return QSize(400, 300); } +QString EditorManager::defaultExternalEditor() const +{ +#ifdef Q_OS_MAC + return m_d->m_core->resourcePath() + +QLatin1String("/runInTerminal.command vi %f %l %c %W %H %x %y"); +#elif defined(Q_OS_UNIX) + return QLatin1String("xterm -geom %Wx%H+%x+%y -e vi %f +%l +\"normal %c|\""); +#elif defined (Q_OS_WIN) + return QLatin1String("notepad %f"); +#else + return QString(); +#endif +} + EditorSplitter *EditorManager::editorSplitter() const { return m_d->m_splitter; @@ -1003,29 +1003,32 @@ bool EditorManager::saveFile(IEditor *editor) return success; } -namespace { - enum ReadOnlyAction { RO_Cancel, RO_OpenSCC, RO_MakeWriteable, RO_SaveAs }; -} - -static ReadOnlyAction promptReadOnly(const QString &fileName, bool hasSCC, QWidget *parent) +EditorManager::ReadOnlyAction + EditorManager::promptReadOnlyFile(const QString &fileName, + const IVersionControl *versionControl, + QWidget *parent, + bool displaySaveAsButton) { QMessageBox msgBox(QMessageBox::Question, QObject::tr("File is Read Only"), QObject::tr("The file %1 is read only.").arg(fileName), QMessageBox::Cancel, parent); QPushButton *sccButton = 0; - if (hasSCC) - sccButton = msgBox.addButton(QObject::tr("Open with SCC"), QMessageBox::AcceptRole); + if (versionControl && versionControl->supportsOperation(IVersionControl::OpenOperation)) + sccButton = msgBox.addButton(QObject::tr("Open with VCS (%1)").arg(versionControl->name()), QMessageBox::AcceptRole); + QPushButton *makeWritableButton = msgBox.addButton(QObject::tr("Make writable"), QMessageBox::AcceptRole); - QPushButton *saveAsButton = msgBox.addButton(QObject::tr("Save as ..."), QMessageBox::ActionRole); - if (hasSCC) - msgBox.setDefaultButton(sccButton); - else - msgBox.setDefaultButton(makeWritableButton); + + QPushButton *saveAsButton = 0; + if (displaySaveAsButton) + msgBox.addButton(QObject::tr("Save as ..."), QMessageBox::ActionRole); + + msgBox.setDefaultButton(sccButton ? sccButton : makeWritableButton); msgBox.exec(); + QAbstractButton *clickedButton = msgBox.clickedButton(); if (clickedButton == sccButton) - return RO_OpenSCC; + return RO_OpenVCS; if (clickedButton == makeWritableButton) return RO_MakeWriteable; if (clickedButton == saveAsButton) @@ -1042,8 +1045,8 @@ EditorManager::makeEditorWritable(IEditor *editor) IFile *file = editor->file(); const QString &fileName = file->fileName(); - switch (promptReadOnly(fileName, versionControl, m_d->m_core->mainWindow())) { - case RO_OpenSCC: + switch (promptReadOnlyFile(fileName, versionControl, m_d->m_core->mainWindow(), true)) { + case RO_OpenVCS: if (!versionControl->vcsOpen(fileName)) { QMessageBox::warning(m_d->m_core->mainWindow(), tr("Failed!"), tr("Could not open the file for edit with SCC.")); return Failed; diff --git a/src/plugins/coreplugin/editormanager/editormanager.h b/src/plugins/coreplugin/editormanager/editormanager.h index b71791f36bfaae03145b5eda8dd2804f48cfa1b2..b9da2e055ff2478a83487564c9593792d7199903 100644 --- a/src/plugins/coreplugin/editormanager/editormanager.h +++ b/src/plugins/coreplugin/editormanager/editormanager.h @@ -55,6 +55,7 @@ class IEditorFactory; class MimeType; class IFile; class IMode; +class IVersionControl; enum MakeWritableResult { OpenedWithVersionControl, @@ -159,6 +160,16 @@ public: QString defaultExternalEditor() const; QString externalEditorHelpText() const; + + // Helper to display a message dialog when encountering a read-only + // file, prompting the user about how to make it writeable. + enum ReadOnlyAction { RO_Cancel, RO_OpenVCS, RO_MakeWriteable, RO_SaveAs }; + + static ReadOnlyAction promptReadOnlyFile(const QString &fileName, + const IVersionControl *versionControl, + QWidget *parent, + bool displaySaveAsButton = false); + signals: void currentEditorChanged(Core::IEditor *editor); void editorCreated(Core::IEditor *editor, const QString &fileName); diff --git a/src/plugins/coreplugin/iversioncontrol.h b/src/plugins/coreplugin/iversioncontrol.h index b90f9d79c659536d31be68d962c5c12794ab6282..0962c5537e8cf6b1594fdcd84b1b4ff449fc955f 100644 --- a/src/plugins/coreplugin/iversioncontrol.h +++ b/src/plugins/coreplugin/iversioncontrol.h @@ -45,51 +45,53 @@ class CORE_EXPORT IVersionControl : public QObject { Q_OBJECT public: + enum Operation { AddOperation, DeleteOperation, OpenOperation }; + IVersionControl(QObject *parent = 0) : QObject(parent) {} virtual ~IVersionControl() {} - // Returns wheter files in this directory should be managed with this + virtual QString name() const = 0; + + // Enable the VCS, that is, make its menu actions visible. + virtual bool isEnabled() const = 0; + virtual void setEnabled(bool enabled) = 0; + + // Returns whether files in this directory should be managed with this // version control. virtual bool managesDirectory(const QString &filename) const = 0; - // This function should return the topmost directory, for - // which this IVersionControl should be used. - // The VCSManager assumes that all files in the returned directory - // are managed by the same IVersionControl + // This function should return the topmost directory, for which this + // IVersionControl should be used. The VCSManager assumes that all files + // in the returned directory are managed by the same IVersionControl // Note that this is used as an optimization, so that the VCSManager // doesn't need to call managesDirectory(..) for each directory - // This function is called after finding out that the directory is managed by - // a specific version control + // This function is called after finding out that the directory is managed + // by a specific version control. virtual QString findTopLevelForDirectory(const QString &directory) const = 0; - // Called prior to save, if the file is read only. - // Should be implemented if the scc requires a operation before editing the file - // E.g. p4 edit - // Note: The EditorManager calls this for the editors + // Called to query whether a VCS supports the respective operations. + virtual bool supportsOperation(Operation operation) const = 0; + + // Called prior to save, if the file is read only. Should be implemented + // if the scc requires a operation before editing the file, e.g. 'p4 edit' + // Note: The EditorManager calls this for the editors. virtual bool vcsOpen(const QString &fileName) = 0; - // Called after a file has been added to a project - // If the version control needs to know which files it needs to track - // you should reimplement this function - // E.g. p4 add, cvs add, svn add - // Note: This function should be called from IProject subclasses after files - // are added to the project + // Called after a file has been added to a project If the version control + // needs to know which files it needs to track you should reimplement this + // function, e.g. 'p4 add', 'cvs add', 'svn add'. + // Note: This function should be called from IProject subclasses after + // files are added to the project virtual bool vcsAdd(const QString &filename) = 0; - // Called after a file has been removed from the project (if the user wants) - // E.g. p4 delete, svn delete - // You probably want to call SccManager::showDeleteDialog, which asks the user to - // confirm the deletion + // Called after a file has been removed from the project (if the user + // wants), e.g. 'p4 delete', 'svn delete'. + // You probably want to call VcsManager::showDeleteDialog, which asks the + // user to confirm the deletion virtual bool vcsDelete(const QString &filename) = 0; // TODO: ADD A WAY TO DETECT WHETHER A FILE IS MANAGED, e.g // virtual bool sccManaged(const QStryng &filename) = 0; - - // TODO - // we probably want to have a function supports( enum Operation ) or - // something which describes which "kind" of revision control system it is. - // That is to check wheter a given operation is needed. - // But well I don't know yet how all different version control systems work }; } // namespace Core diff --git a/src/plugins/coreplugin/mainwindow.cpp b/src/plugins/coreplugin/mainwindow.cpp index 59222acc419685bae0994a0aca0e75fb4c632721..1d9050705496bc05501ed25a3a22cec105f034ce 100644 --- a/src/plugins/coreplugin/mainwindow.cpp +++ b/src/plugins/coreplugin/mainwindow.cpp @@ -127,6 +127,7 @@ MainWindow::MainWindow() : m_mimeDatabase(new MimeDatabase), m_navigationWidget(0), m_rightPaneWidget(0), + m_versionDialog(0), m_activeContext(0), m_pluginManager(0), m_outputPane(new OutputPane(m_globalContext)), @@ -1085,8 +1086,20 @@ void MainWindow::openRecentFile() void MainWindow::aboutQtCreator() { - VersionDialog versionDialog(this); - versionDialog.exec(); + if (!m_versionDialog) { + m_versionDialog = new VersionDialog(this); + connect(m_versionDialog, SIGNAL(finished(int)), + this, SLOT(destroyVersionDialog())); + } + m_versionDialog->show(); +} + +void MainWindow::destroyVersionDialog() +{ + if (m_versionDialog) { + m_versionDialog->deleteLater(); + m_versionDialog = 0; + } } void MainWindow::aboutPlugins() diff --git a/src/plugins/coreplugin/mainwindow.h b/src/plugins/coreplugin/mainwindow.h index 180b932d710bffe7d0b1e71cd5d85ecd937fda41..a8edd089972489c1076ddf1359d078969ec6aa2e 100644 --- a/src/plugins/coreplugin/mainwindow.h +++ b/src/plugins/coreplugin/mainwindow.h @@ -83,6 +83,7 @@ class OutputPane; class ProgressManager; class ShortcutSettings; class ViewManager; +class VersionDialog; class CORE_EXPORT MainWindow : public QMainWindow { @@ -160,6 +161,7 @@ private slots: void aboutPlugins(); void updateFocusWidget(QWidget *old, QWidget *now); void toggleNavigation(); + void destroyVersionDialog(); private: void updateContextObject(IContext *context); @@ -190,6 +192,7 @@ private: NavigationWidget *m_navigationWidget; RightPaneWidget *m_rightPaneWidget; Core::BaseView *m_outputView; + VersionDialog *m_versionDialog; IContext * m_activeContext; diff --git a/src/plugins/coreplugin/vcsmanager.cpp b/src/plugins/coreplugin/vcsmanager.cpp index a0e1cc19c0ad2663899efcf53a566deeeba574da..02475a0d0e66cfb5369327ec1c5f2827f43aa167 100644 --- a/src/plugins/coreplugin/vcsmanager.cpp +++ b/src/plugins/coreplugin/vcsmanager.cpp @@ -45,8 +45,18 @@ #include <QtCore/QFileInfo> #include <QtGui/QMessageBox> +enum { debug = 0 }; + namespace Core { +typedef QList<IVersionControl *> VersionControlList; + +static inline VersionControlList allVersionControls() +{ + return ExtensionSystem::PluginManager::instance()->getObjects<IVersionControl>(); +} + +// ---- VCSManagerPrivate struct VCSManagerPrivate { QMap<QString, IVersionControl *> m_cachedMatches; }; @@ -61,31 +71,54 @@ VCSManager::~VCSManager() delete m_d; } +void VCSManager::setVCSEnabled(const QString &directory) +{ + if (debug) + qDebug() << Q_FUNC_INFO << directory; + IVersionControl* managingVCS = findVersionControlForDirectory(directory); + const VersionControlList versionControls = allVersionControls(); + foreach(IVersionControl *versionControl, versionControls) { + const bool newEnabled = versionControl == managingVCS; + if (newEnabled != versionControl->isEnabled()) + versionControl->setEnabled(newEnabled); + } +} + +void VCSManager::setAllVCSEnabled() +{ + if (debug) + qDebug() << Q_FUNC_INFO; + const VersionControlList versionControls = allVersionControls(); + foreach(IVersionControl *versionControl, versionControls) + if (!versionControl->isEnabled()) + versionControl->setEnabled(true); +} + IVersionControl* VCSManager::findVersionControlForDirectory(const QString &directory) { - // first look into the cache - int pos = 0; - { // First try the whole name - QMap<QString, IVersionControl *>::const_iterator it = m_d->m_cachedMatches.constFind(directory); - if (it != m_d->m_cachedMatches.constEnd()) { + // first look into the cache, check the whole name + + { + const QMap<QString, IVersionControl *>::const_iterator it = m_d->m_cachedMatches.constFind(directory); + if (it != m_d->m_cachedMatches.constEnd()) return it.value(); - } } + int pos = 0; + const QChar slash = QLatin1Char('/'); while(true) { - int index = directory.indexOf('/', pos); + int index = directory.indexOf(slash, pos); if (index == -1) break; - QString directoryPart = directory.left(index); + const QString directoryPart = directory.left(index); QMap<QString, IVersionControl *>::const_iterator it = m_d->m_cachedMatches.constFind(directoryPart); - if (it != m_d->m_cachedMatches.constEnd()) { + if (it != m_d->m_cachedMatches.constEnd()) return it.value(); - } pos = index+1; } // ah nothing so ask the IVersionControls directly - QList<IVersionControl *> versionControls = ExtensionSystem::PluginManager::instance()->getObjects<IVersionControl>(); + const VersionControlList versionControls = allVersionControls(); foreach(IVersionControl * versionControl, versionControls) { if (versionControl->managesDirectory(directory)) { m_d->m_cachedMatches.insert(versionControl->findTopLevelForDirectory(directory), versionControl); @@ -95,20 +128,20 @@ IVersionControl* VCSManager::findVersionControlForDirectory(const QString &direc return 0; } -void VCSManager::showDeleteDialog(const QString &fileName) +bool VCSManager::showDeleteDialog(const QString &fileName) { IVersionControl *vc = findVersionControlForDirectory(QFileInfo(fileName).absolutePath()); - if (!vc) - return; + if (!vc || !vc->supportsOperation(IVersionControl::DeleteOperation)) + return true; const QString title = QCoreApplication::translate("VCSManager", "Version Control"); const QString msg = QCoreApplication::translate("VCSManager", - "Would you like to remove this file from the version control system?\n" - "Note: This might remove the local file."); + "Would you like to remove this file from the version control system (%1)?\n" + "Note: This might remove the local file.").arg(vc->name()); const QMessageBox::StandardButton button = QMessageBox::question(0, title, msg, QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes); - if (button == QMessageBox::Yes) { - vc->vcsDelete(fileName); - } + if (button != QMessageBox::Yes) + return true; + return vc->vcsDelete(fileName); } } // namespace Core diff --git a/src/plugins/coreplugin/vcsmanager.h b/src/plugins/coreplugin/vcsmanager.h index 92e4f35d1540a2a2282b1fb361ae35ea231a75ef..a3afca96d6adef219ad847fcc7427d8818b92814 100644 --- a/src/plugins/coreplugin/vcsmanager.h +++ b/src/plugins/coreplugin/vcsmanager.h @@ -45,12 +45,12 @@ class IVersionControl; // The VCSManager has only one notable function: // findVersionControlFor(), which returns the IVersionControl * for a given -// filename. Note that the VCSManager assumes that if a IVersionControl * +// filename. Note that the VCSManager assumes that if a IVersionControl * // manages a directory, then it also manages all the files and all the // subdirectories. // // It works by asking all IVersionControl * if they manage the file, and ask -// for the topmost directory it manages. This information is cached and +// for the topmost directory it manages. This information is cached and // VCSManager thus knows pretty fast which IVersionControl * is responsible. class CORE_EXPORT VCSManager @@ -62,10 +62,16 @@ public: IVersionControl *findVersionControlForDirectory(const QString &directory); - // Shows a confirmation dialog, - // wheter the file should also be deleted from revision control - // Calls sccDelete on the file - void showDeleteDialog(const QString &fileName); + // Enable the VCS managing a certain directory only. This should + // be used by project manager classes. + void setVCSEnabled(const QString &directory); + // Enable all VCS. + void setAllVCSEnabled(); + + // Shows a confirmation dialog, whether the file should also be deleted + // from revision control Calls sccDelete on the file. Returns false + // if a failure occurs + bool showDeleteDialog(const QString &fileName); private: VCSManagerPrivate *m_d; diff --git a/src/plugins/cppeditor/cppeditor.cpp b/src/plugins/cppeditor/cppeditor.cpp index 254e9341de66b16c24f814dfadeecd1ec0a7170d..da52bb3d6016a367647e00aa59197607fa8d19fa 100644 --- a/src/plugins/cppeditor/cppeditor.cpp +++ b/src/plugins/cppeditor/cppeditor.cpp @@ -206,6 +206,7 @@ void CPPEditor::createToolBar(CPPEditorEditable *editable) connect(m_methodCombo, SIGNAL(activated(int)), this, SLOT(jumpToMethod(int))); connect(this, SIGNAL(cursorPositionChanged()), this, SLOT(updateMethodBoxIndex())); + connect(m_methodCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(updateMethodBoxToolTip())); connect(file(), SIGNAL(changed()), this, SLOT(updateFileName())); @@ -355,10 +356,16 @@ void CPPEditor::updateMethodBoxIndex() if (lastIndex.isValid()) { bool blocked = m_methodCombo->blockSignals(true); m_methodCombo->setCurrentIndex(lastIndex.row()); + updateMethodBoxToolTip(); (void) m_methodCombo->blockSignals(blocked); } } +void CPPEditor::updateMethodBoxToolTip() +{ + m_methodCombo->setToolTip(m_methodCombo->currentText()); +} + static bool isCompatible(Name *name, Name *otherName) { if (NameId *nameId = name->asNameId()) { diff --git a/src/plugins/cppeditor/cppeditor.h b/src/plugins/cppeditor/cppeditor.h index e6c6d1aa8633cd807179308b2761685119a0a247..2420bcf4e5e441d67834d5d9d0a612dbbad09f06 100644 --- a/src/plugins/cppeditor/cppeditor.h +++ b/src/plugins/cppeditor/cppeditor.h @@ -115,7 +115,7 @@ private slots: void updateFileName(); void jumpToMethod(int index); void updateMethodBoxIndex(); - + void updateMethodBoxToolTip(); void onDocumentUpdated(CPlusPlus::Document::Ptr doc); private: diff --git a/src/plugins/cpptools/cppclassesfilter.cpp b/src/plugins/cpptools/cppclassesfilter.cpp new file mode 100644 index 0000000000000000000000000000000000000000..3d8da9a7387a209638c415d55abe3ddeb5fd039e --- /dev/null +++ b/src/plugins/cpptools/cppclassesfilter.cpp @@ -0,0 +1,49 @@ +/*************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Qt Software Information (qt-info@nokia.com) +** +** +** Non-Open Source Usage +** +** Licensees may use this file in accordance with the Qt Beta Version +** License Agreement, Agreement version 2.2 provided with the Software or, +** alternatively, in accordance with the terms contained in a written +** agreement between you and Nokia. +** +** GNU General Public License Usage +** +** Alternatively, this file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the packaging +** of this file. Please review the following information to ensure GNU +** General Public Licensing requirements will be met: +** +** http://www.fsf.org/licensing/licenses/info/GPLv2.html and +** http://www.gnu.org/copyleft/gpl.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt GPL Exception +** version 1.2, included in the file GPL_EXCEPTION.txt in this package. +** +***************************************************************************/ + +#include "cppclassesfilter.h" + +using namespace CppTools::Internal; + +CppClassesFilter::CppClassesFilter(CppModelManager *manager, Core::EditorManager *editorManager) + : CppQuickOpenFilter(manager, editorManager) +{ + setShortcutString("c"); + setIncludedByDefault(false); + + search.setSymbolsToSearchFor(SearchSymbols::Classes); +} + +CppClassesFilter::~CppClassesFilter() +{ +} diff --git a/src/plugins/cpptools/cppclassesfilter.h b/src/plugins/cpptools/cppclassesfilter.h new file mode 100644 index 0000000000000000000000000000000000000000..ba936eab869fe76cf9b9a0b9ef1ac5f0f266965e --- /dev/null +++ b/src/plugins/cpptools/cppclassesfilter.h @@ -0,0 +1,58 @@ +/*************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Qt Software Information (qt-info@nokia.com) +** +** +** Non-Open Source Usage +** +** Licensees may use this file in accordance with the Qt Beta Version +** License Agreement, Agreement version 2.2 provided with the Software or, +** alternatively, in accordance with the terms contained in a written +** agreement between you and Nokia. +** +** GNU General Public License Usage +** +** Alternatively, this file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the packaging +** of this file. Please review the following information to ensure GNU +** General Public Licensing requirements will be met: +** +** http://www.fsf.org/licensing/licenses/info/GPLv2.html and +** http://www.gnu.org/copyleft/gpl.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt GPL Exception +** version 1.2, included in the file GPL_EXCEPTION.txt in this package. +** +***************************************************************************/ + +#ifndef CPPCLASSESFILTER_H +#define CPPCLASSESFILTER_H + +#include <cppquickopenfilter.h> + +namespace CppTools { +namespace Internal { + +class CppClassesFilter : public CppQuickOpenFilter +{ + Q_OBJECT + +public: + CppClassesFilter(CppModelManager *manager, Core::EditorManager *editorManager); + ~CppClassesFilter(); + + QString trName() const { return tr("Classes"); } + QString name() const { return QLatin1String("Classes"); } + Priority priority() const { return Medium; } +}; + +} // namespace Internal +} // namespace CppTools + +#endif // CPPCLASSESFILTER_H diff --git a/src/plugins/cpptools/cpphoverhandler.cpp b/src/plugins/cpptools/cpphoverhandler.cpp index 37b63bda9c23f4adf11670e34062efaded814a18..16ed8a9215039009e6d47403939d02d996824f83 100644 --- a/src/plugins/cpptools/cpphoverhandler.cpp +++ b/src/plugins/cpptools/cpphoverhandler.cpp @@ -60,7 +60,7 @@ using namespace CppTools::Internal; CppHoverHandler::CppHoverHandler(CppModelManager *manager, QObject *parent) - : QObject(parent), m_manager(manager) + : QObject(parent), m_manager(manager), m_helpEngineNeedsSetup(false) { QFileInfo fi(ExtensionSystem::PluginManager::instance()->getObject<Core::ICore>()->settings()->fileName()); m_helpEngine = new QHelpEngineCore(fi.absolutePath() @@ -68,6 +68,7 @@ CppHoverHandler::CppHoverHandler(CppModelManager *manager, QObject *parent) //m_helpEngine->setAutoSaveFilter(false); m_helpEngine->setupData(); m_helpEngine->setCurrentFilter(tr("Unfiltered")); + m_helpEngineNeedsSetup = m_helpEngine->registeredDocumentations().count() == 0; } void CppHoverHandler::updateContextHelpId(TextEditor::ITextEditor *editor, int pos) @@ -234,6 +235,12 @@ void CppHoverHandler::updateHelpIdAndTooltip(TextEditor::ITextEditor *editor, in } } + if (m_helpEngineNeedsSetup + && m_helpEngine->registeredDocumentations().count() > 0) { + m_helpEngine->setupData(); + m_helpEngineNeedsSetup = false; + } + if (!m_helpId.isEmpty() && !m_helpEngine->linksForIdentifier(m_helpId).isEmpty()) { m_toolTip = QString(QLatin1String("<table><tr><td valign=middle><nobr>%1</td>" "<td><img src=\":/cpptools/images/f1.svg\"></td></tr></table>")).arg(Qt::escape(m_toolTip)); diff --git a/src/plugins/cpptools/cpphoverhandler.h b/src/plugins/cpptools/cpphoverhandler.h index 9aaa17cb0f88e1e47c04ebca1a96114f53f6917b..d1de5277b1241468b5dfdfbeff5d9ec14ea49927 100644 --- a/src/plugins/cpptools/cpphoverhandler.h +++ b/src/plugins/cpptools/cpphoverhandler.h @@ -68,6 +68,7 @@ private: QHelpEngineCore *m_helpEngine; QString m_helpId; QString m_toolTip; + bool m_helpEngineNeedsSetup; }; } // namespace Internal diff --git a/src/plugins/cpptools/cppmodelmanager.cpp b/src/plugins/cpptools/cppmodelmanager.cpp index 1708e62de35b26c5aae7bf7c25d4f5129505278b..b3f9fb604c3c46e6866f9a03eb6065a63942c13a 100644 --- a/src/plugins/cpptools/cppmodelmanager.cpp +++ b/src/plugins/cpptools/cppmodelmanager.cpp @@ -129,9 +129,12 @@ public: void setProjectFiles(const QStringList &files) { m_projectFiles = files; } - void operator()(QString &fileName) + void run(QString &fileName) { sourceNeeded(fileName, IncludeGlobal); } + void operator()(QString &fileName) + { run(fileName); } + protected: bool includeFile(const QString &absoluteFilePath, QByteArray *result) { @@ -253,6 +256,25 @@ protected: m_currentDoc->appendMacro(macroName, macroText); } + virtual void startExpandingMacro(unsigned offset, + const rpp::Macro &, + const QByteArray &originalText) + { + if (! m_currentDoc) + return; + + //qDebug() << "start expanding:" << macro.name << "text:" << originalText; + m_currentDoc->addMacroUse(offset, originalText.length()); + } + + virtual void stopExpandingMacro(unsigned, const rpp::Macro &) + { + if (! m_currentDoc) + return; + + //qDebug() << "stop expanding:" << macro.name; + } + void mergeEnvironment(Document::Ptr doc) { QSet<QString> processed; @@ -390,6 +412,8 @@ CppModelManager::CppModelManager(QObject *parent) : CppModelManagerInterface(parent), m_core(ExtensionSystem::PluginManager::instance()->getObject<Core::ICore>()) { + m_dirty = true; + m_projectExplorer = ExtensionSystem::PluginManager::instance() ->getObject<ProjectExplorer::ProjectExplorerPlugin>(); @@ -398,6 +422,9 @@ CppModelManager::CppModelManager(QObject *parent) : ProjectExplorer::SessionManager *session = m_projectExplorer->session(); Q_ASSERT(session != 0); + connect(session, SIGNAL(projectAdded(ProjectExplorer::Project*)), + this, SLOT(onProjectAdded(ProjectExplorer::Project*))); + connect(session, SIGNAL(aboutToRemoveProject(ProjectExplorer::Project *)), this, SLOT(onAboutToRemoveProject(ProjectExplorer::Project *))); @@ -429,7 +456,7 @@ Document::Ptr CppModelManager::document(const QString &fileName) CppModelManager::DocumentTable CppModelManager::documents() { return m_documents; } -QStringList CppModelManager::projectFiles() const +QStringList CppModelManager::updateProjectFiles() const { QStringList files; QMapIterator<ProjectExplorer::Project *, ProjectInfo> it(m_projects); @@ -441,7 +468,7 @@ QStringList CppModelManager::projectFiles() const return files; } -QStringList CppModelManager::includePaths() const +QStringList CppModelManager::updateIncludePaths() const { QStringList includePaths; QMapIterator<ProjectExplorer::Project *, ProjectInfo> it(m_projects); @@ -453,7 +480,7 @@ QStringList CppModelManager::includePaths() const return includePaths; } -QStringList CppModelManager::frameworkPaths() const +QStringList CppModelManager::updateFrameworkPaths() const { QStringList frameworkPaths; QMapIterator<ProjectExplorer::Project *, ProjectInfo> it(m_projects); @@ -465,7 +492,7 @@ QStringList CppModelManager::frameworkPaths() const return frameworkPaths; } -QByteArray CppModelManager::definedMacros() const +QByteArray CppModelManager::updateDefinedMacros() const { QByteArray macros; QMapIterator<ProjectExplorer::Project *, ProjectInfo> it(m_projects); @@ -477,7 +504,7 @@ QByteArray CppModelManager::definedMacros() const return macros; } -QMap<QString, QByteArray> CppModelManager::buildWorkingCopyList() const +QMap<QString, QByteArray> CppModelManager::buildWorkingCopyList() { QMap<QString, QByteArray> workingCopy; QMapIterator<TextEditor::ITextEditor *, CppEditorSupport *> it(m_editorSupport); @@ -505,11 +532,17 @@ CppModelManager::ProjectInfo *CppModelManager::projectInfo(ProjectExplorer::Proj QFuture<void> CppModelManager::refreshSourceFiles(const QStringList &sourceFiles) { - if (qgetenv("QTCREATOR_NO_CODE_INDEXER").isNull()) { + if (! sourceFiles.isEmpty() && qgetenv("QTCREATOR_NO_CODE_INDEXER").isNull()) { const QMap<QString, QByteArray> workingCopy = buildWorkingCopyList(); - QFuture<void> result = QtConcurrent::run(&CppModelManager::parse, this, - sourceFiles, workingCopy); + CppPreprocessor *preproc = new CppPreprocessor(this); + preproc->setProjectFiles(projectFiles()); + preproc->setIncludePaths(includePaths()); + preproc->setFrameworkPaths(frameworkPaths()); + preproc->setWorkingCopy(workingCopy); + + QFuture<void> result = QtConcurrent::run(&CppModelManager::parse, + preproc, sourceFiles); if (sourceFiles.count() > 1) { m_core->progressManager()->addTask(result, tr("Indexing"), @@ -595,6 +628,22 @@ void CppModelManager::onDocumentUpdated(Document::Ptr doc) QList<QTextEdit::ExtraSelection> selections; +#ifdef QTCREATOR_WITH_MACRO_HIGHLIGHTING + // set up the format for the macros + QTextCharFormat macroFormat; + macroFormat.setUnderlineStyle(QTextCharFormat::SingleUnderline); + + QTextCursor c = ed->textCursor(); + foreach (const Document::Block block, doc->macroUses()) { + QTextEdit::ExtraSelection sel; + sel.cursor = c; + sel.cursor.setPosition(block.begin()); + sel.cursor.setPosition(block.end(), QTextCursor::KeepAnchor); + sel.format = macroFormat; + selections.append(sel); + } +#endif // QTCREATOR_WITH_MACRO_HIGHLIGHTING + // set up the format for the errors QTextCharFormat errorFormat; errorFormat.setUnderlineStyle(QTextCharFormat::WaveUnderline); @@ -640,36 +689,39 @@ void CppModelManager::onDocumentUpdated(Document::Ptr doc) } } +void CppModelManager::onProjectAdded(ProjectExplorer::Project *) +{ + m_dirty = true; +} + void CppModelManager::onAboutToRemoveProject(ProjectExplorer::Project *project) { + m_dirty = true; m_projects.remove(project); GC(); } void CppModelManager::onSessionUnloaded() { - if (m_core->progressManager()) + if (m_core->progressManager()) { m_core->progressManager()->cancelTasks(CppTools::Constants::TASK_INDEX); + m_dirty = true; + } } void CppModelManager::parse(QFutureInterface<void> &future, - CppModelManager *model, - QStringList files, - QMap<QString, QByteArray> workingCopy) + CppPreprocessor *preproc, + QStringList files) { + Q_ASSERT(! files.isEmpty()); + // Change the priority of the background parser thread to idle. QThread::currentThread()->setPriority(QThread::IdlePriority); future.setProgressRange(0, files.size()); - CppPreprocessor preproc(model); - preproc.setWorkingCopy(workingCopy); - preproc.setProjectFiles(model->projectFiles()); - preproc.setIncludePaths(model->includePaths()); - preproc.setFrameworkPaths(model->frameworkPaths()); - QString conf = QLatin1String(pp_configuration_file); - (void) preproc(conf); + (void) preproc->run(conf); const int STEP = 10; @@ -688,7 +740,7 @@ void CppModelManager::parse(QFutureInterface<void> &future, #endif QString fileName = files.at(i); - preproc(fileName); + preproc->run(fileName); if (! (i % STEP)) // Yields execution of the current thread. QThread::yieldCurrentThread(); @@ -698,8 +750,12 @@ void CppModelManager::parse(QFutureInterface<void> &future, #endif } + future.setProgressValue(files.size()); + // Restore the previous thread priority. QThread::currentThread()->setPriority(QThread::NormalPriority); + + delete preproc; } void CppModelManager::GC() @@ -707,7 +763,7 @@ void CppModelManager::GC() DocumentTable documents = m_documents; QSet<QString> processed; - QStringList todo = m_projectFiles; + QStringList todo = projectFiles(); while (! todo.isEmpty()) { QString fn = todo.last(); diff --git a/src/plugins/cpptools/cppmodelmanager.h b/src/plugins/cpptools/cppmodelmanager.h index 187187cc5d313586293cd3fdb0e7d5186dc30c01..a91a414e4803e2464a68a149b5f1eac9ae43068a 100644 --- a/src/plugins/cpptools/cppmodelmanager.h +++ b/src/plugins/cpptools/cppmodelmanager.h @@ -58,6 +58,7 @@ namespace CppTools { namespace Internal { class CppEditorSupport; +class CppPreprocessor; class CppHoverHandler; class CppModelManager : public CppModelManagerInterface @@ -97,18 +98,54 @@ private Q_SLOTS: void onDocumentUpdated(CPlusPlus::Document::Ptr doc); void onAboutToRemoveProject(ProjectExplorer::Project *project); void onSessionUnloaded(); + void onProjectAdded(ProjectExplorer::Project *project); private: - QMap<QString, QByteArray> buildWorkingCopyList() const; - QStringList projectFiles() const; - QStringList includePaths() const; - QStringList frameworkPaths() const; - QByteArray definedMacros() const; + QMap<QString, QByteArray> buildWorkingCopyList(); + + QStringList projectFiles() + { + ensureUpdated(); + return m_projectFiles; + } + + QStringList includePaths() + { + ensureUpdated(); + return m_includePaths; + } + + QStringList frameworkPaths() + { + ensureUpdated(); + return m_frameworkPaths; + } + + QByteArray definedMacros() + { + ensureUpdated(); + return m_definedMacros; + } + + QStringList updateProjectFiles() const; + QStringList updateIncludePaths() const; + QStringList updateFrameworkPaths() const; + QByteArray updateDefinedMacros() const; + + void ensureUpdated() { + if (! m_dirty) + return; + + m_projectFiles = updateProjectFiles(); + m_includePaths = updateIncludePaths(); + m_frameworkPaths = updateFrameworkPaths(); + m_definedMacros = updateDefinedMacros(); + m_dirty = false; + } static void parse(QFutureInterface<void> &future, - CppModelManager *model, - QStringList files, - QMap<QString, QByteArray> workingCopy); + CppPreprocessor *preproc, + QStringList files); private: Core::ICore *m_core; @@ -116,8 +153,12 @@ private: CppHoverHandler *m_hoverHandler; DocumentTable m_documents; - // List of available source files + // cache + bool m_dirty; QStringList m_projectFiles; + QStringList m_includePaths; + QStringList m_frameworkPaths; + QByteArray m_definedMacros; // editor integration QMap<TextEditor::ITextEditor *, CppEditorSupport *> m_editorSupport; diff --git a/src/plugins/cpptools/cppquickopenfilter.cpp b/src/plugins/cpptools/cppquickopenfilter.cpp index 9470ec46039a57c77e3d1499b71c3e457f01c190..a1f1a9b3713e00c76a967d2922dad17875c48034 100644 --- a/src/plugins/cpptools/cppquickopenfilter.cpp +++ b/src/plugins/cpptools/cppquickopenfilter.cpp @@ -32,172 +32,13 @@ ***************************************************************************/ #include "cppquickopenfilter.h" +#include "cppmodelmanager.h" -#include <Literals.h> -#include <Symbols.h> -#include <SymbolVisitor.h> -#include <Scope.h> -#include <cplusplus/Overview.h> -#include <cplusplus/Icons.h> - +#include <coreplugin/editormanager/editormanager.h> #include <coreplugin/editormanager/ieditor.h> #include <texteditor/itexteditor.h> #include <texteditor/basetexteditor.h> -#include <QtCore/QMultiMap> - -#include <functional> - -using namespace CPlusPlus; - -namespace CppTools { -namespace Internal { - -class SearchSymbols: public std::unary_function<Document::Ptr, QList<ModelItemInfo> >, - protected SymbolVisitor -{ - Overview overview; - Icons icons; - QList<ModelItemInfo> items; - -public: - QList<ModelItemInfo> operator()(Document::Ptr doc) - { return operator()(doc, QString()); } - - QList<ModelItemInfo> operator()(Document::Ptr doc, const QString &scope) - { - QString previousScope = switchScope(scope); - items.clear(); - for (unsigned i = 0; i < doc->globalSymbolCount(); ++i) { - accept(doc->globalSymbolAt(i)); - } - (void) switchScope(previousScope); - return items; - } - -protected: - using SymbolVisitor::visit; - - void accept(Symbol *symbol) - { Symbol::visitSymbol(symbol, this); } - - QString switchScope(const QString &scope) - { - QString previousScope = _scope; - _scope = scope; - return previousScope; - } - - virtual bool visit(Enum *symbol) - { - QString name = symbolName(symbol); - QString previousScope = switchScope(name); - QIcon icon = icons.iconForSymbol(symbol); - Scope *members = symbol->members(); - items.append(ModelItemInfo(name, QString(), ModelItemInfo::Enum, - QString::fromUtf8(symbol->fileName(), symbol->fileNameLength()), - symbol->line(), - icon)); - for (unsigned i = 0; i < members->symbolCount(); ++i) { - accept(members->symbolAt(i)); - } - (void) switchScope(previousScope); - return false; - } - - virtual bool visit(Function *symbol) - { - QString name = symbolName(symbol); - QString type = overview.prettyType(symbol->type()); - QIcon icon = icons.iconForSymbol(symbol); - items.append(ModelItemInfo(name, type, ModelItemInfo::Method, - QString::fromUtf8(symbol->fileName(), symbol->fileNameLength()), - symbol->line(), - icon)); - return false; - } - - virtual bool visit(Namespace *symbol) - { - QString name = symbolName(symbol); - QString previousScope = switchScope(name); - Scope *members = symbol->members(); - for (unsigned i = 0; i < members->symbolCount(); ++i) { - accept(members->symbolAt(i)); - } - (void) switchScope(previousScope); - return false; - } -#if 0 - // This visit method would make function declaration be included in QuickOpen - virtual bool visit(Declaration *symbol) - { - if (symbol->type()->isFunction()) { - QString name = symbolName(symbol); - QString type = overview.prettyType(symbol->type()); - //QIcon icon = ...; - items.append(ModelItemInfo(name, type, ModelItemInfo::Method, - QString::fromUtf8(symbol->fileName(), symbol->line()), - symbol->line())); - } - return false; - } -#endif - virtual bool visit(Class *symbol) - { - QString name = symbolName(symbol); - QString previousScope = switchScope(name); - QIcon icon = icons.iconForSymbol(symbol); - items.append(ModelItemInfo(name, QString(), ModelItemInfo::Class, - QString::fromUtf8(symbol->fileName(), symbol->fileNameLength()), - symbol->line(), - icon)); - Scope *members = symbol->members(); - for (unsigned i = 0; i < members->symbolCount(); ++i) { - accept(members->symbolAt(i)); - } - (void) switchScope(previousScope); - return false; - } - - QString symbolName(Symbol *symbol) const - { - QString name = _scope; - if (! name.isEmpty()) - name += QLatin1String("::"); - QString symbolName = overview.prettyName(symbol->name()); - if (symbolName.isEmpty()) { - QString type; - if (symbol->isNamespace()) { - type = QLatin1String("namespace"); - } else if (symbol->isEnum()) { - type = QLatin1String("enum"); - } else if (Class *c = symbol->asClass()) { - if (c->isUnion()) { - type = QLatin1String("union"); - } else if (c->isStruct()) { - type = QLatin1String("struct"); - } else { - type = QLatin1String("class"); - } - } else { - type = QLatin1String("symbol"); - } - symbolName = QLatin1String("<anonymous "); - symbolName += type; - symbolName += QLatin1String(">"); - } - name += symbolName; - return name; - } - -private: - QString _scope; -}; - -} // namespace Internal -} // namespace CppTools - using namespace CppTools::Internal; CppQuickOpenFilter::CppQuickOpenFilter(CppModelManager *manager, Core::EditorManager *editorManager) @@ -225,9 +66,8 @@ void CppQuickOpenFilter::onDocumentUpdated(CPlusPlus::Document::Ptr doc) void CppQuickOpenFilter::onAboutToRemoveFiles(const QStringList &files) { - foreach (QString file, files) { + foreach (const QString &file, files) m_searchList.remove(file); - } } void CppQuickOpenFilter::refresh(QFutureInterface<void> &future) @@ -245,7 +85,6 @@ QList<QuickOpen::FilterEntry> CppQuickOpenFilter::matchesFor(const QString &orig return entries; bool hasWildcard = (entry.contains('*') || entry.contains('?')); - SearchSymbols search; QMutableMapIterator<QString, Info> it(m_searchList); while (it.hasNext()) { it.next(); @@ -276,6 +115,5 @@ QList<QuickOpen::FilterEntry> CppQuickOpenFilter::matchesFor(const QString &orig void CppQuickOpenFilter::accept(QuickOpen::FilterEntry selection) const { ModelItemInfo info = qvariant_cast<CppTools::Internal::ModelItemInfo>(selection.internalData); - TextEditor::BaseTextEditor::openEditorAt(info.fileName, info.line); } diff --git a/src/plugins/cpptools/cppquickopenfilter.h b/src/plugins/cpptools/cppquickopenfilter.h index bf6696a02af24ed690d286177e6ed9746e206112..12eaacb3f980d194b7c1e69416dbd6d8ec2b3504 100644 --- a/src/plugins/cpptools/cppquickopenfilter.h +++ b/src/plugins/cpptools/cppquickopenfilter.h @@ -34,45 +34,18 @@ #ifndef CPPQUICKOPENFILTER_H #define CPPQUICKOPENFILTER_H -#include "cppmodelmanager.h" -#include <cplusplus/CppDocument.h> -#include <coreplugin/editormanager/editormanager.h> +#include "searchsymbols.h" + #include <quickopen/iquickopenfilter.h> -#include <QtGui/QIcon> -#include <QFile> -#include <QMetaType> + +namespace Core { +class EditorManager; +} namespace CppTools { namespace Internal { -struct ModelItemInfo -{ - enum ItemType { Enum, Class, Method }; - - ModelItemInfo() - { } - - ModelItemInfo(const QString &symbolName, - const QString &symbolType, - ItemType type, - const QString &fileName, - int line, - const QIcon &icon) - : symbolName(symbolName), - symbolType(symbolType), - type(type), - fileName(fileName), - line(line), - icon(icon) - { } - - QString symbolName; - QString symbolType; - ItemType type; - QString fileName; - int line; - QIcon icon; -}; +class CppModelManager; class CppQuickOpenFilter : public QuickOpen::IQuickOpenFilter { @@ -82,12 +55,15 @@ public: ~CppQuickOpenFilter(); QString trName() const { return tr("Classes and Methods"); } - QString name() const { return "Classes and Methods"; } + QString name() const { return QLatin1String("Classes and Methods"); } Priority priority() const { return Medium; } QList<QuickOpen::FilterEntry> matchesFor(const QString &entry); void accept(QuickOpen::FilterEntry selection) const; void refresh(QFutureInterface<void> &future); +protected: + SearchSymbols search; + private slots: void onDocumentUpdated(CPlusPlus::Document::Ptr doc); void onAboutToRemoveFiles(const QStringList &files); @@ -114,6 +90,4 @@ private: } // namespace Internal } // namespace CppTools -Q_DECLARE_METATYPE(CppTools::Internal::ModelItemInfo) - #endif // CPPQUICKOPENFILTER_H diff --git a/src/plugins/cpptools/cpptools.cpp b/src/plugins/cpptools/cpptools.cpp index 423ddf3016d0d4a967dffd0d4a7e236163aa9793..957f0cae9b07ed7bf97842baaf316c2dd7bd53a2 100644 --- a/src/plugins/cpptools/cpptools.cpp +++ b/src/plugins/cpptools/cpptools.cpp @@ -32,6 +32,7 @@ ***************************************************************************/ #include "cpptools.h" +#include "cppclassesfilter.h" #include "cppcodecompletion.h" #include "cpphoverhandler.h" #include "cppmodelmanager.h" @@ -87,6 +88,7 @@ bool CppToolsPlugin::initialize(const QStringList & /*arguments*/, QString *) CppQuickOpenFilter *quickOpenFilter = new CppQuickOpenFilter(m_modelManager, m_core->editorManager()); addAutoReleasedObject(quickOpenFilter); + addAutoReleasedObject(new CppClassesFilter(m_modelManager, m_core->editorManager())); // Menus Core::IActionContainer *mtools = am->actionContainer(Core::Constants::M_TOOLS); diff --git a/src/plugins/cpptools/cpptools.pro b/src/plugins/cpptools/cpptools.pro index 17b72496a92f3a8c398e8bc3972da1983a7b8230..8a096900ebf699ba9f0712eafb670660ebffb113 100644 --- a/src/plugins/cpptools/cpptools.pro +++ b/src/plugins/cpptools/cpptools.pro @@ -4,31 +4,27 @@ include(../../qworkbenchplugin.pri) include(../../plugins/quickopen/quickopen.pri) include(cpptools_dependencies.pri) -#DEFINES += QT_NO_CAST_FROM_ASCII +# DEFINES += QT_NO_CAST_FROM_ASCII DEFINES += QT_NO_CAST_TO_ASCII -unix:QMAKE_CXXFLAGS_DEBUG+=-O3 - +unix:QMAKE_CXXFLAGS_DEBUG += -O3 INCLUDEPATH += . - DEFINES += CPPTOOLS_LIBRARY - CONFIG += help include(rpp/rpp.pri)|error("Can't find RPP") - -HEADERS += \ - cpptools_global.h \ - cppquickopenfilter.h - -SOURCES += \ - cppquickopenfilter.cpp \ - cpptoolseditorsupport.cpp +HEADERS += cpptools_global.h \ + cppquickopenfilter.h \ + cppclassesfilter.h \ + searchsymbols.h +SOURCES += cppquickopenfilter.cpp \ + cpptoolseditorsupport.cpp \ + cppclassesfilter.cpp \ + searchsymbols.cpp # Input SOURCES += cpptools.cpp \ cppmodelmanager.cpp \ cppcodecompletion.cpp \ cpphoverhandler.cpp - HEADERS += cpptools.h \ cppmodelmanager.h \ cppcodecompletion.h \ @@ -36,5 +32,4 @@ HEADERS += cpptools.h \ cppmodelmanagerinterface.h \ cpptoolseditorsupport.h \ cpptoolsconstants.h - RESOURCES += cpptools.qrc diff --git a/src/plugins/cpptools/rpp/pp-client.h b/src/plugins/cpptools/rpp/pp-client.h index 073fc44c3627ad3643e18eef4be96c2e565a8f40..974004a6ce50ec85aeb2df035d63c686df19b444 100644 --- a/src/plugins/cpptools/rpp/pp-client.h +++ b/src/plugins/cpptools/rpp/pp-client.h @@ -40,6 +40,8 @@ namespace rpp { +class Macro; + class Client { Client(const Client &other); @@ -61,6 +63,13 @@ public: virtual void macroAdded(const QByteArray ¯oId, const QByteArray &text) = 0; virtual void sourceNeeded(QString &fileName, IncludeType mode) = 0; // ### FIX the signature. + virtual void startExpandingMacro(unsigned offset, + const Macro ¯o, + const QByteArray &originalTextt) = 0; + + virtual void stopExpandingMacro(unsigned offset, + const Macro ¯o) = 0; + virtual void startSkippingBlocks(unsigned offset) = 0; virtual void stopSkippingBlocks(unsigned offset) = 0; }; diff --git a/src/plugins/cpptools/rpp/pp-engine.cpp b/src/plugins/cpptools/rpp/pp-engine.cpp index 3a3e9245b30229a330fe9f3ea894eb5ec9a66b29..66e8957f355e5dc28c25c755b4d86e83d49f5a04 100644 --- a/src/plugins/cpptools/rpp/pp-engine.cpp +++ b/src/plugins/cpptools/rpp/pp-engine.cpp @@ -575,7 +575,17 @@ void pp::operator()(const QByteArray &source, QByteArray *result) const QByteArray spell = tokenSpell(*identifierToken); if (env.isBuiltinMacro(spell)) { + const Macro trivial; + + if (client) + client->startExpandingMacro(identifierToken->offset, + trivial, spell); + expand(spell.constBegin(), spell.constEnd(), result); + + if (client) + client->stopExpandingMacro(_dot->offset, trivial); + continue; } @@ -585,18 +595,36 @@ void pp::operator()(const QByteArray &source, QByteArray *result) } else { if (! m->function_like) { if (_dot->isNot(T_LPAREN)) { + if (client) + client->startExpandingMacro(identifierToken->offset, + *m, spell); + m->hidden = true; + expand(m->definition.constBegin(), m->definition.constEnd(), result); + + if (client) + client->stopExpandingMacro(_dot->offset, *m); + m->hidden = false; continue; } else { QByteArray tmp; m->hidden = true; + + if (client) + client->startExpandingMacro(identifierToken->offset, + *m, spell); + expand(m->definition.constBegin(), m->definition.constEnd(), &tmp); + + if (client) + client->stopExpandingMacro(_dot->offset, *m); + m->hidden = false; m = 0; // reset the active the macro @@ -640,9 +668,20 @@ void pp::operator()(const QByteArray &source, QByteArray *result) const char *beginOfText = startOfToken(*identifierToken); const char *endOfText = endOfToken(*_dot); ++_dot; // skip T_RPAREN - //m->hidden = true; + + if (client) { + const QByteArray text = + QByteArray::fromRawData(beginOfText, + endOfText - beginOfText); + + client->startExpandingMacro(identifierToken->offset, + *m, text); + } + expand(beginOfText, endOfText, result); - //m->hidden = false; + + if (client) + client->stopExpandingMacro(_dot->offset, *m); } } } diff --git a/src/plugins/cpptools/searchsymbols.cpp b/src/plugins/cpptools/searchsymbols.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c0d29aae18a7fabde085f4a5e129abd1e4fb7539 --- /dev/null +++ b/src/plugins/cpptools/searchsymbols.cpp @@ -0,0 +1,178 @@ +/*************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Qt Software Information (qt-info@nokia.com) +** +** +** Non-Open Source Usage +** +** Licensees may use this file in accordance with the Qt Beta Version +** License Agreement, Agreement version 2.2 provided with the Software or, +** alternatively, in accordance with the terms contained in a written +** agreement between you and Nokia. +** +** GNU General Public License Usage +** +** Alternatively, this file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the packaging +** of this file. Please review the following information to ensure GNU +** General Public Licensing requirements will be met: +** +** http://www.fsf.org/licensing/licenses/info/GPLv2.html and +** http://www.gnu.org/copyleft/gpl.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt GPL Exception +** version 1.2, included in the file GPL_EXCEPTION.txt in this package. +** +***************************************************************************/ + +#include "searchsymbols.h" + +#include <Literals.h> +#include <Scope.h> + +using namespace CPlusPlus; +using namespace CppTools::Internal; + +SearchSymbols::SearchSymbols(): + symbolsToSearchFor(ClassesMethodsFunctionsAndEnums) +{ +} + +void SearchSymbols::setSymbolsToSearchFor(SymbolType type) +{ + symbolsToSearchFor = type; +} + +QList<ModelItemInfo> SearchSymbols::operator()(Document::Ptr doc, const QString &scope) +{ + QString previousScope = switchScope(scope); + items.clear(); + for (unsigned i = 0; i < doc->globalSymbolCount(); ++i) { + accept(doc->globalSymbolAt(i)); + } + (void) switchScope(previousScope); + return items; +} + +QString SearchSymbols::switchScope(const QString &scope) +{ + QString previousScope = _scope; + _scope = scope; + return previousScope; +} + +bool SearchSymbols::visit(Enum *symbol) +{ + if (symbolsToSearchFor != ClassesMethodsFunctionsAndEnums) + return false; + + QString name = symbolName(symbol); + QString previousScope = switchScope(name); + QIcon icon = icons.iconForSymbol(symbol); + Scope *members = symbol->members(); + items.append(ModelItemInfo(name, QString(), ModelItemInfo::Enum, + QString::fromUtf8(symbol->fileName(), symbol->fileNameLength()), + symbol->line(), + icon)); + for (unsigned i = 0; i < members->symbolCount(); ++i) { + accept(members->symbolAt(i)); + } + (void) switchScope(previousScope); + return false; +} + +bool SearchSymbols::visit(Function *symbol) +{ + if (symbolsToSearchFor != ClassesMethodsFunctionsAndEnums) + return false; + + QString name = symbolName(symbol); + QString type = overview.prettyType(symbol->type()); + QIcon icon = icons.iconForSymbol(symbol); + items.append(ModelItemInfo(name, type, ModelItemInfo::Method, + QString::fromUtf8(symbol->fileName(), symbol->fileNameLength()), + symbol->line(), + icon)); + return false; +} + +bool SearchSymbols::visit(Namespace *symbol) +{ + QString name = symbolName(symbol); + QString previousScope = switchScope(name); + Scope *members = symbol->members(); + for (unsigned i = 0; i < members->symbolCount(); ++i) { + accept(members->symbolAt(i)); + } + (void) switchScope(previousScope); + return false; +} + +#if 0 +bool SearchSymbols::visit(Declaration *symbol) +{ + if (symbol->type()->isFunction()) { + QString name = symbolName(symbol); + QString type = overview.prettyType(symbol->type()); + //QIcon icon = ...; + items.append(ModelItemInfo(name, type, ModelItemInfo::Method, + QString::fromUtf8(symbol->fileName(), symbol->line()), + symbol->line())); + } + return false; +} +#endif + +bool SearchSymbols::visit(Class *symbol) +{ + QString name = symbolName(symbol); + QString previousScope = switchScope(name); + QIcon icon = icons.iconForSymbol(symbol); + items.append(ModelItemInfo(name, QString(), ModelItemInfo::Class, + QString::fromUtf8(symbol->fileName(), symbol->fileNameLength()), + symbol->line(), + icon)); + Scope *members = symbol->members(); + for (unsigned i = 0; i < members->symbolCount(); ++i) { + accept(members->symbolAt(i)); + } + (void) switchScope(previousScope); + return false; +} + +QString SearchSymbols::symbolName(const Symbol *symbol) const +{ + QString name = _scope; + if (! name.isEmpty()) + name += QLatin1String("::"); + QString symbolName = overview.prettyName(symbol->name()); + if (symbolName.isEmpty()) { + QString type; + if (symbol->isNamespace()) { + type = QLatin1String("namespace"); + } else if (symbol->isEnum()) { + type = QLatin1String("enum"); + } else if (const Class *c = symbol->asClass()) { + if (c->isUnion()) { + type = QLatin1String("union"); + } else if (c->isStruct()) { + type = QLatin1String("struct"); + } else { + type = QLatin1String("class"); + } + } else { + type = QLatin1String("symbol"); + } + symbolName = QLatin1String("<anonymous "); + symbolName += type; + symbolName += QLatin1String(">"); + } + name += symbolName; + return name; +} diff --git a/src/plugins/cpptools/searchsymbols.h b/src/plugins/cpptools/searchsymbols.h new file mode 100644 index 0000000000000000000000000000000000000000..d9b678e026fb6778ada898736a45ea3936e571e2 --- /dev/null +++ b/src/plugins/cpptools/searchsymbols.h @@ -0,0 +1,128 @@ +/*************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Qt Software Information (qt-info@nokia.com) +** +** +** Non-Open Source Usage +** +** Licensees may use this file in accordance with the Qt Beta Version +** License Agreement, Agreement version 2.2 provided with the Software or, +** alternatively, in accordance with the terms contained in a written +** agreement between you and Nokia. +** +** GNU General Public License Usage +** +** Alternatively, this file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the packaging +** of this file. Please review the following information to ensure GNU +** General Public Licensing requirements will be met: +** +** http://www.fsf.org/licensing/licenses/info/GPLv2.html and +** http://www.gnu.org/copyleft/gpl.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt GPL Exception +** version 1.2, included in the file GPL_EXCEPTION.txt in this package. +** +***************************************************************************/ + +#ifndef SEARCHSYMBOLS_H +#define SEARCHSYMBOLS_H + +#include <cplusplus/CppDocument.h> +#include <cplusplus/Icons.h> +#include <cplusplus/Overview.h> +#include <Symbols.h> +#include <SymbolVisitor.h> + +#include <QIcon> +#include <QMetaType> +#include <QString> + +namespace CppTools { +namespace Internal { + +struct ModelItemInfo +{ + enum ItemType { Enum, Class, Method }; + + ModelItemInfo() + { } + + ModelItemInfo(const QString &symbolName, + const QString &symbolType, + ItemType type, + const QString &fileName, + int line, + const QIcon &icon) + : symbolName(symbolName), + symbolType(symbolType), + type(type), + fileName(fileName), + line(line), + icon(icon) + { } + + QString symbolName; + QString symbolType; + ItemType type; + QString fileName; + int line; + QIcon icon; +}; + +class SearchSymbols: public std::unary_function<CPlusPlus::Document::Ptr, QList<ModelItemInfo> >, + protected CPlusPlus::SymbolVisitor +{ +public: + // TODO: Probably should use QFlags + enum SymbolType { + Classes, + ClassesMethodsFunctionsAndEnums + }; + + SearchSymbols(); + + void setSymbolsToSearchFor(SymbolType type); + + QList<ModelItemInfo> operator()(CPlusPlus::Document::Ptr doc) + { return operator()(doc, QString()); } + + QList<ModelItemInfo> operator()(CPlusPlus::Document::Ptr doc, const QString &scope); + +protected: + using SymbolVisitor::visit; + + void accept(CPlusPlus::Symbol *symbol) + { CPlusPlus::Symbol::visitSymbol(symbol, this); } + + QString switchScope(const QString &scope); + virtual bool visit(CPlusPlus::Enum *symbol); + virtual bool visit(CPlusPlus::Function *symbol); + virtual bool visit(CPlusPlus::Namespace *symbol); +#if 0 + // This visit method would make function declaration be included in QuickOpen + virtual bool visit(CPlusPlus::Declaration *symbol); +#endif + virtual bool visit(CPlusPlus::Class *symbol); + QString symbolName(const CPlusPlus::Symbol *symbol) const; + +private: + QString _scope; + CPlusPlus::Overview overview; + CPlusPlus::Icons icons; + QList<ModelItemInfo> items; + SymbolType symbolsToSearchFor; +}; + +} // namespace Internal +} // namespace CppTools + +Q_DECLARE_METATYPE(CppTools::Internal::ModelItemInfo) + +#endif // SEARCHSYMBOLS_H diff --git a/src/plugins/debugger/breakhandler.cpp b/src/plugins/debugger/breakhandler.cpp index 8199d4ab518ddc3a1884cb009c5d688b6096ba55..f4b528c50fa9816f896ab3941c062e5f44e0ac2e 100644 --- a/src/plugins/debugger/breakhandler.cpp +++ b/src/plugins/debugger/breakhandler.cpp @@ -231,6 +231,11 @@ BreakHandler::BreakHandler(QObject *parent) { } +BreakHandler::~BreakHandler() +{ + clear(); +} + int BreakHandler::columnCount(const QModelIndex &parent) const { return parent.isValid() ? 0 : 6; diff --git a/src/plugins/debugger/breakhandler.h b/src/plugins/debugger/breakhandler.h index 4581e3a4de97552328dfda23835a41124214ec54..95743f6df50d4727741ffa1f0b4f15d508eff287 100644 --- a/src/plugins/debugger/breakhandler.h +++ b/src/plugins/debugger/breakhandler.h @@ -113,6 +113,7 @@ class BreakHandler : public QAbstractItemModel public: explicit BreakHandler(QObject *parent = 0); + ~BreakHandler(); void removeAllBreakpoints(); void setAllPending(); diff --git a/src/plugins/debugger/debuggermanager.cpp b/src/plugins/debugger/debuggermanager.cpp index f696d728467654a5df68124e060c28f030c97fcc..a94b1fb0931e3ac551f4fb815126b947ec998b80 100644 --- a/src/plugins/debugger/debuggermanager.cpp +++ b/src/plugins/debugger/debuggermanager.cpp @@ -317,10 +317,20 @@ void DebuggerManager::init() m_debugDumpersAction = new QAction(this); m_debugDumpersAction->setText(tr("Debug Custom Dumpers")); + m_debugDumpersAction->setToolTip(tr("This is an internal tool to " + "make debugging the Custom Data Dumper code easier. " + "Using this action is in general not needed unless you " + "want do debug Qt Creator itself.")); m_debugDumpersAction->setCheckable(true); m_skipKnownFramesAction = new QAction(this); m_skipKnownFramesAction->setText(tr("Skip Known Frames When Stepping")); + m_skipKnownFramesAction->setToolTip(tr("After checking this option" + "'Step Into' combines in certain situations several steps, " + "leading to 'less noisy' debugging. So will, e.g., the atomic " + "reference counting code be skipped, and a single 'Step Into' " + "for a signal emission will end up directly in the slot connected " + "to it")); m_skipKnownFramesAction->setCheckable(true); m_useCustomDumpersAction = new QAction(this); @@ -330,13 +340,6 @@ void DebuggerManager::init() m_useCustomDumpersAction->setCheckable(true); m_useCustomDumpersAction->setChecked(true); - m_useCustomDumpersAction = new QAction(this); - m_useCustomDumpersAction->setText(tr("Use Custom Display for Qt Objects")); - m_useCustomDumpersAction->setToolTip(tr("Checking this will make the debugger " - "try to use code to format certain data (QObject, QString, ...) nicely. ")); - m_useCustomDumpersAction->setCheckable(true); - m_useCustomDumpersAction->setChecked(true); - m_useFastStartAction = new QAction(this); m_useFastStartAction->setText(tr("Fast Debugger Start")); m_useFastStartAction->setToolTip(tr("Checking this will make the debugger " @@ -622,7 +625,7 @@ void DebuggerManager::notifyInferiorPidChanged(int pid) void DebuggerManager::showApplicationOutput(const QString &prefix, const QString &str) { - applicationOutputAvailable(prefix, str); + emit applicationOutputAvailable(prefix, str); } void DebuggerManager::shutdown() diff --git a/src/plugins/debugger/debuggerrunner.cpp b/src/plugins/debugger/debuggerrunner.cpp index c161c9bad9881f49f5bbe555b27a0f3afe0c734d..90c8c4e9f7d6dc53acf6bfe7dfcbc415b596b0e1 100644 --- a/src/plugins/debugger/debuggerrunner.cpp +++ b/src/plugins/debugger/debuggerrunner.cpp @@ -44,6 +44,7 @@ #include <QtCore/QDebug> #include <QtCore/QDir> #include <QtCore/QFileInfo> +#include <QtGui/QTextDocument> using namespace Debugger::Internal; @@ -140,8 +141,8 @@ void DebuggerRunControl::slotAddToOutputWindow(const QString &prefix, const QStr { Q_UNUSED(prefix); foreach (const QString &l, line.split('\n')) - emit addToOutputWindow(this, prefix + l); - //emit addToOutputWindow(this, prefix + line); + emit addToOutputWindow(this, prefix + Qt::escape(l)); + //emit addToOutputWindow(this, prefix + Qt::escape(line)); } void DebuggerRunControl::stop() diff --git a/src/plugins/debugger/gdbengine.cpp b/src/plugins/debugger/gdbengine.cpp index df0eaa9f0b293d0379236ebc67172daf095aba40..80d0a046fc3179f334fa054f8ba1abcd59500cdd 100644 --- a/src/plugins/debugger/gdbengine.cpp +++ b/src/plugins/debugger/gdbengine.cpp @@ -110,7 +110,6 @@ enum GdbCommandType GdbFileExecAndSymbols, GdbQueryPwd, GdbQuerySources, - GdbQuerySources2, GdbAsyncOutput2, GdbExecRun, GdbExecRunToFunction, @@ -126,7 +125,6 @@ enum GdbCommandType GdbInfoProc, GdbQueryDataDumper1, GdbQueryDataDumper2, - GdbInitializeSocket1, BreakCondition = 200, BreakEnablePending, @@ -444,7 +442,7 @@ void GdbEngine::handleResponse() break; } - if (token == -1 && *from != '&' && *from != '~') { + if (token == -1 && *from != '&' && *from != '~' && *from != '*') { // FIXME: On Linux the application's std::out is merged in here. // High risk of falsely interpreting this as MI output. // We assume that we _always_ use tokens, so not finding a token @@ -493,8 +491,10 @@ void GdbEngine::handleResponse() m_inbuffer = QByteArray(from, to - from); if (asyncClass == "stopped") { handleAsyncOutput(record); + } else if (asyncClass == "running") { + // Archer has 'thread-id="all"' here } else { - qDebug() << "INGNORED ASYNC OUTPUT " << record.toString(); + qDebug() << "IGNORED ASYNC OUTPUT " << record.toString(); } break; } @@ -633,18 +633,10 @@ void GdbEngine::readGdbStandardOutput() { // This is the function called whenever the Gdb process created // output. As a rule of thumb, stdout contains _real_ Gdb output - // as responses to our command (with exception of the data dumpers) + // as responses to our command // and "spontaneous" events like messages on loaded shared libraries. - // Otoh, stderr contains application output produced by qDebug etc. - // There is no organized way to pass application stdout output - - // The result of custom data dumpers arrives over the socket _before_ - // the corresponding Gdb "^done" message arrives here over stdout - // and is merged into the response via m_pendingCustomValueContents. - - // Note that this code here runs syncronized to the arriving - // output. The completed response will be signalled by a queued - // connection to the handlers. + // OTOH, stderr contains application output produced by qDebug etc. + // There is no organized way to pass application stdout output. QByteArray out = m_gdbProc.readAllStandardOutput(); @@ -765,19 +757,12 @@ void GdbEngine::handleResultRecord(const GdbResultRecord &record) //qDebug() << "TOKEN: " << record.token // << " ACCEPTABLE: " << m_oldestAcceptableToken; //qDebug() << ""; - //qDebug() << qPrintable(currentTime()) << "Reading response: " - // << record.toString() << "\n"; //qDebug() << "\nRESULT" << record.token << record.toString(); int token = record.token; if (token == -1) return; - if (!m_cookieForToken.contains(token)) { - qDebug() << "NO SUCH TOKEN (ANYMORE): " << token; - return; - } - GdbCookie cmd = m_cookieForToken.take(token); // FIXME: this falsely rejects results from the custom dumper recognition @@ -788,12 +773,6 @@ void GdbEngine::handleResultRecord(const GdbResultRecord &record) return; } - // We get _two_ results for a '-exec-foo' command: First a - // 'running' notification, then a 'stopped' or similar. - // So put it back. - if (record.resultClass == GdbResultRunning) - m_cookieForToken[token] = cmd; - #if 0 qDebug() << "# handleOutput, " << "cmd type: " << cmd.type @@ -858,18 +837,12 @@ void GdbEngine::handleResult(const GdbResultRecord & record, int type, case GdbQuerySources: handleQuerySources(record); break; - case GdbQuerySources2: - handleQuerySources2(record, cookie); - break; case GdbAsyncOutput2: handleAsyncOutput2(cookie.value<GdbMi>()); break; case GdbInfoShared: handleInfoShared(record); break; - case GdbInitializeSocket1: - //qDebug() << " INIT SOCKET" << record.toString(); - break; case GdbQueryDataDumper1: handleQueryDataDumper1(record); break; @@ -1072,13 +1045,6 @@ void GdbEngine::handleInfoShared(const GdbResultRecord &record) } } -void GdbEngine::handleQuerySources2(const GdbResultRecord &record, - const QVariant &cookie) -{ - if (record.resultClass == GdbResultDone) - handleAsyncOutput2(cookie.value<GdbMi>()); -} - void GdbEngine::handleExecJumpToLine(const GdbResultRecord &record) { // FIXME: remove this special case as soon as 'jump' @@ -3681,11 +3647,16 @@ void GdbEngine::handleStackListLocals(const GdbResultRecord &record) // stage 2/2 // There could be shadowed variables - QHash<QString, int> seen; QList<GdbMi> locals = record.data.findChild("locals").children(); locals += m_currentFunctionArgs; + setLocals(locals); +} + +void GdbEngine::setLocals(const QList<GdbMi> &locals) +{ //qDebug() << m_varToType; + QHash<QString, int> seen; foreach (const GdbMi &item, locals) { #ifdef Q_OS_MAC diff --git a/src/plugins/debugger/gdbengine.h b/src/plugins/debugger/gdbengine.h index 45eafcdb92c6172f62fa634f4fb450b79e87f29c..b3e13233526754ac0d0c41bec3992bd668f19913 100644 --- a/src/plugins/debugger/gdbengine.h +++ b/src/plugins/debugger/gdbengine.h @@ -206,8 +206,6 @@ private: void handleShowVersion(const GdbResultRecord &response); void handleQueryPwd(const GdbResultRecord &response); void handleQuerySources(const GdbResultRecord &response); - void handleQuerySources2(const GdbResultRecord &response, - const QVariant &); QByteArray m_inbuffer; @@ -219,7 +217,6 @@ private: QByteArray m_pendingConsoleStreamOutput; QByteArray m_pendingTargetStreamOutput; QByteArray m_pendingLogStreamOutput; - //QByteArray m_pendingCustomValueContents; QString m_pwd; // contains the first token number for the current round @@ -329,6 +326,7 @@ private: void handleVarListChildrenHelper(const GdbMi &child, const WatchData &parent); void setWatchDataType(WatchData &data, const GdbMi &mi); + void setLocals(const QList<GdbMi> &locals); QString m_editedData; int m_pendingRequests; diff --git a/src/plugins/find/finddialog.ui b/src/plugins/find/finddialog.ui index 7240551772071624b06dcf80b47e75b3af48b97e..479299316f6d6b68d2ed4259593a5a814f215464 100644 --- a/src/plugins/find/finddialog.ui +++ b/src/plugins/find/finddialog.ui @@ -1,7 +1,8 @@ -<ui version="4.0" > +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> <class>Find::Internal::FindDialog</class> - <widget class="QDialog" name="Find::Internal::FindDialog" > - <property name="geometry" > + <widget class="QDialog" name="Find::Internal::FindDialog"> + <property name="geometry"> <rect> <x>0</x> <y>0</y> @@ -9,109 +10,109 @@ <height>168</height> </rect> </property> - <property name="sizePolicy" > - <sizepolicy vsizetype="Minimum" hsizetype="Minimum" > + <property name="sizePolicy"> + <sizepolicy hsizetype="Minimum" vsizetype="Minimum"> <horstretch>0</horstretch> <verstretch>0</verstretch> </sizepolicy> </property> - <property name="windowTitle" > + <property name="windowTitle"> <string>Search for...</string> </property> - <property name="sizeGripEnabled" > + <property name="sizeGripEnabled"> <bool>false</bool> </property> - <layout class="QVBoxLayout" name="verticalLayout" > + <layout class="QVBoxLayout" name="verticalLayout"> <item> - <layout class="QGridLayout" name="gridLayout" > - <item row="0" column="0" > - <widget class="QLabel" name="label" > - <property name="sizePolicy" > - <sizepolicy vsizetype="Preferred" hsizetype="Fixed" > + <layout class="QGridLayout" name="gridLayout"> + <item row="0" column="0"> + <widget class="QLabel" name="label"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Fixed" vsizetype="Preferred"> <horstretch>0</horstretch> <verstretch>0</verstretch> </sizepolicy> </property> - <property name="minimumSize" > + <property name="minimumSize"> <size> <width>80</width> <height>0</height> </size> </property> - <property name="text" > + <property name="text"> <string>Sc&ope:</string> </property> - <property name="alignment" > + <property name="alignment"> <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> </property> - <property name="buddy" > + <property name="buddy"> <cstring>filterList</cstring> </property> </widget> </item> - <item row="0" column="1" > - <widget class="QComboBox" name="filterList" > - <property name="sizePolicy" > - <sizepolicy vsizetype="Fixed" hsizetype="Expanding" > + <item row="0" column="1"> + <widget class="QComboBox" name="filterList"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Expanding" vsizetype="Fixed"> <horstretch>0</horstretch> <verstretch>0</verstretch> </sizepolicy> </property> </widget> </item> - <item row="0" column="2" > - <widget class="QPushButton" name="searchButton" > - <property name="text" > + <item row="0" column="2"> + <widget class="QPushButton" name="searchButton"> + <property name="text"> <string>&Search</string> </property> - <property name="default" > + <property name="default"> <bool>true</bool> </property> </widget> </item> - <item row="1" column="0" > - <widget class="QLabel" name="label_2" > - <property name="text" > + <item row="1" column="0"> + <widget class="QLabel" name="label_2"> + <property name="text"> <string>Search &for:</string> </property> - <property name="alignment" > + <property name="alignment"> <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> </property> - <property name="buddy" > + <property name="buddy"> <cstring>searchTerm</cstring> </property> </widget> </item> - <item row="1" column="1" > - <widget class="QLineEdit" name="searchTerm" /> + <item row="1" column="1"> + <widget class="QLineEdit" name="searchTerm"/> </item> - <item row="1" column="2" > - <widget class="QPushButton" name="closeButton" > - <property name="text" > - <string>&Close</string> + <item row="1" column="2"> + <widget class="QPushButton" name="closeButton"> + <property name="text"> + <string>Close</string> </property> </widget> </item> - <item row="4" column="0" colspan="2" > - <widget class="QWidget" native="1" name="configWidget" > - <property name="sizePolicy" > - <sizepolicy vsizetype="Fixed" hsizetype="Preferred" > + <item row="4" column="0" colspan="2"> + <widget class="QWidget" name="configWidget" native="true"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Preferred" vsizetype="Fixed"> <horstretch>0</horstretch> <verstretch>10</verstretch> </sizepolicy> </property> </widget> </item> - <item row="2" column="1" > - <widget class="QCheckBox" name="matchCase" > - <property name="text" > - <string>Match &case</string> + <item row="2" column="1"> + <widget class="QCheckBox" name="matchCase"> + <property name="text"> + <string>&Case sensitive</string> </property> </widget> </item> - <item row="3" column="1" > - <widget class="QCheckBox" name="wholeWords" > - <property name="text" > + <item row="3" column="1"> + <widget class="QCheckBox" name="wholeWords"> + <property name="text"> <string>&Whole words only</string> </property> </widget> @@ -119,11 +120,11 @@ </layout> </item> <item> - <spacer name="verticalSpacer_2" > - <property name="orientation" > + <spacer name="verticalSpacer_2"> + <property name="orientation"> <enum>Qt::Vertical</enum> </property> - <property name="sizeHint" stdset="0" > + <property name="sizeHint" stdset="0"> <size> <width>0</width> <height>0</height> diff --git a/src/plugins/git/commitdata.cpp b/src/plugins/git/commitdata.cpp index 60e2173a660ab315b406c5c79313d256a934f107..7ea937233c7e115e901b56ff72d58809edcece29 100644 --- a/src/plugins/git/commitdata.cpp +++ b/src/plugins/git/commitdata.cpp @@ -80,16 +80,16 @@ void CommitData::clear() panelInfo.clear(); panelData.clear(); - commitFiles.clear(); - notUpdatedFiles.clear(); + stagedFiles.clear(); + unstagedFiles.clear(); untrackedFiles.clear(); } QDebug operator<<(QDebug d, const CommitData &data) { d << data.panelInfo << data.panelData; - d.nospace() << "Commit: " << data.commitFiles << " Not updated: " - << data.notUpdatedFiles << " Untracked: " << data.untrackedFiles; + d.nospace() << "Commit: " << data.stagedFiles << " Not updated: " + << data.unstagedFiles << " Untracked: " << data.untrackedFiles; return d; } diff --git a/src/plugins/git/commitdata.h b/src/plugins/git/commitdata.h index 9cd5a83eb16c3e01fec0950c6ef3675354c440bb..b535168f6f357e56e7aa3877313ea9871febeee8 100644 --- a/src/plugins/git/commitdata.h +++ b/src/plugins/git/commitdata.h @@ -71,8 +71,8 @@ struct CommitData void clear(); GitSubmitEditorPanelInfo panelInfo; GitSubmitEditorPanelData panelData; - QStringList commitFiles; - QStringList notUpdatedFiles; + QStringList stagedFiles; + QStringList unstagedFiles; QStringList untrackedFiles; }; diff --git a/src/plugins/git/git.pro b/src/plugins/git/git.pro index 258639dcbe3416cce70579750af6d0b4dd600c12..3c4ca176cb5aa8bfce855a81e380b780ac0739c2 100644 --- a/src/plugins/git/git.pro +++ b/src/plugins/git/git.pro @@ -17,7 +17,9 @@ HEADERS += gitplugin.h \ giteditor.h \ annotationhighlighter.h \ gitsubmiteditorwidget.h \ - gitsubmiteditor.h + gitsubmiteditor.h \ + gitversioncontrol.h \ + gitsettings.h SOURCES += gitplugin.cpp \ gitoutputwindow.cpp \ @@ -28,7 +30,9 @@ SOURCES += gitplugin.cpp \ giteditor.cpp \ annotationhighlighter.cpp \ gitsubmiteditorwidget.cpp \ - gitsubmiteditor.cpp + gitsubmiteditor.cpp \ + gitversioncontrol.cpp \ + gitsettings.cpp FORMS += changeselectiondialog.ui \ settingspage.ui \ diff --git a/src/plugins/git/gitclient.cpp b/src/plugins/git/gitclient.cpp index fb73d4fe5e2b41a2a750f4ab656d3966baab951c..a1668e60cebcf93343e54862c30a7f429cf933dd 100644 --- a/src/plugins/git/gitclient.cpp +++ b/src/plugins/git/gitclient.cpp @@ -35,6 +35,7 @@ #include "gitplugin.h" #include "gitconstants.h" #include "commitdata.h" +#include "gitsubmiteditor.h" #include <coreplugin/icore.h> #include <coreplugin/coreconstants.h> @@ -49,8 +50,11 @@ #include <QtCore/QRegExp> #include <QtCore/QTemporaryFile> #include <QtCore/QFuture> +#include <QtCore/QTime> -#include <QtGui/QErrorMessage> +#include <QtGui/QMessageBox> +#include <QtGui/QMainWindow> // for msg box parent +#include <QtGui/QPushButton> using namespace Git; using namespace Git::Internal; @@ -76,22 +80,37 @@ inline Core::IEditor* locateEditor(const Core::ICore *core, const char *property return 0; } +static inline QString msgRepositoryNotFound(const QString &dir) +{ + return GitClient::tr("Unable to determine the repository for %1.").arg(dir); +} + +static inline QString msgParseFilesFailed() +{ + return GitClient::tr("Unable to parse the file output."); +} + +// Format a command for the status window +static QString formatCommand(const QString &binary, const QStringList &args) +{ + const QString timeStamp = QTime::currentTime().toString(QLatin1String("HH:mm")); + return GitClient::tr("%1 Executing: %2 %3\n").arg(timeStamp, binary, args.join(QString(QLatin1Char(' ')))); +} + +// ---------------- GitClient GitClient::GitClient(GitPlugin* plugin, Core::ICore *core) : m_msgWait(tr("Waiting for data...")), m_plugin(plugin), m_core(core) { + if (QSettings *s = m_core->settings()) + m_settings.fromSettings(s); } GitClient::~GitClient() { } -bool GitClient::vcsOpen(const QString &fileName) -{ - return m_plugin->vcsOpen(fileName); -} - QString GitClient::findRepositoryForFile(const QString &fileName) { const QString gitDirectory = QLatin1String(kGitDirectoryC); @@ -176,7 +195,7 @@ void GitClient::diff(const QString &workingDirectory, const QStringList &fileNam const QString title = tr("Git Diff"); VCSBase::VCSBaseEditor *editor = createVCSEditor(kind, title, workingDirectory, true, "originalFileName", workingDirectory); - executeGit(workingDirectory, arguments, m_plugin->m_outputWindow, editor); + executeGit(workingDirectory, arguments, m_plugin->outputWindow(), editor); } @@ -194,27 +213,26 @@ void GitClient::diff(const QString &workingDirectory, const QString &fileName) const QString sourceFile = source(workingDirectory, fileName); VCSBase::VCSBaseEditor *editor = createVCSEditor(kind, title, sourceFile, true, "originalFileName", sourceFile); - executeGit(workingDirectory, arguments, m_plugin->m_outputWindow, editor); + executeGit(workingDirectory, arguments, m_plugin->outputWindow(), editor); } void GitClient::status(const QString &workingDirectory) { QStringList statusArgs(QLatin1String("status")); statusArgs << QLatin1String("-u"); - executeGit(workingDirectory, statusArgs, m_plugin->m_outputWindow, 0,true); + executeGit(workingDirectory, statusArgs, m_plugin->outputWindow(), 0,true); } void GitClient::log(const QString &workingDirectory, const QString &fileName) { if (Git::Constants::debug) qDebug() << "log" << workingDirectory << fileName; - QStringList arguments; - int logCount = 10; - if (m_plugin->m_settingsPage && m_plugin->m_settingsPage->logCount() > 0) - logCount = m_plugin->m_settingsPage->logCount(); - arguments << QLatin1String("log") << QLatin1String("-n") - << QString::number(logCount); + QStringList arguments(QLatin1String("log")); + + if (m_settings.logCount > 0) + arguments << QLatin1String("-n") << QString::number(m_settings.logCount); + if (!fileName.isEmpty()) arguments << fileName; @@ -222,7 +240,7 @@ void GitClient::log(const QString &workingDirectory, const QString &fileName) const QString kind = QLatin1String(Git::Constants::GIT_LOG_EDITOR_KIND); const QString sourceFile = source(workingDirectory, fileName); VCSBase::VCSBaseEditor *editor = createVCSEditor(kind, title, sourceFile, false, "logFileName", sourceFile); - executeGit(workingDirectory, arguments, m_plugin->m_outputWindow, editor); + executeGit(workingDirectory, arguments, m_plugin->outputWindow(), editor); } void GitClient::show(const QString &source, const QString &id) @@ -238,7 +256,7 @@ void GitClient::show(const QString &source, const QString &id) const QFileInfo sourceFi(source); const QString workDir = sourceFi.isDir() ? sourceFi.absoluteFilePath() : sourceFi.absolutePath(); - executeGit(workDir, arguments, m_plugin->m_outputWindow, editor); + executeGit(workDir, arguments, m_plugin->outputWindow(), editor); } void GitClient::blame(const QString &workingDirectory, const QString &fileName) @@ -253,7 +271,7 @@ void GitClient::blame(const QString &workingDirectory, const QString &fileName) const QString sourceFile = source(workingDirectory, fileName); VCSBase::VCSBaseEditor *editor = createVCSEditor(kind, title, sourceFile, true, "blameFileName", sourceFile); - executeGit(workingDirectory, arguments, m_plugin->m_outputWindow, editor); + executeGit(workingDirectory, arguments, m_plugin->outputWindow(), editor); } void GitClient::checkout(const QString &workingDirectory, const QString &fileName) @@ -267,7 +285,7 @@ void GitClient::checkout(const QString &workingDirectory, const QString &fileNam arguments << QLatin1String("checkout") << QLatin1String("HEAD") << QLatin1String("--") << fileName; - executeGit(workingDirectory, arguments, m_plugin->m_outputWindow, 0,true); + executeGit(workingDirectory, arguments, m_plugin->outputWindow(), 0,true); } void GitClient::hardReset(const QString &workingDirectory, const QString &commit) @@ -277,7 +295,7 @@ void GitClient::hardReset(const QString &workingDirectory, const QString &commit if (!commit.isEmpty()) arguments << commit; - executeGit(workingDirectory, arguments, m_plugin->m_outputWindow, 0,true); + executeGit(workingDirectory, arguments, m_plugin->outputWindow(), 0,true); } void GitClient::addFile(const QString &workingDirectory, const QString &fileName) @@ -285,7 +303,7 @@ void GitClient::addFile(const QString &workingDirectory, const QString &fileName QStringList arguments; arguments << QLatin1String("add") << fileName; - executeGit(workingDirectory, arguments, m_plugin->m_outputWindow, 0,true); + executeGit(workingDirectory, arguments, m_plugin->outputWindow(), 0,true); } bool GitClient::synchronousAdd(const QString &workingDirectory, const QStringList &files) @@ -300,14 +318,27 @@ bool GitClient::synchronousAdd(const QString &workingDirectory, const QStringLis if (!rc) { const QString errorMessage = tr("Unable to add %n file(s) to %1: %2", 0, files.size()). arg(workingDirectory, QString::fromLocal8Bit(errorText)); - m_plugin->m_outputWindow->append(errorMessage); - m_plugin->m_outputWindow->popup(false); + m_plugin->outputWindow()->append(errorMessage); + m_plugin->outputWindow()->popup(false); } return rc; } bool GitClient::synchronousReset(const QString &workingDirectory, const QStringList &files) +{ + QString errorMessage; + const bool rc = synchronousReset(workingDirectory, files, &errorMessage); + if (!rc) { + m_plugin->outputWindow()->append(errorMessage); + m_plugin->outputWindow()->popup(false); + } + return rc; +} + +bool GitClient::synchronousReset(const QString &workingDirectory, + const QStringList &files, + QString *errorMessage) { if (Git::Constants::debug) qDebug() << Q_FUNC_INFO << workingDirectory << files; @@ -317,14 +348,30 @@ bool GitClient::synchronousReset(const QString &workingDirectory, arguments << QLatin1String("reset") << QLatin1String("HEAD") << QLatin1String("--") << files; const bool rc = synchronousGit(workingDirectory, arguments, &outputText, &errorText); const QString output = QString::fromLocal8Bit(outputText); - m_plugin->m_outputWindow->popup(false); - m_plugin->m_outputWindow->append(output); + m_plugin->outputWindow()->popup(false); + m_plugin->outputWindow()->append(output); // Note that git exits with 1 even if the operation is successful // Assume real failure if the output does not contain "foo.cpp modified" if (!rc && !output.contains(QLatin1String("modified"))) { - const QString errorMessage = tr("Unable to reset %n file(s) in %1: %2", 0, files.size()). - arg(workingDirectory, QString::fromLocal8Bit(errorText)); - m_plugin->m_outputWindow->append(errorMessage); + *errorMessage = tr("Unable to reset %n file(s) in %1: %2", 0, files.size()).arg(workingDirectory, QString::fromLocal8Bit(errorText)); + return false; + } + return true; +} + +bool GitClient::synchronousCheckout(const QString &workingDirectory, + const QStringList &files, + QString *errorMessage) +{ + if (Git::Constants::debug) + qDebug() << Q_FUNC_INFO << workingDirectory << files; + QByteArray outputText; + QByteArray errorText; + QStringList arguments; + arguments << QLatin1String("checkout") << QLatin1String("--") << files; + const bool rc = synchronousGit(workingDirectory, arguments, &outputText, &errorText); + if (!rc) { + *errorMessage = tr("Unable to checkout %n file(s) in %1: %2", 0, files.size()).arg(workingDirectory, QString::fromLocal8Bit(errorText)); return false; } return true; @@ -336,13 +383,14 @@ void GitClient::executeGit(const QString &workingDirectory, const QStringList &a { if (Git::Constants::debug) qDebug() << "executeGit" << workingDirectory << arguments << editor; - outputWindow->clearContents(); + + m_plugin->outputWindow()->append(formatCommand(QLatin1String(kGitCommand), arguments)); QProcess process; ProjectExplorer::Environment environment = ProjectExplorer::Environment::systemEnvironment(); - if (m_plugin->m_settingsPage && !m_plugin->m_settingsPage->adoptEnvironment()) - environment.set(QLatin1String("PATH"), m_plugin->m_settingsPage->path()); + if (m_settings.adoptPath) + environment.set(QLatin1String("PATH"), m_settings.path); GitCommand* command = new GitCommand(); if (outputToWindow) { @@ -361,23 +409,28 @@ void GitClient::executeGit(const QString &workingDirectory, const QStringList &a command->execute(arguments, workingDirectory, environment); } -bool GitClient::synchronousGit(const QString &workingDirectory - , const QStringList &arguments - , QByteArray* outputText - , QByteArray* errorText) +bool GitClient::synchronousGit(const QString &workingDirectory, + const QStringList &arguments, + QByteArray* outputText, + QByteArray* errorText, + bool logCommandToWindow) { if (Git::Constants::debug) qDebug() << "synchronousGit" << workingDirectory << arguments; - QProcess process; + const QString binary = QLatin1String(kGitCommand); + + if (logCommandToWindow) + m_plugin->outputWindow()->append(formatCommand(binary, arguments)); + QProcess process; process.setWorkingDirectory(workingDirectory); ProjectExplorer::Environment environment = ProjectExplorer::Environment::systemEnvironment(); - if (m_plugin->m_settingsPage && !m_plugin->m_settingsPage->adoptEnvironment()) - environment.set(QLatin1String("PATH"), m_plugin->m_settingsPage->path()); + if (m_settings.adoptPath) + environment.set(QLatin1String("PATH"), m_settings.path); process.setEnvironment(environment.toStringList()); - process.start(QLatin1String(kGitCommand), arguments); + process.start(binary, arguments); if (!process.waitForFinished()) { if (errorText) *errorText = "Error: Git timed out"; @@ -411,6 +464,34 @@ static inline QString trimFileSpecification(QString fileSpec) return fileSpec; } +GitClient::StatusResult GitClient::gitStatus(const QString &workingDirectory, + bool untracked, + QString *output, + QString *errorMessage) +{ + // Run 'status'. Note that git returns exitcode 1 if there are no added files. + QByteArray outputText; + QByteArray errorText; + QStringList statusArgs(QLatin1String("status")); + if (untracked) + statusArgs << QLatin1String("-u"); + const bool statusRc = synchronousGit(workingDirectory, statusArgs, &outputText, &errorText); + if (output) + *output = QString::fromLocal8Bit(outputText).remove(QLatin1Char('\r')); + // Is it something really fatal? + if (!statusRc && !outputText.contains(kBranchIndicatorC)) { + if (errorMessage) { + const QString error = QString::fromLocal8Bit(errorText).remove(QLatin1Char('\r')); + *errorMessage = tr("Unable to obtain the status: %1").arg(error); + } + return StatusFailed; + } + // Unchanged? + if (outputText.contains("nothing to commit")) + return StatusUnchanged; + return StatusChanged; +} + /* Parse a git status file list: * \code # Changes to be committed: @@ -421,10 +502,11 @@ static inline QString trimFileSpecification(QString fileSpec) #<tab>modified:<blanks>git.pro \endcode */ -static bool parseFiles(const QStringList &lines, CommitData *d) +static bool parseFiles(const QString &output, CommitData *d) { enum State { None, CommitFiles, NotUpdatedFiles, UntrackedFiles }; + const QStringList lines = output.split(QLatin1Char('\n')); const QString branchIndicator = QLatin1String(kBranchIndicatorC); const QString commitIndicator = QLatin1String("# Changes to be committed:"); const QString notUpdatedIndicator = QLatin1String("# Changed but not updated:"); @@ -457,10 +539,10 @@ static bool parseFiles(const QStringList &lines, CommitData *d) const QString fileSpec = line.mid(2).trimmed(); switch (s) { case CommitFiles: - d->commitFiles.push_back(trimFileSpecification(fileSpec)); + d->stagedFiles.push_back(trimFileSpecification(fileSpec)); break; case NotUpdatedFiles: - d->notUpdatedFiles.push_back(trimFileSpecification(fileSpec)); + d->unstagedFiles.push_back(trimFileSpecification(fileSpec)); break; case UntrackedFiles: d->untrackedFiles.push_back(QLatin1String("untracked: ") + fileSpec); @@ -474,7 +556,7 @@ static bool parseFiles(const QStringList &lines, CommitData *d) } } } - return !d->commitFiles.empty() || !d->notUpdatedFiles.empty() || !d->untrackedFiles.empty(); + return !d->stagedFiles.empty() || !d->unstagedFiles.empty() || !d->untrackedFiles.empty(); } bool GitClient::getCommitData(const QString &workingDirectory, @@ -482,12 +564,15 @@ bool GitClient::getCommitData(const QString &workingDirectory, CommitData *d, QString *errorMessage) { + if (Git::Constants::debug) + qDebug() << Q_FUNC_INFO << workingDirectory; + d->clear(); // Find repo const QString repoDirectory = GitClient::findRepositoryForDirectory(workingDirectory); if (repoDirectory.isEmpty()) { - *errorMessage = tr("Unable to determine the repository for %1.").arg(workingDirectory); + *errorMessage = msgRepositoryNotFound(workingDirectory); return false; } @@ -508,23 +593,15 @@ bool GitClient::getCommitData(const QString &workingDirectory, } // Run status. Note that it has exitcode 1 if there are no added files. - QByteArray outputText; - QByteArray errorText; - QStringList statusArgs(QLatin1String("status")); - if (untrackedFilesInCommit) - statusArgs << QLatin1String("-u"); - const bool statusRc = synchronousGit(workingDirectory, statusArgs, &outputText, &errorText); - if (!statusRc) { - // Something fatal - if (!outputText.contains(kBranchIndicatorC)) { - *errorMessage = tr("Unable to obtain the project status: %1").arg(QString::fromLocal8Bit(errorText)); - return false; - } - // All unchanged - if (outputText.contains("nothing to commit")) { - *errorMessage = tr("There are no modified files."); - return false; - } + QString output; + switch (gitStatus(repoDirectory, untrackedFilesInCommit, &output, errorMessage)) { + case StatusChanged: + break; + case StatusUnchanged: + *errorMessage = msgNoChangedFiles(); + return false; + case StatusFailed: + return false; } // Output looks like: @@ -545,9 +622,8 @@ bool GitClient::getCommitData(const QString &workingDirectory, // # // # list of files... - const QStringList lines = QString::fromLocal8Bit(outputText).remove(QLatin1Char('\r')).split(QLatin1Char('\n')); - if (!parseFiles(lines, d)) { - *errorMessage = tr("Unable to parse the file output."); + if (!parseFiles(output, d)) { + *errorMessage = msgParseFilesFailed(); return false; } @@ -570,24 +646,24 @@ bool GitClient::getCommitData(const QString &workingDirectory, } // addAndCommit: -bool GitClient::addAndCommit(const QString &workingDirectory, +bool GitClient::addAndCommit(const QString &repositoryDirectory, const GitSubmitEditorPanelData &data, const QString &messageFile, const QStringList &checkedFiles, const QStringList &origCommitFiles) { if (Git::Constants::debug) - qDebug() << "GitClient::addAndCommit:" << workingDirectory << checkedFiles << origCommitFiles; + qDebug() << "GitClient::addAndCommit:" << repositoryDirectory << checkedFiles << origCommitFiles; // Do we need to reset any files that had been added before // (did the user uncheck any previously added files) const QSet<QString> resetFiles = origCommitFiles.toSet().subtract(checkedFiles.toSet()); if (!resetFiles.empty()) - if (!synchronousReset(workingDirectory, resetFiles.toList())) + if (!synchronousReset(repositoryDirectory, resetFiles.toList())) return false; // Re-add all to make sure we have the latest changes - if (!synchronousAdd(workingDirectory, checkedFiles)) + if (!synchronousAdd(repositoryDirectory, checkedFiles)) return false; // Do the final commit @@ -598,24 +674,192 @@ bool GitClient::addAndCommit(const QString &workingDirectory, QByteArray outputText; QByteArray errorText; - const bool rc = synchronousGit(workingDirectory, args, &outputText, &errorText); + const bool rc = synchronousGit(repositoryDirectory, args, &outputText, &errorText); const QString message = rc ? - tr("Committed %n file(s).", 0, checkedFiles.size()) : - tr("Unable to commit %n file(s): %1", 0, checkedFiles.size()).arg(QString::fromLocal8Bit(errorText)); + tr("Committed %n file(s).\n", 0, checkedFiles.size()) : + tr("Unable to commit %n file(s): %1\n", 0, checkedFiles.size()).arg(QString::fromLocal8Bit(errorText)); - m_plugin->m_outputWindow->append(message); - m_plugin->m_outputWindow->popup(false); + m_plugin->outputWindow()->append(message); + m_plugin->outputWindow()->popup(false); return rc; } +static inline bool askWithInformativeText(QWidget *parent, + const QString &title, + const QString &msg, + const QString &inf, + bool defaultValue) +{ + QMessageBox msgBox(QMessageBox::Question, title, msg, QMessageBox::Yes|QMessageBox::No, parent); + msgBox.setInformativeText(inf); + msgBox.setDefaultButton(defaultValue ? QMessageBox::Yes : QMessageBox::No); + return msgBox.exec() == QMessageBox::Yes; +} + +/* Revert: This function can be called with a file list (to revert single + * files) or a single directory (revert all). Qt Creator currently has only + * 'revert single' in its VCS menus, but the code is prepared to deal with + * reverting a directory pending a sophisticated selection dialog in the + * VCSBase plugin. */ + +GitClient::RevertResult GitClient::revertI(QStringList files, bool *ptrToIsDirectory, QString *errorMessage) +{ + if (Git::Constants::debug) + qDebug() << Q_FUNC_INFO << files; + + if (files.empty()) + return RevertCanceled; + + // Figure out the working directory + const QFileInfo firstFile(files.front()); + const bool isDirectory = firstFile.isDir(); + if (ptrToIsDirectory) + *ptrToIsDirectory = isDirectory; + const QString workingDirectory = isDirectory ? firstFile.absoluteFilePath() : firstFile.absolutePath(); + + const QString repoDirectory = GitClient::findRepositoryForDirectory(workingDirectory); + if (repoDirectory.isEmpty()) { + *errorMessage = msgRepositoryNotFound(workingDirectory); + return RevertFailed; + } + + // Check for changes + QString output; + switch (gitStatus(repoDirectory, false, &output, errorMessage)) { + case StatusChanged: + break; + case StatusUnchanged: + return RevertUnchanged; + case StatusFailed: + return RevertFailed; + } + CommitData d; + if (!parseFiles(output, &d)) { + *errorMessage = msgParseFilesFailed(); + return RevertFailed; + } + + // If we are looking at files, make them relative to the repository + // directory to match them in the status output list. + if (!isDirectory) { + const QDir repoDir(repoDirectory); + const QStringList::iterator cend = files.end(); + for (QStringList::iterator it = files.begin(); it != cend; ++it) + *it = repoDir.relativeFilePath(*it); + } + + // From the status output, determine all modified [un]staged files. + const QString modifiedPattern = QLatin1String("modified: "); + const QStringList allStagedFiles = GitSubmitEditor::statusListToFileList(d.stagedFiles.filter(modifiedPattern)); + const QStringList allUnstagedFiles = GitSubmitEditor::statusListToFileList(d.unstagedFiles.filter(modifiedPattern)); + // Unless a directory was passed, filter all modified files for the + // argument file list. + QStringList stagedFiles = allStagedFiles; + QStringList unstagedFiles = allUnstagedFiles; + if (!isDirectory) { + const QSet<QString> filesSet = files.toSet(); + stagedFiles = allStagedFiles.toSet().intersect(filesSet).toList(); + unstagedFiles = allUnstagedFiles.toSet().intersect(filesSet).toList(); + } + if (Git::Constants::debug) + qDebug() << Q_FUNC_INFO << d.stagedFiles << d.unstagedFiles << allStagedFiles << allUnstagedFiles << stagedFiles << unstagedFiles; + + if (stagedFiles.empty() && unstagedFiles.empty()) + return RevertUnchanged; + + // Ask to revert (to do: Handle lists with a selection dialog) + const QMessageBox::StandardButton answer + = QMessageBox::question(m_core->mainWindow(), + tr("Revert"), + tr("The file has been changed. Do you want to revert it?"), + QMessageBox::Yes|QMessageBox::No, + QMessageBox::No); + if (answer == QMessageBox::No) + return RevertCanceled; + + // Unstage the staged files + if (!stagedFiles.empty() && !synchronousReset(repoDirectory, stagedFiles, errorMessage)) + return RevertFailed; + // Finally revert! + if (!synchronousCheckout(repoDirectory, stagedFiles + unstagedFiles, errorMessage)) + return RevertFailed; + return RevertOk; +} + +void GitClient::revert(const QStringList &files) +{ + bool isDirectory; + QString errorMessage; + switch (revertI(files, &isDirectory, &errorMessage)) { + case RevertOk: + case RevertCanceled: + break; + case RevertUnchanged: { + const QString msg = (isDirectory || files.size() > 1) ? msgNoChangedFiles() : tr("The file is not modified."); + m_plugin->outputWindow()->append(msg); + m_plugin->outputWindow()->popup(); + } + break; + case RevertFailed: + m_plugin->outputWindow()->append(errorMessage); + m_plugin->outputWindow()->popup(); + break; + } +} + void GitClient::pull(const QString &workingDirectory) { - executeGit(workingDirectory, QStringList(QLatin1String("pull")), m_plugin->m_outputWindow, 0,true); + executeGit(workingDirectory, QStringList(QLatin1String("pull")), m_plugin->outputWindow(), 0, true); } void GitClient::push(const QString &workingDirectory) { - executeGit(workingDirectory, QStringList(QLatin1String("push")), m_plugin->m_outputWindow, 0,true); + executeGit(workingDirectory, QStringList(QLatin1String("push")), m_plugin->outputWindow(), 0, true); +} + +QString GitClient::msgNoChangedFiles() +{ + return tr("There are no modified files."); +} + +void GitClient::stash(const QString &workingDirectory) +{ + // Check for changes and stash + QString errorMessage; + switch (gitStatus(workingDirectory, false, 0, &errorMessage)) { + case StatusChanged: + executeGit(workingDirectory, QStringList(QLatin1String("stash")), m_plugin->outputWindow(), 0, true); + break; + case StatusUnchanged: + m_plugin->outputWindow()->append(msgNoChangedFiles()); + m_plugin->outputWindow()->popup(); + break; + case StatusFailed: + m_plugin->outputWindow()->append(errorMessage); + m_plugin->outputWindow()->popup(); + break; + } +} + +void GitClient::stashPop(const QString &workingDirectory) +{ + QStringList arguments(QLatin1String("stash")); + arguments << QLatin1String("pop"); + executeGit(workingDirectory, arguments, m_plugin->outputWindow(), 0, true); +} + +void GitClient::branchList(const QString &workingDirectory) +{ + QStringList arguments(QLatin1String("branch")); + arguments << QLatin1String("-r"); + executeGit(workingDirectory, arguments, m_plugin->outputWindow(), 0, true); +} + +void GitClient::stashList(const QString &workingDirectory) +{ + QStringList arguments(QLatin1String("stash")); + arguments << QLatin1String("list"); + executeGit(workingDirectory, arguments, m_plugin->outputWindow(), 0, true); } QString GitClient::readConfig(const QString &workingDirectory, const QStringList &configVar) @@ -624,8 +868,8 @@ QString GitClient::readConfig(const QString &workingDirectory, const QStringList arguments << QLatin1String("config") << configVar; QByteArray outputText; - if (synchronousGit(workingDirectory, arguments, &outputText)) - return QString::fromLocal8Bit(outputText); + if (synchronousGit(workingDirectory, arguments, &outputText, 0, false)) + return QString::fromLocal8Bit(outputText).remove(QLatin1Char('\r')); return QString(); } @@ -635,6 +879,21 @@ QString GitClient::readConfigValue(const QString &workingDirectory, const QStrin return readConfig(workingDirectory, QStringList(configVar)).remove(QLatin1Char('\n')); } +GitSettings GitClient::settings() const +{ + return m_settings; +} + +void GitClient::setSettings(const GitSettings &s) +{ + if (s != m_settings) { + m_settings = s; + if (QSettings *s = m_core->settings()) + m_settings.toSettings(s); + } +} + +// ------------------------ GitCommand GitCommand::GitCommand() { } diff --git a/src/plugins/git/gitclient.h b/src/plugins/git/gitclient.h index 1a7ebe8c983a8f83dd970e1019b02ca4c2e8286b..efc767e54095e98e8be96022f1bd5ed04cf4989f 100644 --- a/src/plugins/git/gitclient.h +++ b/src/plugins/git/gitclient.h @@ -34,6 +34,8 @@ #ifndef GITCLIENT_H #define GITCLIENT_H +#include "gitsettings.h" + #include <coreplugin/iversioncontrol.h> #include <coreplugin/editormanager/ieditor.h> #include <projectexplorer/environment.h> @@ -62,17 +64,14 @@ class GitCommand; struct CommitData; struct GitSubmitEditorPanelData; -class GitClient : public Core::IVersionControl +class GitClient : public QObject { Q_OBJECT public: - GitClient(GitPlugin *plugin, Core::ICore *core); + explicit GitClient(GitPlugin *plugin, Core::ICore *core); ~GitClient(); - bool vcsOpen(const QString &fileName); - bool vcsAdd(const QString &) { return false; } - bool vcsDelete(const QString &) { return false; } bool managesDirectory(const QString &) const { return false; } QString findTopLevelForDirectory(const QString &) const { return QString(); } @@ -91,9 +90,17 @@ public: void addFile(const QString &workingDirectory, const QString &fileName); bool synchronousAdd(const QString &workingDirectory, const QStringList &files); bool synchronousReset(const QString &workingDirectory, const QStringList &files); + bool synchronousReset(const QString &workingDirectory, const QStringList &files, QString *errorMessage); + bool synchronousCheckout(const QString &workingDirectory, const QStringList &files, QString *errorMessage); void pull(const QString &workingDirectory); void push(const QString &workingDirectory); + void stash(const QString &workingDirectory); + void stashPop(const QString &workingDirectory); + void revert(const QStringList &files); + void branchList(const QString &workingDirectory); + void stashList(const QString &workingDirectory); + QString readConfig(const QString &workingDirectory, const QStringList &configVar); QString readConfigValue(const QString &workingDirectory, const QString &configVar); @@ -109,6 +116,17 @@ public: const QStringList &checkedFiles, const QStringList &origCommitFiles); + enum StatusResult { StatusChanged, StatusUnchanged, StatusFailed }; + StatusResult gitStatus(const QString &workingDirectory, + bool untracked, + QString *output = 0, + QString *errorMessage = 0); + + GitSettings settings() const; + void setSettings(const GitSettings &s); + + static QString msgNoChangedFiles(); + public slots: void show(const QString &source, const QString &id); @@ -128,13 +146,18 @@ private: bool outputToWindow = false); bool synchronousGit(const QString &workingDirectory, - const QStringList &arguments, - QByteArray* outputText = 0, - QByteArray* errorText = 0); + const QStringList &arguments, + QByteArray* outputText = 0, + QByteArray* errorText = 0, + bool logCommandToWindow = true); + + enum RevertResult { RevertOk, RevertUnchanged, RevertCanceled, RevertFailed }; + RevertResult revertI(QStringList files, bool *isDirectory, QString *errorMessage); const QString m_msgWait; GitPlugin *m_plugin; Core::ICore *m_core; + GitSettings m_settings; }; class GitCommand : public QObject diff --git a/src/plugins/git/gitoutputwindow.cpp b/src/plugins/git/gitoutputwindow.cpp index a321449b1e22614c5367d0138e0502ede392a5f8..375be9095973414a65bf715b3c2c38e7a394ffd0 100644 --- a/src/plugins/git/gitoutputwindow.cpp +++ b/src/plugins/git/gitoutputwindow.cpp @@ -104,6 +104,7 @@ void GitOutputWindow::append(const QString &text) const QStringList lines = text.split(QLatin1Char('\n')); foreach (const QString &s, lines) m_outputListWidget->addItem(s); + m_outputListWidget->scrollToBottom(); popup(); } diff --git a/src/plugins/git/gitplugin.cpp b/src/plugins/git/gitplugin.cpp index 6209996edc141052ff75a4571df052fdb3d85144..ebce0f7c452dbf9624a7186d3aded21a0fe056d0 100644 --- a/src/plugins/git/gitplugin.cpp +++ b/src/plugins/git/gitplugin.cpp @@ -33,6 +33,7 @@ #include "gitplugin.h" #include "gitclient.h" +#include "gitversioncontrol.h" #include "giteditor.h" #include "gitconstants.h" #include "changeselectiondialog.h" @@ -117,7 +118,9 @@ GitPlugin::GitPlugin() : m_undoFileAction(0), m_undoProjectAction(0), m_showAction(0), - m_addAction(0), + m_stageAction(0), + m_unstageAction(0), + m_revertAction(0), m_commitAction(0), m_pullAction(0), m_pushAction(0), @@ -125,6 +128,10 @@ GitPlugin::GitPlugin() : m_diffSelectedFilesAction(0), m_undoAction(0), m_redoAction(0), + m_stashAction(0), + m_stashPopAction(0), + m_stashListAction(0), + m_branchListAction(0), m_projectExplorer(0), m_gitClient(0), m_outputWindow(0), @@ -132,6 +139,7 @@ GitPlugin::GitPlugin() : m_settingsPage(0), m_coreListener(0), m_submitEditorFactory(0), + m_versionControl(0), m_changeTmpFile(0) { Q_ASSERT(m_instance == 0); @@ -170,6 +178,12 @@ GitPlugin::~GitPlugin() m_submitEditorFactory = 0; } + if (m_versionControl) { + removeObject(m_versionControl); + delete m_versionControl; + m_versionControl = 0; + } + cleanChangeTmpFile(); delete m_gitClient; m_instance = 0; @@ -198,6 +212,15 @@ static const VCSBase::VCSBaseSubmitEditorParameters submitParameters = { Git::Constants::DIFF_SELECTED }; +static inline Core::ICommand *createSeparator(Core::ActionManagerInterface *am, + const QList<int> &context, + const QString &id, + QObject *parent) +{ + QAction *a = new QAction(parent); + a->setSeparator(true); + return am->registerAction(a, id, context); +} bool GitPlugin::initialize(const QStringList &arguments, QString *error_message) { @@ -235,6 +258,9 @@ bool GitPlugin::initialize(const QStringList &arguments, QString *error_message) m_submitEditorFactory = new GitSubmitEditorFactory(&submitParameters); addObject(m_submitEditorFactory); + m_versionControl = new GitVersionControl(m_gitClient); + addObject(m_versionControl); + //register actions Core::ActionManagerInterface *actionManager = m_core->actionManager(); @@ -245,9 +271,12 @@ bool GitPlugin::initialize(const QStringList &arguments, QString *error_message) actionManager->createMenu(QLatin1String("Git")); gitContainer->menu()->setTitle(tr("&Git")); toolsContainer->addMenu(gitContainer); + if (QAction *ma = gitContainer->menu()->menuAction()) { + ma->setEnabled(m_versionControl->isEnabled()); + connect(m_versionControl, SIGNAL(enabledChanged(bool)), ma, SLOT(setVisible(bool))); + } Core::ICommand *command; - QAction *tmpaction; m_diffAction = new QAction(tr("Diff current file"), this); command = actionManager->registerAction(m_diffAction, "Git.Diff", globalcontext); @@ -284,18 +313,27 @@ bool GitPlugin::initialize(const QStringList &arguments, QString *error_message) connect(m_undoFileAction, SIGNAL(triggered()), this, SLOT(undoFileChanges())); gitContainer->addAction(command); - m_addAction = new QAction(tr("Add File"), this); - command = actionManager->registerAction(m_addAction, "Git.Add", globalcontext); + m_stageAction = new QAction(tr("Stage file for commit"), this); + command = actionManager->registerAction(m_stageAction, "Git.Stage", globalcontext); command->setDefaultKeySequence(QKeySequence(tr("Alt+G,Alt+A"))); command->setAttribute(Core::ICommand::CA_UpdateText); - connect(m_addAction, SIGNAL(triggered()), this, SLOT(addFile())); + connect(m_stageAction, SIGNAL(triggered()), this, SLOT(stageFile())); gitContainer->addAction(command); - tmpaction = new QAction(this); - tmpaction->setSeparator(true); - command = actionManager->registerAction(tmpaction, QLatin1String("Git.Sep.Project"), globalcontext); + m_unstageAction = new QAction(tr("Unstage file from commit"), this); + command = actionManager->registerAction(m_unstageAction, "Git.Unstage", globalcontext); + command->setAttribute(Core::ICommand::CA_UpdateText); + connect(m_unstageAction, SIGNAL(triggered()), this, SLOT(unstageFile())); gitContainer->addAction(command); + m_revertAction = new QAction(tr("Revert..."), this); + command = actionManager->registerAction(m_revertAction, "Git.Revert", globalcontext); + command->setAttribute(Core::ICommand::CA_UpdateText); + connect(m_revertAction, SIGNAL(triggered()), this, SLOT(revertFile())); + gitContainer->addAction(command); + + gitContainer->addAction(createSeparator(actionManager, globalcontext, QLatin1String("Git.Sep.Project"), this)); + m_diffProjectAction = new QAction(tr("Diff current project"), this); command = actionManager->registerAction(m_diffProjectAction, "Git.DiffProject", globalcontext); command->setDefaultKeySequence(QKeySequence("Alt+G,Alt+Shift+D")); @@ -322,15 +360,26 @@ bool GitPlugin::initialize(const QStringList &arguments, QString *error_message) connect(m_undoProjectAction, SIGNAL(triggered()), this, SLOT(undoProjectChanges())); gitContainer->addAction(command); - tmpaction = new QAction(this); - tmpaction->setSeparator(true); - command = actionManager->registerAction(tmpaction, QLatin1String("Git.Sep.Global"), globalcontext); + gitContainer->addAction(createSeparator(actionManager, globalcontext, QLatin1String("Git.Sep.Global"), this)); + + m_stashAction = new QAction(tr("Stash"), this); + m_stashAction->setToolTip("Saves the current state of your work."); + command = actionManager->registerAction(m_stashAction, "Git.Stash", globalcontext); + command->setAttribute(Core::ICommand::CA_UpdateText); + connect(m_stashAction, SIGNAL(triggered()), this, SLOT(stash())); gitContainer->addAction(command); - m_showAction = new QAction(tr("Show commit..."), this); - command = actionManager->registerAction(m_showAction, "Git.ShowCommit", globalcontext); + m_pullAction = new QAction(tr("Pull"), this); + command = actionManager->registerAction(m_pullAction, "Git.Pull", globalcontext); command->setAttribute(Core::ICommand::CA_UpdateText); - connect(m_showAction, SIGNAL(triggered()), this, SLOT(showCommit())); + connect(m_pullAction, SIGNAL(triggered()), this, SLOT(pull())); + gitContainer->addAction(command); + + m_stashPopAction = new QAction(tr("Stash pop"), this); + m_stashAction->setToolTip("Restores changes saved to the stash list using \"Stash\"."); + command = actionManager->registerAction(m_stashPopAction, "Git.StashPop", globalcontext); + command->setAttribute(Core::ICommand::CA_UpdateText); + connect(m_stashPopAction, SIGNAL(triggered()), this, SLOT(stashPop())); gitContainer->addAction(command); m_commitAction = new QAction(tr("Commit..."), this); @@ -340,24 +389,37 @@ bool GitPlugin::initialize(const QStringList &arguments, QString *error_message) connect(m_commitAction, SIGNAL(triggered()), this, SLOT(startCommit())); gitContainer->addAction(command); - m_pullAction = new QAction(tr("Pull"), this); - command = actionManager->registerAction(m_pullAction, "Git.Pull", globalcontext); - command->setAttribute(Core::ICommand::CA_UpdateText); - connect(m_pullAction, SIGNAL(triggered()), this, SLOT(pull())); - gitContainer->addAction(command); - m_pushAction = new QAction(tr("Push"), this); command = actionManager->registerAction(m_pushAction, "Git.Push", globalcontext); command->setAttribute(Core::ICommand::CA_UpdateText); connect(m_pushAction, SIGNAL(triggered()), this, SLOT(push())); gitContainer->addAction(command); + gitContainer->addAction(createSeparator(actionManager, globalcontext, QLatin1String("Git.Sep.Branch"), this)); + + m_branchListAction = new QAction(tr("List branches"), this); + command = actionManager->registerAction(m_branchListAction, "Git.BranchList", globalcontext); + command->setAttribute(Core::ICommand::CA_UpdateText); + connect(m_branchListAction, SIGNAL(triggered()), this, SLOT(branchList())); + gitContainer->addAction(command); + + m_stashListAction = new QAction(tr("List stashes"), this); + command = actionManager->registerAction(m_stashListAction, "Git.StashList", globalcontext); + command->setAttribute(Core::ICommand::CA_UpdateText); + connect(m_stashListAction, SIGNAL(triggered()), this, SLOT(stashList())); + gitContainer->addAction(command); + + m_showAction = new QAction(tr("Show commit..."), this); + command = actionManager->registerAction(m_showAction, "Git.ShowCommit", globalcontext); + command->setAttribute(Core::ICommand::CA_UpdateText); + connect(m_showAction, SIGNAL(triggered()), this, SLOT(showCommit())); + gitContainer->addAction(command); + // Submit editor QList<int> submitContext; submitContext.push_back(m_core->uniqueIDManager()->uniqueIdentifier(QLatin1String(Constants::C_GITSUBMITEDITOR))); m_submitCurrentAction = new QAction(VCSBase::VCSBaseSubmitEditor::submitIcon(), tr("Commit"), this); command = actionManager->registerAction(m_submitCurrentAction, Constants::SUBMIT_CURRENT, submitContext); - // TODO connect(m_submitCurrentAction, SIGNAL(triggered()), this, SLOT(submitCurrentLog())); m_diffSelectedFilesAction = new QAction(VCSBase::VCSBaseSubmitEditor::diffIcon(), tr("Diff Selected Files"), this); @@ -383,12 +445,6 @@ void GitPlugin::extensionsInitialized() m_projectExplorer = ExtensionSystem::PluginManager::instance()->getObject<ProjectExplorer::ProjectExplorerPlugin>(); } -bool GitPlugin::vcsOpen(const QString &fileName) -{ - Q_UNUSED(fileName); - return false; -} - void GitPlugin::submitEditorDiff(const QStringList &files) { if (files.empty()) @@ -412,7 +468,7 @@ void GitPlugin::diffCurrentProject() m_gitClient->diff(workingDirectory, QString()); } -QFileInfo GitPlugin::currentFile() +QFileInfo GitPlugin::currentFile() const { QString fileName = m_core->fileManager()->currentFile(); QFileInfo fileInfo(fileName); @@ -495,14 +551,28 @@ void GitPlugin::undoProjectChanges() m_gitClient->hardReset(workingDirectory, QString()); } -void GitPlugin::addFile() +void GitPlugin::stageFile() { - QFileInfo fileInfo = currentFile(); - QString fileName = fileInfo.fileName(); - QString workingDirectory = fileInfo.absolutePath(); + const QFileInfo fileInfo = currentFile(); + const QString fileName = fileInfo.fileName(); + const QString workingDirectory = fileInfo.absolutePath(); m_gitClient->addFile(workingDirectory, fileName); } +void GitPlugin::unstageFile() +{ + const QFileInfo fileInfo = currentFile(); + const QString fileName = fileInfo.fileName(); + const QString workingDirectory = fileInfo.absolutePath(); + m_gitClient->synchronousReset(workingDirectory, QStringList(fileName)); +} + +void GitPlugin::revertFile() +{ + const QFileInfo fileInfo = currentFile(); + m_gitClient->revert(QStringList(fileInfo.absoluteFilePath())); +} + void GitPlugin::startCommit() { if (m_changeTmpFile) { @@ -528,7 +598,7 @@ void GitPlugin::startCommit() // Store repository for diff and the original list of // files to be able to unstage files the user unchecks m_submitRepository = data.panelInfo.repository; - m_submitOrigCommitFiles = GitSubmitEditor::statusListToFileList(data.commitFiles); + m_submitOrigCommitFiles = GitSubmitEditor::statusListToFileList(data.stagedFiles); if (Git::Constants::debug) qDebug() << Q_FUNC_INFO << data << commitTemplate; @@ -560,7 +630,7 @@ Core::IEditor *GitPlugin::openSubmitEditor(const QString &fileName, const Commit Q_ASSERT(submitEditor); // The actions are for some reason enabled by the context switching // mechanism. Disable them correctly. - m_submitCurrentAction->setEnabled(!cd.commitFiles.empty()); + m_submitCurrentAction->setEnabled(!cd.stagedFiles.empty()); m_diffSelectedFilesAction->setEnabled(false); m_undoAction->setEnabled(false); m_redoAction->setEnabled(false); @@ -627,26 +697,52 @@ bool GitPlugin::editorAboutToClose(Core::IEditor *iEditor) void GitPlugin::pull() { - QString workingDirectory = getWorkingDirectory(); - if (workingDirectory.isEmpty()) - return; - m_gitClient->pull(workingDirectory); + const QString workingDirectory = getWorkingDirectory(); + if (!workingDirectory.isEmpty()) + m_gitClient->pull(workingDirectory); } void GitPlugin::push() { - QString workingDirectory = getWorkingDirectory(); - if (workingDirectory.isEmpty()) - return; - m_gitClient->push(workingDirectory); + const QString workingDirectory = getWorkingDirectory(); + if (!workingDirectory.isEmpty()) + m_gitClient->push(workingDirectory); +} + +void GitPlugin::stash() +{ + const QString workingDirectory = getWorkingDirectory(); + if (!workingDirectory.isEmpty()) + m_gitClient->stash(workingDirectory); +} + +void GitPlugin::stashPop() +{ + const QString workingDirectory = getWorkingDirectory(); + if (!workingDirectory.isEmpty()) + m_gitClient->stashPop(workingDirectory); +} + +void GitPlugin::branchList() +{ + const QString workingDirectory = getWorkingDirectory(); + if (!workingDirectory.isEmpty()) + m_gitClient->branchList(workingDirectory); +} + +void GitPlugin::stashList() +{ + const QString workingDirectory = getWorkingDirectory(); + if (!workingDirectory.isEmpty()) + m_gitClient->stashList(workingDirectory); } void GitPlugin::updateActions() { - QFileInfo current = currentFile(); + const QFileInfo current = currentFile(); const QString fileName = current.fileName(); const QString currentDirectory = getWorkingDirectory(); - QString repository = m_gitClient->findRepositoryForFile(current.absoluteFilePath()); + const QString repository = m_gitClient->findRepositoryForFile(current.absoluteFilePath()); // First check for file commands and if the current file is inside // a Git-repository m_diffAction->setText(tr("Diff %1").arg(fileName)); @@ -654,7 +750,9 @@ void GitPlugin::updateActions() m_logAction->setText(tr("Log %1").arg(fileName)); m_blameAction->setText(tr("Blame %1").arg(fileName)); m_undoFileAction->setText(tr("Undo changes for %1").arg(fileName)); - m_addAction->setText(tr("Add %1").arg(fileName)); + m_stageAction->setText(tr("Stage %1 for commit").arg(fileName)); + m_unstageAction->setText(tr("Unstage %1 from commit").arg(fileName)); + m_revertAction->setText(tr("Revert %1...").arg(fileName)); if (repository.isEmpty()) { // If the file is not in a repository, the corresponding project will // be neither and we can disable everything and return @@ -663,7 +761,9 @@ void GitPlugin::updateActions() m_logAction->setEnabled(false); m_blameAction->setEnabled(false); m_undoFileAction->setEnabled(false); - m_addAction->setEnabled(false); + m_stageAction->setEnabled(false); + m_unstageAction->setEnabled(false); + m_revertAction->setEnabled(false); m_diffProjectAction->setEnabled(false); m_diffProjectAction->setText(tr("Diff Project")); m_statusProjectAction->setText(tr("Status Project")); @@ -679,12 +779,14 @@ void GitPlugin::updateActions() m_logAction->setEnabled(true); m_blameAction->setEnabled(true); m_undoFileAction->setEnabled(true); - m_addAction->setEnabled(true); + m_stageAction->setEnabled(true); + m_unstageAction->setEnabled(true); + m_revertAction->setEnabled(true); } if (m_projectExplorer && m_projectExplorer->currentNode() && m_projectExplorer->currentNode()->projectNode()) { - QString name = QFileInfo(m_projectExplorer->currentNode()->projectNode()->path()).baseName(); + const QString name = QFileInfo(m_projectExplorer->currentNode()->projectNode()->path()).baseName(); m_diffProjectAction->setEnabled(true); m_diffProjectAction->setText(tr("Diff Project %1").arg(name)); m_statusProjectAction->setEnabled(true); @@ -720,4 +822,19 @@ void GitPlugin::showCommit() m_gitClient->show(m_changeSelectionDialog->m_ui.repositoryEdit->text(), change); } +GitOutputWindow *GitPlugin::outputWindow() const +{ + return m_outputWindow; +} + +GitSettings GitPlugin::settings() const +{ + return m_gitClient->settings(); +} + +void GitPlugin::setSettings(const GitSettings &s) +{ + m_gitClient->setSettings(s); +} + Q_EXPORT_PLUGIN(GitPlugin) diff --git a/src/plugins/git/gitplugin.h b/src/plugins/git/gitplugin.h index 51846c71d66650bb197b63ae58e0769b62d9289a..adff899e505564dc680a3a9dc4ac161bcae306a0 100644 --- a/src/plugins/git/gitplugin.h +++ b/src/plugins/git/gitplugin.h @@ -55,6 +55,7 @@ QT_END_NAMESPACE namespace Core { class IEditorFactory; class ICore; + class IVersionControl; } namespace Git { @@ -65,6 +66,7 @@ namespace Internal { class ChangeSelectionDialog; class GitSubmitEditor; struct CommitData; + struct GitSettings; // Just a proxy for GitPlugin class CoreListener : public Core::ICoreListener @@ -87,14 +89,17 @@ public: ~GitPlugin(); static GitPlugin *instance(); - bool vcsOpen(const QString &fileName); - bool initialize(const QStringList &arguments , QString *error_message); void extensionsInitialized(); QString getWorkingDirectory(); + GitOutputWindow *outputWindow() const; + + GitSettings settings() const; + void setSettings(const GitSettings &s); + public slots: void updateActions(); bool editorAboutToClose(Core::IEditor *editor); @@ -111,16 +116,21 @@ private slots: void logProject(); void undoFileChanges(); void undoProjectChanges(); - void addFile(); + void stageFile(); + void unstageFile(); + void revertFile(); void showCommit(); void startCommit(); + void stash(); + void stashPop(); + void branchList(); + void stashList(); void pull(); void push(); private: - friend class GitClient; - QFileInfo currentFile(); + QFileInfo currentFile() const; Core::IEditor *openSubmitEditor(const QString &fileName, const CommitData &cd); void cleanChangeTmpFile(); @@ -136,7 +146,9 @@ private: QAction *m_undoFileAction; QAction *m_undoProjectAction; QAction *m_showAction; - QAction *m_addAction; + QAction *m_stageAction; + QAction *m_unstageAction; + QAction *m_revertAction; QAction *m_commitAction; QAction *m_pullAction; QAction *m_pushAction; @@ -145,6 +157,10 @@ private: QAction *m_diffSelectedFilesAction; QAction *m_undoAction; QAction *m_redoAction; + QAction *m_stashAction; + QAction *m_stashPopAction; + QAction *m_stashListAction; + QAction *m_branchListAction; ProjectExplorer::ProjectExplorerPlugin *m_projectExplorer; GitClient *m_gitClient; @@ -154,6 +170,7 @@ private: QList<Core::IEditorFactory*> m_editorFactories; CoreListener *m_coreListener; Core::IEditorFactory *m_submitEditorFactory; + Core::IVersionControl *m_versionControl; QString m_submitRepository; QStringList m_submitOrigCommitFiles; QTemporaryFile *m_changeTmpFile; diff --git a/src/plugins/git/gitsettings.cpp b/src/plugins/git/gitsettings.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f4473e1fd92e222539cc2d82d99cff9168873454 --- /dev/null +++ b/src/plugins/git/gitsettings.cpp @@ -0,0 +1,79 @@ +/*************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Qt Software Information (qt-info@nokia.com) +** +** +** Non-Open Source Usage +** +** Licensees may use this file in accordance with the Qt Beta Version +** License Agreement, Agreement version 2.2 provided with the Software or, +** alternatively, in accordance with the terms contained in a written +** agreement between you and Nokia. +** +** GNU General Public License Usage +** +** Alternatively, this file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the packaging +** of this file. Please review the following information to ensure GNU +** General Public Licensing requirements will be met: +** +** http://www.fsf.org/licensing/licenses/info/GPLv2.html and +** http://www.gnu.org/copyleft/gpl.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt GPL Exception +** version 1.2, included in the file GPL_EXCEPTION.txt in this package. +** +***************************************************************************/ + +#include "gitsettings.h" + +#include <QtCore/QSettings> +#include <QtCore/QTextStream> + +static const char *groupC = "Git"; +static const char *sysEnvKeyC = "SysEnv"; +static const char *pathKeyC = "Path"; +static const char *logCountKeyC = "LogCount"; + +enum { defaultLogCount = 10 }; + +namespace Git { +namespace Internal { + +GitSettings::GitSettings() : + adoptPath(false), + logCount(defaultLogCount) +{ +} + +void GitSettings::fromSettings(QSettings *settings) +{ + settings->beginGroup(QLatin1String(groupC)); + adoptPath = settings->value(QLatin1String(sysEnvKeyC), false).toBool(); + path = settings->value(QLatin1String(pathKeyC), QString()).toString(); + logCount = settings->value(QLatin1String(logCountKeyC), defaultLogCount).toInt(); + settings->endGroup(); +} + +void GitSettings::toSettings(QSettings *settings) const +{ + settings->beginGroup(QLatin1String(groupC)); + settings->setValue(QLatin1String(sysEnvKeyC), adoptPath); + settings->setValue(QLatin1String(pathKeyC), path); + settings->setValue(QLatin1String(logCountKeyC), logCount); + settings->endGroup(); +} + +bool GitSettings::equals(const GitSettings &s) const +{ + return adoptPath == s.adoptPath && path == s.path && logCount == s.logCount; +} + +} +} diff --git a/src/plugins/git/gitsettings.h b/src/plugins/git/gitsettings.h new file mode 100644 index 0000000000000000000000000000000000000000..1b07f4437963f89496af0d75fae7b9439bf3a021 --- /dev/null +++ b/src/plugins/git/gitsettings.h @@ -0,0 +1,69 @@ +/*************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Qt Software Information (qt-info@nokia.com) +** +** +** Non-Open Source Usage +** +** Licensees may use this file in accordance with the Qt Beta Version +** License Agreement, Agreement version 2.2 provided with the Software or, +** alternatively, in accordance with the terms contained in a written +** agreement between you and Nokia. +** +** GNU General Public License Usage +** +** Alternatively, this file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the packaging +** of this file. Please review the following information to ensure GNU +** General Public Licensing requirements will be met: +** +** http://www.fsf.org/licensing/licenses/info/GPLv2.html and +** http://www.gnu.org/copyleft/gpl.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt GPL Exception +** version 1.2, included in the file GPL_EXCEPTION.txt in this package. +** +***************************************************************************/ + +#ifndef GITSETTINGS_H +#define GITSETTINGS_H + +#include <QtCore/QStringList> + +QT_BEGIN_NAMESPACE +class QSettings; +QT_END_NAMESPACE + +namespace Git { +namespace Internal { + +// Todo: Add user name and password? +struct GitSettings +{ + GitSettings(); + + void fromSettings(QSettings *); + void toSettings(QSettings *) const; + + bool equals(const GitSettings &s) const; + + bool adoptPath; + QString path; + int logCount; +}; + +inline bool operator==(const GitSettings &p1, const GitSettings &p2) + { return p1.equals(p2); } +inline bool operator!=(const GitSettings &p1, const GitSettings &p2) + { return !p1.equals(p2); } + +} // namespace Internal +} // namespace Git + +#endif // GITSETTINGS_H diff --git a/src/plugins/git/gitsubmiteditor.cpp b/src/plugins/git/gitsubmiteditor.cpp index 516dc6570b73c7b9e62d72e0fb0d01def65c0513..db854f3e3c6d406bd20f3ff2ca98cd6203645ca0 100644 --- a/src/plugins/git/gitsubmiteditor.cpp +++ b/src/plugins/git/gitsubmiteditor.cpp @@ -67,9 +67,9 @@ void GitSubmitEditor::setCommitData(const CommitData &d) submitEditorWidget()->setPanelData(d.panelData); submitEditorWidget()->setPanelInfo(d.panelInfo); - addFiles(d.commitFiles, true, true); + addFiles(d.stagedFiles, true, true); // Not Updated: Initially unchecked - addFiles(d.notUpdatedFiles, false, true); + addFiles(d.unstagedFiles, false, true); addFiles(d.untrackedFiles, false, true); } diff --git a/src/plugins/git/gitversioncontrol.cpp b/src/plugins/git/gitversioncontrol.cpp new file mode 100644 index 0000000000000000000000000000000000000000..5f403ef2b57d22fdb4cbcae06ad4845bfe3b12e4 --- /dev/null +++ b/src/plugins/git/gitversioncontrol.cpp @@ -0,0 +1,104 @@ +/*************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Qt Software Information (qt-info@nokia.com) +** +** +** Non-Open Source Usage +** +** Licensees may use this file in accordance with the Qt Beta Version +** License Agreement, Agreement version 2.2 provided with the Software or, +** alternatively, in accordance with the terms contained in a written +** agreement between you and Nokia. +** +** GNU General Public License Usage +** +** Alternatively, this file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the packaging +** of this file. Please review the following information to ensure GNU +** General Public Licensing requirements will be met: +** +** http://www.fsf.org/licensing/licenses/info/GPLv2.html and +** http://www.gnu.org/copyleft/gpl.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt GPL Exception +** version 1.2, included in the file GPL_EXCEPTION.txt in this package. +** +***************************************************************************/ + +#include "gitversioncontrol.h" +#include "gitclient.h" + +namespace Git { +namespace Internal { + +GitVersionControl::GitVersionControl(GitClient *client) : + m_enabled(true), + m_client(client) +{ +} + +QString GitVersionControl::name() const +{ + return QLatin1String("git"); +} + +bool GitVersionControl::isEnabled() const +{ + return m_enabled; +} + +void GitVersionControl::setEnabled(bool enabled) +{ + if (m_enabled != enabled) { + m_enabled = enabled; + emit enabledChanged(m_enabled); + } +} + +bool GitVersionControl::supportsOperation(Operation operation) const +{ + bool rc = false; + switch (operation) { + case AddOperation: + case DeleteOperation: + case OpenOperation: + break; + } + return rc; +} + +bool GitVersionControl::vcsOpen(const QString & /*fileName*/) +{ + return false; +} + +bool GitVersionControl::vcsAdd(const QString & /*fileName*/) +{ + return false; +} + +bool GitVersionControl::vcsDelete(const QString & /*fileName*/) +{ + // TODO: implement using 'git rm'. + return false; +} + +bool GitVersionControl::managesDirectory(const QString &directory) const +{ + return !GitClient::findRepositoryForDirectory(directory).isEmpty(); + +} + +QString GitVersionControl::findTopLevelForDirectory(const QString &directory) const +{ + return GitClient::findRepositoryForDirectory(directory); +} + +} // Internal +} // Git diff --git a/src/plugins/help/indexwindow.h b/src/plugins/git/gitversioncontrol.h similarity index 59% rename from src/plugins/help/indexwindow.h rename to src/plugins/git/gitversioncontrol.h index 51ebb06653d197fa2fd1b74f5bcdf1bcc44031c8..e12e7736713c9a6b5ed100cef2b1fd705680d3c8 100644 --- a/src/plugins/help/indexwindow.h +++ b/src/plugins/git/gitversioncontrol.h @@ -31,52 +31,45 @@ ** ***************************************************************************/ -#ifndef INDEXWINDOW_H -#define INDEXWINDOW_H +#ifndef GITVERSIONCONTROL_H +#define GITVERSIONCONTROL_H -#include <QtCore/QUrl> -#include <QtGui/QWidget> -#include <QtGui/QLineEdit> +#include <coreplugin/iversioncontrol.h> -QT_BEGIN_NAMESPACE +namespace Git { +namespace Internal { -class QHelpIndexWidget; -class QHelpEngine; +class GitClient; -class IndexWindow : public QWidget +// Just a proxy for GitPlugin +class GitVersionControl : public Core::IVersionControl { Q_OBJECT - public: - IndexWindow(QHelpEngine *helpEngine, QWidget *parent = 0); - ~IndexWindow(); + explicit GitVersionControl(GitClient *plugin); - void setSearchLineEditText(const QString &text); - QString searchLineEditText() const - { - return m_searchLineEdit->text(); - } + virtual QString name() const; -signals: - void linkActivated(const QUrl &link); - void linksActivated(const QMap<QString, QUrl> &links, - const QString &keyword); - void escapePressed(); + virtual bool isEnabled() const; + virtual void setEnabled(bool enabled); -private slots: - void filterIndices(const QString &filter); - void enableSearchLineEdit(); - void disableSearchLineEdit(); + bool managesDirectory(const QString &directory) const; + virtual QString findTopLevelForDirectory(const QString &directory) const; -private: - bool eventFilter(QObject *obj, QEvent *e); - void focusInEvent(QFocusEvent *e); + virtual bool supportsOperation(Operation operation) const; + virtual bool vcsOpen(const QString &fileName); + virtual bool vcsAdd(const QString &fileName); + virtual bool vcsDelete(const QString &filename); - QLineEdit *m_searchLineEdit; - QHelpIndexWidget *m_indexWidget; - QHelpEngine *m_helpEngine; +signals: + void enabledChanged(bool); + +private: + bool m_enabled; + GitClient *m_client; }; -QT_END_NAMESPACE +} // Internal +} // Git -#endif // INDEXWINDOW_H +#endif // GITVERSIONCONTROL_H diff --git a/src/plugins/git/settingspage.cpp b/src/plugins/git/settingspage.cpp index 7b0c37284aa1793bd82b7ff74ca58c8715164e4f..e1b14cb9ccc627c31fff00065d560f8f7fa7e31e 100644 --- a/src/plugins/git/settingspage.cpp +++ b/src/plugins/git/settingspage.cpp @@ -32,35 +32,44 @@ ***************************************************************************/ #include "settingspage.h" +#include "gitsettings.h" +#include "gitplugin.h" -#include <coreplugin/icore.h> -#include <extensionsystem/pluginmanager.h> - -#include <QtCore/QSettings> -#include <QtGui/QLineEdit> -#include <QtGui/QFileDialog> #include <QtCore/QDebug> using namespace Git::Internal; -static const char *groupC = "Git"; -static const char *sysEnvKeyC = "SysEnv"; -static const char *pathKeyC = "Path"; -static const char *logCountKeyC = "LogCount"; +SettingsPageWidget::SettingsPageWidget(QWidget *parent) : + QWidget(parent) +{ + m_ui.setupUi(this); + connect(m_ui.adoptButton, SIGNAL(clicked()), this, SLOT(setSystemPath())); +} -SettingsPage::SettingsPage() +GitSettings SettingsPageWidget::settings() const { - Core::ICore *coreIFace = ExtensionSystem::PluginManager::instance()->getObject<Core::ICore>(); - if (coreIFace) - m_settings = coreIFace->settings(); + GitSettings rc; + rc.path = m_ui.pathLineEdit->text(); + rc.adoptPath = m_ui.environmentGroupBox->isChecked() && !rc.path.isEmpty(); + rc.logCount = m_ui.logCountSpinBox->value(); + return rc; +} - if (m_settings) { - m_settings->beginGroup(QLatin1String(groupC)); - m_adopt = m_settings->value(QLatin1String(sysEnvKeyC), true).toBool(); - m_path = m_settings->value(QLatin1String(pathKeyC), QString()).toString(); - m_logCount = m_settings->value(QLatin1String(logCountKeyC), 10).toInt(); - m_settings->endGroup(); - } +void SettingsPageWidget::setSettings(const GitSettings &s) +{ + m_ui.environmentGroupBox->setChecked(s.adoptPath); + m_ui.pathLineEdit->setText(s.path); + m_ui.logCountSpinBox->setValue(s.logCount); +} + +void SettingsPageWidget::setSystemPath() +{ + m_ui.pathLineEdit->setText(QLatin1String(qgetenv("PATH"))); +} + +// -------- SettingsPage +SettingsPage::SettingsPage() +{ } QString SettingsPage::name() const @@ -68,7 +77,7 @@ QString SettingsPage::name() const return tr("General"); } -QString SettingsPage::category() const + QString SettingsPage::category() const { return QLatin1String("Git"); } @@ -80,37 +89,17 @@ QString SettingsPage::trCategory() const QWidget *SettingsPage::createPage(QWidget *parent) { - QWidget *w = new QWidget(parent); - m_ui.setupUi(w); - m_ui.adoptCheckBox->setChecked(m_adopt); - m_ui.pathLineEdit->setText(m_path); - m_ui.logLineEdit->setText(QString::number(m_logCount)); - - connect(m_ui.adoptButton, SIGNAL(clicked()), this, SLOT(setSystemPath())); - return w; + if (!m_widget) + m_widget = new SettingsPageWidget(parent); + m_widget->setSettings(GitPlugin::instance()->settings()); + return m_widget; } void SettingsPage::finished(bool accepted) { - if (!accepted) + if (!accepted || !m_widget) return; - m_adopt = m_ui.adoptCheckBox->isChecked(); - m_path = m_ui.pathLineEdit->text(); - m_logCount = m_ui.logLineEdit->text().toInt(); - - if (!m_settings) - return; - - m_settings->beginGroup(QLatin1String(groupC)); - m_settings->setValue(QLatin1String(sysEnvKeyC), m_adopt); - m_settings->setValue(QLatin1String(pathKeyC), m_path); - m_settings->setValue(QLatin1String(logCountKeyC), m_logCount); - m_settings->endGroup(); + GitPlugin::instance()->setSettings(m_widget->settings()); } -void SettingsPage::setSystemPath() -{ - m_path = qgetenv("PATH"); - m_ui.pathLineEdit->setText(m_path); -} diff --git a/src/plugins/git/settingspage.h b/src/plugins/git/settingspage.h index 95147cf6552e1a1ae50bf0e75218dd3bf678da51..c1f1403c4c909336fcba3b373fbb036e7c897aab 100644 --- a/src/plugins/git/settingspage.h +++ b/src/plugins/git/settingspage.h @@ -35,6 +35,7 @@ #define SETTINGSPAGE_H #include <QtGui/QWidget> +#include <QtCore/QPointer> #include <coreplugin/dialogs/ioptionspage.h> @@ -47,6 +48,23 @@ QT_END_NAMESPACE namespace Git { namespace Internal { +struct GitSettings; + +class SettingsPageWidget : public QWidget { + Q_OBJECT +public: + explicit SettingsPageWidget(QWidget *parent = 0); + + GitSettings settings() const; + void setSettings(const GitSettings &); + +private slots: + void setSystemPath(); + +private: + Ui::SettingsPage m_ui; +}; + class SettingsPage : public Core::IOptionsPage { Q_OBJECT @@ -61,20 +79,8 @@ public: QWidget *createPage(QWidget *parent); void finished(bool accepted); - bool adoptEnvironment() const { return m_adopt; } - int logCount() const { return m_logCount; } - QString path() const { return m_path; } - -private slots: - void setSystemPath(); - private: - Ui_SettingsPage m_ui; - QSettings *m_settings; - - bool m_adopt; - QString m_path; - int m_logCount; + QPointer<SettingsPageWidget> m_widget; }; } // namespace Internal diff --git a/src/plugins/git/settingspage.ui b/src/plugins/git/settingspage.ui index 738413e676f87c3e0405d20baf4a58befa82f780..aa2337605b8bf95f21521e9e0fdb8fb790ace6d8 100644 --- a/src/plugins/git/settingspage.ui +++ b/src/plugins/git/settingspage.ui @@ -6,103 +6,113 @@ <rect> <x>0</x> <y>0</y> - <width>345</width> - <height>177</height> + <width>436</width> + <height>186</height> </rect> </property> <property name="windowTitle"> <string>Form</string> </property> - <layout class="QVBoxLayout" name="verticalLayout"> + <layout class="QHBoxLayout" name="horizontalLayout"> <item> - <widget class="QCheckBox" name="adoptCheckBox"> - <property name="text"> - <string>Use System Environment</string> - </property> - </widget> - </item> - <item> - <widget class="QGroupBox" name="groupBox"> - <property name="enabled"> - <bool>true</bool> - </property> - <property name="title"> - <string>Environment variables</string> - </property> - <property name="checkable"> - <bool>false</bool> - </property> - <layout class="QGridLayout" name="gridLayout"> - <item row="0" column="0"> - <widget class="QLabel" name="label"> - <property name="text"> - <string>PATH:</string> - </property> - </widget> - </item> - <item row="0" column="1"> - <widget class="QLineEdit" name="pathLineEdit"/> - </item> - <item row="0" column="2"> - <widget class="QPushButton" name="adoptButton"> - <property name="text"> - <string>Adopt</string> - </property> - </widget> - </item> - <item row="1" column="0"> - <spacer name="horizontalSpacer"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>52</width> - <height>20</height> - </size> - </property> - </spacer> - </item> - <item row="1" column="1" colspan="2"> - <widget class="QLabel" name="label_2"> - <property name="text"> - <string><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> -<html><head><meta name="qrichtext" content="1" /><style type="text/css"> -p, li { white-space: pre-wrap; } -</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt; font-weight:600;">Note</span><span style=" font-size:8pt;"> that Git needs Perl in the environment as well</span></p></body></html></string> - </property> - </widget> - </item> - </layout> - </widget> - </item> - <item> - <layout class="QHBoxLayout" name="horizontalLayout"> + <layout class="QVBoxLayout" name="verticalLayout"> <item> - <widget class="QLabel" name="label_3"> - <property name="text"> - <string>Commit display count:</string> + <widget class="QGroupBox" name="environmentGroupBox"> + <property name="enabled"> + <bool>true</bool> </property> + <property name="title"> + <string>Environment variables</string> + </property> + <property name="checkable"> + <bool>true</bool> + </property> + <layout class="QFormLayout" name="formLayout"> + <item row="0" column="0"> + <widget class="QLabel" name="pathlabel"> + <property name="text"> + <string>PATH:</string> + </property> + </widget> + </item> + <item row="0" column="1"> + <layout class="QHBoxLayout" name="horizontalLayout_2"> + <item> + <widget class="QLineEdit" name="pathLineEdit"/> + </item> + <item> + <widget class="QPushButton" name="adoptButton"> + <property name="text"> + <string>From system</string> + </property> + </widget> + </item> + </layout> + </item> + <item row="1" column="0"> + <widget class="QLabel" name="noteLabel"> + <property name="text"> + <string><b>Note:</b></string> + </property> + </widget> + </item> + <item row="1" column="1"> + <widget class="QLabel" name="noteFieldlabel"> + <property name="text"> + <string>Git needs to find Perl in the environment as well.</string> + </property> + </widget> + </item> + </layout> </widget> </item> <item> - <widget class="QLineEdit" name="logLineEdit"> - <property name="toolTip"> - <string>Note that huge amount of commits might take some time.</string> + <layout class="QFormLayout" name="logFormLayout"> + <property name="fieldGrowthPolicy"> + <enum>QFormLayout::ExpandingFieldsGrow</enum> </property> - </widget> + <item row="0" column="1"> + <widget class="QSpinBox" name="logCountSpinBox"> + <property name="toolTip"> + <string>Note that huge amount of commits might take some time.</string> + </property> + <property name="maximum"> + <number>1000</number> + </property> + </widget> + </item> + <item row="0" column="0"> + <widget class="QLabel" name="logCountLabel"> + <property name="text"> + <string>Log commit display count:</string> + </property> + </widget> + </item> + </layout> + </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> <item> - <spacer> + <spacer name="horizontalSpacer"> <property name="orientation"> - <enum>Qt::Vertical</enum> + <enum>Qt::Horizontal</enum> </property> <property name="sizeHint" stdset="0"> <size> - <width>141</width> + <width>40</width> <height>20</height> </size> </property> @@ -114,22 +124,5 @@ p, li { white-space: pre-wrap; } <tabstop>pathLineEdit</tabstop> </tabstops> <resources/> - <connections> - <connection> - <sender>adoptCheckBox</sender> - <signal>toggled(bool)</signal> - <receiver>groupBox</receiver> - <slot>setDisabled(bool)</slot> - <hints> - <hint type="sourcelabel"> - <x>144</x> - <y>33</y> - </hint> - <hint type="destinationlabel"> - <x>139</x> - <y>65</y> - </hint> - </hints> - </connection> - </connections> + <connections/> </ui> diff --git a/src/plugins/help/help.pro b/src/plugins/help/help.pro index 1148606cab73e847a7b8bb75ce359cae31a93c21..b2e9a1dbd613cec02e2b73ed04d1cd6c7e1eaa3d 100644 --- a/src/plugins/help/help.pro +++ b/src/plugins/help/help.pro @@ -16,8 +16,8 @@ HEADERS += helpplugin.h \ searchwidget.h \ helpfindsupport.h \ help_global.h \ - helpindexfilter.h \ - indexwindow.h + helpindexfilter.h + SOURCES += helpplugin.cpp \ docsettingspage.cpp \ filtersettingspage.cpp \ @@ -26,6 +26,7 @@ SOURCES += helpplugin.cpp \ searchwidget.cpp \ helpfindsupport.cpp \ helpindexfilter.cpp + FORMS += docsettingspage.ui \ filtersettingspage.ui RESOURCES += help.qrc diff --git a/src/plugins/perforce/perforceplugin.cpp b/src/plugins/perforce/perforceplugin.cpp index 7f71282fbbf71df8d7ea6d6bcef2e50c41073ce2..dc28901b7050540b8dc028165ccf658308a0c493 100644 --- a/src/plugins/perforce/perforceplugin.cpp +++ b/src/plugins/perforce/perforceplugin.cpp @@ -235,6 +235,10 @@ bool PerforcePlugin::initialize(const QStringList & /*arguments*/, QString *erro am->createMenu(QLatin1String(PERFORCE_MENU)); mperforce->menu()->setTitle(tr("&Perforce")); mtools->addMenu(mperforce); + if (QAction *ma = mperforce->menu()->menuAction()) { + ma->setEnabled(m_versionControl->isEnabled()); + connect(m_versionControl, SIGNAL(enabledChanged(bool)), ma, SLOT(setVisible(bool))); + } QList<int> globalcontext; globalcontext << Core::Constants::C_GLOBAL_ID; @@ -401,17 +405,17 @@ void PerforcePlugin::extensionsInitialized() void PerforcePlugin::openCurrentFile() { - runP4Cmd(QStringList() << QLatin1String("edit") << currentFileName(), QStringList(), true); + vcsOpen(currentFileName()); } void PerforcePlugin::addCurrentFile() { - runP4Cmd(QStringList() << QLatin1String("add") << currentFileName(), QStringList(), true); + vcsAdd(currentFileName()); } void PerforcePlugin::deleteCurrentFile() { - runP4Cmd(QStringList() << QLatin1String("delete") << currentFileName(), QStringList(), true); + vcsDelete(currentFileName()); } void PerforcePlugin::revertCurrentFile() @@ -422,7 +426,7 @@ void PerforcePlugin::revertCurrentFile() QTextCodec *codec = VCSBase::VCSBaseEditor::getCodec(m_coreInstance, fileName); QStringList args; args << QLatin1String("diff") << QLatin1String("-sa"); - PerforceResponse result = runP4Cmd(args, QStringList(), false, true, codec); + PerforceResponse result = runP4Cmd(args, QStringList(), CommandToWindow|StdErrToWindow|ErrorToWindow, codec); if (result.error) return; @@ -440,7 +444,7 @@ void PerforcePlugin::revertCurrentFile() foreach (Core::IFile *file, files) { fm->blockFileChange(file); } - PerforceResponse result2 = runP4Cmd(QStringList() << QLatin1String("revert") << fileName, QStringList(), true); + PerforceResponse result2 = runP4Cmd(QStringList() << QLatin1String("revert") << fileName, QStringList(), CommandToWindow|StdOutToWindow|StdErrToWindow|ErrorToWindow); Core::IFile::ReloadBehavior tempBehavior = Core::IFile::ReloadAll; foreach (Core::IFile *file, files) { @@ -485,7 +489,7 @@ void PerforcePlugin::printOpenedFileList() Core::IEditor *e = m_coreInstance->editorManager()->currentEditor(); if (e) e->widget()->setFocus(); - PerforceResponse result = runP4Cmd(QStringList() << QLatin1String("opened"), QStringList(), true); + PerforceResponse result = runP4Cmd(QStringList() << QLatin1String("opened"), QStringList(), CommandToWindow|StdOutToWindow|StdErrToWindow|ErrorToWindow); } #ifdef USE_P4_API @@ -518,7 +522,8 @@ void PerforcePlugin::submit() return; } - PerforceResponse result = runP4Cmd(QStringList()<< QLatin1String("change") << QLatin1String("-o"), QStringList(), false); + PerforceResponse result = runP4Cmd(QStringList()<< QLatin1String("change") << QLatin1String("-o"), QStringList(), + CommandToWindow|StdErrToWindow|ErrorToWindow); if (result.error) { delete m_changeTmpFile; m_changeTmpFile = 0; @@ -546,7 +551,8 @@ void PerforcePlugin::submit() foreach (const QString &f, files) nativeFiles << QDir::toNativeSeparators(f); - PerforceResponse result2 = runP4Cmd(QStringList(QLatin1String("fstat")), nativeFiles, false); + PerforceResponse result2 = runP4Cmd(QStringList(QLatin1String("fstat")), nativeFiles, + CommandToWindow|StdErrToWindow|ErrorToWindow); if (result2.error) { delete m_changeTmpFile; m_changeTmpFile = 0; @@ -593,8 +599,10 @@ void PerforcePlugin::printPendingChanges() PendingChangesDialog dia(pendingChangesData(), m_coreInstance->mainWindow()); qApp->restoreOverrideCursor(); if (dia.exec() == QDialog::Accepted) { - int i = dia.changeNumber(); - PerforceResponse result = runP4Cmd(QStringList()<<"submit"<<"-c"<<QString::number(i), QStringList(), true); + const int i = dia.changeNumber(); + QStringList args(QLatin1String("submit")); + args << QLatin1String("-c") << QString::number(i); + runP4Cmd(args, QStringList(), CommandToWindow|StdOutToWindow|StdErrToWindow|ErrorToWindow); } } @@ -624,7 +632,8 @@ void PerforcePlugin::annotate(const QString &fileName) QTextCodec *codec = VCSBase::VCSBaseEditor::getCodec(m_coreInstance, fileName); QStringList args; args << QLatin1String("annotate") << QLatin1String("-cqi") << fileName; - const PerforceResponse result = runP4Cmd(args, QStringList(), false, true, codec); + const PerforceResponse result = runP4Cmd(args, QStringList(), + CommandToWindow|StdErrToWindow|ErrorToWindow, codec); if (!result.error) { const QFileInfo fi(fileName); showOutputInEditor(tr("p4 annotate %1").arg(fi.fileName()), result.stdOut, VCSBase::AnnotateOutput, codec); @@ -650,7 +659,8 @@ void PerforcePlugin::filelog(const QString &fileName) QTextCodec *codec = VCSBase::VCSBaseEditor::getCodec(m_coreInstance, fileName); QStringList args; args << QLatin1String("filelog") << QLatin1String("-li") << fileName; - const PerforceResponse result = runP4Cmd(args, QStringList(), false, true, codec); + const PerforceResponse result = runP4Cmd(args, QStringList(), + CommandToWindow|StdErrToWindow|ErrorToWindow, codec); if (!result.error) { const QFileInfo fi(fileName); showOutputInEditor(tr("p4 filelog %1").arg(fi.fileName()), result.stdOut, VCSBase::LogOutput, codec); @@ -714,18 +724,19 @@ bool PerforcePlugin::managesDirectory(const QString &directory) const QStringList args; args << QLatin1String("fstat") << QLatin1String("-m1") << p4Path; - const PerforceResponse result = runP4Cmd(args, QStringList(), false, false); + const PerforceResponse result = runP4Cmd(args, QStringList(), 0u); return result.stdOut.contains("depotFile") || result.stdErr.contains("... - no such file(s)"); } QString PerforcePlugin::findTopLevelForDirectory(const QString & /* dir */) const { // First check with p4 client -o - PerforceResponse result = runP4Cmd(QStringList() << QLatin1String("client") << QLatin1String("-o"), QStringList(), false, false); + PerforceResponse result = runP4Cmd(QStringList() << QLatin1String("client") << QLatin1String("-o"), QStringList(), 0u); if (result.error) return QString::null; QRegExp regExp(QLatin1String("(\\n|\\r\\n|\\r)Root:\\s*(.*)(\\n|\\r\\n|\\r)")); + Q_ASSERT(regExp.isValid()); regExp.setMinimal(true); if (regExp.indexIn(result.stdOut) != -1) { QString file = regExp.cap(2).trimmed(); @@ -737,20 +748,24 @@ QString PerforcePlugin::findTopLevelForDirectory(const QString & /* dir */) cons bool PerforcePlugin::vcsOpen(const QString &fileName) { - PerforceResponse result = runP4Cmd(QStringList() << QLatin1String("edit") << QDir::toNativeSeparators(fileName), QStringList(), true); + PerforceResponse result = runP4Cmd(QStringList() << QLatin1String("edit") << QDir::toNativeSeparators(fileName), QStringList(), + CommandToWindow|StdOutToWindow|StdErrToWindow|ErrorToWindow); return !result.error; } bool PerforcePlugin::vcsAdd(const QString &fileName) { - PerforceResponse result = runP4Cmd(QStringList() << QLatin1String("add") << fileName, QStringList(), true); + PerforceResponse result = runP4Cmd(QStringList() << QLatin1String("add") << fileName, QStringList(), + CommandToWindow|StdOutToWindow|StdErrToWindow|ErrorToWindow); return !result.error; } bool PerforcePlugin::vcsDelete(const QString &fileName) { - PerforceResponse result = runP4Cmd(QStringList() << QLatin1String("revert") << fileName, QStringList(), true); - PerforceResponse result2 = runP4Cmd(QStringList() << QLatin1String("delete") << fileName, QStringList(), true); + PerforceResponse result = runP4Cmd(QStringList() << QLatin1String("revert") << fileName, QStringList(), + CommandToWindow|StdOutToWindow|StdErrToWindow|ErrorToWindow); + PerforceResponse result2 = runP4Cmd(QStringList() << QLatin1String("delete") << fileName, QStringList(), + CommandToWindow|StdOutToWindow|StdErrToWindow|ErrorToWindow); // TODO need to carefully parse the actual messages from perforce // or do a fstat before to decide what to do @@ -763,8 +778,7 @@ bool PerforcePlugin::vcsDelete(const QString &fileName) PerforceResponse PerforcePlugin::runP4Cmd(const QStringList &args, const QStringList &extraArgs, - bool showStdOutInOutputWindow, - bool showStdErrInOutputWindow, + unsigned logFlags, QTextCodec *outputCodec) const { if (Perforce::Constants::debug) @@ -797,12 +811,14 @@ PerforceResponse PerforcePlugin::runP4Cmd(const QStringList &args, } actualArgs << args; - response.command = m_settings.p4Command; - response.command += blank; - response.command += actualArgs.join(QString(blank)); - const QString timeStamp = QTime::currentTime().toString(QLatin1String("HH:mm")); - const QString outputText = tr("%1 Executing: %2\n").arg(timeStamp, response.command); - showOutput(outputText, false); + if (logFlags & CommandToWindow) { + QString command = m_settings.p4Command; + command += blank; + command += actualArgs.join(QString(blank)); + const QString timeStamp = QTime::currentTime().toString(QLatin1String("HH:mm")); + const QString outputText = tr("%1 Executing: %2\n").arg(timeStamp, command); + showOutput(outputText, false); + } // Run, connect stderr to the output window Core::Utils::SynchronousProcess process; @@ -811,13 +827,13 @@ PerforceResponse PerforcePlugin::runP4Cmd(const QStringList &args, process.setEnvironment(environment()); // connect stderr to the output window if desired - if (showStdErrInOutputWindow) { + if (logFlags & StdErrToWindow) { process.setStdErrBufferedSignalsEnabled(true); connect(&process, SIGNAL(stdErrBuffered(QString,bool)), m_perforceOutputWindow, SLOT(append(QString,bool))); } // connect stdout to the output window if desired - if (showStdOutInOutputWindow) { + if (logFlags & StdOutToWindow) { process.setStdOutBufferedSignalsEnabled(true); connect(&process, SIGNAL(stdOutBuffered(QString,bool)), m_perforceOutputWindow, SLOT(append(QString,bool))); } @@ -843,13 +859,15 @@ PerforceResponse PerforcePlugin::runP4Cmd(const QStringList &args, response.message = tr("Could not start perforce '%1'. Please check your settings in the preferences.").arg(m_settings.p4Command); break; case Core::Utils::SynchronousProcessResponse::Hang: - response.message = tr("Subversion did not respond within timeout limit (%1 ms).").arg(p4Timeout ); + response.message = tr("Perforce did not respond within timeout limit (%1 ms).").arg(p4Timeout ); break; } - if (response.error) - m_perforceOutputWindow->append(response.message, true); - - + if (response.error) { + if (Perforce::Constants::debug) + qDebug() << response.message; + if (logFlags & ErrorToWindow) + m_perforceOutputWindow->append(response.message, true); + } return response; } @@ -919,7 +937,7 @@ void PerforcePlugin::p4Diff(const QStringList &files, QString diffname) } } - const PerforceResponse result = runP4Cmd(QStringList() << QLatin1String("diff") << QLatin1String("-du"), files, false, codec); + const PerforceResponse result = runP4Cmd(QStringList() << QLatin1String("diff") << QLatin1String("-du"), files, CommandToWindow|StdErrToWindow|ErrorToWindow, codec); if (result.error) return; @@ -944,7 +962,7 @@ void PerforcePlugin::describe(const QString & source, const QString &n) QTextCodec *codec = source.isEmpty() ? static_cast<QTextCodec *>(0) : VCSBase::VCSBaseEditor::getCodec(m_coreInstance, source); QStringList args; args << QLatin1String("describe") << QLatin1String("-du") << n; - const PerforceResponse result = runP4Cmd(args, QStringList(), codec); + const PerforceResponse result = runP4Cmd(args, QStringList(), CommandToWindow|StdErrToWindow|ErrorToWindow, codec); if (!result.error) showOutputInEditor(tr("p4 describe %1").arg(n), result.stdOut, VCSBase::DiffOutput, codec); } diff --git a/src/plugins/perforce/perforceplugin.h b/src/plugins/perforce/perforceplugin.h index 4c088563324ae8999d279b5c8607b3300aeabec2..7a4e23077794ef89599d00b3818d537fb118c46a 100644 --- a/src/plugins/perforce/perforceplugin.h +++ b/src/plugins/perforce/perforceplugin.h @@ -86,7 +86,6 @@ private: struct PerforceResponse { bool error; - QString command; QString stdOut; QString stdErr; QString message; @@ -161,12 +160,15 @@ private: Core::IEditor *showOutputInEditor(const QString& title, const QString output, int editorType, QTextCodec *codec = 0); + + // Verbosity flags for runP4Cmd. + enum RunLogFlags { CommandToWindow = 0x1, StdOutToWindow = 0x2, StdErrToWindow = 0x4, ErrorToWindow = 0x8 }; + // args are passed as command line arguments // extra args via a tempfile and the option -x "temp-filename" PerforceResponse runP4Cmd(const QStringList &args, const QStringList &extraArgs = QStringList(), - bool showStdOutInOutputWindow = false, - bool showStdErrInOutputWindow = true, + unsigned logFlags = CommandToWindow|StdErrToWindow|ErrorToWindow, QTextCodec *outputCodec = 0) const; void openFiles(const QStringList &files); diff --git a/src/plugins/perforce/perforceversioncontrol.cpp b/src/plugins/perforce/perforceversioncontrol.cpp index a51930c1e6daf254994442a27bfd9e25d3007d1e..98379024bc04858b349778ae904133d3b5d62c23 100644 --- a/src/plugins/perforce/perforceversioncontrol.cpp +++ b/src/plugins/perforce/perforceversioncontrol.cpp @@ -38,10 +38,41 @@ namespace Perforce { namespace Internal { PerforceVersionControl::PerforceVersionControl(PerforcePlugin *plugin) : + m_enabled(true), m_plugin(plugin) { } +QString PerforceVersionControl::name() const +{ + return QLatin1String("perforce"); +} + +bool PerforceVersionControl::isEnabled() const +{ + return m_enabled; +} + +void PerforceVersionControl::setEnabled(bool enabled) +{ + if (m_enabled != enabled) { + m_enabled = enabled; + emit enabledChanged(m_enabled); + } +} + +bool PerforceVersionControl::supportsOperation(Operation operation) const +{ + bool rc = true; + switch (operation) { + case AddOperation: + case DeleteOperation: + case OpenOperation: + break; + } + return rc; +} + bool PerforceVersionControl::vcsOpen(const QString &fileName) { return m_plugin->vcsOpen(fileName); diff --git a/src/plugins/perforce/perforceversioncontrol.h b/src/plugins/perforce/perforceversioncontrol.h index d87a7f15ae4ef86de7870d1662d062965d331b95..0e8a1ea6539d6aaaa1465bbca2be2d25ba96cc83 100644 --- a/src/plugins/perforce/perforceversioncontrol.h +++ b/src/plugins/perforce/perforceversioncontrol.h @@ -46,13 +46,25 @@ class PerforceVersionControl : public Core::IVersionControl Q_OBJECT public: explicit PerforceVersionControl(PerforcePlugin *plugin); + + virtual QString name() const; + + virtual bool isEnabled() const; + virtual void setEnabled(bool enabled); + bool managesDirectory(const QString &directory) const; virtual QString findTopLevelForDirectory(const QString &directory) const; + + virtual bool supportsOperation(Operation operation) const; virtual bool vcsOpen(const QString &fileName); virtual bool vcsAdd(const QString &fileName); virtual bool vcsDelete(const QString &filename); +signals: + void enabledChanged(bool); + private: + bool m_enabled; PerforcePlugin *m_plugin; }; diff --git a/src/plugins/projectexplorer/abstractprocessstep.cpp b/src/plugins/projectexplorer/abstractprocessstep.cpp index 09bd73fe7676effdca5524515f2941679b29057a..06b40135c1262da635ecd62f21b5ec24364c7e5f 100644 --- a/src/plugins/projectexplorer/abstractprocessstep.cpp +++ b/src/plugins/projectexplorer/abstractprocessstep.cpp @@ -39,6 +39,7 @@ #include <QtCore/QEventLoop> #include <QtCore/QDebug> #include <QtCore/QTimer> +#include <QtGui/QTextDocument> using namespace ProjectExplorer; @@ -165,7 +166,7 @@ void AbstractProcessStep::run(QFutureInterface<bool> & fi) void AbstractProcessStep::processStarted() { - emit addToOutputWindow(tr("<font color=\"#0000ff\">Starting: %1 %2</font>\n").arg(m_command, m_arguments.join(" "))); + emit addToOutputWindow(tr("<font color=\"#0000ff\">Starting: %1 %2</font>\n").arg(m_command, Qt::escape(m_arguments.join(" ")))); } bool AbstractProcessStep::processFinished(int exitCode, QProcess::ExitStatus status) @@ -196,7 +197,7 @@ void AbstractProcessStep::processReadyReadStdOutput() void AbstractProcessStep::stdOut(const QString &line) { - emit addToOutputWindow(line); + emit addToOutputWindow(Qt::escape(line)); } void AbstractProcessStep::processReadyReadStdError() @@ -211,7 +212,7 @@ void AbstractProcessStep::processReadyReadStdError() void AbstractProcessStep::stdError(const QString &line) { - emit addToOutputWindow(QLatin1String("<font color=\"#ff0000\">") + line + QLatin1String("</font>")); + emit addToOutputWindow(QLatin1String("<font color=\"#ff0000\">") + Qt::escape(line) + QLatin1String("</font>")); } void AbstractProcessStep::checkForCancel() diff --git a/src/plugins/projectexplorer/allprojectsfind.cpp b/src/plugins/projectexplorer/allprojectsfind.cpp index f892f5ff39900c8c98ee67b1660635346d194199..be7d9d96ee452ae48e8c82ac2ef386a8a986e859 100644 --- a/src/plugins/projectexplorer/allprojectsfind.cpp +++ b/src/plugins/projectexplorer/allprojectsfind.cpp @@ -108,12 +108,14 @@ QWidget *AllProjectsFind::createConfigWidget() gridLayout->setMargin(0); m_configWidget->setLayout(gridLayout); gridLayout->addWidget(createRegExpWidget(), 0, 1); - QLabel * const filePatternLabel = new QLabel(tr("File pattern:")); + QLabel * const filePatternLabel = new QLabel(tr("File &pattern:")); filePatternLabel->setMinimumWidth(80); filePatternLabel->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Preferred); filePatternLabel->setAlignment(Qt::AlignRight | Qt::AlignVCenter); + QWidget *patternWidget = createPatternWidget(); + filePatternLabel->setBuddy(patternWidget); gridLayout->addWidget(filePatternLabel, 1, 0, Qt::AlignRight); - gridLayout->addWidget(createPatternWidget(), 1, 1); + gridLayout->addWidget(patternWidget, 1, 1); m_configWidget->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred); } return m_configWidget; diff --git a/src/plugins/projectexplorer/applicationrunconfiguration.cpp b/src/plugins/projectexplorer/applicationrunconfiguration.cpp index ba459d563c1f7338e1f248d207898251d354ad09..30b9a7f7caab9ec98223e647ef13ccd392e9f71b 100644 --- a/src/plugins/projectexplorer/applicationrunconfiguration.cpp +++ b/src/plugins/projectexplorer/applicationrunconfiguration.cpp @@ -38,6 +38,7 @@ #include <projectexplorer/projectexplorerconstants.h> #include <QtGui/QLabel> +#include <QtGui/QTextDocument> #include <QDebug> using namespace ProjectExplorer; @@ -160,7 +161,7 @@ void ApplicationRunControl::slotError(const QString & err) void ApplicationRunControl::slotAddToOutputWindow(const QString &line) { - emit addToOutputWindow(this, line); + emit addToOutputWindow(this, Qt::escape(line)); } void ApplicationRunControl::processExited(int exitCode) diff --git a/src/plugins/projectexplorer/currentprojectfind.cpp b/src/plugins/projectexplorer/currentprojectfind.cpp index 58300f4ca83f7adcb6dcaa5359cc0930f74fe1e4..fb55df3e0fd7a6f1e9710e9cf0884b6ea288111c 100644 --- a/src/plugins/projectexplorer/currentprojectfind.cpp +++ b/src/plugins/projectexplorer/currentprojectfind.cpp @@ -104,12 +104,14 @@ QWidget *CurrentProjectFind::createConfigWidget() layout->setMargin(0); m_configWidget->setLayout(layout); layout->addWidget(createRegExpWidget(), 0, 1); - QLabel * const filePatternLabel = new QLabel(tr("File pattern:")); + QLabel * const filePatternLabel = new QLabel(tr("File &pattern:")); filePatternLabel->setMinimumWidth(80); filePatternLabel->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Preferred); filePatternLabel->setAlignment(Qt::AlignRight | Qt::AlignVCenter); + QWidget *patternWidget = createPatternWidget(); + filePatternLabel->setBuddy(patternWidget); layout->addWidget(filePatternLabel, 1, 0, Qt::AlignRight); - layout->addWidget(createPatternWidget(), 1, 1); + layout->addWidget(patternWidget, 1, 1); m_configWidget->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred); } return m_configWidget; diff --git a/src/plugins/projectexplorer/projectexplorer.cpp b/src/plugins/projectexplorer/projectexplorer.cpp index e04553763a36e1194fc9a2cffd5dc707afa6486e..b95d5c19463d46a20a554fa4381b49ef178bf661 100644 --- a/src/plugins/projectexplorer/projectexplorer.cpp +++ b/src/plugins/projectexplorer/projectexplorer.cpp @@ -76,6 +76,7 @@ #include <coreplugin/welcomemode.h> #include <coreplugin/vcsmanager.h> #include <coreplugin/iversioncontrol.h> +#include <coreplugin/vcsmanager.h> #include <utils/listutils.h> #include <QtCore/qplugin.h> @@ -685,28 +686,19 @@ void ProjectExplorerPlugin::loadAction() updateActions(); } -bool ProjectExplorerPlugin::saveAction(Project *pro) +void ProjectExplorerPlugin::unloadProject() { if (debug) - qDebug() << "ProjectExplorerPlugin::saveAction"; - - if (!pro) - pro = m_currentProject; - Q_ASSERT(pro); - - Core::IFile *fi = pro->file(); + qDebug() << "ProjectExplorerPlugin::unloadProject"; - if (!fi) // TODO Why saving the session here???? - fi = m_session->file(); + Core::IFile *fi = m_currentProject->file(); if (!fi || fi->fileName().isEmpty()) //nothing to save? - return false; + return; QList<Core::IFile*> filesToSave; - filesToSave << fi; - if (pro) - filesToSave << pro->dependencies(); + filesToSave << m_currentProject->dependencies(); // check the number of modified files int readonlycount = 0; @@ -721,20 +713,10 @@ bool ProjectExplorerPlugin::saveAction(Project *pro) else success = m_core->fileManager()->saveModifiedFilesSilently(filesToSave).isEmpty(); - if (success) - addToRecentProjects(fi->fileName()); - updateActions(); - return success; -} - -void ProjectExplorerPlugin::unloadProject() -{ - if (debug) - qDebug() << "ProjectExplorerPlugin::unloadProject"; - - if (!saveAction(m_currentProject)) + if (!success) return; + addToRecentProjects(fi->fileName()); m_session->removeProject(m_currentProject); updateActions(); } @@ -1172,6 +1154,13 @@ void ProjectExplorerPlugin::setCurrent(Project *project, QString filePath, Node if (projectChanged) { if (debug) qDebug() << "ProjectExplorer - currentProjectChanged(" << (project ? project->name() : "0") << ")"; + // Enable the right VCS + if (const Core::IFile *projectFile = project ? project->file() : static_cast<const Core::IFile *>(0)) { + m_core->vcsManager()->setVCSEnabled(QFileInfo(projectFile->fileName()).absolutePath()); + } else { + m_core->vcsManager()->setAllVCSEnabled(); + } + emit currentProjectChanged(project); updateActions(); } @@ -1584,27 +1573,28 @@ void ProjectExplorerPlugin::addExistingFiles() fileNames.removeOne(file); } - if (Core::IVersionControl *vcManager = m_core->vcsManager()->findVersionControlForDirectory(dir)) { - const QString files = fileNames.join("\n"); - QMessageBox::StandardButton button = + if (Core::IVersionControl *vcManager = m_core->vcsManager()->findVersionControlForDirectory(dir)) + if (vcManager->supportsOperation(Core::IVersionControl::AddOperation)) { + const QString files = fileNames.join(QString(QLatin1Char('\n'))); + QMessageBox::StandardButton button = QMessageBox::question(m_core->mainWindow(), tr("Add to Version Control"), - tr("Add files\n%1\nto version control?").arg(files), + tr("Add files\n%1\nto version control (%2)?").arg(files, vcManager->name()), QMessageBox::Yes | QMessageBox::No); - if (button == QMessageBox::Yes) { - QStringList notAddedToVc; - foreach (const QString file, fileNames) { - if (!vcManager->vcsAdd(file)) - notAddedToVc << file; - } + if (button == QMessageBox::Yes) { + QStringList notAddedToVc; + foreach (const QString &file, fileNames) { + if (!vcManager->vcsAdd(file)) + notAddedToVc << file; + } - if (!notAddedToVc.isEmpty()) { - const QString message = tr("Could not add following files to version control\n"); - const QString filesNotAdded = notAddedToVc.join("\n"); - QMessageBox::warning(m_core->mainWindow(), tr("Add files to version control failed"), - message + filesNotAdded); + if (!notAddedToVc.isEmpty()) { + const QString message = tr("Could not add following files to version control (%1)\n").arg(vcManager->name()); + const QString filesNotAdded = notAddedToVc.join(QString(QLatin1Char('\n'))); + QMessageBox::warning(m_core->mainWindow(), tr("Add files to version control failed"), + message + filesNotAdded); + } } } - } } void ProjectExplorerPlugin::openFile() diff --git a/src/plugins/projectexplorer/projectexplorer.h b/src/plugins/projectexplorer/projectexplorer.h index 039def13052347ccb61ab58c3f14cca361224902..6a7f4beb83119b92c5756cd744430a9c720b2b9c 100644 --- a/src/plugins/projectexplorer/projectexplorer.h +++ b/src/plugins/projectexplorer/projectexplorer.h @@ -139,7 +139,6 @@ private slots: void cancelBuild(); void debugProject(); void editDependencies(); - bool saveAction(ProjectExplorer::Project *pro = 0); void loadAction(); void unloadProject(); void clearSession(); diff --git a/src/plugins/projectexplorer/projectfilewizardextension.cpp b/src/plugins/projectexplorer/projectfilewizardextension.cpp index 2cd220ef58e3e9c1eb4cf7b39699871d92098718..7445d4799c7e7a304d421f6ce4545e2bf084eaaf 100644 --- a/src/plugins/projectexplorer/projectfilewizardextension.cpp +++ b/src/plugins/projectexplorer/projectfilewizardextension.cpp @@ -118,7 +118,11 @@ void ProjectFileWizardExtension::firstExtensionPageShown(const QList<Core::Gener m_context->versionControl = m_core->vcsManager()->findVersionControlForDirectory(directory); m_context->page->setFilesDisplay(fileNames); - m_context->page->setAddToVersionControlEnabled(m_context->versionControl != 0); + + const bool canAddToVCS = m_context->versionControl && m_context->versionControl->supportsOperation(Core::IVersionControl::AddOperation); + if (m_context->versionControl) + m_context->page->setVCSDisplay(m_context->versionControl->name()); + m_context->page->setAddToVersionControlEnabled(canAddToVCS); } static ProjectNode *currentProject() diff --git a/src/plugins/projectexplorer/projectwizardpage.cpp b/src/plugins/projectexplorer/projectwizardpage.cpp index 8a2873c336db953bbfc3e2eac0a00938683f5518..8912fbb9e948e02c1c505fd56b8ca699cb8f9aab 100644 --- a/src/plugins/projectexplorer/projectwizardpage.cpp +++ b/src/plugins/projectexplorer/projectwizardpage.cpp @@ -108,6 +108,11 @@ void ProjectWizardPage::changeEvent(QEvent *e) } } +void ProjectWizardPage::setVCSDisplay(const QString &vcsName) +{ + m_ui->addToVersionControlLabel->setText(tr("Add to &VCS (%1)").arg(vcsName)); +} + void ProjectWizardPage::setFilesDisplay(const QStringList &files) { QString fileMessage; { diff --git a/src/plugins/projectexplorer/projectwizardpage.h b/src/plugins/projectexplorer/projectwizardpage.h index 2031923d37c8a3c7adf4404c321f931f7e490463..bc86bb6fa7eccc52ca0af34bf910a78077a29f2a 100644 --- a/src/plugins/projectexplorer/projectwizardpage.h +++ b/src/plugins/projectexplorer/projectwizardpage.h @@ -69,6 +69,7 @@ public: bool addToVersionControl() const; void setAddToVersionControlEnabled(bool b); + void setVCSDisplay(const QString &vcsName); void setFilesDisplay(const QStringList &files); protected: diff --git a/src/plugins/projectexplorer/session.cpp b/src/plugins/projectexplorer/session.cpp index 61ca7df05a9a705c0cb84867e9810a44ba2d6ecf..876b8294a377c0ca72f49d88e2823ca8309acd2c 100644 --- a/src/plugins/projectexplorer/session.cpp +++ b/src/plugins/projectexplorer/session.cpp @@ -939,6 +939,7 @@ void SessionManager::removeProjects(QList<Project *> remove) // Delete projects foreach (Project *pro, remove) { + pro->saveSettings(); m_file->m_projects.removeOne(pro); if (pro == m_file->m_startupProject) diff --git a/src/plugins/projectexplorer/taskwindow.cpp b/src/plugins/projectexplorer/taskwindow.cpp index b69d37541ee4d54865089981e68abb3ced71d249..309e8ab983693116aff611f19822792519565785 100644 --- a/src/plugins/projectexplorer/taskwindow.cpp +++ b/src/plugins/projectexplorer/taskwindow.cpp @@ -37,6 +37,7 @@ #include <coreplugin/actionmanager/actionmanager.h> #include <coreplugin/editormanager/editormanager.h> #include <coreplugin/coreconstants.h> +#include <coreplugin/uniqueidmanager.h> #include <texteditor/itexteditor.h> #include <texteditor/basetexteditor.h> #include <projectexplorerconstants.h> @@ -47,6 +48,8 @@ #include <QtGui/QListView> #include <QtGui/QPainter> #include <QtCore/QAbstractItemModel> +#include <QtGui/QApplication> +#include <QtGui/QClipboard> #include <QtGui/QFont> #include <QtGui/QFontMetrics> #include <QtGui/QTextLayout> @@ -81,7 +84,7 @@ public: QModelIndex firstError() const; void setFileNotFound(const QModelIndex &index, bool b); - enum Roles { File = Qt::UserRole, Line, Description, FileNotFound }; + enum Roles { File = Qt::UserRole, Line, Description, FileNotFound, Type }; private: QList<TaskItem> m_items; int m_maxSizeOfFileName; @@ -196,6 +199,8 @@ QVariant TaskModel::data(const QModelIndex &index, int role) const return m_items.at(index.row()).description; else if (role == TaskModel::FileNotFound) return m_items.at(index.row()).fileNotFound; + else if (role == TaskModel::Type) + return (int)m_items.at(index.row()).type; else if (role == Qt::DecorationRole) { if (m_items.at(index.row()).type == ProjectExplorer::BuildParserInterface::Error) { return QIcon(":/projectexplorer/images/compile_error.png"); @@ -257,6 +262,15 @@ TaskWindow::TaskWindow() TaskDelegate *tld = new TaskDelegate(this); m_listview->setItemDelegate(tld); m_listview->setWindowIcon(QIcon(":/qt4projectmanager/images/window.png")); + m_listview->setContextMenuPolicy(Qt::ActionsContextMenu); + + m_taskWindowContext = new TaskWindowContext(m_listview); + m_coreIFace->addContextObject(m_taskWindowContext); + + m_copyAction = new QAction(QIcon(Core::Constants::ICON_COPY), tr("&Copy"), this); + m_coreIFace->actionManager()-> + registerAction(m_copyAction, Core::Constants::COPY, m_taskWindowContext->context()); + m_listview->addAction(m_copyAction); connect(m_listview->selectionModel(), SIGNAL(currentChanged(const QModelIndex &, const QModelIndex &)), tld, SLOT(currentChanged(const QModelIndex &, const QModelIndex &))); @@ -266,12 +280,15 @@ TaskWindow::TaskWindow() connect(m_listview, SIGNAL(clicked(const QModelIndex &)), this, SLOT(showTaskInFile(const QModelIndex &))); + connect(m_copyAction, SIGNAL(triggered()), SLOT(copy())); + m_errorCount = 0; m_currentTask = -1; } TaskWindow::~TaskWindow() { + m_coreIFace->removeContextObject(m_taskWindowContext); delete m_listview; delete m_model; } @@ -291,6 +308,7 @@ void TaskWindow::clearContents() m_errorCount = 0; m_currentTask = -1; m_model->clear(); + m_copyAction->setEnabled(false); emit tasksChanged(); } @@ -305,6 +323,7 @@ void TaskWindow::addItem(ProjectExplorer::BuildParserInterface::PatternType type m_model->addTask(type, description, file, line); if (type == ProjectExplorer::BuildParserInterface::Error) ++m_errorCount; + m_copyAction->setEnabled(true); emit tasksChanged(); } @@ -327,6 +346,25 @@ void TaskWindow::showTaskInFile(const QModelIndex &index) m_listview->selectionModel()->select(index, QItemSelectionModel::ClearAndSelect); } +void TaskWindow::copy() +{ + QModelIndex index = m_listview->selectionModel()->currentIndex(); + QString file = index.data(TaskModel::File).toString(); + QString line = index.data(TaskModel::Line).toString(); + QString description = index.data(TaskModel::Description).toString(); + QString type; + switch (index.data(TaskModel::Type).toInt()) { + case ProjectExplorer::BuildParserInterface::Error: + type = "error: "; + break; + case ProjectExplorer::BuildParserInterface::Warning: + type = "warning: "; + break; + } + + QApplication::clipboard()->setText(file + ':' + line + ": " + type + description); +} + int TaskWindow::numberOfTasks() const { return m_model->rowCount(QModelIndex()); @@ -483,7 +521,7 @@ void TaskDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, painter->fillRect(width, 2 + opt.rect.top(), gwidth, fm.height() + 1, lg); } } else { - // Descritption + // Description QString description = index.data(TaskModel::Description).toString(); // Layout the description int leading = fm.leading(); @@ -536,3 +574,21 @@ void TaskDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, painter->drawLine(0, opt.rect.bottom(), opt.rect.right(), opt.rect.bottom()); painter->restore(); } + +TaskWindowContext::TaskWindowContext(QWidget *widget) + : m_taskList(widget) +{ + Core::ICore *core = ExtensionSystem::PluginManager::instance()->getObject<Core::ICore>(); + m_context << core->uniqueIDManager()->uniqueIdentifier(Core::Constants::C_PROBLEM_PANE); +} + +QList<int> TaskWindowContext::context() const +{ + return m_context; +} + +QWidget *TaskWindowContext::widget() +{ + return m_taskList; +} + diff --git a/src/plugins/projectexplorer/taskwindow.h b/src/plugins/projectexplorer/taskwindow.h index efd2752469e24ad2a0af89b4103382a4e23d9c92..702534115309eb1b95c137dd9c34025faa5f42af 100644 --- a/src/plugins/projectexplorer/taskwindow.h +++ b/src/plugins/projectexplorer/taskwindow.h @@ -37,6 +37,7 @@ #include "buildparserinterface.h" #include <coreplugin/ioutputpane.h> +#include <coreplugin/icontext.h> #include <coreplugin/icore.h> #include <QtGui/QTreeWidget> @@ -49,6 +50,7 @@ namespace Internal { class TaskModel; class TaskView; +class TaskWindowContext; class TaskWindow : public Core::IOutputPane { @@ -82,6 +84,7 @@ signals: private slots: void showTaskInFile(const QModelIndex &index); + void copy(); private: int sizeHintForColumn(int column) const; @@ -92,6 +95,8 @@ private: TaskModel *m_model; TaskView *m_listview; + TaskWindowContext *m_taskWindowContext; + QAction *m_copyAction; }; class TaskView : public QListView @@ -122,6 +127,17 @@ private: void generateGradientPixmap(int width, int height, QColor color, bool selected) const; }; +class TaskWindowContext : public Core::IContext +{ +public: + TaskWindowContext(QWidget *widget); + virtual QList<int> context() const; + virtual QWidget *widget(); +private: + QWidget *m_taskList; + QList<int> m_context; +}; + } //namespace Internal } //namespace ProjectExplorer diff --git a/src/plugins/qt4projectmanager/gccparser.cpp b/src/plugins/qt4projectmanager/gccparser.cpp index de69904ac80d66807e82b6316a839d326b0356d7..a208fc63052dfb4accd20b768ead5ee18aa5cda3 100644 --- a/src/plugins/qt4projectmanager/gccparser.cpp +++ b/src/plugins/qt4projectmanager/gccparser.cpp @@ -40,13 +40,13 @@ using namespace Qt4ProjectManager; GccParser::GccParser() { - m_regExp.setPattern("^([^\\(\\)]+[^\\d]):(\\d+):(\\d+:)*(\\s(warning|error):)?(.+)$"); + m_regExp.setPattern("^([^\\(\\)]+[^\\d]):(\\d+):(\\d+:)*(\\s(warning|error):)?\\s(.+)$"); m_regExp.setMinimal(true); m_regExpIncluded.setPattern("^.*from\\s([^:]+):(\\d+)(,|:)$"); m_regExpIncluded.setMinimal(true); - m_regExpLinker.setPattern("^(\\S+)\\(\\S+\\):(.+)$"); + m_regExpLinker.setPattern("^(\\S+)\\(\\S+\\):\\s(.+)$"); m_regExpLinker.setMinimal(true); //make[4]: Entering directory `/home/kkoehne/dev/ide-explorer/src/plugins/qtscripteditor' diff --git a/src/plugins/qt4projectmanager/qmakestep.cpp b/src/plugins/qt4projectmanager/qmakestep.cpp index 44654496dc84eb867020f20abe7dfdf4217261ad..44780a7dcc5584ce297475f637b1a619e41235dd 100644 --- a/src/plugins/qt4projectmanager/qmakestep.cpp +++ b/src/plugins/qt4projectmanager/qmakestep.cpp @@ -159,7 +159,6 @@ bool QMakeStep::init(const QString &name) setCommand(name, program); setArguments(name, args); setEnvironment(name, environment); - setWorkingDirectory(name, workingDirectory); return AbstractProcessStep::init(name); } diff --git a/src/plugins/qt4projectmanager/qt4nodes.cpp b/src/plugins/qt4projectmanager/qt4nodes.cpp index 672ce8b835b9077fd5ae28c743231979b39b1304..8c4010aac5ea9603646b662d3faed8e80ddba377 100644 --- a/src/plugins/qt4projectmanager/qt4nodes.cpp +++ b/src/plugins/qt4projectmanager/qt4nodes.cpp @@ -84,7 +84,7 @@ Qt4PriFileNode::Qt4PriFileNode(Qt4Project *project, : ProjectNode(filePath), m_core(project->qt4ProjectManager()->core()), m_project(project), - m_projectFilePath(filePath), + m_projectFilePath(QDir::fromNativeSeparators(filePath)), m_projectDir(QFileInfo(filePath).absolutePath()), m_includeFile(0), m_saveTimer(new QTimer(this)), @@ -265,46 +265,18 @@ bool Qt4PriFileNode::changeIncludes(ProFile *includeFile, const QStringList &pro return false; } - -namespace { - enum ReadOnlyAction { RO_Cancel, RO_OpenSCC, RO_MakeWriteable }; -} - -static ReadOnlyAction promptReadOnly(const QString &fileName, bool hasSCC, QWidget *parent) -{ - QMessageBox msgBox(QMessageBox::Question, QObject::tr("File is Read Only"), - QObject::tr("The file %1 is read only.").arg(fileName), - QMessageBox::Cancel, parent); - - QPushButton *sccButton = 0; - if (hasSCC) - sccButton = msgBox.addButton(QObject::tr("Open with SCC"), QMessageBox::AcceptRole); - QPushButton *makeWritableButton = msgBox.addButton(QObject::tr("Make writable"), QMessageBox::AcceptRole); - if (hasSCC) - msgBox.setDefaultButton(sccButton); - else - msgBox.setDefaultButton(makeWritableButton); - msgBox.exec(); - QAbstractButton *clickedButton = msgBox.clickedButton(); - if (clickedButton == sccButton) - return RO_OpenSCC; - if (clickedButton == makeWritableButton) - return RO_MakeWriteable; - return RO_Cancel; -} - bool Qt4PriFileNode::priFileWritable(const QString &path) { const QString dir = QFileInfo(path).dir().path(); Core::IVersionControl *versionControl = m_core->vcsManager()->findVersionControlForDirectory(dir); - switch (promptReadOnly(path, versionControl != 0, m_core->mainWindow())) { - case RO_OpenSCC: + switch (Core::EditorManager::promptReadOnlyFile(path, versionControl, m_core->mainWindow(), false)) { + case Core::EditorManager::RO_OpenVCS: if (!versionControl->vcsOpen(path)) { QMessageBox::warning(m_core->mainWindow(), tr("Failed!"), tr("Could not open the file for edit with SCC.")); return false; } break; - case RO_MakeWriteable: { + case Core::EditorManager::RO_MakeWriteable: { const bool permsOk = QFile::setPermissions(path, QFile::permissions(path) | QFile::WriteUser); if (!permsOk) { QMessageBox::warning(m_core->mainWindow(), tr("Failed!"), tr("Could not set permissions to writable.")); @@ -312,10 +284,10 @@ bool Qt4PriFileNode::priFileWritable(const QString &path) } break; } - case RO_Cancel: { + case Core::EditorManager::RO_SaveAs: + case Core::EditorManager::RO_Cancel: return false; } - } return true; } @@ -457,7 +429,8 @@ void Qt4PriFileNode::save() if (modifiedFileHandle) fileManager->blockFileChange(modifiedFileHandle); ProWriter pw; - bool ok = pw.write(m_includeFile, m_includeFile->fileName()); + const bool ok = pw.write(m_includeFile, m_includeFile->fileName()); + Q_UNUSED(ok) m_includeFile->setModified(false); m_project->qt4ProjectManager()->notifyChanged(m_includeFile->fileName()); if (modifiedFileHandle) diff --git a/src/plugins/qt4projectmanager/wizards/consoleappwizarddialog.cpp b/src/plugins/qt4projectmanager/wizards/consoleappwizarddialog.cpp index 14965f50187675bf5c69cec9cc2ddc79032c16ff..1090673284f08a4d50278b104b826541e71c9208 100644 --- a/src/plugins/qt4projectmanager/wizards/consoleappwizarddialog.cpp +++ b/src/plugins/qt4projectmanager/wizards/consoleappwizarddialog.cpp @@ -35,6 +35,7 @@ #include "consoleappwizard.h" #include "modulespage.h" +#include <QtCore/QDebug> #include <utils/projectintropage.h> namespace Qt4ProjectManager { @@ -51,13 +52,11 @@ ConsoleAppWizardDialog::ConsoleAppWizardDialog(const QString &templateName, setWindowIcon(icon); setWindowTitle(templateName); Core::BaseFileWizard::setupWizard(this); - setOptions(QWizard::IndependentPages | QWizard::HaveNextButtonOnLastPage); m_introPage->setDescription(tr("This wizard generates a Qt4 console application " "project. The application derives from QCoreApplication and does not " "present a GUI. You can press 'Finish' at any point in time.")); - m_introPage->setFinalPage(true); addPage(m_introPage); m_modulesPage->setModuleSelected(QLatin1String("core")); diff --git a/src/plugins/qt4projectmanager/wizards/guiappwizarddialog.cpp b/src/plugins/qt4projectmanager/wizards/guiappwizarddialog.cpp index 7b1ba073d34e6203a1f2cb720d6dafac79c2faed..621a3b6ba92072de3d411f1713ac6515166102c6 100644 --- a/src/plugins/qt4projectmanager/wizards/guiappwizarddialog.cpp +++ b/src/plugins/qt4projectmanager/wizards/guiappwizarddialog.cpp @@ -63,7 +63,6 @@ GuiAppWizardDialog::GuiAppWizardDialog(const QString &templateName, setWindowIcon(icon); setWindowTitle(templateName); Core::BaseFileWizard::setupWizard(this); - setOptions(QWizard::IndependentPages); m_introPage->setDescription(tr("This wizard generates a Qt4 GUI application " "project. The application derives by default from QApplication " diff --git a/src/plugins/subversion/subversioncontrol.cpp b/src/plugins/subversion/subversioncontrol.cpp index ba2a2f2e8e92dcfa8b5af88c36b308418aa05f32..56ad229954743e3719088985e4eecc15be726919 100644 --- a/src/plugins/subversion/subversioncontrol.cpp +++ b/src/plugins/subversion/subversioncontrol.cpp @@ -38,10 +38,43 @@ using namespace Subversion; using namespace Subversion::Internal; SubversionControl::SubversionControl(SubversionPlugin *plugin) : + m_enabled(true), m_plugin(plugin) { } +QString SubversionControl::name() const +{ + return QLatin1String("subversion"); +} + +bool SubversionControl::isEnabled() const +{ + return m_enabled; +} + +void SubversionControl::setEnabled(bool enabled) +{ + if (m_enabled != enabled) { + m_enabled = enabled; + emit enabledChanged(m_enabled); + } +} + +bool SubversionControl::supportsOperation(Operation operation) const +{ + bool rc = true; + switch (operation) { + case AddOperation: + case DeleteOperation: + break; + case OpenOperation: + rc = false; + break; + } + return rc; +} + bool SubversionControl::vcsOpen(const QString & /* fileName */) { // Open for edit: N/A diff --git a/src/plugins/subversion/subversioncontrol.h b/src/plugins/subversion/subversioncontrol.h index f293852a3a11e4917dd912d1d767ef324ef8afd4..c4a2f8aa79c69d5145438a9182fd6737821e1443 100644 --- a/src/plugins/subversion/subversioncontrol.h +++ b/src/plugins/subversion/subversioncontrol.h @@ -47,13 +47,24 @@ class SubversionControl : public Core::IVersionControl Q_OBJECT public: explicit SubversionControl(SubversionPlugin *plugin); + virtual QString name() const; + + virtual bool isEnabled() const; + virtual void setEnabled(bool enabled); + virtual bool managesDirectory(const QString &directory) const; virtual QString findTopLevelForDirectory(const QString &directory) const; + + virtual bool supportsOperation(Operation operation) const; virtual bool vcsOpen(const QString &fileName); virtual bool vcsAdd(const QString &fileName); virtual bool vcsDelete(const QString &filename); +signals: + void enabledChanged(bool); + private: + bool m_enabled; SubversionPlugin *m_plugin; }; diff --git a/src/plugins/subversion/subversionplugin.cpp b/src/plugins/subversion/subversionplugin.cpp index 6532a9d43357775f8de4e8ba199f447c60039979..a24bb7d3d06bbb0e652143e6a73cc134332f97a1 100644 --- a/src/plugins/subversion/subversionplugin.cpp +++ b/src/plugins/subversion/subversionplugin.cpp @@ -276,6 +276,10 @@ bool SubversionPlugin::initialize(const QStringList & /*arguments*/, QString *er ami->createMenu(QLatin1String(SUBVERSION_MENU)); subversionMenu->menu()->setTitle(tr("&Subversion")); toolsContainer->addMenu(subversionMenu); + if (QAction *ma = subversionMenu->menu()->menuAction()) { + ma->setEnabled(m_versionControl->isEnabled()); + connect(m_versionControl, SIGNAL(enabledChanged(bool)), ma, SLOT(setVisible(bool))); + } QList<int> globalcontext; globalcontext << m_coreInstance->uniqueIDManager()->uniqueIdentifier(C_GLOBAL); diff --git a/src/plugins/texteditor/basefilefind.cpp b/src/plugins/texteditor/basefilefind.cpp index 43606bf205a5cab80cde45f9f9a00f806404ba2d..4811e4e4c18454cc8b4eca3637e49e2092e352a8 100644 --- a/src/plugins/texteditor/basefilefind.cpp +++ b/src/plugins/texteditor/basefilefind.cpp @@ -146,7 +146,7 @@ QWidget *BaseFileFind::createPatternWidget() */ QString filterToolTip = tr("List of comma separated wildcard filters"); /* - QLabel *label = new QLabel(tr("File pattern:")); + QLabel *label = new QLabel(tr("File &pattern:")); label->setToolTip(filterToolTip); */ /* @@ -163,6 +163,7 @@ QWidget *BaseFileFind::createPatternWidget() m_filterCombo->setToolTip(filterToolTip); syncComboWithSettings(m_filterCombo, m_filterSetting); /* + label->setBuddy(m_filterCombo); hlayout->addWidget(m_filterCombo); */ return m_filterCombo; @@ -170,7 +171,7 @@ QWidget *BaseFileFind::createPatternWidget() QWidget *BaseFileFind::createRegExpWidget() { - m_useRegExpCheckBox = new QCheckBox(tr("Use Regular Expressions")); + m_useRegExpCheckBox = new QCheckBox(tr("Use Regular E&xpressions")); m_useRegExpCheckBox->setChecked(m_useRegExp); connect(m_useRegExpCheckBox, SIGNAL(toggled(bool)), this, SLOT(syncRegExpSetting(bool))); return m_useRegExpCheckBox; diff --git a/src/plugins/texteditor/basetexteditor.cpp b/src/plugins/texteditor/basetexteditor.cpp index 4dda8f7b952265305a7198a9d2ffd8dd1f1417ee..1e6a266e6da886b16eb0f7ec44c1fddd12c9cdcd 100644 --- a/src/plugins/texteditor/basetexteditor.cpp +++ b/src/plugins/texteditor/basetexteditor.cpp @@ -502,7 +502,8 @@ void BaseTextEditor::currentEditorChanged(Core::IEditor *editor) if (editor == d->m_editable) { if (d->m_document->hasDecodingError()) { Core::EditorManager::instance()->showEditorInfoBar(QLatin1String(Constants::SELECT_ENCODING), - tr("<b>Error:</b> Could not decode \"%1\" with \"%2\"-encoding. Editing not possible.").arg(displayName()).arg(QString::fromLatin1(d->m_document->codec()->name())), + tr("<b>Error:</b> Could not decode \"%1\" with \"%2\"-encoding. Editing not possible.") + .arg(displayName()).arg(QString::fromLatin1(d->m_document->codec()->name())), tr("Select Encoding"), this, SLOT(selectEncoding())); } diff --git a/src/plugins/texteditor/findinfiles.cpp b/src/plugins/texteditor/findinfiles.cpp index 55ecd01e5ad380b7589dabd2c52b86ecbef77b2e..a67dbebe11065c0b7ad2c4e4e8fc5bbd633c8b6b 100644 --- a/src/plugins/texteditor/findinfiles.cpp +++ b/src/plugins/texteditor/findinfiles.cpp @@ -88,7 +88,8 @@ QWidget *FindInFiles::createConfigWidget() m_configWidget->setLayout(gridLayout); gridLayout->addWidget(createRegExpWidget(), 0, 1, 1, 2); - gridLayout->addWidget(new QLabel(tr("Directory:")), 1, 0, Qt::AlignRight); + QLabel *dirLabel = new QLabel(tr("&Directory:")); + gridLayout->addWidget(dirLabel, 1, 0, Qt::AlignRight); m_directory = new QComboBox; m_directory->setEditable(true); m_directory->setMaxCount(30); @@ -98,17 +99,20 @@ QWidget *FindInFiles::createConfigWidget() m_directory->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); m_directory->setModel(&m_directoryStrings); syncComboWithSettings(m_directory, m_directorySetting); + dirLabel->setBuddy(m_directory); gridLayout->addWidget(m_directory, 1, 1); - QPushButton *browseButton = new QPushButton(tr("Browse")); + QPushButton *browseButton = new QPushButton(tr("&Browse")); gridLayout->addWidget(browseButton, 1, 2); connect(browseButton, SIGNAL(clicked()), this, SLOT(openFileBrowser())); - QLabel * const filePatternLabel = new QLabel(tr("File pattern:")); + QLabel * const filePatternLabel = new QLabel(tr("File &pattern:")); filePatternLabel->setMinimumWidth(80); filePatternLabel->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Preferred); filePatternLabel->setAlignment(Qt::AlignRight | Qt::AlignVCenter); + QWidget *patternWidget = createPatternWidget(); + filePatternLabel->setBuddy(patternWidget); gridLayout->addWidget(filePatternLabel, 2, 0); - gridLayout->addWidget(createPatternWidget(), 2, 1, 1, 2); + gridLayout->addWidget(patternWidget, 2, 1, 1, 2); m_configWidget->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred); } return m_configWidget;