From db14533928d5bcdb8bd3a50b30ec7317d4141b4c Mon Sep 17 00:00:00 2001 From: Roberto Raggi Date: Mon, 12 Oct 2009 10:37:36 +0200 Subject: [PATCH 01/34] Updated changes-1.3.0 --- dist/changes-1.3.0 | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/dist/changes-1.3.0 b/dist/changes-1.3.0 index 578ce887b70..6013a3074f3 100644 --- a/dist/changes-1.3.0 +++ b/dist/changes-1.3.0 @@ -38,6 +38,10 @@ Editing * Added left/right arrow buttons for "Go back/forward" in navigation history * Added smart indentation for pasted text blocks +Refactoring + * Added rename symbol under cursor + * Find usages of a symbol + Project support * Added support for adding and removing files from a generic Makefile-based project From 420b09e8c25e92fc173ff6f6a6547fd7f13699d3 Mon Sep 17 00:00:00 2001 From: Roberto Raggi Date: Mon, 12 Oct 2009 10:38:00 +0200 Subject: [PATCH 02/34] Expose CppModelManagerInterface::workingCopy() --- src/plugins/cpptools/cppfindreferences.cpp | 6 +++--- src/plugins/cpptools/cppfindreferences.h | 8 ++++---- src/plugins/cpptools/cppmodelmanager.cpp | 5 +++++ src/plugins/cpptools/cppmodelmanager.h | 5 +++-- src/plugins/cpptools/cppmodelmanagerinterface.h | 1 + 5 files changed, 16 insertions(+), 9 deletions(-) diff --git a/src/plugins/cpptools/cppfindreferences.cpp b/src/plugins/cpptools/cppfindreferences.cpp index 03397a655ad..06bc4affa87 100644 --- a/src/plugins/cpptools/cppfindreferences.cpp +++ b/src/plugins/cpptools/cppfindreferences.cpp @@ -28,7 +28,7 @@ **************************************************************************/ #include "cppfindreferences.h" -#include "cppmodelmanager.h" +#include "cppmodelmanagerinterface.h" #include "cpptoolsconstants.h" #include @@ -452,7 +452,7 @@ private: } // end of anonymous namespace -CppFindReferences::CppFindReferences(CppModelManager *modelManager) +CppFindReferences::CppFindReferences(CppTools::CppModelManagerInterface *modelManager) : _modelManager(modelManager), _resultWindow(ExtensionSystem::PluginManager::instance()->getObject()) { @@ -614,7 +614,7 @@ void CppFindReferences::findAll_helper(Symbol *symbol) _resultWindow->popup(true); const Snapshot snapshot = _modelManager->snapshot(); - const QMap wl = _modelManager->buildWorkingCopyList(); + const QMap wl = _modelManager->workingCopy(); Core::ProgressManager *progressManager = Core::ICore::instance()->progressManager(); diff --git a/src/plugins/cpptools/cppfindreferences.h b/src/plugins/cpptools/cppfindreferences.h index 4b4a5a9b04b..cbddf8fb5c3 100644 --- a/src/plugins/cpptools/cppfindreferences.h +++ b/src/plugins/cpptools/cppfindreferences.h @@ -43,16 +43,16 @@ namespace Find { } // end of namespace Find namespace CppTools { -namespace Internal { +class CppModelManagerInterface; -class CppModelManager; +namespace Internal { class CppFindReferences: public QObject { Q_OBJECT public: - CppFindReferences(CppModelManager *modelManager); + CppFindReferences(CppModelManagerInterface *modelManager); virtual ~CppFindReferences(); QList references(CPlusPlus::Symbol *symbol, @@ -76,7 +76,7 @@ private: void findAll_helper(CPlusPlus::Symbol *symbol); private: - QPointer _modelManager; + QPointer _modelManager; Find::SearchResultWindow *_resultWindow; QFutureWatcher m_watcher; }; diff --git a/src/plugins/cpptools/cppmodelmanager.cpp b/src/plugins/cpptools/cppmodelmanager.cpp index d60cd1752ff..f0373e89bf8 100644 --- a/src/plugins/cpptools/cppmodelmanager.cpp +++ b/src/plugins/cpptools/cppmodelmanager.cpp @@ -793,6 +793,11 @@ QMap CppModelManager::buildWorkingCopyList() return workingCopy; } +QMap CppModelManager::workingCopy() const +{ + return const_cast(this)->buildWorkingCopyList(); +} + void CppModelManager::updateSourceFiles(const QStringList &sourceFiles) { (void) refreshSourceFiles(sourceFiles); } diff --git a/src/plugins/cpptools/cppmodelmanager.h b/src/plugins/cpptools/cppmodelmanager.h index 9aa3a800b2c..0e7b0271ce1 100644 --- a/src/plugins/cpptools/cppmodelmanager.h +++ b/src/plugins/cpptools/cppmodelmanager.h @@ -73,6 +73,7 @@ public: virtual ~CppModelManager(); virtual void updateSourceFiles(const QStringList &sourceFiles); + virtual QMap workingCopy() const; virtual QList projectInfos() const; virtual ProjectInfo projectInfo(ProjectExplorer::Project *project) const; @@ -92,8 +93,6 @@ public: CppEditorSupport *editorSupport(TextEditor::ITextEditor *editor) const { return m_editorSupport.value(editor); } - QMap buildWorkingCopyList(); - void emitDocumentUpdated(CPlusPlus::Document::Ptr doc); void stopEditorSelectionsUpdate() @@ -132,6 +131,8 @@ private Q_SLOTS: void updateEditorSelections(); private: + QMap buildWorkingCopyList(); + QStringList projectFiles() { ensureUpdated(); diff --git a/src/plugins/cpptools/cppmodelmanagerinterface.h b/src/plugins/cpptools/cppmodelmanagerinterface.h index 58b04d4bf57..9c6f0fb4432 100644 --- a/src/plugins/cpptools/cppmodelmanagerinterface.h +++ b/src/plugins/cpptools/cppmodelmanagerinterface.h @@ -86,6 +86,7 @@ public: virtual void GC() = 0; virtual void updateSourceFiles(const QStringList &sourceFiles) = 0; + virtual QMap workingCopy() const = 0; virtual CPlusPlus::Snapshot snapshot() const = 0; virtual QList projectInfos() const = 0; From eacb27f1fb114046c5cf7881eca2bf841ab8b334 Mon Sep 17 00:00:00 2001 From: Rohan McGovern Date: Thu, 8 Oct 2009 12:01:45 +0200 Subject: [PATCH 03/34] Fixed transient compile failure with highly parallel jom. These .pri files which add to INCLUDEPATH and have FORMS should also add to DEPENDPATH. Adding to INCLUDEPATH does not add to DEPENDPATH by default with qmake. That means qmake may not find headers in those paths and won't consider them dependencies when compiling the source files which include them. This doesn't matter when all the headers in the new INCLUDEPATH are always present, but when some of them are generated (e.g. from FORMS), the dependencies are important and omitting them means a race condition in parallel builds. Fixes errors of the form: ..\..\shared\help\topicchooser.h(33) : fatal error C1083: Cannot open include file: 'ui_topicchooser.h': No such file or directory (cherry picked from commit 9a7e02946ab702e25f1b616187492dd1a3486727) --- src/plugins/debugger/cdb/cdb.pri | 1 + src/plugins/designer/cpp/cpp.pri | 1 + src/plugins/git/gitorious/gitorious.pri | 1 + .../qt4projectmanager/customwidgetwizard/customwidgetwizard.pri | 1 + src/shared/help/help.pri | 1 + src/shared/proparser/proparser.pri | 1 + src/shared/qrceditor/qrceditor.pri | 1 + 7 files changed, 7 insertions(+) diff --git a/src/plugins/debugger/cdb/cdb.pri b/src/plugins/debugger/cdb/cdb.pri index 16c33776496..ff877890a48 100644 --- a/src/plugins/debugger/cdb/cdb.pri +++ b/src/plugins/debugger/cdb/cdb.pri @@ -27,6 +27,7 @@ CDB_PLATFORM=i386 INCLUDEPATH*=$$CDB_PATH INCLUDEPATH*=$$PWD +DEPENDPATH*=$$PWD CDB_LIBPATH=$$CDB_PATH/lib/$$CDB_PLATFORM diff --git a/src/plugins/designer/cpp/cpp.pri b/src/plugins/designer/cpp/cpp.pri index a30a7940228..2df8138f638 100644 --- a/src/plugins/designer/cpp/cpp.pri +++ b/src/plugins/designer/cpp/cpp.pri @@ -1,4 +1,5 @@ INCLUDEPATH+=$$PWD +DEPENDPATH+=$$PWD DEFINES+=CPP_ENABLED diff --git a/src/plugins/git/gitorious/gitorious.pri b/src/plugins/git/gitorious/gitorious.pri index 8678042a262..d10e09c15bc 100644 --- a/src/plugins/git/gitorious/gitorious.pri +++ b/src/plugins/git/gitorious/gitorious.pri @@ -1,5 +1,6 @@ QT += network INCLUDEPATH+=$$PWD +DEPENDPATH+=$$PWD HEADERS += $$PWD/gitoriousclonewizard.h \ $$PWD/gitorioushostwizardpage.h \ diff --git a/src/plugins/qt4projectmanager/customwidgetwizard/customwidgetwizard.pri b/src/plugins/qt4projectmanager/customwidgetwizard/customwidgetwizard.pri index 4547080e961..374fca6aec3 100644 --- a/src/plugins/qt4projectmanager/customwidgetwizard/customwidgetwizard.pri +++ b/src/plugins/qt4projectmanager/customwidgetwizard/customwidgetwizard.pri @@ -1,4 +1,5 @@ INCLUDEPATH *= $$PWD +DEPENDPATH *= $$PWD SOURCES += \ $$PWD/plugingenerator.cpp \ $$PWD/classlist.cpp \ diff --git a/src/shared/help/help.pri b/src/shared/help/help.pri index dff0ae7699b..69801bb672b 100644 --- a/src/shared/help/help.pri +++ b/src/shared/help/help.pri @@ -1,6 +1,7 @@ VPATH += $$PWD INCLUDEPATH *= $$PWD $$PWD/.. +DEPENDPATH *= $$PWD $$PWD/.. # Input HEADERS += \ diff --git a/src/shared/proparser/proparser.pri b/src/shared/proparser/proparser.pri index d1c5d630e86..8b274d51b28 100644 --- a/src/shared/proparser/proparser.pri +++ b/src/shared/proparser/proparser.pri @@ -2,6 +2,7 @@ VPATH += $$PWD QT += xml INCLUDEPATH *= $$PWD $$PWD/.. +DEPENDPATH *= $$PWD $$PWD/.. # Input HEADERS += \ diff --git a/src/shared/qrceditor/qrceditor.pri b/src/shared/qrceditor/qrceditor.pri index 47e54c936e1..00c26ce6777 100644 --- a/src/shared/qrceditor/qrceditor.pri +++ b/src/shared/qrceditor/qrceditor.pri @@ -1,4 +1,5 @@ INCLUDEPATH *= $$PWD $$PWD/.. +DEPENDPATH *= $$PWD $$PWD/.. QT *= xml From 99c33277198948bab7f9664c939f748bfefd2181 Mon Sep 17 00:00:00 2001 From: Roberto Raggi Date: Mon, 12 Oct 2009 12:00:40 +0200 Subject: [PATCH 04/34] Improved support for private classes. --- src/libs/cplusplus/LookupContext.cpp | 68 ++++++++++++++++++++++------ src/shared/cplusplus/Scope.cpp | 15 ++++++ src/shared/cplusplus/Scope.h | 1 + 3 files changed, 69 insertions(+), 15 deletions(-) diff --git a/src/libs/cplusplus/LookupContext.cpp b/src/libs/cplusplus/LookupContext.cpp index 0b2fd4bba26..410e1fac786 100644 --- a/src/libs/cplusplus/LookupContext.cpp +++ b/src/libs/cplusplus/LookupContext.cpp @@ -130,26 +130,66 @@ QList LookupContext::resolveQualifiedNameId(QualifiedNameId *q, const QList &visibleScopes, ResolveMode mode) const { - QList scopes; + QList candidates; - if (q->nameCount() == 1) - scopes = visibleScopes; // ### handle global scope lookup - else - scopes = resolveNestedNameSpecifier(q, visibleScopes); + for (int i = 0; i < visibleScopes.size(); ++i) { + Scope *scope = visibleScopes.at(i); - QList expanded; - foreach (Scope *scope, scopes) { - expanded.append(scope); + for (Symbol *symbol = scope->lookat(q); symbol; symbol = symbol->next()) { + if (! symbol->name()) + continue; - for (unsigned i = 0; i < scope->symbolCount(); ++i) { - Symbol *member = scope->symbolAt(i); + QualifiedNameId *qq = symbol->name()->asQualifiedNameId(); - if (ScopedSymbol *scopedSymbol = member->asScopedSymbol()) - expandEnumOrAnonymousSymbol(scopedSymbol, &expanded); + if (! qq) + continue; + else if (! maybeValidSymbol(symbol, mode, candidates)) + continue; + + if (! q->unqualifiedNameId()->isEqualTo(qq->unqualifiedNameId())) + continue; + + else if (qq->nameCount() == q->nameCount()) { + unsigned j = 0; + + for (; j < q->nameCount(); ++j) { + Name *classOrNamespaceName1 = q->nameAt(j); + Name *classOrNamespaceName2 = qq->nameAt(j); + + if (! classOrNamespaceName1->isEqualTo(classOrNamespaceName2)) + break; + } + + if (j == q->nameCount()) + candidates.append(symbol); + } } } - return resolve(q->unqualifiedNameId(), expanded, mode); + if (candidates.isEmpty()) { + QList scopes; + + if (q->nameCount() == 1) + scopes = visibleScopes; // ### handle global scope lookup + else + scopes = resolveNestedNameSpecifier(q, visibleScopes); + + QList expanded; + foreach (Scope *scope, scopes) { + expanded.append(scope); + + for (unsigned i = 0; i < scope->symbolCount(); ++i) { + Symbol *member = scope->symbolAt(i); + + if (ScopedSymbol *scopedSymbol = member->asScopedSymbol()) + expandEnumOrAnonymousSymbol(scopedSymbol, &expanded); + } + } + + candidates += resolve(q->unqualifiedNameId(), expanded, mode); + } + + return candidates; } QList LookupContext::resolveOperatorNameId(OperatorNameId *opId, @@ -198,13 +238,11 @@ QList LookupContext::resolve(Name *name, const QList &visible else if (! maybeValidSymbol(symbol, mode, candidates)) continue; // skip it, we're not looking for this kind of symbols - else if (Identifier *symbolId = symbol->identifier()) { if (! symbolId->isEqualTo(id)) continue; // skip it, the symbol's id is not compatible with this lookup. } - if (QualifiedNameId *q = symbol->name()->asQualifiedNameId()) { if (name->isDestructorNameId() != q->unqualifiedNameId()->isDestructorNameId()) diff --git a/src/shared/cplusplus/Scope.cpp b/src/shared/cplusplus/Scope.cpp index 6c910c072c6..fcb5a68027c 100644 --- a/src/shared/cplusplus/Scope.cpp +++ b/src/shared/cplusplus/Scope.cpp @@ -208,6 +208,21 @@ void Scope::enterSymbol(Symbol *symbol) } } +Symbol *Scope::lookat(Name *name) const +{ + if (! name) + return 0; + + else if (OperatorNameId *opId = name->asOperatorNameId()) + return lookat(opId->kind()); + + else if (Identifier *id = name->identifier()) + return lookat(id); + + else + return 0; +} + Symbol *Scope::lookat(Identifier *id) const { if (! _hash || ! id) diff --git a/src/shared/cplusplus/Scope.h b/src/shared/cplusplus/Scope.h index 5fb9eb3ac7c..1abc41530df 100644 --- a/src/shared/cplusplus/Scope.h +++ b/src/shared/cplusplus/Scope.h @@ -129,6 +129,7 @@ public: /// Returns the last Symbol in the scope. iterator lastSymbol() const; + Symbol *lookat(Name *name) const; Symbol *lookat(Identifier *id) const; Symbol *lookat(int operatorId) const; From 8ccc07a10ba7c7885c0f6a51dcdac2c50db9997a Mon Sep 17 00:00:00 2001 From: Roberto Raggi Date: Mon, 12 Oct 2009 12:25:22 +0200 Subject: [PATCH 05/34] Stop at the T_COMMA when searching backward for an expression. --- src/libs/cplusplus/ExpressionUnderCursor.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/libs/cplusplus/ExpressionUnderCursor.cpp b/src/libs/cplusplus/ExpressionUnderCursor.cpp index d95982b881c..26a2b3a961a 100644 --- a/src/libs/cplusplus/ExpressionUnderCursor.cpp +++ b/src/libs/cplusplus/ExpressionUnderCursor.cpp @@ -51,6 +51,7 @@ int ExpressionUnderCursor::startOfExpression(BackwardsScanner &tk, int index) const SimpleToken &tok = tk[index - 1]; switch (tok.kind()) { + case T_COMMA: case T_LPAREN: case T_LBRACKET: case T_LBRACE: From b2924aa66b98fbab3d55c475f0be688ba93f81ec Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Mon, 12 Oct 2009 12:33:12 +0200 Subject: [PATCH 06/34] I18n: Tr()-fixes --- src/plugins/coreplugin/generalsettings.ui | 18 +++-------- .../debugger/gdb/abstractgdbadapter.cpp | 30 +++++++++++++++++++ src/plugins/debugger/gdb/abstractgdbadapter.h | 7 +++++ src/plugins/debugger/gdb/attachgdbadapter.cpp | 8 ++--- src/plugins/debugger/gdb/coregdbadapter.cpp | 3 +- src/plugins/debugger/gdb/plaingdbadapter.cpp | 8 ++--- src/plugins/debugger/gdb/remotegdbadapter.cpp | 11 +++---- src/plugins/debugger/gdb/trkgdbadapter.cpp | 12 +++----- src/plugins/find/searchresultwindow.cpp | 4 +-- .../qt4projectmanager/qt4runconfiguration.cpp | 8 ++--- 10 files changed, 62 insertions(+), 47 deletions(-) diff --git a/src/plugins/coreplugin/generalsettings.ui b/src/plugins/coreplugin/generalsettings.ui index dd680aa10cf..b33497825c7 100644 --- a/src/plugins/coreplugin/generalsettings.ui +++ b/src/plugins/coreplugin/generalsettings.ui @@ -59,7 +59,7 @@ 0 - + false @@ -163,6 +163,9 @@ When files are externally modified: + + true + @@ -193,19 +196,6 @@ - - - - Qt::Horizontal - - - - 40 - 20 - - - - diff --git a/src/plugins/debugger/gdb/abstractgdbadapter.cpp b/src/plugins/debugger/gdb/abstractgdbadapter.cpp index 1a523f8d1ca..52c76107606 100644 --- a/src/plugins/debugger/gdb/abstractgdbadapter.cpp +++ b/src/plugins/debugger/gdb/abstractgdbadapter.cpp @@ -83,5 +83,35 @@ bool AbstractGdbAdapter::isTrkAdapter() const return false; } +QString AbstractGdbAdapter::msgGdbStopFailed(const QString &why) +{ + return tr("The Gdb process could not be stopped:\n%1").arg(why); +} + +QString AbstractGdbAdapter::msgInferiorStopFailed(const QString &why) +{ + return tr("Inferior process could not be stopped:\n%1").arg(why); +} + +QString AbstractGdbAdapter::msgInferiorStarted() +{ + return tr("Inferior started."); +} + +QString AbstractGdbAdapter::msgInferiorRunning() +{ + return tr("Inferior running."); +} + +QString AbstractGdbAdapter::msgAttachedToStoppedInferior() +{ + return tr("Attached to stopped inferior."); +} + +QString AbstractGdbAdapter::msgConnectRemoteServerFailed(const QString &why) +{ + return tr("Connecting to remote server failed:\n%1").arg(why); +} + } // namespace Internal } // namespace Debugger diff --git a/src/plugins/debugger/gdb/abstractgdbadapter.h b/src/plugins/debugger/gdb/abstractgdbadapter.h index cafc03d491d..ecb52f9316e 100644 --- a/src/plugins/debugger/gdb/abstractgdbadapter.h +++ b/src/plugins/debugger/gdb/abstractgdbadapter.h @@ -93,6 +93,13 @@ protected: void showStatusMessage(const QString &msg) const { m_engine->showStatusMessage(msg); } + static QString msgGdbStopFailed(const QString &why); + static QString msgInferiorStopFailed(const QString &why); + static QString msgAttachedToStoppedInferior(); + static QString msgInferiorStarted(); + static QString msgInferiorRunning(); + static QString msgConnectRemoteServerFailed(const QString &why); + GdbEngine * const m_engine; QProcess m_gdbProc; diff --git a/src/plugins/debugger/gdb/attachgdbadapter.cpp b/src/plugins/debugger/gdb/attachgdbadapter.cpp index a43947129b7..e06790e0ab4 100644 --- a/src/plugins/debugger/gdb/attachgdbadapter.cpp +++ b/src/plugins/debugger/gdb/attachgdbadapter.cpp @@ -107,7 +107,7 @@ void AttachGdbAdapter::handleAttach(const GdbResponse &response) if (response.resultClass == GdbResultDone) { setState(InferiorStopped); debugMessage(_("INFERIOR STARTED")); - showStatusMessage(tr("Attached to stopped inferior.")); + showStatusMessage(msgAttachedToStoppedInferior()); m_engine->updateAll(); } else if (response.resultClass == GdbResultError) { QString msg = __(response.data.findChild("msg").data()); @@ -155,8 +155,7 @@ void AttachGdbAdapter::handleDetach(const GdbResponse &response) emit inferiorShutDown(); shutdown(); // re-iterate... } else if (response.resultClass == GdbResultError) { - QString msg = tr("Inferior process could not be stopped:\n") + - __(response.data.findChild("msg").data()); + const QString msg = msgInferiorStopFailed(__(response.data.findChild("msg").data())); setState(InferiorShutdownFailed); emit inferiorShutdownFailed(msg); } @@ -167,8 +166,7 @@ void AttachGdbAdapter::handleExit(const GdbResponse &response) if (response.resultClass == GdbResultDone) { // don't set state here, this will be handled in handleGdbFinished() } else if (response.resultClass == GdbResultError) { - QString msg = tr("Gdb process could not be stopped:\n") + - __(response.data.findChild("msg").data()); + const QString msg = msgGdbStopFailed(__(response.data.findChild("msg").data())); emit adapterShutdownFailed(msg); } } diff --git a/src/plugins/debugger/gdb/coregdbadapter.cpp b/src/plugins/debugger/gdb/coregdbadapter.cpp index d51963606e3..dd4d5725e8e 100644 --- a/src/plugins/debugger/gdb/coregdbadapter.cpp +++ b/src/plugins/debugger/gdb/coregdbadapter.cpp @@ -221,8 +221,7 @@ void CoreGdbAdapter::handleExit(const GdbResponse &response) if (response.resultClass == GdbResultDone) { // don't set state here, this will be handled in handleGdbFinished() } else if (response.resultClass == GdbResultError) { - QString msg = tr("Gdb process could not be stopped:\n") + - __(response.data.findChild("msg").data()); + const QString msg = msgGdbStopFailed(__(response.data.findChild("msg").data())); emit adapterShutdownFailed(msg); } } diff --git a/src/plugins/debugger/gdb/plaingdbadapter.cpp b/src/plugins/debugger/gdb/plaingdbadapter.cpp index 5d679527aa4..c0fdea89487 100644 --- a/src/plugins/debugger/gdb/plaingdbadapter.cpp +++ b/src/plugins/debugger/gdb/plaingdbadapter.cpp @@ -135,7 +135,7 @@ void PlainGdbAdapter::handleExecRun(const GdbResponse &response) if (response.resultClass == GdbResultRunning) { QTC_ASSERT(state() == InferiorRunning, qDebug() << state()); debugMessage(_("INFERIOR STARTED")); - showStatusMessage(tr("Inferior started.")); + showStatusMessage(msgInferiorStarted()); } else { QTC_ASSERT(state() == InferiorRunningRequested, qDebug() << state()); QTC_ASSERT(response.resultClass == GdbResultError, /**/); @@ -219,8 +219,7 @@ void PlainGdbAdapter::handleKill(const GdbResponse &response) emit inferiorShutDown(); shutdown(); // re-iterate... } else if (response.resultClass == GdbResultError) { - QString msg = tr("Inferior process could not be stopped:\n") + - __(response.data.findChild("msg").data()); + const QString msg = msgInferiorStopFailed(__(response.data.findChild("msg").data())); setState(InferiorShutdownFailed); emit inferiorShutdownFailed(msg); } @@ -231,8 +230,7 @@ void PlainGdbAdapter::handleExit(const GdbResponse &response) if (response.resultClass == GdbResultDone) { // don't set state here, this will be handled in handleGdbFinished() } else if (response.resultClass == GdbResultError) { - QString msg = tr("Gdb process could not be stopped:\n") + - __(response.data.findChild("msg").data()); + const QString msg = msgGdbStopFailed(__(response.data.findChild("msg").data())); emit adapterShutdownFailed(msg); } } diff --git a/src/plugins/debugger/gdb/remotegdbadapter.cpp b/src/plugins/debugger/gdb/remotegdbadapter.cpp index 71ee7852b27..0b386f8b0f6 100644 --- a/src/plugins/debugger/gdb/remotegdbadapter.cpp +++ b/src/plugins/debugger/gdb/remotegdbadapter.cpp @@ -212,13 +212,12 @@ void RemoteGdbAdapter::handleTargetRemote(const GdbResponse &record) if (record.resultClass == GdbResultDone) { // gdb server will stop the remote application itself. debugMessage(_("INFERIOR STARTED")); - showStatusMessage(tr("Attached to stopped inferior.")); + showStatusMessage(msgAttachedToStoppedInferior()); setState(InferiorStopped); m_engine->continueInferior(); } else if (record.resultClass == GdbResultError) { // 16^error,msg="hd:5555: Connection timed out." - QString msg = tr("Connecting to remote server failed:\n"); - msg += __(record.data.findChild("msg").data()); + QString msg = msgConnectRemoteServerFailed(__(record.data.findChild("msg").data())); setState(InferiorPreparationFailed); emit inferiorStartFailed(msg); } @@ -273,8 +272,7 @@ void RemoteGdbAdapter::handleKill(const GdbResponse &response) emit inferiorShutDown(); shutdown(); // re-iterate... } else if (response.resultClass == GdbResultError) { - QString msg = tr("Inferior process could not be stopped:\n") + - __(response.data.findChild("msg").data()); + QString msg = msgInferiorStopFailed(__(response.data.findChild("msg").data())); setState(InferiorShutdownFailed); emit inferiorShutdownFailed(msg); } @@ -285,8 +283,7 @@ void RemoteGdbAdapter::handleExit(const GdbResponse &response) if (response.resultClass == GdbResultDone) { // don't set state here, this will be handled in handleGdbFinished() } else if (response.resultClass == GdbResultError) { - QString msg = tr("Gdb process could not be stopped:\n") + - __(response.data.findChild("msg").data()); + QString msg = msgGdbStopFailed(__(response.data.findChild("msg").data())); emit adapterShutdownFailed(msg); } } diff --git a/src/plugins/debugger/gdb/trkgdbadapter.cpp b/src/plugins/debugger/gdb/trkgdbadapter.cpp index a2b735777c4..1db8f66ff08 100644 --- a/src/plugins/debugger/gdb/trkgdbadapter.cpp +++ b/src/plugins/debugger/gdb/trkgdbadapter.cpp @@ -1702,11 +1702,9 @@ void TrkGdbAdapter::handleFirstContinue(const GdbResponse &record) QTC_ASSERT(state() == InferiorRunning, qDebug() << state()); if (record.resultClass == GdbResultDone) { debugMessage(_("INFERIOR STARTED")); - showStatusMessage(tr("Inferior running.")); + showStatusMessage(msgInferiorRunning()); } else if (record.resultClass == GdbResultError) { - //QString msg = __(record.data.findChild("msg").data()); - QString msg1 = tr("Connecting to remote server failed:"); - emit inferiorStartFailed(msg1 + record.toString()); + emit inferiorStartFailed(msgConnectRemoteServerFailed(record.toString())); } } @@ -2083,8 +2081,7 @@ void TrkGdbAdapter::handleKill(const GdbResponse &response) emit inferiorShutDown(); shutdown(); // re-iterate... } else if (response.resultClass == GdbResultError) { - QString msg = tr("Inferior process could not be stopped:\n") + - __(response.data.findChild("msg").data()); + const QString msg = msgInferiorStopFailed(__(response.data.findChild("msg").data())); setState(InferiorShutdownFailed); emit inferiorShutdownFailed(msg); } @@ -2096,8 +2093,7 @@ void TrkGdbAdapter::handleExit(const GdbResponse &response) qDebug() << "EXITED, NO MESSAGE..."; // don't set state here, this will be handled in handleGdbFinished() } else if (response.resultClass == GdbResultError) { - QString msg = tr("Gdb process could not be stopped:\n") + - __(response.data.findChild("msg").data()); + const QString msg = msgGdbStopFailed(__(response.data.findChild("msg").data())); emit adapterShutdownFailed(msg); } } diff --git a/src/plugins/find/searchresultwindow.cpp b/src/plugins/find/searchresultwindow.cpp index a995dfc5b7b..c60e2d6c9ee 100644 --- a/src/plugins/find/searchresultwindow.cpp +++ b/src/plugins/find/searchresultwindow.cpp @@ -78,7 +78,7 @@ SearchResultWindow::SearchResultWindow() m_replaceLabel->setContentsMargins(12, 0, 5, 0); m_replaceTextEdit = new QLineEdit(m_widget); m_replaceButton = new QToolButton(m_widget); - m_replaceButton->setToolTip(tr("Replace all occurances")); + m_replaceButton->setToolTip(tr("Replace all occurrences")); m_replaceButton->setText(tr("Replace")); m_replaceButton->setToolButtonStyle(Qt::ToolButtonTextOnly); m_replaceButton->setAutoRaise(true); @@ -234,7 +234,7 @@ void SearchResultWindow::setTextEditorFont(const QFont &font) m_searchResultTreeView->setTextEditorFont(font); } -void SearchResultWindow::handleJumpToSearchResult(int index, bool checked) +void SearchResultWindow::handleJumpToSearchResult(int index, bool /* checked */) { QTC_ASSERT(m_currentSearch, return); m_currentSearch->activated(m_items.at(index)); diff --git a/src/plugins/qt4projectmanager/qt4runconfiguration.cpp b/src/plugins/qt4projectmanager/qt4runconfiguration.cpp index 2c4083ad46f..4c7a31e13bc 100644 --- a/src/plugins/qt4projectmanager/qt4runconfiguration.cpp +++ b/src/plugins/qt4projectmanager/qt4runconfiguration.cpp @@ -241,10 +241,10 @@ void Qt4RunConfigurationWidget::updateSummary() { const QString &filename = QFileInfo(m_qt4RunConfiguration->executable()).fileName(); const QString &arguments = ProjectExplorer::Environment::joinArgumentList(m_qt4RunConfiguration->commandLineArguments()); - QString text = tr("Running executable: %1 %2 %3").arg( - filename, - arguments, - m_qt4RunConfiguration->runMode() == LocalApplicationRunConfiguration::Console ? tr("(in terminal)") : ""); + const bool terminal = m_qt4RunConfiguration->runMode() == LocalApplicationRunConfiguration::Console; + const QString text = terminal ? + tr("Running executable: %1 %2 (in terminal)").arg(filename, arguments) : + tr("Running executable: %1 %2").arg(filename, arguments); m_detailsContainer->setSummaryText(text); } From e1ce20bf8fc5a1974fe4a0d92acdb8e67af2acb0 Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Mon, 12 Oct 2009 12:35:10 +0200 Subject: [PATCH 07/34] i18n: Update German translation for 1.3 --- share/qtcreator/translations/qtcreator_de.ts | 1540 ++++++------------ 1 file changed, 467 insertions(+), 1073 deletions(-) diff --git a/share/qtcreator/translations/qtcreator_de.ts b/share/qtcreator/translations/qtcreator_de.ts index 1d348113c52..ca905d5a1f4 100644 --- a/share/qtcreator/translations/qtcreator_de.ts +++ b/share/qtcreator/translations/qtcreator_de.ts @@ -23,10 +23,6 @@ Qt Creator - Plugin loader messages Qt Creator - Meldungen der Plugin-Verwaltung - - Couldn't find 'Core.pluginspec' in %1 - Die Datei 'Core.pluginspec' konnte in %1 nicht gefunden werden - AttachCoreDialog @@ -69,29 +65,6 @@ Löschen - - AttachTcfDialog - - Start Debugger - Debugger starten - - - Host and port: - Host und Portnummer: - - - Architecture: - Architektur: - - - Use server start script: - Server-Startskript benutzen: - - - Server start script: - Server-Startskript: - - BINEditor::Internal::BinEditorPlugin @@ -616,12 +589,12 @@ "%1" hinzufügen - + Alt+C,Alt+A Alt+C,Alt+A - + Delete Löschen @@ -656,12 +629,12 @@ Diff für "%1" - + Alt+C,Alt+D Alt+C,Alt+D - + Commit All Files Alle Dateien abgeben @@ -676,12 +649,12 @@ "%1" abgeben - + Alt+C,Alt+C Alt+C,Alt+C - + Filelog Current File Filelog für Datei @@ -806,13 +779,7 @@ Executing in %1: %2 %3 - Kommando [%1]: %2 %3 - - - - Executing in %1: %2 %2 - - Kommando [%1]: %2 %3 + Kommando [%1]: %2 %3 @@ -940,7 +907,7 @@ CVSPlugin - + Cannot find repository for '%1' Das Repository der Datei '%1' konnte nicht gefunden werden @@ -1010,12 +977,12 @@ <Unknown Type> - + <Unbekannter Typ> <Unknown Value> - + <Unbekannter Wert> @@ -1076,22 +1043,22 @@ Ausschnitt einfügen... - + Alt+C,Alt+P Alt+C,Alt+P - + Fetch Snippet... Ausschnitt holen... - + Alt+C,Alt+F Alt+C,Alt+F - + This protocol supports no listing Dieses Protokoll stellt keine Liste zur Verfügung @@ -1187,10 +1154,6 @@ Skip known frames when stepping Bekannte Stellen beim Einzelschritt überspringen - - Use tooltips while debugging - Tooltips beim Debuggen benutzen - Maximal stack depth: @@ -1206,10 +1169,6 @@ Use alternating row colors in debug views Alternierende Farben für Debugansichten benutzen - - Checking this will enable tooltips for variable values during debugging. Since this can slow down debugging and does not provide reliable information as it does not use scope information, it is switched off by default. - Diese Option aktiviert Tooltips für Variablen beim Debuggen. Das es das Debuggen verlangsamt und wegen der fehlenden Scope-Information nicht zuverlässig ist, ist es per Vorgabe deaktiviert. - Enable reverse debugging @@ -1223,7 +1182,7 @@ Use tooltips in main editor while debugging - + Tooltips beim Debuggen benutzen @@ -1349,12 +1308,12 @@ Sollen sie überschrieben werden? Core::EditorManager - + Revert to Saved Wiederherstellen - + Close Schließen @@ -1366,12 +1325,12 @@ Sollen sie überschrieben werden? - + Close Others Andere schließen - + Open in External Editor Öffne in externem Editor @@ -1431,57 +1390,42 @@ Sollen sie überschrieben werden? Alt+Right - + + Meta+E + Meta+E + + + + Ctrl+E + Ctrl+E + + + Split Teilen - - Ctrl+E,2 - Ctrl+E,2 - - - + Split Side by Side Nebeneinander teilen - - Ctrl+E,3 - Ctrl+E,3 - - - + Remove Current Split Teilung aufheben - - Ctrl+E,0 - Ctrl+E,0 - - - + Remove All Splits Alle Teilungen aufheben - - Ctrl+E,1 - Ctrl+E,1 - - - + Goto Other Split Gehe zu anderer Teilung - - Ctrl+E,o - Ctrl+E,o - - - + &Advanced &Weitere @@ -1559,7 +1503,7 @@ Sollen sie überschrieben werden? Schreibbar machen - + Next Open Document in History Nächstes geöffnetes Dokument im Verlauf @@ -1579,7 +1523,32 @@ Sollen sie überschrieben werden? Nächstes - + + %1,2 + %1,2 + + + + %1,3 + %1,3 + + + + %1,0 + %1,0 + + + + %1,1 + %1,1 + + + + %1,o + %1,o + + + Save %1 As... Speicher '%1' unter... @@ -1626,23 +1595,15 @@ Sollen sie überschrieben werden? Core::FileManager - - Can't save file - Die Datei kann nicht gespeichert werden - - - Can't save changes to '%1'. Do you want to continue and loose your changes? - Die Datei '%1' kann nicht gespeichert werden. Wollen Sie trotzdem fortsetzen und Ihre Änderungen aufgeben? - Cannot save file - Die Datei kann nicht gespeichert werden + Die Datei kann nicht gespeichert werden Cannot save changes to '%1'. Do you want to continue and lose your changes? - Die Datei '%1' kann nicht gespeichert werden. Wollen Sie trotzdem fortsetzen und Ihre Änderungen aufgeben? + Die Datei '%1' kann nicht gespeichert werden. Wollen Sie trotzdem fortsetzen und Ihre Änderungen aufgeben? @@ -1833,7 +1794,7 @@ Sollen sie überschrieben werden? External editor: - 'Externer Editor: + Externer Editor: @@ -1864,7 +1825,7 @@ Sollen sie überschrieben werden? Core::Internal::MainWindow - + Qt Creator Qt Creator @@ -2044,6 +2005,11 @@ Sollen sie überschrieben werden? Title of dialog Neu... + + + Settings... + Einstellungen... + Core::Internal::MessageOutputWindow @@ -2218,14 +2184,10 @@ Sollen sie überschrieben werden? Core::Internal::SaveItemsDialog - - Don't Save - Nicht speichern - Do not Save - Nicht speichern + Nicht speichern @@ -2352,19 +2314,19 @@ Sollen sie überschrieben werden? CppEditor::Internal::CPPEditor - + Sort alphabetically Alphabetisch sortieren - + This change cannot be undone. - + Diese Änderung kann nicht rückgängig gemacht werden. Yes, I know what I am doing. - + Ja, Ich bin mir dessen bewußt. @@ -2459,12 +2421,12 @@ Sollen sie überschrieben werden? Find Usages - + Verwendung suchen Ctrl+Shift+U - Ctrl+Shift+U + Ctrl+Shift+U @@ -2503,7 +2465,7 @@ Sollen sie überschrieben werden? CppPreprocessor - + %1: No such file or directory %1: Es existiert keine Datei oder kein Verzeichnis dieses Namens @@ -2593,7 +2555,7 @@ Sollen sie überschrieben werden? CppTools::Internal::CppFindReferences - + Searching... Suche... @@ -2609,7 +2571,7 @@ Sollen sie überschrieben werden? CppTools::Internal::CppModelManager - + Scanning Suche @@ -2630,7 +2592,7 @@ Sollen sie überschrieben werden? CppTools::Internal::CppToolsPlugin - + &C++ &C++ @@ -2640,32 +2602,6 @@ Sollen sie überschrieben werden? Zwischen Header- und Quelldatei wechseln - - CppTools::Internal::FindClassDeclarations - - - Search class - Suche Klasse - - - - Class Declarations - Klassendeklarationen - - - - CppTools::Internal::FindFunctionCalls - - - Search functions - Suche Funktion - - - - Function calls - Funktionsaufrufe - - CppTools::Internal::FunctionArgumentWidget @@ -2695,18 +2631,18 @@ Sollen sie überschrieben werden? Debugger::DebuggerManager - + Continue Fortsetzen - + Interrupt Anhalten - + Reset Debugger Debugger zurücksetzen @@ -2768,7 +2704,7 @@ Sollen sie überschrieben werden? Exited. - Beendet. + Beendet. @@ -2782,12 +2718,7 @@ Sollen sie überschrieben werden? Diese Anwendung erfordert den Debugger '%1', der gegenwärtig deaktiviert ist. - - Debugging VS executables is currently not enabled. - Das Debuggen von mit VS erzeugten ausführbaren Dateien ist momentan deaktiviert. - - - + Starting debugger for tool chain '%1'... Starte Debugger für Toolchain '%1'... @@ -2802,11 +2733,7 @@ Sollen sie überschrieben werden? Der Debugger kann nicht mit '%1' (Toolchain '%2') gestartet werden: %3 - Settings... - Einstellungen... - - - + Save Debugger Log Debugger Log speichern @@ -2850,19 +2777,11 @@ Sollen sie überschrieben werden? Stop Debugger Debugger anhalten - - Stop requested... - Stop angefordert... - - - Running requested... - Fortsetzung angefordert... - Debugger::Internal::AddressDialog - + Select start address Startadresse @@ -2908,37 +2827,6 @@ Sollen sie überschrieben werden? Aktualisieren - - Debugger::Internal::AttachGdbAdapter - - Cannot set up communication with child process: %1 - Die Kommunikation mit dem untergeordneten Prozesss konnte nicht hergestellt werden: %1 - - - - Attached to stopped inferior. - - - - - Inferior process could not be stopped: - - - - - - Gdb process could not be stopped: - - - - - - Debugger::Internal::AttachTcfDialog - - Select Executable - Ausführbare Datei auswählen - - Debugger::Internal::BreakHandler @@ -3039,7 +2927,7 @@ Sollen sie überschrieben werden? Address - Adresse + Adresse @@ -3149,12 +3037,27 @@ Sollen sie überschrieben werden? Der Funktionsaufruf "%1()" schlug fehl: %2 - + Unable to resolve '%1' in the debugger engine library '%2' '%1' konnte in der Debugger-Bibliothek '%2' nicht gefunden werden - + + Version: %1 + Version: %1 + + + + <html>The installed version of the <i>Debugging Tools for Windows</i> (%1) is rather old. Upgrading to version %2 is recommended for the proper display of Qt's data types.</html> + <html>Die gegenwärtig installierte Version der <i>Debugging Tools for Windows</i> (%1) ist veraltet. Es wird ein Upgrade auf Version %2 empfohlen, um die Qt-Datentypen richtig anzeigen zu können.</html> + + + + Debugger + Debugger + + + The dumper library was not found at %1. Es konnte keine Ausgabe-Hilfsbibliothek unter %1 gefunden werden. @@ -3191,52 +3094,52 @@ Sollen sie überschrieben werden? The process exited with exit code %1. - + Der Prozess wurde beendet, Rückgabewert %1. Continuing with '%1'... - + Setze mit '%1' fort... Unable to continue: %1 - + Die Ausführung des Prozesses kann nicht fortgesetzt werden: %1 Reverse stepping is not implemented. - + Die Funktionalität für 'Einzelschritt rückwärts' ist nicht implementiert. Stepping %1 - + Führe Schritt aus (%1) Running to 0x%1... - + Ausführung bis zur Adresse 0x%1... Running requested... - Fortsetzung angefordert... + Fortsetzung angefordert... Running up to %1:%2... - + Ausführung bis %1:%2... Running up to function '%1()'... - + Ausführung bis zu Funktion '%1()'... Jump to line is not implemented - + Die Funktionalität für 'Springe zu Zeile' ist nicht implementiert @@ -3262,22 +3165,22 @@ Sollen sie überschrieben werden? Stopped, current thread: %1 - + Angehalten, Thread: %1 Changing threads: %1 -> %2 - + Wechsel von Thread %1 zu %2 Thread %1: Missing debug information for top stack frame (%2). - + Thread %1: Es ist keine Debug-Information für obersten Stack-Rahmen (%2) vorhanden. Thread %1: No debug information available (%2). - + Thread %1: Es ist keine Debug-Information vorhanden (%2). @@ -3333,7 +3236,7 @@ Sollen sie überschrieben werden? Die Ausgabe-Hilfsbibliothek konnte nicht initialisiert werden: %1 - + Querying dumpers for '%1'/'%2' (%3) Abfrage der Ausgabe-Hilfsbibliothek für '%1'/'%2' (%3) @@ -3388,47 +3291,39 @@ Sollen sie überschrieben werden? Debugger::Internal::CoreGdbAdapter - - Cannot set up communication with child process: %1 - Die Kommunikation mit dem untergeordneten Prozesss konnte nicht hergestellt werden: %1 - Attached to core. - + Debugge core-Datei. Symbols found. - + Die Symbole wurden gefunden. Attached to core temporarily. - + Debugge core-Datei temporär. No binary found. - + Es konnte keine ausführbare Datei gefunden werden. Symbols not found in "%1" failed: %2 - + In "%1" konnten keine Symbole gefunden werden; Fehler: +%2 Attach to core "%1" failed: %2 - - - - - Gdb process could not be stopped: - - + Das Debuggen der core-Datei "%1" schlug fehl: +%2 @@ -3484,14 +3379,6 @@ Sollen sie überschrieben werden? Attach to Core... Debugge core-Datei - - Attach to Running Tcf Agent... - An laufenden Tcf-Agenten anhängen... - - - This attaches to a running 'Target Communication Framework' agent. - An einen laufenden 'Target Communication Framework'-Agenten anhängen. - Start and Attach to Remote Application... @@ -3570,22 +3457,23 @@ Sollen sie überschrieben werden? Attaching to core %1. - + Debugge core-Datei %1. Debugger::Internal::DebuggerRunControlFactory - + Debug Debuggen - Debugger::Internal::DebuggerRunner + Debugger::Internal::DebuggerRunControl - Debug - Debuggen + + Debugger + Debugger @@ -3620,29 +3508,25 @@ Sollen sie überschrieben werden? Log time stamps Zeitstempel loggen - - Step by instruction - Einzelschritt über Anweisung - Operate by instruction - + Auf Anweisungsebene arbeiten This switches the debugger to instruction-wise operation mode. In this mode, stepping operates on single instructions and the source location view also shows the disassembled instructions. - + Weist den Debugger an, auf Anweisungsebene zu arbeiten. In diesem Modus arbeitet die Einzelschritt-Funktion auf Maschinenanweisungen und die Quelltextanzeige zeigt die disassemblierten Anweisungen an. Dereference pointers automatically - + Zeiger automatisch dereferenzieren This switches the Locals&Watchers view to automatically derefence pointers. This saves a level in the tree view, but also loses data for the now-missing intermediate level. - + Bewirkt, dass Zeiger im Fenster "Lokale Variablen und Überwachte Ausdrücke" automatisch dereferenziert werden. Das vereinfacht die Baumanzeige, allerdings fehlt die Information über die Zwischenebene. @@ -3687,56 +3571,52 @@ Sollen sie überschrieben werden? Use tooltips in main editor when debugging - + Tooltips im Haupt-Editor beim Debuggen benutzen Checking this will enable tooltips for variable values during debugging. Since this can slow down debugging and does not provide reliable information as it does not use scope information, it is switched off by default. - Diese Option aktiviert Tooltips für Variablen beim Debuggen. Das es das Debuggen verlangsamt und wegen der fehlenden Scope-Information nicht zuverlässig ist, ist es per Vorgabe deaktiviert. + Diese Option aktiviert Tooltips für Variablen beim Debuggen. Da es das Debuggen verlangsamt und wegen der fehlenden Scope-Information nicht zuverlässig ist, ist es per Vorgabe deaktiviert. Use tooltips in locals view when debugging - + Tooltips für Anzeige der lokalen Variablen Checking this will enable tooltips in the locals view during debugging. - + Schaltet Tooltips für die Anzeige der lokalen Variablen während des Debuggens ein. Use tooltips in breakpoints view when debugging - + Tooltips im Haltepunkt-Fenster Checking this will enable tooltips in the breakpoints view during debugging. - + Schaltet Tooltips im Haltepunkt-Fenster während des Debuggens ein. Show address data in breakpoints view when debugging - + Adresse des Haltepunkts anzeigen Checking this will show a column with address information in the breakpoint view during debugging. - + Fügt eine Spalte mit den Adressen der Haltepunkte zur Anzeige während des Debuggens hinzu. Show address data in stack view when debugging - + Addressen im Stack-Fenster anzeigen Checking this will show a column with address information in the stack view during debugging. - - - - Use tooltips when debugging - Tooltips beim Debuggen benutzen + Fügt eine Spalte mit Adressinformation zur Anzeige während des Debuggens hinzu. @@ -3785,7 +3665,7 @@ Sollen sie überschrieben werden? Debugger::Internal::GdbEngine - + The Gdb process failed to start. Either the invoked program '%1' is missing, or you may have insufficient permissions to invoke the program. Der Start des Gdb-Prozesses schlug fehl. Entweder fehlt die ausführbare Datei '%1' oder die Berechtigungen sind nicht ausreichend. @@ -3810,16 +3690,12 @@ Sollen sie überschrieben werden? Ein Fehler trat beim Versuch des Lesens vom Gdb-Prozess auf. Wahrscheinlich läuft der Prozess nicht. - An unknown error in the Gdb process occurred. This is the default return value of error(). - Es trat ein unbekannter Fehler im Gdb-Prozess auf. - - - + Error Fehler - + Library %1 loaded. Bibliothek %1 geladen. @@ -3834,7 +3710,7 @@ Sollen sie überschrieben werden? Thread-Gruppe %1 erzeugt. - + Thread %1 created. Thread-Gruppe %1 erzeugt. @@ -3854,36 +3730,17 @@ Sollen sie überschrieben werden? Thread %1 ausgewählt. - Debugger Error - Debugger-Fehler - - - + Stopping temporarily. Temporär Anhalten. - - Executable failed: - - Die ausführbare Datei schlug: - - Process failed to start. Der Prozess konnte nicht gestartet werden. - - Continuing after temporary stop. - Fortsetzen nach temporären Anhalten. - - - Core file loaded. - Core-Datei geladen. - - - + <p>The inferior stopped because it received a signal from the Operating System.<p><table><tr><td>Signal name : </td><td>%1</td></tr><tr><td>Signal meaning : </td><td>%2</td></tr></table> <p>Der Prozess wurde nach Erhalt eines Signals vom Betriebssystem angehalten.<p><table><tr><td>Name des Signals : </td><td>%1</td></tr><tr><td>Bedeutung : </td><td>%2</td></tr></table> @@ -3899,32 +3756,12 @@ Sollen sie überschrieben werden? Signal erhalten - + The dumper library was not found at %1. Es konnte keine Ausgabe-Hilfsbibliothek unter %1 gefunden werden. - The upload process failed to start. Either the invoked script '%1' is missing, or you may have insufficient permissions to invoke the program. - Das Hochladen konnte nicht gestartet weden. Entweder fehlt das Skript '%1', oder die Berechtigungen sind nicht ausreichend. - - - The upload process crashed some time after starting successfully. - Das Hochladen ist nach dem Starten abgestürzt. - - - An error occurred when attempting to write to the upload process. For example, the process may not be running, or it may have closed its input channel. - Ein Fehler trat beim Versuch des Schreibens zum Hochlade-Prozess auf. Wahrscheinlich läuft der Prozess nicht, oder hat seinen Eingabekanal geschlossen. - - - An error occurred when attempting to read from the upload process. For example, the process may not be running. - Ein Fehler trat beim Versuch des Lesens vom Hochlade-Prozess auf. Wahrscheinlich läuft der Prozess nicht. - - - An unknown error in the upload process occurred. This is the default return value of error(). - Es trat ein unbekannter Fehler im Hochlade-Prozess auf. - - - + Reading %1... Lese %1... @@ -3934,29 +3771,17 @@ Sollen sie überschrieben werden? Sprung ausgeführt/ Angehalten. - + Run to Function finished. Stopped. Ausgeführung bis zu Funktion beendet. Angehalten. - Program exited with exit code %1 - Das Programm wurde beendet, Rückgabewert %1 - - - Program exited after receiving signal %1 - Das Programm wurde nach Erhalt des Signals %1 beendet - - - Program exited normally - Das Programm wurde normal beendet - - - + Loading %1... Lade %1... - + Stopped at breakpoint. An Haltepunkt angehalten. @@ -3987,40 +3812,19 @@ Es wird empfohlen, gdb 6.7 oder später zu benutzen. - + Processing queued commands. Kommando-Warteschlange wird abgearbeitet. - - + Stopped. Angehalten. - Debugger Startup Failure - Fehler beim Starten des Debuggers - - - Cannot set up communication with child process: %1 - Die Kommunikation mit dem untergeordneten Prozesss konnte nicht hergestellt werden: %1 - - - Starting Debugger: - Starte Debugger: - - - Cannot start debugger: %1 - Der Debugger konnte nicht gestartet werden: %1 - - - Gdb Running... - Gdb läuft... - - - + Cannot find debugger initialization script Das Initalisierungsskript konnte nicht gefunden werden @@ -4030,19 +3834,7 @@ Es wird empfohlen, gdb 6.7 oder später zu benutzen. Auf die in den Debugger-Einstellungen angegebene Skriptdatei '%1' kann nicht zugegriffen werden. Wenn kein Skript benötigt wird, können Sie die Einstellung rücksetzen, um diese Warnung zu umgehen. - Attached to running process. Stopped. - An laufenden Prozess angehängt. Angehalten. - - - Connecting to remote server failed: - Die Verbindung zum Server konnte nicht hergestellt werden: - - - Debugger exited. - Debugger beendet. - - - + Unable to run '%1': %2 '%1' kann nicht ausgeführt werden: %2 @@ -4100,12 +3892,12 @@ Es wird empfohlen, gdb 6.7 oder später zu benutzen. - + An unknown error in the Gdb process occurred. - + Im Gdb-Prozess trat ein unbekannter Fehler auf. - + Running... Läuft... @@ -4118,77 +3910,82 @@ Es wird empfohlen, gdb 6.7 oder später zu benutzen. Executable failed - + Fehler bei Ausführung Executable failed: %1 - + Fehler bei Ausführung: %1 Function reached. Stopped. - + Die Funktion wurde erreicht. Angehalten. Program exited with exit code %1. - + Das Programm wurde beendet, Rückgabewert %1. Program exited after receiving signal %1. - + Das Programm wurde nach Erhalt des Signals %1 beendet. Program exited normally. - + Das Programm wurde normal beendet. - + Starting executable failed - + Das Starten der ausführbaren Datei schlug fehl - + + Continuing after temporary stop... + Setze nach temporärem Anhalten fort... + + + Running requested... Fortsetzung angefordert... - + Step requested... - + Einzelschritt angefordert... Step by instruction requested... - + Einzelschritt über Anweisung angefordert... Finish function requested... - + Ausführung bis Funktionsende angefordert... Step next requested... - + Einzelschritt angefordert... Step next instruction requested... - + Einzelschritt über Anweisung angefordert... Run to line %1 requested... - + Ausführung bis Zeile %1 angefordert... Run to function %1 requested... - + Ausführung bis Funktion %1 angefordert... @@ -4253,52 +4050,52 @@ Es wird empfohlen, gdb 6.7 oder später zu benutzen. Disassembler failed: %1 - + Fehler beim Disassemblieren: %1 Adapter start failed - + Der Start des Adapters schlug fehl - + Inferior start preparation failed - + Die Vorbereitung des zu debuggenden Prozesses schlug fehl Inferior prepared for startup. - + Zu debuggender Prozess vorbereitet. Setting breakpoints... - + Setze Haltepunkte... Starting inferior... - + Starte zu debuggenden Prozess... Inferior start failed - + Der Start des zu debuggenden Prozesses schlug fehl Inferior shutdown failed - + Das Beenden des zu debuggenden Prozesses schlug fehl Adapter crashed - + Der Adapter ist abgestürzt Adapter shutdown failed - + Das Beenden des Adapter schlug fehl @@ -4465,27 +4262,6 @@ Es wird empfohlen, gdb 6.7 oder später zu benutzen. Das Starten der ausführbaren Datei schlug fehl: - - - Inferior started. - - - - - Inferior process could not be stopped: - - - - - - Gdb process could not be stopped: - - - - - Debugger Error - Debugger-Fehler - Debugger::Internal::RegisterHandler @@ -4522,10 +4298,6 @@ Es wird empfohlen, gdb 6.7 oder später zu benutzen. Reload register listing Register neu laden - - Always reload register listing - Register immer laden - Open memory editor @@ -4559,10 +4331,6 @@ Es wird empfohlen, gdb 6.7 oder später zu benutzen. Debugger::Internal::RemoteGdbAdapter - - Cannot set up communication with child process: %1 - Die Kommunikation mit dem untergeordneten Prozesss konnte nicht hergestellt werden: %1 - The upload process failed to start. Either the invoked script '%1' is missing, or you may have insufficient permissions to invoke the program. @@ -4601,36 +4369,14 @@ Es wird empfohlen, gdb 6.7 oder später zu benutzen. Adapter too old: does not support asynchronous mode. - + Der Adapter ist veraltet; er unterstützt den asynchronen Modus nicht. Starting remote executable failed: - - - - - Connecting to remote server failed: - - - - - - Attached to stopped inferior. - - - - - Inferior process could not be stopped: - - - - - - Gdb process could not be stopped: - - + Das Starten der ausführbaren Datei auf dem entfernten Rechner schlug fehl: + @@ -4662,17 +4408,6 @@ Es wird empfohlen, gdb 6.7 oder später zu benutzen. Angehalten. - - Debugger::Internal::SourceFilesModel - - Internal name - Interner Name - - - Full name - Vollständiger Name - - Debugger::Internal::SourceFilesWindow @@ -4839,17 +4574,6 @@ Es wird empfohlen, gdb 6.7 oder später zu benutzen. Ausführbare Datei auswählen - - Debugger::Internal::TcfEngine - - Running requested... - Fortsetzung angefordert... - - - Stopped. - Angehalten. - - Debugger::Internal::ThreadsHandler @@ -4880,12 +4604,12 @@ Es wird empfohlen, gdb 6.7 oder später zu benutzen. Thread: %1 at %2 (0x%3) - + Thread: %1bei %2 (0x%3) Thread: %1 at %2, %3:%4 (0x%5) - + Thread: %1 bei %2, %3:%4 (0x%5) @@ -4917,37 +4641,8 @@ Es wird empfohlen, gdb 6.7 oder später zu benutzen. Connecting to trk server adapter failed: - - - - - Inferior running. - - - - - Connecting to remote server failed: - Die Verbindung zum Server konnte nicht hergestellt werden: - - - - Inferior process could not be stopped: - - - - - - Gdb process could not be stopped: - - - - - - Debugger::Internal::TrkOptionsPage - - - S60 / Trk - + Die Verbindung zum Trk-Server-Adapter schlug fehl: + @@ -4965,37 +4660,32 @@ Es wird empfohlen, gdb 6.7 oder später zu benutzen. Symbian ARM gdb location: - - - - - Cygwin location: - + Pfad zu Symbian-ARM gdb: Communication - + Kommunkation Serial Port - + Serielle Schnittstelle Bluetooth - + Bluetooth Port: - + Port: Device: - + Gerät: @@ -5071,7 +4761,7 @@ Es wird empfohlen, gdb 6.7 oder später zu benutzen. Generation - + Generation @@ -5170,14 +4860,6 @@ Es wird empfohlen, gdb 6.7 oder später zu benutzen. Speicher-Editor bei %1 öffnen - - Debugger::MessageBox - - - Settings... - Einstellungen... - - DebuggerPane @@ -5494,7 +5176,7 @@ Es wird empfohlen, gdb 6.7 oder später zu benutzen. Signals && Slots Editor - + Signale und Slots @@ -5545,13 +5227,6 @@ Es wird empfohlen, gdb 6.7 oder später zu benutzen. %1 - Fehler - - Designer::Internal::FormWindowEditor - - untitled - kein Titel - - Designer::Internal::FormWindowFile @@ -5621,40 +5296,6 @@ Versuchen Sie, das Projekt neu zu erstellen. Entfernen - - DuiEditor::Internal::DuiEditorPlugin - - Creates a Qt QML file. - Erzeugt eine Qt-QML-Datei. - - - Qt QML File - Qt QML-Datei - - - Qt - Qt - - - - DuiEditor::Internal::ScriptEditor - - <Select Symbol> - <Symbol auswählen> - - - Rename... - Umbenennen... - - - New id: - Neue Id: - - - Rename id '%1'... - Id '%1' Umbenennen - - EmbeddedPropertiesPage @@ -5915,14 +5556,6 @@ Grund: %3 FakeVim::Internal::FakeVimHandler - - %1,%2 - %1,%2 - - - %1 - %1 - Not implemented in FakeVim @@ -6017,84 +5650,6 @@ Grund: %3 Letzte Änderung erreicht - - FakeVim::Internal::FakeVimHandler::Private - - %1,%2 - %1,%2 - - - %1 - %1 - - - Not implemented in FakeVim - In FakeVim nicht implementiert - - - E20: Mark '%1' not set - E20: Die Marke '%1' ist nicht gesetzt - - - File '%1' exists (add ! to override) - Die '%1' existiert bereits (Fügen Sie ! an, um sie zu überschreiben) - - - Cannot open file '%1' for writing - Die Datei '%1' kann nicht zum Schreiben geöffnet werden - - - "%1" %2 %3L, %4C written - "%1" %2 %3L, %4C geschrieben - - - Cannot open file '%1' for reading - Die Datei '%1' kann nicht zum Lesen geöffnet werden - - - "%1" %2L, %3C - "%1" %2L, %3C - - - %n lines filtered - - Eine Zeile gefiltert - %n Zeilen gefiltert - - - - - %n lines >ed %1 time - - Eine Zeile >ed %1-mal - %n Zeilen >ed %1-mal - - - - E512: Unknown option: - E512: Unbekannte Option: - - - search hit BOTTOM, continuing at TOP - Die Suche hat das Ende erreicht, setze am Anfang fort - - - search hit TOP, continuing at BOTTOM - Die Suche hat den Anfang erreicht, setze am Ende fort - - - Pattern not found: - Suchmuster nicht gefunden: - - - Already at oldest change - Älteste Änderung erreicht - - - Already at newest change - Letzte Änderung erreicht - - FakeVim::Internal::FakeVimOptionPage @@ -6440,13 +5995,13 @@ Grund: %3 - Replace all occurances - + Replace all occurrences + Alle Vorkommen ersetzen Replace - + Ersetzen @@ -7046,12 +6601,12 @@ Grund: %3 Diff für "%1" - + Alt+G,Alt+D Alt+G,Alt+D - + File Status Status der Datei @@ -7061,12 +6616,12 @@ Grund: %3 Status relativ zu "%1" - + Alt+G,Alt+S Alt+G,Alt+S - + Log File Log für Datei @@ -7076,12 +6631,12 @@ Grund: %3 Log für "%1" - + Alt+G,Alt+L Alt+G,Alt+L - + Blame Blame für Datei @@ -7091,12 +6646,12 @@ Grund: %3 Blame für "%1" - + Alt+G,Alt+B Alt+G,Alt+B - + Undo Changes Änderungen rückgängig machen @@ -7106,12 +6661,12 @@ Grund: %3 Änderungen in "%1" rückgängig machen - + Alt+G,Alt+U Alt+G,Alt+U - + Stage File for Commit Datei zu Commit hinzufügen (stage) @@ -7121,12 +6676,12 @@ Grund: %3 "%1" zu Commit hinzufügen (stage) - + Alt+G,Alt+A Alt+G,Alt+A - + Unstage File from Commit Datei aus Commit entfernen (unstage) @@ -7135,14 +6690,6 @@ Grund: %3 Unstage "%1" from Commit "%1" aus Commit entfernen (unstage) - - Revert... - Änderungen in Datei rückgängig machen... - - - Revert "%1"... - Änderungen in "%1" rückgängig machen... - Diff Current Project @@ -7154,7 +6701,7 @@ Grund: %3 Diff für Projekt "%1" - + Project Status Status des Projekts (status) @@ -7174,12 +6721,12 @@ Grund: %3 Log für Projekt "%1" - + Alt+G,Alt+K Alt+G,Alt+K - + Undo Project Changes Änderungen des Projekts rückgängig machen @@ -7214,12 +6761,12 @@ Grund: %3 Commit... - + Alt+G,Alt+C Alt+G,Alt+C - + Push Push @@ -7271,7 +6818,7 @@ Grund: %3 Would you like to revert all pending changes to the project? - + Möchten Sie alle ausstehenden Änderungen des Projektes rückgängig machen? @@ -7330,7 +6877,7 @@ Grund: %3 repository - + repository @@ -8067,7 +7614,7 @@ Grund: %3 Ctrl+O - Ctrl+O + @@ -8087,7 +7634,7 @@ Grund: %3 F5 - F5 + F5 @@ -8142,7 +7689,7 @@ Grund: %3 Debug - Debuggen + Debuggen @@ -8157,7 +7704,7 @@ Grund: %3 Open File - Datei öffnen + Datei öffnen @@ -8743,12 +8290,12 @@ p, li { white-space: pre-wrap; } "%1" anfordern - + Alt+P,Alt+E Alt+P,Alt+E - + Edit File Datei zum Editieren anfordern @@ -8763,12 +8310,12 @@ p, li { white-space: pre-wrap; } "%1" hinzufügen - + Alt+P,Alt+A Alt+P,Alt+A - + Add File Datei hinzufügen @@ -8798,12 +8345,12 @@ p, li { white-space: pre-wrap; } Änderungen in "%1" rückgängig machen (revert) - + Alt+P,Alt+R Alt+P,Alt+R - + Revert File Änderungen in Datei rückgängig machen (revert) @@ -8829,12 +8376,12 @@ p, li { white-space: pre-wrap; } Diff für Projekt "%1" - + Alt+P,Alt+D Alt+P,Alt+D - + Diff Opened Files Diff für angeforderte Dateien @@ -8844,12 +8391,12 @@ p, li { white-space: pre-wrap; } Angefordert - + Alt+P,Alt+O Alt+P,Alt+O - + Submit Project Projekt abgeben @@ -8896,22 +8443,22 @@ p, li { white-space: pre-wrap; } - + Filelog Current File Filelog für Datei - + Filelog "%1" Filelog für "%1" - + Alt+P,Alt+F Alt+P,Alt+F - + Filelog... Filelog... @@ -9287,17 +8834,7 @@ p, li { white-space: pre-wrap; } Plugin is not valid (does not derive from IPlugin) - - - - -Library base name: %1 - -Basisname der Bibliothek: %1 - - - Plugin is not valid (doesn't derive from IPlugin) - Das Plugin ist ungültig (nicht von Klasse IPlugin abgeleitet) + Das Plugin ist ungültig (nicht von Klasse IPlugin abgeleitet) @@ -9529,10 +9066,6 @@ Fehler: %2 ProjectExplorer::EnvironmentWidget - - Details - Details - &Edit @@ -9574,7 +9107,7 @@ Fehler: %2 Active run configuration - + Aktive Ausführungskonfiguration @@ -9598,24 +9131,6 @@ Fehler: %2 Such&muster für Dateinamen - - ProjectExplorer::Internal::ApplicationRunConfigurationRunner - - Run - Ausführung - - - - ProjectExplorer::Internal::ApplicationRunControl - - Starting %1... - Starte %1... - - - %1 exited with code %2 - %1 beendet, Rückgabewert %2 - - ProjectExplorer::Internal::BuildSettingsPanel @@ -9627,11 +9142,7 @@ Fehler: %2 ProjectExplorer::Internal::BuildSettingsWidget - Create &New - &Neu erzeugen - - - + &Clone Selected Auswahl duplizieren @@ -9640,14 +9151,10 @@ Fehler: %2 Build Steps Erstellungsschritte - - Build Configuration: - Build-Konfiguration: - Edit Build Configuration: - + Build-Konfiguration bearbeiten: @@ -9664,10 +9171,6 @@ Fehler: %2 Clean Steps Schritte zur Bereinigung - - New configuration - Neue Konfiguration - New Configuration Name: @@ -9681,26 +9184,6 @@ Fehler: %2 ProjectExplorer::Internal::BuildStepsPage - - 1 - 1 - - - + - + - - - - - - - - - ^ - ^ - - - v - v - No Build Steps @@ -9714,7 +9197,7 @@ Fehler: %2 Add clean step - + Schritt zur Bereinigung hinzufügen @@ -9724,7 +9207,7 @@ Fehler: %2 Remove clean step - + Schritt zur Bereinigung entfernen @@ -9736,14 +9219,6 @@ Fehler: %2 Clean Steps Schritte zur Bereinigung - - Details - Details - - - No step selected - Kein Schritt ausgewählt - ProjectExplorer::Internal::CompileOutputWindow @@ -9761,10 +9236,6 @@ Fehler: %2 Cancel Build && Close Erstellen abbrechen und schließen - - Don't Close - Nicht schließen - A project is currently being built. @@ -9778,7 +9249,7 @@ Fehler: %2 Do not Close - + Nicht Schließen @@ -9862,7 +9333,8 @@ Fehler: %2 No Executable specified. - + Es wurde keine ausführbaren Datei angegeben. + @@ -9880,10 +9352,6 @@ Fehler: %2 ProjectExplorer::Internal::DependenciesWidget - - Details - Details - %1 has no dependencies. @@ -9966,7 +9434,7 @@ Fehler: %2 Run - + Ausführen @@ -10043,11 +9511,7 @@ Fehler: %2 <b>%1</b> %2 %3 %4 - - - - <b>Process Step</b> %1 %2 %3 - <b>Verarbeitungsschritt</b> %1 %2 %3 + <b>%1</b> %2 %3 %4 @@ -10095,10 +9559,6 @@ Fehler: %2 Projects Projekte - - Projectexplorer - Projekt-Explorer - ProjectExplorer::Internal::ProjectExplorerSettingsPageUi @@ -10160,12 +9620,12 @@ Fehler: %2 Edit Project Settings for Project <b>%1</b> - + Einstellungen für Projekt <b>%1</b> bearbeiten No Project loaded - + Es ist kein Projekt geladen @@ -10173,7 +9633,7 @@ Fehler: %2 Select Project - + Projekt auswählen @@ -10258,29 +9718,13 @@ Fehler: %2 No project loaded. - - - - Project Explorer - Projekt-Explorer - - - Projects - Projekte - - - Startup - Start - - - Path - Pfad + Es ist kein Projekt geladen. Active Build and Run Configurations - + Aktive Build- und Ausführungskonfigurationen @@ -10339,10 +9783,6 @@ Fehler: %2 - - - - Active run configuration: - Aktive Ausführungskonfiguration: - Edit run configuration: @@ -10545,7 +9985,7 @@ Fehler: %2 Show in Explorer... - + In Explorer anzeigen... @@ -10555,7 +9995,7 @@ Fehler: %2 Show containing folder... - + Ordner anzeigen... @@ -10772,22 +10212,22 @@ unter Versionsverwaltung (%2) gestellt werden? Launching Windows Explorer failed - + Das Starten des Windows-Explorers schlug fehl Could not find explorer.exe in path to launch Windows Explorer. - + Windows Explorer konnte nicht gestartet werden, da die Datei explorer.exe nicht im Pfad gefunden werden konnte. Launching a file explorer failed - + Das Starten des Datei-Browsers schlug fehl Could not find xdg-open to launch the native file explorer. - + Der Dateibrowser konnte nicht gestartet werden, da die Datei xdg-open nicht im Pfad gefunden werden konnte. @@ -10910,7 +10350,7 @@ unter Versionsverwaltung (%2) gestellt werden? Warning - Warnung + Warnung @@ -10979,7 +10419,7 @@ unter Versionsverwaltung (%2) gestellt werden? Qt - Qt + Qt @@ -11121,21 +10561,17 @@ unter Versionsverwaltung (%2) gestellt werden? QML Viewer QML-Betrachter - - Could not find the qmlviewer executable, please specify one. - Die ausführbare Datei des QML-Betrachters konnte nicht gefunden werden; bitte geben Sie sie an. - - + <Current File> <Aktuelle Datei> - + QML Viewer arguments: - + Kommandozeilenargumente für QML-Betrachter: @@ -11596,7 +11032,7 @@ unter Versionsverwaltung (%2) gestellt werden? Ctrl Shortcut key - + Ctrl @@ -11648,11 +11084,7 @@ unter Versionsverwaltung (%2) gestellt werden? You can quickly search methods, classes, help and more using the <a href="qthelp://com.nokia.qtcreator/doc/creator-navigation.html">Locator bar</a> (<tt>%1+K</tt>). - - - - You can quickly search methods, classes, help and more using the <a href="qthelp://com.nokia.qtcreator/doc/creator-navigation.html">Locator bar</a> (<tt>Ctrl+K</tt>). - Mit der <a href="qthelp://com.nokia.qtcreator/doc/creator-navigation.html">Locator bar</a> (<tt>Ctrl+K</tt>) können Sie schnell nach Klassen, Methoden, Hilfe und anderem suchen. + Mit der <a href="qthelp://com.nokia.qtcreator/doc/creator-navigation.html">Locator bar</a> (<tt>%1+K</tt>) können Sie schnell nach Methoden, Klassen, Hilfe und anderem suchen. @@ -11910,7 +11342,7 @@ unter Versionsverwaltung (%2) gestellt werden? Qt4ProjectManager::Internal::ProjectLoadWizard - + Import existing settings Existierende Einstellungen importieren @@ -11927,11 +11359,7 @@ unter Versionsverwaltung (%2) gestellt werden? <b>Note:</b> Importing the settings will automatically add the Qt Version identified by <br><b>%1</b> to the list of Qt versions. - - - - <b>Note:</b> Importing the settings will automatically add the Qt Version from:<br><b>%1</b> to the list of Qt versions. - <b>Hinweis:</b> Das Importieren der Einstellungen wird die Qt-Version aus:<br><b>%1</b> zur Liste der Qt-Versionen hinzufügen. + <b>Hinweis:</b> Das Importieren der Einstellungen wird die Qt-Version aus:<br><b>%1</b> zur Liste der Qt-Versionen hinzufügen. @@ -11960,27 +11388,27 @@ unter Versionsverwaltung (%2) gestellt werden? Headers - + Header-Dateien Sources - + Quelldateien Forms - + Formular-Dateien Resources - + Ressourcendateien Other files - + Andere Dateien @@ -12068,12 +11496,12 @@ unter Versionsverwaltung (%2) gestellt werden? Default Qt Version (%1) - + Vorgabe-Qt-Version (%1) No Qt Version set - + Es ist keine Qt-Version gesetzt @@ -12085,10 +11513,6 @@ unter Versionsverwaltung (%2) gestellt werden? General Allgemein - - Default Qt Version - Vorgabe-Qt-Version - Manage @@ -12099,18 +11523,6 @@ unter Versionsverwaltung (%2) gestellt werden? Tool Chain: Toolchain: - - Multi -Line -placeholder - Multi -Line -placeholder - - - Details - Details - Qt4ProjectManager::Internal::Qt4ProjectManagerPlugin @@ -12138,14 +11550,14 @@ placeholder Qt4ProjectManager::Internal::Qt4RunConfigurationWidget - - Running executable: <b>%1</b> %2 %3 - + + Running executable: <b>%1</b> %2 (in terminal) + Führe in Terminal aus: <b>%1</b> %2 - - (in terminal) - + + Running executable: <b>%1</b> %2 + Führe aus: <b>%1</b> %2 @@ -12220,32 +11632,20 @@ placeholder <specify a name> <Geben Sie einen Namen an> - - <specify a path> - <Geben Sie einenPfad an> - - - Select QTDIR - QTDIR Auswählen - - - Select the Qt Directory - Wählen Sie das Qt-Verzeichnis aus - <specify a qmake location> - + <Geben Sie den Pfad zu qmake an> Select QMake Executable - + Wählen Sie die ausführbare qmake-Datei aus Select the MinGW Directory - + Wählen Sie das MinGW-Verzeichnis aus @@ -12276,20 +11676,12 @@ placeholder The Qt Version identified by %1 is not installed. Run make install - + Die Qt-Version %1 ist nicht installiert. Führen Sie make install aus %1 does not specify a valid Qt installation - - - - The Qt Version %1 is not installed. Run make install - Die Qt-Version %1 ist nicht installiert. Führen Sie make install aus - - - %1 is not a valid Qt directory - %1 ist kein gültiges Qt-Verzeichnis + %1 ist keine gültige Qt-Installation @@ -12299,10 +11691,6 @@ placeholder Qt4ProjectManager::Internal::QtVersionManager - - Path: - Pfad: - Qt versions @@ -12323,10 +11711,6 @@ placeholder Name Name - - Path - Pfad - Debugging Helper @@ -12388,12 +11772,12 @@ p, li { white-space: pre-wrap; } QMake Location - + QMake-Pfad QMake Location: - + QMake-Pfad: @@ -12407,31 +11791,25 @@ p, li { white-space: pre-wrap; } Qt4ProjectManager::Internal::S60DeviceDebugRunControl - + Warning: Cannot locate the symbol file belonging to %1. - + Warnung: Die zu %1 gehörige Symboldatei konnte nicht gefunden werden. Launching debugger... - + Starte Debugger... Debugging finished. - + Debuggen beendet. Qt4ProjectManager::Internal::S60DeviceRunConfiguration - - %1 on Device - %1 auf Gerät - - - - + QtS60DeviceRunConfiguration QtS60DeviceRunConfiguration @@ -12441,27 +11819,17 @@ p, li { white-space: pre-wrap; } %1 konnte nicht ausgewertet werden. Die Qt S60-Ausführungskonfiguration %2 kann nicht gestartet werden. - Cannot open %1: %2 - Die Datei %1 kann nicht geöffnet werden: %2 - - - Unable to find the executable in the package file %1. - Es wurde keine ausführbare Datei in dem Installationspaket %1 gefunden. + + %1 on Symbian Device + %1 auf Symbian-Gerät Qt4ProjectManager::Internal::S60DeviceRunConfigurationFactory - - %1 on Device - %1 auf Gerät - - - - Qt4ProjectManager::Internal::S60DeviceRunConfigurationRunner - - Run on Device - Auf Gerät ausführen + + %1 on Symbian Device + %1 auf Symbian-Gerät @@ -12510,41 +11878,9 @@ p, li { white-space: pre-wrap; } Qt4ProjectManager::Internal::S60DeviceRunControl - + Could not start application: %1 - - - - Creating %1.sisx ... - Erstelle %1.sisx ... - - - Executable file: %1 - Ausführbare Datei: %1 - - - %1 %2 - %1 %2 - - - An error occurred while creating the package. - Bei der Erstellung des Installationspakets trat ein Fehler auf. - - - Package: %1 -Deploying application to '%2'... - Installationspaket: %1 -Installiere Anwendung auf '%2'... - - - Could not connect to phone on port '%1': %2 -Check if the phone is connected and the TRK application is running. - Die Verbindung zum Gerät über den Port '%1' konnte nicht hergestellt werden: %2 -Bitte prüfen Sie, ob das Gerät verbunden ist und die Anwendung 'TRK' läuft. - - - Copying install file... - Kopiere Installationspaket... + Die Anwendung konnte nicht gestartet werden: %1 @@ -12556,37 +11892,21 @@ Bitte prüfen Sie, ob das Gerät verbunden ist und die Anwendung 'TRK' Application running with pid %1. Die Anwendung läuft mit der Prozess-Id: %1. - - An error has occurred while running %1. - Bei der Ausführung von %1 trat ein Fehler auf. - - - Installing application... - Installiere Anwendung... - Finished. Beendet. - - Failed to start %1. - %1 konnte nicht gestartet werden. - - - %1 has unexpectedly finished. - %1 ist abgestürzt. - Qt4ProjectManager::Internal::S60DeviceRunControlBase - + Could not install from package %1 on device: %2 - + Das Installation des Pakets %1 auf dem Gerät schlug fehl: %2 - + Creating %1.sisx ... Erstelle %1.sisx ... @@ -12596,23 +11916,28 @@ Bitte prüfen Sie, ob das Gerät verbunden ist und die Anwendung 'TRK' Ausführbare Datei: %1 - - + + Debugger for Symbian Platform + Debugger für Symbian-Platform + + + + %1 %2 %1 %2 - + Could not read template package file '%1' - + Die Vorlagedatei für die Paketbeschreibung ('%1') konnte nicht gelesen werden - + Could not write package file '%1' - + Die Paketbeschreibungsdatei '%1' konnte nicht geschrieben werden - + An error occurred while creating the package. Bei der Erstellung des Installationspakets trat ein Fehler auf. @@ -12634,17 +11959,17 @@ Bitte prüfen Sie, ob das Gerät verbunden ist und die Anwendung 'TRK' Could not create file %1 on device: %2 - + Die Datei %1 konnte nicht auf dem Gerät erzeugt werden: %2 Could not write to file %1 on device: %2 - + Die Datei %1 konnte nicht auf dem Gerät geschrieben werden: %2 Could not close file %1 on device: %2. It will be closed when App TRK is closed. - + Die Datei %1 konnte nicht auf dem Gerät geschlossen werden: %2. Sie wird beim Beenden der Trk-Anwendung geschlossen. @@ -12654,7 +11979,7 @@ Bitte prüfen Sie, ob das Gerät verbunden ist und die Anwendung 'TRK' %1% copied. - + %1% kopiert. @@ -12722,17 +12047,17 @@ Bitte prüfen Sie, ob das Gerät verbunden ist und die Anwendung 'TRK' Qt4ProjectManager::Internal::S60EmulatorRunConfiguration - %1 in Emulator - %1 im Emulator + %1 in Symbian Emulator + %1 im Symbian-Emulator - QtS60EmulatorRunConfiguration - QtS60EmulatorRunConfiguration + QtSymbianEmulatorRunConfiguration + QtSymbianEmulatorRunConfiguration - Could not parse %1. The QtS60 emulator run configuration %2 can not be started. + Could not parse %1. The Qt for Symbian emulator run configuration %2 can not be started. %1 konnte nicht ausgewertet werden. Die Qt S60-Emulator-Ausführungskonfiguration %2 kann nicht gestartet werden. @@ -12740,15 +12065,8 @@ Bitte prüfen Sie, ob das Gerät verbunden ist und die Anwendung 'TRK' Qt4ProjectManager::Internal::S60EmulatorRunConfigurationFactory - %1 in Emulator - %1 im Emulator - - - - Qt4ProjectManager::Internal::S60EmulatorRunConfigurationRunner - - Run in Emulator - Im Emulator ausführen + %1 in Symbian Emulator + %1 im Symbian-Emulator @@ -12797,7 +12115,7 @@ Bitte prüfen Sie, ob das Gerät verbunden ist und die Anwendung 'TRK' Debug on Device - + Auf Gerät Debuggen @@ -12978,12 +12296,12 @@ Bitte prüfen Sie, ob das Gerät verbunden ist und die Anwendung 'TRK' Using Default Qt Version - + Es wird die Vorgabe-Qt-Version benutzt Using Qt Version "%1" - + Es wird die Qt-Version "%1" benutzt @@ -12995,6 +12313,16 @@ Bitte prüfen Sie, ob das Gerät verbunden ist und die Anwendung 'TRK' New Configuration Name: Name der neuen Konfiguration: + + + %1 Debug + %1 Debug + + + + %1 Release + %1 Release + Qt4ProjectManager::Qt4Manager @@ -13130,12 +12458,12 @@ Bitte prüfen Sie, ob das Gerät verbunden ist und die Anwendung 'TRK' QtScriptTools Module - + QtScriptTools-Modul Additional Qt Script components - + Zusätzliche Qt-Skript-Komponenten @@ -13190,12 +12518,12 @@ Bitte prüfen Sie, ob das Gerät verbunden ist und die Anwendung 'TRK' QtMultimedia Module - + QtMultimedia-Modul Classes for low-level multimedia functionality - + Klassen für Multimedia-Funktionalität @@ -13947,7 +13275,7 @@ Um es abzurufen, tippen Sie das Kürzel im Locator, gefolgt von einem Leerzeich Internal name - Interner Name + Interner Name @@ -14091,12 +13419,12 @@ Um es abzurufen, tippen Sie das Kürzel im Locator, gefolgt von einem Leerzeich "%1" hinzufügen - + Alt+S,Alt+A Alt+S,Alt+A - + Delete Löschen @@ -14131,12 +13459,12 @@ Um es abzurufen, tippen Sie das Kürzel im Locator, gefolgt von einem Leerzeich Diff für "%1" - + Alt+S,Alt+D Alt+S,Alt+D - + Commit All Files Alle Dateien abgeben @@ -14151,12 +13479,12 @@ Um es abzurufen, tippen Sie das Kürzel im Locator, gefolgt von einem Leerzeich "%1" abgeben - + Alt+S,Alt+C Alt+S,Alt+C - + Filelog Current File Filelog für Datei @@ -14364,7 +13692,7 @@ Um es abzurufen, tippen Sie das Kürzel im Locator, gefolgt von einem Leerzeich TextEditor::BaseTextEditorEditable - + Line: %1, Col: %2 Zeile: %1, Spalte: %2 @@ -14548,7 +13876,7 @@ Um es abzurufen, tippen Sie das Kürzel im Locator, gefolgt von einem Leerzeich TextEditor::FontSettingsPage - + Font & Colors Zeichensatz und Farben @@ -14835,17 +14163,27 @@ Die folgenden Encodings scheinen der Datei zu entsprechen: Ctrl+I - + + Meta + Meta + + + + Ctrl + Ctrl + + + + %1+E, R + %1+E, R + + + &Visualize Whitespace &Leerzeichen anzeigen - - Ctrl+E, Ctrl+V - Ctrl+E, Ctrl+V - - - + Clean Whitespace Leerzeichen bereinigen @@ -14855,12 +14193,7 @@ Die folgenden Encodings scheinen der Datei zu entsprechen: Text&umbruch aktivieren - - Ctrl+E, Ctrl+W - Ctrl+E, Ctrl+W - - - + (Un)Comment &Selection Auswahl aus&kommentieren @@ -14880,17 +14213,22 @@ Die folgenden Encodings scheinen der Datei zu entsprechen: Shift+Del - + &Rewrap Paragraph Abschnitt neu um&brechen - - Ctrl+E, R - Ctrl+E, R + + %1+E, %2+V + %1+E, %2+V - + + %1+E, %2+W + %1+E, %2+W + + + Cut &Line &Zeile ausschneiden @@ -14994,10 +14332,6 @@ Die folgenden Encodings scheinen der Datei zu entsprechen: Select Block Down Einen Block nach unten auswählen - - Ctrl+Shift+U - Ctrl+Shift+U - Move Line Up @@ -15099,7 +14433,7 @@ Die folgenden Encodings scheinen der Datei zu entsprechen: Unused Occurrence - + Nicht verwendet @@ -15159,7 +14493,7 @@ Die folgenden Encodings scheinen der Datei zu entsprechen: Visual Whitespace - + Leerzeichen darstellen @@ -15300,17 +14634,17 @@ Die folgenden Encodings scheinen der Datei zu entsprechen: Dialog - + Dialog TextLabel - + TextLabel CheckBox - + CheckBox @@ -15399,7 +14733,7 @@ Die folgenden Encodings scheinen der Datei zu entsprechen: Show Details - + Details anzeigen @@ -16067,7 +15401,7 @@ Qt Centre - Qt for S60 at Forum Nokia + Qt for Symbian at Forum Nokia Qt für S60 im Forum Nokia @@ -16133,4 +15467,64 @@ Qt Centre + + TrkOptions + + + No Symbian gdb executable specified. + Es wurde keine ausführbaren Datei des Symbian-Gdb angegeben. + + + + The Symbian gdb executable '%1' could not be found in the search path. + Die ausführbare Datei des Symbian-Gdb ('%1') konnte nicht im Suchpfad gefunden werden. + + + + Debugger::Internal::TrkOptionsPage + + + Symbian Trk + Symbian-Trk + + + + Debugger::Internal::AbstractGdbAdapter + + + The Gdb process could not be stopped: +%1 + Der Gdb-Prozess konnte nicht angehalten werden: +%1 + + + + Inferior process could not be stopped: +%1 + Zu debuggender Prozess konnte nicht angehalten werden: +%1 + + + + Inferior started. + Zu debuggender Prozess gestartet. + + + + Inferior running. + Zu debuggender Prozess läuft. + + + + Attached to stopped inferior. + + + + + Connecting to remote server failed: +%1 + Die Verbindung zum Server konnte nicht hergestellt werden: +%1 + + From b0e58aa834e2b02190a9e517a077256afb859f14 Mon Sep 17 00:00:00 2001 From: dt Date: Mon, 12 Oct 2009 13:49:16 +0200 Subject: [PATCH 08/34] Update changelog --- dist/changes-1.3.0 | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/dist/changes-1.3.0 b/dist/changes-1.3.0 index 6013a3074f3..ecec4ad3784 100644 --- a/dist/changes-1.3.0 +++ b/dist/changes-1.3.0 @@ -22,6 +22,7 @@ General * Reworked the projects pane * Made the welcome screen tabs into plugins, reimplement IWelcomePage to add your own welcome screen page + * Overhauled the project pane. Editing * Added support for text editor color schemes @@ -46,9 +47,9 @@ Project support * Added support for adding and removing files from a generic Makefile-based project * Added better control over the environment used for running. - * Add all cmake files to the project tree (only works with a cvs cmake) - * Support cmake with Microsoft Visual Studio Compiler (only works with cvs - cmake) + * Add all cmake files to the project tree (only works with a cmake 2.8) + * Support cmake with Microsoft Visual Studio Compiler (only works with + cmake 2.8 ) * Fix a few cmake wizard bugs, where canceling left creator in a strange state * The qmake and make steps can now be removed. @@ -58,6 +59,9 @@ Project support * Show subdirectory structure below .pro/.pri files in project tree * Add "Show file in Finder/Explorer" (Mac/Windows) to context menu. On Linux it opens the containing directory. + * The qmake step and make step can be removed from qt projects now. + * Made importing build settings for qt projects more robust + * Only run qmake, if it needs to be run. Compilation * Support multi-core compilation on Windows/MSVC via jom From f7263f2333e331b32b03a4b81b0a7fd0f2f779f6 Mon Sep 17 00:00:00 2001 From: Roberto Raggi Date: Mon, 12 Oct 2009 14:07:01 +0200 Subject: [PATCH 09/34] Fixed lookup of qualified name ids. --- src/libs/cplusplus/LookupContext.cpp | 78 ++++++++++++++-------------- 1 file changed, 40 insertions(+), 38 deletions(-) diff --git a/src/libs/cplusplus/LookupContext.cpp b/src/libs/cplusplus/LookupContext.cpp index 410e1fac786..e04ee2a1b80 100644 --- a/src/libs/cplusplus/LookupContext.cpp +++ b/src/libs/cplusplus/LookupContext.cpp @@ -132,63 +132,65 @@ QList LookupContext::resolveQualifiedNameId(QualifiedNameId *q, { QList candidates; - for (int i = 0; i < visibleScopes.size(); ++i) { - Scope *scope = visibleScopes.at(i); + if (true || mode & ResolveClass) { + for (int i = 0; i < visibleScopes.size(); ++i) { + Scope *scope = visibleScopes.at(i); - for (Symbol *symbol = scope->lookat(q); symbol; symbol = symbol->next()) { - if (! symbol->name()) - continue; + for (Symbol *symbol = scope->lookat(q); symbol; symbol = symbol->next()) { + if (! symbol->name()) + continue; + else if (! symbol->isClass()) + continue; - QualifiedNameId *qq = symbol->name()->asQualifiedNameId(); + QualifiedNameId *qq = symbol->name()->asQualifiedNameId(); - if (! qq) - continue; - else if (! maybeValidSymbol(symbol, mode, candidates)) - continue; + if (! qq) + continue; + else if (! maybeValidSymbol(symbol, mode, candidates)) + continue; - if (! q->unqualifiedNameId()->isEqualTo(qq->unqualifiedNameId())) - continue; + if (! q->unqualifiedNameId()->isEqualTo(qq->unqualifiedNameId())) + continue; - else if (qq->nameCount() == q->nameCount()) { - unsigned j = 0; + else if (qq->nameCount() == q->nameCount()) { + unsigned j = 0; - for (; j < q->nameCount(); ++j) { - Name *classOrNamespaceName1 = q->nameAt(j); - Name *classOrNamespaceName2 = qq->nameAt(j); + for (; j < q->nameCount(); ++j) { + Name *classOrNamespaceName1 = q->nameAt(j); + Name *classOrNamespaceName2 = qq->nameAt(j); - if (! classOrNamespaceName1->isEqualTo(classOrNamespaceName2)) - break; + if (! classOrNamespaceName1->isEqualTo(classOrNamespaceName2)) + break; + } + + if (j == q->nameCount()) + candidates.append(symbol); } - - if (j == q->nameCount()) - candidates.append(symbol); } } } - if (candidates.isEmpty()) { - QList scopes; + QList scopes; - if (q->nameCount() == 1) - scopes = visibleScopes; // ### handle global scope lookup - else - scopes = resolveNestedNameSpecifier(q, visibleScopes); + if (q->nameCount() == 1) + scopes = visibleScopes; // ### handle global scope lookup + else + scopes = resolveNestedNameSpecifier(q, visibleScopes); - QList expanded; - foreach (Scope *scope, scopes) { - expanded.append(scope); + QList expanded; + foreach (Scope *scope, scopes) { + expanded.append(scope); - for (unsigned i = 0; i < scope->symbolCount(); ++i) { - Symbol *member = scope->symbolAt(i); + for (unsigned i = 0; i < scope->symbolCount(); ++i) { + Symbol *member = scope->symbolAt(i); - if (ScopedSymbol *scopedSymbol = member->asScopedSymbol()) - expandEnumOrAnonymousSymbol(scopedSymbol, &expanded); - } + if (ScopedSymbol *scopedSymbol = member->asScopedSymbol()) + expandEnumOrAnonymousSymbol(scopedSymbol, &expanded); } - - candidates += resolve(q->unqualifiedNameId(), expanded, mode); } + candidates += resolve(q->unqualifiedNameId(), expanded, mode); + return candidates; } From 982347dda5ee8fa916a9760ecd89452fd3cd90c1 Mon Sep 17 00:00:00 2001 From: hjk Date: Mon, 12 Oct 2009 09:30:28 +0200 Subject: [PATCH 10/34] debugger: provide support for .toHex() encoded string data. more verbose than base64 but also less work on the dumper side --- src/plugins/debugger/watchutils.cpp | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/plugins/debugger/watchutils.cpp b/src/plugins/debugger/watchutils.cpp index c004a25652c..a351f34ced7 100644 --- a/src/plugins/debugger/watchutils.cpp +++ b/src/plugins/debugger/watchutils.cpp @@ -409,7 +409,8 @@ QString decodeData(const QByteArray &ba, int encoding) const QChar doubleQuote(QLatin1Char('"')); const QByteArray decodedBa = QByteArray::fromBase64(ba); QString rc = doubleQuote; - rc += QString::fromUtf16(reinterpret_cast(decodedBa.data()), decodedBa.size() / 2); + rc += QString::fromUtf16(reinterpret_cast + (decodedBa.data()), decodedBa.size() / 2); rc += doubleQuote; return rc; } @@ -417,17 +418,25 @@ QString decodeData(const QByteArray &ba, int encoding) const QByteArray decodedBa = QByteArray::fromBase64(ba); const QChar doubleQuote(QLatin1Char('"')); QString rc = doubleQuote; - rc += QString::fromUcs4(reinterpret_cast(decodedBa.data()), decodedBa.size() / 4); + rc += QString::fromUcs4(reinterpret_cast + (decodedBa.data()), decodedBa.size() / 4); rc += doubleQuote; return rc; } case 4: { // base64 encoded 16 bit data, without quotes (see 2) const QByteArray decodedBa = QByteArray::fromBase64(ba); - return QString::fromUtf16(reinterpret_cast(decodedBa.data()), decodedBa.size() / 2); + return QString::fromUtf16(reinterpret_cast + (decodedBa.data()), decodedBa.size() / 2); } case 5: { // base64 encoded 8 bit data, without quotes (see 1) return quoteUnprintableLatin1(QByteArray::fromBase64(ba)); } + case 7: { // %04x endoded 16 bit data + const QByteArray decodedBa = QByteArray::fromHex(ba); + qDebug() << quoteUnprintableLatin1(decodedBa) << "\n\n"; + return QString::fromUtf16(reinterpret_cast + (decodedBa.data()), decodedBa.size() / 2); + } } return QCoreApplication::translate("Debugger", ""); } From 7e3d95419582d7276d94131ddd8958180f6a94b5 Mon Sep 17 00:00:00 2001 From: hjk Date: Mon, 12 Oct 2009 14:50:27 +0200 Subject: [PATCH 11/34] debugger: work on a "synchroneous" mode For the case that gdb can give all the interesting data in one go. --- src/plugins/debugger/gdb/gdbengine.cpp | 155 +++++++++++++++++++------ src/plugins/debugger/gdb/gdbengine.h | 8 +- src/plugins/debugger/idebuggerengine.h | 1 + 3 files changed, 129 insertions(+), 35 deletions(-) diff --git a/src/plugins/debugger/gdb/gdbengine.cpp b/src/plugins/debugger/gdb/gdbengine.cpp index 90570591ad3..e1656eb6d50 100644 --- a/src/plugins/debugger/gdb/gdbengine.cpp +++ b/src/plugins/debugger/gdb/gdbengine.cpp @@ -89,7 +89,7 @@ #endif #include -// FIXME: temporary hack to evalute tbreak based step-over behaviour +// FIXME: temporary hack to evalaute tbreak based step-over behaviour static QString lastFile; static int lastLine; @@ -2648,8 +2648,6 @@ static void setWatchDataSAddress(WatchData &data, const GdbMi &mi) void GdbEngine::setUseDebuggingHelpers(const QVariant &on) { //qDebug() << "SWITCHING ON/OFF DUMPER DEBUGGING:" << on; - // FIXME: a bit too harsh, but otherwise the treeview sometimes look funny - //m_expandedINames.clear(); Q_UNUSED(on) setTokenBarrier(); updateLocals(); @@ -2916,6 +2914,7 @@ void GdbEngine::updateSubItem(const WatchData &data0) return; } +//#if !X if (data.isHasChildrenNeeded() && data.variable.isEmpty()) { #if DEBUG_SUBITEM qDebug() << "UPDATE SUBITEM: VARIABLE NEEDED FOR CHILDCOUNT"; @@ -2925,6 +2924,7 @@ void GdbEngine::updateSubItem(const WatchData &data0) // item, with childrenNeeded() set. return; } +//#endif if (data.isHasChildrenNeeded()) { QTC_ASSERT(!data.variable.isEmpty(), return); // tested above @@ -2939,16 +2939,32 @@ void GdbEngine::updateSubItem(const WatchData &data0) void GdbEngine::updateWatchData(const WatchData &data) { - // Bump requests to avoid model rebuilding during the nested - // updateWatchModel runs. - ++m_pendingRequests; - PENDING_DEBUG("UPDATE WATCH BUMPS PENDING UP TO " << m_pendingRequests); -#if 1 - QMetaObject::invokeMethod(this, "updateWatchDataHelper", - Qt::QueuedConnection, Q_ARG(WatchData, data)); + if (isSynchroneous()) { + // This should only be called for fresh expanded items, not for + // items that had their children retrieved earlier. + qDebug() << "\nUPDATE WATCH DATA: " << data.toString() << "\n"; +#if 0 + WatchData data1 = data; + data1.setAllUnneeded(); + insertData(data1); + rebuildModel(); #else - updateWatchDataHelper(data); + if (data.iname.endsWith(_("."))) + return; + updateLocals(); #endif + } else { + // Bump requests to avoid model rebuilding during the nested + // updateWatchModel runs. + ++m_pendingRequests; + PENDING_DEBUG("UPDATE WATCH BUMPS PENDING UP TO " << m_pendingRequests); +#if 1 + QMetaObject::invokeMethod(this, "updateWatchDataHelper", + Qt::QueuedConnection, Q_ARG(WatchData, data)); +#else + updateWatchDataHelper(data); +#endif + } } void GdbEngine::updateWatchDataHelper(const WatchData &data) @@ -3341,12 +3357,6 @@ void GdbEngine::handleDebuggingHelperValue3(const GdbResponse &response) void GdbEngine::updateLocals() { - // Asynchronous load of injected library, initialize in first stop - if (m_dumperInjectionLoad && m_debuggingHelperState == DebuggingHelperLoadTried - && m_dumperHelper.typeCount() == 0 - && inferiorPid() > 0) - tryQueryDebuggingHelpers(); - m_pendingRequests = 0; m_processedNames.clear(); @@ -3355,13 +3365,70 @@ void GdbEngine::updateLocals() m_toolTipExpression.clear(); manager()->watchHandler()->beginCycle(); - QString level = QString::number(currentFrame()); - // '2' is 'list with type and value' - QString cmd = _("-stack-list-arguments 2 ") + level + _c(' ') + level; - postCommand(cmd, WatchUpdate, CB(handleStackListArguments)); - // '2' is 'list with type and value' - postCommand(_("-stack-list-locals 2"), WatchUpdate, - CB(handleStackListLocals)); // stage 2/2 + // Asynchronous load of injected library, initialize in first stop + if (m_dumperInjectionLoad && m_debuggingHelperState == DebuggingHelperLoadTried + && m_dumperHelper.typeCount() == 0 + && inferiorPid() > 0) + tryQueryDebuggingHelpers(); + + if (isSynchroneous()) { + QStringList expanded = m_manager->watchHandler()->expandedINames().toList(); + qDebug() << "EXPANDED: " << expanded; + postCommand(_("bb %1").arg(expanded.join(_(","))), + WatchUpdate, CB(handleStackFrame1)); + postCommand(_("p 0"), WatchUpdate, CB(handleStackFrame2)); + } else { + QString level = QString::number(currentFrame()); + // '2' is 'list with type and value' + QString cmd = _("-stack-list-arguments 2 ") + level + _c(' ') + level; + postCommand(cmd, WatchUpdate, CB(handleStackListArguments)); + // '2' is 'list with type and value' + postCommand(_("-stack-list-locals 2"), WatchUpdate, + CB(handleStackListLocals)); // stage 2/2 + } +} + +void GdbEngine::handleStackFrame1(const GdbResponse &response) +{ + if (response.resultClass == GdbResultDone) { + QByteArray out = response.data.findChild("consolestreamoutput").data(); + while (out.endsWith(' ') || out.endsWith('\n')) + out.chop(1); + //qDebug() << "FIRST CHUNK: " << out; + m_firstChunk = out; + } else if (response.resultClass == GdbResultError) { + QTC_ASSERT(false, /**/); + } +} + +void GdbEngine::handleStackFrame2(const GdbResponse &response) +{ + if (response.resultClass == GdbResultDone) { + QByteArray out = response.data.findChild("consolestreamoutput").data(); + while (out.endsWith(' ') || out.endsWith('\n')) + out.chop(1); + //qDebug() << "SECOND CHUNK: " << out; + out = m_firstChunk + out; + // FIXME: Hack, make sure dumper does not return "{}" + out.replace(",{}", ""); + GdbMi all("[" + out + "]"); + qDebug() << "ALL: " << all.toString(); + QList locals = all.children(); + //manager()->watchHandler()->insertBulkData(locals); + //setLocals(locals); + WatchData *data = manager()->watchHandler()->findItem(_("local")); + QTC_ASSERT(data, return); + + QList list; + foreach (const GdbMi &local, locals) + handleChildren(*data, local, &list); + + manager()->watchHandler()->insertBulkData(list); + + manager()->watchHandler()->updateWatchers(); + } else if (response.resultClass == GdbResultError) { + QTC_ASSERT(false, /**/); + } } void GdbEngine::handleStackListArguments(const GdbResponse &response) @@ -3456,14 +3523,23 @@ void GdbEngine::setLocals(const QList &locals) data.exp = nam; data.framekey = m_currentFrame + data.name; setWatchDataType(data, item.findChild("type")); - // set value only directly if it is simple enough, otherwise - // pass through the insertData() machinery - if (isIntOrFloatType(data.type) || isPointerType(data.type)) - setWatchDataValue(data, item.findChild("value")); - if (isSymbianIntType(data.type)) { - setWatchDataValue(data, item.findChild("value")); - data.setHasChildren(false); + if (isSynchroneous()) { + setWatchDataValue(data, item.findChild("value"), + item.findChild("valueencoded").data().toInt()); + // We know that the complete list of children is + // somewhere in the response. + data.setChildrenUnneeded(); + } else { + // set value only directly if it is simple enough, otherwise + // pass through the insertData() machinery + if (isIntOrFloatType(data.type) || isPointerType(data.type)) + setWatchDataValue(data, item.findChild("value")); + if (isSymbianIntType(data.type)) { + setWatchDataValue(data, item.findChild("value")); + data.setHasChildren(false); + } } + // Let's be a bit more bold: //if (!hasDebuggingHelperForType(data.type)) { // QByteArray value = item.findChild("value").data(); @@ -3515,7 +3591,8 @@ void GdbEngine::handleVarListChildrenHelper(const GdbMi &item, //qDebug() << "DATA" << data.toString(); QString cmd = _("-var-list-children --all-values \"") + data.variable + _c('"'); //iname += '.' + exp; - postCommand(cmd, WatchUpdate, CB(handleVarListChildren), QVariant::fromValue(data)); + postCommand(cmd, WatchUpdate, + CB(handleVarListChildren), QVariant::fromValue(data)); } else if (item.findChild("numchild").data() == "0") { // happens for structs without data, e.g. interfaces. WatchData data; @@ -3533,7 +3610,8 @@ void GdbEngine::handleVarListChildrenHelper(const GdbMi &item, WatchData data; data.iname = _(name); QString cmd = _("-var-list-children --all-values \"") + data.variable + _c('"'); - postCommand(cmd, WatchUpdate, CB(handleVarListChildren), QVariant::fromValue(data)); + postCommand(cmd, WatchUpdate, + CB(handleVarListChildren), QVariant::fromValue(data)); } else if (exp == "staticMetaObject") { // && item.findChild("type").data() == "const QMetaObject") // FIXME: Namespaces? @@ -3655,6 +3733,9 @@ void GdbEngine::assignValueInDebugger(const QString &expression, const QString & void GdbEngine::tryLoadDebuggingHelpers() { + if (isSynchroneous()) + return; + if (m_debuggingHelperState != DebuggingHelperUninitialized) return; if (!startModeAllowsDumpers()) { @@ -3735,9 +3816,13 @@ void GdbEngine::tryLoadDebuggingHelpers() void GdbEngine::tryQueryDebuggingHelpers() { +#if !X // retrieve list of dumpable classes postCommand(_("call (void*)qDumpObjectData440(1,%1+1,0,0,0,0,0,0)"), EmbedToken); postCommand(_("p (char*)&qDumpOutBuffer"), CB(handleQueryDebuggingHelper)); +#else + m_debuggingHelperState = DebuggingHelperUnavailable; +#endif } void GdbEngine::recheckDebuggingHelperAvailability() @@ -4186,6 +4271,10 @@ void GdbEngine::showMessageBox(int icon, const QString &title, const QString &te m_manager->showMessageBox(icon, title, text); } +bool GdbEngine::isSynchroneous() const +{ + return false; +} // // Factory diff --git a/src/plugins/debugger/gdb/gdbengine.h b/src/plugins/debugger/gdb/gdbengine.h index 73d898fc2fd..56b4aefb883 100644 --- a/src/plugins/debugger/gdb/gdbengine.h +++ b/src/plugins/debugger/gdb/gdbengine.h @@ -146,9 +146,10 @@ private: Q_SLOT void setDebugDebuggingHelpers(const QVariant &on); Q_SLOT void setUseDebuggingHelpers(const QVariant &on); Q_SLOT void setAutoDerefPointers(const QVariant &on); - virtual bool isGdbEngine() const { return true; } + bool isGdbEngine() const { return true; } + bool isSynchroneous() const; - virtual bool checkConfiguration(int toolChain, QString *errorMessage, QString *settingsPage= 0) const; + bool checkConfiguration(int toolChain, QString *errorMessage, QString *settingsPage= 0) const; // // Own stuff @@ -347,6 +348,9 @@ private: void handleStackListFrames(const GdbResponse &response); void handleStackSelectThread(const GdbResponse &response); void handleStackListThreads(const GdbResponse &response); + void handleStackFrame1(const GdbResponse &response); + void handleStackFrame2(const GdbResponse &response); + QByteArray m_firstChunk; Q_SLOT void reloadStack(bool forceGotoLocation); Q_SLOT void reloadFullStack(); diff --git a/src/plugins/debugger/idebuggerengine.h b/src/plugins/debugger/idebuggerengine.h index b1110bda67a..619ac2bddb9 100644 --- a/src/plugins/debugger/idebuggerengine.h +++ b/src/plugins/debugger/idebuggerengine.h @@ -119,6 +119,7 @@ public: virtual bool isGdbEngine() const { return false; } virtual bool checkConfiguration(int /* toolChain */, QString * /* errorMessage */, QString * /* settingsPage */ = 0) const { return true; } + virtual bool isSynchroneous() const { return false; } protected: void showStatusMessage(const QString &msg, int timeout = -1); DebuggerState state() const; From 2de8f49ee35e7fe1ca816648300296691baf94c2 Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Mon, 12 Oct 2009 14:24:26 +0200 Subject: [PATCH 12/34] remove dead code --- src/plugins/debugger/gdb/gdbmi.h | 1 - src/plugins/debugger/gdb/trkgdbadapter.cpp | 4 ---- 2 files changed, 5 deletions(-) diff --git a/src/plugins/debugger/gdb/gdbmi.h b/src/plugins/debugger/gdb/gdbmi.h index 6abea9292f0..c23239cafca 100644 --- a/src/plugins/debugger/gdb/gdbmi.h +++ b/src/plugins/debugger/gdb/gdbmi.h @@ -149,7 +149,6 @@ enum GdbResultClass // "done" | "running" | "connected" | "error" | "exit" GdbResultUnknown, GdbResultDone, - GdbResultCustomDone, GdbResultRunning, GdbResultConnected, GdbResultError, diff --git a/src/plugins/debugger/gdb/trkgdbadapter.cpp b/src/plugins/debugger/gdb/trkgdbadapter.cpp index 1db8f66ff08..502f9a60fe1 100644 --- a/src/plugins/debugger/gdb/trkgdbadapter.cpp +++ b/src/plugins/debugger/gdb/trkgdbadapter.cpp @@ -1187,10 +1187,6 @@ void TrkGdbAdapter::handleCreateProcess(const TrkResult &result) logMessage("COD: " + hexxNumber(m_session.codeseg)); logMessage("DAT: " + hexxNumber(m_session.dataseg)); - QByteArray ba; - appendInt(&ba, m_session.pid); - appendInt(&ba, m_session.tid); - startGdb(); } From a1a8f6adcbd4771d8464c2932beb0220c2d7aaa1 Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Mon, 12 Oct 2009 12:00:07 +0200 Subject: [PATCH 13/34] centralize gdb command result class checking each command can have only one of two legitimate responses: "error" or - depending on the command, and thus declared via a flag - "done" or "running". this is way nicer than sprinkling the code with else-ifs (where elses are sufficient) and asserts all over the place - and silently failing in release builds. --- src/plugins/debugger/gdb/attachgdbadapter.cpp | 6 +- src/plugins/debugger/gdb/coregdbadapter.cpp | 8 +-- src/plugins/debugger/gdb/gdbengine.cpp | 71 ++++++++++--------- src/plugins/debugger/gdb/gdbengine.h | 3 +- src/plugins/debugger/gdb/gdbmi.cpp | 2 +- src/plugins/debugger/gdb/gdbmi.h | 1 + src/plugins/debugger/gdb/plaingdbadapter.cpp | 9 ++- src/plugins/debugger/gdb/remotegdbadapter.cpp | 10 +-- src/plugins/debugger/gdb/trkgdbadapter.cpp | 8 +-- 9 files changed, 60 insertions(+), 58 deletions(-) diff --git a/src/plugins/debugger/gdb/attachgdbadapter.cpp b/src/plugins/debugger/gdb/attachgdbadapter.cpp index e06790e0ab4..91a1a216360 100644 --- a/src/plugins/debugger/gdb/attachgdbadapter.cpp +++ b/src/plugins/debugger/gdb/attachgdbadapter.cpp @@ -109,7 +109,7 @@ void AttachGdbAdapter::handleAttach(const GdbResponse &response) debugMessage(_("INFERIOR STARTED")); showStatusMessage(msgAttachedToStoppedInferior()); m_engine->updateAll(); - } else if (response.resultClass == GdbResultError) { + } else { QString msg = __(response.data.findChild("msg").data()); setState(InferiorStartFailed); emit inferiorStartFailed(msg); @@ -154,7 +154,7 @@ void AttachGdbAdapter::handleDetach(const GdbResponse &response) setState(InferiorShutDown); emit inferiorShutDown(); shutdown(); // re-iterate... - } else if (response.resultClass == GdbResultError) { + } else { const QString msg = msgInferiorStopFailed(__(response.data.findChild("msg").data())); setState(InferiorShutdownFailed); emit inferiorShutdownFailed(msg); @@ -165,7 +165,7 @@ void AttachGdbAdapter::handleExit(const GdbResponse &response) { if (response.resultClass == GdbResultDone) { // don't set state here, this will be handled in handleGdbFinished() - } else if (response.resultClass == GdbResultError) { + } else { const QString msg = msgGdbStopFailed(__(response.data.findChild("msg").data())); emit adapterShutdownFailed(msg); } diff --git a/src/plugins/debugger/gdb/coregdbadapter.cpp b/src/plugins/debugger/gdb/coregdbadapter.cpp index dd4d5725e8e..c0158caccaf 100644 --- a/src/plugins/debugger/gdb/coregdbadapter.cpp +++ b/src/plugins/debugger/gdb/coregdbadapter.cpp @@ -133,7 +133,6 @@ void CoreGdbAdapter::handleTargetCore1(const GdbResponse &response) m_engine->postCommand(_("detach"), CB(handleDetach1)); } } else { - QTC_ASSERT(response.resultClass == GdbResultError, /**/); const QByteArray msg = response.data.findChild("msg").data(); setState(InferiorStartFailed); emit inferiorStartFailed(msg); @@ -149,7 +148,6 @@ void CoreGdbAdapter::handleDetach1(const GdbResponse &response) m_engine->postCommand(_("-file-exec-and-symbols \"%1\"") .arg(fi.absoluteFilePath()), CB(handleFileExecAndSymbols)); } else { - QTC_ASSERT(response.resultClass == GdbResultError, /**/); const QByteArray msg = response.data.findChild("msg").data(); setState(InferiorStartFailed); emit inferiorStartFailed(msg); @@ -165,7 +163,7 @@ void CoreGdbAdapter::handleFileExecAndSymbols(const GdbResponse &response) QFileInfo fi(startParameters().coreFile); QString coreName = fi.absoluteFilePath(); m_engine->postCommand(_("target core ") + coreName, CB(handleTargetCore2)); - } else if (response.resultClass == GdbResultError) { + } else { QString msg = tr("Symbols not found in \"%1\" failed:\n%2") .arg(__(response.data.findChild("msg").data())); setState(InferiorUnrunnable); @@ -182,7 +180,7 @@ void CoreGdbAdapter::handleTargetCore2(const GdbResponse &response) showStatusMessage(tr("Attached to core.")); setState(InferiorUnrunnable); m_engine->updateAll(); - } else if (response.resultClass == GdbResultError) { + } else { QString msg = tr("Attach to core \"%1\" failed:\n%2") .arg(__(response.data.findChild("msg").data())); setState(InferiorUnrunnable); @@ -220,7 +218,7 @@ void CoreGdbAdapter::handleExit(const GdbResponse &response) { if (response.resultClass == GdbResultDone) { // don't set state here, this will be handled in handleGdbFinished() - } else if (response.resultClass == GdbResultError) { + } else { const QString msg = msgGdbStopFailed(__(response.data.findChild("msg").data())); emit adapterShutdownFailed(msg); } diff --git a/src/plugins/debugger/gdb/gdbengine.cpp b/src/plugins/debugger/gdb/gdbengine.cpp index e1656eb6d50..c9984dcd362 100644 --- a/src/plugins/debugger/gdb/gdbengine.cpp +++ b/src/plugins/debugger/gdb/gdbengine.cpp @@ -811,10 +811,17 @@ void GdbEngine::handleResultRecord(const GdbResponse &response) GdbResponse responseWithCookie = response; responseWithCookie.cookie = cmd.cookie; - if (cmd.callback) - (this->*cmd.callback)(responseWithCookie); - if (cmd.adapterCallback) - (m_gdbAdapter->*cmd.adapterCallback)(responseWithCookie); + if (response.resultClass != GdbResultError && + response.resultClass != ((cmd.flags & RunRequest) ? GdbResultRunning : GdbResultDone)) { + debugMessage(_("UNEXPECTED RESPONSE %1 TO COMMAND %2") + .arg(_(GdbResponse::stringFromResultClass(response.resultClass))) + .arg(cmd.command)); + } else { + if (cmd.callback) + (this->*cmd.callback)(responseWithCookie); + else if (cmd.adapterCallback) + (m_gdbAdapter->*cmd.adapterCallback)(responseWithCookie); + } if (cmd.flags & RebuildModel) { --m_pendingRequests; @@ -1173,7 +1180,7 @@ void GdbEngine::handleStop1(const GdbMi &data) GdbMi frameData = data.findChild("frame"); if (frameData.findChild("func").data() == "_start" && frameData.findChild("from").data() == "/lib/ld-linux.so.2") { - postCommand(_("-exec-continue"), CB(handleExecContinue)); + postCommand(_("-exec-continue"), RunRequest, CB(handleExecContinue)); return; } } @@ -1302,7 +1309,7 @@ void GdbEngine::handleFileExecAndSymbols(const GdbResponse &response) { if (response.resultClass == GdbResultDone) { //m_breakHandler->clearBreakMarkers(); - } else if (response.resultClass == GdbResultError) { + } else { QString msg = __(response.data.findChild("msg").data()); showMessageBox(QMessageBox::Critical, tr("Starting executable failed"), msg); QTC_ASSERT(state() == InferiorRunning, /**/); @@ -1316,7 +1323,7 @@ void GdbEngine::handleExecContinue(const GdbResponse &response) if (response.resultClass == GdbResultRunning) { // The "running" state is picked up in handleResponse() QTC_ASSERT(state() == InferiorRunning, /**/); - } else if (response.resultClass == GdbResultError) { + } else { QTC_ASSERT(state() == InferiorRunningRequested, /**/); QByteArray msg = response.data.findChild("msg").data(); if (msg.startsWith("Cannot find bounds of current function")) { @@ -1331,8 +1338,6 @@ void GdbEngine::handleExecContinue(const GdbResponse &response) QTC_ASSERT(state() == InferiorRunning, /**/); shutdown(); } - } else { - QTC_ASSERT(false, /**/); } } @@ -1474,7 +1479,7 @@ void GdbEngine::continueInferiorInternal() m_manager->resetLocation(); setTokenBarrier(); setState(InferiorRunningRequested); - postCommand(_("-exec-continue"), CB(handleExecContinue)); + postCommand(_("-exec-continue"), RunRequest, CB(handleExecContinue)); } void GdbEngine::autoContinueInferior() @@ -1496,9 +1501,9 @@ void GdbEngine::stepExec() setState(InferiorRunningRequested); showStatusMessage(tr("Step requested..."), 5000); if (manager()->isReverseDebugging()) - postCommand(_("-reverse-step"), CB(handleExecContinue)); + postCommand(_("-reverse-step"), RunRequest, CB(handleExecContinue)); else - postCommand(_("-exec-step"), CB(handleExecContinue)); + postCommand(_("-exec-step"), RunRequest, CB(handleExecContinue)); } void GdbEngine::stepIExec() @@ -1508,9 +1513,9 @@ void GdbEngine::stepIExec() setState(InferiorRunningRequested); showStatusMessage(tr("Step by instruction requested..."), 5000); if (manager()->isReverseDebugging()) - postCommand(_("-reverse-stepi"), CB(handleExecContinue)); + postCommand(_("-reverse-stepi"), RunRequest, CB(handleExecContinue)); else - postCommand(_("-exec-step-instruction"), CB(handleExecContinue)); + postCommand(_("-exec-step-instruction"), RunRequest, CB(handleExecContinue)); } void GdbEngine::stepOutExec() @@ -1519,7 +1524,7 @@ void GdbEngine::stepOutExec() setTokenBarrier(); setState(InferiorRunningRequested); showStatusMessage(tr("Finish function requested..."), 5000); - postCommand(_("-exec-finish"), CB(handleExecContinue)); + postCommand(_("-exec-finish"), RunRequest, CB(handleExecContinue)); } void GdbEngine::nextExec() @@ -1529,14 +1534,14 @@ void GdbEngine::nextExec() setState(InferiorRunningRequested); showStatusMessage(tr("Step next requested..."), 5000); if (manager()->isReverseDebugging()) - postCommand(_("-reverse-next"), CB(handleExecContinue)); + postCommand(_("-reverse-next"), RunRequest, CB(handleExecContinue)); else { #if 1 - postCommand(_("-exec-next"), CB(handleExecContinue)); + postCommand(_("-exec-next"), RunRequest, CB(handleExecContinue)); #else postCommand(_("tbreak %1:%2").arg(QFileInfo(lastFile).fileName()) .arg(lastLine + 1)); - postCommand(_("-exec-continue"), CB(handleExecContinue)); + postCommand(_("-exec-continue"), RunRequest, CB(handleExecContinue)); #endif } } @@ -1548,9 +1553,9 @@ void GdbEngine::nextIExec() setState(InferiorRunningRequested); showStatusMessage(tr("Step next instruction requested..."), 5000); if (manager()->isReverseDebugging()) - postCommand(_("-reverse-nexti"), CB(handleExecContinue)); + postCommand(_("-reverse-nexti"), RunRequest, CB(handleExecContinue)); else - postCommand(_("-exec-next-instruction"), CB(handleExecContinue)); + postCommand(_("-exec-next-instruction"), RunRequest, CB(handleExecContinue)); } void GdbEngine::runToLineExec(const QString &fileName, int lineNumber) @@ -1571,7 +1576,7 @@ void GdbEngine::runToFunctionExec(const QString &functionName) showStatusMessage(tr("Run to function %1 requested...").arg(functionName), 5000); // that should be "^running". We need to handle the resulting // "Stopped" - postCommand(_("-exec-continue"), CB(handleExecContinue)); + postCommand(_("-exec-continue"), RunRequest, CB(handleExecContinue)); //postCommand(_("-exec-continue"), handleExecRunToFunction); } @@ -1851,7 +1856,7 @@ void GdbEngine::handleBreakCondition(const GdbResponse &response) BreakpointData *data = handler->at(index); //qDebug() << "HANDLE BREAK CONDITION" << index << data->condition; data->bpCondition = data->condition; - } else { // GdbResultError + } else { QByteArray msg = response.data.findChild("msg").data(); // happens on Mac if (1 || msg.startsWith("Error parsing breakpoint condition. " @@ -1877,7 +1882,7 @@ void GdbEngine::handleBreakInsert(const GdbResponse &response) //#endif attemptBreakpointSynchronization(); handler->updateMarkers(); - } else { // GdbResultError + } else { const BreakpointData *data = handler->at(index); // Note that it is perfectly correct that the file name is put // in quotes but not escaped. GDB simply is like that. @@ -1967,7 +1972,7 @@ void GdbEngine::handleBreakInsert1(const GdbResponse &response) BreakpointData *data = handler->at(index); GdbMi bkpt = response.data.findChild("bkpt"); breakpointDataFromOutput(data, bkpt); - } else { // GdbResultError + } else { qDebug() << "INSERTING BREAKPOINT WITH BASE NAME FAILED. GIVING UP"; BreakpointData *data = handler->at(index); data->bpNumber = _(""); @@ -3128,7 +3133,7 @@ void GdbEngine::handleVarCreate(const GdbResponse &response) // data.setValue(QString()); insertData(data); } - } else if (response.resultClass == GdbResultError) { + } else { data.setError(QString::fromLocal8Bit(response.data.findChild("msg").data())); if (data.isWatcher()) { data.value = strNotInScope; @@ -3151,7 +3156,7 @@ void GdbEngine::handleEvaluateExpression(const GdbResponse &response) // data.name = response.data.findChild("value").data(); //else setWatchDataValue(data, response.data.findChild("value")); - } else if (response.resultClass == GdbResultError) { + } else { data.setError(QString::fromLocal8Bit(response.data.findChild("msg").data())); } //qDebug() << "HANDLE EVALUATE EXPRESSION:" << data.toString(); @@ -3163,7 +3168,7 @@ void GdbEngine::handleDebuggingHelperSetup(const GdbResponse &response) { //qDebug() << "CUSTOM SETUP RESULT:" << response.toString(); if (response.resultClass == GdbResultDone) { - } else if (response.resultClass == GdbResultError) { + } else { QString msg = QString::fromLocal8Bit(response.data.findChild("msg").data()); //qDebug() << "CUSTOM DUMPER SETUP ERROR MESSAGE:" << msg; showStatusMessage(tr("Custom dumper setup: %1").arg(msg), 10000); @@ -3176,7 +3181,7 @@ void GdbEngine::handleDebuggingHelperValue1(const GdbResponse &response) QTC_ASSERT(data.isValid(), return); if (response.resultClass == GdbResultDone) { // ignore this case, data will follow - } else if (response.resultClass == GdbResultError) { + } else { QString msg = QString::fromLocal8Bit(response.data.findChild("msg").data()); #ifdef QT_DEBUG // Make debugging of dumpers easier @@ -3347,7 +3352,7 @@ void GdbEngine::handleDebuggingHelperValue3(const GdbResponse &response) data.setAllUnneeded(); insertData(data); } - } else if (response.resultClass == GdbResultError) { + } else { WatchData data = response.cookie.value(); data.setError(strNotInScope); data.setAllUnneeded(); @@ -3460,7 +3465,7 @@ void GdbEngine::handleStackListArguments(const GdbResponse &response) const GdbMi frame = list.findChild("frame"); const GdbMi args = frame.findChild("args"); m_currentFunctionArgs = args.children(); - } else if (response.resultClass == GdbResultError) { + } else { qDebug() << "FIXME: GdbEngine::handleStackListArguments: should not happen" << response.toString(); } @@ -3705,10 +3710,8 @@ void GdbEngine::handleVarListChildren(const GdbResponse &response) // this skips the spurious "public", "private" etc levels // gdb produces } - } else if (response.resultClass == GdbResultError) { - data.setError(QString::fromLocal8Bit(response.data.findChild("msg").data())); } else { - data.setError(tr("Unknown error: ") + QString::fromLocal8Bit(response.toString())); + data.setError(QString::fromLocal8Bit(response.data.findChild("msg").data())); } } @@ -4024,7 +4027,7 @@ void GdbEngine::handleFetchDisassemblerByLine(const GdbResponse &response) fetchDisassemblerByAddress(ac.agent, true); else ac.agent->setContents(parseDisassembler(lines)); - } else if (response.resultClass == GdbResultError) { + } else { // 536^error,msg="mi_cmd_disassemble: Invalid line number" QByteArray msg = response.data.findChild("msg").data(); if (msg == "mi_cmd_disassemble: Invalid line number") diff --git a/src/plugins/debugger/gdb/gdbengine.h b/src/plugins/debugger/gdb/gdbengine.h index 56b4aefb883..81b6952c045 100644 --- a/src/plugins/debugger/gdb/gdbengine.h +++ b/src/plugins/debugger/gdb/gdbengine.h @@ -176,7 +176,8 @@ public: // otherwise the Qt flag macros are unhappy Discardable = 2, RebuildModel = 4, WatchUpdate = Discardable | RebuildModel, - EmbedToken = 8 + EmbedToken = 8, + RunRequest = 16 }; Q_DECLARE_FLAGS(GdbCommandFlags, GdbCommandFlag) diff --git a/src/plugins/debugger/gdb/gdbmi.cpp b/src/plugins/debugger/gdb/gdbmi.cpp index a805df94df7..ffac5d76d15 100644 --- a/src/plugins/debugger/gdb/gdbmi.cpp +++ b/src/plugins/debugger/gdb/gdbmi.cpp @@ -362,7 +362,7 @@ GdbMi GdbMi::findChild(const char *name) const // ////////////////////////////////////////////////////////////////////////////////// -QByteArray stringFromResultClass(GdbResultClass resultClass) +QByteArray GdbResponse::stringFromResultClass(GdbResultClass resultClass) { switch (resultClass) { case GdbResultDone: return "done"; diff --git a/src/plugins/debugger/gdb/gdbmi.h b/src/plugins/debugger/gdb/gdbmi.h index c23239cafca..24295afea66 100644 --- a/src/plugins/debugger/gdb/gdbmi.h +++ b/src/plugins/debugger/gdb/gdbmi.h @@ -160,6 +160,7 @@ class GdbResponse public: GdbResponse() : token(-1), resultClass(GdbResultUnknown) {} QByteArray toString() const; + static QByteArray stringFromResultClass(GdbResultClass resultClass); int token; GdbResultClass resultClass; diff --git a/src/plugins/debugger/gdb/plaingdbadapter.cpp b/src/plugins/debugger/gdb/plaingdbadapter.cpp index c0fdea89487..8cbfd89b6ee 100644 --- a/src/plugins/debugger/gdb/plaingdbadapter.cpp +++ b/src/plugins/debugger/gdb/plaingdbadapter.cpp @@ -122,7 +122,7 @@ void PlainGdbAdapter::handleFileExecAndSymbols(const GdbResponse &response) //m_breakHandler->clearBreakMarkers(); setState(InferiorPrepared); emit inferiorPrepared(); - } else if (response.resultClass == GdbResultError) { + } else { QString msg = tr("Starting executable failed:\n") + __(response.data.findChild("msg").data()); setState(InferiorPreparationFailed); @@ -138,7 +138,6 @@ void PlainGdbAdapter::handleExecRun(const GdbResponse &response) showStatusMessage(msgInferiorStarted()); } else { QTC_ASSERT(state() == InferiorRunningRequested, qDebug() << state()); - QTC_ASSERT(response.resultClass == GdbResultError, /**/); const QByteArray &msg = response.data.findChild("msg").data(); //QTC_ASSERT(status() == InferiorRunning, /**/); //interruptInferior(); @@ -151,7 +150,7 @@ void PlainGdbAdapter::startInferior() { QTC_ASSERT(state() == InferiorStarting, qDebug() << state()); setState(InferiorRunningRequested); - m_engine->postCommand(_("-exec-run"), CB(handleExecRun)); + m_engine->postCommand(_("-exec-run"), GdbEngine::RunRequest, CB(handleExecRun)); } void PlainGdbAdapter::interruptInferior() @@ -218,7 +217,7 @@ void PlainGdbAdapter::handleKill(const GdbResponse &response) setState(InferiorShutDown); emit inferiorShutDown(); shutdown(); // re-iterate... - } else if (response.resultClass == GdbResultError) { + } else { const QString msg = msgInferiorStopFailed(__(response.data.findChild("msg").data())); setState(InferiorShutdownFailed); emit inferiorShutdownFailed(msg); @@ -229,7 +228,7 @@ void PlainGdbAdapter::handleExit(const GdbResponse &response) { if (response.resultClass == GdbResultDone) { // don't set state here, this will be handled in handleGdbFinished() - } else if (response.resultClass == GdbResultError) { + } else { const QString msg = msgGdbStopFailed(__(response.data.findChild("msg").data())); emit adapterShutdownFailed(msg); } diff --git a/src/plugins/debugger/gdb/remotegdbadapter.cpp b/src/plugins/debugger/gdb/remotegdbadapter.cpp index 0b386f8b0f6..5e16587d188 100644 --- a/src/plugins/debugger/gdb/remotegdbadapter.cpp +++ b/src/plugins/debugger/gdb/remotegdbadapter.cpp @@ -184,7 +184,7 @@ void RemoteGdbAdapter::handleSetTargetAsync(const GdbResponse &response) QString fileName = fi.absoluteFilePath(); m_engine->postCommand(_("-file-exec-and-symbols \"%1\"").arg(fileName), CB(handleFileExecAndSymbols)); - } else if (response.resultClass == GdbResultError) { + } else { QString msg = tr("Adapter too old: does not support asynchronous mode."); setState(InferiorPreparationFailed); emit inferiorPreparationFailed(msg); @@ -198,7 +198,7 @@ void RemoteGdbAdapter::handleFileExecAndSymbols(const GdbResponse &response) //m_breakHandler->clearBreakMarkers(); m_engine->setState(InferiorPrepared); emit inferiorPrepared(); - } else if (response.resultClass == GdbResultError) { + } else { QString msg = tr("Starting remote executable failed:\n"); msg += __(response.data.findChild("msg").data()); setState(InferiorPreparationFailed); @@ -215,7 +215,7 @@ void RemoteGdbAdapter::handleTargetRemote(const GdbResponse &record) showStatusMessage(msgAttachedToStoppedInferior()); setState(InferiorStopped); m_engine->continueInferior(); - } else if (record.resultClass == GdbResultError) { + } else { // 16^error,msg="hd:5555: Connection timed out." QString msg = msgConnectRemoteServerFailed(__(record.data.findChild("msg").data())); setState(InferiorPreparationFailed); @@ -271,7 +271,7 @@ void RemoteGdbAdapter::handleKill(const GdbResponse &response) setState(InferiorShutDown); emit inferiorShutDown(); shutdown(); // re-iterate... - } else if (response.resultClass == GdbResultError) { + } else { QString msg = msgInferiorStopFailed(__(response.data.findChild("msg").data())); setState(InferiorShutdownFailed); emit inferiorShutdownFailed(msg); @@ -282,7 +282,7 @@ void RemoteGdbAdapter::handleExit(const GdbResponse &response) { if (response.resultClass == GdbResultDone) { // don't set state here, this will be handled in handleGdbFinished() - } else if (response.resultClass == GdbResultError) { + } else { QString msg = msgGdbStopFailed(__(response.data.findChild("msg").data())); emit adapterShutdownFailed(msg); } diff --git a/src/plugins/debugger/gdb/trkgdbadapter.cpp b/src/plugins/debugger/gdb/trkgdbadapter.cpp index 502f9a60fe1..2a994f8c51f 100644 --- a/src/plugins/debugger/gdb/trkgdbadapter.cpp +++ b/src/plugins/debugger/gdb/trkgdbadapter.cpp @@ -1679,7 +1679,7 @@ void TrkGdbAdapter::handleTargetRemote(const GdbResponse &record) if (record.resultClass == GdbResultDone) { setState(InferiorPrepared); emit inferiorPrepared(); - } else if (record.resultClass == GdbResultError) { + } else { QString msg = tr("Connecting to trk server adapter failed:\n") + _(record.data.findChild("msg").data()); emit inferiorPreparationFailed(msg); @@ -1699,7 +1699,7 @@ void TrkGdbAdapter::handleFirstContinue(const GdbResponse &record) if (record.resultClass == GdbResultDone) { debugMessage(_("INFERIOR STARTED")); showStatusMessage(msgInferiorRunning()); - } else if (record.resultClass == GdbResultError) { + } else { emit inferiorStartFailed(msgConnectRemoteServerFailed(record.toString())); } } @@ -2076,7 +2076,7 @@ void TrkGdbAdapter::handleKill(const GdbResponse &response) setState(InferiorShutDown); emit inferiorShutDown(); shutdown(); // re-iterate... - } else if (response.resultClass == GdbResultError) { + } else { const QString msg = msgInferiorStopFailed(__(response.data.findChild("msg").data())); setState(InferiorShutdownFailed); emit inferiorShutdownFailed(msg); @@ -2088,7 +2088,7 @@ void TrkGdbAdapter::handleExit(const GdbResponse &response) if (response.resultClass == GdbResultDone) { qDebug() << "EXITED, NO MESSAGE..."; // don't set state here, this will be handled in handleGdbFinished() - } else if (response.resultClass == GdbResultError) { + } else { const QString msg = msgGdbStopFailed(__(response.data.findChild("msg").data())); emit adapterShutdownFailed(msg); } From 68c2156f6fa9a9595610126333240d7951b8ee89 Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Mon, 12 Oct 2009 12:05:35 +0200 Subject: [PATCH 14/34] add docu to GdbCommandFlag values --- src/plugins/debugger/gdb/gdbengine.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/plugins/debugger/gdb/gdbengine.h b/src/plugins/debugger/gdb/gdbengine.h index 81b6952c045..8c5b3020cdb 100644 --- a/src/plugins/debugger/gdb/gdbengine.h +++ b/src/plugins/debugger/gdb/gdbengine.h @@ -172,12 +172,12 @@ private: public: // otherwise the Qt flag macros are unhappy enum GdbCommandFlag { NoFlags = 0, - NeedsStop = 1, - Discardable = 2, - RebuildModel = 4, + NeedsStop = 1, // The command needs a stopped inferior + Discardable = 2, // No need to wait for the reply before continuing inferior + RebuildModel = 4, // Trigger model rebuild when no such commands are pending any more WatchUpdate = Discardable | RebuildModel, - EmbedToken = 8, - RunRequest = 16 + EmbedToken = 8, // Expand %1 in the command to the command token + RunRequest = 16 // Callback expect GdbResultRunning instead of GdbResultDone }; Q_DECLARE_FLAGS(GdbCommandFlags, GdbCommandFlag) From 9a0896802dca4676f8233f1ca2c42a4ebf721b72 Mon Sep 17 00:00:00 2001 From: con Date: Mon, 12 Oct 2009 15:31:20 +0200 Subject: [PATCH 15/34] Missing bookkeeping when removing Qt Versions. Reviewed-by: dt --- src/plugins/qt4projectmanager/qtversionmanager.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/plugins/qt4projectmanager/qtversionmanager.cpp b/src/plugins/qt4projectmanager/qtversionmanager.cpp index fadaf923184..9dea8af0bdc 100644 --- a/src/plugins/qt4projectmanager/qtversionmanager.cpp +++ b/src/plugins/qt4projectmanager/qtversionmanager.cpp @@ -158,6 +158,7 @@ QtVersionManager *QtVersionManager::instance() void QtVersionManager::addVersion(QtVersion *version) { + QTC_ASSERT(version != 0, return); m_versions.append(version); m_uniqueIdToIndex.insert(version->uniqueId(), m_versions.count() - 1); emit qtVersionsChanged(); @@ -166,7 +167,9 @@ void QtVersionManager::addVersion(QtVersion *version) void QtVersionManager::removeVersion(QtVersion *version) { + QTC_ASSERT(version != 0, return); m_versions.removeAll(version); + m_uniqueIdToIndex.remove(version->uniqueId()); emit qtVersionsChanged(); writeVersionsIntoSettings(); delete version; From cbee229700a794ee1f445d06dd93058232bd891c Mon Sep 17 00:00:00 2001 From: Daniel Molkentin Date: Mon, 12 Oct 2009 13:44:09 +0200 Subject: [PATCH 16/34] docs: Compile Fixes, Fixups in addressbook example Reviewed-By: TrustMe --- doc/examples/addressbook-sdk/part6/addressbook.cpp | 10 +++++++++- doc/examples/addressbook-sdk/part7/addressbook.cpp | 5 ++++- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/doc/examples/addressbook-sdk/part6/addressbook.cpp b/doc/examples/addressbook-sdk/part6/addressbook.cpp index 6d8a15bc24d..4927eae297d 100644 --- a/doc/examples/addressbook-sdk/part6/addressbook.cpp +++ b/doc/examples/addressbook-sdk/part6/addressbook.cpp @@ -1,3 +1,5 @@ +#include + #include "addressbook.h" #include "ui_addressbook.h" @@ -31,6 +33,12 @@ AddressBook::AddressBook(QWidget *parent) SLOT(removeContact())); connect(ui->findButton, SIGNAL(clicked()), this, SLOT(findContact())); + //! [connectSlots] + connect(ui->loadButton, SIGNAL(clicked()), this, + SLOT(loadFromFile())); + connect(ui->saveButton, SIGNAL(clicked()), this, + SLOT(saveToFile())); + //! [connectSlots] setWindowTitle(tr("Simple Address Book")); } @@ -292,7 +300,7 @@ void AddressBook::loadFromFile() //! [loadFromFile part3] if (contacts.isEmpty()) { - QMessagebox::information(this, tr("No contacts in file"), + QMessageBox::information(this, tr("No contacts in file"), tr("The file you are attempting to open contains no contacts.")); } else { QMap::iterator i = contacts.begin(); diff --git a/doc/examples/addressbook-sdk/part7/addressbook.cpp b/doc/examples/addressbook-sdk/part7/addressbook.cpp index 5761030f4ab..f70fbda4844 100644 --- a/doc/examples/addressbook-sdk/part7/addressbook.cpp +++ b/doc/examples/addressbook-sdk/part7/addressbook.cpp @@ -1,3 +1,6 @@ +#include +#include + #include "addressbook.h" #include "ui_addressbook.h" @@ -348,5 +351,5 @@ void AddressBook::exportAsVCard() out << "END;VCARD" << "\n"; QMessageBox::information(this, tr("Export Successful"), - tr("\%1\" has been exported as a vCard.").arg(name)); + tr("\"%1\" has been exported as a vCard.").arg(name)); } From c48c3cb46679fd9c73311c0d29928d058a228fd1 Mon Sep 17 00:00:00 2001 From: Daniel Molkentin Date: Mon, 12 Oct 2009 14:29:40 +0200 Subject: [PATCH 17/34] Fixes to tutorial, added missing screenshots. Reviewed-By: con --- doc/addressbook-sdk.qdoc | 75 +++++----- doc/eike_doc.patch | 138 ++++++++++++++++++ .../addressbook-tutorial-part5-dialogbox.png | Bin 0 -> 6526 bytes ...-tutorial-part5-finddialog-in-designer.png | Bin 0 -> 98226 bytes .../addressbook-tutorial-part5-screenshot.png | Bin 0 -> 9948 bytes .../addressbook-tutorial-part6-opendialog.png | Bin 0 -> 55036 bytes ...ressbook-tutorial-part6-propertyeditor.png | Bin 0 -> 18467 bytes .../addressbook-tutorial-part6-savedialog.png | Bin 0 -> 16166 bytes .../addressbook-tutorial-part6-screenshot.png | Bin 0 -> 11329 bytes .../addressbook-tutorial-part7-screenshot.png | Bin 0 -> 15248 bytes 10 files changed, 177 insertions(+), 36 deletions(-) create mode 100644 doc/eike_doc.patch create mode 100644 doc/images/addressbook-tutorial-part5-dialogbox.png create mode 100644 doc/images/addressbook-tutorial-part5-finddialog-in-designer.png create mode 100644 doc/images/addressbook-tutorial-part5-screenshot.png create mode 100644 doc/images/addressbook-tutorial-part6-opendialog.png create mode 100644 doc/images/addressbook-tutorial-part6-propertyeditor.png create mode 100644 doc/images/addressbook-tutorial-part6-savedialog.png create mode 100644 doc/images/addressbook-tutorial-part6-screenshot.png create mode 100644 doc/images/addressbook-tutorial-part7-screenshot.png diff --git a/doc/addressbook-sdk.qdoc b/doc/addressbook-sdk.qdoc index 49195e9a8e8..7d7734bea78 100644 --- a/doc/addressbook-sdk.qdoc +++ b/doc/addressbook-sdk.qdoc @@ -348,7 +348,7 @@ \snippet examples/addressbook-sdk/part2/addressbook.h members We also declare two private QString objects, \c oldName and \c oldAddress. - These objects are needed to hold the name and address of hte contact that + These objects are needed to hold the name and address of the contact that was last displayed, before the user clicked \gui Add. So, when the user clicks \gui Cancel, we can revert to displaying the details of the last contact. @@ -529,7 +529,7 @@ \snippet examples/addressbook-sdk/part3/addressbook.cpp enable navigation - We also include these lins of code in the \c cancel() function. + We also include these lines of code in the \c cancel() function. Recall that we intend to emulate a circularly-linked list with our QMap object, \c contacts. So in the \c next() function, we obtain an iterator @@ -735,7 +735,7 @@ In this chapter, we look at ways to locate contacts and addresses in the address book application. - # image + \image addressbook-tutorial-part5-screenshot.png As we keep adding contacts to our address book, it becomes tedious to navigate them with the \gui Next and \gui Previous buttons. In this case, @@ -750,13 +750,14 @@ \section1 Designing The FindDialog - #image + \image addressbook-tutorial-part5-finddialog-in-designer.png - We begin by adding a new \c{.ui} file to our project. Right click on your + We begin by adding a new \c{.ui} file and a corresponding class to our project. Right click on your project and select \gui{Add New...}. In the \gui{New File} dialog, select - \gui{Qt Designer Form}. In the \gui{Qt Designer Form} dialog, select - \e{Dialog without buttons}. Name it \c{finddialog.ui} and add it to your - project. The \QD plugin within Qt Creator will now display your new form. + \gui{Qt Designer Form Class}. In the \gui{Qt Designer Form Class} dialog, select + \e{Dialog without buttons}. Name the class \c{FindDialog} and add the files it to your + project. Open your new form in the \QD form editor within Qt Creator by + double-clicking on the \c{finddialog.ui} file in the \gui{Project Sidebar}. To replicate the screenshot above, we need a label, a line edit, and a push button. Drag these onto your form. Set their text accordingly and name them @@ -781,17 +782,6 @@ \snippet examples/addressbook-sdk/part5/finddialog.cpp constructor - We connect our signals to their respective slots. Notice that - \c{findButton}'s \l{QPushButton:}{clicked()} signal is connected to - \c findClicked() and \l{QDialog::}{accept()}. The \l{QDialog::}{accept()} - slot provided by QDialog hides the dialog and sets the result code to - \l{QDialog::}{Accepted}. We use this function to help \c{AddressBook}'s - \c findContact() function know when the \c FindDialog object has been - closed. We will explain this logic in further detail when discussing the - \c findContact() function. - - \image addressbook-tutorial-part5-signals-and-slots.png - In \c findClicked(), we validate to ensure that the user did not click the \gui Find button without entering a contact's name. Then, we set \c findText to the search string, extracted from \c lineEdit. After that, @@ -799,15 +789,24 @@ \snippet examples/addressbook-sdk/part5/finddialog.cpp findClicked - The \c findText variable has a public getter function, \c getFindText(), - associated with it. Since we only ever set \c findText directly in both - the constructor and in hte \c findClicked() function, we do not create a - setter function to accompany \c getFindText(). Because \c getFindText() is - public, classes instantiating and using \c FindDialog can always access the - search string that the user has entered and accepted. + \c findText() is public, which makes it easy for classes instantiating + and using \c FindDialog to access the search string that the user has entered + and accepted. \snippet examples/addressbook-sdk/part5/finddialog.cpp findText + Finally, we connect our signals to their respective slots. Notice that + \c{findButton}'s \l{QPushButton::}{clicked()} signal is connected to + \c findClicked(), which calls \l{QDialog::}{accept()} or \l{QDialog::}{reject()}. + The \l{QDialog::}{accept()} slot provided by QDialog hides the dialog + and sets the result code to \l{QDialog::}{Accepted}, while \l{QDialog::}{reject()} + sets it to \l{QDialog::}{Rejected} accordingly. We use this function to help + \c{AddressBook}'s \c findContact() function know when the \c FindDialog object has been + closed. We will explain this logic in further detail when discussing the + \c findContact() function. + + \image addressbook-tutorial-part5-signals-and-slots.png + \section1 The AddressBook Class @@ -818,7 +817,7 @@ So far, all our address book features have a QPushButton and a corresponding slot. Similarly, for the \gui Find feature, we have - \c findButton and \c findContact(). + \c{ui->findButton} and \c findContact(). \snippet examples/addressbook-sdk/part5/addressbook.h slot definition @@ -838,15 +837,17 @@ We start out by displaying the \c FindDialog instance, \c dialog. This is when the user enters a contact name to look up. Once the user clicks the dialog's \c findButton, the dialog is hidden and the result code is set to - QDialog::Accepted. THis ensures that our \c if statement is always true. + either QDialog::Accepted or QDialog::Rejected by the FindDialog's + \c findClicked() method. This ensures that we only search for a contact + if the user typed something in the FindDialog's line edit. We then proceed to extract the search string, which in this case is - \c contactName, using \c{FindDialog}'s \c getFindText() function. If the + \c contactName, using \c{FindDialog}'s \c findText() function. If the contact exists in our address book, we display it immediately. Otherwise, we display the QMessageBox shown below to indicate that their search failed. - # image + \image addressbook-tutorial-part5-dialogbox.png The concept behind finding a contact only applies for cases where we have more than two contacts in our address book. Hence, we implement this @@ -870,7 +871,7 @@ This chapter covers the file handling features of Qt that we used to write loading and saving routines for the address book application. - # screenshot + \image addressbook-tutorial-part6-screenshot.png Although browsing and searching for contacts are useful features, our address book is not really ready for use until we can save existing @@ -910,7 +911,7 @@ the push buttons. - # screenshot of property editor + \image addressbook-tutorial-part6-propertyeditor.png \section1 The AddressBook Class @@ -935,7 +936,7 @@ The file dialog that pops up is displayed in the screenshot below: - #screenshot + \image addressbook-tutorial-part6-savedialog.png If \c fileName is not empty, we create a QFile object, \c file, with \c fileName. The QFile object works with QDataStream as QFile is a @@ -967,7 +968,7 @@ On Windows, for example, this function pops up a native file dialog, as shown in the following screenshot. - # screenshot + \image addressbook-tutorial-part6-opendialog.png If \c fileName is not empty, again, we use a QFile object, \c file, and attempt to open it in \l{QIODevice::}{ReadOnly} mode. Similar to our @@ -989,8 +990,10 @@ validate the data obtained to ensure that the file we read from actually contains address book contacts. If it does, we display the first contact; otherwise, we display a QMessageBox to inform the user about the problem. - Lastly, we update the interface to enable and disable the push buttons - accordingly. + Lastly, we connect the \c clicked() signal of the push buttons + with the \c loadFromFile() and \c saveToFile(): + + \snippet examples/addressbook-sdk/part6/addressbook.cpp connectSlots */ @@ -1014,7 +1017,7 @@ \c exportButton as its \c objectName. The \c toolTip property is set to \gui{Export as vCard}. - # screenshot + \image addressbook-tutorial-part7-screenshot.png \section1 The AddressBook Class diff --git a/doc/eike_doc.patch b/doc/eike_doc.patch new file mode 100644 index 00000000000..f23c589de23 --- /dev/null +++ b/doc/eike_doc.patch @@ -0,0 +1,138 @@ +diff --git a/doc/addressbook-sdk.qdoc b/doc/addressbook-sdk.qdoc +index 0441666..7012ea6 100644 +--- a/doc/addressbook-sdk.qdoc ++++ b/doc/addressbook-sdk.qdoc +@@ -139,7 +139,7 @@ + \section1 Placing Widgets on The Form + + In the \gui{Project Sidebar}, double-click on the \c{addressbook.ui} file. +- The \QD plugin will be launched, allowing you to design your program's user ++ The \QD form editor will be launched, allowing you to design your program's user + interface. + + We require two \l{QLabel}s to label the input fields as well as a QLineEdit +@@ -156,6 +156,7 @@ + diagram below shows the layout cells and the position of our widgets. Place + your widgets accordingly and save the form by choosing + \gui{File | Save} or using the \key{Ctrl+S} shortcut. ++ (We have to actually layout the widgets in a grid layout, this step seems to be missing to me?) + + \image addressbook-tutorial-part1-labeled-screenshot.png + +@@ -311,7 +312,7 @@ + \snippet examples/addressbook-sdk/part2/addressbook.h slot definition + + Since the \c AddressBook class is a subclass of QWidget, Qt Creator +- includes QWidget in the hedaer file. ++ includes QWidget in the header file. + + \snippet examples/addressbook-sdk/part2/addressbook.h include + +@@ -323,7 +324,7 @@ + \snippet examples/addressbook-sdk/part2/addressbook.h members + + We also declare two private QString objects, \c oldName and \c oldAddress. +- These objects are needed to hold the name and address of hte contact that ++ These objects are needed to hold the name and address of the contact that + was last displayed, before the user clicked \gui Add. So, when the user + clicks \gui Cancel, we can revert to displaying the details of the last + contact. +@@ -499,7 +500,7 @@ + + \snippet examples/addressbook-sdk/part3/addressbook.cpp enable navigation + +- We also include these lins of code in the \c cancel() function. ++ We also include these lines of code in the \c cancel() function. + + Recall that we intend to emulate a circularly-linked list with our QMap + object, \c contacts. So in the \c next() function, we obtain an iterator +@@ -722,11 +723,12 @@ + + #image + +- We begin by adding a new \c{.ui} file to our project. Right click on your ++ We begin by adding a new \c{.ui} file and a corresponding class to our project. Right click on your + project and select \gui{Add New...}. In the \gui{New File} dialog, select +- \gui{Qt Designer Form}. In the \gui{Qt Designer Form} dialog, select +- \e{Dialog without buttons}. Name it \c{finddialog.ui} and add it to your +- project. The \QD plugin within Qt Creator will now display your new form. ++ \gui{Qt Designer Form Class}. In the \gui{Qt Designer Form Class} dialog, select ++ \e{Dialog without buttons}. Name the class \c{FindDialog} and add the files it to your ++ project. Open your new form in the \QD form editor within Qt Creator by ++ double-clicking on the \c{finddialog.ui} file in the \gui{Project Sidebar}. + + To replicate the screenshot above, we need a label, a line edit, and a push + button. Drag these onto your form. Set their text accordingly and name them +@@ -759,6 +761,9 @@ + \c findContact() function know when the \c FindDialog object has been + closed. We will explain this logic in further detail when discussing the + \c findContact() function. ++ (The above paragraph is not up to date, since clicked() is not connected ++ to accept(). The description of accept() can move below to the implementation ++ of findClicked().) + + \image addressbook-tutorial-part5-signals-and-slots.png + +@@ -766,17 +771,17 @@ + \gui Find button without entering a contact's name. Then, we set + \c findText to the search string, extracted from \c lineEdit. After that, + we clear the contents of \c lineEdit and hide the dialog. ++ (There is no findText member. The description of accept() should move here, together ++ with words about reject.) + + \snippet examples/addressbook-sdk/part5/finddialog.cpp findClicked + +- The \c findText variable has a public getter function, \c getFindText(), +- associated with it. Since we only ever set \c findText directly in both +- the constructor and in hte \c findClicked() function, we do not create a +- setter function to accompany \c getFindText(). Because \c getFindText() is ++ The \c text of the find dialog's line edit has a public getter function, \c findText(), ++ associated with it. Because \c findText() is + public, classes instantiating and using \c FindDialog can always access the + search string that the user has entered and accepted. + +- \snippet examples/addressbook-sdk/part5/finddialog.cpp getFindText ++ \snippet examples/addressbook-sdk/part5/finddialog.cpp findText + + + \section1 The AddressBook Class +@@ -788,23 +793,9 @@ + + So far, all our address book features have a QPushButton and a + corresponding slot. Similarly, for the \gui Find feature, we have +- \c findButton and \c findContact(). ++ \c {ui->findButton} and \c findContact(). + + \snippet examples/addressbook-sdk/part5/addressbook.h slot definition +- \dots +- \snippet examples/addressbook-sdk/part5/addressbook.h private members +- +- Lastly, we declare the private variable, \c dialog, which we will use to +- refer to an instance of \c FindDialog. +- +- Once we have instantiated a dialog, we might want to use it more than once; +- using a private variable allows us to refer to it from more than one place +- in the class. +- +- Within the \c AddressBook class's constructor, we insantiate our private +- objects, \c findButton and \c dialog: +- +- \snippet examples/addressbook-sdk/part5/addressbook.cpp private members + + Next, we connect the \c{findButton}'s \l{QPushButton::}{clicked()} signal + to \c findContact(). +@@ -818,10 +809,12 @@ + We start out by displaying the \c FindDialog instance, \c dialog. This is + when the user enters a contact name to look up. Once the user clicks the + dialog's \c findButton, the dialog is hidden and the result code is set to +- QDialog::Accepted. THis ensures that our \c if statement is always true. ++ either QDialog::Accepted or QDialog::Rejected by the FindDialog's ++ \c findClicked() method. This ensures that we only search for a contact ++ if the user typed something in the FindDialog's line edit. + + We then proceed to extract the search string, which in this case is +- \c contactName, using \c{FindDialog}'s \c getFindText() function. If the ++ \c contactName, using \c{FindDialog}'s \c findText() function. If the + contact exists in our address book, we display it immediately. Otherwise, + we display the QMessageBox shown below to indicate that their search + failed. diff --git a/doc/images/addressbook-tutorial-part5-dialogbox.png b/doc/images/addressbook-tutorial-part5-dialogbox.png new file mode 100644 index 0000000000000000000000000000000000000000..ad7378ccf28fa6c98e73af8ddc75497d651ad01b GIT binary patch literal 6526 zcmeAS@N?(olHy`uVBq!ia0y~yVANt@U?}HcV_;y|63e@Zfq{XsILO_JVcj{ImkbOH zEa{HEjtmSN`?>!lvNA9*C?tCX`7$t6sWC7#v@kIIVqjosc)`F>YQVtoDuIE)Y6b&? zc)^@qfi?^b5`R2h978JN-p);r5PiPw_}=;FcRoM-x8Qwk(iM^9BojAZL(A*JtRguX zZ#;c`bT+#B<~*N~A+oqb*4xMMSkuJ?5ef}WN(qZQJcJ#)IygFxv4vgvy#Kw_jI$PR zZnCBon63G1!@X?X_qqRf-@Cu2{M(r~{~Lao1lRof{(k+Or)MED*#&1ev(Ttig zV@~Ic%asr{4Vp;`*4qP;CVQ-1<*>ElqtTJBV~NSU7Hk%5XGEAA8y!OzEc(*bR^=Y_ z>1G6TA7dY5@KJ}G^F=QS1Tcx7mGQOB-^kiMZGoQH25p~Hr>5+y*yR>}t!Zn)Q3(r) za#Z!WN%y z`KA8z)?J*wH94F_2Hxr zst%3GUY6yY?URdmOtqR%1!V%bqw#Sm9GyQ zgCPCupBzuGXcZfo2T;cPc>Tg^R}{K!b$xXn{#ycg#S){z<*kI!7hEH z6~Di~^O||(fc*4mqgBc$Eye7;=3lX#^0~_Q`t|i||2{2!l`ErrS@3?<%LhI3?yukX z_}|;M?7xYbZcX@mr?!R@7q2j_e)fF7XVay}$NP2Da_4Qk47Gn{yl%kUQ<|+gqE{EZ z+WMpVOYBZI=4)#YEto$o@x`*ELMz_g-~a!}h5SeVR*D74`kvhSBk*vR@C~=&o~t& zU~_KH{+`E~t+SqOuiDJA`qZgYQEsO*_pbe$DGN$%Ti3C!dUEIVgtd>(*=jES^ew*k z`}Oq)9`Je_)|^(V*>cyNDfDTxx}$3R=0({d$AdoW)J?Hl$*lSO>g88oPgU;xeDe2- z>zO}GQ>>%EUb=OETD<$ICBIfVroFxK>J5_-_-Gh&WcsMWEA$$*bnk=GgVn^MINP;x>*tiG$^Hy=a?o>MT@(HFlGb*+(&BA) zrMjmt{>_0~?e3uJ{OZxs?ts~gH%xL|dS#c`il9&H9n2&{4x9acwD`W*gUJVWN^DIx zJJxn)io?_?Q&Kkm{{HUawY9T%R6gGIW$pcsUp|9VK;e|nuQI<@J>4VsddsQpq55l! zUPqa`f4T5DVx^4x>x|XD6|vxO*Aa{KD|h$T&GqzUV@;lA0 zyBw5HuWfah8umdwWq0v+JEm=Kr?%B+1vkGs_xARVy1!QI;&-bxYP~zd3d*{(mYrK1 zvuuue)!bYAWBAuTz4l65e|7fWt$lZ|6|LR$WKG~}3z@tAcin8_FY`xqYw7;E_HG?p zXeWbjuChjIYHDQ9v($=})1z<4$GI(7v}ww&>rA1)TC*p-b^B@i;3M2s#?GSX z?9ZoCxBWTs`pUm6cA0yx8Lj;!dpGX%c4MiPwHAvfZmo*S){YCitUha#7)$@0MXx=q z!qcu!TYvl8k=hUw|Jzx**FQO@21I(T&2H3M{J|AN3d6n9S z>1%fv7`>i!wEvR2|MeHAqc(`G6Jhqg_SP})qiVBTi z^zJ#^mb^*oZ1ak@iCwIneK2ZA63?2yrZR<()(Wvs*M^pQA>1J|#q*nbO&>@+kO(;L zkd(%GEr)0NCRycPP+EL?o$2b$MbQcHLVl}bsi%p6boK$m1BMBUBv!DlTI2l`AuSg0 z_4RfCs>AA`efDb@v=4C2aAiyq+Sn;^wZ}1aTH3>^4NPkqf*9FEk28ZL;~3edzMS2m zeS&KP6OUFOV_1Wz!CodFt;^!py|QxBMHAh{ zrCWG&Ps@YUvwAeLF<#wS{Cq?9bH5*F=Jz)=FdR8{Oi5jx{rZvJSLN+$G$eg58%4R_ zzOZcz|68!8j9Xk1T&q@xuUE3LkofoSUq@#rQzgp_$_Cv96=n-TxX@$;WV)`-SsD;p9QoD$pbva#-Om5ZB;$IYOc zL!K^2mLw;8a6bE2BY63mNYbZM+!Fi0*c|)yG;vG5*fAZCqbn*oXBfO^c&2}|=S1_x zOZ%QQ*G%+ZY=3r^X>*R-^whKVQ+?%s?zhPe**oQ_#_Qy@a@Vfe^Y&i(WwX}mMc}$= z|9C5Vw!I3to_yu@a>WH+-rk32U0pqK;>5;3pPv^RJQFedQz&b^U;o&VsY@lcKQeOD z*FLPiZ>faIccDG|^^PpCWR>`rYu9%6H`HStc z3crfoo>-OLcxqzp>rK9~j-k^x&AIzL^Tqod+1I;mn@<_Cma>bc+OkYJbjWFrh`ryg z_W|2ZEbuZ&tTa5Pv%4vp_3p#qxcaNyZ+?I7xt=5%KKL}iT+$>)UzusRr~M;GnJ5L*X(_Eht=FS z%dLI5aFgG*O>XH263+H3f8DaJcWagQ^vt))*;%iDT)CaGwb}OVnx7j@ZLWP%=YN?q zb@|fvDvJzVxvBrI9$%IITjT47tNK?;%XqxEZoecNQgU(jI`xYM`NaW3%hu=|IN{pL zbYkoCSQ29C93h2hwR$YBKKEGs}Eo}w+tw_~E55dD!D@z3e@4yi zoy#xg)(HJGG-LcPA>97m&HZrknY=T<%C?5EO-+5Wmb;22Jl1OK)?=H>)wYy9D_Qoh zlvAzRVEa@@t6=l!50_6(lexHhUFn9c^LMS=W~A(%bU03S?a%9{5^}a~G*;)XE)7bL z`lj&iMb%vg*Y7qL-?A8PbpP=7S4q!|`Mr+!pCn$m{!`*dsocHkz6@Ch-o#Y+TDNc9 zXX$ZnPZRg_b&0tSLc98`nEE|m7R**q__}k3{N#>u_v4T6p6`1+*FWiE=@Z6^+Fg=~ zzm=D6TH&K?|JC-fl~7OLmHQL>(sjFwmMGsobt>oT*_p=M<75wpZA;|t`F3le;_Kz% zk>C9E{1?|=5!f8=?w%BX&rLkwV(gQWX0=%JsEv8nZu+N=9H^h``akmdk=DY(!a4uK zqwmkW`NCLPy0*1+_JqcAJ7EJU$>wwNa|I6D7(SUjrR&{e|HpebGKDM_{_t*j;R~Zr z7Wd=?wciNb`<-HbtafXNR`;nZpZUtxDy+&bh&){~CsRiEf(4gC`nF=T74zKOSLm-u znQ{9x+ty8NrdMRo2EBT8J}&axt=E}b`nNtVSthsbSDW5~MecDg@;+^TPmj zc@f6NK81mE^m@`mZ%2NarS@jE&zE0D!nXTQIK+RvADwgAU+2BP-h$oz{%*$~8on@4 z;mW<=f8g}r!xxw3OWdkxf0X*ZV2_mo&)oJmjmO(xPn&k-qp}G@BCu-_%fDv2an&EalZfZ_K5La z=GM0^#k0z|U5X9=ubEM|@OfFur+<>K>u)tFyZ3pVXWMn?cwBmEYjOrpX~{E|ixPd? zH_9~YEm+jv`O?yM|5Ry%f?tM=i&GdEiR`FX)a&9d7C*dG%KPwrch!ZDH)JfCW7m7- z$z-8|E`8C5z4y95O!vF}Va;zj#-$1;XYGC~7G~;u?Ub^>+p7E{OESBc7_H0+|6x(A zR@VBs@T!&3ikQt$OBhA>{%qLSIoq(@_E&ACPfhZ4m38*2-T7~`*8FY}DZHyGxt`lW zuw&lmJMEK~`#n7JF~Y^oZPAM)MXPGT6?K!ZnZMU#_}apmQOfV+Ju!6a*IPYx@^!jX zJyU1@Tx@#9pm?ry^4%S>F}p)c8AbOlYrWTCPkgP_qB5U>ym|!ZZA_mx|a3O zk=Bpf?d%%GtJ}S9UNmO1SXqn!PvUp6`KIoWc)Y zZIjl$Q?}6e{MrI(19z>-r=Ia^AK)^{V=ZC5xr=1(VwA;?G2}e&0B;;`!yp71d8TO9Z!zZIKsIb?jnr zz2Q1Ev9dcAM|-`lPKD&B7nDEX-pb?0*l%Ud?tHBBMsYng&VuN|tL z&lK`eXvMd8ceUj#mi3$xuYbEExIrt1L5oLs)!UnS3zO_Z&agkWoY=ed{Z`ib{@)5$ zcE9|Zul4N!mq{$x{OUu?bgduQ6-{rr;<(4mLTK#~)?y>cAYIlaQ9IbV1KtW>U-8Xb zGIWN-uh#bW$CrAyRvgYY{I_|r#J!!a3sSc;C(Tgr`RBbYUWfZAw~})9>yN_w{ugfc zzB}(iiE~f?9MKi~nRYdJ?R#jf{FrBt`~Rlxb^;DBg>@8E*Q9Sav7)7t#d|{5Lpdb} z(WYy0>`Ssk+86V698XLt+__|jR0vZ}USP)6*py_kZjsA^NjK~ETq@?bs@5}q({}!s z_bIsu#xRF`kT*UF&eAlVzUcD-*+)q~^InRvaE34i>9Q_3!4Y!SHSNkRZK0JbH6NY( zwD^*C;<`B9!?XAP`LMlDG2^M2@&b|A-1ejOo18P=Zj_g;Voy3EA^%cv7OS1zE<2~i z+jqR_7foRO66hcv5E%NTebV9Y?h8);&c3+q{rif0#rpFmJA|@oa)#tR5@RiV`_h$h z)tNOpbI$s>9{kBP<^HZl^J@Kr_v82ve}3nFWUI!eh?Dc)%QcJN;d>mq-k{{oM!v*{ z6EDsE;ATH%P5+TMt)dC6uU0qYEeP88EcMkH*NVOG)waA8RoSFvIh#v#0hjRMT?LG* z{#INx7Gh;}-4PYm)zx+T(5a8xSXLG6c~K{Ge)q|;kTb_0J)Ot?F>QbBj2~Agu~nY+ zu5Eq#HnbtJOalPQudb+w}@#5r*$uE@lTvKPzzbJ4)S>!xtz}BLE zf%^|+MXt|L5|o^+DCf0L`wibC|EG%=A5Z!dzTAUx6$|4^i#<;Ynbubw>+sPExzo8X zWKY)*mUD9~lV7av_$n~97Su4`2eM<;tWU>flal%tyl4M>l=Xvdg)0wp{2M_nqm|5$ zq(o|0i}!A~nSLnyLir2J0>L}K^yJ%MRFT;6pzN?)>*n)}L7ZxnYdJ^^NAt)6%av7}P5t?>)6VsZ8 zIxd41UoKAqrw-!8Gn!T{Sm3aytrgOdtoUWPfOFMsb6CgHz?sKjg~W*(r$-V7wLAtZ zEIfSWm!w%NE|#5_mv(YNQh?zK3pO8lW*#lRpv&x<>Bj!%vkja7@o2G$Hg_c-_+ofq z!6OCJ+6l8B_M9uN*cB<;+~s(50kUCp&f46~ImYwLc!fj=j}~)Mg7+6mp3n9j>pnZ* zSY@hU>oI*-L%(CH!-Q)~6)WZ+n{1lXb;@D6sr$#Q8dj_MKh2}JvMphM>GaD&`aO>p z+tkaBk8>uNZhgzXzRP8I%k3EvFkCT*Pb$56&C1;MELW%Ao|>@wQiJ2s4T(2qXs~5D z9Gwv4RF$2nnjYf&cFo!2+4s8Nhc2k<(Or~0?QY$L1=rR@8lPCEH+!1(rZX$7Cd)11 z=Kt$c5|%n)hPaB`cHYt>ev6#*wAQ&~9&KhbW}3LkCjEKuI_;N^y9`!HgxIi{IPz#X zhAKH+6>tmK6xLU?^ID1XmHtx+0W%dWdhNV7*Iz$*Atm5%)E|bUPkEDB6thz`r=PwY zbz3Sn{8F>AR-0&guv#Z0Q|Rw4?h#Y##ZN9RmpZ~>ckNV=-t_gcrXh2$Je>e>lF*7d ze|PwOOLmE#DH+1Tue(B$*MLowxofkg@KJ`wRk5#}*PPhhyyVes-Xs=zkS*E1<{`44 z{FhpdwS-w$3#Mm%dnq+@7SF1uJIf~&tXy=k$6<-i`J0uCUwc&Y3Ew@YTypRV?M+p@Vl`=UkNn`8hpAjWgt2O^otq!&P%%94%PefA`RXFV!DT?l~E@ zmhq+H%R~C-vTw;AS{s&(I@l`=>vCdU+~X{~xWSbIU4Tq%V^A@if4SZC%F$ z`LcjNJ6K;j?z-~y$npFiCV>Ulmoiq$Ki?#K?X>AvP~Lb|()O6|{Vdsgp|^V-k1j|G zDCC)8$0iXXvt${6Q21G<9ru2v&c(m@=jp2v?`xkwRw4AfzJOcv* NgQu&X%Q~loCIISId0qej literal 0 HcmV?d00001 diff --git a/doc/images/addressbook-tutorial-part5-finddialog-in-designer.png b/doc/images/addressbook-tutorial-part5-finddialog-in-designer.png new file mode 100644 index 0000000000000000000000000000000000000000..2ffa61e36dfeadf221fc0fd7381d67a8f3807c1a GIT binary patch literal 98226 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 literal 0 HcmV?d00001 diff --git a/doc/images/addressbook-tutorial-part5-screenshot.png b/doc/images/addressbook-tutorial-part5-screenshot.png new file mode 100644 index 0000000000000000000000000000000000000000..f9c1e6ff7f196e77bc52b649448d4357c617b3d6 GIT binary patch literal 9948 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 literal 0 HcmV?d00001 diff --git a/doc/images/addressbook-tutorial-part6-opendialog.png b/doc/images/addressbook-tutorial-part6-opendialog.png new file mode 100644 index 0000000000000000000000000000000000000000..4f281faca5b9934eba060ab32d21c4b497145261 GIT binary patch literal 55036 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 literal 0 HcmV?d00001 diff --git a/doc/images/addressbook-tutorial-part6-propertyeditor.png b/doc/images/addressbook-tutorial-part6-propertyeditor.png new file mode 100644 index 0000000000000000000000000000000000000000..949c0be68d2107ae69008146bf4d3c832f7c1e0b GIT binary patch literal 18467 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 Bb6EfY literal 0 HcmV?d00001 diff --git a/doc/images/addressbook-tutorial-part6-savedialog.png b/doc/images/addressbook-tutorial-part6-savedialog.png new file mode 100644 index 0000000000000000000000000000000000000000..0c1b0bbbdeff90adaf2af2204952c288f196a4c0 GIT binary patch literal 16166 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 J);T3K0RWy})QkWC literal 0 HcmV?d00001 diff --git a/doc/images/addressbook-tutorial-part6-screenshot.png b/doc/images/addressbook-tutorial-part6-screenshot.png new file mode 100644 index 0000000000000000000000000000000000000000..39c33a77f0c1aa11137a1170a9796990580a1e49 GIT binary patch literal 11329 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 literal 0 HcmV?d00001 diff --git a/doc/images/addressbook-tutorial-part7-screenshot.png b/doc/images/addressbook-tutorial-part7-screenshot.png new file mode 100644 index 0000000000000000000000000000000000000000..e2f0cf47c099105bbe530e165dbd6bcb88c8f73c GIT binary patch literal 15248 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 literal 0 HcmV?d00001 From 264463283a2a73ad12c23b5568461cce3f9f91c7 Mon Sep 17 00:00:00 2001 From: hjk Date: Mon, 12 Oct 2009 15:22:11 +0200 Subject: [PATCH 18/34] debugger: remove debug output --- src/plugins/debugger/watchutils.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/debugger/watchutils.cpp b/src/plugins/debugger/watchutils.cpp index a351f34ced7..e8f51d0d424 100644 --- a/src/plugins/debugger/watchutils.cpp +++ b/src/plugins/debugger/watchutils.cpp @@ -433,7 +433,7 @@ QString decodeData(const QByteArray &ba, int encoding) } case 7: { // %04x endoded 16 bit data const QByteArray decodedBa = QByteArray::fromHex(ba); - qDebug() << quoteUnprintableLatin1(decodedBa) << "\n\n"; + //qDebug() << quoteUnprintableLatin1(decodedBa) << "\n\n"; return QString::fromUtf16(reinterpret_cast (decodedBa.data()), decodedBa.size() / 2); } From 71d1f3eeba237c070919060e68cc348487591587 Mon Sep 17 00:00:00 2001 From: con Date: Mon, 12 Oct 2009 17:50:26 +0200 Subject: [PATCH 19/34] Update changes file --- dist/changes-1.3.0 | 3 +++ 1 file changed, 3 insertions(+) diff --git a/dist/changes-1.3.0 b/dist/changes-1.3.0 index ecec4ad3784..fd55ce90a72 100644 --- a/dist/changes-1.3.0 +++ b/dist/changes-1.3.0 @@ -103,6 +103,9 @@ Platform Specific Mac * Make use of system's language settings +Symbian Target + * Preliminary support for targeting Qt for Symbian applications + Additional credits go to: * Christian Hoenig (Locator filter for symbols in current document) * Henrik Abelsson (Configure what to do with externally modified files) From 5523c77eacee95345f2913c240c3c82a4cb9c7e6 Mon Sep 17 00:00:00 2001 From: hjk Date: Mon, 12 Oct 2009 18:28:48 +0200 Subject: [PATCH 20/34] fix a few license headers --- src/plugins/qmleditor/parser/qmljs.g | 119 ++++++------------ src/plugins/qmleditor/parser/qmljsast.cpp | 38 ++---- src/plugins/qmleditor/parser/qmljsast_p.h | 38 ++---- src/plugins/qmleditor/parser/qmljsastfwd_p.h | 38 ++---- .../qmleditor/parser/qmljsastvisitor.cpp | 40 +++--- .../qmleditor/parser/qmljsastvisitor_p.h | 40 +++--- .../qmleditor/parser/qmljsengine_p.cpp | 38 ++---- src/plugins/qmleditor/parser/qmljsengine_p.h | 40 +++--- src/plugins/qmleditor/parser/qmljslexer.cpp | 40 +++--- src/plugins/qmleditor/parser/qmljslexer_p.h | 40 +++--- .../qmleditor/parser/qmljsmemorypool_p.h | 38 ++---- .../qmleditor/parser/qmljsnodepool_p.h | 40 +++--- src/plugins/qmleditor/parser/qmljsparser.cpp | 38 ++---- src/plugins/qmleditor/parser/qmljsparser_p.h | 38 ++---- .../qt4projectmanager/qt-s60/s60manager.cpp | 4 +- .../qt4projectmanager/qt-s60/s60manager.h | 4 +- 16 files changed, 219 insertions(+), 414 deletions(-) diff --git a/src/plugins/qmleditor/parser/qmljs.g b/src/plugins/qmleditor/parser/qmljs.g index 211887b4f48..8531ed51079 100644 --- a/src/plugins/qmleditor/parser/qmljs.g +++ b/src/plugins/qmleditor/parser/qmljs.g @@ -1,18 +1,20 @@ ---------------------------------------------------------------------------- -- --- Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). --- Contact: Qt Software Information (qt-info@nokia.com) +-- This file is part of Qt Creator -- --- This file is part of the QtDeclarative module of the Qt Toolkit. +-- Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). -- --- $QT_BEGIN_LICENSE:LGPL$ --- No Commercial Usage --- This file contains pre-release code and may not be distributed. --- You may use this file in accordance with the terms and conditions --- contained in the either Technology Preview License Agreement or the --- Beta Release License Agreement. +-- Contact: Nokia Corporation (qt-info@nokia.com) +-- +-- Commercial Usage +-- +-- Licensees holding valid Qt Commercial licenses may use this file in +-- accordance with the Qt Commercial License Agreement provided with the +-- Software or, alternatively, in accordance with the terms contained in +-- a written agreement between you and Nokia. -- -- GNU Lesser General Public License Usage +-- -- Alternatively, this file may be used under the terms of the GNU Lesser -- General Public License version 2.1 as published by the Free Software -- Foundation and appearing in the file LICENSE.LGPL included in the @@ -20,25 +22,8 @@ -- 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. -- --- In addition, as a special exception, Nokia gives you certain --- additional rights. These rights are described in the Nokia Qt LGPL --- Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this --- package. --- --- GNU General Public License Usage --- Alternatively, this file may be used under the terms of the GNU --- General Public License version 3.0 as published by the Free Software --- Foundation and appearing in the file LICENSE.GPL included in the --- packaging of this file. Please review the following information to --- ensure the GNU General Public License version 3.0 requirements will be --- met: http://www.gnu.org/copyleft/gpl.html. --- -- If you are unsure which license is appropriate for your use, please --- contact the sales department at qt-sales@nokia.com. --- $QT_END_LICENSE$ --- --- This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE --- WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +-- contact the sales department at http://qt.nokia.com/contact. -- ---------------------------------------------------------------------------- @@ -100,21 +85,23 @@ %start TopLevel /. -/**************************************************************************** +/************************************************************************** ** -** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). -** Contact: Qt Software Information (qt-info@nokia.com) +** This file is part of Qt Creator ** -** This file is part of the QtScript module of the Qt Toolkit. +** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). ** -** $QT_BEGIN_LICENSE:LGPL$ -** No Commercial Usage -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the either Technology Preview License Agreement or the -** Beta Release License Agreement. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** Commercial Usage +** +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. ** ** GNU Lesser General Public License Usage +** ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL included in the @@ -122,24 +109,10 @@ ** 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. ** -** In addition, as a special exception, Nokia gives you certain -** additional rights. These rights are described in the Nokia Qt LGPL -** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this -** package. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3.0 as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU General Public License version 3.0 requirements will be -** met: http://www.gnu.org/copyleft/gpl.html. -** ** If you are unsure which license is appropriate for your use, please -** contact the sales department at qt-sales@nokia.com. -** $QT_END_LICENSE$ +** contact the sales department at http://qt.nokia.com/contact. ** -****************************************************************************/ +**************************************************************************/ #include @@ -153,21 +126,23 @@ ./ /: -/**************************************************************************** +/************************************************************************** ** -** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). -** Contact: Qt Software Information (qt-info@nokia.com) +** This file is part of Qt Creator ** -** This file is part of the QtScript module of the Qt Toolkit. +** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). ** -** $QT_BEGIN_LICENSE:LGPL$ -** No Commercial Usage -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the either Technology Preview License Agreement or the -** Beta Release License Agreement. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** Commercial Usage +** +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. ** ** GNU Lesser General Public License Usage +** ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL included in the @@ -175,24 +150,10 @@ ** 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. ** -** In addition, as a special exception, Nokia gives you certain -** additional rights. These rights are described in the Nokia Qt LGPL -** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this -** package. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3.0 as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU General Public License version 3.0 requirements will be -** met: http://www.gnu.org/copyleft/gpl.html. -** ** If you are unsure which license is appropriate for your use, please -** contact the sales department at qt-sales@nokia.com. -** $QT_END_LICENSE$ +** contact the sales department at http://qt.nokia.com/contact. ** -****************************************************************************/ +**************************************************************************/ // // W A R N I N G diff --git a/src/plugins/qmleditor/parser/qmljsast.cpp b/src/plugins/qmleditor/parser/qmljsast.cpp index 4c45bc89d9e..ec199e80ae7 100644 --- a/src/plugins/qmleditor/parser/qmljsast.cpp +++ b/src/plugins/qmleditor/parser/qmljsast.cpp @@ -1,18 +1,20 @@ /**************************************************************************** ** -** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). -** Contact: Qt Software Information (qt-info@nokia.com) +** This file is part of Qt Creator ** -** This file is part of the QtScript module of the Qt Toolkit. +** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). ** -** $QT_BEGIN_LICENSE:LGPL$ -** No Commercial Usage -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the either Technology Preview License Agreement or the -** Beta Release License Agreement. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** Commercial Usage +** +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. ** ** GNU Lesser General Public License Usage +** ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL included in the @@ -20,24 +22,10 @@ ** 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. ** -** In addition, as a special exception, Nokia gives you certain -** additional rights. These rights are described in the Nokia Qt LGPL -** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this -** package. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3.0 as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU General Public License version 3.0 requirements will be -** met: http://www.gnu.org/copyleft/gpl.html. -** ** If you are unsure which license is appropriate for your use, please -** contact the sales department at qt-sales@nokia.com. -** $QT_END_LICENSE$ +** contact the sales department at http://qt.nokia.com/contact. ** -****************************************************************************/ +**************************************************************************/ #include "qmljsast_p.h" #include "qmljsastvisitor_p.h" diff --git a/src/plugins/qmleditor/parser/qmljsast_p.h b/src/plugins/qmleditor/parser/qmljsast_p.h index ef8a66bd949..94a26096ee2 100644 --- a/src/plugins/qmleditor/parser/qmljsast_p.h +++ b/src/plugins/qmleditor/parser/qmljsast_p.h @@ -1,18 +1,20 @@ /**************************************************************************** ** -** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). -** Contact: Qt Software Information (qt-info@nokia.com) +** This file is part of Qt Creator ** -** This file is part of the QtDeclarative module of the Qt Toolkit. +** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). ** -** $QT_BEGIN_LICENSE:LGPL$ -** No Commercial Usage -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the either Technology Preview License Agreement or the -** Beta Release License Agreement. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** Commercial Usage +** +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. ** ** GNU Lesser General Public License Usage +** ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL included in the @@ -20,24 +22,10 @@ ** 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. ** -** In addition, as a special exception, Nokia gives you certain -** additional rights. These rights are described in the Nokia Qt LGPL -** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this -** package. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3.0 as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU General Public License version 3.0 requirements will be -** met: http://www.gnu.org/copyleft/gpl.html. -** ** If you are unsure which license is appropriate for your use, please -** contact the sales department at qt-sales@nokia.com. -** $QT_END_LICENSE$ +** contact the sales department at http://qt.nokia.com/contact. ** -****************************************************************************/ +**************************************************************************/ #ifndef QMLJSAST_P_H #define QMLJSAST_P_H diff --git a/src/plugins/qmleditor/parser/qmljsastfwd_p.h b/src/plugins/qmleditor/parser/qmljsastfwd_p.h index fcb97ad870a..dd164e9e3c8 100644 --- a/src/plugins/qmleditor/parser/qmljsastfwd_p.h +++ b/src/plugins/qmleditor/parser/qmljsastfwd_p.h @@ -1,18 +1,20 @@ /**************************************************************************** ** -** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). -** Contact: Qt Software Information (qt-info@nokia.com) +** This file is part of Qt Creator ** -** This file is part of the QtScript module of the Qt Toolkit. +** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). ** -** $QT_BEGIN_LICENSE:LGPL$ -** No Commercial Usage -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the either Technology Preview License Agreement or the -** Beta Release License Agreement. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** Commercial Usage +** +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. ** ** GNU Lesser General Public License Usage +** ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL included in the @@ -20,24 +22,10 @@ ** 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. ** -** In addition, as a special exception, Nokia gives you certain -** additional rights. These rights are described in the Nokia Qt LGPL -** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this -** package. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3.0 as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU General Public License version 3.0 requirements will be -** met: http://www.gnu.org/copyleft/gpl.html. -** ** If you are unsure which license is appropriate for your use, please -** contact the sales department at qt-sales@nokia.com. -** $QT_END_LICENSE$ +** contact the sales department at http://qt.nokia.com/contact. ** -****************************************************************************/ +**************************************************************************/ #ifndef QMLJSAST_FWD_P_H #define QMLJSAST_FWD_P_H diff --git a/src/plugins/qmleditor/parser/qmljsastvisitor.cpp b/src/plugins/qmleditor/parser/qmljsastvisitor.cpp index d3a1d530682..6a0d55a4f16 100644 --- a/src/plugins/qmleditor/parser/qmljsastvisitor.cpp +++ b/src/plugins/qmleditor/parser/qmljsastvisitor.cpp @@ -1,18 +1,20 @@ -/**************************************************************************** +/************************************************************************** ** -** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). -** Contact: Qt Software Information (qt-info@nokia.com) +** This file is part of Qt Creator ** -** This file is part of the QtScript module of the Qt Toolkit. +** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). ** -** $QT_BEGIN_LICENSE:LGPL$ -** No Commercial Usage -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the either Technology Preview License Agreement or the -** Beta Release License Agreement. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** Commercial Usage +** +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. ** ** GNU Lesser General Public License Usage +** ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL included in the @@ -20,24 +22,10 @@ ** 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. ** -** In addition, as a special exception, Nokia gives you certain -** additional rights. These rights are described in the Nokia Qt LGPL -** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this -** package. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3.0 as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU General Public License version 3.0 requirements will be -** met: http://www.gnu.org/copyleft/gpl.html. -** ** If you are unsure which license is appropriate for your use, please -** contact the sales department at qt-sales@nokia.com. -** $QT_END_LICENSE$ +** contact the sales department at http://qt.nokia.com/contact. ** -****************************************************************************/ +**************************************************************************/ #include "qmljsastvisitor_p.h" diff --git a/src/plugins/qmleditor/parser/qmljsastvisitor_p.h b/src/plugins/qmleditor/parser/qmljsastvisitor_p.h index eea492a0572..09714ee0a0a 100644 --- a/src/plugins/qmleditor/parser/qmljsastvisitor_p.h +++ b/src/plugins/qmleditor/parser/qmljsastvisitor_p.h @@ -1,18 +1,20 @@ -/**************************************************************************** +/************************************************************************** ** -** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). -** Contact: Qt Software Information (qt-info@nokia.com) +** This file is part of Qt Creator ** -** This file is part of the QtScript module of the Qt Toolkit. +** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). ** -** $QT_BEGIN_LICENSE:LGPL$ -** No Commercial Usage -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the either Technology Preview License Agreement or the -** Beta Release License Agreement. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** Commercial Usage +** +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. ** ** GNU Lesser General Public License Usage +** ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL included in the @@ -20,24 +22,10 @@ ** 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. ** -** In addition, as a special exception, Nokia gives you certain -** additional rights. These rights are described in the Nokia Qt LGPL -** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this -** package. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3.0 as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU General Public License version 3.0 requirements will be -** met: http://www.gnu.org/copyleft/gpl.html. -** ** If you are unsure which license is appropriate for your use, please -** contact the sales department at qt-sales@nokia.com. -** $QT_END_LICENSE$ +** contact the sales department at http://qt.nokia.com/contact. ** -****************************************************************************/ +**************************************************************************/ #ifndef QMLJSASTVISITOR_P_H #define QMLJSASTVISITOR_P_H diff --git a/src/plugins/qmleditor/parser/qmljsengine_p.cpp b/src/plugins/qmleditor/parser/qmljsengine_p.cpp index 7d4d6d7695d..6e7a45a5065 100644 --- a/src/plugins/qmleditor/parser/qmljsengine_p.cpp +++ b/src/plugins/qmleditor/parser/qmljsengine_p.cpp @@ -1,18 +1,20 @@ /**************************************************************************** ** -** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). -** Contact: Qt Software Information (qt-info@nokia.com) +** This file is part of Qt Creator ** -** This file is part of the QtDeclarative module of the Qt Toolkit. +** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). ** -** $QT_BEGIN_LICENSE:LGPL$ -** No Commercial Usage -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the either Technology Preview License Agreement or the -** Beta Release License Agreement. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** Commercial Usage +** +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. ** ** GNU Lesser General Public License Usage +** ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL included in the @@ -20,24 +22,10 @@ ** 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. ** -** In addition, as a special exception, Nokia gives you certain -** additional rights. These rights are described in the Nokia Qt LGPL -** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this -** package. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3.0 as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU General Public License version 3.0 requirements will be -** met: http://www.gnu.org/copyleft/gpl.html. -** ** If you are unsure which license is appropriate for your use, please -** contact the sales department at qt-sales@nokia.com. -** $QT_END_LICENSE$ +** contact the sales department at http://qt.nokia.com/contact. ** -****************************************************************************/ +**************************************************************************/ #include "qmljsglobal_p.h" #include "qmljsengine_p.h" diff --git a/src/plugins/qmleditor/parser/qmljsengine_p.h b/src/plugins/qmleditor/parser/qmljsengine_p.h index 8627a990243..98e71c88790 100644 --- a/src/plugins/qmleditor/parser/qmljsengine_p.h +++ b/src/plugins/qmleditor/parser/qmljsengine_p.h @@ -1,18 +1,20 @@ -/**************************************************************************** +/************************************************************************** ** -** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). -** Contact: Qt Software Information (qt-info@nokia.com) +** This file is part of Qt Creator ** -** This file is part of the QtDeclarative module of the Qt Toolkit. +** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). ** -** $QT_BEGIN_LICENSE:LGPL$ -** No Commercial Usage -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the either Technology Preview License Agreement or the -** Beta Release License Agreement. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** Commercial Usage +** +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. ** ** GNU Lesser General Public License Usage +** ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL included in the @@ -20,24 +22,10 @@ ** 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. ** -** In addition, as a special exception, Nokia gives you certain -** additional rights. These rights are described in the Nokia Qt LGPL -** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this -** package. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3.0 as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU General Public License version 3.0 requirements will be -** met: http://www.gnu.org/copyleft/gpl.html. -** ** If you are unsure which license is appropriate for your use, please -** contact the sales department at qt-sales@nokia.com. -** $QT_END_LICENSE$ +** contact the sales department at http://qt.nokia.com/contact. ** -****************************************************************************/ +**************************************************************************/ #ifndef QMLJSENGINE_P_H #define QMLJSENGINE_P_H diff --git a/src/plugins/qmleditor/parser/qmljslexer.cpp b/src/plugins/qmleditor/parser/qmljslexer.cpp index f71b92f0fdb..a52ea7c0896 100644 --- a/src/plugins/qmleditor/parser/qmljslexer.cpp +++ b/src/plugins/qmleditor/parser/qmljslexer.cpp @@ -1,18 +1,20 @@ -/**************************************************************************** +/************************************************************************** ** -** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). -** Contact: Qt Software Information (qt-info@nokia.com) +** This file is part of Qt Creator ** -** This file is part of the QtDeclarative module of the Qt Toolkit. +** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). ** -** $QT_BEGIN_LICENSE:LGPL$ -** No Commercial Usage -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the either Technology Preview License Agreement or the -** Beta Release License Agreement. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** Commercial Usage +** +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. ** ** GNU Lesser General Public License Usage +** ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL included in the @@ -20,24 +22,10 @@ ** 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. ** -** In addition, as a special exception, Nokia gives you certain -** additional rights. These rights are described in the Nokia Qt LGPL -** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this -** package. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3.0 as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU General Public License version 3.0 requirements will be -** met: http://www.gnu.org/copyleft/gpl.html. -** ** If you are unsure which license is appropriate for your use, please -** contact the sales department at qt-sales@nokia.com. -** $QT_END_LICENSE$ +** contact the sales department at http://qt.nokia.com/contact. ** -****************************************************************************/ +**************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" diff --git a/src/plugins/qmleditor/parser/qmljslexer_p.h b/src/plugins/qmleditor/parser/qmljslexer_p.h index 50f7c4b279d..1be466c3e62 100644 --- a/src/plugins/qmleditor/parser/qmljslexer_p.h +++ b/src/plugins/qmleditor/parser/qmljslexer_p.h @@ -1,18 +1,20 @@ -/**************************************************************************** +/************************************************************************** ** -** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). -** Contact: Qt Software Information (qt-info@nokia.com) +** This file is part of Qt Creator ** -** This file is part of the QtScript module of the Qt Toolkit. +** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). ** -** $QT_BEGIN_LICENSE:LGPL$ -** No Commercial Usage -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the either Technology Preview License Agreement or the -** Beta Release License Agreement. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** Commercial Usage +** +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. ** ** GNU Lesser General Public License Usage +** ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL included in the @@ -20,24 +22,10 @@ ** 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. ** -** In addition, as a special exception, Nokia gives you certain -** additional rights. These rights are described in the Nokia Qt LGPL -** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this -** package. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3.0 as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU General Public License version 3.0 requirements will be -** met: http://www.gnu.org/copyleft/gpl.html. -** ** If you are unsure which license is appropriate for your use, please -** contact the sales department at qt-sales@nokia.com. -** $QT_END_LICENSE$ +** contact the sales department at http://qt.nokia.com/contact. ** -****************************************************************************/ +**************************************************************************/ #ifndef QMLJSLEXER_P_H #define QMLJSLEXER_P_H diff --git a/src/plugins/qmleditor/parser/qmljsmemorypool_p.h b/src/plugins/qmleditor/parser/qmljsmemorypool_p.h index 70e77371127..4b79f174fb0 100644 --- a/src/plugins/qmleditor/parser/qmljsmemorypool_p.h +++ b/src/plugins/qmleditor/parser/qmljsmemorypool_p.h @@ -1,18 +1,20 @@ /**************************************************************************** ** -** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). -** Contact: Qt Software Information (qt-info@nokia.com) +** This file is part of Qt Creator ** -** This file is part of the QtDeclarative module of the Qt Toolkit. +** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). ** -** $QT_BEGIN_LICENSE:LGPL$ -** No Commercial Usage -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the either Technology Preview License Agreement or the -** Beta Release License Agreement. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** Commercial Usage +** +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. ** ** GNU Lesser General Public License Usage +** ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL included in the @@ -20,24 +22,10 @@ ** 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. ** -** In addition, as a special exception, Nokia gives you certain -** additional rights. These rights are described in the Nokia Qt LGPL -** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this -** package. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3.0 as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU General Public License version 3.0 requirements will be -** met: http://www.gnu.org/copyleft/gpl.html. -** ** If you are unsure which license is appropriate for your use, please -** contact the sales department at qt-sales@nokia.com. -** $QT_END_LICENSE$ +** contact the sales department at http://qt.nokia.com/contact. ** -****************************************************************************/ +**************************************************************************/ #ifndef QMLJSMEMORYPOOL_P_H #define QMLJSMEMORYPOOL_P_H diff --git a/src/plugins/qmleditor/parser/qmljsnodepool_p.h b/src/plugins/qmleditor/parser/qmljsnodepool_p.h index dfe3bac4652..ba0c3678efd 100644 --- a/src/plugins/qmleditor/parser/qmljsnodepool_p.h +++ b/src/plugins/qmleditor/parser/qmljsnodepool_p.h @@ -1,18 +1,20 @@ -/**************************************************************************** +/************************************************************************** ** -** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). -** Contact: Qt Software Information (qt-info@nokia.com) +** This file is part of Qt Creator ** -** This file is part of the QtDeclarative module of the Qt Toolkit. +** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). ** -** $QT_BEGIN_LICENSE:LGPL$ -** No Commercial Usage -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the either Technology Preview License Agreement or the -** Beta Release License Agreement. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** Commercial Usage +** +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. ** ** GNU Lesser General Public License Usage +** ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL included in the @@ -20,24 +22,10 @@ ** 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. ** -** In addition, as a special exception, Nokia gives you certain -** additional rights. These rights are described in the Nokia Qt LGPL -** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this -** package. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3.0 as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU General Public License version 3.0 requirements will be -** met: http://www.gnu.org/copyleft/gpl.html. -** ** If you are unsure which license is appropriate for your use, please -** contact the sales department at qt-sales@nokia.com. -** $QT_END_LICENSE$ +** contact the sales department at http://qt.nokia.com/contact. ** -****************************************************************************/ +**************************************************************************/ #ifndef QMLJSNODEPOOL_P_H #define QMLJSNODEPOOL_P_H diff --git a/src/plugins/qmleditor/parser/qmljsparser.cpp b/src/plugins/qmleditor/parser/qmljsparser.cpp index e805ce5b6fc..f5fab00f4cc 100644 --- a/src/plugins/qmleditor/parser/qmljsparser.cpp +++ b/src/plugins/qmleditor/parser/qmljsparser.cpp @@ -2,19 +2,21 @@ /**************************************************************************** ** -** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). -** Contact: Qt Software Information (qt-info@nokia.com) +** This file is part of Qt Creator ** -** This file is part of the QtScript module of the Qt Toolkit. +** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). ** -** $QT_BEGIN_LICENSE:LGPL$ -** No Commercial Usage -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the either Technology Preview License Agreement or the -** Beta Release License Agreement. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** Commercial Usage +** +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. ** ** GNU Lesser General Public License Usage +** ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL included in the @@ -22,24 +24,10 @@ ** 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. ** -** In addition, as a special exception, Nokia gives you certain -** additional rights. These rights are described in the Nokia Qt LGPL -** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this -** package. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3.0 as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU General Public License version 3.0 requirements will be -** met: http://www.gnu.org/copyleft/gpl.html. -** ** If you are unsure which license is appropriate for your use, please -** contact the sales department at qt-sales@nokia.com. -** $QT_END_LICENSE$ +** contact the sales department at http://qt.nokia.com/contact. ** -****************************************************************************/ +**************************************************************************/ #include diff --git a/src/plugins/qmleditor/parser/qmljsparser_p.h b/src/plugins/qmleditor/parser/qmljsparser_p.h index b35bec32b38..7ee69a57d56 100644 --- a/src/plugins/qmleditor/parser/qmljsparser_p.h +++ b/src/plugins/qmleditor/parser/qmljsparser_p.h @@ -2,19 +2,21 @@ /**************************************************************************** ** -** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). -** Contact: Qt Software Information (qt-info@nokia.com) +** This file is part of Qt Creator ** -** This file is part of the QtScript module of the Qt Toolkit. +** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). ** -** $QT_BEGIN_LICENSE:LGPL$ -** No Commercial Usage -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the either Technology Preview License Agreement or the -** Beta Release License Agreement. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** Commercial Usage +** +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. ** ** GNU Lesser General Public License Usage +** ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL included in the @@ -22,24 +24,10 @@ ** 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. ** -** In addition, as a special exception, Nokia gives you certain -** additional rights. These rights are described in the Nokia Qt LGPL -** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this -** package. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3.0 as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU General Public License version 3.0 requirements will be -** met: http://www.gnu.org/copyleft/gpl.html. -** ** If you are unsure which license is appropriate for your use, please -** contact the sales department at qt-sales@nokia.com. -** $QT_END_LICENSE$ +** contact the sales department at http://qt.nokia.com/contact. ** -****************************************************************************/ +**************************************************************************/ // // W A R N I N G diff --git a/src/plugins/qt4projectmanager/qt-s60/s60manager.cpp b/src/plugins/qt4projectmanager/qt-s60/s60manager.cpp index 6ef0c4dde5b..4b16410e61b 100644 --- a/src/plugins/qt4projectmanager/qt-s60/s60manager.cpp +++ b/src/plugins/qt4projectmanager/qt-s60/s60manager.cpp @@ -4,7 +4,7 @@ ** ** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). ** -** Contact: Qt Software Information (qt-info@nokia.com) +** Contact: Nokia Corporation (qt-info@nokia.com) ** ** Commercial Usage ** @@ -23,7 +23,7 @@ ** 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. +** contact the sales department at http://qt.nokia.com/contact. ** **************************************************************************/ diff --git a/src/plugins/qt4projectmanager/qt-s60/s60manager.h b/src/plugins/qt4projectmanager/qt-s60/s60manager.h index 08c0be623d5..fe4078583d8 100644 --- a/src/plugins/qt4projectmanager/qt-s60/s60manager.h +++ b/src/plugins/qt4projectmanager/qt-s60/s60manager.h @@ -4,7 +4,7 @@ ** ** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). ** -** Contact: Qt Software Information (qt-info@nokia.com) +** Contact: Nokia Corporation (qt-info@nokia.com) ** ** Commercial Usage ** @@ -23,7 +23,7 @@ ** 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. +** contact the sales department at http://qt.nokia.com/contact. ** **************************************************************************/ From 63882fc773ffe012b8d8b51581e0c4c5b9dc1fd5 Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Mon, 12 Oct 2009 15:11:51 +0200 Subject: [PATCH 21/34] simplify --- src/plugins/debugger/gdb/trkgdbadapter.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/plugins/debugger/gdb/trkgdbadapter.cpp b/src/plugins/debugger/gdb/trkgdbadapter.cpp index 2a994f8c51f..a4b69aa014a 100644 --- a/src/plugins/debugger/gdb/trkgdbadapter.cpp +++ b/src/plugins/debugger/gdb/trkgdbadapter.cpp @@ -2011,10 +2011,9 @@ void TrkGdbAdapter::handleDirectStep3(const TrkResult &result) void TrkGdbAdapter::cleanup() { - if (m_trkDevice.isOpen()) - m_trkDevice.close(); - if (m_gdbServer) - delete m_gdbServer; + m_trkDevice.close(); + delete m_gdbServer; + m_gdbServer = 0; } void TrkGdbAdapter::shutdown() From 9254bc0bb1e13fde2873e9035235db1d42b949fc Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Mon, 12 Oct 2009 15:12:04 +0200 Subject: [PATCH 22/34] remove dead code --- src/plugins/debugger/gdb/trkgdbadapter.cpp | 29 ---------------------- src/plugins/debugger/gdb/trkgdbadapter.h | 4 --- 2 files changed, 33 deletions(-) diff --git a/src/plugins/debugger/gdb/trkgdbadapter.cpp b/src/plugins/debugger/gdb/trkgdbadapter.cpp index a4b69aa014a..4a249dfa3ed 100644 --- a/src/plugins/debugger/gdb/trkgdbadapter.cpp +++ b/src/plugins/debugger/gdb/trkgdbadapter.cpp @@ -969,24 +969,6 @@ i */ } } -void TrkGdbAdapter::executeCommand(const QString &msg) -{ - if (msg == "EI") { - sendGdbMessage("-exec-interrupt"); - } else if (msg == "C") { - sendTrkMessage(0x18, TrkCallback(), trkContinueMessage(), "CONTINUE"); - } else if (msg == "S") { - sendTrkMessage(0x19, TrkCallback(), trkStepRangeMessage(0x01), "STEP"); - } else if (msg == "N") { - sendTrkMessage(0x19, TrkCallback(), trkStepRangeMessage(0x11), "NEXT"); - } else if (msg == "I") { - interruptInferior(); - } else { - logMessage("EXECUTING GDB COMMAND " + msg); - sendGdbMessage(msg); - } -} - void TrkGdbAdapter::sendTrkMessage(byte code, TrkCallback callback, const QByteArray &data, const QVariant &cookie) { @@ -1736,17 +1718,6 @@ void TrkGdbAdapter::startGdb() m_gdbProc.start(m_options->gdb, gdbArgs); } -void TrkGdbAdapter::sendGdbMessage(const QString &msg, GdbCallback callback, - const QVariant &cookie) -{ - GdbCommand data; - data.command = msg; - data.callback = callback; - data.cookie = cookie; - logMessage(QString("<- ADAPTER TO GDB: %2").arg(msg)); - m_gdbProc.write(msg.toLatin1() + "\n"); -} - // // Rfcomm process handling // diff --git a/src/plugins/debugger/gdb/trkgdbadapter.h b/src/plugins/debugger/gdb/trkgdbadapter.h index 030d61215a2..59f31e06b46 100644 --- a/src/plugins/debugger/gdb/trkgdbadapter.h +++ b/src/plugins/debugger/gdb/trkgdbadapter.h @@ -273,9 +273,6 @@ private: //QTime postTime; }; - void sendGdbMessage(const QString &msg, - GdbCallback callback = GdbCallback(), - const QVariant &cookie = QVariant()); Q_SLOT void handleGdbConnection(); Q_SLOT void readGdbServerCommand(); void readGdbResponse(); @@ -316,7 +313,6 @@ private: QString effectiveTrkDevice() const; // Debuggee state - Q_SLOT void executeCommand(const QString &msg); trk::Session m_session; // global-ish data (process id, target information) Snapshot m_snapshot; // local-ish data (memory and registers) QString m_remoteExecutable; From 1a27681c784603f505052bcebbffd7bc5920e486 Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Mon, 12 Oct 2009 16:39:13 +0200 Subject: [PATCH 23/34] change trk adapter setup sequence gdb can be started before the debugee, so do it. that's more in line with the other adapters. --- src/plugins/debugger/gdb/trkgdbadapter.cpp | 154 ++++++++++----------- src/plugins/debugger/gdb/trkgdbadapter.h | 5 +- 2 files changed, 80 insertions(+), 79 deletions(-) diff --git a/src/plugins/debugger/gdb/trkgdbadapter.cpp b/src/plugins/debugger/gdb/trkgdbadapter.cpp index 4a249dfa3ed..4605044bf6a 100644 --- a/src/plugins/debugger/gdb/trkgdbadapter.cpp +++ b/src/plugins/debugger/gdb/trkgdbadapter.cpp @@ -391,7 +391,7 @@ void TrkGdbAdapter::slotEmitDelayedAdapterStartFailed() emit adapterStartFailed(m_adapterFailMessage, TrkOptionsPage::settingsId()); } -void TrkGdbAdapter::startInferiorEarly() +void TrkGdbAdapter::waitForTrkConnect() { QTC_ASSERT(state() == AdapterStarting, qDebug() << state()); QString errorMessage; @@ -406,7 +406,7 @@ void TrkGdbAdapter::startInferiorEarly() } // Do not loop forever if (m_waitCount++ < (m_options->mode == TrkOptions::BlueTooth ? 60 : 5)) { - QTimer::singleShot(1000, this, SLOT(startInferiorEarly())); + QTimer::singleShot(1000, this, SLOT(waitForTrkConnect())); } else { QString msg = _("Failed to connect to %1 after " "%2 attempts").arg(device).arg(m_waitCount); @@ -426,14 +426,7 @@ void TrkGdbAdapter::startInferiorEarly() // "10 " + formatString("C:\\data\\usingdlls.sisx")); // Open File //sendTrkMessage(0x4B, 0, "00 00 00 01 73 1C 3A C8"); // Close File - QByteArray ba; - appendByte(&ba, 0); // ? - appendByte(&ba, 0); // ? - appendByte(&ba, 0); // ? - - appendString(&ba, m_remoteExecutable.toLatin1(), TargetByteOrder); - sendTrkMessage(0x40, TrkCB(handleCreateProcess), ba); // Create Item - //sendTrkMessage(TRK_WRITE_QUEUE_NOOP_CODE, TrkCB(startGdbServer)); + maybeAdapterStarted(); } void TrkGdbAdapter::logMessage(const QString &msg) @@ -1143,35 +1136,6 @@ void TrkGdbAdapter::handleCpuType(const TrkResult &result) logMessage(logMsg); } -void TrkGdbAdapter::handleCreateProcess(const TrkResult &result) -{ - QTC_ASSERT(state() == AdapterStarting, qDebug() << state()); - // 40 00 00] - //logMessage(" RESULT: " + result.toString()); - // [80 08 00 00 00 01 B5 00 00 01 B6 78 67 40 00 00 40 00 00] - if (result.errorCode()) { - logMessage("ERROR: " + result.errorString()); - QString msg = _("Cannot start executable \"%1\" on the device:\n%2") - .arg(m_remoteExecutable).arg(result.errorString()); - // Delay cleanup as not to close a trk device from its read handler, - // which blocks. - emitDelayedAdapterStartFailed(msg); - return; - } - const char *data = result.data.data(); - m_session.pid = extractInt(data + 1); - m_session.tid = extractInt(data + 5); - m_session.codeseg = extractInt(data + 9); - m_session.dataseg = extractInt(data + 13); - - logMessage("PID: " + hexxNumber(m_session.pid)); - logMessage("TID: " + hexxNumber(m_session.tid)); - logMessage("COD: " + hexxNumber(m_session.codeseg)); - logMessage("DAT: " + hexxNumber(m_session.dataseg)); - - startGdb(); -} - void TrkGdbAdapter::handleDeleteProcess(const TrkResult &result) { Q_UNUSED(result); @@ -1580,10 +1544,17 @@ void TrkGdbAdapter::handleGdbFinished(int exitCode, QProcess::ExitStatus exitSta void TrkGdbAdapter::handleGdbStarted() { - QTC_ASSERT(state() == AdapterStarting, qDebug() << state()); logMessage(QString("GDB: Process Started")); - setState(AdapterStarted); - emit adapterStarted(); + maybeAdapterStarted(); +} + +void TrkGdbAdapter::maybeAdapterStarted() +{ + QTC_ASSERT(state() == AdapterStarting, qDebug() << state()); + if (m_gdbProc.state() == QProcess::Running && m_trkDevice.isOpen()) { + setState(AdapterStarted); + emit adapterStarted(); + } } void TrkGdbAdapter::handleGdbStateChanged(QProcess::ProcessState newState) @@ -1634,15 +1605,76 @@ void TrkGdbAdapter::startAdapter() } m_waitCount = 0; - startInferiorEarly(); + QTC_ASSERT(m_gdbServer == 0, delete m_gdbServer); + QTC_ASSERT(m_gdbConnection == 0, m_gdbConnection = 0); + m_gdbServer = new QTcpServer(this); + + if (!m_gdbServer->listen(QHostAddress(gdbServerIP()), gdbServerPort())) { + QString msg = QString("Unable to start the gdb server at %1: %2.") + .arg(m_gdbServerName).arg(m_gdbServer->errorString()); + logMessage(msg); + emit adapterStartFailed(msg, TrkOptionsPage::settingsId()); + return; + } + + logMessage(QString("Gdb server running on %1.\nLittle endian assumed.") + .arg(m_gdbServerName)); + + connect(m_gdbServer, SIGNAL(newConnection()), + this, SLOT(handleGdbConnection())); + + logMessage("STARTING GDB"); + logMessage(_("### Starting gdb %1").arg(m_options->gdb)); + QStringList gdbArgs; + gdbArgs.append(QLatin1String("--nx")); // Do not read .gdbinit file + gdbArgs.append(QLatin1String("-i")); + gdbArgs.append(QLatin1String("mi")); + m_gdbProc.start(m_options->gdb, gdbArgs); + + waitForTrkConnect(); } void TrkGdbAdapter::prepareInferior() { QTC_ASSERT(state() == AdapterStarted, qDebug() << state()); - // We already started the inferior process during the adapter start. - // Now make gdb aware of it. setState(InferiorPreparing); + + QByteArray ba; + appendByte(&ba, 0); // ? + appendByte(&ba, 0); // ? + appendByte(&ba, 0); // ? + + appendString(&ba, m_remoteExecutable.toLatin1(), TargetByteOrder); + sendTrkMessage(0x40, TrkCB(handleCreateProcess), ba); // Create Item + //sendTrkMessage(TRK_WRITE_QUEUE_NOOP_CODE, TrkCB(startGdbServer)); +} + +void TrkGdbAdapter::handleCreateProcess(const TrkResult &result) +{ + QTC_ASSERT(state() == InferiorPreparing, qDebug() << state()); + // 40 00 00] + //logMessage(" RESULT: " + result.toString()); + // [80 08 00 00 00 01 B5 00 00 01 B6 78 67 40 00 00 40 00 00] + if (result.errorCode()) { + logMessage("ERROR: " + result.errorString()); + QString msg = _("Cannot start executable \"%1\" on the device:\n%2") + .arg(m_remoteExecutable).arg(result.errorString()); + // Delay cleanup as not to close a trk device from its read handler, + // which blocks. + emitDelayedAdapterStartFailed(msg); + return; + } + const char *data = result.data.data(); + m_session.pid = extractInt(data + 1); + m_session.tid = extractInt(data + 5); + m_session.codeseg = extractInt(data + 9); + m_session.dataseg = extractInt(data + 13); + + logMessage("PID: " + hexxNumber(m_session.pid)); + logMessage("TID: " + hexxNumber(m_session.tid)); + logMessage("COD: " + hexxNumber(m_session.codeseg)); + logMessage("DAT: " + hexxNumber(m_session.dataseg)); + const QString fileName = m_symbolFile; if (m_symbolFile.isEmpty()) { logMessage(_("WARNING: No symbol file available.")); @@ -1686,38 +1718,6 @@ void TrkGdbAdapter::handleFirstContinue(const GdbResponse &record) } } -void TrkGdbAdapter::startGdb() -{ - QTC_ASSERT(state() == AdapterStarting, qDebug() << state()); - QTC_ASSERT(m_gdbServer == 0, delete m_gdbServer); - QTC_ASSERT(m_gdbConnection == 0, m_gdbConnection = 0); - m_gdbServer = new QTcpServer(this); - - if (!m_gdbServer->listen(QHostAddress(gdbServerIP()), gdbServerPort())) { - QString msg = QString("Unable to start the gdb server at %1: %2.") - .arg(m_gdbServerName).arg(m_gdbServer->errorString()); - logMessage(msg); - // Delay cleanup as not to close a trk device from its read handler, - // which blocks. - emitDelayedAdapterStartFailed(msg); - return; - } - - logMessage(QString("Gdb server running on %1.\nLittle endian assumed.") - .arg(m_gdbServerName)); - - connect(m_gdbServer, SIGNAL(newConnection()), - this, SLOT(handleGdbConnection())); - - logMessage("STARTING GDB"); - logMessage(_("### Starting gdb %1").arg(m_options->gdb)); - QStringList gdbArgs; - gdbArgs.append(QLatin1String("--nx")); // Do not read .gdbinit file - gdbArgs.append(QLatin1String("-i")); - gdbArgs.append(QLatin1String("mi")); - m_gdbProc.start(m_options->gdb, gdbArgs); -} - // // Rfcomm process handling // diff --git a/src/plugins/debugger/gdb/trkgdbadapter.h b/src/plugins/debugger/gdb/trkgdbadapter.h index 59f31e06b46..d5c9243bf3a 100644 --- a/src/plugins/debugger/gdb/trkgdbadapter.h +++ b/src/plugins/debugger/gdb/trkgdbadapter.h @@ -140,7 +140,6 @@ public: void setVerbose(int verbose) { m_verbose = verbose; } void setBufferedMemoryRead(bool b) { m_bufferedMemoryRead = b; } trk::Session &session() { return m_session; } - void startGdb(); // Set a device (from the project) to override the settings. QString overrideTrkDevice() const; @@ -180,7 +179,7 @@ private: void emitDelayedAdapterStartFailed(const QString &msg); Q_SLOT void slotEmitDelayedAdapterStartFailed(); - Q_SLOT void startInferiorEarly(); + Q_SLOT void waitForTrkConnect(); void handleKill(const GdbResponse &response); void handleExit(const GdbResponse &response); void handleTargetRemote(const GdbResponse &response); @@ -290,6 +289,8 @@ private: Q_SLOT void handleGdbStarted(); Q_SLOT void handleGdbStateChanged(QProcess::ProcessState newState); + void maybeAdapterStarted(); + void logMessage(const QString &msg); // triggers output() if m_verbose Q_SLOT void trkLogMessage(const QString &msg); From 973f607e64c9440b8c59f87f5d18e7d0099a7fcd Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Mon, 12 Oct 2009 18:23:54 +0200 Subject: [PATCH 24/34] centralize entering the InferiorStartFailed state --- src/plugins/debugger/gdb/attachgdbadapter.cpp | 1 - src/plugins/debugger/gdb/coregdbadapter.cpp | 5 ----- src/plugins/debugger/gdb/gdbengine.cpp | 1 + src/plugins/debugger/gdb/plaingdbadapter.cpp | 1 - 4 files changed, 1 insertion(+), 7 deletions(-) diff --git a/src/plugins/debugger/gdb/attachgdbadapter.cpp b/src/plugins/debugger/gdb/attachgdbadapter.cpp index 91a1a216360..7095db9b9a6 100644 --- a/src/plugins/debugger/gdb/attachgdbadapter.cpp +++ b/src/plugins/debugger/gdb/attachgdbadapter.cpp @@ -111,7 +111,6 @@ void AttachGdbAdapter::handleAttach(const GdbResponse &response) m_engine->updateAll(); } else { QString msg = __(response.data.findChild("msg").data()); - setState(InferiorStartFailed); emit inferiorStartFailed(msg); } } diff --git a/src/plugins/debugger/gdb/coregdbadapter.cpp b/src/plugins/debugger/gdb/coregdbadapter.cpp index c0158caccaf..5a522f4d5eb 100644 --- a/src/plugins/debugger/gdb/coregdbadapter.cpp +++ b/src/plugins/debugger/gdb/coregdbadapter.cpp @@ -121,7 +121,6 @@ void CoreGdbAdapter::handleTargetCore1(const GdbResponse &response) int pos1 = console.data().indexOf('`'); int pos2 = console.data().indexOf('\''); if (pos1 == -1 || pos2 == -1) { - setState(InferiorStartFailed); emit inferiorStartFailed(tr("No binary found.")); } else { m_executable = console.data().mid(pos1 + 1, pos2 - pos1 - 1); @@ -134,7 +133,6 @@ void CoreGdbAdapter::handleTargetCore1(const GdbResponse &response) } } else { const QByteArray msg = response.data.findChild("msg").data(); - setState(InferiorStartFailed); emit inferiorStartFailed(msg); } } @@ -149,7 +147,6 @@ void CoreGdbAdapter::handleDetach1(const GdbResponse &response) .arg(fi.absoluteFilePath()), CB(handleFileExecAndSymbols)); } else { const QByteArray msg = response.data.findChild("msg").data(); - setState(InferiorStartFailed); emit inferiorStartFailed(msg); } } @@ -168,7 +165,6 @@ void CoreGdbAdapter::handleFileExecAndSymbols(const GdbResponse &response) .arg(__(response.data.findChild("msg").data())); setState(InferiorUnrunnable); m_engine->updateAll(); - //setState(InferiorStartFailed); // emit inferiorStartFailed(msg); } } @@ -185,7 +181,6 @@ void CoreGdbAdapter::handleTargetCore2(const GdbResponse &response) .arg(__(response.data.findChild("msg").data())); setState(InferiorUnrunnable); m_engine->updateAll(); - //setState(InferiorStartFailed); // emit inferiorStartFailed(msg); } } diff --git a/src/plugins/debugger/gdb/gdbengine.cpp b/src/plugins/debugger/gdb/gdbengine.cpp index c9984dcd362..f45b63f648e 100644 --- a/src/plugins/debugger/gdb/gdbengine.cpp +++ b/src/plugins/debugger/gdb/gdbengine.cpp @@ -4218,6 +4218,7 @@ void GdbEngine::handleInferiorStartFailed(const QString &msg) { debugMessage(_("INFERIOR START FAILED")); showMessageBox(QMessageBox::Critical, tr("Inferior start failed"), msg); + setState(InferiorStartFailed); shutdown(); } diff --git a/src/plugins/debugger/gdb/plaingdbadapter.cpp b/src/plugins/debugger/gdb/plaingdbadapter.cpp index 8cbfd89b6ee..100d1f5f772 100644 --- a/src/plugins/debugger/gdb/plaingdbadapter.cpp +++ b/src/plugins/debugger/gdb/plaingdbadapter.cpp @@ -141,7 +141,6 @@ void PlainGdbAdapter::handleExecRun(const GdbResponse &response) const QByteArray &msg = response.data.findChild("msg").data(); //QTC_ASSERT(status() == InferiorRunning, /**/); //interruptInferior(); - setState(InferiorStartFailed); emit inferiorStartFailed(msg); } } From 1653e287e7c8482dae7fc4bb6d284a437e9066be Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Mon, 12 Oct 2009 18:25:03 +0200 Subject: [PATCH 25/34] if 0 some code - the calling code is if 0'd as well --- src/plugins/debugger/gdb/remotegdbadapter.cpp | 2 ++ src/plugins/debugger/gdb/remotegdbadapter.h | 2 ++ 2 files changed, 4 insertions(+) diff --git a/src/plugins/debugger/gdb/remotegdbadapter.cpp b/src/plugins/debugger/gdb/remotegdbadapter.cpp index 5e16587d188..732fe7ed097 100644 --- a/src/plugins/debugger/gdb/remotegdbadapter.cpp +++ b/src/plugins/debugger/gdb/remotegdbadapter.cpp @@ -175,6 +175,7 @@ void RemoteGdbAdapter::prepareInferior() #endif } +#if 0 void RemoteGdbAdapter::handleSetTargetAsync(const GdbResponse &response) { QTC_ASSERT(state() == InferiorPreparing, qDebug() << state()); @@ -190,6 +191,7 @@ void RemoteGdbAdapter::handleSetTargetAsync(const GdbResponse &response) emit inferiorPreparationFailed(msg); } } +#endif void RemoteGdbAdapter::handleFileExecAndSymbols(const GdbResponse &response) { diff --git a/src/plugins/debugger/gdb/remotegdbadapter.h b/src/plugins/debugger/gdb/remotegdbadapter.h index a0ca3aac4cb..44600b9b89e 100644 --- a/src/plugins/debugger/gdb/remotegdbadapter.h +++ b/src/plugins/debugger/gdb/remotegdbadapter.h @@ -65,7 +65,9 @@ private: Q_SLOT void readUploadStandardError(); Q_SLOT void uploadProcError(QProcess::ProcessError error); +#if 0 void handleSetTargetAsync(const GdbResponse &response); +#endif void handleFileExecAndSymbols(const GdbResponse &response); void handleTargetRemote(const GdbResponse &response); void handleKill(const GdbResponse &response); From b07c1be547d7beb432c43bb8f0c9301595a0dde8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thorbj=C3=B8rn=20Lindeijer?= Date: Tue, 13 Oct 2009 12:12:51 +0200 Subject: [PATCH 26/34] Fixed a crash on exit when include files are still being scanned Found by Roberto. --- src/plugins/cpptools/cppmodelmanager.cpp | 4 ++-- src/plugins/cpptools/cppmodelmanager.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/plugins/cpptools/cppmodelmanager.cpp b/src/plugins/cpptools/cppmodelmanager.cpp index f0373e89bf8..1d886920566 100644 --- a/src/plugins/cpptools/cppmodelmanager.cpp +++ b/src/plugins/cpptools/cppmodelmanager.cpp @@ -727,7 +727,7 @@ QByteArray CppModelManager::internalDefinedMacros() const return macros; } -void CppModelManager::setIncludesInPaths(const QMap includesInPaths) +void CppModelManager::setIncludesInPaths(const QMap &includesInPaths) { QMutexLocker locker(&mutex); QMapIterator i(includesInPaths); @@ -1182,7 +1182,7 @@ void CppModelManager::updateIncludesInPaths(QFutureInterface &future, future.waitForResume(); if (future.isCanceled()) - break; + return; const QString path = paths.takeFirst(); diff --git a/src/plugins/cpptools/cppmodelmanager.h b/src/plugins/cpptools/cppmodelmanager.h index 0e7b0271ce1..4222ccab6be 100644 --- a/src/plugins/cpptools/cppmodelmanager.h +++ b/src/plugins/cpptools/cppmodelmanager.h @@ -163,7 +163,7 @@ private: QStringList internalFrameworkPaths() const; QByteArray internalDefinedMacros() const; - void setIncludesInPaths(const QMap includesInPaths); + void setIncludesInPaths(const QMap &includesInPaths); static void updateIncludesInPaths(QFutureInterface &future, CppModelManager *manager, From 5bee5dea132d755f903c73434ba17cdacb0578e3 Mon Sep 17 00:00:00 2001 From: Roberto Raggi Date: Tue, 13 Oct 2009 12:20:21 +0200 Subject: [PATCH 27/34] Check the scope of class and fwd-class declarations --- src/plugins/cpptools/cppfindreferences.cpp | 24 ++++++++++++++++++++-- src/shared/cplusplus/Symbol.cpp | 8 ++++++++ src/shared/cplusplus/Symbol.h | 2 ++ 3 files changed, 32 insertions(+), 2 deletions(-) diff --git a/src/plugins/cpptools/cppfindreferences.cpp b/src/plugins/cpptools/cppfindreferences.cpp index 06bc4affa87..a60d8be4136 100644 --- a/src/plugins/cpptools/cppfindreferences.cpp +++ b/src/plugins/cpptools/cppfindreferences.cpp @@ -166,6 +166,26 @@ protected: return false; } + bool checkScope(Symbol *symbol, Symbol *otherSymbol) const + { + if (! (symbol && otherSymbol)) + return false; + + else if (symbol->scope() == otherSymbol->scope()) + return true; + + else if (symbol->name() && otherSymbol->name()) { + + if (! symbol->name()->isEqualTo(otherSymbol->name())) + return false; + + } else if (symbol->name() != otherSymbol->name()) { + return false; + } + + return checkScope(symbol->enclosingSymbol(), otherSymbol->enclosingSymbol()); + } + bool isDeclSymbol(Symbol *symbol) const { if (! symbol) @@ -180,11 +200,11 @@ protected: } else if (symbol->isForwardClassDeclaration() && (_declSymbol->isClass() || _declSymbol->isForwardClassDeclaration())) { - return true; + return checkScope(symbol, _declSymbol); } else if (_declSymbol->isForwardClassDeclaration() && (symbol->isClass() || symbol->isForwardClassDeclaration())) { - return true; + return checkScope(symbol, _declSymbol); } return false; diff --git a/src/shared/cplusplus/Symbol.cpp b/src/shared/cplusplus/Symbol.cpp index 3d3f3c78744..dc80add92b2 100644 --- a/src/shared/cplusplus/Symbol.cpp +++ b/src/shared/cplusplus/Symbol.cpp @@ -314,6 +314,14 @@ void Symbol::setScope(Scope *scope) _scope = scope; } +Symbol *Symbol::enclosingSymbol() const +{ + if (! _scope) + return 0; + + return _scope->owner(); +} + Scope *Symbol::enclosingNamespaceScope() const { if (! _scope) diff --git a/src/shared/cplusplus/Symbol.h b/src/shared/cplusplus/Symbol.h index 511e14c9f21..0857673d3f4 100644 --- a/src/shared/cplusplus/Symbol.h +++ b/src/shared/cplusplus/Symbol.h @@ -281,6 +281,8 @@ public: bool isGenerated() const; + Symbol *enclosingSymbol() const; + /// Returns the eclosing namespace scope. Scope *enclosingNamespaceScope() const; From 744febe01a41bb8e1eea77822f7b07d31e34075d Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Tue, 13 Oct 2009 12:35:47 +0200 Subject: [PATCH 28/34] Debugger/Dumpers: Perform checks on QList/QVector. Reviewed-by: hjk --- share/qtcreator/gdbmacros/gdbmacros.cpp | 35 ++++++++++++------------- 1 file changed, 17 insertions(+), 18 deletions(-) diff --git a/share/qtcreator/gdbmacros/gdbmacros.cpp b/share/qtcreator/gdbmacros/gdbmacros.cpp index 3407b3645c1..f68a1cf6cc9 100644 --- a/share/qtcreator/gdbmacros/gdbmacros.cpp +++ b/share/qtcreator/gdbmacros/gdbmacros.cpp @@ -1618,9 +1618,11 @@ static void qDumpQList(QDumper &d) const QListData &ldata = *reinterpret_cast(d.data); const QListData::Data *pdata = *reinterpret_cast(d.data); - int nn = ldata.size(); + const int nn = ldata.size(); if (nn < 0) return; + const bool innerTypeIsPointer = isPointerType(d.innerType); + const int n = qMin(nn, 1000); if (nn > 0) { if (ldata.d->begin < 0) return; @@ -1631,18 +1633,19 @@ static void qDumpQList(QDumper &d) return; #endif qCheckAccess(ldata.d->array); - //qCheckAccess(ldata.d->array[0]); - //qCheckAccess(ldata.d->array[nn - 1]); + // Additional checks on pointer arrays + if (innerTypeIsPointer) + for (int i = 0; i != n; ++i) + if (const void *p = ldata.d->array + i + pdata->begin) + qCheckAccess(deref(p)); } qCheckAccess(pdata); - int n = nn; d.putItemCount("value", n); d.putItem("valueeditable", "false"); d.putItem("numchild", n); if (d.dumpChildren) { - unsigned innerSize = d.extraInt[0]; - bool innerTypeIsPointer = isPointerType(d.innerType); + const unsigned innerSize = d.extraInt[0]; QByteArray strippedInnerType = stripPointerType(d.innerType); // The exact condition here is: @@ -1653,8 +1656,6 @@ static void qDumpQList(QDumper &d) bool isInternal = innerSize <= int(sizeof(void*)) && isMovableType(d.innerType); d.putItem("internal", (int)isInternal); - if (n > 1000) - n = 1000; d.beginChildren(n ? d.innerType : 0); for (int i = 0; i != n; ++i) { d.beginHash(); @@ -2917,23 +2918,21 @@ static void qDumpQVector(QDumper &d) int nn = v->size; if (nn < 0) return; - if (nn > 0) { - //qCheckAccess(&vec.front()); - //qCheckAccess(&vec.back()); - } - + const bool innerIsPointerType = isPointerType(d.innerType); const unsigned innersize = d.extraInt[0]; + const int n = qMin(nn, 1000); + // Check pointers + if (innerIsPointerType && nn > 0) + for (int i = 0; i != n; ++i) + if (const void *p = addOffset(v, i * innersize + typeddatasize)) + qCheckAccess(deref(p)); - int n = nn; d.putItemCount("value", n); d.putItem("valueeditable", "false"); d.putItem("numchild", n); if (d.dumpChildren) { QByteArray strippedInnerType = stripPointerType(d.innerType); - const char *stripped = - isPointerType(d.innerType) ? strippedInnerType.data() : 0; - if (n > 1000) - n = 1000; + const char *stripped = innerIsPointerType ? strippedInnerType.data() : 0; d.beginChildren(d.innerType); for (int i = 0; i != n; ++i) { d.beginHash(); From 14058c07ecf0fe254b2d2caec33dbb2a70f13c6b Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Tue, 13 Oct 2009 14:16:50 +0200 Subject: [PATCH 29/34] CDB: Bug fixing - Turn off initial breakpoint when attaching (terminal) and additionally ignore it before the first startup complete - Refuse to step the artifical thread created when interrupting - If possible, switch to thread 0 when interupting (do not use artificial thread) - Ignore non-fatal exceptions in dumper calls (stray Startup- complete-traps) - Use right thread for dumper call loading - Rename windows exception code enumeration - Turn off modification off watch-data children by setType, show empty lists correctly. - Verbose warnings about inserting invalid watch data. --- src/plugins/debugger/cdb/cdbdebugengine.cpp | 118 ++++++++++++++---- src/plugins/debugger/cdb/cdbdebugengine_p.h | 7 +- .../debugger/cdb/cdbdebugeventcallback.cpp | 26 ++-- .../debugger/cdb/cdbdebugeventcallback.h | 5 +- src/plugins/debugger/cdb/cdbdumperhelper.cpp | 16 ++- .../debugger/cdb/cdbexceptionutils.cpp | 29 ++--- src/plugins/debugger/cdb/cdbexceptionutils.h | 11 ++ .../debugger/cdb/cdbstackframecontext.cpp | 2 +- .../debugger/cdb/cdbstacktracecontext.cpp | 1 + .../debugger/cdb/cdbstacktracecontext.h | 2 + src/plugins/debugger/debuggermanager.cpp | 15 ++- src/plugins/debugger/debuggermanager.h | 2 + src/plugins/debugger/watchhandler.cpp | 17 ++- src/plugins/debugger/watchhandler.h | 2 +- 14 files changed, 180 insertions(+), 73 deletions(-) diff --git a/src/plugins/debugger/cdb/cdbdebugengine.cpp b/src/plugins/debugger/cdb/cdbdebugengine.cpp index 1086adf8e55..181ed4e0603 100644 --- a/src/plugins/debugger/cdb/cdbdebugengine.cpp +++ b/src/plugins/debugger/cdb/cdbdebugengine.cpp @@ -37,6 +37,7 @@ #include "cdbassembler.h" #include "cdboptionspage.h" #include "cdboptions.h" +#include "cdbexceptionutils.h" #include "debuggeragents.h" #include "debuggeractions.h" @@ -305,12 +306,14 @@ CdbDebugEnginePrivate::CdbDebugEnginePrivate(DebuggerManager *manager, m_dumper(new CdbDumperHelper(manager, &m_cif)), m_currentThreadId(-1), m_eventThreadId(-1), - m_interrupted(false), + m_interruptArticifialThreadId(-1), + m_interrupted(false), m_watchTimer(-1), m_debugEventCallBack(engine), m_engine(engine), m_currentStackTrace(0), m_firstActivatedFrame(true), + m_inferiorStartupComplete(false), m_mode(AttachCore) { } @@ -447,7 +450,7 @@ void CdbDebugEnginePrivate::clearForRun() qDebug() << Q_FUNC_INFO; m_breakEventMode = BreakEventHandle; - m_eventThreadId = -1; + m_eventThreadId = m_interruptArticifialThreadId = -1; m_interrupted = false; cleanStackTrace(); } @@ -619,6 +622,8 @@ void CdbDebugEnginePrivate::checkVersion() void CdbDebugEngine::startDebugger(const QSharedPointer &sp) { + if (debugCDBExecution) + qDebug() << "startDebugger" << *sp; setState(AdapterStarting, Q_FUNC_INFO, __LINE__); m_d->checkVersion(); if (m_d->m_hDebuggeeProcess) { @@ -627,6 +632,7 @@ void CdbDebugEngine::startDebugger(const QSharedPointer emit startFailed(); } m_d->clearDisplay(); + m_d->m_inferiorStartupComplete = false; setState(AdapterStarted, Q_FUNC_INFO, __LINE__); setState(InferiorPreparing, Q_FUNC_INFO, __LINE__); @@ -699,10 +705,11 @@ bool CdbDebugEngine::startAttachDebugger(qint64 pid, DebuggerStartMode sm, QStri { // Need to attrach invasively, otherwise, no notification signals // for for CreateProcess/ExitProcess occur. - const ULONG flags = DEBUG_ATTACH_INVASIVE_RESUME_PROCESS; + // As of version 6.11, the initial breakpoint suppression has no effect (see notifyException). + const ULONG flags = DEBUG_ATTACH_INVASIVE_RESUME_PROCESS|DEBUG_ATTACH_INVASIVE_NO_INITIAL_BREAK; const HRESULT hr = m_d->m_cif.debugClient->AttachProcess(NULL, pid, flags); if (debugCDB) - qDebug() << "Attaching to " << pid << " returns " << hr << executionStatusString(m_d->m_cif.debugControl); + qDebug() << "Attaching to " << pid << " using flags" << flags << " returns " << hr << executionStatusString(m_d->m_cif.debugControl); if (FAILED(hr)) { *errorMessage = tr("Attaching to a process failed for process id %1: %2").arg(pid).arg(msgDebugEngineComResult(hr)); return false; @@ -771,7 +778,7 @@ bool CdbDebugEngine::startDebuggerWithExecutable(DebuggerStartMode sm, QString * } void CdbDebugEnginePrivate::processCreatedAttached(ULONG64 processHandle, ULONG64 initialThreadHandle) -{ +{ m_engine->setState(InferiorRunningRequested, Q_FUNC_INFO, __LINE__); setDebuggeeHandles(reinterpret_cast(processHandle), reinterpret_cast(initialThreadHandle)); ULONG currentThreadId; @@ -782,8 +789,11 @@ void CdbDebugEnginePrivate::processCreatedAttached(ULONG64 processHandle, ULONG6 } // Clear any saved breakpoints and set initial breakpoints m_engine->executeDebuggerCommand(QLatin1String("bc")); - if (manager()->breakHandler()->hasPendingBreakpoints()) + if (manager()->breakHandler()->hasPendingBreakpoints()) { + if (debugCDBExecution) + qDebug() << "processCreatedAttached: Syncing breakpoints"; m_engine->attemptBreakpointSynchronization(); + } // Attaching to crashed: This handshake (signalling an event) is required for // the exception to be delivered to the debugger if (m_mode == AttachCrashedExternal) { @@ -796,8 +806,8 @@ void CdbDebugEnginePrivate::processCreatedAttached(ULONG64 processHandle, ULONG6 } } m_engine->setState(InferiorRunning, Q_FUNC_INFO, __LINE__); - if (debugCDB) - qDebug() << Q_FUNC_INFO << '\n' << executionStatusString(m_cif.debugControl); + if (debugCDBExecution) + qDebug() << "m_currentThreadId << " evt " << m_d->m_eventThreadId; + if (debugCDBExecution) + qDebug() << ">step" << executionStatus << "curr " << m_d->m_currentThreadId << " evt " << m_d->m_eventThreadId; // State of reverse stepping as of 10/2009 (Debugging tools 6.11@404): // The constants exist, but invoking the calls leads to E_NOINTERFACE. @@ -1029,6 +1039,12 @@ bool CdbDebugEngine::step(unsigned long executionStatus) return false; } + // Do not step the artifical thread created to interrupt the debuggee. + if (m_d->m_interrupted && m_d->m_currentThreadId == m_d->m_interruptArticifialThreadId) { + warning(tr("Thread %1 cannot be stepped.").arg(m_d->m_currentThreadId)); + return false; + } + // SetExecutionStatus() continues the thread that triggered the // stop event (~# p). This can be confusing if the user is looking // at the stack trace of another thread and wants to step that one. If that @@ -1067,6 +1083,8 @@ bool CdbDebugEngine::step(unsigned long executionStatus) } else { setState(InferiorStopped, Q_FUNC_INFO, __LINE__); } + if (debugCDBExecution) + qDebug() << "stackHandler(); @@ -1142,8 +1160,8 @@ void CdbDebugEngine::continueInferior() // Continue process without notifications bool CdbDebugEnginePrivate::continueInferiorProcess(QString *errorMessagePtr /* = 0 */) { - if (debugCDB) - qDebug() << Q_FUNC_INFO; + if (debugCDBExecution) + qDebug() << "continueInferiorProcess"; const HRESULT hr = m_cif.debugControl->SetExecutionStatus(DEBUG_STATUS_GO); if (FAILED(hr)) { const QString errorMessage = msgComFailed("SetExecutionStatus", hr); @@ -1198,11 +1216,12 @@ bool CdbDebugEnginePrivate::continueInferior(QString *errorMessage) bool CdbDebugEnginePrivate::interruptInterferiorProcess(QString *errorMessage) { + // Interrupt the interferior process without notifications - if (debugCDB) { + if (debugCDBExecution) { ULONG executionStatus; getExecutionStatus(m_cif.debugControl, &executionStatus, errorMessage); - qDebug() << Q_FUNC_INFO << "\n ex=" << executionStatus; + qDebug() << "interruptInterferiorProcess ex=" << executionStatus; } if (DebugBreakProcess(m_hDebuggeeProcess)) { @@ -1218,6 +1237,7 @@ bool CdbDebugEnginePrivate::interruptInterferiorProcess(QString *errorMessage) arg(getInterruptTimeOutSecs(m_cif.debugControl)).arg(msgComFailed("SetInterrupt", hr)); return false; } + m_interrupted = true; #endif return true; } @@ -1646,10 +1666,27 @@ void CdbDebugEngine::warning(const QString &w) qWarning("%s\n", qPrintable(w)); } -void CdbDebugEnginePrivate::notifyCrashed() +void CdbDebugEnginePrivate::notifyException(long code, bool fatal) { + if (debugCDBExecution) + qDebug() << "notifyException code" << code << " fatal=" << fatal; + // Suppress the initial breakpoint that occurs when + // attaching (If a breakpoint is encountered before startup + // is complete). + switch (code) { + case winExceptionStartupCompleteTrap: + m_inferiorStartupComplete = true; + break; + case EXCEPTION_BREAKPOINT: + if (!m_inferiorStartupComplete && m_breakEventMode == BreakEventHandle) { + manager()->showDebuggerOutput(LogMisc, CdbDebugEngine::tr("Ignoring initial breakpoint...")); + m_breakEventMode = BreakEventIgnoreOnce; + } + break; + } // Cannot go over crash point to execute calls. - m_dumper->disable(); + if (fatal) + m_dumper->disable(); } static int threadIndexById(const ThreadsHandler *threadsHandler, int id) @@ -1664,10 +1701,10 @@ static int threadIndexById(const ThreadsHandler *threadsHandler, int id) void CdbDebugEnginePrivate::handleDebugEvent() { - if (debugCDB) - qDebug() << Q_FUNC_INFO << '\n' << m_hDebuggeeProcess << m_breakEventMode - << executionStatusString(m_cif.debugControl); - + if (debugCDBExecution) + qDebug() << "handleDebugEvent mode " << m_breakEventMode + << executionStatusString(m_cif.debugControl) << " interrupt" << m_interrupted + << " startupcomplete" << m_inferiorStartupComplete; // restore mode and do special handling const HandleBreakEventMode mode = m_breakEventMode; m_breakEventMode = BreakEventHandle; @@ -1679,9 +1716,27 @@ void CdbDebugEnginePrivate::handleDebugEvent() if (m_engine->state() != InferiorStopping) m_engine->setState(InferiorStopping, Q_FUNC_INFO, __LINE__); m_engine->setState(InferiorStopped, Q_FUNC_INFO, __LINE__); - m_eventThreadId = m_currentThreadId = updateThreadList(); - manager()->showDebuggerOutput(LogMisc, CdbDebugEngine::tr("Stopped, current thread: %1").arg(m_currentThreadId)); + m_eventThreadId = updateThreadList(); + m_interruptArticifialThreadId = m_interrupted ? m_eventThreadId : -1; + // Get thread to stop and its index. If avoidable, do not use + // the artifical thread that is created when interrupting, + // use the oldest thread 0 instead. ThreadsHandler *threadsHandler = manager()->threadsHandler(); + m_currentThreadId = m_interrupted ? 0 : m_eventThreadId; + int currentThreadIndex = -1; + m_currentThreadId = -1; + if (m_interrupted) { + m_currentThreadId = 0; + currentThreadIndex = threadIndexById(threadsHandler, m_currentThreadId); + } + if (!m_interrupted || currentThreadIndex == -1) { + m_currentThreadId = m_eventThreadId; + currentThreadIndex = threadIndexById(threadsHandler, m_currentThreadId); + } + const QString msg = m_interrupted ? + CdbDebugEngine::tr("Interrupted in thread %1, current thread: %2").arg(m_interruptArticifialThreadId).arg(m_currentThreadId) : + CdbDebugEngine::tr("Stopped, current thread: %1").arg(m_currentThreadId); + manager()->showDebuggerOutput(LogMisc, msg); const int threadIndex = threadIndexById(threadsHandler, m_currentThreadId); if (threadIndex != -1) threadsHandler->setCurrentThread(threadIndex); @@ -1690,8 +1745,10 @@ void CdbDebugEnginePrivate::handleDebugEvent() break; case BreakEventIgnoreOnce: m_engine->startWatchTimer(); + m_interrupted = false; break; case BreakEventSyncBreakPoints: { + m_interrupted = false; // Temp stop to sync breakpoints QString errorMessage; attemptBreakpointSynchronization(&errorMessage); @@ -1764,9 +1821,12 @@ static inline unsigned long dumperThreadId(const QList &frames, return CdbDumperHelper::InvalidDumperCallThread; const int waitCheckDepth = qMin(frames.size(), 5); static const QString waitForPrefix = QLatin1String(CdbStackTraceContext::winFuncWaitForPrefix); - for (int f = 0; f < waitCheckDepth; f++) - if (frames.at(f).function.startsWith(waitForPrefix)) + static const QString msgWaitForPrefix = QLatin1String(CdbStackTraceContext::winFuncMsgWaitForPrefix); + for (int f = 0; f < waitCheckDepth; f++) { + const QString &function = frames.at(f).function; + if (function.startsWith(waitForPrefix) || function.startsWith(msgWaitForPrefix)) return CdbDumperHelper::InvalidDumperCallThread; + } return currentThread; } @@ -1812,7 +1872,7 @@ void CdbDebugEnginePrivate::updateStackTrace() } // Set up dumper with a thread (or invalid) const unsigned long dumperThread = dumperThreadId(stackFrames, m_currentThreadId); - if (debugCDB) + if (debugCDBExecution) qDebug() << "updateStackTrace() current: " << m_currentThreadId << " dumper=" << dumperThread; m_dumper->setDumperCallThread(dumperThread); // Display frames @@ -1824,6 +1884,10 @@ void CdbDebugEnginePrivate::updateStackTrace() if (m_dumper->isEnabled() && m_dumper->state() != CdbDumperHelper::Initialized) QApplication::processEvents(QEventLoop::ExcludeUserInputEvents); m_engine->activateFrame(current); + } else { + // Clean out variables + manager()->watchHandler()->beginCycle(); + manager()->watchHandler()->endCycle(); } manager()->watchHandler()->updateWatchers(); } diff --git a/src/plugins/debugger/cdb/cdbdebugengine_p.h b/src/plugins/debugger/cdb/cdbdebugengine_p.h index b0a01d37896..e52ddadef5c 100644 --- a/src/plugins/debugger/cdb/cdbdebugengine_p.h +++ b/src/plugins/debugger/cdb/cdbdebugengine_p.h @@ -135,7 +135,7 @@ struct CdbDebugEnginePrivate bool executeContinueCommand(const QString &command); bool attemptBreakpointSynchronization(QString *errorMessage); - void notifyCrashed(); + void notifyException(long code, bool fatal); enum EndInferiorAction { DetachInferior, TerminateInferior }; bool endInferior(EndInferiorAction a, QString *errorMessage); @@ -157,9 +157,10 @@ struct CdbDebugEnginePrivate const QSharedPointer m_options; HANDLE m_hDebuggeeProcess; HANDLE m_hDebuggeeThread; - bool m_interrupted; + bool m_interrupted; int m_currentThreadId; int m_eventThreadId; + int m_interruptArticifialThreadId; HandleBreakEventMode m_breakEventMode; int m_watchTimer; @@ -175,6 +176,7 @@ struct CdbDebugEnginePrivate EditorToolTipCache m_editorToolTipCache; bool m_firstActivatedFrame; + bool m_inferiorStartupComplete; DebuggerStartMode m_mode; Utils::ConsoleProcess m_consoleStubProc; @@ -192,6 +194,7 @@ QString msgDebugEngineComResult(HRESULT hr); QString msgComFailed(const char *func, HRESULT hr); enum { debugCDB = 0 }; +enum { debugCDBExecution = 0 }; enum { debugCDBWatchHandling = 0 }; } // namespace Internal diff --git a/src/plugins/debugger/cdb/cdbdebugeventcallback.cpp b/src/plugins/debugger/cdb/cdbdebugeventcallback.cpp index 21f867ede22..26c24b2058b 100644 --- a/src/plugins/debugger/cdb/cdbdebugeventcallback.cpp +++ b/src/plugins/debugger/cdb/cdbdebugeventcallback.cpp @@ -35,6 +35,7 @@ #include #include +#include namespace Debugger { namespace Internal { @@ -249,8 +250,7 @@ STDMETHODIMP CdbDebugEventCallback::Exception( qDebug() << Q_FUNC_INFO << "\nex=" << Exception->ExceptionCode << " fatal=" << fatal << msg; m_pEngine->manager()->showApplicationOutput(msg); m_pEngine->manager()->showDebuggerOutput(LogMisc, msg); - if (fatal) - m_pEngine->m_d->notifyCrashed(); + m_pEngine->m_d->notifyException(Exception->ExceptionCode, fatal); return S_OK; } @@ -373,8 +373,11 @@ STDMETHODIMP CdbDebugEventCallback::SystemError( } // -----------ExceptionLoggerEventCallback -CdbExceptionLoggerEventCallback::CdbExceptionLoggerEventCallback(int logChannel, DebuggerManager *manager) : +CdbExceptionLoggerEventCallback::CdbExceptionLoggerEventCallback(int logChannel, + bool skipNonFatalExceptions, + DebuggerManager *manager) : m_logChannel(logChannel), + m_skipNonFatalExceptions(skipNonFatalExceptions), m_manager(manager) { } @@ -391,15 +394,18 @@ STDMETHODIMP CdbExceptionLoggerEventCallback::Exception( __in ULONG /* FirstChance */ ) { - m_exceptionCodes.push_back(Exception->ExceptionCode); - m_exceptionMessages.push_back(QString()); - { - QTextStream str(&m_exceptionMessages.back()); - formatException(Exception, str); + const bool recordException = !m_skipNonFatalExceptions || isFatalException(Exception->ExceptionCode); + QString message; + formatException(Exception, QTextStream(&message)); + if (recordException) { + m_exceptionCodes.push_back(Exception->ExceptionCode); + m_exceptionMessages.push_back(message); } if (debugCDB) - qDebug() << Q_FUNC_INFO << '\n' << m_exceptionMessages.back(); - m_manager->showDebuggerOutput(m_logChannel, m_exceptionMessages.back()); + qDebug() << Q_FUNC_INFO << '\n' << message; + m_manager->showDebuggerOutput(m_logChannel, message); + if (recordException) + QCoreApplication::processEvents(QEventLoop::ExcludeUserInputEvents); return S_OK; } diff --git a/src/plugins/debugger/cdb/cdbdebugeventcallback.h b/src/plugins/debugger/cdb/cdbdebugeventcallback.h index b9de88e1745..4250cd5b24c 100644 --- a/src/plugins/debugger/cdb/cdbdebugeventcallback.h +++ b/src/plugins/debugger/cdb/cdbdebugeventcallback.h @@ -242,7 +242,9 @@ private: class CdbExceptionLoggerEventCallback : public CdbDebugEventCallbackBase { public: - CdbExceptionLoggerEventCallback(int logChannel, DebuggerManager *access); + CdbExceptionLoggerEventCallback(int logChannel, + bool skipNonFatalExceptions, + DebuggerManager *access); STDMETHOD(GetInterestMask)( THIS_ @@ -261,6 +263,7 @@ public: private: const int m_logChannel; + const bool m_skipNonFatalExceptions; DebuggerManager *m_manager; QList m_exceptionCodes; QStringList m_exceptionMessages; diff --git a/src/plugins/debugger/cdb/cdbdumperhelper.cpp b/src/plugins/debugger/cdb/cdbdumperhelper.cpp index a188d2c1f2b..753c54be845 100644 --- a/src/plugins/debugger/cdb/cdbdumperhelper.cpp +++ b/src/plugins/debugger/cdb/cdbdumperhelper.cpp @@ -144,13 +144,14 @@ static bool createDebuggeeAscIIString(CdbComInterfaces *cif, // make sense for Qt apps. static bool debuggeeLoadLibrary(DebuggerManager *manager, CdbComInterfaces *cif, + unsigned long threadId, const QString &moduleName, QString *errorMessage) { if (loadDebug > 1) qDebug() << Q_FUNC_INFO << moduleName; - // Try to ignore the breakpoints - CdbExceptionLoggerEventCallback exLogger(LogWarning, manager); + // Try to ignore the breakpoints, skip stray startup-complete trap exceptions + CdbExceptionLoggerEventCallback exLogger(LogWarning, true, manager); EventCallbackRedirector eventRedir(cif->debugClient, &exLogger); // Make a call to LoadLibraryA. First, reserve memory in debugger // and copy name over. @@ -178,7 +179,9 @@ static bool debuggeeLoadLibrary(DebuggerManager *manager, if (!CdbDebugEnginePrivate::executeDebuggerCommand(cif->debugControl, callCmd, errorMessage)) return false; // Execute current thread. This will hit a breakpoint. - if (!CdbDebugEnginePrivate::executeDebuggerCommand(cif->debugControl, QLatin1String("~. g"), errorMessage)) + QString goCmd; + QTextStream(&goCmd) << '~' << threadId << " g"; + if (!CdbDebugEnginePrivate::executeDebuggerCommand(cif->debugControl, goCmd, errorMessage)) return false; const HRESULT hr = cif->debugControl->WaitForEvent(0, waitTimeOutMS); if (FAILED(hr)) { @@ -329,7 +332,7 @@ CdbDumperHelper::CallLoadResult CdbDumperHelper::initCallLoad(QString *errorMess if (modules.filter(QLatin1String(qtCoreModuleNameC), Qt::CaseInsensitive).isEmpty()) return CallLoadNoQtApp; // Try to load - if (!debuggeeLoadLibrary(m_manager, m_cif, m_library, errorMessage)) + if (!debuggeeLoadLibrary(m_manager, m_cif, m_dumperCallThread, m_library, errorMessage)) return CallLoadError; return CallLoadOk; } @@ -495,7 +498,8 @@ CdbDumperHelper::CallResult bool ignoreAccessViolation, QString *errorMessage) { *outDataPtr = 0; - CdbExceptionLoggerEventCallback exLogger(LogWarning, m_manager); + // Skip stray startup-complete trap exceptions. + CdbExceptionLoggerEventCallback exLogger(LogWarning, true, m_manager); EventCallbackRedirector eventRedir(m_cif->debugClient, &exLogger); // write input buffer if (!inBuffer.isEmpty()) { @@ -576,7 +580,7 @@ static inline QString msgNotHandled(const QString &type) CdbDumperHelper::DumpResult CdbDumperHelper::dumpType(const WatchData &wd, bool dumpChildren, QList *result, QString *errorMessage) { - if (dumpDebug) + if (dumpDebug || debugCDBExecution) qDebug() << ">dumpType() thread: " << m_dumperCallThread << " state: " << m_state << wd.type << QTime::currentTime().toString(); const CdbDumperHelper::DumpResult rc = dumpTypeI(wd, dumpChildren, result, errorMessage); if (dumpDebug) diff --git a/src/plugins/debugger/cdb/cdbexceptionutils.cpp b/src/plugins/debugger/cdb/cdbexceptionutils.cpp index 4975b697243..2c9b49d413e 100644 --- a/src/plugins/debugger/cdb/cdbexceptionutils.cpp +++ b/src/plugins/debugger/cdb/cdbexceptionutils.cpp @@ -38,15 +38,6 @@ enum { debugExc = 0 }; -// Special exception codes. -enum { cppExceptionCode = 0xe06d7363, startupCompleteTrap = 0x406d1388, - rpcServerUnavailableExceptionCode = 0x6ba, - dllNotFoundExceptionCode = 0xc0000135, - dllInitFailed = 0xc0000142, - missingSystemFile = 0xc0000143, - appInitFailed = 0xc0000143 - }; - namespace Debugger { namespace Internal { @@ -167,19 +158,19 @@ void formatException(const EXCEPTION_RECORD64 *e, QTextStream &str) str << "\nException at 0x" << e->ExceptionAddress << ", code: 0x" << e->ExceptionCode << ": "; switch (e->ExceptionCode) { - case cppExceptionCode: + case winExceptionCppException: str << "C++ exception"; break; - case startupCompleteTrap: + case winExceptionStartupCompleteTrap: str << "Startup complete"; break; - case dllNotFoundExceptionCode: + case winExceptionDllNotFound: str << "DLL not found"; break; - case dllInitFailed: + case winExceptionDllInitFailed: str << "DLL failed to initialize"; break; - case missingSystemFile: + case winExceptionMissingSystemFile: str << "System file is missing"; break; case EXCEPTION_ACCESS_VIOLATION: { @@ -260,7 +251,7 @@ void formatException(const EXCEPTION_RECORD64 *e, QTextStream &str) { formatException(e, str); - if (e->ExceptionCode == cppExceptionCode) { + if (e->ExceptionCode == winExceptionCppException) { QString errorMessage; ULONG currentThreadId = 0; dumper->comInterfaces()->debugSystemObjects->GetCurrentThreadId(¤tThreadId); @@ -278,10 +269,10 @@ bool isFatalException(LONG code) switch (code) { case EXCEPTION_BREAKPOINT: case EXCEPTION_SINGLE_STEP: - case startupCompleteTrap: // Mysterious exception at start of application - case rpcServerUnavailableExceptionCode: - case dllNotFoundExceptionCode: - case cppExceptionCode: + case winExceptionStartupCompleteTrap: // Mysterious exception at start of application + case winExceptionRpcServerUnavailable: + case winExceptionDllNotFound: + case winExceptionCppException: return false; default: break; diff --git a/src/plugins/debugger/cdb/cdbexceptionutils.h b/src/plugins/debugger/cdb/cdbexceptionutils.h index 98af74706fa..b54447580f3 100644 --- a/src/plugins/debugger/cdb/cdbexceptionutils.h +++ b/src/plugins/debugger/cdb/cdbexceptionutils.h @@ -42,6 +42,17 @@ QT_END_NAMESPACE namespace Debugger { namespace Internal { +// Special exception codes. +enum { winExceptionCppException = 0xe06d7363, + winExceptionStartupCompleteTrap = 0x406d1388, + winExceptionRpcServerUnavailable = 0x6ba, + winExceptionDllNotFound = 0xc0000135, + winExceptionDllInitFailed = 0xc0000142, + winExceptionMissingSystemFile = 0xc0000143, + winExceptionAppInitFailed = 0xc0000143 +}; + + class CdbDumperHelper; // Utility class that blocks out exception handling (breaking) diff --git a/src/plugins/debugger/cdb/cdbstackframecontext.cpp b/src/plugins/debugger/cdb/cdbstackframecontext.cpp index 93ab11d75ef..d97a968768c 100644 --- a/src/plugins/debugger/cdb/cdbstackframecontext.cpp +++ b/src/plugins/debugger/cdb/cdbstackframecontext.cpp @@ -134,7 +134,7 @@ static inline bool fixDumperType(WatchData *wd, const WatchData *source = 0) const bool missing = wd->isTypeNeeded() || wd->type.isEmpty(); if (missing) { static const QString unknownType = QCoreApplication::translate("CdbStackFrameContext", ""); - wd->setType(source ? source->type : unknownType); + wd->setType(source ? source->type : unknownType, false); } return missing; } diff --git a/src/plugins/debugger/cdb/cdbstacktracecontext.cpp b/src/plugins/debugger/cdb/cdbstacktracecontext.cpp index 605eeb61dbf..0a338f9fdcc 100644 --- a/src/plugins/debugger/cdb/cdbstacktracecontext.cpp +++ b/src/plugins/debugger/cdb/cdbstacktracecontext.cpp @@ -43,6 +43,7 @@ namespace Internal { const char *CdbStackTraceContext::winFuncFastSystemCallRet = "ntdll!KiFastSystemCallRet"; const char *CdbStackTraceContext::winFuncDebugBreakPoint = "ntdll!DbgBreakPoint"; const char *CdbStackTraceContext::winFuncWaitForPrefix = "kernel32!WaitFor"; +const char *CdbStackTraceContext::winFuncMsgWaitForPrefix = "kernel32!MsgWaitForMultipleObjects"; CdbStackTraceContext::CdbStackTraceContext(const QSharedPointer &dumper) : m_dumper(dumper), diff --git a/src/plugins/debugger/cdb/cdbstacktracecontext.h b/src/plugins/debugger/cdb/cdbstacktracecontext.h index 3b0e2061fc8..ac9cb030b06 100644 --- a/src/plugins/debugger/cdb/cdbstacktracecontext.h +++ b/src/plugins/debugger/cdb/cdbstacktracecontext.h @@ -67,6 +67,8 @@ public: static const char *winFuncFastSystemCallRet; // WaitFor... static const char *winFuncWaitForPrefix; + static const char *winFuncMsgWaitForPrefix; + // Dummy function used for interrupting a debuggee static const char *winFuncDebugBreakPoint; diff --git a/src/plugins/debugger/debuggermanager.cpp b/src/plugins/debugger/debuggermanager.cpp index ea3924ddd26..166902112eb 100644 --- a/src/plugins/debugger/debuggermanager.cpp +++ b/src/plugins/debugger/debuggermanager.cpp @@ -1406,10 +1406,14 @@ void DebuggerManager::modulesDockToggled(bool on) void DebuggerManager::showDebuggerOutput(int channel, const QString &msg) { - if (d->m_outputWindow) + if (d->m_outputWindow) { emit emitShowOutput(channel, msg); - else + if (channel == LogError) + ensureLogVisible(); + } else { qDebug() << "OUTPUT: " << channel << msg; + + } } void DebuggerManager::showDebuggerInput(int channel, const QString &msg) @@ -1761,6 +1765,13 @@ bool DebuggerManager::checkDebugConfiguration(int toolChain, return success; } +void DebuggerManager::ensureLogVisible() +{ + QAction *action = d->m_outputDock->toggleViewAction(); + if (!action->isChecked()) + action->trigger(); +} + QDebug operator<<(QDebug d, DebuggerState state) { return d << stateName(state) << '(' << int(state) << ')'; diff --git a/src/plugins/debugger/debuggermanager.h b/src/plugins/debugger/debuggermanager.h index ddd692b4316..2d84c9383cc 100644 --- a/src/plugins/debugger/debuggermanager.h +++ b/src/plugins/debugger/debuggermanager.h @@ -234,6 +234,8 @@ public slots: public slots: // FIXME void showDebuggerOutput(const QString &msg) { showDebuggerOutput(LogDebug, msg); } + void ensureLogVisible(); + //private slots: // FIXME void showDebuggerOutput(int channel, const QString &msg); void showDebuggerInput(int channel, const QString &msg); diff --git a/src/plugins/debugger/watchhandler.cpp b/src/plugins/debugger/watchhandler.cpp index 04e3bee8f73..1cf41e93235 100644 --- a/src/plugins/debugger/watchhandler.cpp +++ b/src/plugins/debugger/watchhandler.cpp @@ -177,7 +177,7 @@ void WatchData::setValueToolTip(const QString &tooltip) valuetooltip = tooltip; } -void WatchData::setType(const QString &str) +void WatchData::setType(const QString &str, bool guessChildrenFromType) { type = str.trimmed(); bool changed = true; @@ -202,7 +202,8 @@ void WatchData::setType(const QString &str) changed = false; } setTypeUnneeded(); - switch (guessChildren(type)) { + if (guessChildrenFromType) { + switch (guessChildren(type)) { case HasChildren: setHasChildren(true); break; @@ -212,6 +213,7 @@ void WatchData::setType(const QString &str) case HasPossiblyChildren: setHasChildren(true); // FIXME: bold assumption break; + } } } @@ -1091,7 +1093,10 @@ void WatchHandler::cleanup() void WatchHandler::insertData(const WatchData &data) { MODEL_DEBUG("INSERTDATA: " << data.toString()); - QTC_ASSERT(data.isValid(), return); + if (!data.isValid()) { + qWarning("%s:%d: Attempt to insert invalid watch item: %s", __FILE__, __LINE__, qPrintable(data.toString())); + return; + } if (data.isSomethingNeeded()) { m_manager->updateWatchData(data); } else { @@ -1117,7 +1122,11 @@ void WatchHandler::insertBulkData(const QList &list) foreach (const WatchData &data, list) { // we insert everything, including incomplete stuff // to reduce the number of row add operations in the model. - hash[parentName(data.iname)].append(data); + if (data.isValid()) { + hash[parentName(data.iname)].append(data); + } else { + qWarning("%s:%d: Attempt to bulk-insert invalid watch item: %s", __FILE__, __LINE__, qPrintable(data.toString())); + } } foreach (const QString &parentIName, hash.keys()) { WatchModel *model = modelForIName(parentIName); diff --git a/src/plugins/debugger/watchhandler.h b/src/plugins/debugger/watchhandler.h index eb2797f3e0e..dc426f4e22d 100644 --- a/src/plugins/debugger/watchhandler.h +++ b/src/plugins/debugger/watchhandler.h @@ -78,7 +78,7 @@ public: }; void setValue(const QString &); - void setType(const QString &); + void setType(const QString &, bool guessChildrenFromType = true); void setValueToolTip(const QString &); void setError(const QString &); void setAddress(const QString &address); From c33a8e94981f6b1acf2b11aaf04c3e86f6ceea12 Mon Sep 17 00:00:00 2001 From: Roberto Raggi Date: Tue, 13 Oct 2009 14:38:37 +0200 Subject: [PATCH 30/34] Rename the given enumerator. --- src/plugins/cpptools/cppfindreferences.cpp | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/src/plugins/cpptools/cppfindreferences.cpp b/src/plugins/cpptools/cppfindreferences.cpp index a60d8be4136..3c11479a025 100644 --- a/src/plugins/cpptools/cppfindreferences.cpp +++ b/src/plugins/cpptools/cppfindreferences.cpp @@ -188,10 +188,10 @@ protected: bool isDeclSymbol(Symbol *symbol) const { - if (! symbol) + if (! symbol) { return false; - else if (symbol == _declSymbol) { + } else if (symbol == _declSymbol) { return true; } else if (symbol->line() == _declSymbol->line() && symbol->column() == _declSymbol->column()) { @@ -369,6 +369,20 @@ protected: return false; } + virtual bool visit(EnumeratorAST *ast) + { + Identifier *id = identifier(ast->identifier_token); + if (id == _id) { + LookupContext context = currentContext(ast); + const QList candidates = context.resolve(control()->nameId(id)); + reportResult(ast->identifier_token, candidates); + } + + accept(ast->expression); + + return false; + } + virtual bool visit(SimpleNameAST *ast) { Identifier *id = identifier(ast->identifier_token); From 51906dc408cd3a0c89f4357edb2d38c84dc14fea Mon Sep 17 00:00:00 2001 From: hjk Date: Tue, 13 Oct 2009 08:48:24 +0200 Subject: [PATCH 31/34] debugger: don't test json parsing as this was removed --- tests/auto/debugger/tst_plugin.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/auto/debugger/tst_plugin.cpp b/tests/auto/debugger/tst_plugin.cpp index 5d26a6ac121..84ffc58a685 100644 --- a/tests/auto/debugger/tst_plugin.cpp +++ b/tests/auto/debugger/tst_plugin.cpp @@ -24,7 +24,6 @@ #include #include "gdb/gdbmi.h" -#include "tcf/json.h" #include "gdbmacros.h" #include "gdbmacros_p.h" From 594730f3ac785e08dc50455161fa8c5e25a0c700 Mon Sep 17 00:00:00 2001 From: hjk Date: Tue, 13 Oct 2009 08:52:33 +0200 Subject: [PATCH 32/34] debugger: adjust dumper autotest to valuedisabled='true' -> valueeditable='false' change --- tests/auto/debugger/tst_dumpers.cpp | 49 +++++++++++++++-------------- 1 file changed, 25 insertions(+), 24 deletions(-) diff --git a/tests/auto/debugger/tst_dumpers.cpp b/tests/auto/debugger/tst_dumpers.cpp index b4ca3723c84..3a3fbef043f 100644 --- a/tests/auto/debugger/tst_dumpers.cpp +++ b/tests/auto/debugger/tst_dumpers.cpp @@ -1195,7 +1195,7 @@ template const QString &sizeStr = N(size); const QByteArray elemTypeStr = typeToString(); QByteArray expected = QByteArray("value='<").append(sizeStr). - append(" items>',valuedisabled='true',numchild='").append(sizeStr). + append(" items>',valueeditable='false',numchild='").append(sizeStr). append("',childtype='").append(elemTypeStr).append("',childnumchild='"). append(typeToNumchild()).append("',children=["); typename QLinkedList::const_iterator iter = l.constBegin(); @@ -1277,13 +1277,13 @@ void tst_Debugger::dumpQLinkedList() QLinkedList l; // Case 1.1: Empty list. - testDumper("value='<0 items>',valuedisabled='true',numchild='0'," + testDumper("value='<0 items>',valueeditable='false',numchild='0'," "childtype='int',childnumchild='0',children=[]", &l, NS"QLinkedList", true, "int"); // Case 1.2: One element. l.append(2); - testDumper("value='<1 items>',valuedisabled='true',numchild='1'," + testDumper("value='<1 items>',valueeditable='false',numchild='1'," "childtype='int',childnumchild='0',children=[{addr='%',value='2'}]" << ptrToBa(l.constBegin().operator->()), &l, NS"QLinkedList", true, "int"); @@ -1292,7 +1292,7 @@ void tst_Debugger::dumpQLinkedList() l.append(3); QByteArray it0 = ptrToBa(l.constBegin().operator->()); QByteArray it1 = ptrToBa(l.constBegin().operator++().operator->()); - testDumper("value='<2 items>',valuedisabled='true',numchild='2'," + testDumper("value='<2 items>',valueeditable='false',numchild='2'," "childtype='int',childnumchild='0',children=[{addr='%',value='2'}," "{addr='%',value='3'}]" << it0 << it1, &l, NS"QLinkedList", true, "int"); @@ -1302,7 +1302,7 @@ void tst_Debugger::dumpQLinkedList() QLinkedList::const_iterator iter; // Case 2.1: Empty list. - testDumper("value='<0 items>',valuedisabled='true',numchild='0'," + testDumper("value='<0 items>',valueeditable='false',numchild='0'," "childtype='"NS"QString',childnumchild='0',children=[]", &l2, NS"QLinkedList", true, NS"QString"); @@ -1310,13 +1310,13 @@ void tst_Debugger::dumpQLinkedList() l2.append("Teststring 1"); iter = l2.constBegin(); qDebug() << *iter; - testDumper("value='<1 items>',valuedisabled='true',numchild='1'," + testDumper("value='<1 items>',valueeditable='false',numchild='1'," "childtype='"NS"QString',childnumchild='0',children=[{addr='%',value='%',}]" << ptrToBa(iter.operator->()) << utfToBase64(*iter), &l2, NS"QLinkedList", true, NS"QString"); // Case 2.3: Two elements. - QByteArray expected = "value='<2 items>',valuedisabled='true',numchild='2'," + QByteArray expected = "value='<2 items>',valueeditable='false',numchild='2'," "childtype='int',childnumchild='0',children=["; iter = l2.constBegin(); expected.append("{addr='%',%}," @@ -1331,7 +1331,7 @@ void tst_Debugger::dumpQLinkedList() for (int i = 3; i <= 1002; ++i) l2.append("Test " + N(i)); - expected = "value='<1002 items>',valuedisabled='true'," + expected = "value='<1002 items>',valueeditable='false'," "numchild='1002',childtype='"NS"QString',childnumchild='0',children=['"; iter = l2.constBegin(); for (int i = 0; i < 1002; ++i, ++iter) @@ -1354,12 +1354,12 @@ void tst_Debugger::dumpQLinkedList() void tst_Debugger::dumpQList_int() { QList ilist; - testDumper("value='<0 items>',valuedisabled='true',numchild='0'," + testDumper("value='<0 items>',valueeditable='false',numchild='0'," "internal='1',children=[]", &ilist, NS"QList", true, "int"); ilist.append(1); ilist.append(2); - testDumper("value='<2 items>',valuedisabled='true',numchild='2'," + testDumper("value='<2 items>',valueeditable='false',numchild='2'," "internal='1',childtype='int',childnumchild='0',children=[" "{addr='" + str(&ilist.at(0)) + "',value='1'}," "{addr='" + str(&ilist.at(1)) + "',value='2'}]", @@ -1369,12 +1369,12 @@ void tst_Debugger::dumpQList_int() void tst_Debugger::dumpQList_char() { QList clist; - testDumper("value='<0 items>',valuedisabled='true',numchild='0'," + testDumper("value='<0 items>',valueeditable='false',numchild='0'," "internal='1',children=[]", &clist, NS"QList", true, "char"); clist.append('a'); clist.append('b'); - testDumper("value='<2 items>',valuedisabled='true',numchild='2'," + testDumper("value='<2 items>',valueeditable='false',numchild='2'," "internal='1',childtype='char',childnumchild='0',children=[" "{addr='" + str(&clist.at(0)) + "',value=''a', ascii=97'}," "{addr='" + str(&clist.at(1)) + "',value=''b', ascii=98'}]", @@ -1384,12 +1384,12 @@ void tst_Debugger::dumpQList_char() void tst_Debugger::dumpQList_QString() { QList slist; - testDumper("value='<0 items>',valuedisabled='true',numchild='0'," + testDumper("value='<0 items>',valueeditable='false',numchild='0'," "internal='1',children=[]", &slist, NS"QList", true, NS"QString"); slist.append("a"); slist.append("b"); - testDumper("value='<2 items>',valuedisabled='true',numchild='2'," + testDumper("value='<2 items>',valueeditable='false',numchild='2'," "internal='1',childtype='"NS"QString',childnumchild='0',children=[" "{addr='" + str(&slist.at(0)) + "',value='YQA=',valueencoded='2'}," "{addr='" + str(&slist.at(1)) + "',value='YgA=',valueencoded='2'}]", @@ -1399,12 +1399,12 @@ void tst_Debugger::dumpQList_QString() void tst_Debugger::dumpQList_Int3() { QList i3list; - testDumper("value='<0 items>',valuedisabled='true',numchild='0'," + testDumper("value='<0 items>',valueeditable='false',numchild='0'," "internal='0',children=[]", &i3list, NS"QList", true, "Int3"); i3list.append(Int3()); i3list.append(Int3()); - testDumper("value='<2 items>',valuedisabled='true',numchild='2'," + testDumper("value='<2 items>',valueeditable='false',numchild='2'," "internal='0',childtype='Int3',children=[" "{addr='" + str(&i3list.at(0)) + "'}," "{addr='" + str(&i3list.at(1)) + "'}]", @@ -1414,12 +1414,12 @@ void tst_Debugger::dumpQList_Int3() void tst_Debugger::dumpQList_QString3() { QList s3list; - testDumper("value='<0 items>',valuedisabled='true',numchild='0'," + testDumper("value='<0 items>',valueeditable='false',numchild='0'," "internal='0',children=[]", &s3list, NS"QList", true, "QString3"); s3list.append(QString3()); s3list.append(QString3()); - testDumper("value='<2 items>',valuedisabled='true',numchild='2'," + testDumper("value='<2 items>',valueeditable='false',numchild='2'," "internal='0',childtype='QString3',children=[" "{addr='" + str(&s3list.at(0)) + "'}," "{addr='" + str(&s3list.at(1)) + "'}]", @@ -1819,6 +1819,7 @@ void tst_Debugger::dumpQObjectSignalHelper(QObject &o, int sigNum) connLists != 0 && connLists->size() > sigNum ? connLists->at(sigNum) : QObjectPrivate::ConnectionList(); int i = 0; + // FIXME: 4.6 only for (QObjectPrivate::Connection *conn = connList.first; conn != 0; ++i, conn = conn->nextConnectionList) { const QString iStr = N(i); @@ -2137,7 +2138,7 @@ void tst_Debugger::dumpQSharedPointerHelper(QSharedPointer &ptr) weakAddr = strongAddr = 0; weakValue = strongValue = 0; } - expected.append(val2).append("',valuedisabled='true',numchild='1',children=["). + expected.append(val2).append("',valueeditable='false',numchild='1',children=["). append("{name='data',addr='").append(ptrToBa(ptr.data())). append("',type='").append(typeToString()).append("',value='").append(val1). append("'},{name='weakref',value='").append(N(weakValue)). @@ -2236,18 +2237,18 @@ void tst_Debugger::dumpStdVector() std::vector *> vector; QByteArray inner = "std::list *"; QByteArray innerp = "std::list"; - testDumper("value='<0 items>',valuedisabled='true',numchild='0'", + testDumper("value='<0 items>',valueeditable='false',numchild='0'", &vector, "std::vector", false, inner, "", sizeof(std::list *)); std::list list; vector.push_back(new std::list(list)); - testDumper("value='<1 items>',valuedisabled='true',numchild='1'," + testDumper("value='<1 items>',valueeditable='false',numchild='1'," "childtype='" + inner + "',childnumchild='1'," "children=[{addr='" + str(deref(&vector[0])) + "'," "saddr='" + str(deref(&vector[0])) + "',type='" + innerp + "'}]", &vector, "std::vector", true, inner, "", sizeof(std::list *)); vector.push_back(0); list.push_back(45); - testDumper("value='<2 items>',valuedisabled='true',numchild='2'," + testDumper("value='<2 items>',valueeditable='false',numchild='2'," "childtype='" + inner + "',childnumchild='1'," "children=[{addr='" + str(deref(&vector[0])) + "'," "saddr='" + str(deref(&vector[0])) + "',type='" + innerp + "'}," @@ -2297,7 +2298,7 @@ void tst_Debugger::dumpQWeakPointerHelper(QWeakPointer &ptr) QByteArray expected("value='"); if (isSimpleType()) expected.append(dataStr); - expected.append("',valuedisabled='true',numchild='1',children=[{name='data',addr='"). + expected.append("',valueeditable='false',numchild='1',children=[{name='data',addr='"). append(ptrToBa(data)).append("',type='").append(typeToString()). append("',value='").append(dataStr).append("'},{name='weakref',value='"). append(valToString(*weakRefPtr)).append("',type='int',addr='"). @@ -2316,7 +2317,7 @@ void tst_Debugger::dumpQWeakPointer() // Case 1.1: Null pointer. QSharedPointer spNull; QWeakPointer wp = spNull.toWeakRef(); - testDumper("value='',valuedisabled='true',numchild='0'", + testDumper("value='',valueeditable='false',numchild='0'", &wp, NS"QWeakPointer", true, "int"); // Case 1.2: Weak pointer is unique. From b9cd3378f737b55ff40d1d50f58aa4bdc803452b Mon Sep 17 00:00:00 2001 From: hjk Date: Tue, 13 Oct 2009 14:42:18 +0200 Subject: [PATCH 33/34] debugger: work on dumper autotests --- tests/auto/debugger/debugger.pro | 2 +- tests/auto/debugger/tst_gdb.cpp | 2324 ++++++++++++++++++++++++++++++ 2 files changed, 2325 insertions(+), 1 deletion(-) create mode 100644 tests/auto/debugger/tst_gdb.cpp diff --git a/tests/auto/debugger/debugger.pro b/tests/auto/debugger/debugger.pro index c4cadd3715f..ef1547f9ce6 100644 --- a/tests/auto/debugger/debugger.pro +++ b/tests/auto/debugger/debugger.pro @@ -1,5 +1,5 @@ TEMPLATE = subdirs -SUBDIRS = dumpers.pro plugin.pro +SUBDIRS = dumpers.pro plugin.pro gdb.pro diff --git a/tests/auto/debugger/tst_gdb.cpp b/tests/auto/debugger/tst_gdb.cpp new file mode 100644 index 00000000000..9310016b4b5 --- /dev/null +++ b/tests/auto/debugger/tst_gdb.cpp @@ -0,0 +1,2324 @@ + +#include +#include +#include + +#include + +#include +#include + +#include + +#include "gdb/gdbmi.h" + +#include +#include + + +#undef NS +#ifdef QT_NAMESPACE +# define STRINGIFY0(s) #s +# define STRINGIFY1(s) STRINGIFY0(s) +# define NS STRINGIFY1(QT_NAMESPACE) "::" +# define NSX "'" STRINGIFY1(QT_NAMESPACE) "::" +# define NSY "'" +#else +# define NS "" +# define NSX "" +# define NSY "" +#endif + +#define gettid() QString("0x%1").arg((qulonglong)(void *)currentThread(), 0, 16) + +using namespace Debugger; +using namespace Debugger::Internal; + +typedef QList QByteArrayList; + +static QByteArray operator<<(QByteArray ba, const QByteArray &replacement) +{ + int pos = ba.indexOf('%'); + Q_ASSERT(pos != -1); + return ba.replace(pos, 1, replacement); +} + +static QByteArray &operator<<=(QByteArray &ba, const QByteArray &replacement) +{ + int pos = ba.indexOf('%'); + Q_ASSERT(pos != -1); + return ba.replace(pos, 1, replacement); +} + + +template +inline QByteArray N(T t) { return QByteArray::number(t); } + + + +struct Int3 { + Int3() { i1 = 42; i2 = 43; i3 = 44; } + int i1, i2, i3; +}; + +struct QString3 { + QString3() { s1 = "a"; s2 = "b"; s3 = "c"; } + QString s1, s2, s3; +}; + +class tst_Gdb; + +class Thread : public QThread +{ + Q_OBJECT + +public: + Thread(tst_Gdb *test); + void run(); + +public slots: + void readStandardOutput(); + void readStandardError(); + void handleGdbStarted(); + void handleGdbError(QProcess::ProcessError); + void handleGdbFinished(int, QProcess::ExitStatus); + void writeToGdbRequested(const QByteArray &ba) + { + //qDebug() << "THREAD GDB IN: " << ba; + m_proc->write(ba); + m_proc->write("\n"); + } + + +public: + QByteArray m_output; + QByteArray m_error; + QProcess *m_proc; // owned + tst_Gdb *m_test; // not owned +}; + +class tst_Gdb : public QObject +{ + Q_OBJECT + +public: + tst_Gdb() : m_thread(this) {} + +public slots: + void dumperCompatibility(); + void dumpQAbstractItemAndModelIndex(); + void dumpQAbstractItemModel(); + void dumpQByteArray(); + void dumpQChar(); + void dumpQDateTime(); + void dumpQDir(); + void dumpQFile(); + void dumpQFileInfo(); + void dumpQHash(); + void dumpQHashNode(); + void dumpQImage(); + void dumpQImageData(); + void dumpQLinkedList(); + void dumpQList_int(); + void dumpQList_char(); + void dumpQList_QString(); + void dumpQList_QString3(); + void dumpQList_Int3(); + void dumpQLocale(); + void dumpQMap(); + void dumpQMapNode(); + void dumpQObject(); + void dumpQObjectChildList(); + void dumpQObjectMethodList(); + void dumpQObjectPropertyList(); + void dumpQObjectSignal(); + void dumpQObjectSignalList(); + void dumpQObjectSlot(); + void dumpQObjectSlotList(); + void dumpQPixmap(); + void dumpQSharedPointer(); + void dumpQTextCodec(); + void dumpQVariant_invalid(); + void dumpQVariant_QString(); + void dumpQVariant_QStringList(); + void dumpStdVector(); + void dumpQWeakPointer(); + void initTestCase(); + void cleanupTestCase(); + void runTestCase(const QByteArray &name, + const QByteArray &type, + const QByteArrayList &expexted); + +signals: + void writeToGdb(const QByteArray &ba); + +private slots: + void dumpQString(); + void dumpQStringList(); + +private: + void dumpQAbstractItemHelper(QModelIndex &index); + void dumpQAbstractItemModelHelper(QAbstractItemModel &m); + void dumpQDateTimeHelper(const QDateTime &d); + void dumpQFileHelper(const QString &name, bool exists); + template void dumpQHashNodeHelper(QHash &hash); + void dumpQImageHelper(const QImage &img); + void dumpQImageDataHelper(QImage &img); + template void dumpQLinkedListHelper(QLinkedList &l); + void dumpQLocaleHelper(QLocale &loc); + template void dumpQMapHelper(QMap &m); + template void dumpQMapNodeHelper(QMap &m); + void dumpQObjectChildListHelper(QObject &o); + void dumpQObjectSignalHelper(QObject &o, int sigNum); +#if QT_VERSION >= 0x040500 + template + void dumpQSharedPointerHelper(QSharedPointer &ptr); + template + void dumpQWeakPointerHelper(QWeakPointer &ptr); +#endif + void dumpQTextCodecHelper(QTextCodec *codec); + +private: + Thread m_thread; +}; + +QMutex m_mutex; +QWaitCondition m_waitCondition; + +// +// Dumpers +// + +static void testDumper(QByteArray expected, const void *data, QByteArray outertype, + bool dumpChildren, QByteArray actual____ = QByteArray(), + QByteArray = QByteArray(), int = 0, int = 0, int = 0, int = 0) +{ + Q_UNUSED(dumpChildren); + expected = "locals={iname='local',name='Locals',value=' ',type=' '," + "children=[" + expected + "],arg=''}"; + char buf[100]; + sprintf(buf, "%p", data); + //if ((!expected.startsWith('t') && !expected.startsWith('f')) + // || expected.startsWith("type")) + // expected = "tiname='$I',addr='$A'," + expected; + expected.replace("$I", "iname"); + expected.replace("$T", QByteArray(outertype)); + expected.replace("$A", QByteArray(buf)); + if (actual____ != expected) { + QByteArrayList l1 = actual____.split(','); + QByteArrayList l2 = expected.split(','); + for (int i = 0; i < l1.size() && i < l2.size(); ++i) { + if (l1.at(i) == l2.at(i)) + qWarning() << "== " << l1.at(i); + else + //qWarning() << "!= " << l1.at(i).right(30) << l2.at(i).right(30); + qWarning() << "!= " << l1.at(i) << l2.at(i); + } + if (l1.size() != l2.size()) + qWarning() << "!= size: " << l1.size() << l2.size(); + } + QCOMPARE(actual____, expected); +} + +QByteArray str(const void *p) +{ + char buf[100]; + sprintf(buf, "%p", p); + return buf; +} + +static const void *deref(const void *p) +{ + return *reinterpret_cast(p); +} + +void tst_Gdb::dumperCompatibility() +{ + // Ensure that no arbitrary padding is introduced by QVectorTypedData. + const size_t qVectorDataSize = 16; + QCOMPARE(sizeof(QVectorData), qVectorDataSize); + QVectorTypedData *v = 0; + QCOMPARE(size_t(&v->array), qVectorDataSize); +} + +static const QByteArray utfToBase64(const QString &string) +{ + return QByteArray(reinterpret_cast(string.utf16()), 2 * string.size()).toBase64(); +} + +static const char *boolToVal(bool b) +{ + return b ? "'true'" : "'false'"; +} + +static const QByteArray ptrToBa(const void *p, bool symbolicNull = true) +{ + return QByteArray().append(p == 0 && symbolicNull ? + "" : + QByteArray("0x") + QByteArray::number((quintptr) p, 16)); +} + +static const QByteArray generateQStringSpec(const QString &str) +{ + return QByteArray("value='%',type='"NS"QString',numchild='0',valueencoded='2'") + << utfToBase64(str); +} + +static const QByteArray generateQCharSpec(const QChar& ch) +{ + return QByteArray("value='%',valueencoded='2',type='"NS"QChar',numchild='0'") + << utfToBase64(QString(QLatin1String("'%1' (%2, 0x%3)")). + arg(ch).arg(ch.unicode()).arg(ch.unicode(), 0, 16)); +} + +static const QByteArray generateBoolSpec(bool b) +{ + return QByteArray("value=%,type='bool',numchild='0'") + << boolToVal(b); +} + +static const QByteArray generateLongSpec(long n) +{ + return QByteArray("value='%',type='long',numchild='0'") + << N(qlonglong(n)); +} + +static const QByteArray generateIntSpec(int n) +{ + return QByteArray("value='%',type='int',numchild='0'") + << N(n); +} + +const QByteArray createExp(const void *ptr, + const QByteArray &type, const QByteArray &method) +{ + return QByteArray("exp='(("NSX"%"NSY"*)%)->%'") + << type << ptrToBa(ptr) << method; +} + +// Helper functions. + +#ifdef Q_CC_MSVC +# define MAP_NODE_TYPE_END ">" +#else +# define MAP_NODE_TYPE_END " >" +#endif + +template static const char *typeToString() +{ + return ""; +} +template const QByteArray valToString(const T &) +{ + return ""; +} +template <> const QByteArray valToString(const int &n) +{ + return QByteArray().append(N(n)); +} +template <> const QByteArray valToString(const QString &s) +{ + return QByteArray(utfToBase64(s)).append("',valueencoded='2"); +} +template <> const QByteArray valToString(int * const &p) +{ + return ptrToBa(p); +} +template const QByteArray derefValToString(const T &v) +{ + return valToString(v); +} +template <> const QByteArray derefValToString(int * const &ptr) +{ + return valToString(*ptr); +} +const QString stripPtrType(const QString &ptrTypeStr) +{ + return ptrTypeStr.mid(0, ptrTypeStr.size() - 2); +} +template <> const char *typeToString() +{ + return "int"; +} +template <> const char *typeToString() +{ + return NS"QString"; +} +template <> const char *typeToString() +{ + return "int *"; +} +template bool isSimpleType() +{ + return false; +} +template <> bool isSimpleType() +{ + return true; +} +template bool isPointer() +{ + return false; +} +template <> bool isPointer() +{ + return true; +} + +template static const char *typeToNumchild() +{ + return "1"; +} +template <> const char *typeToNumchild() +{ + return "0"; +} +template <> const char *typeToNumchild() +{ + return "0"; +} +template +QByteArray getMapType() +{ + return QByteArray(typeToString()) + "@" + QByteArray(typeToString()); +} +template +void getMapNodeParams(size_t &nodeSize, size_t &valOffset) +{ +#if QT_VERSION >= 0x040500 + typedef QMapNode NodeType; + NodeType *node = 0; + nodeSize = sizeof(NodeType); + valOffset = size_t(&node->value); +#else + nodeSize = sizeof(K) + sizeof(V) + 2*sizeof(void *); + valOffset = sizeof(K); +#endif +} + +void tst_Gdb::dumpQAbstractItemHelper(QModelIndex &index) +{ + const QAbstractItemModel *model = index.model(); + const QString &rowStr = N(index.row()); + const QString &colStr = N(index.column()); + const QByteArray &internalPtrStrSymbolic = ptrToBa(index.internalPointer()); + const QByteArray &internalPtrStrValue = ptrToBa(index.internalPointer(), false); + const QByteArray &modelPtrStr = ptrToBa(model); + QByteArray indexSpecSymbolic = QByteArray().append(rowStr + "," + colStr + ","). + append(internalPtrStrSymbolic + "," + modelPtrStr); + QByteArray indexSpecValue = QByteArray().append(rowStr + "," + colStr + ","). + append(internalPtrStrValue + "," + modelPtrStr); + QByteArray expected = QByteArray("tiname='iname',addr='").append(ptrToBa(&index)). + append("',type='"NS"QAbstractItem',addr='$").append(indexSpecSymbolic). + append("',value='").append(valToString(model->data(index).toString())). + append("',numchild='1',children=["); + int rowCount = model->rowCount(index); + int columnCount = model->columnCount(index); + for (int row = 0; row < rowCount; ++row) { + for (int col = 0; col < columnCount; ++col) { + const QModelIndex &childIndex = model->index(row, col, index); + expected.append("{name='[").append(valToString(row)).append(","). + append(N(col)).append("]',numchild='1',addr='$"). + append(N(childIndex.row())).append(","). + append(N(childIndex.column())).append(","). + append(ptrToBa(childIndex.internalPointer())).append(","). + append(modelPtrStr).append("',type='"NS"QAbstractItem',value='"). + append(valToString(model->data(childIndex).toString())).append("'}"); + if (col < columnCount - 1 || row < rowCount - 1) + expected.append(","); + } + } + expected.append("]"); + testDumper(expected, &index, NS"QAbstractItem", true, indexSpecValue); +} + +void tst_Gdb::dumpQAbstractItemAndModelIndex() +{ + class PseudoTreeItemModel : public QAbstractItemModel + { + public: + PseudoTreeItemModel() : QAbstractItemModel(), parent1(0), + parent1Child(1), parent2(10), parent2Child1(11), parent2Child2(12) + {} + + int columnCount(const QModelIndex &parent = QModelIndex()) const + { + Q_UNUSED(parent); + return 1; + } + + QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const + { + return !index.isValid() || role != Qt::DisplayRole ? + QVariant() : *static_cast(index.internalPointer()); + } + + QModelIndex index(int row, int column, + const QModelIndex & parent = QModelIndex()) const + { + QModelIndex index; + if (column == 0) { + if (!parent.isValid()) { + if (row == 0) + index = createIndex(row, column, &parent1); + else if (row == 1) + index = createIndex(row, column, &parent2); + } else if (parent.internalPointer() == &parent1 && row == 0) { + index = createIndex(row, column, &parent1Child); + } else if (parent.internalPointer() == &parent2) { + index = createIndex(row, column, + row == 0 ? &parent2Child1 : &parent2Child2); + } + } + return index; + } + + QModelIndex parent(const QModelIndex & index) const + { + QModelIndex parent; + if (index.isValid()) { + if (index.internalPointer() == &parent1Child) + parent = createIndex(0, 0, &parent1); + else if (index.internalPointer() == &parent2Child1 || + index.internalPointer() == &parent2Child2) + parent = createIndex(1, 0, &parent2); + } + return parent; + } + + int rowCount(const QModelIndex &parent = QModelIndex()) const + { + int rowCount; + if (!parent.isValid() || parent.internalPointer() == &parent2) + rowCount = 2; + else if (parent.internalPointer() == &parent1) + rowCount = 1; + else + rowCount = 0; + return rowCount; + } + + private: + mutable int parent1; + mutable int parent1Child; + mutable int parent2; + mutable int parent2Child1; + mutable int parent2Child2; + }; + + PseudoTreeItemModel m2; + + // Case 1: ModelIndex with no children. + QStringListModel m(QStringList() << "item1" << "item2" << "item3"); + QModelIndex index = m.index(2, 0); + + testDumper(QByteArray("type='$T',value='(2, 0)',numchild='5',children=[" + "{name='row',value='2',type='int',numchild='0'}," + "{name='column',value='0',type='int',numchild='0'}," + "{name='parent',value='',exp='(('$T'*)$A)->parent()'," + "type='$T',numchild='1'}," + "{name='internalId',%}," + "{name='model',value='%',type='"NS"QAbstractItemModel*'," + "numchild='1'}]") + << generateQStringSpec(N(index.internalId())) + << ptrToBa(&m), + &index, NS"QModelIndex", true); + + // Case 2: ModelIndex with one child. + QModelIndex index2 = m2.index(0, 0); + dumpQAbstractItemHelper(index2); + + qDebug() << "FIXME: invalid indices should not have children"; + testDumper(QByteArray("type='$T',value='(0, 0)',numchild='5',children=[" + "{name='row',value='0',type='int',numchild='0'}," + "{name='column',value='0',type='int',numchild='0'}," + "{name='parent',value='',exp='(('$T'*)$A)->parent()'," + "type='$T',numchild='1'}," + "{name='internalId',%}," + "{name='model',value='%',type='"NS"QAbstractItemModel*'," + "numchild='1'}]") + << generateQStringSpec(N(index2.internalId())) + << ptrToBa(&m2), + &index2, NS"QModelIndex", true); + + + // Case 3: ModelIndex with two children. + QModelIndex index3 = m2.index(1, 0); + dumpQAbstractItemHelper(index3); + + testDumper(QByteArray("type='$T',value='(1, 0)',numchild='5',children=[" + "{name='row',value='1',type='int',numchild='0'}," + "{name='column',value='0',type='int',numchild='0'}," + "{name='parent',value='',exp='(('$T'*)$A)->parent()'," + "type='$T',numchild='1'}," + "{name='internalId',%}," + "{name='model',value='%',type='"NS"QAbstractItemModel*'," + "numchild='1'}]") + << generateQStringSpec(N(index3.internalId())) + << ptrToBa(&m2), + &index3, NS"QModelIndex", true); + + + // Case 4: ModelIndex with a parent. + index = m2.index(0, 0, index3); + testDumper(QByteArray("type='$T',value='(0, 0)',numchild='5',children=[" + "{name='row',value='0',type='int',numchild='0'}," + "{name='column',value='0',type='int',numchild='0'}," + "{name='parent',value='(1, 0)',exp='(('$T'*)$A)->parent()'," + "type='$T',numchild='1'}," + "{name='internalId',%}," + "{name='model',value='%',type='"NS"QAbstractItemModel*'," + "numchild='1'}]") + << generateQStringSpec(N(index.internalId())) + << ptrToBa(&m2), + &index, NS"QModelIndex", true); + + + // Case 5: Empty ModelIndex + QModelIndex index4; + testDumper("type='$T',value='',numchild='0'", + &index4, NS"QModelIndex", true); +} + +void tst_Gdb::dumpQAbstractItemModelHelper(QAbstractItemModel &m) +{ + QByteArray address = ptrToBa(&m); + QByteArray expected = QByteArray("tiname='iname',addr='%'," + "type='"NS"QAbstractItemModel',value='(%,%)',numchild='1',children=[" + "{numchild='1',name='"NS"QObject',addr='%',value='%'," + "valueencoded='2',type='"NS"QObject',displayedtype='%'}") + << address + << N(m.rowCount()) + << N(m.columnCount()) + << address + << utfToBase64(m.objectName()) + << m.metaObject()->className(); + + for (int row = 0; row < m.rowCount(); ++row) { + for (int column = 0; column < m.columnCount(); ++column) { + QModelIndex mi = m.index(row, column); + expected.append(QByteArray(",{name='[%,%]',value='%'," + "valueencoded='2',numchild='1',addr='$%,%,%,%'," + "type='"NS"QAbstractItem'}") + << N(row) + << N(column) + << utfToBase64(m.data(mi).toString()) + << N(mi.row()) + << N(mi.column()) + << ptrToBa(mi.internalPointer()) + << ptrToBa(mi.model())); + } + } + expected.append("]"); + testDumper(expected, &m, NS"QAbstractItemModel", true); +} + +void tst_Gdb::dumpQAbstractItemModel() +{ + // Case 1: No rows, one column. + QStringList strList; + QStringListModel model(strList); + dumpQAbstractItemModelHelper(model); + + // Case 2: One row, one column. + strList << "String 1"; + model.setStringList(strList); + dumpQAbstractItemModelHelper(model); + + // Case 3: Two rows, one column. + strList << "String 2"; + model.setStringList(strList); + dumpQAbstractItemModelHelper(model); + + // Case 4: No rows, two columns. + QStandardItemModel model2(0, 2); + dumpQAbstractItemModelHelper(model2); + + // Case 5: One row, two columns. + QStandardItem item1("Item (0,0)"); + QStandardItem item2("(Item (0,1)"); + model2.appendRow(QList() << &item1 << &item2); + dumpQAbstractItemModelHelper(model2); + + // Case 6: Two rows, two columns + QStandardItem item3("Item (1,0"); + QStandardItem item4("Item (1,1)"); + model2.appendRow(QList() << &item3 << &item4); + dumpQAbstractItemModelHelper(model); +} + +void tst_Gdb::dumpQByteArray() +{ + // Case 1: Empty object. + QByteArray ba; + testDumper("value='',valueencoded='1',type='"NS"QByteArray',numchild='0'," + "childtype='char',childnumchild='0',children=[]", + &ba, NS"QByteArray", true); + + // Case 2: One element. + ba.append('a'); + testDumper("value='YQ==',valueencoded='1',type='"NS"QByteArray',numchild='1'," + "childtype='char',childnumchild='0',children=[{value='61 (97 'a')'}]", + &ba, NS"QByteArray", true); + + // Case 3: Two elements. + ba.append('b'); + testDumper("value='YWI=',valueencoded='1',type='"NS"QByteArray',numchild='2'," + "childtype='char',childnumchild='0',children=[" + "{value='61 (97 'a')'},{value='62 (98 'b')'}]", + &ba, NS"QByteArray", true); + + // Case 4: > 100 elements. + ba = QByteArray(101, 'a'); + QByteArray children; + for (int i = 0; i < 101; i++) + children.append("{value='61 (97 'a')'},"); + children.chop(1); + testDumper(QByteArray("value='YWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFh" + "YWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFh" + "YWFhYWFhYWFhYWFhYWFhYWFhYWFhYQ== '," + "valueencoded='1',type='"NS"QByteArray',numchild='101'," + "childtype='char',childnumchild='0',children=[%]") << children, + &ba, NS"QByteArray", true); + + // Case 5: Regular and special characters and the replacement character. + ba = QByteArray("abc\a\n\r\e\'\"?"); + testDumper("value='YWJjBwoNGyciPw==',valueencoded='1',type='"NS"QByteArray'," + "numchild='10',childtype='char',childnumchild='0',children=[" + "{value='61 (97 'a')'},{value='62 (98 'b')'}," + "{value='63 (99 'c')'},{value='07 (7 '?')'}," + "{value='0a (10 '?')'},{value='0d (13 '?')'}," + "{value='1b (27 '?')'},{value='27 (39 '?')'}," + "{value='22 (34 '?')'},{value='3f (63 '?')'}]", + &ba, NS"QByteArray", true); +} + +void tst_Gdb::dumpQChar() +{ + // Case 1: Printable ASCII character. + QChar c('X'); + testDumper("value=''X', ucs=88',numchild='0'", + &c, NS"QChar", false); + + // Case 2: Printable non-ASCII character. + c = QChar(0x600); + testDumper("value=''?', ucs=1536',numchild='0'", + &c, NS"QChar", false); + + // Case 3: Non-printable ASCII character. + c = QChar::fromAscii('\a'); + testDumper("value=''?', ucs=7',numchild='0'", + &c, NS"QChar", false); + + // Case 4: Non-printable non-ASCII character. + c = QChar(0x9f); + testDumper("value=''?', ucs=159',numchild='0'", + &c, NS"QChar", false); + + // Case 5: Printable ASCII Character that looks like the replacement character. + c = QChar::fromAscii('?'); + testDumper("value=''?', ucs=63',numchild='0'", + &c, NS"QChar", false); +} + +void tst_Gdb::dumpQDateTimeHelper(const QDateTime &d) +{ + QByteArray value; + if (d.isNull()) + value = "value='(null)'"; + else + value = QByteArray("value='%',valueencoded='2'") + << utfToBase64(d.toString()); + + QByteArray expected = QByteArray("%,type='$T',numchild='3',children=[" + "{name='isNull',%}," + "{name='toTime_t',%}," + "{name='toString',%}," + "{name='toString_(ISO)',%}," + "{name='toString_(SystemLocale)',%}," + "{name='toString_(Locale)',%}]") + << value + << generateBoolSpec(d.isNull()) + << generateLongSpec((d.toTime_t())) + << generateQStringSpec(d.toString()) + << generateQStringSpec(d.toString(Qt::ISODate)) + << generateQStringSpec(d.toString(Qt::SystemLocaleDate)) + << generateQStringSpec(d.toString(Qt::LocaleDate)); + testDumper(expected, &d, NS"QDateTime", true); +} + +void tst_Gdb::dumpQDateTime() +{ + // Case 1: Null object. + QDateTime d; + dumpQDateTimeHelper(d); + + // Case 2: Non-null object. + d = QDateTime::currentDateTime(); + dumpQDateTimeHelper(d); +} + +void tst_Gdb::dumpQDir() +{ + // Case 1: Current working directory. + QDir dir = QDir::current(); + testDumper(QByteArray("value='%',valueencoded='2',type='"NS"QDir',numchild='3'," + "children=[{name='absolutePath',%},{name='canonicalPath',%}]") + << utfToBase64(dir.absolutePath()) + << generateQStringSpec(dir.absolutePath()) + << generateQStringSpec(dir.canonicalPath()), + &dir, NS"QDir", true); + + // Case 2: Root directory. + dir = QDir::root(); + testDumper(QByteArray("value='%',valueencoded='2',type='"NS"QDir',numchild='3'," + "children=[{name='absolutePath',%},{name='canonicalPath',%}]") + << utfToBase64(dir.absolutePath()) + << generateQStringSpec(dir.absolutePath()) + << generateQStringSpec(dir.canonicalPath()), + &dir, NS"QDir", true); +} + +void tst_Gdb::dumpQFileHelper(const QString &name, bool exists) +{ + QFile file(name); + QByteArray filenameAsBase64 = utfToBase64(name); + testDumper(QByteArray("value='%',valueencoded='2',type='$T',numchild='2'," + "children=[{name='fileName',value='%',type='"NS"QString'," + "numchild='0',valueencoded='2'}," + "{name='exists',value=%,type='bool',numchild='0'}]") + << filenameAsBase64 << filenameAsBase64 << boolToVal(exists), + &file, NS"QFile", true); +} + +void tst_Gdb::dumpQFile() +{ + // Case 1: Empty file name => Does not exist. + dumpQFileHelper("", false); + + // Case 2: File that is known to exist. + QTemporaryFile file; + file.open(); + dumpQFileHelper(file.fileName(), true); + + // Case 3: File with a name that most likely does not exist. + dumpQFileHelper("jfjfdskjdflsdfjfdls", false); +} + +void tst_Gdb::dumpQFileInfo() +{ + QFileInfo fi("."); + QByteArray expected("value='%',valueencoded='2',type='$T',numchild='3'," + "children=[" + "{name='absolutePath',%}," + "{name='absoluteFilePath',%}," + "{name='canonicalPath',%}," + "{name='canonicalFilePath',%}," + "{name='completeBaseName',%}," + "{name='completeSuffix',%}," + "{name='baseName',%}," +#ifdef QX + "{name='isBundle',%}," + "{name='bundleName',%}," +#endif + "{name='fileName',%}," + "{name='filePath',%}," + "{name='group',%}," + "{name='owner',%}," + "{name='path',%}," + "{name='groupid',%}," + "{name='ownerid',%}," + "{name='permissions',%}," + "{name='caching',%}," + "{name='exists',%}," + "{name='isAbsolute',%}," + "{name='isDir',%}," + "{name='isExecutable',%}," + "{name='isFile',%}," + "{name='isHidden',%}," + "{name='isReadable',%}," + "{name='isRelative',%}," + "{name='isRoot',%}," + "{name='isSymLink',%}," + "{name='isWritable',%}," + "{name='created',value='%',valueencoded='2',%," + "type='"NS"QDateTime',numchild='1'}," + "{name='lastModified',value='%',valueencoded='2',%," + "type='"NS"QDateTime',numchild='1'}," + "{name='lastRead',value='%',valueencoded='2',%," + "type='"NS"QDateTime',numchild='1'}]"); + + expected <<= utfToBase64(fi.filePath()); + expected <<= generateQStringSpec(fi.absolutePath()); + expected <<= generateQStringSpec(fi.absoluteFilePath()); + expected <<= generateQStringSpec(fi.canonicalPath()); + expected <<= generateQStringSpec(fi.canonicalFilePath()); + expected <<= generateQStringSpec(fi.completeBaseName()); + expected <<= generateQStringSpec(fi.completeSuffix()); + expected <<= generateQStringSpec(fi.baseName()); +#ifdef Q_OS_MACX + expected <<= generateBoolSpec(fi.isBundle()); + expected <<= generateQStringSpec(fi.bundleName()); +#endif + expected <<= generateQStringSpec(fi.fileName()); + expected <<= generateQStringSpec(fi.filePath()); + expected <<= generateQStringSpec(fi.group()); + expected <<= generateQStringSpec(fi.owner()); + expected <<= generateQStringSpec(fi.path()); + expected <<= generateLongSpec(fi.groupId()); + expected <<= generateLongSpec(fi.ownerId()); + expected <<= generateLongSpec(fi.permissions()); + expected <<= generateBoolSpec(fi.caching()); + expected <<= generateBoolSpec(fi.exists()); + expected <<= generateBoolSpec(fi.isAbsolute()); + expected <<= generateBoolSpec(fi.isDir()); + expected <<= generateBoolSpec(fi.isExecutable()); + expected <<= generateBoolSpec(fi.isFile()); + expected <<= generateBoolSpec(fi.isHidden()); + expected <<= generateBoolSpec(fi.isReadable()); + expected <<= generateBoolSpec(fi.isRelative()); + expected <<= generateBoolSpec(fi.isRoot()); + expected <<= generateBoolSpec(fi.isSymLink()); + expected <<= generateBoolSpec(fi.isWritable()); + expected <<= utfToBase64(fi.created().toString()); + expected <<= createExp(&fi, "QFileInfo", "created()"); + expected <<= utfToBase64(fi.lastModified().toString()); + expected <<= createExp(&fi, "QFileInfo", "lastModified()"); + expected <<= utfToBase64(fi.lastRead().toString()); + expected <<= createExp(&fi, "QFileInfo", "lastRead()"); + + testDumper(expected, &fi, NS"QFileInfo", true); +} + +void tst_Gdb::dumpQHash() +{ + QHash > hash; + hash.insert("Hallo", QList()); + hash.insert("Welt", QList() << 1); + hash.insert("!", QList() << 1 << 2); + hash.insert("!", QList() << 1 << 2); +} + +template +void tst_Gdb::dumpQHashNodeHelper(QHash &hash) +{ + typename QHash::iterator it = hash.begin(); + typedef QHashNode HashNode; + HashNode *dummy = 0; + HashNode *node = + reinterpret_cast(reinterpret_cast(const_cast(&it.key())) - + size_t(&dummy->key)); + const K &key = it.key(); + const V &val = it.value(); + QByteArray expected("value='"); + if (isSimpleType()) + expected.append(valToString(val)); + expected.append("',numchild='2',children=[{name='key',type='"). + append(typeToString()).append("',addr='").append(ptrToBa(&key)). + append("'},{name='value',type='").append(typeToString()). + append("',addr='").append(ptrToBa(&val)).append("'}]"); + testDumper(expected, node, NS"QHashNode", true, + getMapType(), "", sizeof(it.key()), sizeof(it.value())); +} + +void tst_Gdb::dumpQHashNode() +{ + // Case 1: simple type -> simple type. + QHash hash1; + hash1[2] = 3; + dumpQHashNodeHelper(hash1); + + // Case 2: simple type -> composite type. + QHash hash2; + hash2[5] = "String 7"; + dumpQHashNodeHelper(hash2); + + // Case 3: composite type -> simple type + QHash hash3; + hash3["String 11"] = 13; + dumpQHashNodeHelper(hash3); + + // Case 4: composite type -> composite type + QHash hash4; + hash4["String 17"] = "String 19"; + dumpQHashNodeHelper(hash4); +} + +void tst_Gdb::dumpQImageHelper(const QImage &img) +{ + QByteArray expected = "value='(%x%)',type='"NS"QImage',numchild='1'," + "children=[{name='data',type='"NS"QImageData',addr='%'}]" + << N(img.width()) + << N(img.height()) + << ptrToBa(&img); + testDumper(expected, &img, NS"QImage", true); +} + +void tst_Gdb::dumpQImage() +{ + // Case 1: Null image. + QImage img; + dumpQImageHelper(img); + + // Case 2: Normal image. + img = QImage(3, 700, QImage::Format_RGB555); + dumpQImageHelper(img); + + // Case 3: Invalid image. + img = QImage(100, 0, QImage::Format_Invalid); + dumpQImageHelper(img); +} + +void tst_Gdb::dumpQImageDataHelper(QImage &img) +{ + const QByteArray ba(QByteArray::fromRawData((const char*) img.bits(), img.numBytes())); + QByteArray expected = QByteArray("tiname='$I',addr='$A',type='"NS"QImageData',"). + append("numchild='0',value='',valuetooltipencoded='1',"). + append("valuetooltipsize='").append(N(ba.size())).append("',"). + append("valuetooltip='").append(ba.toBase64()).append("'"); + testDumper(expected, &img, NS"QImageData", false); +} + +void tst_Gdb::dumpQImageData() +{ + // Case 1: Null image. + QImage img; + dumpQImageDataHelper(img); + + // Case 2: Normal image. + img = QImage(3, 700, QImage::Format_RGB555); + dumpQImageDataHelper(img); + + // Case 3: Invalid image. + img = QImage(100, 0, QImage::Format_Invalid); + dumpQImageDataHelper(img); +} + +template + void tst_Gdb::dumpQLinkedListHelper(QLinkedList &l) +{ + const int size = qMin(l.size(), 1000); + const QString &sizeStr = N(size); + const QByteArray elemTypeStr = typeToString(); + QByteArray expected = QByteArray("value='<").append(sizeStr). + append(" items>',valuedisabled='true',numchild='").append(sizeStr). + append("',childtype='").append(elemTypeStr).append("',childnumchild='"). + append(typeToNumchild()).append("',children=["); + typename QLinkedList::const_iterator iter = l.constBegin(); + for (int i = 0; i < size; ++i, ++iter) { + expected.append("{"); + const T &curElem = *iter; + if (isPointer()) { + const QString typeStr = stripPtrType(typeToString()); + const QByteArray addrStr = valToString(curElem); + if (curElem != 0) { + expected.append("addr='").append(addrStr).append("',saddr='"). + append(addrStr).append("',type='").append(typeStr). + append("',value='"). + append(derefValToString(curElem)).append("'"); + } else { + expected.append("addr='").append(ptrToBa(&curElem)).append("',type='"). + append(typeStr).append("',value='',numchild='0'"); + } + } else { + expected.append("addr='").append(ptrToBa(&curElem)). + append("',value='").append(valToString(curElem)).append("'"); + } + expected.append("}"); + if (i < size - 1) + expected.append(","); + } + if (size < l.size()) + expected.append(",..."); + expected.append("]"); + testDumper(expected, &l, NS"QLinkedList", true, elemTypeStr); +} + +void tst_Gdb::dumpQLinkedList() +{ + // Case 1: Simple element type. + QLinkedList l; + + // Case 1.1: Empty list. + dumpQLinkedListHelper(l); + + // Case 1.2: One element. + l.append(2); + dumpQLinkedListHelper(l); + + // Case 1.3: Two elements + l.append(3); + dumpQLinkedListHelper(l); + + // Case 2: Composite element type. + QLinkedList l2; + + // Case 2.1: Empty list. + dumpQLinkedListHelper(l2); + + // Case 2.2: One element. + l2.append("Teststring 1"); + dumpQLinkedListHelper(l2); + + // Case 2.3: Two elements. + l2.append("Teststring 2"); + dumpQLinkedListHelper(l2); + + // Case 2.4: > 1000 elements. + for (int i = 3; i <= 1002; ++i) + l2.append("Test " + N(i)); + + // Case 3: Pointer type. + QLinkedList l3; + l3.append(new int(5)); + l3.append(new int(7)); + l3.append(0); + dumpQLinkedListHelper(l3); +} + + #if 0 + void tst_Gdb::dumpQLinkedList() + { + // Case 1: Simple element type. + QLinkedList l; + + // Case 1.1: Empty list. + testDumper("value='<0 items>',valuedisabled='true',numchild='0'," + "childtype='int',childnumchild='0',children=[]", + &l, NS"QLinkedList", true, "int"); + + // Case 1.2: One element. + l.append(2); + testDumper("value='<1 items>',valuedisabled='true',numchild='1'," + "childtype='int',childnumchild='0',children=[{addr='%',value='2'}]" + << ptrToBa(l.constBegin().operator->()), + &l, NS"QLinkedList", true, "int"); + + // Case 1.3: Two elements + l.append(3); + QByteArray it0 = ptrToBa(l.constBegin().operator->()); + QByteArray it1 = ptrToBa(l.constBegin().operator++().operator->()); + testDumper("value='<2 items>',valuedisabled='true',numchild='2'," + "childtype='int',childnumchild='0',children=[{addr='%',value='2'}," + "{addr='%',value='3'}]" << it0 << it1, + &l, NS"QLinkedList", true, "int"); + + // Case 2: Composite element type. + QLinkedList l2; + QLinkedList::const_iterator iter; + + // Case 2.1: Empty list. + testDumper("value='<0 items>',valuedisabled='true',numchild='0'," + "childtype='"NS"QString',childnumchild='0',children=[]", + &l2, NS"QLinkedList", true, NS"QString"); + + // Case 2.2: One element. + l2.append("Teststring 1"); + iter = l2.constBegin(); + qDebug() << *iter; + testDumper("value='<1 items>',valuedisabled='true',numchild='1'," + "childtype='"NS"QString',childnumchild='0',children=[{addr='%',value='%',}]" + << ptrToBa(iter.operator->()) << utfToBase64(*iter), + &l2, NS"QLinkedList", true, NS"QString"); + + // Case 2.3: Two elements. + QByteArray expected = "value='<2 items>',valuedisabled='true',numchild='2'," + "childtype='int',childnumchild='0',children=["; + iter = l2.constBegin(); + expected.append("{addr='%',%}," + << ptrToBa(iter.operator->()) << utfToBase64(*iter)); + ++iter; + expected.append("{addr='%',%}]" + << ptrToBa(iter.operator->()) << utfToBase64(*iter)); + testDumper(expected, + &l, NS"QLinkedList", true, NS"QString"); + + // Case 2.4: > 1000 elements. + for (int i = 3; i <= 1002; ++i) + l2.append("Test " + N(i)); + + expected = "value='<1002 items>',valuedisabled='true'," + "numchild='1002',childtype='"NS"QString',childnumchild='0',children=['"; + iter = l2.constBegin(); + for (int i = 0; i < 1002; ++i, ++iter) + expected.append("{addr='%',value='%'}," + << ptrToBa(iter.operator->()) << utfToBase64(*iter)); + expected.append(",...]"); + testDumper(expected, &l, NS"QLinkedList", true, NS"QString"); + + + // Case 3: Pointer type. + QLinkedList l3; + l3.append(new int(5)); + l3.append(new int(7)); + l3.append(0); + //dumpQLinkedListHelper(l3); + testDumper("", &l, NS"QLinkedList", true, NS"QString"); + } + #endif + +void tst_Gdb::dumpQList_int() +{ + QList ilist; + testDumper("value='<0 items>',valuedisabled='true',numchild='0'," + "internal='1',children=[]", + &ilist, NS"QList", true, "int"); + ilist.append(1); + ilist.append(2); + testDumper("value='<2 items>',valuedisabled='true',numchild='2'," + "internal='1',childtype='int',childnumchild='0',children=[" + "{addr='" + str(&ilist.at(0)) + "',value='1'}," + "{addr='" + str(&ilist.at(1)) + "',value='2'}]", + &ilist, NS"QList", true, "int"); +} + +void tst_Gdb::dumpQList_char() +{ + QList clist; + testDumper("value='<0 items>',valuedisabled='true',numchild='0'," + "internal='1',children=[]", + &clist, NS"QList", true, "char"); + clist.append('a'); + clist.append('b'); + testDumper("value='<2 items>',valuedisabled='true',numchild='2'," + "internal='1',childtype='char',childnumchild='0',children=[" + "{addr='" + str(&clist.at(0)) + "',value=''a', ascii=97'}," + "{addr='" + str(&clist.at(1)) + "',value=''b', ascii=98'}]", + &clist, NS"QList", true, "char"); +} + +void tst_Gdb::dumpQList_QString() +{ + QList slist; + testDumper("value='<0 items>',valuedisabled='true',numchild='0'," + "internal='1',children=[]", + &slist, NS"QList", true, NS"QString"); + slist.append("a"); + slist.append("b"); + testDumper("value='<2 items>',valuedisabled='true',numchild='2'," + "internal='1',childtype='"NS"QString',childnumchild='0',children=[" + "{addr='" + str(&slist.at(0)) + "',value='YQA=',valueencoded='2'}," + "{addr='" + str(&slist.at(1)) + "',value='YgA=',valueencoded='2'}]", + &slist, NS"QList", true, NS"QString"); +} + +void tst_Gdb::dumpQList_Int3() +{ + QList i3list; + testDumper("value='<0 items>',valuedisabled='true',numchild='0'," + "internal='0',children=[]", + &i3list, NS"QList", true, "Int3"); + i3list.append(Int3()); + i3list.append(Int3()); + testDumper("value='<2 items>',valuedisabled='true',numchild='2'," + "internal='0',childtype='Int3',children=[" + "{addr='" + str(&i3list.at(0)) + "'}," + "{addr='" + str(&i3list.at(1)) + "'}]", + &i3list, NS"QList", true, "Int3"); +} + +void tst_Gdb::dumpQList_QString3() +{ + QList s3list; + testDumper("value='<0 items>',valuedisabled='true',numchild='0'," + "internal='0',children=[]", + &s3list, NS"QList", true, "QString3"); + s3list.append(QString3()); + s3list.append(QString3()); + testDumper("value='<2 items>',valuedisabled='true',numchild='2'," + "internal='0',childtype='QString3',children=[" + "{addr='" + str(&s3list.at(0)) + "'}," + "{addr='" + str(&s3list.at(1)) + "'}]", + &s3list, NS"QList", true, "QString3"); +} + +void tst_Gdb::dumpQLocaleHelper(QLocale &loc) +{ + QByteArray expected = QByteArray("value='%',type='$T',numchild='8'," + "children=[{name='country',%}," + "{name='language',%}," + "{name='measurementSystem',%}," + "{name='numberOptions',%}," + "{name='timeFormat_(short)',%}," + "{name='timeFormat_(long)',%}," + "{name='decimalPoint',%}," + "{name='exponential',%}," + "{name='percent',%}," + "{name='zeroDigit',%}," + "{name='groupSeparator',%}," + "{name='negativeSign',%}]") + << valToString(loc.name()) + << createExp(&loc, "QLocale", "country()") + << createExp(&loc, "QLocale", "language()") + << createExp(&loc, "QLocale", "measurementSystem()") + << createExp(&loc, "QLocale", "numberOptions()") + << generateQStringSpec(loc.timeFormat(QLocale::ShortFormat)) + << generateQStringSpec(loc.timeFormat()) + << generateQCharSpec(loc.decimalPoint()) + << generateQCharSpec(loc.exponential()) + << generateQCharSpec(loc.percent()) + << generateQCharSpec(loc.zeroDigit()) + << generateQCharSpec(loc.groupSeparator()) + << generateQCharSpec(loc.negativeSign()); + testDumper(expected, &loc, NS"QLocale", true); +} + +void tst_Gdb::dumpQLocale() +{ + QLocale english(QLocale::English); + dumpQLocaleHelper(english); + + QLocale german(QLocale::German); + dumpQLocaleHelper(german); + + QLocale chinese(QLocale::Chinese); + dumpQLocaleHelper(chinese); + + QLocale swahili(QLocale::Swahili); + dumpQLocaleHelper(swahili); +} + +template + void tst_Gdb::dumpQMapHelper(QMap &map) +{ + QByteArray sizeStr(valToString(map.size())); + size_t nodeSize; + size_t valOff; + getMapNodeParams(nodeSize, valOff); + int transKeyOffset = static_cast(2*sizeof(void *)) - static_cast(nodeSize); + int transValOffset = transKeyOffset + valOff; + bool simpleKey = isSimpleType(); + bool simpleVal = isSimpleType(); + QByteArray expected = QByteArray("value='<").append(sizeStr).append(" items>',numchild='"). + append(sizeStr).append("',extra='simplekey: ").append(N(simpleKey)). + append(" isSimpleValue: ").append(N(simpleVal)). + append(" keyOffset: ").append(N(transKeyOffset)).append(" valueOffset: "). + append(N(transValOffset)).append(" mapnodesize: "). + append(N(qulonglong(nodeSize))).append("',children=["); // 64bit Linux hack + typedef typename QMap::iterator mapIter; + for (mapIter it = map.begin(); it != map.end(); ++it) { + if (it != map.begin()) + expected.append(","); + const QByteArray keyString = + QByteArray(valToString(it.key())).replace("valueencoded","keyencoded"); + expected.append("{key='").append(keyString).append("',value='"). + append(valToString(it.value())).append("',"); + if (simpleKey && simpleVal) { + expected.append("type='").append(typeToString()). + append("',addr='").append(ptrToBa(&it.value())).append("'"); + } else { + QByteArray keyTypeStr = typeToString(); + QByteArray valTypeStr = typeToString(); +#if QT_VERSION >= 0x040500 + expected.append("addr='"). + append(ptrToBa(reinterpret_cast(&(*it)) + sizeof(V))). + append("',type='"NS"QMapNode<").append(keyTypeStr).append(","). + append(valTypeStr).append(MAP_NODE_TYPE_END).append("'"); +#else + expected.append("type='"NS"QMapData::Node<").append(keyTypeStr). + append(",").append(valTypeStr).append(MAP_NODE_TYPE_END). + append("',exp='*('"NS"QMapData::Node<").append(keyTypeStr). + append(",").append(valTypeStr).append(MAP_NODE_TYPE_END). + append(" >'*)").append(ptrToBa(&(*it))).append("'"); +#endif + } + expected.append("}"); + } + expected.append("]"); + mapIter it = map.begin(); + testDumper(expected, *reinterpret_cast(&it), NS"QMap", + true, getMapType(), "", 0, 0, nodeSize, valOff); +} + +void tst_Gdb::dumpQMap() +{ + // Case 1: Simple type -> simple type. + QMap map1; + + // Case 1.1: Empty map. + dumpQMapHelper(map1); + + // Case 1.2: One element. + map1[2] = 3; + dumpQMapHelper(map1); + + // Case 1.3: Two elements. + map1[3] = 5; + dumpQMapHelper(map1); + + // Case 2: Simple type -> composite type. + QMap map2; + + // Case 2.1: Empty Map. + dumpQMapHelper(map2); + + // Case 2.2: One element. + map2[5] = "String 7"; + dumpQMapHelper(map2); + + // Case 2.3: Two elements. + map2[7] = "String 11"; + dumpQMapHelper(map2); + + // Case 3: Composite type -> simple type. + QMap map3; + + // Case 3.1: Empty map. + dumpQMapHelper(map3); + + // Case 3.2: One element. + map3["String 13"] = 11; + dumpQMapHelper(map3); + + // Case 3.3: Two elements. + map3["String 17"] = 13; + dumpQMapHelper(map3); + + // Case 4: Composite type -> composite type. + QMap map4; + + // Case 4.1: Empty map. + dumpQMapHelper(map4); + + // Case 4.2: One element. + map4["String 19"] = "String 23"; + dumpQMapHelper(map4); + + // Case 4.3: Two elements. + map4["String 29"] = "String 31"; + dumpQMapHelper(map4); + + // Case 4.4: Different value, same key (multimap functionality). + map4["String 29"] = "String 37"; + dumpQMapHelper(map4); +} + +template + void tst_Gdb::dumpQMapNodeHelper(QMap &m) +{ + typename QMap::iterator it = m.begin(); + const K &key = it.key(); + const V &val = it.value(); + //const char * const keyType = typeToString(key); + QByteArray expected = QByteArray("value='',numchild='2'," + "children=[{name='key',addr='").append(ptrToBa(&key)). + append("',type='").append(typeToString()).append("',value='"). + append(valToString(key)).append("'},{name='value',addr='"). + append(ptrToBa(&val)).append("',type='").append(typeToString()). + append("',value='").append(valToString(val)). + append("'}]"); + size_t nodeSize; + size_t valOffset; + getMapNodeParams(nodeSize, valOffset); + testDumper(expected, *reinterpret_cast(&it), NS"QMapNode", + true, getMapType(), "", 0, 0, nodeSize, valOffset); +} + +void tst_Gdb::dumpQMapNode() +{ + // Case 1: simple type -> simple type. + QMap map; + map[2] = 3; + dumpQMapNodeHelper(map); + + // Case 2: simple type -> composite type. + QMap map2; + map2[3] = "String 5"; + dumpQMapNodeHelper(map2); + + // Case 3: composite type -> simple type. + QMap map3; + map3["String 7"] = 11; + dumpQMapNodeHelper(map3); + + // Case 4: composite type -> composite type. + QMap map4; + map4["String 13"] = "String 17"; + dumpQMapNodeHelper(map4); +} + +void tst_Gdb::dumpQObject() +{ + QObject parent; + testDumper("value='',valueencoded='2',type='$T',displayedtype='QObject'," + "numchild='4'", + &parent, NS"QObject", false); + testDumper("value='',valueencoded='2',type='$T',displayedtype='QObject'," + "numchild='4',children=[" + "{name='properties',addr='$A',type='$TPropertyList'," + "value='<1 items>',numchild='1'}," + "{name='signals',addr='$A',type='$TSignalList'," + "value='<2 items>',numchild='2'}," + "{name='slots',addr='$A',type='$TSlotList'," + "value='<2 items>',numchild='2'}," + "{name='parent',value='0x0',type='$T *',numchild='0'}," + "{name='className',value='QObject',type='',numchild='0'}]", + &parent, NS"QObject", true); + +#if 0 + testDumper("numchild='2',value='<2 items>',type='QObjectSlotList'," + "children=[{name='2',value='deleteLater()'," + "numchild='0',addr='$A',type='QObjectSlot'}," + "{name='3',value='_q_reregisterTimers(void*)'," + "numchild='0',addr='$A',type='QObjectSlot'}]", + &parent, NS"QObjectSlotList", true); +#endif + + parent.setObjectName("A Parent"); + testDumper("value='QQAgAFAAYQByAGUAbgB0AA==',valueencoded='2',type='$T'," + "displayedtype='QObject',numchild='4'", + &parent, NS"QObject", false); + QObject child(&parent); + testDumper("value='',valueencoded='2',type='$T'," + "displayedtype='QObject',numchild='4'", + &child, NS"QObject", false); + child.setObjectName("A Child"); + QByteArray ba ="value='QQAgAEMAaABpAGwAZAA=',valueencoded='2',type='$T'," + "displayedtype='QObject',numchild='4',children=[" + "{name='properties',addr='$A',type='$TPropertyList'," + "value='<1 items>',numchild='1'}," + "{name='signals',addr='$A',type='$TSignalList'," + "value='<2 items>',numchild='2'}," + "{name='slots',addr='$A',type='$TSlotList'," + "value='<2 items>',numchild='2'}," + "{name='parent',addr='" + str(&parent) + "'," + "value='QQAgAFAAYQByAGUAbgB0AA==',valueencoded='2',type='$T'," + "displayedtype='QObject',numchild='1'}," + "{name='className',value='QObject',type='',numchild='0'}]"; + testDumper(ba, &child, NS"QObject", true); + connect(&child, SIGNAL(destroyed()), qApp, SLOT(quit())); + testDumper(ba, &child, NS"QObject", true); + disconnect(&child, SIGNAL(destroyed()), qApp, SLOT(quit())); + testDumper(ba, &child, NS"QObject", true); + child.setObjectName("A renamed Child"); + testDumper("value='QQAgAHIAZQBuAGEAbQBlAGQAIABDAGgAaQBsAGQA',valueencoded='2'," + "type='$T',displayedtype='QObject',numchild='4'", + &child, NS"QObject", false); +} + +void tst_Gdb::dumpQObjectChildListHelper(QObject &o) +{ + const QObjectList children = o.children(); + const int size = children.size(); + const QString sizeStr = N(size); + QByteArray expected = QByteArray("numchild='").append(sizeStr).append("',value='<"). + append(sizeStr).append(" items>',type='"NS"QObjectChildList',children=["); + for (int i = 0; i < size; ++i) { + const QObject *child = children.at(i); + expected.append("{addr='").append(ptrToBa(child)).append("',value='"). + append(utfToBase64(child->objectName())). + append("',valueencoded='2',type='"NS"QObject',displayedtype='"). + append(child->metaObject()->className()).append("',numchild='1'}"); + if (i < size - 1) + expected.append(","); + } + expected.append("]"); + testDumper(expected, &o, NS"QObjectChildList", true); +} + +void tst_Gdb::dumpQObjectChildList() +{ + // Case 1: Object with no children. + QObject o; + dumpQObjectChildListHelper(o); + + // Case 2: Object with one child. + QObject o2(&o); + dumpQObjectChildListHelper(o); + + // Case 3: Object with two children. + QObject o3(&o); + dumpQObjectChildListHelper(o); +} + +void tst_Gdb::dumpQObjectMethodList() +{ + QStringListModel m; + testDumper("addr='',type='$T',numchild='20'," + "childtype='"NS"QMetaMethod::Method',childnumchild='0',children=[" + "{name='0 0 destroyed(QObject*)',value=' (1)'}," + "{name='1 1 destroyed()',value=' (1)'}," + "{name='2 2 deleteLater()',value=' (2)'}," + "{name='3 3 _q_reregisterTimers(void*)',value=' (2)'}," + "{name='4 4 dataChanged(QModelIndex,QModelIndex)',value=' (1)'}," + "{name='5 5 headerDataChanged(Qt::Orientation,int,int)',value=' (1)'}," + "{name='6 6 layoutChanged()',value=' (1)'}," + "{name='7 7 layoutAboutToBeChanged()',value=' (1)'}," + "{name='8 8 rowsAboutToBeInserted(QModelIndex,int,int)',value=' (1)'}," + "{name='9 9 rowsInserted(QModelIndex,int,int)',value=' (1)'}," + "{name='10 10 rowsAboutToBeRemoved(QModelIndex,int,int)',value=' (1)'}," + "{name='11 11 rowsRemoved(QModelIndex,int,int)',value=' (1)'}," + "{name='12 12 columnsAboutToBeInserted(QModelIndex,int,int)',value=' (1)'}," + "{name='13 13 columnsInserted(QModelIndex,int,int)',value=' (1)'}," + "{name='14 14 columnsAboutToBeRemoved(QModelIndex,int,int)',value=' (1)'}," + "{name='15 15 columnsRemoved(QModelIndex,int,int)',value=' (1)'}," + "{name='16 16 modelAboutToBeReset()',value=' (1)'}," + "{name='17 17 modelReset()',value=' (1)'}," + "{name='18 18 submit()',value=' (2)'}," + "{name='19 19 revert()',value=' (2)'}]", + &m, NS"QObjectMethodList", true); +} + +void tst_Gdb::dumpQObjectPropertyList() +{ + // Case 1: Model without a parent. + QStringListModel m(QStringList() << "Test1" << "Test2"); + testDumper("addr='',type='$T',numchild='1',value='<1 items>'," + "children=[{name='objectName',type='QString',value=''," + "valueencoded='2',numchild='0'}]", + &m, NS"QObjectPropertyList", true); + + // Case 2: Model with a parent. + QStringListModel m2(&m); + testDumper("addr='',type='$T',numchild='1',value='<1 items>'," + "children=[{name='objectName',type='QString',value=''," + "valueencoded='2',numchild='0'}]", + &m2, NS"QObjectPropertyList", true); +} + +static const char *connectionType(uint type) +{ + Qt::ConnectionType connType = static_cast(type); + const char *output = "unknown"; + switch (connType) { + case Qt::AutoConnection: output = "auto"; break; + case Qt::DirectConnection: output = "direct"; break; + case Qt::QueuedConnection: output = "queued"; break; + case Qt::BlockingQueuedConnection: output = "blockingqueued"; break; + case 3: output = "autocompat"; break; +#if QT_VERSION >= 0x040600 + case Qt::UniqueConnection: break; // Can't happen. +#endif + default: + qWarning() << "Unknown connection type: " << type; + break; + }; + return output; +}; + +class Cheater : public QObject +{ +public: + static const QObjectPrivate *getPrivate(const QObject &o) + { + const Cheater &cheater = static_cast(o); +#if QT_VERSION >= 0x040600 + return dynamic_cast(cheater.d_ptr.data()); +#else + return dynamic_cast(cheater.d_ptr); +#endif + } +}; + +typedef QVector ConnLists; + +void tst_Gdb::dumpQObjectSignalHelper(QObject &o, int sigNum) +{ + //qDebug() << o.objectName() << sigNum; + QByteArray expected("addr='',numchild='1',type='"NS"QObjectSignal'"); +#if QT_VERSION >= 0x040400 + expected.append(",children=["); + const QObjectPrivate *p = Cheater::getPrivate(o); + Q_ASSERT(p != 0); + const ConnLists *connLists = reinterpret_cast(p->connectionLists); + QObjectPrivate::ConnectionList connList = + connLists != 0 && connLists->size() > sigNum ? + connLists->at(sigNum) : QObjectPrivate::ConnectionList(); + int i = 0; + for (QObjectPrivate::Connection *conn = connList.first; conn != 0; + ++i, conn = conn->nextConnectionList) { + const QString iStr = N(i); + expected.append("{name='").append(iStr).append(" receiver',"); + if (conn->receiver == &o) + expected.append("value='',type='"). + append(o.metaObject()->className()). + append("',numchild='0',addr='").append(ptrToBa(&o)).append("'"); + else if (conn->receiver == 0) + expected.append("value='0x0',type='"NS"QObject *',numchild='0'"); + else + expected.append("addr='").append(ptrToBa(conn->receiver)).append("',value='"). + append(utfToBase64(conn->receiver->objectName())).append("',valueencoded='2',"). + append("type='"NS"QObject',displayedtype='"). + append(conn->receiver->metaObject()->className()).append("',numchild='1'"); + expected.append("},{name='").append(iStr).append(" slot',type='',value='"); + if (conn->receiver != 0) + expected.append(conn->receiver->metaObject()->method(conn->method).signature()); + else + expected.append(""); + expected.append("',numchild='0'},{name='").append(iStr).append(" type',type='',value='<"). + append(connectionType(conn->connectionType)).append(" connection>',"). + append("numchild='0'}"); + if (conn != connList.last) + expected.append(","); + } + expected.append("],numchild='").append(N(i)).append("'"); +#endif + testDumper(expected, &o, NS"QObjectSignal", true, "", "", sigNum); +} + +void tst_Gdb::dumpQObjectSignal() +{ + // Case 1: Simple QObject. + QObject o; + o.setObjectName("Test"); + testDumper("addr='',numchild='1',type='"NS"QObjectSignal'," + "children=[],numchild='0'", + &o, NS"QObjectSignal", true, "", "", 0); + + // Case 2: QAbstractItemModel with no connections. + QStringListModel m(QStringList() << "Test1" << "Test2"); + for (int signalIndex = 0; signalIndex < 17; ++signalIndex) + dumpQObjectSignalHelper(m, signalIndex); + + // Case 3: QAbstractItemModel with connections to itself and to another + // object, using different connection types. + qRegisterMetaType("QModelIndex"); + connect(&m, SIGNAL(columnsAboutToBeInserted(const QModelIndex &, int, int)), + &o, SLOT(deleteLater()), Qt::DirectConnection); + connect(&m, SIGNAL(columnsAboutToBeRemoved(const QModelIndex &, int, int)), + &m, SLOT(revert()), Qt::QueuedConnection); + connect(&m, SIGNAL(columnsAboutToBeRemoved(const QModelIndex &, int, int)), + &m, SLOT(submit()), Qt::QueuedConnection); + connect(&m, SIGNAL(columnsInserted(const QModelIndex &, int, int)), + &m, SLOT(submit()), Qt::BlockingQueuedConnection); + connect(&m, SIGNAL(columnsRemoved(const QModelIndex &, int, int)), + &m, SLOT(deleteLater()), Qt::AutoConnection); +#if QT_VERSION >= 0x040600 + connect(&m, SIGNAL(dataChanged(const QModelIndex &, const QModelIndex &)), + &m, SLOT(revert()), Qt::UniqueConnection); +#endif + for (int signalIndex = 0; signalIndex < 17; ++signalIndex) + dumpQObjectSignalHelper(m, signalIndex); +} + +void tst_Gdb::dumpQObjectSignalList() +{ + // Case 1: Simple QObject. + QObject o; + o.setObjectName("Test"); + + testDumper("type='"NS"QObjectSignalList',value='<2 items>'," + "addr='$A',numchild='2',children=[" + "{name='0',value='destroyed(QObject*)',numchild='0'," + "addr='$A',type='"NS"QObjectSignal'}," + "{name='1',value='destroyed()',numchild='0'," + "addr='$A',type='"NS"QObjectSignal'}]", + &o, NS"QObjectSignalList", true); + + // Case 2: QAbstractItemModel with no connections. + QStringListModel m(QStringList() << "Test1" << "Test2"); + QByteArray expected = "type='"NS"QObjectSignalList',value='<16 items>'," + "addr='$A',numchild='16',children=[" + "{name='0',value='destroyed(QObject*)',numchild='0'," + "addr='$A',type='"NS"QObjectSignal'}," + "{name='1',value='destroyed()',numchild='0'," + "addr='$A',type='"NS"QObjectSignal'}," + "{name='4',value='dataChanged(QModelIndex,QModelIndex)',numchild='0'," + "addr='$A',type='"NS"QObjectSignal'}," + "{name='5',value='headerDataChanged(Qt::Orientation,int,int)'," + "numchild='0',addr='$A',type='"NS"QObjectSignal'}," + "{name='6',value='layoutChanged()',numchild='0'," + "addr='$A',type='"NS"QObjectSignal'}," + "{name='7',value='layoutAboutToBeChanged()',numchild='0'," + "addr='$A',type='"NS"QObjectSignal'}," + "{name='8',value='rowsAboutToBeInserted(QModelIndex,int,int)'," + "numchild='0',addr='$A',type='"NS"QObjectSignal'}," + "{name='9',value='rowsInserted(QModelIndex,int,int)'," + "numchild='0',addr='$A',type='"NS"QObjectSignal'}," + "{name='10',value='rowsAboutToBeRemoved(QModelIndex,int,int)'," + "numchild='%',addr='$A',type='"NS"QObjectSignal'}," + "{name='11',value='rowsRemoved(QModelIndex,int,int)'," + "numchild='%',addr='$A',type='"NS"QObjectSignal'}," + "{name='12',value='columnsAboutToBeInserted(QModelIndex,int,int)'," + "numchild='%',addr='$A',type='"NS"QObjectSignal'}," + "{name='13',value='columnsInserted(QModelIndex,int,int)'," + "numchild='%',addr='$A',type='"NS"QObjectSignal'}," + "{name='14',value='columnsAboutToBeRemoved(QModelIndex,int,int)'," + "numchild='%',addr='$A',type='"NS"QObjectSignal'}," + "{name='15',value='columnsRemoved(QModelIndex,int,int)'," + "numchild='%',addr='$A',type='"NS"QObjectSignal'}," + "{name='16',value='modelAboutToBeReset()'," + "numchild='0',addr='$A',type='"NS"QObjectSignal'}," + "{name='17',value='modelReset()'," + "numchild='0',addr='$A',type='"NS"QObjectSignal'}]"; + + testDumper(expected << "0" << "0" << "0" << "0" << "0" << "0", + &m, NS"QObjectSignalList", true); + + + // Case 3: QAbstractItemModel with connections to itself and to another + // object, using different connection types. + qRegisterMetaType("QModelIndex"); + connect(&m, SIGNAL(columnsAboutToBeInserted(QModelIndex, int, int)), + &o, SLOT(deleteLater()), Qt::DirectConnection); + connect(&m, SIGNAL(columnsAboutToBeRemoved(QModelIndex, int, int)), + &m, SLOT(revert()), Qt::QueuedConnection); + connect(&m, SIGNAL(columnsAboutToBeRemoved(QModelIndex, int, int)), + &m, SLOT(submit()), Qt::QueuedConnection); + connect(&m, SIGNAL(columnsInserted(QModelIndex, int, int)), + &m, SLOT(submit()), Qt::BlockingQueuedConnection); + connect(&m, SIGNAL(columnsRemoved(QModelIndex, int, int)), + &m, SLOT(deleteLater()), Qt::AutoConnection); + + testDumper(expected << "1" << "1" << "2" << "1" << "0" << "0", + &m, NS"QObjectSignalList", true); +} + +QByteArray slotIndexList(const QObject *ob) +{ + QByteArray slotIndices; + const QMetaObject *mo = ob->metaObject(); + for (int i = 0; i < mo->methodCount(); ++i) { + const QMetaMethod &mm = mo->method(i); + if (mm.methodType() == QMetaMethod::Slot) { + int slotIndex = mo->indexOfSlot(mm.signature()); + Q_ASSERT(slotIndex != -1); + slotIndices.append(N(slotIndex)); + slotIndices.append(','); + } + } + slotIndices.chop(1); + return slotIndices; +} + +void tst_Gdb::dumpQObjectSlot() +{ + // Case 1: Simple QObject. + QObject o; + o.setObjectName("Test"); + + QByteArray slotIndices = slotIndexList(&o); + QCOMPARE(slotIndices, QByteArray("2,3")); + QCOMPARE(o.metaObject()->indexOfSlot("deleteLater()"), 2); + + QByteArray expected = QByteArray("addr='$A',numchild='1',type='$T'," + //"children=[{name='1 sender'}],numchild='1'"); + "children=[],numchild='0'"); + qDebug() << "FIXME!"; + testDumper(expected, &o, NS"QObjectSlot", true, "", "", 2); + + + // Case 2: QAbstractItemModel with no connections. + QStringListModel m(QStringList() << "Test1" << "Test2"); + slotIndices = slotIndexList(&o); + + QCOMPARE(slotIndices, QByteArray("2,3")); + QCOMPARE(o.metaObject()->indexOfSlot("deleteLater()"), 2); + + expected = QByteArray("addr='$A',numchild='1',type='$T'," + //"children=[{name='1 sender'}],numchild='1'"); + "children=[],numchild='0'"); + qDebug() << "FIXME!"; + testDumper(expected, &o, NS"QObjectSlot", true, "", "", 2); + + + // Case 3: QAbstractItemModel with connections to itself and to another + // o, using different connection types. + qRegisterMetaType("QModelIndex"); + connect(&m, SIGNAL(columnsAboutToBeInserted(QModelIndex, int, int)), + &o, SLOT(deleteLater()), Qt::DirectConnection); + connect(&o, SIGNAL(destroyed(QObject *)), + &m, SLOT(revert()), Qt::QueuedConnection); + connect(&m, SIGNAL(columnsAboutToBeRemoved(QModelIndex, int, int)), + &m, SLOT(submit()), Qt::QueuedConnection); + connect(&m, SIGNAL(columnsInserted(QModelIndex, int, int)), + &m, SLOT(submit()), Qt::BlockingQueuedConnection); + connect(&m, SIGNAL(columnsRemoved(QModelIndex, int, int)), + &m, SLOT(deleteLater()), Qt::AutoConnection); +#if QT_VERSION >= 0x040600 + connect(&m, SIGNAL(dataChanged(QModelIndex, QModelIndex)), + &m, SLOT(revert()), Qt::UniqueConnection); +#endif + expected = QByteArray("addr='$A',numchild='1',type='$T'," + //"children=[{name='1 sender'}],numchild='1'"); + "children=[],numchild='0'"); + qDebug() << "FIXME!"; + testDumper(expected, &o, NS"QObjectSlot", true, "", "", 2); + +} + +void tst_Gdb::dumpQObjectSlotList() +{ + // Case 1: Simple QObject. + QObject o; + o.setObjectName("Test"); + testDumper("numchild='2',value='<2 items>',type='$T'," + "children=[{name='2',value='deleteLater()',numchild='0'," + "addr='$A',type='"NS"QObjectSlot'}," + "{name='3',value='_q_reregisterTimers(void*)',numchild='0'," + "addr='$A',type='"NS"QObjectSlot'}]", + &o, NS"QObjectSlotList", true); + + // Case 2: QAbstractItemModel with no connections. + QStringListModel m(QStringList() << "Test1" << "Test2"); + testDumper("numchild='4',value='<4 items>',type='$T'," + "children=[{name='2',value='deleteLater()',numchild='0'," + "addr='$A',type='"NS"QObjectSlot'}," + "{name='3',value='_q_reregisterTimers(void*)',numchild='0'," + "addr='$A',type='"NS"QObjectSlot'}," + "{name='18',value='submit()',numchild='0'," + "addr='$A',type='"NS"QObjectSlot'}," + "{name='19',value='revert()',numchild='0'," + "addr='$A',type='"NS"QObjectSlot'}]", + &m, NS"QObjectSlotList", true); + + // Case 3: QAbstractItemModel with connections to itself and to another + // object, using different connection types. + qRegisterMetaType("QModelIndex"); + connect(&m, SIGNAL(columnsAboutToBeInserted(QModelIndex, int, int)), + &o, SLOT(deleteLater()), Qt::DirectConnection); + connect(&m, SIGNAL(columnsAboutToBeRemoved(QModelIndex, int, int)), + &m, SLOT(revert()), Qt::QueuedConnection); + connect(&m, SIGNAL(columnsAboutToBeRemoved(QModelIndex, int, int)), + &m, SLOT(submit()), Qt::QueuedConnection); + connect(&m, SIGNAL(columnsInserted(QModelIndex, int, int)), + &m, SLOT(submit()), Qt::BlockingQueuedConnection); + connect(&m, SIGNAL(columnsRemoved(QModelIndex, int, int)), + &m, SLOT(deleteLater()), Qt::AutoConnection); + connect(&o, SIGNAL(destroyed(QObject *)), &m, SLOT(submit())); + testDumper("numchild='4',value='<4 items>',type='$T'," + "children=[{name='2',value='deleteLater()',numchild='0'," + "addr='$A',type='"NS"QObjectSlot'}," + "{name='3',value='_q_reregisterTimers(void*)',numchild='0'," + "addr='$A',type='"NS"QObjectSlot'}," + "{name='18',value='submit()',numchild='0'," + "addr='$A',type='"NS"QObjectSlot'}," + "{name='19',value='revert()',numchild='0'," + "addr='$A',type='"NS"QObjectSlot'}]", + &m, NS"QObjectSlotList", true); +} + +void tst_Gdb::dumpQPixmap() +{ + // Case 1: Null Pixmap. + QPixmap p; + + testDumper("value='(0x0)',type='$T',numchild='0'", + &p, NS"QPixmap", true); + + + // Case 2: Uninitialized non-null pixmap. + p = QPixmap(20, 100); + testDumper("value='(20x100)',type='$T',numchild='0'", + &p, NS"QPixmap", true); + + + // Case 3: Initialized non-null pixmap. + const char * const pixmap[] = { + "2 24 3 1", " c None", ". c #DBD3CB", "+ c #FCFBFA", + " ", " ", " ", ".+", ".+", ".+", ".+", ".+", ".+", ".+", ".+", ".+", + ".+", ".+", ".+", ".+", ".+", ".+", ".+", ".+", ".+", " ", " ", " " + }; + p = QPixmap(pixmap); + testDumper("value='(2x24)',type='$T',numchild='0'", + &p, NS"QPixmap", true); +} + +#if QT_VERSION >= 0x040500 +template +void tst_Gdb::dumpQSharedPointerHelper(QSharedPointer &ptr) +{ + struct Cheater : public QSharedPointer + { + static const typename QSharedPointer::Data *getData(const QSharedPointer &p) + { + return static_cast(p).d; + } + }; + + QByteArray expected("value='"); + QString val1 = ptr.isNull() ? "" : valToString(*ptr.data()); + QString val2 = isSimpleType() ? val1 : ""; +/* + const int *weakAddr; + const int *strongAddr; + int weakValue; + int strongValue; + if (!ptr.isNull()) { + weakAddr = reinterpret_cast(&Cheater::getData(ptr)->weakref); + strongAddr = reinterpret_cast(&Cheater::getData(ptr)->strongref); + weakValue = *weakAddr; + strongValue = *strongAddr; + } else { + weakAddr = strongAddr = 0; + weakValue = strongValue = 0; + } + expected.append(val2).append("',valuedisabled='true',numchild='1',children=["). + append("{name='data',addr='").append(ptrToBa(ptr.data())). + append("',type='").append(typeToString()).append("',value='").append(val1). + append("'},{name='weakref',value='").append(N(weakValue)). + append("',type='int',addr='").append(ptrToBa(weakAddr)).append("',numchild='0'},"). + append("{name='strongref',value='").append(N(strongValue)). + append("',type='int',addr='").append(ptrToBa(strongAddr)).append("',numchild='0'}]"); + testDumper(expected, &ptr, NS"QSharedPointer", true, typeToString()); +*/ +} +#endif + +void tst_Gdb::dumpQSharedPointer() +{ +#if QT_VERSION >= 0x040500 + // Case 1: Simple type. + // Case 1.1: Null pointer. + QSharedPointer simplePtr; + dumpQSharedPointerHelper(simplePtr); + + // Case 1.2: Non-null pointer, + QSharedPointer simplePtr2(new int(99)); + dumpQSharedPointerHelper(simplePtr2); + + // Case 1.3: Shared pointer. + QSharedPointer simplePtr3 = simplePtr2; + dumpQSharedPointerHelper(simplePtr2); + + // Case 1.4: Weak pointer. + QWeakPointer simplePtr4(simplePtr2); + dumpQSharedPointerHelper(simplePtr2); + + // Case 2: Composite type. + // Case 1.1: Null pointer. + QSharedPointer compositePtr; + // TODO: This case is not handled in gdbmacros.cpp (segfault!) + //dumpQSharedPointerHelper(compoistePtr); + + // Case 1.2: Non-null pointer, + QSharedPointer compositePtr2(new QString("Test")); + dumpQSharedPointerHelper(compositePtr2); + + // Case 1.3: Shared pointer. + QSharedPointer compositePtr3 = compositePtr2; + dumpQSharedPointerHelper(compositePtr2); + + // Case 1.4: Weak pointer. + QWeakPointer compositePtr4(compositePtr2); + dumpQSharedPointerHelper(compositePtr2); +#endif +} + +void tst_Gdb::dumpQVariant_invalid() +{ + QVariant v; + testDumper("value='(invalid)',type='$T',numchild='0'", + &v, NS"QVariant", false); +} + +void tst_Gdb::dumpQVariant_QString() +{ + QVariant v = "abc"; + testDumper("value='KFFTdHJpbmcpICJhYmMi',valueencoded='5',type='$T'," + "numchild='0'", + &v, NS"QVariant", true); +/* + FIXME: the QString version should have a child: + testDumper("value='KFFTdHJpbmcpICJhYmMi',valueencoded='5',type='$T'," + "numchild='1',children=[{name='value',value='IgBhAGIAYwAiAA=='," + "valueencoded='4',type='QString',numchild='0'}]", + &v, NS"QVariant", true); +*/ +} + +void tst_Gdb::dumpQVariant_QStringList() +{ + QVariant v = QStringList() << "Hi"; + testDumper("value='(QStringList) ',type='$T',numchild='1'," + "children=[{name='value',exp='(*('myns::QStringList'*)%)'," + "type='QStringList',numchild='1'}]" + << QByteArray::number(quintptr(&v)), + &v, NS"QVariant", true); +} + +void tst_Gdb::dumpStdVector() +{ + std::vector *> vector; + QByteArray inner = "std::list *"; + QByteArray innerp = "std::list"; + testDumper("value='<0 items>',valuedisabled='true',numchild='0'", + &vector, "std::vector", false, inner, "", sizeof(std::list *)); + std::list list; + vector.push_back(new std::list(list)); + testDumper("value='<1 items>',valuedisabled='true',numchild='1'," + "childtype='" + inner + "',childnumchild='1'," + "children=[{addr='" + str(deref(&vector[0])) + "'," + "saddr='" + str(deref(&vector[0])) + "',type='" + innerp + "'}]", + &vector, "std::vector", true, inner, "", sizeof(std::list *)); + vector.push_back(0); + list.push_back(45); + testDumper("value='<2 items>',valuedisabled='true',numchild='2'," + "childtype='" + inner + "',childnumchild='1'," + "children=[{addr='" + str(deref(&vector[0])) + "'," + "saddr='" + str(deref(&vector[0])) + "',type='" + innerp + "'}," + "{addr='" + str(&vector[1]) + "'," + "type='" + innerp + "',value='',numchild='0'}]", + &vector, "std::vector", true, inner, "", sizeof(std::list *)); + vector.push_back(new std::list(list)); + vector.push_back(0); +} + +void tst_Gdb::dumpQTextCodecHelper(QTextCodec *codec) +{ + const QByteArray name = codec->name().toBase64(); + QByteArray expected = QByteArray("value='%',valueencoded='1',type='$T'," + "numchild='2',children=[{name='name',value='%',type='"NS"QByteArray'," + "numchild='0',valueencoded='1'},{name='mibEnum',%}]") + << name << name << generateIntSpec(codec->mibEnum()); + testDumper(expected, codec, NS"QTextCodec", true); +} + +void tst_Gdb::dumpQTextCodec() +{ + const QList &codecNames = QTextCodec::availableCodecs(); + foreach (const QByteArray &codecName, codecNames) + dumpQTextCodecHelper(QTextCodec::codecForName(codecName)); +} + +#if QT_VERSION >= 0x040500 +template + size_t offsetOf(const T1 *klass, const T2 *member) +{ + return static_cast(reinterpret_cast(member) - + reinterpret_cast(klass)); +} + +template +void tst_Gdb::dumpQWeakPointerHelper(QWeakPointer &ptr) +{ + typedef QtSharedPointer::ExternalRefCountData Data; + const size_t dataOffset = 0; + const Data *d = *reinterpret_cast( + reinterpret_cast(&ptr) + dataOffset); + const int *weakRefPtr = reinterpret_cast(&d->weakref); + const int *strongRefPtr = reinterpret_cast(&d->strongref); + T *data = ptr.toStrongRef().data(); + const QString dataStr = valToString(*data); + QByteArray expected("value='"); + if (isSimpleType()) + expected.append(dataStr); + expected.append("',valuedisabled='true',numchild='1',children=[{name='data',addr='"). + append(ptrToBa(data)).append("',type='").append(typeToString()). + append("',value='").append(dataStr).append("'},{name='weakref',value='"). + append(valToString(*weakRefPtr)).append("',type='int',addr='"). + append(ptrToBa(weakRefPtr)).append("',numchild='0'},{name='strongref',value='"). + append(valToString(*strongRefPtr)).append("',type='int',addr='"). + append(ptrToBa(strongRefPtr)).append("',numchild='0'}]"); + testDumper(expected, &ptr, NS"QWeakPointer", true, typeToString()); +} +#endif + +void tst_Gdb::dumpQWeakPointer() +{ +#if QT_VERSION >= 0x040500 + // Case 1: Simple type. + + // Case 1.1: Null pointer. + QSharedPointer spNull; + QWeakPointer wp = spNull.toWeakRef(); + testDumper("value='',valuedisabled='true',numchild='0'", + &wp, NS"QWeakPointer", true, "int"); + + // Case 1.2: Weak pointer is unique. + QSharedPointer sp(new int(99)); + wp = sp.toWeakRef(); + dumpQWeakPointerHelper(wp); + + // Case 1.3: There are other weak pointers. + QWeakPointer wp2 = sp.toWeakRef(); + dumpQWeakPointerHelper(wp); + + // Case 1.4: There are other strong shared pointers as well. + QSharedPointer sp2(sp); + dumpQWeakPointerHelper(wp); + + // Case 2: Composite type. + QSharedPointer spS(new QString("Test")); + QWeakPointer wpS = spS.toWeakRef(); + dumpQWeakPointerHelper(wpS); +#endif +} + +#define VERIFY_OFFSETOF(member) \ +do { \ + QObjectPrivate *qob = 0; \ + ObjectPrivate *ob = 0; \ + QVERIFY(size_t(&qob->member) == size_t(&ob->member)); \ +} while (0) + + +Thread::Thread(tst_Gdb *test) +{ + moveToThread(this); + m_test = test; + m_proc = 0; + m_proc = new QProcess; + m_proc->moveToThread(this); + qDebug() << "\nTHREAD CREATED" << getpid() << gettid(); + connect(m_test, SIGNAL(writeToGdb(QByteArray)), + this, SLOT(writeToGdbRequested(QByteArray))); + connect(m_proc, SIGNAL(error(QProcess::ProcessError)), + this, SLOT(handleGdbError(QProcess::ProcessError))); + connect(m_proc, SIGNAL(finished(int, QProcess::ExitStatus)), + this, SLOT(handleGdbFinished(int, QProcess::ExitStatus))); + connect(m_proc, SIGNAL(started()), + this, SLOT(handleGdbStarted())); + connect(m_proc, SIGNAL(readyReadStandardOutput()), + this, SLOT(readStandardOutput())); + connect(m_proc, SIGNAL(readyReadStandardError()), + this, SLOT(readStandardError())); + start(); +} + +void Thread::handleGdbError(QProcess::ProcessError) +{ + qDebug() << "GDB ERROR: "; +} + +void Thread::handleGdbFinished(int, QProcess::ExitStatus) +{ + qDebug() << "GDB FINISHED: "; +} + +void Thread::readStandardOutput() +{ + QByteArray ba = m_proc->readAllStandardOutput(); + if (ba.isEmpty()) + return; + // =library-loaded... + if (ba.startsWith("=")) + return; + //if (ba.startsWith("~")) + // return; + if (!ba.startsWith("~\"locals=")) + return; + //qDebug() << "THREAD GDB OUT: " << ba; + //m_output += ba; + ba = ba.mid(2, ba.size() - 4); + ba = ba.replace("\\\"", "\""); + m_output = ba; + m_waitCondition.wakeAll(); +} + +void Thread::readStandardError() +{ + return; + QByteArray ba = m_proc->readAllStandardOutput(); + qDebug() << "THREAD GDB ERR: " << ba; + m_error += ba; + m_waitCondition.wakeAll(); +} + +void Thread::handleGdbStarted() +{ + //qDebug() << "\n\nGDB STARTED" << getpid() << gettid() << "\n\n"; +} + +void Thread::run() +{ + //qDebug() << "\nTHREAD RUN" << getpid() << gettid(); + m_proc->start("./gdb -i mi --args ./tst_gdb run"); + m_proc->waitForStarted(); + m_proc->write("b main\n"); + m_proc->write("run\n"); + m_proc->write("handle SIGSTOP stop pass\n"); + //qDebug() << "\nTHREAD RUNNING"; + exec(); +} + +void tst_Gdb::initTestCase() +{ + // FIXME: Wait until gdb proc is running. + QTest::qWait(1000); +} + + +void tst_Gdb::runTestCase(const QByteArray &name, const QByteArray &type, + const QByteArrayList &expected) +{ + //qDebug() << "\nABOUT TO RUN TEST: " << name << m_thread.m_proc; + + writeToGdb("b " + name); + + for (int i = 0; i != expected.size(); ++i) { + if (i == 0) + writeToGdb("call " + name + "()"); + else + writeToGdb("next"); + writeToGdb("bb"); + m_mutex.lock(); + m_waitCondition.wait(&m_mutex); + QByteArray ba = m_thread.m_output; + m_mutex.unlock(); + //GdbMi locals; + //locals.fromString("{" + ba + "}"); + QByteArray received = ba.replace("\"", "'"); + //qDebug() << "OUTPUT: " << ba << "\n\n"; + //qDebug() << "OUTPUT: " << locals.toString() << "\n\n"; + testDumper(expected.at(i), 0, type, false, received); + } +} + +void tst_Gdb::cleanupTestCase() +{ + writeToGdb("kill"); + writeToGdb("quit"); + //m_thread.m_proc->waitForFinished(); +} + +void dumpQStringTest() +{ + QString s; + s = "hallo"; + s += "x"; + s += "y"; +} + +void tst_Gdb::dumpQString() +{ + QByteArrayList bal; + + bal.append("{iname='local.s',addr='0xbffff19c',name='S'," + "type='"NS"QString',value='',numchild='0'}"); + + //bal.append("xxx"); + //bal.append("xxx"); + runTestCase("dumpQStringTest", NS"QString", bal); +/* + testDumper("value='',valueencoded='2',type='$T',numchild='0'", + &s, NS"QString", false); + s = "abc"; + testDumper("value='YQBiAGMA',valueencoded='2',type='$T',numchild='0'", + &s, NS"QString", false); +*/ +} + +void dumpQStringListTest() +{ + QStringList s; +} + +void tst_Gdb::dumpQStringList() +{ + QByteArrayList bal; + //bal.append("xxx"); + runTestCase("dumpQStringListTest", NS"QStringList", bal); +} + +int runit(int &argc, char *argv[]) +{ + // Plain call. Start the testing. + QApplication app(argc, argv); + tst_Gdb test; + return QTest::qExec(&test, argc, argv); +} + +int main(int argc, char *argv[]) +{ + if (argc == 2 && QByteArray(argv[1]) == "run") { + // We are the debugged process, recursively called and steered + // by our spawning alter ego. + return 0; + } + + return runit(argc, argv); +} + +#include "tst_gdb.moc" + From ceaa92ecbb0b54bd34bbd8d713c9e62ceb32c3ad Mon Sep 17 00:00:00 2001 From: dt Date: Tue, 13 Oct 2009 17:17:08 +0200 Subject: [PATCH 34/34] Set correct mime type for C++ files. --- src/plugins/cppeditor/cppeditor.cpp | 8 ++++++++ src/plugins/cppeditor/cppeditor.h | 1 + src/plugins/cppeditor/cppplugin.cpp | 1 - 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/plugins/cppeditor/cppeditor.cpp b/src/plugins/cppeditor/cppeditor.cpp index f53b7aae759..a9f9ea95882 100644 --- a/src/plugins/cppeditor/cppeditor.cpp +++ b/src/plugins/cppeditor/cppeditor.cpp @@ -67,6 +67,7 @@ #include #include #include +#include #include #include #include @@ -1751,6 +1752,13 @@ const char *CPPEditorEditable::kind() const return CppEditor::Constants::CPPEDITOR_KIND; } +bool CPPEditorEditable::open(const QString & fileName) +{ + bool b = TextEditor::BaseTextEditorEditable::open(fileName); + editor()->setMimeType(Core::ICore::instance()->mimeDatabase()->findByFile(QFileInfo(fileName)).type()); + return b; +} + void CPPEditor::setFontSettings(const TextEditor::FontSettings &fs) { TextEditor::BaseTextEditor::setFontSettings(fs); diff --git a/src/plugins/cppeditor/cppeditor.h b/src/plugins/cppeditor/cppeditor.h index 699cb9e49fa..68159ee9100 100644 --- a/src/plugins/cppeditor/cppeditor.h +++ b/src/plugins/cppeditor/cppeditor.h @@ -164,6 +164,7 @@ public: const char *kind() const; bool isTemporary() const { return false; } + virtual bool open(const QString & fileName); private: QList m_context; diff --git a/src/plugins/cppeditor/cppplugin.cpp b/src/plugins/cppeditor/cppplugin.cpp index 3372fd336d1..f27e82bdb96 100644 --- a/src/plugins/cppeditor/cppplugin.cpp +++ b/src/plugins/cppeditor/cppplugin.cpp @@ -97,7 +97,6 @@ Core::IEditor *CppEditorFactory::createEditor(QWidget *parent) { CPPEditor *editor = new CPPEditor(parent); editor->setRevisionsVisible(true); - editor->setMimeType(CppEditor::Constants::CPP_SOURCE_MIMETYPE); m_owner->initializeEditor(editor); return editor->editableInterface(); }