diff --git a/doc/fixnavi.pl b/doc/fixnavi.pl index 1ddbd4fe1ba..eb0f16be57b 100755 --- a/doc/fixnavi.pl +++ b/doc/fixnavi.pl @@ -133,7 +133,8 @@ my %next = (); my $last = $doctitle; my $lastpage = $title2page{$last}; for my $title (@toc) { - my $page = $title2page{$title}; + my $type = $title2type{$title}; + my $page = ($type eq "page") ? $title2page{$title} : "{$title}\n"; defined($page) or die "TOC refers to unknown page/example '$title'.\n"; $next{$last} = $page; $prev{$title} = $lastpage; diff --git a/share/qtcreator/debugger/dumper.py b/share/qtcreator/debugger/dumper.py index 9111b230b37..40230fee147 100644 --- a/share/qtcreator/debugger/dumper.py +++ b/share/qtcreator/debugger/dumper.py @@ -286,8 +286,6 @@ class DumperBase: 'personaltypes', ] - self.currentQtNamespaceGuess = None - # These values are never used, but the variables need to have # some value base for the swapping logic in Children.__enter__() # and Children.__exit__(). @@ -324,11 +322,6 @@ class DumperBase: #warn('EXPANDED INAMES: %s' % self.expandedINames) #warn('WATCHERS: %s' % self.watchers) - # The guess does not need to be updated during a fetchVariables() - # as the result is fixed during that time (ignoring "active" - # dumpers causing loading of shared objects etc). - self.currentQtNamespaceGuess = None - def resetCaches(self): # This is a cache mapping from 'type name' to 'display alternatives'. self.qqFormats = { 'QVariant (QVariantMap)' : mapForms() } diff --git a/share/qtcreator/debugger/gdbbridge.py b/share/qtcreator/debugger/gdbbridge.py index ebf15ab8288..33c19a20658 100644 --- a/share/qtcreator/debugger/gdbbridge.py +++ b/share/qtcreator/debugger/gdbbridge.py @@ -959,10 +959,8 @@ class Dumper(DumperBase): self.importPlainDumper(printer) def qtNamespace(self): - self.preping('qtNamespace') - res = self.qtNamespaceX() - self.ping('qtNamespace') - return res + # This function is replaced by handleQtCoreLoaded() + return '' def findSymbol(self, symbolName): try: @@ -970,53 +968,55 @@ class Dumper(DumperBase): except: return 0 - def qtNamespaceX(self): - if not self.currentQtNamespaceGuess is None: - return self.currentQtNamespaceGuess + def handleNewObjectFile(self, objfile): + name = objfile.filename + if self.isWindowsTarget(): + isQtCoreObjFile = name.find('Qt5Cored.dll') >= 0 or name.find('Qt5Core.dll') >= 0 + else: + isQtCoreObjFile = name.find('/libQt5Core') >= 0 + if isQtCoreObjFile: + self.handleQtCoreLoaded(objfile) - for objfile in gdb.objfiles(): - name = objfile.filename - if name.find('/libQt5Core') >= 0: - fd, tmppath = tempfile.mkstemp() - os.close(fd) - cmd = 'maint print msymbols %s "%s"' % (tmppath, name) - symbols = gdb.execute(cmd, to_string = True) - ns = '' - with open(tmppath) as f: - for line in f: - if line.find('msgHandlerGrabbed ') >= 0: - # [11] b 0x7ffff683c000 _ZN4MynsL17msgHandlerGrabbedE - # section .tbss Myns::msgHandlerGrabbed qlogging.cpp - ns = re.split('_ZN?(\d*)(\w*)L17msgHandlerGrabbedE? ', line)[2] - if len(ns): - ns += '::' - break - os.remove(tmppath) + def handleQtCoreLoaded(self, objfile): + fd, tmppath = tempfile.mkstemp() + os.close(fd) + cmd = 'maint print msymbols %s "%s"' % (tmppath, objfile.filename) + try: + symbols = gdb.execute(cmd, to_string = True) + except: + pass + ns = '' + with open(tmppath) as f: + for line in f: + if line.find('msgHandlerGrabbed ') >= 0: + # [11] b 0x7ffff683c000 _ZN4MynsL17msgHandlerGrabbedE + # section .tbss Myns::msgHandlerGrabbed qlogging.cpp + ns = re.split('_ZN?(\d*)(\w*)L17msgHandlerGrabbedE? ', line)[2] + if len(ns): + ns += '::' + break + os.remove(tmppath) - lenns = len(ns) - strns = ('%d%s' % (lenns - 2, ns[:lenns - 2])) if lenns else '' + lenns = len(ns) + strns = ('%d%s' % (lenns - 2, ns[:lenns - 2])) if lenns else '' - if lenns: - sym = '_ZN%s7QObject11customEventEPNS_6QEventE' % strns - else: - sym = '_ZN7QObject11customEventEP6QEvent' - self.qtCustomEventFunc = self.findSymbol(sym) + if lenns: + # This might be wrong, but we can't do better: We found + # a libQt5Core and could not extract a namespace. + # The best guess is that there isn't any. + self.qtNamespaceToReport = ns + self.qtNamespace = lambda: ns - sym += '@plt' - self.qtCustomEventPltFunc = self.findSymbol(sym) + sym = '_ZN%s7QObject11customEventEPNS_6QEventE' % strns + else: + sym = '_ZN7QObject11customEventEP6QEvent' + self.qtCustomEventFunc = self.findSymbol(sym) - sym = '_ZNK%s7QObject8propertyEPKc' % strns - self.qtPropertyFunc = self.findSymbol(sym) + sym += '@plt' + self.qtCustomEventPltFunc = self.findSymbol(sym) - # This might be wrong, but we can't do better: We found - # a libQt5Core and could not extract a namespace. - # The best guess is that there isn't any. - self.qtNamespaceToReport = ns - self.qtNamespace = lambda: ns - return ns - - self.currentQtNamespaceGuess = '' - return '' + sym = '_ZNK%s7QObject8propertyEPKc' % strns + self.qtPropertyFunc = self.findSymbol(sym) def assignValue(self, args): typeName = self.hexdecode(args['type']) @@ -1406,4 +1406,17 @@ class InterpreterMessageBreakpoint(gdb.Breakpoint): print('Interpreter event received.') return theDumper.handleInterpreterMessage() + +####################################################################### +# +# Shared objects +# +####################################################################### + +def new_objfile_handler(event): + return theDumper.handleNewObjectFile(event.new_objfile) + +gdb.events.new_objfile.connect(new_objfile_handler) + + #InterpreterMessageBreakpoint() diff --git a/src/libs/modelinglib/qmt/diagram_scene/items/classitem.cpp b/src/libs/modelinglib/qmt/diagram_scene/items/classitem.cpp index 87354577fba..8f6c935417f 100644 --- a/src/libs/modelinglib/qmt/diagram_scene/items/classitem.cpp +++ b/src/libs/modelinglib/qmt/diagram_scene/items/classitem.cpp @@ -565,11 +565,6 @@ void ClassItem::updateMembers(const Style *style) auto dclass = dynamic_cast(object()); QMT_CHECK(dclass); - // TODO move bool haveIconFonts into class Style? - bool haveIconFonts = false; // style->normalFont().family() == QStringLiteral("Modelling"); - // TODO any reason to show visibility as group instead of per member? - bool useGroupVisibility = false; - foreach (const MClassMember &member, dclass->members()) { switch (member.memberType()) { case MClassMember::MemberUndefined: @@ -587,50 +582,14 @@ void ClassItem::updateMembers(const Style *style) break; } - if (!text->isEmpty()) + if (text && !text->isEmpty()) *text += QStringLiteral("
"); bool addNewline = false; bool addSpace = false; - if (member.visibility() != *currentVisibility) { - if (useGroupVisibility) { - if (member.visibility() != MClassMember::VisibilityUndefined) { - QString vis; - switch (member.visibility()) { - case MClassMember::VisibilityUndefined: - break; - case MClassMember::VisibilityPublic: - vis = QStringLiteral("public:"); - break; - case MClassMember::VisibilityProtected: - vis = QStringLiteral("protected:"); - break; - case MClassMember::VisibilityPrivate: - vis = QStringLiteral("private:"); - break; - case MClassMember::VisibilitySignals: - vis = QStringLiteral("signals:"); - break; - case MClassMember::VisibilityPrivateSlots: - vis = QStringLiteral("private slots:"); - break; - case MClassMember::VisibilityProtectedSlots: - vis = QStringLiteral("protected slots:"); - break; - case MClassMember::VisibilityPublicSlots: - vis = QStringLiteral("public slots:"); - break; - } - *text += vis; - addNewline = true; - addSpace = true; - } - } + if (currentVisibility) *currentVisibility = member.visibility(); - } if (member.group() != currentGroup) { - if (addSpace) - *text += QStringLiteral(" "); *text += QString(QStringLiteral("[%1]")).arg(member.group()); addNewline = true; *currentGroup = member.group(); @@ -638,61 +597,55 @@ void ClassItem::updateMembers(const Style *style) if (addNewline) *text += QStringLiteral("
"); - addSpace = false; bool haveSignal = false; bool haveSlot = false; - if (!useGroupVisibility) { - if (member.visibility() != MClassMember::VisibilityUndefined) { - QString vis; - switch (member.visibility()) { - case MClassMember::VisibilityUndefined: - break; - case MClassMember::VisibilityPublic: - vis = haveIconFonts ? QString(QChar(0xe990)) : QStringLiteral("+"); - addSpace = true; - break; - case MClassMember::VisibilityProtected: - vis = haveIconFonts ? QString(QChar(0xe98e)) : QStringLiteral("#"); - addSpace = true; - break; - case MClassMember::VisibilityPrivate: - vis = haveIconFonts ? QString(QChar(0xe98f)) : QStringLiteral("-"); - addSpace = true; - break; - case MClassMember::VisibilitySignals: - vis = haveIconFonts ? QString(QChar(0xe994)) : QStringLiteral(">"); - haveSignal = true; - addSpace = true; - break; - case MClassMember::VisibilityPrivateSlots: - vis = haveIconFonts ? QString(QChar(0xe98f)) + QChar(0xe9cb) - : QStringLiteral("-$"); - haveSlot = true; - addSpace = true; - break; - case MClassMember::VisibilityProtectedSlots: - vis = haveIconFonts ? QString(QChar(0xe98e)) + QChar(0xe9cb) - : QStringLiteral("#$"); - haveSlot = true; - addSpace = true; - break; - case MClassMember::VisibilityPublicSlots: - vis = haveIconFonts ? QString(QChar(0xe990)) + QChar(0xe9cb) - : QStringLiteral("+$"); - haveSlot = true; - addSpace = true; - break; - } - *text += vis; + if (member.visibility() != MClassMember::VisibilityUndefined) { + QString vis; + switch (member.visibility()) { + case MClassMember::VisibilityUndefined: + break; + case MClassMember::VisibilityPublic: + vis = QStringLiteral("+"); + addSpace = true; + break; + case MClassMember::VisibilityProtected: + vis = QStringLiteral("#"); + addSpace = true; + break; + case MClassMember::VisibilityPrivate: + vis = QStringLiteral("-"); + addSpace = true; + break; + case MClassMember::VisibilitySignals: + vis = QStringLiteral(">"); + haveSignal = true; + addSpace = true; + break; + case MClassMember::VisibilityPrivateSlots: + vis = QStringLiteral("-$"); + haveSlot = true; + addSpace = true; + break; + case MClassMember::VisibilityProtectedSlots: + vis = QStringLiteral("#$"); + haveSlot = true; + addSpace = true; + break; + case MClassMember::VisibilityPublicSlots: + vis = QStringLiteral("+$"); + haveSlot = true; + addSpace = true; + break; } + *text += vis; } if (member.properties() & MClassMember::PropertyQsignal && !haveSignal) { - *text += haveIconFonts ? QString(QChar(0xe994)) : QStringLiteral(">"); + *text += QStringLiteral(">"); addSpace = true; } if (member.properties() & MClassMember::PropertyQslot && !haveSlot) { - *text += haveIconFonts ? QString(QChar(0xe9cb)) : QStringLiteral("$"); + *text += QStringLiteral("$"); addSpace = true; } if (addSpace) diff --git a/src/libs/qmljs/parser/qmljskeywords_p.h b/src/libs/qmljs/parser/qmljskeywords_p.h index df0030d6dde..94c2d8aca23 100644 --- a/src/libs/qmljs/parser/qmljskeywords_p.h +++ b/src/libs/qmljs/parser/qmljskeywords_p.h @@ -63,7 +63,7 @@ static inline int classify2(const QChar *s, bool qmlMode) { } else if (qmlMode && s[0].unicode() == 'o') { if (s[1].unicode() == 'n') { - return qmlMode ? Lexer::T_ON : Lexer::T_IDENTIFIER; + return Lexer::T_ON; } } return Lexer::T_IDENTIFIER; @@ -675,7 +675,7 @@ static inline int classify8(const QChar *s, bool qmlMode) { if (s[5].unicode() == 'r') { if (s[6].unicode() == 't') { if (s[7].unicode() == 'y') { - return qmlMode ? Lexer::T_PROPERTY : Lexer::T_IDENTIFIER; + return Lexer::T_PROPERTY; } } } diff --git a/src/libs/qmljs/qmljscheck.cpp b/src/libs/qmljs/qmljscheck.cpp index 714d20dc049..2b07dd1c66f 100644 --- a/src/libs/qmljs/qmljscheck.cpp +++ b/src/libs/qmljs/qmljscheck.cpp @@ -33,6 +33,7 @@ #include #include +#include using namespace QmlJS; using namespace QmlJS::AST; diff --git a/src/libs/qmljs/qmljsdocument.cpp b/src/libs/qmljs/qmljsdocument.cpp index 071da4fff92..474a64b1e7d 100644 --- a/src/libs/qmljs/qmljsdocument.cpp +++ b/src/libs/qmljs/qmljsdocument.cpp @@ -35,6 +35,7 @@ #include #include #include +#include #include diff --git a/src/libs/qmljs/qmljsfindexportedcpptypes.cpp b/src/libs/qmljs/qmljsfindexportedcpptypes.cpp index e1c4d55de70..7c45339d905 100644 --- a/src/libs/qmljs/qmljsfindexportedcpptypes.cpp +++ b/src/libs/qmljs/qmljsfindexportedcpptypes.cpp @@ -34,6 +34,7 @@ #include #include +#include //using namespace QmlJS; diff --git a/src/libs/qmljs/qmljsmodelmanagerinterface.cpp b/src/libs/qmljs/qmljsmodelmanagerinterface.cpp index 577fbf4b2b1..d88b1c261e7 100644 --- a/src/libs/qmljs/qmljsmodelmanagerinterface.cpp +++ b/src/libs/qmljs/qmljsmodelmanagerinterface.cpp @@ -579,7 +579,7 @@ void ModelManagerInterface::updateProjectInfo(const ProjectInfo &pinfo, ProjectE &majorVersion, &minorVersion, &patchVersion) != 3) majorVersion = minorVersion = patchVersion = -1; - if (majorVersion > 4 || (majorVersion == 4 && (minorVersion > 8 || (majorVersion == 8 + if (majorVersion > 4 || (majorVersion == 4 && (minorVersion > 8 || (minorVersion == 8 && patchVersion >= 5)))) { m_pluginDumper->loadBuiltinTypes(pinfo); } diff --git a/src/libs/qmljs/qmljsscopechain.cpp b/src/libs/qmljs/qmljsscopechain.cpp index a2d3b253efb..cda0b0c6564 100644 --- a/src/libs/qmljs/qmljsscopechain.cpp +++ b/src/libs/qmljs/qmljsscopechain.cpp @@ -29,6 +29,8 @@ #include "qmljsmodelmanagerinterface.h" #include "parser/qmljsengine_p.h" +#include + using namespace QmlJS; /*! diff --git a/src/libs/utils/buildablehelperlibrary.cpp b/src/libs/utils/buildablehelperlibrary.cpp index c46b4b85020..13d3f14f4b7 100644 --- a/src/libs/utils/buildablehelperlibrary.cpp +++ b/src/libs/utils/buildablehelperlibrary.cpp @@ -30,6 +30,7 @@ #include #include #include +#include namespace Utils { diff --git a/src/libs/utils/fileutils.cpp b/src/libs/utils/fileutils.cpp index 000407f01f1..fb70cbf85af 100644 --- a/src/libs/utils/fileutils.cpp +++ b/src/libs/utils/fileutils.cpp @@ -36,6 +36,7 @@ #include #include #include +#include #include #include diff --git a/src/libs/utils/qtcprocess.cpp b/src/libs/utils/qtcprocess.cpp index 5868e52d9c0..be588bfbbf7 100644 --- a/src/libs/utils/qtcprocess.cpp +++ b/src/libs/utils/qtcprocess.cpp @@ -32,6 +32,7 @@ #include #include #include +#include #include #ifdef Q_OS_WIN diff --git a/src/libs/utils/templateengine.cpp b/src/libs/utils/templateengine.cpp index b76d42d6314..e78af8bc36a 100644 --- a/src/libs/utils/templateengine.cpp +++ b/src/libs/utils/templateengine.cpp @@ -28,6 +28,7 @@ #include "qtcassert.h" #include +#include #include namespace Utils { diff --git a/src/plugins/android/androidmanager.cpp b/src/plugins/android/androidmanager.cpp index 29791c2ae6a..0b8762f24dc 100644 --- a/src/plugins/android/androidmanager.cpp +++ b/src/plugins/android/androidmanager.cpp @@ -56,6 +56,7 @@ #include #include #include +#include #include #include #include diff --git a/src/plugins/android/androidrunner.cpp b/src/plugins/android/androidrunner.cpp index 593e44ef758..e7b95bc0767 100644 --- a/src/plugins/android/androidrunner.cpp +++ b/src/plugins/android/androidrunner.cpp @@ -47,6 +47,7 @@ #include #include #include +#include #include #include #include diff --git a/src/plugins/android/androidtoolchain.cpp b/src/plugins/android/androidtoolchain.cpp index 63cf260bdd3..0f8defe6d1b 100644 --- a/src/plugins/android/androidtoolchain.cpp +++ b/src/plugins/android/androidtoolchain.cpp @@ -45,6 +45,7 @@ #include #include #include +#include #include namespace { diff --git a/src/plugins/android/javaparser.h b/src/plugins/android/javaparser.h index 642db44e236..f47075b4e28 100644 --- a/src/plugins/android/javaparser.h +++ b/src/plugins/android/javaparser.h @@ -28,6 +28,8 @@ #include #include +#include + namespace Android { namespace Internal { diff --git a/src/plugins/autotest/gtest/gtestoutputreader.cpp b/src/plugins/autotest/gtest/gtestoutputreader.cpp index 973f384c941..2eba52e7537 100644 --- a/src/plugins/autotest/gtest/gtestoutputreader.cpp +++ b/src/plugins/autotest/gtest/gtestoutputreader.cpp @@ -28,6 +28,7 @@ #include #include +#include namespace Autotest { namespace Internal { diff --git a/src/plugins/autotest/quick/quicktestparser.cpp b/src/plugins/autotest/quick/quicktestparser.cpp index f6b7cf78176..c3440ce15d2 100644 --- a/src/plugins/autotest/quick/quicktestparser.cpp +++ b/src/plugins/autotest/quick/quicktestparser.cpp @@ -165,7 +165,6 @@ static QList scanDirectoryForQuickTestQmlFiles(const QStri } static bool checkQmlDocumentForQuickTestCode(QFutureInterface futureInterface, - const QmlJS::Snapshot &snapshot, const QmlJS::Document::Ptr &qmlJSDoc, const Core::Id &id, const QString &proFile = QString()) @@ -174,6 +173,7 @@ static bool checkQmlDocumentForQuickTestCode(QFutureInterfaceast(); QTC_ASSERT(ast, return false); + QmlJS::Snapshot snapshot = QmlJS::ModelManagerInterface::instance()->snapshot(); TestQmlVisitor qmlVisitor(qmlJSDoc, snapshot); QmlJS::AST::Node::accept(ast, &qmlVisitor); if (!qmlVisitor.isValid()) @@ -212,7 +212,6 @@ static bool checkQmlDocumentForQuickTestCode(QFutureInterface futureInterface, - const QmlJS::Snapshot &snapshot, CPlusPlus::Document::Ptr document, const Core::Id &id) { @@ -233,7 +232,7 @@ static bool handleQtQuickTest(QFutureInterface futureInterfa const QList qmlDocs = scanDirectoryForQuickTestQmlFiles(srcDir); bool result = false; for (const QmlJS::Document::Ptr &qmlJSDoc : qmlDocs) - result |= checkQmlDocumentForQuickTestCode(futureInterface, snapshot, qmlJSDoc, id, proFile); + result |= checkQmlDocumentForQuickTestCode(futureInterface, qmlJSDoc, id, proFile); return result; } @@ -280,14 +279,14 @@ bool QuickTestParser::processDocument(QFutureInterface futur if (proFile.isEmpty()) return false; QmlJS::Document::Ptr qmlJSDoc = m_qmlSnapshot.document(fileName); - return checkQmlDocumentForQuickTestCode(futureInterface, m_qmlSnapshot, qmlJSDoc, id(), proFile); + return checkQmlDocumentForQuickTestCode(futureInterface, qmlJSDoc, id(), proFile); } if (!m_cppSnapshot.contains(fileName) || !selectedForBuilding(fileName)) return false; CPlusPlus::Document::Ptr document = m_cppSnapshot.find(fileName).value(); if (!includesQtQuickTest(document, m_cppSnapshot)) return false; - return handleQtQuickTest(futureInterface, m_qmlSnapshot, document, id()); + return handleQtQuickTest(futureInterface, document, id()); } } // namespace Internal diff --git a/src/plugins/autotest/testrunner.cpp b/src/plugins/autotest/testrunner.cpp index 16ad6efbfac..2e579e7dfa9 100644 --- a/src/plugins/autotest/testrunner.cpp +++ b/src/plugins/autotest/testrunner.cpp @@ -166,11 +166,11 @@ static void performTestRun(QFutureInterface &futureInterface, } } else { futureInterface.reportResult(TestResultPtr(new FaultyTestResult(Result::MessageFatal, - QString("Failed to start test for project \"%1\".").arg(testConfiguration->displayName())))); + TestRunner::tr("Failed to start test for project \"%1\".").arg(testConfiguration->displayName())))); } if (testProcess.exitStatus() == QProcess::CrashExit) { futureInterface.reportResult(TestResultPtr(new FaultyTestResult(Result::MessageFatal, - QString("Test for project \"%1\" crashed.").arg(testConfiguration->displayName())))); + TestRunner::tr("Test for project \"%1\" crashed.").arg(testConfiguration->displayName())))); } if (canceledByTimeout) { diff --git a/src/plugins/autotoolsprojectmanager/autotoolsproject.cpp b/src/plugins/autotoolsprojectmanager/autotoolsproject.cpp index a01fe2c518d..296142ec5a4 100644 --- a/src/plugins/autotoolsprojectmanager/autotoolsproject.cpp +++ b/src/plugins/autotoolsprojectmanager/autotoolsproject.cpp @@ -215,16 +215,12 @@ void AutotoolsProject::makefileParsingFinished() m_watchedFiles.append(configureAcFilePath); } - QList fileNodes = Utils::transform(files, [dir](const QString &f) { - const Utils::FileName path = Utils::FileName::fromString(dir.absoluteFilePath(f)); - return new FileNode(path, - (f == QLatin1String("Makefile.am") || - f == QLatin1String("configure.ac")) ? FileType::Project : FileType::Resource, - false); - }); - auto newRoot = new AutotoolsProjectNode(projectDirectory()); - newRoot->buildTree(fileNodes); + for (const QString &f : files) { + const Utils::FileName path = Utils::FileName::fromString(dir.absoluteFilePath(f)); + FileType ft = (f == "Makefile.am" || f == "configure.ac") ? FileType::Project : FileType::Resource; + newRoot->addNestedNode(new FileNode(path, ft, false)); + } setRootProjectNode(newRoot); updateCppCodeModel(); diff --git a/src/plugins/bazaar/bazaarclient.cpp b/src/plugins/bazaar/bazaarclient.cpp index b2bdac3288b..d8d13cd27a5 100644 --- a/src/plugins/bazaar/bazaarclient.cpp +++ b/src/plugins/bazaar/bazaarclient.cpp @@ -36,6 +36,7 @@ #include #include +#include #include #include diff --git a/src/plugins/clangstaticanalyzer/clangstaticanalyzerruncontrol.cpp b/src/plugins/clangstaticanalyzer/clangstaticanalyzerruncontrol.cpp index 1a31123fc6a..35607a95480 100644 --- a/src/plugins/clangstaticanalyzer/clangstaticanalyzerruncontrol.cpp +++ b/src/plugins/clangstaticanalyzer/clangstaticanalyzerruncontrol.cpp @@ -189,9 +189,6 @@ public: optionsBuilder.addPrecompiledHeaderOptions(pchUsage); optionsBuilder.addMsvcCompatibilityVersion(); - if (type != ProjectExplorer::Constants::MSVC_TOOLCHAIN_TYPEID) - optionsBuilder.add(QLatin1String("-fPIC")); // TODO: Remove? - return optionsBuilder.options(); } diff --git a/src/plugins/clearcase/clearcasesync.cpp b/src/plugins/clearcase/clearcasesync.cpp index cbbacba8109..8f8262ee7c5 100644 --- a/src/plugins/clearcase/clearcasesync.cpp +++ b/src/plugins/clearcase/clearcasesync.cpp @@ -29,6 +29,7 @@ #include #include #include +#include #include #include diff --git a/src/plugins/cmakeprojectmanager/builddirmanager.cpp b/src/plugins/cmakeprojectmanager/builddirmanager.cpp index a68dd482201..f3e039cd375 100644 --- a/src/plugins/cmakeprojectmanager/builddirmanager.cpp +++ b/src/plugins/cmakeprojectmanager/builddirmanager.cpp @@ -24,43 +24,26 @@ ****************************************************************************/ #include "builddirmanager.h" + #include "cmakebuildconfiguration.h" #include "cmakekitinformation.h" -#include "cmakeparser.h" -#include "cmakeprojectconstants.h" -#include "cmakeprojectmanager.h" #include "cmakeprojectnodes.h" #include "cmaketool.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 using namespace ProjectExplorer; @@ -274,7 +257,7 @@ bool BuildDirManager::persistCMakeState() return true; } -void BuildDirManager::generateProjectTree(CMakeListsNode *root, const QList &allFiles) +void BuildDirManager::generateProjectTree(CMakeProjectNode *root, const QList &allFiles) { QTC_ASSERT(m_reader, return); diff --git a/src/plugins/cmakeprojectmanager/builddirmanager.h b/src/plugins/cmakeprojectmanager/builddirmanager.h index 85b95884648..4446c3f03f2 100644 --- a/src/plugins/cmakeprojectmanager/builddirmanager.h +++ b/src/plugins/cmakeprojectmanager/builddirmanager.h @@ -69,7 +69,7 @@ public: bool updateCMakeStateBeforeBuild(); bool persistCMakeState(); - void generateProjectTree(CMakeListsNode *root, + void generateProjectTree(CMakeProjectNode *root, const QList &allFiles); void updateCodeModel(CppTools::RawProjectParts &rpps); diff --git a/src/plugins/cmakeprojectmanager/builddirreader.h b/src/plugins/cmakeprojectmanager/builddirreader.h index b13de736f20..42630c5e13a 100644 --- a/src/plugins/cmakeprojectmanager/builddirreader.h +++ b/src/plugins/cmakeprojectmanager/builddirreader.h @@ -42,7 +42,7 @@ namespace CMakeProjectManager { namespace Internal { class CMakeBuildConfiguration; -class CMakeListsNode; +class CMakeProjectNode; class BuildDirReader : public QObject { @@ -95,7 +95,7 @@ public: virtual CMakeConfig takeParsedConfiguration() = 0; virtual QList buildTargets() const = 0; - virtual void generateProjectTree(CMakeListsNode *root, + virtual void generateProjectTree(CMakeProjectNode *root, const QList &allFiles) = 0; virtual void updateCodeModel(CppTools::RawProjectParts &rpps) = 0; diff --git a/src/plugins/cmakeprojectmanager/cmakeautocompleter.cpp b/src/plugins/cmakeprojectmanager/cmakeautocompleter.cpp index 2605830d0b5..8c2a0ba0a1d 100644 --- a/src/plugins/cmakeprojectmanager/cmakeautocompleter.cpp +++ b/src/plugins/cmakeprojectmanager/cmakeautocompleter.cpp @@ -25,6 +25,7 @@ #include "cmakeautocompleter.h" +#include #include #include #include diff --git a/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp b/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp index f33ecf164a8..6db04c5287a 100644 --- a/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp +++ b/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp @@ -215,13 +215,13 @@ QList CMakeBuildConfiguration::buildTargets() const return m_buildDirManager->buildTargets(); } -CMakeListsNode * +CMakeProjectNode * CMakeBuildConfiguration::generateProjectTree(const QList &allFiles) const { - auto root = new CMakeListsNode(target()->project()->projectFilePath()); if (!m_buildDirManager || m_buildDirManager->isParsing()) return nullptr; + auto root = new CMakeProjectNode(target()->project()->projectDirectory()); m_buildDirManager->generateProjectTree(root, allFiles); return root; } diff --git a/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.h b/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.h index 3ebc2e80bb0..c97cd0f33ae 100644 --- a/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.h +++ b/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.h @@ -47,7 +47,7 @@ namespace Internal { class BuildDirManager; class CMakeBuildConfigurationFactory; class CMakeBuildSettingsWidget; -class CMakeListsNode; +class CMakeProjectNode; class CMakeBuildConfiguration : public ProjectExplorer::BuildConfiguration { @@ -86,7 +86,7 @@ public: void clearCache(); QList buildTargets() const; - CMakeListsNode *generateProjectTree(const QList &allFiles) const; + CMakeProjectManager::Internal::CMakeProjectNode *generateProjectTree(const QList &allFiles) const; void updateCodeModel(CppTools::RawProjectParts &rpps); static Utils::FileName diff --git a/src/plugins/cmakeprojectmanager/cmakebuildstep.h b/src/plugins/cmakeprojectmanager/cmakebuildstep.h index 1fb677e24cb..e7cec2c3b6d 100644 --- a/src/plugins/cmakeprojectmanager/cmakebuildstep.h +++ b/src/plugins/cmakeprojectmanager/cmakebuildstep.h @@ -27,6 +27,8 @@ #include +#include + QT_BEGIN_NAMESPACE class QLineEdit; class QListWidget; diff --git a/src/plugins/cmakeprojectmanager/cmakeparser.h b/src/plugins/cmakeprojectmanager/cmakeparser.h index f8ea4464818..85a20d870d9 100644 --- a/src/plugins/cmakeprojectmanager/cmakeparser.h +++ b/src/plugins/cmakeprojectmanager/cmakeparser.h @@ -30,6 +30,7 @@ #include #include +#include #include namespace CMakeProjectManager { diff --git a/src/plugins/cmakeprojectmanager/cmakeproject.cpp b/src/plugins/cmakeprojectmanager/cmakeproject.cpp index 1ecc0c6e5ee..9339591c939 100644 --- a/src/plugins/cmakeprojectmanager/cmakeproject.cpp +++ b/src/plugins/cmakeprojectmanager/cmakeproject.cpp @@ -309,21 +309,15 @@ QString CMakeProject::displayName() const QStringList CMakeProject::files(FilesMode fileMode) const { - const QList nodes = filtered(rootProjectNode()->recursiveFileNodes(), - [fileMode](const FileNode *fn) { + QStringList result; + rootProjectNode()->forEachNode([&](const FileNode *fn) { const bool isGenerated = fn->isGenerated(); - switch (fileMode) - { - case Project::SourceFiles: - return !isGenerated; - case Project::GeneratedFiles: - return isGenerated; - case Project::AllFiles: - default: - return true; - } + if (fileMode == Project::SourceFiles && !isGenerated) + result.append(fn->filePath().toString()); + if (fileMode == Project::GeneratedFiles && isGenerated) + result.append(fn->filePath().toString()); }); - return transform(nodes, [fileMode](const FileNode* fn) { return fn->filePath().toString(); }); + return result; } Project::RestoreResult CMakeProject::fromMap(const QVariantMap &map, QString *errorMessage) diff --git a/src/plugins/cmakeprojectmanager/servermodereader.cpp b/src/plugins/cmakeprojectmanager/servermodereader.cpp index ed6daf8e5ec..b62060b1032 100644 --- a/src/plugins/cmakeprojectmanager/servermodereader.cpp +++ b/src/plugins/cmakeprojectmanager/servermodereader.cpp @@ -95,6 +95,8 @@ void ServerModeReader::setParameters(const BuildDirReader::Parameters &p) this, &ServerModeReader::handleError); connect(m_cmakeServer.get(), &ServerMode::cmakeProgress, this, &ServerModeReader::handleProgress); + connect(m_cmakeServer.get(), &ServerMode::cmakeSignal, + this, &ServerModeReader::handleSignal); connect(m_cmakeServer.get(), &ServerMode::cmakeMessage, this, [this](const QString &m) { Core::MessageManager::write(m); }); connect(m_cmakeServer.get(), &ServerMode::message, @@ -224,12 +226,12 @@ static void addCMakeVFolder(FolderNode *base, const Utils::FileName &basePath, i auto folder = new VirtualFolderNode(basePath, priority); folder->setDisplayName(displayName); base->addNode(folder); - folder->buildTree(files); + folder->addNestedNodes(files); for (FolderNode *fn : folder->folderNodes()) fn->compress(); } -static void addCMakeInputs(CMakeListsNode *root, +static void addCMakeInputs(FolderNode *root, const Utils::FileName &sourceDir, const Utils::FileName &buildDir, QList &sourceInputs, @@ -250,7 +252,7 @@ static void addCMakeInputs(CMakeListsNode *root, rootInputs); } -void ServerModeReader::generateProjectTree(CMakeListsNode *root, +void ServerModeReader::generateProjectTree(CMakeProjectNode *root, const QList &allFiles) { // Split up cmake inputs into useful chunks: @@ -304,6 +306,7 @@ void ServerModeReader::updateCodeModel(CppTools::RawProjectParts &rpps) CppTools::RawProjectPart rpp; rpp.setProjectFileLocation(fg->target->sourceDirectory.toString() + "/CMakeLists.txt"); + rpp.setBuildSystemTarget(fg->target->name); rpp.setDisplayName(fg->target->name + QString::number(counter)); rpp.setDefines(defineArg.toUtf8()); rpp.setIncludePaths(includes); @@ -387,6 +390,13 @@ void ServerModeReader::handleProgress(int min, int cur, int max, const QString & m_future->setProgressValue(progress); } +void ServerModeReader::handleSignal(const QString &signal, const QVariantMap &data) +{ + Q_UNUSED(data); + if (signal == "dirty") + emit dirty(); +} + void ServerModeReader::extractCodeModelData(const QVariantMap &data) { const QVariantList configs = data.value("configurations").toList(); @@ -518,97 +528,29 @@ void ServerModeReader::extractCacheData(const QVariantMap &data) m_cmakeCache = config; } -void ServerModeReader::addCMakeLists(CMakeListsNode *root, const QList &cmakeLists) +void ServerModeReader::addCMakeLists(CMakeProjectNode *root, const QList &cmakeLists) { const QDir baseDir = QDir(m_parameters.sourceDirectory.toString()); - QHash nodeHash; - for (FileNode *cm : cmakeLists) { - const QString relPath = baseDir.relativeFilePath(cm->filePath().parentDir().toString()); - QTC_CHECK(!nodeHash.contains(relPath)); - nodeHash[(relPath == ".") ? QString() : relPath ] = cm; - } - QStringList tmp = nodeHash.keys(); - Utils::sort(tmp, [](const QString &a, const QString &b) { return a.count() < b.count(); }); - const QStringList keys = tmp; - - QHash knownNodes; - knownNodes[QString()] = root; - - for (const QString &k : keys) { - FileNode *fn = nodeHash[k]; - CMakeListsNode *parentNode = nullptr; - QString prefix = k; - forever { - if (knownNodes.contains(prefix)) { - parentNode = knownNodes.value(prefix); - break; - } - const int pos = prefix.lastIndexOf('/'); - prefix = (pos < 0) ? QString() : prefix.left(prefix.lastIndexOf('/')); - } - - // Find or create CMakeListsNode: - CMakeListsNode *cmln = nullptr; - if (parentNode->filePath() == fn->filePath()) - cmln = parentNode; // Top level! + root->addNestedNodes(cmakeLists, Utils::FileName(), + [&cmakeLists](const Utils::FileName &fp) -> ProjectExplorer::FolderNode * { + if (Utils::contains(cmakeLists, [&fp](const FileNode *fn) { return fn->filePath().parentDir() == fp; })) + return new CMakeListsNode(fp); else - cmln = static_cast(parentNode->projectNode(fn->filePath())); - if (!cmln) { - cmln = new CMakeListsNode(fn->filePath()); - parentNode->addNode(cmln); - } - - // Find or create CMakeLists.txt filenode below CMakeListsNode: - FileNode *cmFn = cmln->fileNode(fn->filePath()); - if (!cmFn) { - cmFn = fn; - cmln->addNode(cmFn); - } - // Update displayName of CMakeListsNode: - const QString dn = prefix.isEmpty() ? k : k.mid(prefix.count() + 1); - if (!dn.isEmpty()) - cmln->setDisplayName(dn); // Set partial path as display name - - knownNodes.insert(k, cmln); - } + return new FolderNode(fp); + }); } -static CMakeListsNode *findCMakeNode(CMakeListsNode *root, const Utils::FileName &dir) +static ProjectNode *findCMakeNode(ProjectNode *root, const Utils::FileName &dir) { - const Utils::FileName stepDir = dir; - const Utils::FileName topDir = root->filePath().parentDir(); - - QStringList relative = stepDir.relativeChildPath(topDir).toString().split('/', QString::SkipEmptyParts); - - CMakeListsNode *result = root; - - QString relativePathElement; - while (!relative.isEmpty()) { - const QString nextDirPath = result->filePath().parentDir().toString(); - Utils::FileName nextFullPath; - // Some directory may not contain CMakeLists.txt file, skip it: - do { - relativePathElement += '/' + relative.takeFirst(); - nextFullPath = Utils::FileName::fromString(nextDirPath + relativePathElement + "/CMakeLists.txt"); - } while (!nextFullPath.exists() && !relative.isEmpty()); - result = static_cast(result->projectNode(nextFullPath)); - // Intermediate directory can contain CMakeLists.txt file - // that is not a part of the root node, skip it: - if (!result && !relative.isEmpty()) { - result = root; - } else { - relativePathElement.clear(); - } - QTC_ASSERT(result, return nullptr); - } - return result; + Node *n = root->findNode([&dir](Node *n) { return n->asProjectNode() && n->filePath() == dir; }); + return n ? n->asProjectNode() : nullptr; } -static CMakeProjectNode *findOrCreateProjectNode(CMakeListsNode *root, const Utils::FileName &dir, - const QString &displayName) +static ProjectNode *findOrCreateProjectNode(ProjectNode *root, const Utils::FileName &dir, + const QString &displayName) { - CMakeListsNode *cmln = findCMakeNode(root, dir); + ProjectNode *cmln = findCMakeNode(root, dir); QTC_ASSERT(cmln, return nullptr); Utils::FileName projectName = dir; @@ -623,7 +565,7 @@ static CMakeProjectNode *findOrCreateProjectNode(CMakeListsNode *root, const Uti return pn; } -void ServerModeReader::addProjects(CMakeListsNode *root, +void ServerModeReader::addProjects(CMakeProjectNode *root, const QList &projects, const QList &allFiles) { @@ -635,17 +577,16 @@ void ServerModeReader::addProjects(CMakeListsNode *root, } for (const Project *p : projects) { - CMakeProjectNode *pNode = findOrCreateProjectNode(root, p->sourceDirectory, p->name); + ProjectNode *pNode = findOrCreateProjectNode(root, p->sourceDirectory, p->name); QTC_ASSERT(pNode, continue); - QTC_ASSERT(root, continue); addTargets(root, p->targets, includeFiles); } } -static CMakeTargetNode *findOrCreateTargetNode(CMakeListsNode *root, const Utils::FileName &dir, +static CMakeTargetNode *findOrCreateTargetNode(ProjectNode *root, const Utils::FileName &dir, const QString &displayName) { - CMakeListsNode *cmln = findCMakeNode(root, dir); + ProjectNode *cmln = findCMakeNode(root, dir); QTC_ASSERT(cmln, return nullptr); Utils::FileName targetName = dir; @@ -660,7 +601,7 @@ static CMakeTargetNode *findOrCreateTargetNode(CMakeListsNode *root, const Utils return tn; } -void ServerModeReader::addTargets(CMakeListsNode *root, +void ServerModeReader::addTargets(CMakeProjectNode *root, const QList &targets, const QHash> &headers) { diff --git a/src/plugins/cmakeprojectmanager/servermodereader.h b/src/plugins/cmakeprojectmanager/servermodereader.h index 36d75fc2ded..8b973ce0ecd 100644 --- a/src/plugins/cmakeprojectmanager/servermodereader.h +++ b/src/plugins/cmakeprojectmanager/servermodereader.h @@ -33,6 +33,8 @@ namespace CMakeProjectManager { namespace Internal { +class CMakeListsNode; + class ServerModeReader : public BuildDirReader { Q_OBJECT @@ -54,7 +56,7 @@ public: QList buildTargets() const final; CMakeConfig takeParsedConfiguration() final; - void generateProjectTree(CMakeListsNode *root, + void generateProjectTree(CMakeProjectNode *root, const QList &allFiles) final; void updateCodeModel(CppTools::RawProjectParts &rpps) final; @@ -62,6 +64,7 @@ private: void handleReply(const QVariantMap &data, const QString &inReplyTo); void handleError(const QString &message); void handleProgress(int min, int cur, int max, const QString &inReplyTo); + void handleSignal(const QString &signal, const QVariantMap &data); struct Target; struct Project; @@ -110,10 +113,10 @@ private: void extractCMakeInputsData(const QVariantMap &data); void extractCacheData(const QVariantMap &data); - void addCMakeLists(CMakeListsNode *root, const QList &cmakeLists); - void addProjects(CMakeListsNode *root, const QList &projects, + void addCMakeLists(CMakeProjectNode *root, const QList &cmakeLists); + void addProjects(CMakeProjectNode *root, const QList &projects, const QList &allFiles); - void addTargets(CMakeListsNode *root, const QList &targets, + void addTargets(CMakeProjectNode *root, const QList &targets, const QHash> &headers); void addFileGroups(ProjectExplorer::ProjectNode *targetRoot, const Utils::FileName &sourceDirectory, diff --git a/src/plugins/cmakeprojectmanager/tealeafreader.cpp b/src/plugins/cmakeprojectmanager/tealeafreader.cpp index 170a7fa2529..b41176d1ed1 100644 --- a/src/plugins/cmakeprojectmanager/tealeafreader.cpp +++ b/src/plugins/cmakeprojectmanager/tealeafreader.cpp @@ -264,7 +264,7 @@ CMakeConfig TeaLeafReader::takeParsedConfiguration() return result; } -void TeaLeafReader::generateProjectTree(CMakeListsNode *root, const QList &allFiles) +void TeaLeafReader::generateProjectTree(CMakeProjectNode *root, const QList &allFiles) { root->setDisplayName(m_projectName); @@ -311,7 +311,7 @@ void TeaLeafReader::generateProjectTree(CMakeListsNode *root, const QList fileNodes = m_files + Utils::transform(missingHeaders, [](const FileNode *fn) { return new FileNode(*fn); }); - root->buildTree(fileNodes, m_parameters.sourceDirectory); + root->addNestedNodes(fileNodes, m_parameters.sourceDirectory); m_files.clear(); // Some of the FileNodes in files() were deleted! } @@ -358,6 +358,7 @@ void TeaLeafReader::updateCodeModel(CppTools::RawProjectParts &rpps) includePaths += m_parameters.buildDirectory.toString(); CppTools::RawProjectPart rpp; rpp.setProjectFileLocation(QString()); // No project file information available! + rpp.setBuildSystemTarget(cbt.title); rpp.setIncludePaths(includePaths); CppTools::RawProjectPartFlags cProjectFlags; diff --git a/src/plugins/cmakeprojectmanager/tealeafreader.h b/src/plugins/cmakeprojectmanager/tealeafreader.h index 3aa258580a5..9853a1b0a2b 100644 --- a/src/plugins/cmakeprojectmanager/tealeafreader.h +++ b/src/plugins/cmakeprojectmanager/tealeafreader.h @@ -56,7 +56,7 @@ public: QList buildTargets() const final; CMakeConfig takeParsedConfiguration() final; - void generateProjectTree(CMakeListsNode *root, + void generateProjectTree(CMakeProjectNode *root, const QList &allFiles) final; void updateCodeModel(CppTools::RawProjectParts &rpps) final; diff --git a/src/plugins/coreplugin/actionmanager/command.cpp b/src/plugins/coreplugin/actionmanager/command.cpp index cdbbe200e3a..186ac4649f1 100644 --- a/src/plugins/coreplugin/actionmanager/command.cpp +++ b/src/plugins/coreplugin/actionmanager/command.cpp @@ -32,6 +32,7 @@ #include #include +#include #include #include diff --git a/src/plugins/coreplugin/find/basetextfind.cpp b/src/plugins/coreplugin/find/basetextfind.cpp index 3786ad142c3..f0b3ad64c33 100644 --- a/src/plugins/coreplugin/find/basetextfind.cpp +++ b/src/plugins/coreplugin/find/basetextfind.cpp @@ -29,10 +29,9 @@ #include #include - -#include #include #include +#include #include namespace Core { diff --git a/src/plugins/coreplugin/locator/basefilefilter.cpp b/src/plugins/coreplugin/locator/basefilefilter.cpp index 99dec707bd0..7562a76d766 100644 --- a/src/plugins/coreplugin/locator/basefilefilter.cpp +++ b/src/plugins/coreplugin/locator/basefilefilter.cpp @@ -30,6 +30,7 @@ #include #include +#include #include #include diff --git a/src/plugins/coreplugin/locator/opendocumentsfilter.cpp b/src/plugins/coreplugin/locator/opendocumentsfilter.cpp index f4ed4b8b29b..73c3c2dc40a 100644 --- a/src/plugins/coreplugin/locator/opendocumentsfilter.cpp +++ b/src/plugins/coreplugin/locator/opendocumentsfilter.cpp @@ -32,6 +32,7 @@ #include #include #include +#include using namespace Core; using namespace Core; diff --git a/src/plugins/coreplugin/toolsettings.cpp b/src/plugins/coreplugin/toolsettings.cpp index 764cbfab6f3..a892edbadc3 100644 --- a/src/plugins/coreplugin/toolsettings.cpp +++ b/src/plugins/coreplugin/toolsettings.cpp @@ -35,6 +35,7 @@ #include #include #include +#include #include diff --git a/src/plugins/cppeditor/cppcodemodelinspectordialog.cpp b/src/plugins/cppeditor/cppcodemodelinspectordialog.cpp index 7f3f624d183..04a1326f206 100644 --- a/src/plugins/cppeditor/cppcodemodelinspectordialog.cpp +++ b/src/plugins/cppeditor/cppcodemodelinspectordialog.cpp @@ -1779,12 +1779,16 @@ void CppCodeModelInspectorDialog::updateProjectPartData(const ProjectPart::Ptr & } const QString callGroupId = part->callGroupId.isEmpty() ? QString::fromLatin1("") : part->callGroupId; + const QString buildSystemTarget + = part->buildSystemTarget.isEmpty() ? QString::fromLatin1("") + : part->buildSystemTarget; KeyValueModel::Table table = KeyValueModel::Table() << qMakePair(QString::fromLatin1("Project Part Name"), part->displayName) << qMakePair(QString::fromLatin1("Project Part File"), part->projectFileLocation()) << qMakePair(QString::fromLatin1("Project Name"), projectName) << qMakePair(QString::fromLatin1("Project File"), projectFilePath) + << qMakePair(QString::fromLatin1("Buildsystem Target"), buildSystemTarget) << qMakePair(QString::fromLatin1("Callgroup Id"), callGroupId) << qMakePair(QString::fromLatin1("Selected For Building"), CMI::Utils::toString(part->selectedForBuilding)) diff --git a/src/plugins/cppeditor/cppfunctiondecldeflink.cpp b/src/plugins/cppeditor/cppfunctiondecldeflink.cpp index ce41df99403..dcc842d0bc1 100644 --- a/src/plugins/cppeditor/cppfunctiondecldeflink.cpp +++ b/src/plugins/cppeditor/cppfunctiondecldeflink.cpp @@ -46,6 +46,7 @@ #include #include +#include #include using namespace CPlusPlus; diff --git a/src/plugins/cpptools/cppcurrentdocumentfilter.cpp b/src/plugins/cpptools/cppcurrentdocumentfilter.cpp index 588915348cb..964720e7a93 100644 --- a/src/plugins/cpptools/cppcurrentdocumentfilter.cpp +++ b/src/plugins/cpptools/cppcurrentdocumentfilter.cpp @@ -31,6 +31,7 @@ #include #include +#include #include using namespace CppTools::Internal; diff --git a/src/plugins/cpptools/cpplocatorfilter.cpp b/src/plugins/cpptools/cpplocatorfilter.cpp index 6c735582711..e18a1a4c57a 100644 --- a/src/plugins/cpptools/cpplocatorfilter.cpp +++ b/src/plugins/cpptools/cpplocatorfilter.cpp @@ -28,6 +28,7 @@ #include +#include #include #include diff --git a/src/plugins/cpptools/cppprojectinfogenerator.cpp b/src/plugins/cpptools/cppprojectinfogenerator.cpp index 525cdbf284a..422dad8cfdf 100644 --- a/src/plugins/cpptools/cppprojectinfogenerator.cpp +++ b/src/plugins/cpptools/cppprojectinfogenerator.cpp @@ -185,6 +185,7 @@ static ProjectPart::Ptr projectPartFromRawProjectPart(const RawProjectPart &rawP part->projectFileLine = rawProjectPart.projectFileLine; part->projectFileColumn = rawProjectPart.projectFileColumn; part->callGroupId = rawProjectPart.callGroupId; + part->buildSystemTarget = rawProjectPart.buildSystemTarget; part->qtVersion = rawProjectPart.qtVersion; part->projectDefines = rawProjectPart.projectDefines; part->headerPaths = rawProjectPart.headerPaths; diff --git a/src/plugins/cpptools/cpprawprojectpart.cpp b/src/plugins/cpptools/cpprawprojectpart.cpp index 6cd5a213157..3668f8caec0 100644 --- a/src/plugins/cpptools/cpprawprojectpart.cpp +++ b/src/plugins/cpptools/cpprawprojectpart.cpp @@ -66,6 +66,11 @@ void RawProjectPart::setConfigFileName(const QString &configFileName) this->projectConfigFile = configFileName; } +void RawProjectPart::setBuildSystemTarget(const QString &target) +{ + buildSystemTarget = target; +} + void RawProjectPart::setCallGroupId(const QString &id) { callGroupId = id; diff --git a/src/plugins/cpptools/cpprawprojectpart.h b/src/plugins/cpptools/cpprawprojectpart.h index c3708f3a3cf..18f0591ec26 100644 --- a/src/plugins/cpptools/cpprawprojectpart.h +++ b/src/plugins/cpptools/cpprawprojectpart.h @@ -63,6 +63,7 @@ public: void setProjectFileLocation(const QString &projectFile, int line = -1, int column = -1); void setConfigFileName(const QString &configFileName); void setCallGroupId(const QString &id); + void setBuildSystemTarget(const QString &target); void setQtVersion(ProjectPart::QtVersion qtVersion); @@ -84,6 +85,7 @@ public: int projectFileColumn = -1; QString projectConfigFile; // currently only used by the Generic Project Manager QString callGroupId; + QString buildSystemTarget; QStringList precompiledHeaders; ProjectPartHeaderPaths headerPaths; QByteArray projectDefines; diff --git a/src/plugins/cpptools/projectpart.h b/src/plugins/cpptools/projectpart.h index 98fc5367adc..fa13aed3444 100644 --- a/src/plugins/cpptools/projectpart.h +++ b/src/plugins/cpptools/projectpart.h @@ -110,6 +110,7 @@ public: int projectFileColumn = -1; QString projectConfigFile; // currently only used by the Generic Project Manager QString callGroupId; + QString buildSystemTarget; ProjectFiles files; diff --git a/src/plugins/debugger/breakhandler.cpp b/src/plugins/debugger/breakhandler.cpp index 7a08a568c05..8c104e0dd8f 100644 --- a/src/plugins/debugger/breakhandler.cpp +++ b/src/plugins/debugger/breakhandler.cpp @@ -1969,15 +1969,15 @@ bool BreakHandler::contextMenuEvent(const ItemViewEvent &ev) // FIXME BP: m_engine->threadsHandler()->currentThreadId(); - int threadId = 0; - addAction(menu, - threadId == -1 ? tr("Associate Breakpoint with All Threads") - : tr("Associate Breakpoint with Thread %1").arg(threadId), - !selectedItems.isEmpty(), - [this, selectedItems, threadId] { - for (Breakpoint bp : selectedItems) - bp.setThreadSpec(threadId); - }); + // int threadId = 0; + // addAction(menu, + // threadId == -1 ? tr("Associate Breakpoint with All Threads") + // : tr("Associate Breakpoint with Thread %1").arg(threadId), + // !selectedItems.isEmpty(), + // [this, selectedItems, threadId] { + // for (Breakpoint bp : selectedItems) + // bp.setThreadSpec(threadId); + // }); addAction(menu, selectedItems.size() > 1 diff --git a/src/plugins/debugger/qml/qmlengine.cpp b/src/plugins/debugger/qml/qmlengine.cpp index 06471158854..33759888faf 100644 --- a/src/plugins/debugger/qml/qmlengine.cpp +++ b/src/plugins/debugger/qml/qmlengine.cpp @@ -112,10 +112,16 @@ enum StepAction struct QmlV8ObjectData { int handle = -1; + int expectedProperties = -1; QString name; QString type; QVariant value; QVariantList properties; + + bool hasChildren() const + { + return expectedProperties > 0 || !properties.isEmpty(); + } }; typedef std::function QmlCallback; @@ -1391,7 +1397,7 @@ void QmlEnginePrivate::handleEvaluateExpression(const QVariantMap &response, if (success) { item->type = body.type; item->value = body.value.toString(); - item->wantsChildren = body.properties.count(); + item->setHasChildren(body.hasChildren()); } else { //Do not set type since it is unknown item->setError(body.value.toString()); @@ -1658,55 +1664,69 @@ QmlV8ObjectData QmlEnginePrivate::extractData(const QVariant &data) const objectData.name = dataMap.value(NAME).toString(); + QString type = dataMap.value(TYPE).toString(); + objectData.handle = dataMap.value(HANDLE).toInt(); + + if (type == "undefined") { + objectData.type = "undefined"; + objectData.value = "undefined"; + + } else if (type == "null") { // Deprecated. typeof(null) == "object" in JavaScript + objectData.type = "object"; + objectData.value = "null"; + + } else if (type == "boolean") { + objectData.type = "boolean"; + objectData.value = dataMap.value(VALUE); + + } else if (type == "number") { + objectData.type = "number"; + objectData.value = dataMap.value(VALUE); + + } else if (type == "string") { + QLatin1Char quote('"'); + objectData.type = "string"; + objectData.value = QString(quote + dataMap.value(VALUE).toString() + quote); + + } else if (type == "object") { + objectData.type = "object"; + // ignore "className": it doesn't make any sense. + + if (dataMap.contains("value")) { + QVariant value = dataMap.value("value"); + if (value.isNull()) + objectData.value = "null"; // Yes, null is an object. + else if (value.isValid()) + objectData.expectedProperties = value.toInt(); + } + + if (dataMap.contains("properties")) + objectData.properties = dataMap.value("properties").toList(); + } else if (type == "function") { + objectData.type = "function"; + objectData.value = dataMap.value(NAME); + objectData.properties = dataMap.value("properties").toList(); + QVariant value = dataMap.value("value"); + if (value.isValid()) + objectData.expectedProperties = value.toInt(); + + } else if (type == "script") { + objectData.type = "script"; + objectData.value = dataMap.value(NAME); + } + if (dataMap.contains(REF)) { objectData.handle = dataMap.value(REF).toInt(); if (refVals.contains(objectData.handle)) { QmlV8ObjectData data = refVals.value(objectData.handle); - objectData.type = data.type; - objectData.value = data.value; - objectData.properties = data.properties; - } - } else { - objectData.handle = dataMap.value(HANDLE).toInt(); - QString type = dataMap.value(TYPE).toString(); - - if (type == "undefined") { - objectData.type = "undefined"; - objectData.value = "undefined"; - - } else if (type == "null") { // Deprecated. typeof(null) == "object" in JavaScript - objectData.type = "object"; - objectData.value = "null"; - - } else if (type == "boolean") { - objectData.type = "boolean"; - objectData.value = dataMap.value(VALUE); - - } else if (type == "number") { - objectData.type = "number"; - objectData.value = dataMap.value(VALUE); - - } else if (type == "string") { - QLatin1Char quote('"'); - objectData.type = "string"; - objectData.value = QString(quote + dataMap.value(VALUE).toString() + quote); - - } else if (type == "object") { - objectData.type = "object"; - // ignore "className": it doesn't make any sense. - - if (dataMap.contains("properties")) - objectData.properties = dataMap.value("properties").toList(); - else if (dataMap.value("value").isNull()) - objectData.value = "null"; // Yes, null is an object. - } else if (type == "function") { - objectData.type = "function"; - objectData.value = dataMap.value(NAME); - objectData.properties = dataMap.value("properties").toList(); - - } else if (type == "script") { - objectData.type = "script"; - objectData.value = dataMap.value(NAME); + if (objectData.type.isEmpty()) + objectData.type = data.type; + if (!objectData.value.isValid()) + objectData.value = data.value; + if (objectData.properties.isEmpty()) + objectData.properties = data.properties; + if (objectData.expectedProperties < 0) + objectData.expectedProperties = data.expectedProperties; } } @@ -2216,7 +2236,7 @@ void QmlEnginePrivate::handleFrame(const QVariantMap &response) item->id = objectData.handle; item->type = objectData.type; item->value = objectData.value.toString(); - item->setHasChildren(objectData.properties.count()); + item->setHasChildren(objectData.hasChildren()); // In case of global object, we do not get children // Set children nevertheless and query later. if (item->value == "global") { @@ -2298,11 +2318,11 @@ void QmlEnginePrivate::handleScope(const QVariantMap &response) item->name = item->exp; item->iname = "local." + item->exp; item->id = localData.handle; + item->type = localData.type; + item->value = localData.value.toString(); + item->setHasChildren(localData.hasChildren()); - if (localData.value.isValid()) { - item->type = localData.type; - item->value = localData.value.toString(); - item->setHasChildren(localData.properties.count()); + if (localData.value.isValid() || item->wantsChildren || localData.expectedProperties == 0) { engine->watchHandler()->insertItem(item.release()); } else { itemsToLookup.insert(int(item->id), {item->iname, item->name, item->exp}); @@ -2443,7 +2463,7 @@ void QmlEnginePrivate::insertSubItems(WatchItem *parent, const QVariantList &pro item->value = propertyData.value.toString(); if (item->type.isEmpty() || expandedINames.contains(item->iname)) itemsToLookup.insert(propertyData.handle, {item->iname, item->name, item->exp}); - item->setHasChildren(propertyData.properties.count() > 0); + item->setHasChildren(propertyData.hasChildren()); parent->appendChild(item.release()); } @@ -2499,7 +2519,7 @@ void QmlEnginePrivate::handleLookup(const QVariantMap &response) item->type = bodyObjectData.type; item->value = bodyObjectData.value.toString(); - item->setHasChildren(bodyObjectData.properties.count()); + item->setHasChildren(bodyObjectData.hasChildren()); insertSubItems(item, bodyObjectData.properties); engine->watchHandler()->insertItem(item); @@ -2515,7 +2535,10 @@ void QmlEnginePrivate::stateChanged(State state) if (state == QmlDebugClient::Enabled) { /// Start session. flushSendBuffer(); - runDirectCommand(CONNECT); + QJsonObject parameters; + parameters.insert("redundantRefs", false); + parameters.insert("namesAsObjects", false); + runDirectCommand(CONNECT, QJsonDocument(parameters).toJson()); runCommand({VERSION}, CB(handleVersion)); } } diff --git a/src/plugins/debugger/watchhandler.cpp b/src/plugins/debugger/watchhandler.cpp index f60cbf59233..f14d82e8caa 100644 --- a/src/plugins/debugger/watchhandler.cpp +++ b/src/plugins/debugger/watchhandler.cpp @@ -2008,7 +2008,7 @@ bool WatchHandler::insertItem(WatchItem *item) bool found = false; const std::vector siblings(parent->begin(), parent->end()); - for (int row = 0, n = siblings.size(); row < n; ++row) { + for (int row = 0, n = int(siblings.size()); row < n; ++row) { if (static_cast(siblings[row])->iname == item->iname) { m_model->destroyItem(parent->childAt(row)); parent->insertChild(row, item); diff --git a/src/plugins/diffeditor/differ.cpp b/src/plugins/diffeditor/differ.cpp index c46277b22b6..a99b14a127b 100644 --- a/src/plugins/diffeditor/differ.cpp +++ b/src/plugins/diffeditor/differ.cpp @@ -34,6 +34,7 @@ publication by Neil Fraser: http://neil.fraser.name/writing/diff/ #include "differ.h" #include +#include #include #include #include diff --git a/src/plugins/diffeditor/diffutils.cpp b/src/plugins/diffeditor/diffutils.cpp index d3a186e5c63..1a6a2b729dd 100644 --- a/src/plugins/diffeditor/diffutils.cpp +++ b/src/plugins/diffeditor/diffutils.cpp @@ -25,6 +25,7 @@ #include "diffutils.h" #include "differ.h" +#include #include #include #include "texteditor/fontsettings.h" diff --git a/src/plugins/genericprojectmanager/genericproject.cpp b/src/plugins/genericprojectmanager/genericproject.cpp index 08b4fdf5adb..c8b14a125d5 100644 --- a/src/plugins/genericprojectmanager/genericproject.cpp +++ b/src/plugins/genericprojectmanager/genericproject.cpp @@ -259,28 +259,25 @@ void GenericProject::refresh(RefreshOptions options) parseProject(options); if (options & Files) { - QList fileNodes = Utils::transform(files(), [](const QString &f) { + auto newRoot = new GenericProjectNode(this); + + for (const QString &f : files()) { FileType fileType = FileType::Source; // ### FIXME if (f.endsWith(".qrc")) fileType = FileType::Resource; - return new FileNode(Utils::FileName::fromString(f), fileType, false); - }); + newRoot->addNestedNode(new FileNode(Utils::FileName::fromString(f), fileType, false)); + } - auto projectFilesNode = new FileNode(Utils::FileName::fromString(m_filesFileName), + newRoot->addNestedNode(new FileNode(Utils::FileName::fromString(m_filesFileName), FileType::Project, - /* generated = */ false); + /* generated = */ false)); + newRoot->addNestedNode(new FileNode(Utils::FileName::fromString(m_includesFileName), + FileType::Project, + /* generated = */ false)); + newRoot->addNestedNode(new FileNode(Utils::FileName::fromString(m_configFileName), + FileType::Project, + /* generated = */ false)); - auto projectIncludesNode = new FileNode(Utils::FileName::fromString(m_includesFileName), - FileType::Project, - /* generated = */ false); - - auto projectConfigNode = new FileNode(Utils::FileName::fromString(m_configFileName), - FileType::Project, - /* generated = */ false); - fileNodes << projectFilesNode << projectIncludesNode << projectConfigNode; - - auto newRoot = new GenericProjectNode(this); - newRoot->buildTree(fileNodes); setRootProjectNode(newRoot); } diff --git a/src/plugins/git/gerrit/gerritdialog.cpp b/src/plugins/git/gerrit/gerritdialog.cpp index 87ff53730bb..66c8c38d22d 100644 --- a/src/plugins/git/gerrit/gerritdialog.cpp +++ b/src/plugins/git/gerrit/gerritdialog.cpp @@ -37,6 +37,7 @@ #include #include #include +#include #include #include @@ -69,7 +70,6 @@ GerritDialog::GerritDialog(const QSharedPointer &p, setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint); m_ui->setupUi(this); - setWindowTitle(tr("Gerrit")); m_queryModel->setStringList(m_parameters->savedQueries); QCompleter *completer = new QCompleter(this); completer->setModel(m_queryModel); @@ -111,6 +111,10 @@ GerritDialog::GerritDialog(const QSharedPointer &p, connect(m_ui->treeView, &QAbstractItemView::activated, this, &GerritDialog::slotActivated); + m_ui->resetRemoteButton->setIcon(Utils::Icons::RESET_TOOLBAR.icon()); + connect(m_ui->resetRemoteButton, &QToolButton::clicked, + this, [this] { updateRemotes(true); }); + m_displayButton = addActionButton(tr("&Show"), [this]() { slotFetchDisplay(); }); m_cherryPickButton = addActionButton(tr("Cherry &Pick"), [this]() { slotFetchCherryPick(); }); m_checkoutButton = addActionButton(tr("C&heckout"), [this]() { slotFetchCheckout(); }); @@ -120,6 +124,11 @@ GerritDialog::GerritDialog(const QSharedPointer &p, m_refreshButton, &QWidget::setDisabled); connect(m_model, &GerritModel::refreshStateChanged, this, &GerritDialog::slotRefreshStateChanged); + connect(m_model, &GerritModel::errorText, + this, [this](const QString &text) { + if (text.contains("returned error: 401")) + updateRemotes(true); + }, Qt::QueuedConnection); setCurrentPath(repository); slotCurrentChanged(); @@ -226,7 +235,7 @@ void GerritDialog::remoteChanged() slotRefresh(); } -void GerritDialog::updateRemotes() +void GerritDialog::updateRemotes(bool forceReload) { m_ui->remoteComboBox->clear(); if (m_repository.isEmpty() || !QFileInfo(m_repository).isDir()) @@ -240,7 +249,7 @@ void GerritDialog::updateRemotes() while (mapIt.hasNext()) { mapIt.next(); GerritServer server; - if (!server.fillFromRemote(mapIt.value(), *m_parameters)) + if (!server.fillFromRemote(mapIt.value(), *m_parameters, forceReload)) continue; addRemote(server, mapIt.key()); } diff --git a/src/plugins/git/gerrit/gerritdialog.h b/src/plugins/git/gerrit/gerritdialog.h index 21c4500be3c..6c1f087764e 100644 --- a/src/plugins/git/gerrit/gerritdialog.h +++ b/src/plugins/git/gerrit/gerritdialog.h @@ -76,7 +76,7 @@ private: void slotFetchCheckout(); void slotRefresh(); void remoteChanged(); - void updateRemotes(); + void updateRemotes(bool forceReload = false); void addRemote(const GerritServer &server, const QString &name); void manageProgressIndicator(); diff --git a/src/plugins/git/gerrit/gerritdialog.ui b/src/plugins/git/gerrit/gerritdialog.ui index cf8ce050d7c..c7be2cd2cda 100644 --- a/src/plugins/git/gerrit/gerritdialog.ui +++ b/src/plugins/git/gerrit/gerritdialog.ui @@ -65,6 +65,13 @@ + + + + Refresh Remote Servers + + + diff --git a/src/plugins/git/gerrit/gerritmodel.cpp b/src/plugins/git/gerrit/gerritmodel.cpp index 20cc112b6a6..1cc7a63f90c 100644 --- a/src/plugins/git/gerrit/gerritmodel.cpp +++ b/src/plugins/git/gerrit/gerritmodel.cpp @@ -233,13 +233,12 @@ public: signals: void resultRetrieved(const QByteArray &); + void errorText(const QString &text); void finished(); private: void processError(QProcess::ProcessError); void processFinished(int exitCode, QProcess::ExitStatus); - void readyReadStandardError(); - void readyReadStandardOutput(); void timeout(); void errorTermination(const QString &msg); @@ -249,6 +248,7 @@ private: QTimer m_timer; QString m_binary; QByteArray m_output; + QString m_error; QFutureInterface m_progress; QFutureWatcher m_watcher; QStringList m_arguments; @@ -277,10 +277,14 @@ QueryContext::QueryContext(const QString &query, + "&o=CURRENT_REVISION&o=DETAILED_LABELS&o=DETAILED_ACCOUNTS"; m_arguments = GerritServer::curlArguments() << url; } - connect(&m_process, &QProcess::readyReadStandardError, - this, &QueryContext::readyReadStandardError); - connect(&m_process, &QProcess::readyReadStandardOutput, - this, &QueryContext::readyReadStandardOutput); + connect(&m_process, &QProcess::readyReadStandardError, this, [this] { + const QString text = QString::fromLocal8Bit(m_process.readAllStandardError()); + VcsOutputWindow::appendError(text); + m_error.append(text); + }); + connect(&m_process, &QProcess::readyReadStandardOutput, this, [this] { + m_output.append(m_process.readAllStandardOutput()); + }); connect(&m_process, static_cast(&QProcess::finished), this, &QueryContext::processFinished); connect(&m_process, &QProcess::errorOccurred, this, &QueryContext::processError); @@ -345,6 +349,7 @@ void QueryContext::processFinished(int exitCode, QProcess::ExitStatus es) { if (m_timer.isActive()) m_timer.stop(); + emit errorText(m_error); if (es != QProcess::NormalExit) { errorTermination(tr("%1 crashed.").arg(m_binary)); return; @@ -357,16 +362,6 @@ void QueryContext::processFinished(int exitCode, QProcess::ExitStatus es) emit finished(); } -void QueryContext::readyReadStandardError() -{ - VcsOutputWindow::appendError(QString::fromLocal8Bit(m_process.readAllStandardError())); -} - -void QueryContext::readyReadStandardOutput() -{ - m_output.append(m_process.readAllStandardOutput()); -} - void QueryContext::timeout() { if (m_process.state() != QProcess::Running) @@ -520,6 +515,7 @@ void GerritModel::refresh(const QSharedPointer &server, const QStr m_query = new QueryContext(realQuery, m_parameters, *m_server, this); connect(m_query, &QueryContext::resultRetrieved, this, &GerritModel::resultRetrieved); + connect(m_query, &QueryContext::errorText, this, &GerritModel::errorText); connect(m_query, &QueryContext::finished, this, &GerritModel::queryFinished); emit refreshStateChanged(true); m_query->start(); diff --git a/src/plugins/git/gerrit/gerritmodel.h b/src/plugins/git/gerrit/gerritmodel.h index 863a2c97c16..d9efd0edd25 100644 --- a/src/plugins/git/gerrit/gerritmodel.h +++ b/src/plugins/git/gerrit/gerritmodel.h @@ -127,6 +127,7 @@ public: signals: void refreshStateChanged(bool isRefreshing); // For disabling the "Refresh" button. void stateChanged(); + void errorText(const QString &text); private: void resultRetrieved(const QByteArray &); diff --git a/src/plugins/git/gerrit/gerritserver.cpp b/src/plugins/git/gerrit/gerritserver.cpp index ea80e8d6e2b..6b3a40e8536 100644 --- a/src/plugins/git/gerrit/gerritserver.cpp +++ b/src/plugins/git/gerrit/gerritserver.cpp @@ -29,12 +29,14 @@ #include "../gitplugin.h" #include "../gitclient.h" +#include #include #include #include #include #include +#include using namespace Utils; using namespace Git::Internal; @@ -44,6 +46,11 @@ namespace Internal { static const char defaultHostC[] = "codereview.qt-project.org"; static const char accountUrlC[] = "/accounts/self"; +static const char isGerritKey[] = "IsGerrit"; +static const char rootPathKey[] = "RootPath"; +static const char userNameKey[] = "UserName"; +static const char fullNameKey[] = "FullName"; +static const char isAuthenticatedKey[] = "IsAuthenticated"; bool GerritUser::isSameAs(const GerritUser &other) const { @@ -111,7 +118,9 @@ QString GerritServer::url(UrlType urlType) const return res; } -bool GerritServer::fillFromRemote(const QString &remote, const GerritParameters ¶meters) +bool GerritServer::fillFromRemote(const QString &remote, + const GerritParameters ¶meters, + bool forceReload) { const GitRemote r(remote); if (!r.isValid) @@ -136,12 +145,61 @@ bool GerritServer::fillFromRemote(const QString &remote, const GerritParameters curlBinary = parameters.curl; if (curlBinary.isEmpty() || !QFile::exists(curlBinary)) return false; - rootPath = r.path; - // Strip the last part of the path, which is always the repo name - // The rest of the path needs to be inspected to find the root path - // (can be http://example.net/review) - ascendPath(); - return resolveRoot(); + const StoredHostValidity validity = forceReload ? Invalid : loadSettings(); + switch (validity) { + case Invalid: + rootPath = r.path; + // Strip the last part of the path, which is always the repo name + // The rest of the path needs to be inspected to find the root path + // (can be http://example.net/review) + ascendPath(); + return resolveRoot(); + case NotGerrit: + return false; + case Valid: + return true; + } + return true; +} + +GerritServer::StoredHostValidity GerritServer::loadSettings() +{ + StoredHostValidity validity = Invalid; + QSettings *settings = Core::ICore::settings(); + settings->beginGroup("Gerrit/" + host); + if (!settings->value(isGerritKey, true).toBool()) { + validity = NotGerrit; + } else if (settings->contains(isAuthenticatedKey)) { + rootPath = settings->value(rootPathKey).toString(); + user.userName = settings->value(userNameKey).toString(); + user.fullName = settings->value(fullNameKey).toString(); + authenticated = settings->value(isAuthenticatedKey).toBool(); + validity = Valid; + } + settings->endGroup(); + return validity; +} + +void GerritServer::saveSettings(StoredHostValidity validity) const +{ + QSettings *settings = Core::ICore::settings(); + settings->beginGroup("Gerrit/" + host); + switch (validity) { + case NotGerrit: + settings->setValue(isGerritKey, false); + break; + case Valid: + settings->setValue(rootPathKey, rootPath); + settings->setValue(userNameKey, user.userName); + settings->setValue(fullNameKey, user.fullName); + settings->setValue(isAuthenticatedKey, authenticated); + break; + case Invalid: + settings->clear(); + break; + } + + settings->endGroup(); } QStringList GerritServer::curlArguments() @@ -165,8 +223,13 @@ int GerritServer::testConnection() QString output = resp.stdOut(); output.remove(0, output.indexOf('\n')); // Strip first line QJsonDocument doc = QJsonDocument::fromJson(output.toUtf8()); - if (!doc.isNull()) - user.fullName = doc.object().value("name").toString(); + if (!doc.isNull()) { + const QJsonObject obj = doc.object(); + user.fullName = obj.value("name").toString(); + const QString userName = obj.value("username").toString(); + if (!userName.isEmpty()) + user.userName = userName; + } return 200; } const QRegularExpression errorRegexp("returned error: (\\d+)"); @@ -182,6 +245,7 @@ bool GerritServer::setupAuthentication() if (!dialog.exec()) return false; authenticated = dialog.isAuthenticated(); + saveSettings(Valid); return true; } @@ -199,12 +263,15 @@ bool GerritServer::resolveRoot() for (;;) { switch (testConnection()) { case 200: + saveSettings(Valid); return true; case 401: return setupAuthentication(); case 404: - if (!ascendPath()) + if (!ascendPath()) { + saveSettings(NotGerrit); return false; + } break; default: // unknown error - fail return false; diff --git a/src/plugins/git/gerrit/gerritserver.h b/src/plugins/git/gerrit/gerritserver.h index b24c0248514..f9f58236131 100644 --- a/src/plugins/git/gerrit/gerritserver.h +++ b/src/plugins/git/gerrit/gerritserver.h @@ -61,13 +61,22 @@ public: RestUrl }; + enum StoredHostValidity + { + Invalid, + NotGerrit, + Valid + }; + GerritServer(); GerritServer(const QString &host, unsigned short port, const QString &userName, HostType type); bool operator==(const GerritServer &other) const; static QString defaultHost(); QString hostArgument() const; QString url(UrlType urlType = DefaultUrl) const; - bool fillFromRemote(const QString &remote, const GerritParameters ¶meters); + bool fillFromRemote(const QString &remote, const GerritParameters ¶meters, bool forceReload); + StoredHostValidity loadSettings(); + void saveSettings(StoredHostValidity validity) const; int testConnection(); static QStringList curlArguments(); diff --git a/src/plugins/git/githighlighters.h b/src/plugins/git/githighlighters.h index 166c6a7be8b..16325423bf4 100644 --- a/src/plugins/git/githighlighters.h +++ b/src/plugins/git/githighlighters.h @@ -27,6 +27,8 @@ #include +#include + namespace Git { namespace Internal { diff --git a/src/plugins/help/searchwidget.cpp b/src/plugins/help/searchwidget.cpp index 1288673a6ec..27e21a9ff88 100644 --- a/src/plugins/help/searchwidget.cpp +++ b/src/plugins/help/searchwidget.cpp @@ -45,6 +45,7 @@ #include #include #include +#include #include #include #include diff --git a/src/plugins/ios/ios.pro b/src/plugins/ios/ios.pro index f54bde30e81..3e5f5bd9597 100644 --- a/src/plugins/ios/ios.pro +++ b/src/plugins/ios/ios.pro @@ -34,7 +34,9 @@ HEADERS += \ iosdeploystepfactory.h \ iosdeploystepwidget.h \ iosanalyzesupport.h \ - simulatorcontrol.h + simulatorcontrol.h \ + iosbuildconfiguration.h \ + iosbuildsettingswidget.h SOURCES += \ @@ -63,13 +65,16 @@ SOURCES += \ iosdeploystepfactory.cpp \ iosdeploystepwidget.cpp \ iosanalyzesupport.cpp \ - simulatorcontrol.cpp + simulatorcontrol.cpp \ + iosbuildconfiguration.cpp \ + iosbuildsettingswidget.cpp FORMS += \ iossettingswidget.ui \ iosbuildstep.ui \ iosdeploystepwidget.ui \ - iospresetbuildstep.ui + iospresetbuildstep.ui \ + iosbuildsettingswidget.ui DEFINES += IOS_LIBRARY diff --git a/src/plugins/ios/iosbuildconfiguration.cpp b/src/plugins/ios/iosbuildconfiguration.cpp new file mode 100644 index 00000000000..74d14d08db4 --- /dev/null +++ b/src/plugins/ios/iosbuildconfiguration.cpp @@ -0,0 +1,193 @@ +/**************************************************************************** +** +** 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. +** +****************************************************************************/ +#include "iosbuildconfiguration.h" + +#include "iosconfigurations.h" +#include "iosconstants.h" +#include "iosbuildsettingswidget.h" +#include "iosmanager.h" + +#include "projectexplorer/kitinformation.h" +#include "projectexplorer/namedwidget.h" +#include "projectexplorer/target.h" +#include "qmakeprojectmanager/qmakebuildinfo.h" +#include "utils/algorithm.h" + +#include + +using namespace QmakeProjectManager; + +namespace Ios { +namespace Internal { + +const char qmakeIosTeamSettings[] = "QMAKE_MAC_XCODE_SETTINGS+=qteam qteam.name=DEVELOPMENT_TEAM qteam.value="; +const char qmakeProvisioningProfileSettings[] = "QMAKE_MAC_XCODE_SETTINGS+=qprofile qprofile.name=PROVISIONING_PROFILE_SPECIFIER qprofile.value="; +const char signingIdentifierKey[] = "Ios.SigningIdentifier"; +const char autoManagedSigningKey[] = "Ios.AutoManagedSigning"; + +IosBuildConfiguration::IosBuildConfiguration(ProjectExplorer::Target *target) : + QmakeBuildConfiguration(target) +{ +} + +IosBuildConfiguration::IosBuildConfiguration(ProjectExplorer::Target *target, IosBuildConfiguration *source) : + QmakeBuildConfiguration(target, source) +{ +} + +QList IosBuildConfiguration::createSubConfigWidgets() +{ + auto subConfigWidgets = QmakeBuildConfiguration::createSubConfigWidgets(); + + Core::Id devType = ProjectExplorer::DeviceTypeKitInformation::deviceTypeId(target()->kit()); + // Ownership of this widget is with BuildSettingsWidget + auto buildSettingsWidget = new IosBuildSettingsWidget(devType, m_signingIdentifier, + m_autoManagedSigning); + subConfigWidgets.prepend(buildSettingsWidget); + connect(buildSettingsWidget, &IosBuildSettingsWidget::signingSettingsChanged, + this, &IosBuildConfiguration::onSigningSettingsChanged); + return subConfigWidgets; +} + +QVariantMap IosBuildConfiguration::toMap() const +{ + QVariantMap map(QmakeBuildConfiguration::toMap()); + map.insert(signingIdentifierKey, m_signingIdentifier); + map.insert(autoManagedSigningKey, m_autoManagedSigning); + return map; +} + +bool IosBuildConfiguration::fromMap(const QVariantMap &map) +{ + if (!QmakeBuildConfiguration::fromMap(map)) + return false; + m_autoManagedSigning = map.value(autoManagedSigningKey).toBool(); + m_signingIdentifier = map.value(signingIdentifierKey).toString(); + updateQmakeCommand(); + return true; +} + +void IosBuildConfiguration::onSigningSettingsChanged(bool autoManagedSigning, QString identifier) +{ + if (m_signingIdentifier.compare(identifier) != 0 + || m_autoManagedSigning != autoManagedSigning) { + m_autoManagedSigning = autoManagedSigning; + m_signingIdentifier = identifier; + updateQmakeCommand(); + } +} + +void IosBuildConfiguration::updateQmakeCommand() +{ + QMakeStep *qmakeStepInstance = qmakeStep(); + const QString forceOverrideArg("-after"); + if (qmakeStepInstance) { + QStringList extraArgs = qmakeStepInstance->extraArguments(); + // remove old extra arguments. + Utils::erase(extraArgs, [forceOverrideArg](const QString& arg) { + return arg.startsWith(qmakeIosTeamSettings) + || arg.startsWith(qmakeProvisioningProfileSettings) + || arg == forceOverrideArg; + }); + + // Set force ovveride qmake switch + if (!m_signingIdentifier.isEmpty() ) + extraArgs << forceOverrideArg; + + Core::Id devType = ProjectExplorer::DeviceTypeKitInformation::deviceTypeId(target()->kit()); + if (devType == Constants::IOS_DEVICE_TYPE && !m_signingIdentifier.isEmpty()) { + if (m_autoManagedSigning) { + extraArgs << qmakeIosTeamSettings + m_signingIdentifier; + } else { + // Get the team id from provisioning profile + ProvisioningProfilePtr profile = + IosConfigurations::provisioningProfile(m_signingIdentifier); + QString teamId; + if (profile) + teamId = profile->developmentTeam()->identifier(); + else + qCDebug(iosLog) << "No provisioing profile found for id:"<< m_signingIdentifier; + + if (!teamId.isEmpty()) { + extraArgs << qmakeProvisioningProfileSettings + m_signingIdentifier; + extraArgs << qmakeIosTeamSettings + teamId; + } else { + qCDebug(iosLog) << "Development team unavailable for profile:" << profile; + } + } + } + + qmakeStepInstance->setExtraArguments(extraArgs); + } +} + +IosBuildConfigurationFactory::IosBuildConfigurationFactory(QObject *parent) + : QmakeBuildConfigurationFactory(parent) +{ +} + + +int IosBuildConfigurationFactory::priority(const ProjectExplorer::Kit *k, const QString &projectPath) const +{ + return (QmakeBuildConfigurationFactory::priority(k, projectPath) >= 0 + && IosManager::supportsIos(k)) ? 1 : -1; +} + +int IosBuildConfigurationFactory::priority(const ProjectExplorer::Target *parent) const +{ + return (QmakeBuildConfigurationFactory::priority(parent) >= 0 + && IosManager::supportsIos(parent)) ? 1 : -1; +} + +ProjectExplorer::BuildConfiguration *IosBuildConfigurationFactory::create(ProjectExplorer::Target *parent, + const ProjectExplorer::BuildInfo *info) const +{ + auto qmakeInfo = static_cast(info); + auto bc = new IosBuildConfiguration(parent); + configureBuildConfiguration(parent, bc, qmakeInfo); + return bc; +} + +ProjectExplorer::BuildConfiguration *IosBuildConfigurationFactory::clone(ProjectExplorer::Target *parent, + ProjectExplorer::BuildConfiguration *source) +{ + if (!canClone(parent, source)) + return nullptr; + auto *oldbc = static_cast(source); + return new IosBuildConfiguration(parent, oldbc); +} + +ProjectExplorer::BuildConfiguration *IosBuildConfigurationFactory::restore(ProjectExplorer::Target *parent, const QVariantMap &map) +{ + if (canRestore(parent, map)) { + std::unique_ptr bc(new IosBuildConfiguration(parent)); + if (bc->fromMap(map)) + return bc.release(); + } + return nullptr; +} + +} // namespace Internal +} // namespace Ios diff --git a/src/plugins/ios/iosbuildconfiguration.h b/src/plugins/ios/iosbuildconfiguration.h new file mode 100644 index 00000000000..2bb94fc529b --- /dev/null +++ b/src/plugins/ios/iosbuildconfiguration.h @@ -0,0 +1,75 @@ +/**************************************************************************** +** +** 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. +** +****************************************************************************/ +#pragma once + +#include "qmakeprojectmanager/qmakebuildconfiguration.h" + +namespace ProjectExplorer { +class Target; +class Kit; +class NamedWidget; +} + +namespace Ios { +namespace Internal { + +class IosBuildConfiguration : public QmakeProjectManager::QmakeBuildConfiguration +{ + friend class IosBuildConfigurationFactory; + Q_OBJECT +public: + explicit IosBuildConfiguration(ProjectExplorer::Target *target); + IosBuildConfiguration(ProjectExplorer::Target *target, IosBuildConfiguration *source); + + QList createSubConfigWidgets() override; + QVariantMap toMap() const override; +protected: + bool fromMap(const QVariantMap &map) override; + +private: + void onSigningSettingsChanged(bool autoManagedSigning, QString identifier); + void updateQmakeCommand(); + +private: + QString m_signingIdentifier; + bool m_autoManagedSigning = true; +}; + + +class IosBuildConfigurationFactory : public QmakeProjectManager::QmakeBuildConfigurationFactory +{ +public: + explicit IosBuildConfigurationFactory(QObject *parent = 0); + + int priority(const ProjectExplorer::Kit *k, const QString &projectPath) const override; + int priority(const ProjectExplorer::Target *parent) const override; + + ProjectExplorer::BuildConfiguration *create(ProjectExplorer::Target *parent, const ProjectExplorer::BuildInfo *info) const override; + ProjectExplorer::BuildConfiguration *clone(ProjectExplorer::Target *parent, ProjectExplorer::BuildConfiguration *source) override; + ProjectExplorer::BuildConfiguration *restore(ProjectExplorer::Target *parent, const QVariantMap &map) override; +}; + +} // namespace Internal +} // namespace Ios diff --git a/src/plugins/ios/iosbuildsettingswidget.cpp b/src/plugins/ios/iosbuildsettingswidget.cpp new file mode 100644 index 00000000000..f5c61fea793 --- /dev/null +++ b/src/plugins/ios/iosbuildsettingswidget.cpp @@ -0,0 +1,290 @@ +/**************************************************************************** +** +** 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. +** +****************************************************************************/ + +#include "iosbuildsettingswidget.h" +#include "ui_iosbuildsettingswidget.h" +#include "iosconfigurations.h" +#include "iosconstants.h" + +#include "utils/utilsicons.h" +#include "utils/algorithm.h" +#include "qmakeprojectmanager/qmakeproject.h" +#include "qmakeprojectmanager/qmakenodes.h" +#include "utils/detailswidget.h" + +#include +#include + +using namespace QmakeProjectManager; + +namespace Ios { +namespace Internal { + +namespace { +Q_LOGGING_CATEGORY(iosSettingsLog, "qtc.ios.common") +} + +static const int IdentifierRole = Qt::UserRole+1; + +IosBuildSettingsWidget::IosBuildSettingsWidget(const Core::Id &deviceType, + const QString &signingIdentifier, + bool isSigningAutoManaged, QWidget *parent) : + ProjectExplorer::NamedWidget(parent), + ui(new Ui::IosBuildSettingsWidget), + m_detailsWidget(new Utils::DetailsWidget(this)), + m_deviceType(deviceType) +{ + auto rootLayout = new QVBoxLayout(this); + rootLayout->setMargin(0); + rootLayout->addWidget(m_detailsWidget); + + auto container = new QWidget(m_detailsWidget); + ui->setupUi(container); + ui->m_autoSignCheckbox->setChecked(isSigningAutoManaged); + connect(ui->m_qmakeDefaults, &QPushButton::clicked, this, &IosBuildSettingsWidget::onReset); + + ui->m_infoIconLabel->hide(); + ui->m_infoIconLabel->setPixmap(Utils::Icons::INFO.pixmap()); + ui->m_infoLabel->hide(); + + ui->m_warningIconLabel->hide(); + ui->m_warningIconLabel->setPixmap(Utils::Icons::WARNING.pixmap()); + ui->m_warningLabel->hide(); + + m_detailsWidget->setState(Utils::DetailsWidget::NoSummary); + m_detailsWidget->setWidget(container); + + setDisplayName(tr("iOS Settings")); + + const bool isDevice = m_deviceType == Constants::IOS_DEVICE_TYPE; + if (isDevice) { + connect(IosConfigurations::instance(), &IosConfigurations::provisioningDataChanged, + this, &IosBuildSettingsWidget::populateDevelopmentTeams); + connect(ui->m_signEntityCombo, static_cast(&QComboBox::currentIndexChanged), + this, &IosBuildSettingsWidget::onSigningEntityComboIndexChanged); + connect(ui->m_autoSignCheckbox, &QCheckBox::toggled, + this, &IosBuildSettingsWidget::configureSigningUi); + configureSigningUi(ui->m_autoSignCheckbox->isChecked()); + setDefaultSigningIdentfier(signingIdentifier); + } + + ui->m_autoSignCheckbox->setEnabled(isDevice); + ui->m_signEntityCombo->setEnabled(isDevice); + ui->m_qmakeDefaults->setEnabled(isDevice); + ui->m_signEntityLabel->setEnabled(isDevice); + adjustSize(); +} + +IosBuildSettingsWidget::~IosBuildSettingsWidget() +{ + delete ui; +} + +void IosBuildSettingsWidget::setDefaultSigningIdentfier(const QString &identifier) const +{ + if (identifier.isEmpty()) { + ui->m_signEntityCombo->setCurrentIndex(0); + return; + } + + int defaultIndex = -1; + for (int index = 0; index < ui->m_signEntityCombo->count(); ++index) { + QString teamID = ui->m_signEntityCombo->itemData(index, IdentifierRole).toString(); + if (teamID == identifier) { + defaultIndex = index; + break; + } + } + if (defaultIndex > -1) { + ui->m_signEntityCombo->setCurrentIndex(defaultIndex); + } else { + // Reset to default + ui->m_signEntityCombo->setCurrentIndex(0); + qCDebug(iosSettingsLog) << "Can not find default" + << (ui->m_autoSignCheckbox->isChecked() ? "team": "provisioning profile") + << ". Identifier: " << identifier; + } +} + +bool IosBuildSettingsWidget::isSigningAutomaticallyManaged() const +{ + return ui->m_autoSignCheckbox->isChecked() && ui->m_signEntityCombo->currentIndex() > 0; +} + +void IosBuildSettingsWidget::onSigningEntityComboIndexChanged() +{ + QString identifier = selectedIdentifier(); + (ui->m_autoSignCheckbox->isChecked() ? m_lastTeamSelection : m_lastProfileSelection) = identifier; + + updateInfoText(); + updateWarningText(); + emit signingSettingsChanged(ui->m_autoSignCheckbox->isChecked(), identifier); +} + +void IosBuildSettingsWidget::onReset() +{ + m_lastTeamSelection.clear(); + m_lastProfileSelection.clear(); + ui->m_autoSignCheckbox->setChecked(true); + setDefaultSigningIdentfier(""); +} + +void IosBuildSettingsWidget::configureSigningUi(bool autoManageSigning) +{ + ui->m_signEntityLabel->setText(autoManageSigning ? tr("Development team:") + : tr("Provisioning profile:")); + if (autoManageSigning) + populateDevelopmentTeams(); + else + populateProvisioningProfiles(); + + updateInfoText(); + emit signingSettingsChanged(autoManageSigning, selectedIdentifier()); +} + +void IosBuildSettingsWidget::populateDevelopmentTeams() +{ + // Populate Team id's + ui->m_signEntityCombo->blockSignals(true); + ui->m_signEntityCombo->clear(); + ui->m_signEntityCombo->addItem(tr("Default")); + foreach (auto team, IosConfigurations::developmentTeams()) { + ui->m_signEntityCombo->addItem(team->displayName()); + const int index = ui->m_signEntityCombo->count() - 1; + ui->m_signEntityCombo->setItemData(index, team->identifier(), IdentifierRole); + ui->m_signEntityCombo->setItemData(index, team->details(), Qt::ToolTipRole); + } + ui->m_signEntityCombo->blockSignals(false); + // Maintain previous selection. + setDefaultSigningIdentfier(m_lastTeamSelection); + updateWarningText(); +} + +void IosBuildSettingsWidget::populateProvisioningProfiles() +{ + // Populate Team id's + ui->m_signEntityCombo->blockSignals(true); + ui->m_signEntityCombo->clear(); + ProvisioningProfiles profiles = IosConfigurations::provisioningProfiles(); + if (profiles.count() > 0) { + foreach (auto profile, profiles) { + ui->m_signEntityCombo->addItem(profile->displayName()); + const int index = ui->m_signEntityCombo->count() - 1; + ui->m_signEntityCombo->setItemData(index, profile->identifier(), IdentifierRole); + ui->m_signEntityCombo->setItemData(index, profile->details(), Qt::ToolTipRole); + } + } else { + ui->m_signEntityCombo->addItem(tr("None")); + } + ui->m_signEntityCombo->blockSignals(false); + // Maintain previous selection. + setDefaultSigningIdentfier(m_lastProfileSelection); + updateWarningText(); +} + +QString IosBuildSettingsWidget::selectedIdentifier() const +{ + return ui->m_signEntityCombo->currentData(IdentifierRole).toString(); +} + +void IosBuildSettingsWidget::updateInfoText() +{ + if (m_deviceType != Constants::IOS_DEVICE_TYPE) + return; + + QString infoMessage; + auto addMessage = [&infoMessage](const QString &msg) { + if (!infoMessage.isEmpty()) + infoMessage += "\n"; + infoMessage += msg; + }; + + QString identifier = selectedIdentifier(); + bool configuringTeams = ui->m_autoSignCheckbox->isChecked(); + + if (identifier.isEmpty()) { + // No signing entity selection. + if (configuringTeams) + addMessage(tr("Development team is not selected.")); + else + addMessage(tr("Provisioning profile is not selected.")); + + addMessage(tr("Using default development team and provisioning profile.")); + } else { + if (!configuringTeams) { + ProvisioningProfilePtr profile = IosConfigurations::provisioningProfile(identifier); + QTC_ASSERT(profile, return); + auto team = profile->developmentTeam(); + if (team) { + // Display corresponding team information. + addMessage(tr("Development team: %1 (%2)").arg(team->displayName()) + .arg(team->identifier())); + addMessage(tr("Settings defined here override the QMake environment.")); + } else { + qCDebug(iosSettingsLog) << "Development team not found for profile" << profile; + } + } else { + addMessage(tr("Settings defined here override the QMake environment.")); + } + } + + ui->m_infoIconLabel->setVisible(!infoMessage.isEmpty()); + ui->m_infoLabel->setVisible(!infoMessage.isEmpty()); + ui->m_infoLabel->setText(infoMessage); +} + +void IosBuildSettingsWidget::updateWarningText() +{ + if (m_deviceType != Constants::IOS_DEVICE_TYPE) + return; + + QString warningText; + bool configuringTeams = ui->m_autoSignCheckbox->isChecked(); + if (ui->m_signEntityCombo->count() < 2) { + warningText = tr("%1 not configured. Use Xcode and Apple developer account to configure the " + "provisioning profiles and teams.") + .arg(configuringTeams ? tr("Development teams") : tr("Provisioning profiles")); + } else { + QString identifier = selectedIdentifier(); + if (configuringTeams) { + auto team = IosConfigurations::developmentTeam(identifier); + if (team && !team->hasProvisioningProfile()) + warningText = tr("No provisioning profile found for the selected team."); + } else { + auto profile = IosConfigurations::provisioningProfile(identifier); + if (profile && QDateTime::currentDateTimeUtc() > profile->expirationDate()) { + warningText = tr("Provisioning profile expired. Expiration date: %1") + .arg(profile->expirationDate().toLocalTime().toString(Qt::SystemLocaleLongDate)); + } + } + } + + ui->m_warningLabel->setVisible(!warningText.isEmpty()); + ui->m_warningIconLabel->setVisible(!warningText.isEmpty()); + ui->m_warningLabel->setText(warningText); +} + +} // namespace Internal +} // namespace Ios diff --git a/src/plugins/ios/iosbuildsettingswidget.h b/src/plugins/ios/iosbuildsettingswidget.h new file mode 100644 index 00000000000..6460599c616 --- /dev/null +++ b/src/plugins/ios/iosbuildsettingswidget.h @@ -0,0 +1,80 @@ +/**************************************************************************** +** +** 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. +** +****************************************************************************/ +#pragma once + +#include "coreplugin/id.h" +#include "projectexplorer/namedwidget.h" + +#include + +namespace Utils { +class DetailsWidget; +} + + +namespace Ios { +namespace Internal { +namespace Ui { + class IosBuildSettingsWidget; +} + +class IosBuildSettingsWidget : public ProjectExplorer::NamedWidget +{ + Q_OBJECT + +public: + explicit IosBuildSettingsWidget(const Core::Id &deviceType, const QString &signingIdentifier, + bool isSigningAutoManaged, QWidget *parent = 0); + ~IosBuildSettingsWidget(); + +public: + bool isSigningAutomaticallyManaged() const; + +private slots: + void onSigningEntityComboIndexChanged(); + void onReset(); + +signals: + void signingSettingsChanged(bool isAutoManaged, QString identifier); + +private: + void setDefaultSigningIdentfier(const QString &identifier) const; + void configureSigningUi(bool autoManageSigning); + void populateDevelopmentTeams(); + void populateProvisioningProfiles(); + QString selectedIdentifier() const; + void updateInfoText(); + void updateWarningText(); + +private: + Ui::IosBuildSettingsWidget *ui; + Utils::DetailsWidget *m_detailsWidget; + QString m_lastProfileSelection; + QString m_lastTeamSelection; + const Core::Id m_deviceType; +}; + +} // namespace Internal +} // namespace Ios diff --git a/src/plugins/ios/iosbuildsettingswidget.ui b/src/plugins/ios/iosbuildsettingswidget.ui new file mode 100644 index 00000000000..3ad4928a893 --- /dev/null +++ b/src/plugins/ios/iosbuildsettingswidget.ui @@ -0,0 +1,137 @@ + + + Ios::Internal::IosBuildSettingsWidget + + + + 0 + 0 + 467 + 141 + + + + Form + + + + + + + + + 0 + 0 + + + + Reset + + + + + + + + 0 + 0 + + + + + + + + + 0 + 0 + + + + Automatically manage signing + + + true + + + + + + + Development team: + + + + + + + + + + + + 0 + 0 + + + + + + + + + + + + 0 + 0 + + + + + + + false + + + + + + + + + + + + 0 + 0 + + + + + + + + + + + + 0 + 0 + + + + + + + true + + + + + + + + + + diff --git a/src/plugins/ios/iosconfigurations.cpp b/src/plugins/ios/iosconfigurations.cpp index 19f6f39d63b..566fcc9fef4 100644 --- a/src/plugins/ios/iosconfigurations.cpp +++ b/src/plugins/ios/iosconfigurations.cpp @@ -32,6 +32,7 @@ #include #include +#include #include #include #include @@ -49,12 +50,15 @@ #include #include +#include #include #include +#include #include #include +#include +#include #include -#include #include using namespace ProjectExplorer; @@ -74,6 +78,21 @@ namespace Internal { const QLatin1String SettingsGroup("IosConfigurations"); const QLatin1String ignoreAllDevicesKey("IgnoreAllDevices"); +const char provisioningTeamsTag[] = "IDEProvisioningTeams"; +const char freeTeamTag[] = "isFreeProvisioningTeam"; +const char emailTag[] = "eMail"; +const char teamNameTag[] = "teamName"; +const char teamIdTag[] = "teamID"; + +const char udidTag[] = "UUID"; +const char profileNameTag[] = "Name"; +const char appIdTag[] = "AppIDName"; +const char expirationDateTag[] = "ExpirationDate"; +const char profileTeamIdTag[] = "TeamIdentifier"; + +static const QString xcodePlistPath = QDir::homePath() + "/Library/Preferences/com.apple.dt.Xcode.plist"; +static const QString provisioningProfileDirPath = QDir::homePath() + "/Library/MobileDevice/Provisioning Profiles"; + static Core::Id deviceId(const Platform &platform) { if (platform.name.startsWith(QLatin1String("iphoneos-"))) @@ -246,6 +265,20 @@ static QVersionNumber findXcodeVersion() return QVersionNumber(); } +static QByteArray decodeProvisioningProfile(const QString &path) +{ + QTC_ASSERT(!path.isEmpty(), return QByteArray()); + + Utils::SynchronousProcess p; + p.setTimeoutS(3); + // path is assumed to be valid file path to .mobileprovision + const QStringList args = {"smime", "-inform", "der", "-verify", "-in", path}; + Utils::SynchronousProcessResponse res = p.runBlocking("openssl", args); + if (res.result != Utils::SynchronousProcessResponse::Finished) + qCDebug(iosCommonLog) << "Reading signed provisioning file failed" << path; + return res.stdOut().toLatin1(); +} + void IosConfigurations::updateAutomaticKitList() { const QList platforms = handledPlatforms(); @@ -320,9 +353,9 @@ void IosConfigurations::updateAutomaticKitList() KitManager::deregisterKit(kit); } -static IosConfigurations *m_instance = 0; +static IosConfigurations *m_instance = nullptr; -QObject *IosConfigurations::instance() +IosConfigurations *IosConfigurations::instance() { return m_instance; } @@ -409,6 +442,137 @@ void IosConfigurations::setDeveloperPath(const FileName &devPath) } } +void IosConfigurations::initializeProvisioningData() +{ + // Initialize provisioning data only on demand. i.e. when first call to a provisioing data API + // is made. + static bool initialized = false; + if (initialized) + return; + initialized = true; + + m_instance->loadProvisioningData(false); + + // Watch the provisioing profiles folder and xcode plist for changes and + // update the content accordingly. + m_provisioningDataWatcher = new QFileSystemWatcher(this); + m_provisioningDataWatcher->addPath(xcodePlistPath); + m_provisioningDataWatcher->addPath(provisioningProfileDirPath); + connect(m_provisioningDataWatcher, &QFileSystemWatcher::directoryChanged, + std::bind(&IosConfigurations::loadProvisioningData, this, true)); + connect(m_provisioningDataWatcher, &QFileSystemWatcher::fileChanged, + std::bind(&IosConfigurations::loadProvisioningData, this, true)); +} + +void IosConfigurations::loadProvisioningData(bool notify) +{ + m_developerTeams.clear(); + m_provisioningProfiles.clear(); + + // Populate Team id's + const QSettings xcodeSettings(xcodePlistPath, QSettings::NativeFormat); + const QVariantMap teamMap = xcodeSettings.value(provisioningTeamsTag).toMap(); + QList teams; + QMapIterator accountiterator(teamMap); + while (accountiterator.hasNext()) { + accountiterator.next(); + QVariantMap teamInfo = accountiterator.value().toMap(); + int provisioningTeamIsFree = teamInfo.value(freeTeamTag).toBool() ? 1 : 0; + teamInfo[freeTeamTag] = provisioningTeamIsFree; + teamInfo[emailTag] = accountiterator.key(); + teams.append(teamInfo); + } + + // Sort team id's to move the free provisioning teams at last of the list. + Utils::sort(teams, [](const QVariantMap &teamInfo1, const QVariantMap &teamInfo2) { + return teamInfo1.value(freeTeamTag).toInt() < teamInfo2.value(freeTeamTag).toInt(); + }); + + foreach (auto teamInfo, teams) { + auto team = std::make_shared(); + team->m_name = teamInfo.value(teamNameTag).toString(); + team->m_email = teamInfo.value(emailTag).toString(); + team->m_identifier = teamInfo.value(teamIdTag).toString(); + team->m_freeTeam = teamInfo.value(freeTeamTag).toInt() == 1; + m_developerTeams.append(team); + } + + const QDir provisioningProflesDir(provisioningProfileDirPath); + foreach (QFileInfo fileInfo, provisioningProflesDir.entryInfoList({"*.mobileprovision"}, QDir::NoDotAndDotDot | QDir::Files)) { + QDomDocument provisioningDoc; + auto profile = std::make_shared(); + QString teamID; + if (provisioningDoc.setContent(decodeProvisioningProfile(fileInfo.absoluteFilePath()))) { + QDomNodeList nodes = provisioningDoc.elementsByTagName("key"); + for (int i = 0;im_identifier = e.nextSiblingElement().text(); + + if (e.text().compare(profileNameTag) == 0) + profile->m_name = e.nextSiblingElement().text(); + + if (e.text().compare(appIdTag) == 0) + profile->m_appID = e.nextSiblingElement().text(); + + if (e.text().compare(expirationDateTag) == 0) + profile->m_expirationDate = QDateTime::fromString(e.nextSiblingElement().text(), + Qt::ISODate).toUTC(); + + if (e.text().compare(profileTeamIdTag) == 0) { + teamID = e.nextSibling().firstChildElement().text(); + auto team = developmentTeam(teamID); + if (team) { + profile->m_team = team; + team->m_profiles.append(profile); + } + } + } + } else { + qCDebug(iosCommonLog) << "Error reading provisoing profile" << fileInfo.absoluteFilePath(); + } + + if (profile->m_team) + m_provisioningProfiles.append(profile); + else + qCDebug(iosCommonLog) << "Skipping profile. No corresponding team found" << profile; + } + + if (notify) + emit provisioningDataChanged(); +} + +const DevelopmentTeams &IosConfigurations::developmentTeams() +{ + QTC_CHECK(m_instance); + m_instance->initializeProvisioningData(); + return m_instance->m_developerTeams; +} + +DevelopmentTeamPtr IosConfigurations::developmentTeam(const QString &teamID) +{ + QTC_CHECK(m_instance); + m_instance->initializeProvisioningData(); + return findOrDefault(m_instance->m_developerTeams, + Utils::equal(&DevelopmentTeam::identifier, teamID)); +} + +const ProvisioningProfiles &IosConfigurations::provisioningProfiles() +{ + QTC_CHECK(m_instance); + m_instance->initializeProvisioningData(); + return m_instance->m_provisioningProfiles; +} + +ProvisioningProfilePtr IosConfigurations::provisioningProfile(const QString &profileID) +{ + QTC_CHECK(m_instance); + m_instance->initializeProvisioningData(); + return Utils::findOrDefault(m_instance->m_provisioningProfiles, + Utils::equal(&ProvisioningProfile::identifier, profileID)); +} + static ClangToolChain *createToolChain(const Platform &platform, Core::Id l) { if (!l.isValid()) @@ -455,5 +619,52 @@ QList IosToolChainFactory::autoDetect(const QList &exi return Utils::transform(toolChains, [](ClangToolChain *tc) -> ToolChain * { return tc; }); } +QString DevelopmentTeam::identifier() const +{ + return m_identifier; +} + +QString DevelopmentTeam::displayName() const +{ + return QString("%1 - %2").arg(m_email).arg(m_name); +} + +QString DevelopmentTeam::details() const +{ + return tr("%1 - Free Provisioning Team : %2") + .arg(m_identifier).arg(m_freeTeam ? tr("Yes") : tr("No")); +} + +QDebug &operator<<(QDebug &stream, DevelopmentTeamPtr team) +{ + QTC_ASSERT(team, return stream); + stream << team->displayName() << team->identifier() << team->isFreeProfile(); + foreach (auto profile, team->m_profiles) + stream << "Profile:" << profile; + return stream; +} + +QString ProvisioningProfile::identifier() const +{ + return m_identifier; +} + +QString ProvisioningProfile::displayName() const +{ + return m_name; +} + +QString ProvisioningProfile::details() const +{ + return tr("Team: %1\nApp ID: %2\nExpiration date: %3").arg(m_team->identifier()).arg(m_appID) + .arg(m_expirationDate.toLocalTime().toString(Qt::SystemLocaleShortDate)); +} + +QDebug &operator<<(QDebug &stream, std::shared_ptr profile) +{ + QTC_ASSERT(profile, return stream); + return stream << profile->displayName() << profile->identifier() << profile->details(); +} + } // namespace Internal } // namespace Ios diff --git a/src/plugins/ios/iosconfigurations.h b/src/plugins/ios/iosconfigurations.h index 7ddbb7e4620..f5f5f9798d5 100644 --- a/src/plugins/ios/iosconfigurations.h +++ b/src/plugins/ios/iosconfigurations.h @@ -29,18 +29,72 @@ #include #include +#include #include #include #include #include +#include + QT_BEGIN_NAMESPACE class QSettings; +class QFileSystemWatcher; QT_END_NAMESPACE namespace Ios { namespace Internal { +class DevelopmentTeam; + +class ProvisioningProfile +{ + Q_DECLARE_TR_FUNCTIONS(ProvisioningProfile) +public: + ProvisioningProfile() {} + std::shared_ptr developmentTeam() { return m_team; } + QString identifier() const; + QString displayName() const; + QString details() const; + const QDateTime &expirationDate() const { return m_expirationDate; } + +private: + std::shared_ptr m_team; + QString m_identifier; + QString m_name; + QString m_appID; + QDateTime m_expirationDate; + friend class IosConfigurations; + friend QDebug &operator<<(QDebug &stream, std::shared_ptr profile); +}; + +using ProvisioningProfilePtr = std::shared_ptr; +using ProvisioningProfiles = QList; + +class DevelopmentTeam +{ + Q_DECLARE_TR_FUNCTIONS(DevelopmentTeam) +public: + DevelopmentTeam() {} + QString identifier() const; + QString displayName() const; + QString details() const; + bool isFreeProfile() const { return m_freeTeam; } + bool hasProvisioningProfile() const { return !m_profiles.isEmpty(); } + +private: + QString m_identifier; + QString m_name; + QString m_email; + bool m_freeTeam = false; + ProvisioningProfiles m_profiles; + friend class IosConfigurations; + friend QDebug &operator<<(QDebug &stream, std::shared_ptr team); +}; + +using DevelopmentTeamPtr = std::shared_ptr; +using DevelopmentTeams = QList; + class IosToolChainFactory : public ProjectExplorer::ToolChainFactory { Q_OBJECT @@ -50,13 +104,12 @@ public: QList autoDetect(const QList &existingToolChains) override; }; - class IosConfigurations : public QObject { Q_OBJECT public: - static QObject *instance(); + static IosConfigurations *instance(); static void initialize(); static bool ignoreAllDevices(); static void setIgnoreAllDevices(bool ignoreDevices); @@ -64,6 +117,13 @@ public: static QVersionNumber xcodeVersion(); static Utils::FileName lldbPath(); static void updateAutomaticKitList(); + static const DevelopmentTeams &developmentTeams(); + static DevelopmentTeamPtr developmentTeam(const QString &teamID); + static const ProvisioningProfiles &provisioningProfiles(); + static ProvisioningProfilePtr provisioningProfile(const QString &profileID); + +signals: + void provisioningDataChanged(); private: IosConfigurations(QObject *parent); @@ -71,11 +131,17 @@ private: void save(); void updateSimulators(); static void setDeveloperPath(const Utils::FileName &devPath); + void initializeProvisioningData(); + void loadProvisioningData(bool notify = true); Utils::FileName m_developerPath; QVersionNumber m_xcodeVersion; bool m_ignoreAllDevices; + QFileSystemWatcher *m_provisioningDataWatcher; + ProvisioningProfiles m_provisioningProfiles; + DevelopmentTeams m_developerTeams; }; - +QDebug &operator<<(QDebug &stream, std::shared_ptr profile); +QDebug &operator<<(QDebug &stream, std::shared_ptr team); } // namespace Internal } // namespace Ios diff --git a/src/plugins/ios/iosplugin.cpp b/src/plugins/ios/iosplugin.cpp index 761326ba05c..28e590167e0 100644 --- a/src/plugins/ios/iosplugin.cpp +++ b/src/plugins/ios/iosplugin.cpp @@ -25,6 +25,7 @@ #include "iosplugin.h" +#include "iosbuildconfiguration.h" #include "iosbuildstep.h" #include "iosconfigurations.h" #include "iosconstants.h" @@ -64,6 +65,7 @@ bool IosPlugin::initialize(const QStringList &arguments, QString *errorMessage) Internal::IosConfigurations::initialize(); + addAutoReleasedObject(new Internal::IosBuildConfigurationFactory); addAutoReleasedObject(new Internal::IosToolChainFactory); addAutoReleasedObject(new Internal::IosRunControlFactory); addAutoReleasedObject(new Internal::IosRunConfigurationFactory); diff --git a/src/plugins/nim/nim.pro b/src/plugins/nim/nim.pro index 85e3881e92c..1a27ab50cf0 100644 --- a/src/plugins/nim/nim.pro +++ b/src/plugins/nim/nim.pro @@ -29,7 +29,6 @@ HEADERS += \ project/nimcompilerbuildstepfactory.h \ project/nimcompilercleanstepfactory.h \ project/nimbuildconfigurationwidget.h \ - project/nimruncontrol.h \ project/nimruncontrolfactory.h \ editor/nimeditorfactory.h \ settings/nimcodestylesettingspage.h \ @@ -59,7 +58,6 @@ SOURCES += \ project/nimcompilerbuildstepfactory.cpp \ project/nimcompilercleanstepfactory.cpp \ project/nimbuildconfigurationwidget.cpp \ - project/nimruncontrol.cpp \ project/nimruncontrolfactory.cpp \ editor/nimeditorfactory.cpp \ settings/nimcodestylesettingspage.cpp \ diff --git a/src/plugins/nim/nim.qbs b/src/plugins/nim/nim.qbs index 94ec0a0de4e..d8fb94f0d9a 100644 --- a/src/plugins/nim/nim.qbs +++ b/src/plugins/nim/nim.qbs @@ -49,7 +49,6 @@ QtcPlugin { "nimrunconfiguration.h", "nimrunconfiguration.cpp", "nimrunconfigurationfactory.h", "nimrunconfigurationfactory.cpp", "nimrunconfigurationwidget.h", "nimrunconfigurationwidget.cpp", - "nimruncontrol.h", "nimruncontrol.cpp", "nimruncontrolfactory.h", "nimruncontrolfactory.cpp", "nimtoolchain.h", "nimtoolchain.cpp", "nimtoolchainfactory.h", "nimtoolchainfactory.cpp", diff --git a/src/plugins/nim/project/nimproject.cpp b/src/plugins/nim/project/nimproject.cpp index 2b6b297adb7..a73daf10955 100644 --- a/src/plugins/nim/project/nimproject.cpp +++ b/src/plugins/nim/project/nimproject.cpp @@ -156,7 +156,7 @@ void NimProject::updateProject() auto newRoot = new NimProjectNode(*this, projectDirectory()); newRoot->setDisplayName(displayName()); - newRoot->buildTree(fileNodes); + newRoot->addNestedNodes(fileNodes); setRootProjectNode(newRoot); emit fileListChanged(); diff --git a/src/plugins/nim/project/nimruncontrol.cpp b/src/plugins/nim/project/nimruncontrol.cpp deleted file mode 100644 index 3e5ea4eee56..00000000000 --- a/src/plugins/nim/project/nimruncontrol.cpp +++ /dev/null @@ -1,92 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) Filippo Cucchetto -** Contact: http://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 "nimruncontrol.h" -#include "nimrunconfiguration.h" - -#include -#include -#include - -#include - -using namespace ProjectExplorer; -using namespace Utils; - -namespace Nim { - -NimRunControl::NimRunControl(NimRunConfiguration *rc, Core::Id mode) - : RunControl(rc, mode) - , m_runnable(rc->runnable().as()) -{ - connect(&m_applicationLauncher, &ApplicationLauncher::appendMessage, - this, &NimRunControl::slotAppendMessage); - connect(&m_applicationLauncher, &ApplicationLauncher::processStarted, - this, &NimRunControl::processStarted); - connect(&m_applicationLauncher, &ApplicationLauncher::processExited, - this, &NimRunControl::processExited); -} - -void NimRunControl::start() -{ - reportApplicationStart(); - m_applicationLauncher.start(m_runnable); - setApplicationProcessHandle(m_applicationLauncher.applicationPID()); - bringApplicationToForeground(); -} - -ProjectExplorer::RunControl::StopResult NimRunControl::stop() -{ - m_applicationLauncher.stop(); - return StoppedSynchronously; -} - -void NimRunControl::processStarted() -{ - // Console processes only know their pid after being started - setApplicationProcessHandle(m_applicationLauncher.applicationPID()); -} - -void NimRunControl::processExited(int exitCode, QProcess::ExitStatus status) -{ - setApplicationProcessHandle(ProcessHandle()); - QString msg; - if (status == QProcess::CrashExit) { - msg = tr("%1 crashed") - .arg(QDir::toNativeSeparators(m_runnable.executable)); - } else { - msg = tr("%1 exited with code %2") - .arg(QDir::toNativeSeparators(m_runnable.executable)).arg(exitCode); - } - appendMessage(msg + QLatin1Char('\n'), NormalMessageFormat); - reportApplicationStop(); -} - -void NimRunControl::slotAppendMessage(const QString &err, OutputFormat format) -{ - appendMessage(err, format); -} - -} diff --git a/src/plugins/nim/project/nimruncontrol.h b/src/plugins/nim/project/nimruncontrol.h deleted file mode 100644 index 0eba08e8cea..00000000000 --- a/src/plugins/nim/project/nimruncontrol.h +++ /dev/null @@ -1,56 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) Filippo Cucchetto -** Contact: http://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. -** -****************************************************************************/ - -#pragma once - -#include -#include - -#include - -namespace Nim { - -class NimRunConfiguration; - -class NimRunControl : public ProjectExplorer::RunControl -{ - Q_DECLARE_TR_FUNCTIONS(Nim::NimRunControl) - -public: - NimRunControl(NimRunConfiguration *runConfiguration, Core::Id mode); - - void start() override; - StopResult stop() override; - -private: - void processStarted(); - void processExited(int exitCode, QProcess::ExitStatus status); - void slotAppendMessage(const QString &err, Utils::OutputFormat isError); - - ProjectExplorer::ApplicationLauncher m_applicationLauncher; - ProjectExplorer::StandardRunnable m_runnable; -}; - -} diff --git a/src/plugins/nim/project/nimruncontrolfactory.cpp b/src/plugins/nim/project/nimruncontrolfactory.cpp index 3f02586ed7d..170e79f82db 100644 --- a/src/plugins/nim/project/nimruncontrolfactory.cpp +++ b/src/plugins/nim/project/nimruncontrolfactory.cpp @@ -25,7 +25,6 @@ #include "nimruncontrolfactory.h" #include "nimrunconfiguration.h" -#include "nimruncontrol.h" namespace Nim { @@ -39,7 +38,7 @@ ProjectExplorer::RunControl *NimRunControlFactory::create(ProjectExplorer::RunCo { Q_UNUSED(errorMessage) QTC_ASSERT(canRun(runConfiguration, mode), return 0); - return new NimRunControl(static_cast(runConfiguration), mode); + return new ProjectExplorer::SimpleRunControl(runConfiguration, mode); } } diff --git a/src/plugins/nim/project/nimtoolchain.cpp b/src/plugins/nim/project/nimtoolchain.cpp index 1c34ec24058..6c8fd0f32b8 100644 --- a/src/plugins/nim/project/nimtoolchain.cpp +++ b/src/plugins/nim/project/nimtoolchain.cpp @@ -32,6 +32,7 @@ #include #include +#include using namespace ProjectExplorer; using namespace Utils; diff --git a/src/plugins/projectexplorer/abi.cpp b/src/plugins/projectexplorer/abi.cpp index 7f4773fc7b8..28356e15838 100644 --- a/src/plugins/projectexplorer/abi.cpp +++ b/src/plugins/projectexplorer/abi.cpp @@ -30,6 +30,7 @@ #include #include #include +#include #include #include #include diff --git a/src/plugins/projectexplorer/gcctoolchain.cpp b/src/plugins/projectexplorer/gcctoolchain.cpp index 30f77f739e0..ae4c9813d8e 100644 --- a/src/plugins/projectexplorer/gcctoolchain.cpp +++ b/src/plugins/projectexplorer/gcctoolchain.cpp @@ -455,6 +455,7 @@ ToolChain::PredefinedMacrosRunner GccToolChain::createPredefinedMacrosRunner() c } else if (a == "-m128bit-long-double" || a == "-m32" || a == "-m3dnow" || a == "-m3dnowa" || a == "-m64" || a == "-m96bit-long-double" || a == "-mabm" || a == "-maes" || a.startsWith("-march=") || a == "-mavx" || a.startsWith("-masm=") + || a.startsWith("-mfloat-abi") || a == "-mcx16" || a == "-mfma" || a == "-mfma4" || a == "-mlwp" || a == "-mpclmul" || a == "-mpopcnt" || a == "-msse" || a == "-msse2" || a == "-msse2avx" || a == "-msse3" || a == "-msse4" || a == "-msse4.1" @@ -907,17 +908,6 @@ ToolChain *GccToolChainFactory::create(Core::Id language) QList GccToolChainFactory::autoDetect(const QList &alreadyKnown) { QList tcs; - if (HostOsInfo::isMacHost()) { - // Old mac compilers needed to support macx-gccXY mkspecs: - tcs.append(autoDetectToolchains("g++-4.0", Abi::hostAbi(), Constants::CXX_LANGUAGE_ID, - Constants::GCC_TOOLCHAIN_TYPEID, alreadyKnown)); - tcs.append(autoDetectToolchains("g++-4.2", Abi::hostAbi(), Constants::CXX_LANGUAGE_ID, - Constants::GCC_TOOLCHAIN_TYPEID, alreadyKnown)); - tcs.append(autoDetectToolchains("gcc-4.0", Abi::hostAbi(), Constants::C_LANGUAGE_ID, - Constants::GCC_TOOLCHAIN_TYPEID, alreadyKnown)); - tcs.append(autoDetectToolchains("gcc-4.2", Abi::hostAbi(), Constants::C_LANGUAGE_ID, - Constants::GCC_TOOLCHAIN_TYPEID, alreadyKnown)); - } tcs.append(autoDetectToolchains("g++", Abi::hostAbi(), Constants::CXX_LANGUAGE_ID, Constants::GCC_TOOLCHAIN_TYPEID, alreadyKnown)); tcs.append(autoDetectToolchains("gcc", Abi::hostAbi(), Constants::C_LANGUAGE_ID, diff --git a/src/plugins/projectexplorer/localapplicationruncontrol.cpp b/src/plugins/projectexplorer/localapplicationruncontrol.cpp index 9cd27dc166e..bb13231ae9d 100644 --- a/src/plugins/projectexplorer/localapplicationruncontrol.cpp +++ b/src/plugins/projectexplorer/localapplicationruncontrol.cpp @@ -25,7 +25,6 @@ #include "localapplicationruncontrol.h" #include "runnables.h" -#include "environmentaspect.h" #include #include @@ -34,91 +33,11 @@ #include #include -#include - using namespace Utils; namespace ProjectExplorer { namespace Internal { -class LocalApplicationRunControl : public RunControl -{ - Q_OBJECT - -public: - LocalApplicationRunControl(RunConfiguration *runConfiguration, Core::Id mode); - - void start() override; - StopResult stop() override; - -private: - void processStarted(); - void processExited(int exitCode, QProcess::ExitStatus status); - - ApplicationLauncher m_applicationLauncher; -}; - -LocalApplicationRunControl::LocalApplicationRunControl(RunConfiguration *rc, Core::Id mode) - : RunControl(rc, mode) -{ - setRunnable(rc->runnable()); - setIcon(Utils::Icons::RUN_SMALL_TOOLBAR); - connect(&m_applicationLauncher, &ApplicationLauncher::appendMessage, - this, static_cast(&RunControl::appendMessage)); - connect(&m_applicationLauncher, &ApplicationLauncher::processStarted, - this, &LocalApplicationRunControl::processStarted); - connect(&m_applicationLauncher, &ApplicationLauncher::processExited, - this, &LocalApplicationRunControl::processExited); -} - -void LocalApplicationRunControl::start() -{ - QTC_ASSERT(runnable().is(), return); - auto r = runnable().as(); - reportApplicationStart(); - if (r.executable.isEmpty()) { - appendMessage(tr("No executable specified.") + QLatin1Char('\n'), Utils::ErrorMessageFormat); - reportApplicationStop(); - } else if (!QFileInfo::exists(r.executable)) { - appendMessage(tr("Executable %1 does not exist.") - .arg(QDir::toNativeSeparators(r.executable)) + QLatin1Char('\n'), - Utils::ErrorMessageFormat); - reportApplicationStop(); - } else { - QString msg = tr("Starting %1...").arg(QDir::toNativeSeparators(r.executable)) + QLatin1Char('\n'); - appendMessage(msg, Utils::NormalMessageFormat); - m_applicationLauncher.start(r); - setApplicationProcessHandle(m_applicationLauncher.applicationPID()); - } -} - -LocalApplicationRunControl::StopResult LocalApplicationRunControl::stop() -{ - m_applicationLauncher.stop(); - return StoppedSynchronously; -} - -void LocalApplicationRunControl::processStarted() -{ - // Console processes only know their pid after being started - setApplicationProcessHandle(m_applicationLauncher.applicationPID()); - bringApplicationToForeground(); -} - -void LocalApplicationRunControl::processExited(int exitCode, QProcess::ExitStatus status) -{ - QString msg; - QString exe = runnable().as().executable; - if (status == QProcess::CrashExit) - msg = tr("%1 crashed.").arg(QDir::toNativeSeparators(exe)); - else - msg = tr("%1 exited with code %2").arg(QDir::toNativeSeparators(exe)).arg(exitCode); - appendMessage(msg + QLatin1Char('\n'), Utils::NormalMessageFormat); - reportApplicationStop(); -} - -// LocalApplicationRunControlFactory - static bool isLocal(RunConfiguration *runConfiguration) { Target *target = runConfiguration ? runConfiguration->target() : nullptr; @@ -142,10 +61,8 @@ bool LocalApplicationRunControlFactory::canRun(RunConfiguration *runConfiguratio RunControl *LocalApplicationRunControlFactory::create(RunConfiguration *runConfiguration, Core::Id mode, QString *errorMessage) { Q_UNUSED(errorMessage) - return new LocalApplicationRunControl(runConfiguration, mode); + return new SimpleRunControl(runConfiguration, mode); } } // namespace Internal } // namespace ProjectExplorer - -#include "localapplicationruncontrol.moc" diff --git a/src/plugins/projectexplorer/project.cpp b/src/plugins/projectexplorer/project.cpp index 43870201dbd..6c97502dd6b 100644 --- a/src/plugins/projectexplorer/project.cpp +++ b/src/plugins/projectexplorer/project.cpp @@ -419,7 +419,7 @@ void Project::setDocument(Core::IDocument *doc) d->m_document = doc; if (!d->m_rootProjectNode) { - auto newRoot = new ProjectNode(projectDirectory()); + auto newRoot = new ProjectNode(projectFilePath()); newRoot->setDisplayName(displayName()); newRoot->addNode(new FileNode(projectFilePath(), FileType::Project, false)); setRootProjectNode(newRoot); diff --git a/src/plugins/projectexplorer/projectnodes.cpp b/src/plugins/projectexplorer/projectnodes.cpp index 87a759efea1..413d722bd2b 100644 --- a/src/plugins/projectexplorer/projectnodes.cpp +++ b/src/plugins/projectexplorer/projectnodes.cpp @@ -60,7 +60,8 @@ static FolderNode *folderNode(const FolderNode *folder, const Utils::FileName &d static FolderNode *recursiveFindOrCreateFolderNode(FolderNode *folder, const Utils::FileName &directory, - const Utils::FileName &overrideBaseDir) + const Utils::FileName &overrideBaseDir, + const FolderNode::FolderNodeFactory &factory) { Utils::FileName path = overrideBaseDir.isEmpty() ? folder->filePath() : overrideBaseDir; @@ -90,7 +91,7 @@ static FolderNode *recursiveFindOrCreateFolderNode(FolderNode *folder, FolderNode *next = folderNode(parent, path); if (!next) { // No FolderNode yet, so create it - auto tmp = new ProjectExplorer::FolderNode(path); + auto tmp = factory(path); tmp->setDisplayName(part); parent->addNode(tmp); next = tmp; @@ -400,6 +401,37 @@ QIcon FolderNode::icon() const return m_icon; } +Node *FolderNode::findNode(const std::function &filter) +{ + if (filter(this)) + return this; + + for (Node *n : m_nodes) { + if (n->asFileNode() && filter(n)) { + return n; + } else if (FolderNode *folder = n->asFolderNode()) { + Node *result = folder->findNode(filter); + if (result) + return result; + } + } + return nullptr; +} + +QList FolderNode::findNodes(const std::function &filter) +{ + QList result; + if (filter(this)) + result.append(this); + for (Node *n : m_nodes) { + if (n->asFileNode() && filter(n)) + result.append(n); + else if (FolderNode *folder = n->asFolderNode()) + result.append(folder->findNode(filter)); + } + return result; +} + void FolderNode::forEachNode(const std::function &fileTask, const std::function &folderTask, const std::function &folderFilterTask) const @@ -450,14 +482,6 @@ FileNode *FolderNode::fileNode(const Utils::FileName &file) const })); } -QList FolderNode::recursiveFileNodes() const -{ - QList result = fileNodes(); - foreach (ProjectExplorer::FolderNode *folder, folderNodes()) - result.append(folder->recursiveFileNodes()); - return result; -} - QList FolderNode::folderNodes() const { QList result; @@ -468,16 +492,22 @@ QList FolderNode::folderNodes() const return result; } -void FolderNode::buildTree(QList &files, const Utils::FileName &overrideBaseDir) +void FolderNode::addNestedNode(FileNode *fileNode, const Utils::FileName &overrideBaseDir, + const FolderNodeFactory &factory) { - foreach (ProjectExplorer::FileNode *fn, files) { - // Get relative path to rootNode - QString parentDir = fn->filePath().toFileInfo().absolutePath(); - ProjectExplorer::FolderNode *folder - = recursiveFindOrCreateFolderNode(this, Utils::FileName::fromString(parentDir), - overrideBaseDir); - folder->addNode(fn); - } + // Get relative path to rootNode + QString parentDir = fileNode->filePath().toFileInfo().absolutePath(); + FolderNode *folder = recursiveFindOrCreateFolderNode(this, Utils::FileName::fromString(parentDir), + overrideBaseDir, factory); + folder->addNode(fileNode); + +} + +void FolderNode::addNestedNodes(const QList &files, const Utils::FileName &overrideBaseDir, + const FolderNodeFactory &factory) +{ + for (FileNode *fn : files) + addNestedNode(fn, overrideBaseDir, factory); } // "Compress" a tree of foldernodes such that foldernodes with exactly one foldernode as a child @@ -673,7 +703,8 @@ ProjectNode::ProjectNode(const Utils::FileName &projectFilePath) : QString ProjectNode::vcsTopic() const { - const QString dir = filePath().toFileInfo().absolutePath(); + const QFileInfo fi = filePath().toFileInfo(); + const QString dir = fi.isDir() ? fi.absoluteFilePath() : fi.absolutePath(); if (Core::IVersionControl *const vc = Core::VcsManager::findVersionControlForDirectory(dir)) diff --git a/src/plugins/projectexplorer/projectnodes.h b/src/plugins/projectexplorer/projectnodes.h index 3785d2265d8..03858db5e73 100644 --- a/src/plugins/projectexplorer/projectnodes.h +++ b/src/plugins/projectexplorer/projectnodes.h @@ -192,6 +192,9 @@ public: QString displayName() const override; QIcon icon() const; + Node *findNode(const std::function &filter); + QList findNodes(const std::function &filter); + void forEachNode(const std::function &fileTask, const std::function &folderTask = {}, const std::function &folderFilterTask = {}) const; @@ -199,9 +202,12 @@ public: const QList nodes() const { return m_nodes; } QList fileNodes() const; FileNode *fileNode(const Utils::FileName &file) const; - QList recursiveFileNodes() const; QList folderNodes() const; - void buildTree(QList &files, const Utils::FileName &overrideBaseDir = Utils::FileName()); + using FolderNodeFactory = std::function; + void addNestedNodes(const QList &files, const Utils::FileName &overrideBaseDir = Utils::FileName(), + const FolderNodeFactory &factory = [](const Utils::FileName &fn) { return new FolderNode(fn); }); + void addNestedNode(FileNode *fileNode, const Utils::FileName &overrideBaseDir = Utils::FileName(), + const FolderNodeFactory &factory = [](const Utils::FileName &fn) { return new FolderNode(fn); }); void compress(); bool isAncesterOf(Node *n); diff --git a/src/plugins/projectexplorer/projectwizardpage.cpp b/src/plugins/projectexplorer/projectwizardpage.cpp index 2a455525f75..6a5c2bd261a 100644 --- a/src/plugins/projectexplorer/projectwizardpage.cpp +++ b/src/plugins/projectexplorer/projectwizardpage.cpp @@ -254,19 +254,6 @@ static inline AddNewTree *buildAddProjectTree(ProjectNode *root, const QString & return new AddNewTree(root, children, root->displayName()); } -static inline AddNewTree *buildAddProjectTree(SessionNode *root, const QString &projectPath, Node *contextNode, BestNodeSelector *selector) -{ - QList children; - for (Node *node : root->nodes()) { - if (ProjectNode *pn = node->asProjectNode()) { - if (AddNewTree *child = buildAddProjectTree(pn, projectPath, contextNode, selector)) - children.append(child); - } - } - children.prepend(createNoneNode(selector)); - return new AddNewTree(root, children, root->displayName()); -} - static inline AddNewTree *buildAddFilesTree(FolderNode *root, const QStringList &files, Node *contextNode, BestNodeSelector *selector) { @@ -289,31 +276,6 @@ static inline AddNewTree *buildAddFilesTree(FolderNode *root, const QStringList return new AddNewTree(root, children, root->displayName()); } -static inline AddNewTree *buildAddFilesTree(SessionNode *root, const QStringList &files, - Node *contextNode, BestNodeSelector *selector) -{ - QList children; - for (Node *node : root->nodes()) { - if (ProjectNode *pn = node->asProjectNode()) { - if (AddNewTree *child = buildAddFilesTree(pn, files, contextNode, selector)) - children.append(child); - } - } - children.prepend(createNoneNode(selector)); - return new AddNewTree(root, children, root->displayName()); -} - -static inline AddNewTree *getChoices(const QStringList &generatedFiles, - IWizardFactory::WizardKind wizardKind, - Node *contextNode, - BestNodeSelector *selector) -{ - if (wizardKind == IWizardFactory::ProjectWizard) - return buildAddProjectTree(SessionManager::sessionNode(), generatedFiles.first(), contextNode, selector); - else - return buildAddFilesTree(SessionManager::sessionNode(), generatedFiles, contextNode, selector); -} - // -------------------------------------------------------------------- // ProjectWizardPage: // -------------------------------------------------------------------- @@ -491,7 +453,25 @@ void ProjectWizardPage::initializeProjectTree(Node *context, const QStringList & ProjectAction action) { BestNodeSelector selector(m_commonDirectory, paths); - AddNewTree *tree = getChoices(paths, kind, context, &selector); + + AddNewTree *tree; + SessionNode *root = SessionManager::sessionNode(); + QList children; + + for (Node *node : root->nodes()) { + if (ProjectNode *pn = node->asProjectNode()) { + if (kind == IWizardFactory::ProjectWizard) { + if (AddNewTree *child = buildAddProjectTree(pn, paths.first(), context, &selector)) + children.append(child); + } else { + if (AddNewTree *child = buildAddFilesTree(pn, paths, context, &selector)) + children.append(child); + } + } + } + + children.prepend(createNoneNode(&selector)); + tree = new AddNewTree(root, children, root->displayName()); setAdditionalInfo(selector.deployingProjects()); diff --git a/src/plugins/projectexplorer/runconfiguration.cpp b/src/plugins/projectexplorer/runconfiguration.cpp index 9ad838d3ca4..5f3e99c0c5d 100644 --- a/src/plugins/projectexplorer/runconfiguration.cpp +++ b/src/plugins/projectexplorer/runconfiguration.cpp @@ -32,18 +32,22 @@ #include "buildconfiguration.h" #include "environmentaspect.h" #include "kitinformation.h" +#include "runnables.h" + #include #include -#include #include +#include #include +#include #include #include -#include +#include #include +#include #ifdef Q_OS_OSX #include @@ -785,4 +789,89 @@ bool Runnable::canReUseOutputPane(const Runnable &other) const return d ? d->canReUseOutputPane(other.d) : (other.d.get() == 0); } + +// SimpleRunControlPrivate + +namespace Internal { + +class SimpleRunControlPrivate +{ +public: + ApplicationLauncher m_launcher; +}; + +} // Internal + +SimpleRunControl::SimpleRunControl(RunConfiguration *runConfiguration, Core::Id mode) + : RunControl(runConfiguration, mode), d(new Internal::SimpleRunControlPrivate) +{ + setRunnable(runConfiguration->runnable()); + setIcon(Utils::Icons::RUN_SMALL_TOOLBAR); +} + +SimpleRunControl::~SimpleRunControl() +{ + delete d; +} + +ApplicationLauncher &SimpleRunControl::applicationLauncher() +{ + return d->m_launcher; +} + +void SimpleRunControl::start() +{ + reportApplicationStart(); + d->m_launcher.disconnect(this); + + connect(&d->m_launcher, &ApplicationLauncher::appendMessage, + this, static_cast(&RunControl::appendMessage)); + connect(&d->m_launcher, &ApplicationLauncher::processStarted, + this, &SimpleRunControl::onProcessStarted); + connect(&d->m_launcher, &ApplicationLauncher::processExited, + this, &SimpleRunControl::onProcessFinished); + + QTC_ASSERT(runnable().is(), return); + auto r = runnable().as(); + if (r.executable.isEmpty()) { + appendMessage(RunControl::tr("No executable specified.") + QLatin1Char('\n'), Utils::ErrorMessageFormat); + reportApplicationStop(); + } else if (!QFileInfo::exists(r.executable)) { + appendMessage(RunControl::tr("Executable %1 does not exist.") + .arg(QDir::toNativeSeparators(r.executable)) + QLatin1Char('\n'), + Utils::ErrorMessageFormat); + reportApplicationStop(); + } else { + QString msg = RunControl::tr("Starting %1...").arg(QDir::toNativeSeparators(r.executable)) + QLatin1Char('\n'); + appendMessage(msg, Utils::NormalMessageFormat); + d->m_launcher.start(r); + setApplicationProcessHandle(d->m_launcher.applicationPID()); + } +} + +RunControl::StopResult SimpleRunControl::stop() +{ + d->m_launcher.stop(); + return StoppedSynchronously; +} + +void SimpleRunControl::onProcessStarted() +{ + // Console processes only know their pid after being started + setApplicationProcessHandle(d->m_launcher.applicationPID()); + bringApplicationToForeground(); +} + +void SimpleRunControl::onProcessFinished(int exitCode, QProcess::ExitStatus status) +{ + QString msg; + QString exe = runnable().as().executable; + if (status == QProcess::CrashExit) + msg = tr("%1 crashed.").arg(QDir::toNativeSeparators(exe)); + else + msg = tr("%1 exited with code %2").arg(QDir::toNativeSeparators(exe)).arg(exitCode); + appendMessage(msg + QLatin1Char('\n'), Utils::NormalMessageFormat); + reportApplicationStop(); +} + } // namespace ProjectExplorer diff --git a/src/plugins/projectexplorer/runconfiguration.h b/src/plugins/projectexplorer/runconfiguration.h index 753b3bf494f..e6ad09513e8 100644 --- a/src/plugins/projectexplorer/runconfiguration.h +++ b/src/plugins/projectexplorer/runconfiguration.h @@ -51,7 +51,10 @@ class RunConfigWidget; class RunControl; class Target; -namespace Internal { class RunControlPrivate; } +namespace Internal { +class RunControlPrivate; +class SimpleRunControlPrivate; +} // Internal /** * An interface for a hunk of global or per-project @@ -414,4 +417,21 @@ private: Internal::RunControlPrivate *d; }; +class PROJECTEXPLORER_EXPORT SimpleRunControl : public RunControl +{ +public: + SimpleRunControl(RunConfiguration *runConfiguration, Core::Id mode); + ~SimpleRunControl(); + + ApplicationLauncher &applicationLauncher(); + void start() override; + StopResult stop() override; + + virtual void onProcessStarted(); + virtual void onProcessFinished(int exitCode, QProcess::ExitStatus status); + +private: + Internal::SimpleRunControlPrivate *d; +}; + } // namespace ProjectExplorer diff --git a/src/plugins/projectexplorer/settingsaccessor.cpp b/src/plugins/projectexplorer/settingsaccessor.cpp index cb59459601d..4920da03b59 100644 --- a/src/plugins/projectexplorer/settingsaccessor.cpp +++ b/src/plugins/projectexplorer/settingsaccessor.cpp @@ -43,6 +43,7 @@ #include #include +#include using namespace Utils; diff --git a/src/plugins/projectexplorer/toolchain.cpp b/src/plugins/projectexplorer/toolchain.cpp index bc69b898561..cb636437046 100644 --- a/src/plugins/projectexplorer/toolchain.cpp +++ b/src/plugins/projectexplorer/toolchain.cpp @@ -225,6 +225,15 @@ QVariantMap ToolChain::toMap() const result.insert(QLatin1String(ID_KEY), idToSave); result.insert(QLatin1String(DISPLAY_NAME_KEY), displayName()); result.insert(QLatin1String(AUTODETECT_KEY), isAutoDetected()); + // + int oldLanguageId = -1; + if (language() == ProjectExplorer::Constants::C_LANGUAGE_ID) + oldLanguageId = 1; + else if (language() == ProjectExplorer::Constants::CXX_LANGUAGE_ID) + oldLanguageId = 2; + if (oldLanguageId >= 0) + result.insert(LANGUAGE_KEY_V1, oldLanguageId); + // result.insert(QLatin1String(LANGUAGE_KEY_V2), language().toSetting()); return result; } diff --git a/src/plugins/pythoneditor/pythoneditorplugin.cpp b/src/plugins/pythoneditor/pythoneditorplugin.cpp index da63b5232ac..08f2ffc95aa 100644 --- a/src/plugins/pythoneditor/pythoneditorplugin.cpp +++ b/src/plugins/pythoneditor/pythoneditorplugin.cpp @@ -59,6 +59,7 @@ #include #include #include +#include using namespace Core; using namespace ProjectExplorer; @@ -197,6 +198,7 @@ public: bool fromMap(const QVariantMap &map) override; bool isEnabled() const override { return m_enabled; } QString disabledReason() const override; + Runnable runnable() const override; bool supportsDebugger() const { return true; } QString mainScript() const { return m_mainScript; } @@ -215,28 +217,6 @@ private: bool m_enabled; }; -class PythonRunControl : public RunControl -{ - Q_OBJECT -public: - PythonRunControl(PythonRunConfiguration *runConfiguration, Core::Id mode); - - void start() override; - StopResult stop() override; - -private: - void processStarted(); - void processExited(int exitCode, QProcess::ExitStatus status); - void slotAppendMessage(const QString &err, Utils::OutputFormat isError); - - ApplicationLauncher m_applicationLauncher; - QString m_interpreter; - QString m_mainScript; - QString m_commandLineArguments; - Utils::Environment m_environment; - ApplicationLauncher::Mode m_runMode; -}; - //////////////////////////////////////////////////////////////// PythonRunConfiguration::PythonRunConfiguration(Target *parent, Core::Id id) : @@ -307,6 +287,17 @@ QString PythonRunConfiguration::disabledReason() const return QString(); } +Runnable PythonRunConfiguration::runnable() const +{ + StandardRunnable r; + QtcProcess::addArg(&r.commandLineArguments, m_mainScript); + QtcProcess::addArgs(&r.commandLineArguments, extraAspect()->arguments()); + r.executable = m_interpreter; + r.runMode = extraAspect()->runMode(); + r.environment = extraAspect()->environment(); + return r; +} + QString PythonRunConfiguration::arguments() const { auto aspect = extraAspect(); @@ -566,14 +557,11 @@ void PythonProject::refresh() parseProject(); QDir baseDir(projectDirectory().toString()); - - QList fileNodes - = Utils::transform(m_files, [baseDir](const QString &f) -> FileNode * { - const QString displayName = baseDir.relativeFilePath(f); - return new PythonFileNode(FileName::fromString(f), displayName); - }); auto newRoot = new PythonProjectNode(this); - newRoot->buildTree(fileNodes); + for (const QString &f : m_files) { + const QString displayName = baseDir.relativeFilePath(f); + newRoot->addNestedNode(new PythonFileNode(FileName::fromString(f), displayName)); + } setRootProjectNode(newRoot); emit parsingFinished(); @@ -732,95 +720,18 @@ public: bool PythonRunControlFactory::canRun(RunConfiguration *runConfiguration, Core::Id mode) const { - return mode == ProjectExplorer::Constants::NORMAL_RUN_MODE - && dynamic_cast(runConfiguration); + auto rc = dynamic_cast(runConfiguration); + return mode == ProjectExplorer::Constants::NORMAL_RUN_MODE && rc && !rc->interpreter().isEmpty(); } RunControl *PythonRunControlFactory::create(RunConfiguration *runConfiguration, Core::Id mode, QString *errorMessage) { Q_UNUSED(errorMessage) QTC_ASSERT(canRun(runConfiguration, mode), return 0); - return new PythonRunControl(static_cast(runConfiguration), mode); + return new SimpleRunControl(runConfiguration, mode); } -// PythonRunControl - -PythonRunControl::PythonRunControl(PythonRunConfiguration *rc, Core::Id mode) - : RunControl(rc, mode) -{ - setIcon(Utils::Icons::RUN_SMALL_TOOLBAR); - - m_interpreter = rc->interpreter(); - 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); - connect(&m_applicationLauncher, &ApplicationLauncher::processStarted, - this, &PythonRunControl::processStarted); - connect(&m_applicationLauncher, &ApplicationLauncher::processExited, - this, &PythonRunControl::processExited); -} - -void PythonRunControl::start() -{ - reportApplicationStart(); - if (m_interpreter.isEmpty()) { - appendMessage(tr("No Python interpreter specified.") + '\n', Utils::ErrorMessageFormat); - reportApplicationStop(); - } else if (!QFileInfo::exists(m_interpreter)) { - appendMessage(tr("Python interpreter %1 does not exist.").arg(QDir::toNativeSeparators(m_interpreter)) + '\n', - Utils::ErrorMessageFormat); - reportApplicationStop(); - } else { - QString msg = tr("Starting %1...").arg(QDir::toNativeSeparators(m_interpreter)) + '\n'; - appendMessage(msg, Utils::NormalMessageFormat); - - StandardRunnable r; - QtcProcess::addArg(&r.commandLineArguments, m_mainScript); - QtcProcess::addArgs(&r.commandLineArguments, m_commandLineArguments); - r.executable = m_interpreter; - r.runMode = m_runMode; - r.environment = m_environment; - m_applicationLauncher.start(r); - - setApplicationProcessHandle(m_applicationLauncher.applicationPID()); - } -} - -PythonRunControl::StopResult PythonRunControl::stop() -{ - m_applicationLauncher.stop(); - return StoppedSynchronously; -} - -void PythonRunControl::slotAppendMessage(const QString &err, Utils::OutputFormat format) -{ - appendMessage(err, format); -} - -void PythonRunControl::processStarted() -{ - // Console processes only know their pid after being started - setApplicationProcessHandle(m_applicationLauncher.applicationPID()); - bringApplicationToForeground(); -} - -void PythonRunControl::processExited(int exitCode, QProcess::ExitStatus status) -{ - QString msg; - if (status == QProcess::CrashExit) { - msg = tr("%1 crashed") - .arg(QDir::toNativeSeparators(m_interpreter)); - } else { - msg = tr("%1 exited with code %2") - .arg(QDir::toNativeSeparators(m_interpreter)).arg(exitCode); - } - appendMessage(msg + '\n', Utils::NormalMessageFormat); - reportApplicationStop(); -} +// PythonRunConfigurationWidget void PythonRunConfigurationWidget::setInterpreter(const QString &interpreter) { diff --git a/src/plugins/qbsprojectmanager/qbsnodetreebuilder.cpp b/src/plugins/qbsprojectmanager/qbsnodetreebuilder.cpp index 2bad75e16e1..80308251074 100644 --- a/src/plugins/qbsprojectmanager/qbsnodetreebuilder.cpp +++ b/src/plugins/qbsprojectmanager/qbsnodetreebuilder.cpp @@ -55,15 +55,13 @@ ProjectExplorer::FileType fileType(const qbs::ArtifactData &artifact) void setupArtifacts(ProjectExplorer::FolderNode *root, const QList &artifacts) { - QList fileNodes - = Utils::transform(artifacts, [](const qbs::ArtifactData &ad) { + for (const qbs::ArtifactData &ad : artifacts) { const Utils::FileName path = Utils::FileName::fromString(ad.filePath()); const ProjectExplorer::FileType type = fileType(ad); const bool isGenerated = ad.isGenerated(); - return new ProjectExplorer::FileNode(path, type, isGenerated); - }); + root->addNestedNode(new ProjectExplorer::FileNode(path, type, isGenerated)); + }; - root->buildTree(fileNodes); root->compress(); } @@ -190,14 +188,12 @@ QbsRootProjectNode *QbsNodeTreeBuilder::buildTree(QbsProject *project) ProjectExplorer::NodeType::Folder, QCoreApplication::translate("QbsRootProjectNode", "Qbs files")); - QList projectBuildSystemFiles; Utils::FileName base = project->projectDirectory(); for (const QString &f : unreferencedBuildSystemFiles(project->qbsProject())) { const Utils::FileName filePath = Utils::FileName::fromString(f); if (filePath.isChildOf(base)) - projectBuildSystemFiles.append(new ProjectExplorer::FileNode(filePath, ProjectExplorer::FileType::Project, false)); + root->addNestedNode(new ProjectExplorer::FileNode(filePath, ProjectExplorer::FileType::Project, false)); } - buildSystemFiles->buildTree(projectBuildSystemFiles); buildSystemFiles->compress(); root->addNode(buildSystemFiles); diff --git a/src/plugins/qbsprojectmanager/qbsproject.cpp b/src/plugins/qbsprojectmanager/qbsproject.cpp index 182537bfaaf..ec047b86390 100644 --- a/src/plugins/qbsprojectmanager/qbsproject.cpp +++ b/src/plugins/qbsprojectmanager/qbsproject.cpp @@ -996,6 +996,7 @@ void QbsProject::updateCppCodeModel() rpp.setDisplayName(grp.name()); rpp.setProjectFileLocation(grp.location().filePath(), grp.location().line(), grp.location().column()); + rpp.setBuildSystemTarget(uniqueProductName(prd)); QHash filePathToSourceArtifact; bool hasCFiles = false; diff --git a/src/plugins/qmakeprojectmanager/customwidgetwizard/plugingenerator.cpp b/src/plugins/qmakeprojectmanager/customwidgetwizard/plugingenerator.cpp index 1355dffde7a..f43b4ca73e5 100644 --- a/src/plugins/qmakeprojectmanager/customwidgetwizard/plugingenerator.cpp +++ b/src/plugins/qmakeprojectmanager/customwidgetwizard/plugingenerator.cpp @@ -33,6 +33,7 @@ #include #include +#include #include static QString headerGuard(const QString &header) diff --git a/src/plugins/qmakeprojectmanager/makefileparse.cpp b/src/plugins/qmakeprojectmanager/makefileparse.cpp index e0c2e4100c4..aea591e5abd 100644 --- a/src/plugins/qmakeprojectmanager/makefileparse.cpp +++ b/src/plugins/qmakeprojectmanager/makefileparse.cpp @@ -32,6 +32,7 @@ #include #include #include +#include #include #include diff --git a/src/plugins/qmakeprojectmanager/qmakenodetreebuilder.cpp b/src/plugins/qmakeprojectmanager/qmakenodetreebuilder.cpp index bed5cfc44b4..2bc3b23682f 100644 --- a/src/plugins/qmakeprojectmanager/qmakenodetreebuilder.cpp +++ b/src/plugins/qmakeprojectmanager/qmakenodetreebuilder.cpp @@ -172,10 +172,8 @@ static void createTree(const QmakePriFile *pri, QmakePriFileNode *node) vfolder->addNode(resourceNode); } } else { - QList fileNodes = Utils::transform(newFilePaths, [type](const FileName &fn) { - return new FileNode(fn, type, false); - }); - vfolder->buildTree(fileNodes); + for (const FileName &fn : newFilePaths) + vfolder->addNestedNode(new FileNode(fn, type, false)); for (FolderNode *fn : vfolder->folderNodes()) fn->compress(); } diff --git a/src/plugins/qmakeprojectmanager/qmakeproject.cpp b/src/plugins/qmakeprojectmanager/qmakeproject.cpp index a5e9cee2b9c..ffdcee6f2ad 100644 --- a/src/plugins/qmakeprojectmanager/qmakeproject.cpp +++ b/src/plugins/qmakeprojectmanager/qmakeproject.cpp @@ -345,6 +345,7 @@ void QmakeProject::updateCppCodeModel() CppTools::RawProjectPart rpp; rpp.setDisplayName(pro->displayName()); rpp.setProjectFileLocation(pro->filePath().toString()); + rpp.setBuildSystemTarget(pro->targetInformation().target); // TODO: Handle QMAKE_CFLAGS rpp.setFlagsForCxx({cxxToolChain, pro->variableValue(Variable::CppFlags)}); rpp.setDefines(pro->cxxDefines()); diff --git a/src/plugins/qmakeprojectmanager/qmakeprojectmanager.cpp b/src/plugins/qmakeprojectmanager/qmakeprojectmanager.cpp index 4a54beadd52..766e9513450 100644 --- a/src/plugins/qmakeprojectmanager/qmakeprojectmanager.cpp +++ b/src/plugins/qmakeprojectmanager/qmakeprojectmanager.cpp @@ -216,9 +216,11 @@ void QmakeManager::handleSubDirContextMenu(QmakeManager::Action action, bool isF if (!contextNode || !buildableFile) isFileBuild = false; - if (QmakeProFileNode *profile = dynamic_cast(contextNode)) { - if (profile != contextProject->rootProjectNode() || isFileBuild) - bc->setSubNodeBuild(profile); + if (QmakePriFileNode *prifile = dynamic_cast(contextNode)) { + if (QmakeProFileNode *profile = prifile->proFileNode()) { + if (profile != contextProject->rootProjectNode() || isFileBuild) + bc->setSubNodeBuild(profile->proFileNode()); + } } if (isFileBuild) diff --git a/src/plugins/qmakeprojectmanager/qmakeprojectmanagerplugin.cpp b/src/plugins/qmakeprojectmanager/qmakeprojectmanagerplugin.cpp index a771f344d54..9641c289e48 100644 --- a/src/plugins/qmakeprojectmanager/qmakeprojectmanagerplugin.cpp +++ b/src/plugins/qmakeprojectmanager/qmakeprojectmanagerplugin.cpp @@ -357,6 +357,7 @@ void QmakeProjectManagerPlugin::updateContextActions() m_subProjectRebuildSeparator->setVisible(subProjectActionsVisible && isProjectNode); m_rebuildSubProjectContextMenu->setVisible(subProjectActionsVisible && isProjectNode); m_cleanSubProjectContextMenu->setVisible(subProjectActionsVisible && isProjectNode); + m_buildFileAction->setVisible(buildFilePossible); m_buildSubProjectAction->setEnabled(enabled); m_rebuildSubProjectAction->setEnabled(enabled); diff --git a/src/plugins/qmakeprojectmanager/qmakestep.cpp b/src/plugins/qmakeprojectmanager/qmakestep.cpp index d8f83e6a0e0..5250042ca27 100644 --- a/src/plugins/qmakeprojectmanager/qmakestep.cpp +++ b/src/plugins/qmakeprojectmanager/qmakestep.cpp @@ -86,6 +86,7 @@ QMakeStep::QMakeStep(BuildStepList *bsl, Core::Id id) : QMakeStep::QMakeStep(BuildStepList *bsl, QMakeStep *bs) : AbstractProcessStep(bsl, bs), m_userArgs(bs->m_userArgs), + m_extraArgs(bs->m_extraArgs), m_forced(bs->m_forced), m_linkQmlDebuggingLibrary(bs->m_linkQmlDebuggingLibrary), m_useQtQuickCompiler(bs->m_useQtQuickCompiler), @@ -154,6 +155,8 @@ QString QMakeStep::allArguments(const BaseQtVersion *v, bool shorted) const QString args = QtcProcess::joinArgs(arguments); // User arguments QtcProcess::addArgs(&args, m_userArgs); + foreach (QString arg, m_extraArgs) + QtcProcess::addArgs(&args, arg); return args; } @@ -405,6 +408,21 @@ void QMakeStep::setUserArguments(const QString &arguments) qmakeBuildConfiguration()->emitProFileEvaluateNeeded(); } +QStringList QMakeStep::extraArguments() const +{ + return m_extraArgs; +} + +void QMakeStep::setExtraArguments(const QStringList &args) +{ + if (m_extraArgs != args) { + m_extraArgs = args; + emit extraArgumentsChanged(); + qmakeBuildConfiguration()->emitQMakeBuildConfigurationChanged(); + qmakeBuildConfiguration()->emitProFileEvaluateNeeded(); + } +} + bool QMakeStep::linkQmlDebuggingLibrary() const { return m_linkQmlDebuggingLibrary; @@ -517,6 +535,7 @@ QString QMakeStep::userArguments() FileName QMakeStep::mkspec() const { QString additionalArguments = m_userArgs; + QtcProcess::addArgs(&additionalArguments, m_extraArgs); for (QtcProcess::ArgIterator ait(&additionalArguments); ait.next(); ) { if (ait.value() == QLatin1String("-spec")) { if (ait.next()) diff --git a/src/plugins/qmakeprojectmanager/qmakestep.h b/src/plugins/qmakeprojectmanager/qmakestep.h index 237e48bb0f5..a69db1113eb 100644 --- a/src/plugins/qmakeprojectmanager/qmakestep.h +++ b/src/plugins/qmakeprojectmanager/qmakestep.h @@ -135,8 +135,11 @@ public: QStringList parserArguments(); // arguments set by the user QString userArguments(); - Utils::FileName mkspec() const; void setUserArguments(const QString &arguments); + // QMake extra arguments. Not user editable. + QStringList extraArguments() const; + void setExtraArguments(const QStringList &args); + Utils::FileName mkspec() const; bool linkQmlDebuggingLibrary() const; void setLinkQmlDebuggingLibrary(bool enable); bool useQtQuickCompiler() const; @@ -152,6 +155,7 @@ public: signals: void userArgumentsChanged(); + void extraArgumentsChanged(); void linkQmlDebuggingLibraryChanged(); void useQtQuickCompilerChanged(); void separateDebugInfoChanged(); @@ -174,6 +178,8 @@ private: QString m_makeExecutable; QString m_makeArguments; QString m_userArgs; + // Extra arguments for qmake. + QStringList m_extraArgs; QFutureInterface m_inputFuture; QFutureWatcher m_inputWatcher; diff --git a/src/plugins/qmldesigner/components/stateseditor/stateseditorview.cpp b/src/plugins/qmldesigner/components/stateseditor/stateseditorview.cpp index 47587fe2ee7..b61ceb1d49a 100644 --- a/src/plugins/qmldesigner/components/stateseditor/stateseditorview.cpp +++ b/src/plugins/qmldesigner/components/stateseditor/stateseditorview.cpp @@ -29,6 +29,7 @@ #include #include +#include #include #include diff --git a/src/plugins/qmldesigner/components/texteditor/texteditorwidget.cpp b/src/plugins/qmldesigner/components/texteditor/texteditorwidget.cpp index 646b43e47eb..e645ad2ef6a 100644 --- a/src/plugins/qmldesigner/components/texteditor/texteditorwidget.cpp +++ b/src/plugins/qmldesigner/components/texteditor/texteditorwidget.cpp @@ -104,7 +104,7 @@ void TextEditorWidget::updateSelectionByCursorPosition() if (rewriterView) { ModelNode modelNode = rewriterView->nodeAtTextCursorPosition(cursorPosition); - if (modelNode.isValid()) + if (modelNode.isValid() && !m_textEditorView->isSelectedModelNode(modelNode)) m_textEditorView->setSelectedModelNode(modelNode); } } @@ -121,10 +121,7 @@ void TextEditorWidget::jumpTextCursorToSelectedModelNode() const int nodeOffset = rewriterView->nodeOffset(selectedNode); if (nodeOffset > 0) { - const ModelNode currentSelectedNode = rewriterView-> - nodeAtTextCursorPosition(m_textEditor->editorWidget()->textCursor().position()); - - if (currentSelectedNode != selectedNode) { + if (!rewriterView->nodeContainsCursor(selectedNode, m_textEditor->editorWidget()->textCursor().position())) { int line, column; m_textEditor->editorWidget()->convertPosition(nodeOffset, &line, &column); m_textEditor->editorWidget()->gotoLine(line, column); diff --git a/src/plugins/qmldesigner/designercore/include/rewriterview.h b/src/plugins/qmldesigner/designercore/include/rewriterview.h index 5d5bc8bb282..9d6e29d8fbd 100644 --- a/src/plugins/qmldesigner/designercore/include/rewriterview.h +++ b/src/plugins/qmldesigner/designercore/include/rewriterview.h @@ -130,6 +130,7 @@ public: int firstDefinitionInsideLength(const ModelNode &node) const; bool modificationGroupActive(); ModelNode nodeAtTextCursorPosition(int cursorPosition) const; + bool nodeContainsCursor(const ModelNode &node, int cursorPosition) const; bool renameId(const QString& oldId, const QString& newId); diff --git a/src/plugins/qmldesigner/designercore/instances/nodeinstance.cpp b/src/plugins/qmldesigner/designercore/instances/nodeinstance.cpp index 212541f0775..6589ceb8756 100644 --- a/src/plugins/qmldesigner/designercore/instances/nodeinstance.cpp +++ b/src/plugins/qmldesigner/designercore/instances/nodeinstance.cpp @@ -26,7 +26,9 @@ #include "nodeinstance.h" #include +#ifndef QMLDESIGNER_TEST #include +#endif #include #include @@ -398,7 +400,9 @@ QPixmap NodeInstance::blurredRenderPixmap() const void NodeInstance::setRenderPixmap(const QImage &image) { d->renderPixmap = QPixmap::fromImage(image); +#ifndef QMLDESIGNER_TEST d->renderPixmap.setDevicePixelRatio(QmlDesignerPlugin::formEditorDevicePixelRatio()); +#endif d->blurredRenderPixmap = QPixmap(); } diff --git a/src/plugins/qmldesigner/designercore/instances/puppetcreator.cpp b/src/plugins/qmldesigner/designercore/instances/puppetcreator.cpp index 38fd35a5b02..67a2764215d 100644 --- a/src/plugins/qmldesigner/designercore/instances/puppetcreator.cpp +++ b/src/plugins/qmldesigner/designercore/instances/puppetcreator.cpp @@ -414,7 +414,9 @@ QProcessEnvironment PuppetCreator::processEnvironment() const environment.set(QLatin1String("QT_LABS_CONTROLS_STYLE"), controlsStyle); } +#ifndef QMLDESIGNER_TEST environment.set(QLatin1String("FORMEDITOR_DEVICE_PIXEL_RATIO"), QString::number(QmlDesignerPlugin::formEditorDevicePixelRatio())); +#endif const QString styleConfigFileName = getStyleConfigFileName(); diff --git a/src/plugins/qmldesigner/designercore/model/abstractview.cpp b/src/plugins/qmldesigner/designercore/model/abstractview.cpp index 3ab67786552..c6084a9c93d 100644 --- a/src/plugins/qmldesigner/designercore/model/abstractview.cpp +++ b/src/plugins/qmldesigner/designercore/model/abstractview.cpp @@ -34,6 +34,8 @@ #include #include +#include + namespace QmlDesigner { diff --git a/src/plugins/qmldesigner/designercore/model/modelnode.cpp b/src/plugins/qmldesigner/designercore/model/modelnode.cpp index 4b5dba99bd8..5d58350f274 100644 --- a/src/plugins/qmldesigner/designercore/model/modelnode.cpp +++ b/src/plugins/qmldesigner/designercore/model/modelnode.cpp @@ -43,6 +43,7 @@ #include #include +#include #include #include diff --git a/src/plugins/qmldesigner/designercore/model/qmlobjectnode.cpp b/src/plugins/qmldesigner/designercore/model/qmlobjectnode.cpp index 5d1ee0c31f2..ddc8cefe976 100644 --- a/src/plugins/qmldesigner/designercore/model/qmlobjectnode.cpp +++ b/src/plugins/qmldesigner/designercore/model/qmlobjectnode.cpp @@ -39,6 +39,8 @@ #include #endif +#include + namespace QmlDesigner { void QmlObjectNode::setVariantProperty(const PropertyName &name, const QVariant &value) diff --git a/src/plugins/qmldesigner/designercore/model/rewriterview.cpp b/src/plugins/qmldesigner/designercore/model/rewriterview.cpp index 08a7d3629fe..1eff8b446fa 100644 --- a/src/plugins/qmldesigner/designercore/model/rewriterview.cpp +++ b/src/plugins/qmldesigner/designercore/model/rewriterview.cpp @@ -38,6 +38,7 @@ #include #include #include +#include #include #include @@ -559,16 +560,32 @@ static bool isInNodeDefinition(int nodeTextOffset, int nodeTextLength, int curso ModelNode RewriterView::nodeAtTextCursorPositionRekursive(const ModelNode &root, int cursorPosition) const { ModelNode node = root; + + int lastOffset = -1; + + bool sorted = true; + + if (!root.nodeProperties().isEmpty()) + sorted = false; + foreach (const ModelNode ¤tNode, node.directSubModelNodes()) { const int offset = nodeOffset(currentNode); - if (offset < cursorPosition) + + if (offset < cursorPosition && offset > lastOffset) { node = nodeAtTextCursorPositionRekursive(currentNode, cursorPosition); - else - break; + lastOffset = offset; + } else { + if (sorted) + break; + } } const int nodeTextLength = nodeLength(node); const int nodeTextOffset = nodeOffset(node); + + if (nodeTextLength < 0) + return ModelNode(); + if (isInNodeDefinition(nodeTextOffset, nodeTextLength, cursorPosition)) return node; @@ -580,6 +597,17 @@ ModelNode RewriterView::nodeAtTextCursorPosition(int cursorPosition) const return nodeAtTextCursorPositionRekursive(rootModelNode(), cursorPosition); } +bool RewriterView::nodeContainsCursor(const ModelNode &node, int cursorPosition) const +{ + const int nodeTextLength = nodeLength(node); + const int nodeTextOffset = nodeOffset(node); + + if (isInNodeDefinition(nodeTextOffset, nodeTextLength, cursorPosition)) + return true; + + return false; +} + bool RewriterView::renameId(const QString& oldId, const QString& newId) { if (textModifier()) { diff --git a/src/plugins/qmljstools/qmljsfunctionfilter.cpp b/src/plugins/qmljstools/qmljsfunctionfilter.cpp index 88af53a0e50..d7c5979fd77 100644 --- a/src/plugins/qmljstools/qmljsfunctionfilter.cpp +++ b/src/plugins/qmljstools/qmljsfunctionfilter.cpp @@ -29,6 +29,7 @@ #include #include +#include #include using namespace QmlJSTools::Internal; diff --git a/src/plugins/qmlprofiler/qmlprofilermodelmanager.cpp b/src/plugins/qmlprofiler/qmlprofilermodelmanager.cpp index 2a766c95976..4edfad3ee45 100644 --- a/src/plugins/qmlprofiler/qmlprofilermodelmanager.cpp +++ b/src/plugins/qmlprofiler/qmlprofilermodelmanager.cpp @@ -37,6 +37,7 @@ #include #include #include +#include #include #include diff --git a/src/plugins/qmlprofiler/qmlprofilertraceview.cpp b/src/plugins/qmlprofiler/qmlprofilertraceview.cpp index 8530994fe52..c8b9b3ec5f3 100644 --- a/src/plugins/qmlprofiler/qmlprofilertraceview.cpp +++ b/src/plugins/qmlprofiler/qmlprofilertraceview.cpp @@ -67,6 +67,7 @@ #include #include #include +#include #include #include diff --git a/src/plugins/qmlprojectmanager/fileformat/filefilteritems.cpp b/src/plugins/qmlprojectmanager/fileformat/filefilteritems.cpp index abdfe4141a0..21863b48d3a 100644 --- a/src/plugins/qmlprojectmanager/fileformat/filefilteritems.cpp +++ b/src/plugins/qmlprojectmanager/fileformat/filefilteritems.cpp @@ -32,6 +32,7 @@ #include #include #include +#include namespace QmlProjectManager { diff --git a/src/plugins/qmlprojectmanager/fileformat/filefilteritems.h b/src/plugins/qmlprojectmanager/fileformat/filefilteritems.h index aebf3093ba7..3b44d8b06cb 100644 --- a/src/plugins/qmlprojectmanager/fileformat/filefilteritems.h +++ b/src/plugins/qmlprojectmanager/fileformat/filefilteritems.h @@ -28,6 +28,7 @@ #include "qmlprojectitem.h" #include +#include #include #include diff --git a/src/plugins/qmlprojectmanager/qmlproject.cpp b/src/plugins/qmlprojectmanager/qmlproject.cpp index 45d791b4ff5..bb88cc898eb 100644 --- a/src/plugins/qmlprojectmanager/qmlproject.cpp +++ b/src/plugins/qmlprojectmanager/qmlproject.cpp @@ -48,6 +48,7 @@ #include #include +#include using namespace Core; using namespace ProjectExplorer; @@ -144,8 +145,8 @@ void QmlProject::parseProject(RefreshOptions options) } if (m_projectItem) { m_projectItem.data()->setSourceDirectory(projectDir().path()); - if (modelManager()) - modelManager()->updateSourceFiles(m_projectItem.data()->files(), true); + if (auto modelManager = QmlJS::ModelManagerInterface::instance()) + modelManager->updateSourceFiles(m_projectItem.data()->files(), true); QString mainFilePath = m_projectItem.data()->mainFile(); if (!mainFilePath.isEmpty()) { @@ -179,37 +180,21 @@ void QmlProject::refresh(RefreshOptions options) if (options & Files) generateProjectTree(); - if (!modelManager()) + auto modelManager = QmlJS::ModelManagerInterface::instance(); + if (!modelManager) return; QmlJS::ModelManagerInterface::ProjectInfo projectInfo = - modelManager()->defaultProjectInfoForProject(this); + modelManager->defaultProjectInfoForProject(this); foreach (const QString &searchPath, customImportPaths()) projectInfo.importPaths.maybeInsert(Utils::FileName::fromString(searchPath), QmlJS::Dialect::Qml); - modelManager()->updateProjectInfo(projectInfo, this); + modelManager->updateProjectInfo(projectInfo, this); emit parsingFinished(); } -QStringList QmlProject::convertToAbsoluteFiles(const QStringList &paths) const -{ - const QDir projectDir(projectDirectory().toString()); - QStringList absolutePaths; - foreach (const QString &file, paths) { - QFileInfo fileInfo(projectDir, file); - absolutePaths.append(fileInfo.absoluteFilePath()); - } - absolutePaths.removeDuplicates(); - return absolutePaths; -} - -QmlJS::ModelManagerInterface *QmlProject::modelManager() const -{ - return QmlJS::ModelManagerInterface::instance(); -} - QStringList QmlProject::files() const { QStringList files; @@ -264,8 +249,10 @@ QmlProject::QmlImport QmlProject::defaultImport() const void QmlProject::refreshFiles(const QSet &/*added*/, const QSet &removed) { refresh(Files); - if (!removed.isEmpty() && modelManager()) - modelManager()->removeFiles(removed.toList()); + if (!removed.isEmpty()) { + if (auto modelManager = QmlJS::ModelManagerInterface::instance()) + modelManager->removeFiles(removed.toList()); + } } QString QmlProject::displayName() const @@ -384,17 +371,15 @@ Project::RestoreResult QmlProject::fromMap(const QVariantMap &map, QString *erro void QmlProject::generateProjectTree() { - QStringList allFiles = files(); + auto newRoot = new Internal::QmlProjectNode(this); - QList fileNodes = Utils::transform(allFiles, [this](const QString &f) { + for (const QString &f : files()) { FileType fileType = FileType::Source; // ### FIXME if (f == projectFilePath().toString()) fileType = FileType::Project; - return new FileNode(Utils::FileName::fromString(f), fileType, false); - }); + newRoot->addNestedNode(new FileNode(Utils::FileName::fromString(f), fileType, false)); + } - auto newRoot = new Internal::QmlProjectNode(this); - newRoot->buildTree(fileNodes); setRootProjectNode(newRoot); } diff --git a/src/plugins/qmlprojectmanager/qmlproject.h b/src/plugins/qmlprojectmanager/qmlproject.h index 8bf4f35bc50..c8900b6ebe1 100644 --- a/src/plugins/qmlprojectmanager/qmlproject.h +++ b/src/plugins/qmlprojectmanager/qmlproject.h @@ -33,7 +33,6 @@ #include namespace ProjectExplorer { class RunConfiguration; } -namespace QmlJS { class ModelManagerInterface; } namespace QmlProjectManager { @@ -91,8 +90,6 @@ private: // plain format void parseProject(RefreshOptions options); - QStringList convertToAbsoluteFiles(const QStringList &paths) const; - QmlJS::ModelManagerInterface *modelManager() const; QmlImport m_defaultImport; ProjectExplorer::Target *m_activeTarget = 0; diff --git a/src/plugins/qnx/qnxversionnumber.cpp b/src/plugins/qnx/qnxversionnumber.cpp index b733e7ed1ac..8a4188c3ef7 100644 --- a/src/plugins/qnx/qnxversionnumber.cpp +++ b/src/plugins/qnx/qnxversionnumber.cpp @@ -26,6 +26,7 @@ #include "qnxversionnumber.h" #include +#include namespace Qnx { namespace Internal { diff --git a/src/plugins/qnx/slog2inforunner.cpp b/src/plugins/qnx/slog2inforunner.cpp index 35ee2a84946..7b5f0f38bf4 100644 --- a/src/plugins/qnx/slog2inforunner.cpp +++ b/src/plugins/qnx/slog2inforunner.cpp @@ -30,6 +30,8 @@ #include #include +#include + using namespace ProjectExplorer; namespace Qnx { diff --git a/src/plugins/qtsupport/qscxmlcgenerator.cpp b/src/plugins/qtsupport/qscxmlcgenerator.cpp index 6920f2e0763..309113322a1 100644 --- a/src/plugins/qtsupport/qscxmlcgenerator.cpp +++ b/src/plugins/qtsupport/qscxmlcgenerator.cpp @@ -30,9 +30,9 @@ #include #include +#include #include #include -#include using namespace ProjectExplorer; diff --git a/src/plugins/qtsupport/qtkitinformation.cpp b/src/plugins/qtsupport/qtkitinformation.cpp index b2b3de41107..93997c901e9 100644 --- a/src/plugins/qtsupport/qtkitinformation.cpp +++ b/src/plugins/qtsupport/qtkitinformation.cpp @@ -25,6 +25,8 @@ #include "qtkitinformation.h" +#include + #include "qtkitconfigwidget.h" #include "qtsupportconstants.h" #include "qtversionmanager.h" diff --git a/src/plugins/qtsupport/qtparser.h b/src/plugins/qtsupport/qtparser.h index 91b74a4aaa1..e4263b7b7e6 100644 --- a/src/plugins/qtsupport/qtparser.h +++ b/src/plugins/qtsupport/qtparser.h @@ -25,6 +25,8 @@ #pragma once +#include + #include "qtsupport_global.h" #include diff --git a/src/plugins/scxmleditor/plugin_interface/scxmldocument.cpp b/src/plugins/scxmleditor/plugin_interface/scxmldocument.cpp index 15dea2d2e1f..ed4ce3e507a 100644 --- a/src/plugins/scxmleditor/plugin_interface/scxmldocument.cpp +++ b/src/plugins/scxmleditor/plugin_interface/scxmldocument.cpp @@ -625,7 +625,7 @@ QString ScxmlDocument::getUniqueCopyId(const ScxmlTag *tag) // Check duplicate foreach (const ScxmlTag *t, m_tags) { if (t->attribute("id") == name && t != tag) { - name = QString::fromLatin1("%1_Copy(%2)").arg(key).arg(counter); + name = QString::fromLatin1("%1_Copy%2").arg(key).arg(counter); bFound = true; counter++; } diff --git a/src/plugins/subversion/subversioneditor.cpp b/src/plugins/subversion/subversioneditor.cpp index 09074723243..cb48da5daaf 100644 --- a/src/plugins/subversion/subversioneditor.cpp +++ b/src/plugins/subversion/subversioneditor.cpp @@ -34,6 +34,7 @@ #include #include +#include #include #include diff --git a/src/plugins/todo/todoitemsprovider.cpp b/src/plugins/todo/todoitemsprovider.cpp index c8e89961100..d7a584179fe 100644 --- a/src/plugins/todo/todoitemsprovider.cpp +++ b/src/plugins/todo/todoitemsprovider.cpp @@ -39,6 +39,7 @@ #include #include +#include #include using namespace ProjectExplorer; diff --git a/src/plugins/vcsbase/vcsoutputwindow.cpp b/src/plugins/vcsbase/vcsoutputwindow.cpp index 51389bdbcc3..14a6f6bf635 100644 --- a/src/plugins/vcsbase/vcsoutputwindow.cpp +++ b/src/plugins/vcsbase/vcsoutputwindow.cpp @@ -45,6 +45,7 @@ #include #include #include +#include #include #include #include diff --git a/src/shared/proparser/ioutils.cpp b/src/shared/proparser/ioutils.cpp index 4239d6ba5c9..97e4c0b8ed4 100644 --- a/src/shared/proparser/ioutils.cpp +++ b/src/shared/proparser/ioutils.cpp @@ -27,6 +27,7 @@ #include #include +#include #ifdef Q_OS_WIN # include diff --git a/src/shared/proparser/prowriter.cpp b/src/shared/proparser/prowriter.cpp index d49c3aa8645..046143c8efb 100644 --- a/src/shared/proparser/prowriter.cpp +++ b/src/shared/proparser/prowriter.cpp @@ -28,6 +28,7 @@ #include "proitems.h" #include +#include #include using namespace QmakeProjectManager::Internal; diff --git a/tests/auto/qml/qmldesigner/coretests/coretests.pro b/tests/auto/qml/qmldesigner/coretests/coretests.pro index bdf97a1ce0a..fbc7f4f0e2e 100644 --- a/tests/auto/qml/qmldesigner/coretests/coretests.pro +++ b/tests/auto/qml/qmldesigner/coretests/coretests.pro @@ -14,6 +14,8 @@ QTC_PLUGIN_DEPENDS += \ qmljseditor \ qmakeprojectmanager +CONFIG -= qtquickcompiler + include(../../../qttest.pri) QT += qml network core-private diff --git a/tests/system/suite_tools/tst_git_clone/test.py b/tests/system/suite_tools/tst_git_clone/test.py index 20a74e6546d..10126c857b2 100644 --- a/tests/system/suite_tools/tst_git_clone/test.py +++ b/tests/system/suite_tools/tst_git_clone/test.py @@ -65,7 +65,7 @@ def verifyVersionControlView(targetDir, canceled): 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, + test.verify("Running in " + targetDir + ":" in vcsLog, "Searching for target directory in clone log") test.verify(" ".join(["clone", "--progress", cloneUrl, cloneDir]) in vcsLog, "Searching for git parameters in clone log")