diff --git a/.gitignore b/.gitignore index 8f3ba0e8541d81eea92fe1700e6919b5e5f2cef0..2c79a07b7596f5d67200cd00235864337c217321 100644 --- a/.gitignore +++ b/.gitignore @@ -56,6 +56,7 @@ examples/tools/plugandpaint/plugins include/* include/*/* lib/* +lib64/* plugins/*/* release tmp diff --git a/doc/example/textfinder/textfinder.cpp b/doc/example/textfinder/textfinder.cpp index b399d17d23feee8f8c6ec3fa38ec1d54bc306ef3..c302f91911f79958f78241fd3b1d3d8f4cfee77e 100644 --- a/doc/example/textfinder/textfinder.cpp +++ b/doc/example/textfinder/textfinder.cpp @@ -33,18 +33,21 @@ #include <QtCore/QTextStream> #include <QtGui/QMessageBox> -TextFinder::TextFinder(QWidget *parent, Qt::WFlags flags) - : QWidget(parent, flags) +//! [2] +TextFinder::TextFinder(QWidget *parent) + : QWidget(parent), ui(new Ui::TextFinder) { - ui.setupUi(this); + ui->setupUi(this); loadTextFile(); - isFirstTime = true; } +//! [2] TextFinder::~TextFinder() { + delete ui; } +//! [0] void TextFinder::loadTextFile() { QFile inputFile(":/input.txt"); @@ -54,20 +57,16 @@ void TextFinder::loadTextFile() QString line = in.readAll(); inputFile.close(); - ui.textEdit->setPlainText(line); - QTextCursor cursor = ui.textEdit->textCursor(); + ui->textEdit->setPlainText(line); + QTextCursor cursor = ui->textEdit->textCursor(); cursor.movePosition(QTextCursor::Start, QTextCursor::MoveAnchor, 1); } +//! [0] +//! [1] void TextFinder::on_findButton_clicked() { - QString searchString = ui.lineEdit->text(); - QTextDocument *document = ui.textEdit->document(); - - bool found = false; - - ui.textEdit->find(searchString, QTextDocument::FindWholeWords); - QTextCursor cursor = ui.textEdit->textCursor(); - if (!cursor.isNull()) - found = true; + QString searchString = ui->lineEdit->text(); + ui->textEdit->find(searchString, QTextDocument::FindWholeWords); } +//! [1] diff --git a/doc/example/textfinder/textfinder.h b/doc/example/textfinder/textfinder.h index 19e34224da41d4d48cc64c84a99f725aec65464f..89dad6913664d898a3d5ccd25f54a1d4a65c2d67 100644 --- a/doc/example/textfinder/textfinder.h +++ b/doc/example/textfinder/textfinder.h @@ -34,29 +34,25 @@ #include <QtGui/QWidget> -class QPushButton; -class QTextEdit; -class QLineEdit; +namespace Ui +{ + class TextFinder; +} class TextFinder : public QWidget { Q_OBJECT public: - TextFinder(QWidget *parent = 0, Qt::WFlags flags = 0); + TextFinder(QWidget *parent = 0); ~TextFinder(); private slots: void on_findButton_clicked(); private: - Ui::Form ui; + Ui::TextFinder *ui; void loadTextFile(); - - QPushButton *ui_findButton; - QTextEdit *ui_textEdit; - QLineEdit *ui_lineEdit; - bool isFirstTime; }; #endif // TEXTFINDER_H diff --git a/doc/example/textfinder/textfinder.ui b/doc/example/textfinder/textfinder.ui index 1cb72c57471781a8a7dd6be933d07b31e8acbf84..ba8018742a555bafc6c9ec4f791732f198223838 100644 --- a/doc/example/textfinder/textfinder.ui +++ b/doc/example/textfinder/textfinder.ui @@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <ui version="4.0"> - <class>Form</class> - <widget class="QWidget" name="Form"> + <class>TextFinder</class> + <widget class="QWidget" name="TextFinder"> <property name="geometry"> <rect> <x>0</x> diff --git a/doc/qtcreator.qdoc b/doc/qtcreator.qdoc index ce316616f41bb13bb369ebb05b176a38f179fd0a..8d38a3cf8800e714f322792464d9d069ebd031d4 100644 --- a/doc/qtcreator.qdoc +++ b/doc/qtcreator.qdoc @@ -531,9 +531,11 @@ \image qtcreator-textfinder-ui.png Design the form above using a \l{http://doc.trolltech.com/qlabel.html} - {QLabel}, \l{http://doc.trolltech.com/qlinedit.html}{QLineEdit}, - \l{http://doc.trolltech.com/qpushbutton.html}{QPushButton} and a - \l{http://doc.trolltech.com/qtextedit.html}{QTextEdit}. We recommend that + {QLabel}, \l{http://doc.trolltech.com/qlinedit.html}{QLineEdit} + (named lineEdit), \l{http://doc.trolltech.com/qpushbutton.html}{QPushButton} + (named findButton), and a + \l{http://doc.trolltech.com/qtextedit.html}{QTextEdit} (named textEdit). + We recommend that you use a QGridLayout to lay out the \l{http://doc.trolltech.com/qlabel.html}{QLabel}, \l{http://doc.trolltech.com/qlinedit.html}{QLineEdit} and @@ -559,11 +561,11 @@ void on_findButton_clicked(); private: - Ui::Form ui; + Ui::TextFinder *ui; void loadTextFile(); \endcode - \note The \c{Ui::Form} object is already provided. + \note The \c{Ui::TextFinder} object is already provided. \section2 The Source File @@ -571,57 +573,36 @@ \c{textfinder.cpp}. We begin by filling in the functionality to load a text file. The code snippet below describes this: - \code - void TextFinder::loadTextFile() - { - QFile inputFile(":/input.txt"); - inputFile.open(QIODevice::ReadOnly); - - QTextStream in(&inputFile); - QString line = in.readAll(); - inputFile.close(); - - ui.textEdit->setPlainText(line); - QTextCursor cursor = ui.textEdit->textCursor(); - } - \endcode + \snippet example/textfinder/textfinder.cpp 0 Basically, we load a text file using \l{http://doc.trolltech.com/qfile.html}{QFile}, read it with \l{http://doc.trolltech.com/qtextstream.html}{QTextStream}, and then display it on \c{textEdit} with - \l{http://doc.trolltech.com/qtextedit.html#plainText-prop}{setPlainText()}. + \l{http://doc.trolltech.com/qtextedit.html#plainText-prop}{setPlainText()} + which requires adding the following additional #includes to textfinder.cpp: + \code + #include <QtCore/QFile> + #include <QtCore/QTextStream> + \endcode For the \c{on_findButton_clicked()} slot, we extract the search string and use the \l{http://doc.trolltech.com/qtextedit.html#find}{find()} function to look for the search string within the text file. The code snippet below further describes it: - \code - void TextFinder::on_findButton_clicked() - { - QString searchString = ui.lineEdit->text(); - ui.textEdit->find(searchString, QTextDocument::FindWholeWords); - } - \endcode + \snippet example/textfinder/textfinder.cpp 1 Once we have both these functions complete, we call \c{loadTextFile()} in our constructor. - \code - TextFinder::TextFinder(QWidget *parent, Qt::WFlags flags) - : QWidget(parent, flags) - { - ui.setupUi(this); - loadTextFile(); - } - \endcode + \snippet example/textfinder/textfinder.cpp 2 The \c{on_findButton_clicked()} slot will be called automatically due to this line of code: \code - QMetaObject::connectSlotsByName(Form); + QMetaObject::connectSlotsByName(TextFinder); \endcode in the uic generated \c{ui_textfinder.h} file. @@ -795,6 +776,40 @@ \image qtcreator-vcs-gitbranch.png \endtable + \section2 Common options + + The \gui{Version Control/Common} settings page features common settings for + version control systems, such as commit message line wrapping and checking options. + + \gui{Submit message checking script} is a script or program that can be used to + perform checks on the submit message before submitting. It is passed the + submit message as first parameter. On error, it should output a message on standard error and + return an exit code different from 0. + + \gui{User/alias configuration file} takes a file in a mailmap format that lists + user names and aliases: + + \code + Jon Doe <Jon.Doe@company.com> + Hans Mustermann <Hans.Mustermann@company.com> hm <info@company.com> + \endcode + + The second line specifies that the alias \e{hm} and the corresponding email address should + be used for \e{Hans Mustermann}. If the file is present, the submit editor will feature + a context menu option \gui{Insert name...} that will pop up a dialog letting the user + choose a name to be inserted. + + \gui{User field configuration file} is a simple text file consisting of lines specifying submit message fields that take user names, for example: + + \code + Reviewed-by: + Signed-off-by: + \endcode + + The fields will appear below the submit message. They provide completion on the + aliases/public user names specified in the \e{User/alias configuration file} and an additional + button that opens the aforementioned user name dialog. + */ @@ -1197,13 +1212,13 @@ \code void TextFinder::on_findButton_clicked() { - QString searchString = ui.lineEdit->text(); + QString searchString = ui->lineEdit->text(); - QTextDocument *document = ui.textEdit->document(); - QTextCursor cursor = ui.textEdit->textCursor(); + QTextDocument *document = ui->textEdit->document(); + QTextCursor cursor = ui->textEdit->textCursor(); cursor = document->find(searchString, cursor, QTextDocument::FindWholeWords); - ui.textEdit->setTextCursor(cursor); + ui->textEdit->setTextCursor(cursor); bool found = cursor.isNull(); @@ -1216,7 +1231,7 @@ if (ret == QMessageBox::Yes) { cursor = document->find(searchString, QTextDocument::FindWholeWords); - ui.textEdit->setTextCursor(cursor); + ui->textEdit->setTextCursor(cursor); } else return; } diff --git a/doc/qtcreator.qdocconf b/doc/qtcreator.qdocconf index 8baed7725cfaa5b6d14a1049d6fd14c940b1dcd0..ea504250cc38bc4484f0e3ba25d3b0d69d89786e 100644 --- a/doc/qtcreator.qdocconf +++ b/doc/qtcreator.qdocconf @@ -8,6 +8,7 @@ sourcedirs = sourcedirs = $SRCDIR imagedirs = $SRCDIR outputdir = $OUTDIR +exampledirs = $SRCDIR extraimages.HTML = qt-logo \ trolltech-logo diff --git a/share/qtcreator/gdbmacros/gdbmacros.cpp b/share/qtcreator/gdbmacros/gdbmacros.cpp index d0e3d68c5cb3becaedb682e6d9c519f687cb4c90..1bf515f92e5d33e38628e4adb29183ac6db78484 100644 --- a/share/qtcreator/gdbmacros/gdbmacros.cpp +++ b/share/qtcreator/gdbmacros/gdbmacros.cpp @@ -2013,7 +2013,7 @@ static void qDumpQVariantHelper(const void *data, QString *value, *numchild = 0; break; case QVariant::StringList: - *exp = QString(QLatin1String("((QVariant*)%1)->d.data.c")) + *exp = QString(QLatin1String("(*('"NS"QStringList'*)%1)")) .arg((quintptr)data); *numchild = v.toStringList().size(); break; @@ -2057,7 +2057,7 @@ static void qDumpQVariant(QDumper &d) ba += ") "; ba += qPrintable(value); P(d, "value", ba); - P(d, "valueencoded", "1"); + P(d, "valueencoded", "4"); } P(d, "type", NS"QVariant"); P(d, "numchild", (isInvalid ? "0" : "1")); @@ -2069,7 +2069,7 @@ static void qDumpQVariant(QDumper &d) P(d, "exp", qPrintable(exp)); if (!value.isEmpty()) { P(d, "value", value); - P(d, "valueencoded", "1"); + P(d, "valueencoded", "4"); } P(d, "type", v.typeName()); P(d, "numchild", numchild); diff --git a/src/libs/cplusplus/ExpressionUnderCursor.cpp b/src/libs/cplusplus/ExpressionUnderCursor.cpp index 257d14443e8587b1a2635698fa6b008d4cb592ba..9cbaeb97539dbc61a1df3d2ad014db5e4a60e99d 100644 --- a/src/libs/cplusplus/ExpressionUnderCursor.cpp +++ b/src/libs/cplusplus/ExpressionUnderCursor.cpp @@ -190,7 +190,10 @@ int ExpressionUnderCursor::previousBlockState(const QTextBlock &block) return 0; } -QString ExpressionUnderCursor::operator()(const QTextCursor &cursor) +void ExpressionUnderCursor::init(const QTextCursor &cursor, + QList<SimpleToken> *tokens, + QString *text, + int *startPosition) { enum { MAX_BLOCK_COUNT = 5 }; @@ -203,8 +206,6 @@ QString ExpressionUnderCursor::operator()(const QTextCursor &cursor) initialBlock = initialBlock.previous(); } - QString text; - QTextBlock it = initialBlock; for (; it.isValid(); it = it.next()) { QString textBlock = it.text(); @@ -212,18 +213,29 @@ QString ExpressionUnderCursor::operator()(const QTextCursor &cursor) if (it == block) textBlock = textBlock.left(cursor.position() - cursor.block().position()); - text += textBlock; + text->append(textBlock); if (it == block) break; - text += QLatin1Char('\n'); + text->append(QLatin1Char('\n')); } SimpleLexer tokenize; tokenize.setSkipComments(true); - QList<SimpleToken> tokens = tokenize(text, previousBlockState(initialBlock)); - tokens.prepend(SimpleToken()); // sentinel + tokens->append(tokenize(*text, previousBlockState(initialBlock))); + tokens->prepend(SimpleToken()); // sentinel + + if (startPosition) + *startPosition = initialBlock.position(); +} + +QString ExpressionUnderCursor::operator()(const QTextCursor &cursor) +{ + QList<SimpleToken> tokens; + QString text; + + init(cursor, &tokens, &text); _jumpedComma = false; @@ -236,3 +248,28 @@ QString ExpressionUnderCursor::operator()(const QTextCursor &cursor) - tokens.at(i).position()); } +int ExpressionUnderCursor::startOfFunctionCall(const QTextCursor &cursor) +{ + QList<SimpleToken> tokens; + QString text; + int startPosition; + + init(cursor, &tokens, &text, &startPosition); + + int index = tokens.size(); + + forever { + const SimpleToken &tk = tokens.at(index - 1); + + if (tk.is(T_EOF_SYMBOL)) + break; + else if (tk.is(T_LPAREN)) + return startPosition + tk.position(); + else if (tk.is(T_RPAREN)) + index = startOfMatchingBrace(tokens, index); + else + --index; + } + + return -1; +} diff --git a/src/libs/cplusplus/ExpressionUnderCursor.h b/src/libs/cplusplus/ExpressionUnderCursor.h index 843b679cb5ffbf82c3662aa91ca16ce11725f5a7..dda77c406c5ed5944e259b826528d8cb146305bf 100644 --- a/src/libs/cplusplus/ExpressionUnderCursor.h +++ b/src/libs/cplusplus/ExpressionUnderCursor.h @@ -50,8 +50,14 @@ public: ~ExpressionUnderCursor(); QString operator()(const QTextCursor &cursor); + int startOfFunctionCall(const QTextCursor &cursor); private: + void init(const QTextCursor &cursor, + QList<SimpleToken> *tokens, + QString *text, + int *startPosition = 0); + int startOfMatchingBrace(const QList<SimpleToken> &tk, int index); int startOfExpression(const QList<SimpleToken> &tk, int index); int previousBlockState(const QTextBlock &block); diff --git a/src/libs/cplusplus/LookupContext.cpp b/src/libs/cplusplus/LookupContext.cpp index 08c54b19a9d79b667fee0ef694c30b330808c5de..64f6bc1e012532105259f4f39852acb5aa698af8 100644 --- a/src/libs/cplusplus/LookupContext.cpp +++ b/src/libs/cplusplus/LookupContext.cpp @@ -223,9 +223,14 @@ QList<Symbol *> LookupContext::resolve(Name *name, const QList<Scope *> &visible continue; if (q->nameCount() > 1) { - Name *classOrNamespaceName = - control()->qualifiedNameId(q->names(), - q->nameCount() - 1); + Name *classOrNamespaceName = 0; + + if (q->nameCount() == 1) + classOrNamespaceName = q->nameAt(0); + else + classOrNamespaceName = control()->qualifiedNameId(q->names(), + q->nameCount() - 1); + const QList<Symbol *> resolvedClassOrNamespace = resolveClassOrNamespace(classOrNamespaceName, visibleScopes); diff --git a/src/libs/cplusplus/pp-engine.cpp b/src/libs/cplusplus/pp-engine.cpp index 626c888d9ebf7762625a5b5b6483065385e9b315..cc1cd5fff95b56600c91dc8f141ce3f3d81b677c 100644 --- a/src/libs/cplusplus/pp-engine.cpp +++ b/src/libs/cplusplus/pp-engine.cpp @@ -1388,6 +1388,10 @@ bool Preprocessor::isQtReservedWord(const QByteArray ¯oId) const return true; else if (size == 7 && macroId.at(0) == 'Q' && macroId == "Q_SLOTS") return true; + else if (size == 8 && macroId.at(0) == 'Q' && macroId == "Q_SIGNAL") + return true; + else if (size == 6 && macroId.at(0) == 'Q' && macroId == "Q_SLOT") + return true; else if (size == 6 && macroId.at(0) == 'S' && macroId == "SIGNAL") return true; else if (size == 4 && macroId.at(0) == 'S' && macroId == "SLOT") diff --git a/src/libs/utils/consoleprocess.h b/src/libs/utils/consoleprocess.h index 370b256c166dda98b3d031e92f74b4c4655aa736..53c69c91af7206d52c76179b50664a18ef4e4d08 100644 --- a/src/libs/utils/consoleprocess.h +++ b/src/libs/utils/consoleprocess.h @@ -41,8 +41,10 @@ #ifdef Q_OS_WIN #include <windows.h> +QT_BEGIN_NAMESPACE class QWinEventNotifier; class QTemporaryFile; +QT_END_NAMESPACE #endif namespace Core { diff --git a/src/libs/utils/submiteditorwidget.cpp b/src/libs/utils/submiteditorwidget.cpp index 0a283c62a09601499db777837d372d8694c626a9..a9f1c1fe9ae989884c034f688e9cc65ba9ed4cd3 100644 --- a/src/libs/utils/submiteditorwidget.cpp +++ b/src/libs/utils/submiteditorwidget.cpp @@ -147,6 +147,7 @@ SubmitEditorWidget::SubmitEditorWidget(QWidget *parent) : m_d->m_ui.setupUi(this); m_d->m_ui.description->setContextMenuPolicy(Qt::CustomContextMenu); m_d->m_ui.description->setLineWrapMode(QTextEdit::NoWrap); + m_d->m_ui.description->setWordWrapMode(QTextOption::WordWrap); connect(m_d->m_ui.description, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(editorCustomContextMenuRequested(QPoint))); @@ -156,9 +157,6 @@ SubmitEditorWidget::SubmitEditorWidget(QWidget *parent) : connect(m_d->m_ui.fileView, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(diffActivated(QModelIndex))); - // Text - m_d->m_ui.description->setFont(QFont(QLatin1String("Courier"))); - setFocusPolicy(Qt::StrongFocus); setFocusProxy(m_d->m_ui.description); } @@ -168,7 +166,7 @@ SubmitEditorWidget::~SubmitEditorWidget() delete m_d; } -void SubmitEditorWidget::registerActions(QAction *editorUndoAction, QAction *editorRedoAction, +void SubmitEditorWidget::registerActions(QAction *editorUndoAction, QAction *editorRedoAction, QAction *submitAction, QAction *diffAction) { if (editorUndoAction) { diff --git a/src/plugins/cmakeprojectmanager/cmakeprojectmanager.cpp b/src/plugins/cmakeprojectmanager/cmakeprojectmanager.cpp index def15f0bba6ace9e25c2c89f0a5eda5679360d92..0f92c8a53ff9eb1b7b02673758921bd7f86b27d4 100644 --- a/src/plugins/cmakeprojectmanager/cmakeprojectmanager.cpp +++ b/src/plugins/cmakeprojectmanager/cmakeprojectmanager.cpp @@ -40,6 +40,8 @@ #include <QtCore/QtConcurrentRun> #include <QtCore/QSettings> #include <QtGui/QFormLayout> +#include <QtGui/QDesktopServices> +#include <QtGui/QApplication> using namespace CMakeProjectManager::Internal; @@ -134,7 +136,83 @@ QString CMakeManager::findCbpFile(const QDir &directory) return QString::null; } +// This code is duplicated from qtversionmanager +QString CMakeManager::qtVersionForQMake(const QString &qmakePath) +{ + QProcess qmake; + qmake.start(qmakePath, QStringList()<<"--version"); + if (!qmake.waitForFinished()) + return false; + QString output = qmake.readAllStandardOutput(); + QRegExp regexp("(QMake version|Qmake version:)[\\s]*([\\d.]*)"); + regexp.indexIn(output); + if (regexp.cap(2).startsWith("2.")) { + QRegExp regexp2("Using Qt version[\\s]*([\\d\\.]*)"); + regexp2.indexIn(output); + return regexp2.cap(1); + } + return QString(); +} +QString CMakeManager::findQtDir(const ProjectExplorer::Environment &env) +{ + QStringList possibleCommands; + // On windows noone has renamed qmake, right? +#ifdef Q_OS_WIN + possibleCommands << "qmake.exe"; +#endif + // On unix some distributions renamed qmake to avoid clashes + possibleCommands << "qmake-qt4" << "qmake4" << "qmake"; + + QStringList paths = env.path(); + foreach (const QString &path, paths) { + foreach (const QString &possibleCommand, possibleCommands) { + QFileInfo qmake(path + "/" + possibleCommand); + if (qmake.exists()) { + if (!qtVersionForQMake(qmake.absoluteFilePath()).isNull()) { + QDir dir(qmake.absoluteDir()); + dir.cdUp(); + return dir.absolutePath(); + } + } + } + } + return QString(); +} + +// This code is more or less duplicated in qtversionmanager +QString CMakeManager::findDumperLibrary(const ProjectExplorer::Environment &env) +{ + static ProjectExplorer::Environment lastenv; + static QString lastpath; + if (lastenv == env) + return lastpath; + QString qtdir = findQtDir(env); + if (qtdir.isEmpty()) + return QString(); + + uint hash = qHash(qtdir); + QStringList directories; + directories + << (qtdir + "/qtc-debugging-helper/") + << (QApplication::applicationDirPath() + "/../qtc-debugging-helper/" + QString::number(hash)) + "/" + << (QDesktopServices::storageLocation(QDesktopServices::DataLocation) + "/qtc-debugging-helper/" + QString::number(hash)) + "/"; + foreach(const QString &directory, directories) { +#if defined(Q_OS_WIN) + QFileInfo fi(directory + "debug/gdbmacros.dll"); +#elif defined(Q_OS_MAC) + QFileInfo fi(directory + "libgdbmacros.dylib"); +#else // generic UNIX + QFileInfo fi(directory + "libgdbmacros.so"); +#endif + if (fi.exists()) { + lastpath = fi.filePath(); + return lastpath; + } + } + lastpath = QString(); + return lastpath; +} ///// // CMakeRunner diff --git a/src/plugins/cmakeprojectmanager/cmakeprojectmanager.h b/src/plugins/cmakeprojectmanager/cmakeprojectmanager.h index 2188edb6e99b536de5b429392739c45ca95ef2bc..f8c734c01147ad8c1319366bf8a8d85202341e63 100644 --- a/src/plugins/cmakeprojectmanager/cmakeprojectmanager.h +++ b/src/plugins/cmakeprojectmanager/cmakeprojectmanager.h @@ -32,6 +32,7 @@ #include <coreplugin/dialogs/ioptionspage.h> #include <projectexplorer/iprojectmanager.h> +#include <projectexplorer/environment.h> #include <utils/pathchooser.h> #include <QtCore/QFuture> #include <QtCore/QStringList> @@ -60,7 +61,11 @@ public: QProcess* createXmlFile(const QStringList &arguments, const QString &sourceDirectory, const QDir &buildDirectory); static QString findCbpFile(const QDir &); + + static QString findDumperLibrary(const ProjectExplorer::Environment &env); private: + static QString qtVersionForQMake(const QString &qmakePath); + static QString findQtDir(const ProjectExplorer::Environment &env); int m_projectContext; int m_projectLanguage; CMakeSettingsPage *m_settingsPage; diff --git a/src/plugins/cmakeprojectmanager/cmakerunconfiguration.cpp b/src/plugins/cmakeprojectmanager/cmakerunconfiguration.cpp index 28213df1e897948312824f0f89f0a32cc348d723..bef4185ba94aa657e4249da2fde389b7c58774c9 100644 --- a/src/plugins/cmakeprojectmanager/cmakerunconfiguration.cpp +++ b/src/plugins/cmakeprojectmanager/cmakerunconfiguration.cpp @@ -34,6 +34,8 @@ #include <projectexplorer/environment.h> #include <utils/qtcassert.h> +#include <QtGui/QFormLayout> +#include <QtGui/QLineEdit> using namespace CMakeProjectManager; using namespace CMakeProjectManager::Internal; @@ -74,8 +76,7 @@ QString CMakeRunConfiguration::workingDirectory() const QStringList CMakeRunConfiguration::commandLineArguments() const { - // TODO - return QStringList(); + return ProjectExplorer::Environment::parseCombinedArgString(m_arguments); } ProjectExplorer::Environment CMakeRunConfiguration::environment() const @@ -106,6 +107,7 @@ void CMakeRunConfiguration::save(ProjectExplorer::PersistentSettingsWriter &writ writer.saveValue("CMakeRunConfiguration.WorkingDirectory", m_workingDirectory); writer.saveValue("CMakeRunConfiguration.UseTerminal", m_runMode == Console); writer.saveValue("CMakeRunConfiguation.Title", m_title); + writer.saveValue("CMakeRunConfiguration.Arguments", m_arguments); } void CMakeRunConfiguration::restore(const ProjectExplorer::PersistentSettingsReader &reader) @@ -115,12 +117,30 @@ void CMakeRunConfiguration::restore(const ProjectExplorer::PersistentSettingsRea m_workingDirectory = reader.restoreValue("CMakeRunConfiguration.WorkingDirectory").toString(); m_runMode = reader.restoreValue("CMakeRunConfiguration.UseTerminal").toBool() ? Console : Gui; m_title = reader.restoreValue("CMakeRunConfiguation.Title").toString(); + m_arguments = reader.restoreValue("CMakeRunConfiguration.Arguments").toString(); } QWidget *CMakeRunConfiguration::configurationWidget() { - //TODO - return new QWidget(); + QWidget *widget = new QWidget(); + QFormLayout *fl = new QFormLayout(); + widget->setLayout(fl); + QLineEdit *argumentsLineEdit = new QLineEdit(widget); + argumentsLineEdit->setText(m_arguments); + connect(argumentsLineEdit, SIGNAL(textChanged(QString)), + this, SLOT(setArguments(QString))); + fl->addRow(tr("Arguments:"), argumentsLineEdit); + return widget; +} + +void CMakeRunConfiguration::setArguments(const QString &newText) +{ + m_arguments = newText; +} + +QString CMakeRunConfiguration::dumperLibrary() const +{ + return CMakeManager::findDumperLibrary(environment()); } // Factory diff --git a/src/plugins/cmakeprojectmanager/cmakerunconfiguration.h b/src/plugins/cmakeprojectmanager/cmakerunconfiguration.h index d2a142ff9f498b4533c3c5ef4f930d3564a77ee5..f014894a67df02e7d513a83f4146f8b16cfbc583 100644 --- a/src/plugins/cmakeprojectmanager/cmakerunconfiguration.h +++ b/src/plugins/cmakeprojectmanager/cmakerunconfiguration.h @@ -41,6 +41,7 @@ class CMakeProject; class CMakeRunConfiguration : public ProjectExplorer::ApplicationRunConfiguration { + Q_OBJECT public: CMakeRunConfiguration(CMakeProject *pro, const QString &target, const QString &workingDirectory, const QString &title); virtual ~CMakeRunConfiguration(); @@ -59,11 +60,16 @@ public: virtual void save(ProjectExplorer::PersistentSettingsWriter &writer) const; virtual void restore(const ProjectExplorer::PersistentSettingsReader &reader); + virtual QString dumperLibrary() const; + +private slots: + void setArguments(const QString &newText); private: RunMode m_runMode; QString m_target; QString m_workingDirectory; QString m_title; + QString m_arguments; }; /* The run configuration factory is used for restoring run configurations from diff --git a/src/plugins/cppeditor/CppEditor.mimetypes.xml b/src/plugins/cppeditor/CppEditor.mimetypes.xml index 05e3da804c9bb748026db411487aa1f01b386510..c80af9efcaa4fe3c43271584c9c8639ae92f188b 100644 --- a/src/plugins/cppeditor/CppEditor.mimetypes.xml +++ b/src/plugins/cppeditor/CppEditor.mimetypes.xml @@ -43,6 +43,7 @@ <glob pattern="*.c++"/> <glob pattern="*.C"/> <glob pattern="*.inl"/> + <glob pattern="*.moc"/> <glob pattern="*.qdoc"/> </mime-type> diff --git a/src/plugins/cppeditor/cppeditor.cpp b/src/plugins/cppeditor/cppeditor.cpp index 9990547838a4a1b283096830b03f36e685e79d92..fea6fd3ed8d305b8eea34b69bc4524d9a1976f7f 100644 --- a/src/plugins/cppeditor/cppeditor.cpp +++ b/src/plugins/cppeditor/cppeditor.cpp @@ -47,6 +47,7 @@ #include <cplusplus/Overview.h> #include <cplusplus/OverviewModel.h> #include <cplusplus/SimpleLexer.h> +#include <cplusplus/TokenUnderCursor.h> #include <cplusplus/TypeOfExpression.h> #include <cpptools/cppmodelmanagerinterface.h> @@ -182,13 +183,13 @@ CPPEditorEditable::CPPEditorEditable(CPPEditor *editor) CPPEditor::CPPEditor(QWidget *parent) : TextEditor::BaseTextEditor(parent) + , m_showingLink(false) { setParenthesesMatchingEnabled(true); setMarksVisible(true); setCodeFoldingSupported(true); setCodeFoldingVisible(true); baseTextDocument()->setSyntaxHighlighter(new CppHighlighter); -// new QShortcut(QKeySequence("Ctrl+Alt+M"), this, SLOT(foo()), 0, Qt::WidgetShortcut); #ifdef WITH_TOKEN_MOVE_POSITION new QShortcut(QKeySequence::MoveToPreviousWord, this, SLOT(moveToPreviousToken()), @@ -235,7 +236,7 @@ void CPPEditor::createToolBar(CPPEditorEditable *editable) policy.setHorizontalPolicy(QSizePolicy::Expanding); m_methodCombo->setSizePolicy(policy); - QTreeView *methodView = new OverviewTreeView(); + QTreeView *methodView = new OverviewTreeView; methodView->header()->hide(); methodView->setItemsExpandable(false); m_methodCombo->setView(methodView); @@ -586,7 +587,8 @@ void CPPEditor::switchDeclarationDefinition() } } -CPPEditor::Link CPPEditor::findLinkAt(const QTextCursor &cursor) +CPPEditor::Link CPPEditor::findLinkAt(const QTextCursor &cursor, + bool lookupDefinition) { Link link; @@ -627,13 +629,15 @@ CPPEditor::Link CPPEditor::findLinkAt(const QTextCursor &cursor) tc.movePosition(QTextCursor::PreviousWord, QTextCursor::KeepAnchor); const int nameStart = tc.position(); const int nameLength = tc.anchor() - tc.position(); + tc.setPosition(endOfName); - // Drop out if we're at a number - if (characterAt(nameStart).isNumber()) + // Drop out if we're at a number, string or comment + static TokenUnderCursor tokenUnderCursor; + const SimpleToken tk = tokenUnderCursor(tc); + if (tk.isLiteral() || tk.isComment()) return link; // Evaluate the type of the expression under the cursor - tc.setPosition(endOfName); ExpressionUnderCursor expressionUnderCursor; const QString expression = expressionUnderCursor(tc); TypeOfExpression typeOfExpression; @@ -642,10 +646,22 @@ CPPEditor::Link CPPEditor::findLinkAt(const QTextCursor &cursor) typeOfExpression(expression, doc, lastSymbol); if (!resolvedSymbols.isEmpty()) { - Symbol *symbol = resolvedSymbols.first().second; - if (symbol) { + TypeOfExpression::Result result = resolvedSymbols.first(); + + if (result.first->isForwardClassDeclarationType()) { + while (! resolvedSymbols.isEmpty()) { + TypeOfExpression::Result r = resolvedSymbols.takeFirst(); + + if (! r.first->isForwardClassDeclarationType()) { + result = r; + break; + } + } + } + + if (Symbol *symbol = result.second) { Symbol *def = 0; - if (!lastSymbol->isFunction()) + if (lookupDefinition && !lastSymbol->isFunction()) def = findDefinition(symbol); link = linkToSymbol(def ? def : symbol); @@ -804,8 +820,7 @@ void CPPEditor::contextMenuEvent(QContextMenuEvent *e) void CPPEditor::mouseMoveEvent(QMouseEvent *e) { - bool hasDestination = false; - Qt::CursorShape cursorShape; + bool linkFound = false; if (e->modifiers() & Qt::ControlModifier) { // Link emulation behaviour for 'go to definition' @@ -819,33 +834,18 @@ void CPPEditor::mouseMoveEvent(QMouseEvent *e) onText = cursorRect(nextPos).right() >= e->x(); } - const Link link = findLinkAt(cursor); + const Link link = findLinkAt(cursor, false); if (onText && !link.fileName.isEmpty()) { - QTextEdit::ExtraSelection sel; - sel.cursor = cursor; - if (link.pos >= 0) { - sel.cursor.setPosition(link.pos); - sel.cursor.setPosition(link.pos + link.length, QTextCursor::KeepAnchor); - } else { - sel.cursor.select(QTextCursor::WordUnderCursor); - } - sel.format.setFontUnderline(true); - sel.format.setForeground(Qt::blue); - setExtraSelections(OtherSelection, QList<QTextEdit::ExtraSelection>() << sel); - hasDestination = true; - cursorShape = Qt::PointingHandCursor; + showLink(link); + linkFound = true; } } - if (!hasDestination) { - setExtraSelections(OtherSelection, QList<QTextEdit::ExtraSelection>()); - cursorShape = Qt::IBeamCursor; - } + if (!linkFound) + clearLink(); TextEditor::BaseTextEditor::mouseMoveEvent(e); - - viewport()->setCursor(cursorShape); } void CPPEditor::mouseReleaseEvent(QMouseEvent *e) @@ -855,8 +855,7 @@ void CPPEditor::mouseReleaseEvent(QMouseEvent *e) const QTextCursor cursor = cursorForPosition(e->pos()); if (openCppEditorAt(findLinkAt(cursor))) { - setExtraSelections(OtherSelection, QList<QTextEdit::ExtraSelection>()); - viewport()->setCursor(Qt::IBeamCursor); + clearLink(); e->accept(); return; } @@ -865,13 +864,42 @@ void CPPEditor::mouseReleaseEvent(QMouseEvent *e) TextEditor::BaseTextEditor::mouseReleaseEvent(e); } +void CPPEditor::leaveEvent(QEvent *e) +{ + clearLink(); + TextEditor::BaseTextEditor::leaveEvent(e); +} + void CPPEditor::keyReleaseEvent(QKeyEvent *e) { // Clear link emulation when Ctrl is released - if (e->key() == Qt::Key_Control) { - setExtraSelections(OtherSelection, QList<QTextEdit::ExtraSelection>()); - viewport()->setCursor(Qt::IBeamCursor); - } + if (e->key() == Qt::Key_Control) + clearLink(); + + TextEditor::BaseTextEditor::keyReleaseEvent(e); +} + +void CPPEditor::showLink(const Link &link) +{ + QTextEdit::ExtraSelection sel; + sel.cursor = textCursor(); + sel.cursor.setPosition(link.pos); + sel.cursor.setPosition(link.pos + link.length, QTextCursor::KeepAnchor); + sel.format = m_linkFormat; + sel.format.setFontUnderline(true); + setExtraSelections(OtherSelection, QList<QTextEdit::ExtraSelection>() << sel); + viewport()->setCursor(Qt::PointingHandCursor); + m_showingLink = true; +} + +void CPPEditor::clearLink() +{ + if (!m_showingLink) + return; + + setExtraSelections(OtherSelection, QList<QTextEdit::ExtraSelection>()); + viewport()->setCursor(Qt::IBeamCursor); + m_showingLink = false; } QList<int> CPPEditorEditable::context() const @@ -916,6 +944,8 @@ void CPPEditor::setFontSettings(const TextEditor::FontSettings &fs) const QVector<QTextCharFormat> formats = fs.toTextCharFormats(categories); highlighter->setFormats(formats.constBegin(), formats.constEnd()); highlighter->rehighlight(); + + m_linkFormat = fs.toTextCharFormat(QLatin1String(TextEditor::Constants::C_LINK)); } diff --git a/src/plugins/cppeditor/cppeditor.h b/src/plugins/cppeditor/cppeditor.h index 35a46cb0c7249fbc8918e724fcb34f5979304d7c..bd30f3031f9dd72a1fd172e7ff0202d44e43894a 100644 --- a/src/plugins/cppeditor/cppeditor.h +++ b/src/plugins/cppeditor/cppeditor.h @@ -99,6 +99,7 @@ protected: void contextMenuEvent(QContextMenuEvent *); void mouseMoveEvent(QMouseEvent *); void mouseReleaseEvent(QMouseEvent *); + void leaveEvent(QEvent *); void keyReleaseEvent(QKeyEvent *); TextEditor::BaseTextEditorEditable *createEditableInterface(); @@ -148,9 +149,14 @@ private: int column; // Target column }; - Link findLinkAt(const QTextCursor &); + void showLink(const Link &); + void clearLink(); + bool m_showingLink; + + Link findLinkAt(const QTextCursor &, bool lookupDefinition = true); static Link linkToSymbol(CPlusPlus::Symbol *symbol); bool openCppEditorAt(const Link &); + QTextCharFormat m_linkFormat; CppTools::CppModelManagerInterface *m_modelManager; diff --git a/src/plugins/cpptools/cppcodecompletion.cpp b/src/plugins/cpptools/cppcodecompletion.cpp index 6157204867fb29585d7214ce28d8a9daef33229d..3813744774c2f91c9a370cb3354a44d9b1ba9afd 100644 --- a/src/plugins/cpptools/cppcodecompletion.cpp +++ b/src/plugins/cpptools/cppcodecompletion.cpp @@ -60,10 +60,11 @@ #include <QtCore/QMap> #include <QtCore/QFile> #include <QtGui/QAction> +#include <QtGui/QApplication> #include <QtGui/QKeyEvent> #include <QtGui/QLabel> +#include <QtGui/QToolButton> #include <QtGui/QVBoxLayout> -#include <QtGui/QApplication> using namespace CPlusPlus; @@ -72,25 +73,38 @@ namespace Internal { class FunctionArgumentWidget : public QLabel { + Q_OBJECT + public: FunctionArgumentWidget(); - void showFunctionHint(Function *functionSymbol, const LookupContext &context); + void showFunctionHint(QList<Function *> functionSymbols, + const LookupContext &context, + int startPosition); protected: bool eventFilter(QObject *obj, QEvent *e); +private slots: + void nextPage(); + void previousPage(); + private: void update(); void close(); void updateHintText(); + Function *currentFunction() const + { return m_items.at(m_current); } + int m_startpos; int m_currentarg; + int m_current; TextEditor::ITextEditor *m_editor; + QWidget *m_pager; QFrame *m_popupFrame; - Function *m_item; + QList<Function *> m_items; LookupContext m_context; }; @@ -180,55 +194,104 @@ protected: using namespace CppTools::Internal; -FunctionArgumentWidget::FunctionArgumentWidget() - : m_item(0) +FunctionArgumentWidget::FunctionArgumentWidget(): + m_startpos(-1), + m_current(0) { QObject *editorObject = Core::EditorManager::instance()->currentEditor(); m_editor = qobject_cast<TextEditor::ITextEditor *>(editorObject); - m_popupFrame = new QFrame(0, Qt::ToolTip | Qt::WindowStaysOnTopHint); + m_popupFrame = new QFrame(m_editor->widget(), Qt::ToolTip | Qt::WindowStaysOnTopHint); m_popupFrame->setFocusPolicy(Qt::NoFocus); m_popupFrame->setAttribute(Qt::WA_DeleteOnClose); - setFrameStyle(QFrame::Box); - setFrameShadow(QFrame::Plain); + QToolButton *leftArrow = new QToolButton; + leftArrow->setArrowType(Qt::LeftArrow); + leftArrow->setFixedSize(16, 16); + leftArrow->setAutoRaise(true); + + QToolButton *rightArrow = new QToolButton; + rightArrow->setArrowType(Qt::RightArrow); + rightArrow->setFixedSize(16, 16); + rightArrow->setAutoRaise(true); + + m_popupFrame->setFrameStyle(QFrame::Box); + m_popupFrame->setFrameShadow(QFrame::Plain); setParent(m_popupFrame); setFocusPolicy(Qt::NoFocus); + m_pager = new QWidget; + QHBoxLayout *hbox = new QHBoxLayout(m_pager); + hbox->setMargin(0); + hbox->setSpacing(0); + hbox->addSpacerItem(new QSpacerItem(0, 0, QSizePolicy::MinimumExpanding, QSizePolicy::Minimum)); + hbox->addWidget(leftArrow); + hbox->addWidget(rightArrow); + QVBoxLayout *layout = new QVBoxLayout; - layout->addWidget(this); layout->setMargin(0); + layout->setSpacing(0); + layout->addWidget(m_pager); + layout->addWidget(this); m_popupFrame->setLayout(layout); - QPalette pal = palette(); + connect(leftArrow, SIGNAL(clicked()), SLOT(previousPage())); + connect(rightArrow, SIGNAL(clicked()), SLOT(nextPage())); + + QPalette pal = m_popupFrame->palette(); setAutoFillBackground(true); pal.setColor(QPalette::Background, QColor(255, 255, 220)); - setPalette(pal); + m_popupFrame->setPalette(pal); setTextFormat(Qt::RichText); setMargin(1); + + qApp->installEventFilter(this); } -void FunctionArgumentWidget::showFunctionHint(Function *functionSymbol, - const LookupContext &context) +void FunctionArgumentWidget::showFunctionHint(QList<Function *> functionSymbols, + const LookupContext &context, + int startPosition) { + Q_ASSERT(!functionSymbols.isEmpty()); + + if (m_startpos == startPosition) + return; + m_popupFrame->hide(); - m_item = functionSymbol; + m_items = functionSymbols; m_context = context; - m_startpos = m_editor->position(); + m_startpos = startPosition; + m_current = 0; // update the text m_currentarg = -1; update(); - QPoint pos = m_editor->cursorRect().topLeft(); - pos.setY(pos.y() - sizeHint().height()); + m_pager->setVisible(functionSymbols.size() > 1); + + QPoint pos = m_editor->cursorRect(m_startpos).topLeft(); + pos.setY(pos.y() - m_popupFrame->sizeHint().height() - 1); m_popupFrame->move(pos); m_popupFrame->show(); +} - qApp->installEventFilter(this); +void FunctionArgumentWidget::nextPage() +{ + m_current = (m_current + 1) % m_items.size(); + updateHintText(); +} + +void FunctionArgumentWidget::previousPage() +{ + if (m_current == 0) + m_current = m_items.size() - 1; + else + --m_current; + + updateHintText(); } void FunctionArgumentWidget::update() @@ -276,22 +339,26 @@ bool FunctionArgumentWidget::eventFilter(QObject *obj, QEvent *e) break; } case QEvent::WindowDeactivate: - case QEvent::Leave: case QEvent::FocusOut: { if (obj != m_editor->widget()) break; } + close(); + break; case QEvent::MouseButtonPress: case QEvent::MouseButtonRelease: case QEvent::MouseButtonDblClick: - case QEvent::Wheel: - close(); + case QEvent::Wheel: { + QWidget *widget = qobject_cast<QWidget *>(obj); + if (! (widget == this || m_popupFrame->isAncestorOf(widget))) { + close(); + } + } break; default: break; } - return false; } @@ -306,8 +373,8 @@ void FunctionArgumentWidget::updateHintText() overview.setShowReturnTypes(true); overview.setShowArgumentNames(true); overview.setMarkArgument(m_currentarg + 1); - QString text = overview(m_item->type(), m_item->name()); - setText(text); + Function *f = currentFunction(); + setText(overview(f->type(), f->name())); } CppCodeCompletion::CppCodeCompletion(CppModelManager *manager) @@ -372,10 +439,13 @@ static int startOfOperator(TextEditor::ITextEditable *editor, if (ch2 != QLatin1Char('.') && ch == QLatin1Char('.')) { k = T_DOT; --start; + } else if (ch == QLatin1Char(',')) { + k = T_COMMA; + --start; } else if (wantFunctionCall && ch == QLatin1Char('(')) { k = T_LPAREN; --start; - } else if (ch2 == QLatin1Char(':') && ch == QLatin1Char(':')) { + } else if (ch3 != QLatin1Char(':') && ch2 == QLatin1Char(':') && ch == QLatin1Char(':')) { k = T_COLON_COLON; start -= 2; } else if (ch2 == QLatin1Char('-') && ch == QLatin1Char('>')) { @@ -406,7 +476,6 @@ static int startOfOperator(TextEditor::ITextEditable *editor, k = T_EOF_SYMBOL; start = pos; } - else if (tk.is(T_COMMENT) || tk.isLiteral()) { k = T_EOF_SYMBOL; start = pos; @@ -458,10 +527,6 @@ int CppCodeCompletion::startCompletion(TextEditor::ITextEditable *editor) edit->convertPosition(editor->position(), &line, &column); // qDebug() << "line:" << line << "column:" << column; - ExpressionUnderCursor expressionUnderCursor; - QString expression; - - if (m_completionOperator == T_DOXY_COMMENT) { for (int i = 1; i < T_DOXY_LAST_TAG; ++i) { TextEditor::CompletionItem item(this); @@ -473,11 +538,23 @@ int CppCodeCompletion::startCompletion(TextEditor::ITextEditable *editor) return m_startPosition; } + ExpressionUnderCursor expressionUnderCursor; + QTextCursor tc(edit->document()); - if (m_completionOperator) { - QTextCursor tc(edit->document()); + if (m_completionOperator == T_COMMA) { tc.setPosition(endOfExpression); + const int start = expressionUnderCursor.startOfFunctionCall(tc); + if (start != -1) { + endOfExpression = start; + m_startPosition = start + 1; + m_completionOperator = T_LPAREN; + } + } + QString expression; + tc.setPosition(endOfExpression); + + if (m_completionOperator) { expression = expressionUnderCursor(tc); if (m_completionOperator == T_LPAREN) { @@ -491,12 +568,12 @@ int CppCodeCompletion::startCompletion(TextEditor::ITextEditable *editor) // We don't want a function completion when the cursor isn't at the opening brace expression.clear(); m_completionOperator = T_EOF_SYMBOL; + m_startPosition = editor->position(); } } } - //if (! expression.isEmpty()) - //qDebug() << "***** expression:" << expression; + //qDebug() << "***** expression:" << expression; const Snapshot snapshot = m_manager->snapshot(); @@ -591,6 +668,8 @@ bool CppCodeCompletion::completeConstructorOrFunction(const QList<TypeOfExpressi o.setShowReturnTypes(true); o.setShowArgumentNames(true); + QList<Function *> functions; + foreach (const TypeOfExpression::Result &result, results) { FullySpecifiedType exprTy = result.first; @@ -604,8 +683,7 @@ bool CppCodeCompletion::completeConstructorOrFunction(const QList<TypeOfExpressi else if (! member->identity()->isEqualTo(klass->identity())) continue; if (TextEditor::CompletionItem item = toCompletionItem(member)) { - item.m_text = o(member->type(), member->name()); - m_completions.append(item); + functions.append(member->type()->asFunctionType()); } } @@ -613,7 +691,7 @@ bool CppCodeCompletion::completeConstructorOrFunction(const QList<TypeOfExpressi } } - if (m_completions.isEmpty()) { + if (functions.isEmpty()) { QSet<QString> signatures; foreach (const TypeOfExpression::Result &p, results) { @@ -628,18 +706,23 @@ bool CppCodeCompletion::completeConstructorOrFunction(const QList<TypeOfExpressi continue; signatures.insert(signature); - item.m_text = o(ty, fun->name()); - m_completions.append(item); + functions.append(fun); } } } } - // If there is only one item, show the function argument widget immediately - if (m_completions.size() == 1) - complete(m_completions.takeFirst()); + if (! functions.isEmpty()) { + // Recreate if necessary + if (!m_functionArgumentWidget) + m_functionArgumentWidget = new FunctionArgumentWidget; - return ! m_completions.isEmpty(); + m_functionArgumentWidget->showFunctionHint(functions, + typeOfExpression.lookupContext(), + m_startPosition); + } + + return false; } bool CppCodeCompletion::completeMember(const QList<TypeOfExpression::Result> &results, @@ -1084,20 +1167,7 @@ void CppCodeCompletion::complete(const TextEditor::CompletionItem &item) if (item.m_data.isValid()) symbol = item.m_data.value<Symbol *>(); - // qDebug() << "*** complete symbol:" << symbol->fileName() << symbol->line(); - - if (m_completionOperator == T_LPAREN) { - if (symbol) { - Function *function = symbol->type()->asFunctionType(); - QTC_ASSERT(function, return); - - // Recreate if necessary - if (!m_functionArgumentWidget) - m_functionArgumentWidget = new FunctionArgumentWidget; - - m_functionArgumentWidget->showFunctionHint(function, typeOfExpression.lookupContext()); - } - } else if (m_completionOperator == T_SIGNAL || m_completionOperator == T_SLOT) { + if (m_completionOperator == T_SIGNAL || m_completionOperator == T_SLOT) { QString toInsert = item.m_text; toInsert += QLatin1Char(')'); // Insert the remainder of the name @@ -1217,3 +1287,5 @@ int CppCodeCompletion::findStartOfName(int pos) const return pos + 1; } + +#include "cppcodecompletion.moc" diff --git a/src/plugins/debugger/breakwindow.cpp b/src/plugins/debugger/breakwindow.cpp index 92fe3c7cb1595b3f93decd8386021f70b74dbb0f..308d565a3e9d89c421e2f4fde8cbfd9879f40055 100644 --- a/src/plugins/debugger/breakwindow.cpp +++ b/src/plugins/debugger/breakwindow.cpp @@ -101,6 +101,7 @@ void BreakWindow::contextMenuEvent(QContextMenuEvent *ev) menu.addAction(act1); menu.addAction(act2); menu.addAction(act4); + menu.addSeparator(); menu.addAction(theDebuggerAction(SettingsDialog)); QAction *act = menu.exec(ev->globalPos()); diff --git a/src/plugins/debugger/cdb/cdb.pri b/src/plugins/debugger/cdb/cdb.pri index 527cd0be298b8ba69a5f06abd83437218a5934f4..27186577c3041746f0c48c5952df1c72d3daba6b 100644 --- a/src/plugins/debugger/cdb/cdb.pri +++ b/src/plugins/debugger/cdb/cdb.pri @@ -1,5 +1,8 @@ +# Detect presence of "Debugging Tools For Windows" +# in case VS compilers are used. + win32 { -# ---- Detect Debugging Tools For Windows +contains(QMAKE_CXX, cl) { CDB_PATH="$$(ProgramFiles)/Debugging Tools For Windows/sdk" @@ -26,6 +29,7 @@ SOURCES += \ $$PWD/cdbdebugeventcallback.cpp \ $$PWD/cdbdebugoutput.cpp } else { - error("Debugging Tools for Windows could not be found in $$CDB_PATH") + message("Debugging Tools for Windows could not be found in $$CDB_PATH") +} } } diff --git a/src/plugins/debugger/cdb/cdbdebugengine.cpp b/src/plugins/debugger/cdb/cdbdebugengine.cpp index efaa12d2b98a8e6b6c8d0a32966d6bced247bf11..73d3953ffb3a51dc3a83ea0fa91bbe11917923a0 100644 --- a/src/plugins/debugger/cdb/cdbdebugengine.cpp +++ b/src/plugins/debugger/cdb/cdbdebugengine.cpp @@ -34,6 +34,7 @@ #include "breakhandler.h" #include "stackhandler.h" #include "watchhandler.h" +#include "watchutils.h" #include <utils/qtcassert.h> #include <utils/winutils.h> @@ -360,6 +361,16 @@ bool CdbDebugEngine::startDebuggerWithExecutable(DebuggerStartMode sm, QString * return true; } +void CdbDebugEngine::processTerminated(unsigned long exitCode) +{ + if (debugCDB) + qDebug() << Q_FUNC_INFO << exitCode; + + m_d->setDebuggeeHandles(0, 0); + m_d->m_debuggerManagerAccess->notifyInferiorExited(); + m_d->m_debuggerManager->exitDebugger(); +} + void CdbDebugEngine::exitDebugger() { if (debugCDB) @@ -380,7 +391,9 @@ void CdbDebugEngine::exitDebugger() break; case StartExternal: case StartInternal: + // Terminate and waitr for stop events. hr = m_d->m_pDebugClient->TerminateCurrentProcess(); + QCoreApplication::processEvents(QEventLoop::ExcludeUserInputEvents); if (debugCDB) qDebug() << Q_FUNC_INFO << "terminated" << msgDebugEngineComResult(hr); @@ -394,6 +407,49 @@ void CdbDebugEngine::exitDebugger() killWatchTimer(); } +// Retrieve a symbol +static WatchData symbolToWatchData(ULONG index, const QString &namePrefix, + IDebugSymbolGroup2 *pDbgSymGroup) +{ + // retrieve symbol names and value strings + ULONG nameLength; + static WCHAR nameBuffer[MAX_PATH + 1]; + // Name + pDbgSymGroup->GetSymbolNameWide(index, nameBuffer, MAX_PATH, &nameLength); + nameBuffer[nameLength] = 0; + const QString name = QString::fromUtf16(nameBuffer); + // Type name + pDbgSymGroup->GetSymbolTypeNameWide(index, nameBuffer, MAX_PATH, &nameLength); + nameBuffer[nameLength] = 0; + const QString type = QString::fromUtf16(nameBuffer); + // Value + QString value; + const HRESULT hr = pDbgSymGroup->GetSymbolValueTextWide(index, nameBuffer, MAX_PATH, &nameLength); + if (SUCCEEDED(hr)) { + nameBuffer[nameLength] = 0; + value = QString::fromUtf16(nameBuffer); + } else { + value = QLatin1String("<unknown>"); + } + WatchData wd; + wd.iname =namePrefix + name; + wd.name = name; + wd.value = value; + wd.type = type; + if (isPointerType(type)) { + wd.setTypeUnneeded(); + wd.setValueUnneeded(); + } else { + wd.setAllUnneeded(); + } + if (debugCDB) { + qDebug() << Q_FUNC_INFO << index << "state=0x" << QString::number(wd.state, 16) + << wd.name << " type=" << wd.type << " (" << type << ')' + << " value " << wd.value << " (" << value << ')'; + } + return wd; +} + bool CdbDebugEnginePrivate::updateLocals(int frameIndex, WatchHandler *wh, QString *errorMessage) @@ -447,36 +503,17 @@ bool CdbDebugEnginePrivate::updateLocals(int frameIndex, break; } wh->cleanup(); - // retrieve symbol names and value strings - ULONG nameLength; - WCHAR nameBuffer[MAX_PATH + 1]; + // retrieve symbol names and value strings. + // Add a dummy place holder in case children are needed + const QString localPrefix = QLatin1String("local."); for (ULONG s = 0 ; s < symbolCount ; s++ ) { - // Name - pDbgSymGroup->GetSymbolNameWide(s, nameBuffer, MAX_PATH, &nameLength); - nameBuffer[nameLength] = 0; - const QString name = QString::fromUtf16(nameBuffer); - // Type name - pDbgSymGroup->GetSymbolTypeNameWide(s, nameBuffer, MAX_PATH, &nameLength); - nameBuffer[nameLength] = 0; - const QString type = QString::fromUtf16(nameBuffer); - // Value - QString value; - hr = pDbgSymGroup->GetSymbolValueTextWide(s, nameBuffer, MAX_PATH, &nameLength); - if (SUCCEEDED(hr)) { - nameBuffer[nameLength] = 0; - value = QString::fromUtf16(nameBuffer); - } else { - value = QLatin1String("<unknown>"); + WatchData wd = symbolToWatchData(s, localPrefix, pDbgSymGroup); + if (wd.isSomethingNeeded()) { + wh->insertData(wd.pointerChildPlaceHolder()); + wd.setAllUnneeded(); + wd.setChildCount(1); } - WatchData wd; - wd.iname = QLatin1String("local"); - wd.name = name; - wd.value = value; - wd.type = type; - wd.setAllUnneeded(); wh->insertData(wd); - if (debugCDB) - qDebug() << ' ' << s << '/'<< symbolCount << name << type << value; } wh->rebuildModel(); success = true; @@ -592,6 +629,7 @@ void CdbDebugEngine::continueInferior() m_d->m_debuggerManager->resetLocation(); ULONG executionStatus; + m_d->m_debuggerManagerAccess->notifyInferiorRunningRequested(); HRESULT hr = m_d->m_pDebugControl->GetExecutionStatus(&executionStatus); if (SUCCEEDED(hr) && executionStatus != DEBUG_STATUS_GO) { hr = m_d->m_pDebugControl->SetExecutionStatus(DEBUG_STATUS_GO); @@ -654,8 +692,10 @@ void CdbDebugEngine::activateFrame(int frameIndex) if (debugCDB) qDebug() << Q_FUNC_INFO << frameIndex; - if (m_d->m_debuggerManager->status() != DebuggerInferiorStopped) + if (m_d->m_debuggerManager->status() != DebuggerInferiorStopped) { + qWarning("WARNING %s: invoked while debuggee is running\n", Q_FUNC_INFO); return; + } QString errorMessage; bool success = false; @@ -793,7 +833,7 @@ void CdbDebugEngine::timerEvent(QTimerEvent* te) const HRESULT hr = m_d->m_pDebugControl->WaitForEvent(0, 1); if (debugCDB) if (debugCDB > 1 || hr != S_FALSE) - qDebug() << Q_FUNC_INFO << "WaitForEvent" << msgDebugEngineComResult(hr); + qDebug() << Q_FUNC_INFO << "WaitForEvent" << m_d->m_debuggerManager->status() << msgDebugEngineComResult(hr); switch (hr) { case S_OK: @@ -974,9 +1014,10 @@ void CdbDebugEnginePrivate::updateStackTrace() } } -void CdbDebugEnginePrivate::handleDebugOutput(const char* szOutputString) +void CdbDebugEnginePrivate::handleDebugOutput(const char *szOutputString) { - qDebug() << Q_FUNC_INFO << szOutputString; + if (debugCDB && strstr(szOutputString, "ModLoad:") == 0) + qDebug() << Q_FUNC_INFO << szOutputString; m_debuggerManagerAccess->showApplicationOutput(QString::fromLocal8Bit(szOutputString)); } diff --git a/src/plugins/debugger/cdb/cdbdebugengine.h b/src/plugins/debugger/cdb/cdbdebugengine.h index 59ebeed571efb3145d10240490d6226d9021a626..0662a8350a091494acc71715e16fea72f65f0d4d 100644 --- a/src/plugins/debugger/cdb/cdbdebugengine.h +++ b/src/plugins/debugger/cdb/cdbdebugengine.h @@ -104,6 +104,7 @@ private: bool startDebuggerWithExecutable(DebuggerStartMode sm, QString *errorMessage); void startWatchTimer(); void killWatchTimer(); + void processTerminated(unsigned long exitCode); CdbDebugEnginePrivate *m_d; diff --git a/src/plugins/debugger/cdb/cdbdebugeventcallback.cpp b/src/plugins/debugger/cdb/cdbdebugeventcallback.cpp index c0f6cd80a40984e224ee5761cc0bb62497de8b39..ee8120f3e53c6ed767ddb1a4b03eceaa489da2fc 100644 --- a/src/plugins/debugger/cdb/cdbdebugeventcallback.cpp +++ b/src/plugins/debugger/cdb/cdbdebugeventcallback.cpp @@ -192,9 +192,7 @@ STDMETHODIMP CdbDebugEventCallback::ExitProcess( { if (debugCDB) qDebug() << Q_FUNC_INFO << ExitCode; - - m_pEngine->m_d->setDebuggeeHandles(0, 0); - m_pEngine->m_d->m_debuggerManagerAccess->notifyInferiorExited(); + m_pEngine->processTerminated(ExitCode); return S_OK; } diff --git a/src/plugins/debugger/debugger.pro b/src/plugins/debugger/debugger.pro index c86d3793014db99b92085c0ee58455d4ad4cc925..f6388fa835947b36a5fa3d9c348bad86bb1eb47c 100644 --- a/src/plugins/debugger/debugger.pro +++ b/src/plugins/debugger/debugger.pro @@ -26,6 +26,7 @@ HEADERS += \ debuggerrunner.h \ disassemblerhandler.h \ disassemblerwindow.h \ + watchutils.h \ gdbengine.h \ gdbmi.h \ idebuggerengine.h \ @@ -56,6 +57,7 @@ SOURCES += \ debuggerrunner.cpp \ disassemblerhandler.cpp \ disassemblerwindow.cpp \ + watchutils.cpp \ gdbengine.cpp \ gdbmi.cpp \ moduleshandler.cpp \ diff --git a/src/plugins/debugger/debuggeractions.cpp b/src/plugins/debugger/debuggeractions.cpp index f7edac224f73d604c659ee75c8a5d3a7942cadf4..75e84b962054a6a97eacd7b670272b0082244c25 100644 --- a/src/plugins/debugger/debuggeractions.cpp +++ b/src/plugins/debugger/debuggeractions.cpp @@ -34,7 +34,9 @@ #include <QtCore/QDebug> #include <QtCore/QSettings> + #include <QtGui/QAction> +#include <QtGui/QActionGroup> #include <QtGui/QAbstractButton> #include <QtGui/QRadioButton> #include <QtGui/QCheckBox> @@ -253,8 +255,15 @@ void DebuggerAction::pathChooserEditingFinished() void DebuggerAction::actionTriggered(bool) { - if (this->isCheckable()) - setValue(this->isChecked()); + //qDebug() << "TRIGGERING" << this << actionGroup(); + if (isCheckable()) + setValue(isChecked()); + if (actionGroup() && actionGroup()->isExclusive()) { + // FIXME: should be taken care of more directly + foreach (QAction *act, actionGroup()->actions()) + if (DebuggerAction *dact = qobject_cast<DebuggerAction *>(act)) + dact->setValue(bool(act == this)); + } } void DebuggerAction::trigger(const QVariant &data) @@ -331,6 +340,9 @@ DebuggerSettings *theDebuggerSettings() DebuggerAction *item = 0; + // + // View + // item = new DebuggerAction(instance); instance->insertItem(AdjustColumnWidths, item); item->setText(QObject::tr("Adjust column widths to contents")); @@ -340,6 +352,9 @@ DebuggerSettings *theDebuggerSettings() item->setText(QObject::tr("Always adjust column widths to contents")); item->setCheckable(true); + // + // Locals & Watchers + // item = new DebuggerAction(instance); instance->insertItem(WatchExpression, item); item->setTextPattern(QObject::tr("Watch expression \"%1\"")); @@ -356,6 +371,14 @@ DebuggerSettings *theDebuggerSettings() item = new DebuggerAction(instance); instance->insertItem(AssignValue, item); + item = new DebuggerAction(instance); + instance->insertItem(ExpandItem, item); + item->setText(QObject::tr("Expand item")); + + item = new DebuggerAction(instance); + instance->insertItem(CollapseItem, item); + item->setText(QObject::tr("Collapse item")); + // // Dumpers // @@ -369,21 +392,69 @@ DebuggerSettings *theDebuggerSettings() item->setCheckable(true); item = new DebuggerAction(instance); - instance->insertItem(RecheckDumpers, item); item->setText(QObject::tr("Recheck custom dumper availability")); + instance->insertItem(RecheckDumpers, item); // // Breakpoints // item = new DebuggerAction(instance); - instance->insertItem(SynchronizeBreakpoints, item); item->setText(QObject::tr("Syncronize breakpoints")); + instance->insertItem(SynchronizeBreakpoints, item); // + // Registers + // + + QActionGroup *registerFormatGroup = new QActionGroup(instance); + registerFormatGroup->setExclusive(true); + item = new DebuggerAction(instance); - instance->insertItem(AutoQuit, item); - item->setText(QObject::tr("Automatically quit debugger")); + item->setText(QObject::tr("Hexadecimal")); item->setCheckable(true); + item->setSettingsKey("DebugMode", "FormatHexadecimal"); + item->setChecked(true); + instance->insertItem(FormatHexadecimal, item); + registerFormatGroup->addAction(item); + + item = new DebuggerAction(instance); + item->setText(QObject::tr("Decimal")); + item->setCheckable(true); + item->setSettingsKey("DebugMode", "FormatDecimal"); + instance->insertItem(FormatDecimal, item); + registerFormatGroup->addAction(item); + + item = new DebuggerAction(instance); + item->setText(QObject::tr("Octal")); + item->setCheckable(true); + item->setSettingsKey("DebugMode", "FormatOctal"); + instance->insertItem(FormatOctal, item); + registerFormatGroup->addAction(item); + + item = new DebuggerAction(instance); + item->setText(QObject::tr("Binary")); + item->setCheckable(true); + item->setSettingsKey("DebugMode", "FormatBinary"); + instance->insertItem(FormatBinary, item); + registerFormatGroup->addAction(item); + + item = new DebuggerAction(instance); + item->setText(QObject::tr("Raw")); + item->setCheckable(true); + item->setSettingsKey("DebugMode", "FormatRaw"); + instance->insertItem(FormatRaw, item); + registerFormatGroup->addAction(item); + + item = new DebuggerAction(instance); + item->setText(QObject::tr("Natural")); + item->setCheckable(true); + item->setSettingsKey("DebugMode", "FormatNatural"); + instance->insertItem(FormatNatural, item); + registerFormatGroup->addAction(item); + + // + // Misc + // item = new DebuggerAction(instance); instance->insertItem(SkipKnownFrames, item); @@ -417,12 +488,10 @@ DebuggerSettings *theDebuggerSettings() item->setSettingsKey("DebugMode", "ScriptFile"); item = new DebuggerAction(instance); - instance->insertItem(GdbAutoQuit, item); item->setSettingsKey("DebugMode", "AutoQuit"); - - item = new DebuggerAction(instance); - instance->insertItem(GdbAutoRun, item); - item->setSettingsKey("DebugMode", "AutoRun"); + item->setText(QObject::tr("Automatically quit debugger")); + item->setCheckable(true); + instance->insertItem(AutoQuit, item); item = new DebuggerAction(instance); instance->insertItem(UseToolTips, item); @@ -440,6 +509,11 @@ DebuggerSettings *theDebuggerSettings() item->setSettingsKey("DebugMode", "BuildDumpersOnTheFly"); item->setCheckable(true); + item = new DebuggerAction(instance); + instance->insertItem(UseQtDumpers, item); + item->setSettingsKey("DebugMode", "UseQtDumpers"); + item->setCheckable(true); + item = new DebuggerAction(instance); instance->insertItem(UsePrebuiltDumpers, item); item->setSettingsKey("DebugMode", "UsePrebuiltDumpers"); @@ -450,7 +524,7 @@ DebuggerSettings *theDebuggerSettings() item->setSettingsKey("DebugMode", "PrebuiltDumpersLocation"); item = new DebuggerAction(instance); - instance->insertItem(Terminal, item); + instance->insertItem(TerminalApplication, item); item->setDefaultValue("xterm"); item->setSettingsKey("DebugMode", "Terminal"); diff --git a/src/plugins/debugger/debuggeractions.h b/src/plugins/debugger/debuggeractions.h index 47ccfa9638620e4f8557a1825ea8ab10e27b587b..5d7e5354d239c332baab76fb0a0d002f0b2fc31b 100644 --- a/src/plugins/debugger/debuggeractions.h +++ b/src/plugins/debugger/debuggeractions.h @@ -134,16 +134,14 @@ enum DebuggerActionCode SettingsDialog, AdjustColumnWidths, AlwaysAdjustColumnWidths, - + AutoQuit, + TerminalApplication, LockView, // Gdb GdbLocation, GdbEnvironment, GdbScriptFile, - GdbAutoRun, - GdbAutoQuit, - Terminal, // Watchers & Locals WatchExpression, @@ -152,9 +150,12 @@ enum DebuggerActionCode WatchModelUpdate, UseToolTips, AssignValue, + ExpandItem, + CollapseItem, RecheckDumpers, UsePrebuiltDumpers, + UseQtDumpers, PrebuiltDumpersLocation, BuildDumpersOnTheFly, UseDumpers, @@ -173,7 +174,13 @@ enum DebuggerActionCode NoPluginBreakpoints, SelectedPluginBreakpointsPattern, - AutoQuit, + // Registers + FormatHexadecimal, + FormatDecimal, + FormatOctal, + FormatBinary, + FormatRaw, + FormatNatural, }; // singleton access diff --git a/src/plugins/debugger/debuggerconstants.h b/src/plugins/debugger/debuggerconstants.h index c1369aa3298d93eb87150a2ae646aa0105601281..a17d1bb060c5cf008d737465ab11f0bd6e871a3a 100644 --- a/src/plugins/debugger/debuggerconstants.h +++ b/src/plugins/debugger/debuggerconstants.h @@ -51,8 +51,6 @@ const char * const M_DEBUG_VIEWS = "Debugger.Menu.View.Debug"; const char * const C_GDBDEBUGGER = "Gdb Debugger"; const char * const GDBRUNNING = "Gdb.Running"; -const char * const PROPERTY_REGISTER_FORMAT = "Debugger.Property.RegisterFormat"; - namespace Internal { enum { debug = 0 }; } diff --git a/src/plugins/debugger/debuggermanager.cpp b/src/plugins/debugger/debuggermanager.cpp index 5b7bb4be8ed236a70bcd5f1b980b9e37d6fb30eb..561397ed36e47c34abc150a9f196f6f745d79710 100644 --- a/src/plugins/debugger/debuggermanager.cpp +++ b/src/plugins/debugger/debuggermanager.cpp @@ -88,6 +88,25 @@ using namespace Debugger::Constants; static const QString tooltipIName = "tooltip"; +static const char *stateName(int s) +{ + switch (s) { + case DebuggerProcessNotReady: + return "DebuggerProcessNotReady"; + case DebuggerProcessStartingUp: + return "DebuggerProcessStartingUp"; + case DebuggerInferiorRunningRequested: + return "DebuggerInferiorRunningRequested"; + case DebuggerInferiorRunning: + return "DebuggerInferiorRunning"; + case DebuggerInferiorStopRequested: + return "DebuggerInferiorStopRequested"; + case DebuggerInferiorStopped: + return "DebuggerInferiorStopped"; + } + return "<unknown>"; +} + /////////////////////////////////////////////////////////////////////// // // BreakByFunctionDialog @@ -251,18 +270,10 @@ void DebuggerManager::init() // Locals QTreeView *localsView = qobject_cast<QTreeView *>(m_localsWindow); localsView->setModel(m_watchHandler->model()); - connect(localsView, SIGNAL(requestExpandChildren(QModelIndex)), - this, SLOT(expandChildren(QModelIndex))); - connect(localsView, SIGNAL(requestCollapseChildren(QModelIndex)), - this, SLOT(collapseChildren(QModelIndex))); // Watchers QTreeView *watchersView = qobject_cast<QTreeView *>(m_watchersWindow); watchersView->setModel(m_watchHandler->model()); - connect(watchersView, SIGNAL(requestExpandChildren(QModelIndex)), - this, SLOT(expandChildren(QModelIndex))); - connect(watchersView, SIGNAL(requestCollapseChildren(QModelIndex)), - this, SLOT(collapseChildren(QModelIndex))); connect(m_watchHandler, SIGNAL(sessionValueRequested(QString,QVariant*)), this, SIGNAL(sessionValueRequested(QString,QVariant*))); connect(m_watchHandler, SIGNAL(setSessionValueRequested(QString,QVariant)), @@ -718,18 +729,6 @@ void DebuggerManager::updateWatchModel() m_engine->updateWatchModel(); } -void DebuggerManager::expandChildren(const QModelIndex &idx) -{ - QTC_ASSERT(m_watchHandler, return); - m_watchHandler->expandChildren(idx); -} - -void DebuggerManager::collapseChildren(const QModelIndex &idx) -{ - QTC_ASSERT(m_watchHandler, return); - m_watchHandler->collapseChildren(idx); -} - QVariant DebuggerManager::sessionValue(const QString &name) { // this is answered by the plugin @@ -1153,13 +1152,16 @@ static bool isAllowedTransition(int from, int to) void DebuggerManager::setStatus(int status) { if (Debugger::Constants::Internal::debug) - qDebug() << Q_FUNC_INFO << "STATUS CHANGE: from" << m_status << "to" << status; + qDebug() << Q_FUNC_INFO << "STATUS CHANGE: from" << stateName(m_status) << "to" << stateName(status); if (status == m_status) return; - if (!isAllowedTransition(m_status, status)) - qDebug() << "UNEXPECTED TRANSITION: " << m_status << status; + if (!isAllowedTransition(m_status, status)) { + const QString msg = QString::fromLatin1("%1: UNEXPECTED TRANSITION: %2 -> %3"). + arg(QLatin1String(Q_FUNC_INFO), QLatin1String(stateName(m_status)), QLatin1String(stateName(status))); + qWarning("%s", qPrintable(msg)); + } m_status = status; diff --git a/src/plugins/debugger/debuggermanager.h b/src/plugins/debugger/debuggermanager.h index 77e629e38e501eedc93fe38613cdc65e6fba08eb..4d9351d951d459ccd5fe0f565f4c52eb89841dc8 100644 --- a/src/plugins/debugger/debuggermanager.h +++ b/src/plugins/debugger/debuggermanager.h @@ -231,8 +231,6 @@ public slots: void addToWatchWindow(); void updateWatchModel(); - void expandChildren(const QModelIndex &idx); - void collapseChildren(const QModelIndex &idx); void sessionLoaded(); void aboutToSaveSession(); @@ -333,6 +331,7 @@ public: QString m_workingDir; QString m_buildDir; QStringList m_processArgs; + QString m_dumperLib; int m_attachedPID; bool m_useTerminal; diff --git a/src/plugins/debugger/debuggeroutputwindow.cpp b/src/plugins/debugger/debuggeroutputwindow.cpp index 74d8e8bb5e63ee1810101ac71d3d20913f83b088..37799215354f53f9d7645c8ebbab88b1bfc1f68b 100644 --- a/src/plugins/debugger/debuggeroutputwindow.cpp +++ b/src/plugins/debugger/debuggeroutputwindow.cpp @@ -28,6 +28,7 @@ **************************************************************************/ #include "debuggeroutputwindow.h" +#include "debuggeractions.h" #include <QtCore/QDebug> @@ -51,7 +52,7 @@ using namespace Find; #endif // GDBDEBUGGERLEAN -using Debugger::Internal::DebuggerOutputWindow; +using namespace Debugger::Internal; ///////////////////////////////////////////////////////////////////// // @@ -83,6 +84,8 @@ public: menu->addAction(m_clearContentsAction); //menu->addAction(m_saveContentsAction); addContextActions(menu); + menu->addSeparator(); + menu->addAction(theDebuggerAction(SettingsDialog)); menu->exec(ev->globalPos()); delete menu; } diff --git a/src/plugins/debugger/debuggerplugin.cpp b/src/plugins/debugger/debuggerplugin.cpp index 2a66c1422e73e3b9fdb5adcc3e9c7f2ac9f06a65..34152a52ca5bff419fb17cb495e78b94f44627f6 100644 --- a/src/plugins/debugger/debuggerplugin.cpp +++ b/src/plugins/debugger/debuggerplugin.cpp @@ -278,7 +278,7 @@ QWidget *GdbOptionPage::createPage(QWidget *parent) ->connectWidget(m_ui.scriptFileChooser); theDebuggerAction(GdbEnvironment) ->connectWidget(m_ui.environmentEdit); - theDebuggerAction(Terminal) + theDebuggerAction(TerminalApplication) ->connectWidget(m_ui.terminalChooser); theDebuggerAction(AllPluginBreakpoints) @@ -319,7 +319,7 @@ void GdbOptionPage::apply() theDebuggerAction(GdbLocation)->apply(s); theDebuggerAction(GdbScriptFile)->apply(s); theDebuggerAction(GdbEnvironment)->apply(s); - theDebuggerAction(Terminal)->apply(s); + theDebuggerAction(TerminalApplication)->apply(s); theDebuggerAction(AllPluginBreakpoints)->apply(s); theDebuggerAction(SelectedPluginBreakpoints)->apply(s); @@ -381,6 +381,8 @@ QWidget *DumperOptionPage::createPage(QWidget *parent) connect(m_ui.radioButtonUsePrebuiltDumpers, SIGNAL(toggled(bool)), m_ui.dumperLocationChooser, SLOT(setEnabled(bool))); + theDebuggerAction(UseQtDumpers) + ->connectWidget(m_ui.radioButtonUseQtDumpers); theDebuggerAction(UsePrebuiltDumpers) ->connectWidget(m_ui.radioButtonUsePrebuiltDumpers); theDebuggerAction(BuildDumpersOnTheFly) @@ -414,6 +416,7 @@ void DumperOptionPage::apply() QSettings *s = ICore::instance()->settings(); theDebuggerAction(UseDumpers)->apply(s); + theDebuggerAction(UseQtDumpers)->apply(s); theDebuggerAction(UsePrebuiltDumpers)->apply(s); theDebuggerAction(BuildDumpersOnTheFly)->apply(s); theDebuggerAction(PrebuiltDumpersLocation)->apply(s); diff --git a/src/plugins/debugger/debuggerrunner.cpp b/src/plugins/debugger/debuggerrunner.cpp index 3cc74138f408a9919f178e166e9688259cb44804..0153ef67531aa240036ace56dbe1f937e99f517f 100644 --- a/src/plugins/debugger/debuggerrunner.cpp +++ b/src/plugins/debugger/debuggerrunner.cpp @@ -128,12 +128,11 @@ void DebuggerRunControl::start() m_manager->m_environment = rc->environment().toStringList(); m_manager->m_workingDir = rc->workingDirectory(); m_manager->m_processArgs = rc->commandLineArguments(); + m_manager->m_dumperLib = rc->dumperLibrary(); m_manager->m_buildDir = project->buildDirectory(project->activeBuildConfiguration()); m_manager->m_useTerminal = rc->runMode() == ApplicationRunConfiguration::Console; - //<daniel> andre: + "\qtc-gdbmacros\" - //emit addToOutputWindow(this, tr("Debugging %1").arg(m_executable)); if (m_manager->startNewDebugger(StartInternal)) emit started(); diff --git a/src/plugins/debugger/dumperoptionpage.ui b/src/plugins/debugger/dumperoptionpage.ui index 0219fe898b5acec3b5ad85d1ca9a6ec6cf997658..ce65d701f461a43e01b0ef7a0a6a4fe358bbce01 100644 --- a/src/plugins/debugger/dumperoptionpage.ui +++ b/src/plugins/debugger/dumperoptionpage.ui @@ -21,6 +21,13 @@ </property> <layout class="QGridLayout" name="gridLayout"> <item row="0" column="0"> + <widget class="QRadioButton" name="radioButtonUseQtDumpers"> + <property name="text"> + <string>Use Qt dumpers</string> + </property> + </widget> + </item> + <item row="1" column="0"> <widget class="QRadioButton" name="radioButtonBuildDumpersOnTheFly"> <property name="toolTip"> <string>This is the slowest but safest option.</string> @@ -30,14 +37,14 @@ </property> </widget> </item> - <item row="1" column="0"> + <item row="2" column="0"> <widget class="QRadioButton" name="radioButtonUsePrebuiltDumpers"> <property name="text"> <string>Load pre-built data dumpers</string> </property> </widget> </item> - <item row="2" column="0"> + <item row="3" column="0"> <layout class="QHBoxLayout" name="horizontalLayout"> <item> <spacer name="horizontalSpacer"> diff --git a/src/plugins/debugger/gdbengine.cpp b/src/plugins/debugger/gdbengine.cpp index 535276b326cfde9604675929fc1b7a9989807092..daf2e6e0c0b355dc4a0af37bf785da39efe2dcd2 100644 --- a/src/plugins/debugger/gdbengine.cpp +++ b/src/plugins/debugger/gdbengine.cpp @@ -29,6 +29,7 @@ #include "gdbengine.h" +#include "watchutils.h" #include "debuggeractions.h" #include "debuggerconstants.h" #include "debuggermanager.h" @@ -152,88 +153,12 @@ enum GdbCommandType WatchDumpCustomEditValue, }; -QString dotEscape(QString str) -{ - str.replace(' ', '.'); - str.replace('\\', '.'); - str.replace('/', '.'); - return str; -} - -QString currentTime() -{ - return QTime::currentTime().toString("hh:mm:ss.zzz"); -} - static int ¤tToken() { static int token = 0; return token; } -static bool isSkippableFunction(const QString &funcName, const QString &fileName) -{ - if (fileName.endsWith("kernel/qobject.cpp")) - return true; - if (fileName.endsWith("kernel/moc_qobject.cpp")) - return true; - if (fileName.endsWith("kernel/qmetaobject.cpp")) - return true; - if (fileName.endsWith(".moc")) - return true; - - if (funcName.endsWith("::qt_metacall")) - return true; - - return false; -} - -static bool isLeavableFunction(const QString &funcName, const QString &fileName) -{ - if (funcName.endsWith("QObjectPrivate::setCurrentSender")) - return true; - if (fileName.endsWith("kernel/qmetaobject.cpp") - && funcName.endsWith("QMetaObject::methodOffset")) - return true; - if (fileName.endsWith("kernel/qobject.h")) - return true; - if (fileName.endsWith("kernel/qobject.cpp") - && funcName.endsWith("QObjectConnectionListVector::at")) - return true; - if (fileName.endsWith("kernel/qobject.cpp") - && funcName.endsWith("~QObject")) - return true; - if (fileName.endsWith("thread/qmutex.cpp")) - return true; - if (fileName.endsWith("thread/qthread.cpp")) - return true; - if (fileName.endsWith("thread/qthread_unix.cpp")) - return true; - if (fileName.endsWith("thread/qmutex.h")) - return true; - if (fileName.contains("thread/qbasicatomic")) - return true; - if (fileName.contains("thread/qorderedmutexlocker_p")) - return true; - if (fileName.contains("arch/qatomic")) - return true; - if (fileName.endsWith("tools/qvector.h")) - return true; - if (fileName.endsWith("tools/qlist.h")) - return true; - if (fileName.endsWith("tools/qhash.h")) - return true; - if (fileName.endsWith("tools/qmap.h")) - return true; - if (fileName.endsWith("tools/qstring.h")) - return true; - if (fileName.endsWith("global/qglobal.h")) - return true; - - return false; -} - - /////////////////////////////////////////////////////////////////////// // // GdbEngine @@ -291,6 +216,19 @@ void GdbEngine::initializeConnections() this, SLOT(setDebugDumpers(bool))); connect(theDebuggerAction(RecheckDumpers), SIGNAL(triggered()), this, SLOT(recheckCustomDumperAvailability())); + + connect(theDebuggerAction(FormatHexadecimal), SIGNAL(triggered()), + this, SLOT(reloadRegisters())); + connect(theDebuggerAction(FormatDecimal), SIGNAL(triggered()), + this, SLOT(reloadRegisters())); + connect(theDebuggerAction(FormatOctal), SIGNAL(triggered()), + this, SLOT(reloadRegisters())); + connect(theDebuggerAction(FormatBinary), SIGNAL(triggered()), + this, SLOT(reloadRegisters())); + connect(theDebuggerAction(FormatRaw), SIGNAL(triggered()), + this, SLOT(reloadRegisters())); + connect(theDebuggerAction(FormatNatural), SIGNAL(triggered()), + this, SLOT(reloadRegisters())); } void GdbEngine::initializeVariables() @@ -351,12 +289,6 @@ void GdbEngine::gdbProcError(QProcess::ProcessError error) q->exitDebugger(); } -static inline bool isNameChar(char c) -{ - // could be 'stopped' or 'shlibs-added' - return (c >= 'a' && c <= 'z') || c == '-'; -} - #if 0 static void dump(const char *first, const char *middle, const QString & to) { @@ -497,7 +429,7 @@ void GdbEngine::handleResponse(const QByteArray &buff) // On Windows, the contents seem to depend on the debugger // version and/or OS version used. if (data.startsWith("warning:")) - qq->showApplicationOutput(data); + qq->showApplicationOutput(data.mid(9)); // cut "warning: " break; } @@ -1562,7 +1494,6 @@ int GdbEngine::currentFrame() const return qq->stackHandler()->currentIndex(); } - bool GdbEngine::startDebugger() { debugMessage(theDebuggerSettings()->dump()); @@ -2656,7 +2587,19 @@ void GdbEngine::handleStackListThreads(const GdbResultRecord &record, int id) void GdbEngine::reloadRegisters() { - QString format = qq->registerHandler()->model()->property(PROPERTY_REGISTER_FORMAT).toString(); + QString format; + if (theDebuggerAction(FormatHexadecimal)->isChecked()) + format = "x"; + else if (theDebuggerAction(FormatDecimal)->isChecked()) + format = "d"; + else if (theDebuggerAction(FormatOctal)->isChecked()) + format = "o"; + else if (theDebuggerAction(FormatBinary)->isChecked()) + format = "t"; + else if (theDebuggerAction(FormatRaw)->isChecked()) + format = "r"; + else + format = "N"; sendCommand("-data-list-register-values " + format, RegisterListValues); } @@ -2718,43 +2661,6 @@ static QString m_toolTipExpression; static QPoint m_toolTipPos; static QMap<QString, WatchData> m_toolTipCache; -static bool hasLetterOrNumber(const QString &exp) -{ - for (int i = exp.size(); --i >= 0; ) - if (exp[i].isLetterOrNumber() || exp[i] == '_') - return true; - return false; -} - -static bool hasSideEffects(const QString &exp) -{ - // FIXME: complete? - return exp.contains("-=") - || exp.contains("+=") - || exp.contains("/=") - || exp.contains("*=") - || exp.contains("&=") - || exp.contains("|=") - || exp.contains("^=") - || exp.contains("--") - || exp.contains("++"); -} - -static bool isKeyWord(const QString &exp) -{ - // FIXME: incomplete - return exp == QLatin1String("class") - || exp == QLatin1String("const") - || exp == QLatin1String("do") - || exp == QLatin1String("if") - || exp == QLatin1String("return") - || exp == QLatin1String("struct") - || exp == QLatin1String("template") - || exp == QLatin1String("void") - || exp == QLatin1String("volatile") - || exp == QLatin1String("while"); -} - void GdbEngine::setToolTipExpression(const QPoint &pos, const QString &exp0) { //qDebug() << "SET TOOLTIP EXP" << pos << exp0; @@ -2861,85 +2767,6 @@ void GdbEngine::setToolTipExpression(const QPoint &pos, const QString &exp0) static const QString strNotInScope = QLatin1String("<not in scope>"); -static bool isPointerType(const QString &type) -{ - return type.endsWith("*") || type.endsWith("* const"); -} - -static bool isAccessSpecifier(const QString &str) -{ - static const QStringList items = - QStringList() << "private" << "protected" << "public"; - return items.contains(str); -} - -static bool startsWithDigit(const QString &str) -{ - return !str.isEmpty() && str[0] >= '0' && str[0] <= '9'; -} - -QString stripPointerType(QString type) -{ - if (type.endsWith("*")) - type.chop(1); - if (type.endsWith("* const")) - type.chop(7); - if (type.endsWith(' ')) - type.chop(1); - return type; -} - -static QString gdbQuoteTypes(const QString &type) -{ - // gdb does not understand sizeof(Core::IFile*). - // "sizeof('Core::IFile*')" is also not acceptable, - // it needs to be "sizeof('Core::IFile'*)" - // - // We never will have a perfect solution here (even if we had a full blown - // C++ parser as we do not have information on what is a type and what is - // a variable name. So "a<b>::c" could either be two comparisons of values - // 'a', 'b' and '::c', or a nested type 'c' in a template 'a<b>'. We - // assume here it is the latter. - //return type; - - // (*('myns::QPointer<myns::QObject>*'*)0x684060)" is not acceptable - // (*('myns::QPointer<myns::QObject>'**)0x684060)" is acceptable - if (isPointerType(type)) - return gdbQuoteTypes(stripPointerType(type)) + "*"; - - QString accu; - QString result; - int templateLevel = 0; - for (int i = 0; i != type.size(); ++i) { - QChar c = type.at(i); - if (c.isLetterOrNumber() || c == '_' || c == ':' || c == ' ') { - accu += c; - } else if (c == '<') { - ++templateLevel; - accu += c; - } else if (c == '<') { - --templateLevel; - accu += c; - } else if (templateLevel > 0) { - accu += c; - } else { - if (accu.contains(':') || accu.contains('<')) - result += '\'' + accu + '\''; - else - result += accu; - accu.clear(); - result += c; - } - } - if (accu.contains(':') || accu.contains('<')) - result += '\'' + accu + '\''; - else - result += accu; - //qDebug() << "GDB_QUOTING" << type << " TO " << result; - - return result; -} - static void setWatchDataValue(WatchData &data, const GdbMi &mi, int encoding = 0) { @@ -2963,6 +2790,9 @@ static void setWatchDataValue(WatchData &data, const GdbMi &mi, ba = QString::fromUcs4((uint *)ba.data(), ba.size() / 4).toUtf8(); ba = '"' + ba + '"'; break; + case 4: // base64 encoded 8 bit data + ba = QByteArray::fromBase64(mi.data()); + break; } data.setValue(ba); } else { @@ -3023,68 +2853,6 @@ static void setWatchDataSAddress(WatchData &data, const GdbMi &mi) data.saddr = mi.data(); } -static bool extractTemplate(const QString &type, QString *tmplate, QString *inner) -{ - // Input "Template<Inner1,Inner2,...>::Foo" will return "Template::Foo" in - // 'tmplate' and "Inner1@Inner2@..." etc in 'inner'. Result indicates - // whether parsing was successful - int level = 0; - bool skipSpace = false; - for (int i = 0; i != type.size(); ++i) { - QChar c = type[i]; - if (c == ' ' && skipSpace) { - skipSpace = false; - } else if (c == '<') { - *(level == 0 ? tmplate : inner) += c; - ++level; - } else if (c == '>') { - --level; - *(level == 0 ? tmplate : inner) += c; - } else if (c == ',') { - *inner += (level == 1) ? '@' : ','; - skipSpace = true; - } else { - *(level == 0 ? tmplate : inner) += c; - } - } - *tmplate = tmplate->trimmed(); - *tmplate = tmplate->remove("<>"); - *inner = inner->trimmed(); - //qDebug() << "EXTRACT TEMPLATE: " << *tmplate << *inner << " FROM " << type; - return !inner->isEmpty(); -} - -static QString extractTypeFromPTypeOutput(const QString &str) -{ - int pos0 = str.indexOf('='); - int pos1 = str.indexOf('{'); - int pos2 = str.lastIndexOf('}'); - QString res = str; - if (pos0 != -1 && pos1 != -1 && pos2 != -1) - res = str.mid(pos0 + 2, pos1 - 1 - pos0) - + " ... " + str.right(str.size() - pos2); - return res.simplified(); -} - -static bool isIntOrFloatType(const QString &type) -{ - static const QStringList types = QStringList() - << "char" << "int" << "short" << "float" << "double" << "long" - << "bool" << "signed char" << "unsigned" << "unsigned char" - << "unsigned int" << "unsigned long" << "long long" - << "unsigned long long"; - return types.contains(type); -} - -static QString sizeofTypeExpression(const QString &type) -{ - if (type.endsWith('*')) - return "sizeof(void*)"; - if (type.endsWith('>')) - return "sizeof(" + type + ")"; - return "sizeof(" + gdbQuoteTypes(type) + ")"; -} - void GdbEngine::setUseDumpers(bool on) { qDebug() << "SWITCHING ON/OFF DUMPER DEBUGGING:" << on; @@ -3362,13 +3130,7 @@ void GdbEngine::updateSubItem(const WatchData &data0) qDebug() << "IT'S A POINTER"; #endif #if 1 - WatchData data1; - data1.iname = data.iname + ".*"; - data1.name = "*" + data.name; - data1.exp = "(*(" + data.exp + "))"; - data1.type = stripPointerType(data.type); - data1.setValueNeeded(); - insertData(data1); + insertData(data.pointerChildPlaceHolder()); data.setChildrenUnneeded(); insertData(data); #else @@ -3573,7 +3335,7 @@ void GdbEngine::handleQueryDataDumper(const GdbResultRecord &record) ); } else { m_dataDumperState = DataDumperAvailable; - q->showStatusMessage(tr("%1 custom dumpers found") + q->showStatusMessage(tr("%1 custom dumpers found.") .arg(m_availableSimpleDumpers.size())); } //qDebug() << "DATA DUMPERS AVAILABLE" << m_availableSimpleDumpers; @@ -4234,6 +3996,8 @@ QString GdbEngine::dumperLibraryName() const { if (theDebuggerAction(UsePrebuiltDumpers)->value().toBool()) return theDebuggerAction(PrebuiltDumpersLocation)->value().toString(); + if (theDebuggerAction(UseQtDumpers)->value().toBool()) + return q->m_dumperLib; #if defined(Q_OS_WIN) return q->m_buildDir + "/qtc-gdbmacros/debug/gdbmacros.dll"; #elif defined(Q_OS_MAC) @@ -4251,6 +4015,7 @@ void GdbEngine::tryLoadCustomDumpers() PENDING_DEBUG("TRY LOAD CUSTOM DUMPERS"); m_dataDumperState = DataDumperUnavailable; QString lib = dumperLibraryName(); + //qDebug() << "DUMPERLIB: " << lib; if (!QFileInfo(lib).exists()) { debugMessage(QString("DEBUG HELPER LIBRARY IS NOT USABLE: " @@ -4304,4 +4069,3 @@ IDebuggerEngine *createGdbEngine(DebuggerManager *parent) { return new GdbEngine(parent); } - diff --git a/src/plugins/debugger/gdbengine.h b/src/plugins/debugger/gdbengine.h index 20c9c222877b92dfbdb544ba90f5dfd8990a03f3..d35f0f0827174a8b059940436ebd175f9daa0dbf 100644 --- a/src/plugins/debugger/gdbengine.h +++ b/src/plugins/debugger/gdbengine.h @@ -265,7 +265,7 @@ private: // // Register specific stuff // - void reloadRegisters(); + Q_SLOT void reloadRegisters(); void handleRegisterListNames(const GdbResultRecord &record); void handleRegisterListValues(const GdbResultRecord &record); diff --git a/src/plugins/debugger/registerhandler.cpp b/src/plugins/debugger/registerhandler.cpp index 70bae1b2b3808946359eaaf0bf6059368bf7c5fe..12dd1d213162b36a8d5ecd0d32866ca594fe7912 100644 --- a/src/plugins/debugger/registerhandler.cpp +++ b/src/plugins/debugger/registerhandler.cpp @@ -51,9 +51,7 @@ using namespace Debugger::Constants; RegisterHandler::RegisterHandler(QObject *parent) : QAbstractTableModel(parent) -{ - setProperty(PROPERTY_REGISTER_FORMAT, "x"); -} +{} int RegisterHandler::rowCount(const QModelIndex &parent) const { diff --git a/src/plugins/debugger/registerwindow.cpp b/src/plugins/debugger/registerwindow.cpp index e83a3abb052fe7086d2b556d7f999d9d80128b9d..03239d8875ab176e9e968505a81fcf8676fa8390 100644 --- a/src/plugins/debugger/registerwindow.cpp +++ b/src/plugins/debugger/registerwindow.cpp @@ -29,17 +29,19 @@ #include "registerwindow.h" +#include "debuggeractions.h" #include "debuggerconstants.h" -#include <QAction> -#include <QDebug> -#include <QDir> -#include <QFileInfo> -#include <QFileInfoList> -#include <QHeaderView> -#include <QMenu> -#include <QResizeEvent> -#include <QToolButton> +#include <QtCore/QDebug> +#include <QtCore/QDir> +#include <QtCore/QFileInfo> +#include <QtCore/QFileInfoList> + +#include <QtGui/QAction> +#include <QtGui/QHeaderView> +#include <QtGui/QMenu> +#include <QtGui/QResizeEvent> +#include <QtGui/QToolButton> using namespace Debugger::Internal; @@ -72,14 +74,12 @@ void RegisterWindow::resizeEvent(QResizeEvent *ev) void RegisterWindow::contextMenuEvent(QContextMenuEvent *ev) { - enum { Hex, Bin, Dec, Raw, Oct, Nat, - Adjust, AlwaysAdjust, Reload, AlwaysReload, Count }; + enum { Adjust, AlwaysAdjust, Reload, AlwaysReload, Count }; QMenu menu; QAction *actions[Count]; - //QTreeWidgetItem *item = itemAt(ev->pos()); - QString format = model()->property(PROPERTY_REGISTER_FORMAT).toString(); - qDebug() << "FORMAT: " << format; + //QString format = model()->property(PROPERTY_REGISTER_FORMAT).toString(); + //qDebug() << "FORMAT: " << format; actions[Adjust] = menu.addAction("Adjust column widths to contents"); @@ -94,30 +94,15 @@ void RegisterWindow::contextMenuEvent(QContextMenuEvent *ev) actions[AlwaysReload]->setChecked(m_alwaysReloadContents); menu.addSeparator(); + menu.addAction(theDebuggerAction(FormatHexadecimal)); + menu.addAction(theDebuggerAction(FormatDecimal)); + menu.addAction(theDebuggerAction(FormatOctal)); + menu.addAction(theDebuggerAction(FormatBinary)); + menu.addAction(theDebuggerAction(FormatRaw)); + menu.addAction(theDebuggerAction(FormatNatural)); - actions[Hex] = menu.addAction("Hexadecimal"); - actions[Hex]->setCheckable(true); - actions[Hex]->setChecked(format == "h"); - - actions[Bin] = menu.addAction("Binary"); - actions[Bin]->setCheckable(true); - actions[Bin]->setChecked(format == "t"); - - actions[Dec] = menu.addAction("Decimal"); - actions[Dec]->setCheckable(true); - actions[Dec]->setChecked(format == "d"); - - actions[Raw] = menu.addAction("Raw"); - actions[Raw]->setCheckable(true); - actions[Raw]->setChecked(format == "r"); - - actions[Nat] = menu.addAction("Natural"); - actions[Nat]->setCheckable(true); - actions[Nat]->setChecked(format == "N"); - - actions[Oct] = menu.addAction("Octal"); - actions[Oct]->setCheckable(true); - actions[Oct]->setChecked(format == "o"); + menu.addSeparator(); + menu.addAction(theDebuggerAction(SettingsDialog)); QAction *act = menu.exec(ev->globalPos()); @@ -129,17 +114,6 @@ void RegisterWindow::contextMenuEvent(QContextMenuEvent *ev) reloadContents(); else if (act == actions[AlwaysReload]) setAlwaysReloadContents(!m_alwaysReloadContents); - else if (act == actions[Hex]) - model()->setProperty(PROPERTY_REGISTER_FORMAT, "h"); - else if (act == actions[Oct]) - model()->setProperty(PROPERTY_REGISTER_FORMAT, "o"); - else if (act == actions[Bin]) - model()->setProperty(PROPERTY_REGISTER_FORMAT, "t"); - else if (act == actions[Dec]) - model()->setProperty(PROPERTY_REGISTER_FORMAT, "d"); - else if (act == actions[Nat]) - model()->setProperty(PROPERTY_REGISTER_FORMAT, "N"); - } void RegisterWindow::resizeColumnsToContents() diff --git a/src/plugins/debugger/sourcefileswindow.cpp b/src/plugins/debugger/sourcefileswindow.cpp index 1f90bc0d8186b41a78a8b7f9b4e0e381c76bb4d2..7b927cd4de829c887ddd6f8887c3391bb9f61c72 100644 --- a/src/plugins/debugger/sourcefileswindow.cpp +++ b/src/plugins/debugger/sourcefileswindow.cpp @@ -28,18 +28,19 @@ **************************************************************************/ #include "sourcefileswindow.h" +#include "debuggeractions.h" -#include <QDebug> -#include <QAction> -#include <QComboBox> -#include <QFileInfo> -#include <QDebug> -#include <QHeaderView> -#include <QMenu> -#include <QResizeEvent> -#include <QTreeView> -#include <QSortFilterProxyModel> -#include <QVBoxLayout> +#include <QtCore/QDebug> +#include <QtCore/QFileInfo> + +#include <QtGui/QAction> +#include <QtGui/QComboBox> +#include <QtGui/QHeaderView> +#include <QtGui/QMenu> +#include <QtGui/QResizeEvent> +#include <QtGui/QSortFilterProxyModel> +#include <QtGui/QTreeView> +#include <QtGui/QVBoxLayout> using Debugger::Internal::SourceFilesWindow; using Debugger::Internal::SourceFilesModel; @@ -205,6 +206,8 @@ void SourceFilesWindow::contextMenuEvent(QContextMenuEvent *ev) menu.addAction(act1); menu.addAction(act2); + menu.addSeparator(); + menu.addAction(theDebuggerAction(SettingsDialog)); QAction *act = menu.exec(ev->globalPos()); diff --git a/src/plugins/debugger/watchhandler.cpp b/src/plugins/debugger/watchhandler.cpp index cfe0eb5338ceb24ee530b0d54f175a4ca8a2f918..88349072e4664c0b952e36e2450c46e11427c215 100644 --- a/src/plugins/debugger/watchhandler.cpp +++ b/src/plugins/debugger/watchhandler.cpp @@ -28,6 +28,7 @@ **************************************************************************/ #include "watchhandler.h" +#include "watchutils.h" #include "debuggeractions.h" #if USE_MODEL_TEST @@ -38,6 +39,7 @@ #include <QtCore/QDebug> #include <QtCore/QEvent> +#include <QtCore/QTextStream> #include <QtGui/QAction> #include <QtGui/QApplication> @@ -45,6 +47,7 @@ #include <QtGui/QToolTip> #include <QtGui/QTextEdit> + #include <ctype.h> // creates debug output regarding pending watch data results @@ -63,44 +66,21 @@ using namespace Debugger::Internal; static const QString strNotInScope = QLatin1String("<not in scope>"); -static bool isIntOrFloatType(const QString &type) -{ - static const QStringList types = QStringList() - << "char" << "int" << "short" << "float" << "double" << "long" - << "bool" << "signed char" << "unsigned" << "unsigned char" - << "unsigned int" << "unsigned long" << "long long"; - return types.contains(type); -} - -static bool isPointerType(const QString &type) -{ - return type.endsWith("*") || type.endsWith("* const"); -} - -static QString htmlQuote(const QString &str0) -{ - QString str = str0; - str.replace('&', "&"); - str.replace('<', "<"); - str.replace('>', ">"); - return str; -} - //////////////////////////////////////////////////////////////////// // // WatchData // //////////////////////////////////////////////////////////////////// -WatchData::WatchData() +WatchData::WatchData() : + childCount(-1), + valuedisabled(false), + state(InitialState), + parentIndex(-1), + row(-1), + level(-1), + changed(false) { - valuedisabled = false; - state = InitialState; - childCount = -1; - parentIndex = -1; - row = -1; - level = -1; - changed = false; } void WatchData::setError(const QString &msg) @@ -170,21 +150,21 @@ void WatchData::setType(const QString &str) type = str.trimmed(); bool changed = true; while (changed) { - if (type.endsWith("const")) + if (type.endsWith(QLatin1String("const"))) type.chop(5); - else if (type.endsWith(" ")) + else if (type.endsWith(QLatin1Char(' '))) type.chop(1); - else if (type.endsWith("&")) + else if (type.endsWith(QLatin1Char('&'))) type.chop(1); - else if (type.startsWith("const ")) + else if (type.startsWith(QLatin1String("const "))) type = type.mid(6); - else if (type.startsWith("volatile ")) + else if (type.startsWith(QLatin1String("volatile "))) type = type.mid(9); - else if (type.startsWith("class ")) + else if (type.startsWith(QLatin1String("class "))) type = type.mid(6); - else if (type.startsWith("struct ")) + else if (type.startsWith(QLatin1String("struct "))) type = type.mid(6); - else if (type.startsWith(" ")) + else if (type.startsWith(QLatin1Char(' '))) type = type.mid(1); else changed = false; @@ -199,58 +179,67 @@ void WatchData::setAddress(const QString & str) addr = str; } +WatchData WatchData::pointerChildPlaceHolder() const +{ + WatchData data1; + data1.iname = iname + QLatin1String(".*"); + data1.name = QLatin1Char('*') + name; + data1.exp = QLatin1String("(*(") + exp + QLatin1String("))"); + data1.type = stripPointerType(type); + data1.setValueNeeded(); + return data1; +} + QString WatchData::toString() const { - QString res = "{"; - - res += "level=\"" + QString::number(level) + "\","; - res += "parent=\"" + QString::number(parentIndex) + "\","; - res += "row=\"" + QString::number(row) + "\","; - res += "child=\""; - foreach (int index, childIndex) - res += QString::number(index) + ","; - if (res.endsWith(',')) - res[res.size() - 1] = '"'; - else - res += '"'; - res += ","; - + const char *doubleQuoteComma = "\","; + QString res; + QTextStream str(&res); + str <<"{state=\"0x" << QString::number(state, 16) << doubleQuoteComma + << "level=\"" << level << doubleQuoteComma + << "parent=\"" << parentIndex << doubleQuoteComma + << "row=\"" << row << doubleQuoteComma + << "child=\""; + const int childCount = childIndex.size(); + for (int i = 0; i < childCount; i++) { + if (i) + str << ','; + str << childIndex.at(i); + } + str << doubleQuoteComma; if (!iname.isEmpty()) - res += "iname=\"" + iname + "\","; + str << "iname=\"" << iname << doubleQuoteComma; if (!exp.isEmpty()) - res += "exp=\"" + exp + "\","; + str << "exp=\"" << exp << doubleQuoteComma; if (!variable.isEmpty()) - res += "variable=\"" + variable + "\","; + str << "variable=\"" << variable << doubleQuoteComma; if (isValueNeeded()) - res += "value=<needed>,"; + str << "value=<needed>,"; if (isValueKnown() && !value.isEmpty()) - res += "value=\"" + value + "\","; + str << "value=\"" << value << doubleQuoteComma; if (!editvalue.isEmpty()) - res += "editvalue=\"" + editvalue + "\","; + str << "editvalue=\"" << editvalue << doubleQuoteComma; if (isTypeNeeded()) - res += "type=<needed>,"; + str << "type=<needed>,"; if (isTypeKnown() && !type.isEmpty()) - res += "type=\"" + type + "\","; + str << "type=\"" << type << doubleQuoteComma; if (isChildCountNeeded()) - res += "numchild=<needed>,"; + str << "numchild=<needed>,"; if (isChildCountKnown() && childCount == -1) - res += "numchild=\"" + QString::number(childCount) + "\","; + str << "numchild=\"" << childCount << doubleQuoteComma; if (isChildrenNeeded()) - res += "children=<needed>,"; - - if (res.endsWith(',')) - res[res.size() - 1] = '}'; - else - res += '}'; - - return res; + str << "children=<needed>,"; + str.flush(); + if (res.endsWith(QLatin1Char(','))) + res.truncate(res.size() - 1); + return res + QLatin1Char('}'); } static bool iNameSorter(const WatchData &d1, const WatchData &d2) @@ -273,7 +262,7 @@ static bool iNameSorter(const WatchData &d1, const WatchData &d2) static QString parentName(const QString &iname) { - int pos = iname.lastIndexOf("."); + int pos = iname.lastIndexOf(QLatin1Char('.')); if (pos == -1) return QString(); return iname.left(pos); @@ -306,7 +295,6 @@ static WatchData take(const QString &iname, QList<WatchData> *list) return WatchData(); } - static QList<WatchData> initialSet() { QList<WatchData> result; @@ -315,7 +303,7 @@ static QList<WatchData> initialSet() root.state = 0; root.level = 0; root.row = 0; - root.name = "Root"; + root.name = QLatin1String("Root"); root.parentIndex = -1; root.childIndex.append(1); root.childIndex.append(2); @@ -323,8 +311,8 @@ static QList<WatchData> initialSet() result.append(root); WatchData local; - local.iname = "local"; - local.name = "Locals"; + local.iname = QLatin1String("local"); + local.name = QLatin1String("Locals"); local.state = 0; local.level = 1; local.row = 0; @@ -332,8 +320,8 @@ static QList<WatchData> initialSet() result.append(local); WatchData tooltip; - tooltip.iname = "tooltip"; - tooltip.name = "Tooltip"; + tooltip.iname = QLatin1String("tooltip"); + tooltip.name = QLatin1String("Tooltip"); tooltip.state = 0; tooltip.level = 1; tooltip.row = 1; @@ -341,8 +329,8 @@ static QList<WatchData> initialSet() result.append(tooltip); WatchData watch; - watch.iname = "watch"; - watch.name = "Watchers"; + watch.iname = QLatin1String("watch"); + watch.name = QLatin1String("Watchers"); watch.state = 0; watch.level = 1; watch.row = 2; @@ -370,62 +358,65 @@ WatchHandler::WatchHandler() connect(theDebuggerAction(WatchExpression), SIGNAL(triggered()), this, SLOT(watchExpression())); - connect(theDebuggerAction(RemoveWatchExpression), SIGNAL(triggered()), this, SLOT(removeWatchExpression())); + connect(theDebuggerAction(ExpandItem), + SIGNAL(triggered()), this, SLOT(expandChildren())); + connect(theDebuggerAction(CollapseItem), + SIGNAL(triggered()), this, SLOT(collapseChildren())); } static QString niceType(QString type) { - if (type.contains("std::")) { + if (type.contains(QLatin1String("std::"))) { // std::string - type.replace("std::basic_string<char, std::char_traits<char>, " - "std::allocator<char> >", "std::string"); + type.replace(QLatin1String("std::basic_string<char, std::char_traits<char>, " + "std::allocator<char> >"), QLatin1String("std::string")); // std::wstring - type.replace("std::basic_string<wchar_t, std::char_traits<wchar_t>, " - "std::allocator<wchar_t> >", "std::wstring"); + type.replace(QLatin1String("std::basic_string<wchar_t, std::char_traits<wchar_t>, " + "std::allocator<wchar_t> >"), QLatin1String("std::wstring")); // std::vector - static QRegExp re1("std::vector<(.*), std::allocator<(.*)>\\s*>"); + static QRegExp re1(QLatin1String("std::vector<(.*), std::allocator<(.*)>\\s*>")); re1.setMinimal(true); for (int i = 0; i != 10; ++i) { if (re1.indexIn(type) == -1 || re1.cap(1) != re1.cap(2)) break; - type.replace(re1.cap(0), "std::vector<" + re1.cap(1) + ">"); + type.replace(re1.cap(0), QLatin1String("std::vector<") + re1.cap(1) + QLatin1Char('>')); } // std::list - static QRegExp re2("std::list<(.*), std::allocator<(.*)>\\s*>"); + static QRegExp re2(QLatin1String("std::list<(.*), std::allocator<(.*)>\\s*>")); re2.setMinimal(true); for (int i = 0; i != 10; ++i) { if (re2.indexIn(type) == -1 || re2.cap(1) != re2.cap(2)) break; - type.replace(re2.cap(0), "std::list<" + re2.cap(1) + ">"); + type.replace(re2.cap(0), QLatin1String("std::list<") + re2.cap(1) + QLatin1Char('>')); } // std::map - static QRegExp re3("std::map<(.*), (.*), std::less<(.*)\\s*>, " - "std::allocator<std::pair<const (.*), (.*)\\s*> > >"); + static QRegExp re3(QLatin1String("std::map<(.*), (.*), std::less<(.*)\\s*>, " + "std::allocator<std::pair<const (.*), (.*)\\s*> > >")); re3.setMinimal(true); for (int i = 0; i != 10; ++i) { if (re3.indexIn(type) == -1 || re3.cap(1) != re3.cap(3) || re3.cap(1) != re3.cap(4) || re3.cap(2) != re3.cap(5)) break; - type.replace(re3.cap(0), "std::map<" + re3.cap(1) + ", " + re3.cap(2) + ">"); + type.replace(re3.cap(0), QLatin1String("std::map<") + re3.cap(1) + QLatin1String(", ") + re3.cap(2) + QLatin1Char('>')); } // std::set - static QRegExp re4("std::set<(.*), std::less<(.*)>, std::allocator<(.*)>\\s*>"); + static QRegExp re4(QLatin1String("std::set<(.*), std::less<(.*)>, std::allocator<(.*)>\\s*>")); re1.setMinimal(true); for (int i = 0; i != 10; ++i) { if (re4.indexIn(type) == -1 || re4.cap(1) != re4.cap(2) || re4.cap(1) != re4.cap(3)) break; - type.replace(re4.cap(0), "std::set<" + re4.cap(1) + ">"); + type.replace(re4.cap(0), QLatin1String("std::set<") + re4.cap(1) + QLatin1Char('>')); } - type.replace(" >", ">"); + type.replace(QLatin1String(" >"), QString(QLatin1Char('>'))); } return type; } @@ -453,31 +444,31 @@ QVariant WatchHandler::data(const QModelIndex &idx, int role) const case Qt::ToolTipRole: { QString val = data.value; if (val.size() > 1000) - val = val.left(1000) + " ... <cut off>"; - - QString tt = "<table>"; - //tt += "<tr><td>internal name</td><td> : </td><td>"; - //tt += htmlQuote(iname) + "</td></tr>"; - tt += "<tr><td>expression</td><td> : </td><td>"; - tt += htmlQuote(data.exp) + "</td></tr>"; - tt += "<tr><td>type</td><td> : </td><td>"; - tt += htmlQuote(data.type) + "</td></tr>"; + val = val.left(1000) + QLatin1String(" ... <cut off>"); + + QString tt = QLatin1String("<table>"); + //tt += QLatin1String("<tr><td>internal name</td><td> : </td><td>"); + //tt += Qt::escape(iname) + QLatin1String("</td></tr>"); + tt += QLatin1String("<tr><td>expression</td><td> : </td><td>"); + tt += Qt::escape(data.exp) + QLatin1String("</td></tr>"); + tt += QLatin1String("<tr><td>type</td><td> : </td><td>"); + tt += Qt::escape(data.type) + QLatin1String("</td></tr>"); //if (!valuetooltip.isEmpty()) // tt += valuetooltip; //else - tt += "<tr><td>value</td><td> : </td><td>"; - tt += htmlQuote(data.value) + "</td></tr>"; - tt += "<tr><td>object addr</td><td> : </td><td>"; - tt += htmlQuote(data.addr) + "</td></tr>"; - tt += "<tr><td>stored addr</td><td> : </td><td>"; - tt += htmlQuote(data.saddr) + "</td></tr>"; - tt += "<tr><td>iname</td><td> : </td><td>"; - tt += htmlQuote(data.iname) + "</td></tr>"; - tt += "</table>"; - tt.replace("@value@", htmlQuote(data.value)); + tt += QLatin1String("<tr><td>value</td><td> : </td><td>"); + tt += Qt::escape(data.value) + QLatin1String("</td></tr>"); + tt += QLatin1String("<tr><td>object addr</td><td> : </td><td>"); + tt += Qt::escape(data.addr) + QLatin1String("</td></tr>"); + tt += QLatin1String("<tr><td>stored addr</td><td> : </td><td>"); + tt += Qt::escape(data.saddr) + QLatin1String("</td></tr>"); + tt += QLatin1String("<tr><td>iname</td><td> : </td><td>"); + tt += Qt::escape(data.iname) + QLatin1String("</td></tr>"); + tt += QLatin1String("</table>"); + tt.replace(QLatin1String("@value@"), Qt::escape(data.value)); if (tt.size() > 10000) - tt = tt.left(10000) + " ... <cut off>"; + tt = tt.left(10000) + QLatin1String(" ... <cut off>"); return tt; } @@ -552,9 +543,9 @@ QVariant WatchHandler::headerData(int section, Qt::Orientation orientation, return QVariant(); if (role == Qt::DisplayRole) { switch (section) { - case 0: return tr("Name") + " "; - case 1: return tr("Value") + " "; - case 2: return tr("Type") + " "; + case 0: return tr("Name") + QLatin1String(" "); + case 1: return tr("Value") + QLatin1String(" "); + case 2: return tr("Type") + QLatin1String(" "); } } return QVariant(); @@ -563,30 +554,21 @@ QVariant WatchHandler::headerData(int section, Qt::Orientation orientation, QString WatchHandler::toString() const { QString res; - res += "\nIncomplete:\n"; - for (int i = 0, n = m_incompleteSet.size(); i != n; ++i) { - res += QString("%1: ").arg(i); - res += m_incompleteSet.at(i).toString(); - res += '\n'; - } - res += "\nComplete:\n"; - for (int i = 0, n = m_completeSet.size(); i != n; ++i) { - res += QString("%1: ").arg(i); - res += m_completeSet.at(i).toString(); - res += '\n'; - } - res += "\nDisplay:\n"; - for (int i = 0, n = m_displaySet.size(); i != n; ++i) { - res += QString("%1: ").arg(i); - res += m_displaySet.at(i).toString(); - res += '\n'; - } + QTextStream str(&res); + str << "\nIncomplete:\n"; + for (int i = 0, n = m_incompleteSet.size(); i != n; ++i) + str << i << ' ' << m_incompleteSet.at(i).toString() << '\n'; + str << "\nComplete:\n"; + for (int i = 0, n = m_completeSet.size(); i != n; ++i) + str << i << ' ' << m_completeSet.at(i).toString() << '\n'; + str << "\nDisplay:\n"; + for (int i = 0, n = m_displaySet.size(); i != n; ++i) + str << i << ' ' << m_displaySet.at(i).toString() << '\n'; + #if 0 - res += "\nOld:\n"; - for (int i = 0, n = m_oldSet.size(); i != n; ++i) { - res += m_oldSet.at(i).toString(); - res += '\n'; - } + str << "\nOld:\n"; + for (int i = 0, n = m_oldSet.size(); i != n; ++i) + str << m_oldSet.at(i).toString() << '\n'; #endif return res; } @@ -702,7 +684,7 @@ void WatchHandler::rebuildModel() WatchData dummy; dummy.state = 0; dummy.row = 0; - dummy.iname = data.iname + ".dummy"; + dummy.iname = data.iname + QLatin1String(".dummy"); //dummy.name = data.iname + ".dummy"; //dummy.name = "<loading>"; dummy.level = data.level + 1; @@ -717,9 +699,9 @@ void WatchHandler::rebuildModel() // Possibly append dummy items to prevent empty views bool ok = true; QTC_ASSERT(m_displaySet.size() >= 2, ok = false); - QTC_ASSERT(m_displaySet.at(1).iname == "local", ok = false); - QTC_ASSERT(m_displaySet.at(2).iname == "tooltip", ok = false); - QTC_ASSERT(m_displaySet.at(3).iname == "watch", ok = false); + QTC_ASSERT(m_displaySet.at(1).iname == QLatin1String("local"), ok = false); + QTC_ASSERT(m_displaySet.at(2).iname == QLatin1String("tooltip"), ok = false); + QTC_ASSERT(m_displaySet.at(3).iname == QLatin1String("watch"), ok = false); if (ok) { for (int i = 1; i <= 3; ++i) { WatchData &data = m_displaySet[i]; @@ -728,14 +710,14 @@ void WatchHandler::rebuildModel() dummy.state = 0; dummy.row = 0; if (i == 1) { - dummy.iname = "local.dummy"; - dummy.name = "<No Locals>"; + dummy.iname = QLatin1String("local.dummy"); + dummy.name = QLatin1String("<No Locals>"); } else if (i == 2) { - dummy.iname = "tooltip.dummy"; - dummy.name = "<No Tooltip>"; + dummy.iname = QLatin1String("tooltip.dummy"); + dummy.name = QLatin1String("<No Tooltip>"); } else { - dummy.iname = "watch.dummy"; - dummy.name = "<No Watchers>"; + dummy.iname = QLatin1String("watch.dummy"); + dummy.name = QLatin1String("<No Watchers>"); } dummy.level = 2; dummy.parentIndex = i; @@ -748,7 +730,8 @@ void WatchHandler::rebuildModel() m_inChange = true; //qDebug() << "WATCHHANDLER: RESET ABOUT TO EMIT"; - emit reset(); + //emit reset(); + emit layoutChanged(); //qDebug() << "WATCHHANDLER: RESET EMITTED"; m_inChange = false; @@ -785,15 +768,19 @@ void WatchHandler::cleanup() emit reset(); } -void WatchHandler::collapseChildren(const QModelIndex &idx) +void WatchHandler::collapseChildren() +{ + if (QAction *act = qobject_cast<QAction *>(sender())) + collapseChildren(act->data().toString()); +} + +void WatchHandler::collapseChildren(const QString &iname) { if (m_inChange || m_completeSet.isEmpty()) { - qDebug() << "WATCHHANDLER: COLLAPSE IGNORED" << idx; + qDebug() << "WATCHHANDLER: COLLAPSE IGNORED" << iname; return; } - QTC_ASSERT(checkIndex(idx.internalId()), return); - QString iname0 = m_displaySet.at(idx.internalId()).iname; - MODEL_DEBUG("COLLAPSE NODE" << iname0); + MODEL_DEBUG("COLLAPSE NODE" << iname); #if 0 QString iname1 = iname0 + '.'; for (int i = m_completeSet.size(); --i >= 0; ) { @@ -806,19 +793,32 @@ void WatchHandler::collapseChildren(const QModelIndex &idx) } } #endif - m_expandedINames.remove(iname0); + m_expandedINames.remove(iname); //MODEL_DEBUG(toString()); //rebuildModel(); } -void WatchHandler::expandChildren(const QModelIndex &idx) +void WatchHandler::expandChildren() +{ + if (QAction *act = qobject_cast<QAction *>(sender())) + expandChildren(act->data().toString()); +} + +void WatchHandler::expandChildren(const QString &iname) { if (m_inChange || m_completeSet.isEmpty()) { - //qDebug() << "WATCHHANDLER: EXPAND IGNORED" << idx; + //qDebug() << "WATCHHANDLER: EXPAND IGNORED" << iname; return; } - int index = idx.internalId(); - if (index == 0) + int index = -1; + for (int i = 0; i != m_displaySet.size(); ++i) { + if (m_displaySet.at(i).iname == iname) { + index = i; + break; + } + } + + if (index == -1) return; QTC_ASSERT(index >= 0, qDebug() << toString() << index; return); QTC_ASSERT(index < m_completeSet.size(), qDebug() << toString() << index; return); @@ -832,8 +832,7 @@ void WatchHandler::expandChildren(const QModelIndex &idx) // "expand()" signals folr the root item from time to time. // Try to handle that gracfully. //MODEL_DEBUG(toString()); - qDebug() << "FIXME: expandChildren, no data " << display.iname << "found" - << idx; + qDebug() << "FIXME: expandChildren, no data " << display.iname << "found"; //rebuildModel(); return; } @@ -883,7 +882,7 @@ void WatchHandler::watchExpression(const QString &exp) WatchData data; data.exp = exp; data.name = exp; - data.iname = "watch." + exp; + data.iname = QLatin1String("watch.") + exp; insertData(data); m_watchers.append(exp); saveWatchers(); @@ -915,7 +914,7 @@ void WatchHandler::showEditValue(const WatchData &data) QWidget *w = m_editWindows.value(data.iname); qDebug() << "SHOW_EDIT_VALUE " << data.toString() << data.type << data.iname << w; - if (data.type == "QImage") { + if (data.type == QLatin1String("QImage")) { if (!w) { w = new QLabel; m_editWindows[data.iname] = w; @@ -927,7 +926,7 @@ void WatchHandler::showEditValue(const WatchData &data) QImage im = v.value<QImage>(); if (QLabel *l = qobject_cast<QLabel *>(w)) l->setPixmap(QPixmap::fromImage(im)); - } else if (data.type == "QPixmap") { + } else if (data.type == QLatin1String("QPixmap")) { if (!w) { w = new QLabel; m_editWindows[data.iname] = w; @@ -939,7 +938,7 @@ void WatchHandler::showEditValue(const WatchData &data) QPixmap im = v.value<QPixmap>(); if (QLabel *l = qobject_cast<QLabel *>(w)) l->setPixmap(im); - } else if (data.type == "QString") { + } else if (data.type == QLatin1String("QString")) { if (!w) { w = new QTextEdit; m_editWindows[data.iname] = w; @@ -973,7 +972,7 @@ void WatchHandler::removeWatchExpression(const QString &exp) m_watchers.removeOne(exp); for (int i = m_completeSet.size(); --i >= 0;) { const WatchData & data = m_completeSet.at(i); - if (data.iname.startsWith("watch.") && data.exp == exp) { + if (data.iname.startsWith(QLatin1String("watch.")) && data.exp == exp) { m_completeSet.takeAt(i); break; } @@ -1002,7 +1001,7 @@ void WatchHandler::reinitializeWatchersHelper() data.variable.clear(); data.setAllNeeded(); data.valuedisabled = false; - data.iname = "watch." + QString::number(i); + data.iname = QLatin1String("watch.") + QString::number(i); data.name = exp; data.exp = exp; insertData(data); @@ -1044,7 +1043,7 @@ void WatchHandler::fetchMore(const QModelIndex &parent) m_inFetchMore = true; WatchData data = takeData(iname); - MODEL_DEBUG("FETCH MORE: " << parent << ":" << iname << data.name); + MODEL_DEBUG("FETCH MORE: " << parent << ':' << iname << data.name); if (!data.isValid()) { MODEL_DEBUG("FIXME: FETCH MORE, no data " << iname << "found"); diff --git a/src/plugins/debugger/watchhandler.h b/src/plugins/debugger/watchhandler.h index a41920381568e8c08c0fc5836566b4a6b7b8abd8..a31c8f0caec7675fe2085427a26a675df827103e 100644 --- a/src/plugins/debugger/watchhandler.h +++ b/src/plugins/debugger/watchhandler.h @@ -98,9 +98,11 @@ public: void setChildCount(int n) { childCount = n; setChildCountUnneeded(); if (n == 0) setChildrenUnneeded(); } + WatchData pointerChildPlaceHolder() const; + QString toString() const; bool isLocal() const { return iname.startsWith(QLatin1String("local.")); } - bool isWatcher() const { return iname.startsWith(QLatin1String("watch.")); }; + bool isWatcher() const { return iname.startsWith(QLatin1String("watch.")); } bool isValid() const { return !iname.isEmpty(); } public: @@ -165,8 +167,10 @@ public: Q_SLOT void removeWatchExpression(const QString &exp); void reinitializeWatchers(); - void collapseChildren(const QModelIndex &idx); - void expandChildren(const QModelIndex &idx); + Q_SLOT void collapseChildren(); + Q_SLOT void expandChildren(); + Q_SLOT void collapseChildren(const QString &iname); + Q_SLOT void expandChildren(const QString &iname); void rebuildModel(); // unconditionally version of above void showEditValue(const WatchData &data); diff --git a/src/plugins/debugger/watchutils.cpp b/src/plugins/debugger/watchutils.cpp new file mode 100644 index 0000000000000000000000000000000000000000..993bd1a914a53c78015db8f5c1918010c53156f0 --- /dev/null +++ b/src/plugins/debugger/watchutils.cpp @@ -0,0 +1,303 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Qt Software Information (qt-info@nokia.com) +** +** Commercial Usage +** +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** GNU Lesser General Public License Usage +** +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** +**************************************************************************/ + +#include "watchutils.h" + +#include <QtCore/QDebug> +#include <QtCore/QTime> +#include <QtCore/QStringList> + +namespace Debugger { +namespace Internal { + +QString dotEscape(QString str) +{ + const QChar dot = QLatin1Char('.'); + str.replace(QLatin1Char(' '), dot); + str.replace(QLatin1Char('\\'), dot); + str.replace(QLatin1Char('/'), dot); + return str; +} + +QString currentTime() +{ + return QTime::currentTime().toString(QLatin1String("hh:mm:ss.zzz")); +} + +bool isSkippableFunction(const QString &funcName, const QString &fileName) +{ + if (fileName.endsWith(QLatin1String("kernel/qobject.cpp"))) + return true; + if (fileName.endsWith(QLatin1String("kernel/moc_qobject.cpp"))) + return true; + if (fileName.endsWith(QLatin1String("kernel/qmetaobject.cpp"))) + return true; + if (fileName.endsWith(QLatin1String(".moc"))) + return true; + + if (funcName.endsWith("::qt_metacall")) + return true; + + return false; +} + +bool isLeavableFunction(const QString &funcName, const QString &fileName) +{ + if (funcName.endsWith(QLatin1String("QObjectPrivate::setCurrentSender"))) + return true; + if (fileName.endsWith(QLatin1String("kernel/qmetaobject.cpp")) + && funcName.endsWith(QLatin1String("QMetaObject::methodOffset"))) + return true; + if (fileName.endsWith(QLatin1String("kernel/qobject.h"))) + return true; + if (fileName.endsWith(QLatin1String("kernel/qobject.cpp")) + && funcName.endsWith(QLatin1String("QObjectConnectionListVector::at"))) + return true; + if (fileName.endsWith(QLatin1String("kernel/qobject.cpp")) + && funcName.endsWith(QLatin1String("~QObject"))) + return true; + if (fileName.endsWith(QLatin1String("thread/qmutex.cpp"))) + return true; + if (fileName.endsWith(QLatin1String("thread/qthread.cpp"))) + return true; + if (fileName.endsWith(QLatin1String("thread/qthread_unix.cpp"))) + return true; + if (fileName.endsWith(QLatin1String("thread/qmutex.h"))) + return true; + if (fileName.contains(QLatin1String("thread/qbasicatomic"))) + return true; + if (fileName.contains(QLatin1String("thread/qorderedmutexlocker_p"))) + return true; + if (fileName.contains(QLatin1String("arch/qatomic"))) + return true; + if (fileName.endsWith(QLatin1String("tools/qvector.h"))) + return true; + if (fileName.endsWith(QLatin1String("tools/qlist.h"))) + return true; + if (fileName.endsWith(QLatin1String("tools/qhash.h"))) + return true; + if (fileName.endsWith(QLatin1String("tools/qmap.h"))) + return true; + if (fileName.endsWith(QLatin1String("tools/qstring.h"))) + return true; + if (fileName.endsWith(QLatin1String("global/qglobal.h"))) + return true; + + return false; +} + +bool hasLetterOrNumber(const QString &exp) +{ + const QChar underscore = QLatin1Char('_'); + for (int i = exp.size(); --i >= 0; ) + if (exp.at(i).isLetterOrNumber() || exp.at(i) == underscore) + return true; + return false; +} + +bool hasSideEffects(const QString &exp) +{ + // FIXME: complete? + return exp.contains(QLatin1String("-=")) + || exp.contains(QLatin1String("+=")) + || exp.contains(QLatin1String("/=")) + || exp.contains(QLatin1String("*=")) + || exp.contains(QLatin1String("&=")) + || exp.contains(QLatin1String("|=")) + || exp.contains(QLatin1String("^=")) + || exp.contains(QLatin1String("--")) + || exp.contains(QLatin1String("++")); +} + +bool isKeyWord(const QString &exp) +{ + // FIXME: incomplete + return exp == QLatin1String("class") + || exp == QLatin1String("const") + || exp == QLatin1String("do") + || exp == QLatin1String("if") + || exp == QLatin1String("return") + || exp == QLatin1String("struct") + || exp == QLatin1String("template") + || exp == QLatin1String("void") + || exp == QLatin1String("volatile") + || exp == QLatin1String("while"); +} + +bool isPointerType(const QString &type) +{ + return type.endsWith(QLatin1Char('*')) || type.endsWith(QLatin1String("* const")); +} + +bool isAccessSpecifier(const QString &str) +{ + static const QStringList items = + QStringList() << QLatin1String("private") << QLatin1String("protected") << QLatin1String("public"); + return items.contains(str); +} + +bool startsWithDigit(const QString &str) +{ + return !str.isEmpty() && str.at(0).isDigit(); +} + +QString stripPointerType(QString type) +{ + if (type.endsWith(QLatin1Char('*'))) + type.chop(1); + if (type.endsWith(QLatin1String("* const"))) + type.chop(7); + if (type.endsWith(QLatin1Char(' '))) + type.chop(1); + return type; +} + +QString gdbQuoteTypes(const QString &type) +{ + // gdb does not understand sizeof(Core::IFile*). + // "sizeof('Core::IFile*')" is also not acceptable, + // it needs to be "sizeof('Core::IFile'*)" + // + // We never will have a perfect solution here (even if we had a full blown + // C++ parser as we do not have information on what is a type and what is + // a variable name. So "a<b>::c" could either be two comparisons of values + // 'a', 'b' and '::c', or a nested type 'c' in a template 'a<b>'. We + // assume here it is the latter. + //return type; + + // (*('myns::QPointer<myns::QObject>*'*)0x684060)" is not acceptable + // (*('myns::QPointer<myns::QObject>'**)0x684060)" is acceptable + if (isPointerType(type)) + return gdbQuoteTypes(stripPointerType(type)) + QLatin1Char('*'); + + QString accu; + QString result; + int templateLevel = 0; + + const QChar colon = QLatin1Char(':'); + const QChar singleQuote = QLatin1Char('\''); + const QChar lessThan = QLatin1Char('<'); + const QChar greaterThan = QLatin1Char('>'); + for (int i = 0; i != type.size(); ++i) { + const QChar c = type.at(i); + if (c.isLetterOrNumber() || c == QLatin1Char('_') || c == colon || c == QLatin1Char(' ')) { + accu += c; + } else if (c == lessThan) { + ++templateLevel; + accu += c; + } else if (c == greaterThan) { + --templateLevel; + accu += c; + } else if (templateLevel > 0) { + accu += c; + } else { + if (accu.contains(colon) || accu.contains(lessThan)) + result += singleQuote + accu + singleQuote; + else + result += accu; + accu.clear(); + result += c; + } + } + if (accu.contains(colon) || accu.contains(lessThan)) + result += singleQuote + accu + singleQuote; + else + result += accu; + //qDebug() << "GDB_QUOTING" << type << " TO " << result; + + return result; +} + +bool extractTemplate(const QString &type, QString *tmplate, QString *inner) +{ + // Input "Template<Inner1,Inner2,...>::Foo" will return "Template::Foo" in + // 'tmplate' and "Inner1@Inner2@..." etc in 'inner'. Result indicates + // whether parsing was successful + int level = 0; + bool skipSpace = false; + + for (int i = 0; i != type.size(); ++i) { + const QChar c = type.at(i); + if (c == QLatin1Char(' ') && skipSpace) { + skipSpace = false; + } else if (c == QLatin1Char('<')) { + *(level == 0 ? tmplate : inner) += c; + ++level; + } else if (c == QLatin1Char('>')) { + --level; + *(level == 0 ? tmplate : inner) += c; + } else if (c == QLatin1Char(',')) { + *inner += (level == 1) ? QLatin1Char('@') : QLatin1Char(','); + skipSpace = true; + } else { + *(level == 0 ? tmplate : inner) += c; + } + } + *tmplate = tmplate->trimmed(); + *tmplate = tmplate->remove(QLatin1String("<>")); + *inner = inner->trimmed(); + //qDebug() << "EXTRACT TEMPLATE: " << *tmplate << *inner << " FROM " << type; + return !inner->isEmpty(); +} + +QString extractTypeFromPTypeOutput(const QString &str) +{ + int pos0 = str.indexOf(QLatin1Char('=')); + int pos1 = str.indexOf(QLatin1Char('{')); + int pos2 = str.lastIndexOf(QLatin1Char('}')); + QString res = str; + if (pos0 != -1 && pos1 != -1 && pos2 != -1) + res = str.mid(pos0 + 2, pos1 - 1 - pos0) + + QLatin1String(" ... ") + str.right(str.size() - pos2); + return res.simplified(); +} + +bool isIntOrFloatType(const QString &type) +{ + static const QStringList types = QStringList() + << QLatin1String("char") << QLatin1String("int") << QLatin1String("short") + << QLatin1String("float") << QLatin1String("double") << QLatin1String("long") + << QLatin1String("bool") << QLatin1String("signed char") << QLatin1String("unsigned") + << QLatin1String("unsigned char") + << QLatin1String("unsigned int") << QLatin1String("unsigned long") + << QLatin1String("long long") << QLatin1String("unsigned long long"); + return types.contains(type); +} + +QString sizeofTypeExpression(const QString &type) +{ + if (type.endsWith(QLatin1Char('*'))) + return QLatin1String("sizeof(void*)"); + if (type.endsWith(QLatin1Char('>'))) + return QLatin1String("sizeof(") + type + QLatin1Char(')'); + return QLatin1String("sizeof(") + gdbQuoteTypes(type) + QLatin1Char(')'); +} + +} +} diff --git a/src/plugins/debugger/watchutils.h b/src/plugins/debugger/watchutils.h new file mode 100644 index 0000000000000000000000000000000000000000..6c7dbb9143acc75536c66589d7a7f07391c0fb00 --- /dev/null +++ b/src/plugins/debugger/watchutils.h @@ -0,0 +1,70 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Qt Software Information (qt-info@nokia.com) +** +** Commercial Usage +** +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** GNU Lesser General Public License Usage +** +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** +**************************************************************************/ + +#ifndef WATCHUTILS_H +#define WATCHUTILS_H + +#include <QtCore/QString> + +QT_BEGIN_NAMESPACE +class QString; +QT_END_NAMESPACE + +namespace Debugger { +namespace Internal { + +QString dotEscape(QString str); +QString currentTime(); +bool isSkippableFunction(const QString &funcName, const QString &fileName); +bool isLeavableFunction(const QString &funcName, const QString &fileName); + +inline bool isNameChar(char c) +{ + // could be 'stopped' or 'shlibs-added' + return (c >= 'a' && c <= 'z') || c == '-'; +} + +bool hasLetterOrNumber(const QString &exp); +bool hasSideEffects(const QString &exp); +bool isKeyWord(const QString &exp); +bool isPointerType(const QString &type); +bool isAccessSpecifier(const QString &str); +bool startsWithDigit(const QString &str); +QString stripPointerType(QString type); +QString gdbQuoteTypes(const QString &type); +bool extractTemplate(const QString &type, QString *tmplate, QString *inner); +QString extractTypeFromPTypeOutput(const QString &str); +bool isIntOrFloatType(const QString &type); +QString sizeofTypeExpression(const QString &type); + + +} // namespace Internal +} // namespace Debugger + +#endif // WATCHUTILS_H diff --git a/src/plugins/debugger/watchwindow.cpp b/src/plugins/debugger/watchwindow.cpp index de30e8f38065c5ca265f9acb38850821f1923bd6..e10d39319b68f80f7b2619ea542e19d8df444f99 100644 --- a/src/plugins/debugger/watchwindow.cpp +++ b/src/plugins/debugger/watchwindow.cpp @@ -125,19 +125,16 @@ WatchWindow::WatchWindow(Type type, QWidget *parent) void WatchWindow::expandNode(const QModelIndex &idx) { - //QModelIndex mi0 = idx.sibling(idx.row(), 0); - //QString iname = model()->data(mi0, INameRole).toString(); - //QString name = model()->data(mi0, Qt::DisplayRole).toString(); - emit requestExpandChildren(idx); + QModelIndex mi0 = idx.sibling(idx.row(), 0); + QVariant iname = model()->data(mi0, INameRole); + theDebuggerAction(ExpandItem)->trigger(iname); } void WatchWindow::collapseNode(const QModelIndex &idx) { - //QModelIndex mi0 = idx.sibling(idx.row(), 0); - //QString iname = model()->data(mi0, INameRole).toString(); - //QString name = model()->data(mi0, Qt::DisplayRole).toString(); - //qDebug() << "COLLAPSE NODE " << idx; - emit requestCollapseChildren(idx); + QModelIndex mi0 = idx.sibling(idx.row(), 0); + QVariant iname = model()->data(mi0, INameRole); + theDebuggerAction(CollapseItem)->trigger(iname); } void WatchWindow::keyPressEvent(QKeyEvent *ev) @@ -218,16 +215,13 @@ void WatchWindow::editItem(const QModelIndex &idx) void WatchWindow::reset() { + QTreeView::reset(); int row = 0; if (m_type == TooltipType) row = 1; else if (m_type == WatchersType) row = 2; - //qDebug() << "WATCHWINDOW::RESET" << row; - QTreeView::reset(); setRootIndex(model()->index(row, 0, model()->index(0, 0))); - //setRootIndex(model()->index(0, 0)); - resetHelper(model()->index(0, 0)); } void WatchWindow::setModel(QAbstractItemModel *model) @@ -239,16 +233,27 @@ void WatchWindow::setModel(QAbstractItemModel *model) header()->setResizeMode(QHeaderView::ResizeToContents); if (m_type != LocalsType) header()->hide(); + + connect(model, SIGNAL(layoutChanged()), this, SLOT(resetHelper())); +} + +void WatchWindow::resetHelper() +{ + resetHelper(model()->index(0, 0)); } void WatchWindow::resetHelper(const QModelIndex &idx) { if (model()->data(idx, ExpandedRole).toBool()) { + //qDebug() << "EXPANDING " << model()->data(idx, INameRole); expand(idx); for (int i = 0, n = model()->rowCount(idx); i != n; ++i) { QModelIndex idx1 = model()->index(i, 0, idx); resetHelper(idx1); } + } else { + //qDebug() << "COLLAPSING " << model()->data(idx, INameRole); + collapse(idx); } } diff --git a/src/plugins/debugger/watchwindow.h b/src/plugins/debugger/watchwindow.h index bf6995edb4adae1bee3eb4310b771bac9e595cc2..715507f8b16df9cef441cebd960581a11e02d9e4 100644 --- a/src/plugins/debugger/watchwindow.h +++ b/src/plugins/debugger/watchwindow.h @@ -57,15 +57,11 @@ public slots: void setAlwaysResizeColumnsToContents(bool on = true); void setModel(QAbstractItemModel *model); -signals: - void requestExpandChildren(const QModelIndex &idx); - void requestCollapseChildren(const QModelIndex &idx); - -private slots: - void expandNode(const QModelIndex &index); - void collapseNode(const QModelIndex &index); - private: + Q_SLOT void expandNode(const QModelIndex &index); + Q_SLOT void collapseNode(const QModelIndex &index); + Q_SLOT void resetHelper(); + void keyPressEvent(QKeyEvent *ev); void contextMenuEvent(QContextMenuEvent *ev); void editItem(const QModelIndex &idx); diff --git a/src/plugins/designer/formeditorplugin.cpp b/src/plugins/designer/formeditorplugin.cpp index 3052c1735855fcd76bc38302eab57c74d2b56546..d77c4af23b9dd32d6fab1153c213a468183268b6 100644 --- a/src/plugins/designer/formeditorplugin.cpp +++ b/src/plugins/designer/formeditorplugin.cpp @@ -46,6 +46,7 @@ #include <QtCore/QtPlugin> #include <QtCore/QDebug> +#include <QtCore/QProcess> #ifdef CPP_ENABLED # include <QtGui/QAction> @@ -100,12 +101,19 @@ bool FormEditorPlugin::initialize(const QStringList &arguments, QString *error) m_factory = new FormEditorFactory; addObject(m_factory); - // Make sure settings pages and action shortcuts are registered - // TODO we don't want to do a full initialization here, - // we actually want to call ensureInitStage(FormEditorW::RegisterPlugins) - // But due to a bug in kde 4.2.0 this crashes then when opening the file dialog - // This should be removed after 4.2.1 is out - FormEditorW::ensureInitStage(FormEditorW::FullyInitialized); + if (qgetenv("KDE_SESSION_VERSION") == QByteArray("4")) { + // KDE 4, possibly dangerous... + // KDE 4.2.0 had a nasty bug, which resulted in the File/Open Dialog crashing + // so check for that an fully load the plugins + QProcess proc; + proc.start("kde4-config", QStringList() << "--version"); + proc.waitForFinished(); + QString output = proc.readAll(); + if (output.contains("KDE: 4.2.0")) + FormEditorW::ensureInitStage(FormEditorW::FullyInitialized); + } else { + FormEditorW::ensureInitStage(FormEditorW::RegisterPlugins); + } error->clear(); return true; diff --git a/src/plugins/fakevim/fakevimhandler.cpp b/src/plugins/fakevim/fakevimhandler.cpp index 985d4db096d9972d238a455fc3bbf25a382843ec..08f13aec960adbcbc35b497c770227dbbd2f68d1 100644 --- a/src/plugins/fakevim/fakevimhandler.cpp +++ b/src/plugins/fakevim/fakevimhandler.cpp @@ -358,6 +358,7 @@ public: // extra data for '.' QString m_dotCommand; + bool m_inReplay; // true if we are executing a '.' // extra data for ';' QString m_semicolonCount; @@ -366,11 +367,11 @@ public: // history for '/' QString lastSearchString() const; - QStringList m_searchHistory; + static QStringList m_searchHistory; int m_searchHistoryIndex; // history for ':' - QStringList m_commandHistory; + static QStringList m_commandHistory; int m_commandHistoryIndex; // visual line mode @@ -403,6 +404,9 @@ public: QList<QTextEdit::ExtraSelection> m_searchSelections; }; +QStringList FakeVimHandler::Private::m_searchHistory; +QStringList FakeVimHandler::Private::m_commandHistory; + FakeVimHandler::Private::Private(FakeVimHandler *parent, QWidget *widget) { q = parent; @@ -424,8 +428,9 @@ FakeVimHandler::Private::Private(FakeVimHandler *parent, QWidget *widget) m_anchor = 0; m_savedYankPosition = 0; m_cursorWidth = EDITOR(cursorWidth()); + m_inReplay = false; -#if 1 +#if 0 // Plain m_config[ConfigStartOfLine] = ConfigOn; m_config[ConfigHlSearch] = ConfigOn; @@ -1012,9 +1017,11 @@ EventResult FakeVimHandler::Private::handleCommandMode(int key, int unmodified, qDebug() << "REPEATING" << m_dotCommand; QString savedCommand = m_dotCommand; m_dotCommand.clear(); + m_inReplay = true; for (int i = count(); --i >= 0; ) foreach (QChar c, savedCommand) handleKey(c.unicode(), c.unicode(), QString(c)); + m_inReplay = false; enterCommandMode(); m_dotCommand = savedCommand; } else if (key == '<' && m_visualMode == NoVisualMode) { @@ -1413,10 +1420,14 @@ EventResult FakeVimHandler::Private::handleCommandMode(int key, int unmodified, recordInsertText(str); recordEndGroup(); } else if (key == Key_PageDown || key == control('f')) { - moveDown(count() * (linesOnScreen() - 2)); + moveDown(count() * (linesOnScreen() - 2) - cursorLineOnScreen()); + scrollToLineInDocument(cursorLineInDocument()); + moveToFirstNonBlankOnLine(); finishMovement(); } else if (key == Key_PageUp || key == control('b')) { - moveUp(count() * (linesOnScreen() - 2)); + moveUp(count() * (linesOnScreen() - 2) + cursorLineOnScreen()); + scrollToLineInDocument(cursorLineInDocument() + linesOnScreen() - 2); + moveToFirstNonBlankOnLine(); finishMovement(); } else if (key == Key_Delete) { setAnchor(); @@ -1512,6 +1523,9 @@ EventResult FakeVimHandler::Private::handleInsertMode(int key, int, if (leftText.simplified().isEmpty()) indentRegion(text.at(0)); } + + if (!m_inReplay) + emit q->completionRequested(); } else { return EventUnhandled; } diff --git a/src/plugins/fakevim/fakevimhandler.h b/src/plugins/fakevim/fakevimhandler.h index d7d978c9d8a90b5c7824f5ecaf79b222bb3d7660..7b5b183cf341af61ddecee3fb43caeb5d98bdfc8 100644 --- a/src/plugins/fakevim/fakevimhandler.h +++ b/src/plugins/fakevim/fakevimhandler.h @@ -77,6 +77,7 @@ signals: const QString &fileName, const QString &contents); void moveToMatchingParenthesis(bool *moved, bool *forward, QTextCursor *cursor); void indentRegion(int *amount, int beginLine, int endLine, QChar typedChar); + void completionRequested(); private: bool eventFilter(QObject *ob, QEvent *ev); diff --git a/src/plugins/fakevim/fakevimplugin.cpp b/src/plugins/fakevim/fakevimplugin.cpp index ee632a1acba1ca83cc1f80359d9256cf1a984aad..65e907cdd8f2e44432fab5798f2c9301a0249bd0 100644 --- a/src/plugins/fakevim/fakevimplugin.cpp +++ b/src/plugins/fakevim/fakevimplugin.cpp @@ -47,6 +47,7 @@ #include <texteditor/basetexteditor.h> #include <texteditor/basetextmark.h> +#include <texteditor/completionsupport.h> #include <texteditor/itexteditor.h> #include <texteditor/texteditorconstants.h> #include <texteditor/interactionsettings.h> @@ -116,6 +117,7 @@ private slots: void installHandlerOnCurrentEditor(); void installHandler(Core::IEditor *editor); void removeHandler(); + void triggerCompletions(); void showCommandBuffer(const QString &contents); void showExtraInformation(const QString &msg); @@ -208,6 +210,8 @@ void FakeVimPluginPrivate::installHandler(Core::IEditor *editor) this, SLOT(moveToMatchingParenthesis(bool*,bool*,QTextCursor*))); connect(handler, SIGNAL(indentRegion(int*,int,int,QChar)), this, SLOT(indentRegion(int*,int,int,QChar))); + connect(handler, SIGNAL(completionRequested()), + this, SLOT(triggerCompletions())); handler->setupWidget(); handler->setExtraData(editor); @@ -235,6 +239,17 @@ void FakeVimPluginPrivate::installHandlerOnCurrentEditor() installHandler(EditorManager::instance()->currentEditor()); } +void FakeVimPluginPrivate::triggerCompletions() +{ + FakeVimHandler *handler = qobject_cast<FakeVimHandler *>(sender()); + if (!handler) + return; + if (BaseTextEditor *bt = qobject_cast<BaseTextEditor *>(handler->widget())) + TextEditor::Internal::CompletionSupport::instance()-> + autoComplete(bt->editableInterface(), false); + // bt->triggerCompletions(); +} + void FakeVimPluginPrivate::writeFile(bool *handled, const QString &fileName, const QString &contents) { diff --git a/src/plugins/git/gitsubmiteditor.cpp b/src/plugins/git/gitsubmiteditor.cpp index 1f082e5188db6fe4feb8d2f9c6baa0a9646f1774..4de97513fd37ba7a62a28db7cb782d3be4c97cc5 100644 --- a/src/plugins/git/gitsubmiteditor.cpp +++ b/src/plugins/git/gitsubmiteditor.cpp @@ -35,6 +35,7 @@ #include <vcsbase/submitfilemodel.h> #include <QtCore/QDebug> +#include <QtCore/QStringList> namespace Git { namespace Internal { @@ -121,6 +122,25 @@ void GitSubmitEditor::slotDiffSelected(const QStringList &files) emit diff(unstagedFiles, stagedFiles); } +QString GitSubmitEditor::fileContents() const +{ + // We need to manually purge out comment lines starting with + // hash '#' since git does not do that when using -F. + const QChar newLine = QLatin1Char('\n'); + const QChar hash = QLatin1Char('#'); + QString message = VCSBase::VCSBaseSubmitEditor::fileContents(); + for (int pos = 0; pos < message.size(); ) { + const int newLinePos = message.indexOf(newLine, pos); + const int startOfNextLine = newLinePos == -1 ? message.size() : newLinePos + 1; + if (message.at(pos) == hash) { + message.remove(pos, startOfNextLine - pos); + } else { + pos = startOfNextLine; + } + } + return message; +} + GitSubmitEditorPanelData GitSubmitEditor::panelData() const { return const_cast<GitSubmitEditor*>(this)->submitEditorWidget()->panelData(); diff --git a/src/plugins/git/gitsubmiteditor.h b/src/plugins/git/gitsubmiteditor.h index a2c97e05e2a715f26fd69d3931ec18132e3899b2..88f4dba8e131a4b8e449a4784d1d8a40c56cde47 100644 --- a/src/plugins/git/gitsubmiteditor.h +++ b/src/plugins/git/gitsubmiteditor.h @@ -54,6 +54,8 @@ public: void setCommitData(const CommitData &); GitSubmitEditorPanelData panelData() const; + virtual QString fileContents() const; + signals: void diff(const QStringList &unstagedFiles, const QStringList &stagedFiles); diff --git a/src/plugins/git/gitsubmiteditorwidget.cpp b/src/plugins/git/gitsubmiteditorwidget.cpp index a8749431771de27fdb82bca817a004734bfdf276..4fcbc20722072c18d0b3a68811c5e116fad7ac4b 100644 --- a/src/plugins/git/gitsubmiteditorwidget.cpp +++ b/src/plugins/git/gitsubmiteditorwidget.cpp @@ -30,15 +30,92 @@ #include "gitsubmiteditorwidget.h" #include "commitdata.h" +#include <texteditor/texteditorsettings.h> +#include <texteditor/fontsettings.h> +#include <texteditor/texteditorconstants.h> + +#include <QtGui/QSyntaxHighlighter> +#include <QtGui/QTextEdit> + +#include <QtCore/QDebug> +#include <QtCore/QRegExp> + namespace Git { namespace Internal { +// Retrieve the comment char format from the text editor. +static QTextCharFormat commentFormat() +{ + const TextEditor::FontSettings settings = TextEditor::TextEditorSettings::instance()->fontSettings(); + return settings.toTextCharFormat(QLatin1String(TextEditor::Constants::C_COMMENT)); +} + +// Highlighter for git submit messages. Make the first line bold, indicates +// comments as such (retrieving the format from the text editor) and marks up +// keywords (words in front of a colon as in 'Task: <bla>'). + +class GitSubmitHighlighter : QSyntaxHighlighter { +public: + explicit GitSubmitHighlighter(QTextEdit *parent); + virtual void highlightBlock(const QString &text); + +private: + enum State { Header, Comment, Other }; + const QTextCharFormat m_commentFormat; + const QRegExp m_keywordPattern; + const QChar m_hashChar; +}; + +GitSubmitHighlighter::GitSubmitHighlighter(QTextEdit * parent) : + QSyntaxHighlighter(parent), + m_commentFormat(commentFormat()), + m_keywordPattern(QLatin1String("^\\w+:")), + m_hashChar(QLatin1Char('#')) +{ + Q_ASSERT(m_keywordPattern.isValid()); +} + +void GitSubmitHighlighter::highlightBlock(const QString &text) +{ + // figure out current state + State state = Other; + const QTextBlock block = currentBlock(); + if (block.position() == 0) { + state = Header; + } else { + if (text.startsWith(m_hashChar)) + state = Comment; + } + // Apply format. + switch (state) { + case Header: { + QTextCharFormat charFormat = format(0); + charFormat.setFontWeight(QFont::Bold); + setFormat(0, text.size(), charFormat); + } + break; + case Comment: + setFormat(0, text.size(), m_commentFormat); + break; + case Other: + // Format key words ("Task:") italic + if (m_keywordPattern.indexIn(text, 0, QRegExp::CaretAtZero) == 0) { + QTextCharFormat charFormat = format(0); + charFormat.setFontItalic(true); + setFormat(0, m_keywordPattern.matchedLength(), charFormat); + } + break; + } +} + +// ------------------ GitSubmitEditorWidget::GitSubmitEditorWidget(QWidget *parent) : Core::Utils::SubmitEditorWidget(parent), m_gitSubmitPanel(new QWidget) { m_gitSubmitPanelUi.setupUi(m_gitSubmitPanel); insertTopWidget(m_gitSubmitPanel); + new GitSubmitHighlighter(descriptionEdit()); } void GitSubmitEditorWidget::setPanelInfo(const GitSubmitEditorPanelInfo &info) diff --git a/src/plugins/projectexplorer/applicationrunconfiguration.h b/src/plugins/projectexplorer/applicationrunconfiguration.h index 6fd9c993c1566095662926feb1e4c48957396426..e23818c1f9fedd956a7ca560d1b48b7cfce40ac0 100644 --- a/src/plugins/projectexplorer/applicationrunconfiguration.h +++ b/src/plugins/projectexplorer/applicationrunconfiguration.h @@ -54,6 +54,7 @@ public: virtual QString workingDirectory() const = 0; virtual QStringList commandLineArguments() const = 0; virtual Environment environment() const = 0; + virtual QString dumperLibrary() const = 0; virtual void save(PersistentSettingsWriter &writer) const; virtual void restore(const PersistentSettingsReader &reader); diff --git a/src/plugins/projectexplorer/customexecutablerunconfiguration.cpp b/src/plugins/projectexplorer/customexecutablerunconfiguration.cpp index 06ab960e35690090a4deac6826c6cb03d2dba7c9..47a1748f4e72ddc99aebfbfcc51974ee22de4e1a 100644 --- a/src/plugins/projectexplorer/customexecutablerunconfiguration.cpp +++ b/src/plugins/projectexplorer/customexecutablerunconfiguration.cpp @@ -308,6 +308,13 @@ void CustomExecutableRunConfiguration::setUserName(const QString &name) emit changed(); } +QString CustomExecutableRunConfiguration::dumperLibrary() const +{ + return QString(); +} + + + // Factory CustomExecutableRunConfigurationFactory::CustomExecutableRunConfigurationFactory() diff --git a/src/plugins/projectexplorer/customexecutablerunconfiguration.h b/src/plugins/projectexplorer/customexecutablerunconfiguration.h index 6d2ca1755a35e2f62e3c3753a8734effaeb78d87..107c889f954c4e9e72128612af856ababa7f03ca 100644 --- a/src/plugins/projectexplorer/customexecutablerunconfiguration.h +++ b/src/plugins/projectexplorer/customexecutablerunconfiguration.h @@ -86,6 +86,7 @@ public: virtual void restore(const PersistentSettingsReader &reader); virtual QWidget *configurationWidget(); + virtual QString dumperLibrary() const; signals: void changed(); diff --git a/src/plugins/qt4projectmanager/gdbmacrosbuildstep.cpp b/src/plugins/qt4projectmanager/gdbmacrosbuildstep.cpp deleted file mode 100644 index 4fe0dc00045c8b9ad57e9e72eedcb5a8edcac8a3..0000000000000000000000000000000000000000 --- a/src/plugins/qt4projectmanager/gdbmacrosbuildstep.cpp +++ /dev/null @@ -1,229 +0,0 @@ -/************************************************************************** -** -** This file is part of Qt Creator -** -** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). -** -** Contact: Qt Software Information (qt-info@nokia.com) -** -** Commercial Usage -** -** Licensees holding valid Qt Commercial licenses may use this file in -** accordance with the Qt Commercial License Agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and Nokia. -** -** GNU Lesser General Public License Usage -** -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** If you are unsure which license is appropriate for your use, please -** contact the sales department at qt-sales@nokia.com. -** -**************************************************************************/ - -#include "gdbmacrosbuildstep.h" - -#include "makestep.h" -#include "qmakestep.h" -#include "qt4project.h" -#include "qt4projectmanagerconstants.h" - -#include <coreplugin/icore.h> -#include <utils/qtcassert.h> - -#include <QFileInfo> - -using namespace Qt4ProjectManager; -using namespace Qt4ProjectManager::Internal; - -GdbMacrosBuildStep::GdbMacrosBuildStep(Qt4Project *project) - : BuildStep(project), m_project(project) -{ -} - -GdbMacrosBuildStep::~GdbMacrosBuildStep() -{ -} - -bool GdbMacrosBuildStep::init(const QString &buildConfiguration) -{ - m_buildDirectory = m_project->buildDirectory(buildConfiguration); - m_qmake = m_project->qtVersion(buildConfiguration)->qmakeCommand(); - m_buildConfiguration = buildConfiguration; - return true; -} - -void GdbMacrosBuildStep::run(QFutureInterface<bool> & fi) -{ - QStringList files; - files << "gdbmacros.cpp" << "gdbmacros.pro" - << "LICENSE.LGPL" << "LGPL_EXCEPTION.TXT"; - - QVariant v = value("clean"); - if (v.isNull() || v.toBool() == false) { - addToOutputWindow("<b>Creating gdb macros library...</b>"); - // Normal run - QString dumperPath = Core::ICore::instance()->resourcePath() + "/gdbmacros/"; - QString destDir = m_buildDirectory + "/qtc-gdbmacros/"; - QDir dir; - dir.mkpath(destDir); - foreach (const QString &file, files) { - QString source = dumperPath + file; - QString dest = destDir + file; - QFileInfo destInfo(dest); - if (destInfo.exists()) { - if (destInfo.lastModified() >= QFileInfo(source).lastModified()) - continue; - QFile::remove(dest); - } - QFile::copy(source, dest); - } - - Qt4Project *qt4Project = static_cast<Qt4Project *>(project()); - - QProcess qmake; - qmake.setEnvironment(qt4Project->environment(m_buildConfiguration).toStringList()); - qmake.setWorkingDirectory(destDir); - QStringList configarguments; - QStringList makeArguments; - - // Find qmake step... - QMakeStep *qmakeStep = qt4Project->qmakeStep(); - // Find out which configuration is used in this build configuration - // and what kind of CONFIG we need to pass to qmake for that - if (qmakeStep->value(m_buildConfiguration, "buildConfiguration").isValid()) { - QtVersion::QmakeBuildConfig defaultBuildConfiguration = qt4Project->qtVersion(m_buildConfiguration)->defaultBuildConfig(); - QtVersion::QmakeBuildConfig projectBuildConfiguration = QtVersion::QmakeBuildConfig(qmakeStep->value(m_buildConfiguration, "buildConfiguration").toInt()); - if ((defaultBuildConfiguration & QtVersion::BuildAll) && !(projectBuildConfiguration & QtVersion::BuildAll)) - configarguments << "CONFIG-=debug_and_release"; - if (!(defaultBuildConfiguration & QtVersion::BuildAll) && (projectBuildConfiguration & QtVersion::BuildAll)) - configarguments << "CONFIG+=debug_and_release"; - if ((defaultBuildConfiguration & QtVersion::DebugBuild) && !(projectBuildConfiguration & QtVersion::DebugBuild)) - configarguments << "CONFIG+=release"; - if (!(defaultBuildConfiguration & QtVersion::DebugBuild) && (projectBuildConfiguration & QtVersion::DebugBuild)) - configarguments << "CONFIG+=debug"; - if (projectBuildConfiguration & QtVersion::BuildAll) - makeArguments << (projectBuildConfiguration & QtVersion::DebugBuild ? "debug" : "release"); - - } else { - // Old style with CONFIG+=debug_and_release - configarguments << "CONFIG+=debug_and_release"; - const MakeStep *ms = qt4Project->makeStep(); - QStringList makeargs = ms->value(m_buildConfiguration, "makeargs").toStringList(); - if (makeargs.contains("debug")) { - makeArguments << "debug"; - } else if (makeargs.contains("release")) { - makeArguments << "release"; - } - } - - QString mkspec = qt4Project->qtVersion(m_buildConfiguration)->mkspec(); - qmake.start(m_qmake, QStringList()<<"-spec"<<mkspec<<configarguments<<"gdbmacros.pro"); - qmake.waitForFinished(); - - QString makeCmd = qt4Project->makeCommand(m_buildConfiguration); - if (!value(m_buildConfiguration, "makeCmd").toString().isEmpty()) - makeCmd = value(m_buildConfiguration, "makeCmd").toString(); - if (!QFileInfo(makeCmd).isAbsolute()) { - // Try to detect command in environment - QString tmp = qt4Project->environment(m_buildConfiguration).searchInPath(makeCmd); - makeCmd = tmp; - } - qmake.start(makeCmd, makeArguments); - qmake.waitForFinished(); - - fi.reportResult(true); - } else { - // Clean step, we want to remove the directory - QString destDir = m_buildDirectory + "/qtc-gdbmacros/"; - Qt4Project *qt4Project = static_cast<Qt4Project *>(project()); - - QProcess make; - make.setEnvironment(qt4Project->environment(m_buildConfiguration).toStringList()); - make.setWorkingDirectory(destDir); - make.start(qt4Project->makeCommand(m_buildConfiguration), QStringList()<<"distclean"); - make.waitForFinished(); - - QStringList directories; - directories << "debug" - << "release"; - - foreach(const QString &file, files) { - QFile destination(destDir + file); - destination.remove(); - } - - foreach(const QString &dir, directories) { - QDir destination(destDir + dir); - destination.rmdir(destDir + dir); - } - - QDir(destDir).rmdir(destDir); - fi.reportResult(true); - } -} - -QString GdbMacrosBuildStep::name() -{ - return Constants::GDBMACROSBUILDSTEP; -} - -QString GdbMacrosBuildStep::displayName() -{ - return "Gdb Macros Build"; -} - -ProjectExplorer::BuildStepConfigWidget *GdbMacrosBuildStep::createConfigWidget() -{ - return new GdbMacrosBuildStepConfigWidget; -} - -bool GdbMacrosBuildStep::immutable() const -{ - return false; -} - -bool GdbMacrosBuildStepFactory::canCreate(const QString &name) const -{ - return name == Constants::GDBMACROSBUILDSTEP; -} - -ProjectExplorer::BuildStep *GdbMacrosBuildStepFactory::create(ProjectExplorer::Project *pro, const QString &name) const -{ - Q_ASSERT(name == Constants::GDBMACROSBUILDSTEP); - Qt4Project *qt4project = qobject_cast<Qt4Project *>(pro); - Q_ASSERT(qt4project); - return new GdbMacrosBuildStep(qt4project); -} - -QStringList GdbMacrosBuildStepFactory::canCreateForProject(ProjectExplorer::Project *pro) const -{ - QStringList results; - if (qobject_cast<Qt4Project *>(pro)) - results << Constants::GDBMACROSBUILDSTEP; - return results; -} - -QString GdbMacrosBuildStepFactory::displayNameForName(const QString &name) const -{ - if (name == Constants::GDBMACROSBUILDSTEP) - return "Gdb Macros Build"; - else - return QString::null; -} - -QString GdbMacrosBuildStepConfigWidget::displayName() const -{ - return "Gdb Macros Build"; -} - -void GdbMacrosBuildStepConfigWidget::init(const QString & /*buildConfiguration*/) -{ - // TODO -} diff --git a/src/plugins/qt4projectmanager/gdbmacrosbuildstep.h b/src/plugins/qt4projectmanager/gdbmacrosbuildstep.h deleted file mode 100644 index ba78a0f6321564df173af8c35d5a61b705212ebb..0000000000000000000000000000000000000000 --- a/src/plugins/qt4projectmanager/gdbmacrosbuildstep.h +++ /dev/null @@ -1,79 +0,0 @@ -/************************************************************************** -** -** This file is part of Qt Creator -** -** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). -** -** Contact: Qt Software Information (qt-info@nokia.com) -** -** Commercial Usage -** -** Licensees holding valid Qt Commercial licenses may use this file in -** accordance with the Qt Commercial License Agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and Nokia. -** -** GNU Lesser General Public License Usage -** -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** If you are unsure which license is appropriate for your use, please -** contact the sales department at qt-sales@nokia.com. -** -**************************************************************************/ - -#ifndef GDBMACROSBUILDSTEP_H -#define GDBMACROSBUILDSTEP_H - -#include <projectexplorer/buildstep.h> - -namespace Qt4ProjectManager { -class Qt4Project; -namespace Internal { -class GdbMacrosBuildStepConfigWidget; - -class GdbMacrosBuildStep : public ProjectExplorer::BuildStep -{ - Q_OBJECT -public: - GdbMacrosBuildStep(Qt4Project * project); - virtual ~GdbMacrosBuildStep(); - virtual bool init(const QString &buildConfiguration); - virtual void run(QFutureInterface<bool> &); - virtual QString name(); - virtual QString displayName(); - virtual ProjectExplorer::BuildStepConfigWidget *createConfigWidget(); - virtual bool immutable() const; -private: - Qt4Project *m_project; - QString m_buildDirectory; - QString m_qmake; - QString m_buildConfiguration; -}; - -class GdbMacrosBuildStepFactory : public ProjectExplorer::IBuildStepFactory -{ - Q_OBJECT -public: - 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; - -}; - -class GdbMacrosBuildStepConfigWidget : public ProjectExplorer::BuildStepConfigWidget -{ - virtual QString displayName() const; - virtual void init(const QString &buildConfiguration); -}; - -} // namespace Internal -} // namespace Qt4ProjectManager - -#endif // GDBMACROSBUILDSTEP_H diff --git a/src/plugins/qt4projectmanager/qt4project.cpp b/src/plugins/qt4projectmanager/qt4project.cpp index cf496f991bbc8b84e64ec82e268310130b6a47a0..36901bbc1c395f31e845ca7cff87f15147914f8d 100644 --- a/src/plugins/qt4projectmanager/qt4project.cpp +++ b/src/plugins/qt4projectmanager/qt4project.cpp @@ -42,7 +42,6 @@ #include "qt4buildenvironmentwidget.h" #include "qt4projectmanagerconstants.h" #include "projectloadwizard.h" -#include "gdbmacrosbuildstep.h" #include <coreplugin/icore.h> #include <coreplugin/messagemanager.h> @@ -656,10 +655,6 @@ void Qt4Project::addDefaultBuild() //TODO have a better check wheter there is already a configuration? QMakeStep *qmakeStep = 0; MakeStep *makeStep = 0; - GdbMacrosBuildStep *gdbmacrostep; - - gdbmacrostep = new GdbMacrosBuildStep(this); - insertBuildStep(0, gdbmacrostep); qmakeStep = new QMakeStep(this); qmakeStep->setValue("mkspec", ""); @@ -668,10 +663,6 @@ void Qt4Project::addDefaultBuild() makeStep = new MakeStep(this); insertBuildStep(2, makeStep); - GdbMacrosBuildStep *gdbmacrosCleanStep = new GdbMacrosBuildStep(this); - gdbmacrosCleanStep->setValue("clean", true); - insertCleanStep(0, gdbmacrosCleanStep); - MakeStep* cleanStep = new MakeStep(this); cleanStep->setValue("clean", true); insertCleanStep(1, cleanStep); @@ -680,25 +671,6 @@ void Qt4Project::addDefaultBuild() wizard.execDialog(); } else { // Restoring configuration - // Do we already have a gdbmacrobuildstep? - // If not add it and disable linking of debugging helper - - // Check for old link debugging helper setting in each buildConfiguration - // We add a gdbmacrosbuildstep if at least one has it - // TODO remove migration code from pre beta - foreach(const QString &bc, buildConfigurations()) { - QVariant v = value(bc, "addQDumper"); - if (v.isValid() && v.toBool()) { - GdbMacrosBuildStep *gdbmacrostep = new GdbMacrosBuildStep(this); - insertBuildStep(0, gdbmacrostep); - - GdbMacrosBuildStep *gdbmacrosCleanStep = new GdbMacrosBuildStep(this); - gdbmacrosCleanStep->setValue("clean", true); - insertCleanStep(0, gdbmacrosCleanStep ); - break; - } - } - foreach(const QString &bc, buildConfigurations()) { setValue(bc, "addQDumper", QVariant()); } diff --git a/src/plugins/qt4projectmanager/qt4projectmanager.pro b/src/plugins/qt4projectmanager/qt4projectmanager.pro index 04ac5d8067be1459f3427055fda69ed6bf792b4c..98e9527470688f5d15613d73434569a9ce1f42ad 100644 --- a/src/plugins/qt4projectmanager/qt4projectmanager.pro +++ b/src/plugins/qt4projectmanager/qt4projectmanager.pro @@ -35,8 +35,7 @@ HEADERS = qt4projectmanagerplugin.h \ qt4buildconfigwidget.h \ qt4buildenvironmentwidget.h \ projectloadwizard.h \ - directorywatcher.h \ - gdbmacrosbuildstep.h + directorywatcher.h SOURCES = qt4projectmanagerplugin.cpp \ qt4projectmanager.cpp \ qtversionmanager.cpp \ @@ -67,8 +66,7 @@ SOURCES = qt4projectmanagerplugin.cpp \ qt4buildconfigwidget.cpp \ qt4buildenvironmentwidget.cpp \ projectloadwizard.cpp \ - directorywatcher.cpp \ - gdbmacrosbuildstep.cpp + directorywatcher.cpp FORMS = qtversionmanager.ui \ envvariablespage.ui \ enveditdialog.ui \ @@ -77,7 +75,8 @@ FORMS = qtversionmanager.ui \ qmakestep.ui \ qt4buildconfigwidget.ui \ embeddedpropertiespage.ui \ - qt4buildenvironmentwidget.ui + qt4buildenvironmentwidget.ui \ + showbuildlog.ui RESOURCES = qt4projectmanager.qrc \ wizards/wizards.qrc include(../../shared/proparser/proparser.pri) diff --git a/src/plugins/qt4projectmanager/qt4projectmanagerconstants.h b/src/plugins/qt4projectmanager/qt4projectmanagerconstants.h index f916effd0cf5f3d075db1a1ad15aa9a86188ec5c..14f77bdbbb6e464f34b846e3702063e1d98079a3 100644 --- a/src/plugins/qt4projectmanager/qt4projectmanagerconstants.h +++ b/src/plugins/qt4projectmanager/qt4projectmanagerconstants.h @@ -71,7 +71,6 @@ const char * const GC_COMPILER = "Qt4.Compiler"; // qmakestep const char * const QMAKESTEP = "trolltech.qt4projectmanager.qmake"; const char * const MAKESTEP = "trolltech.qt4projectmanager.make"; -const char * const GDBMACROSBUILDSTEP = "trolltech.qt4projectmanager.gdbmaros"; const char * const QT4RUNSTEP = "trolltech.qt4projectmanager.qt4runstep"; const char * const DEPLOYHELPERRUNSTEP = "trolltech.qt4projectmanager.deployhelperrunstep"; diff --git a/src/plugins/qt4projectmanager/qt4projectmanagerplugin.cpp b/src/plugins/qt4projectmanager/qt4projectmanagerplugin.cpp index cc37449efc1cec27df3e880c884df46bffea136a..529a927279487d3c0b44dc189b5ab8e35ecbd107 100644 --- a/src/plugins/qt4projectmanager/qt4projectmanagerplugin.cpp +++ b/src/plugins/qt4projectmanager/qt4projectmanagerplugin.cpp @@ -41,7 +41,6 @@ #include "embeddedpropertiespage.h" #include "qt4runconfiguration.h" #include "profilereader.h" -#include "gdbmacrosbuildstep.h" #include <coreplugin/icore.h> #include <extensionsystem/pluginmanager.h> @@ -125,7 +124,6 @@ bool Qt4ProjectManagerPlugin::initialize(const QStringList &arguments, QString * addAutoReleasedObject(new QMakeBuildStepFactory); addAutoReleasedObject(new MakeBuildStepFactory); - addAutoReleasedObject(new GdbMacrosBuildStepFactory); m_qtVersionManager = new QtVersionManager; addObject(m_qtVersionManager); diff --git a/src/plugins/qt4projectmanager/qt4runconfiguration.cpp b/src/plugins/qt4projectmanager/qt4runconfiguration.cpp index fea2b436ee0fb003a0549eacf9449acd5b1f1610..64cb11b448c1d3ff0cb54ece8ed110d056587145 100644 --- a/src/plugins/qt4projectmanager/qt4runconfiguration.cpp +++ b/src/plugins/qt4projectmanager/qt4runconfiguration.cpp @@ -59,7 +59,8 @@ Qt4RunConfiguration::Qt4RunConfiguration(Qt4Project *pro, const QString &proFile m_configWidget(0), m_executableLabel(0), m_workingDirectoryLabel(0), - m_cachedTargetInformationValid(false) + m_cachedTargetInformationValid(false), + m_isUsingDyldImageSuffix(false) { if (!m_proFilePath.isEmpty()) setName(QFileInfo(m_proFilePath).completeBaseName()); @@ -85,7 +86,11 @@ QString Qt4RunConfiguration::type() const ///// Qt4RunConfigurationWidget::Qt4RunConfigurationWidget(Qt4RunConfiguration *qt4RunConfiguration, QWidget *parent) - : QWidget(parent), m_qt4RunConfiguration(qt4RunConfiguration), m_ignoreChange(false), m_isShown(false) + : QWidget(parent), + m_qt4RunConfiguration(qt4RunConfiguration), + m_ignoreChange(false), + m_isShown(false), + m_usingDyldImageSuffix(0) { QFormLayout *toplayout = new QFormLayout(this); toplayout->setMargin(0); @@ -110,12 +115,18 @@ Qt4RunConfigurationWidget::Qt4RunConfigurationWidget(Qt4RunConfiguration *qt4Run m_useTerminalCheck->setChecked(m_qt4RunConfiguration->runMode() == ProjectExplorer::ApplicationRunConfiguration::Console); toplayout->addRow(QString(), m_useTerminalCheck); +#ifdef Q_OS_MAC + m_usingDyldImageSuffix = new QCheckBox(tr("Use debug version of frameworks (DYLD_IMAGE_SUFFIX=_debug)")); + m_usingDyldImageSuffix->setChecked(m_qt4RunConfiguration->isUsingDyldImageSuffix()); + toplayout->addRow(QString(), m_usingDyldImageSuffix); + connect(m_usingDyldImageSuffix, SIGNAL(toggled(bool)), + this, SLOT(usingDyldImageSuffixToggled(bool))); +#endif + connect(m_argumentsLineEdit, SIGNAL(textEdited(QString)), this, SLOT(setCommandLineArguments(QString))); - connect(m_nameLineEdit, SIGNAL(textEdited(QString)), this, SLOT(nameEdited(QString))); - connect(m_useTerminalCheck, SIGNAL(toggled(bool)), this, SLOT(termToggled(bool))); @@ -125,6 +136,8 @@ Qt4RunConfigurationWidget::Qt4RunConfigurationWidget(Qt4RunConfiguration *qt4Run this, SLOT(nameChanged(QString))); connect(qt4RunConfiguration, SIGNAL(runModeChanged(ProjectExplorer::ApplicationRunConfiguration::RunMode)), this, SLOT(runModeChanged(ProjectExplorer::ApplicationRunConfiguration::RunMode))); + connect(qt4RunConfiguration, SIGNAL(usingDyldImageSuffixChanged(bool)), + this, SLOT(usingDyldImageSuffixChanged(bool))); connect(qt4RunConfiguration, SIGNAL(effectiveTargetInformationChanged()), this, SLOT(effectiveTargetInformationChanged()), Qt::QueuedConnection); @@ -152,6 +165,13 @@ void Qt4RunConfigurationWidget::termToggled(bool on) m_ignoreChange = false; } +void Qt4RunConfigurationWidget::usingDyldImageSuffixToggled(bool state) +{ + m_ignoreChange = true; + m_qt4RunConfiguration->setUsingDyldImageSuffix(state); + m_ignoreChange = false; +} + void Qt4RunConfigurationWidget::commandLineArgumentsChanged(const QString &args) { if (!m_ignoreChange) @@ -170,6 +190,12 @@ void Qt4RunConfigurationWidget::runModeChanged(ApplicationRunConfiguration::RunM m_useTerminalCheck->setChecked(runMode == ApplicationRunConfiguration::Console); } +void Qt4RunConfigurationWidget::usingDyldImageSuffixChanged(bool state) +{ + if (!m_ignoreChange && m_usingDyldImageSuffix) + m_usingDyldImageSuffix->setChecked(state); +} + void Qt4RunConfigurationWidget::effectiveTargetInformationChanged() { if (m_isShown) { @@ -203,6 +229,7 @@ void Qt4RunConfiguration::save(PersistentSettingsWriter &writer) const writer.saveValue("ProFile", m_proFilePath); writer.saveValue("UserSetName", m_userSetName); writer.saveValue("UseTerminal", m_runMode == Console); + writer.saveValue("UseDyldImageSuffix", m_isUsingDyldImageSuffix); ApplicationRunConfiguration::save(writer); } @@ -213,6 +240,7 @@ void Qt4RunConfiguration::restore(const PersistentSettingsReader &reader) m_proFilePath = reader.restoreValue("ProFile").toString(); m_userSetName = reader.restoreValue("UserSetName").toBool(); m_runMode = reader.restoreValue("UseTerminal").toBool() ? Console : Gui; + m_isUsingDyldImageSuffix = reader.restoreValue("UseDyldImageSuffix").toBool(); if (!m_proFilePath.isEmpty()) { m_cachedTargetInformationValid = false; if (!m_userSetName) @@ -231,6 +259,17 @@ ApplicationRunConfiguration::RunMode Qt4RunConfiguration::runMode() const return m_runMode; } +bool Qt4RunConfiguration::isUsingDyldImageSuffix() const +{ + return m_isUsingDyldImageSuffix; +} + +void Qt4RunConfiguration::setUsingDyldImageSuffix(bool state) +{ + m_isUsingDyldImageSuffix = state; + emit usingDyldImageSuffixChanged(state); +} + QString Qt4RunConfiguration::workingDirectory() const { const_cast<Qt4RunConfiguration *>(this)->updateTarget(); @@ -246,7 +285,12 @@ ProjectExplorer::Environment Qt4RunConfiguration::environment() const { Qt4Project *pro = qobject_cast<Qt4Project *>(project()); Q_ASSERT(pro); - return pro->environment(pro->activeBuildConfiguration()); + QString config = pro->activeBuildConfiguration(); + ProjectExplorer::Environment env = pro->environment(pro->activeBuildConfiguration()); + if (m_isUsingDyldImageSuffix) { + env.set("DYLD_IMAGE_SUFFIX", "_debug"); + } + return env; } void Qt4RunConfiguration::setCommandLineArguments(const QString &argumentsString) @@ -370,6 +414,14 @@ void Qt4RunConfiguration::invalidateCachedTargetInformation() emit effectiveTargetInformationChanged(); } +QString Qt4RunConfiguration::dumperLibrary() const +{ + Qt4Project *pro = qobject_cast<Qt4Project *>(project()); + QtVersion *version = pro->qtVersion(pro->activeBuildConfiguration()); + return version->dumperLibrary(); +} + + /// /// Qt4RunConfigurationFactory /// This class is used to restore run settings (saved in .user files) diff --git a/src/plugins/qt4projectmanager/qt4runconfiguration.h b/src/plugins/qt4projectmanager/qt4runconfiguration.h index 30ff16a294fbe2d6540faeb9d5425e006daa2b90..3b59b65732c18ea72b1a30f1d11ef898f312e8c2 100644 --- a/src/plugins/qt4projectmanager/qt4runconfiguration.h +++ b/src/plugins/qt4projectmanager/qt4runconfiguration.h @@ -70,7 +70,10 @@ public: virtual QString workingDirectory() const; virtual QStringList commandLineArguments() const; virtual ProjectExplorer::Environment environment() const; + virtual QString dumperLibrary() const; + bool isUsingDyldImageSuffix() const; + void setUsingDyldImageSuffix(bool state); QString proFilePath() const; // TODO detectQtShadowBuild() ? how did this work ? @@ -87,6 +90,7 @@ signals: void nameChanged(const QString&); void commandLineArgumentsChanged(const QString&); void runModeChanged(ProjectExplorer::ApplicationRunConfiguration::RunMode runMode); + void usingDyldImageSuffixChanged(bool); // note those signals might not emited for every change void effectiveTargetInformationChanged(); @@ -112,6 +116,7 @@ private: QLabel *m_executableLabel; QLabel *m_workingDirectoryLabel; bool m_cachedTargetInformationValid; + bool m_isUsingDyldImageSuffix; }; class Qt4RunConfigurationWidget : public QWidget @@ -131,6 +136,8 @@ private slots: void runModeChanged(ProjectExplorer::ApplicationRunConfiguration::RunMode runMode); void effectiveTargetInformationChanged(); void termToggled(bool); + void usingDyldImageSuffixToggled(bool); + void usingDyldImageSuffixChanged(bool); private: Qt4RunConfiguration *m_qt4RunConfiguration; bool m_ignoreChange; @@ -139,6 +146,7 @@ private: QLineEdit *m_nameLineEdit; QLineEdit *m_argumentsLineEdit; QCheckBox *m_useTerminalCheck; + QCheckBox *m_usingDyldImageSuffix; bool m_isShown; }; diff --git a/src/plugins/qt4projectmanager/qtversionmanager.cpp b/src/plugins/qt4projectmanager/qtversionmanager.cpp index d8628d5699225d0eb562e40244669fb21caf4f0a..3621c06ac9ece9cd90ff8e4c9a72b1a6b0ec1b2f 100644 --- a/src/plugins/qt4projectmanager/qtversionmanager.cpp +++ b/src/plugins/qt4projectmanager/qtversionmanager.cpp @@ -30,6 +30,7 @@ #include "qtversionmanager.h" #include "qt4projectmanagerconstants.h" +#include "ui_showbuildlog.h" #include <coreplugin/icore.h> #include <coreplugin/coreconstants.h> @@ -48,6 +49,12 @@ #include <QtGui/QFileDialog> #include <QtGui/QHeaderView> #include <QtGui/QMessageBox> +#include <QtGui/QPushButton> +#include <QtGui/QToolButton> +#include <QtGui/QApplication> +#include <QtGui/QDesktopServices> +#include <QtGui/QHBoxLayout> +#include <QtGui/QLabel> using namespace Qt4ProjectManager::Internal; @@ -57,6 +64,46 @@ static const char *QtVersionsSectionName = "QtVersions"; static const char *defaultQtVersionKey = "DefaultQtVersion"; static const char *newQtVersionsKey = "NewQtVersions"; +DebuggingHelperWidget::DebuggingHelperWidget() +{ + setLayout(new QHBoxLayout()); + m_statusLabel = new QLabel(this); + + layout()->addWidget(m_statusLabel); + + m_showLog = new QPushButton(this); + m_showLog->setText("Show Log"); + layout()->addWidget(m_showLog); + + m_rebuild = new QPushButton(this); + m_rebuild->setText("Rebuild"); + layout()->addWidget(m_rebuild); + + connect(m_showLog, SIGNAL(clicked()), this, SIGNAL(showLogClicked())); + connect(m_rebuild, SIGNAL(clicked()), this, SIGNAL(rebuildClicked())); +} + +void DebuggingHelperWidget::setState(State s) +{ + if (s & InvalidQt) { + m_statusLabel->setVisible(false); + m_showLog->setVisible(false); + m_rebuild->setVisible(false); + return; + } else { + m_statusLabel->setVisible(true); + m_statusLabel->setText(""); + m_showLog->setVisible(true); + m_rebuild->setVisible(true); + if (s & Error) + m_statusLabel->setPixmap(QPixmap(":/extensionsystem/images/error.png")); + else + m_statusLabel->setPixmap(QPixmap(":/extensionsystem/images/ok.png")); + m_showLog->setVisible(s & ShowLog); + } +} + + QtVersionManager::QtVersionManager() : m_emptyVersion(new QtVersion) { @@ -370,7 +417,6 @@ QtVersion *QtVersionManager::currentQtVersion() const } //----------------------------------------------------- - QtDirWidget::QtDirWidget(QWidget *parent, QList<QtVersion *> versions, int defaultVersion) : QWidget(parent) , m_defaultVersion(defaultVersion) @@ -398,6 +444,17 @@ QtDirWidget::QtDirWidget(QWidget *parent, QList<QtVersion *> versions, int defau item->setText(0, version->name()); item->setText(1, version->path()); item->setData(0, Qt::UserRole, version->uniqueId()); + + DebuggingHelperWidget *dhw = new DebuggingHelperWidget(); + m_ui.qtdirList->setItemWidget(item, 2, dhw); + if (version->hasDebuggingHelper()) + dhw->setState(DebuggingHelperWidget::Ok); + else + dhw->setState(DebuggingHelperWidget::Error); + + connect(dhw, SIGNAL(rebuildClicked()), this, SLOT(buildDebuggingHelper())); + connect(dhw, SIGNAL(showLogClicked()), this, SLOT(showDebuggingBuildLog())); + m_ui.defaultCombo->addItem(version->name()); if (i == m_defaultVersion) m_ui.defaultCombo->setCurrentIndex(i); @@ -434,6 +491,53 @@ QtDirWidget::QtDirWidget(QWidget *parent, QList<QtVersion *> versions, int defau updateState(); } +void QtDirWidget::buildDebuggingHelper() +{ + // Find the qt version for this button.. + int index = indexForWidget(qobject_cast<QWidget *>(sender())); + if (index == -1) + return; + + QString result = m_versions.at(index)->buildDebuggingHelperLibrary(); + + QTreeWidgetItem *item = m_ui.qtdirList->topLevelItem(index); + item->setData(2, Qt::UserRole, result); + DebuggingHelperWidget *dhw = + qobject_cast<DebuggingHelperWidget *>(m_ui.qtdirList->itemWidget(item, 2)); + if (dhw) { + + if (m_versions.at(index)->hasDebuggingHelper()) + dhw->setState(DebuggingHelperWidget::State(DebuggingHelperWidget::Ok | DebuggingHelperWidget::ShowLog)); + else + dhw->setState(DebuggingHelperWidget::State(DebuggingHelperWidget::Error | DebuggingHelperWidget::ShowLog)); + } +} + +int QtDirWidget::indexForWidget(QWidget *widget) const +{ + int index = -1; + for (int i = 0; i < m_ui.qtdirList->topLevelItemCount(); ++i) { + if (m_ui.qtdirList->itemWidget(m_ui.qtdirList->topLevelItem(i), 2) == widget) { + index = i; + break; + } + } + return index; +} + +void QtDirWidget::showDebuggingBuildLog() +{ + int index = indexForWidget(qobject_cast<QWidget *>(sender())); + if (index == -1) + return; + + QDialog dlg; + Ui_ShowBuildLog ui; + ui.setupUi(&dlg); + ui.log->setPlainText(m_ui.qtdirList->topLevelItem(index)->data(2, Qt::UserRole).toString()); + dlg.exec(); +} + QtDirWidget::~QtDirWidget() { qDeleteAll(m_versions); @@ -449,6 +553,16 @@ void QtDirWidget::addQtDir() item->setText(1, newVersion->path()); item->setData(0, Qt::UserRole, newVersion->uniqueId()); + DebuggingHelperWidget *dhw = new DebuggingHelperWidget(); + m_ui.qtdirList->setItemWidget(item, 2, dhw); + if (newVersion->hasDebuggingHelper()) + dhw->setState(DebuggingHelperWidget::Ok); + else + dhw->setState(DebuggingHelperWidget::Error); + connect(dhw, SIGNAL(rebuildClicked()), this, SLOT(buildDebuggingHelper())); + connect(dhw, SIGNAL(showLogClicked()), this, SLOT(showDebuggingBuildLog())); + m_ui.qtdirList->setItemWidget(item, 2, dhw); + m_ui.qtdirList->setCurrentItem(item); m_ui.nameEdit->setText(newVersion->name()); @@ -506,19 +620,14 @@ void QtDirWidget::showEnvironmentPage(QTreeWidgetItem *item) ProjectExplorer::ToolChain::ToolChainType t = m_versions.at(index)->toolchainType(); if (t == ProjectExplorer::ToolChain::MinGW) { m_ui.msvcComboBox->setVisible(false); - m_ui.msvcLabel->setVisible(false); makeMingwVisible(true); m_ui.mingwPath->setPath(m_versions.at(index)->mingwDirectory()); } else if (t == ProjectExplorer::ToolChain::MSVC || t == ProjectExplorer::ToolChain::WINCE){ m_ui.msvcComboBox->setVisible(false); - m_ui.msvcLabel->setVisible(true); makeMingwVisible(false); QStringList msvcEnvironments = ProjectExplorer::ToolChain::availableMSVCVersions(); if (msvcEnvironments.count() == 0) { - m_ui.msvcLabel->setText(tr("No Visual Studio Installation found")); } else if (msvcEnvironments.count() == 1) { - //TODO m_ui.msvcLabel->setText( msvcEnvironments.at(0).description()); - m_ui.msvcLabel->setText(""); } else { m_ui.msvcComboBox->setVisible(true); bool block = m_ui.msvcComboBox->blockSignals(true); @@ -527,14 +636,12 @@ void QtDirWidget::showEnvironmentPage(QTreeWidgetItem *item) m_ui.msvcComboBox->addItem(msvcenv); if (msvcenv == m_versions.at(index)->msvcVersion()) { m_ui.msvcComboBox->setCurrentIndex(m_ui.msvcComboBox->count() - 1); - m_ui.msvcLabel->setText(""); //TODO } } m_ui.msvcComboBox->blockSignals(block); } } else if (t == ProjectExplorer::ToolChain::INVALID) { m_ui.msvcComboBox->setVisible(false); - m_ui.msvcLabel->setVisible(false); makeMingwVisible(false); if (!m_versions.at(index)->isInstalled()) m_ui.errorLabel->setText(tr("The Qt Version is not installed. Run make install") @@ -543,7 +650,6 @@ void QtDirWidget::showEnvironmentPage(QTreeWidgetItem *item) m_ui.errorLabel->setText(tr("%1 is not a valid qt directory").arg(m_versions.at(index)->path())); } else { //ProjectExplorer::ToolChain::GCC m_ui.msvcComboBox->setVisible(false); - m_ui.msvcLabel->setVisible(false); makeMingwVisible(false); m_ui.errorLabel->setText("Found Qt version " + m_versions.at(index)->qtVersionString() @@ -552,7 +658,6 @@ void QtDirWidget::showEnvironmentPage(QTreeWidgetItem *item) } } else { m_ui.msvcComboBox->setVisible(false); - m_ui.msvcLabel->setVisible(false); makeMingwVisible(false); } } @@ -665,10 +770,24 @@ void QtDirWidget::updateCurrentQtPath() QTreeWidgetItem *currentItem = m_ui.qtdirList->currentItem(); Q_ASSERT(currentItem); int currentItemIndex = m_ui.qtdirList->indexOfTopLevelItem(currentItem); + if (m_versions[currentItemIndex]->path() == m_ui.qtPath->path()) + return; m_versions[currentItemIndex]->setPath(m_ui.qtPath->path()); currentItem->setText(1, m_versions[currentItemIndex]->path()); showEnvironmentPage(currentItem); + + DebuggingHelperWidget *dhw = qobject_cast<DebuggingHelperWidget *>(m_ui.qtdirList->itemWidget(currentItem, 2)); + if (m_versions[currentItemIndex]->isValid()) { + DebuggingHelperWidget::State s = DebuggingHelperWidget::Ok; + if (!m_versions[currentItemIndex]->hasDebuggingHelper()) + s = DebuggingHelperWidget::State(s | DebuggingHelperWidget::Error); + if (!currentItem->data(2, Qt::UserRole).toString().isEmpty()) + s = DebuggingHelperWidget::State(s | DebuggingHelperWidget::ShowLog); + dhw->setState(s); + } else { + dhw->setState(DebuggingHelperWidget::InvalidQt); + } } void QtDirWidget::updateCurrentMingwDirectory() @@ -686,16 +805,6 @@ void QtDirWidget::msvcVersionChanged() Q_ASSERT(currentItem); int currentItemIndex = m_ui.qtdirList->indexOfTopLevelItem(currentItem); m_versions[currentItemIndex]->setMsvcVersion(msvcVersion); - - //get descriptionx - //TODO -// QList<MSVCEnvironment> msvcEnvironments = MSVCEnvironment::availableVersions(); -// foreach(const MSVCEnvironment &msvcEnv, msvcEnvironments) { -// if (msvcEnv.name() == msvcVersion) { -// m_ui.msvcLabel->setText(msvcEnv.description()); -// break; -// } -// } } QList<QtVersion *> QtDirWidget::versions() const @@ -713,7 +822,12 @@ int QtDirWidget::defaultVersion() const /// QtVersion::QtVersion(const QString &name, const QString &path, int id, bool isSystemVersion) - : m_name(name), m_isSystemVersion(isSystemVersion), m_notInstalled(false), m_defaultConfigIsDebug(true), m_defaultConfigIsDebugAndRelease(true) + : m_name(name), + m_isSystemVersion(isSystemVersion), + m_notInstalled(false), + m_defaultConfigIsDebug(true), + m_defaultConfigIsDebugAndRelease(true), + m_hasDebuggingHelper(false) { setPath(path); if (id == -1) @@ -726,7 +840,8 @@ QtVersion::QtVersion(const QString &name, const QString &path) : m_name(name), m_versionInfoUpToDate(false), m_mkspecUpToDate(false), - m_isSystemVersion(false) + m_isSystemVersion(false), + m_hasDebuggingHelper(false) { setPath(path); m_id = getUniqueId(); @@ -783,6 +898,30 @@ void QtVersion::setPath(const QString &path) m_versionInfoUpToDate = false; m_mkspecUpToDate = false; m_qmakeCommand = QString::null; +// TODO do i need to optimize this? + m_hasDebuggingHelper = !dumperLibrary().isEmpty(); +} + +QString QtVersion::dumperLibrary() const +{ + uint hash = qHash(path()); + QStringList directories; + directories + << (path() + "/qtc-debugging-helper/") + << (QApplication::applicationDirPath() + "/../qtc-debugging-helper/" + QString::number(hash)) + "/" + << (QDesktopServices::storageLocation(QDesktopServices::DataLocation) + "/qtc-debugging-helper/" + QString::number(hash)) + "/"; + foreach(const QString &directory, directories) { +#if defined(Q_OS_WIN) + QFileInfo fi(directory + "debug/gdbmacros.dll"); +#elif defined(Q_OS_MAC) + QFileInfo fi(directory + "libgdbmacros.dylib"); +#else // generic UNIX + QFileInfo fi(directory + "libgdbmacros.so"); +#endif + if (fi.exists()) + return fi.filePath(); + } + return QString(); } void QtVersion::updateSourcePath() @@ -1263,3 +1402,94 @@ QtVersion::QmakeBuildConfig QtVersion::defaultBuildConfig() const result = QtVersion::QmakeBuildConfig(result | QtVersion::DebugBuild); return result; } + +bool QtVersion::hasDebuggingHelper() const +{ + return m_hasDebuggingHelper; +} + +QString QtVersion::buildDebuggingHelperLibrary() +{ +// Locations to try: +// $QTDIR/qtc-debugging-helper +// $APPLICATION-DIR/qtc-debugging-helper/$hash +// $USERDIR/qtc-debugging-helper/$hash + + QString output; + uint hash = qHash(path()); + QStringList directories; + directories + << path() + "/qtc-debugging-helper/" + << QApplication::applicationDirPath() + "/../qtc-debugging-helper/" + QString::number(hash) +"/" + << QDesktopServices::storageLocation (QDesktopServices::DataLocation) + "/qtc-debugging-helper/" + QString::number(hash) +"/"; + + QStringList files; + files << "gdbmacros.cpp" << "gdbmacros.pro" + << "LICENSE.LGPL" << "LGPL_EXCEPTION.TXT"; + + foreach(const QString &directory, directories) { + QString dumperPath = Core::ICore::instance()->resourcePath() + "/gdbmacros/"; + bool success = true; + QDir().mkpath(directory); + foreach (const QString &file, files) { + QString source = dumperPath + file; + QString dest = directory + file; + QFileInfo destInfo(dest); + if (destInfo.exists()) { + if (destInfo.lastModified() >= QFileInfo(source).lastModified()) + continue; + success &= QFile::remove(dest); + } + success &= QFile::copy(source, dest); + } + if (!success) + continue; + + output += QString("Building debugging helper library in %1\n").arg(directory); + output += "\n"; + output += "Runinng qmake...\n"; + + QProcess qmake; + ProjectExplorer::Environment env = ProjectExplorer::Environment::systemEnvironment(); + addToEnvironment(env); + + qmake.setEnvironment(env.toStringList()); + qmake.setWorkingDirectory(directory); + qmake.setProcessChannelMode(QProcess::MergedChannels); + + qmake.start(qmakeCommand(), QStringList()<<"-spec"<<"default"<<"gdbmacros.pro"); + qmake.waitForFinished(); + + output += qmake.readAll(); + + // TODO this is butt ugly + // only qt4projects have a toolchain() method. (Reason mostly, that in order to create + // the toolchain, we need to have the path to gcc + // which might depend on environment settings of the project + // so we hardcode the toolchainType to make conversation here + // and think about how to fix that later + + QString make; + ProjectExplorer::ToolChain::ToolChainType t = toolchainType(); + if (t == ProjectExplorer::ToolChain::MinGW) + make = "mingw32-make.exe"; + else if(t == ProjectExplorer::ToolChain::MSVC || t == ProjectExplorer::ToolChain::WINCE) + make = "nmake.exe"; + else if (t == ProjectExplorer::ToolChain::GCC || t == ProjectExplorer::ToolChain::LinuxICC) + make = "make"; + + QString makeFullPath = env.searchInPath(make); + output += "\n"; + if (!makeFullPath.isEmpty()) { + output += QString("Running %1...\n").arg(makeFullPath); + qmake.start(makeFullPath, QStringList()); + qmake.waitForFinished(); + output += qmake.readAll(); + } else { + output += QString("%1 not found in PATH\n").arg(make); + } + break; + } + m_hasDebuggingHelper = !dumperLibrary().isEmpty(); + return output; +} diff --git a/src/plugins/qt4projectmanager/qtversionmanager.h b/src/plugins/qt4projectmanager/qtversionmanager.h index 7252a698cd4c5b07f44d6cb16870d3f78eb52859..0d61ac22d191dcba9998fb8e24cf0ebc3e081aaa 100644 --- a/src/plugins/qt4projectmanager/qtversionmanager.h +++ b/src/plugins/qt4projectmanager/qtversionmanager.h @@ -38,6 +38,7 @@ #include <QtCore/QPointer> #include <QtGui/QWidget> +#include <QtGui/QPushButton> namespace Qt4ProjectManager { namespace Internal { @@ -79,6 +80,10 @@ public: QString wincePlatform() const; void setMsvcVersion(const QString &version); void addToEnvironment(ProjectExplorer::Environment &env); + bool hasDebuggingHelper() const; + // Builds a debugging library + // returns the output of the commands + QString buildDebuggingHelperLibrary(); int uniqueId() const; @@ -90,6 +95,7 @@ public: }; QmakeBuildConfig defaultBuildConfig() const; + QString dumperLibrary() const; private: static int getUniqueId(); void setName(const QString &name); @@ -117,6 +123,7 @@ private: // This is updated on first call to qmakeCommand // That function is called from updateVersionInfo() mutable QString m_qtVersionString; + bool m_hasDebuggingHelper; }; @@ -129,9 +136,11 @@ public: QList<QtVersion *> versions() const; int defaultVersion() const; void finish(); + private: void showEnvironmentPage(QTreeWidgetItem * item); void fixQtVersionName(int index); + int indexForWidget(QWidget *debuggingHelperWidget) const; Ui::QtVersionManager m_ui; QList<QtVersion *> m_versions; int m_defaultVersion; @@ -151,6 +160,8 @@ private slots: void updateCurrentQtPath(); void updateCurrentMingwDirectory(); void msvcVersionChanged(); + void buildDebuggingHelper(); + void showDebuggingBuildLog(); }; class QtVersionManager : public Core::IOptionsPage @@ -212,6 +223,27 @@ private: int m_idcount; }; +class DebuggingHelperWidget : public QWidget +{ + Q_OBJECT +public: + DebuggingHelperWidget(); + enum State { + Ok = 0, + Error = 1, + ShowLog = 2, + InvalidQt = 4 + }; + void setState(State s); +signals: + void rebuildClicked(); + void showLogClicked(); +private: + QLabel *m_statusLabel; + QPushButton *m_showLog; + QPushButton *m_rebuild; +}; + } // namespace Internal } // namespace Qt4ProjectManager diff --git a/src/plugins/qt4projectmanager/qtversionmanager.ui b/src/plugins/qt4projectmanager/qtversionmanager.ui index 0d3941d03883d42c30d26d08b5350134b4c932c5..fd61e92f4bbb6286bb83eeed45105a210b1a7b53 100644 --- a/src/plugins/qt4projectmanager/qtversionmanager.ui +++ b/src/plugins/qt4projectmanager/qtversionmanager.ui @@ -78,7 +78,7 @@ <bool>false</bool> </property> <property name="columnCount"> - <number>2</number> + <number>3</number> </property> <column> <property name="text"> @@ -90,6 +90,11 @@ <string>Path</string> </property> </column> + <column> + <property name="text"> + <string>Debugging Helper</string> + </property> + </column> </widget> </item> <item row="1" column="0"> @@ -116,21 +121,14 @@ </property> </widget> </item> - <item row="4" column="0" colspan="3"> - <widget class="QLabel" name="msvcLabel"> - <property name="text"> - <string/> - </property> - </widget> - </item> - <item row="7" column="0" colspan="4"> + <item row="6" column="0" colspan="4"> <widget class="QLabel" name="errorLabel"> <property name="text"> <string/> </property> </widget> </item> - <item row="5" column="1" colspan="2"> + <item row="4" column="1" colspan="2"> <widget class="QComboBox" name="msvcComboBox"/> </item> <item row="2" column="1" colspan="2"> diff --git a/src/plugins/qt4projectmanager/showbuildlog.ui b/src/plugins/qt4projectmanager/showbuildlog.ui new file mode 100644 index 0000000000000000000000000000000000000000..98c61b360e7d1b59c27b4bdc748d742365c5bee0 --- /dev/null +++ b/src/plugins/qt4projectmanager/showbuildlog.ui @@ -0,0 +1,74 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>ShowBuildLog</class> + <widget class="QDialog" name="ShowBuildLog"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>400</width> + <height>300</height> + </rect> + </property> + <property name="windowTitle"> + <string>Dialog</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout"> + <item> + <widget class="QPlainTextEdit" name="log"> + <property name="tabChangesFocus"> + <bool>true</bool> + </property> + <property name="readOnly"> + <bool>true</bool> + </property> + </widget> + </item> + <item> + <widget class="QDialogButtonBox" name="buttonBox"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="standardButtons"> + <set>QDialogButtonBox::Ok</set> + </property> + </widget> + </item> + </layout> + </widget> + <resources/> + <connections> + <connection> + <sender>buttonBox</sender> + <signal>accepted()</signal> + <receiver>ShowBuildLog</receiver> + <slot>accept()</slot> + <hints> + <hint type="sourcelabel"> + <x>248</x> + <y>254</y> + </hint> + <hint type="destinationlabel"> + <x>157</x> + <y>274</y> + </hint> + </hints> + </connection> + <connection> + <sender>buttonBox</sender> + <signal>rejected()</signal> + <receiver>ShowBuildLog</receiver> + <slot>reject()</slot> + <hints> + <hint type="sourcelabel"> + <x>316</x> + <y>260</y> + </hint> + <hint type="destinationlabel"> + <x>286</x> + <y>274</y> + </hint> + </hints> + </connection> + </connections> +</ui> diff --git a/src/plugins/texteditor/basetexteditor.cpp b/src/plugins/texteditor/basetexteditor.cpp index 6574d416310a5e2691c92f9c4be52a7be3ba3928..322039c0cbd036c34e365cf16730f82dcfa47eaa 100644 --- a/src/plugins/texteditor/basetexteditor.cpp +++ b/src/plugins/texteditor/basetexteditor.cpp @@ -1255,6 +1255,7 @@ BaseTextEditorPrivate::BaseTextEditorPrivate() m_document(new BaseTextDocument()), m_parenthesesMatchingEnabled(false), m_extraArea(0), + m_mouseOnCollapsedMarker(false), m_marksVisible(false), m_codeFoldingVisible(false), m_codeFoldingSupported(false), @@ -2421,22 +2422,30 @@ void BaseTextEditorPrivate::clearVisibleCollapsedBlock() void BaseTextEditor::mouseMoveEvent(QMouseEvent *e) { d->m_lastEventWasBlockSelectionEvent = (e->modifiers() & Qt::AltModifier); - if (e->buttons() == 0) { - QTextBlock collapsedBlock = collapsedBlockAt(e->pos()); - int blockNumber = collapsedBlock.next().blockNumber(); + if (e->buttons() == Qt::NoButton) { + const QTextBlock collapsedBlock = collapsedBlockAt(e->pos()); + const int blockNumber = collapsedBlock.next().blockNumber(); if (blockNumber < 0) { d->clearVisibleCollapsedBlock(); } else if (blockNumber != d->visibleCollapsedBlockNumber) { d->suggestedVisibleCollapsedBlockNumber = blockNumber; d->collapsedBlockTimer.start(40, this); } - viewport()->setCursor(collapsedBlock.isValid() ? Qt::PointingHandCursor : Qt::IBeamCursor); + + // Update the mouse cursor + if (collapsedBlock.isValid() && !d->m_mouseOnCollapsedMarker) { + d->m_mouseOnCollapsedMarker = true; + viewport()->setCursor(Qt::PointingHandCursor); + } else if (!collapsedBlock.isValid() && d->m_mouseOnCollapsedMarker) { + d->m_mouseOnCollapsedMarker = false; + viewport()->setCursor(Qt::IBeamCursor); + } } else { QPlainTextEdit::mouseMoveEvent(e); } if (d->m_lastEventWasBlockSelectionEvent && d->m_inBlockSelectionMode) { if (textCursor().atBlockEnd()) { - d->m_blockSelectionExtraX = qMax(0, e->pos().x() - cursorRect().center().x()) / fontMetrics().width(QLatin1Char('x')); + d->m_blockSelectionExtraX = qMax(0, e->pos().x() - cursorRect().center().x()) / fontMetrics().averageCharWidth(); } else { d->m_blockSelectionExtraX = 0; } diff --git a/src/plugins/texteditor/basetexteditor.h b/src/plugins/texteditor/basetexteditor.h index 8c106181349edbde83d0f8c4a82f6dc9aba51633..c3cae63467fa8afb8058f6b5c6544742748eda5c 100644 --- a/src/plugins/texteditor/basetexteditor.h +++ b/src/plugins/texteditor/basetexteditor.h @@ -27,7 +27,6 @@ ** **************************************************************************/ - #ifndef BASETEXTEDITOR_H #define BASETEXTEDITOR_H @@ -42,7 +41,6 @@ QT_BEGIN_NAMESPACE class QLabel; -class QTextCharFormat; class QToolBar; QT_END_NAMESPACE diff --git a/src/plugins/texteditor/basetexteditor_p.h b/src/plugins/texteditor/basetexteditor_p.h index 638f2faba225d217c36cb8a45841b3475e712cc3..d33fa9d7d4c2fdef660fb8967638787d50f2ec17 100644 --- a/src/plugins/texteditor/basetexteditor_p.h +++ b/src/plugins/texteditor/basetexteditor_p.h @@ -175,6 +175,7 @@ public: int visibleCollapsedBlockNumber; int suggestedVisibleCollapsedBlockNumber; void clearVisibleCollapsedBlock(); + bool m_mouseOnCollapsedMarker; QBasicTimer autoScrollTimer; void updateMarksLineNumber(); diff --git a/src/plugins/texteditor/texteditorconstants.h b/src/plugins/texteditor/texteditorconstants.h index 654bba0d4bcbc96d1ad060285ae80c5ab1d67122..e598a8911484cba9c91c427d7a5c0d35779cd0a6 100644 --- a/src/plugins/texteditor/texteditorconstants.h +++ b/src/plugins/texteditor/texteditorconstants.h @@ -65,6 +65,7 @@ const char * const C_TEXTEDITOR_MIMETYPE_XML = "application/xml"; // Text color and style categories const char * const C_TEXT = "Text"; +const char * const C_LINK = "Link"; const char * const C_SELECTION = "Selection"; const char * const C_LINE_NUMBER = "LineNumber"; const char * const C_SEARCH_RESULT = "SearchResult"; diff --git a/src/plugins/texteditor/texteditorsettings.cpp b/src/plugins/texteditor/texteditorsettings.cpp index cc55dec6b24c6726a8c1abd655bd36a98d6a394d..31204648a1d2a778f8f94d897348c2caf8c28507 100644 --- a/src/plugins/texteditor/texteditorsettings.cpp +++ b/src/plugins/texteditor/texteditorsettings.cpp @@ -65,6 +65,7 @@ TextEditorSettings::TextEditorSettings(QObject *parent) // Special categories const QPalette p = QApplication::palette(); + formatDescriptions.push_back(FormatDescription(QLatin1String(C_LINK), tr("Link"), Qt::blue)); formatDescriptions.push_back(FormatDescription(QLatin1String(C_SELECTION), tr("Selection"), p.color(QPalette::HighlightedText))); formatDescriptions.push_back(FormatDescription(QLatin1String(C_LINE_NUMBER), tr("Line Number"))); formatDescriptions.push_back(FormatDescription(QLatin1String(C_SEARCH_RESULT), tr("Search Result"))); diff --git a/src/plugins/vcsbase/vcsbasesettingspage.ui b/src/plugins/vcsbase/vcsbasesettingspage.ui index 0585c680e3e259c00bd6b16cdeabf9ae249a7dfa..16012b7239cbb09340b40d4483982b05669db6ba 100644 --- a/src/plugins/vcsbase/vcsbasesettingspage.ui +++ b/src/plugins/vcsbase/vcsbasesettingspage.ui @@ -38,6 +38,9 @@ </item> <item> <widget class="QSpinBox" name="lineWrapSpinBox"> + <property name="enabled"> + <bool>false</bool> + </property> <property name="minimum"> <number>40</number> </property> @@ -79,7 +82,7 @@ </widget> </item> <item row="0" column="1"> - <widget class="Core::Utils::PathChooser" name="submitMessageCheckScriptChooser"/> + <widget class="Core::Utils::PathChooser" name="submitMessageCheckScriptChooser" native="true"/> </item> <item row="1" column="0"> <widget class="QLabel" name="nickNameMailMapLabel"> @@ -93,7 +96,7 @@ name <email> alias <email></string> </widget> </item> <item row="1" column="1"> - <widget class="Core::Utils::PathChooser" name="nickNameMailMapChooser"/> + <widget class="Core::Utils::PathChooser" name="nickNameMailMapChooser" native="true"/> </item> <item row="2" column="0"> <widget class="QLabel" name="nickNameFieldsFileLabel"> @@ -106,7 +109,7 @@ name <email> alias <email></string> </widget> </item> <item row="2" column="1"> - <widget class="Core::Utils::PathChooser" name="nickNameFieldsFileChooser"/> + <widget class="Core::Utils::PathChooser" name="nickNameFieldsFileChooser" native="true"/> </item> </layout> </item> @@ -151,5 +154,22 @@ name <email> alias <email></string> </customwidget> </customwidgets> <resources/> - <connections/> + <connections> + <connection> + <sender>lineWrapCheckBox</sender> + <signal>toggled(bool)</signal> + <receiver>lineWrapSpinBox</receiver> + <slot>setEnabled(bool)</slot> + <hints> + <hint type="sourcelabel"> + <x>186</x> + <y>58</y> + </hint> + <hint type="destinationlabel"> + <x>225</x> + <y>58</y> + </hint> + </hints> + </connection> + </connections> </ui> diff --git a/src/plugins/vcsbase/vcsbasesubmiteditor.cpp b/src/plugins/vcsbase/vcsbasesubmiteditor.cpp index 62ea9417b825aa869e5ca4afe2a16bbccfd5c68b..204c825793907b49b13ef1e1316b25bbd2d2690a 100644 --- a/src/plugins/vcsbase/vcsbasesubmiteditor.cpp +++ b/src/plugins/vcsbase/vcsbasesubmiteditor.cpp @@ -41,6 +41,8 @@ #include <utils/submiteditorwidget.h> #include <utils/submitfieldwidget.h> #include <find/basetextfind.h> +#include <texteditor/fontsettings.h> +#include <texteditor/texteditorsettings.h> #include <projectexplorer/projectexplorer.h> #include <projectexplorer/session.h> @@ -107,6 +109,13 @@ VCSBaseSubmitEditor::VCSBaseSubmitEditor(const VCSBaseSubmitEditorParameters *pa Core::Utils::SubmitEditorWidget *editorWidget) : m_d(new VCSBaseSubmitEditorPrivate(parameters, editorWidget, this)) { + // Message font according to settings + const TextEditor::FontSettings fs = TextEditor::TextEditorSettings::instance()->fontSettings(); + QFont font = editorWidget->descriptionEdit()->font(); + font.setFamily(fs.family()); + font.setPointSize(fs.fontSize()); + editorWidget->descriptionEdit()->setFont(font); + m_d->m_file->setModified(false); // We are always clean to prevent the editor manager from asking to save. connect(m_d->m_file, SIGNAL(saveMe(QString)), this, SLOT(save(QString))); diff --git a/src/shared/cplusplus/AST.h b/src/shared/cplusplus/AST.h index 3f3f802506f462246e200d112f832a4ab47a2b27..44d5cd695a499a8d58d5cfd7e1684a3383dbe9e4 100644 --- a/src/shared/cplusplus/AST.h +++ b/src/shared/cplusplus/AST.h @@ -396,6 +396,7 @@ protected: class CPLUSPLUS_EXPORT SimpleDeclarationAST: public DeclarationAST { public: + unsigned qt_invokable_token; SpecifierAST *decl_specifier_seq; DeclaratorListAST *declarators; unsigned semicolon_token; @@ -1071,6 +1072,7 @@ protected: class CPLUSPLUS_EXPORT FunctionDefinitionAST: public DeclarationAST { public: + unsigned qt_invokable_token; SpecifierAST *decl_specifier_seq; DeclaratorAST *declarator; CtorInitializerAST *ctor_initializer; diff --git a/src/shared/cplusplus/CheckDeclaration.cpp b/src/shared/cplusplus/CheckDeclaration.cpp index 06b85f8c5b19216afc40684be6c25fe448cb2432..c6de2cf4aa0d412e408dcbe08b7c3e6dc8190180 100644 --- a/src/shared/cplusplus/CheckDeclaration.cpp +++ b/src/shared/cplusplus/CheckDeclaration.cpp @@ -154,6 +154,9 @@ bool CheckDeclaration::visit(SimpleDeclarationAST *ast) } } + const bool isQ_SLOT = ast->qt_invokable_token && tokenKind(ast->qt_invokable_token) == T_Q_SLOT; + const bool isQ_SIGNAL = ast->qt_invokable_token && tokenKind(ast->qt_invokable_token) == T_Q_SIGNAL; + List<Declaration *> **decl_it = &ast->symbols; for (DeclaratorListAST *it = ast->declarators; it; it = it->next) { Name *name = 0; @@ -172,6 +175,10 @@ bool CheckDeclaration::visit(SimpleDeclarationAST *ast) fun->setScope(_scope); fun->setName(name); fun->setMethodKey(semantic()->currentMethodKey()); + if (isQ_SIGNAL) + fun->setMethodKey(Function::SignalMethod); + else if (isQ_SLOT) + fun->setMethodKey(Function::SlotMethod); fun->setVisibility(semantic()->currentVisibility()); } else if (semantic()->currentMethodKey() != Function::NormalMethod) { translationUnit()->warning(ast->firstToken(), @@ -259,6 +266,14 @@ bool CheckDeclaration::visit(FunctionDefinitionAST *ast) fun->setVisibility(semantic()->currentVisibility()); fun->setMethodKey(semantic()->currentMethodKey()); + const bool isQ_SLOT = ast->qt_invokable_token && tokenKind(ast->qt_invokable_token) == T_Q_SLOT; + const bool isQ_SIGNAL = ast->qt_invokable_token && tokenKind(ast->qt_invokable_token) == T_Q_SIGNAL; + + if (isQ_SIGNAL) + fun->setMethodKey(Function::SignalMethod); + else if (isQ_SLOT) + fun->setMethodKey(Function::SlotMethod); + checkFunctionArguments(fun); ast->symbol = fun; diff --git a/src/shared/cplusplus/Keywords.cpp b/src/shared/cplusplus/Keywords.cpp index 28cd42227b8f1d5866907b57cbeeb92ff452eb84..57d3b56961b4c6459f14af3808ac074ba4dad767 100644 --- a/src/shared/cplusplus/Keywords.cpp +++ b/src/shared/cplusplus/Keywords.cpp @@ -532,6 +532,19 @@ static inline int classify6(const char *s, bool q) { } } } + else if (q && s[0] == 'Q') { + if (s[1] == '_') { + if (s[2] == 'S') { + if (s[3] == 'L') { + if (s[4] == 'O') { + if (s[5] == 'T') { + return T_Q_SLOT; + } + } + } + } + } + } return T_IDENTIFIER; } @@ -850,6 +863,23 @@ static inline int classify8(const char *s, bool) { } } } + else if (s[0] == 'Q') { + if (s[1] == '_') { + if (s[2] == 'S') { + if (s[3] == 'I') { + if (s[4] == 'G') { + if (s[5] == 'N') { + if (s[6] == 'A') { + if (s[7] == 'L') { + return T_Q_SIGNAL; + } + } + } + } + } + } + } + } return T_IDENTIFIER; } diff --git a/src/shared/cplusplus/Parser.cpp b/src/shared/cplusplus/Parser.cpp index 423a05e05be8352e4ebccc5b24166fbbefc9bfbb..5bae822f350a216577aa935b95706c121ab452d9 100644 --- a/src/shared/cplusplus/Parser.cpp +++ b/src/shared/cplusplus/Parser.cpp @@ -2381,10 +2381,12 @@ bool Parser::parseBuiltinTypeSpecifier(SpecifierAST *&node) bool Parser::parseSimpleDeclaration(DeclarationAST *&node, bool acceptStructDeclarator) { + unsigned qt_invokable_token = 0; + if (acceptStructDeclarator && (LA() == T_Q_SIGNAL || LA() == T_Q_SLOT)) + qt_invokable_token = consumeToken(); + // parse a simple declaration, a function definition, // or a contructor declaration. - cursor(); - bool has_type_specifier = false; bool has_complex_type_specifier = false; unsigned startOfNamedTypeSpecifier = 0; @@ -2498,6 +2500,7 @@ bool Parser::parseSimpleDeclaration(DeclarationAST *&node, } } SimpleDeclarationAST *ast = new (_pool) SimpleDeclarationAST; + ast->qt_invokable_token = qt_invokable_token; ast->decl_specifier_seq = decl_specifier_seq; ast->declarators = declarator_list; match(T_SEMICOLON, &ast->semicolon_token); @@ -2510,6 +2513,7 @@ bool Parser::parseSimpleDeclaration(DeclarationAST *&node, if (LA() == T_LBRACE) { FunctionDefinitionAST *ast = new (_pool) FunctionDefinitionAST; + ast->qt_invokable_token = qt_invokable_token; ast->decl_specifier_seq = decl_specifier_seq; ast->declarator = firstDeclarator; ast->ctor_initializer = ctor_initializer; @@ -2518,6 +2522,7 @@ bool Parser::parseSimpleDeclaration(DeclarationAST *&node, return true; // recognized a function definition. } else if (LA() == T_TRY) { FunctionDefinitionAST *ast = new (_pool) FunctionDefinitionAST; + ast->qt_invokable_token = qt_invokable_token; ast->decl_specifier_seq = decl_specifier_seq; ast->declarator = firstDeclarator; ast->ctor_initializer = ctor_initializer; diff --git a/src/shared/cplusplus/Token.cpp b/src/shared/cplusplus/Token.cpp index 70d4af8e9a415903dfea398a5ae1582dafcf8e65..0fdb0cee2b625ae2b9e1c8ed8e691ca5f051cc16 100644 --- a/src/shared/cplusplus/Token.cpp +++ b/src/shared/cplusplus/Token.cpp @@ -90,7 +90,7 @@ static const char *token_names[] = { ("@protected"), ("@protocol"), ("@public"), ("@required"), ("@selector"), ("@synchronized"), ("@synthesize"), ("@throw"), ("@try"), - ("SIGNAL"), ("SLOT"), ("Q_SIGNALS"), ("Q_SLOTS") + ("SIGNAL"), ("SLOT"), ("Q_SIGNAL"), ("Q_SLOT"), ("signals"), ("slots") }; Token::Token() : diff --git a/src/shared/cplusplus/Token.h b/src/shared/cplusplus/Token.h index 260eaac43d61988294fb48852cc12a98353131bd..69ba4c37826023181a5d32a4128b88edf89132aa 100644 --- a/src/shared/cplusplus/Token.h +++ b/src/shared/cplusplus/Token.h @@ -232,6 +232,8 @@ enum Kind { // Qt keywords T_SIGNAL = T_FIRST_QT_KEYWORD, T_SLOT, + T_Q_SIGNAL, + T_Q_SLOT, T_SIGNALS, T_SLOTS, diff --git a/tests/manual/gdbdebugger/simple/app.cpp b/tests/manual/gdbdebugger/simple/app.cpp index 4115a49a50853b155ed20815b97609922075f05b..141c7b547396283d785e298e0434d3c899e343bf 100644 --- a/tests/manual/gdbdebugger/simple/app.cpp +++ b/tests/manual/gdbdebugger/simple/app.cpp @@ -783,7 +783,18 @@ void testQVariant1() void testQVariant2() { + int i = 1; QVariant var; + var.setValue(1); + var.setValue(2); + var.setValue(3); + var.setValue(QString("Hello")); + var.setValue(QString("World")); + var.setValue(QString("Hello")); + var.setValue(QStringList() << "World"); + var.setValue(QStringList() << "World" << "Hello"); + var.setValue(QStringList() << "Hello" << "Hello"); + var.setValue(QStringList() << "World" << "Hello" << "Hello"); #if 0 QVariant var3; QHostAddress ha("127.0.0.1"); @@ -793,7 +804,6 @@ void testQVariant2() var3 = var; var3 = var; QHostAddress ha1 = var.value<QHostAddress>(); -#endif typedef QMap<uint, QStringList> MyType; MyType my; my[1] = (QStringList() << "Hello"); @@ -804,6 +814,7 @@ void testQVariant2() var.setValue(my); var.setValue(my); var.setValue(my); +#endif } void testQVariant3()