diff --git a/dist/changes-3.6.1.md b/dist/changes-3.6.1.md new file mode 100644 index 00000000000..e63bcf478a2 --- /dev/null +++ b/dist/changes-3.6.1.md @@ -0,0 +1,61 @@ +Qt Creator version 3.6.1 contains bug fixes. + +The most important changes are listed in this document. For a complete +list of changes, see the Git log for the Qt Creator sources that +you can check out from the public Git repository. For example: + + git clone git://code.qt.io/qt-creator/qt-creator.git + git log --cherry-pick --pretty=oneline v3.6.0..v3.6.1 + +Editing + +* Fixed issues with setting font size (QTCREATORBUG-15608, QTCREATORBUG-15609) + +Help + +* Fixed opening external links (QTCREATORBUG-15491) + +C++ Support + +* Clang code model + * Fixed crash when closing many documents fast (QTCREATORBUG-15532) + * Fixed that HTML code was shown in completion tool tip (QTCREATORBUG-15630) + * Fixed highlighting for using a namespaced type (QTCREATORBUG-15271) + * Fixed highlighting of current parameter in function signature tool tip + (QTCREATORBUG-15108) + * Fixed that template parameters were not shown in function signature tool + tip (QTCREATORBUG-15286) + +Qt Support + +* Fixed crash when updating code model for `.ui` files (QTCREATORBUG-15672) + +QML Support + +* Added Qt 5.6 as an option to the wizards + +Debugging + +* LLDB + * Fixed that switching thread did not update stack view (QTCREATORBUG-15587) +* GDB/MinGW + * Fixed editing values while debugging + +Beautifier + +* Fixed formatting with `clang-format` + +Platform Specific + +Windows + +* Added detection of Microsoft Visual C++ Build Tools +* Fixed issue with console applications that run only for a short time + `Cannot obtain a handle to the inferior: The parameter is incorrect` + (QTCREATORBUG-13042) +* Fixed that debug messages could get lost after the application finished + (QTCREATORBUG-15546) + +Android + +* Fixed issues with Gradle wrapper (QTCREATORBUG-15568) diff --git a/doc/images/qml-profiler-flamegraph.png b/doc/images/qml-profiler-flamegraph.png new file mode 100644 index 00000000000..23c6558028f Binary files /dev/null and b/doc/images/qml-profiler-flamegraph.png differ diff --git a/doc/images/qml-profiler-statistics.png b/doc/images/qml-profiler-statistics.png new file mode 100644 index 00000000000..d45b950c2c8 Binary files /dev/null and b/doc/images/qml-profiler-statistics.png differ diff --git a/doc/images/qtcreator-analyzer-bindings.png b/doc/images/qtcreator-analyzer-bindings.png deleted file mode 100644 index e9ce84b2bb6..00000000000 Binary files a/doc/images/qtcreator-analyzer-bindings.png and /dev/null differ diff --git a/doc/src/analyze/cpu-usage-analyzer.qdoc b/doc/src/analyze/cpu-usage-analyzer.qdoc index 237134594e0..92fac2b990e 100644 --- a/doc/src/analyze/cpu-usage-analyzer.qdoc +++ b/doc/src/analyze/cpu-usage-analyzer.qdoc @@ -167,6 +167,16 @@ depending on the exact value of the program counter when the sample was recorded. + \section2 Resolving Names for JIT-compiled JavaScript Functions + + From version 5.6.0, Qt can generate perf.map files with information about + JavaScript functions. The CPU Usage Analyzer will read them and show the + function names in the \uicontrol Timeline and \uicontrol Statistics views. + This only works if the process being profiled is running on the host + computer, not on the target device. To switch on the generation of perf.map + files, add the environment variable \c QV4_PROFILE_WRITE_PERF_MAP to the + \uicontrol {Run Environment} and set its value to \c 1. + \section1 Analyzing Collected Data The \uicontrol Timeline view displays a graphical representation of CPU @@ -257,6 +267,36 @@ overall bottleneck, and the thread with less samples taken has likely spent time waiting for external events such as I/O or a mutex. + \section1 Viewing Statistics + + The \uicontrol Statistics view displays the number of samples each function + in the timeline was contained in, in total and when on the top of the + stack (called \c self). This allows you to examine which functions you need + to optimize. A high number of occurrences might indicate that a function is + triggered unnecessarily or takes very long to execute. + + Click on a row to move to the respective function in the source code in the + code editor. + + The \uicontrol Callers and \uicontrol Callees panes show dependencies + between functions. They allow you to examine the internal functions of the + application. The \uicontrol Callers pane summarizes the functions that + called the function selected in the main view. The \uicontrol Callees pane + summarizes the functions called from the function selected in the main + view. + + Click on a row to move to the respective function in the source code in the + code editor and select it in the main view. + + When you select a stack frame in the \uicontrol Timeline view, information + about it is displayed in the \uicontrol Statistics view. To view a time + range in the \uicontrol Statistics view, select + \uicontrol {Limit Statistics to Selected Range} in the context menu in the + \uicontrol Timeline view. + + To copy the contents of one view or row to the clipboard, select + \uicontrol {Copy Table} or \uicontrol {Copy Row} in the context menu. + \section1 Loading Perf Data Files You can load any \c perf.data files generated by recent versions of the diff --git a/doc/src/analyze/creator-valgrind.qdoc b/doc/src/analyze/creator-valgrind.qdoc index 2ad30acc690..28010de2006 100644 --- a/doc/src/analyze/creator-valgrind.qdoc +++ b/doc/src/analyze/creator-valgrind.qdoc @@ -277,8 +277,7 @@ \list 1 \li Select \uicontrol Analyze > \uicontrol {Valgrind Memory Analyzer (External - Remote Application)} or - \uicontrol {Valgrind Function Profiler (External Remote Application)}. + Application)} or \uicontrol {Valgrind Function Profiler (External Application)}. \image qtcreator-valgrind-remote-settings.png "Start Analyzer dialog" diff --git a/doc/src/analyze/qtquick-profiler.qdoc b/doc/src/analyze/qtquick-profiler.qdoc index c1ad3325696..6f3753ad409 100644 --- a/doc/src/analyze/qtquick-profiler.qdoc +++ b/doc/src/analyze/qtquick-profiler.qdoc @@ -528,7 +528,7 @@ Click on an event to move to it in the source code in the code editor. - \image qtcreator-analyzer-bindings.png "Statistics view" + \image qml-profiler-statistics.png "Statistics view" The \uicontrol Callers and \uicontrol Callees panes show dependencies between events. They allow you to examine the internal functions of the application. @@ -549,4 +549,18 @@ JavaScript events are shown in the \uicontrol Statistics view only for applications that use Qt Quick 2 and are compiled with Qt 5.3 or later. + + \section2 Visualizing Statistics as Flame Graphs + + The \uicontrol Flamegraph view shows a more concise statistical overview + of QML and JavaScript execution. The horizontal bars show the amount of + time all invocations of a certain function took together, relative to the + total runtime of all JavaScript and QML events. The nesting shows which + functions were called by which other ones. Mind that, unlike the + \uicontrol Timeline view, the \uicontrol Flamegraph view does not show the + time spans when no QML or JavaScript is running at all. Thus, it is not + suitable for analyzing per frame execution times. However, it is very easy + to see the total impact of the various QML and JavaScript events there. + + \image qml-profiler-flamegraph.png "Flame Graph View" */ diff --git a/scripts/deployqt.py b/scripts/deployqt.py index 53220365120..64dbe426e37 100755 --- a/scripts/deployqt.py +++ b/scripts/deployqt.py @@ -89,6 +89,10 @@ def op_failed(details = None): def is_ignored_windows_file(use_debug, basepath, filename): ignore_patterns = ['.lib', '.pdb', '.exp', '.ilk'] + if use_debug: + ignore_patterns.extend(['libEGL.dll', 'libGLESv2.dll']) + else: + ignore_patterns.extend(['libEGLd.dll', 'libGLESv2d.dll']) for ip in ignore_patterns: if filename.endswith(ip): return True @@ -120,7 +124,7 @@ def copy_qt_libs(target_qt_prefix_path, qt_libs_dir, qt_plugin_dir, qt_import_di os.makedirs(lib_dest) if common.is_windows_platform(): - libraries = [lib for lib in libraries if debug_build == is_debug(lib)] + libraries = [lib for lib in libraries if not is_ignored_windows_file(debug_build, '', lib)] for library in libraries: print library, '->', lib_dest diff --git a/src/libs/3rdparty/cplusplus/Lexer.cpp b/src/libs/3rdparty/cplusplus/Lexer.cpp index db7cb9e0f83..feddf3a5d07 100644 --- a/src/libs/3rdparty/cplusplus/Lexer.cpp +++ b/src/libs/3rdparty/cplusplus/Lexer.cpp @@ -263,8 +263,8 @@ void Lexer::scan_helper(Token *tok) case '#': if (_yychar == '#') { - tok->f.kind = T_POUND_POUND; yyinp(); + tok->f.kind = T_POUND_POUND; } else { tok->f.kind = T_POUND; } @@ -336,20 +336,62 @@ void Lexer::scan_helper(Token *tok) break; case '?': - if (_yychar == '?') { + if (_yychar == '?' && f._ppMode) { yyinp(); if (_yychar == '(') { yyinp(); tok->f.kind = T_LBRACKET; + tok->f.trigraph = true; } else if (_yychar == ')') { yyinp(); tok->f.kind = T_RBRACKET; + tok->f.trigraph = true; } else if (_yychar == '<') { yyinp(); tok->f.kind = T_LBRACE; + tok->f.trigraph = true; } else if (_yychar == '>') { yyinp(); tok->f.kind = T_RBRACE; + tok->f.trigraph = true; + } else if (_yychar == '=') { + yyinp(); + tok->f.trigraph = true; + if (_yychar == '?' && *(_currentChar + 1) == '?' && *(_currentChar + 2) == '=') { + yyinp(); + yyinp(); + yyinp(); + tok->f.kind = T_POUND_POUND; + } else { + tok->f.kind = T_POUND; + } + } else if (_yychar == '\'') { + yyinp(); + if (_yychar == '=') { + yyinp(); + tok->f.kind = T_CARET_EQUAL; + } else { + tok->f.kind = T_CARET; + } + tok->f.trigraph = true; + } else if (_yychar == '!') { + yyinp(); + if (_yychar == '=') { + yyinp(); + tok->f.kind = T_PIPE_EQUAL; + } else { + tok->f.kind = T_PIPE; + } + tok->f.trigraph = true; + } else if (_yychar == '-') { + yyinp(); + if (_yychar == '=') { + yyinp(); + tok->f.kind = T_TILDE_EQUAL; + } else { + tok->f.kind = T_TILDE; + } + tok->f.trigraph = true; } } else { tok->f.kind = T_QUESTION; @@ -473,7 +515,13 @@ void Lexer::scan_helper(Token *tok) tok->f.kind = T_RBRACE; } else if (_yychar == ':') { yyinp(); - tok->f.kind = T_POUND; + if (_yychar == '%' && *(_currentChar + 1) == ':') { + yyinp(); + yyinp(); + tok->f.kind = T_POUND_POUND; + } else { + tok->f.kind = T_POUND; + } } else { tok->f.kind = T_PERCENT; } @@ -562,8 +610,12 @@ void Lexer::scan_helper(Token *tok) yyinp(); tok->f.kind = T_LESS_EQUAL; } else if (_yychar == ':') { - yyinp(); - tok->f.kind = T_LBRACKET; + if (*(_currentChar+1) != ':' || *(_currentChar+2) == ':' || *(_currentChar+2) == '>') { + yyinp(); + tok->f.kind = T_LBRACKET; + } else { + tok->f.kind = T_LESS; + } } else if (_yychar == '%') { yyinp(); tok->f.kind = T_LBRACE; diff --git a/src/libs/3rdparty/cplusplus/Lexer.h b/src/libs/3rdparty/cplusplus/Lexer.h index d47dcdf12ae..8e862ea54c4 100644 --- a/src/libs/3rdparty/cplusplus/Lexer.h +++ b/src/libs/3rdparty/cplusplus/Lexer.h @@ -125,6 +125,7 @@ private: unsigned _scanKeywords: 1; unsigned _scanAngleStringLiteralTokens: 1; unsigned _ppMode: 1; + unsigned _ignoreTrigraph : 1; }; struct State { diff --git a/src/libs/3rdparty/cplusplus/Token.h b/src/libs/3rdparty/cplusplus/Token.h index 39a74031c9e..afe732d4931 100644 --- a/src/libs/3rdparty/cplusplus/Token.h +++ b/src/libs/3rdparty/cplusplus/Token.h @@ -371,8 +371,10 @@ public: // The token is C++11 user-defined literal such as: // 12_km, 0.5_Pa, 'c'_X, "abd"_L, u16"xyz"_M unsigned userDefinedLiteral : 1; + // Indicates the token is a trigraph + unsigned trigraph : 1; // Unused... - unsigned pad : 2; + unsigned pad : 1; // The token length in bytes and UTF16 chars. unsigned bytes : 16; unsigned utf16chars : 16; diff --git a/src/libs/cplusplus/pp-engine.cpp b/src/libs/cplusplus/pp-engine.cpp index c505f94e3e0..134fb4d51c8 100644 --- a/src/libs/cplusplus/pp-engine.cpp +++ b/src/libs/cplusplus/pp-engine.cpp @@ -50,6 +50,7 @@ #include #include #include +#include #include @@ -1439,7 +1440,25 @@ void Preprocessor::preprocess(const QString &fileName, const QByteArray &source, enforceSpacing(tk, macroExpanded); // Finally output the token. - currentOutputBuffer().append(tk.tokenStart(), tk.bytes()); + if (!tk.f.trigraph) { + currentOutputBuffer().append(tk.tokenStart(), tk.bytes()); + } else { + switch (tk.kind()) { + case T_LBRACKET: currentOutputBuffer().append("["); break; + case T_RBRACKET: currentOutputBuffer().append("]"); break; + case T_LBRACE: currentOutputBuffer().append("{"); break; + case T_RBRACE: currentOutputBuffer().append("}"); break; + case T_POUND: currentOutputBuffer().append("#"); break; + case T_POUND_POUND: currentOutputBuffer().append("##"); break; + case T_CARET: currentOutputBuffer().append("^"); break; + case T_CARET_EQUAL: currentOutputBuffer().append("^="); break; + case T_PIPE: currentOutputBuffer().append("|"); break; + case T_PIPE_EQUAL: currentOutputBuffer().append("|="); break; + case T_TILDE: currentOutputBuffer().append("~"); break; + case T_TILDE_EQUAL: currentOutputBuffer().append("~="); break; + default: CPP_ASSERT(0, qDebug() << tk.spell()); break; + } + } } while (tk.isNot(T_EOF_SYMBOL)); diff --git a/src/libs/qmldebug/qmldebugclient.cpp b/src/libs/qmldebug/qmldebugclient.cpp index 40b1b3d4c13..a35fc0b3052 100644 --- a/src/libs/qmldebug/qmldebugclient.cpp +++ b/src/libs/qmldebug/qmldebugclient.cpp @@ -122,7 +122,8 @@ void QmlDebugConnection::socketConnected() { Q_D(QmlDebugConnection); QPacket pack(d->currentDataStreamVersion); - pack << serverId << 0 << protocolVersion << d->plugins.keys() << d->maximumDataStreamVersion; + pack << serverId << 0 << protocolVersion << d->plugins.keys() << d->maximumDataStreamVersion + << true; // We accept multiple messages per packet d->protocol->send(pack.data()); d->flush(); } @@ -254,14 +255,17 @@ void QmlDebugConnection::protocolReadyRead() qWarning() << "QML Debug Client: Unknown control message id" << op; } } else { - QByteArray message; - pack >> message; - QHash::Iterator iter = d->plugins.find(name); - if (iter == d->plugins.end()) + if (iter == d->plugins.end()) { qWarning() << "QML Debug Client: Message received for missing plugin" << name; - else - (*iter)->messageReceived(message); + } else { + QmlDebugClient *client = *iter; + QByteArray message; + while (!pack.atEnd()) { + pack >> message; + client->messageReceived(message); + } + } } } } diff --git a/src/libs/utils/fancymainwindow.cpp b/src/libs/utils/fancymainwindow.cpp index 30e8547a512..4fc91537da7 100644 --- a/src/libs/utils/fancymainwindow.cpp +++ b/src/libs/utils/fancymainwindow.cpp @@ -61,7 +61,6 @@ struct FancyMainWindowPrivate QAction m_menuSeparator1; QAction m_menuSeparator2; QAction m_resetLayoutAction; - QDockWidget *m_toolBarDockWidget; QAction m_autoHideTitleBars; }; @@ -336,7 +335,6 @@ FancyMainWindowPrivate::FancyMainWindowPrivate(FancyMainWindow *parent) : m_menuSeparator1(0), m_menuSeparator2(0), m_resetLayoutAction(FancyMainWindow::tr("Reset to Default Layout"), 0), - m_toolBarDockWidget(0), m_autoHideTitleBars(FancyMainWindow::tr("Automatically Hide View Title Bars"), 0) { m_menuSeparator1.setSeparator(true); @@ -552,14 +550,4 @@ void FancyMainWindow::setDockActionsVisible(bool v) d->m_resetLayoutAction.setVisible(v); } -QDockWidget *FancyMainWindow::toolBarDockWidget() const -{ - return d->m_toolBarDockWidget; -} - -void FancyMainWindow::setToolBarDockWidget(QDockWidget *dock) -{ - d->m_toolBarDockWidget = dock; -} - } // namespace Utils diff --git a/src/libs/utils/fancymainwindow.h b/src/libs/utils/fancymainwindow.h index 4a620ee5e45..1b1cbde4a1a 100644 --- a/src/libs/utils/fancymainwindow.h +++ b/src/libs/utils/fancymainwindow.h @@ -65,9 +65,6 @@ public: QAction *resetLayoutAction() const; void addDockActionsToMenu(QMenu *menu); - QDockWidget *toolBarDockWidget() const; - void setToolBarDockWidget(QDockWidget *dock); - bool autoHideTitleBars() const; signals: diff --git a/src/libs/utils/tooltip/tooltip.cpp b/src/libs/utils/tooltip/tooltip.cpp index ccdc92a764a..8947976c91b 100644 --- a/src/libs/utils/tooltip/tooltip.cpp +++ b/src/libs/utils/tooltip/tooltip.cpp @@ -48,6 +48,13 @@ ToolTip::ToolTip() : m_tip(0), m_widget(0) { connect(&m_showTimer, &QTimer::timeout, this, &ToolTip::hideTipImmediately); connect(&m_hideDelayTimer, &QTimer::timeout, this, &ToolTip::hideTipImmediately); + connect(static_cast(QGuiApplication::instance()), + &QGuiApplication::applicationStateChanged, + [this](Qt::ApplicationState state) { + if (state != Qt::ApplicationActive) + hideTipImmediately(); + } + ); } ToolTip::~ToolTip() diff --git a/src/plugins/android/androidanalyzesupport.cpp b/src/plugins/android/androidanalyzesupport.cpp index 352a5f16bd4..820e9ab00de 100644 --- a/src/plugins/android/androidanalyzesupport.cpp +++ b/src/plugins/android/androidanalyzesupport.cpp @@ -39,7 +39,7 @@ #include #include -using namespace Analyzer; +using namespace Debugger; using namespace ProjectExplorer; namespace Android { @@ -48,7 +48,7 @@ namespace Internal { RunControl *AndroidAnalyzeSupport::createAnalyzeRunControl(AndroidRunConfiguration *runConfig, Core::Id runMode) { - AnalyzerRunControl *runControl = AnalyzerManager::createRunControl(runConfig, runMode); + AnalyzerRunControl *runControl = Debugger::createAnalyzerRunControl(runConfig, runMode); QTC_ASSERT(runControl, return 0); AnalyzerConnection connection; if (runMode == ProjectExplorer::Constants::QML_PROFILER_RUN_MODE) { diff --git a/src/plugins/android/androidanalyzesupport.h b/src/plugins/android/androidanalyzesupport.h index ba4416a2d44..e272688a271 100644 --- a/src/plugins/android/androidanalyzesupport.h +++ b/src/plugins/android/androidanalyzesupport.h @@ -29,7 +29,7 @@ #include "androidrunconfiguration.h" #include -namespace Analyzer { class AnalyzerRunControl; } +namespace Debugger { class AnalyzerRunControl; } namespace ProjectExplorer { class RunControl; } namespace Android { @@ -43,7 +43,7 @@ class AndroidAnalyzeSupport : public QObject public: AndroidAnalyzeSupport(AndroidRunConfiguration *runConfig, - Analyzer::AnalyzerRunControl *runControl); + Debugger::AnalyzerRunControl *runControl); static ProjectExplorer::RunControl *createAnalyzeRunControl(AndroidRunConfiguration *runConfig, Core::Id runMode); diff --git a/src/plugins/android/androidmanifesteditorwidget.cpp b/src/plugins/android/androidmanifesteditorwidget.cpp index dd224c22c0e..de30cb46f4e 100644 --- a/src/plugins/android/androidmanifesteditorwidget.cpp +++ b/src/plugins/android/androidmanifesteditorwidget.cpp @@ -594,7 +594,8 @@ void AndroidManifestEditorWidget::postSave() if (project) { if (Target *target = project->activeTarget()) { AndroidQtSupport *androidQtSupport = AndroidManager::androidQtSupport(target); - androidQtSupport->manifestSaved(target); + if (androidQtSupport) + androidQtSupport->manifestSaved(target); } } } diff --git a/src/plugins/android/androidrunner.cpp b/src/plugins/android/androidrunner.cpp index 237e850cfb5..80c49b55646 100644 --- a/src/plugins/android/androidrunner.cpp +++ b/src/plugins/android/androidrunner.cpp @@ -249,15 +249,13 @@ static int extractPid(const QString &exeName, const QByteArray &psOutput) QByteArray AndroidRunner::runPs() { - QProcess psProc; - QStringList args = m_selector; - args << _("shell") << _("ps"); + QByteArray psLine("ps"); if (m_isBusyBox) - args << _("-w"); - - psProc.start(m_adb, args); - psProc.waitForFinished(); - return psProc.readAll(); + psLine += " -w"; + psLine += '\n'; + m_psProc.write(psLine); + m_psProc.waitForBytesWritten(psLine.size()); + return m_psProc.readAllStandardOutput(); } void AndroidRunner::checkPID() @@ -322,6 +320,7 @@ void AndroidRunner::forceStop() void AndroidRunner::start() { m_adbLogcatProcess.start(m_adb, selector() << _("logcat")); + m_psProc.start(m_adb, selector() << _("shell")); Utils::runAsync(&AndroidRunner::asyncStart, this); } @@ -551,6 +550,8 @@ void AndroidRunner::stop() //QObject::disconnect(&m_adbLogcatProcess, 0, this, 0); m_adbLogcatProcess.kill(); m_adbLogcatProcess.waitForFinished(); + m_psProc.kill(); + m_psProc.waitForFinished(); foreach (const QStringList &entry, m_androidRunnable.afterFinishADBCommands) { QProcess adb; adb.start(m_adb, selector() << entry); diff --git a/src/plugins/android/androidrunner.h b/src/plugins/android/androidrunner.h index 84ae0c69ee3..32f7418ad9e 100644 --- a/src/plugins/android/androidrunner.h +++ b/src/plugins/android/androidrunner.h @@ -92,6 +92,7 @@ private: private: QProcess m_adbLogcatProcess; + QProcess m_psProc; QTimer m_checkPIDTimer; bool m_wasStarted; int m_tries; diff --git a/src/plugins/autotest/testcodeparser.cpp b/src/plugins/autotest/testcodeparser.cpp index 76e5037ef63..2b0f921577d 100644 --- a/src/plugins/autotest/testcodeparser.cpp +++ b/src/plugins/autotest/testcodeparser.cpp @@ -259,7 +259,7 @@ static bool qtTestLibDefined(const CppTools::CppModelManager *cppMM, { const QList parts = cppMM->projectPart(fileName); if (parts.size() > 0) - return parts.at(0)->projectDefines.contains("#define QT_TESTLIB_LIB 1"); + return parts.at(0)->projectDefines.contains("#define QT_TESTLIB_LIB"); return false; } diff --git a/src/plugins/autotest/testconfiguration.cpp b/src/plugins/autotest/testconfiguration.cpp index ffacd05d1af..ba4597b36dc 100644 --- a/src/plugins/autotest/testconfiguration.cpp +++ b/src/plugins/autotest/testconfiguration.cpp @@ -69,11 +69,20 @@ void completeBasicProjectInformation(Project *project, const QString &proFile, Q CppTools::CppModelManager *cppMM = CppTools::CppModelManager::instance(); QList projParts = cppMM->projectInfo(project).projectParts(); - foreach (const CppTools::ProjectPart::Ptr &part, projParts) { - if (part->projectFile == proFile) { - *displayName = part->displayName; - *targetProject = part->project; - return; + if (displayName->isEmpty()) { + foreach (const CppTools::ProjectPart::Ptr &part, projParts) { + if (part->projectFile == proFile) { + *displayName = part->displayName; + *targetProject = part->project; + return; + } + } + } else { // for CMake based projects we've got the displayname already + foreach (const CppTools::ProjectPart::Ptr &part, projParts) { + if (part->displayName == *displayName) { + *targetProject = part->project; + return; + } } } } @@ -96,7 +105,7 @@ void TestConfiguration::completeTestInformation() QString targetFile; QString targetName; QString workDir; - QString displayName; + QString displayName = m_displayName; QString buildDir; Project *targetProject = 0; Utils::Environment env; @@ -111,12 +120,23 @@ void TestConfiguration::completeTestInformation() return; BuildTargetInfoList appTargets = target->applicationTargets(); - foreach (const BuildTargetInfo &bti, appTargets.list) { - // some project manager store line/column information as well inside ProjectPart - if (bti.isValid() && m_proFile.startsWith(bti.projectFilePath.toString())) { - targetFile = Utils::HostOsInfo::withExecutableSuffix(bti.targetFilePath.toString()); - targetName = bti.targetName; - break; + if (m_displayName.isEmpty()) { + foreach (const BuildTargetInfo &bti, appTargets.list) { + // some project manager store line/column information as well inside ProjectPart + if (bti.isValid() && m_proFile.startsWith(bti.projectFilePath.toString())) { + targetFile = Utils::HostOsInfo::withExecutableSuffix(bti.targetFilePath.toString()); + targetName = bti.targetName; + break; + } + } + } else { // CMake based projects have no specific pro file, but target name matches displayname + foreach (const BuildTargetInfo &bti, appTargets.list) { + if (bti.isValid() && m_displayName == bti.targetName) { + // for CMake base projects targetFilePath has executable suffix already + targetFile = bti.targetFilePath.toString(); + targetName = m_displayName; + break; + } } } diff --git a/src/plugins/autotest/testtreemodel.cpp b/src/plugins/autotest/testtreemodel.cpp index 0d00fdc7c45..9425581e703 100644 --- a/src/plugins/autotest/testtreemodel.cpp +++ b/src/plugins/autotest/testtreemodel.cpp @@ -31,6 +31,7 @@ #include "testtreemodel.h" #include +#include #include #include @@ -189,6 +190,48 @@ bool TestTreeModel::hasTests() const || m_googleTestRootItem->childCount() > 0; } +static QString getCMakeDisplayNameIfNecessary(const QString &filePath, const QString &proFile) +{ + static const QString CMAKE_LISTS = QLatin1String("CMakeLists.txt"); + if (!proFile.endsWith(CMAKE_LISTS)) + return QString(); + + const QList &projectParts + = CppTools::CppModelManager::instance()->projectPart(filePath); + if (projectParts.size()) + return projectParts.first()->displayName; + + return QString(); +} + +// used as key inside getAllTestCases()/getSelectedTestCases() for Google Tests +class ProFileWithDisplayName +{ +public: + ProFileWithDisplayName(const QString &file, const QString &name) + : proFile(file), displayName(name) {} + QString proFile; + QString displayName; + + bool operator==(const ProFileWithDisplayName &rhs) const + { + return proFile == rhs.proFile && displayName == rhs.displayName; + } +}; + +// needed as ProFileWithDisplayName is used as key inside a QHash +bool operator<(const ProFileWithDisplayName &lhs, const ProFileWithDisplayName &rhs) +{ + return lhs.proFile == rhs.proFile ? lhs.displayName < rhs.displayName + : lhs.proFile < rhs.proFile; +} + +// needed as ProFileWithDisplayName is used as a key inside a QHash +uint qHash(const ProFileWithDisplayName &lhs) +{ + return ::qHash(lhs.proFile) ^ ::qHash(lhs.displayName); +} + QList TestTreeModel::getAllTestCases() const { QList result; @@ -205,6 +248,7 @@ QList TestTreeModel::getAllTestCases() const child->childCount()); tc->setProFile(child->proFile()); tc->setProject(project); + tc->setDisplayName(getCMakeDisplayNameIfNecessary(child->filePath(), child->proFile())); result << tc; } @@ -237,20 +281,32 @@ QList TestTreeModel::getAllTestCases() const foundProFiles.clear(); // get all Google Tests + QHash proFilesWithTestSets; for (int row = 0, count = m_googleTestRootItem->childCount(); row < count; ++row) { - const TestTreeItem *child = m_googleTestRootItem->childItem(row); - for (int childRow = 0, childCount = child->childCount(); childRow < childCount; ++childRow) { - const QString &proFilePath = child->childItem(childRow)->proFile(); - foundProFiles.insert(proFilePath, foundProFiles[proFilePath] + 1); + const GoogleTestTreeItem *child = m_googleTestRootItem->childItem(row)->asGoogleTestTreeItem(); + + const int grandChildCount = child->childCount(); + for (int grandChildRow = 0; grandChildRow < grandChildCount; ++grandChildRow) { + const TestTreeItem *grandChild = child->childItem(grandChildRow); + if (grandChild->checked() == Qt::Checked) { + ProFileWithDisplayName key(grandChild->proFile(), + getCMakeDisplayNameIfNecessary(grandChild->filePath(), + grandChild->proFile())); + + proFilesWithTestSets.insert(key, proFilesWithTestSets[key] + 1); + } } } - foreach (const QString &proFile, foundProFiles.keys()) { - TestConfiguration *tc = new TestConfiguration(QString(), QStringList(), - foundProFiles.value(proFile)); - tc->setProFile(proFile); - tc->setProject(project); + QHash::Iterator it = proFilesWithTestSets.begin(); + QHash::Iterator end = proFilesWithTestSets.end(); + for ( ; it != end; ++it) { + const ProFileWithDisplayName &key = it.key(); + TestConfiguration *tc = new TestConfiguration(QString(), QStringList(), it.value()); tc->setTestType(TestTypeGTest); + tc->setProFile(key.proFile); + tc->setDisplayName(key.displayName); + tc->setProject(project); result << tc; } @@ -287,6 +343,8 @@ QList TestTreeModel::getSelectedTests() const testConfiguration = new TestConfiguration(child->name(), QStringList(), child->childCount()); testConfiguration->setProFile(child->proFile()); testConfiguration->setProject(project); + testConfiguration->setDisplayName(getCMakeDisplayNameIfNecessary(child->filePath(), + child->proFile())); result << testConfiguration; continue; case Qt::PartiallyChecked: @@ -303,6 +361,8 @@ QList TestTreeModel::getSelectedTests() const testConfiguration = new TestConfiguration(childName, testCases); testConfiguration->setProFile(child->proFile()); testConfiguration->setProject(project); + testConfiguration->setDisplayName(getCMakeDisplayNameIfNecessary(child->filePath(), + child->proFile())); result << testConfiguration; } } @@ -385,29 +445,34 @@ QList TestTreeModel::getSelectedTests() const } // get selected Google Tests - QMap proFilesWithEnabledTestSets; - + QHash proFilesWithCheckedTestSets; for (int row = 0, count = m_googleTestRootItem->childCount(); row < count; ++row) { const auto child = m_googleTestRootItem->childItem(row)->asGoogleTestTreeItem(); - if (child->checked() == Qt::Unchecked) // add this test name to disabled list ? + if (child->checked() == Qt::Unchecked) continue; int grandChildCount = child->childCount(); for (int grandChildRow = 0; grandChildRow < grandChildCount; ++grandChildRow) { const TestTreeItem *grandChild = child->childItem(grandChildRow); - const QString &proFile = grandChild->proFile(); if (grandChild->checked() == Qt::Checked) { - proFilesWithEnabledTestSets[proFile].append( + ProFileWithDisplayName key(grandChild->proFile(), + getCMakeDisplayNameIfNecessary(grandChild->filePath(), + grandChild->proFile())); + + proFilesWithCheckedTestSets[key].append( gtestFilter(child->state()).arg(child->name()).arg(grandChild->name())); } } } - foreach (const QString &proFile, proFilesWithEnabledTestSets.keys()) { - TestConfiguration *tc = new TestConfiguration(QString(), - proFilesWithEnabledTestSets.value(proFile)); + QHash::Iterator it = proFilesWithCheckedTestSets.begin(); + QHash::Iterator end = proFilesWithCheckedTestSets.end(); + for ( ; it != end; ++it) { + const ProFileWithDisplayName &key = it.key(); + TestConfiguration *tc = new TestConfiguration(QString(), it.value()); tc->setTestType(TestTypeGTest); - tc->setProFile(proFile); + tc->setProFile(key.proFile); + tc->setDisplayName(key.displayName); tc->setProject(project); result << tc; } @@ -439,6 +504,8 @@ TestConfiguration *TestTreeModel::getTestConfiguration(const TestTreeItem *item) config = new TestConfiguration(item->name(), QStringList(), item->childCount()); config->setProFile(item->proFile()); config->setProject(project); + config->setDisplayName(getCMakeDisplayNameIfNecessary(item->filePath(), + item->proFile())); } else if (auto gtestItem = item->asGoogleTestTreeItem()) { const QString &testSpecifier = gtestFilter(gtestItem->state()).arg(item->name()).arg(QLatin1Char('*')); @@ -448,6 +515,9 @@ TestConfiguration *TestTreeModel::getTestConfiguration(const TestTreeItem *item) config->setTestCaseCount(childCount); config->setProFile(item->proFile()); config->setProject(project); + // item has no filePath set - so take it of the first children + config->setDisplayName(getCMakeDisplayNameIfNecessary( + item->childItem(0)->filePath(), item->proFile())); config->setTestType(TestTypeGTest); } } @@ -466,6 +536,8 @@ TestConfiguration *TestTreeModel::getTestConfiguration(const TestTreeItem *item) config = new TestConfiguration(parent->name(), QStringList() << item->name()); config->setProFile(parent->proFile()); config->setProject(project); + config->setDisplayName(getCMakeDisplayNameIfNecessary(item->filePath(), + parent->proFile())); } else if (auto gtestParent = parent->asGoogleTestTreeItem()) { const QString &testSpecifier = gtestFilter(gtestParent->state()).arg(parent->name()).arg(item->name()); @@ -473,6 +545,8 @@ TestConfiguration *TestTreeModel::getTestConfiguration(const TestTreeItem *item) config = new TestConfiguration(QString(), QStringList(testSpecifier)); config->setProFile(item->proFile()); config->setProject(project); + config->setDisplayName(getCMakeDisplayNameIfNecessary(item->filePath(), + parent->proFile())); config->setTestType(TestTypeGTest); } break; @@ -486,6 +560,7 @@ TestConfiguration *TestTreeModel::getTestConfiguration(const TestTreeItem *item) config = new TestConfiguration(parent->name(), QStringList() << functionWithTag); config->setProFile(parent->proFile()); config->setProject(project); + config->setDisplayName(getCMakeDisplayNameIfNecessary(item->filePath(), parent->proFile())); break; } // not supported items diff --git a/src/plugins/autotest/unit_test/mixed_atp/tests/auto/quickauto/quickauto.qbs b/src/plugins/autotest/unit_test/mixed_atp/tests/auto/quickauto/quickauto.qbs index 1697cd51a29..3350943ee77 100644 --- a/src/plugins/autotest/unit_test/mixed_atp/tests/auto/quickauto/quickauto.qbs +++ b/src/plugins/autotest/unit_test/mixed_atp/tests/auto/quickauto/quickauto.qbs @@ -20,7 +20,6 @@ CppApplication { Group { name: "qml test files" - qbs.install: true files: [ "tst_test1.qml", "tst_test2.qml", "TestDummy.qml", diff --git a/src/plugins/autotest/unit_test/mixed_atp/tests/auto/quickauto2/quickauto2.qbs b/src/plugins/autotest/unit_test/mixed_atp/tests/auto/quickauto2/quickauto2.qbs index a5fe65fbd65..63a97fb7b7c 100644 --- a/src/plugins/autotest/unit_test/mixed_atp/tests/auto/quickauto2/quickauto2.qbs +++ b/src/plugins/autotest/unit_test/mixed_atp/tests/auto/quickauto2/quickauto2.qbs @@ -19,7 +19,6 @@ CppApplication { Group { name: "qml test files" - qbs.install: true files: [ "tst_test1.qml", "tst_test2.qml" ] } diff --git a/src/plugins/baremetal/baremetalruncontrolfactory.cpp b/src/plugins/baremetal/baremetalruncontrolfactory.cpp index 0221fab3ad4..b9b49286db3 100644 --- a/src/plugins/baremetal/baremetalruncontrolfactory.cpp +++ b/src/plugins/baremetal/baremetalruncontrolfactory.cpp @@ -50,7 +50,6 @@ #include -using namespace Analyzer; using namespace Debugger; using namespace ProjectExplorer; diff --git a/src/plugins/bineditor/bineditor.cpp b/src/plugins/bineditor/bineditor.cpp index 41d4155f46c..ef3f2b31c4d 100644 --- a/src/plugins/bineditor/bineditor.cpp +++ b/src/plugins/bineditor/bineditor.cpp @@ -376,6 +376,7 @@ bool BinEditorWidget::save(QString *errorString, const QString &oldFileName, con void BinEditorWidget::setSizes(quint64 startAddr, int range, int blockSize) { int newBlockSize = blockSize; + QTC_ASSERT(blockSize, return); QTC_ASSERT((blockSize/m_bytesPerLine) * m_bytesPerLine == blockSize, blockSize = (blockSize/m_bytesPerLine + 1) * m_bytesPerLine); // Users can edit data in the range diff --git a/src/plugins/bineditor/bineditorplugin.cpp b/src/plugins/bineditor/bineditorplugin.cpp index 1d686b5912d..cce44ebebeb 100644 --- a/src/plugins/bineditor/bineditorplugin.cpp +++ b/src/plugins/bineditor/bineditorplugin.cpp @@ -243,8 +243,10 @@ public: bool setContents(const QByteArray &contents) override { m_widget->clear(); - m_widget->setSizes(0, contents.length(), contents.length()); - m_widget->addData(0, contents); + if (!contents.isEmpty()) { + m_widget->setSizes(0, contents.length(), contents.length()); + m_widget->addData(0, contents); + } return true; } diff --git a/src/plugins/clangstaticanalyzer/clangstaticanalyzerdiagnostic.h b/src/plugins/clangstaticanalyzer/clangstaticanalyzerdiagnostic.h index ecb5e8e94e4..708b5137f59 100644 --- a/src/plugins/clangstaticanalyzer/clangstaticanalyzerdiagnostic.h +++ b/src/plugins/clangstaticanalyzer/clangstaticanalyzerdiagnostic.h @@ -44,8 +44,8 @@ public: QString message; QString extendedMessage; - Analyzer::DiagnosticLocation location; - QList ranges; + Debugger::DiagnosticLocation location; + QList ranges; int depth; }; @@ -59,7 +59,7 @@ public: QString type; QString issueContextKind; QString issueContext; - Analyzer::DiagnosticLocation location; + Debugger::DiagnosticLocation location; QList explainingSteps; }; diff --git a/src/plugins/clangstaticanalyzer/clangstaticanalyzerdiagnosticmodel.cpp b/src/plugins/clangstaticanalyzer/clangstaticanalyzerdiagnosticmodel.cpp index fa0625891a3..49b904a812c 100644 --- a/src/plugins/clangstaticanalyzer/clangstaticanalyzerdiagnosticmodel.cpp +++ b/src/plugins/clangstaticanalyzer/clangstaticanalyzerdiagnosticmodel.cpp @@ -168,7 +168,7 @@ static QString createExplainingStepToolTipString(const ExplainingStep &step) return html; } -static QString createLocationString(const Analyzer::DiagnosticLocation &location) +static QString createLocationString(const Debugger::DiagnosticLocation &location) { const QString filePath = location.filePath; const QString lineNumber = QString::number(location.line); @@ -224,10 +224,10 @@ DiagnosticItem::DiagnosticItem(const Diagnostic &diag) : m_diagnostic(diag) appendChild(new ExplainingStepItem(s)); } -QVariant locationData(int role, const Analyzer::DiagnosticLocation &location) +QVariant locationData(int role, const Debugger::DiagnosticLocation &location) { switch (role) { - case Analyzer::DetailedErrorView::LocationRole: + case Debugger::DetailedErrorView::LocationRole: return QVariant::fromValue(location); case Qt::ToolTipRole: return location.filePath.isEmpty() ? QVariant() : QVariant(location.filePath); @@ -238,12 +238,12 @@ QVariant locationData(int role, const Analyzer::DiagnosticLocation &location) QVariant DiagnosticItem::data(int column, int role) const { - if (column == Analyzer::DetailedErrorView::LocationColumn) + if (column == Debugger::DetailedErrorView::LocationColumn) return locationData(role, m_diagnostic.location); // DiagnosticColumn switch (role) { - case Analyzer::DetailedErrorView::FullTextRole: + case Debugger::DetailedErrorView::FullTextRole: return fullText(m_diagnostic); case ClangStaticAnalyzerDiagnosticModel::DiagnosticRole: return QVariant::fromValue(m_diagnostic); @@ -262,12 +262,12 @@ ExplainingStepItem::ExplainingStepItem(const ExplainingStep &step) : m_step(step QVariant ExplainingStepItem::data(int column, int role) const { - if (column == Analyzer::DetailedErrorView::LocationColumn) + if (column == Debugger::DetailedErrorView::LocationColumn) return locationData(role, m_step.location); // DiagnosticColumn switch (role) { - case Analyzer::DetailedErrorView::FullTextRole: + case Debugger::DetailedErrorView::FullTextRole: return fullText(static_cast(parent())->diagnostic()); case ClangStaticAnalyzerDiagnosticModel::DiagnosticRole: return QVariant::fromValue(static_cast(parent())->diagnostic()); diff --git a/src/plugins/clangstaticanalyzer/clangstaticanalyzerdiagnosticmodel.h b/src/plugins/clangstaticanalyzer/clangstaticanalyzerdiagnosticmodel.h index 437e83ce402..e8a30f34efe 100644 --- a/src/plugins/clangstaticanalyzer/clangstaticanalyzerdiagnosticmodel.h +++ b/src/plugins/clangstaticanalyzer/clangstaticanalyzerdiagnosticmodel.h @@ -52,7 +52,7 @@ public: QList diagnostics() const; enum ItemRole { - DiagnosticRole = Analyzer::DetailedErrorView::FullTextRole + 1 + DiagnosticRole = Debugger::DetailedErrorView::FullTextRole + 1 }; }; diff --git a/src/plugins/clangstaticanalyzer/clangstaticanalyzerdiagnosticview.cpp b/src/plugins/clangstaticanalyzer/clangstaticanalyzerdiagnosticview.cpp index 69fb87a3bb5..fdd3a7aef59 100644 --- a/src/plugins/clangstaticanalyzer/clangstaticanalyzerdiagnosticview.cpp +++ b/src/plugins/clangstaticanalyzer/clangstaticanalyzerdiagnosticview.cpp @@ -36,13 +36,13 @@ #include #include -using namespace Analyzer; +using namespace Debugger; namespace ClangStaticAnalyzer { namespace Internal { ClangStaticAnalyzerDiagnosticView::ClangStaticAnalyzerDiagnosticView(QWidget *parent) - : Analyzer::DetailedErrorView(parent) + : Debugger::DetailedErrorView(parent) { m_suppressAction = new QAction(tr("Suppress this diagnostic"), this); connect(m_suppressAction, &QAction::triggered, [this](bool) { suppressCurrentDiagnostic(); }); diff --git a/src/plugins/clangstaticanalyzer/clangstaticanalyzerdiagnosticview.h b/src/plugins/clangstaticanalyzer/clangstaticanalyzerdiagnosticview.h index 0d5016fd7c4..55ba24642cf 100644 --- a/src/plugins/clangstaticanalyzer/clangstaticanalyzerdiagnosticview.h +++ b/src/plugins/clangstaticanalyzer/clangstaticanalyzerdiagnosticview.h @@ -31,7 +31,7 @@ namespace ClangStaticAnalyzer { namespace Internal { -class ClangStaticAnalyzerDiagnosticView : public Analyzer::DetailedErrorView +class ClangStaticAnalyzerDiagnosticView : public Debugger::DetailedErrorView { Q_OBJECT diff --git a/src/plugins/clangstaticanalyzer/clangstaticanalyzerlogfilereader.cpp b/src/plugins/clangstaticanalyzer/clangstaticanalyzerlogfilereader.cpp index dd0727864fc..f66ce2a545b 100644 --- a/src/plugins/clangstaticanalyzer/clangstaticanalyzerlogfilereader.cpp +++ b/src/plugins/clangstaticanalyzer/clangstaticanalyzerlogfilereader.cpp @@ -55,8 +55,8 @@ private: void readDiagnosticsDict(); QList readPathArray(); ExplainingStep readPathDict(); - Analyzer::DiagnosticLocation readLocationDict(bool elementIsRead = false); - QList readRangesArray(); + Debugger::DiagnosticLocation readLocationDict(bool elementIsRead = false); + QList readRangesArray(); QString readString(); QStringList readStringArray(); @@ -284,9 +284,9 @@ ExplainingStep ClangStaticAnalyzerLogFileReader::readPathDict() return explainingStep; } -Analyzer::DiagnosticLocation ClangStaticAnalyzerLogFileReader::readLocationDict(bool elementIsRead) +Debugger::DiagnosticLocation ClangStaticAnalyzerLogFileReader::readLocationDict(bool elementIsRead) { - Analyzer::DiagnosticLocation location; + Debugger::DiagnosticLocation location; if (elementIsRead) { QTC_ASSERT(m_xml.isStartElement() && m_xml.name() == QLatin1String("dict"), return location); @@ -317,14 +317,14 @@ Analyzer::DiagnosticLocation ClangStaticAnalyzerLogFileReader::readLocationDict( if (lineOk && columnOk && fileIndexOk) { QTC_ASSERT(fileIndex < m_referencedFiles.size(), return location); - location = Analyzer::DiagnosticLocation(m_referencedFiles.at(fileIndex), line, column); + location = Debugger::DiagnosticLocation(m_referencedFiles.at(fileIndex), line, column); } return location; } -QList ClangStaticAnalyzerLogFileReader::readRangesArray() +QList ClangStaticAnalyzerLogFileReader::readRangesArray() { - QList result; + QList result; // It's an array of arrays... QTC_ASSERT(m_xml.readNextStartElement() && m_xml.name() == QLatin1String("array"), diff --git a/src/plugins/clangstaticanalyzer/clangstaticanalyzerplugin.cpp b/src/plugins/clangstaticanalyzer/clangstaticanalyzerplugin.cpp index 28146c0acdd..0ab5c15e000 100644 --- a/src/plugins/clangstaticanalyzer/clangstaticanalyzerplugin.cpp +++ b/src/plugins/clangstaticanalyzer/clangstaticanalyzerplugin.cpp @@ -53,7 +53,7 @@ #include -using namespace Analyzer; +using namespace Debugger; namespace ClangStaticAnalyzer { namespace Internal { @@ -122,36 +122,10 @@ bool ClangStaticAnalyzerPlugin::initialize(const QStringList &arguments, QString panelFactory->setSimpleCreateWidgetFunction(QIcon()); ProjectExplorer::ProjectPanelFactory::registerFactory(panelFactory); - auto tool = m_analyzerTool = new ClangStaticAnalyzerTool(this); + m_analyzerTool = new ClangStaticAnalyzerTool(this); addAutoReleasedObject(new ClangStaticAnalyzerRunControlFactory(m_analyzerTool)); addAutoReleasedObject(new ClangStaticAnalyzerOptionsPage); - AnalyzerManager::registerToolbar(ClangStaticAnalyzerPerspectiveId, tool->createWidgets()); - - auto runControlCreator = [tool](ProjectExplorer::RunConfiguration *runConfiguration, - Core::Id runMode) { - return tool->createRunControl(runConfiguration, runMode); - }; - - const QString toolTip = tr("Clang Static Analyzer uses the analyzer from the clang project " - "to find bugs."); - - AnalyzerManager::registerPerspective(ClangStaticAnalyzerPerspectiveId, { - { ClangStaticAnalyzerDockId, Core::Id(), Perspective::SplitVertical } - }); - - ActionDescription desc; - desc.setText(tr("Clang Static Analyzer")); - desc.setToolTip(toolTip); - desc.setRunMode(Constants::CLANGSTATICANALYZER_RUN_MODE); - desc.setPerspectiveId(ClangStaticAnalyzerPerspectiveId); - desc.setRunControlCreator(runControlCreator); - desc.setCustomToolStarter([tool](ProjectExplorer::RunConfiguration *rc) { - tool->startTool(rc); - }); - desc.setMenuGroup(Analyzer::Constants::G_ANALYZER_TOOLS); - AnalyzerManager::registerAction(ClangStaticAnalyzerActionId, desc); - return true; } diff --git a/src/plugins/clangstaticanalyzer/clangstaticanalyzerruncontrol.cpp b/src/plugins/clangstaticanalyzer/clangstaticanalyzerruncontrol.cpp index 5d4c1e3194d..e16c7a46c16 100644 --- a/src/plugins/clangstaticanalyzer/clangstaticanalyzerruncontrol.cpp +++ b/src/plugins/clangstaticanalyzer/clangstaticanalyzerruncontrol.cpp @@ -304,12 +304,12 @@ static Core::Id toolchainType(ProjectExplorer::RunConfiguration *runConfiguratio return ToolChainKitInformation::toolChain(runConfiguration->target()->kit())->typeId(); } -bool ClangStaticAnalyzerRunControl::startEngine() +void ClangStaticAnalyzerRunControl::start() { m_success = false; emit starting(); - QTC_ASSERT(m_projectInfo.isValid(), emit finished(); return false); + QTC_ASSERT(m_projectInfo.isValid(), emit finished(); return); const Utils::FileName projectFile = m_projectInfo.project()->projectFilePath(); appendMessage(tr("Running Clang Static Analyzer on %1").arg(projectFile.toUserOutput()) + QLatin1Char('\n'), Utils::NormalMessageFormat); @@ -324,7 +324,7 @@ bool ClangStaticAnalyzerRunControl::startEngine() appendMessage(errorMessage + QLatin1Char('\n'), Utils::ErrorMessageFormat); AnalyzerUtils::logToIssuesPane(Task::Error, errorMessage); emit finished(); - return false; + return; } m_clangExecutable = executable; @@ -337,7 +337,7 @@ bool ClangStaticAnalyzerRunControl::startEngine() appendMessage(errorMessage + QLatin1Char('\n'), Utils::ErrorMessageFormat); AnalyzerUtils::logToIssuesPane(Task::Error, errorMessage); emit finished(); - return false; + return; } m_clangLogFileDir = temporaryDir.path(); @@ -364,19 +364,22 @@ bool ClangStaticAnalyzerRunControl::startEngine() qCDebug(LOG) << "Environment:" << m_environment; m_runners.clear(); const int parallelRuns = ClangStaticAnalyzerSettings::instance()->simultaneousProcesses(); - QTC_ASSERT(parallelRuns >= 1, emit finished(); return false); + QTC_ASSERT(parallelRuns >= 1, emit finished(); return); m_success = true; + m_running = true; if (m_unitsToProcess.isEmpty()) { finalize(); - return false; + return; } + + emit started(); + while (m_runners.size() < parallelRuns && !m_unitsToProcess.isEmpty()) analyzeNextFile(); - return true; } -void ClangStaticAnalyzerRunControl::stopEngine() +RunControl::StopResult ClangStaticAnalyzerRunControl::stop() { QSetIterator i(m_runners); while (i.hasNext()) { @@ -389,7 +392,14 @@ void ClangStaticAnalyzerRunControl::stopEngine() appendMessage(tr("Clang Static Analyzer stopped by user.") + QLatin1Char('\n'), Utils::NormalMessageFormat); m_progress.reportFinished(); + m_running = false; emit finished(); + return RunControl::StoppedSynchronously; +} + +bool ClangStaticAnalyzerRunControl::isRunning() const +{ + return m_running; } void ClangStaticAnalyzerRunControl::analyzeNextFile() @@ -479,7 +489,6 @@ void ClangStaticAnalyzerRunControl::handleFinished() void ClangStaticAnalyzerRunControl::onProgressCanceled() { - Analyzer::AnalyzerManager::stopTool(); m_progress.reportCanceled(); m_progress.reportFinished(); } @@ -504,6 +513,7 @@ void ClangStaticAnalyzerRunControl::finalize() } m_progress.reportFinished(); + m_running = false; emit finished(); } diff --git a/src/plugins/clangstaticanalyzer/clangstaticanalyzerruncontrol.h b/src/plugins/clangstaticanalyzer/clangstaticanalyzerruncontrol.h index 84ad1ae9fce..0293f4d3b19 100644 --- a/src/plugins/clangstaticanalyzer/clangstaticanalyzerruncontrol.h +++ b/src/plugins/clangstaticanalyzer/clangstaticanalyzerruncontrol.h @@ -48,7 +48,7 @@ struct AnalyzeUnit { }; typedef QList AnalyzeUnits; -class ClangStaticAnalyzerRunControl : public Analyzer::AnalyzerRunControl +class ClangStaticAnalyzerRunControl : public Debugger::AnalyzerRunControl { Q_OBJECT @@ -57,8 +57,9 @@ public: Core::Id runMode, const CppTools::ProjectInfo &projectInfo); - bool startEngine() override; - void stopEngine() override; + void start() override; + StopResult stop() override; + bool isRunning() const override; bool success() const { return m_success; } // For testing. @@ -93,6 +94,7 @@ private: int m_filesAnalyzed; int m_filesNotAnalyzed; bool m_success; + bool m_running = false; }; } // namespace Internal diff --git a/src/plugins/clangstaticanalyzer/clangstaticanalyzerruncontrolfactory.cpp b/src/plugins/clangstaticanalyzer/clangstaticanalyzerruncontrolfactory.cpp index a179e2fa1fe..017a87cefdd 100644 --- a/src/plugins/clangstaticanalyzer/clangstaticanalyzerruncontrolfactory.cpp +++ b/src/plugins/clangstaticanalyzer/clangstaticanalyzerruncontrolfactory.cpp @@ -47,7 +47,7 @@ #include -using namespace Analyzer; +using namespace Debugger; using namespace ProjectExplorer; namespace ClangStaticAnalyzer { @@ -115,7 +115,7 @@ RunControl *ClangStaticAnalyzerRunControlFactory::create(RunConfiguration *runCo return 0; } - return AnalyzerManager::createRunControl(runConfiguration, runMode); + return Debugger::createAnalyzerRunControl(runConfiguration, runMode); } } // namespace Internal diff --git a/src/plugins/clangstaticanalyzer/clangstaticanalyzertool.cpp b/src/plugins/clangstaticanalyzer/clangstaticanalyzertool.cpp index 93a18a1d3ff..994b507f700 100644 --- a/src/plugins/clangstaticanalyzer/clangstaticanalyzertool.cpp +++ b/src/plugins/clangstaticanalyzer/clangstaticanalyzertool.cpp @@ -53,8 +53,9 @@ #include #include -using namespace Analyzer; +using namespace Debugger; using namespace ProjectExplorer; +using namespace Utils; namespace ClangStaticAnalyzer { namespace Internal { @@ -69,14 +70,6 @@ ClangStaticAnalyzerTool::ClangStaticAnalyzerTool(QObject *parent) , m_running(false) { setObjectName(QLatin1String("ClangStaticAnalyzerTool")); -} - -QWidget *ClangStaticAnalyzerTool::createWidgets() -{ - QTC_ASSERT(!m_diagnosticView, return 0); - QTC_ASSERT(!m_diagnosticModel, return 0); - QTC_ASSERT(!m_goBack, return 0); - QTC_ASSERT(!m_goNext, return 0); // // Diagnostic View @@ -104,27 +97,19 @@ QWidget *ClangStaticAnalyzerTool::createWidgets() this, &ClangStaticAnalyzerTool::handleStateUpdate); } - AnalyzerManager::registerDockWidget(ClangStaticAnalyzerDockId, m_diagnosticView); - // // Toolbar widget // - QHBoxLayout *layout = new QHBoxLayout; - layout->setMargin(0); - layout->setSpacing(0); - QAction *action = 0; - QToolButton *button = 0; + m_startAction = Debugger::createStartAction(); + m_stopAction = Debugger::createStopAction(); // Go to previous diagnostic - action = new QAction(this); + auto action = new QAction(this); action->setDisabled(true); action->setIcon(Core::Icons::PREV.icon()); action->setToolTip(tr("Go to previous bug.")); connect(action, &QAction::triggered, m_diagnosticView, &DetailedErrorView::goBack); - button = new QToolButton; - button->setDefaultAction(action); - layout->addWidget(button); m_goBack = action; // Go to next diagnostic @@ -133,17 +118,41 @@ QWidget *ClangStaticAnalyzerTool::createWidgets() action->setIcon(Core::Icons::NEXT.icon()); action->setToolTip(tr("Go to next bug.")); connect(action, &QAction::triggered, m_diagnosticView, &DetailedErrorView::goNext); - button = new QToolButton; - button->setDefaultAction(action); - layout->addWidget(button); m_goNext = action; - layout->addStretch(); + const QString toolTip = tr("Clang Static Analyzer uses the analyzer from the clang project " + "to find bugs."); - QWidget *toolbarWidget = new QWidget; - toolbarWidget->setObjectName(QLatin1String("ClangStaticAnalyzerToolBarWidget")); - toolbarWidget->setLayout(layout); - return toolbarWidget; + Debugger::registerPerspective(ClangStaticAnalyzerPerspectiveId, { + tr("Clang Static Analyzer"), + {{ ClangStaticAnalyzerDockId, m_diagnosticView, {}, Perspective::SplitVertical }} + }); + + ActionDescription desc; + desc.setText(tr("Clang Static Analyzer")); + desc.setToolTip(toolTip); + desc.setRunMode(Constants::CLANGSTATICANALYZER_RUN_MODE); + desc.setPerspectiveId(ClangStaticAnalyzerPerspectiveId); + desc.setRunControlCreator([this](RunConfiguration *runConfiguration, Core::Id runMode) { + return createRunControl(runConfiguration, runMode); + }); + desc.setCustomToolStarter([this](RunConfiguration *runConfiguration) { + startTool(runConfiguration); + }); + desc.setMenuGroup(Debugger::Constants::G_ANALYZER_TOOLS); + Debugger::registerAction(ClangStaticAnalyzerActionId, desc, m_startAction); + + ToolbarDescription toolbar; + toolbar.addAction(m_startAction); + toolbar.addAction(m_stopAction); + toolbar.addAction(m_goBack); + toolbar.addAction(m_goNext); + Debugger::registerToolbar(ClangStaticAnalyzerPerspectiveId, toolbar); + + updateRunActions(); + + connect(ProjectExplorerPlugin::instance(), &ProjectExplorerPlugin::updateRunActions, + this, &ClangStaticAnalyzerTool::updateRunActions); } AnalyzerRunControl *ClangStaticAnalyzerTool::createRunControl(RunConfiguration *runConfiguration, @@ -171,6 +180,11 @@ AnalyzerRunControl *ClangStaticAnalyzerTool::createRunControl(RunConfiguration * this, &ClangStaticAnalyzerTool::onNewDiagnosticsAvailable); connect(runControl, &ClangStaticAnalyzerRunControl::finished, this, &ClangStaticAnalyzerTool::onEngineFinished); + + connect(m_stopAction, &QAction::triggered, runControl, [runControl] { runControl->stop(); }); + + m_toolBusy = true; + updateRunActions(); return runControl; } @@ -208,8 +222,6 @@ static bool dontStartAfterHintForDebugMode(Project *project) void ClangStaticAnalyzerTool::startTool(ProjectExplorer::RunConfiguration *runConfiguration) { - AnalyzerManager::showMode(); - Project *project = SessionManager::startupProject(); QTC_ASSERT(project, emit finished(false); return); @@ -261,8 +273,25 @@ void ClangStaticAnalyzerTool::onEngineFinished() m_running = false; handleStateUpdate(); emit finished(static_cast(sender())->success()); + m_toolBusy = false; + updateRunActions(); } +void ClangStaticAnalyzerTool::updateRunActions() +{ + if (m_toolBusy) { + m_startAction->setEnabled(false); + m_startAction->setToolTip(tr("Clang Static Analyzer is still running.")); + m_stopAction->setEnabled(true); + } else { + QString whyNot = tr("Start Clang Static Analyzer."); + bool canRun = ProjectExplorerPlugin::canRunStartupProject( + Constants::CLANGSTATICANALYZER_RUN_MODE, &whyNot); + m_startAction->setToolTip(whyNot); + m_startAction->setEnabled(canRun); + m_stopAction->setEnabled(false); + } +} void ClangStaticAnalyzerTool::setBusyCursor(bool busy) { QTC_ASSERT(m_diagnosticView, return); @@ -291,7 +320,7 @@ void ClangStaticAnalyzerTool::handleStateUpdate() message += tr("%n issues found (%1 suppressed).", 0, issuesFound) .arg(issuesFound - issuesVisible); } - AnalyzerManager::showPermanentStatusMessage(message); + Debugger::showPermanentStatusMessage(message); } } // namespace Internal diff --git a/src/plugins/clangstaticanalyzer/clangstaticanalyzertool.h b/src/plugins/clangstaticanalyzer/clangstaticanalyzertool.h index 37f5f3e75c4..08580b39537 100644 --- a/src/plugins/clangstaticanalyzer/clangstaticanalyzertool.h +++ b/src/plugins/clangstaticanalyzer/clangstaticanalyzertool.h @@ -56,8 +56,7 @@ public: bool isRunning() const { return m_running; } QList diagnostics() const; - QWidget *createWidgets(); - Analyzer::AnalyzerRunControl *createRunControl(ProjectExplorer::RunConfiguration *runConfiguration, + Debugger::AnalyzerRunControl *createRunControl(ProjectExplorer::RunConfiguration *runConfiguration, Core::Id runMode); void startTool(ProjectExplorer::RunConfiguration *rc); @@ -71,6 +70,7 @@ private: void setBusyCursor(bool busy); void handleStateUpdate(); + void updateRunActions(); private: CppTools::ProjectInfo m_projectInfoBeforeBuild; @@ -79,9 +79,12 @@ private: ClangStaticAnalyzerDiagnosticFilterModel *m_diagnosticFilterModel; ClangStaticAnalyzerDiagnosticView *m_diagnosticView; + QAction *m_startAction = 0; + QAction *m_stopAction = 0; QAction *m_goBack; QAction *m_goNext; bool m_running; + bool m_toolBusy = false; }; } // namespace Internal diff --git a/src/plugins/clangstaticanalyzer/clangstaticanalyzerunittests.cpp b/src/plugins/clangstaticanalyzer/clangstaticanalyzerunittests.cpp index 76a063a260d..ba8814cbfa3 100644 --- a/src/plugins/clangstaticanalyzer/clangstaticanalyzerunittests.cpp +++ b/src/plugins/clangstaticanalyzer/clangstaticanalyzerunittests.cpp @@ -44,7 +44,7 @@ #include #include -using namespace Analyzer; +using namespace Debugger; using namespace ProjectExplorer; using namespace Utils; @@ -89,7 +89,7 @@ void ClangStaticAnalyzerUnitTests::testProject() CppTools::Tests::ProjectOpenerAndCloser projectManager; const CppTools::ProjectInfo projectInfo = projectManager.open(projectFilePath, true); QVERIFY(projectInfo.isValid()); - AnalyzerManager::selectAction(ClangStaticAnalyzerPerspectiveId, /* alsoRunIt = */ true); + Debugger::runAction(ClangStaticAnalyzerActionId); QSignalSpy waiter(m_analyzerTool, SIGNAL(finished(bool))); QVERIFY(waiter.wait(30000)); const QList arguments = waiter.takeFirst(); diff --git a/src/plugins/clangstaticanalyzer/clangstaticanalyzerutils.cpp b/src/plugins/clangstaticanalyzer/clangstaticanalyzerutils.cpp index 1c7af5176ba..d800af2588d 100644 --- a/src/plugins/clangstaticanalyzer/clangstaticanalyzerutils.cpp +++ b/src/plugins/clangstaticanalyzer/clangstaticanalyzerutils.cpp @@ -77,7 +77,7 @@ QString clangExecutable(const QString &fileNameOrPath, bool *isValid) return executable; } -QString createFullLocationString(const Analyzer::DiagnosticLocation &location) +QString createFullLocationString(const Debugger::DiagnosticLocation &location) { const QString filePath = location.filePath; const QString lineNumber = QString::number(location.line); diff --git a/src/plugins/clangstaticanalyzer/clangstaticanalyzerutils.h b/src/plugins/clangstaticanalyzer/clangstaticanalyzerutils.h index 63f6f6517f9..1531d050c6d 100644 --- a/src/plugins/clangstaticanalyzer/clangstaticanalyzerutils.h +++ b/src/plugins/clangstaticanalyzer/clangstaticanalyzerutils.h @@ -34,7 +34,7 @@ QT_BEGIN_NAMESPACE class QString; QT_END_NAMESPACE -namespace Analyzer { class DiagnosticLocation; } +namespace Debugger { class DiagnosticLocation; } namespace ClangStaticAnalyzer { namespace Internal { @@ -44,7 +44,7 @@ bool isClangExecutableUsable(const QString &filePath, QString *errorMessage = 0) QString clangExecutable(const QString &fileNameOrPath, bool *isValid); QString clangExecutableFromSettings(Core::Id toolchainType, bool *isValid); -QString createFullLocationString(const Analyzer::DiagnosticLocation &location); +QString createFullLocationString(const Debugger::DiagnosticLocation &location); } // namespace Internal } // namespace ClangStaticAnalyzer diff --git a/src/plugins/clearcase/clearcaseplugin.h b/src/plugins/clearcase/clearcaseplugin.h index ea20248c004..a3c93c4c2ce 100644 --- a/src/plugins/clearcase/clearcaseplugin.h +++ b/src/plugins/clearcase/clearcaseplugin.h @@ -200,7 +200,7 @@ public slots: private: void annotateVersion(const QString &workingDirectory, const QString &file, const QString &revision, int lineNumber); void syncSlot(); - void updateStatusActions(); + Q_INVOKABLE void updateStatusActions(); void checkOutCurrentFile(); void addCurrentFile(); diff --git a/src/plugins/cmakeprojectmanager/builddirmanager.cpp b/src/plugins/cmakeprojectmanager/builddirmanager.cpp index d549a53fb5b..8e2807c8bc7 100644 --- a/src/plugins/cmakeprojectmanager/builddirmanager.cpp +++ b/src/plugins/cmakeprojectmanager/builddirmanager.cpp @@ -225,6 +225,21 @@ void BuildDirManager::parse() } } +void BuildDirManager::clearCache() +{ + auto cmakeCache = Utils::FileName(buildDirectory()).appendPath(QLatin1String("CMakeCache.txt")); + auto cmakeFiles = Utils::FileName(buildDirectory()).appendPath(QLatin1String("CMakeFiles")); + + const bool mustCleanUp = cmakeCache.exists() || cmakeFiles.exists(); + if (!mustCleanUp) + return; + + Utils::FileUtils::removeRecursively(cmakeCache); + Utils::FileUtils::removeRecursively(cmakeFiles); + + forceReparse(); +} + bool BuildDirManager::isProjectFile(const Utils::FileName &fileName) const { return m_watchedFiles.contains(fileName); diff --git a/src/plugins/cmakeprojectmanager/builddirmanager.h b/src/plugins/cmakeprojectmanager/builddirmanager.h index 53abb3cf98b..edc0196b0df 100644 --- a/src/plugins/cmakeprojectmanager/builddirmanager.h +++ b/src/plugins/cmakeprojectmanager/builddirmanager.h @@ -75,6 +75,7 @@ public: bool isParsing() const; void parse(); + void clearCache(); void forceReparse(); void resetData(); bool persistCMakeState(); diff --git a/src/plugins/cmakeprojectmanager/cmakekitconfigwidget.cpp b/src/plugins/cmakeprojectmanager/cmakekitconfigwidget.cpp index f73022f6dc1..e83f71fcdee 100644 --- a/src/plugins/cmakeprojectmanager/cmakekitconfigwidget.cpp +++ b/src/plugins/cmakeprojectmanager/cmakekitconfigwidget.cpp @@ -241,6 +241,7 @@ void CMakeGeneratorKitConfigWidget::refresh() CMakeTool *const tool = CMakeKitInformation::cmakeTool(m_kit); if (tool != m_currentTool) { + m_currentTool = tool; m_comboBox->clear(); m_comboBox->addItem(tr(""), QString()); if (tool && tool->isValid()) { diff --git a/src/plugins/cmakeprojectmanager/cmakeprojectconstants.h b/src/plugins/cmakeprojectmanager/cmakeprojectconstants.h index 3c69dfcb893..55ce0644863 100644 --- a/src/plugins/cmakeprojectmanager/cmakeprojectconstants.h +++ b/src/plugins/cmakeprojectmanager/cmakeprojectconstants.h @@ -34,6 +34,7 @@ const char CMAKEPROJECTMIMETYPE[] = "text/x-cmake-project"; const char CMAKE_EDITOR_ID[] = "CMakeProject.CMakeEditor"; const char CMAKE_EDITOR_DISPLAY_NAME[] = "CMake Editor"; const char RUNCMAKE[] = "CMakeProject.RunCMake"; +const char CLEARCMAKECACHE[] = "CMakeProject.ClearCache"; const char RUNCMAKECONTEXTMENU[] = "CMakeProject.RunCMakeContextMenu"; // Project diff --git a/src/plugins/cmakeprojectmanager/cmakeprojectmanager.cpp b/src/plugins/cmakeprojectmanager/cmakeprojectmanager.cpp index d53679b1b0b..2a2376f1487 100644 --- a/src/plugins/cmakeprojectmanager/cmakeprojectmanager.cpp +++ b/src/plugins/cmakeprojectmanager/cmakeprojectmanager.cpp @@ -24,6 +24,9 @@ ****************************************************************************/ #include "cmakeprojectmanager.h" +#include "builddirmanager.h" +#include "cmakebuildconfiguration.h" +#include "cmakekitinformation.h" #include "cmakeprojectconstants.h" #include "cmakeproject.h" #include "cmakesettingspage.h" @@ -52,6 +55,7 @@ using namespace CMakeProjectManager::Internal; CMakeManager::CMakeManager() : m_runCMakeAction(new QAction(QIcon(), tr("Run CMake"), this)), + m_clearCMakeCacheAction(new QAction(QIcon(), tr("Clear CMake Configuration"), this)), m_runCMakeActionContextMenu(new QAction(QIcon(), tr("Run CMake"), this)) { Core::ActionContainer *mbuild = @@ -62,16 +66,24 @@ CMakeManager::CMakeManager() : Core::ActionManager::actionContainer(ProjectExplorer::Constants::M_SUBPROJECTCONTEXT); const Core::Context projectContext(CMakeProjectManager::Constants::PROJECTCONTEXT); - const Core::Context globalcontext(Core::Constants::C_GLOBAL); + const Core::Context globalContext(Core::Constants::C_GLOBAL); Core::Command *command = Core::ActionManager::registerAction(m_runCMakeAction, - Constants::RUNCMAKE, globalcontext); + Constants::RUNCMAKE, globalContext); command->setAttribute(Core::Command::CA_Hide); mbuild->addAction(command, ProjectExplorer::Constants::G_BUILD_DEPLOY); connect(m_runCMakeAction, &QAction::triggered, [this]() { runCMake(SessionManager::startupProject()); }); + command = Core::ActionManager::registerAction(m_clearCMakeCacheAction, + Constants::CLEARCMAKECACHE, globalContext); + command->setAttribute(Core::Command::CA_Hide); + mbuild->addAction(command, ProjectExplorer::Constants::G_BUILD_DEPLOY); + connect(m_clearCMakeCacheAction, &QAction::triggered, [this]() { + clearCMakeCache(SessionManager::startupProject()); + }); + command = Core::ActionManager::registerAction(m_runCMakeActionContextMenu, Constants::RUNCMAKECONTEXTMENU, projectContext); command->setAttribute(Core::Command::CA_Hide); @@ -82,16 +94,31 @@ CMakeManager::CMakeManager() : }); connect(SessionManager::instance(), &SessionManager::startupProjectChanged, - this, &CMakeManager::updateRunCmakeAction); + this, &CMakeManager::updateCmakeActions); connect(BuildManager::instance(), &BuildManager::buildStateChanged, - this, &CMakeManager::updateRunCmakeAction); + this, &CMakeManager::updateCmakeActions); + updateCmakeActions(); } -void CMakeManager::updateRunCmakeAction() +void CMakeManager::updateCmakeActions() { auto project = qobject_cast(SessionManager::startupProject()); - m_runCMakeAction->setVisible(project && !BuildManager::isBuilding(project)); + const bool visible = project && !BuildManager::isBuilding(project); + m_runCMakeAction->setVisible(visible); + m_clearCMakeCacheAction->setVisible(visible); +} + +void CMakeManager::clearCMakeCache(Project *project) +{ + if (!project || !project->activeTarget()) + return; + auto bc = qobject_cast(project->activeTarget()->activeBuildConfiguration()); + if (!bc) + return; + + bc->setCMakeConfiguration(CMakeConfigurationKitInformation::configuration(bc->target()->kit())); + bc->buildDirManager()->clearCache(); } void CMakeManager::runCMake(Project *project) diff --git a/src/plugins/cmakeprojectmanager/cmakeprojectmanager.h b/src/plugins/cmakeprojectmanager/cmakeprojectmanager.h index c1328373b5c..795406494bf 100644 --- a/src/plugins/cmakeprojectmanager/cmakeprojectmanager.h +++ b/src/plugins/cmakeprojectmanager/cmakeprojectmanager.h @@ -58,10 +58,12 @@ public: static QString findCbpFile(const QDir &); private: - void updateRunCmakeAction(); + void updateCmakeActions(); + void clearCMakeCache(ProjectExplorer::Project *project); void runCMake(ProjectExplorer::Project *project); QAction *m_runCMakeAction; + QAction *m_clearCMakeCacheAction; QAction *m_runCMakeActionContextMenu; }; diff --git a/src/plugins/coreplugin/editormanager/documentmodel.cpp b/src/plugins/coreplugin/editormanager/documentmodel.cpp index d5975785943..6f84a4bd5ed 100644 --- a/src/plugins/coreplugin/editormanager/documentmodel.cpp +++ b/src/plugins/coreplugin/editormanager/documentmodel.cpp @@ -31,6 +31,7 @@ #include #include +#include #include #include @@ -323,7 +324,7 @@ bool DocumentModelPrivate::disambiguateDisplayNames(DocumentModel::Entry *entry) } for (int j = i + 1; j < dupsCount; ++j) { DynamicEntry &e2 = dups[j]; - if (e->displayName() == e2->displayName()) { + if (e->displayName().compare(e2->displayName(), Utils::HostOsInfo::fileNameCaseSensitivity()) == 0) { const Utils::FileName otherFileName = e2->document->filePath(); if (otherFileName.isEmpty()) continue; diff --git a/src/plugins/coreplugin/editormanager/editormanager.cpp b/src/plugins/coreplugin/editormanager/editormanager.cpp index 535f2fdbad6..9d6a44ed64d 100644 --- a/src/plugins/coreplugin/editormanager/editormanager.cpp +++ b/src/plugins/coreplugin/editormanager/editormanager.cpp @@ -181,7 +181,7 @@ static void setFocusToEditorViewAndUnmaximizePanes(EditorView *view) if (holder && holder->window() == view->window()) { // unmaximize output pane if necessary if (holder->isVisible() && holder->isMaximized()) - holder->unmaximize(); + holder->setMaximized(false); } } @@ -563,15 +563,17 @@ IEditor *EditorManagerPrivate::openEditor(EditorView *view, const QString &fileN int columnNumber = -1; if ((flags & EditorManager::CanContainLineAndColumnNumber) && !fi.exists()) { const EditorManager::FilePathInfo fp = EditorManager::splitLineAndColumnNumber(fn); - fn = fp.filePath; + fn = Utils::FileUtils::normalizePathName(fp.filePath); lineNumber = fp.lineNumber; columnNumber = fp.columnNumber; - if (lineNumber != -1) - fi.setFile(fn); + } else { + fn = Utils::FileUtils::normalizePathName(fn); } if (fn.isEmpty()) return 0; + if (fn != fileName) + fi.setFile(fn); if (newEditor) *newEditor = false; diff --git a/src/plugins/coreplugin/locator/locatorwidget.cpp b/src/plugins/coreplugin/locator/locatorwidget.cpp index 4dd47d3bea2..44917a54a40 100644 --- a/src/plugins/coreplugin/locator/locatorwidget.cpp +++ b/src/plugins/coreplugin/locator/locatorwidget.cpp @@ -233,6 +233,7 @@ LocatorWidget::LocatorWidget(Locator *qop) : // Explicitly hide the completion list popup. m_completionList->hide(); + setAttribute(Qt::WA_Hover); setFocusProxy(m_fileLineEdit); setWindowTitle(tr("Locate...")); resize(200, 90); diff --git a/src/plugins/coreplugin/outputpane.cpp b/src/plugins/coreplugin/outputpane.cpp index dd270e14fe0..99933d5a692 100644 --- a/src/plugins/coreplugin/outputpane.cpp +++ b/src/plugins/coreplugin/outputpane.cpp @@ -28,22 +28,26 @@ #include "outputpane.h" #include "outputpanemanager.h" +#include #include #include namespace Core { -struct OutputPanePlaceHolderPrivate { +class OutputPanePlaceHolderPrivate { +public: explicit OutputPanePlaceHolderPrivate(IMode *mode, QSplitter *parent); IMode *m_mode; QSplitter *m_splitter; - int m_lastNonMaxSize; + int m_nonMaximizedSize = 0; + bool m_isMaximized = false; + bool m_initialized = false; static OutputPanePlaceHolder* m_current; }; OutputPanePlaceHolderPrivate::OutputPanePlaceHolderPrivate(IMode *mode, QSplitter *parent) : - m_mode(mode), m_splitter(parent), m_lastNonMaxSize(0) + m_mode(mode), m_splitter(parent) { } @@ -62,6 +66,9 @@ OutputPanePlaceHolder::OutputPanePlaceHolder(IMode *mode, QSplitter* parent) layout()->setMargin(0); connect(ModeManager::instance(), &ModeManager::currentModeChanged, this, &OutputPanePlaceHolder::currentModeChanged); + // if this is part of a lazily created mode widget, + // we need to check if this is the current placeholder + currentModeChanged(ModeManager::currentMode()); } OutputPanePlaceHolder::~OutputPanePlaceHolder() @@ -79,32 +86,42 @@ void OutputPanePlaceHolder::currentModeChanged(IMode *mode) { if (d->m_current == this) { d->m_current = 0; + if (d->m_initialized) + Internal::OutputPaneManager::setOutputPaneHeightSetting(d->m_nonMaximizedSize); Internal::OutputPaneManager *om = Internal::OutputPaneManager::instance(); - om->setParent(0); om->hide(); + om->setParent(0); om->updateStatusButtons(false); } if (d->m_mode == mode) { + if (d->m_current && d->m_current->d->m_initialized) + Internal::OutputPaneManager::setOutputPaneHeightSetting(d->m_current->d->m_nonMaximizedSize); d->m_current = this; Internal::OutputPaneManager *om = Internal::OutputPaneManager::instance(); layout()->addWidget(om); om->show(); om->updateStatusButtons(isVisible()); + Internal::OutputPaneManager::updateMaximizeButton(d->m_isMaximized); } } -void OutputPanePlaceHolder::maximizeOrMinimize(bool maximize) +void OutputPanePlaceHolder::setMaximized(bool maximize) { + if (d->m_isMaximized == maximize) + return; if (!d->m_splitter) return; int idx = d->m_splitter->indexOf(this); if (idx < 0) return; + d->m_isMaximized = maximize; + if (d->m_current == this) + Internal::OutputPaneManager::updateMaximizeButton(d->m_isMaximized); QList sizes = d->m_splitter->sizes(); if (maximize) { - d->m_lastNonMaxSize = sizes[idx]; + d->m_nonMaximizedSize = sizes[idx]; int sum = 0; foreach (int s, sizes) sum += s; @@ -113,7 +130,7 @@ void OutputPanePlaceHolder::maximizeOrMinimize(bool maximize) } sizes[idx] = sum - (sizes.count()-1) * 32; } else { - int target = d->m_lastNonMaxSize > 0 ? d->m_lastNonMaxSize : sizeHint().height(); + int target = d->m_nonMaximizedSize > 0 ? d->m_nonMaximizedSize : sizeHint().height(); int space = sizes[idx] - target; if (space > 0) { for (int i = 0; i < sizes.count(); ++i) { @@ -124,31 +141,31 @@ void OutputPanePlaceHolder::maximizeOrMinimize(bool maximize) } d->m_splitter->setSizes(sizes); - } bool OutputPanePlaceHolder::isMaximized() const { - return Internal::OutputPaneManager::instance()->isMaximized(); + return d->m_isMaximized; } -void OutputPanePlaceHolder::setDefaultHeight(int height) +void OutputPanePlaceHolder::setHeight(int height) { if (height == 0) return; if (!d->m_splitter) return; - int idx = d->m_splitter->indexOf(this); + const int idx = d->m_splitter->indexOf(this); if (idx < 0) return; d->m_splitter->refresh(); QList sizes = d->m_splitter->sizes(); - int difference = height - sizes.at(idx); - if (difference <= 0) // is already larger + const int difference = height - sizes.at(idx); + if (difference == 0) return; + const int adaption = difference / (sizes.count()-1); for (int i = 0; i < sizes.count(); ++i) { - sizes[i] += difference / (sizes.count()-1); + sizes[i] -= adaption; } sizes[idx] = height; d->m_splitter->setSizes(sizes); @@ -159,13 +176,28 @@ void OutputPanePlaceHolder::ensureSizeHintAsMinimum() Internal::OutputPaneManager *om = Internal::OutputPaneManager::instance(); int minimum = (d->m_splitter->orientation() == Qt::Vertical ? om->sizeHint().height() : om->sizeHint().width()); - setDefaultHeight(minimum); + if (height() < minimum) + setHeight(minimum); } -void OutputPanePlaceHolder::unmaximize() +int OutputPanePlaceHolder::nonMaximizedSize() const { - if (Internal::OutputPaneManager::instance()->isMaximized()) - Internal::OutputPaneManager::instance()->slotMinMax(); + return d->m_nonMaximizedSize; +} + +void OutputPanePlaceHolder::resizeEvent(QResizeEvent *event) +{ + if (d->m_isMaximized || event->size().height() == 0) + return; + d->m_nonMaximizedSize = event->size().height(); +} + +void OutputPanePlaceHolder::showEvent(QShowEvent *) +{ + if (!d->m_initialized) { + d->m_initialized = true; + setHeight(Internal::OutputPaneManager::outputPaneHeightSetting()); + } } OutputPanePlaceHolder *OutputPanePlaceHolder::getCurrent() @@ -173,11 +205,6 @@ OutputPanePlaceHolder *OutputPanePlaceHolder::getCurrent() return OutputPanePlaceHolderPrivate::m_current; } -bool OutputPanePlaceHolder::canMaximizeOrMinimize() const -{ - return d->m_splitter != 0; -} - bool OutputPanePlaceHolder::isCurrentVisible() { return OutputPanePlaceHolderPrivate::m_current && OutputPanePlaceHolderPrivate::m_current->isVisible(); diff --git a/src/plugins/coreplugin/outputpane.h b/src/plugins/coreplugin/outputpane.h index a7a9c5061c9..6486cc999f1 100644 --- a/src/plugins/coreplugin/outputpane.h +++ b/src/plugins/coreplugin/outputpane.h @@ -39,12 +39,11 @@ namespace Core { class IMode; namespace Internal { class OutputPaneManager; } -struct OutputPanePlaceHolderPrivate; +class OutputPanePlaceHolderPrivate; class CORE_EXPORT OutputPanePlaceHolder : public QWidget { Q_OBJECT - friend class Core::Internal::OutputPaneManager; // needs to set m_visible and thus access m_current public: explicit OutputPanePlaceHolder(IMode *mode, QSplitter *parent = 0); @@ -53,15 +52,18 @@ public: static OutputPanePlaceHolder *getCurrent(); static bool isCurrentVisible(); - void unmaximize(); bool isMaximized() const; - void setDefaultHeight(int height); + void setMaximized(bool maximize); void ensureSizeHintAsMinimum(); + int nonMaximizedSize() const; + +protected: + void resizeEvent(QResizeEvent *event); + void showEvent(QShowEvent *); private: + void setHeight(int height); void currentModeChanged(IMode *); - bool canMaximizeOrMinimize() const; - void maximizeOrMinimize(bool maximize); OutputPanePlaceHolderPrivate *d; }; diff --git a/src/plugins/coreplugin/outputpanemanager.cpp b/src/plugins/coreplugin/outputpanemanager.cpp index 58e6f30d22d..231ea7509ca 100644 --- a/src/plugins/coreplugin/outputpanemanager.cpp +++ b/src/plugins/coreplugin/outputpanemanager.cpp @@ -103,8 +103,17 @@ void OutputPaneManager::updateStatusButtons(bool visible) QTC_ASSERT(m_panes.size() == m_buttons.size(), return); m_buttons.at(idx)->setChecked(visible); m_panes.at(idx)->visibilityChanged(visible); - OutputPanePlaceHolder *ph = OutputPanePlaceHolder::getCurrent(); - m_minMaxAction->setVisible(ph && ph->canMaximizeOrMinimize()); +} + +void OutputPaneManager::updateMaximizeButton(bool maximized) +{ + if (maximized) { + m_instance->m_minMaxAction->setIcon(m_instance->m_minimizeIcon); + m_instance->m_minMaxAction->setText(tr("Minimize Output Pane")); + } else { + m_instance->m_minMaxAction->setIcon(m_instance->m_maximizeIcon); + m_instance->m_minMaxAction->setText(tr("Maximize Output Pane")); + } } OutputPaneManager::OutputPaneManager(QWidget *parent) : @@ -120,8 +129,7 @@ OutputPaneManager::OutputPaneManager(QWidget *parent) : m_opToolBarWidgets(new QStackedWidget), m_minimizeIcon(Icons::ARROW_DOWN.icon()), m_maximizeIcon(Icons::ARROW_UP.icon()), - m_maximised(false), - m_outputPaneHeight(0) + m_outputPaneHeightSetting(0) { setWindowTitle(tr("Output")); @@ -231,7 +239,7 @@ void OutputPaneManager::init() cmd->setAttribute(Command::CA_UpdateText); cmd->setAttribute(Command::CA_UpdateIcon); mpanes->addAction(cmd, "Coreplugin.OutputPane.ActionsGroup"); - connect(m_minMaxAction, &QAction::triggered, this, &OutputPaneManager::slotMinMax); + connect(m_minMaxAction, &QAction::triggered, this, &OutputPaneManager::toggleMaximized); m_minMaxButton->setDefaultAction(cmd->action()); mpanes->addSeparator("Coreplugin.OutputPane.ActionsGroup"); @@ -334,23 +342,24 @@ void OutputPaneManager::shortcutTriggered() } } -bool OutputPaneManager::isMaximized()const +int OutputPaneManager::outputPaneHeightSetting() { - return m_maximised; + return m_instance->m_outputPaneHeightSetting; } -void OutputPaneManager::slotMinMax() +void OutputPaneManager::setOutputPaneHeightSetting(int value) +{ + m_instance->m_outputPaneHeightSetting = value; +} + +void OutputPaneManager::toggleMaximized() { OutputPanePlaceHolder *ph = OutputPanePlaceHolder::getCurrent(); QTC_ASSERT(ph, return); if (!ph->isVisible()) // easier than disabling/enabling the action return; - m_maximised = !m_maximised; - ph->maximizeOrMinimize(m_maximised); - m_minMaxAction->setIcon(m_maximised ? m_minimizeIcon : m_maximizeIcon); - m_minMaxAction->setText(m_maximised ? tr("Minimize Output Pane") - : tr("Maximize Output Pane")); + ph->setMaximized(!ph->isMaximized()); } void OutputPaneManager::buttonTriggered(int idx) @@ -380,7 +389,7 @@ void OutputPaneManager::readSettings() m_buttons.at(i)->setVisible(m_buttonVisibility.value(m_ids.at(i))); } - m_outputPaneHeight = settings->value(QLatin1String("OutputPanePlaceHolder/Height"), 0).toInt(); + m_outputPaneHeightSetting = settings->value(QLatin1String("OutputPanePlaceHolder/Height"), 0).toInt(); } void OutputPaneManager::slotNext() @@ -490,7 +499,6 @@ void OutputPaneManager::showPage(int idx, int flags) ICore::raiseWindow(m_outputWidgetPane); } - ph->setDefaultHeight(m_outputPaneHeight); if (flags & IOutputPane::EnsureSizeHint) ph->ensureSizeHintAsMinimum(); } @@ -511,13 +519,6 @@ void OutputPaneManager::focusInEvent(QFocusEvent *e) w->setFocus(e->reason()); } -void OutputPaneManager::resizeEvent(QResizeEvent *e) -{ - if (e->size().height() == 0) - return; - m_outputPaneHeight = e->size().height(); -} - void OutputPaneManager::setCurrentIndex(int idx) { static int lastIndex = -1; @@ -586,7 +587,11 @@ void OutputPaneManager::saveSettings() const m_buttonVisibility.value(m_ids.at(i))); } settings->endArray(); - settings->setValue(QLatin1String("OutputPanePlaceHolder/Height"), m_outputPaneHeight); + int heightSetting = m_outputPaneHeightSetting; + // update if possible + if (OutputPanePlaceHolder *curr = OutputPanePlaceHolder::getCurrent()) + heightSetting = curr->nonMaximizedSize(); + settings->setValue(QLatin1String("OutputPanePlaceHolder/Height"), heightSetting); } void OutputPaneManager::clearPage() diff --git a/src/plugins/coreplugin/outputpanemanager.h b/src/plugins/coreplugin/outputpanemanager.h index 81ff63e263a..304774856d7 100644 --- a/src/plugins/coreplugin/outputpanemanager.h +++ b/src/plugins/coreplugin/outputpanemanager.h @@ -60,19 +60,20 @@ public: static OutputPaneManager *instance(); QWidget *buttonsWidget(); void updateStatusButtons(bool visible); + static void updateMaximizeButton(bool maximized); - bool isMaximized()const; + static int outputPaneHeightSetting(); + static void setOutputPaneHeightSetting(int value); public slots: void slotHide(); void slotNext(); void slotPrev(); void shortcutTriggered(); - void slotMinMax(); + void toggleMaximized(); protected: void focusInEvent(QFocusEvent *e); - void resizeEvent(QResizeEvent *e); private: // the only class that is allowed to create and destroy @@ -126,8 +127,8 @@ private: QWidget *m_buttonsWidget; QIcon m_minimizeIcon; QIcon m_maximizeIcon; - bool m_maximised; - int m_outputPaneHeight; + bool m_maximized; + int m_outputPaneHeightSetting; }; class BadgeLabel diff --git a/src/plugins/cpptools/generatedcodemodelsupport.cpp b/src/plugins/cpptools/generatedcodemodelsupport.cpp index 50b1000997c..5a37219ab90 100644 --- a/src/plugins/cpptools/generatedcodemodelsupport.cpp +++ b/src/plugins/cpptools/generatedcodemodelsupport.cpp @@ -98,7 +98,7 @@ void GeneratedCodeModelSupport::onContentsChanged(const Utils::FileName &file) void GeneratedCodeModelSupport::init() const { connect(m_generator, &ProjectExplorer::ExtraCompiler::contentsChanged, - this, &GeneratedCodeModelSupport::onContentsChanged); + this, &GeneratedCodeModelSupport::onContentsChanged, Qt::QueuedConnection); } QByteArray GeneratedCodeModelSupport::contents() const diff --git a/src/plugins/debugger/analyzer/analyzer.pri b/src/plugins/debugger/analyzer/analyzer.pri index 40da12eb3d6..2ae4afc5987 100644 --- a/src/plugins/debugger/analyzer/analyzer.pri +++ b/src/plugins/debugger/analyzer/analyzer.pri @@ -5,7 +5,6 @@ QT += network SOURCES += \ $$PWD/analyzerruncontrol.cpp \ - $$PWD/analyzermanager.cpp \ $$PWD/analyzerrunconfigwidget.cpp \ $$PWD/analyzerutils.cpp \ $$PWD/detailederrorview.cpp \ @@ -13,7 +12,6 @@ SOURCES += \ $$PWD/startremotedialog.cpp HEADERS += \ - $$PWD/analyzerbase_global.h \ $$PWD/analyzerconstants.h \ $$PWD/analyzerruncontrol.h \ $$PWD/analyzermanager.h \ diff --git a/src/plugins/debugger/analyzer/analyzerbase_global.h b/src/plugins/debugger/analyzer/analyzerbase_global.h deleted file mode 100644 index 4d47f89a6d4..00000000000 --- a/src/plugins/debugger/analyzer/analyzerbase_global.h +++ /dev/null @@ -1,34 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Author: Nicolas Arnaud-Cormos, KDAB (nicolas.arnaud-cormos@kdab.com) -** Contact: https://www.qt.io/licensing/ -** -** This file is part of Qt Creator. -** -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -****************************************************************************/ - -#ifndef ANALYZERBASE_GLOBAL_H -#define ANALYZERBASE_GLOBAL_H - -#include "../debugger_global.h" - -#define ANALYZER_EXPORT DEBUGGER_EXPORT - -#endif // ANALYZERBASE_GLOBAL_H diff --git a/src/plugins/debugger/analyzer/analyzerconstants.h b/src/plugins/debugger/analyzer/analyzerconstants.h index 8f6da351e85..c2554f42c26 100644 --- a/src/plugins/debugger/analyzer/analyzerconstants.h +++ b/src/plugins/debugger/analyzer/analyzerconstants.h @@ -29,16 +29,9 @@ #include -namespace Analyzer { +namespace Debugger { namespace Constants { -// Mode and its priority. -const char MODE_ANALYZE[] = "Mode.Analyze"; -const int P_MODE_ANALYZE = 76; - -// Context. -const char C_ANALYZEMODE[] = "Analyzer.AnalyzeMode"; - // Menu. const char M_DEBUG_ANALYZER[] = "Analyzer.Menu.StartAnalyzer"; const char M_DEBUG_ANALYZER_QML_OPTIONS[] = "Analyzer.Menu.QMLOptions"; @@ -51,6 +44,6 @@ const char G_ANALYZER_OPTIONS[] = "Menu.Group.Analyzer.Options"; const char ANALYZERTASK_ID[] = "Analyzer.TaskId"; } // namespace Constants -} // namespace Analyzer +} // namespace Debugger #endif // ANALYZERCONSTANTS_H diff --git a/src/plugins/debugger/analyzer/analyzericons.h b/src/plugins/debugger/analyzer/analyzericons.h index fa8d6a8bef7..f9f4a69056b 100644 --- a/src/plugins/debugger/analyzer/analyzericons.h +++ b/src/plugins/debugger/analyzer/analyzericons.h @@ -28,7 +28,7 @@ #include -namespace Analyzer { +namespace Debugger { namespace Icons { const Utils::Icon ANALYZER_CONTROL_START({ @@ -42,6 +42,6 @@ const Utils::Icon MODE_ANALYZE_FLAT_ACTIVE({ {QLatin1String(":/images/mode_analyze_mask.png"), Utils::Theme::IconsModeAnalyzeActiveColor}}); } // namespace Icons -} // namespace Analyzer +} // namespace Debugger #endif // ANALYZERICONS_H diff --git a/src/plugins/debugger/analyzer/analyzermanager.cpp b/src/plugins/debugger/analyzer/analyzermanager.cpp deleted file mode 100644 index 15ab6253cd6..00000000000 --- a/src/plugins/debugger/analyzer/analyzermanager.cpp +++ /dev/null @@ -1,738 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Author: Andreas Hartmetz, KDAB (andreas.hartmetz@kdab.com) -** Contact: https://www.qt.io/licensing/ -** -** This file is part of Qt Creator. -** -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -****************************************************************************/ - -#include "analyzermanager.h" - -#include "analyzericons.h" -#include "analyzerstartparameters.h" -#include "analyzerruncontrol.h" -#include "../debuggerplugin.h" - -#include "../debuggermainwindow.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -using namespace Core; -using namespace Utils; -using namespace Core::Constants; -using namespace Analyzer::Constants; -using namespace ProjectExplorer; -using namespace Debugger; -using namespace Debugger::Internal; - -namespace Analyzer { - -bool ActionDescription::isRunnable(QString *reason) const -{ - if (m_customToolStarter) // Something special. Pretend we can always run it. - return true; - - return ProjectExplorerPlugin::canRun(SessionManager::startupProject(), m_runMode, reason); -} - -static bool buildTypeAccepted(QFlags toolMode, BuildConfiguration::BuildType buildType) -{ - if (buildType == BuildConfiguration::Unknown) - return true; - if (buildType == BuildConfiguration::Debug && (toolMode & DebugMode)) - return true; - if (buildType == BuildConfiguration::Release && (toolMode & ReleaseMode)) - return true; - if (buildType == BuildConfiguration::Profile && (toolMode & ProfileMode)) - return true; - return false; -} - -void ActionDescription::startTool() const -{ - // Make sure mode is shown. - AnalyzerManager::showMode(); - - TaskHub::clearTasks(Constants::ANALYZERTASK_ID); - AnalyzerManager::showPermanentStatusMessage(QString()); - - if (m_toolPreparer && !m_toolPreparer()) - return; - - // ### not sure if we're supposed to check if the RunConFiguration isEnabled - Project *pro = SessionManager::startupProject(); - RunConfiguration *rc = 0; - BuildConfiguration::BuildType buildType = BuildConfiguration::Unknown; - if (pro) { - if (const Target *target = pro->activeTarget()) { - // Build configuration is 0 for QML projects. - if (const BuildConfiguration *buildConfig = target->activeBuildConfiguration()) - buildType = buildConfig->buildType(); - rc = target->activeRunConfiguration(); - } - } - - // Custom start. - if (m_customToolStarter) { - if (rc) { - m_customToolStarter(rc); - } else { - QMessageBox *errorDialog = new QMessageBox(ICore::mainWindow()); - errorDialog->setIcon(QMessageBox::Warning); - errorDialog->setWindowTitle(m_text); - errorDialog->setText(tr("Cannot start %1 without a project. Please open the project " - "and try again.").arg(m_text)); - errorDialog->setStandardButtons(QMessageBox::Ok); - errorDialog->setDefaultButton(QMessageBox::Ok); - errorDialog->show(); - } - return; - } - - // Check the project for whether the build config is in the correct mode - // if not, notify the user and urge him to use the correct mode. - if (!buildTypeAccepted(m_toolMode, buildType)) { - QString currentMode; - switch (buildType) { - case BuildConfiguration::Debug: - currentMode = AnalyzerManager::tr("Debug"); - break; - case BuildConfiguration::Profile: - currentMode = AnalyzerManager::tr("Profile"); - break; - case BuildConfiguration::Release: - currentMode = AnalyzerManager::tr("Release"); - break; - default: - QTC_CHECK(false); - } - - QString toolModeString; - switch (m_toolMode) { - case DebugMode: - toolModeString = AnalyzerManager::tr("in Debug mode"); - break; - case ProfileMode: - toolModeString = AnalyzerManager::tr("in Profile mode"); - break; - case ReleaseMode: - toolModeString = AnalyzerManager::tr("in Release mode"); - break; - case SymbolsMode: - toolModeString = AnalyzerManager::tr("with debug symbols (Debug or Profile mode)"); - break; - case OptimizedMode: - toolModeString = AnalyzerManager::tr("on optimized code (Profile or Release mode)"); - break; - default: - QTC_CHECK(false); - } - const QString toolName = m_text; // The action text is always the name of the tool - const QString title = AnalyzerManager::tr("Run %1 in %2 Mode?").arg(toolName).arg(currentMode); - const QString message = AnalyzerManager::tr("

You are trying " - "to run the tool \"%1\" on an application in %2 mode. " - "The tool is designed to be used %3.

" - "Run-time characteristics differ significantly between " - "optimized and non-optimized binaries. Analytical " - "findings for one mode may or may not be relevant for " - "the other.

" - "Running tools that need debug symbols on binaries that " - "don't provide any may lead to missing function names " - "or otherwise insufficient output.

" - "Do you want to continue and run the tool in %2 mode?

") - .arg(toolName).arg(currentMode).arg(toolModeString); - if (Utils::CheckableMessageBox::doNotAskAgainQuestion(ICore::mainWindow(), - title, message, ICore::settings(), QLatin1String("AnalyzerCorrectModeWarning")) - != QDialogButtonBox::Yes) - return; - } - - ProjectExplorerPlugin::runStartupProject(m_runMode); -} - -namespace Internal { - -const char LAST_ACTIVE_ACTION[] = "Analyzer.Plugin.LastActiveTool"; - -//////////////////////////////////////////////////////////////////// -// -// AnalyzerMode -// -//////////////////////////////////////////////////////////////////// - -class AnalyzerMode : public IMode -{ -public: - AnalyzerMode(QObject *parent = 0) - : IMode(parent) - { - setContext(Context(C_ANALYZEMODE, C_NAVIGATION_PANE)); - setDisplayName(AnalyzerManager::tr("Analyze")); - setIcon(Utils::Icon::modeIcon(Icons::MODE_ANALYZE_CLASSIC, - Icons::MODE_ANALYZE_FLAT, Icons::MODE_ANALYZE_FLAT_ACTIVE)); - setPriority(P_MODE_ANALYZE); - setId(MODE_ANALYZE); - } - - ~AnalyzerMode() - { - delete m_widget; - m_widget = 0; - } -}; - -} // namespace Internal - -//////////////////////////////////////////////////////////////////// -// -// AnalyzerManagerPrivate -// -//////////////////////////////////////////////////////////////////// - -class AnalyzerManagerPrivate : public QObject -{ - Q_DECLARE_TR_FUNCTIONS(Analyzer::AnalyzerManager) - -public: - AnalyzerManagerPrivate(AnalyzerManager *qq); - - /** - * After calling this, a proper instance of IMode is initialized - * It is delayed since an analyzer mode makes no sense without analyzer tools - * - * \note Call this before adding a tool to the manager - */ - void delayedInit(); - - void setupActions(); - void createModeMainWindow(); - bool showPromptDialog(const QString &title, const QString &text, - const QString &stopButtonText, const QString &cancelButtonText) const; - - void registerAction(Core::Id actionId, const ActionDescription &desc); - void selectSavedTool(); - void selectAction(Id actionId); - void handleToolStarted(); - void handleToolFinished(); - void modeChanged(IMode *mode); - void resetLayout(); - void updateRunActions(); - -public: - AnalyzerManager *q; - Internal::AnalyzerMode *m_mode = 0; - bool m_isRunning = false; - Core::Id m_currentActionId; - QHash m_actions; - QHash m_descriptions; - QAction *m_startAction = 0; - QAction *m_stopAction = 0; - ActionContainer *m_menu = 0; - MainWindowBase *m_mainWindow; -}; - -AnalyzerManagerPrivate::AnalyzerManagerPrivate(AnalyzerManager *qq): - q(qq), m_mainWindow(new MainWindowBase) -{ - QComboBox *toolBox = m_mainWindow->toolBox(); - toolBox->setObjectName(QLatin1String("AnalyzerManagerToolBox")); - toolBox->insertSeparator(0); - connect(toolBox, static_cast(&QComboBox::activated), this, [this, toolBox](int item) { - selectAction(Id::fromSetting(toolBox->itemData(item))); - }); - - setupActions(); - - ProjectExplorerPlugin *pe = ProjectExplorerPlugin::instance(); - connect(pe, &ProjectExplorerPlugin::updateRunActions, this, &AnalyzerManagerPrivate::updateRunActions); -} - -void AnalyzerManagerPrivate::setupActions() -{ - Command *command = 0; - - // Menus - m_menu = ActionManager::createMenu(M_DEBUG_ANALYZER); - m_menu->menu()->setTitle(tr("&Analyze")); - m_menu->menu()->setEnabled(true); - - m_menu->appendGroup(G_ANALYZER_CONTROL); - m_menu->appendGroup(G_ANALYZER_TOOLS); - m_menu->appendGroup(G_ANALYZER_REMOTE_TOOLS); - m_menu->appendGroup(G_ANALYZER_OPTIONS); - - ActionContainer *menubar = ActionManager::actionContainer(MENU_BAR); - ActionContainer *mtools = ActionManager::actionContainer(M_TOOLS); - menubar->addMenu(mtools, m_menu); - - m_startAction = new QAction(tr("Start"), m_menu); - m_startAction->setIcon(Analyzer::Icons::ANALYZER_CONTROL_START.icon()); - ActionManager::registerAction(m_startAction, "Analyzer.Start"); - connect(m_startAction, &QAction::triggered, this, [this] { - QTC_ASSERT(m_descriptions.contains(m_currentActionId), return); - m_descriptions.value(m_currentActionId).startTool(); - }); - - m_stopAction = new QAction(tr("Stop"), m_menu); - m_stopAction->setEnabled(false); - m_stopAction->setIcon(ProjectExplorer::Icons::STOP_SMALL.icon()); - command = ActionManager::registerAction(m_stopAction, "Analyzer.Stop"); - m_menu->addAction(command, G_ANALYZER_CONTROL); - - m_menu->addSeparator(G_ANALYZER_TOOLS); - m_menu->addSeparator(G_ANALYZER_REMOTE_TOOLS); - m_menu->addSeparator(G_ANALYZER_OPTIONS); -} - -void AnalyzerManagerPrivate::delayedInit() -{ - if (m_mode) - return; - - m_mode = new Internal::AnalyzerMode(q); - createModeMainWindow(); - - connect(ModeManager::instance(), &ModeManager::currentModeChanged, - this, &AnalyzerManagerPrivate::modeChanged); - - // Right-side window with editor, output etc. - auto mainWindowSplitter = new MiniSplitter; - mainWindowSplitter->addWidget(m_mainWindow); - mainWindowSplitter->addWidget(new OutputPanePlaceHolder(m_mode, mainWindowSplitter)); - mainWindowSplitter->setStretchFactor(0, 10); - mainWindowSplitter->setStretchFactor(1, 0); - mainWindowSplitter->setOrientation(Qt::Vertical); - - // Navigation + right-side window. - auto splitter = new MiniSplitter; - splitter->addWidget(new NavigationWidgetPlaceHolder(m_mode)); - splitter->addWidget(mainWindowSplitter); - splitter->setStretchFactor(0, 0); - splitter->setStretchFactor(1, 1); - - auto modeContextObject = new IContext(this); - modeContextObject->setContext(Context(C_EDITORMANAGER)); - modeContextObject->setWidget(splitter); - ICore::addContextObject(modeContextObject); - m_mode->setWidget(splitter); - - Debugger::Internal::DebuggerPlugin::instance()->addAutoReleasedObject(m_mode); - - // Populate Windows->Views menu with standard actions. - Context analyzerContext(C_ANALYZEMODE); - ActionContainer *viewsMenu = ActionManager::actionContainer(M_WINDOW_VIEWS); - Command *cmd = ActionManager::registerAction(m_mainWindow->menuSeparator1(), - "Analyzer.Views.Separator1", analyzerContext); - cmd->setAttribute(Command::CA_Hide); - viewsMenu->addAction(cmd, G_DEFAULT_THREE); - cmd = ActionManager::registerAction(m_mainWindow->autoHideTitleBarsAction(), - "Analyzer.Views.AutoHideTitleBars", analyzerContext); - cmd->setAttribute(Command::CA_Hide); - viewsMenu->addAction(cmd, G_DEFAULT_THREE); - cmd = ActionManager::registerAction(m_mainWindow->menuSeparator2(), - "Analyzer.Views.Separator2", analyzerContext); - cmd->setAttribute(Command::CA_Hide); - viewsMenu->addAction(cmd, G_DEFAULT_THREE); - cmd = ActionManager::registerAction(m_mainWindow->resetLayoutAction(), - "Analyzer.Views.ResetSimple", analyzerContext); - cmd->setAttribute(Command::CA_Hide); - viewsMenu->addAction(cmd, G_DEFAULT_THREE); -} - -static QToolButton *toolButton(QAction *action) -{ - auto button = new QToolButton; - button->setDefaultAction(action); - return button; -} - -void AnalyzerManagerPrivate::createModeMainWindow() -{ - m_mainWindow->setObjectName(QLatin1String("AnalyzerManagerMainWindow")); - m_mainWindow->setLastSettingsName(QLatin1String(Internal::LAST_ACTIVE_ACTION)); - - auto editorHolderLayout = new QVBoxLayout; - editorHolderLayout->setMargin(0); - editorHolderLayout->setSpacing(0); - - auto editorAndFindWidget = new QWidget; - editorAndFindWidget->setLayout(editorHolderLayout); - editorHolderLayout->addWidget(new EditorManagerPlaceHolder(m_mode)); - editorHolderLayout->addWidget(new FindToolBarPlaceHolder(editorAndFindWidget)); - - auto documentAndRightPane = new MiniSplitter; - documentAndRightPane->addWidget(editorAndFindWidget); - documentAndRightPane->addWidget(new RightPanePlaceHolder(m_mode)); - documentAndRightPane->setStretchFactor(0, 1); - documentAndRightPane->setStretchFactor(1, 0); - - auto analyzeToolBar = new StyledBar; - analyzeToolBar->setProperty("topBorder", true); - - auto analyzeToolBarLayout = new QHBoxLayout(analyzeToolBar); - analyzeToolBarLayout->setMargin(0); - analyzeToolBarLayout->setSpacing(0); - analyzeToolBarLayout->addWidget(toolButton(m_startAction)); - analyzeToolBarLayout->addWidget(toolButton(m_stopAction)); - analyzeToolBarLayout->addWidget(new StyledSeparator); - analyzeToolBarLayout->addWidget(m_mainWindow->toolBox()); - analyzeToolBarLayout->addWidget(m_mainWindow->controlsStack()); - analyzeToolBarLayout->addWidget(m_mainWindow->statusLabel()); - analyzeToolBarLayout->addStretch(); - - auto dock = new QDockWidget(tr("Analyzer Toolbar")); - dock->setObjectName(QLatin1String("Analyzer Toolbar")); - dock->setWidget(analyzeToolBar); - dock->setFeatures(QDockWidget::NoDockWidgetFeatures); - dock->setProperty("managed_dockwidget", QLatin1String("true")); - dock->setAllowedAreas(Qt::BottomDockWidgetArea); - // hide title bar - dock->setTitleBarWidget(new QWidget(dock)); - m_mainWindow->addDockWidget(Qt::BottomDockWidgetArea, dock); - m_mainWindow->setToolBarDockWidget(dock); - - auto centralWidget = new QWidget; - m_mainWindow->setCentralWidget(centralWidget); - - auto centralLayout = new QVBoxLayout(centralWidget); - centralWidget->setLayout(centralLayout); - centralLayout->setMargin(0); - centralLayout->setSpacing(0); - centralLayout->addWidget(documentAndRightPane); - centralLayout->setStretch(0, 1); - centralLayout->setStretch(1, 0); -} - -bool AnalyzerManagerPrivate::showPromptDialog(const QString &title, const QString &text, - const QString &stopButtonText, const QString &cancelButtonText) const -{ - CheckableMessageBox messageBox(ICore::mainWindow()); - messageBox.setWindowTitle(title); - messageBox.setText(text); - messageBox.setStandardButtons(QDialogButtonBox::Yes|QDialogButtonBox::Cancel); - if (!stopButtonText.isEmpty()) - messageBox.button(QDialogButtonBox::Yes)->setText(stopButtonText); - if (!cancelButtonText.isEmpty()) - messageBox.button(QDialogButtonBox::Cancel)->setText(cancelButtonText); - messageBox.setDefaultButton(QDialogButtonBox::Yes); - messageBox.setCheckBoxVisible(false); - messageBox.exec(); - return messageBox.clickedStandardButton() == QDialogButtonBox::Yes; -} - -void AnalyzerManagerPrivate::modeChanged(IMode *mode) -{ - if (mode && mode == m_mode) { - m_mainWindow->setDockActionsVisible(true); - static bool firstTime = !m_currentActionId.isValid(); - if (firstTime) - selectSavedTool(); - firstTime = false; - updateRunActions(); - } else { - m_mainWindow->setDockActionsVisible(false); - } -} - -void AnalyzerManagerPrivate::selectSavedTool() -{ - const QSettings *settings = ICore::settings(); - - if (settings->contains(QLatin1String(Internal::LAST_ACTIVE_ACTION))) { - const Id lastAction = Id::fromSetting(settings->value(QLatin1String(Internal::LAST_ACTIVE_ACTION))); - selectAction(lastAction); - } - // fallback to first available tool - if (!m_descriptions.isEmpty()) - selectAction(m_descriptions.begin().key()); -} - -void AnalyzerManagerPrivate::selectAction(Id actionId) -{ - QTC_ASSERT(m_descriptions.contains(actionId), return); - if (m_currentActionId == actionId) - return; - - // Now change the tool. - m_currentActionId = actionId; - ActionDescription desc = m_descriptions.value(actionId); - - m_mainWindow->restorePerspective(desc.perspectiveId()); - - const int toolboxIndex = m_mainWindow->toolBox()->findText(desc.text()); - QTC_ASSERT(toolboxIndex >= 0, return); - m_mainWindow->toolBox()->setCurrentIndex(toolboxIndex); - - updateRunActions(); -} - -void AnalyzerManagerPrivate::registerAction(Id actionId, const ActionDescription &desc) -{ - delayedInit(); // Make sure that there is a valid IMode instance. - - auto action = new QAction(this); - action->setText(desc.text()); - action->setToolTip(desc.toolTip()); - m_actions.insert(actionId, action); - m_descriptions.insert(actionId, desc); - - int index = -1; - if (desc.menuGroup() == Constants::G_ANALYZER_REMOTE_TOOLS) { - index = m_mainWindow->toolBox()->count(); - } else if (desc.menuGroup() == Constants::G_ANALYZER_TOOLS) { - for (int i = m_mainWindow->toolBox()->count(); --i >= 0; ) - if (m_mainWindow->toolBox()->itemText(i).isEmpty()) - index = i; - } - - if (index >= 0) - m_mainWindow->toolBox()->insertItem(index, desc.text(), actionId.toSetting()); - - Id menuGroup = desc.menuGroup(); - if (menuGroup.isValid()) { - Command *command = ActionManager::registerAction(action, actionId); - m_menu->addAction(command, menuGroup); - } - - connect(action, &QAction::triggered, this, [this, desc, actionId] { - selectAction(actionId); - desc.startTool(); - }); -} - -void AnalyzerManagerPrivate::handleToolStarted() -{ - m_isRunning = true; // FIXME: Make less global. - updateRunActions(); -} - -void AnalyzerManagerPrivate::handleToolFinished() -{ - m_isRunning = false; - updateRunActions(); -} - -void AnalyzerManagerPrivate::updateRunActions() -{ - QString disabledReason; - bool enabled = false; - if (m_isRunning) - disabledReason = tr("An analysis is still in progress."); - else if (m_currentActionId.isValid()) - enabled = m_descriptions.value(m_currentActionId).isRunnable(&disabledReason); - else - disabledReason = tr("No analyzer tool selected."); - - m_startAction->setEnabled(enabled); - m_startAction->setToolTip(disabledReason); - m_mainWindow->toolBox()->setEnabled(!m_isRunning); - m_stopAction->setEnabled(m_isRunning); - - for (auto it = m_actions.begin(), end = m_actions.end(); it != end; ++it) - it.value()->setEnabled(!m_isRunning && m_descriptions.value(it.key()).isRunnable()); -} - -//////////////////////////////////////////////////////////////////// -// -// AnalyzerManager -// -//////////////////////////////////////////////////////////////////// - -static AnalyzerManagerPrivate *d = 0; - -AnalyzerManager::AnalyzerManager(QObject *parent) - : QObject(parent) -{ - QTC_CHECK(d == 0); - d = new AnalyzerManagerPrivate(this); -} - -AnalyzerManager::~AnalyzerManager() -{ - QTC_CHECK(d); - delete d; - d = 0; -} - -void AnalyzerManager::shutdown() -{ - d->m_mainWindow->saveCurrentPerspective(); -} - -void AnalyzerManager::registerAction(Id actionId, const ActionDescription &desc) -{ - d->registerAction(actionId, desc); -} - -void AnalyzerManager::registerDockWidget(Id dockId, QWidget *widget) -{ - QTC_ASSERT(!widget->objectName().isEmpty(), return); - QDockWidget *dockWidget = d->m_mainWindow->registerDockWidget(dockId, widget); - - QAction *toggleViewAction = dockWidget->toggleViewAction(); - toggleViewAction->setText(dockWidget->windowTitle()); - - Command *cmd = ActionManager::registerAction(toggleViewAction, - Id("Analyzer.").withSuffix(dockWidget->objectName())); - cmd->setAttribute(Command::CA_Hide); - - ActionContainer *viewsMenu = ActionManager::actionContainer(Id(M_WINDOW_VIEWS)); - viewsMenu->addAction(cmd); -} - -void AnalyzerManager::registerToolbar(Id toolbarId, QWidget *widget) -{ - d->m_mainWindow->registerToolbar(toolbarId, widget); -} - -Perspective::Operation::Operation(Id dockId, Id existing, Perspective::OperationType operationType, - bool visibleByDefault, Qt::DockWidgetArea area) - : dockId(dockId), existing(existing), operationType(operationType), - visibleByDefault(visibleByDefault), area(area) -{} - -Perspective::Perspective(std::initializer_list operations) - : m_operations(operations) -{ - for (const Operation &operation : operations) - m_docks.append(operation.dockId); -} - -void Perspective::addOperation(const Operation &operation) -{ - m_docks.append(operation.dockId); - m_operations.append(operation); -} - -void AnalyzerManager::registerPerspective(Id perspectiveId, const Perspective &perspective) -{ - d->m_mainWindow->registerPerspective(perspectiveId, perspective); -} - -void AnalyzerManager::selectAction(Id actionId, bool alsoRunIt) -{ - d->selectAction(actionId); - if (alsoRunIt) - d->m_descriptions.value(actionId).startTool(); -} - -void AnalyzerManager::enableMainWindow(bool on) -{ - d->m_mainWindow->setEnabled(on); -} - -void AnalyzerManager::showStatusMessage(const QString &message, int timeoutMS) -{ - d->m_mainWindow->showStatusMessage(message, timeoutMS); -} - -void AnalyzerManager::showPermanentStatusMessage(const QString &message) -{ - d->m_mainWindow->showStatusMessage(message, -1); -} - -void AnalyzerManager::showMode() -{ - if (d->m_mode) - ModeManager::activateMode(d->m_mode->id()); -} - -void AnalyzerManager::stopTool() -{ - stopAction()->trigger(); -} - -QAction *AnalyzerManager::stopAction() -{ - return d->m_stopAction; -} - -void AnalyzerManager::handleToolStarted() -{ - d->handleToolStarted(); -} - -void AnalyzerManager::handleToolFinished() -{ - d->handleToolFinished(); -} - -AnalyzerRunControl *AnalyzerManager::createRunControl(RunConfiguration *runConfiguration, Id runMode) -{ - foreach (const ActionDescription &action, d->m_descriptions) { - if (action.runMode() == runMode) - return action.runControlCreator()(runConfiguration, runMode); - } - return 0; -} - -bool operator==(const AnalyzerConnection &c1, const AnalyzerConnection &c2) -{ - return c1.connParams == c2.connParams - && c1.analyzerHost == c2.analyzerHost - && c1.analyzerSocket == c2.analyzerSocket - && c1.analyzerPort == c2.analyzerPort; -} - -} // namespace Analyzer diff --git a/src/plugins/debugger/analyzer/analyzermanager.h b/src/plugins/debugger/analyzer/analyzermanager.h index d4bfd35ab53..70209ea2914 100644 --- a/src/plugins/debugger/analyzer/analyzermanager.h +++ b/src/plugins/debugger/analyzer/analyzermanager.h @@ -27,7 +27,6 @@ #ifndef ANALYZERMANAGER_H #define ANALYZERMANAGER_H -#include "analyzerbase_global.h" #include "analyzerconstants.h" #include "../debuggermainwindow.h" @@ -48,7 +47,7 @@ QT_END_NAMESPACE namespace ProjectExplorer { class RunConfiguration; } -namespace Analyzer { +namespace Debugger { class AnalyzerRunControl; @@ -75,9 +74,9 @@ Q_DECLARE_FLAGS(ToolModes, ToolMode) * */ -class ANALYZER_EXPORT ActionDescription +class DEBUGGER_EXPORT ActionDescription { - Q_DECLARE_TR_FUNCTIONS(Analyzer::AnalyzerAction) + Q_DECLARE_TR_FUNCTIONS(Debugger::AnalyzerAction) public: ActionDescription() {} @@ -85,8 +84,8 @@ public: Core::Id menuGroup() const { return m_menuGroup; } void setMenuGroup(Core::Id menuGroup) { m_menuGroup = menuGroup; } - Core::Id perspectiveId() const { return m_perspective; } - void setPerspectiveId(Core::Id id) { m_perspective = id; } + QByteArray perspectiveId() const { return m_perspectiveId; } + void setPerspectiveId(const QByteArray &id) { m_perspectiveId = id; } void setToolMode(QFlags mode) { m_toolMode = mode; } Core::Id runMode() const { return m_runMode; } @@ -120,7 +119,7 @@ private: QString m_text; QString m_toolTip; Core::Id m_menuGroup; - Core::Id m_perspective; + QByteArray m_perspectiveId; QFlags m_toolMode = AnyMode; Core::Id m_runMode; RunControlCreator m_runControlCreator; @@ -128,41 +127,28 @@ private: ToolPreparer m_toolPreparer; }; -// FIXME: Merge with AnalyzerPlugin. -class ANALYZER_EXPORT AnalyzerManager : public QObject -{ - Q_OBJECT +// FIXME: Merge with something sensible. -public: - explicit AnalyzerManager(QObject *parent); - ~AnalyzerManager(); +// Register a tool for a given start mode. +DEBUGGER_EXPORT void registerAction(Core::Id actionId, const ActionDescription &desc, QAction *startAction = 0); +DEBUGGER_EXPORT void registerPerspective(const QByteArray &perspectiveId, const Utils::Perspective &perspective); +DEBUGGER_EXPORT void registerToolbar(const QByteArray &perspectiveId, const Utils::ToolbarDescription &desc); - static void shutdown(); +DEBUGGER_EXPORT void enableMainWindow(bool on); - // Register a tool for a given start mode. - static void registerAction(Core::Id actionId, const ActionDescription &desc); - static void registerPerspective(Core::Id perspectiveId, const Perspective &perspective); - static void registerDockWidget(Core::Id dockId, QWidget *widget); - static void registerToolbar(Core::Id toolbarId, QWidget *widget); +DEBUGGER_EXPORT void selectPerspective(const QByteArray &perspectiveId); +DEBUGGER_EXPORT void runAction(Core::Id actionId); - static void enableMainWindow(bool on); +// Convenience functions. +DEBUGGER_EXPORT void showStatusMessage(const QString &message, int timeoutMS = 10000); +DEBUGGER_EXPORT void showPermanentStatusMessage(const QString &message); - static void showMode(); - static void selectAction(Core::Id actionId, bool alsoRunIt = false); - static void stopTool(); +DEBUGGER_EXPORT QAction *createStartAction(); +DEBUGGER_EXPORT QAction *createStopAction(); - // Convenience functions. - static void showStatusMessage(const QString &message, int timeoutMS = 10000); - static void showPermanentStatusMessage(const QString &message); +DEBUGGER_EXPORT AnalyzerRunControl *createAnalyzerRunControl( + ProjectExplorer::RunConfiguration *runConfiguration, Core::Id runMode); - static void handleToolStarted(); - static void handleToolFinished(); - static QAction *stopAction(); - - static AnalyzerRunControl *createRunControl( - ProjectExplorer::RunConfiguration *runConfiguration, Core::Id runMode); -}; - -} // namespace Analyzer +} // namespace Debugger #endif // ANALYZERMANAGER_H diff --git a/src/plugins/debugger/analyzer/analyzerrunconfigwidget.cpp b/src/plugins/debugger/analyzer/analyzerrunconfigwidget.cpp index 9504ebce9fb..94e0314d5ab 100644 --- a/src/plugins/debugger/analyzer/analyzerrunconfigwidget.cpp +++ b/src/plugins/debugger/analyzer/analyzerrunconfigwidget.cpp @@ -36,7 +36,7 @@ #include #include -namespace Analyzer { +namespace Debugger { AnalyzerRunConfigWidget::AnalyzerRunConfigWidget(ProjectExplorer::IRunConfigurationAspect *aspect) { @@ -105,4 +105,4 @@ void AnalyzerRunConfigWidget::restoreGlobal() m_aspect->resetProjectToGlobalSettings(); } -} // namespace Analyzer +} // namespace Debugger diff --git a/src/plugins/debugger/analyzer/analyzerrunconfigwidget.h b/src/plugins/debugger/analyzer/analyzerrunconfigwidget.h index aa18b74156d..ad4ba8cc2d3 100644 --- a/src/plugins/debugger/analyzer/analyzerrunconfigwidget.h +++ b/src/plugins/debugger/analyzer/analyzerrunconfigwidget.h @@ -27,7 +27,7 @@ #ifndef ANALYZERRUNCONFIGWIDGET_H #define ANALYZERRUNCONFIGWIDGET_H -#include "analyzerbase_global.h" +#include #include @@ -38,9 +38,9 @@ QT_END_NAMESPACE namespace Utils { class DetailsWidget; } -namespace Analyzer { +namespace Debugger { -class ANALYZER_EXPORT AnalyzerRunConfigWidget : public ProjectExplorer::RunConfigWidget +class DEBUGGER_EXPORT AnalyzerRunConfigWidget : public ProjectExplorer::RunConfigWidget { Q_OBJECT @@ -62,6 +62,6 @@ private: Utils::DetailsWidget *m_details; }; -} // namespace Analyzer +} // namespace Debugger #endif // ANALYZERRUNCONFIGWIDGET_H diff --git a/src/plugins/debugger/analyzer/analyzerruncontrol.cpp b/src/plugins/debugger/analyzer/analyzerruncontrol.cpp index 9d4957e54f2..18e74abe185 100644 --- a/src/plugins/debugger/analyzer/analyzerruncontrol.cpp +++ b/src/plugins/debugger/analyzer/analyzerruncontrol.cpp @@ -37,60 +37,12 @@ using namespace ProjectExplorer; -////////////////////////////////////////////////////////////////////////// -// -// AnalyzerRunControl -// -////////////////////////////////////////////////////////////////////////// - -namespace Analyzer { +namespace Debugger { AnalyzerRunControl::AnalyzerRunControl(RunConfiguration *runConfiguration, Core::Id runMode) : RunControl(runConfiguration, runMode) { setIcon(Icons::ANALYZER_CONTROL_START); - - connect(this, &AnalyzerRunControl::finished, - this, &AnalyzerRunControl::runControlFinished); - connect(AnalyzerManager::stopAction(), &QAction::triggered, - this, &AnalyzerRunControl::stopIt); } -void AnalyzerRunControl::stopIt() -{ - if (stop() == RunControl::StoppedSynchronously) - AnalyzerManager::handleToolFinished(); -} - -void AnalyzerRunControl::runControlFinished() -{ - m_isRunning = false; - AnalyzerManager::handleToolFinished(); -} - -void AnalyzerRunControl::start() -{ - AnalyzerManager::handleToolStarted(); - - if (startEngine()) { - m_isRunning = true; - emit started(); - } -} - -RunControl::StopResult AnalyzerRunControl::stop() -{ - if (!m_isRunning) - return StoppedSynchronously; - - stopEngine(); - m_isRunning = false; - return AsynchronousStop; -} - -bool AnalyzerRunControl::isRunning() const -{ - return m_isRunning; -} - -} // namespace Analyzer +} // namespace Debugger diff --git a/src/plugins/debugger/analyzer/analyzerruncontrol.h b/src/plugins/debugger/analyzer/analyzerruncontrol.h index d13adc98b76..a919a7f3638 100644 --- a/src/plugins/debugger/analyzer/analyzerruncontrol.h +++ b/src/plugins/debugger/analyzer/analyzerruncontrol.h @@ -27,31 +27,26 @@ #ifndef ANALYZERRUNCONTROL_H #define ANALYZERRUNCONTROL_H -#include "analyzerbase_global.h" +#include #include #include -namespace Analyzer { +namespace Debugger { /** * An AnalyzerRunControl instance handles the launch of an analyzation tool. * * It gets created for each launch and deleted when the launch is stopped or ended. */ -class ANALYZER_EXPORT AnalyzerRunControl : public ProjectExplorer::RunControl +class DEBUGGER_EXPORT AnalyzerRunControl : public ProjectExplorer::RunControl { Q_OBJECT public: AnalyzerRunControl(ProjectExplorer::RunConfiguration *runConfiguration, Core::Id runMode); - /// Start analyzation process. - virtual bool startEngine() = 0; - /// Trigger async stop of the analyzation process. - virtual void stopEngine() = 0; - /// Controller actions. virtual bool canPause() const { return false; } virtual void pause() {} @@ -60,28 +55,16 @@ public: virtual void notifyRemoteSetupDone(quint16) {} virtual void notifyRemoteFinished() {} - // ProjectExplorer::RunControl - void start() override; - StopResult stop() override; - bool isRunning() const override; +signals: + void starting(); public slots: virtual void logApplicationMessage(const QString &, Utils::OutputFormat) { } -private slots: - void stopIt(); - void runControlFinished(); - -signals: - /// Must be emitted when the engine is starting. - void starting(); - private: bool supportsReRunning() const override { return false; } - -protected: - bool m_isRunning; }; -} // namespace Analyzer + +} // namespace Debugger #endif // ANALYZERRUNCONTROL_H diff --git a/src/plugins/debugger/analyzer/analyzerstartparameters.h b/src/plugins/debugger/analyzer/analyzerstartparameters.h index 1b4a3a6bdff..73226c0e33e 100644 --- a/src/plugins/debugger/analyzer/analyzerstartparameters.h +++ b/src/plugins/debugger/analyzer/analyzerstartparameters.h @@ -26,16 +26,16 @@ #ifndef ANALYZERSTARTPARAMETERS_H #define ANALYZERSTARTPARAMETERS_H -#include "analyzerbase_global.h" +#include #include #include #include -namespace Analyzer { +namespace Debugger { -class ANALYZER_EXPORT AnalyzerConnection +class DEBUGGER_EXPORT AnalyzerConnection { public: QSsh::SshConnectionParameters connParams; @@ -44,8 +44,8 @@ public: quint16 analyzerPort = 0; }; -ANALYZER_EXPORT bool operator==(const AnalyzerConnection &c1, const AnalyzerConnection &c2); +DEBUGGER_EXPORT bool operator==(const AnalyzerConnection &c1, const AnalyzerConnection &c2); -} // namespace Analyzer +} // namespace Debugger #endif // ANALYZERSTARTPARAMETERS_H diff --git a/src/plugins/debugger/analyzer/analyzerutils.cpp b/src/plugins/debugger/analyzer/analyzerutils.cpp index cafafa1f114..c38e54bb454 100644 --- a/src/plugins/debugger/analyzer/analyzerutils.cpp +++ b/src/plugins/debugger/analyzer/analyzerutils.cpp @@ -39,7 +39,7 @@ #include -using namespace Analyzer; +using namespace Debugger; using namespace Core; using namespace ProjectExplorer; @@ -92,7 +92,7 @@ CPlusPlus::Symbol *AnalyzerUtils::findSymbolUnderCursor() void AnalyzerUtils::logToIssuesPane(Task::TaskType type, const QString &message) { - TaskHub::addTask(type, message, Analyzer::Constants::ANALYZERTASK_ID); + TaskHub::addTask(type, message, Debugger::Constants::ANALYZERTASK_ID); if (type == Task::Error) TaskHub::requestPopup(); } diff --git a/src/plugins/debugger/analyzer/analyzerutils.h b/src/plugins/debugger/analyzer/analyzerutils.h index e173c58d1e5..65f3de5f304 100644 --- a/src/plugins/debugger/analyzer/analyzerutils.h +++ b/src/plugins/debugger/analyzer/analyzerutils.h @@ -26,7 +26,7 @@ #ifndef ANALYZERUTILS_H #define ANALYZERUTILS_H -#include "analyzerbase_global.h" +#include #include @@ -34,8 +34,8 @@ namespace CPlusPlus { class Symbol; } namespace AnalyzerUtils { - ANALYZER_EXPORT CPlusPlus::Symbol *findSymbolUnderCursor(); - ANALYZER_EXPORT void logToIssuesPane(ProjectExplorer::Task::TaskType type, + DEBUGGER_EXPORT CPlusPlus::Symbol *findSymbolUnderCursor(); + DEBUGGER_EXPORT void logToIssuesPane(ProjectExplorer::Task::TaskType type, const QString &message); } diff --git a/src/plugins/debugger/analyzer/detailederrorview.cpp b/src/plugins/debugger/analyzer/detailederrorview.cpp index c539102c4f1..7a47e408576 100644 --- a/src/plugins/debugger/analyzer/detailederrorview.cpp +++ b/src/plugins/debugger/analyzer/detailederrorview.cpp @@ -44,7 +44,7 @@ #include #include -namespace Analyzer { +namespace Debugger { namespace Internal { class DetailedErrorDelegate : public QStyledItemDelegate @@ -138,8 +138,7 @@ DetailedErrorView::DetailedErrorView(QWidget *parent) : }); connect(this, &QAbstractItemView::clicked, [](const QModelIndex &index) { if (index.column() == LocationColumn) { - const auto loc = index.model() - ->data(index, Analyzer::DetailedErrorView::LocationRole) + const auto loc = index.model()->data(index, DetailedErrorView::LocationRole) .value(); if (loc.isValid()) Core::EditorManager::openEditorAt(loc.filePath, loc.line, loc.column - 1); @@ -212,6 +211,6 @@ void DetailedErrorView::setCurrentRow(int row) scrollTo(index); } -} // namespace Analyzer +} // namespace Debugger #include "detailederrorview.moc" diff --git a/src/plugins/debugger/analyzer/detailederrorview.h b/src/plugins/debugger/analyzer/detailederrorview.h index 485e082e08e..ab141ad57ec 100644 --- a/src/plugins/debugger/analyzer/detailederrorview.h +++ b/src/plugins/debugger/analyzer/detailederrorview.h @@ -26,14 +26,14 @@ #ifndef DETAILEDERRORVIEW_H #define DETAILEDERRORVIEW_H -#include "analyzerbase_global.h" +#include #include #include -namespace Analyzer { +namespace Debugger { -class ANALYZER_EXPORT DetailedErrorView : public QTreeView +class DEBUGGER_EXPORT DetailedErrorView : public QTreeView { Q_OBJECT @@ -67,6 +67,6 @@ private: QAction * const m_copyAction; }; -} // namespace Analyzer +} // namespace Debugger #endif // DETAILEDERRORVIEW_H diff --git a/src/plugins/debugger/analyzer/diagnosticlocation.cpp b/src/plugins/debugger/analyzer/diagnosticlocation.cpp index 7fa15f83c84..e5f6c8ee495 100644 --- a/src/plugins/debugger/analyzer/diagnosticlocation.cpp +++ b/src/plugins/debugger/analyzer/diagnosticlocation.cpp @@ -25,7 +25,7 @@ #include "diagnosticlocation.h" -namespace Analyzer { +namespace Debugger { DiagnosticLocation::DiagnosticLocation() : line(0), column(0) { @@ -56,5 +56,5 @@ QDebug operator<<(QDebug dbg, const DiagnosticLocation &location) return dbg.space(); } -} // namespace Analyzer +} // namespace Debugger diff --git a/src/plugins/debugger/analyzer/diagnosticlocation.h b/src/plugins/debugger/analyzer/diagnosticlocation.h index 497698413dd..61fdbe22988 100644 --- a/src/plugins/debugger/analyzer/diagnosticlocation.h +++ b/src/plugins/debugger/analyzer/diagnosticlocation.h @@ -26,15 +26,15 @@ #ifndef ANALYZERDIAGNOSTIC_H #define ANALYZERDIAGNOSTIC_H -#include "analyzerbase_global.h" +#include #include #include #include -namespace Analyzer { +namespace Debugger { -class ANALYZER_EXPORT DiagnosticLocation +class DEBUGGER_EXPORT DiagnosticLocation { public: DiagnosticLocation(); @@ -49,12 +49,12 @@ public: int column; }; -ANALYZER_EXPORT bool operator==(const DiagnosticLocation &first, const DiagnosticLocation &second); -ANALYZER_EXPORT QDebug operator<<(QDebug dbg, const DiagnosticLocation &location); +DEBUGGER_EXPORT bool operator==(const DiagnosticLocation &first, const DiagnosticLocation &second); +DEBUGGER_EXPORT QDebug operator<<(QDebug dbg, const DiagnosticLocation &location); -} // namespace Analyzer +} // namespace Debugger -Q_DECLARE_METATYPE(Analyzer::DiagnosticLocation) +Q_DECLARE_METATYPE(Debugger::DiagnosticLocation) #endif // Include guard. diff --git a/src/plugins/debugger/analyzer/startremotedialog.cpp b/src/plugins/debugger/analyzer/startremotedialog.cpp index 79c37c390ff..8616ab2f782 100644 --- a/src/plugins/debugger/analyzer/startremotedialog.cpp +++ b/src/plugins/debugger/analyzer/startremotedialog.cpp @@ -41,7 +41,7 @@ using namespace ProjectExplorer; using namespace Utils; -namespace Analyzer { +namespace Debugger { namespace Internal { class StartRemoteDialogPrivate @@ -146,4 +146,4 @@ StandardRunnable StartRemoteDialog::runnable() const return r; } -} // namespace Analyzer +} // namespace Debugger diff --git a/src/plugins/debugger/analyzer/startremotedialog.h b/src/plugins/debugger/analyzer/startremotedialog.h index f6694d08efc..ff559a51bf0 100644 --- a/src/plugins/debugger/analyzer/startremotedialog.h +++ b/src/plugins/debugger/analyzer/startremotedialog.h @@ -26,7 +26,7 @@ #ifndef STARTREMOTEDIALOG_H #define STARTREMOTEDIALOG_H -#include "analyzerbase_global.h" +#include #include @@ -34,29 +34,28 @@ namespace QSsh { class SshConnectionParameters; } namespace ProjectExplorer { class StandardRunnable; } -namespace Analyzer { +namespace Debugger { namespace Internal { class StartRemoteDialogPrivate; } -class ANALYZER_EXPORT StartRemoteDialog : public QDialog +class DEBUGGER_EXPORT StartRemoteDialog : public QDialog { Q_OBJECT public: explicit StartRemoteDialog(QWidget *parent = 0); - ~StartRemoteDialog(); + ~StartRemoteDialog() override; QSsh::SshConnectionParameters sshParams() const; ProjectExplorer::StandardRunnable runnable() const; -private slots: - void validate(); - virtual void accept(); - private: + void validate(); + void accept() override; + Internal::StartRemoteDialogPrivate *d; }; -} // namespace Analyzer +} // namespace Debugger #endif // STARTREMOTEDIALOG_H diff --git a/src/plugins/debugger/cdb/cdbengine.cpp b/src/plugins/debugger/cdb/cdbengine.cpp index f9317178bb1..c323cf6cb71 100644 --- a/src/plugins/debugger/cdb/cdbengine.cpp +++ b/src/plugins/debugger/cdb/cdbengine.cpp @@ -32,6 +32,7 @@ #include #include #include +#include #include #include #include diff --git a/src/plugins/debugger/debugger.qbs b/src/plugins/debugger/debugger.qbs index 9a927632f1f..df08a58de4d 100644 --- a/src/plugins/debugger/debugger.qbs +++ b/src/plugins/debugger/debugger.qbs @@ -234,10 +234,8 @@ QtcPlugin { files: [ "analyzer/analyzerbase.qrc", - "analyzer/analyzerbase_global.h", "analyzer/analyzerconstants.h", "analyzer/analyzericons.h", - "analyzer/analyzermanager.cpp", "analyzer/analyzermanager.h", "analyzer/analyzerrunconfigwidget.cpp", "analyzer/analyzerrunconfigwidget.h", diff --git a/src/plugins/debugger/debuggerconstants.h b/src/plugins/debugger/debuggerconstants.h index b5966c35209..5964860883e 100644 --- a/src/plugins/debugger/debuggerconstants.h +++ b/src/plugins/debugger/debuggerconstants.h @@ -39,6 +39,9 @@ const char C_DEBUGMODE[] = "Debugger.DebugMode"; const char C_CPPDEBUGGER[] = "Gdb Debugger"; const char C_QMLDEBUGGER[] = "Qml/JavaScript Debugger"; +const char CppPerspectiveId[] = "Debugger.Perspective.Cpp"; +const char QmlPerspectiveId[] = "Debugger.Perspective.Qml"; + // Menu Groups const char G_GENERAL[] = "Debugger.Group.General"; const char G_SPECIAL[] = "Debugger.Group.Special"; diff --git a/src/plugins/debugger/debuggercore.h b/src/plugins/debugger/debuggercore.h index 7431f4cab58..023278d4271 100644 --- a/src/plugins/debugger/debuggercore.h +++ b/src/plugins/debugger/debuggercore.h @@ -74,7 +74,6 @@ bool isReverseDebugging(); void runControlStarted(DebuggerEngine *engine); void runControlFinished(DebuggerEngine *engine); void displayDebugger(DebuggerEngine *engine, bool updateEngine); -DebuggerLanguages activeLanguages(); void synchronizeBreakpoints(); QWidget *mainWindow(); diff --git a/src/plugins/debugger/debuggerengine.cpp b/src/plugins/debugger/debuggerengine.cpp index 9ba2a3697df..42c3e80ee59 100644 --- a/src/plugins/debugger/debuggerengine.cpp +++ b/src/plugins/debugger/debuggerengine.cpp @@ -1836,24 +1836,42 @@ void DebuggerEngine::validateExecutable(DebuggerRunParameters *sp) return; const bool warnOnRelease = boolSetting(WarnOnReleaseBuilds); + bool warnOnInappropriateDebugger = false; QString detailedWarning; switch (sp->toolChainAbi.binaryFormat()) { case Abi::PEFormat: { - if (!warnOnRelease || (sp->masterEngineType != CdbEngineType)) + if (sp->masterEngineType != CdbEngineType) { + warnOnInappropriateDebugger = true; + detailedWarning = tr( + "The inferior is in the Portable Executable format.\n" + "Selecting CDB as debugger would improve the debugging " + "experience for this binary format."); return; - if (!binary.endsWith(QLatin1String(".exe"), Qt::CaseInsensitive)) - binary.append(QLatin1String(".exe")); - QString errorMessage; - QStringList rc; - if (getPDBFiles(binary, &rc, &errorMessage) && !rc.isEmpty()) + } else if (warnOnRelease) { + if (!binary.endsWith(QLatin1String(".exe"), Qt::CaseInsensitive)) + binary.append(QLatin1String(".exe")); + QString errorMessage; + QStringList rc; + if (getPDBFiles(binary, &rc, &errorMessage) && !rc.isEmpty()) + return; + if (!errorMessage.isEmpty()) { + detailedWarning.append(QLatin1Char('\n')); + detailedWarning.append(errorMessage); + } + } else { return; - if (!errorMessage.isEmpty()) { - detailedWarning.append(QLatin1Char('\n')); - detailedWarning.append(errorMessage); } break; } case Abi::ElfFormat: { + if (sp->masterEngineType == CdbEngineType) { + warnOnInappropriateDebugger = true; + detailedWarning = tr( + "The inferior is in the ELF format.\n" + "Selecting GDB or LLDB as debugger would improve the debugging " + "experience for this binary format."); + return; + } Utils::ElfReader reader(binary); Utils::ElfData elfData = reader.readHeaders(); @@ -1951,11 +1969,17 @@ void DebuggerEngine::validateExecutable(DebuggerRunParameters *sp) default: return; } - if (warnOnRelease) { + if (warnOnInappropriateDebugger) { AsynchronousMessageBox::information(tr("Warning"), - tr("This does not seem to be a \"Debug\" build.\n" - "Setting breakpoints by file name and line number may fail.") - + QLatin1Char('\n') + detailedWarning); + tr("The selected debugger may be inappropiate for the inferior.\n" + "Examining symbols and setting breakpoints by file name and line number " + "may fail.\n") + + QLatin1Char('\n') + detailedWarning); + } else if (warnOnRelease) { + AsynchronousMessageBox::information(tr("Warning"), + tr("This does not seem to be a \"Debug\" build.\n" + "Setting breakpoints by file name and line number may fail.") + + QLatin1Char('\n') + detailedWarning); } } diff --git a/src/plugins/debugger/debuggerinternalconstants.h b/src/plugins/debugger/debuggerinternalconstants.h index 89afc314f66..3b9f65977ce 100644 --- a/src/plugins/debugger/debuggerinternalconstants.h +++ b/src/plugins/debugger/debuggerinternalconstants.h @@ -29,6 +29,21 @@ #include namespace Debugger { +namespace Internal { + +// DebuggerMainWindow dock widget names +const char DOCKWIDGET_BREAK[] = "Debugger.Docks.Break"; +const char DOCKWIDGET_MODULES[] = "Debugger.Docks.Modules"; +const char DOCKWIDGET_REGISTER[] = "Debugger.Docks.Register"; +const char DOCKWIDGET_OUTPUT[] = "Debugger.Docks.Output"; +const char DOCKWIDGET_SNAPSHOTS[] = "Debugger.Docks.Snapshots"; +const char DOCKWIDGET_STACK[] = "Debugger.Docks.Stack"; +const char DOCKWIDGET_SOURCE_FILES[] = "Debugger.Docks.SourceFiles"; +const char DOCKWIDGET_THREADS[] = "Debugger.Docks.Threads"; +const char DOCKWIDGET_WATCHERS[] = "Debugger.Docks.LocalsAndWatchers"; + +} // namespace Internal + namespace Constants { const char DEBUGGER_COMMON_SETTINGS_ID[] = "A.Debugger.General"; diff --git a/src/plugins/debugger/debuggermainwindow.cpp b/src/plugins/debugger/debuggermainwindow.cpp index dbcfe449ae8..c118d048107 100644 --- a/src/plugins/debugger/debuggermainwindow.cpp +++ b/src/plugins/debugger/debuggermainwindow.cpp @@ -24,37 +24,60 @@ ****************************************************************************/ #include "debuggermainwindow.h" +#include "debuggerconstants.h" +#include "debuggerinternalconstants.h" +#include "analyzer/analyzericons.h" +#include +#include +#include +#include +#include +#include #include +#include +#include +#include +#include + +#include #include +#include #include #include +#include +#include #include +#include -using namespace Analyzer; +using namespace Debugger; using namespace Core; -using namespace Utils; -namespace Debugger { -namespace Internal { +namespace Utils { -MainWindowBase::MainWindowBase() +const char LAST_PERSPECTIVE_KEY[] = "LastPerspective"; + +DebuggerMainWindow::DebuggerMainWindow() { m_controlsStackWidget = new QStackedWidget; m_statusLabel = new Utils::StatusLabel; - m_toolBox = new QComboBox; + + m_perspectiveChooser = new QComboBox; + m_perspectiveChooser->setObjectName(QLatin1String("PerspectiveChooser")); + connect(m_perspectiveChooser, static_cast(&QComboBox::activated), + this, [this](int item) { restorePerspective(m_perspectiveChooser->itemData(item).toByteArray()); }); setDockNestingEnabled(true); setDockActionsVisible(false); setDocumentMode(true); connect(this, &FancyMainWindow::resetLayout, - this, &MainWindowBase::resetCurrentPerspective); + this, &DebuggerMainWindow::resetCurrentPerspective); } -MainWindowBase::~MainWindowBase() +DebuggerMainWindow::~DebuggerMainWindow() { // as we have to setParent(0) on dock widget that are not selected, // we keep track of all and make sure we don't leak any @@ -64,64 +87,229 @@ MainWindowBase::~MainWindowBase() } } -void MainWindowBase::registerPerspective(Id perspectiveId, const Perspective &perspective) +void DebuggerMainWindow::registerPerspective(const QByteArray &perspectiveId, const Perspective &perspective) { m_perspectiveForPerspectiveId.insert(perspectiveId, perspective); + m_perspectiveChooser->addItem(perspective.name(), perspectiveId); + // adjust width if necessary + const int oldWidth = m_perspectiveChooser->width(); + const int contentWidth = m_perspectiveChooser->fontMetrics().width(perspective.name()); + QStyleOptionComboBox option; + option.initFrom(m_perspectiveChooser); + const QSize sz(contentWidth, 1); + const int width = m_perspectiveChooser->style()->sizeFromContents( + QStyle::CT_ComboBox, &option, sz).width(); + if (width > oldWidth) + m_perspectiveChooser->setFixedWidth(width); } -void MainWindowBase::registerToolbar(Id perspectiveId, QWidget *widget) +void DebuggerMainWindow::registerToolbar(const QByteArray &perspectiveId, QWidget *widget) { m_toolbarForPerspectiveId.insert(perspectiveId, widget); m_controlsStackWidget->addWidget(widget); } -void MainWindowBase::showStatusMessage(const QString &message, int timeoutMS) +void DebuggerMainWindow::showStatusMessage(const QString &message, int timeoutMS) { m_statusLabel->showStatusMessage(message, timeoutMS); } -void MainWindowBase::resetCurrentPerspective() +QDockWidget *DebuggerMainWindow::dockWidget(const QByteArray &dockId) const +{ + return m_dockForDockId.value(dockId); +} + +QWidget *DebuggerMainWindow::modeWindow() +{ + return m_modeWindow; +} + +void DebuggerMainWindow::resetCurrentPerspective() { loadPerspectiveHelper(m_currentPerspectiveId, false); } -void MainWindowBase::restorePerspective(Id perspectiveId) +void DebuggerMainWindow::restorePerspective(const QByteArray &perspectiveId) { loadPerspectiveHelper(perspectiveId, true); + + int index = m_perspectiveChooser->findData(perspectiveId); + if (index == -1) + index = m_perspectiveChooser->findData(m_currentPerspectiveId); + if (index != -1) + m_perspectiveChooser->setCurrentIndex(index); } -void MainWindowBase::loadPerspectiveHelper(Id perspectiveId, bool fromStoredSettings) +void DebuggerMainWindow::finalizeSetup(Core::IMode *mode, QWidget *central) { - QTC_ASSERT(perspectiveId.isValid(), return); + auto viewButton = new QToolButton; + viewButton->setText(tr("Views")); + auto toolbar = new Utils::StyledBar; + toolbar->setProperty("topBorder", true); + auto hbox = new QHBoxLayout(toolbar); + hbox->setMargin(0); + hbox->setSpacing(0); + hbox->addWidget(m_perspectiveChooser); + hbox->addWidget(m_controlsStackWidget); + hbox->addWidget(m_statusLabel); + hbox->addWidget(new Utils::StyledSeparator); + hbox->addStretch(); + hbox->addWidget(viewButton); + + connect(viewButton, &QAbstractButton::clicked, [this, viewButton] { + QMenu menu; + addDockActionsToMenu(&menu); + menu.exec(viewButton->mapToGlobal(QPoint())); + }); + + Context debugcontext(Debugger::Constants::C_DEBUGMODE); + + ActionContainer *viewsMenu = ActionManager::actionContainer(Core::Constants::M_WINDOW_VIEWS); + Command *cmd = ActionManager::registerAction(menuSeparator1(), + "Debugger.Views.Separator1", debugcontext); + cmd->setAttribute(Command::CA_Hide); + viewsMenu->addAction(cmd, Core::Constants::G_DEFAULT_THREE); + cmd = ActionManager::registerAction(autoHideTitleBarsAction(), + "Debugger.Views.AutoHideTitleBars", debugcontext); + cmd->setAttribute(Command::CA_Hide); + viewsMenu->addAction(cmd, Core::Constants::G_DEFAULT_THREE); + cmd = ActionManager::registerAction(menuSeparator2(), + "Debugger.Views.Separator2", debugcontext); + cmd->setAttribute(Command::CA_Hide); + viewsMenu->addAction(cmd, Core::Constants::G_DEFAULT_THREE); + cmd = ActionManager::registerAction(resetLayoutAction(), + "Debugger.Views.ResetSimple", debugcontext); + cmd->setAttribute(Command::CA_Hide); + viewsMenu->addAction(cmd, Core::Constants::G_DEFAULT_THREE); + + addDockActionsToMenu(viewsMenu->menu()); + + auto dock = new QDockWidget(tr("Toolbar")); + dock->setObjectName(QLatin1String("Toolbar")); + dock->setFeatures(QDockWidget::NoDockWidgetFeatures); + dock->setAllowedAreas(Qt::BottomDockWidgetArea); + dock->setTitleBarWidget(new QWidget(dock)); // hide title bar + dock->setProperty("managed_dockwidget", QLatin1String("true")); + dock->setWidget(toolbar); + m_toolbarDock = dock; + + addDockWidget(Qt::BottomDockWidgetArea, dock); + + if (!central) + central = new EditorManagerPlaceHolder(mode); + + auto editorHolderLayout = new QVBoxLayout; + editorHolderLayout->setMargin(0); + editorHolderLayout->setSpacing(0); + + auto editorAndFindWidget = new QWidget; + editorAndFindWidget->setLayout(editorHolderLayout); + editorHolderLayout->addWidget(central); + editorHolderLayout->addWidget(new FindToolBarPlaceHolder(editorAndFindWidget)); + + auto documentAndRightPane = new MiniSplitter; + documentAndRightPane->addWidget(editorAndFindWidget); + documentAndRightPane->addWidget(new RightPanePlaceHolder(mode)); + documentAndRightPane->setStretchFactor(0, 1); + documentAndRightPane->setStretchFactor(1, 0); + + auto centralEditorWidget = new QWidget; + auto centralLayout = new QVBoxLayout(centralEditorWidget); + centralEditorWidget->setLayout(centralLayout); + centralLayout->setMargin(0); + centralLayout->setSpacing(0); + centralLayout->addWidget(documentAndRightPane); + centralLayout->setStretch(0, 1); + centralLayout->setStretch(1, 0); + + // Right-side window with editor, output etc. + auto mainWindowSplitter = new MiniSplitter; + mainWindowSplitter->addWidget(this); + mainWindowSplitter->addWidget(new OutputPanePlaceHolder(mode, mainWindowSplitter)); + auto outputPane = new OutputPanePlaceHolder(mode, mainWindowSplitter); + outputPane->setObjectName(QLatin1String("DebuggerOutputPanePlaceHolder")); + mainWindowSplitter->addWidget(outputPane); + mainWindowSplitter->setStretchFactor(0, 10); + mainWindowSplitter->setStretchFactor(1, 0); + mainWindowSplitter->setOrientation(Qt::Vertical); + + // Navigation and right-side window. + auto splitter = new MiniSplitter; + splitter->setFocusProxy(central); + splitter->addWidget(new NavigationWidgetPlaceHolder(mode)); + splitter->addWidget(mainWindowSplitter); + splitter->setStretchFactor(0, 0); + splitter->setStretchFactor(1, 1); + splitter->setObjectName(QLatin1String("DebugModeWidget")); + setCentralWidget(centralEditorWidget); + + m_modeWindow = splitter; +} + +void DebuggerMainWindow::loadPerspectiveHelper(const QByteArray &perspectiveId, bool fromStoredSettings) +{ // Clean up old perspective. - closeCurrentPerspective(); + if (!m_currentPerspectiveId.isEmpty()) { + saveCurrentPerspective(); + foreach (QDockWidget *dockWidget, m_dockForDockId) { + QTC_ASSERT(dockWidget, continue); + removeDockWidget(dockWidget); + dockWidget->hide(); + // Prevent saveState storing the data of the wrong children. + dockWidget->setParent(0); + } + + ICore::removeAdditionalContext(Context(Id::fromName(m_currentPerspectiveId))); + } m_currentPerspectiveId = perspectiveId; - QTC_ASSERT(m_perspectiveForPerspectiveId.contains(perspectiveId), return); - const auto operations = m_perspectiveForPerspectiveId.value(perspectiveId).operations(); - for (const Perspective::Operation &operation : operations) { + if (m_currentPerspectiveId.isEmpty()) { + const QSettings *settings = ICore::settings(); + m_currentPerspectiveId = settings->value(QLatin1String(LAST_PERSPECTIVE_KEY)).toByteArray(); + if (m_currentPerspectiveId.isEmpty()) + m_currentPerspectiveId = Debugger::Constants::CppPerspectiveId; + } + + ICore::addAdditionalContext(Context(Id::fromName(m_currentPerspectiveId))); + + QTC_ASSERT(m_perspectiveForPerspectiveId.contains(m_currentPerspectiveId), return); + const Perspective perspective = m_perspectiveForPerspectiveId.value(m_currentPerspectiveId); + for (const Perspective::Operation &operation : perspective.operations()) { QDockWidget *dock = m_dockForDockId.value(operation.dockId); - QTC_ASSERT(dock, continue); + if (!dock) { + QTC_CHECK(!operation.widget->objectName().isEmpty()); + dock = registerDockWidget(operation.dockId, operation.widget); + + QAction *toggleViewAction = dock->toggleViewAction(); + toggleViewAction->setText(dock->windowTitle()); + + Command *cmd = ActionManager::registerAction(toggleViewAction, + Id("Dock.").withSuffix(dock->objectName()), + Context(Id::fromName(m_currentPerspectiveId))); + cmd->setAttribute(Command::CA_Hide); + + ActionManager::actionContainer(Core::Constants::M_WINDOW_VIEWS)->addAction(cmd); + } if (operation.operationType == Perspective::Raise) { dock->raise(); continue; } addDockWidget(operation.area, dock); - QDockWidget *existing = m_dockForDockId.value(operation.existing); - if (!existing && operation.area == Qt::BottomDockWidgetArea) - existing = toolBarDockWidget(); - if (existing) { + QDockWidget *anchor = m_dockForDockId.value(operation.anchorDockId); + if (!anchor && operation.area == Qt::BottomDockWidgetArea) + anchor = m_toolbarDock; + if (anchor) { switch (operation.operationType) { case Perspective::AddToTab: - tabifyDockWidget(existing, dock); + tabifyDockWidget(anchor, dock); break; case Perspective::SplitHorizontal: - splitDockWidget(existing, dock, Qt::Horizontal); + splitDockWidget(anchor, dock, Qt::Horizontal); break; case Perspective::SplitVertical: - splitDockWidget(existing, dock, Qt::Vertical); + splitDockWidget(anchor, dock, Qt::Vertical); break; default: break; @@ -135,66 +323,84 @@ void MainWindowBase::loadPerspectiveHelper(Id perspectiveId, bool fromStoredSett if (fromStoredSettings) { QSettings *settings = ICore::settings(); - settings->beginGroup(perspectiveId.toString()); + settings->beginGroup(QString::fromLatin1(m_currentPerspectiveId)); if (settings->value(QLatin1String("ToolSettingsSaved"), false).toBool()) restoreSettings(settings); settings->endGroup(); } - QTC_CHECK(m_toolbarForPerspectiveId.contains(perspectiveId)); - m_controlsStackWidget->setCurrentWidget(m_toolbarForPerspectiveId.value(perspectiveId)); + QTC_CHECK(m_toolbarForPerspectiveId.contains(m_currentPerspectiveId)); + m_controlsStackWidget->setCurrentWidget(m_toolbarForPerspectiveId.value(m_currentPerspectiveId)); + m_statusLabel->clear(); } -void MainWindowBase::closeCurrentPerspective() +void DebuggerMainWindow::saveCurrentPerspective() { - if (!m_currentPerspectiveId.isValid()) - return; - - saveCurrentPerspective(); - foreach (QDockWidget *dockWidget, m_dockForDockId) { - QTC_ASSERT(dockWidget, continue); - removeDockWidget(dockWidget); - dockWidget->hide(); - // Prevent saveState storing the data of the wrong children. - dockWidget->setParent(0); - } -} - -void MainWindowBase::saveCurrentPerspective() -{ - if (!m_currentPerspectiveId.isValid()) + if (m_currentPerspectiveId.isEmpty()) return; QSettings *settings = ICore::settings(); - settings->beginGroup(m_currentPerspectiveId.toString()); + settings->beginGroup(QString::fromLatin1(m_currentPerspectiveId)); saveSettings(settings); settings->setValue(QLatin1String("ToolSettingsSaved"), true); settings->endGroup(); - settings->setValue(m_lastSettingsName, m_currentPerspectiveId.toString()); + settings->setValue(QLatin1String(LAST_PERSPECTIVE_KEY), m_currentPerspectiveId); } -QDockWidget *MainWindowBase::registerDockWidget(Id dockId, QWidget *widget) +QDockWidget *DebuggerMainWindow::registerDockWidget(const QByteArray &dockId, QWidget *widget) { QTC_ASSERT(!widget->objectName().isEmpty(), return 0); QDockWidget *dockWidget = addDockForWidget(widget); - m_dockWidgets.append(MainWindowBase::DockPtr(dockWidget)); + dockWidget->setParent(0); + m_dockWidgets.append(DebuggerMainWindow::DockPtr(dockWidget)); m_dockForDockId[dockId] = dockWidget; return dockWidget; } -Core::Id MainWindowBase::currentPerspectiveId() const +QString Perspective::name() const { - return m_currentPerspectiveId; + return m_name; } -QString MainWindowBase::lastSettingsName() const +void Perspective::setName(const QString &name) { - return m_lastSettingsName; + m_name = name; } -void MainWindowBase::setLastSettingsName(const QString &lastSettingsName) +QList ToolbarDescription::widgets() const { - m_lastSettingsName = lastSettingsName; + return m_widgets; } -} // Internal -} // Debugger +void ToolbarDescription::addAction(QAction *action) +{ + auto button = new QToolButton; + button->setDefaultAction(action); + m_widgets.append(button); +} + +void ToolbarDescription::addWidget(QWidget *widget) +{ + m_widgets.append(widget); +} + +Perspective::Operation::Operation(const QByteArray &dockId, QWidget *widget, const QByteArray &anchorDockId, + Perspective::OperationType splitType, bool visibleByDefault, + Qt::DockWidgetArea area) + : dockId(dockId), widget(widget), anchorDockId(anchorDockId), + operationType(splitType), visibleByDefault(visibleByDefault), area(area) +{} + +Perspective::Perspective(const QString &name, const QVector &splits) + : m_name(name), m_operations(splits) +{ + for (const Operation &split : splits) + m_docks.append(split.dockId); +} + +void Perspective::addOperation(const Operation &operation) +{ + m_docks.append(operation.dockId); + m_operations.append(operation); +} + +} // Utils diff --git a/src/plugins/debugger/debuggermainwindow.h b/src/plugins/debugger/debuggermainwindow.h index 3f12344c84a..3c7d221a59a 100644 --- a/src/plugins/debugger/debuggermainwindow.h +++ b/src/plugins/debugger/debuggermainwindow.h @@ -27,9 +27,6 @@ #define DEBUGGERMAINWINDOW_H #include "debugger_global.h" -#include "analyzer/analyzerbase_global.h" - -#include #include #include @@ -38,113 +35,115 @@ #include #include -#include QT_BEGIN_NAMESPACE class QComboBox; class QStackedWidget; QT_END_NAMESPACE -namespace Analyzer { +namespace Core { class IMode; } -class ANALYZER_EXPORT Perspective +namespace Utils { + +class DEBUGGER_EXPORT Perspective { public: enum OperationType { SplitVertical, SplitHorizontal, AddToTab, Raise }; - class ANALYZER_EXPORT Operation + class DEBUGGER_EXPORT Operation { public: Operation() = default; - Operation(Core::Id dockId, Core::Id existing, OperationType operationType, - bool visibleByDefault = true, - Qt::DockWidgetArea area = Qt::BottomDockWidgetArea); + Operation(const QByteArray &dockId, QWidget *widget, + const QByteArray &anchorDockId, + OperationType operationType, + bool visibleByDefault = true, + Qt::DockWidgetArea area = Qt::BottomDockWidgetArea); - Core::Id dockId; - Core::Id existing; + QByteArray dockId; + QWidget *widget = 0; + QByteArray anchorDockId; OperationType operationType; bool visibleByDefault; Qt::DockWidgetArea area; }; Perspective() = default; - Perspective(std::initializer_list operations); + Perspective(const QString &name, const QVector &operations); void addOperation(const Operation &operation); QVector operations() const { return m_operations; } - QVector docks() const { return m_docks; } + QVector docks() const { return m_docks; } + + QString name() const; + void setName(const QString &name); private: - QVector m_docks; + QString m_name; + QVector m_docks; QVector m_operations; }; -} // Analyzer +class DEBUGGER_EXPORT ToolbarDescription +{ +public: + ToolbarDescription() = default; + ToolbarDescription(const QList &widgets) : m_widgets(widgets) {} -namespace Debugger { -namespace Internal { + QList widgets() const; -// DebuggerMainWindow dock widget names -const char DOCKWIDGET_BREAK[] = "Debugger.Docks.Break"; -const char DOCKWIDGET_MODULES[] = "Debugger.Docks.Modules"; -const char DOCKWIDGET_REGISTER[] = "Debugger.Docks.Register"; -const char DOCKWIDGET_OUTPUT[] = "Debugger.Docks.Output"; -const char DOCKWIDGET_SNAPSHOTS[] = "Debugger.Docks.Snapshots"; -const char DOCKWIDGET_STACK[] = "Debugger.Docks.Stack"; -const char DOCKWIDGET_SOURCE_FILES[] = "Debugger.Docks.SourceFiles"; -const char DOCKWIDGET_THREADS[] = "Debugger.Docks.Threads"; -const char DOCKWIDGET_WATCHERS[] = "Debugger.Docks.LocalsAndWatchers"; + void addAction(QAction *action); + void addWidget(QWidget *widget); -const char CppPerspectiveId[] = "Debugger.Perspective.Cpp"; -const char QmlPerspectiveId[] = "Debugger.Perspective.Qml"; +private: + QList m_widgets; +}; -class MainWindowBase : public Utils::FancyMainWindow +class DEBUGGER_EXPORT DebuggerMainWindow : public FancyMainWindow { Q_OBJECT public: - MainWindowBase(); - ~MainWindowBase() override; + DebuggerMainWindow(); + ~DebuggerMainWindow() override; - QComboBox *toolBox() const { return m_toolBox; } - QStackedWidget *controlsStack() const { return m_controlsStackWidget; } - Utils::StatusLabel *statusLabel() const { return m_statusLabel; } - - void registerPerspective(Core::Id perspectiveId, const Analyzer::Perspective &perspective); - void registerToolbar(Core::Id perspectiveId, QWidget *widget); - QDockWidget *registerDockWidget(Core::Id dockId, QWidget *widget); + void registerPerspective(const QByteArray &perspectiveId, const Perspective &perspective); + void registerToolbar(const QByteArray &perspectiveId, QWidget *widget); void saveCurrentPerspective(); - void closeCurrentPerspective(); void resetCurrentPerspective(); - void restorePerspective(Core::Id perspectiveId); + void restorePerspective(const QByteArray &perspectiveId); + + void finalizeSetup(Core::IMode *mode, QWidget *central = 0); void showStatusMessage(const QString &message, int timeoutMS); + QDockWidget *dockWidget(const QByteArray &dockId) const; + QByteArray currentPerspective() const { return m_currentPerspectiveId; } - QString lastSettingsName() const; - void setLastSettingsName(const QString &lastSettingsName); - - Core::Id currentPerspectiveId() const; + QWidget *modeWindow(); private: - void loadPerspectiveHelper(Core::Id perspectiveId, bool fromStoredSettings = true); + QDockWidget *registerDockWidget(const QByteArray &dockId, QWidget *widget); + void loadPerspectiveHelper(const QByteArray &perspectiveId, bool fromStoredSettings = true); - Core::Id m_currentPerspectiveId; - QString m_lastSettingsName; - QComboBox *m_toolBox; + QByteArray m_currentPerspectiveId; + QComboBox *m_perspectiveChooser; QStackedWidget *m_controlsStackWidget; Utils::StatusLabel *m_statusLabel; - QHash m_dockForDockId; - QHash m_toolbarForPerspectiveId; - QHash m_perspectiveForPerspectiveId; + QDockWidget *m_toolbarDock; + + QHash m_dockForDockId; + QHash m_toolbarForPerspectiveId; + QHash m_perspectiveForPerspectiveId; // list of dock widgets to prevent memory leak typedef QPointer DockPtr; QList m_dockWidgets; + + QWidget *m_modeWindow = 0; }; -} // namespace Internal -} // namespace Debugger +} // Utils #endif // DEBUGGERMAINWINDOW_H diff --git a/src/plugins/debugger/debuggerplugin.cpp b/src/plugins/debugger/debuggerplugin.cpp index 78d24374b1d..8f910027b4e 100644 --- a/src/plugins/debugger/debuggerplugin.cpp +++ b/src/plugins/debugger/debuggerplugin.cpp @@ -71,7 +71,10 @@ #include "gdb/startgdbserverdialog.h" #include "analyzer/analyzerconstants.h" +#include "analyzer/analyzericons.h" #include "analyzer/analyzermanager.h" +#include "analyzer/analyzerruncontrol.h" +#include "analyzer/analyzerstartparameters.h" #include #include @@ -87,6 +90,7 @@ #include #include #include +#include #include #include #include @@ -96,21 +100,21 @@ #include +#include #include -#include -#include -#include #include +#include +#include #include #include -#include #include -#include +#include #include #include #include -#include #include +#include +#include #include #include @@ -120,6 +124,7 @@ #include #include #include +#include #include #include #include @@ -128,7 +133,6 @@ #include #include #include -#include #include #include @@ -136,21 +140,33 @@ #include #include #include +#include +#include #include #include #include #include #include #include -#include #include +#include +#include +#include #include #include #include #include #include +#include #include +using namespace Core; +using namespace Utils; +using namespace Core::Constants; +using namespace ProjectExplorer; +using namespace Debugger; +using namespace Debugger::Internal; + #ifdef WITH_TESTS #include #include @@ -405,13 +421,9 @@ using namespace ProjectExplorer; using namespace TextEditor; using namespace Utils; -using namespace Analyzer; -//using namespace Analyzer::Internal; - namespace CC = Core::Constants; namespace PE = ProjectExplorer::Constants; - namespace Debugger { namespace Internal { @@ -425,36 +437,15 @@ struct TestCallBack QVariant cookie; }; - -} // namespace Internal -} // namespace Debugger - -Q_DECLARE_METATYPE(Debugger::Internal::TestCallBack) - -namespace Debugger { -namespace Internal { - void addCdbOptionPages(QList *opts); void addGdbOptionPages(QList *opts); QObject *createDebuggerRunControlFactory(QObject *parent); -static QToolButton *toolButton(QAction *action) -{ - QToolButton *button = new QToolButton; - button->setDefaultAction(action); - return button; -} - static void setProxyAction(ProxyAction *proxy, Id id) { proxy->setAction(ActionManager::command(id)->action()); } -static QToolButton *toolButton(Id id) -{ - return toolButton(ActionManager::command(id)->action()); -} - /////////////////////////////////////////////////////////////////////// // // DummyEngine @@ -465,17 +456,17 @@ class DummyEngine : public DebuggerEngine { public: DummyEngine() : DebuggerEngine(DebuggerRunParameters()) {} - ~DummyEngine() {} + ~DummyEngine() override {} - void setupEngine() {} - void setupInferior() {} - void runEngine() {} - void shutdownEngine() {} - void shutdownInferior() {} - bool hasCapability(unsigned cap) const; - bool acceptsBreakpoint(Breakpoint) const { return false; } - bool acceptsDebuggerCommands() const { return false; } - void selectThread(ThreadId) {} + void setupEngine() override {} + void setupInferior() override {} + void runEngine() override {} + void shutdownEngine() override {} + void shutdownInferior() override {} + bool hasCapability(unsigned cap) const override; + bool acceptsBreakpoint(Breakpoint) const override { return false; } + bool acceptsDebuggerCommands() const override { return false; } + void selectThread(ThreadId) override {} }; bool DummyEngine::hasCapability(unsigned cap) const @@ -506,24 +497,44 @@ bool DummyEngine::hasCapability(unsigned cap) const // /////////////////////////////////////////////////////////////////////// +class DebugModeContext : public IContext +{ +public: + DebugModeContext(DebuggerMainWindow *mainWindow) : m_mainWindow(mainWindow) + { + setContext(Context(CC::C_EDITORMANAGER)); + ICore::addContextObject(this); + } + + QWidget *widget() const override { return m_mainWindow->modeWindow(); } + + DebuggerMainWindow *m_mainWindow; +}; + class DebugMode : public IMode { public: - DebugMode() + DebugMode(DebuggerMainWindow *mainWindow) : m_mainWindow(mainWindow) { setObjectName(QLatin1String("DebugMode")); setContext(Context(C_DEBUGMODE, CC::C_NAVIGATION_PANE)); setDisplayName(DebuggerPlugin::tr("Debug")); setIcon(Utils::Icon::modeIcon(Icons::MODE_DEBUGGER_CLASSIC, Icons::MODE_DEBUGGER_FLAT, Icons::MODE_DEBUGGER_FLAT_ACTIVE)); +// setIcon(Utils::Icon::modeIcon(Icons::MODE_ANALYZE_CLASSIC, +// Icons::MODE_ANALYZE_FLAT, Icons::MODE_ANALYZE_FLAT_ACTIVE)); setPriority(85); setId(MODE_DEBUG); } + QWidget *widget() const override { return m_mainWindow->modeWindow(); } + ~DebugMode() { - delete m_widget; +// delete m_widget; } + + DebuggerMainWindow *m_mainWindow; }; /////////////////////////////////////////////////////////////////////// @@ -716,7 +727,6 @@ public: void toggleBreakpointHelper(); void toggleBreakpoint(const ContextData &location, const QString &tracePointMessage = QString()); void onModeChanged(IMode *mode); - void onCoreAboutToOpen(); void updateDebugWithoutDeployMenu(); void startAndDebugApplication(); @@ -778,7 +788,7 @@ public: #endif -public slots: +public: void updateDebugActions(); void handleExecDetach() @@ -962,45 +972,27 @@ public slots: bool parseArguments(const QStringList &args, QString *errorMessage); void parseCommandLineArguments(); -public: - // Active languages to be debugged. - DebuggerLanguages activeDebugLanguages() const; - // Called when all dependent plugins have loaded. void initialize(); - void onModeChangedHelper(Core::IMode *mode); - - // Dockwidgets are registered to the main window. - QDockWidget *createDockWidget(Id dockId, QWidget *widget); - QWidget *createContents(Core::IMode *mode); - - void readWindowSettings(); - void writeWindowSettings() const; - - void createViewsMenuItems(); - - QWidget *mainWindow() const { return m_mainWindow; } - void updateUiForProject(ProjectExplorer::Project *project); void updateUiForTarget(ProjectExplorer::Target *target); void updateUiForRunConfiguration(ProjectExplorer::RunConfiguration *rc); void updateActiveLanguages(); public: - MainWindowBase *m_mainWindow = 0; + DebuggerMainWindow *m_mainWindow = 0; + + QHash m_descriptions; + ActionContainer *m_menu = 0; // DockWidgetEventFilter m_resizeEventFilter; QHash m_contextsForLanguage; - bool m_inDebugMode = false; - - Core::ActionContainer *m_viewsMenu = 0; - - ProjectExplorer::Project *m_previousProject = 0; - ProjectExplorer::Target *m_previousTarget = 0; - ProjectExplorer::RunConfiguration *m_previousRunConfiguration = 0; + Project *m_previousProject = 0; + Target *m_previousTarget = 0; + QPointer m_previousRunConfiguration; Id m_previousMode; QVector> m_scheduledStarts; @@ -1037,15 +1029,11 @@ public: QAction *m_frameUpAction = 0; QAction *m_frameDownAction = 0; QAction *m_resetAction = 0; + QAction *m_operateByInstructionAction = 0; QToolButton *m_reverseToolButton = 0; - QIcon m_startIcon; - QIcon m_exitIcon; - QIcon m_continueIcon; - QIcon m_interruptIcon; QIcon m_locationMarkIcon; - QIcon m_resetIcon; QComboBox *m_threadBox = 0; @@ -1112,10 +1100,6 @@ DebuggerPluginPrivate::DebuggerPluginPrivate(DebuggerPlugin *plugin) DebuggerPluginPrivate::~DebuggerPluginPrivate() { -// Mainwindow will be deleted by debug mode. -// delete m_mainWindow; -// m_mainWindow = 0; - delete m_debuggerSettings; m_debuggerSettings = 0; @@ -1124,6 +1108,11 @@ DebuggerPluginPrivate::~DebuggerPluginPrivate() delete m_breakHandler; m_breakHandler = 0; + +// delete m_debugMode; +// m_debugMode = 0; + delete m_mainWindow; + m_mainWindow = 0; } DebuggerEngine *DebuggerPluginPrivate::dummyEngine() @@ -1270,10 +1259,37 @@ bool DebuggerPluginPrivate::initialize(const QStringList &arguments, connect(KitManager::instance(), &KitManager::kitsLoaded, this, &DebuggerPluginPrivate::parseCommandLineArguments); - m_mainWindow = new MainWindowBase; - m_mainWindow->setObjectName(QLatin1String("DebuggerMainWindow")); + m_mainWindow = new DebuggerMainWindow; - createViewsMenuItems(); + // Menus + m_menu = ActionManager::createMenu(M_DEBUG_ANALYZER); + m_menu->menu()->setTitle(tr("&Analyze")); + m_menu->menu()->setEnabled(true); + + m_menu->appendGroup(G_ANALYZER_CONTROL); + m_menu->appendGroup(G_ANALYZER_TOOLS); + m_menu->appendGroup(G_ANALYZER_REMOTE_TOOLS); + m_menu->appendGroup(G_ANALYZER_OPTIONS); + + ActionContainer *menubar = ActionManager::actionContainer(MENU_BAR); + ActionContainer *mtools = ActionManager::actionContainer(M_TOOLS); + menubar->addMenu(mtools, m_menu); + + m_menu->addSeparator(G_ANALYZER_TOOLS); + m_menu->addSeparator(G_ANALYZER_REMOTE_TOOLS); + m_menu->addSeparator(G_ANALYZER_OPTIONS); + + // Populate Windows->Views menu with standard actions. + Context debugcontext(Constants::C_DEBUGMODE); + + auto openMemoryEditorAction = new QAction(this); + openMemoryEditorAction->setText(DebuggerPluginPrivate::tr("Memory...")); + connect(openMemoryEditorAction, &QAction::triggered, + this, &Internal::openMemoryEditor); + + Command *cmd = ActionManager::registerAction(openMemoryEditorAction, + "Debugger.Views.OpenMemoryEditor", debugcontext); + cmd->setAttribute(Command::CA_Hide); m_plugin->addAutoReleasedObject(debuggerConsole()); @@ -1282,6 +1298,589 @@ bool DebuggerPluginPrivate::initialize(const QStringList &arguments, TaskHub::addCategory(TASK_CATEGORY_DEBUGGER_RUNTIME, tr("Debugger Runtime")); + const QKeySequence debugKey = QKeySequence(UseMacShortcuts ? tr("Ctrl+Y") : tr("F5")); + + QSettings *settings = ICore::settings(); + + m_debuggerSettings = new DebuggerSettings; + m_debuggerSettings->readSettings(); + + connect(ICore::instance(), &ICore::coreAboutToClose, this, &DebuggerPluginPrivate::coreShutdown); + + const Context cppDebuggercontext(C_CPPDEBUGGER); + const Context cppeditorcontext(CppEditor::Constants::CPPEDITOR_ID); + + const QIcon continueSideBarIcon = Icon::sideBarIcon(Icons::CONTINUE, Icons::CONTINUE_FLAT); + const QIcon interruptSideBarIcon = Icon::sideBarIcon(Icons::INTERRUPT, Icons::INTERRUPT_FLAT); + m_locationMarkIcon = Icons::LOCATION.icon(); + + m_busy = false; + + m_logWindow = new LogWindow; + m_logWindow->setObjectName(QLatin1String(DOCKWIDGET_OUTPUT)); + + m_breakHandler = new BreakHandler; + m_breakView = new BreakTreeView; + m_breakView->setSettings(settings, "Debugger.BreakWindow"); + m_breakView->setModel(m_breakHandler->model()); + m_breakWindow = addSearch(m_breakView, tr("Breakpoints"), DOCKWIDGET_BREAK); + + m_modulesView = new ModulesTreeView; + m_modulesView->setSettings(settings, "Debugger.ModulesView"); + m_modulesWindow = addSearch(m_modulesView, tr("Modules"), DOCKWIDGET_MODULES); + + m_registerView = new RegisterTreeView; + m_registerView->setSettings(settings, "Debugger.RegisterView"); + m_registerWindow = addSearch(m_registerView, tr("Registers"), DOCKWIDGET_REGISTER); + + m_stackView = new StackTreeView; + m_stackView->setSettings(settings, "Debugger.StackView"); + m_stackWindow = addSearch(m_stackView, tr("Stack"), DOCKWIDGET_STACK); + + m_sourceFilesView = new SourceFilesTreeView; + m_sourceFilesView->setSettings(settings, "Debugger.SourceFilesView"); + m_sourceFilesWindow = addSearch(m_sourceFilesView, tr("Source Files"), DOCKWIDGET_SOURCE_FILES); + + m_threadsView = new ThreadsTreeView; + m_threadsView->setSettings(settings, "Debugger.ThreadsView"); + m_threadsWindow = addSearch(m_threadsView, tr("Threads"), DOCKWIDGET_THREADS); + + m_returnView = new WatchTreeView(ReturnType); // No settings. + m_returnWindow = addSearch(m_returnView, tr("Locals and Expressions"), "CppDebugReturn"); + + m_localsView = new WatchTreeView(LocalsType); + m_localsView->setSettings(settings, "Debugger.LocalsView"); + m_localsWindow = addSearch(m_localsView, tr("Locals and Expressions"), "CppDebugLocals"); + + m_watchersView = new WatchTreeView(WatchersType); // No settings. + m_watchersWindow = addSearch(m_watchersView, tr("Locals and Expressions"), "CppDebugWatchers"); + + m_inspectorView = new WatchTreeView(InspectType); + m_inspectorView->setSettings(settings, "Debugger.LocalsView"); // sic! same as locals view. + m_inspectorWindow = addSearch(m_inspectorView, tr("Locals and Expressions"), "Inspector"); + + // Snapshot + m_snapshotHandler = new SnapshotHandler; + m_snapshotView = new SnapshotTreeView(m_snapshotHandler); + m_snapshotView->setSettings(settings, "Debugger.SnapshotView"); + m_snapshotView->setModel(m_snapshotHandler->model()); + m_snapshotWindow = addSearch(m_snapshotView, tr("Snapshots"), DOCKWIDGET_SNAPSHOTS); + + // Watchers + connect(m_localsView->header(), &QHeaderView::sectionResized, + this, &DebuggerPluginPrivate::updateWatchersHeader, Qt::QueuedConnection); + + auto act = m_continueAction = new QAction(tr("Continue"), this); + act->setIcon(Icon::combinedIcon({Core::Icons::DEBUG_CONTINUE_SMALL.icon(), continueSideBarIcon})); + connect(act, &QAction::triggered, this, &DebuggerPluginPrivate::handleExecContinue); + + act = m_exitAction = new QAction(tr("Stop Debugger"), this); + act->setIcon(Core::Icons::DEBUG_EXIT_SMALL.icon()); + connect(act, &QAction::triggered, this, &DebuggerPluginPrivate::handleExecExit); + + auto interruptIcon = Icon::combinedIcon({Core::Icons::DEBUG_INTERRUPT_SMALL.icon(), interruptSideBarIcon}); + act = m_interruptAction = new QAction(tr("Interrupt"), this); + act->setIcon(interruptIcon); + connect(act, &QAction::triggered, this, &DebuggerPluginPrivate::handleExecInterrupt); + + // A "disabled pause" seems to be a good choice. + act = m_undisturbableAction = new QAction(tr("Debugger is Busy"), this); + act->setIcon(interruptIcon); + act->setEnabled(false); + + act = m_abortAction = new QAction(tr("Abort Debugging"), this); + act->setToolTip(tr("Aborts debugging and " + "resets the debugger to the initial state.")); + connect(act, &QAction::triggered, this, &DebuggerPluginPrivate::handleAbort); + + act = m_resetAction = new QAction(tr("Restart Debugging"),this); + act->setToolTip(tr("Restart the debugging session.")); + act->setIcon(Icons::RESTART.icon()); + connect(act, &QAction::triggered, this, &DebuggerPluginPrivate::handleReset); + + act = m_nextAction = new QAction(tr("Step Over"), this); + act->setIcon(Icons::STEP_OVER.icon()); + connect(act, &QAction::triggered, this, &DebuggerPluginPrivate::handleExecNext); + + act = m_stepAction = new QAction(tr("Step Into"), this); + act->setIcon(Icons::STEP_INTO.icon()); + connect(act, &QAction::triggered, this, &DebuggerPluginPrivate::handleExecStep); + + act = m_stepOutAction = new QAction(tr("Step Out"), this); + act->setIcon(Icons::STEP_OUT.icon()); + connect(act, &QAction::triggered, this, &DebuggerPluginPrivate::handleExecStepOut); + + act = m_runToLineAction = new QAction(tr("Run to Line"), this); + connect(act, &QAction::triggered, this, &DebuggerPluginPrivate::handleExecRunToLine); + + act = m_runToSelectedFunctionAction = new QAction(tr("Run to Selected Function"), this); + connect(act, &QAction::triggered, this, &DebuggerPluginPrivate::handleExecRunToSelectedFunction); + + act = m_returnFromFunctionAction = + new QAction(tr("Immediately Return From Inner Function"), this); + connect(act, &QAction::triggered, this, &DebuggerPluginPrivate::handleExecReturn); + + act = m_jumpToLineAction = new QAction(tr("Jump to Line"), this); + connect(act, &QAction::triggered, this, &DebuggerPluginPrivate::handleExecJumpToLine); + + m_breakAction = new QAction(tr("Toggle Breakpoint"), this); + + act = m_watchAction1 = new QAction(tr("Add Expression Evaluator"), this); + connect(act, &QAction::triggered, this, &DebuggerPluginPrivate::handleAddToWatchWindow); + + act = m_watchAction2 = new QAction(tr("Add Expression Evaluator"), this); + connect(act, &QAction::triggered, this, &DebuggerPluginPrivate::handleAddToWatchWindow); + + //act = m_snapshotAction = new QAction(tr("Create Snapshot"), this); + //act->setProperty(Role, RequestCreateSnapshotRole); + //act->setIcon(Icons::SNAPSHOT.icon()); + + act = m_reverseDirectionAction = new QAction(tr("Reverse Direction"), this); + act->setCheckable(true); + act->setChecked(false); + act->setCheckable(false); + act->setIcon(Icons::REVERSE_MODE.icon()); + act->setIconVisibleInMenu(false); + + act = m_frameDownAction = new QAction(tr("Move to Called Frame"), this); + connect(act, &QAction::triggered, this, &DebuggerPluginPrivate::handleFrameDown); + + act = m_frameUpAction = new QAction(tr("Move to Calling Frame"), this); + connect(act, &QAction::triggered, this, &DebuggerPluginPrivate::handleFrameUp); + + act = m_operateByInstructionAction = action(OperateByInstruction); + connect(act, &QAction::triggered, + this, &DebuggerPluginPrivate::handleOperateByInstructionTriggered); + + ActionContainer *debugMenu = ActionManager::actionContainer(PE::M_DEBUG); + + m_localsAndExpressionsWindow = new LocalsAndExpressionsWindow( + m_localsWindow, m_inspectorWindow, m_returnWindow, m_watchersWindow); + m_localsAndExpressionsWindow->setObjectName(QLatin1String(DOCKWIDGET_WATCHERS)); + m_localsAndExpressionsWindow->setWindowTitle(m_localsWindow->windowTitle()); + + m_plugin->addAutoReleasedObject(createDebuggerRunControlFactory(m_plugin)); + + // The main "Start Debugging" action. + act = m_startAction = new QAction(this); + const QIcon sideBarIcon = + Icon::sideBarIcon(ProjectExplorer::Icons::DEBUG_START, ProjectExplorer::Icons::DEBUG_START_FLAT); + const QIcon debuggerIcon = Icon::combinedIcon({Core::Icons::DEBUG_START_SMALL.icon(), sideBarIcon}); + act->setIcon(debuggerIcon); + act->setText(tr("Start Debugging")); + connect(act, &QAction::triggered, [] { ProjectExplorerPlugin::runStartupProject(ProjectExplorer::Constants::DEBUG_RUN_MODE); }); + + act = m_debugWithoutDeployAction = new QAction(this); + act->setText(tr("Start Debugging Without Deployment")); + connect(act, &QAction::triggered, [] { ProjectExplorerPlugin::runStartupProject(ProjectExplorer::Constants::DEBUG_RUN_MODE, true); }); + + act = m_startAndDebugApplicationAction = new QAction(this); + act->setText(tr("Start and Debug External Application...")); + connect(act, &QAction::triggered, this, &DebuggerPluginPrivate::startAndDebugApplication); + + act = m_attachToCoreAction = new QAction(this); + act->setText(tr("Load Core File...")); + connect(act, &QAction::triggered, this, &DebuggerPluginPrivate::attachCore); + + act = m_attachToRemoteServerAction = new QAction(this); + act->setText(tr("Attach to Running Debug Server...")); + connect(act, &QAction::triggered, this, &DebuggerPluginPrivate::attachToRemoteServer); + + act = m_startRemoteServerAction = new QAction(this); + act->setText(tr("Start Debug Server Attached to Process...")); + connect(act, &QAction::triggered, this, &DebuggerPluginPrivate::startRemoteServerAndAttachToProcess); + + act = m_attachToRunningApplication = new QAction(this); + act->setText(tr("Attach to Running Application...")); + connect(act, &QAction::triggered, this, &DebuggerPluginPrivate::attachToRunningApplication); + + act = m_attachToUnstartedApplication = new QAction(this); + act->setText(tr("Attach to Unstarted Application...")); + connect(act, &QAction::triggered, this, &DebuggerPluginPrivate::attachToUnstartedApplicationDialog); + + act = m_attachToQmlPortAction = new QAction(this); + act->setText(tr("Attach to QML Port...")); + connect(act, &QAction::triggered, this, &DebuggerPluginPrivate::attachToQmlPort); + + if (HostOsInfo::isWindowsHost()) { + m_startRemoteCdbAction = new QAction(tr("Attach to Remote CDB Session..."), this); + connect(m_startRemoteCdbAction, &QAction::triggered, + this, &DebuggerPluginPrivate::startRemoteCdbSession); + } + + act = m_detachAction = new QAction(this); + act->setText(tr("Detach Debugger")); + connect(act, &QAction::triggered, this, &DebuggerPluginPrivate::handleExecDetach); + + // "Start Debugging" sub-menu + // groups: + // G_DEFAULT_ONE + // G_START_LOCAL + // G_START_REMOTE + // G_START_QML + + ActionContainer *mstart = ActionManager::actionContainer(PE::M_DEBUG_STARTDEBUGGING); + + cmd = ActionManager::registerAction(m_startAction, Constants::DEBUG); + cmd->setDescription(tr("Start Debugging")); + cmd->setDefaultKeySequence(debugKey); + cmd->setAttribute(Command::CA_UpdateText); + mstart->addAction(cmd, CC::G_DEFAULT_ONE); + m_visibleStartAction = new ProxyAction(this); + m_visibleStartAction->initialize(cmd->action()); + m_visibleStartAction->setAttribute(ProxyAction::UpdateText); + m_visibleStartAction->setAttribute(ProxyAction::UpdateIcon); + m_visibleStartAction->setAction(cmd->action()); + + ModeManager::addAction(m_visibleStartAction, Constants::P_ACTION_DEBUG); + + cmd = ActionManager::registerAction(m_debugWithoutDeployAction, + "Debugger.DebugWithoutDeploy"); + cmd->setAttribute(Command::CA_Hide); + mstart->addAction(cmd, CC::G_DEFAULT_ONE); + + cmd = ActionManager::registerAction(m_attachToRunningApplication, + "Debugger.AttachToRemoteProcess"); + cmd->setDescription(tr("Attach to Running Application")); + mstart->addAction(cmd, G_GENERAL); + + cmd = ActionManager::registerAction(m_attachToUnstartedApplication, + "Debugger.AttachToUnstartedProcess"); + cmd->setDescription(tr("Attach to Unstarted Application")); + mstart->addAction(cmd, G_GENERAL); + + cmd = ActionManager::registerAction(m_startAndDebugApplicationAction, + "Debugger.StartAndDebugApplication"); + cmd->setAttribute(Command::CA_Hide); + mstart->addAction(cmd, G_GENERAL); + + cmd = ActionManager::registerAction(m_attachToCoreAction, + "Debugger.AttachCore"); + cmd->setAttribute(Command::CA_Hide); + mstart->addAction(cmd, Constants::G_GENERAL); + + cmd = ActionManager::registerAction(m_attachToRemoteServerAction, + "Debugger.AttachToRemoteServer"); + cmd->setAttribute(Command::CA_Hide); + mstart->addAction(cmd, Constants::G_SPECIAL); + + cmd = ActionManager::registerAction(m_startRemoteServerAction, + "Debugger.StartRemoteServer"); + cmd->setDescription(tr("Start Gdbserver")); + mstart->addAction(cmd, Constants::G_SPECIAL); + + if (m_startRemoteCdbAction) { + cmd = ActionManager::registerAction(m_startRemoteCdbAction, + "Debugger.AttachRemoteCdb"); + cmd->setAttribute(Command::CA_Hide); + mstart->addAction(cmd, Constants::G_SPECIAL); + } + + mstart->addSeparator(Context(CC::C_GLOBAL), Constants::G_START_QML); + + cmd = ActionManager::registerAction(m_attachToQmlPortAction, "Debugger.AttachToQmlPort"); + cmd->setAttribute(Command::CA_Hide); + mstart->addAction(cmd, Constants::G_START_QML); + + cmd = ActionManager::registerAction(m_detachAction, "Debugger.Detach"); + cmd->setAttribute(Command::CA_Hide); + debugMenu->addAction(cmd, CC::G_DEFAULT_ONE); + + cmd = ActionManager::registerAction(m_interruptAction, Constants::INTERRUPT); + cmd->setDescription(tr("Interrupt Debugger")); + debugMenu->addAction(cmd, CC::G_DEFAULT_ONE); + + cmd = ActionManager::registerAction(m_continueAction, Constants::CONTINUE); + cmd->setDefaultKeySequence(debugKey); + debugMenu->addAction(cmd, CC::G_DEFAULT_ONE); + + cmd = ActionManager::registerAction(m_exitAction, Constants::STOP); + debugMenu->addAction(cmd, CC::G_DEFAULT_ONE); + m_hiddenStopAction = new ProxyAction(this); + m_hiddenStopAction->initialize(cmd->action()); + m_hiddenStopAction->setAttribute(ProxyAction::UpdateText); + m_hiddenStopAction->setAttribute(ProxyAction::UpdateIcon); + + cmd = ActionManager::registerAction(m_hiddenStopAction, Constants::HIDDEN_STOP); + cmd->setDefaultKeySequence(QKeySequence(UseMacShortcuts ? tr("Shift+Ctrl+Y") : tr("Shift+F5"))); + + cmd = ActionManager::registerAction(m_abortAction, Constants::ABORT); + cmd->setDescription(tr("Reset Debugger")); + debugMenu->addAction(cmd, CC::G_DEFAULT_ONE); + + cmd = ActionManager::registerAction(m_resetAction, Constants::RESET); + cmd->setDescription(tr("Restart Debugging")); + debugMenu->addAction(cmd, CC::G_DEFAULT_ONE); + + debugMenu->addSeparator(); + + cmd = ActionManager::registerAction(m_nextAction, Constants::NEXT); + cmd->setDefaultKeySequence(QKeySequence(UseMacShortcuts ? tr("Ctrl+Shift+O") : tr("F10"))); + cmd->setAttribute(Command::CA_Hide); + cmd->setAttribute(Command::CA_UpdateText); + debugMenu->addAction(cmd); + + cmd = ActionManager::registerAction(m_stepAction, Constants::STEP); + cmd->setDefaultKeySequence(QKeySequence(UseMacShortcuts ? tr("Ctrl+Shift+I") : tr("F11"))); + cmd->setAttribute(Command::CA_Hide); + cmd->setAttribute(Command::CA_UpdateText); + debugMenu->addAction(cmd); + + cmd = ActionManager::registerAction(m_stepOutAction, + Constants::STEPOUT, cppDebuggercontext); + cmd->setDefaultKeySequence(QKeySequence(UseMacShortcuts ? tr("Ctrl+Shift+T") : tr("Shift+F11"))); + cmd->setAttribute(Command::CA_Hide); + debugMenu->addAction(cmd); + + cmd = ActionManager::registerAction(m_runToLineAction, + "Debugger.RunToLine", cppDebuggercontext); + cmd->setDefaultKeySequence(QKeySequence(UseMacShortcuts ? tr("Shift+F8") : tr("Ctrl+F10"))); + cmd->setAttribute(Command::CA_Hide); + debugMenu->addAction(cmd); + + cmd = ActionManager::registerAction(m_runToSelectedFunctionAction, + "Debugger.RunToSelectedFunction", cppDebuggercontext); + cmd->setDefaultKeySequence(QKeySequence(tr("Ctrl+F6"))); + cmd->setAttribute(Command::CA_Hide); + // Don't add to menu by default as keeping its enabled state + // and text up-to-date is a lot of hassle. + // debugMenu->addAction(cmd); + + cmd = ActionManager::registerAction(m_jumpToLineAction, + "Debugger.JumpToLine", cppDebuggercontext); + cmd->setAttribute(Command::CA_Hide); + debugMenu->addAction(cmd); + + cmd = ActionManager::registerAction(m_returnFromFunctionAction, + "Debugger.ReturnFromFunction", cppDebuggercontext); + cmd->setAttribute(Command::CA_Hide); + debugMenu->addAction(cmd); + + if (isReverseDebuggingEnabled()) { + cmd = ActionManager::registerAction(m_reverseDirectionAction, + Constants::REVERSE, cppDebuggercontext); + cmd->setDefaultKeySequence(QKeySequence(UseMacShortcuts ? QString() : tr("F12"))); + cmd->setAttribute(Command::CA_Hide); + debugMenu->addAction(cmd); + } + + debugMenu->addSeparator(); + + //cmd = ActionManager::registerAction(m_snapshotAction, + // "Debugger.Snapshot", cppDebuggercontext); + //cmd->setDefaultKeySequence(QKeySequence(tr("Ctrl+D,Ctrl+S"))); + //cmd->setAttribute(Command::CA_Hide); + //debugMenu->addAction(cmd); + + ActionManager::registerAction(m_frameDownAction, + "Debugger.FrameDown", cppDebuggercontext); + ActionManager::registerAction(m_frameUpAction, + "Debugger.FrameUp", cppDebuggercontext); + + cmd = ActionManager::registerAction(m_operateByInstructionAction, + Constants::OPERATE_BY_INSTRUCTION, cppDebuggercontext); + cmd->setAttribute(Command::CA_Hide); + debugMenu->addAction(cmd); + + cmd = ActionManager::registerAction(m_breakAction, "Debugger.ToggleBreak"); + cmd->setDefaultKeySequence(QKeySequence(UseMacShortcuts ? tr("F8") : tr("F9"))); + debugMenu->addAction(cmd); + connect(m_breakAction, &QAction::triggered, + this, &DebuggerPluginPrivate::toggleBreakpointHelper); + + debugMenu->addSeparator(); + + // currently broken +// auto qmlUpdateOnSaveDummyAction = new QAction(tr("Apply Changes on Save"), this); +// qmlUpdateOnSaveDummyAction->setCheckable(true); +// qmlUpdateOnSaveDummyAction->setIcon(Icons::APPLY_ON_SAVE.icon()); +// qmlUpdateOnSaveDummyAction->setEnabled(false); +// cmd = ActionManager::registerAction(qmlUpdateOnSaveDummyAction, Constants::QML_UPDATE_ON_SAVE); +// debugMenu->addAction(cmd); + + auto qmlShowAppOnTopDummyAction = new QAction(tr("Show Application on Top"), this); + qmlShowAppOnTopDummyAction->setCheckable(true); + qmlShowAppOnTopDummyAction->setIcon(Icons::APP_ON_TOP.icon()); + qmlShowAppOnTopDummyAction->setEnabled(false); + cmd = ActionManager::registerAction(qmlShowAppOnTopDummyAction, Constants::QML_SHOW_APP_ON_TOP); + debugMenu->addAction(cmd); + + auto qmlSelectDummyAction = new QAction(tr("Select"), this); + qmlSelectDummyAction->setCheckable(true); + qmlSelectDummyAction->setIcon(Icons::SELECT.icon()); + qmlSelectDummyAction->setEnabled(false); + cmd = ActionManager::registerAction(qmlSelectDummyAction, Constants::QML_SELECTTOOL); + debugMenu->addAction(cmd); + + auto qmlZoomDummyAction = new QAction(tr("Zoom"), this); + qmlZoomDummyAction->setCheckable(true); + qmlZoomDummyAction->setIcon(Core::Icons::ZOOM.icon()); + qmlZoomDummyAction->setEnabled(false); + cmd = ActionManager::registerAction(qmlZoomDummyAction, Constants::QML_ZOOMTOOL); + debugMenu->addAction(cmd); + + debugMenu->addSeparator(); + + // Don't add '1' to the string as it shows up in the shortcut dialog. + cmd = ActionManager::registerAction(m_watchAction1, + "Debugger.AddToWatch", cppeditorcontext); + //cmd->setDefaultKeySequence(QKeySequence(tr("Ctrl+D,Ctrl+W"))); + debugMenu->addAction(cmd); + + // If the CppEditor plugin is there, we want to add something to + // the editor context menu. + if (ActionContainer *editorContextMenu = + ActionManager::actionContainer(CppEditor::Constants::M_CONTEXT)) { + cmd = editorContextMenu->addSeparator(cppDebuggercontext); + cmd->setAttribute(Command::CA_Hide); + + cmd = ActionManager::registerAction(m_watchAction2, + "Debugger.AddToWatch2", cppDebuggercontext); + cmd->action()->setEnabled(true); + editorContextMenu->addAction(cmd); + cmd->setAttribute(Command::CA_Hide); + cmd->setAttribute(Command::CA_NonConfigurable); + // Debugger.AddToWatch is enough. + } + + QList engineOptionPages; + addGdbOptionPages(&engineOptionPages); + addCdbOptionPages(&engineOptionPages); + + foreach (IOptionsPage *op, engineOptionPages) + m_plugin->addAutoReleasedObject(op); + m_plugin->addAutoReleasedObject(new LocalsAndExpressionsOptionsPage); + m_plugin->addAutoReleasedObject(new DebuggerOptionsPage); + + connect(ModeManager::instance(), &ModeManager::currentModeChanged, + this, &DebuggerPluginPrivate::onModeChanged); + connect(ProjectExplorerPlugin::instance(), &ProjectExplorerPlugin::settingsChanged, + this, &DebuggerPluginPrivate::updateDebugWithoutDeployMenu); + + // Debug mode setup + auto mode = new DebugMode(m_mainWindow); + + (void) new DebugModeContext(m_mainWindow); + m_mainWindow->finalizeSetup(mode); + + m_plugin->addAutoReleasedObject(mode); + + + connect(SessionManager::instance(), &SessionManager::startupProjectChanged, + this, &DebuggerPluginPrivate::updateUiForProject); + + // + // Connections + // + + // Core + connect(ICore::instance(), &ICore::saveSettingsRequested, + this, &DebuggerPluginPrivate::writeSettings); + + // TextEditor + connect(TextEditorSettings::instance(), &TextEditorSettings::fontSettingsChanged, + this, &DebuggerPluginPrivate::fontSettingsChanged); + + // ProjectExplorer + connect(SessionManager::instance(), &SessionManager::sessionLoaded, + this, &DebuggerPluginPrivate::sessionLoaded); + connect(SessionManager::instance(), &SessionManager::aboutToSaveSession, + this, &DebuggerPluginPrivate::aboutToSaveSession); + connect(SessionManager::instance(), &SessionManager::aboutToUnloadSession, + this, &DebuggerPluginPrivate::aboutToUnloadSession); + connect(ProjectExplorerPlugin::instance(), &ProjectExplorerPlugin::updateRunActions, + this, &DebuggerPluginPrivate::updateDebugActions); + + // EditorManager + connect(EditorManager::instance(), &EditorManager::editorOpened, + this, &DebuggerPluginPrivate::editorOpened); + connect(EditorManager::instance(), &EditorManager::currentEditorChanged, + this, &DebuggerPluginPrivate::updateBreakMenuItem); + + // Application interaction + connect(action(SettingsDialog), &QAction::triggered, + [] { ICore::showOptionsDialog(DEBUGGER_COMMON_SETTINGS_ID); }); + + // Toolbar + ToolbarDescription toolbar; + toolbar.addAction(m_visibleStartAction); + toolbar.addAction(m_exitAction); + toolbar.addAction(m_nextAction); + toolbar.addAction(m_stepAction); + toolbar.addAction(m_stepOutAction); + toolbar.addAction(m_resetAction); + toolbar.addAction(m_operateByInstructionAction); + + if (isReverseDebuggingEnabled()) { + m_reverseToolButton = new QToolButton; + m_reverseToolButton->setDefaultAction(m_reverseDirectionAction); + toolbar.addWidget(m_reverseToolButton); + } + + toolbar.addWidget(new StyledSeparator); + toolbar.addWidget(new QLabel(tr("Threads:"))); + + m_threadBox = new QComboBox; + m_threadBox->setSizeAdjustPolicy(QComboBox::AdjustToContents); + connect(m_threadBox, static_cast(&QComboBox::activated), + this, &DebuggerPluginPrivate::selectThread); + + toolbar.addWidget(m_threadBox); +// toolbar.addSpacerItem(new QSpacerItem(4, 0)); + +// ToolbarDescription qmlToolbar +// qmlToolbar.addAction(qmlUpdateOnSaveDummyAction); +// qmlToolbar.addAction(qmlShowAppOnTopDummyAction); +// qmlToolbar.addWidget(new StyledSeparator); +// qmlToolbar.addAction(qmlSelectDummyAction); +// qmlToolbar.addAction(qmlZoomDummyAction); +// qmlToolbar.addWidget(new StyledSeparator); + + Perspective basePerspective({}, { + { DOCKWIDGET_STACK, m_stackWindow, {}, Perspective::SplitVertical }, + { DOCKWIDGET_BREAK, m_breakWindow, DOCKWIDGET_STACK, Perspective::SplitHorizontal }, + { DOCKWIDGET_THREADS, m_threadsWindow, DOCKWIDGET_BREAK, Perspective::AddToTab, false }, + { DOCKWIDGET_MODULES, m_modulesWindow, DOCKWIDGET_THREADS, Perspective::AddToTab, false }, + { DOCKWIDGET_SOURCE_FILES, m_sourceFilesWindow, DOCKWIDGET_MODULES, Perspective::AddToTab, false }, + { DOCKWIDGET_SNAPSHOTS, m_snapshotWindow, DOCKWIDGET_SOURCE_FILES, Perspective::AddToTab, false }, + { DOCKWIDGET_WATCHERS, m_localsAndExpressionsWindow, {}, Perspective::AddToTab, true, + Qt::RightDockWidgetArea }, + { DOCKWIDGET_OUTPUT, m_logWindow, {}, Perspective::AddToTab, false, Qt::TopDockWidgetArea }, + { DOCKWIDGET_BREAK, 0, {}, Perspective::Raise } + }); + + Perspective cppPerspective = basePerspective; + cppPerspective.setName(tr("Debugger")); + cppPerspective.addOperation({ DOCKWIDGET_REGISTER, m_registerWindow, DOCKWIDGET_SNAPSHOTS, + Perspective::AddToTab, false }); + + Debugger::registerToolbar(CppPerspectiveId, toolbar); + Debugger::registerPerspective(CppPerspectiveId, cppPerspective); + +// Perspective qmlPerspective = basePerspective; +// qmlPerspective.setName(tr("QML Debugger")); +// qmlPerspective.addOperation({ DOCKWIDGET_REGISTER, DOCKWIDGET_SNAPSHOTS, +// Perspective::AddToTab, false }); +// +// Debugger::registerToolbar(QmlPerspectiveId, toolbarContainer); +// Debugger::registerPerspective(QmlPerspectiveId, qmlPerspective); + + connect(action(EnableReverseDebugging), &SavedAction::valueChanged, + this, &DebuggerPluginPrivate::enableReverseDebuggingTriggered); + + setInitialState(); + connectEngine(0); + + connect(SessionManager::instance(), &SessionManager::startupProjectChanged, + this, &DebuggerPluginPrivate::onCurrentProjectChanged); + + m_commonOptionsPage = new CommonOptionsPage(m_globalDebuggerOptions); + m_plugin->addAutoReleasedObject(m_commonOptionsPage); + + m_globalDebuggerOptions->fromSettings(); + m_watchersWindow->setVisible(false); + m_returnWindow->setVisible(false); + return true; } @@ -1327,7 +1926,7 @@ void DebuggerPluginPrivate::onCurrentProjectChanged(Project *project) m_continueAction->setEnabled(false); m_exitAction->setEnabled(false); QString whyNot; - const bool canRun = ProjectExplorerPlugin::canRun(project, ProjectExplorer::Constants::DEBUG_RUN_MODE, &whyNot); + const bool canRun = ProjectExplorerPlugin::canRunStartupProject(ProjectExplorer::Constants::DEBUG_RUN_MODE, &whyNot); m_startAction->setEnabled(canRun); m_startAction->setToolTip(whyNot); m_debugWithoutDeployAction->setEnabled(canRun); @@ -1809,8 +2408,7 @@ static void changeFontSize(QWidget *widget, qreal size) widget->setFont(font); } -void DebuggerPluginPrivate::fontSettingsChanged - (const FontSettings &settings) +void DebuggerPluginPrivate::fontSettingsChanged(const FontSettings &settings) { if (!boolSetting(FontSizeFollowsEditor)) return; @@ -1902,7 +2500,7 @@ void DebuggerPluginPrivate::setInitialState() m_watchAction2->setEnabled(true); m_breakAction->setEnabled(false); //m_snapshotAction->setEnabled(false); - action(OperateByInstruction)->setEnabled(false); + m_operateByInstructionAction->setEnabled(false); m_exitAction->setEnabled(false); m_abortAction->setEnabled(false); @@ -1975,8 +2573,7 @@ void DebuggerPluginPrivate::updateState(DebuggerEngine *engine) m_localsAndExpressionsWindow->setShowLocals(false); activateDebugMode(); } else if (state == DebuggerFinished) { - Project *project = SessionManager::startupProject(); - const bool canRun = ProjectExplorerPlugin::canRun(project, ProjectExplorer::Constants::DEBUG_RUN_MODE); + const bool canRun = ProjectExplorerPlugin::canRunStartupProject(ProjectExplorer::Constants::DEBUG_RUN_MODE); // We don't want to do anything anymore. m_interruptAction->setEnabled(false); m_continueAction->setEnabled(false); @@ -2038,7 +2635,7 @@ void DebuggerPluginPrivate::updateState(DebuggerEngine *engine) const bool canOperateByInstruction = engine->hasCapability(OperateByInstructionCapability) && (stopped || isCore); - action(OperateByInstruction)->setEnabled(canOperateByInstruction); + m_operateByInstructionAction->setEnabled(canOperateByInstruction); m_abortAction->setEnabled(state != DebuggerNotReady && state != DebuggerFinished); @@ -2077,9 +2674,8 @@ void DebuggerPluginPrivate::updateDebugActions() if (m_currentEngine->state() != DebuggerNotReady) return; - Project *project = SessionManager::startupProject(); QString whyNot; - const bool canRun = ProjectExplorerPlugin::canRun(project, ProjectExplorer::Constants::DEBUG_RUN_MODE, &whyNot); + const bool canRun = ProjectExplorerPlugin::canRunStartupProject(ProjectExplorer::Constants::DEBUG_RUN_MODE, &whyNot); m_startAction->setEnabled(canRun); m_startAction->setToolTip(whyNot); m_debugWithoutDeployAction->setEnabled(canRun); @@ -2088,11 +2684,12 @@ void DebuggerPluginPrivate::updateDebugActions() if (m_snapshotHandler->currentIndex() < 0) { QString toolTip; const bool canRunAndBreakMain - = ProjectExplorerPlugin::canRun(project, ProjectExplorer::Constants::DEBUG_RUN_MODE_WITH_BREAK_ON_MAIN, &toolTip); + = ProjectExplorerPlugin::canRunStartupProject(ProjectExplorer::Constants::DEBUG_RUN_MODE_WITH_BREAK_ON_MAIN, &toolTip); m_stepAction->setEnabled(canRunAndBreakMain); m_nextAction->setEnabled(canRunAndBreakMain); if (canRunAndBreakMain) { - QTC_ASSERT(project, return ; ); + Project *project = SessionManager::startupProject(); + QTC_ASSERT(project, return); toolTip = tr("Start \"%1\" and break at function \"main()\"") .arg(project->displayName()); } @@ -2101,48 +2698,6 @@ void DebuggerPluginPrivate::updateDebugActions() } } -void DebuggerPluginPrivate::onCoreAboutToOpen() -{ - onModeChangedHelper(ModeManager::currentMode()); -} - -void DebuggerPluginPrivate::onModeChanged(IMode *mode) -{ - // FIXME: This one gets always called, even if switching between modes - // different then the debugger mode. E.g. Welcome and Help mode and - // also on shutdown. - - onModeChangedHelper(mode); - - if (mode->id() != Constants::MODE_DEBUG) { - m_toolTipManager.leavingDebugMode(); - return; - } - - if (IEditor *editor = EditorManager::currentEditor()) - editor->widget()->setFocus(); - - m_toolTipManager.debugModeEntered(); -} - -void DebuggerPluginPrivate::onModeChangedHelper(IMode *mode) -{ - m_inDebugMode = (mode && mode->id() == Constants::MODE_DEBUG); - m_mainWindow->setDockActionsVisible(m_inDebugMode); - - // Hide all the debugger windows if mode is different. - if (m_inDebugMode) { -// readWindowSettings(); - updateActiveLanguages(); - } else { - // Hide dock widgets manually in case they are floating. - foreach (QDockWidget *dockWidget, m_mainWindow->dockWidgets()) { - if (dockWidget->isFloating()) - dockWidget->hide(); - } - } -} - void DebuggerPluginPrivate::updateDebugWithoutDeployMenu() { const bool state = ProjectExplorerPlugin::projectExplorerSettings().deployBeforeRun; @@ -2245,7 +2800,6 @@ QTreeView *inspectorView() void DebuggerPluginPrivate::showMessage(const QString &msg, int channel, int timeout) { //qDebug() << "PLUGIN OUTPUT: " << channel << msg; - //ConsoleWindow *cw = m_consoleWindow; QTC_ASSERT(m_logWindow, return); switch (channel) { case StatusBar: @@ -2272,8 +2826,21 @@ void DebuggerPluginPrivate::showMessage(const QString &msg, int channel, int tim static void createNewDock(QWidget *widget) { - dd->createDockWidget(Core::Id::fromString(widget->objectName()), widget); - QDockWidget *dockWidget = qobject_cast(widget->parentWidget()); +// m_mainWindow->registerDockWidget(dockId, widget); + +// QDockWidget *dockWidget = qobject_cast(widget->parentWidget()); +// //dockWidget->installEventFilter(&m_resizeEventFilter); + +// QAction *toggleViewAction = dockWidget->toggleViewAction(); +// Command *cmd = ActionManager::registerAction(toggleViewAction, +// Id("Debugger.").withSuffix(widget->objectName())); +// cmd->setAttribute(Command::CA_Hide); +// dd->createDockWidget(Core::Id::fromString(widget->objectName()), widget); +// QDockWidget *dockWidget = qobject_cast(widget->parentWidget()); +// QDockWidget *dockWidget = Debugger::registerDockWidget(Id::fromString(widget->objectName()), widget); + QDockWidget *dockWidget = new QDockWidget; + dockWidget->setWidget(widget); + dockWidget->setWindowTitle(widget->windowTitle()); dockWidget->setFeatures(QDockWidget::DockWidgetClosable); dockWidget->show(); @@ -2287,7 +2854,7 @@ static QString formatStartParameters(DebuggerRunParameters &sp) << "\nABI: " << sp.toolChainAbi.toString() << '\n'; str << "Languages: "; if (sp.languages == AnyLanguage) - str << "any"; + str << "any "; if (sp.languages & CppLanguage) str << "c++ "; if (sp.languages & QmlLanguage) @@ -2351,7 +2918,7 @@ void DebuggerPluginPrivate::runControlFinished(DebuggerEngine *engine) // Connect to some existing engine. m_snapshotHandler->activateSnapshot(0); } - action(OperateByInstruction)->setValue(QVariant(false)); + m_operateByInstructionAction->setChecked(false); m_logWindow->clearUndoRedoStacks(); } @@ -2394,629 +2961,6 @@ bool isReverseDebugging() void DebuggerPluginPrivate::extensionsInitialized() { - const QKeySequence debugKey = QKeySequence(UseMacShortcuts ? tr("Ctrl+Y") : tr("F5")); - - QSettings *settings = ICore::settings(); - - m_debuggerSettings = new DebuggerSettings; - m_debuggerSettings->readSettings(); - - connect(ICore::instance(), &ICore::coreAboutToClose, this, &DebuggerPluginPrivate::coreShutdown); - - const Context cppDebuggercontext(C_CPPDEBUGGER); - const Context cppeditorcontext(CppEditor::Constants::CPPEDITOR_ID); - - m_startIcon = Core::Icons::DEBUG_START_SMALL.icon(); - m_exitIcon = Core::Icons::DEBUG_EXIT_SMALL.icon(); - const QIcon continueSideBarIcon = - Icon::sideBarIcon(Icons::CONTINUE, Icons::CONTINUE_FLAT); - m_continueIcon = Icon::combinedIcon({Core::Icons::DEBUG_CONTINUE_SMALL.icon(), continueSideBarIcon}); - const QIcon interruptSideBarIcon = - Icon::sideBarIcon(Icons::INTERRUPT, Icons::INTERRUPT_FLAT); - m_interruptIcon = Icon::combinedIcon({Core::Icons::DEBUG_INTERRUPT_SMALL.icon(), interruptSideBarIcon}); - m_locationMarkIcon = Icons::LOCATION.icon(); - m_resetIcon = Icons::RESTART.icon(); - - m_busy = false; - - m_logWindow = new LogWindow; - m_logWindow->setObjectName(QLatin1String(DOCKWIDGET_OUTPUT)); - - m_breakHandler = new BreakHandler; - m_breakView = new BreakTreeView; - m_breakView->setSettings(settings, "Debugger.BreakWindow"); - m_breakView->setModel(m_breakHandler->model()); - m_breakWindow = addSearch(m_breakView, tr("Breakpoints"), DOCKWIDGET_BREAK); - - m_modulesView = new ModulesTreeView; - m_modulesView->setSettings(settings, "Debugger.ModulesView"); - m_modulesWindow = addSearch(m_modulesView, tr("Modules"), DOCKWIDGET_MODULES); - - m_registerView = new RegisterTreeView; - m_registerView->setSettings(settings, "Debugger.RegisterView"); - m_registerWindow = addSearch(m_registerView, tr("Registers"), DOCKWIDGET_REGISTER); - - m_stackView = new StackTreeView; - m_stackView->setSettings(settings, "Debugger.StackView"); - m_stackWindow = addSearch(m_stackView, tr("Stack"), DOCKWIDGET_STACK); - - m_sourceFilesView = new SourceFilesTreeView; - m_sourceFilesView->setSettings(settings, "Debugger.SourceFilesView"); - m_sourceFilesWindow = addSearch(m_sourceFilesView, tr("Source Files"), DOCKWIDGET_SOURCE_FILES); - - m_threadsView = new ThreadsTreeView; - m_threadsView->setSettings(settings, "Debugger.ThreadsView"); - m_threadsWindow = addSearch(m_threadsView, tr("Threads"), DOCKWIDGET_THREADS); - - m_returnView = new WatchTreeView(ReturnType); // No settings. - m_returnWindow = addSearch(m_returnView, tr("Locals and Expressions"), "CppDebugReturn"); - - m_localsView = new WatchTreeView(LocalsType); - m_localsView->setSettings(settings, "Debugger.LocalsView"); - m_localsWindow = addSearch(m_localsView, tr("Locals and Expressions"), "CppDebugLocals"); - - m_watchersView = new WatchTreeView(WatchersType); // No settings. - m_watchersWindow = addSearch(m_watchersView, tr("Locals and Expressions"), "CppDebugWatchers"); - - m_inspectorView = new WatchTreeView(InspectType); - m_inspectorView->setSettings(settings, "Debugger.LocalsView"); // sic! same as locals view. - m_inspectorWindow = addSearch(m_inspectorView, tr("Locals and Expressions"), "Inspector"); - - // Snapshot - m_snapshotHandler = new SnapshotHandler; - m_snapshotView = new SnapshotTreeView(m_snapshotHandler); - m_snapshotView->setSettings(settings, "Debugger.SnapshotView"); - m_snapshotView->setModel(m_snapshotHandler->model()); - m_snapshotWindow = addSearch(m_snapshotView, tr("Snapshots"), DOCKWIDGET_SNAPSHOTS); - - // Watchers - connect(m_localsView->header(), &QHeaderView::sectionResized, - this, &DebuggerPluginPrivate::updateWatchersHeader, Qt::QueuedConnection); - - QAction *act = 0; - - act = m_continueAction = new QAction(tr("Continue"), this); - act->setIcon(m_continueIcon); - connect(act, &QAction::triggered, this, &DebuggerPluginPrivate::handleExecContinue); - - act = m_exitAction = new QAction(tr("Stop Debugger"), this); - act->setIcon(m_exitIcon); - connect(act, &QAction::triggered, this, &DebuggerPluginPrivate::handleExecExit); - - act = m_interruptAction = new QAction(tr("Interrupt"), this); - act->setIcon(m_interruptIcon); - connect(act, &QAction::triggered, this, &DebuggerPluginPrivate::handleExecInterrupt); - - // A "disabled pause" seems to be a good choice. - act = m_undisturbableAction = new QAction(tr("Debugger is Busy"), this); - act->setIcon(m_interruptIcon); - act->setEnabled(false); - - act = m_abortAction = new QAction(tr("Abort Debugging"), this); - act->setToolTip(tr("Aborts debugging and " - "resets the debugger to the initial state.")); - connect(act, &QAction::triggered, this, &DebuggerPluginPrivate::handleAbort); - - act = m_resetAction = new QAction(tr("Restart Debugging"),this); - act->setToolTip(tr("Restart the debugging session.")); - act->setIcon(m_resetIcon); - connect(act, &QAction::triggered, this, &DebuggerPluginPrivate::handleReset); - - act = m_nextAction = new QAction(tr("Step Over"), this); - act->setIcon(Icons::STEP_OVER.icon()); - connect(act, &QAction::triggered, this, &DebuggerPluginPrivate::handleExecNext); - - act = m_stepAction = new QAction(tr("Step Into"), this); - act->setIcon(Icons::STEP_INTO.icon()); - connect(act, &QAction::triggered, this, &DebuggerPluginPrivate::handleExecStep); - - act = m_stepOutAction = new QAction(tr("Step Out"), this); - act->setIcon(Icons::STEP_OUT.icon()); - connect(act, &QAction::triggered, this, &DebuggerPluginPrivate::handleExecStepOut); - - act = m_runToLineAction = new QAction(tr("Run to Line"), this); - connect(act, &QAction::triggered, this, &DebuggerPluginPrivate::handleExecRunToLine); - - act = m_runToSelectedFunctionAction = - new QAction(tr("Run to Selected Function"), this); - connect(act, &QAction::triggered, this, &DebuggerPluginPrivate::handleExecRunToSelectedFunction); - - act = m_returnFromFunctionAction = - new QAction(tr("Immediately Return From Inner Function"), this); - connect(act, &QAction::triggered, this, &DebuggerPluginPrivate::handleExecReturn); - - act = m_jumpToLineAction = new QAction(tr("Jump to Line"), this); - connect(act, &QAction::triggered, this, &DebuggerPluginPrivate::handleExecJumpToLine); - - m_breakAction = new QAction(tr("Toggle Breakpoint"), this); - - act = m_watchAction1 = new QAction(tr("Add Expression Evaluator"), this); - connect(act, &QAction::triggered, this, &DebuggerPluginPrivate::handleAddToWatchWindow); - - act = m_watchAction2 = new QAction(tr("Add Expression Evaluator"), this); - connect(act, &QAction::triggered, this, &DebuggerPluginPrivate::handleAddToWatchWindow); - - //m_snapshotAction = new QAction(tr("Create Snapshot"), this); - //m_snapshotAction->setProperty(Role, RequestCreateSnapshotRole); - //m_snapshotAction->setIcon(Icons::SNAPSHOT.icon()); - - act = m_reverseDirectionAction = new QAction(tr("Reverse Direction"), this); - act->setCheckable(true); - act->setChecked(false); - act->setCheckable(false); - act->setIcon(Icons::REVERSE_MODE.icon()); - act->setIconVisibleInMenu(false); - - act = m_frameDownAction = new QAction(tr("Move to Called Frame"), this); - connect(act, &QAction::triggered, this, &DebuggerPluginPrivate::handleFrameDown); - - act = m_frameUpAction = new QAction(tr("Move to Calling Frame"), this); - connect(act, &QAction::triggered, this, &DebuggerPluginPrivate::handleFrameUp); - - connect(action(OperateByInstruction), &QAction::triggered, - this, &DebuggerPluginPrivate::handleOperateByInstructionTriggered); - - ActionContainer *debugMenu = ActionManager::actionContainer(PE::M_DEBUG); - - // Dock widgets - QDockWidget *dock = 0; - dock = createDockWidget(DOCKWIDGET_MODULES, m_modulesWindow); - connect(dock->toggleViewAction(), &QAction::toggled, - this, &DebuggerPluginPrivate::modulesDockToggled, Qt::QueuedConnection); - - dock = createDockWidget(DOCKWIDGET_REGISTER, m_registerWindow); - connect(dock->toggleViewAction(), &QAction::toggled, - this, &DebuggerPluginPrivate::registerDockToggled, Qt::QueuedConnection); - - dock = createDockWidget(DOCKWIDGET_SOURCE_FILES, m_sourceFilesWindow); - connect(dock->toggleViewAction(), &QAction::toggled, - this, &DebuggerPluginPrivate::sourceFilesDockToggled, Qt::QueuedConnection); - - createDockWidget(DOCKWIDGET_OUTPUT, m_logWindow); - createDockWidget(DOCKWIDGET_BREAK, m_breakWindow); - createDockWidget(DOCKWIDGET_SNAPSHOTS, m_snapshotWindow); - createDockWidget(DOCKWIDGET_STACK, m_stackWindow); - createDockWidget(DOCKWIDGET_THREADS, m_threadsWindow); - - m_localsAndExpressionsWindow = new LocalsAndExpressionsWindow( - m_localsWindow, m_inspectorWindow, m_returnWindow, - m_watchersWindow); - m_localsAndExpressionsWindow->setObjectName(QLatin1String(DOCKWIDGET_WATCHERS)); - m_localsAndExpressionsWindow->setWindowTitle(m_localsWindow->windowTitle()); - - dock = createDockWidget(DOCKWIDGET_WATCHERS, m_localsAndExpressionsWindow); - - m_mainWindow->addDockActionsToMenu(m_viewsMenu->menu()); - - m_plugin->addAutoReleasedObject(createDebuggerRunControlFactory(m_plugin)); - - // The main "Start Debugging" action. - act = m_startAction = new QAction(this); - const QIcon sideBarIcon = - Icon::sideBarIcon(ProjectExplorer::Icons::DEBUG_START, ProjectExplorer::Icons::DEBUG_START_FLAT); - const QIcon debuggerIcon = Icon::combinedIcon({Core::Icons::DEBUG_START_SMALL.icon(), sideBarIcon}); - act->setIcon(debuggerIcon); - act->setText(tr("Start Debugging")); - connect(act, &QAction::triggered, [] { ProjectExplorerPlugin::runStartupProject(ProjectExplorer::Constants::DEBUG_RUN_MODE); }); - - act = m_debugWithoutDeployAction = new QAction(this); - act->setText(tr("Start Debugging Without Deployment")); - connect(act, &QAction::triggered, [] { ProjectExplorerPlugin::runStartupProject(ProjectExplorer::Constants::DEBUG_RUN_MODE, true); }); - - act = m_startAndDebugApplicationAction = new QAction(this); - act->setText(tr("Start and Debug External Application...")); - connect(act, &QAction::triggered, this, &DebuggerPluginPrivate::startAndDebugApplication); - - act = m_attachToCoreAction = new QAction(this); - act->setText(tr("Load Core File...")); - connect(act, &QAction::triggered, this, &DebuggerPluginPrivate::attachCore); - - act = m_attachToRemoteServerAction = new QAction(this); - act->setText(tr("Attach to Running Debug Server...")); - connect(act, &QAction::triggered, this, &DebuggerPluginPrivate::attachToRemoteServer); - - act = m_startRemoteServerAction = new QAction(this); - act->setText(tr("Start Debug Server Attached to Process...")); - connect(act, &QAction::triggered, this, &DebuggerPluginPrivate::startRemoteServerAndAttachToProcess); - - act = m_attachToRunningApplication = new QAction(this); - act->setText(tr("Attach to Running Application...")); - connect(act, &QAction::triggered, this, &DebuggerPluginPrivate::attachToRunningApplication); - - act = m_attachToUnstartedApplication = new QAction(this); - act->setText(tr("Attach to Unstarted Application...")); - connect(act, &QAction::triggered, this, &DebuggerPluginPrivate::attachToUnstartedApplicationDialog); - - act = m_attachToQmlPortAction = new QAction(this); - act->setText(tr("Attach to QML Port...")); - connect(act, &QAction::triggered, this, &DebuggerPluginPrivate::attachToQmlPort); - - if (HostOsInfo::isWindowsHost()) { - m_startRemoteCdbAction = new QAction(tr("Attach to Remote CDB Session..."), this); - connect(m_startRemoteCdbAction, &QAction::triggered, - this, &DebuggerPluginPrivate::startRemoteCdbSession); - } - - act = m_detachAction = new QAction(this); - act->setText(tr("Detach Debugger")); - connect(act, &QAction::triggered, this, &DebuggerPluginPrivate::handleExecDetach); - - // "Start Debugging" sub-menu - // groups: - // G_DEFAULT_ONE - // G_START_LOCAL - // G_START_REMOTE - // G_START_QML - - Command *cmd = 0; - ActionContainer *mstart = ActionManager::actionContainer(PE::M_DEBUG_STARTDEBUGGING); - - cmd = ActionManager::registerAction(m_startAction, Constants::DEBUG); - cmd->setDescription(tr("Start Debugging")); - cmd->setDefaultKeySequence(debugKey); - cmd->setAttribute(Command::CA_UpdateText); - mstart->addAction(cmd, CC::G_DEFAULT_ONE); - m_visibleStartAction = new ProxyAction(this); - m_visibleStartAction->initialize(cmd->action()); - m_visibleStartAction->setAttribute(ProxyAction::UpdateText); - m_visibleStartAction->setAttribute(ProxyAction::UpdateIcon); - m_visibleStartAction->setAction(cmd->action()); - - ModeManager::addAction(m_visibleStartAction, Constants::P_ACTION_DEBUG); - - cmd = ActionManager::registerAction(m_debugWithoutDeployAction, - "Debugger.DebugWithoutDeploy"); - cmd->setAttribute(Command::CA_Hide); - mstart->addAction(cmd, CC::G_DEFAULT_ONE); - - cmd = ActionManager::registerAction(m_attachToRunningApplication, - "Debugger.AttachToRemoteProcess"); - cmd->setDescription(tr("Attach to Running Application")); - mstart->addAction(cmd, G_GENERAL); - - cmd = ActionManager::registerAction(m_attachToUnstartedApplication, - "Debugger.AttachToUnstartedProcess"); - cmd->setDescription(tr("Attach to Unstarted Application")); - mstart->addAction(cmd, G_GENERAL); - - cmd = ActionManager::registerAction(m_startAndDebugApplicationAction, - "Debugger.StartAndDebugApplication"); - cmd->setAttribute(Command::CA_Hide); - mstart->addAction(cmd, G_GENERAL); - - cmd = ActionManager::registerAction(m_attachToCoreAction, - "Debugger.AttachCore"); - cmd->setAttribute(Command::CA_Hide); - mstart->addAction(cmd, Constants::G_GENERAL); - - cmd = ActionManager::registerAction(m_attachToRemoteServerAction, - "Debugger.AttachToRemoteServer"); - cmd->setAttribute(Command::CA_Hide); - mstart->addAction(cmd, Constants::G_SPECIAL); - - cmd = ActionManager::registerAction(m_startRemoteServerAction, - "Debugger.StartRemoteServer"); - cmd->setDescription(tr("Start Gdbserver")); - mstart->addAction(cmd, Constants::G_SPECIAL); - - if (m_startRemoteCdbAction) { - cmd = ActionManager::registerAction(m_startRemoteCdbAction, - "Debugger.AttachRemoteCdb"); - cmd->setAttribute(Command::CA_Hide); - mstart->addAction(cmd, Constants::G_SPECIAL); - } - - mstart->addSeparator(Context(CC::C_GLOBAL), Constants::G_START_QML); - - cmd = ActionManager::registerAction(m_attachToQmlPortAction, "Debugger.AttachToQmlPort"); - cmd->setAttribute(Command::CA_Hide); - mstart->addAction(cmd, Constants::G_START_QML); - - cmd = ActionManager::registerAction(m_detachAction, "Debugger.Detach"); - cmd->setAttribute(Command::CA_Hide); - debugMenu->addAction(cmd, CC::G_DEFAULT_ONE); - - cmd = ActionManager::registerAction(m_interruptAction, Constants::INTERRUPT); - cmd->setDescription(tr("Interrupt Debugger")); - debugMenu->addAction(cmd, CC::G_DEFAULT_ONE); - - cmd = ActionManager::registerAction(m_continueAction, Constants::CONTINUE); - cmd->setDefaultKeySequence(debugKey); - debugMenu->addAction(cmd, CC::G_DEFAULT_ONE); - - cmd = ActionManager::registerAction(m_exitAction, Constants::STOP); - debugMenu->addAction(cmd, CC::G_DEFAULT_ONE); - m_hiddenStopAction = new ProxyAction(this); - m_hiddenStopAction->initialize(cmd->action()); - m_hiddenStopAction->setAttribute(ProxyAction::UpdateText); - m_hiddenStopAction->setAttribute(ProxyAction::UpdateIcon); - - cmd = ActionManager::registerAction(m_hiddenStopAction, Constants::HIDDEN_STOP); - cmd->setDefaultKeySequence(QKeySequence(UseMacShortcuts ? tr("Shift+Ctrl+Y") : tr("Shift+F5"))); - - cmd = ActionManager::registerAction(m_abortAction, Constants::ABORT); - cmd->setDescription(tr("Reset Debugger")); - debugMenu->addAction(cmd, CC::G_DEFAULT_ONE); - - cmd = ActionManager::registerAction(m_resetAction, Constants::RESET); - cmd->setDescription(tr("Restart Debugging")); - debugMenu->addAction(cmd, CC::G_DEFAULT_ONE); - - debugMenu->addSeparator(); - - cmd = ActionManager::registerAction(m_nextAction, Constants::NEXT); - cmd->setDefaultKeySequence(QKeySequence(UseMacShortcuts ? tr("Ctrl+Shift+O") : tr("F10"))); - cmd->setAttribute(Command::CA_Hide); - cmd->setAttribute(Command::CA_UpdateText); - debugMenu->addAction(cmd); - - cmd = ActionManager::registerAction(m_stepAction, Constants::STEP); - cmd->setDefaultKeySequence(QKeySequence(UseMacShortcuts ? tr("Ctrl+Shift+I") : tr("F11"))); - cmd->setAttribute(Command::CA_Hide); - cmd->setAttribute(Command::CA_UpdateText); - debugMenu->addAction(cmd); - - cmd = ActionManager::registerAction(m_stepOutAction, - Constants::STEPOUT, cppDebuggercontext); - cmd->setDefaultKeySequence(QKeySequence(UseMacShortcuts ? tr("Ctrl+Shift+T") : tr("Shift+F11"))); - cmd->setAttribute(Command::CA_Hide); - debugMenu->addAction(cmd); - - cmd = ActionManager::registerAction(m_runToLineAction, - "Debugger.RunToLine", cppDebuggercontext); - cmd->setDefaultKeySequence(QKeySequence(UseMacShortcuts ? tr("Shift+F8") : tr("Ctrl+F10"))); - cmd->setAttribute(Command::CA_Hide); - debugMenu->addAction(cmd); - - cmd = ActionManager::registerAction(m_runToSelectedFunctionAction, - "Debugger.RunToSelectedFunction", cppDebuggercontext); - cmd->setDefaultKeySequence(QKeySequence(tr("Ctrl+F6"))); - cmd->setAttribute(Command::CA_Hide); - // Don't add to menu by default as keeping its enabled state - // and text up-to-date is a lot of hassle. - // debugMenu->addAction(cmd); - - cmd = ActionManager::registerAction(m_jumpToLineAction, - "Debugger.JumpToLine", cppDebuggercontext); - cmd->setAttribute(Command::CA_Hide); - debugMenu->addAction(cmd); - - cmd = ActionManager::registerAction(m_returnFromFunctionAction, - "Debugger.ReturnFromFunction", cppDebuggercontext); - cmd->setAttribute(Command::CA_Hide); - debugMenu->addAction(cmd); - - if (isReverseDebuggingEnabled()) { - cmd = ActionManager::registerAction(m_reverseDirectionAction, - Constants::REVERSE, cppDebuggercontext); - cmd->setDefaultKeySequence(QKeySequence(UseMacShortcuts ? QString() : tr("F12"))); - cmd->setAttribute(Command::CA_Hide); - debugMenu->addAction(cmd); - } - - debugMenu->addSeparator(); - - //cmd = ActionManager::registerAction(m_snapshotAction, - // "Debugger.Snapshot", cppDebuggercontext); - //cmd->setDefaultKeySequence(QKeySequence(tr("Ctrl+D,Ctrl+S"))); - //cmd->setAttribute(Command::CA_Hide); - //debugMenu->addAction(cmd); - - ActionManager::registerAction(m_frameDownAction, - "Debugger.FrameDown", cppDebuggercontext); - ActionManager::registerAction(m_frameUpAction, - "Debugger.FrameUp", cppDebuggercontext); - - cmd = ActionManager::registerAction(action(OperateByInstruction), - Constants::OPERATE_BY_INSTRUCTION, cppDebuggercontext); - cmd->setAttribute(Command::CA_Hide); - debugMenu->addAction(cmd); - - cmd = ActionManager::registerAction(m_breakAction, "Debugger.ToggleBreak"); - cmd->setDefaultKeySequence(QKeySequence(UseMacShortcuts ? tr("F8") : tr("F9"))); - debugMenu->addAction(cmd); - connect(m_breakAction, &QAction::triggered, - this, &DebuggerPluginPrivate::toggleBreakpointHelper); - - debugMenu->addSeparator(); - - // currently broken -// QAction *qmlUpdateOnSaveDummyAction = new QAction(tr("Apply Changes on Save"), this); -// qmlUpdateOnSaveDummyAction->setCheckable(true); -// qmlUpdateOnSaveDummyAction->setIcon(Icons::APPLY_ON_SAVE.icon()); -// qmlUpdateOnSaveDummyAction->setEnabled(false); -// cmd = ActionManager::registerAction(qmlUpdateOnSaveDummyAction, Constants::QML_UPDATE_ON_SAVE); -// debugMenu->addAction(cmd); - - QAction *qmlShowAppOnTopDummyAction = new QAction(tr("Show Application on Top"), this); - qmlShowAppOnTopDummyAction->setCheckable(true); - qmlShowAppOnTopDummyAction->setIcon(Icons::APP_ON_TOP.icon()); - qmlShowAppOnTopDummyAction->setEnabled(false); - cmd = ActionManager::registerAction(qmlShowAppOnTopDummyAction, Constants::QML_SHOW_APP_ON_TOP); - debugMenu->addAction(cmd); - - QAction *qmlSelectDummyAction = new QAction(tr("Select"), this); - qmlSelectDummyAction->setCheckable(true); - qmlSelectDummyAction->setIcon(Icons::SELECT.icon()); - qmlSelectDummyAction->setEnabled(false); - cmd = ActionManager::registerAction(qmlSelectDummyAction, Constants::QML_SELECTTOOL); - debugMenu->addAction(cmd); - - QAction *qmlZoomDummyAction = new QAction(tr("Zoom"), this); - qmlZoomDummyAction->setCheckable(true); - qmlZoomDummyAction->setIcon(Core::Icons::ZOOM.icon()); - qmlZoomDummyAction->setEnabled(false); - cmd = ActionManager::registerAction(qmlZoomDummyAction, Constants::QML_ZOOMTOOL); - debugMenu->addAction(cmd); - - debugMenu->addSeparator(); - - // Don't add '1' to the string as it shows up in the shortcut dialog. - cmd = ActionManager::registerAction(m_watchAction1, - "Debugger.AddToWatch", cppeditorcontext); - //cmd->setDefaultKeySequence(QKeySequence(tr("Ctrl+D,Ctrl+W"))); - debugMenu->addAction(cmd); - - // If the CppEditor plugin is there, we want to add something to - // the editor context menu. - if (ActionContainer *editorContextMenu = - ActionManager::actionContainer(CppEditor::Constants::M_CONTEXT)) { - cmd = editorContextMenu->addSeparator(cppDebuggercontext); - cmd->setAttribute(Command::CA_Hide); - - cmd = ActionManager::registerAction(m_watchAction2, - "Debugger.AddToWatch2", cppDebuggercontext); - cmd->action()->setEnabled(true); - editorContextMenu->addAction(cmd); - cmd->setAttribute(Command::CA_Hide); - cmd->setAttribute(Command::CA_NonConfigurable); - // Debugger.AddToWatch is enough. - } - - QList engineOptionPages; - addGdbOptionPages(&engineOptionPages); - addCdbOptionPages(&engineOptionPages); - - foreach (IOptionsPage *op, engineOptionPages) - m_plugin->addAutoReleasedObject(op); - m_plugin->addAutoReleasedObject(new LocalsAndExpressionsOptionsPage); - m_plugin->addAutoReleasedObject(new DebuggerOptionsPage); - - connect(ModeManager::instance(), &ModeManager::currentModeChanged, - this, &DebuggerPluginPrivate::onModeChanged); - connect(ICore::instance(), &ICore::coreAboutToOpen, - this, &DebuggerPluginPrivate::onCoreAboutToOpen); - connect(ProjectExplorerPlugin::instance(), &ProjectExplorerPlugin::settingsChanged, - this, &DebuggerPluginPrivate::updateDebugWithoutDeployMenu); - - // Debug mode setup - DebugMode *debugMode = new DebugMode; - QWidget *widget = createContents(debugMode); - IContext *modeContextObject = new IContext(this); - modeContextObject->setContext(Context(CC::C_EDITORMANAGER)); - modeContextObject->setWidget(widget); - ICore::addContextObject(modeContextObject); - debugMode->setWidget(widget); - - m_plugin->addAutoReleasedObject(debugMode); - - // - // Connections - // - - // Core - connect(ICore::instance(), &ICore::saveSettingsRequested, - this, &DebuggerPluginPrivate::writeSettings); - - // TextEditor - connect(TextEditorSettings::instance(), &TextEditorSettings::fontSettingsChanged, - this, &DebuggerPluginPrivate::fontSettingsChanged); - - // ProjectExplorer - connect(SessionManager::instance(), &SessionManager::sessionLoaded, - this, &DebuggerPluginPrivate::sessionLoaded); - connect(SessionManager::instance(), &SessionManager::aboutToSaveSession, - this, &DebuggerPluginPrivate::aboutToSaveSession); - connect(SessionManager::instance(), &SessionManager::aboutToUnloadSession, - this, &DebuggerPluginPrivate::aboutToUnloadSession); - connect(ProjectExplorerPlugin::instance(), &ProjectExplorerPlugin::updateRunActions, - this, &DebuggerPluginPrivate::updateDebugActions); - - // EditorManager - connect(EditorManager::instance(), &EditorManager::editorOpened, - this, &DebuggerPluginPrivate::editorOpened); - connect(EditorManager::instance(), &EditorManager::currentEditorChanged, - this, &DebuggerPluginPrivate::updateBreakMenuItem); - - // Application interaction - connect(action(SettingsDialog), &QAction::triggered, - [] { ICore::showOptionsDialog(DEBUGGER_COMMON_SETTINGS_ID); }); - - // Toolbar - QWidget *toolbarContainer = new QWidget(mainWindow()); - - QHBoxLayout *hbox = new QHBoxLayout(toolbarContainer); - hbox->setMargin(0); - hbox->setSpacing(0); - hbox->addWidget(toolButton(m_visibleStartAction)); - hbox->addWidget(toolButton(Constants::STOP)); - hbox->addWidget(toolButton(Constants::NEXT)); - hbox->addWidget(toolButton(Constants::STEP)); - hbox->addWidget(toolButton(Constants::STEPOUT)); - hbox->addWidget(toolButton(Constants::RESET)); - hbox->addWidget(toolButton(Constants::OPERATE_BY_INSTRUCTION)); - - if (isReverseDebuggingEnabled()) { - m_reverseToolButton = toolButton(Constants::REVERSE); - hbox->addWidget(m_reverseToolButton); - } - - hbox->addWidget(new StyledSeparator); - hbox->addWidget(new QLabel(tr("Threads:"))); - - m_threadBox = new QComboBox; - m_threadBox->setSizeAdjustPolicy(QComboBox::AdjustToContents); - connect(m_threadBox, static_cast(&QComboBox::activated), - this, &DebuggerPluginPrivate::selectThread); - - hbox->addWidget(m_threadBox); - hbox->addSpacerItem(new QSpacerItem(4, 0)); - - QWidget *qmlToolbar = new QWidget(mainWindow()); - hbox = new QHBoxLayout(qmlToolbar); - hbox->setMargin(0); - hbox->setSpacing(0); - // currently broken - //hbox->addWidget(toolButton(Constants::QML_UPDATE_ON_SAVE)); - hbox->addWidget(toolButton(Constants::QML_SHOW_APP_ON_TOP)); - hbox->addWidget(new StyledSeparator); - hbox->addWidget(toolButton(Constants::QML_SELECTTOOL)); - hbox->addWidget(toolButton(Constants::QML_ZOOMTOOL)); - hbox->addWidget(new StyledSeparator); - - m_mainWindow->registerToolbar(CppPerspectiveId, toolbarContainer); - m_mainWindow->registerPerspective(CppPerspectiveId, { - { DOCKWIDGET_STACK, Core::Id(), Perspective::SplitVertical }, - { DOCKWIDGET_BREAK, DOCKWIDGET_STACK, Perspective::SplitHorizontal }, - { DOCKWIDGET_MODULES, DOCKWIDGET_BREAK, Perspective::AddToTab }, - { DOCKWIDGET_SOURCE_FILES, DOCKWIDGET_MODULES, Perspective::AddToTab }, - { DOCKWIDGET_WATCHERS, Core::Id(), Perspective::AddToTab, - true, Qt::RightDockWidgetArea }, - { DOCKWIDGET_REGISTER, DOCKWIDGET_WATCHERS, Perspective::AddToTab, - true, Qt::RightDockWidgetArea }, - { DOCKWIDGET_OUTPUT, Core::Id(), Perspective::AddToTab, - false, Qt::TopDockWidgetArea } - }); - - m_mainWindow->registerToolbar(QmlPerspectiveId, toolbarContainer); - m_mainWindow->registerPerspective(QmlPerspectiveId, { - { DOCKWIDGET_STACK, Core::Id(), Perspective::SplitVertical }, - { DOCKWIDGET_BREAK, DOCKWIDGET_STACK, Perspective::SplitHorizontal }, - { DOCKWIDGET_MODULES, DOCKWIDGET_BREAK, Perspective::AddToTab }, - { DOCKWIDGET_SOURCE_FILES, DOCKWIDGET_MODULES, Perspective::AddToTab }, - { DOCKWIDGET_WATCHERS, Core::Id(), Perspective::AddToTab, - true, Qt::RightDockWidgetArea }, - { DOCKWIDGET_OUTPUT, Core::Id(), Perspective::AddToTab, - false, Qt::TopDockWidgetArea } - }); - - connect(action(EnableReverseDebugging), &SavedAction::valueChanged, - this, &DebuggerPluginPrivate::enableReverseDebuggingTriggered); - - setInitialState(); - connectEngine(0); - - connect(SessionManager::instance(), &SessionManager::startupProjectChanged, - this, &DebuggerPluginPrivate::onCurrentProjectChanged); - - m_commonOptionsPage = new CommonOptionsPage(m_globalDebuggerOptions); - m_plugin->addAutoReleasedObject(m_commonOptionsPage); - - m_globalDebuggerOptions->fromSettings(); - m_watchersWindow->setVisible(false); - m_returnWindow->setVisible(false); - - // time gdb -i mi -ex 'b debuggerplugin.cpp:800' -ex r -ex q bin/qtcreator.bin } DebuggerEngine *currentEngine() @@ -3174,11 +3118,6 @@ void displayDebugger(DebuggerEngine *engine, bool updateEngine) dd->displayDebugger(engine, updateEngine); } -DebuggerLanguages activeLanguages() -{ - return dd->activeDebugLanguages(); -} - void synchronizeBreakpoints() { dd->synchronizeBreakpoints(); @@ -3186,7 +3125,7 @@ void synchronizeBreakpoints() QWidget *mainWindow() { - return dd->mainWindow(); + return dd->m_mainWindow; } bool isDockVisible(const QString &objectName) @@ -3215,8 +3154,6 @@ QSharedPointer globalDebuggerOptions() return dd->m_globalDebuggerOptions; } -} // namespace Internal - /////////////////////////////////////////////////////////////////////// // // DebuggerPlugin @@ -3272,12 +3209,9 @@ bool DebuggerPlugin::initialize(const QStringList &arguments, QString *errorMess KitManager::registerKitInformation(new DebuggerKitInformation); - // Ex-Analyzer stuff - (void) new AnalyzerManager(this); - // Task integration. //: Category under which Analyzer tasks are listed in Issues view - ProjectExplorer::TaskHub::addCategory(Analyzer::Constants::ANALYZERTASK_ID, tr("Analyzer")); + ProjectExplorer::TaskHub::addCategory(Debugger::Constants::ANALYZERTASK_ID, tr("Debugger")); return dd->initialize(arguments, errorMessage); } @@ -3286,7 +3220,7 @@ IPlugin::ShutdownFlag DebuggerPlugin::aboutToShutdown() { removeObject(this); dd->aboutToShutdown(); - AnalyzerManager::shutdown(); + dd->m_mainWindow->saveCurrentPerspective(); return SynchronousShutdown; } @@ -3317,7 +3251,8 @@ void DebuggerPluginPrivate::updateUiForProject(Project *project) return; } connect(project, &Project::activeTargetChanged, - this, &DebuggerPluginPrivate::updateUiForTarget); + this, &DebuggerPluginPrivate::updateUiForTarget, + Qt::QueuedConnection); updateUiForTarget(project->activeTarget()); } @@ -3336,163 +3271,39 @@ void DebuggerPluginPrivate::updateUiForTarget(Target *target) } connect(target, &Target::activeRunConfigurationChanged, - this, &DebuggerPluginPrivate::updateUiForRunConfiguration); + this, &DebuggerPluginPrivate::updateUiForRunConfiguration, + Qt::QueuedConnection); updateUiForRunConfiguration(target->activeRunConfiguration()); } // updates default debug language settings per run config. void DebuggerPluginPrivate::updateUiForRunConfiguration(RunConfiguration *rc) { - if (m_previousRunConfiguration) - disconnect(m_previousRunConfiguration, &RunConfiguration::requestRunActionsUpdate, - this, &DebuggerPluginPrivate::updateActiveLanguages); - m_previousRunConfiguration = rc; +// if (m_previousRunConfiguration) +// disconnect(m_previousRunConfiguration, &RunConfiguration::requestRunActionsUpdate, +// this, &DebuggerPluginPrivate::updateActiveLanguages); +// m_previousRunConfiguration = rc; + Q_UNUSED(rc); // FIXME updateActiveLanguages(); - if (m_previousRunConfiguration) - connect(m_previousRunConfiguration, &RunConfiguration::requestRunActionsUpdate, - this, &DebuggerPluginPrivate::updateActiveLanguages); +// if (m_previousRunConfiguration) +// connect(m_previousRunConfiguration, &RunConfiguration::requestRunActionsUpdate, +// this, &DebuggerPluginPrivate::updateActiveLanguages, +// Qt::QueuedConnection); } void DebuggerPluginPrivate::updateActiveLanguages() { - if (!(activeDebugLanguages() & QmlLanguage)) - m_mainWindow->restorePerspective(CppPerspectiveId); - else - m_mainWindow->restorePerspective(QmlPerspectiveId); -} - -DebuggerLanguages DebuggerPluginPrivate::activeDebugLanguages() const -{ - return dd->m_currentEngine->runParameters().languages; -} - -void DebuggerPluginPrivate::createViewsMenuItems() -{ - Context debugcontext(Constants::C_DEBUGMODE); - m_viewsMenu = ActionManager::actionContainer(Id(Core::Constants::M_WINDOW_VIEWS)); - QTC_ASSERT(m_viewsMenu, return); - - auto openMemoryEditorAction = new QAction(this); - openMemoryEditorAction->setText(DebuggerPluginPrivate::tr("Memory...")); - connect(openMemoryEditorAction, &QAction::triggered, - this, &Internal::openMemoryEditor); - - // Add menu items - Command *cmd = 0; - cmd = ActionManager::registerAction(openMemoryEditorAction, - "Debugger.Views.OpenMemoryEditor", debugcontext); - cmd->setAttribute(Command::CA_Hide); - m_viewsMenu->addAction(cmd, Core::Constants::G_DEFAULT_THREE); - cmd = ActionManager::registerAction(m_mainWindow->menuSeparator1(), - "Debugger.Views.Separator1", debugcontext); - cmd->setAttribute(Command::CA_Hide); - m_viewsMenu->addAction(cmd, Core::Constants::G_DEFAULT_THREE); - cmd = ActionManager::registerAction(m_mainWindow->menuSeparator2(), - "Debugger.Views.Separator2", debugcontext); - cmd->setAttribute(Command::CA_Hide); - m_viewsMenu->addAction(cmd, Core::Constants::G_DEFAULT_THREE); -} - -/*! - Keep track of dock widgets so they can be shown/hidden for different languages -*/ -QDockWidget *DebuggerPluginPrivate::createDockWidget(Core::Id dockId, QWidget *widget) -{ - m_mainWindow->registerDockWidget(dockId, widget); - - QDockWidget *dockWidget = qobject_cast(widget->parentWidget()); - - QAction *toggleViewAction = dockWidget->toggleViewAction(); - Command *cmd = ActionManager::registerAction(toggleViewAction, - Id("Debugger.").withSuffix(widget->objectName())); - cmd->setAttribute(Command::CA_Hide); - - //dockWidget->installEventFilter(&m_resizeEventFilter); - return dockWidget; -} - -QWidget *DebuggerPluginPrivate::createContents(IMode *mode) -{ - connect(SessionManager::instance(), &SessionManager::startupProjectChanged, - this, &DebuggerPluginPrivate::updateUiForProject); - - auto editorHolderLayout = new QVBoxLayout; - editorHolderLayout->setMargin(0); - editorHolderLayout->setSpacing(0); - - auto editorAndFindWidget = new QWidget; - editorAndFindWidget->setLayout(editorHolderLayout); - auto editorManagerPlaceHolder = new EditorManagerPlaceHolder(mode); - editorHolderLayout->addWidget(editorManagerPlaceHolder); - editorHolderLayout->addWidget(new FindToolBarPlaceHolder(editorAndFindWidget)); - - auto documentAndRightPane = new MiniSplitter; - documentAndRightPane->addWidget(editorAndFindWidget); - documentAndRightPane->addWidget(new RightPanePlaceHolder(mode)); - documentAndRightPane->setStretchFactor(0, 1); - documentAndRightPane->setStretchFactor(1, 0); - - auto viewButton = new QToolButton(); - viewButton->setText(tr("Views")); - - auto debugToolBar = new Utils::StyledBar; - debugToolBar->setProperty("topBorder", true); - auto debugToolBarLayout = new QHBoxLayout(debugToolBar); - debugToolBarLayout->setMargin(0); - debugToolBarLayout->setSpacing(0); -// debugToolBarLayout->addWidget(m_mainWindow->toolBox()); - debugToolBarLayout->addWidget(m_mainWindow->controlsStack()); - debugToolBarLayout->addWidget(m_mainWindow->statusLabel()); - debugToolBarLayout->addWidget(new Utils::StyledSeparator); - debugToolBarLayout->addStretch(); - debugToolBarLayout->addWidget(viewButton); - - connect(viewButton, &QAbstractButton::clicked, [this, viewButton] { - QMenu menu; - m_mainWindow->addDockActionsToMenu(&menu); - menu.exec(viewButton->mapToGlobal(QPoint())); - }); - - auto dock = new QDockWidget(DebuggerPluginPrivate::tr("Debugger Toolbar")); - dock->setObjectName(QLatin1String("Debugger Toolbar")); - dock->setWidget(debugToolBar); - dock->setFeatures(QDockWidget::NoDockWidgetFeatures); - dock->setAllowedAreas(Qt::BottomDockWidgetArea); - dock->setTitleBarWidget(new QWidget(dock)); - dock->setProperty("managed_dockwidget", QLatin1String("true")); - m_mainWindow->addDockWidget(Qt::BottomDockWidgetArea, dock); - m_mainWindow->setToolBarDockWidget(dock); - - auto centralWidget = new QWidget; - m_mainWindow->setCentralWidget(centralWidget); - - auto centralLayout = new QVBoxLayout(centralWidget); - centralWidget->setLayout(centralLayout); - centralLayout->setMargin(0); - centralLayout->setSpacing(0); - centralLayout->addWidget(documentAndRightPane); - centralLayout->setStretch(0, 1); - centralLayout->setStretch(1, 0); - - // Right-side window with editor, output etc. - auto mainWindowSplitter = new MiniSplitter; - mainWindowSplitter->addWidget(m_mainWindow); - auto outputPane = new OutputPanePlaceHolder(mode, mainWindowSplitter); - outputPane->setObjectName(QLatin1String("DebuggerOutputPanePlaceHolder")); - mainWindowSplitter->addWidget(outputPane); - mainWindowSplitter->setStretchFactor(0, 10); - mainWindowSplitter->setStretchFactor(1, 0); - mainWindowSplitter->setOrientation(Qt::Vertical); - - // Navigation and right-side window. - auto splitter = new MiniSplitter; - splitter->setFocusProxy(editorManagerPlaceHolder); - splitter->addWidget(new NavigationWidgetPlaceHolder(mode)); - splitter->addWidget(mainWindowSplitter); - splitter->setStretchFactor(0, 0); - splitter->setStretchFactor(1, 1); - splitter->setObjectName(QLatin1String("DebugModeWidget")); - return splitter; + const DebuggerLanguages languages = dd->m_currentEngine->runParameters().languages; +// Id perspective = (languages & QmlLanguage) && !(languages & CppLanguage) +// ? QmlPerspectiveId : CppPerspectiveId; +// m_mainWindow->restorePerspective(perspective); + for (DebuggerLanguage language: {QmlLanguage, CppLanguage}) { + const Context context = m_contextsForLanguage.value(language); + if (languages & language) + ICore::addAdditionalContext(context); + else + ICore::removeAdditionalContext(context); + } } //bool DockWidgetEventFilter::eventFilter(QObject *obj, QEvent *event) @@ -3508,6 +3319,274 @@ QWidget *DebuggerPluginPrivate::createContents(IMode *mode) // return QObject::eventFilter(obj, event); //} +void DebuggerPluginPrivate::onModeChanged(IMode *mode) +{ + // FIXME: This one gets always called, even if switching between modes + // different then the debugger mode. E.g. Welcome and Help mode and + // also on shutdown. + + if (mode && mode->id() == MODE_DEBUG) { + if (IEditor *editor = EditorManager::currentEditor()) + editor->widget()->setFocus(); + + m_toolTipManager.debugModeEntered(); + m_mainWindow->setDockActionsVisible(true); + m_mainWindow->restorePerspective({}); + +// static bool firstTime = true; +// if (firstTime) { + +// // Dock widgets +// connect(m_mainWindow->dockWidget(DOCKWIDGET_MODULES)->toggleViewAction(), &QAction::toggled, +// this, &DebuggerPluginPrivate::modulesDockToggled, Qt::QueuedConnection); +// connect(m_mainWindow->dockWidget(DOCKWIDGET_OUTPUT)->toggleViewAction(), &QAction::toggled, +// this, &DebuggerPluginPrivate::registerDockToggled, Qt::QueuedConnection); +// connect(m_mainWindow->dockWidget(DOCKWIDGET_SOURCE_FILES)->toggleViewAction(), &QAction::toggled, +// this, &DebuggerPluginPrivate::sourceFilesDockToggled, Qt::QueuedConnection); + +// firstTime = false; +// } + updateActiveLanguages(); + } else { + m_toolTipManager.leavingDebugMode(); + m_mainWindow->setDockActionsVisible(false); + + // Hide dock widgets manually in case they are floating. + foreach (QDockWidget *dockWidget, m_mainWindow->dockWidgets()) { + if (dockWidget->isFloating()) + dockWidget->hide(); + } + } +} + +} // namespace Internal + +bool ActionDescription::isRunnable(QString *reason) const +{ + if (m_customToolStarter) // Something special. Pretend we can always run it. + return true; + + return ProjectExplorerPlugin::canRunStartupProject(m_runMode, reason); +} + +static bool buildTypeAccepted(QFlags toolMode, BuildConfiguration::BuildType buildType) +{ + if (buildType == BuildConfiguration::Unknown) + return true; + if (buildType == BuildConfiguration::Debug && (toolMode & DebugMode)) + return true; + if (buildType == BuildConfiguration::Release && (toolMode & ReleaseMode)) + return true; + if (buildType == BuildConfiguration::Profile && (toolMode & ProfileMode)) + return true; + return false; +} + +void ActionDescription::startTool() const +{ + TaskHub::clearTasks(Constants::ANALYZERTASK_ID); + Debugger::selectPerspective(m_perspectiveId); + + if (m_toolPreparer && !m_toolPreparer()) + return; + + // ### not sure if we're supposed to check if the RunConFiguration isEnabled + Project *pro = SessionManager::startupProject(); + RunConfiguration *rc = 0; + BuildConfiguration::BuildType buildType = BuildConfiguration::Unknown; + if (pro) { + if (const Target *target = pro->activeTarget()) { + // Build configuration is 0 for QML projects. + if (const BuildConfiguration *buildConfig = target->activeBuildConfiguration()) + buildType = buildConfig->buildType(); + rc = target->activeRunConfiguration(); + } + } + + // Custom start. + if (m_customToolStarter) { + if (rc) { + m_customToolStarter(rc); + } else { + QMessageBox *errorDialog = new QMessageBox(ICore::mainWindow()); + errorDialog->setIcon(QMessageBox::Warning); + errorDialog->setWindowTitle(m_text); + errorDialog->setText(tr("Cannot start %1 without a project. Please open the project " + "and try again.").arg(m_text)); + errorDialog->setStandardButtons(QMessageBox::Ok); + errorDialog->setDefaultButton(QMessageBox::Ok); + errorDialog->show(); + } + return; + } + + // Check the project for whether the build config is in the correct mode + // if not, notify the user and urge him to use the correct mode. + if (!buildTypeAccepted(m_toolMode, buildType)) { + QString currentMode; + switch (buildType) { + case BuildConfiguration::Debug: + currentMode = tr("Debug"); + break; + case BuildConfiguration::Profile: + currentMode = tr("Profile"); + break; + case BuildConfiguration::Release: + currentMode = tr("Release"); + break; + default: + QTC_CHECK(false); + } + + QString toolModeString; + switch (m_toolMode) { + case DebugMode: + toolModeString = tr("in Debug mode"); + break; + case ProfileMode: + toolModeString = tr("in Profile mode"); + break; + case ReleaseMode: + toolModeString = tr("in Release mode"); + break; + case SymbolsMode: + toolModeString = tr("with debug symbols (Debug or Profile mode)"); + break; + case OptimizedMode: + toolModeString = tr("on optimized code (Profile or Release mode)"); + break; + default: + QTC_CHECK(false); + } + const QString toolName = m_text; // The action text is always the name of the tool + const QString title = tr("Run %1 in %2 Mode?").arg(toolName).arg(currentMode); + const QString message = tr("

You are trying " + "to run the tool \"%1\" on an application in %2 mode. " + "The tool is designed to be used %3.

" + "Run-time characteristics differ significantly between " + "optimized and non-optimized binaries. Analytical " + "findings for one mode may or may not be relevant for " + "the other.

" + "Running tools that need debug symbols on binaries that " + "don't provide any may lead to missing function names " + "or otherwise insufficient output.

" + "Do you want to continue and run the tool in %2 mode?

") + .arg(toolName).arg(currentMode).arg(toolModeString); + if (Utils::CheckableMessageBox::doNotAskAgainQuestion(ICore::mainWindow(), + title, message, ICore::settings(), QLatin1String("AnalyzerCorrectModeWarning")) + != QDialogButtonBox::Yes) + return; + } + + ProjectExplorerPlugin::runStartupProject(m_runMode); +} + +void registerAction(Id actionId, const ActionDescription &desc, QAction *startAction) +{ + auto action = new QAction(dd); + action->setText(desc.text()); + action->setToolTip(desc.toolTip()); + dd->m_descriptions.insert(actionId, desc); + + Id menuGroup = desc.menuGroup(); + if (menuGroup.isValid()) { + Command *command = ActionManager::registerAction(action, actionId); + dd->m_menu->addAction(command, menuGroup); + } + + QObject::connect(action, &QAction::triggered, dd, [desc] { desc.startTool(); }); + + if (startAction) { + QObject::connect(startAction, &QAction::triggered, action, &QAction::triggered); + + QObject::connect(startAction, &QAction::changed, action, [action, startAction] { + action->setEnabled(startAction->isEnabled()); + }); + } +} + +void registerToolbar(const QByteArray &perspectiveId, const ToolbarDescription &desc) +{ + auto toolbar = new QWidget; + toolbar->setObjectName(QString::fromLatin1(perspectiveId + ".Toolbar")); + auto hbox = new QHBoxLayout(toolbar); + hbox->setMargin(0); + hbox->setSpacing(0); + for (QWidget *widget : desc.widgets()) + hbox->addWidget(widget); + hbox->addStretch(); + toolbar->setLayout(hbox); + + dd->m_mainWindow->registerToolbar(perspectiveId, toolbar); +} + +QAction *createStartAction() +{ + auto action = new QAction(DebuggerMainWindow::tr("Start"), 0); + action->setIcon(Debugger::Icons::ANALYZER_CONTROL_START.icon()); + action->setEnabled(true); + return action; +} + +QAction *createStopAction() +{ + auto action = new QAction(DebuggerMainWindow::tr("Stop"), 0); + action->setIcon(ProjectExplorer::Icons::STOP_SMALL.icon()); + action->setEnabled(true); + return action; +} + +void registerPerspective(const QByteArray &perspectiveId, const Perspective &perspective) +{ + dd->m_mainWindow->registerPerspective(perspectiveId, perspective); +} + +void selectPerspective(const QByteArray &perspectiveId) +{ + // FIXME: Work-around aslong as the GammaRay integration does not use the same setup, + if (perspectiveId.isEmpty()) + return; + ModeManager::activateMode(MODE_DEBUG); + dd->m_mainWindow->restorePerspective(perspectiveId); +} + +void runAction(Id actionId) +{ + ActionDescription desc = dd->m_descriptions.value(actionId); + desc.startTool(); +} + +void enableMainWindow(bool on) +{ + dd->m_mainWindow->setEnabled(on); +} + +void showStatusMessage(const QString &message, int timeoutMS) +{ + dd->m_mainWindow->showStatusMessage(message, timeoutMS); +} + +void showPermanentStatusMessage(const QString &message) +{ + dd->m_mainWindow->showStatusMessage(message, -1); +} + +AnalyzerRunControl *createAnalyzerRunControl(RunConfiguration *runConfiguration, Id runMode) +{ + foreach (const ActionDescription &action, dd->m_descriptions) { + if (action.runMode() == runMode) + return action.runControlCreator()(runConfiguration, runMode); + } + return 0; +} + +bool operator==(const AnalyzerConnection &c1, const AnalyzerConnection &c2) +{ + return c1.connParams == c2.connParams + && c1.analyzerHost == c2.analyzerHost + && c1.analyzerSocket == c2.analyzerSocket + && c1.analyzerPort == c2.analyzerPort; +} #ifdef WITH_TESTS void DebuggerPluginPrivate::testLoadProject(const QString &proFile, const TestCallBack &cb) diff --git a/src/plugins/debugger/debuggerruncontrol.cpp b/src/plugins/debugger/debuggerruncontrol.cpp index 8edb6b40778..f676fbfe9bc 100644 --- a/src/plugins/debugger/debuggerruncontrol.cpp +++ b/src/plugins/debugger/debuggerruncontrol.cpp @@ -25,6 +25,7 @@ #include "debuggerruncontrol.h" +#include "analyzer/analyzermanager.h" #include "debuggeractions.h" #include "debuggercore.h" #include "debuggerengine.h" @@ -140,6 +141,7 @@ QString DebuggerRunControl::displayName() const void DebuggerRunControl::start() { + Debugger::selectPerspective(Debugger::Constants::CppPerspectiveId); TaskHub::clearTasks(Debugger::Constants::TASK_CATEGORY_DEBUGGER_DEBUGINFO); TaskHub::clearTasks(Debugger::Constants::TASK_CATEGORY_DEBUGGER_RUNTIME); diff --git a/src/plugins/debugger/pdb/pdbengine.cpp b/src/plugins/debugger/pdb/pdbengine.cpp index 3f510f31500..1c6dc62e652 100644 --- a/src/plugins/debugger/pdb/pdbengine.cpp +++ b/src/plugins/debugger/pdb/pdbengine.cpp @@ -137,6 +137,7 @@ void PdbEngine::setupEngine() QStringList args = { bridge, scriptFile.fileName() }; args.append(Utils::QtcProcess::splitArgs(runParameters().inferior.workingDirectory)); showMessage(_("STARTING ") + m_interpreter + QLatin1Char(' ') + args.join(QLatin1Char(' '))); + m_proc.setEnvironment(runParameters().debuggerEnvironment.toStringList()); m_proc.start(m_interpreter, args); if (!m_proc.waitForStarted()) { diff --git a/src/plugins/debugger/unstartedappwatcherdialog.cpp b/src/plugins/debugger/unstartedappwatcherdialog.cpp index 31378377d0e..1899b928bb7 100644 --- a/src/plugins/debugger/unstartedappwatcherdialog.cpp +++ b/src/plugins/debugger/unstartedappwatcherdialog.cpp @@ -147,6 +147,7 @@ UnstartedAppWatcherDialog::UnstartedAppWatcherDialog(QWidget *parent) m_watchingPushButton->setCheckable(true); m_watchingPushButton->setChecked(false); m_watchingPushButton->setEnabled(false); + m_watchingPushButton->setDefault(true); QFormLayout *mainLayout = new QFormLayout(this); mainLayout->addRow(new QLabel(tr("Kit: "), this), m_kitChooser); @@ -170,6 +171,7 @@ UnstartedAppWatcherDialog::UnstartedAppWatcherDialog(QWidget *parent) connect(m_kitChooser, &KitChooser::currentIndexChanged, this, &UnstartedAppWatcherDialog::kitChanged); kitChanged(); + m_pathChooser->setFocus(); setWaitingState(checkExecutableString() ? NotWatchingState : InvalidWacherState); } diff --git a/src/plugins/git/branchdialog.cpp b/src/plugins/git/branchdialog.cpp index 81802e238ff..b790ba4cc55 100644 --- a/src/plugins/git/branchdialog.cpp +++ b/src/plugins/git/branchdialog.cpp @@ -30,6 +30,7 @@ #include "gitclient.h" #include "gitplugin.h" #include "gitutils.h" +#include "gitconstants.h" #include "ui_branchdialog.h" #include "stashdialog.h" // Label helpers @@ -61,6 +62,9 @@ BranchDialog::BranchDialog(QWidget *parent) : setAttribute(Qt::WA_DeleteOnClose, true); // Do not update unnecessarily m_ui->setupUi(this); + m_ui->includeOldCheckBox->setToolTip( + tr("Include branches and tags that have not been active for %1 days.") + .arg(Constants::OBSOLETE_COMMIT_AGE_IN_DAYS)); connect(m_ui->refreshButton, &QAbstractButton::clicked, this, &BranchDialog::refreshCurrentRepository); connect(m_ui->addButton, &QAbstractButton::clicked, this, &BranchDialog::add); @@ -74,8 +78,13 @@ BranchDialog::BranchDialog(QWidget *parent) : connect(m_ui->rebaseButton, &QAbstractButton::clicked, this, &BranchDialog::rebase); connect(m_ui->cherryPickButton, &QAbstractButton::clicked, this, &BranchDialog::cherryPick); connect(m_ui->trackButton, &QAbstractButton::clicked, this, &BranchDialog::setRemoteTracking); + connect(m_ui->includeOldCheckBox, &QCheckBox::toggled, this, [this](bool value) { + m_model->setOldBranchesIncluded(value); + refreshCurrentRepository(); + }); m_ui->branchView->setModel(m_model); + m_ui->branchView->setFocus(); connect(m_ui->branchView->selectionModel(), &QItemSelectionModel::selectionChanged, this, &BranchDialog::enableButtons); diff --git a/src/plugins/git/branchdialog.ui b/src/plugins/git/branchdialog.ui index 36d07c7dfce..d3b8de6a02e 100644 --- a/src/plugins/git/branchdialog.ui +++ b/src/plugins/git/branchdialog.ui @@ -15,36 +15,28 @@ - - - - 4 - - - 4 - - - - - Repository: Dummy - - - - - - - - 0 - 0 - - - - Re&fresh - - - - - + + + + + Repository: Dummy + + + + + + + + 0 + 0 + + + + Re&fresh + + + + @@ -59,17 +51,28 @@ 4 - - - false - - - true - - - false - - + + + + + false + + + true + + + false + + + + + + + &Include old entries + + + + @@ -210,11 +213,6 @@ - - branchView - buttonBox - refreshButton - diff --git a/src/plugins/git/branchmodel.cpp b/src/plugins/git/branchmodel.cpp index 86895f38977..a6aa90fcfcf 100644 --- a/src/plugins/git/branchmodel.cpp +++ b/src/plugins/git/branchmodel.cpp @@ -25,11 +25,13 @@ #include "branchmodel.h" #include "gitclient.h" +#include "gitconstants.h" #include #include #include +#include #include using namespace VcsBase; @@ -348,7 +350,8 @@ bool BranchModel::refresh(const QString &workingDirectory, QString *errorMessage m_currentSha = m_client->synchronousTopRevision(workingDirectory); QStringList args; - args << QLatin1String("--format=%(objectname)\t%(refname)\t%(upstream:short)\t%(*objectname)"); + args << QLatin1String("--format=%(objectname)\t%(refname)\t%(upstream:short)\t" + "%(*objectname)\t%(committerdate:raw)\t%(*committerdate:raw)"); QString output; if (!m_client->synchronousForEachRefCmd(workingDirectory, args, &output, errorMessage)) VcsOutputWindow::appendError(*errorMessage); @@ -629,16 +632,34 @@ void BranchModel::setRemoteTracking(const QModelIndex &trackingIndex) emit dataChanged(current, current); } +void BranchModel::setOldBranchesIncluded(bool value) +{ + m_oldBranchesIncluded = value; +} + void BranchModel::parseOutputLine(const QString &line) { if (line.size() < 3) return; + // objectname, refname, upstream:short, *objectname, committerdate:raw, *committerdate:raw QStringList lineParts = line.split(QLatin1Char('\t')); const QString shaDeref = lineParts.at(3); const QString sha = shaDeref.isEmpty() ? lineParts.at(0) : shaDeref; const QString fullName = lineParts.at(1); + const QString upstream = lineParts.at(2); + if (!m_oldBranchesIncluded) { + QString strDateTime = lineParts.at(5); + if (strDateTime.isEmpty()) + strDateTime = lineParts.at(4); + if (!strDateTime.isEmpty()) { + const uint timeT = strDateTime.leftRef(strDateTime.indexOf(QLatin1Char(' '))).toUInt(); + const int age = QDateTime::fromTime_t(timeT).daysTo(QDateTime::currentDateTime()); + if (age > Constants::OBSOLETE_COMMIT_AGE_IN_DAYS) + return; + } + } bool current = (sha == m_currentSha); bool showTags = m_client->settings().boolValue(GitSettings::showTagsKey); @@ -671,7 +692,7 @@ void BranchModel::parseOutputLine(const QString &line) const QString name = nameParts.last(); nameParts.removeLast(); - auto newNode = new BranchNode(name, sha, lineParts.at(2)); + auto newNode = new BranchNode(name, sha, upstream); root->insert(nameParts, newNode); if (current) m_currentBranch = newNode; diff --git a/src/plugins/git/branchmodel.h b/src/plugins/git/branchmodel.h index e7e2686f6d9..214061b208b 100644 --- a/src/plugins/git/branchmodel.h +++ b/src/plugins/git/branchmodel.h @@ -79,6 +79,7 @@ public: bool branchIsMerged(const QModelIndex &idx); QModelIndex addBranch(const QString &name, bool track, const QModelIndex &trackedBranch); void setRemoteTracking(const QModelIndex &trackingIndex); + void setOldBranchesIncluded(bool value); private: void parseOutputLine(const QString &line); @@ -94,6 +95,7 @@ private: BranchNode *m_rootNode; BranchNode *m_currentBranch = nullptr; QString m_currentSha; + bool m_oldBranchesIncluded = false; }; } // namespace Internal diff --git a/src/plugins/git/gerrit/gerritpushdialog.cpp b/src/plugins/git/gerrit/gerritpushdialog.cpp index 23c3c147d9d..c33bf231b77 100644 --- a/src/plugins/git/gerrit/gerritpushdialog.cpp +++ b/src/plugins/git/gerrit/gerritpushdialog.cpp @@ -29,6 +29,7 @@ #include "../gitplugin.h" #include "../gitclient.h" +#include "../gitconstants.h" #include #include @@ -235,7 +236,7 @@ void GerritPushDialog::setRemoteBranches(bool includeOld) foreach (const BranchDate &bd, m_remoteBranches.values(remoteName)) { const bool isSuggested = bd.first == m_suggestedRemoteBranch; if (includeOld || isSuggested || !bd.second.isValid() - || bd.second.daysTo(QDate::currentDate()) <= 60) { + || bd.second.daysTo(QDate::currentDate()) <= Git::Constants::OBSOLETE_COMMIT_AGE_IN_DAYS) { m_ui->targetBranchComboBox->addItem(bd.first); if (isSuggested) m_ui->targetBranchComboBox->setCurrentIndex(i); diff --git a/src/plugins/git/gitconstants.h b/src/plugins/git/gitconstants.h index 352aac7c403..a4fce448399 100644 --- a/src/plugins/git/gitconstants.h +++ b/src/plugins/git/gitconstants.h @@ -49,5 +49,7 @@ const char DIFF_SELECTED[] = "Git.DiffSelectedFilesInLog"; const char SUBMIT_MIMETYPE[] = "text/vnd.qtcreator.git.submit"; const char C_GITEDITORID[] = "Git Editor"; +const int OBSOLETE_COMMIT_AGE_IN_DAYS = 90; + } // namespace Constants } // namespace Git diff --git a/src/plugins/git/gitplugin.cpp b/src/plugins/git/gitplugin.cpp index 5a76acf0046..23d9b0fadb1 100644 --- a/src/plugins/git/gitplugin.cpp +++ b/src/plugins/git/gitplugin.cpp @@ -686,8 +686,10 @@ void GitPlugin::logRepository() void GitPlugin::undoFileChanges(bool revertStaging) { - if (!DocumentManager::saveAllModifiedDocuments()) - return; + if (IDocument *document = EditorManager::currentDocument()) { + if (!DocumentManager::saveModifiedDocument(document)) + return; + } const VcsBasePluginState state = currentState(); QTC_ASSERT(state.hasFile(), return); FileChangeBlocker fcb(state.currentFile()); diff --git a/src/plugins/ios/iosanalyzesupport.cpp b/src/plugins/ios/iosanalyzesupport.cpp index dc40be7f79d..c9e7020af35 100644 --- a/src/plugins/ios/iosanalyzesupport.cpp +++ b/src/plugins/ios/iosanalyzesupport.cpp @@ -56,7 +56,7 @@ #include #endif -using namespace Analyzer; +using namespace Debugger; using namespace ProjectExplorer; namespace Ios { diff --git a/src/plugins/ios/iosanalyzesupport.h b/src/plugins/ios/iosanalyzesupport.h index 76c4da284d8..2b18c5f6936 100644 --- a/src/plugins/ios/iosanalyzesupport.h +++ b/src/plugins/ios/iosanalyzesupport.h @@ -33,7 +33,7 @@ #include #include -namespace Analyzer { class AnalyzerRunControl; } +namespace Debugger { class AnalyzerRunControl; } namespace Ios { namespace Internal { @@ -47,7 +47,7 @@ class IosAnalyzeSupport : public QObject public: IosAnalyzeSupport(IosRunConfiguration *runConfig, - Analyzer::AnalyzerRunControl *runControl, bool cppDebug, bool qmlDebug); + Debugger::AnalyzerRunControl *runControl, bool cppDebug, bool qmlDebug); ~IosAnalyzeSupport(); private: @@ -59,7 +59,7 @@ private: void handleRemoteOutput(const QString &output); void handleRemoteErrorOutput(const QString &output); - Analyzer::AnalyzerRunControl *m_runControl; + Debugger::AnalyzerRunControl *m_runControl; IosRunner * const m_runner; QmlDebug::QmlOutputParser m_outputParser; int m_qmlPort; diff --git a/src/plugins/ios/iosrunfactories.cpp b/src/plugins/ios/iosrunfactories.cpp index bd5a0dbf563..a8262b4abdd 100644 --- a/src/plugins/ios/iosrunfactories.cpp +++ b/src/plugins/ios/iosrunfactories.cpp @@ -48,7 +48,7 @@ #include #include -using namespace Analyzer; +using namespace Debugger; using namespace ProjectExplorer; using namespace QmakeProjectManager; @@ -190,7 +190,7 @@ RunControl *IosRunControlFactory::create(RunConfiguration *runConfig, if (mode == ProjectExplorer::Constants::NORMAL_RUN_MODE) res = new Ios::Internal::IosRunControl(rc); else if (mode == ProjectExplorer::Constants::QML_PROFILER_RUN_MODE) { - AnalyzerRunControl *runControl = AnalyzerManager::createRunControl(runConfig, mode); + AnalyzerRunControl *runControl = Debugger::createAnalyzerRunControl(runConfig, mode); QTC_ASSERT(runControl, return 0); IDevice::ConstPtr device = DeviceKitInformation::device(target->kit()); if (device.isNull()) diff --git a/src/plugins/modeleditor/extpropertiesmview.cpp b/src/plugins/modeleditor/extpropertiesmview.cpp index e0ac9d1b528..05acb4435b5 100644 --- a/src/plugins/modeleditor/extpropertiesmview.cpp +++ b/src/plugins/modeleditor/extpropertiesmview.cpp @@ -35,6 +35,9 @@ #include #include +namespace ModelEditor { +namespace Internal { + ExtPropertiesMView::ExtPropertiesMView(qmt::PropertiesView *view) : qmt::PropertiesView::MView(view) { @@ -107,3 +110,6 @@ void ExtPropertiesMView::onConfigPathChanged(const QString &path) if (modified && m_configPathInfo) m_configPathInfo->setText(tr("Model file must be reloaded.")); } + +} // namespace Interal +} // namespace ModelEditor diff --git a/src/plugins/modeleditor/extpropertiesmview.h b/src/plugins/modeleditor/extpropertiesmview.h index 61fc732377c..1ad45aff819 100644 --- a/src/plugins/modeleditor/extpropertiesmview.h +++ b/src/plugins/modeleditor/extpropertiesmview.h @@ -31,6 +31,9 @@ namespace qmt { class ProjectController; } namespace Utils { class PathChooser; } +namespace ModelEditor { +namespace Internal { + class ExtPropertiesMView : public qmt::PropertiesView::MView { Q_OBJECT @@ -52,4 +55,7 @@ private: QLabel *m_configPathInfo = 0; }; +} // namespace Interal +} // namespace ModelEditor + #endif // EXTPROPERTIESMVIEW_H diff --git a/src/plugins/projectexplorer/extracompiler.cpp b/src/plugins/projectexplorer/extracompiler.cpp index 409f300050a..ecefbf353a8 100644 --- a/src/plugins/projectexplorer/extracompiler.cpp +++ b/src/plugins/projectexplorer/extracompiler.cpp @@ -24,26 +24,33 @@ ****************************************************************************/ #include "extracompiler.h" + +#include "buildconfiguration.h" #include "buildmanager.h" +#include "kitinformation.h" #include "session.h" #include "target.h" -#include "buildconfiguration.h" -#include "kitinformation.h" +#include +#include #include #include #include #include + #include -#include -#include +#include #include +#include +#include +#include #include #include namespace ProjectExplorer { +Q_GLOBAL_STATIC(QThreadPool, s_extraCompilerThreadPool); Q_GLOBAL_STATIC(QList, factories); class ExtraCompilerPrivate @@ -55,7 +62,7 @@ public: Utils::FileNameList targets; QList issues; QDateTime compileTime; - Core::IEditor *lastEditor = 0; + Core::IEditor *lastEditor = nullptr; QMetaObject::Connection activeBuildConfigConnection; QMetaObject::Connection activeEnvironmentConnection; bool dirty = false; @@ -80,8 +87,8 @@ ExtraCompiler::ExtraCompiler(const Project *project, const Utils::FileName &sour connect(&d->timer, &QTimer::timeout, this, [this](){ if (d->dirty && d->lastEditor) { - run(d->lastEditor->document()->contents()); d->dirty = false; + run(d->lastEditor->document()->contents()); } }); @@ -122,13 +129,8 @@ ExtraCompiler::ExtraCompiler(const Project *project, const Utils::FileName &sour } if (d->dirty) { - // Run in the next event loop, as run() is not available yet in the ctor. - QTimer::singleShot(0, this, [this](){ - QFile file(d->source.toString()); - if (file.open(QFile::ReadOnly | QFile::Text)) - run(file.readAll()); - d->dirty = false; - }); + d->dirty = false; + QTimer::singleShot(0, this, [this]() { run(d->source); }); // delay till available. } } @@ -167,6 +169,11 @@ QDateTime ExtraCompiler::compileTime() const return d->compileTime; } +QThreadPool *ExtraCompiler::extraCompilerThreadPool() +{ + return s_extraCompilerThreadPool(); +} + void ExtraCompiler::onTargetsBuilt(Project *project) { if (project != d->project || BuildManager::isBuilding(project)) @@ -203,8 +210,8 @@ void ExtraCompiler::onEditorChanged(Core::IEditor *editor) this, &ExtraCompiler::setDirty); if (d->dirty) { - run(doc->contents()); d->dirty = false; + run(doc->contents()); } } @@ -216,7 +223,7 @@ void ExtraCompiler::onEditorChanged(Core::IEditor *editor) connect(d->lastEditor->document(), &Core::IDocument::contentsChanged, this, &ExtraCompiler::setDirty); } else { - d->lastEditor = 0; + d->lastEditor = nullptr; } } @@ -237,10 +244,10 @@ void ExtraCompiler::onEditorAboutToClose(Core::IEditor *editor) disconnect(doc, &Core::IDocument::contentsChanged, this, &ExtraCompiler::setDirty); if (d->dirty) { - run(doc->contents()); d->dirty = false; + run(doc->contents()); } - d->lastEditor = 0; + d->lastEditor = nullptr; } void ExtraCompiler::onActiveTargetChanged() @@ -355,4 +362,114 @@ QList ExtraCompilerFactory::extraCompilerFactories() return *factories(); } +ProcessExtraCompiler::ProcessExtraCompiler(const Project *project, const Utils::FileName &source, + const Utils::FileNameList &targets, QObject *parent) : + ExtraCompiler(project, source, targets, parent) +{ } + +void ProcessExtraCompiler::run(const QByteArray &sourceContents) +{ + ContentProvider contents = [this, sourceContents]() { return sourceContents; }; + runImpl(contents); +} + +void ProcessExtraCompiler::run(const Utils::FileName &fileName) +{ + ContentProvider contents = [this, fileName]() { + QFile file(fileName.toString()); + if (!file.open(QFile::ReadOnly | QFile::Text)) + return QByteArray(); + return file.readAll(); + }; + runImpl(contents); +} + +Utils::FileName ProcessExtraCompiler::workingDirectory() const +{ + return Utils::FileName(); +} + +QStringList ProcessExtraCompiler::arguments() const +{ + return QStringList(); +} + +bool ProcessExtraCompiler::prepareToRun(const QByteArray &sourceContents) +{ + Q_UNUSED(sourceContents); + return true; +} + +QList ProcessExtraCompiler::parseIssues(const QByteArray &stdErr) +{ + Q_UNUSED(stdErr); + return QList(); +} + +void ProcessExtraCompiler::runImpl(const ContentProvider &provider) +{ + if (m_watcher) + delete m_watcher; + + m_watcher = new QFutureWatcher>(); + connect(m_watcher, &QFutureWatcher>::finished, + this, &ProcessExtraCompiler::cleanUp); + + m_watcher->setFuture(Utils::runAsync(extraCompilerThreadPool(), + &ProcessExtraCompiler::runInThread, this, + command(), workingDirectory(), arguments(), provider, + buildEnvironment())); +} + +QList ProcessExtraCompiler::runInThread(const Utils::FileName &cmd, const Utils::FileName &workDir, + const QStringList &args, const ContentProvider &provider, + const Utils::Environment &env) +{ + if (cmd.isEmpty() || !cmd.toFileInfo().isExecutable()) + return QList(); + + const QByteArray sourceContents = provider(); + if (sourceContents.isNull() || !prepareToRun(sourceContents)) + return QList(); + + QProcess process; + + process.setProcessEnvironment(env.toProcessEnvironment()); + if (!workDir.isEmpty()) + process.setWorkingDirectory(workDir.toString()); + process.start(cmd.toString(), args, QIODevice::ReadWrite); + if (!process.waitForStarted()) { + handleProcessError(&process); + return QList(); + } + handleProcessStarted(&process, sourceContents); + process.waitForFinished(); + + if (process.state() == QProcess::Running) { + process.kill(); + process.waitForFinished(3000); + } + + return handleProcessFinished(&process); +} + +void ProcessExtraCompiler::cleanUp() +{ + QTC_ASSERT(m_watcher, return); + const QList data = m_watcher->future().result(); + delete m_watcher; + m_watcher = nullptr; + + if (data.isEmpty()) + return; // There was some kind of error... + + const Utils::FileNameList targetList = targets(); + QTC_ASSERT(data.count() == targetList.count(), return); + + for (int i = 0; i < targetList.count(); ++i) + setContent(targetList.at(i), data.at(i)); + + setCompileTime(QDateTime::currentDateTime()); +} + } // namespace ProjectExplorer diff --git a/src/plugins/projectexplorer/extracompiler.h b/src/plugins/projectexplorer/extracompiler.h index eb5e0123d9c..6f2ec8bc63c 100644 --- a/src/plugins/projectexplorer/extracompiler.h +++ b/src/plugins/projectexplorer/extracompiler.h @@ -33,6 +33,13 @@ #include #include +#include +#include +#include + +QT_FORWARD_DECLARE_CLASS(QProcess); +QT_FORWARD_DECLARE_CLASS(QThreadPool); + namespace ProjectExplorer { class ExtraCompilerPrivate; @@ -42,8 +49,8 @@ class PROJECTEXPLORER_EXPORT ExtraCompiler : public QObject public: ExtraCompiler(const Project *project, const Utils::FileName &source, - const Utils::FileNameList &targets, QObject *parent = 0); - virtual ~ExtraCompiler() override; + const Utils::FileNameList &targets, QObject *parent = nullptr); + ~ExtraCompiler() override; const Project *project() const; Utils::FileName source() const; @@ -58,6 +65,8 @@ public: void setCompileTime(const QDateTime &time); QDateTime compileTime() const; + static QThreadPool *extraCompilerThreadPool(); + signals: void contentsChanged(const Utils::FileName &file); @@ -72,16 +81,60 @@ private: void onActiveTargetChanged(); void onActiveBuildConfigurationChanged(); void setDirty(); + // This method may not block! virtual void run(const QByteArray &sourceContent) = 0; + virtual void run(const Utils::FileName &file) = 0; ExtraCompilerPrivate *const d; }; +class PROJECTEXPLORER_EXPORT ProcessExtraCompiler : public ExtraCompiler +{ + Q_OBJECT +public: + + ProcessExtraCompiler(const Project *project, const Utils::FileName &source, + const Utils::FileNameList &targets, QObject *parent = nullptr); + +protected: + // This will run a process in a thread, if + // * command() does not return an empty file name + // * command() is exectuable + // * prepareToRun returns true + // * The process is not yet running + void run(const QByteArray &sourceContents) override; + void run(const Utils::FileName &fileName) override; + + // Information about the process to run: + virtual Utils::FileName workingDirectory() const; + virtual Utils::FileName command() const = 0; + virtual QStringList arguments() const; + + virtual bool prepareToRun(const QByteArray &sourceContents); + + virtual void handleProcessError(QProcess *process) { Q_UNUSED(process); } + virtual void handleProcessStarted(QProcess *process, const QByteArray &sourceContents) + { Q_UNUSED(process); Q_UNUSED(sourceContents); } + virtual QList handleProcessFinished(QProcess *process) = 0; + + virtual QList parseIssues(const QByteArray &stdErr); + +private: + using ContentProvider = std::function; + void runImpl(const ContentProvider &sourceContents); + QList runInThread(const Utils::FileName &cmd, const Utils::FileName &workDir, + const QStringList &args, const ContentProvider &provider, + const Utils::Environment &env); + void cleanUp(); + + QFutureWatcher> *m_watcher = nullptr; +}; + class PROJECTEXPLORER_EXPORT ExtraCompilerFactory : public QObject { Q_OBJECT public: - explicit ExtraCompilerFactory(QObject *parent = 0); + explicit ExtraCompilerFactory(QObject *parent = nullptr); virtual FileType sourceType() const = 0; virtual QString sourceTag() const = 0; diff --git a/src/plugins/projectexplorer/projectexplorer.cpp b/src/plugins/projectexplorer/projectexplorer.cpp index 4e103cc528f..fec7d9938ce 100644 --- a/src/plugins/projectexplorer/projectexplorer.cpp +++ b/src/plugins/projectexplorer/projectexplorer.cpp @@ -2733,8 +2733,9 @@ void ProjectExplorerPluginPrivate::updateDeployActions() emit m_instance->updateRunActions(); } -bool ProjectExplorerPlugin::canRun(Project *project, Core::Id runMode, QString *whyNot) +bool ProjectExplorerPlugin::canRunStartupProject(Core::Id runMode, QString *whyNot) { + Project *project = SessionManager::startupProject(); if (!project) { if (whyNot) *whyNot = tr("No active project."); @@ -2798,9 +2799,8 @@ bool ProjectExplorerPlugin::canRun(Project *project, Core::Id runMode, QString * void ProjectExplorerPluginPrivate::slotUpdateRunActions() { - Project *project = SessionManager::startupProject(); QString whyNot; - const bool state = ProjectExplorerPlugin::canRun(project, Constants::NORMAL_RUN_MODE, &whyNot); + const bool state = ProjectExplorerPlugin::canRunStartupProject(Constants::NORMAL_RUN_MODE, &whyNot); m_runAction->setEnabled(state); m_runAction->setToolTip(whyNot); m_runWithoutDeployAction->setEnabled(state); diff --git a/src/plugins/projectexplorer/projectexplorer.h b/src/plugins/projectexplorer/projectexplorer.h index 1ca80bfacfa..aee6d28f738 100644 --- a/src/plugins/projectexplorer/projectexplorer.h +++ b/src/plugins/projectexplorer/projectexplorer.h @@ -134,7 +134,7 @@ public: static QStringList projectFilePatterns(); static QList > recentProjects(); - static bool canRun(Project *pro, Core::Id runMode, QString *whyNot = 0); + static bool canRunStartupProject(Core::Id runMode, QString *whyNot = 0); static void runProject(Project *pro, Core::Id, const bool forceSkipDeploy = false); static void runStartupProject(Core::Id runMode, bool forceSkipDeploy = false); static void runRunConfiguration(RunConfiguration *rc, Core::Id runMode, diff --git a/src/plugins/pythoneditor/pythoneditorplugin.cpp b/src/plugins/pythoneditor/pythoneditorplugin.cpp index a3f92a9884a..fdeb8e2134e 100644 --- a/src/plugins/pythoneditor/pythoneditorplugin.cpp +++ b/src/plugins/pythoneditor/pythoneditorplugin.cpp @@ -405,6 +405,7 @@ private: QString m_interpreter; QString m_mainScript; QString m_commandLineArguments; + Utils::Environment m_environment; ApplicationLauncher::Mode m_runMode; bool m_running; }; @@ -1077,6 +1078,7 @@ PythonRunControl::PythonRunControl(PythonRunConfiguration *rc, Core::Id mode) m_mainScript = rc->mainScript(); m_runMode = rc->extraAspect()->runMode(); m_commandLineArguments = rc->extraAspect()->arguments(); + m_environment = rc->extraAspect()->environment(); connect(&m_applicationLauncher, &ApplicationLauncher::appendMessage, this, &PythonRunControl::slotAppendMessage); @@ -1108,6 +1110,7 @@ void PythonRunControl::start() QtcProcess::addArgs(&r.commandLineArguments, m_commandLineArguments); r.executable = m_interpreter; r.runMode = m_runMode; + r.environment = m_environment; m_applicationLauncher.start(r); setApplicationProcessHandle(ProcessHandle(m_applicationLauncher.applicationPID())); diff --git a/src/plugins/qbsprojectmanager/qbsproject.cpp b/src/plugins/qbsprojectmanager/qbsproject.cpp index 97d2297d163..326340085e8 100644 --- a/src/plugins/qbsprojectmanager/qbsproject.cpp +++ b/src/plugins/qbsprojectmanager/qbsproject.cpp @@ -431,6 +431,33 @@ bool QbsProject::needsSpecialDeployment() const return true; } +void QbsProject::handleProjectStructureAvailable() +{ + QTC_ASSERT(m_qbsProjectParser, return); + + bool dataChanged = false; + m_qbsProject = m_qbsProjectParser->qbsProject(); + const qbs::ProjectData &projectData = m_qbsProject.projectData(); + QTC_CHECK(m_qbsProject.isValid()); + + if (projectData != m_projectData) { + m_projectData = projectData; + rootProjectNode()->update(); + updateDocuments(m_qbsProject.isValid() + ? m_qbsProject.buildSystemFiles() : QSet() << projectFilePath().toString()); + dataChanged = true; + } + + if (dataChanged) { + auto * const futureInterface = m_qbsUpdateFutureInterface; + m_qbsUpdateFutureInterface = nullptr; // So that isParsing() returns false; + updateCppCodeModel(); + updateQmlJsCodeModel(); + emit fileListChanged(); + m_qbsUpdateFutureInterface = futureInterface; + } +} + void QbsProject::handleQbsParsingDone(bool success) { QTC_ASSERT(m_qbsProjectParser, return); @@ -448,20 +475,9 @@ void QbsProject::handleQbsParsingDone(bool success) generateErrors(m_qbsProjectParser->error()); - bool dataChanged = false; if (success) { - m_qbsProject = m_qbsProjectParser->qbsProject(); - const qbs::ProjectData &projectData = m_qbsProject.projectData(); - QTC_CHECK(m_qbsProject.isValid()); - - if (projectData != m_projectData) { - m_projectData = projectData; - rootProjectNode()->update(); - - updateDocuments(m_qbsProject.isValid() - ? m_qbsProject.buildSystemFiles() : QSet() << projectFilePath().toString()); - dataChanged = true; - } + QTC_ASSERT(m_qbsProject.isValid(), return); + m_projectData = m_qbsProject.projectData(); } else { m_qbsUpdateFutureInterface->reportCanceled(); } @@ -475,13 +491,8 @@ void QbsProject::handleQbsParsingDone(bool success) m_qbsUpdateFutureInterface = 0; } - if (dataChanged) { // Do this now when isParsing() is false! - updateCppCodeModel(); - updateQmlJsCodeModel(); + if (success) updateBuildTargetData(); - - emit fileListChanged(); - } emit projectParsingDone(success); } @@ -593,8 +604,11 @@ void QbsProject::registerQbsProjectParser(QbsProjectParser *p) m_qbsProjectParser = p; - if (p) + if (p) { + connect(m_qbsProjectParser, &QbsProjectParser::projectStructureAvailable, + this, &QbsProject::handleProjectStructureAvailable); connect(m_qbsProjectParser, SIGNAL(done(bool)), this, SLOT(handleQbsParsingDone(bool))); + } } Project::RestoreResult QbsProject::fromMap(const QVariantMap &map, QString *errorMessage) diff --git a/src/plugins/qbsprojectmanager/qbsproject.h b/src/plugins/qbsprojectmanager/qbsproject.h index 5ad9ecff053..cd102b735c9 100644 --- a/src/plugins/qbsprojectmanager/qbsproject.h +++ b/src/plugins/qbsprojectmanager/qbsproject.h @@ -136,6 +136,7 @@ private: void updateApplicationTargets(); void updateDeploymentInfo(); void updateBuildTargetData(); + void handleProjectStructureAvailable(); void projectLoaded() override; static bool ensureWriteableQbsFile(const QString &file); diff --git a/src/plugins/qbsprojectmanager/qbsprojectparser.cpp b/src/plugins/qbsprojectmanager/qbsprojectparser.cpp index 77b0ebbb80d..f12b08404e1 100644 --- a/src/plugins/qbsprojectmanager/qbsprojectparser.cpp +++ b/src/plugins/qbsprojectmanager/qbsprojectparser.cpp @@ -143,10 +143,12 @@ void QbsProjectParser::handleQbsParsingDone(bool success) // Do not report the operation as canceled here, as we might want to make overlapping // parses appear atomic to the user. - if (!success) + if (!success) { emit done(false); - else + } else { + emit projectStructureAvailable(); startRuleExecution(); + } } void QbsProjectParser::startRuleExecution() diff --git a/src/plugins/qbsprojectmanager/qbsprojectparser.h b/src/plugins/qbsprojectmanager/qbsprojectparser.h index d50c2ab9e27..6a3ea3c7ce3 100644 --- a/src/plugins/qbsprojectmanager/qbsprojectparser.h +++ b/src/plugins/qbsprojectmanager/qbsprojectparser.h @@ -55,6 +55,7 @@ public: signals: void done(bool success); + void projectStructureAvailable(); private slots: void handleQbsParsingDone(bool success); diff --git a/src/plugins/qmakeprojectmanager/qmakeprojectmanager.cpp b/src/plugins/qmakeprojectmanager/qmakeprojectmanager.cpp index b56ac0cf7a1..d83879e6da9 100644 --- a/src/plugins/qmakeprojectmanager/qmakeprojectmanager.cpp +++ b/src/plugins/qmakeprojectmanager/qmakeprojectmanager.cpp @@ -123,17 +123,17 @@ void QmakeManager::setContextFile(ProjectExplorer::FileNode *file) void QmakeManager::addLibrary() { if (auto editor = qobject_cast(Core::EditorManager::currentEditor())) - addLibrary(editor->document()->filePath().toString(), editor); + addLibraryImpl(editor->document()->filePath().toString(), editor); } void QmakeManager::addLibraryContextMenu() { Node *node = ProjectTree::currentNode(); if (dynamic_cast(node)) - addLibrary(node->filePath().toString()); + addLibraryImpl(node->filePath().toString(), nullptr); } -void QmakeManager::addLibrary(const QString &fileName, BaseTextEditor *editor) +void QmakeManager::addLibraryImpl(const QString &fileName, BaseTextEditor *editor) { Internal::AddLibraryWizard wizard(fileName, Core::ICore::dialogParent()); if (wizard.exec() != QDialog::Accepted) @@ -161,15 +161,15 @@ void QmakeManager::addLibrary(const QString &fileName, BaseTextEditor *editor) void QmakeManager::runQMake() { - runQMake(SessionManager::startupProject(), 0); + runQMakeImpl(SessionManager::startupProject(), nullptr); } void QmakeManager::runQMakeContextMenu() { - runQMake(m_contextProject, m_contextNode); + runQMakeImpl(m_contextProject, m_contextNode); } -void QmakeManager::runQMake(ProjectExplorer::Project *p, ProjectExplorer::Node *node) +void QmakeManager::runQMakeImpl(ProjectExplorer::Project *p, ProjectExplorer::Node *node) { if (!ProjectExplorerPlugin::saveModifiedFiles()) return; diff --git a/src/plugins/qmakeprojectmanager/qmakeprojectmanager.h b/src/plugins/qmakeprojectmanager/qmakeprojectmanager.h index 52c31afafc4..ece682f76d5 100644 --- a/src/plugins/qmakeprojectmanager/qmakeprojectmanager.h +++ b/src/plugins/qmakeprojectmanager/qmakeprojectmanager.h @@ -23,8 +23,7 @@ ** ****************************************************************************/ -#ifndef QMAKEPROJECTMANAGER_H -#define QMAKEPROJECTMANAGER_H +#pragma once #include "qmakeprojectmanager_global.h" @@ -68,7 +67,6 @@ public: enum Action { BUILD, REBUILD, CLEAN }; -public slots: void addLibrary(); void addLibraryContextMenu(); void runQMake(); @@ -86,8 +84,8 @@ private: ProjectExplorer::Project *contextProject, ProjectExplorer::Node *contextNode, ProjectExplorer::FileNode *contextFile); - void addLibrary(const QString &fileName, TextEditor::BaseTextEditor *editor = 0); - void runQMake(ProjectExplorer::Project *p, ProjectExplorer::Node *node); + void addLibraryImpl(const QString &fileName, TextEditor::BaseTextEditor *editor); + void runQMakeImpl(ProjectExplorer::Project *p, ProjectExplorer::Node *node); ProjectExplorer::Node *m_contextNode = nullptr; ProjectExplorer::Project *m_contextProject = nullptr; @@ -95,5 +93,3 @@ private: }; } // namespace QmakeProjectManager - -#endif // QMAKEPROJECTMANAGER_H diff --git a/src/plugins/qmakeprojectmanager/qmakeprojectmanagerplugin.cpp b/src/plugins/qmakeprojectmanager/qmakeprojectmanagerplugin.cpp index c567cfbc810..97c691c4f6d 100644 --- a/src/plugins/qmakeprojectmanager/qmakeprojectmanagerplugin.cpp +++ b/src/plugins/qmakeprojectmanager/qmakeprojectmanagerplugin.cpp @@ -135,14 +135,15 @@ bool QmakeProjectManagerPlugin::initialize(const QStringList &arguments, QString command->setAttribute(Command::CA_UpdateText); command->setDescription(m_buildSubProjectContextMenu->text()); msubproject->addAction(command, ProjectExplorer::Constants::G_PROJECT_BUILD); - connect(m_buildSubProjectContextMenu, SIGNAL(triggered()), m_qmakeProjectManager, SLOT(buildSubDirContextMenu())); + connect(m_buildSubProjectContextMenu, &QAction::triggered, m_qmakeProjectManager, &QmakeManager::buildSubDirContextMenu); m_runQMakeActionContextMenu = new QAction(tr("Run qmake"), this); command = ActionManager::registerAction(m_runQMakeActionContextMenu, Constants::RUNQMAKECONTEXTMENU, projectContext); command->setAttribute(Command::CA_Hide); mproject->addAction(command, ProjectExplorer::Constants::G_PROJECT_BUILD); msubproject->addAction(command, ProjectExplorer::Constants::G_PROJECT_BUILD); - connect(m_runQMakeActionContextMenu, SIGNAL(triggered()), m_qmakeProjectManager, SLOT(runQMakeContextMenu())); + connect(m_runQMakeActionContextMenu, &QAction::triggered, + m_qmakeProjectManager, &QmakeManager::runQMakeContextMenu); command = msubproject->addSeparator(projectContext, ProjectExplorer::Constants::G_PROJECT_BUILD, &m_subProjectRebuildSeparator); @@ -153,20 +154,23 @@ bool QmakeProjectManagerPlugin::initialize(const QStringList &arguments, QString m_rebuildSubProjectContextMenu, Constants::REBUILDSUBDIRCONTEXTMENU, projectContext); command->setAttribute(Command::CA_Hide); msubproject->addAction(command, ProjectExplorer::Constants::G_PROJECT_BUILD); - connect(m_rebuildSubProjectContextMenu, SIGNAL(triggered()), m_qmakeProjectManager, SLOT(rebuildSubDirContextMenu())); + connect(m_rebuildSubProjectContextMenu, &QAction::triggered, + m_qmakeProjectManager, &QmakeManager::rebuildSubDirContextMenu); m_cleanSubProjectContextMenu = new QAction(tr("Clean"), this); command = ActionManager::registerAction( m_cleanSubProjectContextMenu, Constants::CLEANSUBDIRCONTEXTMENU, projectContext); command->setAttribute(Command::CA_Hide); msubproject->addAction(command, ProjectExplorer::Constants::G_PROJECT_BUILD); - connect(m_cleanSubProjectContextMenu, SIGNAL(triggered()), m_qmakeProjectManager, SLOT(cleanSubDirContextMenu())); + connect(m_cleanSubProjectContextMenu, &QAction::triggered, + m_qmakeProjectManager, &QmakeManager::cleanSubDirContextMenu); m_buildFileContextMenu = new QAction(tr("Build"), this); command = ActionManager::registerAction(m_buildFileContextMenu, Constants::BUILDFILECONTEXTMENU, projectContext); command->setAttribute(Command::CA_Hide); mfile->addAction(command, ProjectExplorer::Constants::G_FILE_OTHER); - connect(m_buildFileContextMenu, SIGNAL(triggered()), m_qmakeProjectManager, SLOT(buildFileContextMenu())); + connect(m_buildFileContextMenu, &QAction::triggered, + m_qmakeProjectManager, &QmakeManager::buildFileContextMenu); m_buildSubProjectAction = new Utils::ParameterAction(tr("Build Subproject"), tr("Build Subproject \"%1\""), Utils::ParameterAction::AlwaysEnabled, this); @@ -175,13 +179,14 @@ bool QmakeProjectManagerPlugin::initialize(const QStringList &arguments, QString command->setAttribute(Command::CA_UpdateText); command->setDescription(m_buildSubProjectAction->text()); mbuild->addAction(command, ProjectExplorer::Constants::G_BUILD_BUILD); - connect(m_buildSubProjectAction, SIGNAL(triggered()), m_qmakeProjectManager, SLOT(buildSubDirContextMenu())); + connect(m_buildSubProjectAction, &QAction::triggered, + m_qmakeProjectManager, &QmakeManager::buildSubDirContextMenu); m_runQMakeAction = new QAction(tr("Run qmake"), this); const Context globalcontext(Core::Constants::C_GLOBAL); command = ActionManager::registerAction(m_runQMakeAction, Constants::RUNQMAKE, globalcontext); mbuild->addAction(command, ProjectExplorer::Constants::G_BUILD_BUILD); - connect(m_runQMakeAction, SIGNAL(triggered()), m_qmakeProjectManager, SLOT(runQMake())); + connect(m_runQMakeAction, &QAction::triggered, m_qmakeProjectManager, &QmakeManager::runQMake); m_rebuildSubProjectAction = new Utils::ParameterAction(tr("Rebuild Subproject"), tr("Rebuild Subproject \"%1\""), Utils::ParameterAction::AlwaysEnabled, this); @@ -190,7 +195,8 @@ bool QmakeProjectManagerPlugin::initialize(const QStringList &arguments, QString command->setAttribute(Command::CA_UpdateText); command->setDescription(m_rebuildSubProjectAction->text()); mbuild->addAction(command, ProjectExplorer::Constants::G_BUILD_REBUILD); - connect(m_rebuildSubProjectAction, SIGNAL(triggered()), m_qmakeProjectManager, SLOT(rebuildSubDirContextMenu())); + connect(m_rebuildSubProjectAction, &QAction::triggered, + m_qmakeProjectManager, &QmakeManager::rebuildSubDirContextMenu); m_cleanSubProjectAction = new Utils::ParameterAction(tr("Clean Subproject"), tr("Clean Subproject \"%1\""), Utils::ParameterAction::AlwaysEnabled, this); @@ -199,7 +205,8 @@ bool QmakeProjectManagerPlugin::initialize(const QStringList &arguments, QString command->setAttribute(Command::CA_UpdateText); command->setDescription(m_cleanSubProjectAction->text()); mbuild->addAction(command, ProjectExplorer::Constants::G_BUILD_CLEAN); - connect(m_cleanSubProjectAction, SIGNAL(triggered()), m_qmakeProjectManager, SLOT(cleanSubDirContextMenu())); + connect(m_cleanSubProjectAction, &QAction::triggered, + m_qmakeProjectManager, &QmakeManager::cleanSubDirContextMenu); m_buildFileAction = new Utils::ParameterAction(tr("Build File"), tr("Build File \"%1\""), Utils::ParameterAction::AlwaysEnabled, this); @@ -209,10 +216,10 @@ bool QmakeProjectManagerPlugin::initialize(const QStringList &arguments, QString command->setDescription(m_buildFileAction->text()); command->setDefaultKeySequence(QKeySequence(tr("Ctrl+Alt+B"))); mbuild->addAction(command, ProjectExplorer::Constants::G_BUILD_BUILD); - connect(m_buildFileAction, SIGNAL(triggered()), m_qmakeProjectManager, SLOT(buildFile())); + connect(m_buildFileAction, &QAction::triggered, m_qmakeProjectManager, &QmakeManager::buildFile); - connect(BuildManager::instance(), SIGNAL(buildStateChanged(ProjectExplorer::Project*)), - this, SLOT(buildStateChanged(ProjectExplorer::Project*))); + connect(BuildManager::instance(), &BuildManager::buildStateChanged, + this, &QmakeProjectManagerPlugin::buildStateChanged); connect(SessionManager::instance(), &SessionManager::startupProjectChanged, this, &QmakeProjectManagerPlugin::projectChanged); connect(ProjectTree::instance(), &ProjectTree::currentProjectChanged, @@ -231,15 +238,14 @@ bool QmakeProjectManagerPlugin::initialize(const QStringList &arguments, QString m_addLibraryAction = new QAction(tr("Add Library..."), this); command = ActionManager::registerAction(m_addLibraryAction, Constants::ADDLIBRARY, proFileEditorContext); - connect(m_addLibraryAction, SIGNAL(triggered()), - m_qmakeProjectManager, SLOT(addLibrary())); + connect(m_addLibraryAction, &QAction::triggered, m_qmakeProjectManager, &QmakeManager::addLibrary); contextMenu->addAction(command); m_addLibraryActionContextMenu = new QAction(tr("Add Library..."), this); command = ActionManager::registerAction(m_addLibraryActionContextMenu, Constants::ADDLIBRARY, projecTreeContext); - connect(m_addLibraryActionContextMenu, SIGNAL(triggered()), - m_qmakeProjectManager, SLOT(addLibraryContextMenu())); + connect(m_addLibraryActionContextMenu, &QAction::triggered, + m_qmakeProjectManager, &QmakeManager::addLibraryContextMenu); mproject->addAction(command, ProjectExplorer::Constants::G_PROJECT_FILES); msubproject->addAction(command, ProjectExplorer::Constants::G_PROJECT_FILES); @@ -251,6 +257,8 @@ bool QmakeProjectManagerPlugin::initialize(const QStringList &arguments, QString connect(EditorManager::instance(), &EditorManager::currentEditorChanged, this, &QmakeProjectManagerPlugin::updateBuildFileAction); + updateRunQMakeAction(); + return true; } @@ -260,8 +268,8 @@ void QmakeProjectManagerPlugin::extensionsInitialized() void QmakeProjectManagerPlugin::projectChanged() { if (m_previousStartupProject) - disconnect(m_previousStartupProject, SIGNAL(activeTargetChanged(ProjectExplorer::Target*)), - this, SLOT(activeTargetChanged())); + disconnect(m_previousStartupProject, &Project::activeTargetChanged, + this, &QmakeProjectManagerPlugin::activeTargetChanged); if (ProjectTree::currentProject()) m_previousStartupProject = qobject_cast(ProjectTree::currentProject()); @@ -269,8 +277,8 @@ void QmakeProjectManagerPlugin::projectChanged() m_previousStartupProject = qobject_cast(SessionManager::startupProject()); if (m_previousStartupProject) - connect(m_previousStartupProject, SIGNAL(activeTargetChanged(ProjectExplorer::Target*)), - this, SLOT(activeTargetChanged())); + connect(m_previousStartupProject, &Project::activeTargetChanged, + this, &QmakeProjectManagerPlugin::activeTargetChanged); activeTargetChanged(); } @@ -278,14 +286,14 @@ void QmakeProjectManagerPlugin::projectChanged() void QmakeProjectManagerPlugin::activeTargetChanged() { if (m_previousTarget) - disconnect(m_previousTarget, SIGNAL(activeBuildConfigurationChanged(ProjectExplorer::BuildConfiguration*)), - this, SLOT(updateRunQMakeAction())); + disconnect(m_previousTarget, &Target::activeBuildConfigurationChanged, + this, &QmakeProjectManagerPlugin::updateRunQMakeAction); m_previousTarget = m_previousStartupProject ? m_previousStartupProject->activeTarget() : 0; if (m_previousTarget) - connect(m_previousTarget, SIGNAL(activeBuildConfigurationChanged(ProjectExplorer::BuildConfiguration*)), - this, SLOT(updateRunQMakeAction())); + connect(m_previousTarget, &Target::activeBuildConfigurationChanged, + this, &QmakeProjectManagerPlugin::updateRunQMakeAction); updateRunQMakeAction(); } diff --git a/src/plugins/qmakeprojectmanager/qmakeprojectmanagerplugin.h b/src/plugins/qmakeprojectmanager/qmakeprojectmanagerplugin.h index 3ed014d9741..2029fe2b9e7 100644 --- a/src/plugins/qmakeprojectmanager/qmakeprojectmanagerplugin.h +++ b/src/plugins/qmakeprojectmanager/qmakeprojectmanagerplugin.h @@ -58,7 +58,13 @@ public: bool initialize(const QStringList &arguments, QString *errorMessage); void extensionsInitialized(); +#ifdef WITH_TESTS private slots: + void testQmakeOutputParsers_data(); + void testQmakeOutputParsers(); +#endif + +private: void projectChanged(); void activeTargetChanged(); void updateRunQMakeAction(); @@ -66,12 +72,6 @@ private slots: void buildStateChanged(ProjectExplorer::Project *pro); void updateBuildFileAction(); -#ifdef WITH_TESTS - void testQmakeOutputParsers_data(); - void testQmakeOutputParsers(); -#endif - -private: QmakeManager *m_qmakeProjectManager = nullptr; QmakeProject *m_previousStartupProject = nullptr; ProjectExplorer::Target *m_previousTarget = nullptr; diff --git a/src/plugins/qmlprofiler/localqmlprofilerrunner.cpp b/src/plugins/qmlprofiler/localqmlprofilerrunner.cpp index 7492ce0ff15..b79aa79e927 100644 --- a/src/plugins/qmlprofiler/localqmlprofilerrunner.cpp +++ b/src/plugins/qmlprofiler/localqmlprofilerrunner.cpp @@ -74,7 +74,7 @@ LocalQmlProfilerRunner::LocalQmlProfilerRunner(const Configuration &configuratio engine, &QmlProfilerRunControl::notifyRemoteFinished); connect(this, &LocalQmlProfilerRunner::appendMessage, engine, &QmlProfilerRunControl::logApplicationMessage); - connect(engine, &Analyzer::AnalyzerRunControl::starting, + connect(engine, &Debugger::AnalyzerRunControl::starting, this, &LocalQmlProfilerRunner::start); connect(engine, &RunControl::finished, this, &LocalQmlProfilerRunner::stop); diff --git a/src/plugins/qmlprofiler/qmlprofilerplugin.cpp b/src/plugins/qmlprofiler/qmlprofilerplugin.cpp index 4cad320dbf9..be64b14a26e 100644 --- a/src/plugins/qmlprofiler/qmlprofilerplugin.cpp +++ b/src/plugins/qmlprofiler/qmlprofilerplugin.cpp @@ -34,8 +34,6 @@ #include -using namespace Analyzer; - namespace QmlProfiler { namespace Internal { diff --git a/src/plugins/qmlprofiler/qmlprofilerrunconfigurationaspect.cpp b/src/plugins/qmlprofiler/qmlprofilerrunconfigurationaspect.cpp index 27260698fe2..1522acba0d0 100644 --- a/src/plugins/qmlprofiler/qmlprofilerrunconfigurationaspect.cpp +++ b/src/plugins/qmlprofiler/qmlprofilerrunconfigurationaspect.cpp @@ -53,7 +53,7 @@ ProjectExplorer::IRunConfigurationAspect *QmlProfilerRunConfigurationAspect::cre ProjectExplorer::RunConfigWidget *QmlProfilerRunConfigurationAspect::createConfigurationWidget() { - return new Analyzer::AnalyzerRunConfigWidget(this); + return new Debugger::AnalyzerRunConfigWidget(this); } } // Internal diff --git a/src/plugins/qmlprofiler/qmlprofilerruncontrol.cpp b/src/plugins/qmlprofiler/qmlprofilerruncontrol.cpp index 4626072e967..ec78fe1c758 100644 --- a/src/plugins/qmlprofiler/qmlprofilerruncontrol.cpp +++ b/src/plugins/qmlprofiler/qmlprofilerruncontrol.cpp @@ -51,7 +51,7 @@ #include #include -using namespace Analyzer; +using namespace Debugger; using namespace Core; using namespace ProjectExplorer; @@ -102,16 +102,16 @@ QmlProfilerRunControl::QmlProfilerRunControl(RunConfiguration *runConfiguration, QmlProfilerRunControl::~QmlProfilerRunControl() { if (d->m_profilerState) - stopEngine(); + stop(); delete d; } -bool QmlProfilerRunControl::startEngine() +void QmlProfilerRunControl::start() { d->m_tool->finalizeRunControl(this); - QTC_ASSERT(d->m_profilerState, return false); + QTC_ASSERT(d->m_profilerState, finished(); return); - QTC_ASSERT(connection().is(), return false); + QTC_ASSERT(connection().is(), finished(); return); auto conn = connection().as(); if (conn.analyzerPort != 0) @@ -120,13 +120,14 @@ bool QmlProfilerRunControl::startEngine() d->m_noDebugOutputTimer.start(); d->m_profilerState->setCurrentState(QmlProfilerStateManager::AppRunning); + d->m_running = true; emit starting(); - return true; } -void QmlProfilerRunControl::stopEngine() +RunControl::StopResult QmlProfilerRunControl::stop() { - QTC_ASSERT(d->m_profilerState, return); + d->m_running = false; + QTC_ASSERT(d->m_profilerState, return RunControl::StoppedSynchronously); switch (d->m_profilerState->currentState()) { case QmlProfilerStateManager::AppRunning: @@ -147,6 +148,13 @@ void QmlProfilerRunControl::stopEngine() } break; } + + return RunControl::StoppedSynchronously; +} + +bool QmlProfilerRunControl::isRunning() const +{ + return d->m_running; } void QmlProfilerRunControl::notifyRemoteFinished() @@ -156,7 +164,7 @@ void QmlProfilerRunControl::notifyRemoteFinished() switch (d->m_profilerState->currentState()) { case QmlProfilerStateManager::AppRunning: d->m_profilerState->setCurrentState(QmlProfilerStateManager::AppDying); - AnalyzerManager::stopTool(); + d->m_running = false; emit finished(); break; case QmlProfilerStateManager::Idle: @@ -186,6 +194,7 @@ void QmlProfilerRunControl::cancelProcess() return; } } + d->m_running = false; emit finished(); } @@ -215,7 +224,7 @@ void QmlProfilerRunControl::wrongSetupMessageBox(const QString &errorMessage) // KILL d->m_profilerState->setCurrentState(QmlProfilerStateManager::AppDying); d->m_noDebugOutputTimer.stop(); - AnalyzerManager::stopTool(); + d->m_running = false; emit finished(); } @@ -262,6 +271,7 @@ void QmlProfilerRunControl::profilerStateChanged() { switch (d->m_profilerState->currentState()) { case QmlProfilerStateManager::Idle: + d->m_running = false; emit finished(); d->m_noDebugOutputTimer.stop(); break; @@ -270,12 +280,4 @@ void QmlProfilerRunControl::profilerStateChanged() } } -RunControl::StopResult QmlProfilerRunControl::stop() -{ - StopResult result = Analyzer::AnalyzerRunControl::stop(); - if (d->m_profilerState->currentState() != QmlProfilerStateManager::Idle) - m_isRunning = true; - return result; -} - } // namespace QmlProfiler diff --git a/src/plugins/qmlprofiler/qmlprofilerruncontrol.h b/src/plugins/qmlprofiler/qmlprofilerruncontrol.h index a7d42d7c34b..a44e6c710a1 100644 --- a/src/plugins/qmlprofiler/qmlprofilerruncontrol.h +++ b/src/plugins/qmlprofiler/qmlprofilerruncontrol.h @@ -35,7 +35,7 @@ namespace QmlProfiler { namespace Internal { class QmlProfilerTool; } -class QmlProfilerRunControl : public Analyzer::AnalyzerRunControl +class QmlProfilerRunControl : public Debugger::AnalyzerRunControl { Q_OBJECT @@ -47,25 +47,22 @@ public: void registerProfilerStateManager( QmlProfilerStateManager *profilerState ); void notifyRemoteSetupDone(quint16 port) override; + void start() override; StopResult stop() override; - -signals: - void processRunning(quint16 port); - -public slots: - bool startEngine() override; - void stopEngine() override; + bool isRunning() const override; void cancelProcess(); void notifyRemoteFinished() override; void logApplicationMessage(const QString &msg, Utils::OutputFormat format) override; -private slots: +signals: + void processRunning(quint16 port); + +private: void wrongSetupMessageBox(const QString &errorMessage); void wrongSetupMessageBoxFinished(int); void processIsRunning(quint16 port); void profilerStateChanged(); -private: class QmlProfilerRunControlPrivate; QmlProfilerRunControlPrivate *d; }; diff --git a/src/plugins/qmlprofiler/qmlprofilerruncontrolfactory.cpp b/src/plugins/qmlprofiler/qmlprofilerruncontrolfactory.cpp index b6252f64b18..5803d239576 100644 --- a/src/plugins/qmlprofiler/qmlprofilerruncontrolfactory.cpp +++ b/src/plugins/qmlprofiler/qmlprofilerruncontrolfactory.cpp @@ -45,7 +45,7 @@ #include -using namespace Analyzer; +using namespace Debugger; using namespace ProjectExplorer; namespace QmlProfiler { @@ -94,7 +94,7 @@ RunControl *QmlProfilerRunControlFactory::create(RunConfiguration *runConfigurat } auto runControl = qobject_cast - (AnalyzerManager::createRunControl(runConfiguration, mode)); + (Debugger::createAnalyzerRunControl(runConfiguration, mode)); QTC_ASSERT(runControl, return 0); runControl->setRunnable(runnable); diff --git a/src/plugins/qmlprofiler/qmlprofilertool.cpp b/src/plugins/qmlprofiler/qmlprofilertool.cpp index ed862ce0190..1d822a9cd9d 100644 --- a/src/plugins/qmlprofiler/qmlprofilertool.cpp +++ b/src/plugins/qmlprofiler/qmlprofilertool.cpp @@ -82,8 +82,8 @@ using namespace Core; using namespace Core::Constants; -using namespace Analyzer; -using namespace Analyzer::Constants; +using namespace Debugger; +using namespace Debugger::Constants; using namespace QmlProfiler::Constants; using namespace QmlDebug; using namespace ProjectExplorer; @@ -103,6 +103,8 @@ public: QToolButton *m_recordButton = 0; QMenu *m_recordFeaturesMenu = 0; + QAction *m_startAction = 0; + QAction *m_stopAction = 0; QToolButton *m_clearButton = 0; // elapsed time display @@ -120,6 +122,8 @@ public: // save and load actions QAction *m_saveQmlTrace = 0; QAction *m_loadQmlTrace = 0; + + bool m_toolBusy = false; }; QmlProfilerTool::QmlProfilerTool(QObject *parent) @@ -176,8 +180,6 @@ QmlProfilerTool::QmlProfilerTool(QObject *parent) d->m_recordingTimer.setInterval(100); connect(&d->m_recordingTimer, &QTimer::timeout, this, &QmlProfilerTool::updateTimeDisplay); - - d->m_viewContainer = new QmlProfilerViewManager(this, d->m_profilerModelManager, d->m_profilerState); @@ -187,14 +189,7 @@ QmlProfilerTool::QmlProfilerTool(QObject *parent) // // Toolbar // - QWidget *toolbarWidget = new QWidget; - toolbarWidget->setObjectName(QLatin1String("QmlProfilerToolBarWidget")); - - QHBoxLayout *layout = new QHBoxLayout; - layout->setMargin(0); - layout->setSpacing(0); - - d->m_recordButton = new QToolButton(toolbarWidget); + d->m_recordButton = new QToolButton; d->m_recordButton->setCheckable(true); connect(d->m_recordButton,&QAbstractButton::clicked, @@ -207,9 +202,8 @@ QmlProfilerTool::QmlProfilerTool(QObject *parent) this, &QmlProfilerTool::toggleRequestedFeature); setRecording(d->m_profilerState->clientRecording()); - layout->addWidget(d->m_recordButton); - d->m_clearButton = new QToolButton(toolbarWidget); + d->m_clearButton = new QToolButton; d->m_clearButton->setIcon(Icons::CLEAN_PANE.icon()); d->m_clearButton->setToolTip(tr("Discard data")); @@ -218,12 +212,9 @@ QmlProfilerTool::QmlProfilerTool(QObject *parent) clearData(); }); - layout->addWidget(d->m_clearButton); - d->m_searchButton = new QToolButton; d->m_searchButton->setIcon(Icons::ZOOM.icon()); d->m_searchButton->setToolTip(tr("Search timeline event notes.")); - layout->addWidget(d->m_searchButton); connect(d->m_searchButton, &QToolButton::clicked, this, &QmlProfilerTool::showTimeLineSearch); @@ -236,7 +227,6 @@ QmlProfilerTool::QmlProfilerTool(QObject *parent) d->m_displayFeaturesButton->setMenu(d->m_displayFeaturesMenu); connect(d->m_displayFeaturesMenu, &QMenu::triggered, this, &QmlProfilerTool::toggleVisibleFeature); - layout->addWidget(d->m_displayFeaturesButton); d->m_timeLabel = new QLabel(); QPalette palette; @@ -244,11 +234,7 @@ QmlProfilerTool::QmlProfilerTool(QObject *parent) d->m_timeLabel->setPalette(palette); d->m_timeLabel->setIndent(10); updateTimeDisplay(); - layout->addWidget(d->m_timeLabel); - layout->addStretch(); - - toolbarWidget->setLayout(layout); setAvailableFeatures(d->m_profilerModelManager->availableFeatures()); setRecordedFeatures(0); @@ -263,6 +249,9 @@ QmlProfilerTool::QmlProfilerTool(QObject *parent) QString description = tr("The QML Profiler can be used to find performance " "bottlenecks in applications using QML."); + d->m_startAction = Debugger::createStartAction(); + d->m_stopAction = Debugger::createStopAction(); + ActionDescription desc; desc.setText(tr("QML Profiler")); desc.setToolTip(description); @@ -270,8 +259,8 @@ QmlProfilerTool::QmlProfilerTool(QObject *parent) desc.setRunControlCreator(runControlCreator); desc.setToolPreparer([this] { return prepareTool(); }); desc.setRunMode(ProjectExplorer::Constants::QML_PROFILER_RUN_MODE); - desc.setMenuGroup(Analyzer::Constants::G_ANALYZER_TOOLS); - AnalyzerManager::registerAction(Constants::QmlProfilerLocalActionId, desc); + desc.setMenuGroup(Debugger::Constants::G_ANALYZER_TOOLS); + Debugger::registerAction(Constants::QmlProfilerLocalActionId, desc, d->m_startAction); desc.setText(tr("QML Profiler (External)")); desc.setToolTip(description); @@ -280,10 +269,21 @@ QmlProfilerTool::QmlProfilerTool(QObject *parent) desc.setCustomToolStarter([this](RunConfiguration *rc) { startRemoteTool(rc); }); desc.setToolPreparer([this] { return prepareTool(); }); desc.setRunMode(ProjectExplorer::Constants::QML_PROFILER_RUN_MODE); - desc.setMenuGroup(Analyzer::Constants::G_ANALYZER_REMOTE_TOOLS); - AnalyzerManager::registerAction(Constants::QmlProfilerRemoteActionId, desc); + desc.setMenuGroup(Debugger::Constants::G_ANALYZER_REMOTE_TOOLS); + Debugger::registerAction(Constants::QmlProfilerRemoteActionId, desc); - AnalyzerManager::registerToolbar(Constants::QmlProfilerPerspectiveId, toolbarWidget); + Utils::ToolbarDescription toolbar; + toolbar.addAction(d->m_startAction); + toolbar.addAction(d->m_stopAction); + toolbar.addWidget(d->m_recordButton); + toolbar.addWidget(d->m_clearButton); + toolbar.addWidget(d->m_searchButton); + toolbar.addWidget(d->m_displayFeaturesButton); + toolbar.addWidget(d->m_timeLabel); + Debugger::registerToolbar(Constants::QmlProfilerPerspectiveId, toolbar); + + connect(ProjectExplorerPlugin::instance(), &ProjectExplorerPlugin::updateRunActions, + this, &QmlProfilerTool::updateRunActions); } QmlProfilerTool::~QmlProfilerTool() @@ -291,6 +291,22 @@ QmlProfilerTool::~QmlProfilerTool() delete d; } +void QmlProfilerTool::updateRunActions() +{ + if (d->m_toolBusy) { + d->m_startAction->setEnabled(false); + d->m_startAction->setToolTip(tr("A Qml Profiler analysis is still in progress.")); + d->m_stopAction->setEnabled(true); + } else { + QString whyNot = tr("Start Qml Profiler analysis."); + bool canRun = ProjectExplorerPlugin::canRunStartupProject + (ProjectExplorer::Constants::QML_PROFILER_RUN_MODE, &whyNot); + d->m_startAction->setToolTip(whyNot); + d->m_startAction->setEnabled(canRun); + d->m_stopAction->setEnabled(false); + } +} + static QString sysroot(RunConfiguration *runConfig) { QTC_ASSERT(runConfig, return QString()); @@ -302,6 +318,7 @@ static QString sysroot(RunConfiguration *runConfig) AnalyzerRunControl *QmlProfilerTool::createRunControl(RunConfiguration *runConfiguration) { + d->m_toolBusy = true; if (runConfiguration) { QmlProfilerRunConfigurationAspect *aspect = static_cast( runConfiguration->extraAspect(Constants::SETTINGS)); @@ -314,7 +331,16 @@ AnalyzerRunControl *QmlProfilerTool::createRunControl(RunConfiguration *runConfi } } - return new QmlProfilerRunControl(runConfiguration, this); + auto runControl = new QmlProfilerRunControl(runConfiguration, this); + connect(runControl, &RunControl::finished, [this, runControl] { + d->m_toolBusy = false; + updateRunActions(); + }); + + connect(d->m_stopAction, &QAction::triggered, runControl, [runControl] { runControl->stop(); }); + + updateRunActions(); + return runControl; } void QmlProfilerTool::finalizeRunControl(QmlProfilerRunControl *runControl) @@ -503,8 +529,6 @@ bool QmlProfilerTool::prepareTool() void QmlProfilerTool::startRemoteTool(ProjectExplorer::RunConfiguration *rc) { - AnalyzerManager::showMode(); - Id kitId; quint16 port; Kit *kit = 0; @@ -596,7 +620,7 @@ void QmlProfilerTool::showSaveDialog() if (!filename.endsWith(QLatin1String(TraceFileExtension))) filename += QLatin1String(TraceFileExtension); saveLastTraceFile(filename); - AnalyzerManager::enableMainWindow(false); + Debugger::enableMainWindow(false); d->m_profilerModelManager->save(filename); } } @@ -606,10 +630,7 @@ void QmlProfilerTool::showLoadDialog() if (!checkForUnsavedNotes()) return; - if (ModeManager::currentMode()->id() != MODE_ANALYZE) - AnalyzerManager::showMode(); - - AnalyzerManager::selectAction(QmlProfilerRemoteActionId); + Debugger::selectPerspective(QmlProfilerPerspectiveId); QString filename = QFileDialog::getOpenFileName( ICore::mainWindow(), tr("Load QML Trace"), @@ -618,7 +639,7 @@ void QmlProfilerTool::showLoadDialog() if (!filename.isEmpty()) { saveLastTraceFile(filename); - AnalyzerManager::enableMainWindow(false); + Debugger::enableMainWindow(false); connect(d->m_profilerModelManager, &QmlProfilerModelManager::recordedFeaturesChanged, this, &QmlProfilerTool::setRecordedFeatures); d->m_profilerModelManager->load(filename); @@ -629,7 +650,7 @@ void QmlProfilerTool::onLoadSaveFinished() { disconnect(d->m_profilerModelManager, &QmlProfilerModelManager::recordedFeaturesChanged, this, &QmlProfilerTool::setRecordedFeatures); - AnalyzerManager::enableMainWindow(true); + Debugger::enableMainWindow(true); } /*! diff --git a/src/plugins/qmlprofiler/qmlprofilertool.h b/src/plugins/qmlprofiler/qmlprofilertool.h index 23f740e2d31..34c7e215051 100644 --- a/src/plugins/qmlprofiler/qmlprofilertool.h +++ b/src/plugins/qmlprofiler/qmlprofilertool.h @@ -51,7 +51,7 @@ public: explicit QmlProfilerTool(QObject *parent); ~QmlProfilerTool(); - Analyzer::AnalyzerRunControl *createRunControl(ProjectExplorer::RunConfiguration *runConfiguration = 0); + Debugger::AnalyzerRunControl *createRunControl(ProjectExplorer::RunConfiguration *runConfiguration = 0); void finalizeRunControl(QmlProfilerRunControl *runControl); bool prepareTool(); @@ -96,6 +96,7 @@ private slots: void toggleVisibleFeature(QAction *action); private: + void updateRunActions(); void clearDisplay(); void populateFileFinder(QString projectDirectory = QString(), QString activeSysroot = QString()); template diff --git a/src/plugins/qmlprofiler/qmlprofilerviewmanager.cpp b/src/plugins/qmlprofiler/qmlprofilerviewmanager.cpp index 9655734d9d2..1c4a67e5b93 100644 --- a/src/plugins/qmlprofiler/qmlprofilerviewmanager.cpp +++ b/src/plugins/qmlprofiler/qmlprofilerviewmanager.cpp @@ -40,7 +40,8 @@ #include -using namespace Analyzer; +using namespace Debugger; +using namespace Utils; namespace QmlProfiler { namespace Internal { @@ -80,7 +81,7 @@ void QmlProfilerViewManager::createViews() QTC_ASSERT(d->profilerModelManager, return); QTC_ASSERT(d->profilerState, return); - //Utils::FancyMainWindow *mw = AnalyzerManager::mainWindow(); + //Utils::FancyMainWindow *mw = Debugger::mainWindow(); d->traceView = new QmlProfilerTraceView(0, this, d->profilerModelManager); d->traceView->setWindowTitle(tr("Timeline")); @@ -90,12 +91,12 @@ void QmlProfilerViewManager::createViews() this, &QmlProfilerViewManager::typeSelected); connect(this, &QmlProfilerViewManager::typeSelected, d->traceView, &QmlProfilerTraceView::selectByTypeId); - AnalyzerManager::registerDockWidget(Constants::QmlProfilerTimelineDockId, d->traceView); new QmlProfilerStateWidget(d->profilerState, d->profilerModelManager, d->traceView); - Perspective perspective; - perspective.addOperation({Constants::QmlProfilerTimelineDockId, Core::Id(), + Utils::Perspective perspective; + perspective.setName(tr("QML Profiler")); + perspective.addOperation({Constants::QmlProfilerTimelineDockId, d->traceView, {}, Perspective::SplitVertical}); d->eventsViews << new QmlProfilerStatisticsView(0, d->profilerModelManager); @@ -118,19 +119,17 @@ void QmlProfilerViewManager::createViews() this, &QmlProfilerViewManager::gotoSourceLocation); connect(view, &QmlProfilerEventsView::showFullRange, this, [this](){restrictEventsToRange(-1, -1);}); - Core::Id dockId = Core::Id::fromString(view->objectName()); - AnalyzerManager::registerDockWidget(dockId, view); - perspective.addOperation({dockId, Constants::QmlProfilerTimelineDockId, Perspective::AddToTab}); + QByteArray dockId = view->objectName().toLatin1(); + perspective.addOperation({dockId, view, Constants::QmlProfilerTimelineDockId, Perspective::AddToTab}); new QmlProfilerStateWidget(d->profilerState, d->profilerModelManager, view); - if (!settings->contains(view->parent()->objectName())) // parent() is QDockWidget. - settings->remove(QString()); +// if (!settings->contains(view->parent()->objectName())) // parent() is QDockWidget. +// settings->remove(QString()); } - AnalyzerManager::registerPerspective(Constants::QmlProfilerPerspectiveId, perspective); + perspective.addOperation({Constants::QmlProfilerTimelineDockId, 0, {}, Perspective::Raise}); + Debugger::registerPerspective(Constants::QmlProfilerPerspectiveId, perspective); settings->endGroup(); - QTC_ASSERT(qobject_cast(d->traceView->parentWidget()), return); - d->traceView->parentWidget()->raise(); } bool QmlProfilerViewManager::hasValidSelection() const diff --git a/src/plugins/qmlprofilerextension/FlameGraphDetails.qml b/src/plugins/qmlprofilerextension/FlameGraphDetails.qml new file mode 100644 index 00000000000..2875d114af3 --- /dev/null +++ b/src/plugins/qmlprofilerextension/FlameGraphDetails.qml @@ -0,0 +1,211 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +import QtQuick 2.1 + +Item { + id: rangeDetails + + property color titleBarColor: "#55a3b8" + property color titleBarTextColor: "white" + property color contentColor: "white" + property color contentTextColor: "black" + property color borderColor: "#a0a0a0" + property color noteTextColor: "orange" + + property real titleBarHeight: 20 + property real borderWidth: 1 + property real outerMargin: 10 + property real innerMargin: 5 + property real minimumInnerWidth: 150 + property real initialWidth: 300 + + property real minimumX + property real maximumX + property real minimumY + property real maximumY + + property string dialogTitle + property var model + property string note + + signal clearSelection + + visible: dialogTitle.length > 0 || model.length > 0 + + width: dragHandle.x + dragHandle.width + height: contentArea.height + titleBar.height + + onMinimumXChanged: x = Math.max(x, minimumX) + onMaximumXChanged: x = Math.min(x, Math.max(minimumX, maximumX - width)) + onMinimumYChanged: y = Math.max(y, minimumY) + onMaximumYChanged: y = Math.min(y, Math.max(minimumY, maximumY - height)) + + MouseArea { + anchors.fill: parent + drag.target: parent + drag.minimumX: parent.minimumX + drag.maximumX: parent.maximumX - rangeDetails.width + drag.minimumY: parent.minimumY + drag.maximumY: parent.maximumY - rangeDetails.height + } + + Rectangle { + id: titleBar + width: parent.width + height: titleBarHeight + color: titleBarColor + border.width: borderWidth + border.color: borderColor + + FlameGraphText { + id: typeTitle + text: rangeDetails.dialogTitle + font.bold: true + verticalAlignment: Text.AlignVCenter + anchors.left: parent.left + anchors.right: closeIcon.left + anchors.leftMargin: outerMargin + anchors.rightMargin: innerMargin + anchors.top: parent.top + anchors.bottom: parent.bottom + color: titleBarTextColor + elide: Text.ElideRight + } + + FlameGraphText { + id: closeIcon + anchors.right: parent.right + anchors.top: parent.top + anchors.bottom: parent.bottom + anchors.rightMargin: innerMargin + verticalAlignment: Text.AlignVCenter + text: "X" + color: titleBarTextColor + MouseArea { + anchors.fill: parent + onClicked: rangeDetails.clearSelection() + } + } + } + + Rectangle { + id: contentArea + color: contentColor + + anchors.top: titleBar.bottom + anchors.left: parent.left + anchors.right: parent.right + anchors.bottom: dragHandle.bottom + + border.width: borderWidth + border.color: borderColor + } + + Grid { + id: col + + anchors.left: parent.left + anchors.top: titleBar.bottom + anchors.topMargin: innerMargin + anchors.leftMargin: outerMargin + anchors.rightMargin: outerMargin + + spacing: innerMargin + columns: 2 + property int minimumWidth: { + var result = minimumInnerWidth; + for (var i = 0; i < children.length; ++i) + result = Math.max(children[i].x, result); + return result + 2 * outerMargin; + } + + onMinimumWidthChanged: { + if (dragHandle.x < minimumWidth) + dragHandle.x = minimumWidth; + } + + Repeater { + model: rangeDetails.model + FlameGraphText { + property bool isLabel: index % 2 === 0 + font.bold: isLabel + elide: Text.ElideRight + width: text === "" ? 0 : (isLabel ? implicitWidth : + (dragHandle.x - x - innerMargin)) + text: isLabel ? (modelData + ":") : modelData + color: contentTextColor + } + } + } + + + TextEdit { + id: noteEdit + + anchors.left: parent.left + anchors.right: parent.right + anchors.leftMargin: outerMargin + anchors.rightMargin: outerMargin + anchors.topMargin: visible ? innerMargin : 0 + anchors.top: col.bottom + height: visible ? implicitHeight : 0 + + readOnly: true + visible: text.length > 0 + text: note + wrapMode: Text.Wrap + color: noteTextColor + font.italic: true + font.pixelSize: typeTitle.font.pixelSize + font.family: typeTitle.font.family + renderType: typeTitle.renderType + selectByMouse: true + } + + Item { + id: dragHandle + width: outerMargin + height: outerMargin + x: initialWidth + anchors.top: noteEdit.bottom + clip: true + MouseArea { + anchors.fill: parent + drag.target: parent + drag.minimumX: col.minimumWidth + drag.axis: Drag.XAxis + cursorShape: Qt.SizeHorCursor + } + Rectangle { + color: titleBarColor + rotation: 45 + width: parent.width * Math.SQRT2 + height: parent.height * Math.SQRT2 + x: parent.width - width / 2 + y: parent.height - height / 2 + } + } +} diff --git a/src/plugins/qmlprofilerextension/FlameGraphView.qml b/src/plugins/qmlprofilerextension/FlameGraphView.qml index eacc7ccb090..e834d1fad27 100644 --- a/src/plugins/qmlprofilerextension/FlameGraphView.qml +++ b/src/plugins/qmlprofilerextension/FlameGraphView.qml @@ -51,6 +51,9 @@ ScrollView { property color blue2: Qt.rgba(0.375, 0, 1, 1) property color grey1: "#B0B0B0" property color grey2: "#A0A0A0" + property color orange: "orange" + + function checkBindingLoop(otherTypeId) {return false;} id: flamegraph width: parent.width @@ -62,26 +65,40 @@ ScrollView { delegate: Item { id: flamegraphItem + + property int typeId: FlameGraph.data(FlameGraphModel.TypeId) || -1 + property bool isBindingLoop: parent.checkBindingLoop(typeId) property int level: parent.level + (rangeTypeVisible ? 1 : 0) - property bool isSelected: FlameGraph.data(FlameGraphModel.TypeId) === - root.selectedTypeId + property bool isSelected: typeId !== -1 && typeId === root.selectedTypeId property bool rangeTypeVisible: root.visibleRangeTypes & (1 << FlameGraph.data(FlameGraphModel.RangeType)) onIsSelectedChanged: { if (isSelected && (tooltip.selectedNode === null || - tooltip.selectedNode.FlameGraph.data(FlameGraphModel.TypeId) !== - root.selectedTypeId)) { + tooltip.selectedNode.typeId !== root.selectedTypeId)) { tooltip.selectedNode = flamegraphItem; } else if (!isSelected && tooltip.selectedNode === flamegraphItem) { tooltip.selectedNode = null; } } + function checkBindingLoop(otherTypeId) { + if (typeId === otherTypeId) { + isBindingLoop = true; + return true; + } else { + return parent.checkBindingLoop(otherTypeId); + } + } + + // Functions, not properties to limit the initial overhead when creating the nodes, + // and because FlameGraph.data(...) cannot be notified anyway. + function title() { return FlameGraph.data(FlameGraphModel.Type) || ""; } + function note() { return FlameGraph.data(FlameGraphModel.Note) || ""; } function details() { var model = []; function addDetail(name, index, format) { - model.push(name + ":"); + model.push(name); model.push(format(FlameGraph.data(index))); } @@ -108,7 +125,7 @@ ScrollView { } if (!FlameGraph.dataValid) { - model.push(qsTr("Details") + ":"); + model.push(qsTr("Details")); model.push(qsTr("Various Events")); } else { addDetail(qsTr("Details"), FlameGraphModel.Details, noop); @@ -118,7 +135,7 @@ ScrollView { addDetail(qsTr("Mean Time"), FlameGraphModel.TimePerCall, printTime); addDetail(qsTr("In Percent"), FlameGraphModel.TimeInPercent, addPercent); - + addDetail(qsTr("Location"), FlameGraphModel.Location, noop); } return model; } @@ -129,11 +146,21 @@ ScrollView { return flamegraph.blue2; else if (tooltip.hoveredNode === flamegraphItem) return flamegraph.blue1; + else if (flamegraphItem.note() !== "" || flamegraphItem.isBindingLoop) + return flamegraph.orange; else - return flamegraph.grey1 + return flamegraph.grey1; + } + border.width: { + if (tooltip.hoveredNode === flamegraphItem || + tooltip.selectedNode === flamegraphItem) { + return 2; + } else if (flamegraphItem.note() !== "") { + return 3; + } else { + return 1; + } } - border.width: (tooltip.hoveredNode === flamegraphItem || - tooltip.selectedNode === flamegraphItem) ? 2 : 1 color: Qt.hsla((level % 12) / 72, 0.9 + Math.random() / 10, 0.45 + Math.random() / 10, 0.9 + Math.random() / 10); height: flamegraphItem.rangeTypeVisible ? flamegraph.itemHeight : 0; @@ -198,59 +225,56 @@ ScrollView { } } - Rectangle { - color: "white" - border.width: 1 - border.color: flamegraph.grey2 - width: tooltip.model.length > 0 ? tooltip.width + 10 : 0 - height: tooltip.model.length > 0 ? tooltip.height + 10 : 0 - y: flickable.contentY - x: anchorRight ? parent.width - width : 0 - property bool anchorRight: true + FlameGraphDetails { + id: tooltip - Grid { - id: tooltip - anchors.margins: 5 - anchors.top: parent.top - anchors.left: parent.left - spacing: 5 - columns: 2 - property var hoveredNode: null; - property var selectedNode: null; - property var model: { - if (flameGraphModel.rowCount() === 0) - return [ qsTr("No data available") ]; - else if (hoveredNode !== null) - return hoveredNode.details(); - else if (selectedNode !== null) - return selectedNode.details(); - else - return []; - } + minimumX: 0 + maximumX: flickable.width + minimumY: flickable.contentY + maximumY: flickable.contentY + flickable.height - Connections { - target: flameGraphModel - onModelReset: { - tooltip.hoveredNode = null; - tooltip.selectedNode = null; - } - } + property var hoveredNode: null; + property var selectedNode: null; - Repeater { - model: parent.model - FlameGraphText { - text: modelData - font.bold: (index % 2) === 0 - width: Math.min(implicitWidth, 200) - elide: Text.ElideRight - } - } + property var currentNode: { + if (hoveredNode !== null) + return hoveredNode; + else if (selectedNode !== null) + return selectedNode; + else + return null; } - MouseArea { - anchors.fill: parent - hoverEnabled: true - onEntered: parent.anchorRight = !parent.anchorRight + onClearSelection: { + selectedTypeId = -1; + selectedNode = null; + root.typeSelected(-1); + } + + dialogTitle: { + if (currentNode) + return currentNode.title(); + else if (flameGraphModel.rowCount() === 0) + return qsTr("No data available"); + else + return ""; + } + + model: currentNode ? currentNode.details() : [] + note: currentNode ? currentNode.note() : "" + + Connections { + target: flameGraphModel + onModelReset: { + tooltip.hoveredNode = null; + tooltip.selectedNode = null; + } + onDataChanged: { + // refresh to trigger reevaluation of note + var selectedNode = tooltip.selectedNode; + tooltip.selectedNode = null; + tooltip.selectedNode = selectedNode; + } } } } diff --git a/src/plugins/qmlprofilerextension/flamegraph.qrc b/src/plugins/qmlprofilerextension/flamegraph.qrc index abf7393f4e0..425590b257e 100644 --- a/src/plugins/qmlprofilerextension/flamegraph.qrc +++ b/src/plugins/qmlprofilerextension/flamegraph.qrc @@ -2,5 +2,6 @@ FlameGraphView.qml FlameGraphText.qml + FlameGraphDetails.qml diff --git a/src/plugins/qmlprofilerextension/flamegraphmodel.cpp b/src/plugins/qmlprofilerextension/flamegraphmodel.cpp index e181a66109d..a6a0abeb2f4 100644 --- a/src/plugins/qmlprofilerextension/flamegraphmodel.cpp +++ b/src/plugins/qmlprofilerextension/flamegraphmodel.cpp @@ -96,24 +96,8 @@ void FlameGraphModel::loadNotes(int typeIndex, bool emitSignal) m_typeIdsWithNotes.insert(typeIndex); } - if (!emitSignal) - return; - - QQueue queue; - queue.append(QModelIndex()); - - QVector roles = {Note}; - while (!queue.isEmpty()) { - QModelIndex index = queue.takeFirst(); - if (index.isValid()) { - FlameGraphData *data = static_cast(index.internalPointer()); - if (changedNotes.contains(data->typeIndex)) - emit dataChanged(index, index, roles); - for (int row = 0; row < rowCount(index); ++row) - queue.append(index.child(row, 0)); - } - - } + if (emitSignal) + emit dataChanged(QModelIndex(), QModelIndex(), QVector() << Note); } void FlameGraphModel::loadData(qint64 rangeStart, qint64 rangeEnd) @@ -203,9 +187,9 @@ QVariant FlameGraphModel::lookup(const FlameGraphData &stats, int role) const QmlProfiler::QmlProfilerNotesModel *notes = m_modelManager->notesModel(); foreach (const QVariant &item, notes->byTypeId(stats.typeIndex)) { if (ret.isEmpty()) - ret = item.toString(); + ret = notes->text(item.toInt()); else - ret += QChar::LineFeed + item.toString(); + ret += QChar::LineFeed + notes->text(item.toInt()); } return ret; } @@ -229,6 +213,7 @@ QVariant FlameGraphModel::lookup(const FlameGraphData &stats, int role) const case RangeType: return type.rangeType; case Details: return type.data.isEmpty() ? FlameGraphModel::tr("Source code not available") : type.data; + case Location: return type.displayName; default: return QVariant(); } } else { diff --git a/src/plugins/qmlprofilerextension/flamegraphmodel.h b/src/plugins/qmlprofilerextension/flamegraphmodel.h index 38d04743fe2..e3e49b77a1c 100644 --- a/src/plugins/qmlprofilerextension/flamegraphmodel.h +++ b/src/plugins/qmlprofilerextension/flamegraphmodel.h @@ -68,6 +68,7 @@ public: TimePerCall, TimeInPercent, RangeType, + Location, MaxRole }; diff --git a/src/plugins/qnx/qnxanalyzesupport.cpp b/src/plugins/qnx/qnxanalyzesupport.cpp index e25dcd58550..289d7d1756a 100644 --- a/src/plugins/qnx/qnxanalyzesupport.cpp +++ b/src/plugins/qnx/qnxanalyzesupport.cpp @@ -45,7 +45,7 @@ namespace Qnx { namespace Internal { QnxAnalyzeSupport::QnxAnalyzeSupport(QnxRunConfiguration *runConfig, - Analyzer::AnalyzerRunControl *runControl) + Debugger::AnalyzerRunControl *runControl) : QnxAbstractRunSupport(runConfig, runControl) , m_runnable(runConfig->runnable().as()) , m_runControl(runControl) @@ -65,7 +65,7 @@ QnxAnalyzeSupport::QnxAnalyzeSupport(QnxRunConfiguration *runConfig, connect(runner, &DeviceApplicationRunner::remoteStderr, this, &QnxAnalyzeSupport::handleRemoteOutput); - connect(m_runControl, &Analyzer::AnalyzerRunControl::starting, + connect(m_runControl, &Debugger::AnalyzerRunControl::starting, this, &QnxAnalyzeSupport::handleAdapterSetupRequested); connect(&m_outputParser, &QmlDebug::QmlOutputParser::waitingForConnectionOnPort, this, &QnxAnalyzeSupport::remoteIsRunning); diff --git a/src/plugins/qnx/qnxanalyzesupport.h b/src/plugins/qnx/qnxanalyzesupport.h index 6dbb23c0996..d1361fff3a8 100644 --- a/src/plugins/qnx/qnxanalyzesupport.h +++ b/src/plugins/qnx/qnxanalyzesupport.h @@ -32,7 +32,7 @@ #include #include -namespace Analyzer { class AnalyzerRunControl; } +namespace Debugger { class AnalyzerRunControl; } namespace Qnx { namespace Internal { @@ -44,7 +44,7 @@ class QnxAnalyzeSupport : public QnxAbstractRunSupport { Q_OBJECT public: - QnxAnalyzeSupport(QnxRunConfiguration *runConfig, Analyzer::AnalyzerRunControl *engine); + QnxAnalyzeSupport(QnxRunConfiguration *runConfig, Debugger::AnalyzerRunControl *engine); public slots: void handleProfilingFinished(); @@ -66,7 +66,7 @@ private: void startExecution(); ProjectExplorer::StandardRunnable m_runnable; - Analyzer::AnalyzerRunControl *m_runControl; + Debugger::AnalyzerRunControl *m_runControl; QmlDebug::QmlOutputParser m_outputParser; int m_qmlPort; diff --git a/src/plugins/qnx/qnxruncontrolfactory.cpp b/src/plugins/qnx/qnxruncontrolfactory.cpp index cf38795e862..0b95af65b1e 100644 --- a/src/plugins/qnx/qnxruncontrolfactory.cpp +++ b/src/plugins/qnx/qnxruncontrolfactory.cpp @@ -48,7 +48,6 @@ #include #include -using namespace Analyzer; using namespace Debugger; using namespace ProjectExplorer; using namespace Qnx; @@ -142,7 +141,7 @@ RunControl *QnxRunControlFactory::create(RunConfiguration *runConfig, Core::Id m const IDevice::ConstPtr device = DeviceKitInformation::device(kit); if (device.isNull()) return 0; - AnalyzerRunControl *runControl = AnalyzerManager::createRunControl(runConfig, mode); + AnalyzerRunControl *runControl = Debugger::createAnalyzerRunControl(runConfig, mode); QTC_ASSERT(runControl, return 0); runControl->setRunnable(runConfig->runnable()); AnalyzerConnection connection; diff --git a/src/plugins/qtsupport/qscxmlcgenerator.cpp b/src/plugins/qtsupport/qscxmlcgenerator.cpp index 9d0cc258ba6..1dfe222c351 100644 --- a/src/plugins/qtsupport/qscxmlcgenerator.cpp +++ b/src/plugins/qtsupport/qscxmlcgenerator.cpp @@ -42,13 +42,10 @@ static const char TaskCategory[] = "Task.Category.ExtraCompiler.QScxmlc"; QScxmlcGenerator::QScxmlcGenerator(const ProjectExplorer::Project *project, const Utils::FileName &source, const Utils::FileNameList &targets, QObject *parent) : - ProjectExplorer::ExtraCompiler(project, source, targets, parent) -{ - connect(&m_process, static_cast(&QProcess::finished), - this, &QScxmlcGenerator::finishProcess); -} + ProjectExplorer::ProcessExtraCompiler(project, source, targets, parent) +{ } -void QScxmlcGenerator::parseIssues(const QByteArray &processStderr) +QList QScxmlcGenerator::parseIssues(const QByteArray &processStderr) { QList issues; foreach (const QByteArray &line, processStderr.split('\n')) { @@ -64,30 +61,13 @@ void QScxmlcGenerator::parseIssues(const QByteArray &processStderr) issues.append(ProjectExplorer::Task(type, message, file, line, TaskCategory)); } } - setCompileIssues(issues); + return issues; } -void QScxmlcGenerator::finishProcess() + +Utils::FileName QScxmlcGenerator::command() const { - parseIssues(m_process.readAllStandardError()); - - setCompileTime(QDateTime::currentDateTime()); - foreach (const Utils::FileName &target, targets()) { - QFile generated(m_tmpdir.path() + QLatin1Char('/') + target.fileName()); - if (!generated.open(QIODevice::ReadOnly)) - continue; - setContent(target, generated.readAll()); - } -} - -void QScxmlcGenerator::run(const QByteArray &sourceContent) -{ - if (m_process.state() != QProcess::NotRunning) { - m_process.kill(); - m_process.waitForFinished(3000); - } - - QtSupport::BaseQtVersion *version = 0; + QtSupport::BaseQtVersion *version = nullptr; ProjectExplorer::Target *target; if ((target = project()->activeTarget())) version = QtSupport::QtKitInformation::qtVersion(target->kit()); @@ -95,28 +75,61 @@ void QScxmlcGenerator::run(const QByteArray &sourceContent) version = QtSupport::QtKitInformation::qtVersion(ProjectExplorer::KitManager::defaultKit()); if (!version) - return; + return Utils::FileName(); - const QString generator = version->qscxmlcCommand(); - if (!QFileInfo(generator).isExecutable()) - return; + return Utils::FileName::fromString(version->qscxmlcCommand()); +} - m_process.setProcessEnvironment(buildEnvironment().toProcessEnvironment()); - m_process.setWorkingDirectory(m_tmpdir.path()); +QStringList QScxmlcGenerator::arguments() const +{ + QTC_ASSERT(targets().count() == 2, return QStringList()); - QFile input(m_tmpdir.path() + QLatin1Char('/') + source().fileName()); + const Utils::FileName fn = tmpFile(); + const QString header = m_tmpdir.path() + QLatin1Char('/') + targets()[0].fileName(); + const QString impl = m_tmpdir.path() + QLatin1Char('/') + targets()[1].fileName(); + + return QStringList({ QLatin1String("--header"), header, QLatin1String("--impl"), impl, + fn.fileName() }); +} + +Utils::FileName QScxmlcGenerator::workingDirectory() const +{ + return Utils::FileName::fromString(m_tmpdir.path()); +} + +bool QScxmlcGenerator::prepareToRun(const QByteArray &sourceContents) +{ + const Utils::FileName fn = tmpFile(); + QFile input(fn.toString()); if (!input.open(QIODevice::WriteOnly)) - return; - input.write(sourceContent); + return false; + input.write(sourceContents); input.close(); - qCDebug(log) << " QScxmlcGenerator::run " << generator << " on " - << sourceContent.size() << " bytes"; + return true; +} - m_process.start(generator, QStringList({ - QLatin1String("-oh"), m_tmpdir.path() + QLatin1Char('/') + targets()[0].fileName(), - QLatin1String("-ocpp"), m_tmpdir.path() + QLatin1Char('/') + targets()[1].fileName(), - input.fileName()})); +QList QScxmlcGenerator::handleProcessFinished(QProcess *process) +{ + Q_UNUSED(process); + const Utils::FileName wd = workingDirectory(); + QList result; + foreach (const Utils::FileName &target, targets()) { + Utils::FileName file = wd; + file.appendPath(target.fileName()); + QFile generated(file.toString()); + if (!generated.open(QIODevice::ReadOnly)) + continue; + result << generated.readAll(); + } + return result; +} + +Utils::FileName QScxmlcGenerator::tmpFile() const +{ + Utils::FileName wd = workingDirectory(); + wd.appendPath(source().fileName()); + return wd; } ProjectExplorer::FileType QScxmlcGeneratorFactory::sourceType() const diff --git a/src/plugins/qtsupport/qscxmlcgenerator.h b/src/plugins/qtsupport/qscxmlcgenerator.h index 9a305996e70..cb375999c64 100644 --- a/src/plugins/qtsupport/qscxmlcgenerator.h +++ b/src/plugins/qtsupport/qscxmlcgenerator.h @@ -33,20 +33,25 @@ namespace QtSupport { -class QScxmlcGenerator : public ProjectExplorer::ExtraCompiler +class QScxmlcGenerator : public ProjectExplorer::ProcessExtraCompiler { Q_OBJECT public: QScxmlcGenerator(const ProjectExplorer::Project *project, const Utils::FileName &source, const Utils::FileNameList &targets, QObject *parent = 0); -private: - void finishProcess(); - void run(const QByteArray &sourceContent) override; +protected: + Utils::FileName command() const override; + QStringList arguments() const override; + Utils::FileName workingDirectory() const override; + +private: + Utils::FileName tmpFile() const; + QList handleProcessFinished(QProcess *process) override; + bool prepareToRun(const QByteArray &sourceContents) override; + QList parseIssues(const QByteArray &processStderr) override; - QProcess m_process; QTemporaryDir m_tmpdir; - void parseIssues(const QByteArray &processStderr); }; class QScxmlcGeneratorFactory : public ProjectExplorer::ExtraCompilerFactory diff --git a/src/plugins/qtsupport/uicgenerator.cpp b/src/plugins/qtsupport/uicgenerator.cpp index 33818d01b43..7c8fe71e6ac 100644 --- a/src/plugins/qtsupport/uicgenerator.cpp +++ b/src/plugins/qtsupport/uicgenerator.cpp @@ -39,43 +39,14 @@ namespace QtSupport { -QLoggingCategory UicGenerator::m_log("qtc.uicgenerator"); - UicGenerator::UicGenerator(const ProjectExplorer::Project *project, const Utils::FileName &source, const Utils::FileNameList &targets, QObject *parent) : - ProjectExplorer::ExtraCompiler(project, source, targets, parent) + ProjectExplorer::ProcessExtraCompiler(project, source, targets, parent) +{ } + +Utils::FileName UicGenerator::command() const { - connect(&m_process, static_cast(&QProcess::finished), - this, &UicGenerator::finishProcess); -} - -void UicGenerator::finishProcess() -{ - if (!m_process.waitForFinished(3000) - && m_process.exitStatus() != QProcess::NormalExit - && m_process.exitCode() != 0) { - - qCDebug(m_log) << "finish process: failed" << m_process.readAllStandardError(); - m_process.kill(); - return; - } - - // As far as I can discover in the UIC sources, it writes out local 8-bit encoding. The - // conversion below is to normalize both the encoding, and the line terminators. - QByteArray normalized = QString::fromLocal8Bit(m_process.readAllStandardOutput()).toUtf8(); - qCDebug(m_log) << "finish process: ok" << normalized.size() << "bytes."; - setCompileTime(QDateTime::currentDateTime()); - setContent(targets()[0], normalized); -} - -void UicGenerator::run(const QByteArray &sourceContent) -{ - if (m_process.state() != QProcess::NotRunning) { - m_process.kill(); - m_process.waitForFinished(3000); - } - - QtSupport::BaseQtVersion *version = 0; + QtSupport::BaseQtVersion *version = nullptr; ProjectExplorer::Target *target; if ((target = project()->activeTarget())) version = QtSupport::QtKitInformation::qtVersion(target->kit()); @@ -83,28 +54,25 @@ void UicGenerator::run(const QByteArray &sourceContent) version = QtSupport::QtKitInformation::qtVersion(ProjectExplorer::KitManager::defaultKit()); if (!version) - return; + return Utils::FileName(); - const QString generator = version->uicCommand(); - if (generator.isEmpty()) - return; + return Utils::FileName::fromString(version->uicCommand()); +} - m_process.setProcessEnvironment(buildEnvironment().toProcessEnvironment()); +void UicGenerator::handleProcessStarted(QProcess *process, const QByteArray &sourceContents) +{ + process->write(sourceContents); + process->closeWriteChannel(); +} - qCDebug(m_log) << " UicGenerator::run " << generator << " on " - << sourceContent.size() << " bytes"; - m_process.start(generator, QStringList(), QIODevice::ReadWrite); - if (!m_process.waitForStarted()) - return; +QList UicGenerator::handleProcessFinished(QProcess *process) +{ + if (process->exitStatus() != QProcess::NormalExit && process->exitCode() != 0) + return QList(); - m_process.write(sourceContent); - if (!m_process.waitForBytesWritten(3000)) { - qCDebug(m_log) << "failed" << m_process.readAllStandardError(); - m_process.kill(); - return; - } - - m_process.closeWriteChannel(); + // As far as I can discover in the UIC sources, it writes out local 8-bit encoding. The + // conversion below is to normalize both the encoding, and the line terminators. + return { QString::fromLocal8Bit(process->readAllStandardOutput()).toUtf8() }; } ProjectExplorer::FileType UicGeneratorFactory::sourceType() const diff --git a/src/plugins/qtsupport/uicgenerator.h b/src/plugins/qtsupport/uicgenerator.h index 9b3b1d7d58f..e51281606ee 100644 --- a/src/plugins/qtsupport/uicgenerator.h +++ b/src/plugins/qtsupport/uicgenerator.h @@ -33,20 +33,17 @@ namespace QtSupport { -class UicGenerator : public ProjectExplorer::ExtraCompiler +class UicGenerator : public ProjectExplorer::ProcessExtraCompiler { Q_OBJECT public: UicGenerator(const ProjectExplorer::Project *project, const Utils::FileName &source, const Utils::FileNameList &targets, QObject *parent = 0); -private slots: - void finishProcess(); - void run(const QByteArray &sourceContent) override; - -private: - QProcess m_process; - static QLoggingCategory m_log; +protected: + Utils::FileName command() const override; + void handleProcessStarted(QProcess *process, const QByteArray &sourceContents) override; + QList handleProcessFinished(QProcess *process) override; }; class UicGeneratorFactory : public ProjectExplorer::ExtraCompilerFactory diff --git a/src/plugins/remotelinux/remotelinuxanalyzesupport.cpp b/src/plugins/remotelinux/remotelinuxanalyzesupport.cpp index 0e88bea8736..e63baf8949c 100644 --- a/src/plugins/remotelinux/remotelinuxanalyzesupport.cpp +++ b/src/plugins/remotelinux/remotelinuxanalyzesupport.cpp @@ -45,7 +45,7 @@ #include using namespace QSsh; -using namespace Analyzer; +using namespace Debugger; using namespace ProjectExplorer; using namespace Utils; diff --git a/src/plugins/remotelinux/remotelinuxanalyzesupport.h b/src/plugins/remotelinux/remotelinuxanalyzesupport.h index 9f69296a16d..de083d38bce 100644 --- a/src/plugins/remotelinux/remotelinuxanalyzesupport.h +++ b/src/plugins/remotelinux/remotelinuxanalyzesupport.h @@ -33,7 +33,7 @@ #include -namespace Analyzer { class AnalyzerRunControl; } +namespace Debugger { class AnalyzerRunControl; } namespace RemoteLinux { @@ -44,7 +44,7 @@ class REMOTELINUX_EXPORT RemoteLinuxAnalyzeSupport : public AbstractRemoteLinuxR Q_OBJECT public: RemoteLinuxAnalyzeSupport(ProjectExplorer::RunConfiguration *runConfig, - Analyzer::AnalyzerRunControl *engine, Core::Id runMode); + Debugger::AnalyzerRunControl *engine, Core::Id runMode); ~RemoteLinuxAnalyzeSupport(); protected: diff --git a/src/plugins/remotelinux/remotelinuxruncontrolfactory.cpp b/src/plugins/remotelinux/remotelinuxruncontrolfactory.cpp index 42158d46178..3439c977b4b 100644 --- a/src/plugins/remotelinux/remotelinuxruncontrolfactory.cpp +++ b/src/plugins/remotelinux/remotelinuxruncontrolfactory.cpp @@ -48,7 +48,6 @@ #include #include -using namespace Analyzer; using namespace Debugger; using namespace ProjectExplorer; @@ -139,7 +138,7 @@ RunControl *RemoteLinuxRunControlFactory::create(RunConfiguration *runConfig, Co } if (mode == ProjectExplorer::Constants::QML_PROFILER_RUN_MODE) { - auto runControl = AnalyzerManager::createRunControl(runConfig, mode); + auto runControl = Debugger::createAnalyzerRunControl(runConfig, mode); AnalyzerConnection connection; connection.connParams = DeviceKitInformation::device(runConfig->target()->kit())->sshParameters(); diff --git a/src/plugins/valgrind/callgrind/callgrindcontroller.cpp b/src/plugins/valgrind/callgrind/callgrindcontroller.cpp index 0b1503ff8bc..9e2344d1530 100644 --- a/src/plugins/valgrind/callgrind/callgrindcontroller.cpp +++ b/src/plugins/valgrind/callgrind/callgrindcontroller.cpp @@ -128,7 +128,7 @@ void CallgrindController::run(Option option) const int pid = Utils::HostOsInfo::isWindowsHost() ? 0 : m_valgrindProc->pid(); m_process->setValgrindExecutable(CALLGRIND_CONTROL_BINARY); m_process->setValgrindArguments(QStringList() << optionString << QString::number(pid)); - m_process->run(); + m_process->run(ProjectExplorer::ApplicationLauncher::Gui); } void CallgrindController::processError(QProcess::ProcessError) diff --git a/src/plugins/valgrind/callgrindengine.cpp b/src/plugins/valgrind/callgrindengine.cpp index b3a9a183c0b..cc7e41ac0db 100644 --- a/src/plugins/valgrind/callgrindengine.cpp +++ b/src/plugins/valgrind/callgrindengine.cpp @@ -35,7 +35,7 @@ #include -using namespace Analyzer; +using namespace Debugger; using namespace Valgrind; using namespace Valgrind::Internal; @@ -48,7 +48,7 @@ CallgrindRunControl::CallgrindRunControl(ProjectExplorer::RunConfiguration *runC connect(m_runner.parser(), &Callgrind::Parser::parserDataReady, this, &CallgrindRunControl::slotFinished); connect(&m_runner, &Callgrind::CallgrindRunner::statusMessage, - this, &AnalyzerManager::showPermanentStatusMessage); + this, &Debugger::showPermanentStatusMessage); } QStringList CallgrindRunControl::toolArguments() const @@ -89,10 +89,10 @@ ValgrindRunner * CallgrindRunControl::runner() return &m_runner; } -bool CallgrindRunControl::startEngine() +void CallgrindRunControl::start() { appendMessage(tr("Profiling %1").arg(executable()) + QLatin1Char('\n'), Utils::NormalMessageFormat); - return ValgrindRunControl::startEngine(); + return ValgrindRunControl::start(); } void CallgrindRunControl::dump() diff --git a/src/plugins/valgrind/callgrindengine.h b/src/plugins/valgrind/callgrindengine.h index 87da36fd146..19e91a95b41 100644 --- a/src/plugins/valgrind/callgrindengine.h +++ b/src/plugins/valgrind/callgrindengine.h @@ -41,7 +41,7 @@ class CallgrindRunControl : public ValgrindRunControl public: CallgrindRunControl(ProjectExplorer::RunConfiguration *runConfiguration); - bool startEngine() override; + void start() override; Valgrind::Callgrind::ParseData *takeParserData(); diff --git a/src/plugins/valgrind/callgrindtool.cpp b/src/plugins/valgrind/callgrindtool.cpp index fb416135ed4..d13659146e2 100644 --- a/src/plugins/valgrind/callgrindtool.cpp +++ b/src/plugins/valgrind/callgrindtool.cpp @@ -43,6 +43,7 @@ #include #include +#include #include #include #include @@ -90,11 +91,12 @@ #include #include -using namespace Analyzer; +using namespace Debugger; using namespace Core; using namespace Valgrind::Callgrind; using namespace TextEditor; using namespace ProjectExplorer; +using namespace Utils; namespace Valgrind { namespace Internal { @@ -108,7 +110,6 @@ public: ~CallgrindTool(); ValgrindRunControl *createRunControl(RunConfiguration *runConfiguration); - void createWidgets(); void setParseData(ParseData *data); CostDelegate::CostFormat costFormat() const; @@ -164,6 +165,7 @@ public: void editorOpened(IEditor *); void requestContextMenu(TextEditorWidget *widget, int line, QMenu *menu); + void updateRunActions(); public: DataModel m_dataModel; @@ -200,15 +202,17 @@ public: QVector m_textMarks; + QAction *m_startAction = 0; + QAction *m_stopAction = 0; QAction *m_loadExternalLogFile; QAction *m_dumpAction = 0; QAction *m_resetAction = 0; QAction *m_pauseAction = 0; QString m_toggleCollectFunction; + bool m_toolBusy = false; }; - CallgrindTool::CallgrindTool(QObject *parent) : QObject(parent) { @@ -231,6 +235,9 @@ CallgrindTool::CallgrindTool(QObject *parent) connect(EditorManager::instance(), &EditorManager::editorOpened, this, &CallgrindTool::editorOpened); + m_startAction = Debugger::createStartAction(); + m_stopAction = Debugger::createStopAction(); + ActionDescription desc; desc.setToolTip(tr("Valgrind Function Profile uses the " "Callgrind tool to record function calls when a program runs.")); @@ -243,13 +250,13 @@ CallgrindTool::CallgrindTool(QObject *parent) }); desc.setToolMode(OptimizedMode); desc.setRunMode(CALLGRIND_RUN_MODE); - desc.setMenuGroup(Analyzer::Constants::G_ANALYZER_TOOLS); - AnalyzerManager::registerAction(CallgrindLocalActionId, desc); + desc.setMenuGroup(Debugger::Constants::G_ANALYZER_TOOLS); + Debugger::registerAction(CallgrindLocalActionId, desc, m_startAction); } - desc.setText(tr("Valgrind Function Profiler (External Remote Application)")); + desc.setText(tr("Valgrind Function Profiler (External Application)")); desc.setPerspectiveId(CallgrindPerspectiveId); - desc.setCustomToolStarter([this](ProjectExplorer::RunConfiguration *runConfig) { + desc.setCustomToolStarter([this](RunConfiguration *runConfig) { StartRemoteDialog dlg; if (dlg.exec() != QDialog::Accepted) return; @@ -263,17 +270,17 @@ CallgrindTool::CallgrindTool(QObject *parent) rc->setDisplayName(runnable.executable); ProjectExplorerPlugin::startRunControl(rc, CALLGRIND_RUN_MODE); }); - desc.setMenuGroup(Analyzer::Constants::G_ANALYZER_REMOTE_TOOLS); - AnalyzerManager::registerAction(CallgrindRemoteActionId, desc); + desc.setMenuGroup(Debugger::Constants::G_ANALYZER_REMOTE_TOOLS); + Debugger::registerAction(CallgrindRemoteActionId, desc); // If there is a CppEditor context menu add our own context menu actions. if (ActionContainer *editorContextMenu = ActionManager::actionContainer(CppEditor::Constants::M_CONTEXT)) { - Context analyzerContext = Context(Analyzer::Constants::C_ANALYZEMODE); + Context analyzerContext = Context(Debugger::Constants::C_DEBUGMODE); editorContextMenu->addSeparator(analyzerContext); auto action = new QAction(tr("Profile Costs of This Function and Its Callees"), this); - action->setIcon(Analyzer::Icons::ANALYZER_CONTROL_START.icon()); + action->setIcon(Debugger::Icons::ANALYZER_CONTROL_START.icon()); connect(action, &QAction::triggered, this, &CallgrindTool::handleShowCostsOfFunction); Command *cmd = ActionManager::registerAction(action, "Analyzer.Callgrind.ShowCostsOfFunction", @@ -283,7 +290,214 @@ CallgrindTool::CallgrindTool(QObject *parent) cmd->setAttribute(Command::CA_NonConfigurable); } - createWidgets(); + QSettings *coreSettings = ICore::settings(); + + // + // DockWidgets + // + m_visualization = new Visualisation; + m_visualization->setFrameStyle(QFrame::NoFrame); + m_visualization->setObjectName(QLatin1String("Valgrind.CallgrindTool.Visualisation")); + m_visualization->setWindowTitle(tr("Visualization")); + m_visualization->setModel(&m_dataModel); + connect(m_visualization, &Visualisation::functionActivated, + this, &CallgrindTool::visualisationFunctionSelected); + + m_callersView = new CostView; + m_callersView->setObjectName(QLatin1String("Valgrind.CallgrindTool.CallersView")); + m_callersView->setWindowTitle(tr("Callers")); + m_callersView->setSettings(coreSettings, "Valgrind.CallgrindTool.CallersView"); + m_callersView->sortByColumn(CallModel::CostColumn); + m_callersView->setFrameStyle(QFrame::NoFrame); + // enable sorting + m_callersProxy.setSourceModel(&m_callersModel); + m_callersView->setModel(&m_callersProxy); + m_callersView->hideColumn(CallModel::CalleeColumn); + connect(m_callersView, &QAbstractItemView::activated, + this, &CallgrindTool::callerFunctionSelected); + + m_calleesView = new CostView; + m_calleesView->setObjectName(QLatin1String("Valgrind.CallgrindTool.CalleesView")); + m_calleesView->setWindowTitle(tr("Callees")); + m_calleesView->setSettings(coreSettings, "Valgrind.CallgrindTool.CalleesView"); + m_calleesView->sortByColumn(CallModel::CostColumn); + m_calleesView->setFrameStyle(QFrame::NoFrame); + // enable sorting + m_calleesProxy.setSourceModel(&m_calleesModel); + m_calleesView->setModel(&m_calleesProxy); + m_calleesView->hideColumn(CallModel::CallerColumn); + connect(m_calleesView, &QAbstractItemView::activated, + this, &CallgrindTool::calleeFunctionSelected); + + m_flatView = new CostView; + m_flatView->setObjectName(QLatin1String("Valgrind.CallgrindTool.FlatView")); + m_flatView->setWindowTitle(tr("Functions")); + m_flatView->setSettings(coreSettings, "Valgrind.CallgrindTool.FlatView"); + m_flatView->sortByColumn(DataModel::SelfCostColumn); + m_flatView->setFrameStyle(QFrame::NoFrame); + m_flatView->setAttribute(Qt::WA_MacShowFocusRect, false); + m_flatView->setModel(&m_proxyModel); + connect(m_flatView, &QAbstractItemView::activated, + this, &CallgrindTool::dataFunctionSelected); + + updateCostFormat(); + + // + // Control Widget + // + + // load external log file + auto action = m_loadExternalLogFile = new QAction(this); + action->setIcon(Core::Icons::OPENFILE.icon()); + action->setToolTip(tr("Load External Log File")); + connect(action, &QAction::triggered, this, &CallgrindTool::loadExternalLogFile); + + // dump action + m_dumpAction = action = new QAction(this); + action->setDisabled(true); + action->setIcon(Core::Icons::REDO.icon()); + //action->setText(tr("Dump")); + action->setToolTip(tr("Request the dumping of profile information. This will update the Callgrind visualization.")); + connect(action, &QAction::triggered, this, &CallgrindTool::slotRequestDump); + + // reset action + m_resetAction = action = new QAction(this); + action->setDisabled(true); + action->setIcon(Core::Icons::RELOAD.icon()); + //action->setText(tr("Reset")); + action->setToolTip(tr("Reset all event counters.")); + connect(action, &QAction::triggered, this, &CallgrindTool::resetRequested); + + // pause action + m_pauseAction = action = new QAction(this); + action->setCheckable(true); + action->setIcon(ProjectExplorer::Icons::INTERRUPT_SMALL.icon()); + //action->setText(tr("Ignore")); + action->setToolTip(tr("Pause event logging. No events are counted which will speed up program execution during profiling.")); + connect(action, &QAction::toggled, this, &CallgrindTool::pauseToggled); + + // navigation + // go back + m_goBack = action = new QAction(this); + action->setDisabled(true); + action->setIcon(Core::Icons::PREV.icon()); + action->setToolTip(tr("Go back one step in history. This will select the previously selected item.")); + connect(action, &QAction::triggered, &m_stackBrowser, &StackBrowser::goBack); + + // go forward + m_goNext = action = new QAction(this); + action->setDisabled(true); + action->setIcon(Core::Icons::NEXT.icon()); + action->setToolTip(tr("Go forward one step in history.")); + connect(action, &QAction::triggered, &m_stackBrowser, &StackBrowser::goNext); + + // event selection + m_eventCombo = new QComboBox; + m_eventCombo->setToolTip(tr("Selects which events from the profiling data are shown and visualized.")); + connect(m_eventCombo, static_cast(&QComboBox::currentIndexChanged), + this, &CallgrindTool::setCostEvent); + updateEventCombo(); + + ToolbarDescription toolbar; + toolbar.addAction(m_startAction); + toolbar.addAction(m_stopAction); + toolbar.addAction(m_loadExternalLogFile); + toolbar.addAction(m_dumpAction); + toolbar.addAction(m_resetAction); + toolbar.addAction(m_pauseAction); + toolbar.addAction(m_goBack); + toolbar.addAction(m_goNext); + toolbar.addWidget(new Utils::StyledSeparator); + toolbar.addWidget(m_eventCombo); + + // Cost formatting + { + auto menu = new QMenu; + auto group = new QActionGroup(this); + + // Show costs as absolute numbers + m_costAbsolute = new QAction(tr("Absolute Costs"), this); + m_costAbsolute->setToolTip(tr("Show costs as absolute numbers.")); + m_costAbsolute->setCheckable(true); + m_costAbsolute->setChecked(true); + connect(m_costAbsolute, &QAction::toggled, this, &CallgrindTool::updateCostFormat); + group->addAction(m_costAbsolute); + menu->addAction(m_costAbsolute); + + // Show costs in percentages + m_costRelative = new QAction(tr("Relative Costs"), this); + m_costRelative->setToolTip(tr("Show costs relative to total inclusive cost.")); + m_costRelative->setCheckable(true); + connect(m_costRelative, &QAction::toggled, this, &CallgrindTool::updateCostFormat); + group->addAction(m_costRelative); + menu->addAction(m_costRelative); + + // Show costs relative to parent + m_costRelativeToParent = new QAction(tr("Relative Costs to Parent"), this); + m_costRelativeToParent->setToolTip(tr("Show costs relative to parent functions inclusive cost.")); + m_costRelativeToParent->setCheckable(true); + connect(m_costRelativeToParent, &QAction::toggled, this, &CallgrindTool::updateCostFormat); + group->addAction(m_costRelativeToParent); + menu->addAction(m_costRelativeToParent); + + auto button = new QToolButton; + button->setMenu(menu); + button->setPopupMode(QToolButton::InstantPopup); + button->setText(QLatin1String("$")); + button->setToolTip(tr("Cost Format")); + toolbar.addWidget(button); + } + + ValgrindGlobalSettings *settings = ValgrindPlugin::globalSettings(); + + // Cycle detection + //action = new QAction(QLatin1String("Cycle Detection"), this); ///FIXME: icon + action = m_cycleDetection = new QAction(QLatin1String("O"), this); ///FIXME: icon + action->setToolTip(tr("Enable cycle detection to properly handle recursive or circular function calls.")); + action->setCheckable(true); + connect(action, &QAction::toggled, &m_dataModel, &DataModel::enableCycleDetection); + connect(action, &QAction::toggled, settings, &ValgrindGlobalSettings::setDetectCycles); + + // Shorter template signature + action = m_shortenTemplates = new QAction(QLatin1String("<>"), this); + action->setToolTip(tr("This removes template parameter lists when displaying function names.")); + action->setCheckable(true); + connect(action, &QAction::toggled, &m_dataModel, &DataModel::setShortenTemplates); + connect(action, &QAction::toggled, settings, &ValgrindGlobalSettings::setShortenTemplates); + + // Filtering + action = m_filterProjectCosts = new QAction(tr("Show Project Costs Only"), this); + action->setIcon(Core::Icons::FILTER.icon()); + action->setToolTip(tr("Show only profiling info that originated from this project source.")); + action->setCheckable(true); + connect(action, &QAction::toggled, this, &CallgrindTool::handleFilterProjectCosts); + + // Filter + ///FIXME: find workaround for https://bugreports.qt.io/browse/QTCREATORBUG-3247 + m_searchFilter = new QLineEdit; + m_searchFilter->setPlaceholderText(tr("Filter...")); + connect(m_searchFilter, &QLineEdit::textChanged, + &m_updateTimer, static_cast(&QTimer::start)); + + setCostFormat(settings->costFormat()); + enableCycleDetection(settings->detectCycles()); + + toolbar.addAction(m_cycleDetection); + toolbar.addAction(m_shortenTemplates); + toolbar.addAction(m_filterProjectCosts); + toolbar.addWidget(m_searchFilter); + Debugger::registerToolbar(CallgrindPerspectiveId, toolbar); + + Debugger::registerPerspective(CallgrindPerspectiveId, { tr("Callgrind"), { + { CallgrindFlatDockId, m_flatView, {}, Perspective::SplitVertical }, + { CallgrindCalleesDockId, m_calleesView, {}, Perspective::SplitVertical }, + { CallgrindCallersDockId, m_callersView, CallgrindCalleesDockId, Perspective::SplitHorizontal }, + { CallgrindVisualizationDockId, m_visualization, {}, Perspective::SplitVertical, + false, Qt::RightDockWidgetArea } + }}); + + connect(ProjectExplorerPlugin::instance(), &ProjectExplorerPlugin::updateRunActions, + this, &CallgrindTool::updateRunActions); } CallgrindTool::~CallgrindTool() @@ -521,34 +735,28 @@ void CallgrindTool::updateEventCombo() m_eventCombo->addItem(ParseData::prettyStringForEvent(event)); } -static QToolButton *createToolButton(QAction *action) -{ - QToolButton *button = new QToolButton; - button->setDefaultAction(action); - //button->setToolButtonStyle(Qt::ToolButtonTextBesideIcon); - return button; -} - ValgrindRunControl *CallgrindTool::createRunControl(RunConfiguration *runConfiguration) { - auto rc = new CallgrindRunControl(runConfiguration); + auto runControl = new CallgrindRunControl(runConfiguration); - connect(rc, &CallgrindRunControl::parserDataReady, this, &CallgrindTool::takeParserDataFromRunControl); - connect(rc, &AnalyzerRunControl::starting, this, &CallgrindTool::engineStarting); - connect(rc, &RunControl::finished, this, &CallgrindTool::engineFinished); + connect(runControl, &CallgrindRunControl::parserDataReady, this, &CallgrindTool::takeParserDataFromRunControl); + connect(runControl, &AnalyzerRunControl::starting, this, &CallgrindTool::engineStarting); + connect(runControl, &RunControl::finished, this, &CallgrindTool::engineFinished); - connect(this, &CallgrindTool::dumpRequested, rc, &CallgrindRunControl::dump); - connect(this, &CallgrindTool::resetRequested, rc, &CallgrindRunControl::reset); - connect(this, &CallgrindTool::pauseToggled, rc, &CallgrindRunControl::setPaused); + connect(this, &CallgrindTool::dumpRequested, runControl, &CallgrindRunControl::dump); + connect(this, &CallgrindTool::resetRequested, runControl, &CallgrindRunControl::reset); + connect(this, &CallgrindTool::pauseToggled, runControl, &CallgrindRunControl::setPaused); + + connect(m_stopAction, &QAction::triggered, runControl, [runControl] { runControl->stop(); }); // initialize run control - rc->setPaused(m_pauseAction->isChecked()); + runControl->setPaused(m_pauseAction->isChecked()); // we may want to toggle collect for one function only in this run - rc->setToggleCollectFunction(m_toggleCollectFunction); + runControl->setToggleCollectFunction(m_toggleCollectFunction); m_toggleCollectFunction.clear(); - QTC_ASSERT(m_visualization, return rc); + QTC_ASSERT(m_visualization, return runControl); // apply project settings if (runConfiguration) { @@ -560,241 +768,27 @@ ValgrindRunControl *CallgrindTool::createRunControl(RunConfiguration *runConfigu } } } - return rc; + + m_toolBusy = true; + updateRunActions(); + + return runControl; } -void CallgrindTool::createWidgets() +void CallgrindTool::updateRunActions() { - QTC_ASSERT(!m_visualization, return); - - QSettings *coreSettings = ICore::settings(); - - // - // DockWidgets - // - m_visualization = new Visualisation; - m_visualization->setFrameStyle(QFrame::NoFrame); - m_visualization->setObjectName(QLatin1String("Valgrind.CallgrindTool.Visualisation")); - m_visualization->setWindowTitle(tr("Visualization")); - m_visualization->setModel(&m_dataModel); - connect(m_visualization, &Visualisation::functionActivated, - this, &CallgrindTool::visualisationFunctionSelected); - - m_callersView = new CostView; - m_callersView->setObjectName(QLatin1String("Valgrind.CallgrindTool.CallersView")); - m_callersView->setWindowTitle(tr("Callers")); - m_callersView->setSettings(coreSettings, "Valgrind.CallgrindTool.CallersView"); - m_callersView->sortByColumn(CallModel::CostColumn); - m_callersView->setFrameStyle(QFrame::NoFrame); - // enable sorting - m_callersProxy.setSourceModel(&m_callersModel); - m_callersView->setModel(&m_callersProxy); - m_callersView->hideColumn(CallModel::CalleeColumn); - connect(m_callersView, &QAbstractItemView::activated, - this, &CallgrindTool::callerFunctionSelected); - - m_calleesView = new CostView; - m_calleesView->setObjectName(QLatin1String("Valgrind.CallgrindTool.CalleesView")); - m_calleesView->setWindowTitle(tr("Callees")); - m_calleesView->setSettings(coreSettings, "Valgrind.CallgrindTool.CalleesView"); - m_calleesView->sortByColumn(CallModel::CostColumn); - m_calleesView->setFrameStyle(QFrame::NoFrame); - // enable sorting - m_calleesProxy.setSourceModel(&m_calleesModel); - m_calleesView->setModel(&m_calleesProxy); - m_calleesView->hideColumn(CallModel::CallerColumn); - connect(m_calleesView, &QAbstractItemView::activated, - this, &CallgrindTool::calleeFunctionSelected); - - m_flatView = new CostView; - m_flatView->setObjectName(QLatin1String("Valgrind.CallgrindTool.FlatView")); - m_flatView->setWindowTitle(tr("Functions")); - m_flatView->setSettings(coreSettings, "Valgrind.CallgrindTool.FlatView"); - m_flatView->sortByColumn(DataModel::SelfCostColumn); - m_flatView->setFrameStyle(QFrame::NoFrame); - m_flatView->setAttribute(Qt::WA_MacShowFocusRect, false); - m_flatView->setModel(&m_proxyModel); - connect(m_flatView, &QAbstractItemView::activated, - this, &CallgrindTool::dataFunctionSelected); - - updateCostFormat(); - - // - // Control Widget - // - auto layout = new QHBoxLayout; - layout->setMargin(0); - layout->setSpacing(0); - - auto widget = new QWidget; - widget->setLayout(layout); - - // load external log file - auto action = new QAction(this); - action->setIcon(Core::Icons::OPENFILE.icon()); - action->setToolTip(tr("Load External Log File")); - connect(action, &QAction::triggered, this, &CallgrindTool::loadExternalLogFile); - layout->addWidget(createToolButton(action)); - m_loadExternalLogFile = action; - - // dump action - action = new QAction(this); - action->setDisabled(true); - action->setIcon(Core::Icons::REDO.icon()); - //action->setText(tr("Dump")); - action->setToolTip(tr("Request the dumping of profile information. This will update the Callgrind visualization.")); - connect(action, &QAction::triggered, this, &CallgrindTool::slotRequestDump); - layout->addWidget(createToolButton(action)); - m_dumpAction = action; - - // reset action - action = new QAction(this); - action->setDisabled(true); - action->setIcon(Core::Icons::RELOAD.icon()); - //action->setText(tr("Reset")); - action->setToolTip(tr("Reset all event counters.")); - connect(action, &QAction::triggered, this, &CallgrindTool::resetRequested); - layout->addWidget(createToolButton(action)); - m_resetAction = action; - - // pause action - action = new QAction(this); - action->setCheckable(true); - action->setIcon(ProjectExplorer::Icons::INTERRUPT_SMALL.icon()); - //action->setText(tr("Ignore")); - action->setToolTip(tr("Pause event logging. No events are counted which will speed up program execution during profiling.")); - connect(action, &QAction::toggled, this, &CallgrindTool::pauseToggled); - layout->addWidget(createToolButton(action)); - m_pauseAction = action; - - // navigation - // go back - action = new QAction(this); - action->setDisabled(true); - action->setIcon(Core::Icons::PREV.icon()); - action->setToolTip(tr("Go back one step in history. This will select the previously selected item.")); - connect(action, &QAction::triggered, &m_stackBrowser, &StackBrowser::goBack); - layout->addWidget(createToolButton(action)); - m_goBack = action; - - // go forward - action = new QAction(this); - action->setDisabled(true); - action->setIcon(Core::Icons::NEXT.icon()); - action->setToolTip(tr("Go forward one step in history.")); - connect(action, &QAction::triggered, &m_stackBrowser, &StackBrowser::goNext); - layout->addWidget(createToolButton(action)); - m_goNext = action; - - layout->addWidget(new Utils::StyledSeparator); - - // event selection - m_eventCombo = new QComboBox; - m_eventCombo->setToolTip(tr("Selects which events from the profiling data are shown and visualized.")); - connect(m_eventCombo, static_cast(&QComboBox::currentIndexChanged), - this, &CallgrindTool::setCostEvent); - updateEventCombo(); - layout->addWidget(m_eventCombo); - - // Cost formatting - { - auto menu = new QMenu(layout->parentWidget()); - auto group = new QActionGroup(this); - - // Show costs as absolute numbers - m_costAbsolute = new QAction(tr("Absolute Costs"), this); - m_costAbsolute->setToolTip(tr("Show costs as absolute numbers.")); - m_costAbsolute->setCheckable(true); - m_costAbsolute->setChecked(true); - connect(m_costAbsolute, &QAction::toggled, this, &CallgrindTool::updateCostFormat); - group->addAction(m_costAbsolute); - menu->addAction(m_costAbsolute); - - // Show costs in percentages - m_costRelative = new QAction(tr("Relative Costs"), this); - m_costRelative->setToolTip(tr("Show costs relative to total inclusive cost.")); - m_costRelative->setCheckable(true); - connect(m_costRelative, &QAction::toggled, this, &CallgrindTool::updateCostFormat); - group->addAction(m_costRelative); - menu->addAction(m_costRelative); - - // Show costs relative to parent - m_costRelativeToParent = new QAction(tr("Relative Costs to Parent"), this); - m_costRelativeToParent->setToolTip(tr("Show costs relative to parent functions inclusive cost.")); - m_costRelativeToParent->setCheckable(true); - connect(m_costRelativeToParent, &QAction::toggled, this, &CallgrindTool::updateCostFormat); - group->addAction(m_costRelativeToParent); - menu->addAction(m_costRelativeToParent); - - auto button = new QToolButton; - button->setMenu(menu); - button->setPopupMode(QToolButton::InstantPopup); - button->setText(QLatin1String("$")); - button->setToolTip(tr("Cost Format")); - layout->addWidget(button); + if (m_toolBusy) { + m_startAction->setEnabled(false); + m_startAction->setToolTip(tr("A Valgrind Callgrind analysis is still in progress.")); + m_stopAction->setEnabled(true); + } else { + QString whyNot = tr("Start a Valgrind Callgrind analysis."); + bool canRun = ProjectExplorerPlugin::canRunStartupProject(CALLGRIND_RUN_MODE, &whyNot); + m_startAction->setToolTip(whyNot); + m_startAction->setEnabled(canRun); + m_stopAction->setEnabled(false); } - - ValgrindGlobalSettings *settings = ValgrindPlugin::globalSettings(); - - // Cycle detection - //action = new QAction(QLatin1String("Cycle Detection"), this); ///FIXME: icon - action = new QAction(QLatin1String("O"), this); ///FIXME: icon - action->setToolTip(tr("Enable cycle detection to properly handle recursive or circular function calls.")); - action->setCheckable(true); - connect(action, &QAction::toggled, &m_dataModel, &DataModel::enableCycleDetection); - connect(action, &QAction::toggled, settings, &ValgrindGlobalSettings::setDetectCycles); - layout->addWidget(createToolButton(action)); - m_cycleDetection = action; - - // Shorter template signature - action = new QAction(QLatin1String("<>"), this); - action->setToolTip(tr("This removes template parameter lists when displaying function names.")); - action->setCheckable(true); - connect(action, &QAction::toggled, &m_dataModel, &DataModel::setShortenTemplates); - connect(action, &QAction::toggled, settings, &ValgrindGlobalSettings::setShortenTemplates); - layout->addWidget(createToolButton(action)); - m_shortenTemplates = action; - - // Filtering - action = new QAction(tr("Show Project Costs Only"), this); - action->setIcon(Core::Icons::FILTER.icon()); - action->setToolTip(tr("Show only profiling info that originated from this project source.")); - action->setCheckable(true); - connect(action, &QAction::toggled, this, &CallgrindTool::handleFilterProjectCosts); - layout->addWidget(createToolButton(action)); - m_filterProjectCosts = action; - - // Filter - ///FIXME: find workaround for https://bugreports.qt.io/browse/QTCREATORBUG-3247 - auto filter = new QLineEdit; - filter->setPlaceholderText(tr("Filter...")); - connect(filter, &QLineEdit::textChanged, - &m_updateTimer, static_cast(&QTimer::start)); - layout->addWidget(filter); - m_searchFilter = filter; - - setCostFormat(settings->costFormat()); - enableCycleDetection(settings->detectCycles()); - - layout->addWidget(new Utils::StyledSeparator); - layout->addStretch(); - - AnalyzerManager::registerDockWidget(CallgrindCallersDockId, m_callersView); - AnalyzerManager::registerDockWidget(CallgrindFlatDockId, m_flatView); - AnalyzerManager::registerDockWidget(CallgrindCalleesDockId, m_calleesView); - AnalyzerManager::registerDockWidget(CallgrindVisualizationDockId, m_visualization); - - AnalyzerManager::registerPerspective(CallgrindPerspectiveId, { - { CallgrindFlatDockId, Id(), Perspective::SplitVertical }, - { CallgrindCalleesDockId, Id(), Perspective::SplitVertical }, - { CallgrindCallersDockId, CallgrindCalleesDockId, Perspective::SplitHorizontal }, - { CallgrindVisualizationDockId, Id(), Perspective::SplitVertical, - false, Qt::RightDockWidgetArea } - }); - - AnalyzerManager::registerToolbar(CallgrindPerspectiveId, widget); } - void CallgrindTool::clearTextMarks() { qDeleteAll(m_textMarks); @@ -813,6 +807,9 @@ void CallgrindTool::engineStarting() void CallgrindTool::engineFinished() { + m_toolBusy = false; + updateRunActions(); + // Enable/disable actions m_resetAction->setEnabled(false); m_dumpAction->setEnabled(false); @@ -822,7 +819,7 @@ void CallgrindTool::engineFinished() if (data) showParserResults(data); else - AnalyzerManager::showPermanentStatusMessage(tr("Profiling aborted.")); + Debugger::showPermanentStatusMessage(tr("Profiling aborted.")); setBusyCursor(false); } @@ -841,7 +838,7 @@ void CallgrindTool::showParserResults(const ParseData *data) } else { msg = tr("Parsing failed."); } - AnalyzerManager::showPermanentStatusMessage(msg); + Debugger::showPermanentStatusMessage(msg); } void CallgrindTool::editorOpened(IEditor *editor) @@ -878,8 +875,7 @@ void CallgrindTool::handleShowCostsOfFunction() const QString qualifiedFunctionName = view.prettyName(CPlusPlus::LookupContext::fullyQualifiedName(symbol)); m_toggleCollectFunction = qualifiedFunctionName + QLatin1String("()"); - - AnalyzerManager::selectAction(CallgrindLocalActionId, /* alsoRunIt = */ true); + m_startAction->trigger(); } void CallgrindTool::slotRequestDump() @@ -906,7 +902,7 @@ void CallgrindTool::loadExternalLogFile() return; } - AnalyzerManager::showPermanentStatusMessage(tr("Parsing Profile Data...")); + Debugger::showPermanentStatusMessage(tr("Parsing Profile Data...")); QCoreApplication::processEvents(); Parser parser; diff --git a/src/plugins/valgrind/memcheckengine.cpp b/src/plugins/valgrind/memcheckengine.cpp index a40ffe9db2a..6d4a212c891 100644 --- a/src/plugins/valgrind/memcheckengine.cpp +++ b/src/plugins/valgrind/memcheckengine.cpp @@ -44,7 +44,7 @@ #include -using namespace Analyzer; +using namespace Debugger; using namespace ProjectExplorer; using namespace Valgrind::XmlProtocol; @@ -72,20 +72,20 @@ ValgrindRunner *MemcheckRunControl::runner() return &m_runner; } -bool MemcheckRunControl::startEngine() +void MemcheckRunControl::start() { m_runner.setParser(&m_parser); appendMessage(tr("Analyzing memory of %1").arg(executable()) + QLatin1Char('\n'), Utils::NormalMessageFormat); - return ValgrindRunControl::startEngine(); + ValgrindRunControl::start(); } -void MemcheckRunControl::stopEngine() +RunControl::StopResult MemcheckRunControl::stop() { disconnect(&m_parser, &ThreadedParser::internalError, this, &MemcheckRunControl::internalParserError); - ValgrindRunControl::stopEngine(); + return ValgrindRunControl::stop(); } QStringList MemcheckRunControl::toolArguments() const diff --git a/src/plugins/valgrind/memcheckengine.h b/src/plugins/valgrind/memcheckengine.h index a1ac1f8373d..b619aa96694 100644 --- a/src/plugins/valgrind/memcheckengine.h +++ b/src/plugins/valgrind/memcheckengine.h @@ -43,8 +43,8 @@ public: MemcheckRunControl(ProjectExplorer::RunConfiguration *runConfiguration, Core::Id runMode); - bool startEngine() override; - void stopEngine() override; + void start() override; + StopResult stop() override; QStringList suppressionFiles() const; diff --git a/src/plugins/valgrind/memcheckerrorview.cpp b/src/plugins/valgrind/memcheckerrorview.cpp index b3627965daa..a15d7731337 100644 --- a/src/plugins/valgrind/memcheckerrorview.cpp +++ b/src/plugins/valgrind/memcheckerrorview.cpp @@ -50,7 +50,7 @@ namespace Valgrind { namespace Internal { MemcheckErrorView::MemcheckErrorView(QWidget *parent) - : Analyzer::DetailedErrorView(parent), + : Debugger::DetailedErrorView(parent), m_settings(0) { m_suppressAction = new QAction(this); diff --git a/src/plugins/valgrind/memcheckerrorview.h b/src/plugins/valgrind/memcheckerrorview.h index 38f92fcf46f..205c7238415 100644 --- a/src/plugins/valgrind/memcheckerrorview.h +++ b/src/plugins/valgrind/memcheckerrorview.h @@ -36,7 +36,7 @@ namespace Internal { class ValgrindBaseSettings; -class MemcheckErrorView : public Analyzer::DetailedErrorView +class MemcheckErrorView : public Debugger::DetailedErrorView { Q_OBJECT diff --git a/src/plugins/valgrind/memchecktool.cpp b/src/plugins/valgrind/memchecktool.cpp index ab5a2897cdd..a0e4b539d1d 100644 --- a/src/plugins/valgrind/memchecktool.cpp +++ b/src/plugins/valgrind/memchecktool.cpp @@ -85,14 +85,60 @@ #include #include -using namespace Analyzer; +using namespace Debugger; using namespace ProjectExplorer; +using namespace Utils; using namespace Valgrind::XmlProtocol; namespace Valgrind { namespace Internal { -class FrameFinder; +class FrameFinder : public ErrorListModel::RelevantFrameFinder +{ +public: + Frame findRelevant(const Error &error) const + { + const QVector stacks = error.stacks(); + if (stacks.isEmpty()) + return Frame(); + const Stack &stack = stacks[0]; + const QVector frames = stack.frames(); + if (frames.isEmpty()) + return Frame(); + + //find the first frame belonging to the project + if (!m_projectFiles.isEmpty()) { + foreach (const Frame &frame, frames) { + if (frame.directory().isEmpty() || frame.fileName().isEmpty()) + continue; + + //filepaths can contain "..", clean them: + const QString f = QFileInfo(frame.filePath()).absoluteFilePath(); + if (m_projectFiles.contains(f)) + return frame; + } + } + + //if no frame belonging to the project was found, return the first one that is not malloc/new + foreach (const Frame &frame, frames) { + if (!frame.functionName().isEmpty() && frame.functionName() != QLatin1String("malloc") + && !frame.functionName().startsWith(QLatin1String("operator new("))) + { + return frame; + } + } + + //else fallback to the first frame + return frames.first(); + } + void setFiles(const QStringList &files) + { + m_projectFiles = files; + } +private: + QStringList m_projectFiles; +}; + class MemcheckErrorFilterProxyModel : public QSortFilterProxyModel { @@ -203,12 +249,13 @@ class MemcheckTool : public QObject public: MemcheckTool(QObject *parent); - QWidget *createWidgets(); + void createWidgets(); MemcheckRunControl *createRunControl(ProjectExplorer::RunConfiguration *runConfiguration, Core::Id runMode); private: + void updateRunActions(); void settingsDestroyed(QObject *settings); void maybeActiveRunConfigurationChanged(); @@ -240,10 +287,14 @@ private: QList m_errorFilterActions; QAction *m_filterProjectAction; QList m_suppressionActions; + QAction *m_startAction; + QAction *m_startWithGdbAction; + QAction *m_stopAction; QAction *m_suppressionSeparator; QAction *m_loadExternalLogFile; QAction *m_goBack; QAction *m_goNext; + bool m_toolBusy = false; }; MemcheckTool::MemcheckTool(QObject *parent) @@ -288,7 +339,79 @@ MemcheckTool::MemcheckTool(QObject *parent) using namespace std::placeholders; - AnalyzerManager::registerToolbar(MemcheckPerspectiveId, createWidgets()); + QTC_ASSERT(!m_errorView, return); + + m_errorView = new MemcheckErrorView; + m_errorView->setObjectName(QLatin1String("MemcheckErrorView")); + m_errorView->setFrameStyle(QFrame::NoFrame); + m_errorView->setAttribute(Qt::WA_MacShowFocusRect, false); + m_errorModel = new ErrorListModel(m_errorView); + m_frameFinder = new Internal::FrameFinder; + m_errorModel->setRelevantFrameFinder(QSharedPointer(m_frameFinder)); + m_errorProxyModel = new MemcheckErrorFilterProxyModel(m_errorView); + m_errorProxyModel->setSourceModel(m_errorModel); + m_errorProxyModel->setDynamicSortFilter(true); + m_errorView->setModel(m_errorProxyModel); + m_errorView->setSelectionMode(QAbstractItemView::ExtendedSelection); + // make m_errorView->selectionModel()->selectedRows() return something + m_errorView->setSelectionBehavior(QAbstractItemView::SelectRows); + m_errorView->setVerticalScrollMode(QAbstractItemView::ScrollPerPixel); + m_errorView->setAutoScroll(false); + m_errorView->setObjectName(QLatin1String("Valgrind.MemcheckTool.ErrorView")); + m_errorView->setWindowTitle(tr("Memory Issues")); + + Debugger::registerPerspective(MemcheckPerspectiveId, { tr("Memcheck"), { + { MemcheckErrorDockId, m_errorView, {}, Perspective::SplitVertical } + }}); + + connect(ProjectExplorerPlugin::instance(), &ProjectExplorerPlugin::updateRunActions, + this, &MemcheckTool::maybeActiveRunConfigurationChanged); + + // + // The Control Widget. + // + + m_startAction = Debugger::createStartAction(); + m_startWithGdbAction = Debugger::createStartAction(); + m_stopAction = Debugger::createStopAction(); + + // Load external XML log file + auto action = new QAction(this); + action->setIcon(Core::Icons::OPENFILE.icon()); + action->setToolTip(tr("Load External XML Log File")); + connect(action, &QAction::triggered, this, &MemcheckTool::loadExternalXmlLogFile); + m_loadExternalLogFile = action; + + // Go to previous leak. + action = new QAction(this); + action->setDisabled(true); + action->setIcon(Core::Icons::PREV.icon()); + action->setToolTip(tr("Go to previous leak.")); + connect(action, &QAction::triggered, m_errorView, &MemcheckErrorView::goBack); + m_goBack = action; + + // Go to next leak. + action = new QAction(this); + action->setDisabled(true); + action->setIcon(Core::Icons::NEXT.icon()); + action->setToolTip(tr("Go to next leak.")); + connect(action, &QAction::triggered, m_errorView, &MemcheckErrorView::goNext); + m_goNext = action; + + auto filterButton = new QToolButton; + filterButton->setIcon(Core::Icons::FILTER.icon()); + filterButton->setText(tr("Error Filter")); + filterButton->setPopupMode(QToolButton::InstantPopup); + filterButton->setProperty("noArrow", true); + + m_filterMenu = new QMenu(filterButton); + foreach (QAction *filterAction, m_errorFilterActions) + m_filterMenu->addAction(filterAction); + m_filterMenu->addSeparator(); + m_filterMenu->addAction(m_filterProjectAction); + m_filterMenu->addAction(m_suppressionSeparator); + connect(m_filterMenu, &QMenu::triggered, this, &MemcheckTool::updateErrorFilter); + filterButton->setMenu(m_filterMenu); ActionDescription desc; desc.setToolTip(tr("Valgrind Analyze Memory uses the " @@ -300,8 +423,8 @@ MemcheckTool::MemcheckTool(QObject *parent) desc.setRunControlCreator(std::bind(&MemcheckTool::createRunControl, this, _1, _2)); desc.setToolMode(DebugMode); desc.setRunMode(MEMCHECK_RUN_MODE); - desc.setMenuGroup(Analyzer::Constants::G_ANALYZER_TOOLS); - AnalyzerManager::registerAction("Memcheck.Local", desc); + desc.setMenuGroup(Debugger::Constants::G_ANALYZER_TOOLS); + Debugger::registerAction("Memcheck.Local", desc, m_startAction); desc.setText(tr("Valgrind Memory Analyzer with GDB")); desc.setToolTip(tr("Valgrind Analyze Memory with GDB uses the " @@ -311,11 +434,11 @@ MemcheckTool::MemcheckTool(QObject *parent) desc.setRunControlCreator(std::bind(&MemcheckTool::createRunControl, this, _1, _2)); desc.setToolMode(DebugMode); desc.setRunMode(MEMCHECK_WITH_GDB_RUN_MODE); - desc.setMenuGroup(Analyzer::Constants::G_ANALYZER_TOOLS); - AnalyzerManager::registerAction("MemcheckWithGdb.Local", desc); + desc.setMenuGroup(Debugger::Constants::G_ANALYZER_TOOLS); + Debugger::registerAction("MemcheckWithGdb.Local", desc, m_startWithGdbAction); } - desc.setText(tr("Valgrind Memory Analyzer (External Remote Application)")); + desc.setText(tr("Valgrind Memory Analyzer (External Application)")); desc.setPerspectiveId(MemcheckPerspectiveId); desc.setCustomToolStarter([this](ProjectExplorer::RunConfiguration *runConfig) { StartRemoteDialog dlg; @@ -331,8 +454,42 @@ MemcheckTool::MemcheckTool(QObject *parent) rc->setDisplayName(runnable.executable); ProjectExplorerPlugin::startRunControl(rc, MEMCHECK_RUN_MODE); }); - desc.setMenuGroup(Analyzer::Constants::G_ANALYZER_REMOTE_TOOLS); - AnalyzerManager::registerAction("Memcheck.Remote", desc); + desc.setMenuGroup(Debugger::Constants::G_ANALYZER_REMOTE_TOOLS); + Debugger::registerAction("Memcheck.Remote", desc); + + ToolbarDescription toolbar; + toolbar.addAction(m_startAction); + //toolbar.addAction(m_startWithGdbAction); + toolbar.addAction(m_stopAction); + toolbar.addAction(m_loadExternalLogFile); + toolbar.addAction(m_goBack); + toolbar.addAction(m_goNext); + toolbar.addWidget(filterButton); + Debugger::registerToolbar(MemcheckPerspectiveId, toolbar); + + updateFromSettings(); + maybeActiveRunConfigurationChanged(); +} + +void MemcheckTool::updateRunActions() +{ + if (m_toolBusy) { + m_startAction->setEnabled(false); + m_startAction->setToolTip(tr("A Valgrind Memcheck analysis is still in progress.")); + m_startWithGdbAction->setEnabled(false); + m_startWithGdbAction->setToolTip(tr("A Valgrind Memcheck analysis is still in progress.")); + m_stopAction->setEnabled(true); + } else { + QString whyNot = tr("Start a Valgrind Memcheck analysis."); + bool canRun = ProjectExplorerPlugin::canRunStartupProject(MEMCHECK_RUN_MODE, &whyNot); + m_startAction->setToolTip(whyNot); + m_startAction->setEnabled(canRun); + whyNot = tr("Start a Valgrind Memcheck with GDB analysis."); + canRun = ProjectExplorerPlugin::canRunStartupProject(MEMCHECK_WITH_GDB_RUN_MODE, &whyNot); + m_startWithGdbAction->setToolTip(whyNot); + m_startWithGdbAction->setEnabled(canRun); + m_stopAction->setEnabled(false); + } } void MemcheckTool::settingsDestroyed(QObject *settings) @@ -368,6 +525,8 @@ void MemcheckTool::updateFromSettings() void MemcheckTool::maybeActiveRunConfigurationChanged() { + updateRunActions(); + ValgrindBaseSettings *settings = 0; if (Project *project = SessionManager::startupProject()) if (Target *target = project->activeTarget()) @@ -395,150 +554,6 @@ void MemcheckTool::maybeActiveRunConfigurationChanged() updateFromSettings(); } -class FrameFinder : public ErrorListModel::RelevantFrameFinder -{ -public: - Frame findRelevant(const Error &error) const - { - const QVector stacks = error.stacks(); - if (stacks.isEmpty()) - return Frame(); - const Stack &stack = stacks[0]; - const QVector frames = stack.frames(); - if (frames.isEmpty()) - return Frame(); - - //find the first frame belonging to the project - if (!m_projectFiles.isEmpty()) { - foreach (const Frame &frame, frames) { - if (frame.directory().isEmpty() || frame.fileName().isEmpty()) - continue; - - //filepaths can contain "..", clean them: - const QString f = QFileInfo(frame.filePath()).absoluteFilePath(); - if (m_projectFiles.contains(f)) - return frame; - } - } - - //if no frame belonging to the project was found, return the first one that is not malloc/new - foreach (const Frame &frame, frames) { - if (!frame.functionName().isEmpty() && frame.functionName() != QLatin1String("malloc") - && !frame.functionName().startsWith(QLatin1String("operator new("))) - { - return frame; - } - } - - //else fallback to the first frame - return frames.first(); - } - void setFiles(const QStringList &files) - { - m_projectFiles = files; - } -private: - QStringList m_projectFiles; -}; - - -QWidget *MemcheckTool::createWidgets() -{ - QTC_ASSERT(!m_errorView, return 0); - - m_errorView = new MemcheckErrorView; - m_errorView->setObjectName(QLatin1String("MemcheckErrorView")); - m_errorView->setFrameStyle(QFrame::NoFrame); - m_errorView->setAttribute(Qt::WA_MacShowFocusRect, false); - m_errorModel = new ErrorListModel(m_errorView); - m_frameFinder = new Internal::FrameFinder; - m_errorModel->setRelevantFrameFinder(QSharedPointer(m_frameFinder)); - m_errorProxyModel = new MemcheckErrorFilterProxyModel(m_errorView); - m_errorProxyModel->setSourceModel(m_errorModel); - m_errorProxyModel->setDynamicSortFilter(true); - m_errorView->setModel(m_errorProxyModel); - m_errorView->setSelectionMode(QAbstractItemView::ExtendedSelection); - // make m_errorView->selectionModel()->selectedRows() return something - m_errorView->setSelectionBehavior(QAbstractItemView::SelectRows); - m_errorView->setVerticalScrollMode(QAbstractItemView::ScrollPerPixel); - m_errorView->setAutoScroll(false); - m_errorView->setObjectName(QLatin1String("Valgrind.MemcheckTool.ErrorView")); - m_errorView->setWindowTitle(tr("Memory Issues")); - - AnalyzerManager::registerDockWidget(MemcheckErrorDockId, m_errorView); - - AnalyzerManager::registerPerspective(MemcheckPerspectiveId, { - { MemcheckErrorDockId, Core::Id(), Perspective::SplitVertical } - }); - - connect(ProjectExplorerPlugin::instance(), &ProjectExplorerPlugin::updateRunActions, - this, &MemcheckTool::maybeActiveRunConfigurationChanged); - - // - // The Control Widget. - // - QAction *action = 0; - QHBoxLayout *layout = new QHBoxLayout; - QToolButton *button = 0; - - layout->setMargin(0); - layout->setSpacing(0); - - // Load external XML log file - action = new QAction(this); - action->setIcon(Core::Icons::OPENFILE.icon()); - action->setToolTip(tr("Load External XML Log File")); - connect(action, &QAction::triggered, this, &MemcheckTool::loadExternalXmlLogFile); - button = new QToolButton; - button->setDefaultAction(action); - layout->addWidget(button); - m_loadExternalLogFile = action; - - // Go to previous leak. - action = new QAction(this); - action->setDisabled(true); - action->setIcon(Core::Icons::PREV.icon()); - action->setToolTip(tr("Go to previous leak.")); - connect(action, &QAction::triggered, m_errorView, &MemcheckErrorView::goBack); - button = new QToolButton; - button->setDefaultAction(action); - layout->addWidget(button); - m_goBack = action; - - // Go to next leak. - action = new QAction(this); - action->setDisabled(true); - action->setIcon(Core::Icons::NEXT.icon()); - action->setToolTip(tr("Go to next leak.")); - connect(action, &QAction::triggered, m_errorView, &MemcheckErrorView::goNext); - button = new QToolButton; - button->setDefaultAction(action); - layout->addWidget(button); - m_goNext = action; - - QToolButton *filterButton = new QToolButton; - filterButton->setIcon(Core::Icons::FILTER.icon()); - filterButton->setText(tr("Error Filter")); - filterButton->setPopupMode(QToolButton::InstantPopup); - filterButton->setProperty("noArrow", true); - - m_filterMenu = new QMenu(filterButton); - foreach (QAction *filterAction, m_errorFilterActions) - m_filterMenu->addAction(filterAction); - m_filterMenu->addSeparator(); - m_filterMenu->addAction(m_filterProjectAction); - m_filterMenu->addAction(m_suppressionSeparator); - connect(m_filterMenu, &QMenu::triggered, this, &MemcheckTool::updateErrorFilter); - filterButton->setMenu(m_filterMenu); - layout->addWidget(filterButton); - - layout->addStretch(); - QWidget *widget = new QWidget; - widget->setObjectName(QLatin1String("MemCheckToolBarWidget")); - widget->setLayout(layout); - return widget; -} - MemcheckRunControl *MemcheckTool::createRunControl(RunConfiguration *runConfiguration, Core::Id runMode) { @@ -555,6 +570,12 @@ MemcheckRunControl *MemcheckTool::createRunControl(RunConfiguration *runConfigur connect(runControl, &MemcheckRunControl::parserError, this, &MemcheckTool::parserError); connect(runControl, &MemcheckRunControl::internalParserError, this, &MemcheckTool::internalParserError); connect(runControl, &MemcheckRunControl::finished, this, &MemcheckTool::engineFinished); + + connect(m_stopAction, &QAction::triggered, runControl, [runControl] { runControl->stop(); }); + + m_toolBusy = true; + updateRunActions(); + return runControl; } @@ -673,18 +694,19 @@ int MemcheckTool::updateUiAfterFinishedHelper() void MemcheckTool::engineFinished() { + m_toolBusy = false; + updateRunActions(); + const int issuesFound = updateUiAfterFinishedHelper(); - AnalyzerManager::showPermanentStatusMessage(issuesFound > 0 - ? AnalyzerManager::tr("Memory Analyzer Tool finished, %n issues were found.", 0, issuesFound) - : AnalyzerManager::tr("Memory Analyzer Tool finished, no issues were found.")); + Debugger::showPermanentStatusMessage( + tr("Memory Analyzer Tool finished, %n issues were found.", 0, issuesFound)); } void MemcheckTool::loadingExternalXmlLogFileFinished() { const int issuesFound = updateUiAfterFinishedHelper(); - AnalyzerManager::showPermanentStatusMessage(issuesFound > 0 - ? AnalyzerManager::tr("Log file processed, %n issues were found.", 0, issuesFound) - : AnalyzerManager::tr("Log file processed, no issues were found.")); + Debugger::showPermanentStatusMessage( + tr("Log file processed, %n issues were found.", 0, issuesFound)); } void MemcheckTool::setBusyCursor(bool busy) diff --git a/src/plugins/valgrind/valgrindengine.cpp b/src/plugins/valgrind/valgrindengine.cpp index 12c2215c407..935bc1f2434 100644 --- a/src/plugins/valgrind/valgrindengine.cpp +++ b/src/plugins/valgrind/valgrindengine.cpp @@ -43,7 +43,7 @@ #define VALGRIND_DEBUG_OUTPUT 0 -using namespace Analyzer; +using namespace Debugger; using namespace Core; using namespace Utils; using namespace ProjectExplorer; @@ -65,10 +65,9 @@ ValgrindRunControl::ValgrindRunControl(RunConfiguration *runConfiguration, Core: m_settings = ValgrindPlugin::globalSettings(); } -bool ValgrindRunControl::startEngine() +void ValgrindRunControl::start() { emit starting(); - FutureProgress *fp = ProgressManager::addTimedTask(m_progress, progressTitle(), "valgrind", 100); fp->setKeepOnFinish(FutureProgress::HideOnFinish); connect(fp, &FutureProgress::canceled, @@ -86,7 +85,6 @@ bool ValgrindRunControl::startEngine() ValgrindRunner *run = runner(); run->setValgrindExecutable(m_settings->valgrindExecutable()); run->setValgrindArguments(genericToolArguments() + toolArguments()); - QTC_ASSERT(!device().isNull(), return false); run->setDevice(device()); run->setDebuggee(runnable().as()); @@ -99,15 +97,24 @@ bool ValgrindRunControl::startEngine() if (!run->start()) { m_progress.cancel(); - return false; + emit finished(); + return; } - return true; + + m_isRunning = true; + emit started(); } -void ValgrindRunControl::stopEngine() +RunControl::StopResult ValgrindRunControl::stop() { m_isStopping = true; runner()->stop(); + return AsynchronousStop; +} + +bool ValgrindRunControl::isRunning() const +{ + return m_isRunning; } QString ValgrindRunControl::executable() const @@ -139,7 +146,6 @@ QStringList ValgrindRunControl::genericToolArguments() const void ValgrindRunControl::handleProgressCanceled() { - AnalyzerManager::stopTool(); m_progress.reportCanceled(); m_progress.reportFinished(); } @@ -151,6 +157,8 @@ void ValgrindRunControl::handleProgressFinished() void ValgrindRunControl::runnerFinished() { + m_isRunning = false; + appendMessage(tr("Analyzing finished.") + QLatin1Char('\n'), NormalMessageFormat); emit finished(); diff --git a/src/plugins/valgrind/valgrindengine.h b/src/plugins/valgrind/valgrindengine.h index 302f3a7bdb4..fa9ffcc91aa 100644 --- a/src/plugins/valgrind/valgrindengine.h +++ b/src/plugins/valgrind/valgrindengine.h @@ -38,7 +38,7 @@ namespace Valgrind { namespace Internal { -class ValgrindRunControl : public Analyzer::AnalyzerRunControl +class ValgrindRunControl : public Debugger::AnalyzerRunControl { Q_OBJECT @@ -46,8 +46,9 @@ public: ValgrindRunControl(ProjectExplorer::RunConfiguration *runConfiguration, Core::Id runMode); - bool startEngine() override; - void stopEngine() override; + void start() override; + StopResult stop() override; + bool isRunning() const override; QString executable() const; @@ -70,6 +71,7 @@ private: QStringList genericToolArguments() const; private: + bool m_isRunning = false; bool m_isStopping = false; }; diff --git a/src/plugins/valgrind/valgrindprocess.cpp b/src/plugins/valgrind/valgrindprocess.cpp index acffe745f4b..83184c5269e 100644 --- a/src/plugins/valgrind/valgrindprocess.cpp +++ b/src/plugins/valgrind/valgrindprocess.cpp @@ -111,7 +111,7 @@ void ValgrindProcess::close() } } -void ValgrindProcess::run() +void ValgrindProcess::run(ApplicationLauncher::Mode runMode) { if (isLocal()) { connect(&m_localProcess, &ApplicationLauncher::processExited, @@ -125,7 +125,7 @@ void ValgrindProcess::run() StandardRunnable valgrind; valgrind.executable = m_valgrindExecutable; - valgrind.runMode = m_debuggee.runMode; + valgrind.runMode = runMode; valgrind.commandLineArguments = argumentString(Utils::HostOsInfo::hostOs()); valgrind.workingDirectory = m_debuggee.workingDirectory; valgrind.environment = m_debuggee.environment; diff --git a/src/plugins/valgrind/valgrindprocess.h b/src/plugins/valgrind/valgrindprocess.h index 1f6f7d21aae..0d04a4093e2 100644 --- a/src/plugins/valgrind/valgrindprocess.h +++ b/src/plugins/valgrind/valgrindprocess.h @@ -55,7 +55,7 @@ public: void setValgrindArguments(const QStringList &valgrindArguments); void setDebuggee(const ProjectExplorer::StandardRunnable &debuggee); - void run(); + void run(ProjectExplorer::ApplicationLauncher::Mode runMode); void close(); QString errorString() const; diff --git a/src/plugins/valgrind/valgrindruncontrolfactory.cpp b/src/plugins/valgrind/valgrindruncontrolfactory.cpp index 2db334b5845..f1338b16655 100644 --- a/src/plugins/valgrind/valgrindruncontrolfactory.cpp +++ b/src/plugins/valgrind/valgrindruncontrolfactory.cpp @@ -36,7 +36,7 @@ #include -using namespace Analyzer; +using namespace Debugger; using namespace ProjectExplorer; namespace Valgrind { @@ -56,7 +56,7 @@ bool ValgrindRunControlFactory::canRun(RunConfiguration *runConfiguration, Core: RunControl *ValgrindRunControlFactory::create(RunConfiguration *runConfiguration, Core::Id mode, QString *errorMessage) { Q_UNUSED(errorMessage); - return AnalyzerManager::createRunControl(runConfiguration, mode); + return Debugger::createAnalyzerRunControl(runConfiguration, mode); } class ValgrindRunConfigurationAspect : public IRunConfigurationAspect diff --git a/src/plugins/valgrind/valgrindrunner.cpp b/src/plugins/valgrind/valgrindrunner.cpp index 763e7110261..477cf3478b0 100644 --- a/src/plugins/valgrind/valgrindrunner.cpp +++ b/src/plugins/valgrind/valgrindrunner.cpp @@ -148,7 +148,7 @@ bool ValgrindRunner::start() QObject::connect(d->process, &ValgrindProcess::error, this, &ValgrindRunner::processError); - d->process->run(); + d->process->run(d->debuggee.runMode); return true; } @@ -188,8 +188,8 @@ QString ValgrindRunner::errorString() const void ValgrindRunner::stop() { - if (d->process) - d->process->close(); + QTC_ASSERT(d->process, finished(); return); + d->process->close(); } ValgrindProcess *ValgrindRunner::valgrindProcess() const diff --git a/src/plugins/valgrind/xmlprotocol/errorlistmodel.cpp b/src/plugins/valgrind/xmlprotocol/errorlistmodel.cpp index c625a58920a..915b0ab4e88 100644 --- a/src/plugins/valgrind/xmlprotocol/errorlistmodel.cpp +++ b/src/plugins/valgrind/xmlprotocol/errorlistmodel.cpp @@ -191,8 +191,8 @@ ErrorItem::ErrorItem(const ErrorListModelPrivate *modelPrivate, const Error &err static QVariant location(const Frame &frame, int role) { switch (role) { - case Analyzer::DetailedErrorView::LocationRole: - return QVariant::fromValue(Analyzer::DiagnosticLocation(frame.filePath(), frame.line(), 0)); + case Debugger::DetailedErrorView::LocationRole: + return QVariant::fromValue(Debugger::DiagnosticLocation(frame.filePath(), frame.line(), 0)); case Qt::ToolTipRole: return frame.filePath().isEmpty() ? QVariant() : QVariant(frame.filePath()); default: @@ -202,14 +202,14 @@ static QVariant location(const Frame &frame, int role) QVariant ErrorItem::data(int column, int role) const { - if (column == Analyzer::DetailedErrorView::LocationColumn) { + if (column == Debugger::DetailedErrorView::LocationColumn) { const Frame frame = m_modelPrivate->findRelevantFrame(m_error); return location(frame, role); } // DiagnosticColumn switch (role) { - case Analyzer::DetailedErrorView::FullTextRole: { + case Debugger::DetailedErrorView::FullTextRole: { QString content; QTextStream stream(&content); @@ -257,7 +257,7 @@ StackItem::StackItem(const Stack &stack) : m_stack(stack) QVariant StackItem::data(int column, int role) const { const ErrorItem * const errorItem = getErrorItem(); - if (column == Analyzer::DetailedErrorView::LocationColumn) + if (column == Debugger::DetailedErrorView::LocationColumn) return location(errorItem->modelPrivate()->findRelevantFrame(errorItem->error()), role); // DiagnosticColumn @@ -285,7 +285,7 @@ FrameItem::FrameItem(const Frame &frame) : m_frame(frame) QVariant FrameItem::data(int column, int role) const { - if (column == Analyzer::DetailedErrorView::LocationColumn) + if (column == Debugger::DetailedErrorView::LocationColumn) return location(m_frame, role); // DiagnosticColumn diff --git a/src/plugins/valgrind/xmlprotocol/errorlistmodel.h b/src/plugins/valgrind/xmlprotocol/errorlistmodel.h index 9db79252b3c..ec7f5de61c6 100644 --- a/src/plugins/valgrind/xmlprotocol/errorlistmodel.h +++ b/src/plugins/valgrind/xmlprotocol/errorlistmodel.h @@ -45,7 +45,7 @@ class ErrorListModel : public Utils::TreeModel public: enum Role { - ErrorRole = Analyzer::DetailedErrorView::FullTextRole + 1, + ErrorRole = Debugger::DetailedErrorView::FullTextRole + 1, }; class RelevantFrameFinder diff --git a/src/shared/json/json.cpp b/src/shared/json/json.cpp index 9de77a58052..4becf92274d 100644 --- a/src/shared/json/json.cpp +++ b/src/shared/json/json.cpp @@ -4422,7 +4422,7 @@ bool Parser::parseNumber(Value *val, int baseOffset) char *endptr = const_cast(json); double d = strtod(start, &endptr); - if (start == endptr || isinf(d)) { + if (start == endptr || std::isinf(d)) { lastError = JsonParseError::IllegalNumber; return false; } diff --git a/src/shared/qbs b/src/shared/qbs index 451e5ee7778..0741b2c662b 160000 --- a/src/shared/qbs +++ b/src/shared/qbs @@ -1 +1 @@ -Subproject commit 451e5ee77786296a37bad864aca9c44d11bbee9d +Subproject commit 0741b2c662babaeb19983259c659c52fb78bbfeb diff --git a/tests/auto/clangstaticanalyzer/clangstaticanalyzerlogfilereader/tst_clangstaticanalyzerlogfilereader.cpp b/tests/auto/clangstaticanalyzer/clangstaticanalyzerlogfilereader/tst_clangstaticanalyzerlogfilereader.cpp index e8050c514ed..076f576e82b 100644 --- a/tests/auto/clangstaticanalyzer/clangstaticanalyzerlogfilereader/tst_clangstaticanalyzerlogfilereader.cpp +++ b/tests/auto/clangstaticanalyzer/clangstaticanalyzerlogfilereader/tst_clangstaticanalyzerlogfilereader.cpp @@ -31,7 +31,7 @@ enum { debug = 0 }; -using namespace Analyzer; +using namespace Debugger; using namespace ClangStaticAnalyzer::Internal; namespace { diff --git a/tests/auto/cplusplus/lexer/tst_lexer.cpp b/tests/auto/cplusplus/lexer/tst_lexer.cpp index 673a59008a0..92115bc05c6 100644 --- a/tests/auto/cplusplus/lexer/tst_lexer.cpp +++ b/tests/auto/cplusplus/lexer/tst_lexer.cpp @@ -70,6 +70,10 @@ private slots: void literals_data(); void preprocessor(); void preprocessor_data(); + void digraph(); + void digraph_data(); + void trigraph(); + void trigraph_data(); void bytes_and_utf16chars(); void bytes_and_utf16chars_data(); @@ -263,12 +267,6 @@ void tst_SimpleLexer::basic_data() << T_INT << T_IDENTIFIER << T_SEMICOLON << T_CPP_DOXY_COMMENT << T_INT << T_IDENTIFIER << T_SEMICOLON << T_CPP_DOXY_COMMENT << T_CPP_DOXY_COMMENT; QTest::newRow(source) << source << expectedTokenKindList; - - source = "?" "?(?" "?)?" "?a?b:c"; - expectedTokenKindList = TokenKindList() - << T_LBRACKET << T_RBRACKET << T_LBRACE << T_RBRACE - << T_IDENTIFIER << T_QUESTION << T_IDENTIFIER << T_COLON << T_IDENTIFIER; - QTest::newRow(source) << source << expectedTokenKindList; } void tst_SimpleLexer::literals() @@ -744,5 +742,81 @@ void tst_SimpleLexer::incremental_data() << (TokenKindList() << T_IDENTIFIER); } +void tst_SimpleLexer::digraph() +{ + QFETCH(QByteArray, source); + QFETCH(TokenKindList, expectedTokenKindList); + + run(source, toTokens(expectedTokenKindList), false, CompareKind); +} + +void tst_SimpleLexer::digraph_data() +{ + QTest::addColumn("source"); + QTest::addColumn("expectedTokenKindList"); + + QTest::newRow("lbracket_digraph") << _("<:") << (TokenKindList() << T_LBRACKET); + + QTest::newRow("rbracket_digraph") << _(":>") << (TokenKindList() << T_RBRACKET); + + QTest::newRow("lbrace_digraph") << _("<%") << (TokenKindList() << T_LBRACE); + + QTest::newRow("rbrace_digraph") << _("%>") << (TokenKindList() << T_RBRACE); + + QTest::newRow("pound_digraph") << _("%:") << (TokenKindList() << T_POUND); + + QTest::newRow("pound_pound_digraph") << _("%:%:") << (TokenKindList() << T_POUND_POUND); + + QTest::newRow("pound_pound_mixed_digraph_1") << _("#%:") << (TokenKindList() << T_POUND << T_POUND); + + QTest::newRow("pound_pound_mixed_digraph_2") << _("%:#") << (TokenKindList() << T_POUND << T_POUND); + + QTest::newRow("lbracket_digraph_exception1") << _("<::") << (TokenKindList() << T_LESS << T_COLON_COLON); + + QTest::newRow("lbracket_digraph_exception2") << _("<::x") << (TokenKindList() << T_LESS << T_COLON_COLON << T_IDENTIFIER); + + QTest::newRow("lbracket_digraph_exception3") << _("<:::") << (TokenKindList() << T_LBRACKET << T_COLON_COLON); + + QTest::newRow("lbracket_digraph_exception4") << _("<::>") << (TokenKindList() << T_LBRACKET << T_RBRACKET); +} + +void tst_SimpleLexer::trigraph() +{ + QFETCH(QByteArray, source); + QFETCH(TokenKindList, expectedTokenKindList); + + run(source, toTokens(expectedTokenKindList), false, CompareKind, true); +} + +void tst_SimpleLexer::trigraph_data() +{ + QTest::addColumn("source"); + QTest::addColumn("expectedTokenKindList"); + + QTest::newRow("pound_trigraph") << _("?" "?=") << (TokenKindList() << T_POUND); + + QTest::newRow("caret_trigraph") << _("?" "?'") << (TokenKindList() << T_CARET); + + QTest::newRow("left_bracket_trigraph") << _("?" "?(") << (TokenKindList() << T_LBRACKET); + + QTest::newRow("right_bracket_trigraph") << _("?" "?)") << (TokenKindList() << T_RBRACKET); + + QTest::newRow("pipe_trigraph") << _("?" "?!") << (TokenKindList() << T_PIPE); + + QTest::newRow("left_brace_trigraph") << _("?" "?<") << (TokenKindList() << T_LBRACE); + + QTest::newRow("right_brace_trigraph") << _("?" "?>") << (TokenKindList() << T_RBRACE); + + QTest::newRow("tilde_trigraph") << _("?" "?-") << (TokenKindList() << T_TILDE); + + QTest::newRow("pound_pound_trigraph") << _("?" "?=" "?" "?=") << (TokenKindList() << T_POUND_POUND); + + QTest::newRow("caret_equal_trigraph") << _("?" "?'=") << (TokenKindList() << T_CARET_EQUAL); + + QTest::newRow("pipe_equal_trigraph") << _("?" "?!=") << (TokenKindList() << T_PIPE_EQUAL); + + QTest::newRow("tilde_equal_trigraph") << _("?" "?-=") << (TokenKindList() << T_TILDE_EQUAL); +} + QTEST_APPLESS_MAIN(tst_SimpleLexer) #include "tst_lexer.moc" diff --git a/tests/auto/cplusplus/preprocessor/tst_preprocessor.cpp b/tests/auto/cplusplus/preprocessor/tst_preprocessor.cpp index 3eb71da58bd..2b4b6cd97a0 100644 --- a/tests/auto/cplusplus/preprocessor/tst_preprocessor.cpp +++ b/tests/auto/cplusplus/preprocessor/tst_preprocessor.cpp @@ -405,6 +405,7 @@ private slots: void concat(); void excessive_nesting(); void multi_byte_code_point_in_expansion(); + void trigraph(); }; // Remove all #... lines, and 'simplify' string, to allow easily comparing the result @@ -2092,6 +2093,29 @@ void tst_Preprocessor::compare_input_output(bool keepComments) QVERIFY(compare(prep, output)); } +void tst_Preprocessor::trigraph() +{ + Environment env; + Preprocessor preprocess(0, &env); + + // We cannot use actual trigraphs in strings, they would be replaced by the preprocessor when + // compiling the test, so we use strings with 'j' character instead of '?', and perform a + // replacement at runtime. + + // Trigraphs in source code are replaced + QByteArray prep = preprocess.run(QLatin1String(""), + QByteArray("jj( jj) jj< jj> jj= jj=jj= jj' jj'= jj! jj!= jj- jj-=").replace('j', '?'), + true, false); + QCOMPARE(prep.constData(), "[ ] { } # ## ^ ^= | |= ~ ~="); + + // Trigraphs that appear after macro expansion are not replaced + prep = preprocess.run(QLatin1String(""), + "#define TRIGRAPH(x...) ? ## x ## ? ## x ## =\n" + "TRIGRAPH()", + true, false); + QCOMPARE(prep.constData(), QByteArray("\njj=").replace('j', '?').data()); +} + QTEST_APPLESS_MAIN(tst_Preprocessor) #include "tst_preprocessor.moc" diff --git a/tests/system/objects.map b/tests/system/objects.map index dc49f301408..fc44e46139c 100644 --- a/tests/system/objects.map +++ b/tests/system/objects.map @@ -30,20 +30,15 @@ :Add Bookmark_BookmarkDialog {name='BookmarkDialog' type='BookmarkDialog' visible='1' windowTitle='Add Bookmark'} :Add to Version Control.No_QPushButton {text='No' type='QPushButton' unnamed='1' visible='1' window=':Add to Version Control_QMessageBox'} :Add to Version Control_QMessageBox {text~='Add the file.*to version control (.*)?' type='QMessageBox' unnamed='1' visible='1'} -:Analyzer Toolbar.AnalyzerManagerToolBox_QComboBox {container=':Qt Creator.Analyzer Toolbar_QDockWidget' name='AnalyzerManagerToolBox' type='QComboBox' visible='1'} -:Analyzer Toolbar.Clear_QToolButton {container=':Qt Creator.Analyzer Toolbar_QDockWidget' toolTip='Discard data' type='QToolButton' unnamed='1' visible='1'} -:Analyzer Toolbar.Elapsed:_QLabel {container=':Qt Creator.Analyzer Toolbar_QDockWidget' text~='Elapsed: \\\\d+.\\\\d s' type='QLabel' unnamed='1' visible='1'} -:Analyzer Toolbar.Start_QToolButton {container=':Qt Creator.Analyzer Toolbar_QDockWidget' text='Start' type='QToolButton' unnamed='1' visible='1'} +:Analyzer Toolbar.AnalyzerManagerToolBox_QComboBox {container=':DebugModeWidget.Toolbar_QDockWidget' name='PerspectiveChooser' type='QComboBox' visible='1'} +:Analyzer Toolbar.Clear_QToolButton {container=':DebugModeWidget.Toolbar_QDockWidget' toolTip='Discard data' type='QToolButton' unnamed='1' visible='1'} +:Analyzer Toolbar.Elapsed:_QLabel {container=':DebugModeWidget.Toolbar_QDockWidget' text~='Elapsed: \\\\d+.\\\\d s' type='QLabel' unnamed='1' visible='1'} +:Analyzer Toolbar.Start_QToolButton {container=':DebugModeWidget.Toolbar_QDockWidget' text='Start' type='QToolButton' unnamed='1' visible='1'} :Behavior.Autocomplete common prefix_QCheckBox {container=':CppTools__Internal__CompletionSettingsPage.Behavior_QGroupBox' name='partiallyComplete' text='Autocomplete common prefix' type='QCheckBox' visible='1'} :Behavior.completionTrigger_QComboBox {container=':CppTools__Internal__CompletionSettingsPage.Behavior_QGroupBox' name='completionTrigger' type='QComboBox' visible='1'} -:Breakpoints_Debugger::Internal::BreakTreeView {container=':DebugModeWidget.Breakpoints_QDockWidget' type='Debugger::Internal::BreakTreeView' unnamed='1' visible='1'} +:Breakpoints_Debugger::Internal::BreakTreeView {container=':Debugger.Docks.BreakDockWidget.Debugger.Docks.Break_QFrame' type='Debugger::Internal::BreakTreeView' unnamed='1' visible='1'} :Build and Run.Save all files before build_QCheckBox {name='saveAllFilesCheckBox' type='QCheckBox' visible='1'} :BuildAndRun_QTreeView {container=':qt_tabwidget_stackedwidget_QWidget' type='QTreeView' unnamed='1' visible='1'} -:CMake Wizard.Cancel_QPushButton {text='Cancel' type='QPushButton' visible='1' window=':CMake Wizard_CMakeProjectManager::Internal::CMakeOpenProjectWizard'} -:CMake Wizard.Finish_QPushButton {text~='(Finish|Done)' type='QPushButton' visible='1' window=':CMake Wizard_CMakeProjectManager::Internal::CMakeOpenProjectWizard'} -:CMake Wizard.Generator:_QLabel {text='Generator:' type='QLabel' unnamed='1' visible='1' window=':CMake Wizard_CMakeProjectManager::Internal::CMakeOpenProjectWizard'} -:CMake Wizard.Run CMake_QPushButton {text='Run CMake' type='QPushButton' unnamed='1' visible='1' window=':CMake Wizard_CMakeProjectManager::Internal::CMakeOpenProjectWizard'} -:CMake Wizard_CMakeProjectManager::Internal::CMakeOpenProjectWizard {type='CMakeProjectManager::Internal::CMakeOpenProjectWizard' unnamed='1' visible='1' windowTitle='CMake Wizard'} :Cannot Open Project.OK_QPushButton {text='OK' type='QPushButton' unnamed='1' visible='1' window=':Cannot Open Project_QMessageBox'} :Cannot Open Project.Show Details..._QPushButton {text='Show Details...' type='QPushButton' unnamed='1' visible='1' window=':Cannot Open Project_QMessageBox'} :Cannot Open Project_QMessageBox {text?='Failed to open project in *' type='QMessageBox' unnamed='1' visible='1'} @@ -59,16 +54,18 @@ :Compiler:_QLabel {container=':qt_tabwidget_stackedwidget_QWidget' text='Compiler:' type='QLabel' unnamed='1' visible='1'} :Core__Internal__GeneralSettings.User Interface_QGroupBox {container=':qt_tabwidget_stackedwidget.Core__Internal__GeneralSettings_QWidget' name='interfaceBox' title='User Interface' type='QGroupBox' visible='1'} :CppTools__Internal__CompletionSettingsPage.Behavior_QGroupBox {container=':qt_tabwidget_stackedwidget.CppTools__Internal__CompletionSettingsPage_QWidget' name='groupBox' title='Behavior' type='QGroupBox' visible='1'} -:DebugModeWidget.Breakpoints_QDockWidget {container=':Qt Creator.DebugModeWidget_QSplitter' name='Debugger.Docks.Break' type='QDockWidget' visible='1' windowTitle='Breakpoints'} -:DebugModeWidget.Debugger Log_QDockWidget {container=':Qt Creator.DebugModeWidget_QSplitter' name='Debugger.Docks.Output' type='QDockWidget' visible='1' windowTitle='Debugger Log'} +:DebugModeWidget.Debugger Log_QDockWidget {container=':Qt Creator.DebugModeWidget_QSplitter' name='Debugger.Docks.OutputDockWidget' type='QDockWidget' visible='1'} :DebugModeWidget.Debugger Toolbar_QDockWidget {container=':Qt Creator.DebugModeWidget_QSplitter' name='Debugger Toolbar' type='QDockWidget' visible='1' windowTitle='Debugger Toolbar'} +:DebugModeWidget.Debugger.Docks.BreakDockWidget_QDockWidget {container=':Qt Creator.DebugModeWidget_QSplitter' name='Debugger.Docks.BreakDockWidget' type='QDockWidget' visible='1'} :DebugModeWidget.Locals and Expressions_QDockWidget {container=':Qt Creator.DebugModeWidget_QSplitter' name='Debugger.Docks.LocalsAndWatchers' type='QDockWidget' visible='1' windowTitle='Locals and Expressions'} :DebugModeWidget.OK_QPushButton {container=':Qt Creator.DebugModeWidget_QSplitter' text='OK' type='QPushButton' unnamed='1' visible='1'} +:DebugModeWidget.Toolbar_QDockWidget {container=':Qt Creator.DebugModeWidget_QSplitter' name='Toolbar' type='QDockWidget' visible='1'} :DebugModeWidget_QComboBox {container=':Qt Creator.DebugModeWidget_QSplitter' occurrence='2' type='QComboBox' unnamed='1' visible='1'} :DebugModeWidget_Debugger::Internal::ConsoleView {container=':Qt Creator.DebugModeWidget_QSplitter' type='Debugger::Internal::ConsoleView' unnamed='1' visible='1'} -:Debugger Toolbar.Continue_QToolButton {container=':DebugModeWidget.Debugger Toolbar_QDockWidget' text='Continue' type='QToolButton' unnamed='1' visible='1'} +:Debugger Toolbar.Continue_QToolButton {container=':DebugModeWidget.Toolbar_QDockWidget' text='Continue' type='QToolButton' unnamed='1' visible='1'} :Debugger Toolbar.Exit Debugger_QToolButton {container=':DebugModeWidget.Debugger Toolbar_QDockWidget' text='Stop Debugger' type='QToolButton' unnamed='1' visible='1'} -:Debugger Toolbar.StatusText_Utils::StatusLabel {container=':DebugModeWidget.Debugger Toolbar_QDockWidget' type='Utils::StatusLabel' unnamed='1'} +:Debugger Toolbar.StatusText_Utils::StatusLabel {container=':DebugModeWidget.Toolbar_QDockWidget' type='Utils::StatusLabel' unnamed='1'} +:Debugger.Docks.BreakDockWidget.Debugger.Docks.Break_QFrame {container=':DebugModeWidget.Debugger.Docks.BreakDockWidget_QDockWidget' name='Debugger.Docks.Break' type='QFrame' visible='1'} :Description.description_Utils::CompletingTextEdit {container=':splitter.Description_QGroupBox' name='description' type='Utils::CompletingTextEdit' visible='1'} :Dialog.OK_QPushButton {text='OK' type='QPushButton' unnamed='1' visible='1' window=':Dialog_QmlJSEditor::Internal::ComponentNameDialog'} :Dialog.componentNameEdit_QLineEdit {name='componentNameEdit' type='Utils::ClassNameValidatingLineEdit' visible='1' window=':Dialog_QmlJSEditor::Internal::ComponentNameDialog'} @@ -91,7 +88,6 @@ :FormEditorStack.menuBar_QDesignerMenuBar {container=':*Qt Creator.FormEditorStack_Designer::Internal::FormEditorStack' name='menuBar' type='QDesignerMenuBar' visible='1'} :FormEditorStack_qdesigner_internal::FormWindow {container=':*Qt Creator.FormEditorStack_Designer::Internal::FormEditorStack' type='qdesigner_internal::FormWindow' unnamed='1' visible='1'} :FormEditorStack_qdesigner_internal::PropertyLineEdit {container=':*Qt Creator.FormEditorStack_Designer::Internal::FormEditorStack' type='qdesigner_internal::PropertyLineEdit' unnamed='1' visible='1'} -:Generator:_QComboBox {buddy=':CMake Wizard.Generator:_QLabel' type='QComboBox' unnamed='1' visible='1'} :Git Repository Clone.Cancel_QPushButton {text='Cancel' type='QPushButton' visible='1' window=':New Text File_ProjectExplorer::JsonWizard'} :Git Repository Clone.Finish_QPushButton {text~='(Finish|Done)' type='QPushButton' visible='1' window=':New Text File_ProjectExplorer::JsonWizard'} :Git Repository Clone.Result._QLabel {type='QLabel' unnamed='1' visible='1' window=':New Text File_ProjectExplorer::JsonWizard'} @@ -125,7 +121,6 @@ :QML Debugging_QMessageBox {text='The option will only take effect if the project is recompiled. Do you want to recompile now?' type='QMessageBox' unnamed='1' visible='1'} :Debugger::Internal::ConsoleEdit {columnIndex='0' container=':DebugModeWidget_Debugger::Internal::ConsoleView' rowIndex='0' type='Debugger::Internal::ConsoleEdit' unnamed='1' visible='1'} :Qt Creator.Add Bookmark_QToolButton {text='Add Bookmark' type='QToolButton' unnamed='1' visible='1' window=':Qt Creator_Core::Internal::MainWindow'} -:Qt Creator.Analyzer Toolbar_QDockWidget {name='Analyzer Toolbar' type='QDockWidget' visible='1' window=':Qt Creator_Core::Internal::MainWindow' windowTitle='Analyzer Toolbar'} :Qt Creator.CloseDoc_QToolButton {toolTip?='Close Document *' type='QToolButton' unnamed='1' visible='1' window=':Qt Creator_Core::Internal::MainWindow'} :Qt Creator.CloseFind_QToolButton {name='close' type='QToolButton' visible='1' window=':Qt Creator_Core::Internal::MainWindow'} :Qt Creator.Compile Output_Core::OutputWindow {type='Core::OutputWindow' unnamed='1' visible='1' window=':Qt Creator_Core::Internal::MainWindow' windowTitle='Compile Output'} diff --git a/tests/system/shared/classes.py b/tests/system/shared/classes.py index 5185d3aa76c..f276e8d19eb 100644 --- a/tests/system/shared/classes.py +++ b/tests/system/shared/classes.py @@ -100,7 +100,7 @@ class ProjectSettings: # this class defines some constants for the views of the creator's MainWindow class ViewConstants: - WELCOME, EDIT, DESIGN, DEBUG, PROJECTS, ANALYZE, HELP = range(7) + WELCOME, EDIT, DESIGN, DEBUG, PROJECTS, HELP = range(6) FIRST_AVAILABLE = 0 # always adjust the following to the highest value of the available ViewConstants when adding new LAST_AVAILABLE = HELP @@ -120,8 +120,6 @@ class ViewConstants: toolTip = ur'Switch to Debug mode (Ctrl\+|\u2303)%d' elif viewTab == ViewConstants.PROJECTS: toolTip = ur'Switch to Projects mode (Ctrl\+|\u2303)%d' - elif viewTab == ViewConstants.ANALYZE: - toolTip = ur'Switch to Analyze mode (Ctrl\+|\u2303)%d' elif viewTab == ViewConstants.HELP: toolTip = ur'Switch to Help mode (Ctrl\+|\u2303)%d' else: diff --git a/tests/system/shared/project.py b/tests/system/shared/project.py index 22170969197..d3515afb71f 100644 --- a/tests/system/shared/project.py +++ b/tests/system/shared/project.py @@ -79,23 +79,6 @@ def openCmakeProject(projectPath, buildDir): __chooseTargets__(Targets.DESKTOP_480_DEFAULT, additionalFunc=additionalFunction) clickButton(waitForObject("{text='Configure Project' type='QPushButton' unnamed='1' visible='1'" "window=':Qt Creator_Core::Internal::MainWindow'}")) - return __handleCmakeWizardPage__() - -def __handleCmakeWizardPage__(): - generatorText = "Unix Generator (Desktop 480 GCC)" - if platform.system() in ('Windows', 'Microsoft'): - generatorText = "NMake Generator (Desktop 480 MSVC2010)" - selectFromCombo(waitForObject(":Generator:_QComboBox"), generatorText) - clickButton(waitForObject(":CMake Wizard.Run CMake_QPushButton")) - try: - clickButton(waitForObject(":CMake Wizard.Finish_QPushButton", 60000)) - except LookupError: - cmakeOutput = waitForObject("{type='QPlainTextEdit' unnamed='1' visible='1' " - "window=':CMake Wizard_CMakeProjectManager::Internal::CMakeOpenProjectWizard'}") - test.warning("Error while executing cmake - see details for cmake output.", - str(cmakeOutput.plainText)) - clickButton(waitForObject(":CMake Wizard.Cancel_QPushButton")) - return False return True # this function returns a list of available targets - this is not 100% error proof diff --git a/tests/system/shared/utils.py b/tests/system/shared/utils.py index 016891a7320..97f1d7c5d42 100644 --- a/tests/system/shared/utils.py +++ b/tests/system/shared/utils.py @@ -615,9 +615,9 @@ def verifyItemOrder(items, text): def openVcsLog(): try: - foundObj = waitForObject("{type='QPlainTextEdit' unnamed='1' visible='1' " + foundObj = waitForObject("{type='Core::OutputWindow' unnamed='1' visible='1' " "window=':Qt Creator_Core::Internal::MainWindow'}", 2000) - if className(foundObj) != 'QPlainTextEdit': + if className(foundObj) != 'Core::OutputWindow': raise Exception("Found derived class, but not a pure QPlainTextEdit.") except: invokeMenuItem("Window", "Output Panes", "Version Control") diff --git a/tests/system/suite_debugger/tst_simple_analyze/test.py b/tests/system/suite_debugger/tst_simple_analyze/test.py index 57e5671d719..483f7829209 100644 --- a/tests/system/suite_debugger/tst_simple_analyze/test.py +++ b/tests/system/suite_debugger/tst_simple_analyze/test.py @@ -74,9 +74,9 @@ def performTest(workingDir, projectName, targetCount, availableConfigs): test.fatal("Compile had errors... Skipping current build config") continue allowAppThroughWinFW(workingDir, projectName, False) - switchViewTo(ViewConstants.ANALYZE) + switchViewTo(ViewConstants.DEBUG) selectFromCombo(":Analyzer Toolbar.AnalyzerManagerToolBox_QComboBox", "QML Profiler") - recordButton = waitForObject("{container=':Qt Creator.Analyzer Toolbar_QDockWidget' " + recordButton = waitForObject("{container=':DebugModeWidget.Toolbar_QDockWidget' " "type='QToolButton' unnamed='1' visible='1' " "toolTip?='*able profiling'}") if not test.verify(recordButton.checked, "Verifying recording is enabled."): diff --git a/tests/system/suite_tools/tst_git_clone/test.py b/tests/system/suite_tools/tst_git_clone/test.py index 4d0cde5ea49..bb941c473f0 100644 --- a/tests/system/suite_tools/tst_git_clone/test.py +++ b/tests/system/suite_tools/tst_git_clone/test.py @@ -63,7 +63,7 @@ def verifyCloneLog(targetDir, canceled): def verifyVersionControlView(targetDir, canceled): openVcsLog() - vcsLog = str(waitForObject("{type='QPlainTextEdit' unnamed='1' visible='1' " + vcsLog = str(waitForObject("{type='Core::OutputWindow' unnamed='1' visible='1' " "window=':Qt Creator_Core::Internal::MainWindow'}").plainText) test.log("Clone log is: %s" % vcsLog) test.verify("Executing in " + targetDir + ":" in vcsLog, @@ -123,19 +123,13 @@ def main(): continue if button == ":Git Repository Clone.Finish_QPushButton": try: - # CMake wizard shown - clickButton(waitForObject(":CMake Wizard.Cancel_QPushButton", 5000)) - clickButton(waitForObject(":Cannot Open Project.OK_QPushButton")) - test.passes("The checked out project was being opened with CMake.") + # Projects mode shown + clickButton(waitForObject(":*Qt Creator.Cancel_QPushButton", 5000)) + test.passes("The checked out project was being opened.") except: - try: - # QMake Project mode shown - clickButton(waitForObject(":*Qt Creator.Cancel_QPushButton", 5000)) - test.passes("The checked out project was being opened with QMake.") - except: - clickButton(waitForObject(":Cannot Open Project.Show Details..._QPushButton")) - test.fail("The checked out project was not being opened.", - waitForObject(":Cannot Open Project_QTextEdit").plainText) - clickButton(waitForObject(":Cannot Open Project.OK_QPushButton")) + clickButton(waitForObject(":Cannot Open Project.Show Details..._QPushButton")) + test.fail("The checked out project was not being opened.", + waitForObject(":Cannot Open Project_QTextEdit").plainText) + clickButton(waitForObject(":Cannot Open Project.OK_QPushButton")) verifyVersionControlView(targetDir, button == "Cancel immediately") invokeMenuItem("File", "Exit") diff --git a/tests/system/suite_tools/tst_git_local/test.py b/tests/system/suite_tools/tst_git_local/test.py index b969c4c86d1..affd6bbc64f 100644 --- a/tests/system/suite_tools/tst_git_local/test.py +++ b/tests/system/suite_tools/tst_git_local/test.py @@ -166,7 +166,7 @@ def main(): return createProject_Qt_GUI(srcPath, projectName, addToVersionControl = "Git") openVcsLog() - vcsLog = waitForObject("{type='QPlainTextEdit' unnamed='1' visible='1' " + vcsLog = waitForObject("{type='Core::OutputWindow' unnamed='1' visible='1' " "window=':Qt Creator_Core::Internal::MainWindow'}").plainText test.verify("Initialized empty Git repository in %s" % os.path.join(srcPath, projectName, ".git").replace("\\", "/") in str(vcsLog),