Merge remote-tracking branch 'origin/4.3'

Change-Id: Ib0dc9fe5d7c507eb7330f61daedc945a4308292d
This commit is contained in:
Eike Ziller
2017-03-16 10:28:07 +01:00
133 changed files with 1862 additions and 906 deletions

View File

@@ -133,7 +133,8 @@ my %next = ();
my $last = $doctitle; my $last = $doctitle;
my $lastpage = $title2page{$last}; my $lastpage = $title2page{$last};
for my $title (@toc) { 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"; defined($page) or die "TOC refers to unknown page/example '$title'.\n";
$next{$last} = $page; $next{$last} = $page;
$prev{$title} = $lastpage; $prev{$title} = $lastpage;

View File

@@ -286,8 +286,6 @@ class DumperBase:
'personaltypes', 'personaltypes',
] ]
self.currentQtNamespaceGuess = None
# These values are never used, but the variables need to have # These values are never used, but the variables need to have
# some value base for the swapping logic in Children.__enter__() # some value base for the swapping logic in Children.__enter__()
# and Children.__exit__(). # and Children.__exit__().
@@ -324,11 +322,6 @@ class DumperBase:
#warn('EXPANDED INAMES: %s' % self.expandedINames) #warn('EXPANDED INAMES: %s' % self.expandedINames)
#warn('WATCHERS: %s' % self.watchers) #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): def resetCaches(self):
# This is a cache mapping from 'type name' to 'display alternatives'. # This is a cache mapping from 'type name' to 'display alternatives'.
self.qqFormats = { 'QVariant (QVariantMap)' : mapForms() } self.qqFormats = { 'QVariant (QVariantMap)' : mapForms() }

View File

@@ -959,10 +959,8 @@ class Dumper(DumperBase):
self.importPlainDumper(printer) self.importPlainDumper(printer)
def qtNamespace(self): def qtNamespace(self):
self.preping('qtNamespace') # This function is replaced by handleQtCoreLoaded()
res = self.qtNamespaceX() return ''
self.ping('qtNamespace')
return res
def findSymbol(self, symbolName): def findSymbol(self, symbolName):
try: try:
@@ -970,53 +968,55 @@ class Dumper(DumperBase):
except: except:
return 0 return 0
def qtNamespaceX(self): def handleNewObjectFile(self, objfile):
if not self.currentQtNamespaceGuess is None: name = objfile.filename
return self.currentQtNamespaceGuess 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(): def handleQtCoreLoaded(self, objfile):
name = objfile.filename fd, tmppath = tempfile.mkstemp()
if name.find('/libQt5Core') >= 0: os.close(fd)
fd, tmppath = tempfile.mkstemp() cmd = 'maint print msymbols %s "%s"' % (tmppath, objfile.filename)
os.close(fd) try:
cmd = 'maint print msymbols %s "%s"' % (tmppath, name) symbols = gdb.execute(cmd, to_string = True)
symbols = gdb.execute(cmd, to_string = True) except:
ns = '' pass
with open(tmppath) as f: ns = ''
for line in f: with open(tmppath) as f:
if line.find('msgHandlerGrabbed ') >= 0: for line in f:
# [11] b 0x7ffff683c000 _ZN4MynsL17msgHandlerGrabbedE if line.find('msgHandlerGrabbed ') >= 0:
# section .tbss Myns::msgHandlerGrabbed qlogging.cpp # [11] b 0x7ffff683c000 _ZN4MynsL17msgHandlerGrabbedE
ns = re.split('_ZN?(\d*)(\w*)L17msgHandlerGrabbedE? ', line)[2] # section .tbss Myns::msgHandlerGrabbed qlogging.cpp
if len(ns): ns = re.split('_ZN?(\d*)(\w*)L17msgHandlerGrabbedE? ', line)[2]
ns += '::' if len(ns):
break ns += '::'
os.remove(tmppath) break
os.remove(tmppath)
lenns = len(ns) lenns = len(ns)
strns = ('%d%s' % (lenns - 2, ns[:lenns - 2])) if lenns else '' strns = ('%d%s' % (lenns - 2, ns[:lenns - 2])) if lenns else ''
if lenns: if lenns:
sym = '_ZN%s7QObject11customEventEPNS_6QEventE' % strns # This might be wrong, but we can't do better: We found
else: # a libQt5Core and could not extract a namespace.
sym = '_ZN7QObject11customEventEP6QEvent' # The best guess is that there isn't any.
self.qtCustomEventFunc = self.findSymbol(sym) self.qtNamespaceToReport = ns
self.qtNamespace = lambda: ns
sym += '@plt' sym = '_ZN%s7QObject11customEventEPNS_6QEventE' % strns
self.qtCustomEventPltFunc = self.findSymbol(sym) else:
sym = '_ZN7QObject11customEventEP6QEvent'
self.qtCustomEventFunc = self.findSymbol(sym)
sym = '_ZNK%s7QObject8propertyEPKc' % strns sym += '@plt'
self.qtPropertyFunc = self.findSymbol(sym) self.qtCustomEventPltFunc = self.findSymbol(sym)
# This might be wrong, but we can't do better: We found sym = '_ZNK%s7QObject8propertyEPKc' % strns
# a libQt5Core and could not extract a namespace. self.qtPropertyFunc = self.findSymbol(sym)
# The best guess is that there isn't any.
self.qtNamespaceToReport = ns
self.qtNamespace = lambda: ns
return ns
self.currentQtNamespaceGuess = ''
return ''
def assignValue(self, args): def assignValue(self, args):
typeName = self.hexdecode(args['type']) typeName = self.hexdecode(args['type'])
@@ -1406,4 +1406,17 @@ class InterpreterMessageBreakpoint(gdb.Breakpoint):
print('Interpreter event received.') print('Interpreter event received.')
return theDumper.handleInterpreterMessage() 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() #InterpreterMessageBreakpoint()

View File

@@ -565,11 +565,6 @@ void ClassItem::updateMembers(const Style *style)
auto dclass = dynamic_cast<DClass *>(object()); auto dclass = dynamic_cast<DClass *>(object());
QMT_CHECK(dclass); 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()) { foreach (const MClassMember &member, dclass->members()) {
switch (member.memberType()) { switch (member.memberType()) {
case MClassMember::MemberUndefined: case MClassMember::MemberUndefined:
@@ -587,50 +582,14 @@ void ClassItem::updateMembers(const Style *style)
break; break;
} }
if (!text->isEmpty()) if (text && !text->isEmpty())
*text += QStringLiteral("<br/>"); *text += QStringLiteral("<br/>");
bool addNewline = false; bool addNewline = false;
bool addSpace = false; bool addSpace = false;
if (member.visibility() != *currentVisibility) { if (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;
}
}
*currentVisibility = member.visibility(); *currentVisibility = member.visibility();
}
if (member.group() != currentGroup) { if (member.group() != currentGroup) {
if (addSpace)
*text += QStringLiteral(" ");
*text += QString(QStringLiteral("[%1]")).arg(member.group()); *text += QString(QStringLiteral("[%1]")).arg(member.group());
addNewline = true; addNewline = true;
*currentGroup = member.group(); *currentGroup = member.group();
@@ -638,61 +597,55 @@ void ClassItem::updateMembers(const Style *style)
if (addNewline) if (addNewline)
*text += QStringLiteral("<br/>"); *text += QStringLiteral("<br/>");
addSpace = false;
bool haveSignal = false; bool haveSignal = false;
bool haveSlot = false; bool haveSlot = false;
if (!useGroupVisibility) { if (member.visibility() != MClassMember::VisibilityUndefined) {
if (member.visibility() != MClassMember::VisibilityUndefined) { QString vis;
QString vis; switch (member.visibility()) {
switch (member.visibility()) { case MClassMember::VisibilityUndefined:
case MClassMember::VisibilityUndefined: break;
break; case MClassMember::VisibilityPublic:
case MClassMember::VisibilityPublic: vis = QStringLiteral("+");
vis = haveIconFonts ? QString(QChar(0xe990)) : QStringLiteral("+"); addSpace = true;
addSpace = true; break;
break; case MClassMember::VisibilityProtected:
case MClassMember::VisibilityProtected: vis = QStringLiteral("#");
vis = haveIconFonts ? QString(QChar(0xe98e)) : QStringLiteral("#"); addSpace = true;
addSpace = true; break;
break; case MClassMember::VisibilityPrivate:
case MClassMember::VisibilityPrivate: vis = QStringLiteral("-");
vis = haveIconFonts ? QString(QChar(0xe98f)) : QStringLiteral("-"); addSpace = true;
addSpace = true; break;
break; case MClassMember::VisibilitySignals:
case MClassMember::VisibilitySignals: vis = QStringLiteral("&gt;");
vis = haveIconFonts ? QString(QChar(0xe994)) : QStringLiteral("&gt;"); haveSignal = true;
haveSignal = true; addSpace = true;
addSpace = true; break;
break; case MClassMember::VisibilityPrivateSlots:
case MClassMember::VisibilityPrivateSlots: vis = QStringLiteral("-$");
vis = haveIconFonts ? QString(QChar(0xe98f)) + QChar(0xe9cb) haveSlot = true;
: QStringLiteral("-$"); addSpace = true;
haveSlot = true; break;
addSpace = true; case MClassMember::VisibilityProtectedSlots:
break; vis = QStringLiteral("#$");
case MClassMember::VisibilityProtectedSlots: haveSlot = true;
vis = haveIconFonts ? QString(QChar(0xe98e)) + QChar(0xe9cb) addSpace = true;
: QStringLiteral("#$"); break;
haveSlot = true; case MClassMember::VisibilityPublicSlots:
addSpace = true; vis = QStringLiteral("+$");
break; haveSlot = true;
case MClassMember::VisibilityPublicSlots: addSpace = true;
vis = haveIconFonts ? QString(QChar(0xe990)) + QChar(0xe9cb) break;
: QStringLiteral("+$");
haveSlot = true;
addSpace = true;
break;
}
*text += vis;
} }
*text += vis;
} }
if (member.properties() & MClassMember::PropertyQsignal && !haveSignal) { if (member.properties() & MClassMember::PropertyQsignal && !haveSignal) {
*text += haveIconFonts ? QString(QChar(0xe994)) : QStringLiteral("&gt;"); *text += QStringLiteral("&gt;");
addSpace = true; addSpace = true;
} }
if (member.properties() & MClassMember::PropertyQslot && !haveSlot) { if (member.properties() & MClassMember::PropertyQslot && !haveSlot) {
*text += haveIconFonts ? QString(QChar(0xe9cb)) : QStringLiteral("$"); *text += QStringLiteral("$");
addSpace = true; addSpace = true;
} }
if (addSpace) if (addSpace)

View File

@@ -63,7 +63,7 @@ static inline int classify2(const QChar *s, bool qmlMode) {
} }
else if (qmlMode && s[0].unicode() == 'o') { else if (qmlMode && s[0].unicode() == 'o') {
if (s[1].unicode() == 'n') { if (s[1].unicode() == 'n') {
return qmlMode ? Lexer::T_ON : Lexer::T_IDENTIFIER; return Lexer::T_ON;
} }
} }
return Lexer::T_IDENTIFIER; return Lexer::T_IDENTIFIER;
@@ -675,7 +675,7 @@ static inline int classify8(const QChar *s, bool qmlMode) {
if (s[5].unicode() == 'r') { if (s[5].unicode() == 'r') {
if (s[6].unicode() == 't') { if (s[6].unicode() == 't') {
if (s[7].unicode() == 'y') { if (s[7].unicode() == 'y') {
return qmlMode ? Lexer::T_PROPERTY : Lexer::T_IDENTIFIER; return Lexer::T_PROPERTY;
} }
} }
} }

View File

@@ -33,6 +33,7 @@
#include <QColor> #include <QColor>
#include <QDir> #include <QDir>
#include <QRegExp>
using namespace QmlJS; using namespace QmlJS;
using namespace QmlJS::AST; using namespace QmlJS::AST;

View File

@@ -35,6 +35,7 @@
#include <QCryptographicHash> #include <QCryptographicHash>
#include <QDir> #include <QDir>
#include <QFileInfo> #include <QFileInfo>
#include <QRegExp>
#include <algorithm> #include <algorithm>

View File

@@ -34,6 +34,7 @@
#include <utils/qtcassert.h> #include <utils/qtcassert.h>
#include <QList> #include <QList>
#include <QRegExp>
//using namespace QmlJS; //using namespace QmlJS;

View File

@@ -579,7 +579,7 @@ void ModelManagerInterface::updateProjectInfo(const ProjectInfo &pinfo, ProjectE
&majorVersion, &minorVersion, &patchVersion) != 3) &majorVersion, &minorVersion, &patchVersion) != 3)
majorVersion = minorVersion = patchVersion = -1; majorVersion = minorVersion = patchVersion = -1;
if (majorVersion > 4 || (majorVersion == 4 && (minorVersion > 8 || (majorVersion == 8 if (majorVersion > 4 || (majorVersion == 4 && (minorVersion > 8 || (minorVersion == 8
&& patchVersion >= 5)))) { && patchVersion >= 5)))) {
m_pluginDumper->loadBuiltinTypes(pinfo); m_pluginDumper->loadBuiltinTypes(pinfo);
} }

View File

@@ -29,6 +29,8 @@
#include "qmljsmodelmanagerinterface.h" #include "qmljsmodelmanagerinterface.h"
#include "parser/qmljsengine_p.h" #include "parser/qmljsengine_p.h"
#include <QRegExp>
using namespace QmlJS; using namespace QmlJS;
/*! /*!

View File

@@ -30,6 +30,7 @@
#include <QDir> #include <QDir>
#include <QDateTime> #include <QDateTime>
#include <QDebug> #include <QDebug>
#include <QRegExp>
namespace Utils { namespace Utils {

View File

@@ -36,6 +36,7 @@
#include <QDragEnterEvent> #include <QDragEnterEvent>
#include <QDropEvent> #include <QDropEvent>
#include <QMessageBox> #include <QMessageBox>
#include <QRegExp>
#include <QTimer> #include <QTimer>
#include <QUrl> #include <QUrl>

View File

@@ -32,6 +32,7 @@
#include <QDir> #include <QDir>
#include <QDebug> #include <QDebug>
#include <QCoreApplication> #include <QCoreApplication>
#include <QRegExp>
#include <QStack> #include <QStack>
#ifdef Q_OS_WIN #ifdef Q_OS_WIN

View File

@@ -28,6 +28,7 @@
#include "qtcassert.h" #include "qtcassert.h"
#include <QJSEngine> #include <QJSEngine>
#include <QRegExp>
#include <QStack> #include <QStack>
namespace Utils { namespace Utils {

View File

@@ -56,6 +56,7 @@
#include <QFileSystemWatcher> #include <QFileSystemWatcher>
#include <QList> #include <QList>
#include <QProcess> #include <QProcess>
#include <QRegExp>
#include <QMessageBox> #include <QMessageBox>
#include <QApplication> #include <QApplication>
#include <QDomDocument> #include <QDomDocument>

View File

@@ -47,6 +47,7 @@
#include <memory> #include <memory>
#include <QApplication> #include <QApplication>
#include <QDir> #include <QDir>
#include <QRegExp>
#include <QTime> #include <QTime>
#include <QTcpServer> #include <QTcpServer>
#include <QTcpSocket> #include <QTcpSocket>

View File

@@ -45,6 +45,7 @@
#include <QDirIterator> #include <QDirIterator>
#include <QFormLayout> #include <QFormLayout>
#include <QLabel> #include <QLabel>
#include <QRegExp>
#include <QVBoxLayout> #include <QVBoxLayout>
namespace { namespace {

View File

@@ -28,6 +28,8 @@
#include <projectexplorer/ioutputparser.h> #include <projectexplorer/ioutputparser.h>
#include <utils/fileutils.h> #include <utils/fileutils.h>
#include <QRegExp>
namespace Android { namespace Android {
namespace Internal { namespace Internal {

View File

@@ -28,6 +28,7 @@
#include <QDir> #include <QDir>
#include <QFileInfo> #include <QFileInfo>
#include <QRegExp>
namespace Autotest { namespace Autotest {
namespace Internal { namespace Internal {

View File

@@ -165,7 +165,6 @@ static QList<QmlJS::Document::Ptr> scanDirectoryForQuickTestQmlFiles(const QStri
} }
static bool checkQmlDocumentForQuickTestCode(QFutureInterface<TestParseResultPtr> futureInterface, static bool checkQmlDocumentForQuickTestCode(QFutureInterface<TestParseResultPtr> futureInterface,
const QmlJS::Snapshot &snapshot,
const QmlJS::Document::Ptr &qmlJSDoc, const QmlJS::Document::Ptr &qmlJSDoc,
const Core::Id &id, const Core::Id &id,
const QString &proFile = QString()) const QString &proFile = QString())
@@ -174,6 +173,7 @@ static bool checkQmlDocumentForQuickTestCode(QFutureInterface<TestParseResultPtr
return false; return false;
QmlJS::AST::Node *ast = qmlJSDoc->ast(); QmlJS::AST::Node *ast = qmlJSDoc->ast();
QTC_ASSERT(ast, return false); QTC_ASSERT(ast, return false);
QmlJS::Snapshot snapshot = QmlJS::ModelManagerInterface::instance()->snapshot();
TestQmlVisitor qmlVisitor(qmlJSDoc, snapshot); TestQmlVisitor qmlVisitor(qmlJSDoc, snapshot);
QmlJS::AST::Node::accept(ast, &qmlVisitor); QmlJS::AST::Node::accept(ast, &qmlVisitor);
if (!qmlVisitor.isValid()) if (!qmlVisitor.isValid())
@@ -212,7 +212,6 @@ static bool checkQmlDocumentForQuickTestCode(QFutureInterface<TestParseResultPtr
} }
static bool handleQtQuickTest(QFutureInterface<TestParseResultPtr> futureInterface, static bool handleQtQuickTest(QFutureInterface<TestParseResultPtr> futureInterface,
const QmlJS::Snapshot &snapshot,
CPlusPlus::Document::Ptr document, CPlusPlus::Document::Ptr document,
const Core::Id &id) const Core::Id &id)
{ {
@@ -233,7 +232,7 @@ static bool handleQtQuickTest(QFutureInterface<TestParseResultPtr> futureInterfa
const QList<QmlJS::Document::Ptr> qmlDocs = scanDirectoryForQuickTestQmlFiles(srcDir); const QList<QmlJS::Document::Ptr> qmlDocs = scanDirectoryForQuickTestQmlFiles(srcDir);
bool result = false; bool result = false;
for (const QmlJS::Document::Ptr &qmlJSDoc : qmlDocs) for (const QmlJS::Document::Ptr &qmlJSDoc : qmlDocs)
result |= checkQmlDocumentForQuickTestCode(futureInterface, snapshot, qmlJSDoc, id, proFile); result |= checkQmlDocumentForQuickTestCode(futureInterface, qmlJSDoc, id, proFile);
return result; return result;
} }
@@ -280,14 +279,14 @@ bool QuickTestParser::processDocument(QFutureInterface<TestParseResultPtr> futur
if (proFile.isEmpty()) if (proFile.isEmpty())
return false; return false;
QmlJS::Document::Ptr qmlJSDoc = m_qmlSnapshot.document(fileName); 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)) if (!m_cppSnapshot.contains(fileName) || !selectedForBuilding(fileName))
return false; return false;
CPlusPlus::Document::Ptr document = m_cppSnapshot.find(fileName).value(); CPlusPlus::Document::Ptr document = m_cppSnapshot.find(fileName).value();
if (!includesQtQuickTest(document, m_cppSnapshot)) if (!includesQtQuickTest(document, m_cppSnapshot))
return false; return false;
return handleQtQuickTest(futureInterface, m_qmlSnapshot, document, id()); return handleQtQuickTest(futureInterface, document, id());
} }
} // namespace Internal } // namespace Internal

View File

@@ -166,11 +166,11 @@ static void performTestRun(QFutureInterface<TestResultPtr> &futureInterface,
} }
} else { } else {
futureInterface.reportResult(TestResultPtr(new FaultyTestResult(Result::MessageFatal, 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) { if (testProcess.exitStatus() == QProcess::CrashExit) {
futureInterface.reportResult(TestResultPtr(new FaultyTestResult(Result::MessageFatal, 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) { if (canceledByTimeout) {

View File

@@ -215,16 +215,12 @@ void AutotoolsProject::makefileParsingFinished()
m_watchedFiles.append(configureAcFilePath); m_watchedFiles.append(configureAcFilePath);
} }
QList<FileNode *> 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()); 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); setRootProjectNode(newRoot);
updateCppCodeModel(); updateCppCodeModel();

View File

@@ -36,6 +36,7 @@
#include <QDir> #include <QDir>
#include <QFileInfo> #include <QFileInfo>
#include <QRegExp>
#include <QTextStream> #include <QTextStream>
#include <QDebug> #include <QDebug>

View File

@@ -189,9 +189,6 @@ public:
optionsBuilder.addPrecompiledHeaderOptions(pchUsage); optionsBuilder.addPrecompiledHeaderOptions(pchUsage);
optionsBuilder.addMsvcCompatibilityVersion(); optionsBuilder.addMsvcCompatibilityVersion();
if (type != ProjectExplorer::Constants::MSVC_TOOLCHAIN_TYPEID)
optionsBuilder.add(QLatin1String("-fPIC")); // TODO: Remove?
return optionsBuilder.options(); return optionsBuilder.options();
} }

View File

@@ -29,6 +29,7 @@
#include <QDir> #include <QDir>
#include <QFutureInterface> #include <QFutureInterface>
#include <QProcess> #include <QProcess>
#include <QRegExp>
#include <QStringList> #include <QStringList>
#include <utils/qtcassert.h> #include <utils/qtcassert.h>

View File

@@ -24,43 +24,26 @@
****************************************************************************/ ****************************************************************************/
#include "builddirmanager.h" #include "builddirmanager.h"
#include "cmakebuildconfiguration.h" #include "cmakebuildconfiguration.h"
#include "cmakekitinformation.h" #include "cmakekitinformation.h"
#include "cmakeparser.h"
#include "cmakeprojectconstants.h"
#include "cmakeprojectmanager.h"
#include "cmakeprojectnodes.h" #include "cmakeprojectnodes.h"
#include "cmaketool.h" #include "cmaketool.h"
#include <coreplugin/icore.h> #include <coreplugin/icore.h>
#include <coreplugin/documentmanager.h>
#include <coreplugin/messagemanager.h>
#include <coreplugin/editormanager/editormanager.h>
#include <coreplugin/progressmanager/progressmanager.h>
#include <cpptools/cpptoolsconstants.h>
#include <projectexplorer/headerpath.h>
#include <projectexplorer/kit.h> #include <projectexplorer/kit.h>
#include <projectexplorer/kitinformation.h> #include <projectexplorer/kitinformation.h>
#include <projectexplorer/project.h> #include <projectexplorer/project.h>
#include <projectexplorer/projectexplorerconstants.h> #include <projectexplorer/projectexplorerconstants.h>
#include <projectexplorer/projectnodes.h>
#include <projectexplorer/target.h> #include <projectexplorer/target.h>
#include <projectexplorer/taskhub.h> #include <projectexplorer/taskhub.h>
#include <projectexplorer/toolchain.h> #include <projectexplorer/toolchain.h>
#include <utils/algorithm.h> #include <utils/algorithm.h>
#include <utils/fileutils.h> #include <utils/fileutils.h>
#include <utils/mimetypes/mimedatabase.h>
#include <utils/qtcassert.h> #include <utils/qtcassert.h>
#include <utils/qtcprocess.h>
#include <utils/synchronousprocess.h>
#include <utils/temporarydirectory.h>
#include <QDateTime>
#include <QFile>
#include <QFileInfo>
#include <QMessageBox> #include <QMessageBox>
#include <QRegularExpression>
#include <QSet> #include <QSet>
using namespace ProjectExplorer; using namespace ProjectExplorer;
@@ -274,7 +257,7 @@ bool BuildDirManager::persistCMakeState()
return true; return true;
} }
void BuildDirManager::generateProjectTree(CMakeListsNode *root, const QList<const FileNode *> &allFiles) void BuildDirManager::generateProjectTree(CMakeProjectNode *root, const QList<const FileNode *> &allFiles)
{ {
QTC_ASSERT(m_reader, return); QTC_ASSERT(m_reader, return);

View File

@@ -69,7 +69,7 @@ public:
bool updateCMakeStateBeforeBuild(); bool updateCMakeStateBeforeBuild();
bool persistCMakeState(); bool persistCMakeState();
void generateProjectTree(CMakeListsNode *root, void generateProjectTree(CMakeProjectNode *root,
const QList<const ProjectExplorer::FileNode *> &allFiles); const QList<const ProjectExplorer::FileNode *> &allFiles);
void updateCodeModel(CppTools::RawProjectParts &rpps); void updateCodeModel(CppTools::RawProjectParts &rpps);

View File

@@ -42,7 +42,7 @@ namespace CMakeProjectManager {
namespace Internal { namespace Internal {
class CMakeBuildConfiguration; class CMakeBuildConfiguration;
class CMakeListsNode; class CMakeProjectNode;
class BuildDirReader : public QObject class BuildDirReader : public QObject
{ {
@@ -95,7 +95,7 @@ public:
virtual CMakeConfig takeParsedConfiguration() = 0; virtual CMakeConfig takeParsedConfiguration() = 0;
virtual QList<CMakeBuildTarget> buildTargets() const = 0; virtual QList<CMakeBuildTarget> buildTargets() const = 0;
virtual void generateProjectTree(CMakeListsNode *root, virtual void generateProjectTree(CMakeProjectNode *root,
const QList<const ProjectExplorer::FileNode *> &allFiles) = 0; const QList<const ProjectExplorer::FileNode *> &allFiles) = 0;
virtual void updateCodeModel(CppTools::RawProjectParts &rpps) = 0; virtual void updateCodeModel(CppTools::RawProjectParts &rpps) = 0;

View File

@@ -25,6 +25,7 @@
#include "cmakeautocompleter.h" #include "cmakeautocompleter.h"
#include <QRegExp>
#include <QTextCursor> #include <QTextCursor>
#include <QTextBlock> #include <QTextBlock>
#include <QDebug> #include <QDebug>

View File

@@ -215,13 +215,13 @@ QList<CMakeBuildTarget> CMakeBuildConfiguration::buildTargets() const
return m_buildDirManager->buildTargets(); return m_buildDirManager->buildTargets();
} }
CMakeListsNode * CMakeProjectNode *
CMakeBuildConfiguration::generateProjectTree(const QList<const FileNode*> &allFiles) const CMakeBuildConfiguration::generateProjectTree(const QList<const FileNode*> &allFiles) const
{ {
auto root = new CMakeListsNode(target()->project()->projectFilePath());
if (!m_buildDirManager || m_buildDirManager->isParsing()) if (!m_buildDirManager || m_buildDirManager->isParsing())
return nullptr; return nullptr;
auto root = new CMakeProjectNode(target()->project()->projectDirectory());
m_buildDirManager->generateProjectTree(root, allFiles); m_buildDirManager->generateProjectTree(root, allFiles);
return root; return root;
} }

View File

@@ -47,7 +47,7 @@ namespace Internal {
class BuildDirManager; class BuildDirManager;
class CMakeBuildConfigurationFactory; class CMakeBuildConfigurationFactory;
class CMakeBuildSettingsWidget; class CMakeBuildSettingsWidget;
class CMakeListsNode; class CMakeProjectNode;
class CMakeBuildConfiguration : public ProjectExplorer::BuildConfiguration class CMakeBuildConfiguration : public ProjectExplorer::BuildConfiguration
{ {
@@ -86,7 +86,7 @@ public:
void clearCache(); void clearCache();
QList<CMakeBuildTarget> buildTargets() const; QList<CMakeBuildTarget> buildTargets() const;
CMakeListsNode *generateProjectTree(const QList<const ProjectExplorer::FileNode *> &allFiles) const; CMakeProjectManager::Internal::CMakeProjectNode *generateProjectTree(const QList<const ProjectExplorer::FileNode *> &allFiles) const;
void updateCodeModel(CppTools::RawProjectParts &rpps); void updateCodeModel(CppTools::RawProjectParts &rpps);
static Utils::FileName static Utils::FileName

View File

@@ -27,6 +27,8 @@
#include <projectexplorer/abstractprocessstep.h> #include <projectexplorer/abstractprocessstep.h>
#include <QRegExp>
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
class QLineEdit; class QLineEdit;
class QListWidget; class QListWidget;

View File

@@ -30,6 +30,7 @@
#include <projectexplorer/ioutputparser.h> #include <projectexplorer/ioutputparser.h>
#include <projectexplorer/task.h> #include <projectexplorer/task.h>
#include <QRegExp>
#include <QRegularExpression> #include <QRegularExpression>
namespace CMakeProjectManager { namespace CMakeProjectManager {

View File

@@ -309,21 +309,15 @@ QString CMakeProject::displayName() const
QStringList CMakeProject::files(FilesMode fileMode) const QStringList CMakeProject::files(FilesMode fileMode) const
{ {
const QList<FileNode *> nodes = filtered(rootProjectNode()->recursiveFileNodes(), QStringList result;
[fileMode](const FileNode *fn) { rootProjectNode()->forEachNode([&](const FileNode *fn) {
const bool isGenerated = fn->isGenerated(); const bool isGenerated = fn->isGenerated();
switch (fileMode) if (fileMode == Project::SourceFiles && !isGenerated)
{ result.append(fn->filePath().toString());
case Project::SourceFiles: if (fileMode == Project::GeneratedFiles && isGenerated)
return !isGenerated; result.append(fn->filePath().toString());
case Project::GeneratedFiles:
return isGenerated;
case Project::AllFiles:
default:
return true;
}
}); });
return transform(nodes, [fileMode](const FileNode* fn) { return fn->filePath().toString(); }); return result;
} }
Project::RestoreResult CMakeProject::fromMap(const QVariantMap &map, QString *errorMessage) Project::RestoreResult CMakeProject::fromMap(const QVariantMap &map, QString *errorMessage)

View File

@@ -95,6 +95,8 @@ void ServerModeReader::setParameters(const BuildDirReader::Parameters &p)
this, &ServerModeReader::handleError); this, &ServerModeReader::handleError);
connect(m_cmakeServer.get(), &ServerMode::cmakeProgress, connect(m_cmakeServer.get(), &ServerMode::cmakeProgress,
this, &ServerModeReader::handleProgress); this, &ServerModeReader::handleProgress);
connect(m_cmakeServer.get(), &ServerMode::cmakeSignal,
this, &ServerModeReader::handleSignal);
connect(m_cmakeServer.get(), &ServerMode::cmakeMessage, connect(m_cmakeServer.get(), &ServerMode::cmakeMessage,
this, [this](const QString &m) { Core::MessageManager::write(m); }); this, [this](const QString &m) { Core::MessageManager::write(m); });
connect(m_cmakeServer.get(), &ServerMode::message, 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); auto folder = new VirtualFolderNode(basePath, priority);
folder->setDisplayName(displayName); folder->setDisplayName(displayName);
base->addNode(folder); base->addNode(folder);
folder->buildTree(files); folder->addNestedNodes(files);
for (FolderNode *fn : folder->folderNodes()) for (FolderNode *fn : folder->folderNodes())
fn->compress(); fn->compress();
} }
static void addCMakeInputs(CMakeListsNode *root, static void addCMakeInputs(FolderNode *root,
const Utils::FileName &sourceDir, const Utils::FileName &sourceDir,
const Utils::FileName &buildDir, const Utils::FileName &buildDir,
QList<FileNode *> &sourceInputs, QList<FileNode *> &sourceInputs,
@@ -250,7 +252,7 @@ static void addCMakeInputs(CMakeListsNode *root,
rootInputs); rootInputs);
} }
void ServerModeReader::generateProjectTree(CMakeListsNode *root, void ServerModeReader::generateProjectTree(CMakeProjectNode *root,
const QList<const FileNode *> &allFiles) const QList<const FileNode *> &allFiles)
{ {
// Split up cmake inputs into useful chunks: // Split up cmake inputs into useful chunks:
@@ -304,6 +306,7 @@ void ServerModeReader::updateCodeModel(CppTools::RawProjectParts &rpps)
CppTools::RawProjectPart rpp; CppTools::RawProjectPart rpp;
rpp.setProjectFileLocation(fg->target->sourceDirectory.toString() + "/CMakeLists.txt"); rpp.setProjectFileLocation(fg->target->sourceDirectory.toString() + "/CMakeLists.txt");
rpp.setBuildSystemTarget(fg->target->name);
rpp.setDisplayName(fg->target->name + QString::number(counter)); rpp.setDisplayName(fg->target->name + QString::number(counter));
rpp.setDefines(defineArg.toUtf8()); rpp.setDefines(defineArg.toUtf8());
rpp.setIncludePaths(includes); rpp.setIncludePaths(includes);
@@ -387,6 +390,13 @@ void ServerModeReader::handleProgress(int min, int cur, int max, const QString &
m_future->setProgressValue(progress); 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) void ServerModeReader::extractCodeModelData(const QVariantMap &data)
{ {
const QVariantList configs = data.value("configurations").toList(); const QVariantList configs = data.value("configurations").toList();
@@ -518,97 +528,29 @@ void ServerModeReader::extractCacheData(const QVariantMap &data)
m_cmakeCache = config; m_cmakeCache = config;
} }
void ServerModeReader::addCMakeLists(CMakeListsNode *root, const QList<FileNode *> &cmakeLists) void ServerModeReader::addCMakeLists(CMakeProjectNode *root, const QList<FileNode *> &cmakeLists)
{ {
const QDir baseDir = QDir(m_parameters.sourceDirectory.toString()); const QDir baseDir = QDir(m_parameters.sourceDirectory.toString());
QHash<QString, FileNode *> nodeHash; root->addNestedNodes(cmakeLists, Utils::FileName(),
for (FileNode *cm : cmakeLists) { [&cmakeLists](const Utils::FileName &fp) -> ProjectExplorer::FolderNode * {
const QString relPath = baseDir.relativeFilePath(cm->filePath().parentDir().toString()); if (Utils::contains(cmakeLists, [&fp](const FileNode *fn) { return fn->filePath().parentDir() == fp; }))
QTC_CHECK(!nodeHash.contains(relPath)); return new CMakeListsNode(fp);
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<QString, CMakeListsNode *> 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!
else else
cmln = static_cast<CMakeListsNode *>(parentNode->projectNode(fn->filePath())); return new FolderNode(fp);
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);
}
} }
static CMakeListsNode *findCMakeNode(CMakeListsNode *root, const Utils::FileName &dir) static ProjectNode *findCMakeNode(ProjectNode *root, const Utils::FileName &dir)
{ {
const Utils::FileName stepDir = dir; Node *n = root->findNode([&dir](Node *n) { return n->asProjectNode() && n->filePath() == dir; });
const Utils::FileName topDir = root->filePath().parentDir(); return n ? n->asProjectNode() : nullptr;
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<CMakeListsNode *>(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;
} }
static CMakeProjectNode *findOrCreateProjectNode(CMakeListsNode *root, const Utils::FileName &dir, static ProjectNode *findOrCreateProjectNode(ProjectNode *root, const Utils::FileName &dir,
const QString &displayName) const QString &displayName)
{ {
CMakeListsNode *cmln = findCMakeNode(root, dir); ProjectNode *cmln = findCMakeNode(root, dir);
QTC_ASSERT(cmln, return nullptr); QTC_ASSERT(cmln, return nullptr);
Utils::FileName projectName = dir; Utils::FileName projectName = dir;
@@ -623,7 +565,7 @@ static CMakeProjectNode *findOrCreateProjectNode(CMakeListsNode *root, const Uti
return pn; return pn;
} }
void ServerModeReader::addProjects(CMakeListsNode *root, void ServerModeReader::addProjects(CMakeProjectNode *root,
const QList<Project *> &projects, const QList<Project *> &projects,
const QList<const FileNode *> &allFiles) const QList<const FileNode *> &allFiles)
{ {
@@ -635,17 +577,16 @@ void ServerModeReader::addProjects(CMakeListsNode *root,
} }
for (const Project *p : projects) { 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(pNode, continue);
QTC_ASSERT(root, continue);
addTargets(root, p->targets, includeFiles); 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) const QString &displayName)
{ {
CMakeListsNode *cmln = findCMakeNode(root, dir); ProjectNode *cmln = findCMakeNode(root, dir);
QTC_ASSERT(cmln, return nullptr); QTC_ASSERT(cmln, return nullptr);
Utils::FileName targetName = dir; Utils::FileName targetName = dir;
@@ -660,7 +601,7 @@ static CMakeTargetNode *findOrCreateTargetNode(CMakeListsNode *root, const Utils
return tn; return tn;
} }
void ServerModeReader::addTargets(CMakeListsNode *root, void ServerModeReader::addTargets(CMakeProjectNode *root,
const QList<ServerModeReader::Target *> &targets, const QList<ServerModeReader::Target *> &targets,
const QHash<FileName, QList<const FileNode *>> &headers) const QHash<FileName, QList<const FileNode *>> &headers)
{ {

View File

@@ -33,6 +33,8 @@
namespace CMakeProjectManager { namespace CMakeProjectManager {
namespace Internal { namespace Internal {
class CMakeListsNode;
class ServerModeReader : public BuildDirReader class ServerModeReader : public BuildDirReader
{ {
Q_OBJECT Q_OBJECT
@@ -54,7 +56,7 @@ public:
QList<CMakeBuildTarget> buildTargets() const final; QList<CMakeBuildTarget> buildTargets() const final;
CMakeConfig takeParsedConfiguration() final; CMakeConfig takeParsedConfiguration() final;
void generateProjectTree(CMakeListsNode *root, void generateProjectTree(CMakeProjectNode *root,
const QList<const ProjectExplorer::FileNode *> &allFiles) final; const QList<const ProjectExplorer::FileNode *> &allFiles) final;
void updateCodeModel(CppTools::RawProjectParts &rpps) final; void updateCodeModel(CppTools::RawProjectParts &rpps) final;
@@ -62,6 +64,7 @@ private:
void handleReply(const QVariantMap &data, const QString &inReplyTo); void handleReply(const QVariantMap &data, const QString &inReplyTo);
void handleError(const QString &message); void handleError(const QString &message);
void handleProgress(int min, int cur, int max, const QString &inReplyTo); void handleProgress(int min, int cur, int max, const QString &inReplyTo);
void handleSignal(const QString &signal, const QVariantMap &data);
struct Target; struct Target;
struct Project; struct Project;
@@ -110,10 +113,10 @@ private:
void extractCMakeInputsData(const QVariantMap &data); void extractCMakeInputsData(const QVariantMap &data);
void extractCacheData(const QVariantMap &data); void extractCacheData(const QVariantMap &data);
void addCMakeLists(CMakeListsNode *root, const QList<ProjectExplorer::FileNode *> &cmakeLists); void addCMakeLists(CMakeProjectNode *root, const QList<ProjectExplorer::FileNode *> &cmakeLists);
void addProjects(CMakeListsNode *root, const QList<Project *> &projects, void addProjects(CMakeProjectNode *root, const QList<Project *> &projects,
const QList<const ProjectExplorer::FileNode *> &allFiles); const QList<const ProjectExplorer::FileNode *> &allFiles);
void addTargets(CMakeListsNode *root, const QList<Target *> &targets, void addTargets(CMakeProjectNode *root, const QList<Target *> &targets,
const QHash<Utils::FileName, QList<const ProjectExplorer::FileNode *>> &headers); const QHash<Utils::FileName, QList<const ProjectExplorer::FileNode *>> &headers);
void addFileGroups(ProjectExplorer::ProjectNode *targetRoot, void addFileGroups(ProjectExplorer::ProjectNode *targetRoot,
const Utils::FileName &sourceDirectory, const Utils::FileName &sourceDirectory,

View File

@@ -264,7 +264,7 @@ CMakeConfig TeaLeafReader::takeParsedConfiguration()
return result; return result;
} }
void TeaLeafReader::generateProjectTree(CMakeListsNode *root, const QList<const FileNode *> &allFiles) void TeaLeafReader::generateProjectTree(CMakeProjectNode *root, const QList<const FileNode *> &allFiles)
{ {
root->setDisplayName(m_projectName); root->setDisplayName(m_projectName);
@@ -311,7 +311,7 @@ void TeaLeafReader::generateProjectTree(CMakeListsNode *root, const QList<const
QList<FileNode *> fileNodes = m_files + Utils::transform(missingHeaders, [](const FileNode *fn) { return new FileNode(*fn); }); QList<FileNode *> 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! 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(); includePaths += m_parameters.buildDirectory.toString();
CppTools::RawProjectPart rpp; CppTools::RawProjectPart rpp;
rpp.setProjectFileLocation(QString()); // No project file information available! rpp.setProjectFileLocation(QString()); // No project file information available!
rpp.setBuildSystemTarget(cbt.title);
rpp.setIncludePaths(includePaths); rpp.setIncludePaths(includePaths);
CppTools::RawProjectPartFlags cProjectFlags; CppTools::RawProjectPartFlags cProjectFlags;

View File

@@ -56,7 +56,7 @@ public:
QList<CMakeBuildTarget> buildTargets() const final; QList<CMakeBuildTarget> buildTargets() const final;
CMakeConfig takeParsedConfiguration() final; CMakeConfig takeParsedConfiguration() final;
void generateProjectTree(CMakeListsNode *root, void generateProjectTree(CMakeProjectNode *root,
const QList<const ProjectExplorer::FileNode *> &allFiles) final; const QList<const ProjectExplorer::FileNode *> &allFiles) final;
void updateCodeModel(CppTools::RawProjectParts &rpps) final; void updateCodeModel(CppTools::RawProjectParts &rpps) final;

View File

@@ -32,6 +32,7 @@
#include <utils/hostosinfo.h> #include <utils/hostosinfo.h>
#include <QAction> #include <QAction>
#include <QRegExp>
#include <QToolButton> #include <QToolButton>
#include <QTextStream> #include <QTextStream>

View File

@@ -29,10 +29,9 @@
#include <utils/filesearch.h> #include <utils/filesearch.h>
#include <QPointer> #include <QPointer>
#include <QTextBlock>
#include <QPlainTextEdit> #include <QPlainTextEdit>
#include <QRegularExpression> #include <QRegularExpression>
#include <QTextBlock>
#include <QTextCursor> #include <QTextCursor>
namespace Core { namespace Core {

View File

@@ -30,6 +30,7 @@
#include <utils/qtcassert.h> #include <utils/qtcassert.h>
#include <QDir> #include <QDir>
#include <QRegExp>
#include <QStringMatcher> #include <QStringMatcher>
#include <QTimer> #include <QTimer>

View File

@@ -32,6 +32,7 @@
#include <QAbstractItemModel> #include <QAbstractItemModel>
#include <QFileInfo> #include <QFileInfo>
#include <QMutexLocker> #include <QMutexLocker>
#include <QRegExp>
using namespace Core; using namespace Core;
using namespace Core; using namespace Core;

View File

@@ -35,6 +35,7 @@
#include <QCoreApplication> #include <QCoreApplication>
#include <QFileInfo> #include <QFileInfo>
#include <QDir> #include <QDir>
#include <QRegExp>
#include <QDebug> #include <QDebug>

View File

@@ -1779,12 +1779,16 @@ void CppCodeModelInspectorDialog::updateProjectPartData(const ProjectPart::Ptr &
} }
const QString callGroupId = part->callGroupId.isEmpty() ? QString::fromLatin1("<None>") const QString callGroupId = part->callGroupId.isEmpty() ? QString::fromLatin1("<None>")
: part->callGroupId; : part->callGroupId;
const QString buildSystemTarget
= part->buildSystemTarget.isEmpty() ? QString::fromLatin1("<None>")
: part->buildSystemTarget;
KeyValueModel::Table table = KeyValueModel::Table() KeyValueModel::Table table = KeyValueModel::Table()
<< qMakePair(QString::fromLatin1("Project Part Name"), part->displayName) << qMakePair(QString::fromLatin1("Project Part Name"), part->displayName)
<< qMakePair(QString::fromLatin1("Project Part File"), part->projectFileLocation()) << qMakePair(QString::fromLatin1("Project Part File"), part->projectFileLocation())
<< qMakePair(QString::fromLatin1("Project Name"), projectName) << qMakePair(QString::fromLatin1("Project Name"), projectName)
<< qMakePair(QString::fromLatin1("Project File"), projectFilePath) << qMakePair(QString::fromLatin1("Project File"), projectFilePath)
<< qMakePair(QString::fromLatin1("Buildsystem Target"), buildSystemTarget)
<< qMakePair(QString::fromLatin1("Callgroup Id"), callGroupId) << qMakePair(QString::fromLatin1("Callgroup Id"), callGroupId)
<< qMakePair(QString::fromLatin1("Selected For Building"), << qMakePair(QString::fromLatin1("Selected For Building"),
CMI::Utils::toString(part->selectedForBuilding)) CMI::Utils::toString(part->selectedForBuilding))

View File

@@ -46,6 +46,7 @@
#include <utils/runextensions.h> #include <utils/runextensions.h>
#include <utils/tooltip/tooltip.h> #include <utils/tooltip/tooltip.h>
#include <QRegExp>
#include <QVarLengthArray> #include <QVarLengthArray>
using namespace CPlusPlus; using namespace CPlusPlus;

View File

@@ -31,6 +31,7 @@
#include <coreplugin/editormanager/editormanager.h> #include <coreplugin/editormanager/editormanager.h>
#include <coreplugin/editormanager/ieditor.h> #include <coreplugin/editormanager/ieditor.h>
#include <QRegExp>
#include <QStringMatcher> #include <QStringMatcher>
using namespace CppTools::Internal; using namespace CppTools::Internal;

View File

@@ -28,6 +28,7 @@
#include <coreplugin/editormanager/editormanager.h> #include <coreplugin/editormanager/editormanager.h>
#include <QRegExp>
#include <QStringMatcher> #include <QStringMatcher>
#include <algorithm> #include <algorithm>

View File

@@ -185,6 +185,7 @@ static ProjectPart::Ptr projectPartFromRawProjectPart(const RawProjectPart &rawP
part->projectFileLine = rawProjectPart.projectFileLine; part->projectFileLine = rawProjectPart.projectFileLine;
part->projectFileColumn = rawProjectPart.projectFileColumn; part->projectFileColumn = rawProjectPart.projectFileColumn;
part->callGroupId = rawProjectPart.callGroupId; part->callGroupId = rawProjectPart.callGroupId;
part->buildSystemTarget = rawProjectPart.buildSystemTarget;
part->qtVersion = rawProjectPart.qtVersion; part->qtVersion = rawProjectPart.qtVersion;
part->projectDefines = rawProjectPart.projectDefines; part->projectDefines = rawProjectPart.projectDefines;
part->headerPaths = rawProjectPart.headerPaths; part->headerPaths = rawProjectPart.headerPaths;

View File

@@ -66,6 +66,11 @@ void RawProjectPart::setConfigFileName(const QString &configFileName)
this->projectConfigFile = configFileName; this->projectConfigFile = configFileName;
} }
void RawProjectPart::setBuildSystemTarget(const QString &target)
{
buildSystemTarget = target;
}
void RawProjectPart::setCallGroupId(const QString &id) void RawProjectPart::setCallGroupId(const QString &id)
{ {
callGroupId = id; callGroupId = id;

View File

@@ -63,6 +63,7 @@ public:
void setProjectFileLocation(const QString &projectFile, int line = -1, int column = -1); void setProjectFileLocation(const QString &projectFile, int line = -1, int column = -1);
void setConfigFileName(const QString &configFileName); void setConfigFileName(const QString &configFileName);
void setCallGroupId(const QString &id); void setCallGroupId(const QString &id);
void setBuildSystemTarget(const QString &target);
void setQtVersion(ProjectPart::QtVersion qtVersion); void setQtVersion(ProjectPart::QtVersion qtVersion);
@@ -84,6 +85,7 @@ public:
int projectFileColumn = -1; int projectFileColumn = -1;
QString projectConfigFile; // currently only used by the Generic Project Manager QString projectConfigFile; // currently only used by the Generic Project Manager
QString callGroupId; QString callGroupId;
QString buildSystemTarget;
QStringList precompiledHeaders; QStringList precompiledHeaders;
ProjectPartHeaderPaths headerPaths; ProjectPartHeaderPaths headerPaths;
QByteArray projectDefines; QByteArray projectDefines;

View File

@@ -110,6 +110,7 @@ public:
int projectFileColumn = -1; int projectFileColumn = -1;
QString projectConfigFile; // currently only used by the Generic Project Manager QString projectConfigFile; // currently only used by the Generic Project Manager
QString callGroupId; QString callGroupId;
QString buildSystemTarget;
ProjectFiles files; ProjectFiles files;

View File

@@ -1969,15 +1969,15 @@ bool BreakHandler::contextMenuEvent(const ItemViewEvent &ev)
// FIXME BP: m_engine->threadsHandler()->currentThreadId(); // FIXME BP: m_engine->threadsHandler()->currentThreadId();
int threadId = 0; // int threadId = 0;
addAction(menu, // addAction(menu,
threadId == -1 ? tr("Associate Breakpoint with All Threads") // threadId == -1 ? tr("Associate Breakpoint with All Threads")
: tr("Associate Breakpoint with Thread %1").arg(threadId), // : tr("Associate Breakpoint with Thread %1").arg(threadId),
!selectedItems.isEmpty(), // !selectedItems.isEmpty(),
[this, selectedItems, threadId] { // [this, selectedItems, threadId] {
for (Breakpoint bp : selectedItems) // for (Breakpoint bp : selectedItems)
bp.setThreadSpec(threadId); // bp.setThreadSpec(threadId);
}); // });
addAction(menu, addAction(menu,
selectedItems.size() > 1 selectedItems.size() > 1

View File

@@ -112,10 +112,16 @@ enum StepAction
struct QmlV8ObjectData struct QmlV8ObjectData
{ {
int handle = -1; int handle = -1;
int expectedProperties = -1;
QString name; QString name;
QString type; QString type;
QVariant value; QVariant value;
QVariantList properties; QVariantList properties;
bool hasChildren() const
{
return expectedProperties > 0 || !properties.isEmpty();
}
}; };
typedef std::function<void(const QVariantMap &)> QmlCallback; typedef std::function<void(const QVariantMap &)> QmlCallback;
@@ -1391,7 +1397,7 @@ void QmlEnginePrivate::handleEvaluateExpression(const QVariantMap &response,
if (success) { if (success) {
item->type = body.type; item->type = body.type;
item->value = body.value.toString(); item->value = body.value.toString();
item->wantsChildren = body.properties.count(); item->setHasChildren(body.hasChildren());
} else { } else {
//Do not set type since it is unknown //Do not set type since it is unknown
item->setError(body.value.toString()); item->setError(body.value.toString());
@@ -1658,55 +1664,69 @@ QmlV8ObjectData QmlEnginePrivate::extractData(const QVariant &data) const
objectData.name = dataMap.value(NAME).toString(); 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)) { if (dataMap.contains(REF)) {
objectData.handle = dataMap.value(REF).toInt(); objectData.handle = dataMap.value(REF).toInt();
if (refVals.contains(objectData.handle)) { if (refVals.contains(objectData.handle)) {
QmlV8ObjectData data = refVals.value(objectData.handle); QmlV8ObjectData data = refVals.value(objectData.handle);
objectData.type = data.type; if (objectData.type.isEmpty())
objectData.value = data.value; objectData.type = data.type;
objectData.properties = data.properties; if (!objectData.value.isValid())
} objectData.value = data.value;
} else { if (objectData.properties.isEmpty())
objectData.handle = dataMap.value(HANDLE).toInt(); objectData.properties = data.properties;
QString type = dataMap.value(TYPE).toString(); if (objectData.expectedProperties < 0)
objectData.expectedProperties = data.expectedProperties;
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);
} }
} }
@@ -2216,7 +2236,7 @@ void QmlEnginePrivate::handleFrame(const QVariantMap &response)
item->id = objectData.handle; item->id = objectData.handle;
item->type = objectData.type; item->type = objectData.type;
item->value = objectData.value.toString(); item->value = objectData.value.toString();
item->setHasChildren(objectData.properties.count()); item->setHasChildren(objectData.hasChildren());
// In case of global object, we do not get children // In case of global object, we do not get children
// Set children nevertheless and query later. // Set children nevertheless and query later.
if (item->value == "global") { if (item->value == "global") {
@@ -2298,11 +2318,11 @@ void QmlEnginePrivate::handleScope(const QVariantMap &response)
item->name = item->exp; item->name = item->exp;
item->iname = "local." + item->exp; item->iname = "local." + item->exp;
item->id = localData.handle; item->id = localData.handle;
item->type = localData.type;
item->value = localData.value.toString();
item->setHasChildren(localData.hasChildren());
if (localData.value.isValid()) { if (localData.value.isValid() || item->wantsChildren || localData.expectedProperties == 0) {
item->type = localData.type;
item->value = localData.value.toString();
item->setHasChildren(localData.properties.count());
engine->watchHandler()->insertItem(item.release()); engine->watchHandler()->insertItem(item.release());
} else { } else {
itemsToLookup.insert(int(item->id), {item->iname, item->name, item->exp}); 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(); item->value = propertyData.value.toString();
if (item->type.isEmpty() || expandedINames.contains(item->iname)) if (item->type.isEmpty() || expandedINames.contains(item->iname))
itemsToLookup.insert(propertyData.handle, {item->iname, item->name, item->exp}); itemsToLookup.insert(propertyData.handle, {item->iname, item->name, item->exp});
item->setHasChildren(propertyData.properties.count() > 0); item->setHasChildren(propertyData.hasChildren());
parent->appendChild(item.release()); parent->appendChild(item.release());
} }
@@ -2499,7 +2519,7 @@ void QmlEnginePrivate::handleLookup(const QVariantMap &response)
item->type = bodyObjectData.type; item->type = bodyObjectData.type;
item->value = bodyObjectData.value.toString(); item->value = bodyObjectData.value.toString();
item->setHasChildren(bodyObjectData.properties.count()); item->setHasChildren(bodyObjectData.hasChildren());
insertSubItems(item, bodyObjectData.properties); insertSubItems(item, bodyObjectData.properties);
engine->watchHandler()->insertItem(item); engine->watchHandler()->insertItem(item);
@@ -2515,7 +2535,10 @@ void QmlEnginePrivate::stateChanged(State state)
if (state == QmlDebugClient::Enabled) { if (state == QmlDebugClient::Enabled) {
/// Start session. /// Start session.
flushSendBuffer(); flushSendBuffer();
runDirectCommand(CONNECT); QJsonObject parameters;
parameters.insert("redundantRefs", false);
parameters.insert("namesAsObjects", false);
runDirectCommand(CONNECT, QJsonDocument(parameters).toJson());
runCommand({VERSION}, CB(handleVersion)); runCommand({VERSION}, CB(handleVersion));
} }
} }

View File

@@ -2008,7 +2008,7 @@ bool WatchHandler::insertItem(WatchItem *item)
bool found = false; bool found = false;
const std::vector<TreeItem *> siblings(parent->begin(), parent->end()); const std::vector<TreeItem *> 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<WatchItem *>(siblings[row])->iname == item->iname) { if (static_cast<WatchItem *>(siblings[row])->iname == item->iname) {
m_model->destroyItem(parent->childAt(row)); m_model->destroyItem(parent->childAt(row));
parent->insertChild(row, item); parent->insertChild(row, item);

View File

@@ -34,6 +34,7 @@ publication by Neil Fraser: http://neil.fraser.name/writing/diff/
#include "differ.h" #include "differ.h"
#include <QList> #include <QList>
#include <QRegExp>
#include <QStringList> #include <QStringList>
#include <QMap> #include <QMap>
#include <QPair> #include <QPair>

View File

@@ -25,6 +25,7 @@
#include "diffutils.h" #include "diffutils.h"
#include "differ.h" #include "differ.h"
#include <QRegExp>
#include <QStringList> #include <QStringList>
#include <QTextStream> #include <QTextStream>
#include "texteditor/fontsettings.h" #include "texteditor/fontsettings.h"

View File

@@ -259,28 +259,25 @@ void GenericProject::refresh(RefreshOptions options)
parseProject(options); parseProject(options);
if (options & Files) { if (options & Files) {
QList<FileNode *> fileNodes = Utils::transform(files(), [](const QString &f) { auto newRoot = new GenericProjectNode(this);
for (const QString &f : files()) {
FileType fileType = FileType::Source; // ### FIXME FileType fileType = FileType::Source; // ### FIXME
if (f.endsWith(".qrc")) if (f.endsWith(".qrc"))
fileType = FileType::Resource; 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, 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); setRootProjectNode(newRoot);
} }

View File

@@ -37,6 +37,7 @@
#include <utils/hostosinfo.h> #include <utils/hostosinfo.h>
#include <utils/progressindicator.h> #include <utils/progressindicator.h>
#include <utils/qtcassert.h> #include <utils/qtcassert.h>
#include <utils/utilsicons.h>
#include <utils/theme/theme.h> #include <utils/theme/theme.h>
#include <QCompleter> #include <QCompleter>
@@ -69,7 +70,6 @@ GerritDialog::GerritDialog(const QSharedPointer<GerritParameters> &p,
setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint); setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
m_ui->setupUi(this); m_ui->setupUi(this);
setWindowTitle(tr("Gerrit"));
m_queryModel->setStringList(m_parameters->savedQueries); m_queryModel->setStringList(m_parameters->savedQueries);
QCompleter *completer = new QCompleter(this); QCompleter *completer = new QCompleter(this);
completer->setModel(m_queryModel); completer->setModel(m_queryModel);
@@ -111,6 +111,10 @@ GerritDialog::GerritDialog(const QSharedPointer<GerritParameters> &p,
connect(m_ui->treeView, &QAbstractItemView::activated, connect(m_ui->treeView, &QAbstractItemView::activated,
this, &GerritDialog::slotActivated); 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_displayButton = addActionButton(tr("&Show"), [this]() { slotFetchDisplay(); });
m_cherryPickButton = addActionButton(tr("Cherry &Pick"), [this]() { slotFetchCherryPick(); }); m_cherryPickButton = addActionButton(tr("Cherry &Pick"), [this]() { slotFetchCherryPick(); });
m_checkoutButton = addActionButton(tr("C&heckout"), [this]() { slotFetchCheckout(); }); m_checkoutButton = addActionButton(tr("C&heckout"), [this]() { slotFetchCheckout(); });
@@ -120,6 +124,11 @@ GerritDialog::GerritDialog(const QSharedPointer<GerritParameters> &p,
m_refreshButton, &QWidget::setDisabled); m_refreshButton, &QWidget::setDisabled);
connect(m_model, &GerritModel::refreshStateChanged, connect(m_model, &GerritModel::refreshStateChanged,
this, &GerritDialog::slotRefreshStateChanged); 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); setCurrentPath(repository);
slotCurrentChanged(); slotCurrentChanged();
@@ -226,7 +235,7 @@ void GerritDialog::remoteChanged()
slotRefresh(); slotRefresh();
} }
void GerritDialog::updateRemotes() void GerritDialog::updateRemotes(bool forceReload)
{ {
m_ui->remoteComboBox->clear(); m_ui->remoteComboBox->clear();
if (m_repository.isEmpty() || !QFileInfo(m_repository).isDir()) if (m_repository.isEmpty() || !QFileInfo(m_repository).isDir())
@@ -240,7 +249,7 @@ void GerritDialog::updateRemotes()
while (mapIt.hasNext()) { while (mapIt.hasNext()) {
mapIt.next(); mapIt.next();
GerritServer server; GerritServer server;
if (!server.fillFromRemote(mapIt.value(), *m_parameters)) if (!server.fillFromRemote(mapIt.value(), *m_parameters, forceReload))
continue; continue;
addRemote(server, mapIt.key()); addRemote(server, mapIt.key());
} }

View File

@@ -76,7 +76,7 @@ private:
void slotFetchCheckout(); void slotFetchCheckout();
void slotRefresh(); void slotRefresh();
void remoteChanged(); void remoteChanged();
void updateRemotes(); void updateRemotes(bool forceReload = false);
void addRemote(const GerritServer &server, const QString &name); void addRemote(const GerritServer &server, const QString &name);
void manageProgressIndicator(); void manageProgressIndicator();

View File

@@ -65,6 +65,13 @@
</property> </property>
</widget> </widget>
</item> </item>
<item>
<widget class="QToolButton" name="resetRemoteButton">
<property name="toolTip">
<string>Refresh Remote Servers</string>
</property>
</widget>
</item>
</layout> </layout>
</item> </item>
<item> <item>

View File

@@ -233,13 +233,12 @@ public:
signals: signals:
void resultRetrieved(const QByteArray &); void resultRetrieved(const QByteArray &);
void errorText(const QString &text);
void finished(); void finished();
private: private:
void processError(QProcess::ProcessError); void processError(QProcess::ProcessError);
void processFinished(int exitCode, QProcess::ExitStatus); void processFinished(int exitCode, QProcess::ExitStatus);
void readyReadStandardError();
void readyReadStandardOutput();
void timeout(); void timeout();
void errorTermination(const QString &msg); void errorTermination(const QString &msg);
@@ -249,6 +248,7 @@ private:
QTimer m_timer; QTimer m_timer;
QString m_binary; QString m_binary;
QByteArray m_output; QByteArray m_output;
QString m_error;
QFutureInterface<void> m_progress; QFutureInterface<void> m_progress;
QFutureWatcher<void> m_watcher; QFutureWatcher<void> m_watcher;
QStringList m_arguments; QStringList m_arguments;
@@ -277,10 +277,14 @@ QueryContext::QueryContext(const QString &query,
+ "&o=CURRENT_REVISION&o=DETAILED_LABELS&o=DETAILED_ACCOUNTS"; + "&o=CURRENT_REVISION&o=DETAILED_LABELS&o=DETAILED_ACCOUNTS";
m_arguments = GerritServer::curlArguments() << url; m_arguments = GerritServer::curlArguments() << url;
} }
connect(&m_process, &QProcess::readyReadStandardError, connect(&m_process, &QProcess::readyReadStandardError, this, [this] {
this, &QueryContext::readyReadStandardError); const QString text = QString::fromLocal8Bit(m_process.readAllStandardError());
connect(&m_process, &QProcess::readyReadStandardOutput, VcsOutputWindow::appendError(text);
this, &QueryContext::readyReadStandardOutput); m_error.append(text);
});
connect(&m_process, &QProcess::readyReadStandardOutput, this, [this] {
m_output.append(m_process.readAllStandardOutput());
});
connect(&m_process, static_cast<void (QProcess::*)(int, QProcess::ExitStatus)>(&QProcess::finished), connect(&m_process, static_cast<void (QProcess::*)(int, QProcess::ExitStatus)>(&QProcess::finished),
this, &QueryContext::processFinished); this, &QueryContext::processFinished);
connect(&m_process, &QProcess::errorOccurred, this, &QueryContext::processError); connect(&m_process, &QProcess::errorOccurred, this, &QueryContext::processError);
@@ -345,6 +349,7 @@ void QueryContext::processFinished(int exitCode, QProcess::ExitStatus es)
{ {
if (m_timer.isActive()) if (m_timer.isActive())
m_timer.stop(); m_timer.stop();
emit errorText(m_error);
if (es != QProcess::NormalExit) { if (es != QProcess::NormalExit) {
errorTermination(tr("%1 crashed.").arg(m_binary)); errorTermination(tr("%1 crashed.").arg(m_binary));
return; return;
@@ -357,16 +362,6 @@ void QueryContext::processFinished(int exitCode, QProcess::ExitStatus es)
emit finished(); emit finished();
} }
void QueryContext::readyReadStandardError()
{
VcsOutputWindow::appendError(QString::fromLocal8Bit(m_process.readAllStandardError()));
}
void QueryContext::readyReadStandardOutput()
{
m_output.append(m_process.readAllStandardOutput());
}
void QueryContext::timeout() void QueryContext::timeout()
{ {
if (m_process.state() != QProcess::Running) if (m_process.state() != QProcess::Running)
@@ -520,6 +515,7 @@ void GerritModel::refresh(const QSharedPointer<GerritServer> &server, const QStr
m_query = new QueryContext(realQuery, m_parameters, *m_server, this); m_query = new QueryContext(realQuery, m_parameters, *m_server, this);
connect(m_query, &QueryContext::resultRetrieved, this, &GerritModel::resultRetrieved); connect(m_query, &QueryContext::resultRetrieved, this, &GerritModel::resultRetrieved);
connect(m_query, &QueryContext::errorText, this, &GerritModel::errorText);
connect(m_query, &QueryContext::finished, this, &GerritModel::queryFinished); connect(m_query, &QueryContext::finished, this, &GerritModel::queryFinished);
emit refreshStateChanged(true); emit refreshStateChanged(true);
m_query->start(); m_query->start();

View File

@@ -127,6 +127,7 @@ public:
signals: signals:
void refreshStateChanged(bool isRefreshing); // For disabling the "Refresh" button. void refreshStateChanged(bool isRefreshing); // For disabling the "Refresh" button.
void stateChanged(); void stateChanged();
void errorText(const QString &text);
private: private:
void resultRetrieved(const QByteArray &); void resultRetrieved(const QByteArray &);

View File

@@ -29,12 +29,14 @@
#include "../gitplugin.h" #include "../gitplugin.h"
#include "../gitclient.h" #include "../gitclient.h"
#include <coreplugin/icore.h>
#include <coreplugin/shellcommand.h> #include <coreplugin/shellcommand.h>
#include <utils/hostosinfo.h> #include <utils/hostosinfo.h>
#include <QFile> #include <QFile>
#include <QJsonDocument> #include <QJsonDocument>
#include <QRegularExpression> #include <QRegularExpression>
#include <QSettings>
using namespace Utils; using namespace Utils;
using namespace Git::Internal; using namespace Git::Internal;
@@ -44,6 +46,11 @@ namespace Internal {
static const char defaultHostC[] = "codereview.qt-project.org"; static const char defaultHostC[] = "codereview.qt-project.org";
static const char accountUrlC[] = "/accounts/self"; 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 bool GerritUser::isSameAs(const GerritUser &other) const
{ {
@@ -111,7 +118,9 @@ QString GerritServer::url(UrlType urlType) const
return res; return res;
} }
bool GerritServer::fillFromRemote(const QString &remote, const GerritParameters &parameters) bool GerritServer::fillFromRemote(const QString &remote,
const GerritParameters &parameters,
bool forceReload)
{ {
const GitRemote r(remote); const GitRemote r(remote);
if (!r.isValid) if (!r.isValid)
@@ -136,12 +145,61 @@ bool GerritServer::fillFromRemote(const QString &remote, const GerritParameters
curlBinary = parameters.curl; curlBinary = parameters.curl;
if (curlBinary.isEmpty() || !QFile::exists(curlBinary)) if (curlBinary.isEmpty() || !QFile::exists(curlBinary))
return false; return false;
rootPath = r.path; const StoredHostValidity validity = forceReload ? Invalid : loadSettings();
// Strip the last part of the path, which is always the repo name switch (validity) {
// The rest of the path needs to be inspected to find the root path case Invalid:
// (can be http://example.net/review) rootPath = r.path;
ascendPath(); // Strip the last part of the path, which is always the repo name
return resolveRoot(); // 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() QStringList GerritServer::curlArguments()
@@ -165,8 +223,13 @@ int GerritServer::testConnection()
QString output = resp.stdOut(); QString output = resp.stdOut();
output.remove(0, output.indexOf('\n')); // Strip first line output.remove(0, output.indexOf('\n')); // Strip first line
QJsonDocument doc = QJsonDocument::fromJson(output.toUtf8()); QJsonDocument doc = QJsonDocument::fromJson(output.toUtf8());
if (!doc.isNull()) if (!doc.isNull()) {
user.fullName = doc.object().value("name").toString(); 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; return 200;
} }
const QRegularExpression errorRegexp("returned error: (\\d+)"); const QRegularExpression errorRegexp("returned error: (\\d+)");
@@ -182,6 +245,7 @@ bool GerritServer::setupAuthentication()
if (!dialog.exec()) if (!dialog.exec())
return false; return false;
authenticated = dialog.isAuthenticated(); authenticated = dialog.isAuthenticated();
saveSettings(Valid);
return true; return true;
} }
@@ -199,12 +263,15 @@ bool GerritServer::resolveRoot()
for (;;) { for (;;) {
switch (testConnection()) { switch (testConnection()) {
case 200: case 200:
saveSettings(Valid);
return true; return true;
case 401: case 401:
return setupAuthentication(); return setupAuthentication();
case 404: case 404:
if (!ascendPath()) if (!ascendPath()) {
saveSettings(NotGerrit);
return false; return false;
}
break; break;
default: // unknown error - fail default: // unknown error - fail
return false; return false;

View File

@@ -61,13 +61,22 @@ public:
RestUrl RestUrl
}; };
enum StoredHostValidity
{
Invalid,
NotGerrit,
Valid
};
GerritServer(); GerritServer();
GerritServer(const QString &host, unsigned short port, const QString &userName, HostType type); GerritServer(const QString &host, unsigned short port, const QString &userName, HostType type);
bool operator==(const GerritServer &other) const; bool operator==(const GerritServer &other) const;
static QString defaultHost(); static QString defaultHost();
QString hostArgument() const; QString hostArgument() const;
QString url(UrlType urlType = DefaultUrl) const; QString url(UrlType urlType = DefaultUrl) const;
bool fillFromRemote(const QString &remote, const GerritParameters &parameters); bool fillFromRemote(const QString &remote, const GerritParameters &parameters, bool forceReload);
StoredHostValidity loadSettings();
void saveSettings(StoredHostValidity validity) const;
int testConnection(); int testConnection();
static QStringList curlArguments(); static QStringList curlArguments();

View File

@@ -27,6 +27,8 @@
#include <texteditor/syntaxhighlighter.h> #include <texteditor/syntaxhighlighter.h>
#include <QRegExp>
namespace Git { namespace Git {
namespace Internal { namespace Internal {

View File

@@ -45,6 +45,7 @@
#include <QLayout> #include <QLayout>
#include <QMap> #include <QMap>
#include <QMenu> #include <QMenu>
#include <QRegExp>
#include <QString> #include <QString>
#include <QStringList> #include <QStringList>
#include <QTextBrowser> #include <QTextBrowser>

View File

@@ -34,7 +34,9 @@ HEADERS += \
iosdeploystepfactory.h \ iosdeploystepfactory.h \
iosdeploystepwidget.h \ iosdeploystepwidget.h \
iosanalyzesupport.h \ iosanalyzesupport.h \
simulatorcontrol.h simulatorcontrol.h \
iosbuildconfiguration.h \
iosbuildsettingswidget.h
SOURCES += \ SOURCES += \
@@ -63,13 +65,16 @@ SOURCES += \
iosdeploystepfactory.cpp \ iosdeploystepfactory.cpp \
iosdeploystepwidget.cpp \ iosdeploystepwidget.cpp \
iosanalyzesupport.cpp \ iosanalyzesupport.cpp \
simulatorcontrol.cpp simulatorcontrol.cpp \
iosbuildconfiguration.cpp \
iosbuildsettingswidget.cpp
FORMS += \ FORMS += \
iossettingswidget.ui \ iossettingswidget.ui \
iosbuildstep.ui \ iosbuildstep.ui \
iosdeploystepwidget.ui \ iosdeploystepwidget.ui \
iospresetbuildstep.ui iospresetbuildstep.ui \
iosbuildsettingswidget.ui
DEFINES += IOS_LIBRARY DEFINES += IOS_LIBRARY

View File

@@ -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 <memory>
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<ProjectExplorer::NamedWidget *> 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<const QmakeBuildInfo *>(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<IosBuildConfiguration *>(source);
return new IosBuildConfiguration(parent, oldbc);
}
ProjectExplorer::BuildConfiguration *IosBuildConfigurationFactory::restore(ProjectExplorer::Target *parent, const QVariantMap &map)
{
if (canRestore(parent, map)) {
std::unique_ptr<IosBuildConfiguration> bc(new IosBuildConfiguration(parent));
if (bc->fromMap(map))
return bc.release();
}
return nullptr;
}
} // namespace Internal
} // namespace Ios

View File

@@ -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<ProjectExplorer::NamedWidget *> 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

View File

@@ -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 <QLoggingCategory>
#include <QVBoxLayout>
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<void(QComboBox::*)(int)>(&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

View File

@@ -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 <QWidget>
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

View File

@@ -0,0 +1,137 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>Ios::Internal::IosBuildSettingsWidget</class>
<widget class="QWidget" name="Ios::Internal::IosBuildSettingsWidget">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>467</width>
<height>141</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<layout class="QGridLayout" name="gridLayout">
<item row="1" column="1">
<widget class="QPushButton" name="m_qmakeDefaults">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Reset</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QComboBox" name="m_signEntityCombo">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
<item row="0" column="2">
<widget class="QCheckBox" name="m_autoSignCheckbox">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Automatically manage signing</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="m_signEntityLabel">
<property name="text">
<string>Development team:</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QLabel" name="m_infoIconLabel">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string/>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="m_infoLabel">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string/>
</property>
<property name="wordWrap">
<bool>false</bool>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QLabel" name="m_warningIconLabel">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string/>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="m_warningLabel">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string/>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>

View File

@@ -32,6 +32,7 @@
#include <coreplugin/icore.h> #include <coreplugin/icore.h>
#include <utils/algorithm.h> #include <utils/algorithm.h>
#include <utils/synchronousprocess.h>
#include <utils/qtcassert.h> #include <utils/qtcassert.h>
#include <utils/synchronousprocess.h> #include <utils/synchronousprocess.h>
#include <projectexplorer/kitmanager.h> #include <projectexplorer/kitmanager.h>
@@ -49,12 +50,15 @@
#include <qtsupport/qtversionmanager.h> #include <qtsupport/qtversionmanager.h>
#include <qtsupport/qtversionfactory.h> #include <qtsupport/qtversionfactory.h>
#include <QDir>
#include <QDomDocument> #include <QDomDocument>
#include <QFileInfo> #include <QFileInfo>
#include <QFileSystemWatcher>
#include <QHash> #include <QHash>
#include <QList> #include <QList>
#include <QLoggingCategory>
#include <QProcess>
#include <QSettings> #include <QSettings>
#include <QStringList>
#include <QTimer> #include <QTimer>
using namespace ProjectExplorer; using namespace ProjectExplorer;
@@ -74,6 +78,21 @@ namespace Internal {
const QLatin1String SettingsGroup("IosConfigurations"); const QLatin1String SettingsGroup("IosConfigurations");
const QLatin1String ignoreAllDevicesKey("IgnoreAllDevices"); 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) static Core::Id deviceId(const Platform &platform)
{ {
if (platform.name.startsWith(QLatin1String("iphoneos-"))) if (platform.name.startsWith(QLatin1String("iphoneos-")))
@@ -246,6 +265,20 @@ static QVersionNumber findXcodeVersion()
return QVersionNumber(); 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() void IosConfigurations::updateAutomaticKitList()
{ {
const QList<Platform> platforms = handledPlatforms(); const QList<Platform> platforms = handledPlatforms();
@@ -320,9 +353,9 @@ void IosConfigurations::updateAutomaticKitList()
KitManager::deregisterKit(kit); KitManager::deregisterKit(kit);
} }
static IosConfigurations *m_instance = 0; static IosConfigurations *m_instance = nullptr;
QObject *IosConfigurations::instance() IosConfigurations *IosConfigurations::instance()
{ {
return m_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<QVariantMap> teams;
QMapIterator<QString, QVariant> 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<DevelopmentTeam>();
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<ProvisioningProfile>();
QString teamID;
if (provisioningDoc.setContent(decodeProvisioningProfile(fileInfo.absoluteFilePath()))) {
QDomNodeList nodes = provisioningDoc.elementsByTagName("key");
for (int i = 0;i<nodes.count(); ++i) {
QDomElement e = nodes.at(i).toElement();
if (e.text().compare(udidTag) == 0)
profile->m_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) static ClangToolChain *createToolChain(const Platform &platform, Core::Id l)
{ {
if (!l.isValid()) if (!l.isValid())
@@ -455,5 +619,52 @@ QList<ToolChain *> IosToolChainFactory::autoDetect(const QList<ToolChain *> &exi
return Utils::transform(toolChains, [](ClangToolChain *tc) -> ToolChain * { return tc; }); 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<ProvisioningProfile> profile)
{
QTC_ASSERT(profile, return stream);
return stream << profile->displayName() << profile->identifier() << profile->details();
}
} // namespace Internal } // namespace Internal
} // namespace Ios } // namespace Ios

View File

@@ -29,18 +29,72 @@
#include <projectexplorer/toolchain.h> #include <projectexplorer/toolchain.h>
#include <utils/fileutils.h> #include <utils/fileutils.h>
#include <QDateTime>
#include <QObject> #include <QObject>
#include <QString> #include <QString>
#include <QStringList> #include <QStringList>
#include <QVersionNumber> #include <QVersionNumber>
#include <memory>
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
class QSettings; class QSettings;
class QFileSystemWatcher;
QT_END_NAMESPACE QT_END_NAMESPACE
namespace Ios { namespace Ios {
namespace Internal { namespace Internal {
class DevelopmentTeam;
class ProvisioningProfile
{
Q_DECLARE_TR_FUNCTIONS(ProvisioningProfile)
public:
ProvisioningProfile() {}
std::shared_ptr<DevelopmentTeam> developmentTeam() { return m_team; }
QString identifier() const;
QString displayName() const;
QString details() const;
const QDateTime &expirationDate() const { return m_expirationDate; }
private:
std::shared_ptr<DevelopmentTeam> 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<ProvisioningProfile> profile);
};
using ProvisioningProfilePtr = std::shared_ptr<ProvisioningProfile>;
using ProvisioningProfiles = QList<ProvisioningProfilePtr>;
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<DevelopmentTeam> team);
};
using DevelopmentTeamPtr = std::shared_ptr<DevelopmentTeam>;
using DevelopmentTeams = QList<DevelopmentTeamPtr>;
class IosToolChainFactory : public ProjectExplorer::ToolChainFactory class IosToolChainFactory : public ProjectExplorer::ToolChainFactory
{ {
Q_OBJECT Q_OBJECT
@@ -50,13 +104,12 @@ public:
QList<ProjectExplorer::ToolChain *> autoDetect(const QList<ProjectExplorer::ToolChain *> &existingToolChains) override; QList<ProjectExplorer::ToolChain *> autoDetect(const QList<ProjectExplorer::ToolChain *> &existingToolChains) override;
}; };
class IosConfigurations : public QObject class IosConfigurations : public QObject
{ {
Q_OBJECT Q_OBJECT
public: public:
static QObject *instance(); static IosConfigurations *instance();
static void initialize(); static void initialize();
static bool ignoreAllDevices(); static bool ignoreAllDevices();
static void setIgnoreAllDevices(bool ignoreDevices); static void setIgnoreAllDevices(bool ignoreDevices);
@@ -64,6 +117,13 @@ public:
static QVersionNumber xcodeVersion(); static QVersionNumber xcodeVersion();
static Utils::FileName lldbPath(); static Utils::FileName lldbPath();
static void updateAutomaticKitList(); 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: private:
IosConfigurations(QObject *parent); IosConfigurations(QObject *parent);
@@ -71,11 +131,17 @@ private:
void save(); void save();
void updateSimulators(); void updateSimulators();
static void setDeveloperPath(const Utils::FileName &devPath); static void setDeveloperPath(const Utils::FileName &devPath);
void initializeProvisioningData();
void loadProvisioningData(bool notify = true);
Utils::FileName m_developerPath; Utils::FileName m_developerPath;
QVersionNumber m_xcodeVersion; QVersionNumber m_xcodeVersion;
bool m_ignoreAllDevices; bool m_ignoreAllDevices;
QFileSystemWatcher *m_provisioningDataWatcher;
ProvisioningProfiles m_provisioningProfiles;
DevelopmentTeams m_developerTeams;
}; };
QDebug &operator<<(QDebug &stream, std::shared_ptr<ProvisioningProfile> profile);
QDebug &operator<<(QDebug &stream, std::shared_ptr<DevelopmentTeam> team);
} // namespace Internal } // namespace Internal
} // namespace Ios } // namespace Ios

View File

@@ -25,6 +25,7 @@
#include "iosplugin.h" #include "iosplugin.h"
#include "iosbuildconfiguration.h"
#include "iosbuildstep.h" #include "iosbuildstep.h"
#include "iosconfigurations.h" #include "iosconfigurations.h"
#include "iosconstants.h" #include "iosconstants.h"
@@ -64,6 +65,7 @@ bool IosPlugin::initialize(const QStringList &arguments, QString *errorMessage)
Internal::IosConfigurations::initialize(); Internal::IosConfigurations::initialize();
addAutoReleasedObject(new Internal::IosBuildConfigurationFactory);
addAutoReleasedObject(new Internal::IosToolChainFactory); addAutoReleasedObject(new Internal::IosToolChainFactory);
addAutoReleasedObject(new Internal::IosRunControlFactory); addAutoReleasedObject(new Internal::IosRunControlFactory);
addAutoReleasedObject(new Internal::IosRunConfigurationFactory); addAutoReleasedObject(new Internal::IosRunConfigurationFactory);

View File

@@ -29,7 +29,6 @@ HEADERS += \
project/nimcompilerbuildstepfactory.h \ project/nimcompilerbuildstepfactory.h \
project/nimcompilercleanstepfactory.h \ project/nimcompilercleanstepfactory.h \
project/nimbuildconfigurationwidget.h \ project/nimbuildconfigurationwidget.h \
project/nimruncontrol.h \
project/nimruncontrolfactory.h \ project/nimruncontrolfactory.h \
editor/nimeditorfactory.h \ editor/nimeditorfactory.h \
settings/nimcodestylesettingspage.h \ settings/nimcodestylesettingspage.h \
@@ -59,7 +58,6 @@ SOURCES += \
project/nimcompilerbuildstepfactory.cpp \ project/nimcompilerbuildstepfactory.cpp \
project/nimcompilercleanstepfactory.cpp \ project/nimcompilercleanstepfactory.cpp \
project/nimbuildconfigurationwidget.cpp \ project/nimbuildconfigurationwidget.cpp \
project/nimruncontrol.cpp \
project/nimruncontrolfactory.cpp \ project/nimruncontrolfactory.cpp \
editor/nimeditorfactory.cpp \ editor/nimeditorfactory.cpp \
settings/nimcodestylesettingspage.cpp \ settings/nimcodestylesettingspage.cpp \

View File

@@ -49,7 +49,6 @@ QtcPlugin {
"nimrunconfiguration.h", "nimrunconfiguration.cpp", "nimrunconfiguration.h", "nimrunconfiguration.cpp",
"nimrunconfigurationfactory.h", "nimrunconfigurationfactory.cpp", "nimrunconfigurationfactory.h", "nimrunconfigurationfactory.cpp",
"nimrunconfigurationwidget.h", "nimrunconfigurationwidget.cpp", "nimrunconfigurationwidget.h", "nimrunconfigurationwidget.cpp",
"nimruncontrol.h", "nimruncontrol.cpp",
"nimruncontrolfactory.h", "nimruncontrolfactory.cpp", "nimruncontrolfactory.h", "nimruncontrolfactory.cpp",
"nimtoolchain.h", "nimtoolchain.cpp", "nimtoolchain.h", "nimtoolchain.cpp",
"nimtoolchainfactory.h", "nimtoolchainfactory.cpp", "nimtoolchainfactory.h", "nimtoolchainfactory.cpp",

View File

@@ -156,7 +156,7 @@ void NimProject::updateProject()
auto newRoot = new NimProjectNode(*this, projectDirectory()); auto newRoot = new NimProjectNode(*this, projectDirectory());
newRoot->setDisplayName(displayName()); newRoot->setDisplayName(displayName());
newRoot->buildTree(fileNodes); newRoot->addNestedNodes(fileNodes);
setRootProjectNode(newRoot); setRootProjectNode(newRoot);
emit fileListChanged(); emit fileListChanged();

View File

@@ -1,92 +0,0 @@
/****************************************************************************
**
** Copyright (C) Filippo Cucchetto <filippocucchetto@gmail.com>
** 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 <projectexplorer/runnables.h>
#include <utils/qtcprocess.h>
#include <utils/outputformat.h>
#include <QDir>
using namespace ProjectExplorer;
using namespace Utils;
namespace Nim {
NimRunControl::NimRunControl(NimRunConfiguration *rc, Core::Id mode)
: RunControl(rc, mode)
, m_runnable(rc->runnable().as<StandardRunnable>())
{
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);
}
}

View File

@@ -1,56 +0,0 @@
/****************************************************************************
**
** Copyright (C) Filippo Cucchetto <filippocucchetto@gmail.com>
** 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 <projectexplorer/runconfiguration.h>
#include <projectexplorer/runnables.h>
#include <QCoreApplication>
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;
};
}

View File

@@ -25,7 +25,6 @@
#include "nimruncontrolfactory.h" #include "nimruncontrolfactory.h"
#include "nimrunconfiguration.h" #include "nimrunconfiguration.h"
#include "nimruncontrol.h"
namespace Nim { namespace Nim {
@@ -39,7 +38,7 @@ ProjectExplorer::RunControl *NimRunControlFactory::create(ProjectExplorer::RunCo
{ {
Q_UNUSED(errorMessage) Q_UNUSED(errorMessage)
QTC_ASSERT(canRun(runConfiguration, mode), return 0); QTC_ASSERT(canRun(runConfiguration, mode), return 0);
return new NimRunControl(static_cast<NimRunConfiguration *>(runConfiguration), mode); return new ProjectExplorer::SimpleRunControl(runConfiguration, mode);
} }
} }

View File

@@ -32,6 +32,7 @@
#include <QFileInfo> #include <QFileInfo>
#include <QProcess> #include <QProcess>
#include <QRegExp>
using namespace ProjectExplorer; using namespace ProjectExplorer;
using namespace Utils; using namespace Utils;

View File

@@ -30,6 +30,7 @@
#include <QDebug> #include <QDebug>
#include <QtEndian> #include <QtEndian>
#include <QFile> #include <QFile>
#include <QRegExp>
#include <QString> #include <QString>
#include <QStringList> #include <QStringList>
#include <QSysInfo> #include <QSysInfo>

View File

@@ -455,6 +455,7 @@ ToolChain::PredefinedMacrosRunner GccToolChain::createPredefinedMacrosRunner() c
} else if (a == "-m128bit-long-double" || a == "-m32" || a == "-m3dnow" || a == "-m3dnowa" } else if (a == "-m128bit-long-double" || a == "-m32" || a == "-m3dnow" || a == "-m3dnowa"
|| a == "-m64" || a == "-m96bit-long-double" || a == "-mabm" || a == "-maes" || a == "-m64" || a == "-m96bit-long-double" || a == "-mabm" || a == "-maes"
|| a.startsWith("-march=") || a == "-mavx" || a.startsWith("-masm=") || a.startsWith("-march=") || a == "-mavx" || a.startsWith("-masm=")
|| a.startsWith("-mfloat-abi")
|| a == "-mcx16" || a == "-mfma" || a == "-mfma4" || a == "-mlwp" || a == "-mcx16" || a == "-mfma" || a == "-mfma4" || a == "-mlwp"
|| a == "-mpclmul" || a == "-mpopcnt" || a == "-msse" || a == "-msse2" || a == "-mpclmul" || a == "-mpopcnt" || a == "-msse" || a == "-msse2"
|| a == "-msse2avx" || a == "-msse3" || a == "-msse4" || a == "-msse4.1" || a == "-msse2avx" || a == "-msse3" || a == "-msse4" || a == "-msse4.1"
@@ -907,17 +908,6 @@ ToolChain *GccToolChainFactory::create(Core::Id language)
QList<ToolChain *> GccToolChainFactory::autoDetect(const QList<ToolChain *> &alreadyKnown) QList<ToolChain *> GccToolChainFactory::autoDetect(const QList<ToolChain *> &alreadyKnown)
{ {
QList<ToolChain *> tcs; QList<ToolChain *> 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, tcs.append(autoDetectToolchains("g++", Abi::hostAbi(), Constants::CXX_LANGUAGE_ID,
Constants::GCC_TOOLCHAIN_TYPEID, alreadyKnown)); Constants::GCC_TOOLCHAIN_TYPEID, alreadyKnown));
tcs.append(autoDetectToolchains("gcc", Abi::hostAbi(), Constants::C_LANGUAGE_ID, tcs.append(autoDetectToolchains("gcc", Abi::hostAbi(), Constants::C_LANGUAGE_ID,

View File

@@ -25,7 +25,6 @@
#include "localapplicationruncontrol.h" #include "localapplicationruncontrol.h"
#include "runnables.h" #include "runnables.h"
#include "environmentaspect.h"
#include <projectexplorer/projectexplorerconstants.h> #include <projectexplorer/projectexplorerconstants.h>
#include <projectexplorer/kitinformation.h> #include <projectexplorer/kitinformation.h>
@@ -34,91 +33,11 @@
#include <utils/utilsicons.h> #include <utils/utilsicons.h>
#include <utils/qtcassert.h> #include <utils/qtcassert.h>
#include <QDir>
using namespace Utils; using namespace Utils;
namespace ProjectExplorer { namespace ProjectExplorer {
namespace Internal { 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<void(RunControl::*)(const QString &, Utils::OutputFormat)>(&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<StandardRunnable>(), return);
auto r = runnable().as<StandardRunnable>();
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<StandardRunnable>().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) static bool isLocal(RunConfiguration *runConfiguration)
{ {
Target *target = runConfiguration ? runConfiguration->target() : nullptr; 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) RunControl *LocalApplicationRunControlFactory::create(RunConfiguration *runConfiguration, Core::Id mode, QString *errorMessage)
{ {
Q_UNUSED(errorMessage) Q_UNUSED(errorMessage)
return new LocalApplicationRunControl(runConfiguration, mode); return new SimpleRunControl(runConfiguration, mode);
} }
} // namespace Internal } // namespace Internal
} // namespace ProjectExplorer } // namespace ProjectExplorer
#include "localapplicationruncontrol.moc"

View File

@@ -419,7 +419,7 @@ void Project::setDocument(Core::IDocument *doc)
d->m_document = doc; d->m_document = doc;
if (!d->m_rootProjectNode) { if (!d->m_rootProjectNode) {
auto newRoot = new ProjectNode(projectDirectory()); auto newRoot = new ProjectNode(projectFilePath());
newRoot->setDisplayName(displayName()); newRoot->setDisplayName(displayName());
newRoot->addNode(new FileNode(projectFilePath(), FileType::Project, false)); newRoot->addNode(new FileNode(projectFilePath(), FileType::Project, false));
setRootProjectNode(newRoot); setRootProjectNode(newRoot);

View File

@@ -60,7 +60,8 @@ static FolderNode *folderNode(const FolderNode *folder, const Utils::FileName &d
static FolderNode *recursiveFindOrCreateFolderNode(FolderNode *folder, static FolderNode *recursiveFindOrCreateFolderNode(FolderNode *folder,
const Utils::FileName &directory, const Utils::FileName &directory,
const Utils::FileName &overrideBaseDir) const Utils::FileName &overrideBaseDir,
const FolderNode::FolderNodeFactory &factory)
{ {
Utils::FileName path = overrideBaseDir.isEmpty() ? folder->filePath() : overrideBaseDir; Utils::FileName path = overrideBaseDir.isEmpty() ? folder->filePath() : overrideBaseDir;
@@ -90,7 +91,7 @@ static FolderNode *recursiveFindOrCreateFolderNode(FolderNode *folder,
FolderNode *next = folderNode(parent, path); FolderNode *next = folderNode(parent, path);
if (!next) { if (!next) {
// No FolderNode yet, so create it // No FolderNode yet, so create it
auto tmp = new ProjectExplorer::FolderNode(path); auto tmp = factory(path);
tmp->setDisplayName(part); tmp->setDisplayName(part);
parent->addNode(tmp); parent->addNode(tmp);
next = tmp; next = tmp;
@@ -400,6 +401,37 @@ QIcon FolderNode::icon() const
return m_icon; return m_icon;
} }
Node *FolderNode::findNode(const std::function<bool(Node *)> &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<Node *> FolderNode::findNodes(const std::function<bool(Node *)> &filter)
{
QList<Node *> 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<void(FileNode *)> &fileTask, void FolderNode::forEachNode(const std::function<void(FileNode *)> &fileTask,
const std::function<void(FolderNode *)> &folderTask, const std::function<void(FolderNode *)> &folderTask,
const std::function<bool(const FolderNode *)> &folderFilterTask) const const std::function<bool(const FolderNode *)> &folderFilterTask) const
@@ -450,14 +482,6 @@ FileNode *FolderNode::fileNode(const Utils::FileName &file) const
})); }));
} }
QList<FileNode *> FolderNode::recursiveFileNodes() const
{
QList<FileNode *> result = fileNodes();
foreach (ProjectExplorer::FolderNode *folder, folderNodes())
result.append(folder->recursiveFileNodes());
return result;
}
QList<FolderNode*> FolderNode::folderNodes() const QList<FolderNode*> FolderNode::folderNodes() const
{ {
QList<FolderNode *> result; QList<FolderNode *> result;
@@ -468,16 +492,22 @@ QList<FolderNode*> FolderNode::folderNodes() const
return result; return result;
} }
void FolderNode::buildTree(QList<FileNode *> &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
// Get relative path to rootNode QString parentDir = fileNode->filePath().toFileInfo().absolutePath();
QString parentDir = fn->filePath().toFileInfo().absolutePath(); FolderNode *folder = recursiveFindOrCreateFolderNode(this, Utils::FileName::fromString(parentDir),
ProjectExplorer::FolderNode *folder overrideBaseDir, factory);
= recursiveFindOrCreateFolderNode(this, Utils::FileName::fromString(parentDir), folder->addNode(fileNode);
overrideBaseDir);
folder->addNode(fn); }
}
void FolderNode::addNestedNodes(const QList<FileNode *> &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 // "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 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 = if (Core::IVersionControl *const vc =
Core::VcsManager::findVersionControlForDirectory(dir)) Core::VcsManager::findVersionControlForDirectory(dir))

View File

@@ -192,6 +192,9 @@ public:
QString displayName() const override; QString displayName() const override;
QIcon icon() const; QIcon icon() const;
Node *findNode(const std::function<bool(Node *)> &filter);
QList<Node *> findNodes(const std::function<bool(Node *)> &filter);
void forEachNode(const std::function<void(FileNode *)> &fileTask, void forEachNode(const std::function<void(FileNode *)> &fileTask,
const std::function<void(FolderNode *)> &folderTask = {}, const std::function<void(FolderNode *)> &folderTask = {},
const std::function<bool(const FolderNode *)> &folderFilterTask = {}) const; const std::function<bool(const FolderNode *)> &folderFilterTask = {}) const;
@@ -199,9 +202,12 @@ public:
const QList<Node *> nodes() const { return m_nodes; } const QList<Node *> nodes() const { return m_nodes; }
QList<FileNode *> fileNodes() const; QList<FileNode *> fileNodes() const;
FileNode *fileNode(const Utils::FileName &file) const; FileNode *fileNode(const Utils::FileName &file) const;
QList<FileNode *> recursiveFileNodes() const;
QList<FolderNode *> folderNodes() const; QList<FolderNode *> folderNodes() const;
void buildTree(QList<FileNode *> &files, const Utils::FileName &overrideBaseDir = Utils::FileName()); using FolderNodeFactory = std::function<FolderNode *(const Utils::FileName &)>;
void addNestedNodes(const QList<FileNode *> &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(); void compress();
bool isAncesterOf(Node *n); bool isAncesterOf(Node *n);

View File

@@ -254,19 +254,6 @@ static inline AddNewTree *buildAddProjectTree(ProjectNode *root, const QString &
return new AddNewTree(root, children, root->displayName()); return new AddNewTree(root, children, root->displayName());
} }
static inline AddNewTree *buildAddProjectTree(SessionNode *root, const QString &projectPath, Node *contextNode, BestNodeSelector *selector)
{
QList<AddNewTree *> 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, static inline AddNewTree *buildAddFilesTree(FolderNode *root, const QStringList &files,
Node *contextNode, BestNodeSelector *selector) Node *contextNode, BestNodeSelector *selector)
{ {
@@ -289,31 +276,6 @@ static inline AddNewTree *buildAddFilesTree(FolderNode *root, const QStringList
return new AddNewTree(root, children, root->displayName()); return new AddNewTree(root, children, root->displayName());
} }
static inline AddNewTree *buildAddFilesTree(SessionNode *root, const QStringList &files,
Node *contextNode, BestNodeSelector *selector)
{
QList<AddNewTree *> 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: // ProjectWizardPage:
// -------------------------------------------------------------------- // --------------------------------------------------------------------
@@ -491,7 +453,25 @@ void ProjectWizardPage::initializeProjectTree(Node *context, const QStringList &
ProjectAction action) ProjectAction action)
{ {
BestNodeSelector selector(m_commonDirectory, paths); BestNodeSelector selector(m_commonDirectory, paths);
AddNewTree *tree = getChoices(paths, kind, context, &selector);
AddNewTree *tree;
SessionNode *root = SessionManager::sessionNode();
QList<AddNewTree *> 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()); setAdditionalInfo(selector.deployingProjects());

View File

@@ -32,18 +32,22 @@
#include "buildconfiguration.h" #include "buildconfiguration.h"
#include "environmentaspect.h" #include "environmentaspect.h"
#include "kitinformation.h" #include "kitinformation.h"
#include "runnables.h"
#include <extensionsystem/pluginmanager.h> #include <extensionsystem/pluginmanager.h>
#include <utils/algorithm.h> #include <utils/algorithm.h>
#include <utils/outputformatter.h>
#include <utils/checkablemessagebox.h> #include <utils/checkablemessagebox.h>
#include <utils/outputformatter.h>
#include <utils/qtcassert.h> #include <utils/qtcassert.h>
#include <utils/utilsicons.h>
#include <coreplugin/icore.h> #include <coreplugin/icore.h>
#include <coreplugin/icontext.h> #include <coreplugin/icontext.h>
#include <QTimer> #include <QDir>
#include <QPushButton> #include <QPushButton>
#include <QTimer>
#ifdef Q_OS_OSX #ifdef Q_OS_OSX
#include <ApplicationServices/ApplicationServices.h> #include <ApplicationServices/ApplicationServices.h>
@@ -785,4 +789,89 @@ bool Runnable::canReUseOutputPane(const Runnable &other) const
return d ? d->canReUseOutputPane(other.d) : (other.d.get() == 0); 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<void(RunControl::*)(const QString &, Utils::OutputFormat)>(&RunControl::appendMessage));
connect(&d->m_launcher, &ApplicationLauncher::processStarted,
this, &SimpleRunControl::onProcessStarted);
connect(&d->m_launcher, &ApplicationLauncher::processExited,
this, &SimpleRunControl::onProcessFinished);
QTC_ASSERT(runnable().is<StandardRunnable>(), return);
auto r = runnable().as<StandardRunnable>();
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<StandardRunnable>().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 } // namespace ProjectExplorer

View File

@@ -51,7 +51,10 @@ class RunConfigWidget;
class RunControl; class RunControl;
class Target; class Target;
namespace Internal { class RunControlPrivate; } namespace Internal {
class RunControlPrivate;
class SimpleRunControlPrivate;
} // Internal
/** /**
* An interface for a hunk of global or per-project * An interface for a hunk of global or per-project
@@ -414,4 +417,21 @@ private:
Internal::RunControlPrivate *d; 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 } // namespace ProjectExplorer

View File

@@ -43,6 +43,7 @@
#include <QApplication> #include <QApplication>
#include <QDir> #include <QDir>
#include <QRegExp>
using namespace Utils; using namespace Utils;

View File

@@ -225,6 +225,15 @@ QVariantMap ToolChain::toMap() const
result.insert(QLatin1String(ID_KEY), idToSave); result.insert(QLatin1String(ID_KEY), idToSave);
result.insert(QLatin1String(DISPLAY_NAME_KEY), displayName()); result.insert(QLatin1String(DISPLAY_NAME_KEY), displayName());
result.insert(QLatin1String(AUTODETECT_KEY), isAutoDetected()); result.insert(QLatin1String(AUTODETECT_KEY), isAutoDetected());
// <Compatibility with QtC 4.2>
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);
// </Compatibility>
result.insert(QLatin1String(LANGUAGE_KEY_V2), language().toSetting()); result.insert(QLatin1String(LANGUAGE_KEY_V2), language().toSetting());
return result; return result;
} }

View File

@@ -59,6 +59,7 @@
#include <QtPlugin> #include <QtPlugin>
#include <QCoreApplication> #include <QCoreApplication>
#include <QFormLayout> #include <QFormLayout>
#include <QRegExp>
using namespace Core; using namespace Core;
using namespace ProjectExplorer; using namespace ProjectExplorer;
@@ -197,6 +198,7 @@ public:
bool fromMap(const QVariantMap &map) override; bool fromMap(const QVariantMap &map) override;
bool isEnabled() const override { return m_enabled; } bool isEnabled() const override { return m_enabled; }
QString disabledReason() const override; QString disabledReason() const override;
Runnable runnable() const override;
bool supportsDebugger() const { return true; } bool supportsDebugger() const { return true; }
QString mainScript() const { return m_mainScript; } QString mainScript() const { return m_mainScript; }
@@ -215,28 +217,6 @@ private:
bool m_enabled; 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) : PythonRunConfiguration::PythonRunConfiguration(Target *parent, Core::Id id) :
@@ -307,6 +287,17 @@ QString PythonRunConfiguration::disabledReason() const
return QString(); return QString();
} }
Runnable PythonRunConfiguration::runnable() const
{
StandardRunnable r;
QtcProcess::addArg(&r.commandLineArguments, m_mainScript);
QtcProcess::addArgs(&r.commandLineArguments, extraAspect<ArgumentsAspect>()->arguments());
r.executable = m_interpreter;
r.runMode = extraAspect<TerminalAspect>()->runMode();
r.environment = extraAspect<EnvironmentAspect>()->environment();
return r;
}
QString PythonRunConfiguration::arguments() const QString PythonRunConfiguration::arguments() const
{ {
auto aspect = extraAspect<ArgumentsAspect>(); auto aspect = extraAspect<ArgumentsAspect>();
@@ -566,14 +557,11 @@ void PythonProject::refresh()
parseProject(); parseProject();
QDir baseDir(projectDirectory().toString()); QDir baseDir(projectDirectory().toString());
QList<FileNode *> 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); 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); setRootProjectNode(newRoot);
emit parsingFinished(); emit parsingFinished();
@@ -732,95 +720,18 @@ public:
bool PythonRunControlFactory::canRun(RunConfiguration *runConfiguration, Core::Id mode) const bool PythonRunControlFactory::canRun(RunConfiguration *runConfiguration, Core::Id mode) const
{ {
return mode == ProjectExplorer::Constants::NORMAL_RUN_MODE auto rc = dynamic_cast<PythonRunConfiguration *>(runConfiguration);
&& dynamic_cast<PythonRunConfiguration *>(runConfiguration); return mode == ProjectExplorer::Constants::NORMAL_RUN_MODE && rc && !rc->interpreter().isEmpty();
} }
RunControl *PythonRunControlFactory::create(RunConfiguration *runConfiguration, Core::Id mode, QString *errorMessage) RunControl *PythonRunControlFactory::create(RunConfiguration *runConfiguration, Core::Id mode, QString *errorMessage)
{ {
Q_UNUSED(errorMessage) Q_UNUSED(errorMessage)
QTC_ASSERT(canRun(runConfiguration, mode), return 0); QTC_ASSERT(canRun(runConfiguration, mode), return 0);
return new PythonRunControl(static_cast<PythonRunConfiguration *>(runConfiguration), mode); return new SimpleRunControl(runConfiguration, mode);
} }
// PythonRunControl // PythonRunConfigurationWidget
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<TerminalAspect>()->runMode();
m_commandLineArguments = rc->extraAspect<ArgumentsAspect>()->arguments();
m_environment = rc->extraAspect<EnvironmentAspect>()->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();
}
void PythonRunConfigurationWidget::setInterpreter(const QString &interpreter) void PythonRunConfigurationWidget::setInterpreter(const QString &interpreter)
{ {

View File

@@ -55,15 +55,13 @@ ProjectExplorer::FileType fileType(const qbs::ArtifactData &artifact)
void setupArtifacts(ProjectExplorer::FolderNode *root, const QList<qbs::ArtifactData> &artifacts) void setupArtifacts(ProjectExplorer::FolderNode *root, const QList<qbs::ArtifactData> &artifacts)
{ {
QList<ProjectExplorer::FileNode *> fileNodes for (const qbs::ArtifactData &ad : artifacts) {
= Utils::transform(artifacts, [](const qbs::ArtifactData &ad) {
const Utils::FileName path = Utils::FileName::fromString(ad.filePath()); const Utils::FileName path = Utils::FileName::fromString(ad.filePath());
const ProjectExplorer::FileType type = fileType(ad); const ProjectExplorer::FileType type = fileType(ad);
const bool isGenerated = ad.isGenerated(); 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(); root->compress();
} }
@@ -190,14 +188,12 @@ QbsRootProjectNode *QbsNodeTreeBuilder::buildTree(QbsProject *project)
ProjectExplorer::NodeType::Folder, ProjectExplorer::NodeType::Folder,
QCoreApplication::translate("QbsRootProjectNode", "Qbs files")); QCoreApplication::translate("QbsRootProjectNode", "Qbs files"));
QList<ProjectExplorer::FileNode *> projectBuildSystemFiles;
Utils::FileName base = project->projectDirectory(); Utils::FileName base = project->projectDirectory();
for (const QString &f : unreferencedBuildSystemFiles(project->qbsProject())) { for (const QString &f : unreferencedBuildSystemFiles(project->qbsProject())) {
const Utils::FileName filePath = Utils::FileName::fromString(f); const Utils::FileName filePath = Utils::FileName::fromString(f);
if (filePath.isChildOf(base)) 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(); buildSystemFiles->compress();
root->addNode(buildSystemFiles); root->addNode(buildSystemFiles);

View File

@@ -996,6 +996,7 @@ void QbsProject::updateCppCodeModel()
rpp.setDisplayName(grp.name()); rpp.setDisplayName(grp.name());
rpp.setProjectFileLocation(grp.location().filePath(), rpp.setProjectFileLocation(grp.location().filePath(),
grp.location().line(), grp.location().column()); grp.location().line(), grp.location().column());
rpp.setBuildSystemTarget(uniqueProductName(prd));
QHash<QString, qbs::ArtifactData> filePathToSourceArtifact; QHash<QString, qbs::ArtifactData> filePathToSourceArtifact;
bool hasCFiles = false; bool hasCFiles = false;

View File

@@ -33,6 +33,7 @@
#include <QFileInfo> #include <QFileInfo>
#include <QDir> #include <QDir>
#include <QRegExp>
#include <QSet> #include <QSet>
static QString headerGuard(const QString &header) static QString headerGuard(const QString &header)

View File

@@ -32,6 +32,7 @@
#include <QDebug> #include <QDebug>
#include <QDir> #include <QDir>
#include <QFileInfo> #include <QFileInfo>
#include <QRegExp>
#include <QTextStream> #include <QTextStream>
#include <QLoggingCategory> #include <QLoggingCategory>

View File

@@ -172,10 +172,8 @@ static void createTree(const QmakePriFile *pri, QmakePriFileNode *node)
vfolder->addNode(resourceNode); vfolder->addNode(resourceNode);
} }
} else { } else {
QList<FileNode *> fileNodes = Utils::transform<QList>(newFilePaths, [type](const FileName &fn) { for (const FileName &fn : newFilePaths)
return new FileNode(fn, type, false); vfolder->addNestedNode(new FileNode(fn, type, false));
});
vfolder->buildTree(fileNodes);
for (FolderNode *fn : vfolder->folderNodes()) for (FolderNode *fn : vfolder->folderNodes())
fn->compress(); fn->compress();
} }

View File

@@ -345,6 +345,7 @@ void QmakeProject::updateCppCodeModel()
CppTools::RawProjectPart rpp; CppTools::RawProjectPart rpp;
rpp.setDisplayName(pro->displayName()); rpp.setDisplayName(pro->displayName());
rpp.setProjectFileLocation(pro->filePath().toString()); rpp.setProjectFileLocation(pro->filePath().toString());
rpp.setBuildSystemTarget(pro->targetInformation().target);
// TODO: Handle QMAKE_CFLAGS // TODO: Handle QMAKE_CFLAGS
rpp.setFlagsForCxx({cxxToolChain, pro->variableValue(Variable::CppFlags)}); rpp.setFlagsForCxx({cxxToolChain, pro->variableValue(Variable::CppFlags)});
rpp.setDefines(pro->cxxDefines()); rpp.setDefines(pro->cxxDefines());

Some files were not shown because too many files have changed in this diff Show More