diff --git a/share/qtcreator/gdbmacros/gdbmacros.cpp b/share/qtcreator/gdbmacros/gdbmacros.cpp index 6277c5477cda6ddea509e1bd34dfdd7c981f382f..b3f054ffbb2ea639cb6cc418bbb6d3cd7d962f25 100644 --- a/share/qtcreator/gdbmacros/gdbmacros.cpp +++ b/share/qtcreator/gdbmacros/gdbmacros.cpp @@ -32,7 +32,7 @@ // this relies on contents copied from qobject_p.h #define PRIVATE_OBJECT_ALLOWED 1 -#ifdef HAS_QOBJECT_P_H +#ifdef HAS_QOBJECT_P_H // Detected by qmake # include <QtCore/private/qobject_p.h> #endif #include <QtCore/QDateTime> @@ -94,10 +94,10 @@ int qtGhVersion = QT_VERSION; \c{qDumpObjectData440()}. In any case, dumper processesing should end up in - \c{handleProtocolVersion2and3()} and needs an entry in the bis switch there. + \c{handleProtocolVersion2and3()} and needs an entry in the big switch there. Next step is to create a suitable \c{static void qDumpFoo(QDumper &d)} - function. At the bare minimum it should contain something like: + function. At the bare minimum it should contain something like this: \c{ @@ -127,7 +127,7 @@ int qtGhVersion = QT_VERSION; \endlist If the current item has children, it might be queried to produce information - about thes children. In this case the dumper should use something like + about these children. In this case the dumper should use something like this: \c{ if (d.dumpChildren) { @@ -149,7 +149,7 @@ int qtGhVersion = QT_VERSION; # define NSY "" #endif -#if PRIVATE_OBJECT_ALLOWED && !HAS_QOBJECT_P_H +#if PRIVATE_OBJECT_ALLOWED && !defined(HAS_QOBJECT_P_H) #if defined(QT_BEGIN_NAMESPACE) QT_BEGIN_NAMESPACE @@ -221,16 +221,19 @@ Q_DECL_EXPORT char qDumpOutBuffer[100000]; namespace { +static QByteArray strPtrConst = "* const"; + static bool isPointerType(const QByteArray &type) { - return type.endsWith("*") || type.endsWith("* const"); + return type.endsWith('*') || type.endsWith(strPtrConst); } -static QByteArray stripPointerType(QByteArray type) +static QByteArray stripPointerType(const QByteArray &_type) { - if (type.endsWith("*")) + QByteArray type = _type; + if (type.endsWith('*')) type.chop(1); - if (type.endsWith("* const")) + if (type.endsWith(strPtrConst)) type.chop(7); if (type.endsWith(' ')) type.chop(1); @@ -279,25 +282,35 @@ static bool isEqual(const char *s, const char *t) static bool startsWith(const char *s, const char *t) { - return qstrncmp(s, t, qstrlen(t)) == 0; + while (char c = *t++) + if (c != *s++) + return false; + return true; } // Check memory for read access and provoke segfault if nothing else helps. // On Windows, try to be less crash-prone by checking memory using WinAPI #ifdef Q_OS_WIN -# define qCheckAccess(d) if (IsBadReadPtr(d, 1)) return; do { qProvokeSegFaultHelper = *(char*)d; } while (0) -# define qCheckPointer(d) if (d && IsBadReadPtr(d, 1)) return; do { if (d) qProvokeSegFaultHelper = *(char*)d; } while (0) +# define qCheckAccess(d) do { if (IsBadReadPtr(d, 1)) return; qProvokeSegFaultHelper = *(char*)d; } while (0) +# define qCheckPointer(d) do { if (d && IsBadReadPtr(d, 1)) return; if (d) qProvokeSegFaultHelper = *(char*)d; } while (0) #else # define qCheckAccess(d) do { qProvokeSegFaultHelper = *(char*)d; } while (0) # define qCheckPointer(d) do { if (d) qProvokeSegFaultHelper = *(char*)d; } while (0) #endif +#ifdef QT_NAMESPACE const char *stripNamespace(const char *type) { - static const size_t nslen = qstrlen(NS); + static const size_t nslen = strlen(NS); return startsWith(type, NS) ? type + nslen : type; } +#else +inline const char *stripNamespace(const char *type) +{ + return type; +} +#endif static bool isSimpleType(const char *type) { @@ -1168,7 +1181,7 @@ static void qDumpQHashNode(QDumper &d) P(d, "numchild", 2); if (d.dumpChildren) { - // there is a hash specialization in cast the key are integers or shorts + // there is a hash specialization in case the keys are integers or shorts d << ",children=["; d.beginHash(); P(d, "name", "key"); @@ -2239,7 +2252,14 @@ static void qDumpQWeakPointer(QDumper &d) static void qDumpStdList(QDumper &d) { const std::list<int> &list = *reinterpret_cast<const std::list<int> *>(d.data); - const void *p = d.data; +#ifdef Q_CC_MSVC + const int size = static_cast<int>(list.size()); + if (size < 0) + return; + if (size) + qCheckAccess(list.begin().operator ->()); +#else + const void *p = d.data; qCheckAccess(p); p = deref(p); qCheckAccess(p); @@ -2251,7 +2271,7 @@ static void qDumpStdList(QDumper &d) qCheckAccess(p); p = deref(addOffset(p, sizeof(void*))); qCheckAccess(p); - +#endif int nn = 0; std::list<int>::const_iterator it = list.begin(); for (; nn < 101 && it != list.end(); ++nn, ++it) @@ -2434,7 +2454,7 @@ static void qDumpStdWString(QDumper &d) } static void qDumpStdVector(QDumper &d) -{ +{ // Correct type would be something like: // std::_Vector_base<int,std::allocator<int, std::allocator<int> >>::_Vector_impl struct VectorImpl { @@ -2442,8 +2462,13 @@ static void qDumpStdVector(QDumper &d) char *finish; char *end_of_storage; }; +#ifdef Q_CC_MSVC + // Pointers are at end of the structure + const char * vcp = static_cast<const char *>(d.data); + const VectorImpl *v = reinterpret_cast<const VectorImpl *>(vcp + sizeof(std::vector<int>) - sizeof(VectorImpl)); +#else const VectorImpl *v = static_cast<const VectorImpl *>(d.data); - +#endif // Try to provoke segfaults early to prevent the frontend // from asking for unavailable child details int nn = (v->finish - v->start) / d.extraInt[0]; @@ -2679,7 +2704,7 @@ void *qDumpObjectData440( // This is a list of all available dumpers. Note that some templates // currently require special hardcoded handling in the debugger plugin. - // They are mentioned here nevertheless. For types that not listed + // They are mentioned here nevertheless. For types that are not listed // here, dumpers won't be used. d << "dumpers=[" "\""NS"QByteArray\"," diff --git a/share/qtcreator/gdbmacros/test/main.cpp b/share/qtcreator/gdbmacros/test/main.cpp index f760e40aa980b9329349d5cf47a5fb65bd2cec3a..fcb6d9061cd4af4849731845ccfd1dcdbe478131 100644 --- a/share/qtcreator/gdbmacros/test/main.cpp +++ b/share/qtcreator/gdbmacros/test/main.cpp @@ -30,11 +30,11 @@ #include <QtCore/QStringList> #include <QtCore/QVector> #include <QtCore/QTimer> -#include <QtCore/private/qobject_p.h> #include <string> #include <list> #include <vector> +#include <set> #include <stdio.h> #include <string.h> @@ -204,19 +204,36 @@ static int dumpStdStringVector() return 0; } +static int dumpStdIntSet() +{ + std::set<int> test; + test.insert(1); + test.insert(2); + prepareInBuffer("std::set", "local.intset", "local.intset", "int"); + qDumpObjectData440(2, 42, &test, 1, sizeof(int), sizeof(std::list<int>::allocator_type), 0, 0); + fputs(qDumpOutBuffer, stdout); + fputc('\n', stdout); + return 0; +} + +static int dumpStdStringSet() +{ + std::set<std::string> test; + test.insert("item1"); + test.insert("item2"); + prepareInBuffer("std::set", "local.stringset", "local.stringset", "std::string"); + qDumpObjectData440(2, 42, &test, 1, sizeof(std::string), sizeof(std::list<int>::allocator_type), 0, 0); + fputs(qDumpOutBuffer, stdout); + fputc('\n', stdout); + return 0; +} static int dumpQObject() { + // Requires the childOffset to be know, but that is not critical QTimer t; - QObjectPrivate *tp = reinterpret_cast<QObjectPrivate *>(&t); -#ifdef KNOWS_OFFSET - const int childOffset = (char*)&tp->children - (char*)tp; -#else - const int childOffset = 0; -#endif - printf("Qt version %s Child offset: %d\n", QT_VERSION_STR, childOffset); prepareInBuffer("QObject", "local.qobject", "local.qobject", ""); - qDumpObjectData440(2, 42, &t, 1, childOffset, 0, 0, 0); + qDumpObjectData440(2, 42, &t, 1, 0, 0, 0, 0); fputs(qDumpOutBuffer, stdout); fputc('\n', stdout); return 0; @@ -256,6 +273,10 @@ int main(int argc, char *argv[]) dumpStdIntVector(); if (!qstrcmp(arg, "vector<string>")) dumpStdStringVector(); + if (!qstrcmp(arg, "set<int>")) + dumpStdIntSet(); + if (!qstrcmp(arg, "set<string>")) + dumpStdStringSet(); if (!qstrcmp(arg, "QObject")) dumpQObject(); } diff --git a/share/qtcreator/translations/translations.pro b/share/qtcreator/translations/translations.pro index dd4f6d5d47e5440ab0041299ad306d6c2b45d439..2021a405d8e3caac8d2f1fd14af526a72d9a80b4 100644 --- a/share/qtcreator/translations/translations.pro +++ b/share/qtcreator/translations/translations.pro @@ -9,8 +9,8 @@ defineReplace(prependAll) { return($$result) } -LUPDATE = $$targetPath($$[QT_INSTALL_PREFIX]/bin/lupdate) -locations relative -no-ui-lines -LRELEASE = $$targetPath($$[QT_INSTALL_PREFIX]/bin/lrelease) +LUPDATE = $$targetPath($$[QT_INSTALL_BINS]/lupdate) -locations relative -no-ui-lines +LRELEASE = $$targetPath($$[QT_INSTALL_BINS]/lrelease) TS_FILES = $$prependAll(TRANSLATIONS, $$PWD/qtcreator_,.ts) diff --git a/src/plugins/coreplugin/dialogs/saveitemsdialog.cpp b/src/plugins/coreplugin/dialogs/saveitemsdialog.cpp index 80b15b4c94b471979be597db48bc6b7fb01e7982..c49ae2dbbe697cf6c4e49ba45807e18c5757ae7c 100644 --- a/src/plugins/coreplugin/dialogs/saveitemsdialog.cpp +++ b/src/plugins/coreplugin/dialogs/saveitemsdialog.cpp @@ -55,6 +55,8 @@ SaveItemsDialog::SaveItemsDialog(QWidget *parent, m_ui.buttonBox->button(QDialogButtonBox::Save)->setFocus(Qt::TabFocusReason); m_ui.buttonBox->button(QDialogButtonBox::Save)->setMinimumWidth(130); // bad magic number to avoid resizing of button + m_ui.saveBeforeBuildCheckBox->setVisible(false); + foreach (IFile *file, items) { QString visibleName; QString directory; @@ -121,3 +123,14 @@ QList<IFile*> SaveItemsDialog::itemsToSave() const { return m_itemsToSave; } + +void SaveItemsDialog::setAlwaysSaveMessage(const QString &msg) +{ + m_ui.saveBeforeBuildCheckBox->setText(msg); + m_ui.saveBeforeBuildCheckBox->setVisible(true); +} + +bool SaveItemsDialog::alwaysSaveChecked() +{ + return m_ui.saveBeforeBuildCheckBox->isChecked(); +} diff --git a/src/plugins/coreplugin/dialogs/saveitemsdialog.h b/src/plugins/coreplugin/dialogs/saveitemsdialog.h index ff22baa1f66fa04eb1c4d1432ed3aab199a61b66..237db0d752d63bdc36fa2dd10741cd358586bc6e 100644 --- a/src/plugins/coreplugin/dialogs/saveitemsdialog.h +++ b/src/plugins/coreplugin/dialogs/saveitemsdialog.h @@ -57,7 +57,8 @@ public: QList<Core::IFile *> items); void setMessage(const QString &msg); - + void setAlwaysSaveMessage(const QString &msg); + bool alwaysSaveChecked(); QList<Core::IFile *> itemsToSave() const; private slots: diff --git a/src/plugins/coreplugin/dialogs/saveitemsdialog.ui b/src/plugins/coreplugin/dialogs/saveitemsdialog.ui index 966be8f4f303261e840bec53bf4dbf44c8e49c7c..6f37a47ddda003b1ed3ba41be87bd8c0536f8dd9 100644 --- a/src/plugins/coreplugin/dialogs/saveitemsdialog.ui +++ b/src/plugins/coreplugin/dialogs/saveitemsdialog.ui @@ -56,6 +56,13 @@ </column> </widget> </item> + <item> + <widget class="QCheckBox" name="saveBeforeBuildCheckBox"> + <property name="text"> + <string>Automatically save all Files before building</string> + </property> + </widget> + </item> <item> <widget class="QDialogButtonBox" name="buttonBox"> <property name="orientation"> diff --git a/src/plugins/coreplugin/filemanager.cpp b/src/plugins/coreplugin/filemanager.cpp index 5a9276fd85183df55134fd13eb0cefa253c076d0..b42611b2217c28fd829ee6de8dbc4b95949b84f3 100644 --- a/src/plugins/coreplugin/filemanager.cpp +++ b/src/plugins/coreplugin/filemanager.cpp @@ -292,9 +292,11 @@ QList<IFile *> FileManager::saveModifiedFilesSilently(const QList<IFile *> &file Asks the user whether to save the files listed in \a files . Returns the files that have not been saved. */ QList<IFile *> FileManager::saveModifiedFiles(const QList<IFile *> &files, - bool *cancelled, const QString &message) + bool *cancelled, const QString &message, + const QString &alwaysSaveMessage, + bool *alwaysSave) { - return saveModifiedFiles(files, cancelled, false, message); + return saveModifiedFiles(files, cancelled, false, message, alwaysSaveMessage, alwaysSave); } static QMessageBox::StandardButton skipFailedPrompt(QWidget *parent, const QString &fileName) @@ -307,7 +309,11 @@ static QMessageBox::StandardButton skipFailedPrompt(QWidget *parent, const QStri } QList<IFile *> FileManager::saveModifiedFiles(const QList<IFile *> &files, - bool *cancelled, bool silently, const QString &message) + bool *cancelled, + bool silently, + const QString &message, + const QString &alwaysSaveMessage, + bool *alwaysSave) { if (cancelled) (*cancelled) = false; @@ -338,12 +344,18 @@ QList<IFile *> FileManager::saveModifiedFiles(const QList<IFile *> &files, SaveItemsDialog dia(m_mainWindow, modifiedFiles); if (!message.isEmpty()) dia.setMessage(message); + if (!alwaysSaveMessage.isNull()) + dia.setAlwaysSaveMessage(alwaysSaveMessage); if (dia.exec() != QDialog::Accepted) { if (cancelled) (*cancelled) = true; + if (alwaysSave) + *alwaysSave = dia.alwaysSaveChecked(); notSaved = modifiedFiles; return notSaved; } + if (alwaysSave) + *alwaysSave = dia.alwaysSaveChecked(); filesToSave = dia.itemsToSave(); } diff --git a/src/plugins/coreplugin/filemanager.h b/src/plugins/coreplugin/filemanager.h index 52dafe4ca882556b78f49aa82959d9df6543a923..6be80514fd8f0c9cc3acc926ea8f37504afd7fe6 100644 --- a/src/plugins/coreplugin/filemanager.h +++ b/src/plugins/coreplugin/filemanager.h @@ -97,7 +97,9 @@ public: QList<IFile *> saveModifiedFilesSilently(const QList<IFile *> &files); QList<IFile *> saveModifiedFiles(const QList<IFile *> &files, bool *cancelled = 0, - const QString &message = QString()); + const QString &message = QString(), + const QString &alwaysSaveMessage = QString::null, + bool *alwaysSave = 0); signals: void currentFileChanged(const QString &filePath); @@ -116,7 +118,10 @@ private: void updateFileInfo(IFile *file); QList<IFile *> saveModifiedFiles(const QList<IFile *> &files, - bool *cancelled, bool silently, const QString &message); + bool *cancelled, bool silently, + const QString &message, + const QString &alwaysSaveMessage = QString::null, + bool *alwaysSave = 0); QMap<IFile*, FileInfo> m_managedFiles; diff --git a/src/plugins/debugger/cdb/cdbdebugengine.cpp b/src/plugins/debugger/cdb/cdbdebugengine.cpp index a7d60ad7fe7a81b980f30ecf7772a15735c25a23..72a60595ca1ad9ff433218b804ec7323dbebb40c 100644 --- a/src/plugins/debugger/cdb/cdbdebugengine.cpp +++ b/src/plugins/debugger/cdb/cdbdebugengine.cpp @@ -1186,14 +1186,6 @@ bool CdbDebugEnginePrivate::attemptBreakpointSynchronization(QString *errorMessa errorMessage); } -void CdbDebugEngine::loadSessionData() -{ -} - -void CdbDebugEngine::saveSessionData() -{ -} - void CdbDebugEngine::reloadDisassembler() { enum { ContextLines = 40 }; diff --git a/src/plugins/debugger/cdb/cdbdebugengine.h b/src/plugins/debugger/cdb/cdbdebugengine.h index 35fce47f66f7af6ca4263af39a625ed872359bf9..74547ab33adb43f5700e6aff18f62d080b3fc3f2 100644 --- a/src/plugins/debugger/cdb/cdbdebugengine.h +++ b/src/plugins/debugger/cdb/cdbdebugengine.h @@ -85,9 +85,6 @@ public: virtual void attemptBreakpointSynchronization(); - virtual void loadSessionData(); - virtual void saveSessionData(); - virtual void reloadDisassembler(); virtual void reloadModules(); @@ -97,6 +94,7 @@ public: virtual void reloadRegisters(); virtual void reloadSourceFiles(); + virtual void reloadFullStack() {} protected: void timerEvent(QTimerEvent*); diff --git a/src/plugins/debugger/cdb/cdbdumperhelper.cpp b/src/plugins/debugger/cdb/cdbdumperhelper.cpp index 541aa7ea1d0615303b4e67a295364b60ac74a89c..b76398254d0bb1d6c270da66a589416dae79fabf 100644 --- a/src/plugins/debugger/cdb/cdbdumperhelper.cpp +++ b/src/plugins/debugger/cdb/cdbdumperhelper.cpp @@ -571,7 +571,7 @@ CdbDumperHelper::DumpResult CdbDumperHelper::dumpType(const WatchData &wd, bool if (der == DumpExecuteSizeFailed) m_failedTypes.push_back(wd.type); // log error - *errorMessage = *errorMessage = msgDumpFailed(wd, errorMessage); + *errorMessage = msgDumpFailed(wd, errorMessage); m_access->showDebuggerOutput(m_messagePrefix, *errorMessage); return DumpError; } diff --git a/src/plugins/debugger/debuggermanager.cpp b/src/plugins/debugger/debuggermanager.cpp index ee7c653f06efeaf33282e26a5db496a89fb3fdac..23cc84059d2cfa2534435c1b3f668bfd02fd0caf 100644 --- a/src/plugins/debugger/debuggermanager.cpp +++ b/src/plugins/debugger/debuggermanager.cpp @@ -206,6 +206,10 @@ void DebuggerManager::init() stackView->setModel(m_stackHandler->stackModel()); connect(stackView, SIGNAL(frameActivated(int)), this, SLOT(activateFrame(int))); + connect(theDebuggerAction(ExpandStack), SIGNAL(triggered()), + this, SLOT(reloadFullStack())); + connect(theDebuggerAction(MaximalStackDepth), SIGNAL(triggered()), + this, SLOT(reloadFullStack())); // Threads m_threadsHandler = new ThreadsHandler; @@ -273,9 +277,8 @@ void DebuggerManager::init() m_registerHandler = new RegisterHandler; registerView->setModel(m_registerHandler->model()); - m_watchHandler = new WatchHandler; - // Locals + m_watchHandler = new WatchHandler; QTreeView *localsView = qobject_cast<QTreeView *>(m_localsWindow); localsView->setModel(m_watchHandler->model()); @@ -427,7 +430,7 @@ QList<Core::IOptionsPage*> DebuggerManager::initializeEngines(const QStringList const bool cdbDisabled = arguments.contains(_("-disable-cdb")); winEngine = createWinEngine(this, cdbDisabled, &rc); scriptEngine = createScriptEngine(this, &rc); - setDebuggerType(GdbDebugger); + setDebuggerType(NoDebugger); if (Debugger::Constants::Internal::debug) qDebug() << Q_FUNC_INFO << gdbEngine << winEngine << scriptEngine << rc.size(); return rc; @@ -445,6 +448,8 @@ void DebuggerManager::setDebuggerType(DebuggerType type) case WinDebugger: m_engine = winEngine; break; + case NoDebugger: + m_engine = 0; } } @@ -697,7 +702,6 @@ void DebuggerManager::toggleBreakpoint(const QString &fileName, int lineNumber) if (Debugger::Constants::Internal::debug) qDebug() << Q_FUNC_INFO << fileName << lineNumber; - QTC_ASSERT(m_engine, return); QTC_ASSERT(m_breakHandler, return); if (status() != DebuggerInferiorRunning && status() != DebuggerInferiorStopped @@ -712,7 +716,8 @@ void DebuggerManager::toggleBreakpoint(const QString &fileName, int lineNumber) m_breakHandler->setBreakpoint(fileName, lineNumber); else m_breakHandler->removeBreakpoint(index); - m_engine->attemptBreakpointSynchronization(); + + attemptBreakpointSynchronization(); } void DebuggerManager::toggleBreakpointEnabled(const QString &fileName, int lineNumber) @@ -720,7 +725,6 @@ void DebuggerManager::toggleBreakpointEnabled(const QString &fileName, int lineN if (Debugger::Constants::Internal::debug) qDebug() << Q_FUNC_INFO << fileName << lineNumber; - QTC_ASSERT(m_engine, return); QTC_ASSERT(m_breakHandler, return); if (status() != DebuggerInferiorRunning && status() != DebuggerInferiorStopped @@ -731,24 +735,26 @@ void DebuggerManager::toggleBreakpointEnabled(const QString &fileName, int lineN } m_breakHandler->toggleBreakpointEnabled(fileName, lineNumber); - m_engine->attemptBreakpointSynchronization(); + + attemptBreakpointSynchronization(); } void DebuggerManager::attemptBreakpointSynchronization() { - m_engine->attemptBreakpointSynchronization(); + if (m_engine) + m_engine->attemptBreakpointSynchronization(); } void DebuggerManager::setToolTipExpression(const QPoint &pos, const QString &exp) { - QTC_ASSERT(m_engine, return); - m_engine->setToolTipExpression(pos, exp); + if (m_engine) + m_engine->setToolTipExpression(pos, exp); } void DebuggerManager::updateWatchModel() { - QTC_ASSERT(m_engine, return); - m_engine->updateWatchModel(); + if (m_engine) + m_engine->updateWatchModel(); } QVariant DebuggerManager::sessionValue(const QString &name) @@ -946,9 +952,9 @@ void DebuggerManager::startNewDebugger(DebuggerRunControl *runControl) DebuggerType type; QString errorMessage; - const bool hasDebugger = startMode() == AttachExternal ? - determineDebuggerType(m_attachedPID, &type, &errorMessage) : - determineDebuggerType(m_executable, &type, &errorMessage); + const bool hasDebugger = startMode() == AttachExternal + ? determineDebuggerType(m_attachedPID, &type, &errorMessage) + : determineDebuggerType(m_executable, &type, &errorMessage); if (!hasDebugger) { QMessageBox::warning(mainWindow(), tr("Warning"), tr("Cannot debug '%1': %2").arg(m_executable, errorMessage)); @@ -1117,18 +1123,14 @@ void DebuggerManager::aboutToSaveSession() void DebuggerManager::loadSessionData() { - QTC_ASSERT(m_engine, return); m_breakHandler->loadSessionData(); m_watchHandler->loadSessionData(); - m_engine->loadSessionData(); } void DebuggerManager::saveSessionData() { - QTC_ASSERT(m_engine, return); m_breakHandler->saveSessionData(); m_watchHandler->saveSessionData(); - m_engine->saveSessionData(); } void DebuggerManager::dumpLog() @@ -1164,17 +1166,15 @@ void DebuggerManager::setBreakpoint(const QString &fileName, int lineNumber) qDebug() << Q_FUNC_INFO << fileName << lineNumber; QTC_ASSERT(m_breakHandler, return); - QTC_ASSERT(m_engine, return); m_breakHandler->setBreakpoint(fileName, lineNumber); - m_engine->attemptBreakpointSynchronization(); + attemptBreakpointSynchronization(); } void DebuggerManager::breakByFunction(const QString &functionName) { QTC_ASSERT(m_breakHandler, return); - QTC_ASSERT(m_engine, return); m_breakHandler->breakByFunction(functionName); - m_engine->attemptBreakpointSynchronization(); + attemptBreakpointSynchronization(); } void DebuggerManager::breakByFunction() @@ -1300,14 +1300,16 @@ void DebuggerManager::queryCurrentTextEditor(QString *fileName, int *lineNumber, void DebuggerManager::continueExec() { - m_engine->continueInferior(); + if (m_engine) + m_engine->continueInferior(); } void DebuggerManager::interruptDebuggingRequest() { if (Debugger::Constants::Internal::debug) qDebug() << Q_FUNC_INFO << status(); - QTC_ASSERT(m_engine, return); + if (!m_engine) + return; bool interruptIsExit = (status() != DebuggerInferiorRunning); if (interruptIsExit) exitDebugger(); @@ -1319,11 +1321,10 @@ void DebuggerManager::interruptDebuggingRequest() void DebuggerManager::runToLineExec() { - QTC_ASSERT(m_engine, return); QString fileName; int lineNumber = -1; emit currentTextEditorRequested(&fileName, &lineNumber, 0); - if (!fileName.isEmpty()) { + if (m_engine && !fileName.isEmpty()) { if (Debugger::Constants::Internal::debug) qDebug() << Q_FUNC_INFO << fileName << lineNumber; m_engine->runToLineExec(fileName, lineNumber); @@ -1360,7 +1361,7 @@ void DebuggerManager::runToFunctionExec() if (Debugger::Constants::Internal::debug) qDebug() << Q_FUNC_INFO << functionName; - if (!functionName.isEmpty()) + if (m_engine && !functionName.isEmpty()) m_engine->runToFunctionExec(functionName); } @@ -1369,7 +1370,7 @@ void DebuggerManager::jumpToLineExec() QString fileName; int lineNumber = -1; emit currentTextEditorRequested(&fileName, &lineNumber, 0); - if (!fileName.isEmpty()) { + if (m_engine && !fileName.isEmpty()) { if (Debugger::Constants::Internal::debug) qDebug() << Q_FUNC_INFO << fileName << lineNumber; m_engine->jumpToLineExec(fileName, lineNumber); @@ -1404,10 +1405,8 @@ void DebuggerManager::fileOpen(const QString &fileName) void DebuggerManager::reloadDisassembler() { - QTC_ASSERT(m_engine, return); - if (!m_disassemblerDock || !m_disassemblerDock->isVisible()) - return; - m_engine->reloadDisassembler(); + if (m_engine && m_disassemblerDock && m_disassemblerDock->isVisible()) + m_engine->reloadDisassembler(); } void DebuggerManager::disassemblerDockToggled(bool on) @@ -1425,9 +1424,8 @@ void DebuggerManager::disassemblerDockToggled(bool on) void DebuggerManager::reloadSourceFiles() { - if (!m_sourceFilesDock || !m_sourceFilesDock->isVisible()) - return; - m_engine->reloadSourceFiles(); + if (m_engine && m_sourceFilesDock && m_sourceFilesDock->isVisible()) + m_engine->reloadSourceFiles(); } void DebuggerManager::sourceFilesDockToggled(bool on) @@ -1445,9 +1443,8 @@ void DebuggerManager::sourceFilesDockToggled(bool on) void DebuggerManager::reloadModules() { - if (!m_modulesDock || !m_modulesDock->isVisible()) - return; - m_engine->reloadModules(); + if (m_engine && m_modulesDock && m_modulesDock->isVisible()) + m_engine->reloadModules(); } void DebuggerManager::modulesDockToggled(bool on) @@ -1490,9 +1487,8 @@ void DebuggerManager::registerDockToggled(bool on) void DebuggerManager::reloadRegisters() { - if (!m_registerDock || !m_registerDock->isVisible()) - return; - m_engine->reloadRegisters(); + if (m_engine && m_registerDock && m_registerDock->isVisible()) + m_engine->reloadRegisters(); } ////////////////////////////////////////////////////////////////////// @@ -1546,6 +1542,12 @@ DebuggerStartMode DebuggerManager::startMode() const return m_runControl->startMode(); } +void DebuggerManager::reloadFullStack() +{ + if (m_engine) + m_engine->reloadFullStack(); +} + ////////////////////////////////////////////////////////////////////// // diff --git a/src/plugins/debugger/debuggermanager.h b/src/plugins/debugger/debuggermanager.h index ad92a003f3b839e3d184d33a40d09b721dd91064..38a0c5d7b748bd4c0af3bd41f56a1a18601afe34 100644 --- a/src/plugins/debugger/debuggermanager.h +++ b/src/plugins/debugger/debuggermanager.h @@ -202,7 +202,7 @@ public: QMainWindow *mainWindow() const { return m_mainWindow; } QLabel *statusLabel() const { return m_statusLabel; } - enum DebuggerType { GdbDebugger, ScriptDebugger, WinDebugger }; + enum DebuggerType { NoDebugger, GdbDebugger, ScriptDebugger, WinDebugger }; public slots: void startNewDebugger(DebuggerRunControl *runControl); @@ -279,6 +279,7 @@ private slots: void setStatus(int status); void clearStatusMessage(); void attemptBreakpointSynchronization(); + void reloadFullStack(); private: // diff --git a/src/plugins/debugger/debuggerplugin.cpp b/src/plugins/debugger/debuggerplugin.cpp index cbb8a160cabc400a272a5f0d2716a72345ceac30..01d882dba00858c8e23348fbd08d169984871c40 100644 --- a/src/plugins/debugger/debuggerplugin.cpp +++ b/src/plugins/debugger/debuggerplugin.cpp @@ -368,6 +368,7 @@ QWidget *DebuggingHelperOptionPage::createPage(QWidget *parent) mdebug->addAction(cmd); #endif #endif + updateState(); return w; } @@ -376,9 +377,10 @@ void DebuggingHelperOptionPage::updateState() { m_ui.checkBoxUseCustomDebuggingHelperLocation->setEnabled( m_ui.checkBoxUseDebuggingHelpers->isChecked()); - m_ui.dumperLocationChooser->setEnabled( - m_ui.checkBoxUseDebuggingHelpers->isChecked() - && m_ui.checkBoxUseCustomDebuggingHelperLocation->isChecked()); + bool locationEnabled = m_ui.checkBoxUseDebuggingHelpers->isChecked() + && m_ui.checkBoxUseCustomDebuggingHelperLocation->isChecked(); + m_ui.dumperLocationChooser->setEnabled(locationEnabled); + m_ui.dumperLocationLabel->setEnabled(locationEnabled); } } // namespace Internal diff --git a/src/plugins/debugger/dumperoptionpage.ui b/src/plugins/debugger/dumperoptionpage.ui index dc11cfac9d809f7e5861c52ed8bde0762357134c..0ff6ddc6c2d3c23e8339775ec504dfb26811533d 100644 --- a/src/plugins/debugger/dumperoptionpage.ui +++ b/src/plugins/debugger/dumperoptionpage.ui @@ -73,7 +73,7 @@ </spacer> </item> <item> - <widget class="QLabel" name="labelDebuggingHelperLocation"> + <widget class="QLabel" name="dumperLocationLabel"> <property name="text"> <string>Location: </string> </property> diff --git a/src/plugins/debugger/gdbengine.cpp b/src/plugins/debugger/gdbengine.cpp index 653a6817b62afeb6e8c7f00cdbfd0aaff141efdc..454a71df9ef7e491e83934452be181208534c12a 100644 --- a/src/plugins/debugger/gdbengine.cpp +++ b/src/plugins/debugger/gdbengine.cpp @@ -158,17 +158,13 @@ void GdbEngine::initializeConnections() q, SLOT(showApplicationOutput(QString)), Qt::QueuedConnection); + // FIXME: These trigger even if the engine is not active connect(theDebuggerAction(UseDebuggingHelpers), SIGNAL(valueChanged(QVariant)), this, SLOT(setUseDebuggingHelpers(QVariant))); connect(theDebuggerAction(DebugDebuggingHelpers), SIGNAL(valueChanged(QVariant)), this, SLOT(setDebugDebuggingHelpers(QVariant))); connect(theDebuggerAction(RecheckDebuggingHelpers), SIGNAL(triggered()), this, SLOT(recheckDebuggingHelperAvailability())); - - connect(theDebuggerAction(ExpandStack), SIGNAL(triggered()), - this, SLOT(reloadFullStack())); - connect(theDebuggerAction(MaximalStackDepth), SIGNAL(triggered()), - this, SLOT(reloadFullStack())); } void GdbEngine::initializeVariables() @@ -532,12 +528,18 @@ void GdbEngine::readGdbStandardOutput() void GdbEngine::interruptInferior() { qq->notifyInferiorStopRequested(); + if (m_gdbProc.state() == QProcess::NotRunning) { debugMessage(_("TRYING TO INTERRUPT INFERIOR WITHOUT RUNNING GDB")); qq->notifyInferiorExited(); return; } + if (q->startMode() == AttachRemote) { + execCommand(_("-exec-interrupt")); + return; + } + if (q->m_attachedPID <= 0) { debugMessage(_("TRYING TO INTERRUPT INFERIOR BEFORE PID WAS OBTAINED")); return; @@ -1021,8 +1023,6 @@ void GdbEngine::handleAsyncOutput(const GdbMi &data) return; } - //tryLoadDebuggingHelpers(); - // jump over well-known frames static int stepCounter = 0; if (theDebuggerBoolSetting(SkipKnownFrames)) { @@ -1420,6 +1420,7 @@ bool GdbEngine::startDebugger() //execCommand(_("set print pretty on")); //execCommand(_("set confirm off")); //execCommand(_("set pagination off")); + execCommand(_("set print inferior-events 1")); execCommand(_("set breakpoint pending on")); execCommand(_("set print elements 10000")); execCommand(_("-data-list-register-names"), CB(handleRegisterListNames)); @@ -1602,8 +1603,10 @@ void GdbEngine::handleTargetAsync(const GdbResultRecord &record, const QVariant if (record.resultClass == GdbResultDone) { //execCommand(_("info target"), handleStart); qq->notifyInferiorRunningRequested(); - execCommand(_("target remote %1").arg(q->m_remoteChannel)); - execCommand(_("-exec-continue"), CB(handleExecRun)); + execCommand(_("target remote %1").arg(q->m_remoteChannel), + CB(handleAttach)); + //execCommand(_("-exec-continue"), CB(handleExecRun)); + handleAqcuiredInferior(); } else if (record.resultClass == GdbResultError) { // a typical response on "old" gdb is: // &"set target-async on\n" @@ -1824,9 +1827,9 @@ void GdbEngine::sendInsertBreakpoint(int index) //if (where.isEmpty()) // where = data->fileName; #endif - // we need something like "\"file name.cpp\":100" to - // survive the gdb command line parser with file names intact - where = _("\"\\\"") + where + _("\\\":") + data->lineNumber + _c('"'); + // The argument is simply a C-quoted version of the argument to the + // non-MI "break" command, including the "original" quoting it wants. + where = _("\"\\\"") + GdbMi::escapeCString(where) + _("\\\":") + data->lineNumber + _c('"'); } else { where = data->funcName; } @@ -1987,6 +1990,8 @@ void GdbEngine::handleBreakInsert(const GdbResultRecord &record, const QVariant handler->updateMarkers(); } else if (record.resultClass == GdbResultError) { 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. #ifdef Q_OS_LINUX //QString where = "\"\\\"" + data->fileName + "\\\":" // + data->lineNumber + "\""; @@ -3098,8 +3103,7 @@ void GdbEngine::handleQueryDebuggingHelper(const GdbResultRecord &record, const QByteArray out = output.data(); out = out.mid(out.indexOf('"') + 2); // + 1 is success marker out = out.left(out.lastIndexOf('"')); - //out.replace('\'', '"'); - out.replace("\\", ""); + out.replace('\\', ""); // optimization: dumper output never needs real C unquoting out = "dummy={" + out + "}"; //qDebug() << "OUTPUT: " << out; @@ -3302,7 +3306,7 @@ void GdbEngine::handleDebuggingHelperValue2(const GdbResultRecord &record, QByteArray out = output.data(); int markerPos = out.indexOf('"') + 1; // position of 'success marker' - if (markerPos == -1 || out.at(markerPos) == 'f') { // 't' or 'f' + if (markerPos == 0 || out.at(markerPos) == 'f') { // 't' or 'f' // custom dumper produced no output data.setError(strNotInScope); insertData(data); @@ -3311,7 +3315,7 @@ void GdbEngine::handleDebuggingHelperValue2(const GdbResultRecord &record, out = out.mid(markerPos + 1); out = out.left(out.lastIndexOf('"')); - out.replace("\\", ""); + out.replace('\\', ""); // optimization: dumper output never needs real C unquoting out = "dummy={" + out + "}"; GdbMi contents; @@ -3848,13 +3852,13 @@ void GdbEngine::tryLoadDebuggingHelpers() execCommand(_("sharedlibrary .*")); // for LoadLibraryA //execCommand(_("handle SIGSEGV pass stop print")); //execCommand(_("set unwindonsignal off")); - execCommand(_("call LoadLibraryA(\"") + lib + _("\")"), + execCommand(_("call LoadLibraryA(\"") + GdbMi::escapeCString(lib) + _("\")"), CB(handleDebuggingHelperSetup)); execCommand(_("sharedlibrary ") + dotEscape(lib)); #elif defined(Q_OS_MAC) //execCommand(_("sharedlibrary libc")); // for malloc //execCommand(_("sharedlibrary libdl")); // for dlopen - execCommand(_("call (void)dlopen(\"") + lib + _("\", " STRINGIFY(RTLD_NOW) ")"), + execCommand(_("call (void)dlopen(\"") + GdbMi::escapeCString(lib) + _("\", " STRINGIFY(RTLD_NOW) ")"), CB(handleDebuggingHelperSetup)); //execCommand(_("sharedlibrary ") + dotEscape(lib)); m_debuggingHelperState = DebuggingHelperLoadTried; @@ -3863,10 +3867,10 @@ void GdbEngine::tryLoadDebuggingHelpers() QString flag = QString::number(RTLD_NOW); execCommand(_("sharedlibrary libc")); // for malloc execCommand(_("sharedlibrary libdl")); // for dlopen - execCommand(_("call (void*)dlopen(\"") + lib + _("\", " STRINGIFY(RTLD_NOW) ")"), + execCommand(_("call (void*)dlopen(\"") + GdbMi::escapeCString(lib) + _("\", " STRINGIFY(RTLD_NOW) ")"), CB(handleDebuggingHelperSetup)); // some older systems like CentOS 4.6 prefer this: - execCommand(_("call (void*)__dlopen(\"") + lib + _("\", " STRINGIFY(RTLD_NOW) ")"), + execCommand(_("call (void*)__dlopen(\"") + GdbMi::escapeCString(lib) + _("\", " STRINGIFY(RTLD_NOW) ")"), CB(handleDebuggingHelperSetup)); execCommand(_("sharedlibrary ") + dotEscape(lib)); #endif diff --git a/src/plugins/debugger/gdbengine.h b/src/plugins/debugger/gdbengine.h index c053bc1c0acf364cfa799fdafbf75aa60a9a6b97..87523ae703be962b98e735ab83085a2a818653f4 100644 --- a/src/plugins/debugger/gdbengine.h +++ b/src/plugins/debugger/gdbengine.h @@ -112,9 +112,6 @@ private: Q_SLOT void attemptBreakpointSynchronization(); - void loadSessionData() {} - void saveSessionData() {} - void assignValueInDebugger(const QString &expr, const QString &value); void executeDebuggerCommand(const QString & command); diff --git a/src/plugins/debugger/gdbmi.cpp b/src/plugins/debugger/gdbmi.cpp index 4cbd53ab1fed4bd2e6476d5bba5151314ad8af8a..e2fd7e7a25a67ec2e7ca9a0873daff134bd7363b 100644 --- a/src/plugins/debugger/gdbmi.cpp +++ b/src/plugins/debugger/gdbmi.cpp @@ -34,6 +34,8 @@ #include <QtCore/QByteArray> #include <QtCore/QTextStream> +#include <ctype.h> + namespace Debugger { namespace Internal { @@ -44,7 +46,7 @@ QTextStream &operator<<(QTextStream &os, const GdbMi &mi) void GdbMi::parseResultOrValue(const char *&from, const char *to) { - while (from != to && QChar(*from).isSpace()) + while (from != to && isspace(*from)) ++from; //qDebug() << "parseResultOrValue: " << QByteArray(from, to - from); @@ -74,6 +76,7 @@ QByteArray GdbMi::parseCString(const char *&from, const char *to) //qDebug() << "parseCString: " << QByteArray::fromUtf16(from, to - from); if (*from != '"') { qDebug() << "MI Parse Error, double quote expected"; + ++from; // So we don't hang return QByteArray(); } const char *ptr = from; @@ -84,22 +87,66 @@ QByteArray GdbMi::parseCString(const char *&from, const char *to) result = QByteArray(from + 1, ptr - from - 2); break; } - if (*ptr == '\\' && ptr < to - 1) + if (*ptr == '\\') { ++ptr; + if (ptr == to) { + qDebug() << "MI Parse Error, unterminated backslash escape"; + from = ptr; // So we don't hang + return QByteArray(); + } + } ++ptr; } + from = ptr; - if (result.contains('\\')) { - if (result.contains("\\032\\032")) - result.clear(); - else { - result = result.replace("\\n", "\n"); - result = result.replace("\\t", "\t"); - result = result.replace("\\\"", "\""); - } + int idx = result.indexOf('\\'); + if (idx >= 0) { + char *dst = result.data() + idx; + const char *src = dst + 1, *end = result.data() + result.length(); + do { + char c = *src++; + switch (c) { + case 'a': *dst++ = '\a'; break; + case 'b': *dst++ = '\b'; break; + case 'f': *dst++ = '\f'; break; + case 'n': *dst++ = '\n'; break; + case 'r': *dst++ = '\r'; break; + case 't': *dst++ = '\t'; break; + case 'v': *dst++ = '\v'; break; + case '"': *dst++ = '"'; break; + case '\\': *dst++ = '\\'; break; + default: + { + int chars = 0; + uchar prod = 0; + forever { + if (c < '0' || c > '7') { + --src; + break; + } + prod = prod * 8 + c - '0'; + if (++chars == 3 || src == end) + break; + c = *src++; + } + if (!chars) { + qDebug() << "MI Parse Error, unrecognized backslash escape"; + return QByteArray(); + } + *dst++ = prod; + } + } + while (src != end) { + char c = *src++; + if (c == '\\') + break; + *dst++ = c; + } + } while (src != end); + *dst = 0; + result.truncate(dst - result.data()); } - from = ptr; return result; } @@ -203,10 +250,50 @@ void GdbMi::dumpChildren(QByteArray * str, bool multiline, int indent) const } } -static QByteArray escaped(QByteArray ba) +class MyString : public QString { +public: + ushort at(int i) const { return constData()[i].unicode(); } +}; + +template<class ST, typename CT> +inline ST escapeCStringTpl(const ST &ba) +{ + ST ret; + ret.reserve(ba.length() * 2); + for (int i = 0; i < ba.length(); ++i) { + CT c = ba.at(i); + switch (c) { + case '\\': ret += "\\\\"; break; + case '\a': ret += "\\a"; break; + case '\b': ret += "\\b"; break; + case '\f': ret += "\\f"; break; + case '\n': ret += "\\n"; break; + case '\r': ret += "\\r"; break; + case '\t': ret += "\\t"; break; + case '\v': ret += "\\v"; break; + case '"': ret += "\\\""; break; + default: + if (c < 32 || c == 127) { + ret += '\\'; + ret += '0' + (c >> 6); + ret += '0' + ((c >> 3) & 7); + ret += '0' + (c & 7); + } else { + ret += c; + } + } + } + return ret; +} + +QString GdbMi::escapeCString(const QString &ba) +{ + return escapeCStringTpl<MyString, ushort>(static_cast<const MyString &>(ba)); +} + +QByteArray GdbMi::escapeCString(const QByteArray &ba) { - ba.replace("\"", "\\\""); - return ba; + return escapeCStringTpl<QByteArray, uchar>(ba); } QByteArray GdbMi::toString(bool multiline, int indent) const @@ -222,7 +309,7 @@ QByteArray GdbMi::toString(bool multiline, int indent) const case Const: if (!m_name.isEmpty()) result += m_name + "="; - result += "\"" + escaped(m_data) + "\""; + result += "\"" + escapeCString(m_data) + "\""; break; case Tuple: if (!m_name.isEmpty()) diff --git a/src/plugins/debugger/gdbmi.h b/src/plugins/debugger/gdbmi.h index 311bef2a7ce3559dd24511341c0287da2d07d0c5..1e9731bb30362f2f46a786539a16c292922be16a 100644 --- a/src/plugins/debugger/gdbmi.h +++ b/src/plugins/debugger/gdbmi.h @@ -132,6 +132,8 @@ private: friend class GdbEngine; static QByteArray parseCString(const char *&from, const char *to); + static QByteArray escapeCString(const QByteArray &ba); + static QString escapeCString(const QString &ba); void parseResultOrValue(const char *&from, const char *to); void parseValue(const char *&from, const char *to); void parseTuple(const char *&from, const char *to); diff --git a/src/plugins/debugger/idebuggerengine.h b/src/plugins/debugger/idebuggerengine.h index 0d3863a34e71eec3a2bf1b01bcbfaa292e56cdaa..ececbe9aa7a74c65a91481c072677f878998b0e9 100644 --- a/src/plugins/debugger/idebuggerengine.h +++ b/src/plugins/debugger/idebuggerengine.h @@ -74,9 +74,6 @@ public: virtual void attemptBreakpointSynchronization() = 0; - virtual void loadSessionData() = 0; - virtual void saveSessionData() = 0; - virtual void reloadDisassembler() = 0; virtual void reloadModules() = 0; @@ -87,6 +84,7 @@ public: virtual void reloadRegisters() = 0; virtual void reloadSourceFiles() = 0; + virtual void reloadFullStack() = 0; }; } // namespace Internal diff --git a/src/plugins/debugger/scriptengine.h b/src/plugins/debugger/scriptengine.h index ee5612d09d84d3c59bf04f1849f36da2008d26c1..1e116b390150ff2cd180c816333ed65b908676fe 100644 --- a/src/plugins/debugger/scriptengine.h +++ b/src/plugins/debugger/scriptengine.h @@ -94,9 +94,6 @@ private: void attemptBreakpointSynchronization(); - void loadSessionData() {} - void saveSessionData() {} - void assignValueInDebugger(const QString &expr, const QString &value); void executeDebuggerCommand(const QString & command); @@ -107,6 +104,7 @@ private: void reloadModules(); void reloadRegisters() {} void reloadSourceFiles() {} + void reloadFullStack() {} bool supportsThreads() const { return true; } void maybeBreakNow(bool byFunction); diff --git a/src/plugins/debugger/watchutils.cpp b/src/plugins/debugger/watchutils.cpp index 5693c2c2159adfa034117f184ca3df28b498b724..812442a323896035a84c03c235772bf6143e3680 100644 --- a/src/plugins/debugger/watchutils.cpp +++ b/src/plugins/debugger/watchutils.cpp @@ -136,6 +136,7 @@ bool hasSideEffects(const QString &exp) return exp.contains(QLatin1String("-=")) || exp.contains(QLatin1String("+=")) || exp.contains(QLatin1String("/=")) + || exp.contains(QLatin1String("%=")) || exp.contains(QLatin1String("*=")) || exp.contains(QLatin1String("&=")) || exp.contains(QLatin1String("|=")) @@ -454,7 +455,7 @@ QDebug operator<<(QDebug in, const QtDumperResult &d) const QtDumperResult::Child &c = d.children.at(i); nospace << " #" << i << " addr=" << c.address << " disabled=" << c.valuedisabled - << " type=" << c.type + << " type=" << c.type << " exp=" << c.exp << " name=" << c.name << " encoded=" << c.valueEncoded << " value=" << c.value << "childcount=" << c.childCount << '\n'; @@ -1376,6 +1377,8 @@ bool QtDumperHelper::parseValue(const char *data, QtDumperResult *r) // Sanity if (r->childCount < r->children.size()) r->childCount = r->children.size(); + if (debug) + qDebug() << '\n' << data << *r; return true; } diff --git a/src/plugins/projectexplorer/project.cpp b/src/plugins/projectexplorer/project.cpp index 459f8114acffba566e841da0c17031f4564e3da7..cc18fbcfd36de3f58c00201c93215be52468f840 100644 --- a/src/plugins/projectexplorer/project.cpp +++ b/src/plugins/projectexplorer/project.cpp @@ -506,17 +506,17 @@ void Project::setDisplayNameFor(const QString &buildConfiguration, const QString emit buildConfigurationDisplayNameChanged(buildConfiguration); } -QByteArray Project::predefinedMacros(const QString &fileName) const +QByteArray Project::predefinedMacros(const QString &) const { return QByteArray(); } -QStringList Project::includePaths(const QString &fileName) const +QStringList Project::includePaths(const QString &) const { return QStringList(); } -QStringList Project::frameworkPaths(const QString &fileName) const +QStringList Project::frameworkPaths(const QString &) const { return QStringList(); } diff --git a/src/plugins/projectexplorer/projectexplorer.cpp b/src/plugins/projectexplorer/projectexplorer.cpp index ebb6a1000a790436ff1fef914b95340d099547d6..eae61dd93b120be2310b7d8377ae0459822a5834 100644 --- a/src/plugins/projectexplorer/projectexplorer.cpp +++ b/src/plugins/projectexplorer/projectexplorer.cpp @@ -56,6 +56,7 @@ #include "session.h" #include "sessiondialog.h" #include "buildparserfactory.h" +#include "projectexplorersettingspage.h" #include <coreplugin/basemode.h> #include <coreplugin/coreconstants.h> @@ -233,6 +234,9 @@ bool ProjectExplorerPlugin::initialize(const QStringList &arguments, QString *er addAutoReleasedObject(new GccParserFactory); addAutoReleasedObject(new MsvcParserFactory); + // Settings page + addAutoReleasedObject(new ProjectExplorerSettingsPage); + // context menus Core::ActionContainer *msessionContextMenu = am->createMenu(Constants::M_SESSIONCONTEXT); @@ -619,7 +623,6 @@ bool ProjectExplorerPlugin::initialize(const QStringList &arguments, QString *er } // < -- Creator 1.0 compatibility code - // TODO restore recentProjects if (QSettings *s = core->settings()) { const QStringList fileNames = s->value("ProjectExplorer/RecentProjects/FileNames").toStringList(); const QStringList displayNames = s->value("ProjectExplorer/RecentProjects/DisplayNames").toStringList(); @@ -631,7 +634,10 @@ bool ProjectExplorerPlugin::initialize(const QStringList &arguments, QString *er } } - + if (QSettings *s = core->settings()) { + m_projectExplorerSettings.buildBeforeRun = s->value("ProjectExplorer/Settings/BuildBeforeRun", true).toBool(); + m_projectExplorerSettings.saveBeforeBuild = s->value("ProjectExplorer/Settings/SaveBeforeBuild", false).toBool(); + } connect(m_sessionManagerAction, SIGNAL(triggered()), this, SLOT(showSessionManager())); connect(m_newAction, SIGNAL(triggered()), this, SLOT(newProject())); @@ -856,6 +862,9 @@ void ProjectExplorerPlugin::savePersistentSettings() s->setValue("ProjectExplorer/RecentProjects/FileNames", fileNames); s->setValue("ProjectExplorer/RecentProjects/DisplayNames", displayNames); + + s->setValue("ProjectExplorer/Settings/BuildBeforeRun", m_projectExplorerSettings.buildBeforeRun); + s->setValue("ProjectExplorer/Settings/SaveBeforeBuild", m_projectExplorerSettings.saveBeforeBuild); } } @@ -1110,6 +1119,36 @@ void ProjectExplorerPlugin::buildStateChanged(Project * pro) updateActions(); } +void ProjectExplorerPlugin::executeRunConfiguration(QSharedPointer<RunConfiguration> runConfiguration, const QString &runMode) +{ + IRunConfigurationRunner *runner = findRunner(runConfiguration, runMode); + if (runner) { + emit aboutToExecuteProject(runConfiguration->project()); + + RunControl *control = runner->run(runConfiguration, runMode); + m_outputPane->createNewOutputWindow(control); + if (runMode == ProjectExplorer::Constants::RUNMODE) + m_outputPane->popup(false); + m_outputPane->showTabFor(control); + + connect(control, SIGNAL(addToOutputWindow(RunControl *, const QString &)), + this, SLOT(addToApplicationOutputWindow(RunControl *, const QString &))); + connect(control, SIGNAL(addToOutputWindowInline(RunControl *, const QString &)), + this, SLOT(addToApplicationOutputWindowInline(RunControl *, const QString &))); + connect(control, SIGNAL(error(RunControl *, const QString &)), + this, SLOT(addErrorToApplicationOutputWindow(RunControl *, const QString &))); + connect(control, SIGNAL(finished()), + this, SLOT(runControlFinished())); + + if (runMode == ProjectExplorer::Constants::DEBUGMODE) + m_debuggingRunControl = control; + + control->start(); + updateRunAction(); + } + +} + void ProjectExplorerPlugin::buildQueueFinished(bool success) { if (debug) @@ -1118,38 +1157,13 @@ void ProjectExplorerPlugin::buildQueueFinished(bool success) updateActions(); if (success && m_delayedRunConfiguration) { - IRunConfigurationRunner *runner = findRunner(m_delayedRunConfiguration, m_runMode); - if (runner) { - emit aboutToExecuteProject(m_delayedRunConfiguration->project()); - - RunControl *control = runner->run(m_delayedRunConfiguration, m_runMode); - m_outputPane->createNewOutputWindow(control); - if (m_runMode == ProjectExplorer::Constants::RUNMODE) - m_outputPane->popup(false); - m_outputPane->showTabFor(control); - - connect(control, SIGNAL(addToOutputWindow(RunControl *, const QString &)), - this, SLOT(addToApplicationOutputWindow(RunControl *, const QString &))); - connect(control, SIGNAL(addToOutputWindowInline(RunControl *, const QString &)), - this, SLOT(addToApplicationOutputWindowInline(RunControl *, const QString &))); - connect(control, SIGNAL(error(RunControl *, const QString &)), - this, SLOT(addErrorToApplicationOutputWindow(RunControl *, const QString &))); - connect(control, SIGNAL(finished()), - this, SLOT(runControlFinished())); - - if (m_runMode == ProjectExplorer::Constants::DEBUGMODE) - m_debuggingRunControl = control; - - control->start(); - updateRunAction(); - } + executeRunConfiguration(m_delayedRunConfiguration, m_runMode); + m_delayedRunConfiguration = QSharedPointer<RunConfiguration>(0); + m_runMode = QString::null; } else { if (m_buildManager->tasksAvailable()) m_buildManager->showTaskWindow(); } - - m_delayedRunConfiguration = QSharedPointer<RunConfiguration>(0); - m_runMode = QString::null; } void ProjectExplorerPlugin::updateTaskActions() @@ -1306,10 +1320,18 @@ bool ProjectExplorerPlugin::saveModifiedFiles(const QList<Project *> & projects) } if (!filesToSave.isEmpty()) { - bool cancelled; - Core::ICore::instance()->fileManager()->saveModifiedFiles(filesToSave, &cancelled); - if (cancelled) { - return false; + if (m_projectExplorerSettings.saveBeforeBuild) { + Core::ICore::instance()->fileManager()->saveModifiedFilesSilently(filesToSave); + } else { + bool cancelled = false; + bool alwaysSave = false; + Core::ICore::instance()->fileManager()->saveModifiedFiles(filesToSave, &cancelled, QString::null, "Always save files before build", &alwaysSave); + if (cancelled) { + return false; + } + if (alwaysSave) { + m_projectExplorerSettings.saveBeforeBuild = true; + } } } return true; @@ -1408,12 +1430,16 @@ void ProjectExplorerPlugin::runProjectImpl(Project *pro) if (!pro) return; - if (saveModifiedFiles(QList<Project *>() << pro)) { - m_runMode = ProjectExplorer::Constants::RUNMODE; + if (m_projectExplorerSettings.buildBeforeRun) { + if (saveModifiedFiles(QList<Project *>() << pro)) { + m_runMode = ProjectExplorer::Constants::RUNMODE; + m_delayedRunConfiguration = pro->activeRunConfiguration(); - m_delayedRunConfiguration = pro->activeRunConfiguration(); - //NBS TODO make the build project step take into account project dependencies - m_buildManager->buildProject(pro, pro->activeBuildConfiguration()); + //NBS TODO make the build project step take into account project dependencies + m_buildManager->buildProject(pro, pro->activeBuildConfiguration()); + } + } else { + executeRunConfiguration(pro->activeRunConfiguration(), ProjectExplorer::Constants::RUNMODE); } } @@ -1905,4 +1931,15 @@ void ProjectExplorerPlugin::setSession(QAction *action) m_session->loadSession(session); } + +void ProjectExplorerPlugin::setProjectExplorerSettings(const Internal::ProjectExplorerSettings &pes) +{ + m_projectExplorerSettings = pes; +} + +Internal::ProjectExplorerSettings ProjectExplorerPlugin::projectExplorerSettings() const +{ + return m_projectExplorerSettings; +} + Q_EXPORT_PLUGIN(ProjectExplorerPlugin) diff --git a/src/plugins/projectexplorer/projectexplorer.h b/src/plugins/projectexplorer/projectexplorer.h index 987cb323fb69019c81080ca26ac68bbaf8cc8643..6beca9504f98bd21ed0ada55a9d48963c577991a 100644 --- a/src/plugins/projectexplorer/projectexplorer.h +++ b/src/plugins/projectexplorer/projectexplorer.h @@ -71,6 +71,12 @@ class OutputPane; class ProjectWindow; class ProjectFileFactory; +struct ProjectExplorerSettings +{ + bool buildBeforeRun; + bool saveBeforeBuild; +}; + } // namespace Internal class PROJECTEXPLORER_EXPORT ProjectExplorerPlugin @@ -109,6 +115,9 @@ public: void extensionsInitialized(); void shutdown(); + void setProjectExplorerSettings(const Internal::ProjectExplorerSettings &pes); + Internal::ProjectExplorerSettings projectExplorerSettings() const; + signals: void aboutToShowContextMenu(ProjectExplorer::Project *project, ProjectExplorer::Node *node); @@ -186,6 +195,7 @@ private slots: private: void runProjectImpl(Project *pro); + void executeRunConfiguration(QSharedPointer<RunConfiguration>, const QString &mode); void setCurrent(Project *project, QString filePath, Node *node); QStringList allFilesWithDependencies(Project *pro); @@ -259,6 +269,7 @@ private: RunControl *m_debuggingRunControl; QString m_runMode; QString m_projectFilterString; + Internal::ProjectExplorerSettings m_projectExplorerSettings; }; namespace Internal { diff --git a/src/plugins/projectexplorer/projectexplorer.pro b/src/plugins/projectexplorer/projectexplorer.pro index e6a04cf83d9c551f11a90e19512a8fb8886ffe25..170a54387ea16f8408c1ff67247501469b770e84 100644 --- a/src/plugins/projectexplorer/projectexplorer.pro +++ b/src/plugins/projectexplorer/projectexplorer.pro @@ -59,8 +59,9 @@ HEADERS += projectexplorer.h \ gccparser.h \ msvcparser.h \ filewatcher.h \ - debugginghelper.h\ - abstractmakestep.h + debugginghelper.h \ + abstractmakestep.h \ + projectexplorersettingspage.h SOURCES += projectexplorer.cpp \ projectwindow.cpp \ buildmanager.cpp \ @@ -109,7 +110,8 @@ SOURCES += projectexplorer.cpp \ msvcparser.cpp \ filewatcher.cpp \ debugginghelper.cpp \ - abstractmakestep.cpp + abstractmakestep.cpp \ + projectexplorersettingspage.cpp FORMS += dependenciespanel.ui \ buildsettingspropertiespage.ui \ processstep.ui \ @@ -118,7 +120,8 @@ FORMS += dependenciespanel.ui \ sessiondialog.ui \ projectwizardpage.ui \ buildstepspage.ui \ - removefiledialog.ui + removefiledialog.ui \ + projectexplorersettingspage.ui win32 { SOURCES += applicationlauncher_win.cpp \ winguiprocess.cpp diff --git a/src/plugins/projectexplorer/projectexplorerconstants.h b/src/plugins/projectexplorer/projectexplorerconstants.h index 10c56b8deaa91a3699b5a213a63ba9cbdc707411..351f333a27e5b0dda1b3368c85baa96aa833187e 100644 --- a/src/plugins/projectexplorer/projectexplorerconstants.h +++ b/src/plugins/projectexplorer/projectexplorerconstants.h @@ -176,6 +176,11 @@ const char * const RESOURCE_MIMETYPE = "application/vnd.nokia.xml.qt.resource"; // build parsers const char * const BUILD_PARSER_MSVC = "BuildParser.MSVC"; const char * const BUILD_PARSER_GCC = "BuildParser.Gcc"; + +// settings page +const char * const PROJECTEXPLORER_CATEGORY = "ProjectExplorer"; +const char * const PROJECTEXPLORER_PAGE = "ProjectExplorer.ProjectExplorer"; + } // namespace Constants } // namespace ProjectExplorer diff --git a/src/plugins/projectexplorer/projectexplorersettingspage.cpp b/src/plugins/projectexplorer/projectexplorersettingspage.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f5e87f827ed5a0a54663f10b20018029676747d7 --- /dev/null +++ b/src/plugins/projectexplorer/projectexplorersettingspage.cpp @@ -0,0 +1,89 @@ +/************************************************************************** +** +** 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 "projectexplorersettingspage.h" +#include "projectexplorerconstants.h" +#include "projectexplorer.h" + +#include <QtGui/QLabel> + +using namespace ProjectExplorer; +using namespace ProjectExplorer::Internal; + +ProjectExplorerSettingsPage::ProjectExplorerSettingsPage() +{ + +} +ProjectExplorerSettingsPage::~ProjectExplorerSettingsPage() +{ + +} + +QString ProjectExplorerSettingsPage::id() const +{ + return Constants::PROJECTEXPLORER_PAGE; +} + +QString ProjectExplorerSettingsPage::trName() const +{ + return tr("Build and Run Settings"); +} + +QString ProjectExplorerSettingsPage::category() const +{ + return Constants::PROJECTEXPLORER_PAGE; +} + +QString ProjectExplorerSettingsPage::trCategory() const +{ + return tr("Projectexplorer"); +} + +QWidget *ProjectExplorerSettingsPage::createPage(QWidget *parent) +{ + QWidget *w = new QWidget(parent); + m_ui.setupUi(w); + ProjectExplorerSettings pes = ProjectExplorerPlugin::instance()->projectExplorerSettings(); + m_ui.buildProjectBeforeRunCheckBox->setChecked(pes.buildBeforeRun); + m_ui.saveAllFilesCheckBox->setChecked(pes.saveBeforeBuild); + return w; +} + +void ProjectExplorerSettingsPage::apply() +{ + ProjectExplorerSettings pes; + pes.buildBeforeRun = m_ui.buildProjectBeforeRunCheckBox->isChecked(); + pes.saveBeforeBuild = m_ui.saveAllFilesCheckBox->isChecked(); + ProjectExplorerPlugin::instance()->setProjectExplorerSettings(pes); +} + +void ProjectExplorerSettingsPage::finish() +{ + // Nothing to do +} diff --git a/src/plugins/projectexplorer/projectexplorersettingspage.h b/src/plugins/projectexplorer/projectexplorersettingspage.h new file mode 100644 index 0000000000000000000000000000000000000000..378bfc54c7d06b2d8f1f9753e75c4e18ae1a87ac --- /dev/null +++ b/src/plugins/projectexplorer/projectexplorersettingspage.h @@ -0,0 +1,60 @@ +/************************************************************************** +** +** 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 PROJECTEXPLORERSETTINGSPAGE_H +#define PROJECTEXPLORERSETTINGSPAGE_H + +#include <coreplugin/dialogs/ioptionspage.h> +#include "ui_projectexplorersettingspage.h" + +namespace ProjectExplorer { +namespace Internal { + +class ProjectExplorerSettingsPage : public Core::IOptionsPage +{ +public: + ProjectExplorerSettingsPage(); + ~ProjectExplorerSettingsPage(); + + virtual QString id() const; + virtual QString trName() const; + virtual QString category() const; + virtual QString trCategory() const; + + virtual QWidget *createPage(QWidget *parent); + virtual void apply(); + virtual void finish(); +private: + ProjectExplorer::Internal::Ui::ProjetExplorerSettingsPageUi m_ui; +}; + +} // Internal +} // ProjectExplorer + +#endif // PROJECTEXPLORERSETTINGSPAGE_H diff --git a/src/plugins/projectexplorer/projectexplorersettingspage.ui b/src/plugins/projectexplorer/projectexplorersettingspage.ui new file mode 100644 index 0000000000000000000000000000000000000000..6f48641355e7193409fe81ea106ccbb3fd65a4cc --- /dev/null +++ b/src/plugins/projectexplorer/projectexplorersettingspage.ui @@ -0,0 +1,69 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>ProjectExplorer::Internal::ProjetExplorerSettingsPageUi</class> + <widget class="QWidget" name="ProjectExplorer::Internal::ProjetExplorerSettingsPageUi"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>541</width> + <height>358</height> + </rect> + </property> + <property name="windowTitle"> + <string>Form</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout_3"> + <property name="margin"> + <number>0</number> + </property> + <item> + <widget class="QGroupBox" name="groupBox"> + <property name="title"> + <string>Build Settings</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout"> + <item> + <widget class="QCheckBox" name="saveAllFilesCheckBox"> + <property name="text"> + <string>Save all files before Build</string> + </property> + </widget> + </item> + </layout> + </widget> + </item> + <item> + <widget class="QGroupBox" name="groupBox_2"> + <property name="title"> + <string>Run Settings</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout_2"> + <item> + <widget class="QCheckBox" name="buildProjectBeforeRunCheckBox"> + <property name="text"> + <string>Always build Project before Running</string> + </property> + </widget> + </item> + <item> + <spacer name="verticalSpacer"> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>20</width> + <height>40</height> + </size> + </property> + </spacer> + </item> + </layout> + </widget> + </item> + </layout> + </widget> + <resources/> + <connections/> +</ui> diff --git a/src/plugins/texteditor/basetexteditor.cpp b/src/plugins/texteditor/basetexteditor.cpp index d01cc3f1d6ec67665b92584d41bc13cd759be413..0918c841548413fcf621e84439078b52d0f7db77 100644 --- a/src/plugins/texteditor/basetexteditor.cpp +++ b/src/plugins/texteditor/basetexteditor.cpp @@ -960,7 +960,8 @@ void BaseTextEditor::keyPressEvent(QKeyEvent *e) skip_event: if (!ro && e->key() == Qt::Key_Delete && d->m_parenthesesMatchingEnabled) - slotCursorPositionChanged(); // parentheses matching + d->m_parenthesesMatchingTimer->start(50); + if (!ro && d->m_contentsChanged && !e->text().isEmpty() && e->text().at(0).isPrint()) emit requestAutoCompletion(editableInterface(), false); @@ -3535,9 +3536,18 @@ void BaseTextEditor::_q_matchParentheses() } extraSelections.append(sel); } - setExtraSelections(ParenthesesMatchingSelection, extraSelections); + if (animatePosition >= 0) { + foreach (QTextEdit::ExtraSelection sel, BaseTextEditor::extraSelections(ParenthesesMatchingSelection)) { + if (sel.cursor.selectionStart() == animatePosition + || sel.cursor.selectionEnd() - 1 == animatePosition) { + animatePosition = -1; + break; + } + } + } + if (animatePosition >= 0) { if (d->m_animator) d->m_animator->finish(); // one animation is enough @@ -3549,9 +3559,9 @@ void BaseTextEditor::_q_matchParentheses() d->m_animator->setData(font(), pal, characterAt(d->m_animator->position())); connect(d->m_animator, SIGNAL(updateRequest(int,QRectF)), this, SLOT(_q_animateUpdate(int,QRectF))); - } - + } + setExtraSelections(ParenthesesMatchingSelection, extraSelections); } void BaseTextEditor::_q_highlightBlocks() diff --git a/tests/auto/debugger/main.cpp b/tests/auto/debugger/main.cpp index 4e7eeeeb61fa34ae6daa528a1f968890c98a6869..afb51a38c0118d821ac1f58099995172bd48a021 100644 --- a/tests/auto/debugger/main.cpp +++ b/tests/auto/debugger/main.cpp @@ -52,7 +52,7 @@ static const char test11[] = "{name=\"0\",value=\"one\",type=\"QByteArray\"}]"; static const char test12[] = - "[{iname=\"local.hallo\",value=\"\\\"\\\"\",type=\"QByteArray\"," + "[{iname=\"local.hallo\",value=\"\\\"\\\\\\00382\\t\\377\",type=\"QByteArray\"," "numchild=\"0\"}]"; class tst_Debugger : public QObject