forked from qt-creator/qt-creator
Merge remote-tracking branch 'origin/4.3'
Change-Id: Ib0dc9fe5d7c507eb7330f61daedc945a4308292d
This commit is contained in:
@@ -133,7 +133,8 @@ my %next = ();
|
||||
my $last = $doctitle;
|
||||
my $lastpage = $title2page{$last};
|
||||
for my $title (@toc) {
|
||||
my $page = $title2page{$title};
|
||||
my $type = $title2type{$title};
|
||||
my $page = ($type eq "page") ? $title2page{$title} : "{$title}\n";
|
||||
defined($page) or die "TOC refers to unknown page/example '$title'.\n";
|
||||
$next{$last} = $page;
|
||||
$prev{$title} = $lastpage;
|
||||
|
||||
@@ -286,8 +286,6 @@ class DumperBase:
|
||||
'personaltypes',
|
||||
]
|
||||
|
||||
self.currentQtNamespaceGuess = None
|
||||
|
||||
# These values are never used, but the variables need to have
|
||||
# some value base for the swapping logic in Children.__enter__()
|
||||
# and Children.__exit__().
|
||||
@@ -324,11 +322,6 @@ class DumperBase:
|
||||
#warn('EXPANDED INAMES: %s' % self.expandedINames)
|
||||
#warn('WATCHERS: %s' % self.watchers)
|
||||
|
||||
# The guess does not need to be updated during a fetchVariables()
|
||||
# as the result is fixed during that time (ignoring "active"
|
||||
# dumpers causing loading of shared objects etc).
|
||||
self.currentQtNamespaceGuess = None
|
||||
|
||||
def resetCaches(self):
|
||||
# This is a cache mapping from 'type name' to 'display alternatives'.
|
||||
self.qqFormats = { 'QVariant (QVariantMap)' : mapForms() }
|
||||
|
||||
@@ -959,10 +959,8 @@ class Dumper(DumperBase):
|
||||
self.importPlainDumper(printer)
|
||||
|
||||
def qtNamespace(self):
|
||||
self.preping('qtNamespace')
|
||||
res = self.qtNamespaceX()
|
||||
self.ping('qtNamespace')
|
||||
return res
|
||||
# This function is replaced by handleQtCoreLoaded()
|
||||
return ''
|
||||
|
||||
def findSymbol(self, symbolName):
|
||||
try:
|
||||
@@ -970,17 +968,23 @@ class Dumper(DumperBase):
|
||||
except:
|
||||
return 0
|
||||
|
||||
def qtNamespaceX(self):
|
||||
if not self.currentQtNamespaceGuess is None:
|
||||
return self.currentQtNamespaceGuess
|
||||
|
||||
for objfile in gdb.objfiles():
|
||||
def handleNewObjectFile(self, objfile):
|
||||
name = objfile.filename
|
||||
if name.find('/libQt5Core') >= 0:
|
||||
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)
|
||||
|
||||
def handleQtCoreLoaded(self, objfile):
|
||||
fd, tmppath = tempfile.mkstemp()
|
||||
os.close(fd)
|
||||
cmd = 'maint print msymbols %s "%s"' % (tmppath, name)
|
||||
cmd = 'maint print msymbols %s "%s"' % (tmppath, objfile.filename)
|
||||
try:
|
||||
symbols = gdb.execute(cmd, to_string = True)
|
||||
except:
|
||||
pass
|
||||
ns = ''
|
||||
with open(tmppath) as f:
|
||||
for line in f:
|
||||
@@ -997,6 +1001,12 @@ class Dumper(DumperBase):
|
||||
strns = ('%d%s' % (lenns - 2, ns[:lenns - 2])) if lenns else ''
|
||||
|
||||
if lenns:
|
||||
# This might be wrong, but we can't do better: We found
|
||||
# a libQt5Core and could not extract a namespace.
|
||||
# The best guess is that there isn't any.
|
||||
self.qtNamespaceToReport = ns
|
||||
self.qtNamespace = lambda: ns
|
||||
|
||||
sym = '_ZN%s7QObject11customEventEPNS_6QEventE' % strns
|
||||
else:
|
||||
sym = '_ZN7QObject11customEventEP6QEvent'
|
||||
@@ -1008,16 +1018,6 @@ class Dumper(DumperBase):
|
||||
sym = '_ZNK%s7QObject8propertyEPKc' % strns
|
||||
self.qtPropertyFunc = self.findSymbol(sym)
|
||||
|
||||
# This might be wrong, but we can't do better: We found
|
||||
# a libQt5Core and could not extract a namespace.
|
||||
# The best guess is that there isn't any.
|
||||
self.qtNamespaceToReport = ns
|
||||
self.qtNamespace = lambda: ns
|
||||
return ns
|
||||
|
||||
self.currentQtNamespaceGuess = ''
|
||||
return ''
|
||||
|
||||
def assignValue(self, args):
|
||||
typeName = self.hexdecode(args['type'])
|
||||
expr = self.hexdecode(args['expr'])
|
||||
@@ -1406,4 +1406,17 @@ class InterpreterMessageBreakpoint(gdb.Breakpoint):
|
||||
print('Interpreter event received.')
|
||||
return theDumper.handleInterpreterMessage()
|
||||
|
||||
|
||||
#######################################################################
|
||||
#
|
||||
# Shared objects
|
||||
#
|
||||
#######################################################################
|
||||
|
||||
def new_objfile_handler(event):
|
||||
return theDumper.handleNewObjectFile(event.new_objfile)
|
||||
|
||||
gdb.events.new_objfile.connect(new_objfile_handler)
|
||||
|
||||
|
||||
#InterpreterMessageBreakpoint()
|
||||
|
||||
@@ -565,11 +565,6 @@ void ClassItem::updateMembers(const Style *style)
|
||||
auto dclass = dynamic_cast<DClass *>(object());
|
||||
QMT_CHECK(dclass);
|
||||
|
||||
// TODO move bool haveIconFonts into class Style?
|
||||
bool haveIconFonts = false; // style->normalFont().family() == QStringLiteral("Modelling");
|
||||
// TODO any reason to show visibility as group instead of per member?
|
||||
bool useGroupVisibility = false;
|
||||
|
||||
foreach (const MClassMember &member, dclass->members()) {
|
||||
switch (member.memberType()) {
|
||||
case MClassMember::MemberUndefined:
|
||||
@@ -587,50 +582,14 @@ void ClassItem::updateMembers(const Style *style)
|
||||
break;
|
||||
}
|
||||
|
||||
if (!text->isEmpty())
|
||||
if (text && !text->isEmpty())
|
||||
*text += QStringLiteral("<br/>");
|
||||
|
||||
bool addNewline = false;
|
||||
bool addSpace = false;
|
||||
if (member.visibility() != *currentVisibility) {
|
||||
if (useGroupVisibility) {
|
||||
if (member.visibility() != MClassMember::VisibilityUndefined) {
|
||||
QString vis;
|
||||
switch (member.visibility()) {
|
||||
case MClassMember::VisibilityUndefined:
|
||||
break;
|
||||
case MClassMember::VisibilityPublic:
|
||||
vis = QStringLiteral("public:");
|
||||
break;
|
||||
case MClassMember::VisibilityProtected:
|
||||
vis = QStringLiteral("protected:");
|
||||
break;
|
||||
case MClassMember::VisibilityPrivate:
|
||||
vis = QStringLiteral("private:");
|
||||
break;
|
||||
case MClassMember::VisibilitySignals:
|
||||
vis = QStringLiteral("signals:");
|
||||
break;
|
||||
case MClassMember::VisibilityPrivateSlots:
|
||||
vis = QStringLiteral("private slots:");
|
||||
break;
|
||||
case MClassMember::VisibilityProtectedSlots:
|
||||
vis = QStringLiteral("protected slots:");
|
||||
break;
|
||||
case MClassMember::VisibilityPublicSlots:
|
||||
vis = QStringLiteral("public slots:");
|
||||
break;
|
||||
}
|
||||
*text += vis;
|
||||
addNewline = true;
|
||||
addSpace = true;
|
||||
}
|
||||
}
|
||||
if (currentVisibility)
|
||||
*currentVisibility = member.visibility();
|
||||
}
|
||||
if (member.group() != currentGroup) {
|
||||
if (addSpace)
|
||||
*text += QStringLiteral(" ");
|
||||
*text += QString(QStringLiteral("[%1]")).arg(member.group());
|
||||
addNewline = true;
|
||||
*currentGroup = member.group();
|
||||
@@ -638,61 +597,55 @@ void ClassItem::updateMembers(const Style *style)
|
||||
if (addNewline)
|
||||
*text += QStringLiteral("<br/>");
|
||||
|
||||
addSpace = false;
|
||||
bool haveSignal = false;
|
||||
bool haveSlot = false;
|
||||
if (!useGroupVisibility) {
|
||||
if (member.visibility() != MClassMember::VisibilityUndefined) {
|
||||
QString vis;
|
||||
switch (member.visibility()) {
|
||||
case MClassMember::VisibilityUndefined:
|
||||
break;
|
||||
case MClassMember::VisibilityPublic:
|
||||
vis = haveIconFonts ? QString(QChar(0xe990)) : QStringLiteral("+");
|
||||
vis = QStringLiteral("+");
|
||||
addSpace = true;
|
||||
break;
|
||||
case MClassMember::VisibilityProtected:
|
||||
vis = haveIconFonts ? QString(QChar(0xe98e)) : QStringLiteral("#");
|
||||
vis = QStringLiteral("#");
|
||||
addSpace = true;
|
||||
break;
|
||||
case MClassMember::VisibilityPrivate:
|
||||
vis = haveIconFonts ? QString(QChar(0xe98f)) : QStringLiteral("-");
|
||||
vis = QStringLiteral("-");
|
||||
addSpace = true;
|
||||
break;
|
||||
case MClassMember::VisibilitySignals:
|
||||
vis = haveIconFonts ? QString(QChar(0xe994)) : QStringLiteral(">");
|
||||
vis = QStringLiteral(">");
|
||||
haveSignal = true;
|
||||
addSpace = true;
|
||||
break;
|
||||
case MClassMember::VisibilityPrivateSlots:
|
||||
vis = haveIconFonts ? QString(QChar(0xe98f)) + QChar(0xe9cb)
|
||||
: QStringLiteral("-$");
|
||||
vis = QStringLiteral("-$");
|
||||
haveSlot = true;
|
||||
addSpace = true;
|
||||
break;
|
||||
case MClassMember::VisibilityProtectedSlots:
|
||||
vis = haveIconFonts ? QString(QChar(0xe98e)) + QChar(0xe9cb)
|
||||
: QStringLiteral("#$");
|
||||
vis = QStringLiteral("#$");
|
||||
haveSlot = true;
|
||||
addSpace = true;
|
||||
break;
|
||||
case MClassMember::VisibilityPublicSlots:
|
||||
vis = haveIconFonts ? QString(QChar(0xe990)) + QChar(0xe9cb)
|
||||
: QStringLiteral("+$");
|
||||
vis = QStringLiteral("+$");
|
||||
haveSlot = true;
|
||||
addSpace = true;
|
||||
break;
|
||||
}
|
||||
*text += vis;
|
||||
}
|
||||
}
|
||||
|
||||
if (member.properties() & MClassMember::PropertyQsignal && !haveSignal) {
|
||||
*text += haveIconFonts ? QString(QChar(0xe994)) : QStringLiteral(">");
|
||||
*text += QStringLiteral(">");
|
||||
addSpace = true;
|
||||
}
|
||||
if (member.properties() & MClassMember::PropertyQslot && !haveSlot) {
|
||||
*text += haveIconFonts ? QString(QChar(0xe9cb)) : QStringLiteral("$");
|
||||
*text += QStringLiteral("$");
|
||||
addSpace = true;
|
||||
}
|
||||
if (addSpace)
|
||||
|
||||
@@ -63,7 +63,7 @@ static inline int classify2(const QChar *s, bool qmlMode) {
|
||||
}
|
||||
else if (qmlMode && s[0].unicode() == 'o') {
|
||||
if (s[1].unicode() == 'n') {
|
||||
return qmlMode ? Lexer::T_ON : Lexer::T_IDENTIFIER;
|
||||
return Lexer::T_ON;
|
||||
}
|
||||
}
|
||||
return Lexer::T_IDENTIFIER;
|
||||
@@ -675,7 +675,7 @@ static inline int classify8(const QChar *s, bool qmlMode) {
|
||||
if (s[5].unicode() == 'r') {
|
||||
if (s[6].unicode() == 't') {
|
||||
if (s[7].unicode() == 'y') {
|
||||
return qmlMode ? Lexer::T_PROPERTY : Lexer::T_IDENTIFIER;
|
||||
return Lexer::T_PROPERTY;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,6 +33,7 @@
|
||||
|
||||
#include <QColor>
|
||||
#include <QDir>
|
||||
#include <QRegExp>
|
||||
|
||||
using namespace QmlJS;
|
||||
using namespace QmlJS::AST;
|
||||
|
||||
@@ -35,6 +35,7 @@
|
||||
#include <QCryptographicHash>
|
||||
#include <QDir>
|
||||
#include <QFileInfo>
|
||||
#include <QRegExp>
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
|
||||
@@ -34,6 +34,7 @@
|
||||
#include <utils/qtcassert.h>
|
||||
|
||||
#include <QList>
|
||||
#include <QRegExp>
|
||||
|
||||
//using namespace QmlJS;
|
||||
|
||||
|
||||
@@ -579,7 +579,7 @@ void ModelManagerInterface::updateProjectInfo(const ProjectInfo &pinfo, ProjectE
|
||||
&majorVersion, &minorVersion, &patchVersion) != 3)
|
||||
majorVersion = minorVersion = patchVersion = -1;
|
||||
|
||||
if (majorVersion > 4 || (majorVersion == 4 && (minorVersion > 8 || (majorVersion == 8
|
||||
if (majorVersion > 4 || (majorVersion == 4 && (minorVersion > 8 || (minorVersion == 8
|
||||
&& patchVersion >= 5)))) {
|
||||
m_pluginDumper->loadBuiltinTypes(pinfo);
|
||||
}
|
||||
|
||||
@@ -29,6 +29,8 @@
|
||||
#include "qmljsmodelmanagerinterface.h"
|
||||
#include "parser/qmljsengine_p.h"
|
||||
|
||||
#include <QRegExp>
|
||||
|
||||
using namespace QmlJS;
|
||||
|
||||
/*!
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
#include <QDir>
|
||||
#include <QDateTime>
|
||||
#include <QDebug>
|
||||
#include <QRegExp>
|
||||
|
||||
namespace Utils {
|
||||
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
#include <QDragEnterEvent>
|
||||
#include <QDropEvent>
|
||||
#include <QMessageBox>
|
||||
#include <QRegExp>
|
||||
#include <QTimer>
|
||||
#include <QUrl>
|
||||
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
#include <QDir>
|
||||
#include <QDebug>
|
||||
#include <QCoreApplication>
|
||||
#include <QRegExp>
|
||||
#include <QStack>
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
#include "qtcassert.h"
|
||||
|
||||
#include <QJSEngine>
|
||||
#include <QRegExp>
|
||||
#include <QStack>
|
||||
|
||||
namespace Utils {
|
||||
|
||||
@@ -56,6 +56,7 @@
|
||||
#include <QFileSystemWatcher>
|
||||
#include <QList>
|
||||
#include <QProcess>
|
||||
#include <QRegExp>
|
||||
#include <QMessageBox>
|
||||
#include <QApplication>
|
||||
#include <QDomDocument>
|
||||
|
||||
@@ -47,6 +47,7 @@
|
||||
#include <memory>
|
||||
#include <QApplication>
|
||||
#include <QDir>
|
||||
#include <QRegExp>
|
||||
#include <QTime>
|
||||
#include <QTcpServer>
|
||||
#include <QTcpSocket>
|
||||
|
||||
@@ -45,6 +45,7 @@
|
||||
#include <QDirIterator>
|
||||
#include <QFormLayout>
|
||||
#include <QLabel>
|
||||
#include <QRegExp>
|
||||
#include <QVBoxLayout>
|
||||
|
||||
namespace {
|
||||
|
||||
@@ -28,6 +28,8 @@
|
||||
#include <projectexplorer/ioutputparser.h>
|
||||
#include <utils/fileutils.h>
|
||||
|
||||
#include <QRegExp>
|
||||
|
||||
namespace Android {
|
||||
namespace Internal {
|
||||
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
|
||||
#include <QDir>
|
||||
#include <QFileInfo>
|
||||
#include <QRegExp>
|
||||
|
||||
namespace Autotest {
|
||||
namespace Internal {
|
||||
|
||||
@@ -165,7 +165,6 @@ static QList<QmlJS::Document::Ptr> scanDirectoryForQuickTestQmlFiles(const QStri
|
||||
}
|
||||
|
||||
static bool checkQmlDocumentForQuickTestCode(QFutureInterface<TestParseResultPtr> futureInterface,
|
||||
const QmlJS::Snapshot &snapshot,
|
||||
const QmlJS::Document::Ptr &qmlJSDoc,
|
||||
const Core::Id &id,
|
||||
const QString &proFile = QString())
|
||||
@@ -174,6 +173,7 @@ static bool checkQmlDocumentForQuickTestCode(QFutureInterface<TestParseResultPtr
|
||||
return false;
|
||||
QmlJS::AST::Node *ast = qmlJSDoc->ast();
|
||||
QTC_ASSERT(ast, return false);
|
||||
QmlJS::Snapshot snapshot = QmlJS::ModelManagerInterface::instance()->snapshot();
|
||||
TestQmlVisitor qmlVisitor(qmlJSDoc, snapshot);
|
||||
QmlJS::AST::Node::accept(ast, &qmlVisitor);
|
||||
if (!qmlVisitor.isValid())
|
||||
@@ -212,7 +212,6 @@ static bool checkQmlDocumentForQuickTestCode(QFutureInterface<TestParseResultPtr
|
||||
}
|
||||
|
||||
static bool handleQtQuickTest(QFutureInterface<TestParseResultPtr> futureInterface,
|
||||
const QmlJS::Snapshot &snapshot,
|
||||
CPlusPlus::Document::Ptr document,
|
||||
const Core::Id &id)
|
||||
{
|
||||
@@ -233,7 +232,7 @@ static bool handleQtQuickTest(QFutureInterface<TestParseResultPtr> futureInterfa
|
||||
const QList<QmlJS::Document::Ptr> qmlDocs = scanDirectoryForQuickTestQmlFiles(srcDir);
|
||||
bool result = false;
|
||||
for (const QmlJS::Document::Ptr &qmlJSDoc : qmlDocs)
|
||||
result |= checkQmlDocumentForQuickTestCode(futureInterface, snapshot, qmlJSDoc, id, proFile);
|
||||
result |= checkQmlDocumentForQuickTestCode(futureInterface, qmlJSDoc, id, proFile);
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -280,14 +279,14 @@ bool QuickTestParser::processDocument(QFutureInterface<TestParseResultPtr> futur
|
||||
if (proFile.isEmpty())
|
||||
return false;
|
||||
QmlJS::Document::Ptr qmlJSDoc = m_qmlSnapshot.document(fileName);
|
||||
return checkQmlDocumentForQuickTestCode(futureInterface, m_qmlSnapshot, qmlJSDoc, id(), proFile);
|
||||
return checkQmlDocumentForQuickTestCode(futureInterface, qmlJSDoc, id(), proFile);
|
||||
}
|
||||
if (!m_cppSnapshot.contains(fileName) || !selectedForBuilding(fileName))
|
||||
return false;
|
||||
CPlusPlus::Document::Ptr document = m_cppSnapshot.find(fileName).value();
|
||||
if (!includesQtQuickTest(document, m_cppSnapshot))
|
||||
return false;
|
||||
return handleQtQuickTest(futureInterface, m_qmlSnapshot, document, id());
|
||||
return handleQtQuickTest(futureInterface, document, id());
|
||||
}
|
||||
|
||||
} // namespace Internal
|
||||
|
||||
@@ -166,11 +166,11 @@ static void performTestRun(QFutureInterface<TestResultPtr> &futureInterface,
|
||||
}
|
||||
} else {
|
||||
futureInterface.reportResult(TestResultPtr(new FaultyTestResult(Result::MessageFatal,
|
||||
QString("Failed to start test for project \"%1\".").arg(testConfiguration->displayName()))));
|
||||
TestRunner::tr("Failed to start test for project \"%1\".").arg(testConfiguration->displayName()))));
|
||||
}
|
||||
if (testProcess.exitStatus() == QProcess::CrashExit) {
|
||||
futureInterface.reportResult(TestResultPtr(new FaultyTestResult(Result::MessageFatal,
|
||||
QString("Test for project \"%1\" crashed.").arg(testConfiguration->displayName()))));
|
||||
TestRunner::tr("Test for project \"%1\" crashed.").arg(testConfiguration->displayName()))));
|
||||
}
|
||||
|
||||
if (canceledByTimeout) {
|
||||
|
||||
@@ -215,16 +215,12 @@ void AutotoolsProject::makefileParsingFinished()
|
||||
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());
|
||||
newRoot->buildTree(fileNodes);
|
||||
for (const QString &f : files) {
|
||||
const Utils::FileName path = Utils::FileName::fromString(dir.absoluteFilePath(f));
|
||||
FileType ft = (f == "Makefile.am" || f == "configure.ac") ? FileType::Project : FileType::Resource;
|
||||
newRoot->addNestedNode(new FileNode(path, ft, false));
|
||||
}
|
||||
setRootProjectNode(newRoot);
|
||||
|
||||
updateCppCodeModel();
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
|
||||
#include <QDir>
|
||||
#include <QFileInfo>
|
||||
#include <QRegExp>
|
||||
#include <QTextStream>
|
||||
#include <QDebug>
|
||||
|
||||
|
||||
@@ -189,9 +189,6 @@ public:
|
||||
optionsBuilder.addPrecompiledHeaderOptions(pchUsage);
|
||||
optionsBuilder.addMsvcCompatibilityVersion();
|
||||
|
||||
if (type != ProjectExplorer::Constants::MSVC_TOOLCHAIN_TYPEID)
|
||||
optionsBuilder.add(QLatin1String("-fPIC")); // TODO: Remove?
|
||||
|
||||
return optionsBuilder.options();
|
||||
}
|
||||
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
#include <QDir>
|
||||
#include <QFutureInterface>
|
||||
#include <QProcess>
|
||||
#include <QRegExp>
|
||||
#include <QStringList>
|
||||
#include <utils/qtcassert.h>
|
||||
|
||||
|
||||
@@ -24,43 +24,26 @@
|
||||
****************************************************************************/
|
||||
|
||||
#include "builddirmanager.h"
|
||||
|
||||
#include "cmakebuildconfiguration.h"
|
||||
#include "cmakekitinformation.h"
|
||||
#include "cmakeparser.h"
|
||||
#include "cmakeprojectconstants.h"
|
||||
#include "cmakeprojectmanager.h"
|
||||
#include "cmakeprojectnodes.h"
|
||||
#include "cmaketool.h"
|
||||
|
||||
#include <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/kitinformation.h>
|
||||
#include <projectexplorer/project.h>
|
||||
#include <projectexplorer/projectexplorerconstants.h>
|
||||
#include <projectexplorer/projectnodes.h>
|
||||
#include <projectexplorer/target.h>
|
||||
#include <projectexplorer/taskhub.h>
|
||||
#include <projectexplorer/toolchain.h>
|
||||
|
||||
#include <utils/algorithm.h>
|
||||
#include <utils/fileutils.h>
|
||||
#include <utils/mimetypes/mimedatabase.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 <QRegularExpression>
|
||||
#include <QSet>
|
||||
|
||||
using namespace ProjectExplorer;
|
||||
@@ -274,7 +257,7 @@ bool BuildDirManager::persistCMakeState()
|
||||
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);
|
||||
|
||||
|
||||
@@ -69,7 +69,7 @@ public:
|
||||
bool updateCMakeStateBeforeBuild();
|
||||
bool persistCMakeState();
|
||||
|
||||
void generateProjectTree(CMakeListsNode *root,
|
||||
void generateProjectTree(CMakeProjectNode *root,
|
||||
const QList<const ProjectExplorer::FileNode *> &allFiles);
|
||||
void updateCodeModel(CppTools::RawProjectParts &rpps);
|
||||
|
||||
|
||||
@@ -42,7 +42,7 @@ namespace CMakeProjectManager {
|
||||
namespace Internal {
|
||||
|
||||
class CMakeBuildConfiguration;
|
||||
class CMakeListsNode;
|
||||
class CMakeProjectNode;
|
||||
|
||||
class BuildDirReader : public QObject
|
||||
{
|
||||
@@ -95,7 +95,7 @@ public:
|
||||
|
||||
virtual CMakeConfig takeParsedConfiguration() = 0;
|
||||
virtual QList<CMakeBuildTarget> buildTargets() const = 0;
|
||||
virtual void generateProjectTree(CMakeListsNode *root,
|
||||
virtual void generateProjectTree(CMakeProjectNode *root,
|
||||
const QList<const ProjectExplorer::FileNode *> &allFiles) = 0;
|
||||
virtual void updateCodeModel(CppTools::RawProjectParts &rpps) = 0;
|
||||
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
|
||||
#include "cmakeautocompleter.h"
|
||||
|
||||
#include <QRegExp>
|
||||
#include <QTextCursor>
|
||||
#include <QTextBlock>
|
||||
#include <QDebug>
|
||||
|
||||
@@ -215,13 +215,13 @@ QList<CMakeBuildTarget> CMakeBuildConfiguration::buildTargets() const
|
||||
return m_buildDirManager->buildTargets();
|
||||
}
|
||||
|
||||
CMakeListsNode *
|
||||
CMakeProjectNode *
|
||||
CMakeBuildConfiguration::generateProjectTree(const QList<const FileNode*> &allFiles) const
|
||||
{
|
||||
auto root = new CMakeListsNode(target()->project()->projectFilePath());
|
||||
if (!m_buildDirManager || m_buildDirManager->isParsing())
|
||||
return nullptr;
|
||||
|
||||
auto root = new CMakeProjectNode(target()->project()->projectDirectory());
|
||||
m_buildDirManager->generateProjectTree(root, allFiles);
|
||||
return root;
|
||||
}
|
||||
|
||||
@@ -47,7 +47,7 @@ namespace Internal {
|
||||
class BuildDirManager;
|
||||
class CMakeBuildConfigurationFactory;
|
||||
class CMakeBuildSettingsWidget;
|
||||
class CMakeListsNode;
|
||||
class CMakeProjectNode;
|
||||
|
||||
class CMakeBuildConfiguration : public ProjectExplorer::BuildConfiguration
|
||||
{
|
||||
@@ -86,7 +86,7 @@ public:
|
||||
void clearCache();
|
||||
|
||||
QList<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);
|
||||
|
||||
static Utils::FileName
|
||||
|
||||
@@ -27,6 +27,8 @@
|
||||
|
||||
#include <projectexplorer/abstractprocessstep.h>
|
||||
|
||||
#include <QRegExp>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
class QLineEdit;
|
||||
class QListWidget;
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
#include <projectexplorer/ioutputparser.h>
|
||||
#include <projectexplorer/task.h>
|
||||
|
||||
#include <QRegExp>
|
||||
#include <QRegularExpression>
|
||||
|
||||
namespace CMakeProjectManager {
|
||||
|
||||
@@ -309,21 +309,15 @@ QString CMakeProject::displayName() const
|
||||
|
||||
QStringList CMakeProject::files(FilesMode fileMode) const
|
||||
{
|
||||
const QList<FileNode *> nodes = filtered(rootProjectNode()->recursiveFileNodes(),
|
||||
[fileMode](const FileNode *fn) {
|
||||
QStringList result;
|
||||
rootProjectNode()->forEachNode([&](const FileNode *fn) {
|
||||
const bool isGenerated = fn->isGenerated();
|
||||
switch (fileMode)
|
||||
{
|
||||
case Project::SourceFiles:
|
||||
return !isGenerated;
|
||||
case Project::GeneratedFiles:
|
||||
return isGenerated;
|
||||
case Project::AllFiles:
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
if (fileMode == Project::SourceFiles && !isGenerated)
|
||||
result.append(fn->filePath().toString());
|
||||
if (fileMode == Project::GeneratedFiles && isGenerated)
|
||||
result.append(fn->filePath().toString());
|
||||
});
|
||||
return transform(nodes, [fileMode](const FileNode* fn) { return fn->filePath().toString(); });
|
||||
return result;
|
||||
}
|
||||
|
||||
Project::RestoreResult CMakeProject::fromMap(const QVariantMap &map, QString *errorMessage)
|
||||
|
||||
@@ -95,6 +95,8 @@ void ServerModeReader::setParameters(const BuildDirReader::Parameters &p)
|
||||
this, &ServerModeReader::handleError);
|
||||
connect(m_cmakeServer.get(), &ServerMode::cmakeProgress,
|
||||
this, &ServerModeReader::handleProgress);
|
||||
connect(m_cmakeServer.get(), &ServerMode::cmakeSignal,
|
||||
this, &ServerModeReader::handleSignal);
|
||||
connect(m_cmakeServer.get(), &ServerMode::cmakeMessage,
|
||||
this, [this](const QString &m) { Core::MessageManager::write(m); });
|
||||
connect(m_cmakeServer.get(), &ServerMode::message,
|
||||
@@ -224,12 +226,12 @@ static void addCMakeVFolder(FolderNode *base, const Utils::FileName &basePath, i
|
||||
auto folder = new VirtualFolderNode(basePath, priority);
|
||||
folder->setDisplayName(displayName);
|
||||
base->addNode(folder);
|
||||
folder->buildTree(files);
|
||||
folder->addNestedNodes(files);
|
||||
for (FolderNode *fn : folder->folderNodes())
|
||||
fn->compress();
|
||||
}
|
||||
|
||||
static void addCMakeInputs(CMakeListsNode *root,
|
||||
static void addCMakeInputs(FolderNode *root,
|
||||
const Utils::FileName &sourceDir,
|
||||
const Utils::FileName &buildDir,
|
||||
QList<FileNode *> &sourceInputs,
|
||||
@@ -250,7 +252,7 @@ static void addCMakeInputs(CMakeListsNode *root,
|
||||
rootInputs);
|
||||
}
|
||||
|
||||
void ServerModeReader::generateProjectTree(CMakeListsNode *root,
|
||||
void ServerModeReader::generateProjectTree(CMakeProjectNode *root,
|
||||
const QList<const FileNode *> &allFiles)
|
||||
{
|
||||
// Split up cmake inputs into useful chunks:
|
||||
@@ -304,6 +306,7 @@ void ServerModeReader::updateCodeModel(CppTools::RawProjectParts &rpps)
|
||||
|
||||
CppTools::RawProjectPart rpp;
|
||||
rpp.setProjectFileLocation(fg->target->sourceDirectory.toString() + "/CMakeLists.txt");
|
||||
rpp.setBuildSystemTarget(fg->target->name);
|
||||
rpp.setDisplayName(fg->target->name + QString::number(counter));
|
||||
rpp.setDefines(defineArg.toUtf8());
|
||||
rpp.setIncludePaths(includes);
|
||||
@@ -387,6 +390,13 @@ void ServerModeReader::handleProgress(int min, int cur, int max, const QString &
|
||||
m_future->setProgressValue(progress);
|
||||
}
|
||||
|
||||
void ServerModeReader::handleSignal(const QString &signal, const QVariantMap &data)
|
||||
{
|
||||
Q_UNUSED(data);
|
||||
if (signal == "dirty")
|
||||
emit dirty();
|
||||
}
|
||||
|
||||
void ServerModeReader::extractCodeModelData(const QVariantMap &data)
|
||||
{
|
||||
const QVariantList configs = data.value("configurations").toList();
|
||||
@@ -518,97 +528,29 @@ void ServerModeReader::extractCacheData(const QVariantMap &data)
|
||||
m_cmakeCache = config;
|
||||
}
|
||||
|
||||
void ServerModeReader::addCMakeLists(CMakeListsNode *root, const QList<FileNode *> &cmakeLists)
|
||||
void ServerModeReader::addCMakeLists(CMakeProjectNode *root, const QList<FileNode *> &cmakeLists)
|
||||
{
|
||||
const QDir baseDir = QDir(m_parameters.sourceDirectory.toString());
|
||||
|
||||
QHash<QString, FileNode *> nodeHash;
|
||||
for (FileNode *cm : cmakeLists) {
|
||||
const QString relPath = baseDir.relativeFilePath(cm->filePath().parentDir().toString());
|
||||
QTC_CHECK(!nodeHash.contains(relPath));
|
||||
nodeHash[(relPath == ".") ? QString() : relPath ] = cm;
|
||||
}
|
||||
QStringList tmp = nodeHash.keys();
|
||||
Utils::sort(tmp, [](const QString &a, const QString &b) { return a.count() < b.count(); });
|
||||
const QStringList keys = tmp;
|
||||
|
||||
QHash<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!
|
||||
root->addNestedNodes(cmakeLists, Utils::FileName(),
|
||||
[&cmakeLists](const Utils::FileName &fp) -> ProjectExplorer::FolderNode * {
|
||||
if (Utils::contains(cmakeLists, [&fp](const FileNode *fn) { return fn->filePath().parentDir() == fp; }))
|
||||
return new CMakeListsNode(fp);
|
||||
else
|
||||
cmln = static_cast<CMakeListsNode *>(parentNode->projectNode(fn->filePath()));
|
||||
if (!cmln) {
|
||||
cmln = new CMakeListsNode(fn->filePath());
|
||||
parentNode->addNode(cmln);
|
||||
return new FolderNode(fp);
|
||||
});
|
||||
}
|
||||
|
||||
// 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;
|
||||
const Utils::FileName topDir = root->filePath().parentDir();
|
||||
|
||||
QStringList relative = stepDir.relativeChildPath(topDir).toString().split('/', QString::SkipEmptyParts);
|
||||
|
||||
CMakeListsNode *result = root;
|
||||
|
||||
QString relativePathElement;
|
||||
while (!relative.isEmpty()) {
|
||||
const QString nextDirPath = result->filePath().parentDir().toString();
|
||||
Utils::FileName nextFullPath;
|
||||
// Some directory may not contain CMakeLists.txt file, skip it:
|
||||
do {
|
||||
relativePathElement += '/' + relative.takeFirst();
|
||||
nextFullPath = Utils::FileName::fromString(nextDirPath + relativePathElement + "/CMakeLists.txt");
|
||||
} while (!nextFullPath.exists() && !relative.isEmpty());
|
||||
result = static_cast<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;
|
||||
Node *n = root->findNode([&dir](Node *n) { return n->asProjectNode() && n->filePath() == dir; });
|
||||
return n ? n->asProjectNode() : nullptr;
|
||||
}
|
||||
|
||||
static CMakeProjectNode *findOrCreateProjectNode(CMakeListsNode *root, const Utils::FileName &dir,
|
||||
static ProjectNode *findOrCreateProjectNode(ProjectNode *root, const Utils::FileName &dir,
|
||||
const QString &displayName)
|
||||
{
|
||||
CMakeListsNode *cmln = findCMakeNode(root, dir);
|
||||
ProjectNode *cmln = findCMakeNode(root, dir);
|
||||
QTC_ASSERT(cmln, return nullptr);
|
||||
|
||||
Utils::FileName projectName = dir;
|
||||
@@ -623,7 +565,7 @@ static CMakeProjectNode *findOrCreateProjectNode(CMakeListsNode *root, const Uti
|
||||
return pn;
|
||||
}
|
||||
|
||||
void ServerModeReader::addProjects(CMakeListsNode *root,
|
||||
void ServerModeReader::addProjects(CMakeProjectNode *root,
|
||||
const QList<Project *> &projects,
|
||||
const QList<const FileNode *> &allFiles)
|
||||
{
|
||||
@@ -635,17 +577,16 @@ void ServerModeReader::addProjects(CMakeListsNode *root,
|
||||
}
|
||||
|
||||
for (const Project *p : projects) {
|
||||
CMakeProjectNode *pNode = findOrCreateProjectNode(root, p->sourceDirectory, p->name);
|
||||
ProjectNode *pNode = findOrCreateProjectNode(root, p->sourceDirectory, p->name);
|
||||
QTC_ASSERT(pNode, continue);
|
||||
QTC_ASSERT(root, continue);
|
||||
addTargets(root, p->targets, includeFiles);
|
||||
}
|
||||
}
|
||||
|
||||
static CMakeTargetNode *findOrCreateTargetNode(CMakeListsNode *root, const Utils::FileName &dir,
|
||||
static CMakeTargetNode *findOrCreateTargetNode(ProjectNode *root, const Utils::FileName &dir,
|
||||
const QString &displayName)
|
||||
{
|
||||
CMakeListsNode *cmln = findCMakeNode(root, dir);
|
||||
ProjectNode *cmln = findCMakeNode(root, dir);
|
||||
QTC_ASSERT(cmln, return nullptr);
|
||||
|
||||
Utils::FileName targetName = dir;
|
||||
@@ -660,7 +601,7 @@ static CMakeTargetNode *findOrCreateTargetNode(CMakeListsNode *root, const Utils
|
||||
return tn;
|
||||
}
|
||||
|
||||
void ServerModeReader::addTargets(CMakeListsNode *root,
|
||||
void ServerModeReader::addTargets(CMakeProjectNode *root,
|
||||
const QList<ServerModeReader::Target *> &targets,
|
||||
const QHash<FileName, QList<const FileNode *>> &headers)
|
||||
{
|
||||
|
||||
@@ -33,6 +33,8 @@
|
||||
namespace CMakeProjectManager {
|
||||
namespace Internal {
|
||||
|
||||
class CMakeListsNode;
|
||||
|
||||
class ServerModeReader : public BuildDirReader
|
||||
{
|
||||
Q_OBJECT
|
||||
@@ -54,7 +56,7 @@ public:
|
||||
|
||||
QList<CMakeBuildTarget> buildTargets() const final;
|
||||
CMakeConfig takeParsedConfiguration() final;
|
||||
void generateProjectTree(CMakeListsNode *root,
|
||||
void generateProjectTree(CMakeProjectNode *root,
|
||||
const QList<const ProjectExplorer::FileNode *> &allFiles) final;
|
||||
void updateCodeModel(CppTools::RawProjectParts &rpps) final;
|
||||
|
||||
@@ -62,6 +64,7 @@ private:
|
||||
void handleReply(const QVariantMap &data, const QString &inReplyTo);
|
||||
void handleError(const QString &message);
|
||||
void handleProgress(int min, int cur, int max, const QString &inReplyTo);
|
||||
void handleSignal(const QString &signal, const QVariantMap &data);
|
||||
|
||||
struct Target;
|
||||
struct Project;
|
||||
@@ -110,10 +113,10 @@ private:
|
||||
void extractCMakeInputsData(const QVariantMap &data);
|
||||
void extractCacheData(const QVariantMap &data);
|
||||
|
||||
void addCMakeLists(CMakeListsNode *root, const QList<ProjectExplorer::FileNode *> &cmakeLists);
|
||||
void addProjects(CMakeListsNode *root, const QList<Project *> &projects,
|
||||
void addCMakeLists(CMakeProjectNode *root, const QList<ProjectExplorer::FileNode *> &cmakeLists);
|
||||
void addProjects(CMakeProjectNode *root, const QList<Project *> &projects,
|
||||
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);
|
||||
void addFileGroups(ProjectExplorer::ProjectNode *targetRoot,
|
||||
const Utils::FileName &sourceDirectory,
|
||||
|
||||
@@ -264,7 +264,7 @@ CMakeConfig TeaLeafReader::takeParsedConfiguration()
|
||||
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);
|
||||
|
||||
@@ -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); });
|
||||
|
||||
root->buildTree(fileNodes, m_parameters.sourceDirectory);
|
||||
root->addNestedNodes(fileNodes, m_parameters.sourceDirectory);
|
||||
m_files.clear(); // Some of the FileNodes in files() were deleted!
|
||||
}
|
||||
|
||||
@@ -358,6 +358,7 @@ void TeaLeafReader::updateCodeModel(CppTools::RawProjectParts &rpps)
|
||||
includePaths += m_parameters.buildDirectory.toString();
|
||||
CppTools::RawProjectPart rpp;
|
||||
rpp.setProjectFileLocation(QString()); // No project file information available!
|
||||
rpp.setBuildSystemTarget(cbt.title);
|
||||
rpp.setIncludePaths(includePaths);
|
||||
|
||||
CppTools::RawProjectPartFlags cProjectFlags;
|
||||
|
||||
@@ -56,7 +56,7 @@ public:
|
||||
|
||||
QList<CMakeBuildTarget> buildTargets() const final;
|
||||
CMakeConfig takeParsedConfiguration() final;
|
||||
void generateProjectTree(CMakeListsNode *root,
|
||||
void generateProjectTree(CMakeProjectNode *root,
|
||||
const QList<const ProjectExplorer::FileNode *> &allFiles) final;
|
||||
void updateCodeModel(CppTools::RawProjectParts &rpps) final;
|
||||
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
#include <utils/hostosinfo.h>
|
||||
|
||||
#include <QAction>
|
||||
#include <QRegExp>
|
||||
#include <QToolButton>
|
||||
#include <QTextStream>
|
||||
|
||||
|
||||
@@ -29,10 +29,9 @@
|
||||
#include <utils/filesearch.h>
|
||||
|
||||
#include <QPointer>
|
||||
|
||||
#include <QTextBlock>
|
||||
#include <QPlainTextEdit>
|
||||
#include <QRegularExpression>
|
||||
#include <QTextBlock>
|
||||
#include <QTextCursor>
|
||||
|
||||
namespace Core {
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
#include <utils/qtcassert.h>
|
||||
|
||||
#include <QDir>
|
||||
#include <QRegExp>
|
||||
#include <QStringMatcher>
|
||||
#include <QTimer>
|
||||
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
#include <QAbstractItemModel>
|
||||
#include <QFileInfo>
|
||||
#include <QMutexLocker>
|
||||
#include <QRegExp>
|
||||
|
||||
using namespace Core;
|
||||
using namespace Core;
|
||||
|
||||
@@ -35,6 +35,7 @@
|
||||
#include <QCoreApplication>
|
||||
#include <QFileInfo>
|
||||
#include <QDir>
|
||||
#include <QRegExp>
|
||||
|
||||
#include <QDebug>
|
||||
|
||||
|
||||
@@ -1779,12 +1779,16 @@ void CppCodeModelInspectorDialog::updateProjectPartData(const ProjectPart::Ptr &
|
||||
}
|
||||
const QString callGroupId = part->callGroupId.isEmpty() ? QString::fromLatin1("<None>")
|
||||
: part->callGroupId;
|
||||
const QString buildSystemTarget
|
||||
= part->buildSystemTarget.isEmpty() ? QString::fromLatin1("<None>")
|
||||
: part->buildSystemTarget;
|
||||
|
||||
KeyValueModel::Table table = KeyValueModel::Table()
|
||||
<< qMakePair(QString::fromLatin1("Project Part Name"), part->displayName)
|
||||
<< qMakePair(QString::fromLatin1("Project Part File"), part->projectFileLocation())
|
||||
<< qMakePair(QString::fromLatin1("Project Name"), projectName)
|
||||
<< qMakePair(QString::fromLatin1("Project File"), projectFilePath)
|
||||
<< qMakePair(QString::fromLatin1("Buildsystem Target"), buildSystemTarget)
|
||||
<< qMakePair(QString::fromLatin1("Callgroup Id"), callGroupId)
|
||||
<< qMakePair(QString::fromLatin1("Selected For Building"),
|
||||
CMI::Utils::toString(part->selectedForBuilding))
|
||||
|
||||
@@ -46,6 +46,7 @@
|
||||
#include <utils/runextensions.h>
|
||||
#include <utils/tooltip/tooltip.h>
|
||||
|
||||
#include <QRegExp>
|
||||
#include <QVarLengthArray>
|
||||
|
||||
using namespace CPlusPlus;
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
#include <coreplugin/editormanager/editormanager.h>
|
||||
#include <coreplugin/editormanager/ieditor.h>
|
||||
|
||||
#include <QRegExp>
|
||||
#include <QStringMatcher>
|
||||
|
||||
using namespace CppTools::Internal;
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
|
||||
#include <coreplugin/editormanager/editormanager.h>
|
||||
|
||||
#include <QRegExp>
|
||||
#include <QStringMatcher>
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
@@ -185,6 +185,7 @@ static ProjectPart::Ptr projectPartFromRawProjectPart(const RawProjectPart &rawP
|
||||
part->projectFileLine = rawProjectPart.projectFileLine;
|
||||
part->projectFileColumn = rawProjectPart.projectFileColumn;
|
||||
part->callGroupId = rawProjectPart.callGroupId;
|
||||
part->buildSystemTarget = rawProjectPart.buildSystemTarget;
|
||||
part->qtVersion = rawProjectPart.qtVersion;
|
||||
part->projectDefines = rawProjectPart.projectDefines;
|
||||
part->headerPaths = rawProjectPart.headerPaths;
|
||||
|
||||
@@ -66,6 +66,11 @@ void RawProjectPart::setConfigFileName(const QString &configFileName)
|
||||
this->projectConfigFile = configFileName;
|
||||
}
|
||||
|
||||
void RawProjectPart::setBuildSystemTarget(const QString &target)
|
||||
{
|
||||
buildSystemTarget = target;
|
||||
}
|
||||
|
||||
void RawProjectPart::setCallGroupId(const QString &id)
|
||||
{
|
||||
callGroupId = id;
|
||||
|
||||
@@ -63,6 +63,7 @@ public:
|
||||
void setProjectFileLocation(const QString &projectFile, int line = -1, int column = -1);
|
||||
void setConfigFileName(const QString &configFileName);
|
||||
void setCallGroupId(const QString &id);
|
||||
void setBuildSystemTarget(const QString &target);
|
||||
|
||||
void setQtVersion(ProjectPart::QtVersion qtVersion);
|
||||
|
||||
@@ -84,6 +85,7 @@ public:
|
||||
int projectFileColumn = -1;
|
||||
QString projectConfigFile; // currently only used by the Generic Project Manager
|
||||
QString callGroupId;
|
||||
QString buildSystemTarget;
|
||||
QStringList precompiledHeaders;
|
||||
ProjectPartHeaderPaths headerPaths;
|
||||
QByteArray projectDefines;
|
||||
|
||||
@@ -110,6 +110,7 @@ public:
|
||||
int projectFileColumn = -1;
|
||||
QString projectConfigFile; // currently only used by the Generic Project Manager
|
||||
QString callGroupId;
|
||||
QString buildSystemTarget;
|
||||
|
||||
ProjectFiles files;
|
||||
|
||||
|
||||
@@ -1969,15 +1969,15 @@ bool BreakHandler::contextMenuEvent(const ItemViewEvent &ev)
|
||||
|
||||
|
||||
// FIXME BP: m_engine->threadsHandler()->currentThreadId();
|
||||
int threadId = 0;
|
||||
addAction(menu,
|
||||
threadId == -1 ? tr("Associate Breakpoint with All Threads")
|
||||
: tr("Associate Breakpoint with Thread %1").arg(threadId),
|
||||
!selectedItems.isEmpty(),
|
||||
[this, selectedItems, threadId] {
|
||||
for (Breakpoint bp : selectedItems)
|
||||
bp.setThreadSpec(threadId);
|
||||
});
|
||||
// int threadId = 0;
|
||||
// addAction(menu,
|
||||
// threadId == -1 ? tr("Associate Breakpoint with All Threads")
|
||||
// : tr("Associate Breakpoint with Thread %1").arg(threadId),
|
||||
// !selectedItems.isEmpty(),
|
||||
// [this, selectedItems, threadId] {
|
||||
// for (Breakpoint bp : selectedItems)
|
||||
// bp.setThreadSpec(threadId);
|
||||
// });
|
||||
|
||||
addAction(menu,
|
||||
selectedItems.size() > 1
|
||||
|
||||
@@ -112,10 +112,16 @@ enum StepAction
|
||||
struct QmlV8ObjectData
|
||||
{
|
||||
int handle = -1;
|
||||
int expectedProperties = -1;
|
||||
QString name;
|
||||
QString type;
|
||||
QVariant value;
|
||||
QVariantList properties;
|
||||
|
||||
bool hasChildren() const
|
||||
{
|
||||
return expectedProperties > 0 || !properties.isEmpty();
|
||||
}
|
||||
};
|
||||
|
||||
typedef std::function<void(const QVariantMap &)> QmlCallback;
|
||||
@@ -1391,7 +1397,7 @@ void QmlEnginePrivate::handleEvaluateExpression(const QVariantMap &response,
|
||||
if (success) {
|
||||
item->type = body.type;
|
||||
item->value = body.value.toString();
|
||||
item->wantsChildren = body.properties.count();
|
||||
item->setHasChildren(body.hasChildren());
|
||||
} else {
|
||||
//Do not set type since it is unknown
|
||||
item->setError(body.value.toString());
|
||||
@@ -1658,17 +1664,8 @@ QmlV8ObjectData QmlEnginePrivate::extractData(const QVariant &data) const
|
||||
|
||||
objectData.name = dataMap.value(NAME).toString();
|
||||
|
||||
if (dataMap.contains(REF)) {
|
||||
objectData.handle = dataMap.value(REF).toInt();
|
||||
if (refVals.contains(objectData.handle)) {
|
||||
QmlV8ObjectData data = refVals.value(objectData.handle);
|
||||
objectData.type = data.type;
|
||||
objectData.value = data.value;
|
||||
objectData.properties = data.properties;
|
||||
}
|
||||
} else {
|
||||
objectData.handle = dataMap.value(HANDLE).toInt();
|
||||
QString type = dataMap.value(TYPE).toString();
|
||||
objectData.handle = dataMap.value(HANDLE).toInt();
|
||||
|
||||
if (type == "undefined") {
|
||||
objectData.type = "undefined";
|
||||
@@ -1695,19 +1692,42 @@ QmlV8ObjectData QmlEnginePrivate::extractData(const QVariant &data) const
|
||||
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 (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();
|
||||
QVariant value = dataMap.value("value");
|
||||
if (value.isValid())
|
||||
objectData.expectedProperties = value.toInt();
|
||||
|
||||
} else if (type == "script") {
|
||||
objectData.type = "script";
|
||||
objectData.value = dataMap.value(NAME);
|
||||
}
|
||||
|
||||
if (dataMap.contains(REF)) {
|
||||
objectData.handle = dataMap.value(REF).toInt();
|
||||
if (refVals.contains(objectData.handle)) {
|
||||
QmlV8ObjectData data = refVals.value(objectData.handle);
|
||||
if (objectData.type.isEmpty())
|
||||
objectData.type = data.type;
|
||||
if (!objectData.value.isValid())
|
||||
objectData.value = data.value;
|
||||
if (objectData.properties.isEmpty())
|
||||
objectData.properties = data.properties;
|
||||
if (objectData.expectedProperties < 0)
|
||||
objectData.expectedProperties = data.expectedProperties;
|
||||
}
|
||||
}
|
||||
|
||||
return objectData;
|
||||
@@ -2216,7 +2236,7 @@ void QmlEnginePrivate::handleFrame(const QVariantMap &response)
|
||||
item->id = objectData.handle;
|
||||
item->type = objectData.type;
|
||||
item->value = objectData.value.toString();
|
||||
item->setHasChildren(objectData.properties.count());
|
||||
item->setHasChildren(objectData.hasChildren());
|
||||
// In case of global object, we do not get children
|
||||
// Set children nevertheless and query later.
|
||||
if (item->value == "global") {
|
||||
@@ -2298,11 +2318,11 @@ void QmlEnginePrivate::handleScope(const QVariantMap &response)
|
||||
item->name = item->exp;
|
||||
item->iname = "local." + item->exp;
|
||||
item->id = localData.handle;
|
||||
|
||||
if (localData.value.isValid()) {
|
||||
item->type = localData.type;
|
||||
item->value = localData.value.toString();
|
||||
item->setHasChildren(localData.properties.count());
|
||||
item->setHasChildren(localData.hasChildren());
|
||||
|
||||
if (localData.value.isValid() || item->wantsChildren || localData.expectedProperties == 0) {
|
||||
engine->watchHandler()->insertItem(item.release());
|
||||
} else {
|
||||
itemsToLookup.insert(int(item->id), {item->iname, item->name, item->exp});
|
||||
@@ -2443,7 +2463,7 @@ void QmlEnginePrivate::insertSubItems(WatchItem *parent, const QVariantList &pro
|
||||
item->value = propertyData.value.toString();
|
||||
if (item->type.isEmpty() || expandedINames.contains(item->iname))
|
||||
itemsToLookup.insert(propertyData.handle, {item->iname, item->name, item->exp});
|
||||
item->setHasChildren(propertyData.properties.count() > 0);
|
||||
item->setHasChildren(propertyData.hasChildren());
|
||||
parent->appendChild(item.release());
|
||||
}
|
||||
|
||||
@@ -2499,7 +2519,7 @@ void QmlEnginePrivate::handleLookup(const QVariantMap &response)
|
||||
item->type = bodyObjectData.type;
|
||||
item->value = bodyObjectData.value.toString();
|
||||
|
||||
item->setHasChildren(bodyObjectData.properties.count());
|
||||
item->setHasChildren(bodyObjectData.hasChildren());
|
||||
insertSubItems(item, bodyObjectData.properties);
|
||||
|
||||
engine->watchHandler()->insertItem(item);
|
||||
@@ -2515,7 +2535,10 @@ void QmlEnginePrivate::stateChanged(State state)
|
||||
if (state == QmlDebugClient::Enabled) {
|
||||
/// Start session.
|
||||
flushSendBuffer();
|
||||
runDirectCommand(CONNECT);
|
||||
QJsonObject parameters;
|
||||
parameters.insert("redundantRefs", false);
|
||||
parameters.insert("namesAsObjects", false);
|
||||
runDirectCommand(CONNECT, QJsonDocument(parameters).toJson());
|
||||
runCommand({VERSION}, CB(handleVersion));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2008,7 +2008,7 @@ bool WatchHandler::insertItem(WatchItem *item)
|
||||
|
||||
bool found = false;
|
||||
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) {
|
||||
m_model->destroyItem(parent->childAt(row));
|
||||
parent->insertChild(row, item);
|
||||
|
||||
@@ -34,6 +34,7 @@ publication by Neil Fraser: http://neil.fraser.name/writing/diff/
|
||||
#include "differ.h"
|
||||
|
||||
#include <QList>
|
||||
#include <QRegExp>
|
||||
#include <QStringList>
|
||||
#include <QMap>
|
||||
#include <QPair>
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
|
||||
#include "diffutils.h"
|
||||
#include "differ.h"
|
||||
#include <QRegExp>
|
||||
#include <QStringList>
|
||||
#include <QTextStream>
|
||||
#include "texteditor/fontsettings.h"
|
||||
|
||||
@@ -259,28 +259,25 @@ void GenericProject::refresh(RefreshOptions options)
|
||||
parseProject(options);
|
||||
|
||||
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
|
||||
if (f.endsWith(".qrc"))
|
||||
fileType = FileType::Resource;
|
||||
return new FileNode(Utils::FileName::fromString(f), fileType, false);
|
||||
});
|
||||
newRoot->addNestedNode(new FileNode(Utils::FileName::fromString(f), fileType, false));
|
||||
}
|
||||
|
||||
auto projectFilesNode = new FileNode(Utils::FileName::fromString(m_filesFileName),
|
||||
newRoot->addNestedNode(new FileNode(Utils::FileName::fromString(m_filesFileName),
|
||||
FileType::Project,
|
||||
/* generated = */ false);
|
||||
|
||||
auto projectIncludesNode = new FileNode(Utils::FileName::fromString(m_includesFileName),
|
||||
/* generated = */ false));
|
||||
newRoot->addNestedNode(new FileNode(Utils::FileName::fromString(m_includesFileName),
|
||||
FileType::Project,
|
||||
/* generated = */ false);
|
||||
|
||||
auto projectConfigNode = new FileNode(Utils::FileName::fromString(m_configFileName),
|
||||
/* generated = */ false));
|
||||
newRoot->addNestedNode(new FileNode(Utils::FileName::fromString(m_configFileName),
|
||||
FileType::Project,
|
||||
/* generated = */ false);
|
||||
fileNodes << projectFilesNode << projectIncludesNode << projectConfigNode;
|
||||
/* generated = */ false));
|
||||
|
||||
auto newRoot = new GenericProjectNode(this);
|
||||
newRoot->buildTree(fileNodes);
|
||||
setRootProjectNode(newRoot);
|
||||
}
|
||||
|
||||
|
||||
@@ -37,6 +37,7 @@
|
||||
#include <utils/hostosinfo.h>
|
||||
#include <utils/progressindicator.h>
|
||||
#include <utils/qtcassert.h>
|
||||
#include <utils/utilsicons.h>
|
||||
#include <utils/theme/theme.h>
|
||||
|
||||
#include <QCompleter>
|
||||
@@ -69,7 +70,6 @@ GerritDialog::GerritDialog(const QSharedPointer<GerritParameters> &p,
|
||||
setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
|
||||
|
||||
m_ui->setupUi(this);
|
||||
setWindowTitle(tr("Gerrit"));
|
||||
m_queryModel->setStringList(m_parameters->savedQueries);
|
||||
QCompleter *completer = new QCompleter(this);
|
||||
completer->setModel(m_queryModel);
|
||||
@@ -111,6 +111,10 @@ GerritDialog::GerritDialog(const QSharedPointer<GerritParameters> &p,
|
||||
connect(m_ui->treeView, &QAbstractItemView::activated,
|
||||
this, &GerritDialog::slotActivated);
|
||||
|
||||
m_ui->resetRemoteButton->setIcon(Utils::Icons::RESET_TOOLBAR.icon());
|
||||
connect(m_ui->resetRemoteButton, &QToolButton::clicked,
|
||||
this, [this] { updateRemotes(true); });
|
||||
|
||||
m_displayButton = addActionButton(tr("&Show"), [this]() { slotFetchDisplay(); });
|
||||
m_cherryPickButton = addActionButton(tr("Cherry &Pick"), [this]() { slotFetchCherryPick(); });
|
||||
m_checkoutButton = addActionButton(tr("C&heckout"), [this]() { slotFetchCheckout(); });
|
||||
@@ -120,6 +124,11 @@ GerritDialog::GerritDialog(const QSharedPointer<GerritParameters> &p,
|
||||
m_refreshButton, &QWidget::setDisabled);
|
||||
connect(m_model, &GerritModel::refreshStateChanged,
|
||||
this, &GerritDialog::slotRefreshStateChanged);
|
||||
connect(m_model, &GerritModel::errorText,
|
||||
this, [this](const QString &text) {
|
||||
if (text.contains("returned error: 401"))
|
||||
updateRemotes(true);
|
||||
}, Qt::QueuedConnection);
|
||||
|
||||
setCurrentPath(repository);
|
||||
slotCurrentChanged();
|
||||
@@ -226,7 +235,7 @@ void GerritDialog::remoteChanged()
|
||||
slotRefresh();
|
||||
}
|
||||
|
||||
void GerritDialog::updateRemotes()
|
||||
void GerritDialog::updateRemotes(bool forceReload)
|
||||
{
|
||||
m_ui->remoteComboBox->clear();
|
||||
if (m_repository.isEmpty() || !QFileInfo(m_repository).isDir())
|
||||
@@ -240,7 +249,7 @@ void GerritDialog::updateRemotes()
|
||||
while (mapIt.hasNext()) {
|
||||
mapIt.next();
|
||||
GerritServer server;
|
||||
if (!server.fillFromRemote(mapIt.value(), *m_parameters))
|
||||
if (!server.fillFromRemote(mapIt.value(), *m_parameters, forceReload))
|
||||
continue;
|
||||
addRemote(server, mapIt.key());
|
||||
}
|
||||
|
||||
@@ -76,7 +76,7 @@ private:
|
||||
void slotFetchCheckout();
|
||||
void slotRefresh();
|
||||
void remoteChanged();
|
||||
void updateRemotes();
|
||||
void updateRemotes(bool forceReload = false);
|
||||
void addRemote(const GerritServer &server, const QString &name);
|
||||
|
||||
void manageProgressIndicator();
|
||||
|
||||
@@ -65,6 +65,13 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QToolButton" name="resetRemoteButton">
|
||||
<property name="toolTip">
|
||||
<string>Refresh Remote Servers</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
|
||||
@@ -233,13 +233,12 @@ public:
|
||||
|
||||
signals:
|
||||
void resultRetrieved(const QByteArray &);
|
||||
void errorText(const QString &text);
|
||||
void finished();
|
||||
|
||||
private:
|
||||
void processError(QProcess::ProcessError);
|
||||
void processFinished(int exitCode, QProcess::ExitStatus);
|
||||
void readyReadStandardError();
|
||||
void readyReadStandardOutput();
|
||||
void timeout();
|
||||
|
||||
void errorTermination(const QString &msg);
|
||||
@@ -249,6 +248,7 @@ private:
|
||||
QTimer m_timer;
|
||||
QString m_binary;
|
||||
QByteArray m_output;
|
||||
QString m_error;
|
||||
QFutureInterface<void> m_progress;
|
||||
QFutureWatcher<void> m_watcher;
|
||||
QStringList m_arguments;
|
||||
@@ -277,10 +277,14 @@ QueryContext::QueryContext(const QString &query,
|
||||
+ "&o=CURRENT_REVISION&o=DETAILED_LABELS&o=DETAILED_ACCOUNTS";
|
||||
m_arguments = GerritServer::curlArguments() << url;
|
||||
}
|
||||
connect(&m_process, &QProcess::readyReadStandardError,
|
||||
this, &QueryContext::readyReadStandardError);
|
||||
connect(&m_process, &QProcess::readyReadStandardOutput,
|
||||
this, &QueryContext::readyReadStandardOutput);
|
||||
connect(&m_process, &QProcess::readyReadStandardError, this, [this] {
|
||||
const QString text = QString::fromLocal8Bit(m_process.readAllStandardError());
|
||||
VcsOutputWindow::appendError(text);
|
||||
m_error.append(text);
|
||||
});
|
||||
connect(&m_process, &QProcess::readyReadStandardOutput, this, [this] {
|
||||
m_output.append(m_process.readAllStandardOutput());
|
||||
});
|
||||
connect(&m_process, static_cast<void (QProcess::*)(int, QProcess::ExitStatus)>(&QProcess::finished),
|
||||
this, &QueryContext::processFinished);
|
||||
connect(&m_process, &QProcess::errorOccurred, this, &QueryContext::processError);
|
||||
@@ -345,6 +349,7 @@ void QueryContext::processFinished(int exitCode, QProcess::ExitStatus es)
|
||||
{
|
||||
if (m_timer.isActive())
|
||||
m_timer.stop();
|
||||
emit errorText(m_error);
|
||||
if (es != QProcess::NormalExit) {
|
||||
errorTermination(tr("%1 crashed.").arg(m_binary));
|
||||
return;
|
||||
@@ -357,16 +362,6 @@ void QueryContext::processFinished(int exitCode, QProcess::ExitStatus es)
|
||||
emit finished();
|
||||
}
|
||||
|
||||
void QueryContext::readyReadStandardError()
|
||||
{
|
||||
VcsOutputWindow::appendError(QString::fromLocal8Bit(m_process.readAllStandardError()));
|
||||
}
|
||||
|
||||
void QueryContext::readyReadStandardOutput()
|
||||
{
|
||||
m_output.append(m_process.readAllStandardOutput());
|
||||
}
|
||||
|
||||
void QueryContext::timeout()
|
||||
{
|
||||
if (m_process.state() != QProcess::Running)
|
||||
@@ -520,6 +515,7 @@ void GerritModel::refresh(const QSharedPointer<GerritServer> &server, const QStr
|
||||
|
||||
m_query = new QueryContext(realQuery, m_parameters, *m_server, this);
|
||||
connect(m_query, &QueryContext::resultRetrieved, this, &GerritModel::resultRetrieved);
|
||||
connect(m_query, &QueryContext::errorText, this, &GerritModel::errorText);
|
||||
connect(m_query, &QueryContext::finished, this, &GerritModel::queryFinished);
|
||||
emit refreshStateChanged(true);
|
||||
m_query->start();
|
||||
|
||||
@@ -127,6 +127,7 @@ public:
|
||||
signals:
|
||||
void refreshStateChanged(bool isRefreshing); // For disabling the "Refresh" button.
|
||||
void stateChanged();
|
||||
void errorText(const QString &text);
|
||||
|
||||
private:
|
||||
void resultRetrieved(const QByteArray &);
|
||||
|
||||
@@ -29,12 +29,14 @@
|
||||
#include "../gitplugin.h"
|
||||
#include "../gitclient.h"
|
||||
|
||||
#include <coreplugin/icore.h>
|
||||
#include <coreplugin/shellcommand.h>
|
||||
#include <utils/hostosinfo.h>
|
||||
|
||||
#include <QFile>
|
||||
#include <QJsonDocument>
|
||||
#include <QRegularExpression>
|
||||
#include <QSettings>
|
||||
|
||||
using namespace Utils;
|
||||
using namespace Git::Internal;
|
||||
@@ -44,6 +46,11 @@ namespace Internal {
|
||||
|
||||
static const char defaultHostC[] = "codereview.qt-project.org";
|
||||
static const char accountUrlC[] = "/accounts/self";
|
||||
static const char isGerritKey[] = "IsGerrit";
|
||||
static const char rootPathKey[] = "RootPath";
|
||||
static const char userNameKey[] = "UserName";
|
||||
static const char fullNameKey[] = "FullName";
|
||||
static const char isAuthenticatedKey[] = "IsAuthenticated";
|
||||
|
||||
bool GerritUser::isSameAs(const GerritUser &other) const
|
||||
{
|
||||
@@ -111,7 +118,9 @@ QString GerritServer::url(UrlType urlType) const
|
||||
return res;
|
||||
}
|
||||
|
||||
bool GerritServer::fillFromRemote(const QString &remote, const GerritParameters ¶meters)
|
||||
bool GerritServer::fillFromRemote(const QString &remote,
|
||||
const GerritParameters ¶meters,
|
||||
bool forceReload)
|
||||
{
|
||||
const GitRemote r(remote);
|
||||
if (!r.isValid)
|
||||
@@ -136,12 +145,61 @@ bool GerritServer::fillFromRemote(const QString &remote, const GerritParameters
|
||||
curlBinary = parameters.curl;
|
||||
if (curlBinary.isEmpty() || !QFile::exists(curlBinary))
|
||||
return false;
|
||||
const StoredHostValidity validity = forceReload ? Invalid : loadSettings();
|
||||
switch (validity) {
|
||||
case Invalid:
|
||||
rootPath = r.path;
|
||||
// Strip the last part of the path, which is always the repo name
|
||||
// The rest of the path needs to be inspected to find the root path
|
||||
// (can be http://example.net/review)
|
||||
ascendPath();
|
||||
return resolveRoot();
|
||||
case NotGerrit:
|
||||
return false;
|
||||
case Valid:
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
GerritServer::StoredHostValidity GerritServer::loadSettings()
|
||||
{
|
||||
StoredHostValidity validity = Invalid;
|
||||
QSettings *settings = Core::ICore::settings();
|
||||
settings->beginGroup("Gerrit/" + host);
|
||||
if (!settings->value(isGerritKey, true).toBool()) {
|
||||
validity = NotGerrit;
|
||||
} else if (settings->contains(isAuthenticatedKey)) {
|
||||
rootPath = settings->value(rootPathKey).toString();
|
||||
user.userName = settings->value(userNameKey).toString();
|
||||
user.fullName = settings->value(fullNameKey).toString();
|
||||
authenticated = settings->value(isAuthenticatedKey).toBool();
|
||||
validity = Valid;
|
||||
}
|
||||
settings->endGroup();
|
||||
return validity;
|
||||
}
|
||||
|
||||
void GerritServer::saveSettings(StoredHostValidity validity) const
|
||||
{
|
||||
QSettings *settings = Core::ICore::settings();
|
||||
settings->beginGroup("Gerrit/" + host);
|
||||
switch (validity) {
|
||||
case NotGerrit:
|
||||
settings->setValue(isGerritKey, false);
|
||||
break;
|
||||
case Valid:
|
||||
settings->setValue(rootPathKey, rootPath);
|
||||
settings->setValue(userNameKey, user.userName);
|
||||
settings->setValue(fullNameKey, user.fullName);
|
||||
settings->setValue(isAuthenticatedKey, authenticated);
|
||||
break;
|
||||
case Invalid:
|
||||
settings->clear();
|
||||
break;
|
||||
}
|
||||
|
||||
settings->endGroup();
|
||||
}
|
||||
|
||||
QStringList GerritServer::curlArguments()
|
||||
@@ -165,8 +223,13 @@ int GerritServer::testConnection()
|
||||
QString output = resp.stdOut();
|
||||
output.remove(0, output.indexOf('\n')); // Strip first line
|
||||
QJsonDocument doc = QJsonDocument::fromJson(output.toUtf8());
|
||||
if (!doc.isNull())
|
||||
user.fullName = doc.object().value("name").toString();
|
||||
if (!doc.isNull()) {
|
||||
const QJsonObject obj = doc.object();
|
||||
user.fullName = obj.value("name").toString();
|
||||
const QString userName = obj.value("username").toString();
|
||||
if (!userName.isEmpty())
|
||||
user.userName = userName;
|
||||
}
|
||||
return 200;
|
||||
}
|
||||
const QRegularExpression errorRegexp("returned error: (\\d+)");
|
||||
@@ -182,6 +245,7 @@ bool GerritServer::setupAuthentication()
|
||||
if (!dialog.exec())
|
||||
return false;
|
||||
authenticated = dialog.isAuthenticated();
|
||||
saveSettings(Valid);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -199,12 +263,15 @@ bool GerritServer::resolveRoot()
|
||||
for (;;) {
|
||||
switch (testConnection()) {
|
||||
case 200:
|
||||
saveSettings(Valid);
|
||||
return true;
|
||||
case 401:
|
||||
return setupAuthentication();
|
||||
case 404:
|
||||
if (!ascendPath())
|
||||
if (!ascendPath()) {
|
||||
saveSettings(NotGerrit);
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
default: // unknown error - fail
|
||||
return false;
|
||||
|
||||
@@ -61,13 +61,22 @@ public:
|
||||
RestUrl
|
||||
};
|
||||
|
||||
enum StoredHostValidity
|
||||
{
|
||||
Invalid,
|
||||
NotGerrit,
|
||||
Valid
|
||||
};
|
||||
|
||||
GerritServer();
|
||||
GerritServer(const QString &host, unsigned short port, const QString &userName, HostType type);
|
||||
bool operator==(const GerritServer &other) const;
|
||||
static QString defaultHost();
|
||||
QString hostArgument() const;
|
||||
QString url(UrlType urlType = DefaultUrl) const;
|
||||
bool fillFromRemote(const QString &remote, const GerritParameters ¶meters);
|
||||
bool fillFromRemote(const QString &remote, const GerritParameters ¶meters, bool forceReload);
|
||||
StoredHostValidity loadSettings();
|
||||
void saveSettings(StoredHostValidity validity) const;
|
||||
int testConnection();
|
||||
static QStringList curlArguments();
|
||||
|
||||
|
||||
@@ -27,6 +27,8 @@
|
||||
|
||||
#include <texteditor/syntaxhighlighter.h>
|
||||
|
||||
#include <QRegExp>
|
||||
|
||||
namespace Git {
|
||||
namespace Internal {
|
||||
|
||||
|
||||
@@ -45,6 +45,7 @@
|
||||
#include <QLayout>
|
||||
#include <QMap>
|
||||
#include <QMenu>
|
||||
#include <QRegExp>
|
||||
#include <QString>
|
||||
#include <QStringList>
|
||||
#include <QTextBrowser>
|
||||
|
||||
@@ -34,7 +34,9 @@ HEADERS += \
|
||||
iosdeploystepfactory.h \
|
||||
iosdeploystepwidget.h \
|
||||
iosanalyzesupport.h \
|
||||
simulatorcontrol.h
|
||||
simulatorcontrol.h \
|
||||
iosbuildconfiguration.h \
|
||||
iosbuildsettingswidget.h
|
||||
|
||||
|
||||
SOURCES += \
|
||||
@@ -63,13 +65,16 @@ SOURCES += \
|
||||
iosdeploystepfactory.cpp \
|
||||
iosdeploystepwidget.cpp \
|
||||
iosanalyzesupport.cpp \
|
||||
simulatorcontrol.cpp
|
||||
simulatorcontrol.cpp \
|
||||
iosbuildconfiguration.cpp \
|
||||
iosbuildsettingswidget.cpp
|
||||
|
||||
FORMS += \
|
||||
iossettingswidget.ui \
|
||||
iosbuildstep.ui \
|
||||
iosdeploystepwidget.ui \
|
||||
iospresetbuildstep.ui
|
||||
iospresetbuildstep.ui \
|
||||
iosbuildsettingswidget.ui
|
||||
|
||||
DEFINES += IOS_LIBRARY
|
||||
|
||||
|
||||
193
src/plugins/ios/iosbuildconfiguration.cpp
Normal file
193
src/plugins/ios/iosbuildconfiguration.cpp
Normal 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
|
||||
75
src/plugins/ios/iosbuildconfiguration.h
Normal file
75
src/plugins/ios/iosbuildconfiguration.h
Normal 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
|
||||
290
src/plugins/ios/iosbuildsettingswidget.cpp
Normal file
290
src/plugins/ios/iosbuildsettingswidget.cpp
Normal 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
|
||||
80
src/plugins/ios/iosbuildsettingswidget.h
Normal file
80
src/plugins/ios/iosbuildsettingswidget.h
Normal 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
|
||||
137
src/plugins/ios/iosbuildsettingswidget.ui
Normal file
137
src/plugins/ios/iosbuildsettingswidget.ui
Normal 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>
|
||||
@@ -32,6 +32,7 @@
|
||||
|
||||
#include <coreplugin/icore.h>
|
||||
#include <utils/algorithm.h>
|
||||
#include <utils/synchronousprocess.h>
|
||||
#include <utils/qtcassert.h>
|
||||
#include <utils/synchronousprocess.h>
|
||||
#include <projectexplorer/kitmanager.h>
|
||||
@@ -49,12 +50,15 @@
|
||||
#include <qtsupport/qtversionmanager.h>
|
||||
#include <qtsupport/qtversionfactory.h>
|
||||
|
||||
#include <QDir>
|
||||
#include <QDomDocument>
|
||||
#include <QFileInfo>
|
||||
#include <QFileSystemWatcher>
|
||||
#include <QHash>
|
||||
#include <QList>
|
||||
#include <QLoggingCategory>
|
||||
#include <QProcess>
|
||||
#include <QSettings>
|
||||
#include <QStringList>
|
||||
#include <QTimer>
|
||||
|
||||
using namespace ProjectExplorer;
|
||||
@@ -74,6 +78,21 @@ namespace Internal {
|
||||
const QLatin1String SettingsGroup("IosConfigurations");
|
||||
const QLatin1String ignoreAllDevicesKey("IgnoreAllDevices");
|
||||
|
||||
const char provisioningTeamsTag[] = "IDEProvisioningTeams";
|
||||
const char freeTeamTag[] = "isFreeProvisioningTeam";
|
||||
const char emailTag[] = "eMail";
|
||||
const char teamNameTag[] = "teamName";
|
||||
const char teamIdTag[] = "teamID";
|
||||
|
||||
const char udidTag[] = "UUID";
|
||||
const char profileNameTag[] = "Name";
|
||||
const char appIdTag[] = "AppIDName";
|
||||
const char expirationDateTag[] = "ExpirationDate";
|
||||
const char profileTeamIdTag[] = "TeamIdentifier";
|
||||
|
||||
static const QString xcodePlistPath = QDir::homePath() + "/Library/Preferences/com.apple.dt.Xcode.plist";
|
||||
static const QString provisioningProfileDirPath = QDir::homePath() + "/Library/MobileDevice/Provisioning Profiles";
|
||||
|
||||
static Core::Id deviceId(const Platform &platform)
|
||||
{
|
||||
if (platform.name.startsWith(QLatin1String("iphoneos-")))
|
||||
@@ -246,6 +265,20 @@ static QVersionNumber findXcodeVersion()
|
||||
return QVersionNumber();
|
||||
}
|
||||
|
||||
static QByteArray decodeProvisioningProfile(const QString &path)
|
||||
{
|
||||
QTC_ASSERT(!path.isEmpty(), return QByteArray());
|
||||
|
||||
Utils::SynchronousProcess p;
|
||||
p.setTimeoutS(3);
|
||||
// path is assumed to be valid file path to .mobileprovision
|
||||
const QStringList args = {"smime", "-inform", "der", "-verify", "-in", path};
|
||||
Utils::SynchronousProcessResponse res = p.runBlocking("openssl", args);
|
||||
if (res.result != Utils::SynchronousProcessResponse::Finished)
|
||||
qCDebug(iosCommonLog) << "Reading signed provisioning file failed" << path;
|
||||
return res.stdOut().toLatin1();
|
||||
}
|
||||
|
||||
void IosConfigurations::updateAutomaticKitList()
|
||||
{
|
||||
const QList<Platform> platforms = handledPlatforms();
|
||||
@@ -320,9 +353,9 @@ void IosConfigurations::updateAutomaticKitList()
|
||||
KitManager::deregisterKit(kit);
|
||||
}
|
||||
|
||||
static IosConfigurations *m_instance = 0;
|
||||
static IosConfigurations *m_instance = nullptr;
|
||||
|
||||
QObject *IosConfigurations::instance()
|
||||
IosConfigurations *IosConfigurations::instance()
|
||||
{
|
||||
return m_instance;
|
||||
}
|
||||
@@ -409,6 +442,137 @@ void IosConfigurations::setDeveloperPath(const FileName &devPath)
|
||||
}
|
||||
}
|
||||
|
||||
void IosConfigurations::initializeProvisioningData()
|
||||
{
|
||||
// Initialize provisioning data only on demand. i.e. when first call to a provisioing data API
|
||||
// is made.
|
||||
static bool initialized = false;
|
||||
if (initialized)
|
||||
return;
|
||||
initialized = true;
|
||||
|
||||
m_instance->loadProvisioningData(false);
|
||||
|
||||
// Watch the provisioing profiles folder and xcode plist for changes and
|
||||
// update the content accordingly.
|
||||
m_provisioningDataWatcher = new QFileSystemWatcher(this);
|
||||
m_provisioningDataWatcher->addPath(xcodePlistPath);
|
||||
m_provisioningDataWatcher->addPath(provisioningProfileDirPath);
|
||||
connect(m_provisioningDataWatcher, &QFileSystemWatcher::directoryChanged,
|
||||
std::bind(&IosConfigurations::loadProvisioningData, this, true));
|
||||
connect(m_provisioningDataWatcher, &QFileSystemWatcher::fileChanged,
|
||||
std::bind(&IosConfigurations::loadProvisioningData, this, true));
|
||||
}
|
||||
|
||||
void IosConfigurations::loadProvisioningData(bool notify)
|
||||
{
|
||||
m_developerTeams.clear();
|
||||
m_provisioningProfiles.clear();
|
||||
|
||||
// Populate Team id's
|
||||
const QSettings xcodeSettings(xcodePlistPath, QSettings::NativeFormat);
|
||||
const QVariantMap teamMap = xcodeSettings.value(provisioningTeamsTag).toMap();
|
||||
QList<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)
|
||||
{
|
||||
if (!l.isValid())
|
||||
@@ -455,5 +619,52 @@ QList<ToolChain *> IosToolChainFactory::autoDetect(const QList<ToolChain *> &exi
|
||||
return Utils::transform(toolChains, [](ClangToolChain *tc) -> ToolChain * { return tc; });
|
||||
}
|
||||
|
||||
QString DevelopmentTeam::identifier() const
|
||||
{
|
||||
return m_identifier;
|
||||
}
|
||||
|
||||
QString DevelopmentTeam::displayName() const
|
||||
{
|
||||
return QString("%1 - %2").arg(m_email).arg(m_name);
|
||||
}
|
||||
|
||||
QString DevelopmentTeam::details() const
|
||||
{
|
||||
return tr("%1 - Free Provisioning Team : %2")
|
||||
.arg(m_identifier).arg(m_freeTeam ? tr("Yes") : tr("No"));
|
||||
}
|
||||
|
||||
QDebug &operator<<(QDebug &stream, DevelopmentTeamPtr team)
|
||||
{
|
||||
QTC_ASSERT(team, return stream);
|
||||
stream << team->displayName() << team->identifier() << team->isFreeProfile();
|
||||
foreach (auto profile, team->m_profiles)
|
||||
stream << "Profile:" << profile;
|
||||
return stream;
|
||||
}
|
||||
|
||||
QString ProvisioningProfile::identifier() const
|
||||
{
|
||||
return m_identifier;
|
||||
}
|
||||
|
||||
QString ProvisioningProfile::displayName() const
|
||||
{
|
||||
return m_name;
|
||||
}
|
||||
|
||||
QString ProvisioningProfile::details() const
|
||||
{
|
||||
return tr("Team: %1\nApp ID: %2\nExpiration date: %3").arg(m_team->identifier()).arg(m_appID)
|
||||
.arg(m_expirationDate.toLocalTime().toString(Qt::SystemLocaleShortDate));
|
||||
}
|
||||
|
||||
QDebug &operator<<(QDebug &stream, std::shared_ptr<ProvisioningProfile> profile)
|
||||
{
|
||||
QTC_ASSERT(profile, return stream);
|
||||
return stream << profile->displayName() << profile->identifier() << profile->details();
|
||||
}
|
||||
|
||||
} // namespace Internal
|
||||
} // namespace Ios
|
||||
|
||||
@@ -29,18 +29,72 @@
|
||||
#include <projectexplorer/toolchain.h>
|
||||
#include <utils/fileutils.h>
|
||||
|
||||
#include <QDateTime>
|
||||
#include <QObject>
|
||||
#include <QString>
|
||||
#include <QStringList>
|
||||
#include <QVersionNumber>
|
||||
|
||||
#include <memory>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
class QSettings;
|
||||
class QFileSystemWatcher;
|
||||
QT_END_NAMESPACE
|
||||
|
||||
namespace Ios {
|
||||
namespace Internal {
|
||||
|
||||
class DevelopmentTeam;
|
||||
|
||||
class ProvisioningProfile
|
||||
{
|
||||
Q_DECLARE_TR_FUNCTIONS(ProvisioningProfile)
|
||||
public:
|
||||
ProvisioningProfile() {}
|
||||
std::shared_ptr<DevelopmentTeam> 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
|
||||
{
|
||||
Q_OBJECT
|
||||
@@ -50,13 +104,12 @@ public:
|
||||
QList<ProjectExplorer::ToolChain *> autoDetect(const QList<ProjectExplorer::ToolChain *> &existingToolChains) override;
|
||||
};
|
||||
|
||||
|
||||
class IosConfigurations : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
static QObject *instance();
|
||||
static IosConfigurations *instance();
|
||||
static void initialize();
|
||||
static bool ignoreAllDevices();
|
||||
static void setIgnoreAllDevices(bool ignoreDevices);
|
||||
@@ -64,6 +117,13 @@ public:
|
||||
static QVersionNumber xcodeVersion();
|
||||
static Utils::FileName lldbPath();
|
||||
static void updateAutomaticKitList();
|
||||
static const DevelopmentTeams &developmentTeams();
|
||||
static DevelopmentTeamPtr developmentTeam(const QString &teamID);
|
||||
static const ProvisioningProfiles &provisioningProfiles();
|
||||
static ProvisioningProfilePtr provisioningProfile(const QString &profileID);
|
||||
|
||||
signals:
|
||||
void provisioningDataChanged();
|
||||
|
||||
private:
|
||||
IosConfigurations(QObject *parent);
|
||||
@@ -71,11 +131,17 @@ private:
|
||||
void save();
|
||||
void updateSimulators();
|
||||
static void setDeveloperPath(const Utils::FileName &devPath);
|
||||
void initializeProvisioningData();
|
||||
void loadProvisioningData(bool notify = true);
|
||||
|
||||
Utils::FileName m_developerPath;
|
||||
QVersionNumber m_xcodeVersion;
|
||||
bool m_ignoreAllDevices;
|
||||
QFileSystemWatcher *m_provisioningDataWatcher;
|
||||
ProvisioningProfiles m_provisioningProfiles;
|
||||
DevelopmentTeams m_developerTeams;
|
||||
};
|
||||
|
||||
QDebug &operator<<(QDebug &stream, std::shared_ptr<ProvisioningProfile> profile);
|
||||
QDebug &operator<<(QDebug &stream, std::shared_ptr<DevelopmentTeam> team);
|
||||
} // namespace Internal
|
||||
} // namespace Ios
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
|
||||
#include "iosplugin.h"
|
||||
|
||||
#include "iosbuildconfiguration.h"
|
||||
#include "iosbuildstep.h"
|
||||
#include "iosconfigurations.h"
|
||||
#include "iosconstants.h"
|
||||
@@ -64,6 +65,7 @@ bool IosPlugin::initialize(const QStringList &arguments, QString *errorMessage)
|
||||
|
||||
Internal::IosConfigurations::initialize();
|
||||
|
||||
addAutoReleasedObject(new Internal::IosBuildConfigurationFactory);
|
||||
addAutoReleasedObject(new Internal::IosToolChainFactory);
|
||||
addAutoReleasedObject(new Internal::IosRunControlFactory);
|
||||
addAutoReleasedObject(new Internal::IosRunConfigurationFactory);
|
||||
|
||||
@@ -29,7 +29,6 @@ HEADERS += \
|
||||
project/nimcompilerbuildstepfactory.h \
|
||||
project/nimcompilercleanstepfactory.h \
|
||||
project/nimbuildconfigurationwidget.h \
|
||||
project/nimruncontrol.h \
|
||||
project/nimruncontrolfactory.h \
|
||||
editor/nimeditorfactory.h \
|
||||
settings/nimcodestylesettingspage.h \
|
||||
@@ -59,7 +58,6 @@ SOURCES += \
|
||||
project/nimcompilerbuildstepfactory.cpp \
|
||||
project/nimcompilercleanstepfactory.cpp \
|
||||
project/nimbuildconfigurationwidget.cpp \
|
||||
project/nimruncontrol.cpp \
|
||||
project/nimruncontrolfactory.cpp \
|
||||
editor/nimeditorfactory.cpp \
|
||||
settings/nimcodestylesettingspage.cpp \
|
||||
|
||||
@@ -49,7 +49,6 @@ QtcPlugin {
|
||||
"nimrunconfiguration.h", "nimrunconfiguration.cpp",
|
||||
"nimrunconfigurationfactory.h", "nimrunconfigurationfactory.cpp",
|
||||
"nimrunconfigurationwidget.h", "nimrunconfigurationwidget.cpp",
|
||||
"nimruncontrol.h", "nimruncontrol.cpp",
|
||||
"nimruncontrolfactory.h", "nimruncontrolfactory.cpp",
|
||||
"nimtoolchain.h", "nimtoolchain.cpp",
|
||||
"nimtoolchainfactory.h", "nimtoolchainfactory.cpp",
|
||||
|
||||
@@ -156,7 +156,7 @@ void NimProject::updateProject()
|
||||
|
||||
auto newRoot = new NimProjectNode(*this, projectDirectory());
|
||||
newRoot->setDisplayName(displayName());
|
||||
newRoot->buildTree(fileNodes);
|
||||
newRoot->addNestedNodes(fileNodes);
|
||||
setRootProjectNode(newRoot);
|
||||
|
||||
emit fileListChanged();
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -25,7 +25,6 @@
|
||||
|
||||
#include "nimruncontrolfactory.h"
|
||||
#include "nimrunconfiguration.h"
|
||||
#include "nimruncontrol.h"
|
||||
|
||||
namespace Nim {
|
||||
|
||||
@@ -39,7 +38,7 @@ ProjectExplorer::RunControl *NimRunControlFactory::create(ProjectExplorer::RunCo
|
||||
{
|
||||
Q_UNUSED(errorMessage)
|
||||
QTC_ASSERT(canRun(runConfiguration, mode), return 0);
|
||||
return new NimRunControl(static_cast<NimRunConfiguration *>(runConfiguration), mode);
|
||||
return new ProjectExplorer::SimpleRunControl(runConfiguration, mode);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
|
||||
#include <QFileInfo>
|
||||
#include <QProcess>
|
||||
#include <QRegExp>
|
||||
|
||||
using namespace ProjectExplorer;
|
||||
using namespace Utils;
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
#include <QDebug>
|
||||
#include <QtEndian>
|
||||
#include <QFile>
|
||||
#include <QRegExp>
|
||||
#include <QString>
|
||||
#include <QStringList>
|
||||
#include <QSysInfo>
|
||||
|
||||
@@ -455,6 +455,7 @@ ToolChain::PredefinedMacrosRunner GccToolChain::createPredefinedMacrosRunner() c
|
||||
} else if (a == "-m128bit-long-double" || a == "-m32" || a == "-m3dnow" || a == "-m3dnowa"
|
||||
|| a == "-m64" || a == "-m96bit-long-double" || a == "-mabm" || a == "-maes"
|
||||
|| a.startsWith("-march=") || a == "-mavx" || a.startsWith("-masm=")
|
||||
|| a.startsWith("-mfloat-abi")
|
||||
|| a == "-mcx16" || a == "-mfma" || a == "-mfma4" || a == "-mlwp"
|
||||
|| a == "-mpclmul" || a == "-mpopcnt" || a == "-msse" || a == "-msse2"
|
||||
|| a == "-msse2avx" || a == "-msse3" || a == "-msse4" || a == "-msse4.1"
|
||||
@@ -907,17 +908,6 @@ ToolChain *GccToolChainFactory::create(Core::Id language)
|
||||
QList<ToolChain *> GccToolChainFactory::autoDetect(const QList<ToolChain *> &alreadyKnown)
|
||||
{
|
||||
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,
|
||||
Constants::GCC_TOOLCHAIN_TYPEID, alreadyKnown));
|
||||
tcs.append(autoDetectToolchains("gcc", Abi::hostAbi(), Constants::C_LANGUAGE_ID,
|
||||
|
||||
@@ -25,7 +25,6 @@
|
||||
|
||||
#include "localapplicationruncontrol.h"
|
||||
#include "runnables.h"
|
||||
#include "environmentaspect.h"
|
||||
|
||||
#include <projectexplorer/projectexplorerconstants.h>
|
||||
#include <projectexplorer/kitinformation.h>
|
||||
@@ -34,91 +33,11 @@
|
||||
#include <utils/utilsicons.h>
|
||||
#include <utils/qtcassert.h>
|
||||
|
||||
#include <QDir>
|
||||
|
||||
using namespace Utils;
|
||||
|
||||
namespace ProjectExplorer {
|
||||
namespace Internal {
|
||||
|
||||
class LocalApplicationRunControl : public RunControl
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
LocalApplicationRunControl(RunConfiguration *runConfiguration, Core::Id mode);
|
||||
|
||||
void start() override;
|
||||
StopResult stop() override;
|
||||
|
||||
private:
|
||||
void processStarted();
|
||||
void processExited(int exitCode, QProcess::ExitStatus status);
|
||||
|
||||
ApplicationLauncher m_applicationLauncher;
|
||||
};
|
||||
|
||||
LocalApplicationRunControl::LocalApplicationRunControl(RunConfiguration *rc, Core::Id mode)
|
||||
: RunControl(rc, mode)
|
||||
{
|
||||
setRunnable(rc->runnable());
|
||||
setIcon(Utils::Icons::RUN_SMALL_TOOLBAR);
|
||||
connect(&m_applicationLauncher, &ApplicationLauncher::appendMessage,
|
||||
this, static_cast<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)
|
||||
{
|
||||
Target *target = runConfiguration ? runConfiguration->target() : nullptr;
|
||||
@@ -142,10 +61,8 @@ bool LocalApplicationRunControlFactory::canRun(RunConfiguration *runConfiguratio
|
||||
RunControl *LocalApplicationRunControlFactory::create(RunConfiguration *runConfiguration, Core::Id mode, QString *errorMessage)
|
||||
{
|
||||
Q_UNUSED(errorMessage)
|
||||
return new LocalApplicationRunControl(runConfiguration, mode);
|
||||
return new SimpleRunControl(runConfiguration, mode);
|
||||
}
|
||||
|
||||
} // namespace Internal
|
||||
} // namespace ProjectExplorer
|
||||
|
||||
#include "localapplicationruncontrol.moc"
|
||||
|
||||
@@ -419,7 +419,7 @@ void Project::setDocument(Core::IDocument *doc)
|
||||
d->m_document = doc;
|
||||
|
||||
if (!d->m_rootProjectNode) {
|
||||
auto newRoot = new ProjectNode(projectDirectory());
|
||||
auto newRoot = new ProjectNode(projectFilePath());
|
||||
newRoot->setDisplayName(displayName());
|
||||
newRoot->addNode(new FileNode(projectFilePath(), FileType::Project, false));
|
||||
setRootProjectNode(newRoot);
|
||||
|
||||
@@ -60,7 +60,8 @@ static FolderNode *folderNode(const FolderNode *folder, const Utils::FileName &d
|
||||
|
||||
static FolderNode *recursiveFindOrCreateFolderNode(FolderNode *folder,
|
||||
const Utils::FileName &directory,
|
||||
const Utils::FileName &overrideBaseDir)
|
||||
const Utils::FileName &overrideBaseDir,
|
||||
const FolderNode::FolderNodeFactory &factory)
|
||||
{
|
||||
Utils::FileName path = overrideBaseDir.isEmpty() ? folder->filePath() : overrideBaseDir;
|
||||
|
||||
@@ -90,7 +91,7 @@ static FolderNode *recursiveFindOrCreateFolderNode(FolderNode *folder,
|
||||
FolderNode *next = folderNode(parent, path);
|
||||
if (!next) {
|
||||
// No FolderNode yet, so create it
|
||||
auto tmp = new ProjectExplorer::FolderNode(path);
|
||||
auto tmp = factory(path);
|
||||
tmp->setDisplayName(part);
|
||||
parent->addNode(tmp);
|
||||
next = tmp;
|
||||
@@ -400,6 +401,37 @@ QIcon FolderNode::icon() const
|
||||
return m_icon;
|
||||
}
|
||||
|
||||
Node *FolderNode::findNode(const std::function<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,
|
||||
const std::function<void(FolderNode *)> &folderTask,
|
||||
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 *> result;
|
||||
@@ -468,16 +492,22 @@ QList<FolderNode*> FolderNode::folderNodes() const
|
||||
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
|
||||
QString parentDir = fn->filePath().toFileInfo().absolutePath();
|
||||
ProjectExplorer::FolderNode *folder
|
||||
= recursiveFindOrCreateFolderNode(this, Utils::FileName::fromString(parentDir),
|
||||
overrideBaseDir);
|
||||
folder->addNode(fn);
|
||||
QString parentDir = fileNode->filePath().toFileInfo().absolutePath();
|
||||
FolderNode *folder = recursiveFindOrCreateFolderNode(this, Utils::FileName::fromString(parentDir),
|
||||
overrideBaseDir, factory);
|
||||
folder->addNode(fileNode);
|
||||
|
||||
}
|
||||
|
||||
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
|
||||
@@ -673,7 +703,8 @@ ProjectNode::ProjectNode(const Utils::FileName &projectFilePath) :
|
||||
|
||||
QString ProjectNode::vcsTopic() const
|
||||
{
|
||||
const QString dir = filePath().toFileInfo().absolutePath();
|
||||
const QFileInfo fi = filePath().toFileInfo();
|
||||
const QString dir = fi.isDir() ? fi.absoluteFilePath() : fi.absolutePath();
|
||||
|
||||
if (Core::IVersionControl *const vc =
|
||||
Core::VcsManager::findVersionControlForDirectory(dir))
|
||||
|
||||
@@ -192,6 +192,9 @@ public:
|
||||
QString displayName() const override;
|
||||
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,
|
||||
const std::function<void(FolderNode *)> &folderTask = {},
|
||||
const std::function<bool(const FolderNode *)> &folderFilterTask = {}) const;
|
||||
@@ -199,9 +202,12 @@ public:
|
||||
const QList<Node *> nodes() const { return m_nodes; }
|
||||
QList<FileNode *> fileNodes() const;
|
||||
FileNode *fileNode(const Utils::FileName &file) const;
|
||||
QList<FileNode *> recursiveFileNodes() 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();
|
||||
|
||||
bool isAncesterOf(Node *n);
|
||||
|
||||
@@ -254,19 +254,6 @@ static inline AddNewTree *buildAddProjectTree(ProjectNode *root, const QString &
|
||||
return new AddNewTree(root, children, root->displayName());
|
||||
}
|
||||
|
||||
static inline AddNewTree *buildAddProjectTree(SessionNode *root, const QString &projectPath, Node *contextNode, BestNodeSelector *selector)
|
||||
{
|
||||
QList<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,
|
||||
Node *contextNode, BestNodeSelector *selector)
|
||||
{
|
||||
@@ -289,31 +276,6 @@ static inline AddNewTree *buildAddFilesTree(FolderNode *root, const QStringList
|
||||
return new AddNewTree(root, children, root->displayName());
|
||||
}
|
||||
|
||||
static inline AddNewTree *buildAddFilesTree(SessionNode *root, const QStringList &files,
|
||||
Node *contextNode, BestNodeSelector *selector)
|
||||
{
|
||||
QList<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:
|
||||
// --------------------------------------------------------------------
|
||||
@@ -491,7 +453,25 @@ void ProjectWizardPage::initializeProjectTree(Node *context, const QStringList &
|
||||
ProjectAction action)
|
||||
{
|
||||
BestNodeSelector selector(m_commonDirectory, paths);
|
||||
AddNewTree *tree = getChoices(paths, kind, context, &selector);
|
||||
|
||||
AddNewTree *tree;
|
||||
SessionNode *root = SessionManager::sessionNode();
|
||||
QList<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());
|
||||
|
||||
|
||||
@@ -32,18 +32,22 @@
|
||||
#include "buildconfiguration.h"
|
||||
#include "environmentaspect.h"
|
||||
#include "kitinformation.h"
|
||||
#include "runnables.h"
|
||||
|
||||
#include <extensionsystem/pluginmanager.h>
|
||||
|
||||
#include <utils/algorithm.h>
|
||||
#include <utils/outputformatter.h>
|
||||
#include <utils/checkablemessagebox.h>
|
||||
#include <utils/outputformatter.h>
|
||||
#include <utils/qtcassert.h>
|
||||
#include <utils/utilsicons.h>
|
||||
|
||||
#include <coreplugin/icore.h>
|
||||
#include <coreplugin/icontext.h>
|
||||
|
||||
#include <QTimer>
|
||||
#include <QDir>
|
||||
#include <QPushButton>
|
||||
#include <QTimer>
|
||||
|
||||
#ifdef Q_OS_OSX
|
||||
#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);
|
||||
}
|
||||
|
||||
|
||||
// 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
|
||||
|
||||
@@ -51,7 +51,10 @@ class RunConfigWidget;
|
||||
class RunControl;
|
||||
class Target;
|
||||
|
||||
namespace Internal { class RunControlPrivate; }
|
||||
namespace Internal {
|
||||
class RunControlPrivate;
|
||||
class SimpleRunControlPrivate;
|
||||
} // Internal
|
||||
|
||||
/**
|
||||
* An interface for a hunk of global or per-project
|
||||
@@ -414,4 +417,21 @@ private:
|
||||
Internal::RunControlPrivate *d;
|
||||
};
|
||||
|
||||
class PROJECTEXPLORER_EXPORT SimpleRunControl : public RunControl
|
||||
{
|
||||
public:
|
||||
SimpleRunControl(RunConfiguration *runConfiguration, Core::Id mode);
|
||||
~SimpleRunControl();
|
||||
|
||||
ApplicationLauncher &applicationLauncher();
|
||||
void start() override;
|
||||
StopResult stop() override;
|
||||
|
||||
virtual void onProcessStarted();
|
||||
virtual void onProcessFinished(int exitCode, QProcess::ExitStatus status);
|
||||
|
||||
private:
|
||||
Internal::SimpleRunControlPrivate *d;
|
||||
};
|
||||
|
||||
} // namespace ProjectExplorer
|
||||
|
||||
@@ -43,6 +43,7 @@
|
||||
|
||||
#include <QApplication>
|
||||
#include <QDir>
|
||||
#include <QRegExp>
|
||||
|
||||
using namespace Utils;
|
||||
|
||||
|
||||
@@ -225,6 +225,15 @@ QVariantMap ToolChain::toMap() const
|
||||
result.insert(QLatin1String(ID_KEY), idToSave);
|
||||
result.insert(QLatin1String(DISPLAY_NAME_KEY), displayName());
|
||||
result.insert(QLatin1String(AUTODETECT_KEY), isAutoDetected());
|
||||
// <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());
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -59,6 +59,7 @@
|
||||
#include <QtPlugin>
|
||||
#include <QCoreApplication>
|
||||
#include <QFormLayout>
|
||||
#include <QRegExp>
|
||||
|
||||
using namespace Core;
|
||||
using namespace ProjectExplorer;
|
||||
@@ -197,6 +198,7 @@ public:
|
||||
bool fromMap(const QVariantMap &map) override;
|
||||
bool isEnabled() const override { return m_enabled; }
|
||||
QString disabledReason() const override;
|
||||
Runnable runnable() const override;
|
||||
|
||||
bool supportsDebugger() const { return true; }
|
||||
QString mainScript() const { return m_mainScript; }
|
||||
@@ -215,28 +217,6 @@ private:
|
||||
bool m_enabled;
|
||||
};
|
||||
|
||||
class PythonRunControl : public RunControl
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
PythonRunControl(PythonRunConfiguration *runConfiguration, Core::Id mode);
|
||||
|
||||
void start() override;
|
||||
StopResult stop() override;
|
||||
|
||||
private:
|
||||
void processStarted();
|
||||
void processExited(int exitCode, QProcess::ExitStatus status);
|
||||
void slotAppendMessage(const QString &err, Utils::OutputFormat isError);
|
||||
|
||||
ApplicationLauncher m_applicationLauncher;
|
||||
QString m_interpreter;
|
||||
QString m_mainScript;
|
||||
QString m_commandLineArguments;
|
||||
Utils::Environment m_environment;
|
||||
ApplicationLauncher::Mode m_runMode;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
||||
PythonRunConfiguration::PythonRunConfiguration(Target *parent, Core::Id id) :
|
||||
@@ -307,6 +287,17 @@ QString PythonRunConfiguration::disabledReason() const
|
||||
return QString();
|
||||
}
|
||||
|
||||
Runnable PythonRunConfiguration::runnable() const
|
||||
{
|
||||
StandardRunnable r;
|
||||
QtcProcess::addArg(&r.commandLineArguments, m_mainScript);
|
||||
QtcProcess::addArgs(&r.commandLineArguments, extraAspect<ArgumentsAspect>()->arguments());
|
||||
r.executable = m_interpreter;
|
||||
r.runMode = extraAspect<TerminalAspect>()->runMode();
|
||||
r.environment = extraAspect<EnvironmentAspect>()->environment();
|
||||
return r;
|
||||
}
|
||||
|
||||
QString PythonRunConfiguration::arguments() const
|
||||
{
|
||||
auto aspect = extraAspect<ArgumentsAspect>();
|
||||
@@ -566,14 +557,11 @@ void PythonProject::refresh()
|
||||
parseProject();
|
||||
|
||||
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);
|
||||
newRoot->buildTree(fileNodes);
|
||||
for (const QString &f : m_files) {
|
||||
const QString displayName = baseDir.relativeFilePath(f);
|
||||
newRoot->addNestedNode(new PythonFileNode(FileName::fromString(f), displayName));
|
||||
}
|
||||
setRootProjectNode(newRoot);
|
||||
|
||||
emit parsingFinished();
|
||||
@@ -732,95 +720,18 @@ public:
|
||||
|
||||
bool PythonRunControlFactory::canRun(RunConfiguration *runConfiguration, Core::Id mode) const
|
||||
{
|
||||
return mode == ProjectExplorer::Constants::NORMAL_RUN_MODE
|
||||
&& dynamic_cast<PythonRunConfiguration *>(runConfiguration);
|
||||
auto rc = 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)
|
||||
{
|
||||
Q_UNUSED(errorMessage)
|
||||
QTC_ASSERT(canRun(runConfiguration, mode), return 0);
|
||||
return new PythonRunControl(static_cast<PythonRunConfiguration *>(runConfiguration), mode);
|
||||
return new SimpleRunControl(runConfiguration, mode);
|
||||
}
|
||||
|
||||
// PythonRunControl
|
||||
|
||||
PythonRunControl::PythonRunControl(PythonRunConfiguration *rc, Core::Id mode)
|
||||
: RunControl(rc, mode)
|
||||
{
|
||||
setIcon(Utils::Icons::RUN_SMALL_TOOLBAR);
|
||||
|
||||
m_interpreter = rc->interpreter();
|
||||
m_mainScript = rc->mainScript();
|
||||
m_runMode = rc->extraAspect<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();
|
||||
}
|
||||
// PythonRunConfigurationWidget
|
||||
|
||||
void PythonRunConfigurationWidget::setInterpreter(const QString &interpreter)
|
||||
{
|
||||
|
||||
@@ -55,15 +55,13 @@ ProjectExplorer::FileType fileType(const qbs::ArtifactData &artifact)
|
||||
|
||||
void setupArtifacts(ProjectExplorer::FolderNode *root, const QList<qbs::ArtifactData> &artifacts)
|
||||
{
|
||||
QList<ProjectExplorer::FileNode *> fileNodes
|
||||
= Utils::transform(artifacts, [](const qbs::ArtifactData &ad) {
|
||||
for (const qbs::ArtifactData &ad : artifacts) {
|
||||
const Utils::FileName path = Utils::FileName::fromString(ad.filePath());
|
||||
const ProjectExplorer::FileType type = fileType(ad);
|
||||
const bool isGenerated = ad.isGenerated();
|
||||
return new ProjectExplorer::FileNode(path, type, isGenerated);
|
||||
});
|
||||
root->addNestedNode(new ProjectExplorer::FileNode(path, type, isGenerated));
|
||||
};
|
||||
|
||||
root->buildTree(fileNodes);
|
||||
root->compress();
|
||||
}
|
||||
|
||||
@@ -190,14 +188,12 @@ QbsRootProjectNode *QbsNodeTreeBuilder::buildTree(QbsProject *project)
|
||||
ProjectExplorer::NodeType::Folder,
|
||||
QCoreApplication::translate("QbsRootProjectNode", "Qbs files"));
|
||||
|
||||
QList<ProjectExplorer::FileNode *> projectBuildSystemFiles;
|
||||
Utils::FileName base = project->projectDirectory();
|
||||
for (const QString &f : unreferencedBuildSystemFiles(project->qbsProject())) {
|
||||
const Utils::FileName filePath = Utils::FileName::fromString(f);
|
||||
if (filePath.isChildOf(base))
|
||||
projectBuildSystemFiles.append(new ProjectExplorer::FileNode(filePath, ProjectExplorer::FileType::Project, false));
|
||||
root->addNestedNode(new ProjectExplorer::FileNode(filePath, ProjectExplorer::FileType::Project, false));
|
||||
}
|
||||
buildSystemFiles->buildTree(projectBuildSystemFiles);
|
||||
buildSystemFiles->compress();
|
||||
root->addNode(buildSystemFiles);
|
||||
|
||||
|
||||
@@ -996,6 +996,7 @@ void QbsProject::updateCppCodeModel()
|
||||
rpp.setDisplayName(grp.name());
|
||||
rpp.setProjectFileLocation(grp.location().filePath(),
|
||||
grp.location().line(), grp.location().column());
|
||||
rpp.setBuildSystemTarget(uniqueProductName(prd));
|
||||
|
||||
QHash<QString, qbs::ArtifactData> filePathToSourceArtifact;
|
||||
bool hasCFiles = false;
|
||||
|
||||
@@ -33,6 +33,7 @@
|
||||
|
||||
#include <QFileInfo>
|
||||
#include <QDir>
|
||||
#include <QRegExp>
|
||||
#include <QSet>
|
||||
|
||||
static QString headerGuard(const QString &header)
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
#include <QDebug>
|
||||
#include <QDir>
|
||||
#include <QFileInfo>
|
||||
#include <QRegExp>
|
||||
#include <QTextStream>
|
||||
#include <QLoggingCategory>
|
||||
|
||||
|
||||
@@ -172,10 +172,8 @@ static void createTree(const QmakePriFile *pri, QmakePriFileNode *node)
|
||||
vfolder->addNode(resourceNode);
|
||||
}
|
||||
} else {
|
||||
QList<FileNode *> fileNodes = Utils::transform<QList>(newFilePaths, [type](const FileName &fn) {
|
||||
return new FileNode(fn, type, false);
|
||||
});
|
||||
vfolder->buildTree(fileNodes);
|
||||
for (const FileName &fn : newFilePaths)
|
||||
vfolder->addNestedNode(new FileNode(fn, type, false));
|
||||
for (FolderNode *fn : vfolder->folderNodes())
|
||||
fn->compress();
|
||||
}
|
||||
|
||||
@@ -345,6 +345,7 @@ void QmakeProject::updateCppCodeModel()
|
||||
CppTools::RawProjectPart rpp;
|
||||
rpp.setDisplayName(pro->displayName());
|
||||
rpp.setProjectFileLocation(pro->filePath().toString());
|
||||
rpp.setBuildSystemTarget(pro->targetInformation().target);
|
||||
// TODO: Handle QMAKE_CFLAGS
|
||||
rpp.setFlagsForCxx({cxxToolChain, pro->variableValue(Variable::CppFlags)});
|
||||
rpp.setDefines(pro->cxxDefines());
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user