diff --git a/doc/images/qtcreator-cmakeexecutable.png b/doc/images/qtcreator-cmakeexecutable.png index 70265cd2304..1f2244f5881 100644 Binary files a/doc/images/qtcreator-cmakeexecutable.png and b/doc/images/qtcreator-cmakeexecutable.png differ diff --git a/doc/images/qtcreator-qt4-qtversions-add.png b/doc/images/qtcreator-qt4-qtversions-add.png index 2857a28bd81..6c7c201c180 100644 Binary files a/doc/images/qtcreator-qt4-qtversions-add.png and b/doc/images/qtcreator-qt4-qtversions-add.png differ diff --git a/doc/images/qtcreator-run-settings-linux-devices.png b/doc/images/qtcreator-run-settings-linux-devices.png index 533b51fa760..47be61e81a3 100644 Binary files a/doc/images/qtcreator-run-settings-linux-devices.png and b/doc/images/qtcreator-run-settings-linux-devices.png differ diff --git a/doc/images/qtcreator-targets.png b/doc/images/qtcreator-targets.png index d1e63ee8d29..80022ad0e9e 100644 Binary files a/doc/images/qtcreator-targets.png and b/doc/images/qtcreator-targets.png differ diff --git a/doc/images/qtcreator-toolchains.png b/doc/images/qtcreator-toolchains.png index 8f38f27369d..0d4f8c854d2 100644 Binary files a/doc/images/qtcreator-toolchains.png and b/doc/images/qtcreator-toolchains.png differ diff --git a/doc/src/linux-mobile/linuxdev.qdoc b/doc/src/linux-mobile/linuxdev.qdoc index 30edb8535e4..96050276068 100644 --- a/doc/src/linux-mobile/linuxdev.qdoc +++ b/doc/src/linux-mobile/linuxdev.qdoc @@ -47,7 +47,8 @@ either a password or an SSH key. If you do not have an SSH key, you can create it in \QC. For more information, see \l {Generating SSH Keys}. - To configure connections between \QC and embedded Linux devices: + To configure connections between \QC and an embedded Linux device and to + specify build and run settings for the device: \list 1 @@ -90,6 +91,10 @@ \endlist + \o Select \gui Tools > \gui Options > \gui {Build & Run} > \gui Targets + > \gui Add to add a target for building for the device. Select the + Qt version, compiler, and device that you added above. + \o To specify build settings: \list 1 @@ -97,26 +102,17 @@ \o Open a project for an application you want to develop for the device. - \o Select \gui {Projects > Desktop > Build}. + \o Select \gui {Projects > Targets > Add}. - \o Select the Qt version and tool chain for the embedded Linux - device. + \o Select the target that you added above. \endlist - \o To specify run settings: - - \list 1 - - \o Select \gui {Run > Add > Deploy to Remote Linux Host} - to add a new deploy configuration. + \o To specify run settings, select \gui Run. \image qtcreator-run-settings-linux-devices.png "Run settings for embedded Linux devices" - \o In the \gui {Device configuration} field, select the device - connection. - - \endlist + Usually, you can use the default settings. When you run the project, \QC deploys the application as specified by the deploy steps. By default, \QC copies the application files to the device. diff --git a/doc/src/projects/creator-projects-opening.qdoc b/doc/src/projects/creator-projects-opening.qdoc index dd825a89a28..6d30ba4f4d3 100644 --- a/doc/src/projects/creator-projects-opening.qdoc +++ b/doc/src/projects/creator-projects-opening.qdoc @@ -47,7 +47,7 @@ \image qtcreator-open-project-targets.png "Configure Project tab" Even if you do not intend to build the project, the C++ and QML code models - need a Qt version and tool chain to offer code completion. To specify them, + need a Qt version and compiler to offer code completion. To specify them, select the \gui Options link, or select \gui {Tools > Options > Build & Run > Targets}. diff --git a/doc/src/projects/creator-projects-targets.qdoc b/doc/src/projects/creator-projects-targets.qdoc index 34005fa0af4..6cadd5cdbb1 100644 --- a/doc/src/projects/creator-projects-targets.qdoc +++ b/doc/src/projects/creator-projects-targets.qdoc @@ -33,7 +33,7 @@ \QC groups platform specific settings as \e targets to make cross-platform development easier. Each target consists of a set of values that define one - environment, such as a device, tool chain, Qt version, and debugger command + environment, such as a device, compiler, Qt version, and debugger command to use, and some metadata, such as an icon and a name for the target. Once you have defined targets, you can select them to build and run projects. @@ -85,8 +85,8 @@ image is located. If you are not cross-compiling, leave this field empty. - \o In the \gui {Tool chain} field, select the tool chain required - to build the project. You can add tool chains to the list + \o In the \gui {Compiler} field, select the compiler required + to build the project. You can add compilers to the list if they are installed on the development PC, but were not detected automatically. For more information, see \l{Adding Compilers}. diff --git a/src/libs/zeroconf/embed/CommonServices.h b/src/libs/zeroconf/embed/CommonServices.h index bf878faeee9..d0b9e870872 100644 --- a/src/libs/zeroconf/embed/CommonServices.h +++ b/src/libs/zeroconf/embed/CommonServices.h @@ -745,26 +745,6 @@ typedef long long int64_t; typedef unsigned long long uint64_t; #endif - - typedef int8_t int_least8_t; - typedef int16_t int_least16_t; - typedef int32_t int_least32_t; - typedef int64_t int_least64_t; - - typedef uint8_t uint_least8_t; - typedef uint16_t uint_least16_t; - typedef uint32_t uint_least32_t; - typedef uint64_t uint_least64_t; - - typedef int8_t int_fast8_t; - typedef int16_t int_fast16_t; - typedef int32_t int_fast32_t; - typedef int64_t int_fast64_t; - - typedef uint8_t uint_fast8_t; - typedef uint16_t uint_fast16_t; - typedef uint32_t uint_fast32_t; - typedef uint64_t uint_fast64_t; #if (( !defined( _MSC_VER ) || TARGET_OS_WINDOWS_CE ) && !defined( _WIN32 ) ) typedef long int intptr_t; diff --git a/src/libs/zeroconf/embed/dnssd_clientstub.c b/src/libs/zeroconf/embed/dnssd_clientstub.c index b09fc414e48..d70bb2d28d2 100644 --- a/src/libs/zeroconf/embed/dnssd_clientstub.c +++ b/src/libs/zeroconf/embed/dnssd_clientstub.c @@ -79,9 +79,33 @@ namespace ZeroConf { namespace embeddedLib { DWORD err = WSAGetLastError(); (void) priority; va_start( args, message ); + #ifdef _MSC_VER len = _vscprintf( message, args ) + 1; buffer = reinterpret_cast(malloc( len * sizeof(char) )); - if ( buffer ) { vsprintf( buffer, message, args ); OutputDebugStringA( buffer ); free( buffer ); } + if ( buffer ) { + vsprintf(buffer, message, args); + OutputDebugStringA(buffer); + free(buffer); + } + #else // MinGW 4.4, no longer required for 4.6 + len = vsnprintf(NULL, 0, message, args); + va_end(args); + if (len == -1) // encoding error + return; + buffer = reinterpret_cast(malloc((len + 1) * sizeof(char))); + if (buffer == NULL) // no memory allocation possible + return; + va_start(args, message); + len = vsnprintf(buffer, (len + 1) * sizeof(char), message, args); + va_end(args); + if (len == -1) { // encoding error + free(buffer); + return; + } else { + OutputDebugStringA(buffer); + free(buffer); + } + #endif WSASetLastError( err ); } }} diff --git a/src/plugins/cmakeprojectmanager/cmakeopenprojectwizard.cpp b/src/plugins/cmakeprojectmanager/cmakeopenprojectwizard.cpp index 12e008bb414..7807dee197e 100644 --- a/src/plugins/cmakeprojectmanager/cmakeopenprojectwizard.cpp +++ b/src/plugins/cmakeprojectmanager/cmakeopenprojectwizard.cpp @@ -423,8 +423,14 @@ void CMakeRunPage::initializePage() if (hasCodeBlocksGenerator && (cachedGenerator.isEmpty() || cachedGenerator == "NMake Makefiles")) m_generatorComboBox->addItem(tr("NMake Generator (%1)").arg(p->displayName()), profileVariant); } else if (targetAbi.osFlavor() == ProjectExplorer::Abi::WindowsMSysFlavor) { +#ifdef Q_OS_WIN if (cachedGenerator.isEmpty() || cachedGenerator == "MinGW Makefiles") m_generatorComboBox->addItem(tr("MinGW Generator (%1)").arg(p->displayName()), profileVariant); +#else + if (cachedGenerator.isEmpty() || cachedGenerator == "Unix Makefiles") + m_generatorComboBox->addItem(tr("Unix Generator (%1)").arg(p->displayName()), profileVariant); +#endif + } } else { // Non windows @@ -460,7 +466,11 @@ void CMakeRunPage::runCMake() QString generator = QLatin1String("-GCodeBlocks - Unix Makefiles"); if (tc->targetAbi().os() == ProjectExplorer::Abi::WindowsOS) { if (tc->targetAbi().osFlavor() == ProjectExplorer::Abi::WindowsMSysFlavor) +#ifdef Q_OS_WIN generator = QLatin1String("-GCodeBlocks - MinGW Makefiles"); +#else + generator = QLatin1String("-GCodeBlocks - Unix Makefiles"); +#endif else generator = QLatin1String("-GCodeBlocks - NMake Makefiles"); } diff --git a/src/plugins/debugger/cdb/cdbengine.cpp b/src/plugins/debugger/cdb/cdbengine.cpp index 323ae8ca2eb..d0977db14c6 100644 --- a/src/plugins/debugger/cdb/cdbengine.cpp +++ b/src/plugins/debugger/cdb/cdbengine.cpp @@ -404,6 +404,7 @@ void CdbEngine::init() m_sourceStepInto = false; m_watchPointX = m_watchPointY = 0; m_ignoreCdbOutput = false; + m_watchInameToName.clear(); m_outputBuffer.clear(); m_builtinCommandQueue.clear(); @@ -470,23 +471,13 @@ bool CdbEngine::setToolTipExpression(const QPoint &mousePos, // Are we in the current stack frame if (context.function.isEmpty() || exp.isEmpty() || context.function != stackHandler()->currentFrame().function) return false; - // No numerical or any other expressions [yet] - if (!(exp.at(0).isLetter() || exp.at(0) == QLatin1Char('_'))) + // Show tooltips of local variables only. Anything else can slow debugging down. + const WatchData *localVariable = watchHandler()->findCppLocalVariable(exp); + if (!localVariable) return false; - // Can this be found as a local variable? - const QByteArray localsPrefix(localsPrefixC); - QByteArray iname = localsPrefix + exp.toAscii(); - if (!watchHandler()->hasItem(iname)) { - // Nope, try a 'local.this.m_foo'. - exp.prepend(QLatin1String("this.")); - iname.insert(localsPrefix.size(), "this."); - if (!watchHandler()->hasItem(iname)) - return false; - } DebuggerToolTipWidget *tw = new DebuggerToolTipWidget; tw->setContext(context); - tw->setDebuggerModel(LocalsType); - tw->setExpression(exp); + tw->setIname(localVariable->iname); tw->acquireEngine(this); DebuggerToolTipManager::instance()->showToolTip(mousePos, editor, tw); return true; @@ -995,6 +986,10 @@ void CdbEngine::updateWatchData(const WatchData &dataIn, QByteArray args; ByteArrayInputStream str(args); str << dataIn.iname << " \"" << dataIn.exp << '"'; + // Store the name since the CDB extension library + // does not maintain the names of watches. + if (!dataIn.name.isEmpty() && dataIn.name != QLatin1String(dataIn.exp)) + m_watchInameToName.insert(dataIn.iname, dataIn.name); postExtensionCommand("addwatch", args, 0, &CdbEngine::handleAddWatch, 0, qVariantFromValue(dataIn)); @@ -1916,6 +1911,15 @@ void CdbEngine::handleLocals(const CdbExtensionCommandPtr &reply) dummy.name = QLatin1String(child.findChild("name").data()); parseWatchData(watchHandler()->expandedINames(), dummy, child, &watchData); } + // Fix the names of watch data. + for (int i =0; i < watchData.size(); ++i) { + if (watchData.at(i).iname.startsWith('w')) { + const QHash::const_iterator it + = m_watchInameToName.find(watchData.at(i).iname); + if (it != m_watchInameToName.constEnd()) + watchData[i].name = it.value(); + } + } watchHandler()->insertData(watchData); if (debugLocals) { QDebug nsp = qDebug().nospace(); diff --git a/src/plugins/debugger/cdb/cdbengine.h b/src/plugins/debugger/cdb/cdbengine.h index f4e0e04f1a4..07f98401e0a 100644 --- a/src/plugins/debugger/cdb/cdbengine.h +++ b/src/plugins/debugger/cdb/cdbengine.h @@ -275,6 +275,7 @@ private: PendingBreakPointMap m_pendingBreakpointMap; QHash m_fileNameModuleHash; QMultiHash m_symbolAddressCache; + QHash m_watchInameToName; bool m_ignoreCdbOutput; QVariantList m_customSpecialStopData; QList m_sourcePathMappings; diff --git a/src/plugins/debugger/debuggerplugin.cpp b/src/plugins/debugger/debuggerplugin.cpp index b6040565317..b6d5b593b81 100644 --- a/src/plugins/debugger/debuggerplugin.cpp +++ b/src/plugins/debugger/debuggerplugin.cpp @@ -1144,7 +1144,12 @@ public slots: exp = fixCppExpression(exp); if (exp.isEmpty()) return; - currentEngine()->watchHandler()->watchExpression(exp); + const QString name = exp; + // Prefer to watch an existing local variable by its expression (address) if it can be found. + WatchHandler *watchHandler = currentEngine()->watchHandler(); + if (const WatchData *localVariable = watchHandler->findCppLocalVariable(exp)) + exp = QLatin1String(localVariable->exp); + watchHandler->watchExpression(exp, name); } void handleExecExit() diff --git a/src/plugins/debugger/debuggertooltipmanager.cpp b/src/plugins/debugger/debuggertooltipmanager.cpp index fcdf0882c81..d6c956250ed 100644 --- a/src/plugins/debugger/debuggertooltipmanager.cpp +++ b/src/plugins/debugger/debuggertooltipmanager.cpp @@ -98,8 +98,8 @@ static const char offsetYAttributeC[] = "offset_y"; static const char engineTypeAttributeC[] = "engine"; static const char dateAttributeC[] = "date"; static const char treeElementC[] = "tree"; -static const char treeModelAttributeC[] = "model"; // Locals/Watches -static const char treeExpressionAttributeC[] = "expression"; // Locals/Watches +static const char treeExpressionAttributeC[] = "expression"; +static const char treeInameAttributeC[] = "iname"; static const char modelElementC[] = "model"; static const char modelColumnCountAttributeC[] = "columncount"; static const char modelRowElementC[] = "row"; @@ -615,7 +615,6 @@ DebuggerToolTipWidget::DebuggerToolTipWidget(QWidget *parent) : m_titleLabel(new DraggableLabel), m_engineAcquired(false), m_creationDate(QDate::currentDate()), - m_debuggerModel(TooltipType), m_treeView(new DebuggerToolTipTreeView), m_defaultModel(new QStandardItemModel(this)) { @@ -836,11 +835,7 @@ void DebuggerToolTipWidget::saveSessionData(QXmlStreamWriter &w) const /*! \class Debugger::Internal::TooltipFilterModel - \brief Model for tooltips filtering a local variable using the locals or tooltip model, - matching on the name. - - Expressions/names can either be flat ('foo' will match at the root level) - or nested ('this.m_foo' will match 'this' at root level and 'm_foo' at level 1). + \brief Model for tooltips filtering an item on the watchhandler matching its tree on the iname. In addition, suppress the model's tooltip data to avoid a tooltip on a tooltip. */ @@ -848,9 +843,8 @@ void DebuggerToolTipWidget::saveSessionData(QXmlStreamWriter &w) const class TooltipFilterModel : public QSortFilterProxyModel { public: - TooltipFilterModel(QAbstractItemModel *model, const QString &exp, int debuggerModel) : - m_expressions(exp.split(QLatin1Char('.'))), - m_debuggerModel(debuggerModel) + TooltipFilterModel(QAbstractItemModel *model, const QByteArray &iname) + : m_iname(iname) { setSourceModel(model); } @@ -864,27 +858,21 @@ public: bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const; private: - const QStringList m_expressions; - int m_debuggerModel; + const QByteArray m_iname; }; +static bool isSubIname(const QByteArray &haystack, const QByteArray &needle) +{ + return haystack.size() > needle.size() + && haystack.startsWith(needle) + && haystack.at(needle.size()) == '.'; +} + bool TooltipFilterModel::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const { const QModelIndex nameIndex = sourceModel()->index(sourceRow, 0, sourceParent); - QByteArray iname = nameIndex.data(LocalsINameRole).toByteArray(); - if (m_debuggerModel == LocalsType && !iname.startsWith("local")) - return false; - if (m_debuggerModel == TooltipType && !iname.startsWith("tooltip")) - return false; - // Match on expression for top level, else pass through. - const int depth = iname.count('.'); - if (depth == 0) - return true; - if (depth > m_expressions.size()) - return true; - const QString name = nameIndex.data().toString(); - //const QString exp = nameIndex.data(LocalsExpressionRole).toString(); - return name == m_expressions.at(depth - 1); + const QByteArray iname = nameIndex.data(LocalsINameRole).toByteArray(); + return iname == m_iname || isSubIname(iname, m_iname) || isSubIname(m_iname, iname); } /*! @@ -991,7 +979,7 @@ void DebuggerToolTipWidget::doAcquireEngine(DebuggerEngine *engine) // Create a filter model on the debugger's model and switch to it. QAbstractItemModel *model = engine->watchModel(); TooltipFilterModel *filterModel = - new TooltipFilterModel(model, m_expression, m_debuggerModel); + new TooltipFilterModel(model, m_iname); swapModel(filterModel); } @@ -1000,7 +988,7 @@ QAbstractItemModel *DebuggerToolTipWidget::swapModel(QAbstractItemModel *newMode QAbstractItemModel *oldModel = m_treeView->swapModel(newModel); // When looking at some 'this.m_foo.x', expand all items if (newModel) { - if (const int level = m_expression.count(QLatin1Char('.')) + 1) { + if (const int level = m_iname.count('.')) { QModelIndex index = newModel->index(0, 0); for (int i = 0; i < level && index.isValid(); i++, index = index.child(0, 0)) m_treeView->setExpanded(index, true); @@ -1062,8 +1050,9 @@ void DebuggerToolTipWidget::doSaveSessionData(QXmlStreamWriter &w) const { w.writeStartElement(QLatin1String(treeElementC)); QXmlStreamAttributes attributes; - attributes.append(QLatin1String(treeModelAttributeC), QString::number(m_debuggerModel)); - attributes.append(QLatin1String(treeExpressionAttributeC), m_expression); + if (!m_expression.isEmpty()) + attributes.append(QLatin1String(treeExpressionAttributeC), m_expression); + attributes.append(QLatin1String(treeInameAttributeC), QLatin1String(m_iname)); w.writeAttributes(attributes); if (QAbstractItemModel *model = m_treeView->model()) { XmlWriterTreeModelVisitor v(model, w); @@ -1078,11 +1067,11 @@ void DebuggerToolTipWidget::doLoadSessionData(QXmlStreamReader &r) return; // Restore data to default model and show that. const QXmlStreamAttributes attributes = r.attributes(); - m_debuggerModel = attributes.value(QLatin1String(treeModelAttributeC)).toString().toInt(); + m_iname = attributes.value(QLatin1String(treeInameAttributeC)).toString().toLatin1(); m_expression = attributes.value(QLatin1String(treeExpressionAttributeC)).toString(); if (debugToolTips) - qDebug() << "DebuggerTreeViewToolTipWidget::doLoadSessionData() " << m_debuggerModel << m_expression; - setObjectName(QLatin1String("DebuggerTreeViewToolTipWidget: ") + m_expression); + qDebug() << "DebuggerTreeViewToolTipWidget::doLoadSessionData() " << m_debuggerModel << m_iname; + setObjectName(QLatin1String("DebuggerTreeViewToolTipWidget: ") + QLatin1String(m_iname)); restoreTreeModel(r, m_defaultModel); r.readNext(); // Skip m_treeView->swapModel(m_defaultModel); @@ -1480,14 +1469,16 @@ void DebuggerToolTipManager::slotTooltipOverrideRequested(ITextEditor *editor, qDebug() << " &tw, m_tooltips) { if (!tw.isNull() && tw->matches(fileName, engineType, function)) - rc.push_back(tw->expression()); + rc.push_back(ExpressionInamePair(tw->expression(), tw->iname())); } if (debugToolTips) qDebug() << "DebuggerToolTipManager::treeWidgetExpressions" diff --git a/src/plugins/debugger/debuggertooltipmanager.h b/src/plugins/debugger/debuggertooltipmanager.h index b31a8ed6abe..f503dc63b74 100644 --- a/src/plugins/debugger/debuggertooltipmanager.h +++ b/src/plugins/debugger/debuggertooltipmanager.h @@ -119,8 +119,9 @@ public: static DebuggerToolTipWidget *loadSessionData(QXmlStreamReader &r); - int debuggerModel() const { return m_debuggerModel; } - void setDebuggerModel(int m) { m_debuggerModel = m; } + QByteArray iname() const { return m_iname; } + void setIname(const QByteArray &e) { m_iname = e; } + QString expression() const { return m_expression; } void setExpression(const QString &e) { m_expression = e; } @@ -166,6 +167,7 @@ private: int m_debuggerModel; QString m_expression; + QByteArray m_iname; DebuggerToolTipTreeView *m_treeView; QStandardItemModel *m_defaultModel; @@ -196,6 +198,9 @@ class DebuggerToolTipManager : public QObject Q_OBJECT public: + typedef QPair ExpressionInamePair; + typedef QList ExpressionInamePairs; + explicit DebuggerToolTipManager(QObject *parent = 0); virtual ~DebuggerToolTipManager(); @@ -204,9 +209,9 @@ public: bool hasToolTips() const { return !m_tooltips.isEmpty(); } // Collect all expressions of DebuggerTreeViewToolTipWidget - QStringList treeWidgetExpressions(const QString &fileName, - const QString &engineType = QString(), - const QString &function= QString()) const; + ExpressionInamePairs treeWidgetExpressions(const QString &fileName, + const QString &engineType = QString(), + const QString &function= QString()) const; void showToolTip(const QPoint &p, Core::IEditor *editor, DebuggerToolTipWidget *); diff --git a/src/plugins/debugger/gdb/classicgdbengine.cpp b/src/plugins/debugger/gdb/classicgdbengine.cpp index bc227242aad..bc26584d1d4 100644 --- a/src/plugins/debugger/gdb/classicgdbengine.cpp +++ b/src/plugins/debugger/gdb/classicgdbengine.cpp @@ -1022,7 +1022,8 @@ void GdbEngine::handleDebuggingHelperValue2Classic(const GdbResponse &response) parseWatchData(watchHandler()->expandedINames(), data, contents, &list); //for (int i = 0; i != list.size(); ++i) // qDebug() << "READ: " << list.at(i).toString(); - watchHandler()->insertData(list); + foreach (const WatchData &data, list) + insertData(data); } void GdbEngine::handleDebuggingHelperValue3Classic(const GdbResponse &response) @@ -1238,6 +1239,9 @@ void GdbEngine::handleStackListLocalsClassic(const GdbResponse &response) frame.function, frame.file, frame.line, &uninitializedVariables); } + WatchHandler *handler = watchHandler(); + insertData(*handler->findData("local")); + foreach (const GdbMi &item, locals) { const WatchData data = localVariable(item, uninitializedVariables, &seen); if (data.isValid()) @@ -1252,7 +1256,7 @@ void GdbEngine::handleStackListLocalsClassic(const GdbResponse &response) insertData(rd); } - watchHandler()->updateWatchers(); + handler->updateWatchers(); } static void showQtDumperLibraryWarning(const QString &details) diff --git a/src/plugins/debugger/gdb/gdbengine.cpp b/src/plugins/debugger/gdb/gdbengine.cpp index e1bf4e8d346..0d622d8f522 100644 --- a/src/plugins/debugger/gdb/gdbengine.cpp +++ b/src/plugins/debugger/gdb/gdbengine.cpp @@ -118,6 +118,7 @@ public: QPoint mousePosition; QString expression; + QByteArray iname; Core::IEditor *editor; }; @@ -3845,22 +3846,19 @@ void GdbEngine::showToolTip() if (m_toolTipContext.isNull()) return; const QString expression = m_toolTipContext->expression; - const QByteArray iname = tooltipIName(m_toolTipContext->expression); if (DebuggerToolTipManager::debug()) - qDebug() << "GdbEngine::showToolTip " << expression << iname << (*m_toolTipContext); + qDebug() << "GdbEngine::showToolTip " << expression << m_toolTipContext->iname << (*m_toolTipContext); - if (!debuggerCore()->boolSetting(UseToolTipsInMainEditor)) { - watchHandler()->removeData(iname); + if (m_toolTipContext->iname.startsWith("tooltip") + && (!debuggerCore()->boolSetting(UseToolTipsInMainEditor) + || !watchHandler()->isValidToolTip(m_toolTipContext->iname))) { + watchHandler()->removeData(m_toolTipContext->iname); return; } - if (!watchHandler()->isValidToolTip(iname)) { - watchHandler()->removeData(iname); - return; - } DebuggerToolTipWidget *tw = new DebuggerToolTipWidget; - tw->setDebuggerModel(TooltipType); - tw->setExpression(expression); + tw->setIname(m_toolTipContext->iname); + tw->setExpression(m_toolTipContext->expression); tw->setContext(*m_toolTipContext); tw->acquireEngine(this); DebuggerToolTipManager::instance()->showToolTip(m_toolTipContext->mousePosition, @@ -3891,12 +3889,22 @@ bool GdbEngine::setToolTipExpression(const QPoint &mousePos, DebuggerToolTipContext context = contextIn; int line, column; - const QString exp = fixCppExpression(cppExpressionAt(editor, context.position, &line, &column, &context.function)); - if (DebuggerToolTipManager::debug()) - qDebug() << "GdbEngine::setToolTipExpression1 " << exp << context; + QString exp = fixCppExpression(cppExpressionAt(editor, context.position, &line, &column, &context.function)); if (exp.isEmpty()) return false; + // Prefer a filter on an existing local variable if it can be found. + QByteArray iname; + if (const WatchData *localVariable = watchHandler()->findCppLocalVariable(exp)) { + exp = QLatin1String(localVariable->exp); + iname = localVariable->iname; + } else { + iname = tooltipIName(exp); + } + if (DebuggerToolTipManager::debug()) + qDebug() << "GdbEngine::setToolTipExpression1 " << exp << iname << context; + + // Same expression: Display synchronously. if (!m_toolTipContext.isNull() && m_toolTipContext->expression == exp) { showToolTip(); return true; @@ -3905,7 +3913,14 @@ bool GdbEngine::setToolTipExpression(const QPoint &mousePos, m_toolTipContext.reset(new GdbToolTipContext(context)); m_toolTipContext->mousePosition = mousePos; m_toolTipContext->expression = exp; + m_toolTipContext->iname = iname; m_toolTipContext->editor = editor; + // Local variable: Display synchronously. + if (iname.startsWith("local")) { + showToolTip(); + return true; + } + if (DebuggerToolTipManager::debug()) qDebug() << "GdbEngine::setToolTipExpression2 " << exp << (*m_toolTipContext); @@ -3913,13 +3928,13 @@ bool GdbEngine::setToolTipExpression(const QPoint &mousePos, UpdateParameters params; params.tryPartial = true; params.tooltipOnly = true; - params.varList = tooltipIName(exp); + params.varList = iname; updateLocalsPython(params); } else { WatchData toolTip; toolTip.exp = exp.toLatin1(); toolTip.name = exp; - toolTip.iname = tooltipIName(exp); + toolTip.iname = iname; watchHandler()->insertData(toolTip); } return true; diff --git a/src/plugins/debugger/gdb/pythongdbengine.cpp b/src/plugins/debugger/gdb/pythongdbengine.cpp index df6da0ad1fe..920c8c6e743 100644 --- a/src/plugins/debugger/gdb/pythongdbengine.cpp +++ b/src/plugins/debugger/gdb/pythongdbengine.cpp @@ -64,17 +64,35 @@ void GdbEngine::updateLocalsPython(const UpdateParameters ¶ms) const QString fileName = stackHandler()->currentFrame().file; const QString function = stackHandler()->currentFrame().function; if (!fileName.isEmpty()) { - QStringList expressions = DebuggerToolTipManager::instance() + typedef DebuggerToolTipManager::ExpressionInamePair ExpressionInamePair; + typedef DebuggerToolTipManager::ExpressionInamePairs ExpressionInamePairs; + + // Re-create tooltip items that are not filters on existing local variables in + // the tooltip model. + ExpressionInamePairs toolTips = DebuggerToolTipManager::instance() ->treeWidgetExpressions(fileName, objectName(), function); + const QString currentExpression = tooltipExpression(); - if (!currentExpression.isEmpty() && !expressions.contains(currentExpression)) - expressions.push_back(currentExpression); - foreach (const QString &te, expressions) { - if (!watchers.isEmpty()) - watchers += "##"; - watchers += te.toLatin1(); - watchers += '#'; - watchers += tooltipIName(te); + if (!currentExpression.isEmpty()) { + int currentIndex = -1; + for (int i = 0; i < toolTips.size(); ++i) { + if (toolTips.at(i).first == currentExpression) { + currentIndex = i; + break; + } + } + if (currentIndex < 0) + toolTips.push_back(ExpressionInamePair(currentExpression, tooltipIName(currentExpression))); + } + + foreach (const ExpressionInamePair &p, toolTips) { + if (p.second.startsWith("tooltip")) { + if (!watchers.isEmpty()) + watchers += "##"; + watchers += p.first.toLatin1(); + watchers += '#'; + watchers += p.second; + } } } diff --git a/src/plugins/debugger/watchhandler.cpp b/src/plugins/debugger/watchhandler.cpp index fb1cdf29d7b..966bf8c8651 100644 --- a/src/plugins/debugger/watchhandler.cpp +++ b/src/plugins/debugger/watchhandler.cpp @@ -1550,7 +1550,7 @@ QByteArray WatchHandler::watcherName(const QByteArray &exp) return "watch." + QByteArray::number(theWatcherNames[exp]); } -void WatchHandler::watchExpression(const QString &exp) +void WatchHandler::watchExpression(const QString &exp, const QString &name) { QTC_ASSERT(m_engine, return); // Do not insert the same entry more then once. @@ -1560,7 +1560,7 @@ void WatchHandler::watchExpression(const QString &exp) // FIXME: 'exp' can contain illegal characters WatchData data; data.exp = exp.toLatin1(); - data.name = exp; + data.name = name.isEmpty() ? exp : name; theWatcherNames[data.exp] = m_watcherCounter++; saveWatchers(); @@ -1794,6 +1794,20 @@ const WatchData *WatchHandler::findData(const QByteArray &iname) const return m_model->findItem(iname); } +const WatchData *WatchHandler::findCppLocalVariable(const QString &name) const +{ + // Can this be found as a local variable? + const QByteArray localsPrefix("local."); + QByteArray iname = localsPrefix + name.toLatin1(); + if (const WatchData *wd = findData(iname)) + return wd; + // Nope, try a 'local.this.m_foo'. + iname.insert(localsPrefix.size(), "this."); + if (const WatchData *wd = findData(iname)) + return wd; + return 0; +} + QString WatchHandler::displayForAutoTest(const QByteArray &iname) const { return m_model->displayForAutoTest(iname); diff --git a/src/plugins/debugger/watchhandler.h b/src/plugins/debugger/watchhandler.h index bcd243e91fd..b8b2648b09f 100644 --- a/src/plugins/debugger/watchhandler.h +++ b/src/plugins/debugger/watchhandler.h @@ -58,15 +58,6 @@ public: typedef QHash TypeFormats; -enum WatchType -{ - LocalsType, - InspectType, - WatchersType, - ReturnType, - TooltipType -}; - enum IntegerFormat { DecimalFormat = 0, // Keep that at 0 as default. @@ -86,7 +77,7 @@ public: QAbstractItemModel *model() const; void cleanup(); - void watchExpression(const QString &exp); + void watchExpression(const QString &exp, const QString &name = QString()); Q_SLOT void clearWatches(); void updateWatchers(); // Called after locals are fetched @@ -95,6 +86,7 @@ public: const WatchData *watchData(const QModelIndex &) const; const WatchData *findData(const QByteArray &iname) const; + const WatchData *findCppLocalVariable(const QString &name) const; QString displayForAutoTest(const QByteArray &iname) const; bool hasItem(const QByteArray &iname) const; diff --git a/src/plugins/debugger/watchwindow.cpp b/src/plugins/debugger/watchwindow.cpp index 9098ea4f84e..a3ad639d4f6 100644 --- a/src/plugins/debugger/watchwindow.cpp +++ b/src/plugins/debugger/watchwindow.cpp @@ -920,7 +920,7 @@ void WatchTreeView::contextMenuEvent(QContextMenuEvent *ev) grabMouse(Qt::CrossCursor); m_grabbing = true; } else if (act == actWatchExpression) { - watchExpression(exp); + watchExpression(exp, name); } else if (act == actRemoveWatchExpression) { handler->removeData(p.data(LocalsINameRole).toByteArray()); } else if (act == actCopy) { @@ -1036,7 +1036,12 @@ void WatchTreeView::reset() void WatchTreeView::watchExpression(const QString &exp) { - currentEngine()->watchHandler()->watchExpression(exp); + watchExpression(exp, QString()); +} + +void WatchTreeView::watchExpression(const QString &exp, const QString &name) +{ + currentEngine()->watchHandler()->watchExpression(exp, name); } void WatchTreeView::setModelData diff --git a/src/plugins/debugger/watchwindow.h b/src/plugins/debugger/watchwindow.h index 1c091c0840d..41492a346f8 100644 --- a/src/plugins/debugger/watchwindow.h +++ b/src/plugins/debugger/watchwindow.h @@ -56,6 +56,7 @@ public: public slots: void watchExpression(const QString &exp); + void watchExpression(const QString &exp, const QString &name); void handleItemIsExpanded(const QModelIndex &idx); private: diff --git a/src/plugins/qmlprojectmanager/fileformat/qmlprojectitem.h b/src/plugins/qmlprojectmanager/fileformat/qmlprojectitem.h index c91c36d4a3e..f3efc8010d5 100644 --- a/src/plugins/qmlprojectmanager/fileformat/qmlprojectitem.h +++ b/src/plugins/qmlprojectmanager/fileformat/qmlprojectitem.h @@ -32,6 +32,7 @@ #define QMLPROJECTITEM_H #include +#include #include #include diff --git a/src/plugins/qtsupport/qtoptionspage.cpp b/src/plugins/qtsupport/qtoptionspage.cpp index 08c773ff76e..e8d8d1a46f1 100644 --- a/src/plugins/qtsupport/qtoptionspage.cpp +++ b/src/plugins/qtsupport/qtoptionspage.cpp @@ -622,6 +622,11 @@ static QString filterForQmakeFileDialog() // work around QTBUG-7739 that prohibits filters that don't start with * filter += QLatin1Char('*'); filter += commands.at(i); +#if defined(Q_OS_UNIX) && !defined(Q_OS_MAC) + // kde bug, we need at least one wildcard character + // see QTCREATORBUG-7771 + filter += QLatin1Char('*'); +#endif } filter += QLatin1Char(')'); return filter; diff --git a/tests/system/settings/unix/Nokia/qtcreator/profiles.xml b/tests/system/settings/unix/Nokia/qtcreator/profiles.xml index 4aec8bfea37..b3a3a5e5620 100644 --- a/tests/system/settings/unix/Nokia/qtcreator/profiles.xml +++ b/tests/system/settings/unix/Nokia/qtcreator/profiles.xml @@ -1,6 +1,6 @@ - + Profile.0 @@ -20,9 +20,27 @@ Desktop + + Profile.1 + + false + + /usr/bin/gdb + Desktop Device + Desktop + + ProjectExplorer.ToolChain.Gcc:{c3f59b87-6997-4bd8-8067-ee04dc536371} + + 5 + + :///DESKTOP/// + {68d379f6-357c-42a6-83c6-7743840db4ea} + Qt Simulator + + Profile.Count - 1 + 2 Profile.Default diff --git a/tests/system/settings/windows/Nokia/qtcreator/profiles.xml b/tests/system/settings/windows/Nokia/qtcreator/profiles.xml index f1fbebce1a0..f7fde15dea3 100644 --- a/tests/system/settings/windows/Nokia/qtcreator/profiles.xml +++ b/tests/system/settings/windows/Nokia/qtcreator/profiles.xml @@ -1,6 +1,6 @@ - + Profile.0 @@ -20,9 +20,27 @@ Desktop + + Profile.1 + + false + + C:/QtSDK/pythongdb/python_2.7based/gdb-i686-pc-mingw32.exe + Desktop Device + Desktop + + ProjectExplorer.ToolChain.Mingw:{2729dd3e-84f5-42e1-aed1-6a27163346ce} + + 9 + + :///DESKTOP/// + {0ce9f69f-0f60-4b04-8691-c328ee5bfe14} + Qt Simulator + + Profile.Count - 1 + 2 Profile.Default