diff --git a/src/plugins/cmakeprojectmanager/cmakeproject.cpp b/src/plugins/cmakeprojectmanager/cmakeproject.cpp index 45df839ff0f7552e5dea0828dfe168de12e904a7..b048257b8a1e523e5af90b86651e27c83fb26951 100644 --- a/src/plugins/cmakeprojectmanager/cmakeproject.cpp +++ b/src/plugins/cmakeprojectmanager/cmakeproject.cpp @@ -260,6 +260,7 @@ void CMakeProject::parseCMakeLists() QString CMakeProject::buildParser(const QString &buildConfiguration) const { + Q_UNUSED(buildConfiguration); // TODO this is actually slightly wrong, but do i care? // this should call toolchain(buildConfiguration) if (!m_toolChain) diff --git a/src/plugins/coreplugin/navigationwidget.cpp b/src/plugins/coreplugin/navigationwidget.cpp index 2e360155908dc726ff2aa74ec7791a9d3b8c71a4..f1940975467196da52c67dd1190784b764f9e419 100644 --- a/src/plugins/coreplugin/navigationwidget.cpp +++ b/src/plugins/coreplugin/navigationwidget.cpp @@ -238,16 +238,27 @@ void NavigationWidget::saveSettings(QSettings *settings) void NavigationWidget::restoreSettings(QSettings *settings) { - if (settings->contains("Navigation/Views")) { - QStringList views = settings->value("Navigation/Views").toStringList(); - for (int i=0; i<views.count()-1; ++i) { - insertSubItem(0); - } - for (int i=0; i<views.count(); ++i) { - const QString &view = views.at(i); - NavigationSubWidget *nsw = m_subWidgets.at(i); - nsw->setFactory(view); + int version = settings->value("Navigation/Version", 1).toInt(); + QStringList views = settings->value("Navigation/Views").toStringList(); + + bool restoreSplitterState = true; + if (version == 1) { + if (views.isEmpty()) + views += "Projects"; + if (!views.contains("Open Documents")) { + views += "Open Documents"; + restoreSplitterState = false; } + settings->setValue("Navigation/Version", 2); + } + + for (int i=0; i<views.count()-1; ++i) { + insertSubItem(0); + } + for (int i=0; i<views.count(); ++i) { + const QString &view = views.at(i); + NavigationSubWidget *nsw = m_subWidgets.at(i); + nsw->setFactory(view); } if (settings->contains("Navigation/Visible")) { @@ -256,8 +267,15 @@ void NavigationWidget::restoreSettings(QSettings *settings) setShown(true); } - if (settings->contains("Navigation/VerticalPosition")) + if (restoreSplitterState && settings->contains("Navigation/VerticalPosition")) { restoreState(settings->value("Navigation/VerticalPosition").toByteArray()); + } else { + QList<int> sizes; + sizes += 256; + for (int i = views.size()-1; i; --i) + sizes.prepend(512); + setSizes(sizes); + } if (settings->contains("Navigation/Width")) { m_width = settings->value("Navigation/Width").toInt(); diff --git a/src/plugins/cpptools/cppcodecompletion.cpp b/src/plugins/cpptools/cppcodecompletion.cpp index 35b751104d39882b6c8d21426f3f2734b0eb1da0..2bdaa6445f632d134fcb720235b83d1f80c18d61 100644 --- a/src/plugins/cpptools/cppcodecompletion.cpp +++ b/src/plugins/cpptools/cppcodecompletion.cpp @@ -1209,10 +1209,7 @@ void CppCodeCompletion::complete(const TextEditor::CompletionItem &item) if (Function *function = symbol->type()->asFunctionType()) { // If the member is a function, automatically place the opening parenthesis, // except when it might take template parameters. - const bool hasReturnType = function->returnType().isValid() || - function->returnType().isSigned() || - function->returnType().isUnsigned(); - if (! hasReturnType && (function->identity() && !function->identity()->isDestructorNameId())) { + if (! function->hasReturnType() && (function->identity() && !function->identity()->isDestructorNameId())) { // Don't insert any magic, since the user might have just wanted to select the class } else if (function->templateParameterCount() != 0) { @@ -1224,8 +1221,7 @@ void CppCodeCompletion::complete(const TextEditor::CompletionItem &item) extraChars += QLatin1Char('('); // If the function takes no arguments, automatically place the closing parenthesis - if (function->argumentCount() == 0 || (function->argumentCount() == 1 && - function->argumentAt(0)->type()->isVoidType())) { + if (item.m_duplicateCount == 0 && ! function->hasArguments()) { extraChars += QLatin1Char(')'); // If the function doesn't return anything, automatically place the semicolon, diff --git a/src/plugins/debugger/cdb/cdb.pri b/src/plugins/debugger/cdb/cdb.pri index 27186577c3041746f0c48c5952df1c72d3daba6b..8ba7d3a68650872f537992b0c9fd5fd50b18a6c2 100644 --- a/src/plugins/debugger/cdb/cdb.pri +++ b/src/plugins/debugger/cdb/cdb.pri @@ -22,12 +22,16 @@ HEADERS += \ $$PWD/cdbdebugengine.h \ $$PWD/cdbdebugengine_p.h \ $$PWD/cdbdebugeventcallback.h \ - $$PWD/cdbdebugoutput.h + $$PWD/cdbdebugoutput.h \ + $$PWD/cdbsymbolgroupcontext.h \ + $$PWD/cdbstacktracecontext.h SOURCES += \ $$PWD/cdbdebugengine.cpp \ $$PWD/cdbdebugeventcallback.cpp \ - $$PWD/cdbdebugoutput.cpp + $$PWD/cdbdebugoutput.cpp \ + $$PWD/cdbsymbolgroupcontext.cpp \ + $$PWD/cdbstacktracecontext.cpp } else { message("Debugging Tools for Windows could not be found in $$CDB_PATH") } diff --git a/src/plugins/debugger/cdb/cdbdebugengine.cpp b/src/plugins/debugger/cdb/cdbdebugengine.cpp index 73d3953ffb3a51dc3a83ea0fa91bbe11917923a0..7d054e68dd430d24dd42de3d94ad47ad38d3c04b 100644 --- a/src/plugins/debugger/cdb/cdbdebugengine.cpp +++ b/src/plugins/debugger/cdb/cdbdebugengine.cpp @@ -29,6 +29,8 @@ #include "cdbdebugengine.h" #include "cdbdebugengine_p.h" +#include "cdbsymbolgroupcontext.h" +#include "cdbstacktracecontext.h" #include "debuggermanager.h" #include "breakhandler.h" @@ -55,7 +57,12 @@ static const char *dbgEngineDllC = "dbgeng"; static const char *debugCreateFuncC = "DebugCreate"; -static QString msgDebugEngineComResult(HRESULT hr) +static const char *localSymbolRootC = "local"; + +namespace Debugger { +namespace Internal { + +QString msgDebugEngineComResult(HRESULT hr) { switch (hr) { case S_OK: @@ -87,13 +94,12 @@ static QString msgStackIndexOutOfRange(int idx, int size) return QString::fromLatin1("Frame index %1 out of range (%2).").arg(idx).arg(size); } -static QString msgComFailed(const char *func, HRESULT hr) +QString msgComFailed(const char *func, HRESULT hr) { return QString::fromLatin1("%1 failed: %2").arg(QLatin1String(func), msgDebugEngineComResult(hr)); } -namespace Debugger { -namespace Internal { +static const char *msgNoStackTraceC = "Internal error: no stack trace present."; DebuggerEngineLibrary::DebuggerEngineLibrary() : m_debugCreate(0) @@ -138,6 +144,7 @@ CdbDebugEnginePrivate::CdbDebugEnginePrivate(DebuggerManager *parent, CdbDebugEn m_engine(engine), m_debuggerManager(parent), m_debuggerManagerAccess(parent->engineInterface()), + m_currentStackTrace(0), m_mode(AttachCore) { } @@ -205,6 +212,7 @@ IDebuggerEngine *CdbDebugEngine::create(DebuggerManager *parent) CdbDebugEnginePrivate::~CdbDebugEnginePrivate() { + cleanStackTrace(); if (m_pDebugClient) m_pDebugClient->Release(); if (m_pDebugControl) @@ -217,6 +225,17 @@ CdbDebugEnginePrivate::~CdbDebugEnginePrivate() m_pDebugRegisters->Release(); } +void CdbDebugEnginePrivate::cleanStackTrace() +{ + if (debugCDB) + qDebug() << Q_FUNC_INFO; + + if (m_currentStackTrace) { + delete m_currentStackTrace; + m_currentStackTrace = 0; + } +} + CdbDebugEngine::CdbDebugEngine(DebuggerManager *parent) : IDebuggerEngine(parent), m_d(new CdbDebugEnginePrivate(parent, this)) @@ -366,6 +385,7 @@ void CdbDebugEngine::processTerminated(unsigned long exitCode) if (debugCDB) qDebug() << Q_FUNC_INFO << exitCode; + m_d->cleanStackTrace(); m_d->setDebuggeeHandles(0, 0); m_d->m_debuggerManagerAccess->notifyInferiorExited(); m_d->m_debuggerManager->exitDebugger(); @@ -377,6 +397,7 @@ void CdbDebugEngine::exitDebugger() qDebug() << Q_FUNC_INFO; if (m_d->m_hDebuggeeProcess) { + m_d->cleanStackTrace(); // Terminate or detach if we are running HRESULT hr; switch (m_d->m_mode) { @@ -407,47 +428,22 @@ void CdbDebugEngine::exitDebugger() killWatchTimer(); } -// Retrieve a symbol -static WatchData symbolToWatchData(ULONG index, const QString &namePrefix, - IDebugSymbolGroup2 *pDbgSymGroup) +class ModelBuildIterator { +public: + explicit ModelBuildIterator(WatchHandler *wh) : m_wh(wh) {} + + ModelBuildIterator & operator*() { return *this; } + ModelBuildIterator &operator=(const WatchData &wd); + ModelBuildIterator &operator++() { return *this; } + +private: + WatchHandler *m_wh; +}; + +ModelBuildIterator &ModelBuildIterator::operator=(const WatchData &wd) { - // retrieve symbol names and value strings - ULONG nameLength; - static WCHAR nameBuffer[MAX_PATH + 1]; - // Name - pDbgSymGroup->GetSymbolNameWide(index, nameBuffer, MAX_PATH, &nameLength); - nameBuffer[nameLength] = 0; - const QString name = QString::fromUtf16(nameBuffer); - // Type name - pDbgSymGroup->GetSymbolTypeNameWide(index, nameBuffer, MAX_PATH, &nameLength); - nameBuffer[nameLength] = 0; - const QString type = QString::fromUtf16(nameBuffer); - // Value - QString value; - const HRESULT hr = pDbgSymGroup->GetSymbolValueTextWide(index, nameBuffer, MAX_PATH, &nameLength); - if (SUCCEEDED(hr)) { - nameBuffer[nameLength] = 0; - value = QString::fromUtf16(nameBuffer); - } else { - value = QLatin1String("<unknown>"); - } - WatchData wd; - wd.iname =namePrefix + name; - wd.name = name; - wd.value = value; - wd.type = type; - if (isPointerType(type)) { - wd.setTypeUnneeded(); - wd.setValueUnneeded(); - } else { - wd.setAllUnneeded(); - } - if (debugCDB) { - qDebug() << Q_FUNC_INFO << index << "state=0x" << QString::number(wd.state, 16) - << wd.name << " type=" << wd.type << " (" << type << ')' - << " value " << wd.value << " (" << value << ')'; - } - return wd; + m_wh->insertData(wd); + return *this; } bool CdbDebugEnginePrivate::updateLocals(int frameIndex, @@ -456,82 +452,36 @@ bool CdbDebugEnginePrivate::updateLocals(int frameIndex, { if (debugCDB) qDebug() << Q_FUNC_INFO << frameIndex; - - CdbStackTrace cdbStackTrace; - if (!getCdbStrackTrace(&cdbStackTrace, errorMessage)) - return false; - - if ((unsigned)frameIndex >= cdbStackTrace.frameCount) { - *errorMessage = msgStackIndexOutOfRange(frameIndex, cdbStackTrace.frameCount); - return false; - } - - IDebugSymbolGroup2 *pDbgSymGroup = 0; - DEBUG_SYMBOL_PARAMETERS *symParams = 0; bool success = false; - + wh->cleanup(); do { - HRESULT hr = m_pDebugSymbols->GetScopeSymbolGroup2(DEBUG_SCOPE_GROUP_LOCALS, NULL, &pDbgSymGroup); - if (FAILED(hr)) { - *errorMessage = msgComFailed("GetScopeSymbolGroup", hr); - break; - } - - hr = m_pDebugSymbols->SetScope(0, cdbStackTrace.frames + frameIndex, NULL, 0); - if (FAILED(hr)) { - *errorMessage = msgComFailed("SetScope", hr); - break; - } - // refresh with current frame - hr = m_pDebugSymbols->GetScopeSymbolGroup2(DEBUG_SCOPE_GROUP_LOCALS, pDbgSymGroup, &pDbgSymGroup); - if (FAILED(hr)) { - *errorMessage = msgComFailed("GetScopeSymbolGroup", hr); - break; - } - - ULONG symbolCount; - hr = pDbgSymGroup->GetNumberSymbols(&symbolCount); - if (FAILED(hr)) { - *errorMessage = msgComFailed("GetNumberSymbols", hr); + if (!m_currentStackTrace) { + *errorMessage = QLatin1String(msgNoStackTraceC); break; } - symParams = new DEBUG_SYMBOL_PARAMETERS[symbolCount]; - hr = pDbgSymGroup->GetSymbolParameters(0, symbolCount, symParams); - if (FAILED(hr)) { - *errorMessage = msgComFailed("GetSymbolParameters", hr); + CdbSymbolGroupContext *sgc = m_currentStackTrace->symbolGroupContextAt(frameIndex, errorMessage); + if (!sgc) { break; } - wh->cleanup(); - // retrieve symbol names and value strings. - // Add a dummy place holder in case children are needed - const QString localPrefix = QLatin1String("local."); - for (ULONG s = 0 ; s < symbolCount ; s++ ) { - WatchData wd = symbolToWatchData(s, localPrefix, pDbgSymGroup); - if (wd.isSomethingNeeded()) { - wh->insertData(wd.pointerChildPlaceHolder()); - wd.setAllUnneeded(); - wd.setChildCount(1); - } - wh->insertData(wd); - } - wh->rebuildModel(); + ModelBuildIterator it(wh); + sgc->getSymbols(sgc->prefix(), it); success = true; } while (false); + wh->rebuildModel(); - delete [] symParams; - if (pDbgSymGroup) - pDbgSymGroup->Release(); return success; } - void CdbDebugEngine::updateWatchModel() { WatchHandler *watchHandler = m_d->m_debuggerManagerAccess->watchHandler(); const QList<WatchData> incomplete = watchHandler->takeCurrentIncompletes(); + if (debugCDB) qDebug() << Q_FUNC_INFO << incomplete.size(); + foreach (const WatchData& wd, incomplete) + qDebug() << Q_FUNC_INFO << wd.toString(); } void CdbDebugEngine::stepExec() @@ -540,8 +490,9 @@ void CdbDebugEngine::stepExec() qDebug() << Q_FUNC_INFO; //m_pDebugControl->Execute(DEBUG_OUTCTL_THIS_CLIENT, "p", 0); - HRESULT hr; - hr = m_d->m_pDebugControl->SetExecutionStatus(DEBUG_STATUS_STEP_INTO); + m_d->cleanStackTrace(); + const HRESULT hr = m_d->m_pDebugControl->SetExecutionStatus(DEBUG_STATUS_STEP_INTO); + Q_UNUSED(hr) m_d->m_bIgnoreNextDebugEvent = true; startWatchTimer(); } @@ -594,6 +545,7 @@ void CdbDebugEngine::nextExec() if (debugCDB) qDebug() << Q_FUNC_INFO; + m_d->cleanStackTrace(); const HRESULT hr = m_d->m_pDebugControl->SetExecutionStatus(DEBUG_STATUS_STEP_OVER); if (SUCCEEDED(hr)) { startWatchTimer(); @@ -612,6 +564,7 @@ void CdbDebugEngine::nextIExec() if (debugCDB) qDebug() << Q_FUNC_INFO; + m_d->cleanStackTrace(); const HRESULT hr = m_d->m_pDebugControl->Execute(DEBUG_OUTCTL_THIS_CLIENT, "p", 0); if (SUCCEEDED(hr)) { startWatchTimer(); @@ -625,6 +578,7 @@ void CdbDebugEngine::continueInferior() if (debugCDB) qDebug() << Q_FUNC_INFO; + m_d->cleanStackTrace(); killWatchTimer(); m_d->m_debuggerManager->resetLocation(); @@ -714,7 +668,7 @@ void CdbDebugEngine::activateFrame(int frameIndex) } const StackFrame &frame = stackHandler->currentFrame(); - if (frame.file.isEmpty() || !QFileInfo(frame.file).isReadable()) { + if (!frame.isUsable()) { errorMessage = QString::fromLatin1("%1: file %2 unusable."). arg(QLatin1String(Q_FUNC_INFO), frame.file); break; @@ -933,78 +887,29 @@ void CdbDebugEnginePrivate::updateThreadList() th->setThreads(threads); } -// Get CDB stack trace -bool CdbDebugEnginePrivate::getCdbStrackTrace(CdbStackTrace *st, QString *errorMessage) -{ - HRESULT hr = m_pDebugSystemObjects->SetCurrentThreadId(m_currentThreadId); - if (FAILED(hr)) { - *errorMessage = QString::fromLatin1("%1: SetCurrentThreadId %2 failed: %3"). - arg(QString::fromLatin1(Q_FUNC_INFO)). - arg(m_currentThreadId). - arg(msgDebugEngineComResult(hr)); - return false; - } - hr = m_pDebugControl->GetStackTrace(0, 0, 0, st->frames, CdbStackTrace::maxFrames, &(st->frameCount)); - if (FAILED(hr)) { - *errorMessage = *errorMessage = msgComFailed("GetStackTrace", hr); - return false; - } - return true; -} - -bool CdbDebugEnginePrivate::getStackTrace(QList<StackFrame> *stackFrames, - int *current, QString *errorMessage) -{ - stackFrames->clear(); - *current = -1; - // Get the CDB trace and convert into debugger plugin structures - CdbStackTrace cdbStackTrace; - if (!getCdbStrackTrace(&cdbStackTrace, errorMessage)) - return false; - - WCHAR wszBuf[MAX_PATH]; - for (ULONG i=0; i < cdbStackTrace.frameCount; ++i) { - StackFrame frame; - frame.line = 0; - frame.level = i; - frame.address = QString::fromLatin1("0x%1").arg(cdbStackTrace.frames[i].InstructionOffset, 0, 16); - - m_pDebugSymbols->GetNameByOffsetWide(cdbStackTrace.frames[i].InstructionOffset, wszBuf, MAX_PATH, 0, 0); - frame.function = QString::fromUtf16(wszBuf); - - ULONG ulLine; - ULONG ulFileNameSize; - ULONG64 ul64Displacement; - const HRESULT hr = m_pDebugSymbols->GetLineByOffsetWide(cdbStackTrace.frames[i].InstructionOffset, &ulLine, wszBuf, MAX_PATH, &ulFileNameSize, &ul64Displacement); - if (SUCCEEDED(hr)) { - frame.line = ulLine; - frame.file = QString::fromUtf16(wszBuf, ulFileNameSize); - } - stackFrames->append(frame); - } - - // find the first usable frame and select it - const int count = stackFrames->count(); - for (int i=0; i < count; ++i) { - const StackFrame &frame = stackFrames->at(i); - const bool usable = !frame.file.isEmpty() && QFileInfo(frame.file).isReadable(); - if (usable) { - *current = i; - break; - } - } - return true; -} - void CdbDebugEnginePrivate::updateStackTrace() { if (debugCDB) qDebug() << Q_FUNC_INFO; - QList<StackFrame> stackFrames; - int current; + // Create a new context + cleanStackTrace(); QString errorMessage; - if (getStackTrace(&stackFrames, ¤t, &errorMessage)) - qWarning("%s", qPrintable(errorMessage)); + m_currentStackTrace = + CdbStackTraceContext::create(m_pDebugControl, m_pDebugSystemObjects, + m_pDebugSymbols, m_currentThreadId, &errorMessage); + if (!m_currentStackTrace) { + qWarning("%s: failed to create trace context: %s", Q_FUNC_INFO, qPrintable(errorMessage)); + return; + } + const QList<StackFrame> stackFrames = m_currentStackTrace->frames(); + // find the first usable frame and select it + int current = -1; + const int count = stackFrames.count(); + for (int i=0; i < count; ++i) + if (stackFrames.at(i).isUsable()) { + current = i; + break; + } m_debuggerManagerAccess->stackHandler()->setFrames(stackFrames); if (current >= 0) { diff --git a/src/plugins/debugger/cdb/cdbdebugengine_p.h b/src/plugins/debugger/cdb/cdbdebugengine_p.h index e6235569a074b8320cdd3d73363559ed405db4f6..e1991f707deedc75d73b052014eb6653372aaf13 100644 --- a/src/plugins/debugger/cdb/cdbdebugengine_p.h +++ b/src/plugins/debugger/cdb/cdbdebugengine_p.h @@ -42,6 +42,8 @@ namespace Internal { class DebuggerManager; class IDebuggerManagerAccessForEngines; class WatchHandler; +class CdbSymbolGroupContext; +class CdbStackTraceContext; // Thin wrapper around the 'DBEng' debugger engine shared library // which is loaded at runtime. @@ -61,16 +63,6 @@ private: DebugCreateFunction m_debugCreate; }; - -// Helper struct for stack traces -struct CdbStackTrace { - CdbStackTrace() : frameCount(0) {} - enum { maxFrames = 100 }; - - ULONG frameCount; - DEBUG_STACK_FRAME frames[maxFrames]; -}; - struct CdbDebugEnginePrivate { explicit CdbDebugEnginePrivate(DebuggerManager *parent, CdbDebugEngine* engine); @@ -84,10 +76,9 @@ struct CdbDebugEnginePrivate void updateThreadList(); void updateStackTrace(); bool updateLocals(int frameIndex, WatchHandler *wh, QString *errorMessage); - bool getCdbStrackTrace(CdbStackTrace *st, QString *errorMessage); - bool getStackTrace(QList<StackFrame> *stackFrames, int *current, QString *errorMessage); void handleDebugOutput(const char* szOutputString); void handleBreakpointEvent(PDEBUG_BREAKPOINT pBP); + void cleanStackTrace(); HANDLE m_hDebuggeeProcess; HANDLE m_hDebuggeeThread; @@ -106,10 +97,16 @@ struct CdbDebugEnginePrivate CdbDebugEngine* m_engine; DebuggerManager *m_debuggerManager; IDebuggerManagerAccessForEngines *m_debuggerManagerAccess; + CdbStackTraceContext *m_currentStackTrace; + DebuggerStartMode m_mode; Core::Utils::ConsoleProcess m_consoleStubProc; }; +// Message +QString msgDebugEngineComResult(HRESULT hr); +QString msgComFailed(const char *func, HRESULT hr); + enum { debugCDB = 0 }; } // namespace Internal diff --git a/src/plugins/debugger/cdb/cdbstacktracecontext.cpp b/src/plugins/debugger/cdb/cdbstacktracecontext.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d569c6a9baefb6a6b93500c6d06a85b31611d293 --- /dev/null +++ b/src/plugins/debugger/cdb/cdbstacktracecontext.cpp @@ -0,0 +1,161 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Qt Software Information (qt-info@nokia.com) +** +** Commercial Usage +** +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** GNU Lesser General Public License Usage +** +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** +**************************************************************************/ + +#include "cdbstacktracecontext.h" +#include "cdbsymbolgroupcontext.h" +#include "cdbdebugengine_p.h" + +namespace Debugger { +namespace Internal { + +CdbStackTraceContext::CdbStackTraceContext(IDebugSystemObjects4* pDebugSystemObjects, + IDebugSymbols3* pDebugSymbols) : + m_pDebugSystemObjects(pDebugSystemObjects), + m_pDebugSymbols(pDebugSymbols) +{ +} + +CdbStackTraceContext *CdbStackTraceContext::create(IDebugControl4* pDebugControl, + IDebugSystemObjects4* pDebugSystemObjects, + IDebugSymbols3* pDebugSymbols, + unsigned long threadId, + QString *errorMessage) +{ + if (debugCDB) + qDebug() << Q_FUNC_INFO << threadId; + HRESULT hr = pDebugSystemObjects->SetCurrentThreadId(threadId); + if (FAILED(hr)) { + *errorMessage = QString::fromLatin1("%1: SetCurrentThreadId %2 failed: %3"). + arg(QString::fromLatin1(Q_FUNC_INFO)). + arg(threadId). + arg(msgDebugEngineComResult(hr)); + return 0; + } + // fill the DEBUG_STACK_FRAME array + ULONG frameCount; + CdbStackTraceContext *ctx = new CdbStackTraceContext(pDebugSystemObjects, pDebugSymbols); + hr = pDebugControl->GetStackTrace(0, 0, 0, ctx->m_cdbFrames, CdbStackTraceContext::maxFrames, &frameCount); + if (FAILED(hr)) { + delete ctx; + *errorMessage = msgComFailed("GetStackTrace", hr); + return 0; + } + if (!ctx->init(frameCount, errorMessage)) { + delete ctx; + return 0; + + } + return ctx; +} + +CdbStackTraceContext::~CdbStackTraceContext() +{ + qDeleteAll(m_symbolContexts); +} + +bool CdbStackTraceContext::init(unsigned long frameCount, QString * /*errorMessage*/) +{ + if (debugCDB) + qDebug() << Q_FUNC_INFO << frameCount; + + m_symbolContexts.resize(frameCount); + qFill(m_symbolContexts, static_cast<CdbSymbolGroupContext*>(0)); + + // Convert the DEBUG_STACK_FRAMEs to our StackFrame structure and populate the frames + WCHAR wszBuf[MAX_PATH]; + for (ULONG i=0; i < frameCount; ++i) { + StackFrame frame(i); + const ULONG64 instructionOffset = m_cdbFrames[i].InstructionOffset; + frame.address = QString::fromLatin1("0x%1").arg(instructionOffset, 0, 16); + + m_pDebugSymbols->GetNameByOffsetWide(instructionOffset, wszBuf, MAX_PATH, 0, 0); + frame.function = QString::fromUtf16(wszBuf); + + ULONG ulLine; + ULONG ulFileNameSize; + ULONG64 ul64Displacement; + const HRESULT hr = m_pDebugSymbols->GetLineByOffsetWide(instructionOffset, &ulLine, wszBuf, MAX_PATH, &ulFileNameSize, &ul64Displacement); + if (SUCCEEDED(hr)) { + frame.line = ulLine; + frame.file = QString::fromUtf16(wszBuf, ulFileNameSize); + } + m_frames.push_back(frame); + } + return true; +} + +CdbSymbolGroupContext *CdbStackTraceContext::symbolGroupContextAt(int index, QString *errorMessage) +{ + // Create a symbol group on demand + if (debugCDB) + qDebug() << Q_FUNC_INFO << index << m_symbolContexts.at(index); + + if (index < 0 || index >= m_symbolContexts.size()) { + *errorMessage = QString::fromLatin1("%1: Index %2 out of range %3."). + arg(QLatin1String(Q_FUNC_INFO)).arg(index).arg(m_symbolContexts.size()); + return 0; + } + + if (m_symbolContexts.at(index)) + return m_symbolContexts.at(index); + IDebugSymbolGroup2 *sg = createSymbolGroup(index, errorMessage); + if (!sg) + return 0; + CdbSymbolGroupContext *sc = new CdbSymbolGroupContext(QLatin1String("local"), sg); + m_symbolContexts[index] = sc; + return sc; +} + +IDebugSymbolGroup2 *CdbStackTraceContext::createSymbolGroup(int index, QString *errorMessage) +{ + IDebugSymbolGroup2 *sg = 0; + HRESULT hr = m_pDebugSymbols->GetScopeSymbolGroup2(DEBUG_SCOPE_GROUP_LOCALS, NULL, &sg); + if (FAILED(hr)) { + *errorMessage = msgComFailed("GetScopeSymbolGroup", hr); + return 0; + } + + hr = m_pDebugSymbols->SetScope(0, m_cdbFrames + index, NULL, 0); + if (FAILED(hr)) { + *errorMessage = msgComFailed("SetScope", hr); + sg->Release(); + return 0; + } + // refresh with current frame + hr = m_pDebugSymbols->GetScopeSymbolGroup2(DEBUG_SCOPE_GROUP_LOCALS, sg, &sg); + if (FAILED(hr)) { + *errorMessage = msgComFailed("GetScopeSymbolGroup", hr); + sg->Release(); + return 0; + } + return sg; +} + +} +} diff --git a/src/plugins/debugger/cdb/cdbstacktracecontext.h b/src/plugins/debugger/cdb/cdbstacktracecontext.h new file mode 100644 index 0000000000000000000000000000000000000000..bb8286859ef2ed3ade602808f5729a1be37a3511 --- /dev/null +++ b/src/plugins/debugger/cdb/cdbstacktracecontext.h @@ -0,0 +1,86 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Qt Software Information (qt-info@nokia.com) +** +** Commercial Usage +** +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** GNU Lesser General Public License Usage +** +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** +**************************************************************************/ + +#ifndef CDBSTACKTRACECONTEXT_H +#define CDBSTACKTRACECONTEXT_H + +#include "stackhandler.h" + +#include <windows.h> +#include <inc/dbgeng.h> + +#include <QtCore/QString> +#include <QtCore/QVector> + +namespace Debugger { +namespace Internal { + +class CdbSymbolGroupContext; + +/* Context representing a break point stack consisting of several frames. + * Maintains an on-demand constructed list of CdbSymbolGroupContext + * containining the local variables of the stack. */ + +class CdbStackTraceContext +{ + Q_DISABLE_COPY(CdbStackTraceContext) + + explicit CdbStackTraceContext(IDebugSystemObjects4* pDebugSystemObjects, + IDebugSymbols3* pDebugSymbols); +public: + enum { maxFrames = 100 }; + + ~CdbStackTraceContext(); + static CdbStackTraceContext *create(IDebugControl4* pDebugControl, + IDebugSystemObjects4* pDebugSystemObjects, + IDebugSymbols3* pDebugSymbols, + unsigned long threadid, + QString *errorMessage); + + QList<StackFrame> frames() const { return m_frames; } + inline int frameCount() const { return m_frames.size(); } + + CdbSymbolGroupContext *symbolGroupContextAt(int index, QString *errorMessage); + +private: + bool init(unsigned long frameCount, QString *errorMessage); + IDebugSymbolGroup2 *createSymbolGroup(int index, QString *errorMessage); + + IDebugSystemObjects4* m_pDebugSystemObjects; + IDebugSymbols3* m_pDebugSymbols; + + DEBUG_STACK_FRAME m_cdbFrames[maxFrames]; + QVector <CdbSymbolGroupContext*> m_symbolContexts; + QList<StackFrame> m_frames; +}; + +} +} + +#endif // CDBSTACKTRACECONTEXT_H diff --git a/src/plugins/debugger/cdb/cdbsymbolgroupcontext.cpp b/src/plugins/debugger/cdb/cdbsymbolgroupcontext.cpp new file mode 100644 index 0000000000000000000000000000000000000000..aa52ef55e1a304a4d95b832cbefcaf8b24de7702 --- /dev/null +++ b/src/plugins/debugger/cdb/cdbsymbolgroupcontext.cpp @@ -0,0 +1,177 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Qt Software Information (qt-info@nokia.com) +** +** Commercial Usage +** +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** GNU Lesser General Public License Usage +** +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** +**************************************************************************/ + +#include "cdbsymbolgroupcontext.h" +#include "cdbdebugengine_p.h" +#include "watchhandler.h" + +// A helper function to extract a string value from a member function of +// IDebugSymbolGroup2 taking the symbol index and a character buffer. +// Pass in the the member function as '&IDebugSymbolGroup2::GetSymbolNameWide' + +typedef HRESULT (__stdcall IDebugSymbolGroup2::*WideStringRetrievalFunction)(ULONG, PWSTR, ULONG, PULONG); + +static inline QString getSymbolString(IDebugSymbolGroup2 *sg, + WideStringRetrievalFunction wsf, + unsigned long index) +{ + static WCHAR nameBuffer[MAX_PATH + 1]; + // Name + ULONG nameLength; + const HRESULT hr = (sg->*wsf)(index, nameBuffer, MAX_PATH, &nameLength); + if (SUCCEEDED(hr)) { + nameBuffer[nameLength] = 0; + return QString::fromUtf16(nameBuffer); + } + return QString(); +} + +namespace Debugger { + namespace Internal { + +CdbSymbolGroupContext::CdbSymbolGroupContext(const QString &prefix, + IDebugSymbolGroup2 *symbolGroup) : + m_prefix(prefix), + m_nameDelimiter(QLatin1Char('.')), + m_symbolGroup(symbolGroup) +{ +} + +CdbSymbolGroupContext::~CdbSymbolGroupContext() +{ + m_symbolGroup->Release(); +} + +CdbSymbolGroupContext::Range + CdbSymbolGroupContext::getSymbolRange(const QString &prefix) +{ + if (debugCDB) + qDebug() << Q_FUNC_INFO << prefix; + const ChildRangeMap::const_iterator it = m_childRanges.constFind(prefix); + if (it != m_childRanges.constEnd()) + return it.value(); + const Range r = prefix == m_prefix ? allocateRootSymbols() : allocateChildSymbols(prefix); + m_childRanges.insert(prefix, r); + return r; +} + +CdbSymbolGroupContext::Range + CdbSymbolGroupContext::allocateChildSymbols(const QString &prefix) +{ + unsigned long startPos = 0; + unsigned long count = 0; + + bool success = false; + QString errorMessage; + do { + const int parentIndex = m_symbolINames.indexOf(prefix); + if (parentIndex == -1) { + errorMessage = QString::fromLatin1("Prefix not found '%1'").arg(prefix); + break; + } + + success = true; + } while (false); + if (!success) { + qWarning("%s\n", qPrintable(errorMessage)); + } + return Range(startPos, count); +} + +CdbSymbolGroupContext::Range + CdbSymbolGroupContext::allocateRootSymbols() +{ + unsigned long startPos = 0; + unsigned long count = 0; + bool success = false; + + QString errorMessage; + do { + HRESULT hr = m_symbolGroup->GetNumberSymbols(&count); + if (FAILED(hr)) { + errorMessage = msgComFailed("GetNumberSymbols", hr); + break; + } + + m_symbolParameters.reserve(3u * count); + m_symbolParameters.resize(count); + + hr = m_symbolGroup->GetSymbolParameters(0, count, symbolParameters()); + if (FAILED(hr)) { + errorMessage = msgComFailed("GetSymbolParameters", hr); + break; + } + const QString symbolPrefix = m_prefix + m_nameDelimiter; + for (unsigned long i = 0; i < count; i++) + m_symbolINames.push_back(symbolPrefix + getSymbolString(m_symbolGroup, &IDebugSymbolGroup2::GetSymbolNameWide, i)); + + success = true; + } while (false); + if (!success) { + clear(); + count = 0; + qWarning("%s\n", qPrintable(errorMessage)); + } + return Range(startPos, count); +} + +void CdbSymbolGroupContext::clear() +{ + m_symbolParameters.clear(); + m_childRanges.clear(); + m_symbolINames.clear(); +} + +WatchData CdbSymbolGroupContext::symbolAt(unsigned long index) const +{ + if (debugCDB) + qDebug() << Q_FUNC_INFO << index; + + WatchData wd; + wd.iname = m_symbolINames.at(index); + const int lastDelimiterPos = wd.iname.lastIndexOf(m_nameDelimiter); + wd.name = lastDelimiterPos == -1 ? wd.iname : wd.iname.mid(lastDelimiterPos + 1); + wd.type = getSymbolString(m_symbolGroup, &IDebugSymbolGroup2::GetSymbolTypeNameWide, index); + wd.value = getSymbolString(m_symbolGroup, &IDebugSymbolGroup2::GetSymbolValueTextWide, index); + const DEBUG_SYMBOL_PARAMETERS ¶ms = m_symbolParameters.at(index); + if (params.SubElements) { + wd.setTypeUnneeded(); + wd.setValueUnneeded(); + wd.setChildCount(1); + } else { + wd.setAllUnneeded(); + } + if (debugCDB) { + qDebug() << Q_FUNC_INFO << wd.toString(); + } + return wd; +} + +} +} diff --git a/src/plugins/debugger/cdb/cdbsymbolgroupcontext.h b/src/plugins/debugger/cdb/cdbsymbolgroupcontext.h new file mode 100644 index 0000000000000000000000000000000000000000..e5c4ea7c9c731fba630ba1dca161ecdfa0caf2ae --- /dev/null +++ b/src/plugins/debugger/cdb/cdbsymbolgroupcontext.h @@ -0,0 +1,110 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Qt Software Information (qt-info@nokia.com) +** +** Commercial Usage +** +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** GNU Lesser General Public License Usage +** +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** +**************************************************************************/ + +#ifndef CDBSYMBOLGROUPCONTEXT_H +#define CDBSYMBOLGROUPCONTEXT_H + +#include <windows.h> +#include <inc/dbgeng.h> + +#include <QtCore/QString> +#include <QtCore/QVector> +#include <QtCore/QList> +#include <QtCore/QStringList> +#include <QtCore/QPair> +#include <QtCore/QMap> + +namespace Debugger { + namespace Internal { + +class WatchData; + +/* A thin wrapper around the IDebugSymbolGroup2 interface which represents + * a flat list of symbols using an index (for example, belonging to a stack frame). + * It uses the hierarchical naming convention of WatchHandler as: + * "local" (invisible root) + * "local.string" (local class variable) + * "local.string.data" (class member). + * IDebugSymbolGroup2 can "expand" expandable symbols, appending to the flat list. + */ + +class CdbSymbolGroupContext +{ + Q_DISABLE_COPY(CdbSymbolGroupContext); + + // Start position and length of range in m_symbolParameters + typedef QPair<unsigned long, unsigned long> Range; + +public: + explicit CdbSymbolGroupContext(const QString &prefix, + IDebugSymbolGroup2 *symbolGroup); + ~CdbSymbolGroupContext(); + + QString prefix() const { return m_prefix; } + + // Retrieve child symbols of prefix as a sequence of WatchData. + template <class OutputIterator> + void getSymbols(const QString &prefix, OutputIterator it); + +private: + void clear(); + Range getSymbolRange(const QString &prefix); + Range allocateChildSymbols(const QString &prefix); + Range allocateRootSymbols(); + WatchData symbolAt(unsigned long index) const; + + inline DEBUG_SYMBOL_PARAMETERS *symbolParameters() { return &(*m_symbolParameters.begin()); } + inline const DEBUG_SYMBOL_PARAMETERS *symbolParameters() const { return &(*m_symbolParameters.constBegin()); } + + const QString m_prefix; + const QChar m_nameDelimiter; + IDebugSymbolGroup2 *m_symbolGroup; + + QStringList m_symbolINames; + QVector<DEBUG_SYMBOL_PARAMETERS> m_symbolParameters; + + typedef QMap<QString, Range> ChildRangeMap; + + ChildRangeMap m_childRanges; +}; + +template <class OutputIterator> +void CdbSymbolGroupContext::getSymbols(const QString &prefix, OutputIterator it) +{ + const Range r = getSymbolRange(prefix); + const unsigned long end = r.first + r.second; + for (unsigned long i = r.first; i < end; i++) { + *it = symbolAt(i); + ++it; + } +} + +} +} +#endif // CDBSYMBOLGROUPCONTEXT_H diff --git a/src/plugins/debugger/debuggeractions.cpp b/src/plugins/debugger/debuggeractions.cpp index 75e84b962054a6a97eacd7b670272b0082244c25..f5ae15bef109d883c0b86aa3558ad4dcf6ed8bff 100644 --- a/src/plugins/debugger/debuggeractions.cpp +++ b/src/plugins/debugger/debuggeractions.cpp @@ -43,96 +43,93 @@ #include <QtGui/QLineEdit> -namespace Debugger { -namespace Internal { +using namespace Debugger::Internal; +using namespace Core::Utils; ////////////////////////////////////////////////////////////////////////// // -// DebuggerAction +// SavedAction // ////////////////////////////////////////////////////////////////////////// -DebuggerAction::DebuggerAction(QObject *parent) +SavedAction::SavedAction(QObject *parent) : QAction(parent) { m_widget = 0; connect(this, SIGNAL(triggered(bool)), this, SLOT(actionTriggered(bool))); } -QVariant DebuggerAction::value() const +QVariant SavedAction::value() const { return m_value; } -void DebuggerAction::setValue(const QVariant &value, bool doemit) +void SavedAction::setValue(const QVariant &value, bool doemit) { - if (value != m_value) { - m_value = value; - if (this->isCheckable()) - this->setChecked(m_value.toBool()); - if (doemit) { - emit valueChanged(m_value); - emit boolValueChanged(m_value.toBool()); - emit stringValueChanged(m_value.toString()); - } - } + if (value == m_value) + return; + m_value = value; + if (this->isCheckable()) + this->setChecked(m_value.toBool()); + if (doemit) + emit valueChanged(m_value); } -QVariant DebuggerAction::defaultValue() const +QVariant SavedAction::defaultValue() const { return m_defaultValue; } -void DebuggerAction::setDefaultValue(const QVariant &value) +void SavedAction::setDefaultValue(const QVariant &value) { m_defaultValue = value; } -QString DebuggerAction::settingsKey() const +QString SavedAction::settingsKey() const { return m_settingsKey; } -void DebuggerAction::setSettingsKey(const QString &key) +void SavedAction::setSettingsKey(const QString &key) { m_settingsKey = key; } -void DebuggerAction::setSettingsKey(const QString &group, const QString &key) +void SavedAction::setSettingsKey(const QString &group, const QString &key) { m_settingsKey = key; m_settingsGroup = group; } -QString DebuggerAction::settingsGroup() const +QString SavedAction::settingsGroup() const { return m_settingsGroup; } -void DebuggerAction::setSettingsGroup(const QString &group) +void SavedAction::setSettingsGroup(const QString &group) { m_settingsGroup = group; } -QString DebuggerAction::textPattern() const +QString SavedAction::textPattern() const { return m_textPattern; } -void DebuggerAction::setTextPattern(const QString &value) +void SavedAction::setTextPattern(const QString &value) { m_textPattern = value; } -QString DebuggerAction::toString() const +QString SavedAction::toString() const { return "value: " + m_value.toString() + " defaultvalue: " + m_defaultValue.toString() + " settingskey: " + m_settingsGroup + '/' + m_settingsKey; } -QAction *DebuggerAction::updatedAction(const QString &text0) +QAction *SavedAction::updatedAction(const QString &text0) { QString text = text0; bool enabled = true; @@ -152,7 +149,7 @@ QAction *DebuggerAction::updatedAction(const QString &text0) return this; } -void DebuggerAction::readSettings(QSettings *settings) +void SavedAction::readSettings(QSettings *settings) { if (m_settingsGroup.isEmpty() || m_settingsKey.isEmpty()) return; @@ -162,7 +159,7 @@ void DebuggerAction::readSettings(QSettings *settings) settings->endGroup(); } -void DebuggerAction::writeSettings(QSettings *settings) +void SavedAction::writeSettings(QSettings *settings) { if (m_settingsGroup.isEmpty() || m_settingsKey.isEmpty()) return; @@ -172,9 +169,10 @@ void DebuggerAction::writeSettings(QSettings *settings) settings->endGroup(); } -void DebuggerAction::connectWidget(QWidget *widget, ApplyMode applyMode) +void SavedAction::connectWidget(QWidget *widget, ApplyMode applyMode) { - using namespace Core::Utils; + QTC_ASSERT(!m_widget, + qDebug() << "ALREADY CONNECTED: " << widget << m_widget << toString(); return); m_widget = widget; m_applyMode = applyMode; @@ -199,25 +197,29 @@ void DebuggerAction::connectWidget(QWidget *widget, ApplyMode applyMode) connect(pathChooser, SIGNAL(browsingFinished()), this, SLOT(pathChooserEditingFinished())); } else { - qDebug() << "CANNOT CONNECT WIDGET " << widget; + qDebug() << "Cannot connect widget " << widget << toString(); } } -void DebuggerAction::apply(QSettings *s) +void SavedAction::disconnectWidget() +{ + QTC_ASSERT(m_widget, + qDebug() << "Widget already disconnected: " << m_widget << toString(); return); + m_widget = 0; +} +void SavedAction::apply(QSettings *s) { - using namespace Core::Utils; if (QAbstractButton *button = qobject_cast<QAbstractButton *>(m_widget)) setValue(button->isChecked()); else if (QLineEdit *lineEdit = qobject_cast<QLineEdit *>(m_widget)) setValue(lineEdit->text()); else if (PathChooser *pathChooser = qobject_cast<PathChooser *>(m_widget)) setValue(pathChooser->path()); - m_widget = 0; if (s) writeSettings(s); } -void DebuggerAction::uncheckableButtonClicked() +void SavedAction::uncheckableButtonClicked() { QAbstractButton *button = qobject_cast<QAbstractButton *>(sender()); QTC_ASSERT(button, return); @@ -225,7 +227,7 @@ void DebuggerAction::uncheckableButtonClicked() QAction::trigger(); } -void DebuggerAction::checkableButtonClicked(bool) +void SavedAction::checkableButtonClicked(bool) { QAbstractButton *button = qobject_cast<QAbstractButton *>(sender()); QTC_ASSERT(button, return); @@ -234,51 +236,75 @@ void DebuggerAction::checkableButtonClicked(bool) setValue(button->isChecked()); } -void DebuggerAction::lineEditEditingFinished() +void SavedAction::lineEditEditingFinished() { QLineEdit *lineEdit = qobject_cast<QLineEdit *>(sender()); QTC_ASSERT(lineEdit, return); - //qDebug() << "LINEEDIT: " << sender() << lineEdit->text(); if (m_applyMode == ImmediateApply) setValue(lineEdit->text()); } -void DebuggerAction::pathChooserEditingFinished() +void SavedAction::pathChooserEditingFinished() { - using namespace Core::Utils; PathChooser *pathChooser = qobject_cast<PathChooser *>(sender()); QTC_ASSERT(pathChooser, return); - //qDebug() << "PATHCHOOSER: " << sender() << pathChooser->path(); if (m_applyMode == ImmediateApply) setValue(pathChooser->path()); } -void DebuggerAction::actionTriggered(bool) +void SavedAction::actionTriggered(bool) { - //qDebug() << "TRIGGERING" << this << actionGroup(); if (isCheckable()) setValue(isChecked()); if (actionGroup() && actionGroup()->isExclusive()) { // FIXME: should be taken care of more directly foreach (QAction *act, actionGroup()->actions()) - if (DebuggerAction *dact = qobject_cast<DebuggerAction *>(act)) + if (SavedAction *dact = qobject_cast<SavedAction *>(act)) dact->setValue(bool(act == this)); } } -void DebuggerAction::trigger(const QVariant &data) +void SavedAction::trigger(const QVariant &data) { setData(data); QAction::trigger(); } +////////////////////////////////////////////////////////////////////////// +// +// SavedActionSet +// +////////////////////////////////////////////////////////////////////////// + +void SavedActionSet::insert(SavedAction *action, QWidget *widget) +{ + m_list.append(action); + action->connectWidget(widget); +} + +void SavedActionSet::apply(QSettings *settings) +{ + foreach (SavedAction *action, m_list) + action->apply(settings); +} + +void SavedActionSet::finish() +{ + foreach (SavedAction *action, m_list) + action->disconnectWidget(); +} + + ////////////////////////////////////////////////////////////////////////// // // DebuggerSettings // ////////////////////////////////////////////////////////////////////////// +namespace Debugger { +namespace Internal { + DebuggerSettings::DebuggerSettings(QObject *parent) : QObject(parent) {} @@ -288,24 +314,24 @@ DebuggerSettings::~DebuggerSettings() qDeleteAll(m_items); } -void DebuggerSettings::insertItem(int code, DebuggerAction *item) +void DebuggerSettings::insertItem(int code, SavedAction *item) { m_items[code] = item; } void DebuggerSettings::readSettings(QSettings *settings) { - foreach (DebuggerAction *item, m_items) + foreach (SavedAction *item, m_items) item->readSettings(settings); } void DebuggerSettings::writeSettings(QSettings *settings) { - foreach (DebuggerAction *item, m_items) + foreach (SavedAction *item, m_items) item->writeSettings(settings); } -DebuggerAction *DebuggerSettings::item(int code) +SavedAction *DebuggerSettings::item(int code) { QTC_ASSERT(m_items.value(code, 0), return 0); return m_items.value(code, 0); @@ -316,7 +342,7 @@ QString DebuggerSettings::dump() QString out; QTextStream ts(&out); ts << "Debugger settings: "; - foreach (DebuggerAction *item, m_items) + foreach (SavedAction *item, m_items) ts << "\n" << item->value().toString(); return out; } @@ -338,16 +364,16 @@ DebuggerSettings *theDebuggerSettings() instance = new DebuggerSettings; - DebuggerAction *item = 0; + SavedAction *item = 0; // // View // - item = new DebuggerAction(instance); + item = new SavedAction(instance); instance->insertItem(AdjustColumnWidths, item); item->setText(QObject::tr("Adjust column widths to contents")); - item = new DebuggerAction(instance); + item = new SavedAction(instance); instance->insertItem(AlwaysAdjustColumnWidths, item); item->setText(QObject::tr("Always adjust column widths to contents")); item->setCheckable(true); @@ -355,50 +381,50 @@ DebuggerSettings *theDebuggerSettings() // // Locals & Watchers // - item = new DebuggerAction(instance); + item = new SavedAction(instance); instance->insertItem(WatchExpression, item); item->setTextPattern(QObject::tr("Watch expression \"%1\"")); - item = new DebuggerAction(instance); + item = new SavedAction(instance); instance->insertItem(RemoveWatchExpression, item); item->setTextPattern(QObject::tr("Remove watch expression \"%1\"")); - item = new DebuggerAction(instance); + item = new SavedAction(instance); instance->insertItem(WatchExpressionInWindow, item); item->setTextPattern(QObject::tr("Watch expression \"%1\" in separate window")); //item->setCheckable(true); - item = new DebuggerAction(instance); + item = new SavedAction(instance); instance->insertItem(AssignValue, item); - item = new DebuggerAction(instance); + item = new SavedAction(instance); instance->insertItem(ExpandItem, item); item->setText(QObject::tr("Expand item")); - item = new DebuggerAction(instance); + item = new SavedAction(instance); instance->insertItem(CollapseItem, item); item->setText(QObject::tr("Collapse item")); // // Dumpers // - item = new DebuggerAction(instance); + item = new SavedAction(instance); instance->insertItem(SettingsDialog, item); item->setText(QObject::tr("Debugger properties...")); - item = new DebuggerAction(instance); + item = new SavedAction(instance); instance->insertItem(DebugDumpers, item); item->setText(QObject::tr("Debug custom dumpers")); item->setCheckable(true); - item = new DebuggerAction(instance); + item = new SavedAction(instance); item->setText(QObject::tr("Recheck custom dumper availability")); instance->insertItem(RecheckDumpers, item); // // Breakpoints // - item = new DebuggerAction(instance); + item = new SavedAction(instance); item->setText(QObject::tr("Syncronize breakpoints")); instance->insertItem(SynchronizeBreakpoints, item); @@ -409,7 +435,7 @@ DebuggerSettings *theDebuggerSettings() QActionGroup *registerFormatGroup = new QActionGroup(instance); registerFormatGroup->setExclusive(true); - item = new DebuggerAction(instance); + item = new SavedAction(instance); item->setText(QObject::tr("Hexadecimal")); item->setCheckable(true); item->setSettingsKey("DebugMode", "FormatHexadecimal"); @@ -417,35 +443,35 @@ DebuggerSettings *theDebuggerSettings() instance->insertItem(FormatHexadecimal, item); registerFormatGroup->addAction(item); - item = new DebuggerAction(instance); + item = new SavedAction(instance); item->setText(QObject::tr("Decimal")); item->setCheckable(true); item->setSettingsKey("DebugMode", "FormatDecimal"); instance->insertItem(FormatDecimal, item); registerFormatGroup->addAction(item); - item = new DebuggerAction(instance); + item = new SavedAction(instance); item->setText(QObject::tr("Octal")); item->setCheckable(true); item->setSettingsKey("DebugMode", "FormatOctal"); instance->insertItem(FormatOctal, item); registerFormatGroup->addAction(item); - item = new DebuggerAction(instance); + item = new SavedAction(instance); item->setText(QObject::tr("Binary")); item->setCheckable(true); item->setSettingsKey("DebugMode", "FormatBinary"); instance->insertItem(FormatBinary, item); registerFormatGroup->addAction(item); - item = new DebuggerAction(instance); + item = new SavedAction(instance); item->setText(QObject::tr("Raw")); item->setCheckable(true); item->setSettingsKey("DebugMode", "FormatRaw"); instance->insertItem(FormatRaw, item); registerFormatGroup->addAction(item); - item = new DebuggerAction(instance); + item = new SavedAction(instance); item->setText(QObject::tr("Natural")); item->setCheckable(true); item->setSettingsKey("DebugMode", "FormatNatural"); @@ -456,17 +482,17 @@ DebuggerSettings *theDebuggerSettings() // Misc // - item = new DebuggerAction(instance); + item = new SavedAction(instance); instance->insertItem(SkipKnownFrames, item); item->setText(QObject::tr("Skip known frames")); item->setCheckable(true); - item = new DebuggerAction(instance); + item = new SavedAction(instance); instance->insertItem(UseToolTips, item); item->setText(QObject::tr("Use tooltips when debugging")); item->setCheckable(true); - item = new DebuggerAction(instance); + item = new SavedAction(instance); instance->insertItem(ListSourceFiles, item); item->setText(QObject::tr("List source files")); item->setCheckable(true); @@ -475,91 +501,91 @@ DebuggerSettings *theDebuggerSettings() // // Settings // - item = new DebuggerAction(instance); + item = new SavedAction(instance); instance->insertItem(GdbLocation, item); item->setSettingsKey("DebugMode", "Location"); - item = new DebuggerAction(instance); + item = new SavedAction(instance); instance->insertItem(GdbEnvironment, item); item->setSettingsKey("DebugMode", "Environment"); - item = new DebuggerAction(instance); + item = new SavedAction(instance); instance->insertItem(GdbScriptFile, item); item->setSettingsKey("DebugMode", "ScriptFile"); - item = new DebuggerAction(instance); + item = new SavedAction(instance); item->setSettingsKey("DebugMode", "AutoQuit"); item->setText(QObject::tr("Automatically quit debugger")); item->setCheckable(true); instance->insertItem(AutoQuit, item); - item = new DebuggerAction(instance); + item = new SavedAction(instance); instance->insertItem(UseToolTips, item); item->setSettingsKey("DebugMode", "UseToolTips"); - item = new DebuggerAction(instance); + item = new SavedAction(instance); instance->insertItem(UseDumpers, item); item->setSettingsKey("DebugMode", "UseCustomDumpers"); item->setText(QObject::tr("Use custom dumpers")); item->setCheckable(true); - item = new DebuggerAction(instance); + item = new SavedAction(instance); instance->insertItem(BuildDumpersOnTheFly, item); item->setDefaultValue(true); item->setSettingsKey("DebugMode", "BuildDumpersOnTheFly"); item->setCheckable(true); - item = new DebuggerAction(instance); + item = new SavedAction(instance); instance->insertItem(UseQtDumpers, item); item->setSettingsKey("DebugMode", "UseQtDumpers"); item->setCheckable(true); - item = new DebuggerAction(instance); + item = new SavedAction(instance); instance->insertItem(UsePrebuiltDumpers, item); item->setSettingsKey("DebugMode", "UsePrebuiltDumpers"); item->setCheckable(true); - item = new DebuggerAction(instance); + item = new SavedAction(instance); instance->insertItem(PrebuiltDumpersLocation, item); item->setSettingsKey("DebugMode", "PrebuiltDumpersLocation"); - item = new DebuggerAction(instance); + item = new SavedAction(instance); instance->insertItem(TerminalApplication, item); item->setDefaultValue("xterm"); item->setSettingsKey("DebugMode", "Terminal"); - item = new DebuggerAction(instance); + item = new SavedAction(instance); instance->insertItem(ListSourceFiles, item); item->setSettingsKey("DebugMode", "ListSourceFiles"); - item = new DebuggerAction(instance); + item = new SavedAction(instance); instance->insertItem(SkipKnownFrames, item); item->setSettingsKey("DebugMode", "SkipKnownFrames"); - item = new DebuggerAction(instance); + item = new SavedAction(instance); instance->insertItem(DebugDumpers, item); item->setSettingsKey("DebugMode", "DebugDumpers"); - item = new DebuggerAction(instance); + item = new SavedAction(instance); instance->insertItem(AllPluginBreakpoints, item); item->setSettingsKey("DebugMode", "AllPluginBreakpoints"); - item = new DebuggerAction(instance); + item = new SavedAction(instance); instance->insertItem(SelectedPluginBreakpoints, item); item->setSettingsKey("DebugMode", "SelectedPluginBreakpoints"); - item = new DebuggerAction(instance); + item = new SavedAction(instance); instance->insertItem(NoPluginBreakpoints, item); item->setSettingsKey("DebugMode", "NoPluginBreakpoints"); - item = new DebuggerAction(instance); + item = new SavedAction(instance); instance->insertItem(SelectedPluginBreakpointsPattern, item); item->setSettingsKey("DebugMode", "SelectedPluginBreakpointsPattern"); return instance; } -DebuggerAction *theDebuggerAction(int code) +SavedAction *theDebuggerAction(int code) { return theDebuggerSettings()->item(code); } diff --git a/src/plugins/debugger/debuggeractions.h b/src/plugins/debugger/debuggeractions.h index 5d7e5354d239c332baab76fb0a0d002f0b2fc31b..e738ac9eedba7e6f8f6bbdfa3e4d7d8ff3d0b85a 100644 --- a/src/plugins/debugger/debuggeractions.h +++ b/src/plugins/debugger/debuggeractions.h @@ -42,17 +42,17 @@ class QSettings; QT_END_NAMESPACE -namespace Debugger { -namespace Internal { +namespace Core { +namespace Utils { enum ApplyMode { ImmediateApply, DeferedApply }; -class DebuggerAction : public QAction +class SavedAction : public QAction { Q_OBJECT public: - DebuggerAction(QObject *parent = 0); + SavedAction(QObject *parent = 0); virtual QVariant value() const; Q_SLOT virtual void setValue(const QVariant &value, bool doemit = true); @@ -75,6 +75,7 @@ public: Q_SLOT virtual void writeSettings(QSettings *settings); virtual void connectWidget(QWidget *widget, ApplyMode applyMode = DeferedApply); + virtual void disconnectWidget(); Q_SLOT virtual void apply(QSettings *settings); virtual QString textPattern() const; @@ -84,8 +85,6 @@ public: signals: void valueChanged(const QVariant &newValue); - void boolValueChanged(bool newValue); - void stringValueChanged(const QString &newValue); private: Q_SLOT void uncheckableButtonClicked(); @@ -104,6 +103,28 @@ private: ApplyMode m_applyMode; }; +class SavedActionSet +{ +public: + SavedActionSet() {} + ~SavedActionSet() {} + + void insert(SavedAction *action, QWidget *widget); + void apply(QSettings *settings); + void finish(); + void clear() { m_list.clear(); } + +private: + QList<SavedAction *> m_list; +}; + +} // namespace Utils +} // namespace Core + + +namespace Debugger { +namespace Internal { + class DebuggerSettings : public QObject { Q_OBJECT @@ -112,8 +133,8 @@ public: DebuggerSettings(QObject *parent = 0); ~DebuggerSettings(); - void insertItem(int code, DebuggerAction *item); - DebuggerAction *item(int code); + void insertItem(int code, Core::Utils::SavedAction *item); + Core::Utils::SavedAction *item(int code); QString dump(); @@ -122,7 +143,7 @@ public slots: void writeSettings(QSettings *settings); private: - QHash<int, DebuggerAction *> m_items; + QHash<int, Core::Utils::SavedAction *> m_items; }; @@ -185,7 +206,7 @@ enum DebuggerActionCode // singleton access DebuggerSettings *theDebuggerSettings(); -DebuggerAction *theDebuggerAction(int code); +Core::Utils::SavedAction *theDebuggerAction(int code); // convienience bool theDebuggerBoolSetting(int code); diff --git a/src/plugins/debugger/debuggerplugin.cpp b/src/plugins/debugger/debuggerplugin.cpp index 34152a52ca5bff419fb17cb495e78b94f44627f6..5fabcee182187d4978974073675cf05c16016e3e 100644 --- a/src/plugins/debugger/debuggerplugin.cpp +++ b/src/plugins/debugger/debuggerplugin.cpp @@ -251,14 +251,15 @@ public: QString trCategory() const { return tr("Debugger"); } QWidget *createPage(QWidget *parent); - void apply(); - void finish() {} // automatically calls "apply" + void apply() { m_group.apply(ICore::instance()->settings()); } + void finish() { m_group.finish(); } private: friend class DebuggerPlugin; Ui::GdbOptionPage m_ui; DebuggerPlugin *m_plugin; + Core::Utils::SavedActionSet m_group; }; QWidget *GdbOptionPage::createPage(QWidget *parent) @@ -272,30 +273,31 @@ QWidget *GdbOptionPage::createPage(QWidget *parent) m_ui.terminalChooser->setExpectedKind(Core::Utils::PathChooser::Command); m_ui.terminalChooser->setPromptDialogTitle(tr("Choose Location of Terminal Application")); - theDebuggerAction(GdbLocation) - ->connectWidget(m_ui.gdbLocationChooser); - theDebuggerAction(GdbScriptFile) - ->connectWidget(m_ui.scriptFileChooser); - theDebuggerAction(GdbEnvironment) - ->connectWidget(m_ui.environmentEdit); - theDebuggerAction(TerminalApplication) - ->connectWidget(m_ui.terminalChooser); - - theDebuggerAction(AllPluginBreakpoints) - ->connectWidget(m_ui.radioButtonAllPluginBreakpoints); - theDebuggerAction(SelectedPluginBreakpoints) - ->connectWidget(m_ui.radioButtonSelectedPluginBreakpoints); - theDebuggerAction(NoPluginBreakpoints) - ->connectWidget(m_ui.radioButtonNoPluginBreakpoints); - theDebuggerAction(SelectedPluginBreakpointsPattern) - ->connectWidget(m_ui.lineEditSelectedPluginBreakpointsPattern); - - theDebuggerAction(SkipKnownFrames) - ->connectWidget(m_ui.checkBoxSkipKnownFrames); - theDebuggerAction(UseToolTips) - ->connectWidget(m_ui.checkBoxUseToolTips); - theDebuggerAction(SelectedPluginBreakpointsPattern) - ->connectWidget(m_ui.lineEditSelectedPluginBreakpointsPattern); + m_group.clear(); + m_group.insert(theDebuggerAction(GdbLocation), + m_ui.gdbLocationChooser); + m_group.insert(theDebuggerAction(GdbScriptFile), + m_ui.scriptFileChooser); + m_group.insert(theDebuggerAction(GdbEnvironment), + m_ui.environmentEdit); + m_group.insert(theDebuggerAction(TerminalApplication), + m_ui.terminalChooser); + + m_group.insert(theDebuggerAction(AllPluginBreakpoints), + m_ui.radioButtonAllPluginBreakpoints); + m_group.insert(theDebuggerAction(SelectedPluginBreakpoints), + m_ui.radioButtonSelectedPluginBreakpoints); + m_group.insert(theDebuggerAction(NoPluginBreakpoints), + m_ui.radioButtonNoPluginBreakpoints); + m_group.insert(theDebuggerAction(SelectedPluginBreakpointsPattern), + m_ui.lineEditSelectedPluginBreakpointsPattern); + + m_group.insert(theDebuggerAction(ListSourceFiles), + m_ui.checkBoxListSourceFiles); + m_group.insert(theDebuggerAction(SkipKnownFrames), + m_ui.checkBoxSkipKnownFrames); + m_group.insert(theDebuggerAction(UseToolTips), + m_ui.checkBoxUseToolTips); m_ui.lineEditSelectedPluginBreakpointsPattern-> setEnabled(theDebuggerAction(SelectedPluginBreakpoints)->value().toBool()); @@ -312,25 +314,6 @@ QWidget *GdbOptionPage::createPage(QWidget *parent) return w; } -void GdbOptionPage::apply() -{ - QSettings *s = ICore::instance()->settings(); - - theDebuggerAction(GdbLocation)->apply(s); - theDebuggerAction(GdbScriptFile)->apply(s); - theDebuggerAction(GdbEnvironment)->apply(s); - theDebuggerAction(TerminalApplication)->apply(s); - - theDebuggerAction(AllPluginBreakpoints)->apply(s); - theDebuggerAction(SelectedPluginBreakpoints)->apply(s); - theDebuggerAction(NoPluginBreakpoints)->apply(s); - theDebuggerAction(SelectedPluginBreakpointsPattern)->apply(s); - - theDebuggerAction(SkipKnownFrames)->apply(s); - theDebuggerAction(UseToolTips)->apply(s); - theDebuggerAction(SelectedPluginBreakpointsPattern)->apply(s); -} - } // namespace Internal } // namespace Debugger @@ -358,14 +341,15 @@ public: QString trCategory() const { return tr("Debugger"); } QWidget *createPage(QWidget *parent); - void apply(); - void finish() {} // automatically calls "apply" + void apply() { m_group.apply(ICore::instance()->settings()); } + void finish() { m_group.finish(); } private: friend class DebuggerPlugin; Ui::DumperOptionPage m_ui; DebuggerPlugin *m_plugin; + Core::Utils::SavedActionSet m_group; }; QWidget *DumperOptionPage::createPage(QWidget *parent) @@ -381,19 +365,20 @@ QWidget *DumperOptionPage::createPage(QWidget *parent) connect(m_ui.radioButtonUsePrebuiltDumpers, SIGNAL(toggled(bool)), m_ui.dumperLocationChooser, SLOT(setEnabled(bool))); - theDebuggerAction(UseQtDumpers) - ->connectWidget(m_ui.radioButtonUseQtDumpers); - theDebuggerAction(UsePrebuiltDumpers) - ->connectWidget(m_ui.radioButtonUsePrebuiltDumpers); - theDebuggerAction(BuildDumpersOnTheFly) - ->connectWidget(m_ui.radioButtonBuildDumpersOnTheFly); - theDebuggerAction(PrebuiltDumpersLocation) - ->connectWidget(m_ui.dumperLocationChooser); - - theDebuggerAction(UseDumpers) - ->connectWidget(m_ui.checkBoxUseDumpers); - theDebuggerAction(DebugDumpers) - ->connectWidget(m_ui.checkBoxDebugDumpers); + m_group.clear(); + m_group.insert(theDebuggerAction(UseQtDumpers), + m_ui.radioButtonUseQtDumpers); + m_group.insert(theDebuggerAction(UsePrebuiltDumpers), + m_ui.radioButtonUsePrebuiltDumpers); + m_group.insert(theDebuggerAction(BuildDumpersOnTheFly), + m_ui.radioButtonBuildDumpersOnTheFly); + m_group.insert(theDebuggerAction(PrebuiltDumpersLocation), + m_ui.dumperLocationChooser); + + m_group.insert(theDebuggerAction(UseDumpers), + m_ui.checkBoxUseDumpers); + m_group.insert(theDebuggerAction(DebugDumpers), + m_ui.checkBoxDebugDumpers); m_ui.dumperLocationChooser-> setEnabled(theDebuggerAction(UsePrebuiltDumpers)->value().toBool()); @@ -411,18 +396,6 @@ QWidget *DumperOptionPage::createPage(QWidget *parent) return w; } -void DumperOptionPage::apply() -{ - QSettings *s = ICore::instance()->settings(); - - theDebuggerAction(UseDumpers)->apply(s); - theDebuggerAction(UseQtDumpers)->apply(s); - theDebuggerAction(UsePrebuiltDumpers)->apply(s); - theDebuggerAction(BuildDumpersOnTheFly)->apply(s); - theDebuggerAction(PrebuiltDumpersLocation)->apply(s); - theDebuggerAction(DebugDumpers)->apply(s); -} - } // namespace Internal } // namespace Debugger diff --git a/src/plugins/debugger/gdbengine.cpp b/src/plugins/debugger/gdbengine.cpp index daf2e6e0c0b355dc4a0af37bf785da39efe2dcd2..fa4e933044416917b1704258648fa9cf139e78a6 100644 --- a/src/plugins/debugger/gdbengine.cpp +++ b/src/plugins/debugger/gdbengine.cpp @@ -210,10 +210,10 @@ void GdbEngine::initializeConnections() q, SLOT(showApplicationOutput(QString)), Qt::QueuedConnection); - connect(theDebuggerAction(UseDumpers), SIGNAL(boolValueChanged(bool)), - this, SLOT(setUseDumpers(bool))); - connect(theDebuggerAction(DebugDumpers), SIGNAL(boolValueChanged(bool)), - this, SLOT(setDebugDumpers(bool))); + connect(theDebuggerAction(UseDumpers), SIGNAL(valueChanged(QVariant)), + this, SLOT(setUseDumpers(QVariant))); + connect(theDebuggerAction(DebugDumpers), SIGNAL(valueChanged(QVariant)), + this, SLOT(setDebugDumpers(QVariant))); connect(theDebuggerAction(RecheckDumpers), SIGNAL(triggered()), this, SLOT(recheckCustomDumperAvailability())); @@ -1834,9 +1834,9 @@ void GdbEngine::setTokenBarrier() m_oldestAcceptableToken = currentToken(); } -void GdbEngine::setDebugDumpers(bool on) +void GdbEngine::setDebugDumpers(const QVariant &on) { - if (on) { + if (on.toBool()) { debugMessage("SWITCHING ON DUMPER DEBUGGING"); sendCommand("set unwindonsignal off"); q->breakByFunction("qDumpObjectData440"); @@ -2447,8 +2447,7 @@ void GdbEngine::handleStackListFrames(const GdbResultRecord &record) for (int i = 0; i != stack.childCount(); ++i) { //qDebug() << "HANDLING FRAME: " << stack.childAt(i).toString(); const GdbMi frameMi = stack.childAt(i); - StackFrame frame; - frame.level = i; + StackFrame frame(i); QStringList files; files.append(frameMi.findChild("fullname").data()); files.append(frameMi.findChild("file").data()); @@ -2488,8 +2487,7 @@ void GdbEngine::handleStackListFrames(const GdbResultRecord &record) if (0 && topFrame != -1) { // updates of locals already triggered early const StackFrame &frame = qq->stackHandler()->currentFrame(); - bool usable = !frame.file.isEmpty() && QFileInfo(frame.file).isReadable(); - if (usable) + if (frame.isUsable()) q->gotoLocation(frame.file, frame.line, true); else qDebug() << "FULL NAME NOT USABLE 0: " << frame.file; @@ -2500,8 +2498,7 @@ void GdbEngine::handleStackListFrames(const GdbResultRecord &record) if (topFrame != -1) { // updates of locals already triggered early const StackFrame &frame = qq->stackHandler()->currentFrame(); - bool usable = !frame.file.isEmpty() && QFileInfo(frame.file).isReadable(); - if (usable) + if (frame.isUsable()) q->gotoLocation(frame.file, frame.line, true); else qDebug() << "FULL NAME NOT USABLE 0: " << frame.file << topFrame; @@ -2551,8 +2548,7 @@ void GdbEngine::activateFrame(int frameIndex) const StackFrame &frame = stackHandler->currentFrame(); - bool usable = !frame.file.isEmpty() && QFileInfo(frame.file).isReadable(); - if (usable) + if (frame.isUsable()) q->gotoLocation(frame.file, frame.line, true); else qDebug() << "FULL NAME NOT USABLE: " << frame.file; @@ -2853,10 +2849,9 @@ static void setWatchDataSAddress(WatchData &data, const GdbMi &mi) data.saddr = mi.data(); } -void GdbEngine::setUseDumpers(bool on) +void GdbEngine::setUseDumpers(const QVariant &on) { qDebug() << "SWITCHING ON/OFF DUMPER DEBUGGING:" << on; - Q_UNUSED(on); // FIXME: a bit too harsh, but otherwise the treeview sometimes look funny //m_expandedINames.clear(); setTokenBarrier(); diff --git a/src/plugins/debugger/gdbengine.h b/src/plugins/debugger/gdbengine.h index d35f0f0827174a8b059940436ebd175f9daa0dbf..49b823e957bed4e23888531822e99ed9d513c50f 100644 --- a/src/plugins/debugger/gdbengine.h +++ b/src/plugins/debugger/gdbengine.h @@ -130,8 +130,8 @@ private: void loadSymbols(const QString &moduleName); void loadAllSymbols(); - Q_SLOT void setDebugDumpers(bool on); - Q_SLOT void setUseDumpers(bool on); + Q_SLOT void setDebugDumpers(const QVariant &on); + Q_SLOT void setUseDumpers(const QVariant &on); // // Own stuff diff --git a/src/plugins/debugger/stackhandler.cpp b/src/plugins/debugger/stackhandler.cpp index fcc28bdd19df2de7ae87bee3a74e4cf7c8b04936..a131bc004286343ab4c0201994f929ac09d87f07 100644 --- a/src/plugins/debugger/stackhandler.cpp +++ b/src/plugins/debugger/stackhandler.cpp @@ -37,6 +37,16 @@ using namespace Debugger::Internal; +StackFrame::StackFrame(int l) : + level(l), + line(0) +{ +} + +bool StackFrame::isUsable() const +{ + return !file.isEmpty() && QFileInfo(file).isReadable(); +} //////////////////////////////////////////////////////////////////////// // diff --git a/src/plugins/debugger/stackhandler.h b/src/plugins/debugger/stackhandler.h index d427c93e92139cd2743d82b1aa90d03c3f07c836..ae073e3d1369f74a42ba6eeb9b5df0580c545205 100644 --- a/src/plugins/debugger/stackhandler.h +++ b/src/plugins/debugger/stackhandler.h @@ -46,6 +46,9 @@ namespace Internal { struct StackFrame { + StackFrame(int level = 0); + bool isUsable() const; + int level; QString function; QString file; // we try to put an absolute file name in there diff --git a/src/plugins/find/findplugin.cpp b/src/plugins/find/findplugin.cpp index ee62bea84bf99848b62c834153d2ba2911aa8396..2a5d10470708990a5ed420e1f15ac6ca211a3ce6 100644 --- a/src/plugins/find/findplugin.cpp +++ b/src/plugins/find/findplugin.cpp @@ -105,6 +105,14 @@ void FindPlugin::filterChanged() QTC_ASSERT(changedFilter, return); QTC_ASSERT(action, return); action->setEnabled(changedFilter->isEnabled()); + bool haveEnabledFilters = false; + foreach (IFindFilter *filter, m_filterActions.keys()) { + if (filter->isEnabled()) { + haveEnabledFilters = true; + break; + } + } + m_openFindDialog->setEnabled(haveEnabledFilters); } void FindPlugin::openFindFilter() @@ -112,8 +120,6 @@ void FindPlugin::openFindFilter() QAction *action = qobject_cast<QAction*>(sender()); QTC_ASSERT(action, return); IFindFilter *filter = action->data().value<IFindFilter *>(); - QTC_ASSERT(filter, return); - QTC_ASSERT(filter->isEnabled(), return); QString currentFindString = (m_currentDocumentFind->isEnabled() ? m_currentDocumentFind->currentFindString() : ""); if (!currentFindString.isEmpty()) m_findDialog->setFindText(currentFindString); @@ -127,6 +133,7 @@ void FindPlugin::setupMenu() Core::ActionContainer *mfind = am->createMenu(Constants::M_FIND); medit->addMenu(mfind, Core::Constants::G_EDIT_FIND); mfind->menu()->setTitle(tr("&Find/Replace")); + mfind->appendGroup(Constants::G_FIND_CURRENTDOCUMENT); mfind->appendGroup(Constants::G_FIND_FILTERS); mfind->appendGroup(Constants::G_FIND_FLAGS); mfind->appendGroup(Constants::G_FIND_ACTIONS); @@ -141,6 +148,12 @@ void FindPlugin::setupMenu() separator->setSeparator(true); cmd = am->registerAction(separator, QLatin1String("Find.Sep.Actions"), globalcontext); mfind->addAction(cmd, Constants::G_FIND_ACTIONS); + + m_openFindDialog = new QAction(tr("Find Dialog"), this); + cmd = am->registerAction(m_openFindDialog, QLatin1String("Find.Dialog"), globalcontext); + cmd->setDefaultKeySequence(QKeySequence(tr("Ctrl+Shift+F"))); + mfind->addAction(cmd, Constants::G_FIND_FILTERS); + connect(m_openFindDialog, SIGNAL(triggered()), this, SLOT(openFindFilter())); } void FindPlugin::setupFilterMenuItems() @@ -153,9 +166,13 @@ void FindPlugin::setupFilterMenuItems() Core::ActionContainer *mfind = am->actionContainer(Constants::M_FIND); m_filterActions.clear(); + bool haveEnabledFilters = false; foreach (IFindFilter *filter, findInterfaces) { - QAction *action = new QAction(filter->name(), this); - action->setEnabled(filter->isEnabled()); + QAction *action = new QAction(QString(" %1").arg(filter->name()), this); + bool isEnabled = filter->isEnabled(); + if (isEnabled) + haveEnabledFilters = true; + action->setEnabled(isEnabled); action->setData(qVariantFromValue(filter)); cmd = am->registerAction(action, QLatin1String("FindFilter.")+filter->name(), globalcontext); cmd->setDefaultKeySequence(filter->defaultShortcut()); @@ -165,6 +182,8 @@ void FindPlugin::setupFilterMenuItems() connect(filter, SIGNAL(changed()), this, SLOT(filterChanged())); } m_findDialog->setFindFilters(findInterfaces); + m_openFindDialog->setEnabled(haveEnabledFilters); + } QTextDocument::FindFlags FindPlugin::findFlags() const diff --git a/src/plugins/find/findplugin.h b/src/plugins/find/findplugin.h index 53bd805aaa2d5a8f05a2cf2054d48a5e727bbbb7..a4c2ce283823902d6e22495d5ebbdd9a975f1661 100644 --- a/src/plugins/find/findplugin.h +++ b/src/plugins/find/findplugin.h @@ -97,6 +97,7 @@ private: QStringListModel *m_replaceCompletionModel; QStringList m_findCompletions; QStringList m_replaceCompletions; + QAction *m_openFindDialog; }; } // namespace Internal diff --git a/src/plugins/find/findtoolbar.cpp b/src/plugins/find/findtoolbar.cpp index 2c2295740d01bfd0be4a0a445b0d4a938ad21edd..97f66d5d27565b3d6af0cbabec5b8df8f8ab2a11 100644 --- a/src/plugins/find/findtoolbar.cpp +++ b/src/plugins/find/findtoolbar.cpp @@ -149,7 +149,7 @@ FindToolBar::FindToolBar(FindPlugin *plugin, CurrentDocumentFind *currentDocumen m_findInDocumentAction = new QAction(tr("Current Document"), this); cmd = am->registerAction(m_findInDocumentAction, Constants::FIND_IN_DOCUMENT, globalcontext); cmd->setDefaultKeySequence(QKeySequence::Find); - mfind->addAction(cmd, Constants::G_FIND_FILTERS); + mfind->addAction(cmd, Constants::G_FIND_CURRENTDOCUMENT); connect(m_findInDocumentAction, SIGNAL(triggered()), this, SLOT(openFind())); if (QApplication::clipboard()->supportsFindBuffer()) { diff --git a/src/plugins/find/textfindconstants.h b/src/plugins/find/textfindconstants.h index 40394dfb857c37c5288974819bd32a771a376f59..a430c9989767a57c9437f6bb446b79e670f90d51 100644 --- a/src/plugins/find/textfindconstants.h +++ b/src/plugins/find/textfindconstants.h @@ -34,6 +34,7 @@ namespace Find { namespace Constants { const char * const M_FIND = "Find.FindMenu"; +const char * const G_FIND_CURRENTDOCUMENT = "Find.FindMenu.CurrentDocument"; const char * const G_FIND_FILTERS = "Find.FindMenu.Filters"; const char * const G_FIND_FLAGS = "Find.FindMenu.Flags"; const char * const G_FIND_ACTIONS = "Find.FindMenu.Actions"; diff --git a/src/plugins/projectexplorer/allprojectsfind.cpp b/src/plugins/projectexplorer/allprojectsfind.cpp index af0a962ec34c54ddd3daa5b8fa51920ae133f6cc..c6448c2f801ae33d924d958e48d9d0d92424dfc3 100644 --- a/src/plugins/projectexplorer/allprojectsfind.cpp +++ b/src/plugins/projectexplorer/allprojectsfind.cpp @@ -65,7 +65,7 @@ bool AllProjectsFind::isEnabled() const QKeySequence AllProjectsFind::defaultShortcut() const { - return QKeySequence("Ctrl+Shift+F"); + return QKeySequence(); } QStringList AllProjectsFind::files() diff --git a/src/plugins/projectexplorer/currentprojectfind.cpp b/src/plugins/projectexplorer/currentprojectfind.cpp index 123efdbb82409039088a320ce20903ee628cb1f4..4fcfc68642e5f5f27717c98aa242730f86143430 100644 --- a/src/plugins/projectexplorer/currentprojectfind.cpp +++ b/src/plugins/projectexplorer/currentprojectfind.cpp @@ -64,7 +64,7 @@ bool CurrentProjectFind::isEnabled() const QKeySequence CurrentProjectFind::defaultShortcut() const { - return QKeySequence("Ctrl+Alt+F"); + return QKeySequence(); } QStringList CurrentProjectFind::files() diff --git a/src/plugins/qt4projectmanager/qt4runconfiguration.cpp b/src/plugins/qt4projectmanager/qt4runconfiguration.cpp index 64cb11b448c1d3ff0cb54ece8ed110d056587145..0522fab8d35f9b33e9ea9d5d83ceac92ef1501e6 100644 --- a/src/plugins/qt4projectmanager/qt4runconfiguration.cpp +++ b/src/plugins/qt4projectmanager/qt4runconfiguration.cpp @@ -89,8 +89,8 @@ Qt4RunConfigurationWidget::Qt4RunConfigurationWidget(Qt4RunConfiguration *qt4Run : QWidget(parent), m_qt4RunConfiguration(qt4RunConfiguration), m_ignoreChange(false), - m_isShown(false), - m_usingDyldImageSuffix(0) + m_usingDyldImageSuffix(0), + m_isShown(false) { QFormLayout *toplayout = new QFormLayout(this); toplayout->setMargin(0); diff --git a/src/plugins/texteditor/completionsupport.cpp b/src/plugins/texteditor/completionsupport.cpp index 53de9ee66e1dee79c833953bb2413b6d6a9fd3e6..2e456193ad52f2af57952a6667f6e3a63f885ea7 100644 --- a/src/plugins/texteditor/completionsupport.cpp +++ b/src/plugins/texteditor/completionsupport.cpp @@ -186,6 +186,8 @@ QList<CompletionItem> CompletionSupport::getCompletions() const if (item.m_text != lastKey) { uniquelist.append(item); lastKey = item.m_text; + } else { + uniquelist.last().m_duplicateCount++; } } diff --git a/src/plugins/texteditor/icompletioncollector.h b/src/plugins/texteditor/icompletioncollector.h index c8c035802e4e0c83f305b07c6f05421427cd39f7..49d70f182883b2302cd16c1203b2216b3a39d749 100644 --- a/src/plugins/texteditor/icompletioncollector.h +++ b/src/plugins/texteditor/icompletioncollector.h @@ -46,6 +46,7 @@ struct CompletionItem { CompletionItem(ICompletionCollector *collector = 0) : m_relevance(0), + m_duplicateCount(0), m_collector(collector) { } @@ -60,6 +61,7 @@ struct CompletionItem QIcon m_icon; QVariant m_data; int m_relevance; + int m_duplicateCount; ICompletionCollector *m_collector; }; diff --git a/src/shared/cplusplus/Symbols.cpp b/src/shared/cplusplus/Symbols.cpp index 5185aa82659a8fd1f5e6897f21abfeab6cc4a5d0..10b82664c345aeb94648a55049d010e2246fcd72 100644 --- a/src/shared/cplusplus/Symbols.cpp +++ b/src/shared/cplusplus/Symbols.cpp @@ -217,6 +217,12 @@ FullySpecifiedType Function::returnType() const void Function::setReturnType(FullySpecifiedType returnType) { _returnType = returnType; } +bool Function::hasReturnType() const +{ + const FullySpecifiedType ty = returnType(); + return ty.isValid() || ty.isSigned() || ty.isUnsigned(); +} + unsigned Function::argumentCount() const { if (! _arguments) @@ -231,6 +237,12 @@ Symbol *Function::argumentAt(unsigned index) const Scope *Function::arguments() const { return _arguments; } +bool Function::hasArguments() const +{ + return ! (argumentCount() == 0 || + (argumentCount() == 1 && argumentAt(0)->type()->isVoidType())); +} + bool Function::isVariadic() const { return _isVariadic; } diff --git a/src/shared/cplusplus/Symbols.h b/src/shared/cplusplus/Symbols.h index 8efc0fbdbed0c104a843564817f77520b8131223..4052b746da29517391db21158a6db0cef77a60bc 100644 --- a/src/shared/cplusplus/Symbols.h +++ b/src/shared/cplusplus/Symbols.h @@ -288,10 +288,16 @@ public: FullySpecifiedType returnType() const; void setReturnType(FullySpecifiedType returnType); + /** Convenience function that returns whether the function returns something (including void). */ + bool hasReturnType() const; + unsigned argumentCount() const; Symbol *argumentAt(unsigned index) const; Scope *arguments() const; + /** Convenience function that returns whether the function receives any arguments. */ + bool hasArguments() const; + bool isVariadic() const; void setVariadic(bool isVariadic);