diff --git a/src/libs/cplusplus/MatchingText.cpp b/src/libs/cplusplus/MatchingText.cpp index bbbb06b83112c5f223423f5deb86b690f16fa04b..20aa34f068325864c02684c1c47e31107b30010d 100644 --- a/src/libs/cplusplus/MatchingText.cpp +++ b/src/libs/cplusplus/MatchingText.cpp @@ -104,21 +104,43 @@ QString MatchingText::insertMatchingBrace(const QTextCursor &cursor, const QStri const QChar &la, int *skippedChars) const { QTextCursor tc = cursor; + QTextDocument *doc = tc.document(); QString text = textToProcess; const QString blockText = tc.block().text().mid(tc.columnNumber()); const int length = qMin(blockText.length(), textToProcess.length()); - for (int i = 0; i < length; ++i) { - const QChar ch1 = blockText.at(i); - const QChar ch2 = textToProcess.at(i); + const QChar previousChar = doc->characterAt(tc.selectionEnd() - 1); - if (ch1 != ch2) - break; - else if (! shouldOverrideChar(ch1)) - break; + bool escape = false; + + if (! text.isEmpty() && (text.at(0) == QLatin1Char('"') || + text.at(0) == QLatin1Char('\''))) { + if (previousChar == QLatin1Char('\\')) { + int escapeCount = 0; + int index = tc.selectionEnd() - 1; + do { + ++escapeCount; + --index; + } while (doc->characterAt(index) == QLatin1Char('\\')); - ++*skippedChars; + if ((escapeCount % 2) != 0) + escape = true; + } + } + + if (! escape) { + for (int i = 0; i < length; ++i) { + const QChar ch1 = blockText.at(i); + const QChar ch2 = textToProcess.at(i); + + if (ch1 != ch2) + break; + else if (! shouldOverrideChar(ch1)) + break; + + ++*skippedChars; + } } if (*skippedChars != 0) { @@ -142,6 +164,8 @@ QString MatchingText::insertMatchingBrace(const QTextCursor &cursor, const QStri if (isCompleteStringLiteral(tk, index - 1)) return QLatin1String("\""); + qDebug() << "*** here"; + return QString(); } else if (text.at(0) == QLatin1Char('\'') && (token.is(T_CHAR_LITERAL) || token.is(T_WIDE_CHAR_LITERAL))) { if (text.length() != 1) diff --git a/src/libs/utils/detailswidget.cpp b/src/libs/utils/detailswidget.cpp index 1641d09995fb6baaccc6536d3c70dea36cf05776..00be0f70f263022a8f8c957cf362d7ebcca852d7 100644 --- a/src/libs/utils/detailswidget.cpp +++ b/src/libs/utils/detailswidget.cpp @@ -18,11 +18,19 @@ DetailsWidget::DetailsWidget(QWidget *parent) m_grid(new QGridLayout(this)) { + m_grid->setContentsMargins(4, 3, 4, 3); + m_summaryLabel->setTextInteractionFlags(Qt::TextSelectableByMouse); m_summaryLabel->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); - m_grid->addWidget(m_summaryLabel, 0, 0, 2, 0); - m_grid->addWidget(m_detailsButton, 1, 2); + m_grid->addWidget(m_summaryLabel, 0, 0); + m_grid->addWidget(m_detailsButton, 0, 2, 1, 1, Qt::AlignBottom); + + m_dummyWidget = new QWidget(this); + m_dummyWidget->setMaximumHeight(4); + m_dummyWidget->setMaximumHeight(4); + m_dummyWidget->setVisible(false); + m_grid->addWidget(m_dummyWidget, 2, 0, 1, 1); connect(m_detailsButton, SIGNAL(clicked()), this, SLOT(detailsButtonClicked())); @@ -77,8 +85,10 @@ void DetailsWidget::paintEvent(QPaintEvent *paintEvent) void DetailsWidget::detailsButtonClicked() { + bool visible = m_detailsButton->isToggled(); if (m_widget) - m_widget->setVisible(m_detailsButton->isToggled()); + m_widget->setVisible(visible); + m_dummyWidget->setVisible(visible); fixUpLayout(); } @@ -117,9 +127,11 @@ void DetailsWidget::setWidget(QWidget *widget) m_widget = 0; } if (widget) { - m_grid->addWidget(widget, 2, 0, 1, 3); + m_grid->addWidget(widget, 1, 0, 1, 3); m_widget = widget; - m_widget->setVisible(m_detailsButton->isToggled()); + bool visible = m_detailsButton->isToggled(); + m_widget->setVisible(visible); + m_dummyWidget->setVisible(visible); } } @@ -132,7 +144,7 @@ void DetailsWidget::setToolWidget(QWidget *widget) m_toolWidget = 0; } if (widget) { - m_grid->addWidget(widget, 1, 1); + m_grid->addWidget(widget, 0, 1, 1, 1, Qt::AlignBottom); m_toolWidget = widget; } } diff --git a/src/libs/utils/detailswidget.h b/src/libs/utils/detailswidget.h index eee0444cb991302bed6edb1860a215535b5afb50..781fc4026edc53449126163c2ea79e96bb2903a8 100644 --- a/src/libs/utils/detailswidget.h +++ b/src/libs/utils/detailswidget.h @@ -47,6 +47,7 @@ private: QWidget *m_widget; QWidget *m_toolWidget; + QWidget *m_dummyWidget; QGridLayout *m_grid; }; } diff --git a/src/plugins/debugger/cdb/cdbdebugengine.cpp b/src/plugins/debugger/cdb/cdbdebugengine.cpp index c6e4ca512c4b65d80a65014b11813234f737641c..11f37d15f1928cf6f919f03e4aecfb5dc8f01bf6 100644 --- a/src/plugins/debugger/cdb/cdbdebugengine.cpp +++ b/src/plugins/debugger/cdb/cdbdebugengine.cpp @@ -1701,36 +1701,12 @@ ULONG CdbDebugEnginePrivate::updateThreadList() if (debugCDB) qDebug() << Q_FUNC_INFO << m_hDebuggeeProcess; - ThreadsHandler* th = manager()->threadsHandler(); QList<ThreadData> threads; - bool success = false; + ULONG currentThreadId; QString errorMessage; - ULONG currentThreadId = 0; - do { - ULONG threadCount; - HRESULT hr= m_cif.debugSystemObjects->GetNumberThreads(&threadCount); - if (FAILED(hr)) { - errorMessage= msgComFailed("GetNumberThreads", hr); - break; - } - // Get ids and index of current - if (threadCount) { - m_cif.debugSystemObjects->GetCurrentThreadId(¤tThreadId); - QVector<ULONG> threadIds(threadCount); - hr = m_cif.debugSystemObjects->GetThreadIdsByIndex(0, threadCount, &(*threadIds.begin()), 0); - if (FAILED(hr)) { - errorMessage= msgComFailed("GetThreadIdsByIndex", hr); - break; - } - for (ULONG i = 0; i < threadCount; i++) - threads.push_back(ThreadData(threadIds.at(i))); - } - - th->setThreads(threads); - success = true; - } while (false); - if (!success) - m_engine->warning(msgFunctionFailed(Q_FUNC_INFO, errorMessage)); + if (!CdbStackTraceContext::getThreads(m_cif, true, &threads, ¤tThreadId, &errorMessage)) + m_engine->warning(errorMessage); + manager()->threadsHandler()->setThreads(threads); return currentThreadId; } diff --git a/src/plugins/debugger/cdb/cdbstacktracecontext.cpp b/src/plugins/debugger/cdb/cdbstacktracecontext.cpp index 40cd9776bcb94a3880a19241ab44683d36438d0b..3e5f1c65fcb1d9e2ca1b72172a66749298d64646 100644 --- a/src/plugins/debugger/cdb/cdbstacktracecontext.cpp +++ b/src/plugins/debugger/cdb/cdbstacktracecontext.cpp @@ -219,5 +219,105 @@ void CdbStackTraceContext::format(QTextStream &str) const } } +// Thread state helper + +static inline QString msgGetThreadStateFailed(unsigned long threadId, const QString &why) +{ + return QString::fromLatin1("Unable to determine the state of thread %1: %2").arg(threadId).arg(why); +} + +static inline bool getStoppedThreadState(const CdbComInterfaces &cif, + ThreadData *t, + QString *errorMessage) +{ + ULONG currentThread; + HRESULT hr = cif.debugSystemObjects->GetCurrentThreadId(¤tThread); + if (FAILED(hr)) { + *errorMessage = msgGetThreadStateFailed(t->id, msgComFailed("GetCurrentThreadId", hr)); + return false; + } + if (currentThread != t->id) { + hr = cif.debugSystemObjects->SetCurrentThreadId(t->id); + if (FAILED(hr)) { + *errorMessage = msgGetThreadStateFailed(t->id, msgComFailed("SetCurrentThreadId", hr)); + return false; + } + } + ULONG frameCount; + DEBUG_STACK_FRAME topFrame[1]; + hr = cif.debugControl->GetStackTrace(0, 0, 0, topFrame, 1, &frameCount); + if (FAILED(hr)) { + *errorMessage = msgGetThreadStateFailed(t->id, msgComFailed("GetStackTrace", hr)); + return false; + } + + t->address = topFrame[0].InstructionOffset; + WCHAR wszBuf[MAX_PATH]; + + cif.debugSymbols->GetNameByOffsetWide(topFrame[0].InstructionOffset, wszBuf, MAX_PATH, 0, 0); + t->function = QString::fromUtf16(reinterpret_cast<const ushort *>(wszBuf)); + ULONG ulLine; + hr = cif.debugSymbols->GetLineByOffsetWide(topFrame[0].InstructionOffset, &ulLine, wszBuf, MAX_PATH, 0, 0); + if (SUCCEEDED(hr)) { + t->line = ulLine; + // Just display base name + t->file = QString::fromUtf16(reinterpret_cast<const ushort *>(wszBuf)); + if (!t->file.isEmpty()) { + const int slashPos = t->file.lastIndexOf(QLatin1Char('\\')); + if (slashPos != -1) + t->file.remove(0, slashPos + 1); + } + } + return true; +} + +static inline QString msgGetThreadsFailed(const QString &why) +{ + return QString::fromLatin1("Unable to determine the thread information: %1").arg(why); +} + +bool CdbStackTraceContext::getThreads(const CdbComInterfaces &cif, + bool isStopped, + QList<ThreadData> *threads, + ULONG *currentThreadId, + QString *errorMessage) +{ + threads->clear(); + ULONG threadCount; + *currentThreadId = 0; + HRESULT hr= cif.debugSystemObjects->GetNumberThreads(&threadCount); + if (FAILED(hr)) { + *errorMessage= msgGetThreadsFailed(msgComFailed("GetNumberThreads", hr)); + return false; + } + // Get ids and index of current + if (!threadCount) + return true; + hr = cif.debugSystemObjects->GetCurrentThreadId(currentThreadId); + if (FAILED(hr)) { + *errorMessage= msgGetThreadsFailed(msgComFailed("GetCurrentThreadId", hr)); + return false; + } + + QVector<ULONG> threadIds(threadCount); + hr = cif.debugSystemObjects->GetThreadIdsByIndex(0, threadCount, &(*threadIds.begin()), 0); + if (FAILED(hr)) { + *errorMessage= msgGetThreadsFailed(msgComFailed("GetThreadIdsByIndex", hr)); + return false; + } + for (ULONG i = 0; i < threadCount; i++) { + ThreadData threadData(threadIds.at(i)); + if (isStopped) { + if (!getStoppedThreadState(cif, &threadData, errorMessage)) { + qWarning("%s\n", qPrintable(*errorMessage)); + errorMessage->clear(); + } + } + threads->push_back(threadData); + } + return true; +} + + } // namespace Internal } // namespace Debugger diff --git a/src/plugins/debugger/cdb/cdbstacktracecontext.h b/src/plugins/debugger/cdb/cdbstacktracecontext.h index d0d05bea1e8de609120f7aaab61710e94072ebda..ff8c62d5b19dcfda20f91100474229942e0e09cb 100644 --- a/src/plugins/debugger/cdb/cdbstacktracecontext.h +++ b/src/plugins/debugger/cdb/cdbstacktracecontext.h @@ -49,6 +49,7 @@ struct CdbComInterfaces; class CdbSymbolGroupContext; class CdbStackFrameContext; class CdbDumperHelper; +struct ThreadData; /* Context representing a break point stack consisting of several frames. * Maintains an on-demand constructed list of CdbStackFrameContext @@ -81,6 +82,14 @@ public: void format(QTextStream &str) const; QString toString() const; + // Retrieve information about threads. When stopped, add + // current stack frame. + static bool getThreads(const CdbComInterfaces &cif, + bool isStopped, + QList<ThreadData> *threads, + ULONG *currentThreadId, + QString *errorMessage); + private: bool init(unsigned long frameCount, QString *errorMessage); CIDebugSymbolGroup *createSymbolGroup(int index, QString *errorMessage); diff --git a/src/plugins/debugger/debuggermanager.cpp b/src/plugins/debugger/debuggermanager.cpp index 8394cbbf26f65398d2fe61a607d3f27897771588..a90d143f9dd88a198f0820412ee101a74e47df70 100644 --- a/src/plugins/debugger/debuggermanager.cpp +++ b/src/plugins/debugger/debuggermanager.cpp @@ -1654,6 +1654,8 @@ void DebuggerManager::setState(DebuggerState state) || state == InferiorUnrunnable; const bool running = state == InferiorRunning; + if (running) + threadsHandler()->notifyRunning(); const bool stopped = state == InferiorStopped; if (stopped) diff --git a/src/plugins/debugger/stackhandler.cpp b/src/plugins/debugger/stackhandler.cpp index e3b25b24334f82f8406a828ae8c252c38a655f1d..a12367df9a4c2ad6a3abf194a8fb2330b661c434 100644 --- a/src/plugins/debugger/stackhandler.cpp +++ b/src/plugins/debugger/stackhandler.cpp @@ -238,11 +238,28 @@ bool StackHandler::isDebuggingDebuggingHelpers() const // //////////////////////////////////////////////////////////////////////// -ThreadsHandler::ThreadsHandler(QObject *parent) - : QAbstractTableModel(parent), m_currentIndex(0) +ThreadData::ThreadData(int threadId) : + id(threadId), + line(-1) +{ +} + +void ThreadData::notifyRunning() +{ + address = 0; + function.clear(); + file.clear(); + line = -1; +} + +enum { IdColumn, AddressColumn, FunctionColumn, FileColumn, LineColumn, ColumnCount }; + +ThreadsHandler::ThreadsHandler(QObject *parent) : + QAbstractTableModel(parent), + m_currentIndex(0), + m_positionIcon(QLatin1String(":/debugger/images/location.svg")), + m_emptyIcon(QLatin1String(":/debugger/images/empty.svg")) { - m_emptyIcon = QIcon(":/debugger/images/empty.svg"); - m_positionIcon = QIcon(":/debugger/images/location.svg"); } int ThreadsHandler::rowCount(const QModelIndex &parent) const @@ -253,23 +270,39 @@ int ThreadsHandler::rowCount(const QModelIndex &parent) const int ThreadsHandler::columnCount(const QModelIndex &parent) const { - return parent.isValid() ? 0 : 1; + return parent.isValid() ? 0 : int(ColumnCount); } QVariant ThreadsHandler::data(const QModelIndex &index, int role) const { - if (!index.isValid() || index.row() >= m_threads.size()) + if (!index.isValid()) + return QVariant(); + const int row = index.row(); + if (row >= m_threads.size()) return QVariant(); + const ThreadData &thread = m_threads.at(row); if (role == Qt::DisplayRole) { switch (index.column()) { - case 0: // Thread ID - return m_threads.at(index.row()).id; - case 1: // Function name - return "???"; + case IdColumn: + return thread.id; + case FunctionColumn: + return thread.function; + case FileColumn: + return thread.file; + case LineColumn: + return thread.line >= 0 ? QString::number(thread.line) : QString(); + case AddressColumn: + return thread.address > 0 ? QLatin1String("0x") + QString::number(thread.address, 16) : QString(); } } else if (role == Qt::ToolTipRole) { - return tr("Thread: %1").arg(m_threads.at(index.row()).id); + if (thread.address == 0) + return tr("Thread: %1").arg(thread.id); + // Stopped + if (thread.file.isEmpty()) + return tr("Thread: %1 at %2 (0x%3)").arg(thread.id).arg(thread.function).arg(thread.address, 0, 16); + return tr("Thread: %1 at %2, %3:%4 (0x%5)"). + arg(thread.id).arg(thread.function, thread.file).arg(thread.line).arg(thread.address, 0, 16); } else if (role == Qt::DecorationRole && index.column() == 0) { // Return icon that indicates whether this is the active stack frame return (index.row() == m_currentIndex) ? m_positionIcon : m_emptyIcon; @@ -280,9 +313,19 @@ QVariant ThreadsHandler::data(const QModelIndex &index, int role) const QVariant ThreadsHandler::headerData(int section, Qt::Orientation orientation, int role) const { - if (orientation == Qt::Horizontal && role == Qt::DisplayRole) { - if (section < 1) - return tr("Thread ID"); + if (orientation != Qt::Horizontal || role != Qt::DisplayRole) + return QVariant(); + switch (section) { + case IdColumn: + return tr("Thread ID"); + case FunctionColumn: + return tr("Function"); + case FileColumn: + return tr("File"); + case LineColumn: + return tr("Line"); + case AddressColumn: + return tr("Address"); } return QVariant(); } @@ -322,3 +365,16 @@ void ThreadsHandler::removeAll() m_currentIndex = 0; reset(); } + +void ThreadsHandler::notifyRunning() +{ + // Threads stopped (that is, address != 0 showing)? + if (m_threads.empty()) + return; + if (m_threads.front().address == 0) + return; + const QList<ThreadData>::iterator end = m_threads.end(); + for (QList<ThreadData>::iterator it = m_threads.begin(); it != end; ++it) + it->notifyRunning(); + emit dataChanged(index(0, 1), index(m_threads.size()- 1, ColumnCount - 1)); +} diff --git a/src/plugins/debugger/stackhandler.h b/src/plugins/debugger/stackhandler.h index 8b0d7a165c3a4cf095127e8a732778c7a4c5bbd4..0df1d602573d6d2c59e6a5f97a0175c5bf4f1ceb 100644 --- a/src/plugins/debugger/stackhandler.h +++ b/src/plugins/debugger/stackhandler.h @@ -100,8 +100,15 @@ private: struct ThreadData { - ThreadData(int threadId = 0) : id(threadId) {} + ThreadData(int threadId = 0); + void notifyRunning(); // Clear state information + int id; + // State information when stopped + quint64 address; + QString function; + QString file; + int line; }; /*! A model to represent the running threads in a QTreeView or ComboBox */ @@ -119,6 +126,9 @@ public: QList<ThreadData> threads() const; QAbstractItemModel *threadsModel() { return this; } + // Clear out all frame information + void notifyRunning(); + private: int rowCount(const QModelIndex &parent = QModelIndex()) const; int columnCount(const QModelIndex &parent = QModelIndex()) const; @@ -126,11 +136,10 @@ private: QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const; private: - friend class StackHandler; QList<ThreadData> m_threads; int m_currentIndex; - QIcon m_positionIcon; - QIcon m_emptyIcon; + const QIcon m_positionIcon; + const QIcon m_emptyIcon; }; diff --git a/src/plugins/projectexplorer/buildstepspage.cpp b/src/plugins/projectexplorer/buildstepspage.cpp index e909d290ffb3f6690f622143a15bfea71ad8f1b1..ba645c942680a2ed5c20a03ee52670dc2f99b9f9 100644 --- a/src/plugins/projectexplorer/buildstepspage.cpp +++ b/src/plugins/projectexplorer/buildstepspage.cpp @@ -52,6 +52,7 @@ BuildStepsPage::BuildStepsPage(Project *project, bool clean) : { m_vbox = new QVBoxLayout(this); m_vbox->setContentsMargins(0, 0, 0, 0); + m_vbox->setSpacing(0); const QList<BuildStep *> &steps = m_clean ? m_pro->cleanSteps() : m_pro->buildSteps(); foreach (BuildStep *bs, steps) { addBuildStepWidget(-1, bs); @@ -163,8 +164,12 @@ void BuildStepsPage::addBuildStepWidget(int pos, BuildStep *step) s.upButton = new QToolButton(this); s.upButton->setArrowType(Qt::UpArrow); + s.upButton->setMaximumHeight(22); + s.upButton->setMaximumWidth(22); s.downButton = new QToolButton(this); s.downButton->setArrowType(Qt::DownArrow); + s.downButton->setMaximumHeight(22); + s.downButton->setMaximumWidth(22); #ifdef Q_OS_MAC s.upButton->setIconSize(QSize(10, 10)); s.downButton->setIconSize(QSize(10, 10)); @@ -174,6 +179,7 @@ void BuildStepsPage::addBuildStepWidget(int pos, BuildStep *step) toolWidget->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); s.hbox = new QHBoxLayout(toolWidget); s.hbox->setMargin(0); + s.hbox->setSpacing(0); s.hbox->addWidget(s.upButton); s.hbox->addWidget(s.downButton); s.detailsWidget->setToolWidget(toolWidget); diff --git a/src/plugins/projectexplorer/projectwindow.cpp b/src/plugins/projectexplorer/projectwindow.cpp index a3fe25fdd615dc0a9af665153000b8b4691b85bd..326b9ec3961acec693ae9dd3c23a1cb95662cdfe 100644 --- a/src/plugins/projectexplorer/projectwindow.cpp +++ b/src/plugins/projectexplorer/projectwindow.cpp @@ -104,7 +104,7 @@ void PanelsWidget::addWidget(QWidget *widget) p.panelWidget = widget; p.marginLayout = 0; - m_layout->insertWidget(m_layout->count() -1, widget); + m_layout->insertWidget(m_layout->count() - 1, widget); m_panels.append(p); } diff --git a/src/plugins/qt4projectmanager/qmakestep.ui b/src/plugins/qt4projectmanager/qmakestep.ui index fcc45d7fb08090746cd23b6426419b53dd129e8e..f59dedaf52637e1221e1f9184bca9351e500f358 100644 --- a/src/plugins/qt4projectmanager/qmakestep.ui +++ b/src/plugins/qt4projectmanager/qmakestep.ui @@ -11,6 +11,9 @@ </rect> </property> <layout class="QFormLayout" name="formLayout"> + <property name="margin"> + <number>0</number> + </property> <item row="0" column="0"> <widget class="QLabel" name="label_2"> <property name="text">