Merge remote-tracking branch 'origin/4.6'

Conflicts:
	src/plugins/android/androidrunnable.h
	src/plugins/android/androidrunner.cpp
	src/plugins/qmakeandroidsupport/qmakeandroidrunconfiguration.cpp
	src/plugins/qmakeprojectmanager/qmakeproject.cpp
	src/plugins/qmlprofiler/qmlprofilerruncontrol.cpp

Change-Id: I68093d44cfd672347eab82459ff70c21a32297ce
This commit is contained in:
Eike Ziller
2018-04-17 10:09:35 +02:00
49 changed files with 1014 additions and 804 deletions

View File

@@ -18,6 +18,7 @@ HEADERS += \
androiderrormessage.h \ androiderrormessage.h \
androidglobal.h \ androidglobal.h \
androidrunner.h \ androidrunner.h \
androidrunnerworker.h \
androiddebugsupport.h \ androiddebugsupport.h \
androidqtversionfactory.h \ androidqtversionfactory.h \
androidqtversion.h \ androidqtversion.h \
@@ -66,6 +67,7 @@ SOURCES += \
androidtoolchain.cpp \ androidtoolchain.cpp \
androiderrormessage.cpp \ androiderrormessage.cpp \
androidrunner.cpp \ androidrunner.cpp \
androidrunnerworker.cpp \
androiddebugsupport.cpp \ androiddebugsupport.cpp \
androidqtversionfactory.cpp \ androidqtversionfactory.cpp \
androidqtversion.cpp \ androidqtversion.cpp \

View File

@@ -93,6 +93,8 @@ Project {
"androidrunnable.h", "androidrunnable.h",
"androidrunner.cpp", "androidrunner.cpp",
"androidrunner.h", "androidrunner.h",
"androidrunnerworker.cpp",
"androidrunnerworker.h",
"androidsdkmanager.cpp", "androidsdkmanager.cpp",
"androidsdkmanager.h", "androidsdkmanager.h",
"androidsdkmanagerwidget.cpp", "androidsdkmanagerwidget.cpp",

View File

@@ -164,6 +164,7 @@ bool AndroidDeployQtStep::init(QList<const BuildStep *> &earlierSteps)
m_filesToPull["/system/" + libDirName + "/libc.so"] = buildDir + "libc.so"; m_filesToPull["/system/" + libDirName + "/libc.so"] = buildDir + "libc.so";
AndroidManager::setDeviceSerialNumber(target(), m_serialNumber); AndroidManager::setDeviceSerialNumber(target(), m_serialNumber);
AndroidManager::setDeviceApiLevel(target(), info.sdk);
QtSupport::BaseQtVersion *version = QtSupport::QtKitInformation::qtVersion(target()->kit()); QtSupport::BaseQtVersion *version = QtSupport::QtKitInformation::qtVersion(target()->kit());
@@ -325,11 +326,12 @@ AndroidDeployQtStep::DeployErrorCode AndroidDeployQtStep::runDeploy(QFutureInter
emit addOutput(tr("The process \"%1\" crashed.").arg(m_command), BuildStep::OutputFormat::ErrorMessage); emit addOutput(tr("The process \"%1\" crashed.").arg(m_command), BuildStep::OutputFormat::ErrorMessage);
} }
if (exitCode == 0 && exitStatus == QProcess::NormalExit) { if (deployError != NoError) {
if (deployError != NoError && m_uninstallPreviousPackageRun) { if (m_uninstallPreviousPackageRun)
deployError = Failure; deployError = Failure; // Even re-install failed. Set to Failure.
} } else if (exitCode != 0 || exitStatus != QProcess::NormalExit) {
} else { // Set the deployError to Failure when no deployError code was detected
// but the adb tool failed otherwise relay the detected deployError.
deployError = Failure; deployError = Failure;
} }

View File

@@ -241,6 +241,16 @@ void AndroidManager::setDeviceSerialNumber(ProjectExplorer::Target *target, cons
target->setNamedSettings(AndroidDeviceSn, deviceSerialNumber); target->setNamedSettings(AndroidDeviceSn, deviceSerialNumber);
} }
int AndroidManager::deviceApiLevel(ProjectExplorer::Target *target)
{
return target->namedSettings(ApiLevelKey).toInt();
}
void AndroidManager::setDeviceApiLevel(ProjectExplorer::Target *target, int level)
{
target->setNamedSettings(ApiLevelKey, level);
}
QPair<int, int> AndroidManager::apiLevelRange() QPair<int, int> AndroidManager::apiLevelRange()
{ {
return qMakePair(9, 26); return qMakePair(9, 26);

View File

@@ -56,6 +56,9 @@ public:
static QString deviceSerialNumber(ProjectExplorer::Target *target); static QString deviceSerialNumber(ProjectExplorer::Target *target);
static void setDeviceSerialNumber(ProjectExplorer::Target *target, const QString &deviceSerialNumber); static void setDeviceSerialNumber(ProjectExplorer::Target *target, const QString &deviceSerialNumber);
static int deviceApiLevel(ProjectExplorer::Target *target);
static void setDeviceApiLevel(ProjectExplorer::Target *target, int level);
static QString buildTargetSDK(ProjectExplorer::Target *target); static QString buildTargetSDK(ProjectExplorer::Target *target);
static bool signPackage(ProjectExplorer::Target *target); static bool signPackage(ProjectExplorer::Target *target);

View File

@@ -42,6 +42,7 @@ struct ANDROID_EXPORT AndroidRunnable
QString deviceSerialNumber; QString deviceSerialNumber;
QString extraAppParams; QString extraAppParams;
Utils::Environment extraEnvVars; Utils::Environment extraEnvVars;
int apiLevel = -1;
QString displayName() const { return packageName; } QString displayName() const { return packageName; }
static void *staticTypeId; static void *staticTypeId;

View File

@@ -28,35 +28,17 @@
#include "androiddeployqtstep.h" #include "androiddeployqtstep.h"
#include "androidconfigurations.h" #include "androidconfigurations.h"
#include "androidglobal.h"
#include "androidrunconfiguration.h" #include "androidrunconfiguration.h"
#include "androidmanager.h" #include "androidmanager.h"
#include "androidavdmanager.h" #include "androidavdmanager.h"
#include "androidrunnerworker.h"
#include <debugger/debuggerrunconfigurationaspect.h>
#include <coreplugin/messagemanager.h> #include <coreplugin/messagemanager.h>
#include <projectexplorer/projectexplorer.h> #include <projectexplorer/projectexplorer.h>
#include <projectexplorer/projectexplorerconstants.h>
#include <projectexplorer/projectexplorersettings.h> #include <projectexplorer/projectexplorersettings.h>
#include <projectexplorer/target.h> #include <projectexplorer/target.h>
#include <qtsupport/qtkitinformation.h>
#include <utils/qtcassert.h>
#include <utils/runextensions.h>
#include <utils/synchronousprocess.h>
#include <utils/temporaryfile.h>
#include <utils/url.h> #include <utils/url.h>
#include <chrono>
#include <memory>
#include <QApplication>
#include <QDir>
#include <QRegExp>
#include <QTime>
#include <QTcpServer>
#include <QTcpSocket>
using namespace std;
using namespace std::placeholders;
using namespace ProjectExplorer; using namespace ProjectExplorer;
using namespace Utils; using namespace Utils;
@@ -127,568 +109,10 @@ using namespace Utils;
namespace Android { namespace Android {
namespace Internal { namespace Internal {
const int MIN_SOCKET_HANDSHAKE_PORT = 20001; AndroidRunner::AndroidRunner(RunControl *runControl,
const int MAX_SOCKET_HANDSHAKE_PORT = 20999; const QString &intentName,
static const QString pidScript = QStringLiteral("for p in /proc/[0-9]*; " const QString &extraAppParams,
"do cat <$p/cmdline && echo :${p##*/}; done"); const Utils::Environment &extraEnvVars)
static const QString pidPollingScript = QStringLiteral("while true; do sleep 1; "
"cat /proc/%1/cmdline > /dev/null; done");
static const QString regExpLogcat = QStringLiteral("[0-9\\-]*" // date
"\\s+"
"[0-9\\-:.]*"// time
"\\s*"
"(\\d*)" // pid 1. capture
"\\s+"
"\\d*" // unknown
"\\s+"
"(\\w)" // message type 2. capture
"\\s+"
"(.*): " // source 3. capture
"(.*)" // message 4. capture
"[\\n\\r]*"
);
static int APP_START_TIMEOUT = 45000;
static bool isTimedOut(const chrono::high_resolution_clock::time_point &start,
int msecs = APP_START_TIMEOUT)
{
bool timedOut = false;
auto end = chrono::high_resolution_clock::now();
if (chrono::duration_cast<chrono::milliseconds>(end-start).count() > msecs)
timedOut = true;
return timedOut;
}
static qint64 extractPID(const QByteArray &output, const QString &packageName)
{
qint64 pid = -1;
foreach (auto tuple, output.split('\n')) {
tuple = tuple.simplified();
if (!tuple.isEmpty()) {
auto parts = tuple.split(':');
QString commandName = QString::fromLocal8Bit(parts.first());
if (parts.length() == 2 && commandName == packageName) {
pid = parts.last().toLongLong();
break;
}
}
}
return pid;
}
void findProcessPID(QFutureInterface<qint64> &fi, const QString &adbPath,
QStringList selector, const QString &packageName)
{
if (packageName.isEmpty())
return;
qint64 processPID = -1;
chrono::high_resolution_clock::time_point start = chrono::high_resolution_clock::now();
do {
QThread::msleep(200);
const QByteArray out = Utils::SynchronousProcess()
.runBlocking(adbPath, selector << QStringLiteral("shell") << pidScript)
.allRawOutput();
processPID = extractPID(out, packageName);
} while (processPID == -1 && !isTimedOut(start) && !fi.isCanceled());
if (!fi.isCanceled())
fi.reportResult(processPID);
}
static void deleter(QProcess *p)
{
p->kill();
p->waitForFinished();
// Might get deleted from its own signal handler.
p->deleteLater();
}
class AndroidRunnerWorker : public QObject
{
Q_OBJECT
enum DebugHandShakeType {
PingPongFiles,
SocketHandShake
};
public:
AndroidRunnerWorker(RunControl *runControl, const AndroidRunnable &runnable);
~AndroidRunnerWorker();
void asyncStart();
void asyncStop();
void setAndroidRunnable(const AndroidRunnable &runnable);
void handleRemoteDebuggerRunning();
signals:
void remoteProcessStarted(Utils::Port gdbServerPort, const QUrl &qmlServer, int pid);
void remoteProcessFinished(const QString &errString = QString());
void remoteOutput(const QString &output);
void remoteErrorOutput(const QString &output);
private:
void onProcessIdChanged(qint64 pid);
void logcatReadStandardError();
void logcatReadStandardOutput();
void adbKill(qint64 pid);
QStringList selector() const;
void forceStop();
void findPs();
void logcatProcess(const QByteArray &text, QByteArray &buffer, bool onlyError);
bool adbShellAmNeedsQuotes();
bool runAdb(const QStringList &args, QString *exitMessage = nullptr, int timeoutS = 10);
// Create the processes and timer in the worker thread, for correct thread affinity
std::unique_ptr<QProcess, decltype(&deleter)> m_adbLogcatProcess;
std::unique_ptr<QProcess, decltype(&deleter)> m_psIsAlive;
QScopedPointer<QTcpSocket> m_socket;
QByteArray m_stdoutBuffer;
QByteArray m_stderrBuffer;
QFuture<qint64> m_pidFinder;
qint64 m_processPID = -1;
bool m_useCppDebugger = false;
QmlDebug::QmlDebugServicesPreset m_qmlDebugServices;
Utils::Port m_localGdbServerPort; // Local end of forwarded debug socket.
QUrl m_qmlServer;
QString m_pingFile;
QString m_pongFile;
QString m_gdbserverPath;
QString m_gdbserverSocket;
QString m_adb;
QRegExp m_logCatRegExp;
DebugHandShakeType m_handShakeMethod = SocketHandShake;
bool m_customPort = false;
AndroidRunnable m_androidRunnable;
int m_socketHandShakePort = MIN_SOCKET_HANDSHAKE_PORT;
};
AndroidRunnerWorker::AndroidRunnerWorker(RunControl *runControl, const AndroidRunnable &runnable)
: m_adbLogcatProcess(nullptr, deleter)
, m_psIsAlive(nullptr, deleter)
, m_logCatRegExp(regExpLogcat)
, m_androidRunnable(runnable)
{
auto runConfig = runControl->runConfiguration();
auto aspect = runConfig->extraAspect<Debugger::DebuggerRunConfigurationAspect>();
Core::Id runMode = runControl->runMode();
const bool debuggingMode = runMode == ProjectExplorer::Constants::DEBUG_RUN_MODE;
m_useCppDebugger = debuggingMode && aspect->useCppDebugger();
if (debuggingMode && aspect->useQmlDebugger())
m_qmlDebugServices = QmlDebug::QmlDebuggerServices;
else if (runMode == ProjectExplorer::Constants::QML_PROFILER_RUN_MODE)
m_qmlDebugServices = QmlDebug::QmlProfilerServices;
else if (runMode == ProjectExplorer::Constants::QML_PREVIEW_RUN_MODE)
m_qmlDebugServices = QmlDebug::QmlPreviewServices;
else
m_qmlDebugServices = QmlDebug::NoQmlDebugServices;
m_localGdbServerPort = Utils::Port(5039);
QTC_CHECK(m_localGdbServerPort.isValid());
if (m_qmlDebugServices != QmlDebug::NoQmlDebugServices) {
QTcpServer server;
QTC_ASSERT(server.listen(QHostAddress::LocalHost)
|| server.listen(QHostAddress::LocalHostIPv6),
qDebug() << tr("No free ports available on host for QML debugging."));
m_qmlServer.setScheme(Utils::urlTcpScheme());
m_qmlServer.setHost(server.serverAddress().toString());
m_qmlServer.setPort(server.serverPort());
}
m_adb = AndroidConfigurations::currentConfig().adbToolPath().toString();
QString packageDir = "/data/data/" + m_androidRunnable.packageName;
m_pingFile = packageDir + "/debug-ping";
m_pongFile = "/data/local/tmp/qt/debug-pong-" + m_androidRunnable.packageName;
m_gdbserverSocket = packageDir + "/debug-socket";
const QtSupport::BaseQtVersion *version = QtSupport::QtKitInformation::qtVersion(
runConfig->target()->kit());
if (version && version->qtVersion() >= QtSupport::QtVersionNumber(5, 4, 0))
m_gdbserverPath = packageDir + "/lib/libgdbserver.so";
else
m_gdbserverPath = packageDir + "/lib/gdbserver";
if (version && version->qtVersion() >= QtSupport::QtVersionNumber(5, 4, 0)) {
if (qEnvironmentVariableIsSet("QTC_ANDROID_USE_FILE_HANDSHAKE"))
m_handShakeMethod = PingPongFiles;
} else {
m_handShakeMethod = PingPongFiles;
}
if (qEnvironmentVariableIsSet("QTC_ANDROID_SOCKET_HANDSHAKE_PORT")) {
QByteArray envData = qgetenv("QTC_ANDROID_SOCKET_HANDSHAKE_PORT");
if (!envData.isEmpty()) {
bool ok = false;
int port = 0;
port = envData.toInt(&ok);
if (ok && port > 0 && port < 65535) {
m_socketHandShakePort = port;
m_customPort = true;
}
}
}
}
AndroidRunnerWorker::~AndroidRunnerWorker()
{
if (!m_pidFinder.isFinished())
m_pidFinder.cancel();
}
void AndroidRunnerWorker::forceStop()
{
runAdb({"shell", "am", "force-stop", m_androidRunnable.packageName}, nullptr, 30);
// try killing it via kill -9
const QByteArray out = Utils::SynchronousProcess()
.runBlocking(m_adb, selector() << QStringLiteral("shell") << pidScript)
.allRawOutput();
qint64 pid = extractPID(out.simplified(), m_androidRunnable.packageName);
if (pid != -1) {
adbKill(pid);
}
}
void AndroidRunnerWorker::asyncStart()
{
forceStop();
// Start the logcat process before app starts.
std::unique_ptr<QProcess, decltype(&deleter)> logcatProcess(new QProcess, deleter);
connect(logcatProcess.get(), &QProcess::readyReadStandardOutput,
this, &AndroidRunnerWorker::logcatReadStandardOutput);
connect(logcatProcess.get(), &QProcess::readyReadStandardError,
this, &AndroidRunnerWorker::logcatReadStandardError);
// Its assumed that the device or avd returned by selector() is online.
logcatProcess->start(m_adb, selector() << "logcat");
QString errorMessage;
if (m_useCppDebugger)
runAdb({"shell", "rm", m_pongFile}); // Remove pong file.
for (const QString &entry: m_androidRunnable.beforeStartAdbCommands)
runAdb(entry.split(' ', QString::SkipEmptyParts));
QStringList args({"shell", "am", "start"});
args << m_androidRunnable.amStartExtraArgs;
args << "-n" << m_androidRunnable.intentName;
if (m_useCppDebugger) {
if (!runAdb({"forward", "--remove", "tcp:" + m_localGdbServerPort.toString()})){
QTC_CHECK(false);
}
if (!runAdb({"forward", "tcp:" + m_localGdbServerPort.toString(),
"localfilesystem:" + m_gdbserverSocket}, &errorMessage)) {
emit remoteProcessFinished(tr("Failed to forward C++ debugging ports. Reason: %1.").arg(errorMessage));
return;
}
const QString pingPongSocket(m_androidRunnable.packageName + ".ping_pong_socket");
args << "-e" << "debug_ping" << "true";
if (m_handShakeMethod == SocketHandShake) {
args << "-e" << "ping_socket" << pingPongSocket;
} else if (m_handShakeMethod == PingPongFiles) {
args << "-e" << "ping_file" << m_pingFile;
args << "-e" << "pong_file" << m_pongFile;
}
QString gdbserverCommand = QString::fromLatin1(adbShellAmNeedsQuotes() ? "\"%1 --multi +%2\"" : "%1 --multi +%2")
.arg(m_gdbserverPath).arg(m_gdbserverSocket);
args << "-e" << "gdbserver_command" << gdbserverCommand;
args << "-e" << "gdbserver_socket" << m_gdbserverSocket;
if (m_handShakeMethod == SocketHandShake) {
const QString port = QString("tcp:%1").arg(m_socketHandShakePort);
if (!runAdb({"forward", port, "localabstract:" + pingPongSocket}, &errorMessage)) {
emit remoteProcessFinished(tr("Failed to forward ping pong ports. Reason: %1.")
.arg(errorMessage));
return;
}
}
}
if (m_qmlDebugServices != QmlDebug::NoQmlDebugServices) {
// currently forward to same port on device and host
const QString port = QString("tcp:%1").arg(m_qmlServer.port());
if (!runAdb({"forward", port, port}, &errorMessage)) {
emit remoteProcessFinished(tr("Failed to forward QML debugging ports. Reason: %1.")
.arg(errorMessage));
return;
}
args << "-e" << "qml_debug" << "true"
<< "-e" << "qmljsdebugger"
<< QString("port:%1,block,services:%2")
.arg(m_qmlServer.port()).arg(QmlDebug::qmlDebugServices(m_qmlDebugServices));
}
if (!m_androidRunnable.extraAppParams.isEmpty()) {
args << "-e" << "extraappparams"
<< QString::fromLatin1(m_androidRunnable.extraAppParams.toUtf8().toBase64());
}
if (m_androidRunnable.extraEnvVars.size() > 0) {
args << "-e" << "extraenvvars"
<< QString::fromLatin1(m_androidRunnable.extraEnvVars.toStringList().join('\t')
.toUtf8().toBase64());
}
if (!runAdb(args, &errorMessage)) {
emit remoteProcessFinished(tr("Failed to start the activity. Reason: %1.")
.arg(errorMessage));
return;
}
if (m_useCppDebugger) {
if (m_handShakeMethod == SocketHandShake) {
//Handling socket
bool wasSuccess = false;
const int maxAttempts = 20; //20 seconds
m_socket.reset(new QTcpSocket());
for (int i = 0; i < maxAttempts; i++) {
QThread::sleep(1); // give Android time to start process
m_socket->connectToHost(QHostAddress(QStringLiteral("127.0.0.1")),
m_socketHandShakePort);
if (!m_socket->waitForConnected())
continue;
if (!m_socket->waitForReadyRead()) {
m_socket->close();
continue;
}
const QByteArray pid = m_socket->readLine();
if (pid.isEmpty()) {
m_socket->close();
continue;
}
wasSuccess = true;
break;
}
if (!m_customPort) {
// increment running port to avoid clash when using multiple
// debug sessions at the same time
m_socketHandShakePort++;
// wrap ports around to avoid overflow
if (m_socketHandShakePort == MAX_SOCKET_HANDSHAKE_PORT)
m_socketHandShakePort = MIN_SOCKET_HANDSHAKE_PORT;
}
if (!wasSuccess) {
emit remoteProcessFinished(tr("Failed to contact debugging port."));
return;
}
} else {
// Handling ping.
for (int i = 0; ; ++i) {
Utils::TemporaryFile tmp("pingpong");
tmp.open();
tmp.close();
runAdb({"pull", m_pingFile, tmp.fileName()});
QFile res(tmp.fileName());
const bool doBreak = res.size();
res.remove();
if (doBreak)
break;
if (i == 20) {
emit remoteProcessFinished(tr("Unable to start \"%1\".")
.arg(m_androidRunnable.packageName));
return;
}
qDebug() << "WAITING FOR " << tmp.fileName();
QThread::msleep(500);
}
}
}
QTC_ASSERT(!m_adbLogcatProcess, /**/);
m_adbLogcatProcess = std::move(logcatProcess);
m_pidFinder = Utils::onResultReady(Utils::runAsync(&findProcessPID, m_adb, selector(),
m_androidRunnable.packageName),
bind(&AndroidRunnerWorker::onProcessIdChanged, this, _1));
}
bool AndroidRunnerWorker::adbShellAmNeedsQuotes()
{
// Between Android SDK Tools version 24.3.1 and 24.3.4 the quoting
// needs for the 'adb shell am start ...' parameters changed.
// Run a test to find out on what side of the fence we live.
// The command will fail with a complaint about the "--dummy"
// option on newer SDKs, and with "No intent supplied" on older ones.
// In case the test itself fails assume a new SDK.
Utils::SynchronousProcess adb;
adb.setTimeoutS(10);
Utils::SynchronousProcessResponse response
= adb.run(m_adb, selector() << "shell" << "am" << "start"
<< "-e" << "dummy" << "dummy --dummy");
if (response.result == Utils::SynchronousProcessResponse::StartFailed
|| response.result != Utils::SynchronousProcessResponse::Finished)
return true;
const QString output = response.allOutput();
const bool oldSdk = output.contains("Error: No intent supplied");
return !oldSdk;
}
bool AndroidRunnerWorker::runAdb(const QStringList &args, QString *exitMessage, int timeoutS)
{
Utils::SynchronousProcess adb;
adb.setTimeoutS(timeoutS);
Utils::SynchronousProcessResponse response = adb.run(m_adb, selector() + args);
if (exitMessage)
*exitMessage = response.exitMessage(m_adb, timeoutS);
return response.result == Utils::SynchronousProcessResponse::Finished;
}
void AndroidRunnerWorker::handleRemoteDebuggerRunning()
{
if (m_useCppDebugger) {
if (m_handShakeMethod == SocketHandShake) {
m_socket->write("OK");
m_socket->waitForBytesWritten();
m_socket->close();
} else {
Utils::TemporaryFile tmp("pingpong");
tmp.open();
runAdb({"push", tmp.fileName(), m_pongFile});
}
QTC_CHECK(m_processPID != -1);
}
// emit remoteProcessStarted(m_localGdbServerPort, m_qmlPort);
}
void AndroidRunnerWorker::asyncStop()
{
if (!m_pidFinder.isFinished())
m_pidFinder.cancel();
if (m_processPID != -1) {
forceStop();
}
}
void AndroidRunnerWorker::setAndroidRunnable(const AndroidRunnable &runnable)
{
m_androidRunnable = runnable;
}
void AndroidRunnerWorker::logcatProcess(const QByteArray &text, QByteArray &buffer, bool onlyError)
{
QList<QByteArray> lines = text.split('\n');
// lines always contains at least one item
lines[0].prepend(buffer);
if (!lines.last().endsWith('\n')) {
// incomplete line
buffer = lines.last();
lines.removeLast();
} else {
buffer.clear();
}
QString pidString = QString::number(m_processPID);
foreach (const QByteArray &msg, lines) {
const QString line = QString::fromUtf8(msg).trimmed() + QLatin1Char('\n');
if (!line.contains(pidString))
continue;
if (m_logCatRegExp.exactMatch(line)) {
// Android M
if (m_logCatRegExp.cap(1) == pidString) {
const QString &messagetype = m_logCatRegExp.cap(2);
QString output = line.mid(m_logCatRegExp.pos(2));
if (onlyError
|| messagetype == QLatin1String("F")
|| messagetype == QLatin1String("E")
|| messagetype == QLatin1String("W"))
emit remoteErrorOutput(output);
else
emit remoteOutput(output);
}
} else {
if (onlyError || line.startsWith("F/")
|| line.startsWith("E/")
|| line.startsWith("W/"))
emit remoteErrorOutput(line);
else
emit remoteOutput(line);
}
}
}
void AndroidRunnerWorker::onProcessIdChanged(qint64 pid)
{
// Don't write to m_psProc from a different thread
QTC_ASSERT(QThread::currentThread() == thread(), return);
m_processPID = pid;
if (pid == -1) {
emit remoteProcessFinished(QLatin1String("\n\n") + tr("\"%1\" died.")
.arg(m_androidRunnable.packageName));
// App died/killed. Reset log and monitor processes.
m_adbLogcatProcess.reset();
m_psIsAlive.reset();
// Run adb commands after application quit.
for (const QString &entry: m_androidRunnable.afterFinishAdbCommands)
runAdb(entry.split(' ', QString::SkipEmptyParts));
} else {
// In debugging cases this will be funneled to the engine to actually start
// and attach gdb. Afterwards this ends up in handleRemoteDebuggerRunning() below.
emit remoteProcessStarted(m_localGdbServerPort, m_qmlServer, m_processPID);
logcatReadStandardOutput();
QTC_ASSERT(!m_psIsAlive, /**/);
m_psIsAlive.reset(new QProcess);
m_psIsAlive->setProcessChannelMode(QProcess::MergedChannels);
connect(m_psIsAlive.get(), &QProcess::readyRead, [this](){
if (!m_psIsAlive->readAll().simplified().isEmpty())
onProcessIdChanged(-1);
});
m_psIsAlive->start(m_adb, selector() << QStringLiteral("shell")
<< pidPollingScript.arg(m_processPID));
}
}
void AndroidRunnerWorker::logcatReadStandardError()
{
if (m_processPID != -1)
logcatProcess(m_adbLogcatProcess->readAllStandardError(), m_stderrBuffer, true);
}
void AndroidRunnerWorker::logcatReadStandardOutput()
{
if (m_processPID != -1)
logcatProcess(m_adbLogcatProcess->readAllStandardOutput(), m_stdoutBuffer, false);
}
void AndroidRunnerWorker::adbKill(qint64 pid)
{
runAdb({"shell", "kill", "-9", QString::number(pid)});
runAdb({"shell", "run-as", m_androidRunnable.packageName, "kill", "-9", QString::number(pid)});
}
QStringList AndroidRunnerWorker::selector() const
{
return AndroidDeviceInfo::adbSelector(m_androidRunnable.deviceSerialNumber);
}
AndroidRunner::AndroidRunner(RunControl *runControl, const QString &intentName,
const QString &extraAppParams, const Utils::Environment &extraEnvVars)
: RunWorker(runControl), m_target(runControl->runConfiguration()->target()) : RunWorker(runControl), m_target(runControl->runConfiguration()->target())
{ {
setDisplayName("AndroidRunner"); setDisplayName("AndroidRunner");
@@ -709,6 +133,7 @@ AndroidRunner::AndroidRunner(RunControl *runControl, const QString &intentName,
m_androidRunnable.extraAppParams = extraAppParams; m_androidRunnable.extraAppParams = extraAppParams;
m_androidRunnable.extraEnvVars = extraEnvVars; m_androidRunnable.extraEnvVars = extraEnvVars;
m_androidRunnable.deviceSerialNumber = AndroidManager::deviceSerialNumber(m_target); m_androidRunnable.deviceSerialNumber = AndroidManager::deviceSerialNumber(m_target);
m_androidRunnable.apiLevel = AndroidManager::deviceApiLevel(m_target);
if (auto androidRunConfig = qobject_cast<AndroidRunConfiguration *>( if (auto androidRunConfig = qobject_cast<AndroidRunConfiguration *>(
runControl->runConfiguration())) { runControl->runConfiguration())) {
@@ -720,23 +145,26 @@ AndroidRunner::AndroidRunner(RunControl *runControl, const QString &intentName,
m_androidRunnable.afterFinishAdbCommands.append(QString("shell %1").arg(shellCmd)); m_androidRunnable.afterFinishAdbCommands.append(QString("shell %1").arg(shellCmd));
} }
if (m_androidRunnable.apiLevel > 23)
m_worker.reset(new AndroidRunnerWorker(runControl, m_androidRunnable)); m_worker.reset(new AndroidRunnerWorker(runControl, m_androidRunnable));
else
m_worker.reset(new AndroidRunnerWorkerPreNougat(runControl, m_androidRunnable));
m_worker->moveToThread(&m_thread); m_worker->moveToThread(&m_thread);
connect(this, &AndroidRunner::asyncStart, m_worker.data(), &AndroidRunnerWorker::asyncStart); connect(this, &AndroidRunner::asyncStart, m_worker.data(), &AndroidRunnerWorkerBase::asyncStart);
connect(this, &AndroidRunner::asyncStop, m_worker.data(), &AndroidRunnerWorker::asyncStop); connect(this, &AndroidRunner::asyncStop, m_worker.data(), &AndroidRunnerWorkerBase::asyncStop);
connect(this, &AndroidRunner::androidRunnableChanged, connect(this, &AndroidRunner::androidRunnableChanged,
m_worker.data(), &AndroidRunnerWorker::setAndroidRunnable); m_worker.data(), &AndroidRunnerWorkerBase::setAndroidRunnable);
connect(this, &AndroidRunner::remoteDebuggerRunning, connect(this, &AndroidRunner::remoteDebuggerRunning,
m_worker.data(), &AndroidRunnerWorker::handleRemoteDebuggerRunning); m_worker.data(), &AndroidRunnerWorkerBase::handleRemoteDebuggerRunning);
connect(m_worker.data(), &AndroidRunnerWorker::remoteProcessStarted, connect(m_worker.data(), &AndroidRunnerWorkerBase::remoteProcessStarted,
this, &AndroidRunner::handleRemoteProcessStarted); this, &AndroidRunner::handleRemoteProcessStarted);
connect(m_worker.data(), &AndroidRunnerWorker::remoteProcessFinished, connect(m_worker.data(), &AndroidRunnerWorkerBase::remoteProcessFinished,
this, &AndroidRunner::handleRemoteProcessFinished); this, &AndroidRunner::handleRemoteProcessFinished);
connect(m_worker.data(), &AndroidRunnerWorker::remoteOutput, connect(m_worker.data(), &AndroidRunnerWorkerBase::remoteOutput,
this, &AndroidRunner::remoteOutput); this, &AndroidRunner::remoteOutput);
connect(m_worker.data(), &AndroidRunnerWorker::remoteErrorOutput, connect(m_worker.data(), &AndroidRunnerWorkerBase::remoteErrorOutput,
this, &AndroidRunner::remoteErrorOutput); this, &AndroidRunner::remoteErrorOutput);
connect(&m_outputParser, &QmlDebug::QmlOutputParser::waitingForConnectionOnPort, connect(&m_outputParser, &QmlDebug::QmlOutputParser::waitingForConnectionOnPort,
@@ -840,6 +268,7 @@ void AndroidRunner::launchAVD()
m_target->project(), deviceAPILevel, targetArch); m_target->project(), deviceAPILevel, targetArch);
AndroidManager::setDeviceSerialNumber(m_target, info.serialNumber); AndroidManager::setDeviceSerialNumber(m_target, info.serialNumber);
m_androidRunnable.deviceSerialNumber = info.serialNumber; m_androidRunnable.deviceSerialNumber = info.serialNumber;
m_androidRunnable.apiLevel = info.sdk;
emit androidRunnableChanged(m_androidRunnable); emit androidRunnableChanged(m_androidRunnable);
if (info.isValid()) { if (info.isValid()) {
AndroidAvdManager avdManager; AndroidAvdManager avdManager;
@@ -872,5 +301,3 @@ void AndroidRunner::checkAVD()
} // namespace Internal } // namespace Internal
} // namespace Android } // namespace Android
#include "androidrunner.moc"

View File

@@ -43,7 +43,7 @@
namespace Android { namespace Android {
namespace Internal { namespace Internal {
class AndroidRunnerWorker; class AndroidRunnerWorkerBase;
class AndroidRunner : public ProjectExplorer::RunWorker class AndroidRunner : public ProjectExplorer::RunWorker
{ {
@@ -88,7 +88,7 @@ private:
QString m_launchedAVDName; QString m_launchedAVDName;
QThread m_thread; QThread m_thread;
QTimer m_checkAVDTimer; QTimer m_checkAVDTimer;
QScopedPointer<AndroidRunnerWorker> m_worker; QScopedPointer<AndroidRunnerWorkerBase> m_worker;
QPointer<ProjectExplorer::Target> m_target; QPointer<ProjectExplorer::Target> m_target;
Utils::Port m_gdbServerPort; Utils::Port m_gdbServerPort;
QUrl m_qmlServer; QUrl m_qmlServer;

View File

@@ -0,0 +1,569 @@
/****************************************************************************
**
** Copyright (C) 2018 BogDan Vatra <bog_dan_ro@yahoo.com>
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#include "androidconfigurations.h"
#include "androidrunnerworker.h"
#include <QThread>
#include <debugger/debuggerrunconfigurationaspect.h>
#include <projectexplorer/target.h>
#include <qtsupport/baseqtversion.h>
#include <qtsupport/qtkitinformation.h>
#include <utils/hostosinfo.h>
#include <utils/runextensions.h>
#include <utils/synchronousprocess.h>
#include <utils/temporaryfile.h>
#include <utils/url.h>
#include <QTcpServer>
#include <chrono>
using namespace std;
using namespace std::placeholders;
using namespace ProjectExplorer;
namespace Android {
namespace Internal {
static const QString pidScript = "pidof -s \"%1\"";
static const QString pidScriptPreNougat = QStringLiteral("for p in /proc/[0-9]*; "
"do cat <$p/cmdline && echo :${p##*/}; done");
static const QString pidPollingScript = QStringLiteral("while [ -d /proc/%1 ]; do sleep 1; done");
static const QString regExpLogcat = QStringLiteral("[0-9\\-]*" // date
"\\s+"
"[0-9\\-:.]*"// time
"\\s*"
"(\\d*)" // pid 1. capture
"\\s+"
"\\d*" // unknown
"\\s+"
"(\\w)" // message type 2. capture
"\\s+"
"(.*): " // source 3. capture
"(.*)" // message 4. capture
"[\\n\\r]*"
);
static int APP_START_TIMEOUT = 45000;
static bool isTimedOut(const chrono::high_resolution_clock::time_point &start,
int msecs = APP_START_TIMEOUT)
{
bool timedOut = false;
auto end = chrono::high_resolution_clock::now();
if (chrono::duration_cast<chrono::milliseconds>(end-start).count() > msecs)
timedOut = true;
return timedOut;
}
static qint64 extractPID(const QByteArray &output, const QString &packageName)
{
qint64 pid = -1;
foreach (auto tuple, output.split('\n')) {
tuple = tuple.simplified();
if (!tuple.isEmpty()) {
auto parts = tuple.split(':');
QString commandName = QString::fromLocal8Bit(parts.first());
if (parts.length() == 2 && commandName == packageName) {
pid = parts.last().toLongLong();
break;
}
}
}
return pid;
}
void findProcessPIDPreNougat(QFutureInterface<qint64> &fi, const QString &adbPath,
QStringList selector, const QString &packageName)
{
if (packageName.isEmpty())
return;
qint64 processPID = -1;
chrono::high_resolution_clock::time_point start = chrono::high_resolution_clock::now();
do {
QThread::msleep(200);
const QByteArray out = Utils::SynchronousProcess()
.runBlocking(adbPath, selector << QStringLiteral("shell") << pidScriptPreNougat)
.allRawOutput();
processPID = extractPID(out, packageName);
} while (processPID == -1 && !isTimedOut(start) && !fi.isCanceled());
if (!fi.isCanceled())
fi.reportResult(processPID);
}
void findProcessPID(QFutureInterface<qint64> &fi, const QString &adbPath,
QStringList selector, const QString &packageName)
{
if (packageName.isEmpty())
return;
qint64 processPID = -1;
chrono::high_resolution_clock::time_point start = chrono::high_resolution_clock::now();
do {
QThread::msleep(200);
const QByteArray out = Utils::SynchronousProcess()
.runBlocking(adbPath, selector << QStringLiteral("shell") << pidScript.arg(packageName))
.allRawOutput();
if (!out.isEmpty())
processPID = out.trimmed().toLongLong();
} while (processPID == -1 && !isTimedOut(start) && !fi.isCanceled());
if (!fi.isCanceled())
fi.reportResult(processPID);
}
AndroidRunnerWorkerBase::AndroidRunnerWorkerBase(RunControl *runControl, const AndroidRunnable &runnable)
: m_androidRunnable(runnable)
, m_adbLogcatProcess(nullptr, deleter)
, m_psIsAlive(nullptr, deleter)
, m_logCatRegExp(regExpLogcat)
, m_gdbServerProcess(nullptr, deleter)
, m_jdbProcess(nullptr, deleter)
{
auto runConfig = runControl->runConfiguration();
auto aspect = runConfig->extraAspect<Debugger::DebuggerRunConfigurationAspect>();
Core::Id runMode = runControl->runMode();
const bool debuggingMode = runMode == ProjectExplorer::Constants::DEBUG_RUN_MODE;
m_useCppDebugger = debuggingMode && aspect->useCppDebugger();
if (debuggingMode && aspect->useQmlDebugger())
m_qmlDebugServices = QmlDebug::QmlDebuggerServices;
else if (runMode == ProjectExplorer::Constants::QML_PROFILER_RUN_MODE)
m_qmlDebugServices = QmlDebug::QmlProfilerServices;
else if (runMode == ProjectExplorer::Constants::QML_PREVIEW_RUN_MODE)
m_qmlDebugServices = QmlDebug::QmlPreviewServices;
else
m_qmlDebugServices = QmlDebug::NoQmlDebugServices;
m_localGdbServerPort = Utils::Port(5039);
QTC_CHECK(m_localGdbServerPort.isValid());
if (m_qmlDebugServices != QmlDebug::NoQmlDebugServices) {
QTcpServer server;
QTC_ASSERT(server.listen(QHostAddress::LocalHost)
|| server.listen(QHostAddress::LocalHostIPv6),
qDebug() << tr("No free ports available on host for QML debugging."));
m_qmlServer.setScheme(Utils::urlTcpScheme());
m_qmlServer.setHost(server.serverAddress().toString());
m_qmlServer.setPort(server.serverPort());
}
m_adb = AndroidConfigurations::currentConfig().adbToolPath().toString();
m_localJdbServerPort = Utils::Port(5038);
QTC_CHECK(m_localJdbServerPort.isValid());
}
AndroidRunnerWorkerBase::~AndroidRunnerWorkerBase()
{
if (m_processPID != -1)
forceStop();
if (!m_pidFinder.isFinished())
m_pidFinder.cancel();
}
bool AndroidRunnerWorkerBase::adbShellAmNeedsQuotes()
{
// Between Android SDK Tools version 24.3.1 and 24.3.4 the quoting
// needs for the 'adb shell am start ...' parameters changed.
// Run a test to find out on what side of the fence we live.
// The command will fail with a complaint about the "--dummy"
// option on newer SDKs, and with "No intent supplied" on older ones.
// In case the test itself fails assume a new SDK.
Utils::SynchronousProcess adb;
adb.setTimeoutS(10);
Utils::SynchronousProcessResponse response
= adb.run(m_adb, selector() << "shell" << "am" << "start"
<< "-e" << "dummy" << "dummy --dummy");
if (response.result == Utils::SynchronousProcessResponse::StartFailed
|| response.result != Utils::SynchronousProcessResponse::Finished)
return true;
const QString output = response.allOutput();
const bool oldSdk = output.contains("Error: No intent supplied");
return !oldSdk;
}
bool AndroidRunnerWorkerBase::runAdb(const QStringList &args, int timeoutS)
{
Utils::SynchronousProcess adb;
adb.setTimeoutS(timeoutS);
Utils::SynchronousProcessResponse response = adb.run(m_adb, selector() + args);
m_lastRunAdbError = response.exitMessage(m_adb, timeoutS);
m_lastRunAdbRawOutput = response.allRawOutput();
return response.result == Utils::SynchronousProcessResponse::Finished;
}
void AndroidRunnerWorkerBase::adbKill(qint64 pid)
{
runAdb({"shell", "kill", "-9", QString::number(pid)});
runAdb({"shell", "run-as", m_androidRunnable.packageName, "kill", "-9", QString::number(pid)});
}
QStringList AndroidRunnerWorkerBase::selector() const
{
return AndroidDeviceInfo::adbSelector(m_androidRunnable.deviceSerialNumber);
}
void AndroidRunnerWorkerBase::forceStop()
{
runAdb({"shell", "am", "force-stop", m_androidRunnable.packageName}, 30);
// try killing it via kill -9
const QByteArray out = Utils::SynchronousProcess()
.runBlocking(m_adb, selector() << QStringLiteral("shell") << pidScriptPreNougat)
.allRawOutput();
qint64 pid = extractPID(out.simplified(), m_androidRunnable.packageName);
if (pid != -1) {
adbKill(pid);
}
}
void AndroidRunnerWorkerBase::logcatReadStandardError()
{
if (m_processPID != -1)
logcatProcess(m_adbLogcatProcess->readAllStandardError(), m_stderrBuffer, true);
}
void AndroidRunnerWorkerBase::logcatReadStandardOutput()
{
if (m_processPID != -1)
logcatProcess(m_adbLogcatProcess->readAllStandardOutput(), m_stdoutBuffer, false);
}
void AndroidRunnerWorkerBase::logcatProcess(const QByteArray &text, QByteArray &buffer, bool onlyError)
{
QList<QByteArray> lines = text.split('\n');
// lines always contains at least one item
lines[0].prepend(buffer);
if (!lines.last().endsWith('\n')) {
// incomplete line
buffer = lines.last();
lines.removeLast();
} else {
buffer.clear();
}
QString pidString = QString::number(m_processPID);
foreach (const QByteArray &msg, lines) {
const QString line = QString::fromUtf8(msg).trimmed() + QLatin1Char('\n');
if (!line.contains(pidString))
continue;
if (m_useCppDebugger) {
switch (m_jdbState) {
case JDBState::Idle:
if (msg.trimmed().endsWith("Sending WAIT chunk")) {
m_jdbState = JDBState::Waiting;
handleJdbWaiting();
}
break;
case JDBState::Waiting:
if (msg.indexOf("debugger has settled") > 0) {
m_jdbState = JDBState::Settled;
handleJdbSettled();
}
break;
default:
break;
}
}
if (m_logCatRegExp.exactMatch(line)) {
// Android M
if (m_logCatRegExp.cap(1) == pidString) {
const QString &messagetype = m_logCatRegExp.cap(2);
QString output = line.mid(m_logCatRegExp.pos(2));
if (onlyError
|| messagetype == QLatin1String("F")
|| messagetype == QLatin1String("E")
|| messagetype == QLatin1String("W"))
emit remoteErrorOutput(output);
else
emit remoteOutput(output);
}
} else {
if (onlyError || line.startsWith("F/")
|| line.startsWith("E/")
|| line.startsWith("W/"))
emit remoteErrorOutput(line);
else
emit remoteOutput(line);
}
}
}
void AndroidRunnerWorkerBase::setAndroidRunnable(const AndroidRunnable &runnable)
{
m_androidRunnable = runnable;
}
void AndroidRunnerWorkerBase::asyncStart()
{
forceStop();
// Start the logcat process before app starts.
std::unique_ptr<QProcess, decltype(&deleter)> logcatProcess(new QProcess, deleter);
connect(logcatProcess.get(), &QProcess::readyReadStandardOutput,
this, &AndroidRunnerWorkerBase::logcatReadStandardOutput);
connect(logcatProcess.get(), &QProcess::readyReadStandardError,
this, &AndroidRunnerWorkerBase::logcatReadStandardError);
// Its assumed that the device or avd returned by selector() is online.
logcatProcess->start(m_adb, selector() << "logcat");
QTC_ASSERT(!m_adbLogcatProcess, /**/);
m_adbLogcatProcess = std::move(logcatProcess);
for (const QString &entry: m_androidRunnable.beforeStartAdbCommands)
runAdb(entry.split(' ', QString::SkipEmptyParts));
QStringList args({"shell", "am", "start"});
args << m_androidRunnable.amStartExtraArgs;
args << "-n" << m_androidRunnable.intentName;
if (m_useCppDebugger) {
args << "-D";
QString gdbServerSocket;
// run-as <package-name> pwd fails on API 22 so route the pwd through shell.
if (!runAdb({"shell", "run-as", m_androidRunnable.packageName, "/system/bin/sh", "-c", "pwd"})) {
emit remoteProcessFinished(tr("Failed to get process path. Reason: %1.").arg(m_lastRunAdbError));
return;
}
gdbServerSocket = QString::fromUtf8(m_lastRunAdbRawOutput.trimmed()) + "/debug-socket";
QString gdbServerExecutable;
if (!runAdb({"shell", "run-as", m_androidRunnable.packageName, "ls", "lib/"})) {
emit remoteProcessFinished(tr("Failed to get process path. Reason: %1.").arg(m_lastRunAdbError));
return;
}
for (const auto &line: m_lastRunAdbRawOutput.split('\n')) {
if (line.indexOf("gdbserver") != -1/* || line.indexOf("lldb-server") != -1*/) {
gdbServerExecutable = QString::fromUtf8(line.trimmed());
break;
}
}
if (gdbServerExecutable.isEmpty()) {
emit remoteProcessFinished(tr("Can't find C++ debugger."));
return;
}
runAdb({"shell", "run-as", m_androidRunnable.packageName, "killall", gdbServerExecutable});
runAdb({"shell", "run-as", m_androidRunnable.packageName, "rm", gdbServerSocket});
std::unique_ptr<QProcess, decltype(&deleter)> gdbServerProcess(new QProcess, deleter);
gdbServerProcess->start(m_adb, selector() << "shell" << "run-as"
<< m_androidRunnable.packageName << "lib/" + gdbServerExecutable
<< "--multi" << "+" + gdbServerSocket);
if (!gdbServerProcess->waitForStarted()) {
emit remoteProcessFinished(tr("Failed to start C++ debugger."));
return;
}
m_gdbServerProcess = std::move(gdbServerProcess);
QStringList removeForward{"forward", "--remove", "tcp:" + m_localGdbServerPort.toString()};
runAdb(removeForward);
if (!runAdb({"forward", "tcp:" + m_localGdbServerPort.toString(),
"localfilesystem:" + gdbServerSocket})) {
emit remoteProcessFinished(tr("Failed to forward C++ debugging ports. Reason: %1.").arg(m_lastRunAdbError));
return;
}
m_androidRunnable.afterFinishAdbCommands.push_back(removeForward.join(' '));
}
if (m_qmlDebugServices != QmlDebug::NoQmlDebugServices) {
// currently forward to same port on device and host
const QString port = QString("tcp:%1").arg(m_qmlServer.port());
QStringList removeForward{{"forward", "--remove", port}};
runAdb(removeForward);
if (!runAdb({"forward", port, port})) {
emit remoteProcessFinished(tr("Failed to forward QML debugging ports. Reason: %1.")
.arg(m_lastRunAdbError));
return;
}
m_androidRunnable.afterFinishAdbCommands.push_back(removeForward.join(' '));
args << "-e" << "qml_debug" << "true"
<< "-e" << "qmljsdebugger"
<< QString("port:%1,block,services:%2")
.arg(m_qmlServer.port()).arg(QmlDebug::qmlDebugServices(m_qmlDebugServices));
}
if (!m_androidRunnable.extraAppParams.isEmpty()) {
args << "-e" << "extraappparams"
<< QString::fromLatin1(m_androidRunnable.extraAppParams.toUtf8().toBase64());
}
if (m_androidRunnable.extraEnvVars.size() > 0) {
args << "-e" << "extraenvvars"
<< QString::fromLatin1(m_androidRunnable.extraEnvVars.toStringList().join('\t')
.toUtf8().toBase64());
}
if (!runAdb(args)) {
emit remoteProcessFinished(tr("Failed to start the activity. Reason: %1.")
.arg(m_lastRunAdbError));
return;
}
}
void AndroidRunnerWorkerBase::asyncStop()
{
if (!m_pidFinder.isFinished())
m_pidFinder.cancel();
if (m_processPID != -1)
forceStop();
m_jdbProcess.reset();
m_gdbServerProcess.reset();
}
void AndroidRunnerWorkerBase::handleRemoteDebuggerRunning()
{}
void AndroidRunnerWorkerBase::handleJdbWaiting()
{
QStringList removeForward{"forward", "--remove", "tcp:" + m_localJdbServerPort.toString()};
runAdb(removeForward);
if (!runAdb({"forward", "tcp:" + m_localJdbServerPort.toString(),
"jdwp:" + QString::number(m_processPID)})) {
emit remoteProcessFinished(tr("Failed to forward jdb debugging ports. Reason: %1.").arg(m_lastRunAdbError));
return;
}
m_androidRunnable.afterFinishAdbCommands.push_back(removeForward.join(' '));
auto jdbPath = AndroidConfigurations::currentConfig().openJDKLocation().appendPath("bin");
if (Utils::HostOsInfo::isWindowsHost())
jdbPath.appendPath("jdb.exe");
else
jdbPath.appendPath("jdb");
std::unique_ptr<QProcess, decltype(&deleter)> jdbProcess(new QProcess, deleter);
jdbProcess->setProcessChannelMode(QProcess::MergedChannels);
jdbProcess->start(jdbPath.toString(), QStringList() << "-connect" <<
QString("com.sun.jdi.SocketAttach:hostname=localhost,port=%1")
.arg(m_localJdbServerPort.toString()));
if (!jdbProcess->waitForStarted()) {
emit remoteProcessFinished(tr("Failed to start JDB"));
return;
}
m_jdbProcess = std::move(jdbProcess);
}
void AndroidRunnerWorkerBase::handleJdbSettled()
{
auto waitForCommand = [&]() {
for (int i= 0; i < 5 && m_jdbProcess->state() == QProcess::Running; ++i) {
m_jdbProcess->waitForReadyRead(500);
QByteArray lines = m_jdbProcess->readAll();
for (const auto &line: lines.split('\n')) {
auto msg = line.trimmed();
if (msg.startsWith(">"))
return true;
}
}
return false;
};
if (waitForCommand()) {
m_jdbProcess->write("cont\n");
if (m_jdbProcess->waitForBytesWritten(5000) && waitForCommand()) {
m_jdbProcess->write("exit\n");
m_jdbProcess->waitForBytesWritten(5000);
if (!m_jdbProcess->waitForFinished(5000)) {
m_jdbProcess->terminate();
if (!m_jdbProcess->waitForFinished(5000)) {
m_jdbProcess->kill();
m_jdbProcess->waitForFinished();
}
} else if (m_jdbProcess->exitStatus() == QProcess::NormalExit && m_jdbProcess->exitCode() == 0) {
return;
}
}
}
emit remoteProcessFinished(tr("Can't attach jdb to the running application").arg(m_lastRunAdbError));
}
void AndroidRunnerWorkerBase::onProcessIdChanged(qint64 pid)
{
// Don't write to m_psProc from a different thread
QTC_ASSERT(QThread::currentThread() == thread(), return);
m_processPID = pid;
if (pid == -1) {
emit remoteProcessFinished(QLatin1String("\n\n") + tr("\"%1\" died.")
.arg(m_androidRunnable.packageName));
// App died/killed. Reset log, monitor, jdb & gdb processes.
m_adbLogcatProcess.reset();
m_psIsAlive.reset();
m_jdbProcess.reset();
m_gdbServerProcess.reset();
// Run adb commands after application quit.
for (const QString &entry: m_androidRunnable.afterFinishAdbCommands)
runAdb(entry.split(' ', QString::SkipEmptyParts));
} else {
// In debugging cases this will be funneled to the engine to actually start
// and attach gdb. Afterwards this ends up in handleRemoteDebuggerRunning() below.
emit remoteProcessStarted(m_localGdbServerPort, m_qmlServer, m_processPID);
logcatReadStandardOutput();
QTC_ASSERT(!m_psIsAlive, /**/);
m_psIsAlive.reset(new QProcess);
m_psIsAlive->setProcessChannelMode(QProcess::MergedChannels);
connect(m_psIsAlive.get(), static_cast<void(QProcess::*)(int)>(&QProcess::finished),
this, bind(&AndroidRunnerWorkerBase::onProcessIdChanged, this, -1));
m_psIsAlive->start(m_adb, selector() << QStringLiteral("shell")
<< pidPollingScript.arg(m_processPID));
}
}
AndroidRunnerWorker::AndroidRunnerWorker(RunControl *runControl, const AndroidRunnable &runnable)
: AndroidRunnerWorkerBase(runControl, runnable)
{
}
void AndroidRunnerWorker::asyncStart()
{
AndroidRunnerWorkerBase::asyncStart();
m_pidFinder = Utils::onResultReady(Utils::runAsync(&findProcessPID, m_adb, selector(),
m_androidRunnable.packageName),
bind(&AndroidRunnerWorker::onProcessIdChanged, this, _1));
}
AndroidRunnerWorkerPreNougat::AndroidRunnerWorkerPreNougat(RunControl *runControl, const AndroidRunnable &runnable)
: AndroidRunnerWorkerBase(runControl, runnable)
{
}
void AndroidRunnerWorkerPreNougat::asyncStart()
{
AndroidRunnerWorkerBase::asyncStart();
m_pidFinder = Utils::onResultReady(Utils::runAsync(&findProcessPIDPreNougat, m_adb, selector(),
m_androidRunnable.packageName),
bind(&AndroidRunnerWorkerPreNougat::onProcessIdChanged, this, _1));
}
} // namespace Internal
} // namespace Android

View File

@@ -0,0 +1,134 @@
/****************************************************************************
**
** Copyright (C) 2018 BogDan Vatra <bog_dan_ro@yahoo.com>
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#pragma once
#include <qmldebug/qmldebugcommandlinearguments.h>
#include <QFuture>
#include <QTcpSocket>
#include "androidrunnable.h"
namespace ProjectExplorer {
class RunControl;
}
namespace Android {
namespace Internal {
const int MIN_SOCKET_HANDSHAKE_PORT = 20001;
static void deleter(QProcess *p)
{
p->terminate();
if (!p->waitForFinished(1000)) {
p->kill();
p->waitForFinished();
}
// Might get deleted from its own signal handler.
p->deleteLater();
}
class AndroidRunnerWorkerBase : public QObject
{
Q_OBJECT
public:
AndroidRunnerWorkerBase(ProjectExplorer::RunControl *runControl, const AndroidRunnable &runnable);
~AndroidRunnerWorkerBase() override;
bool adbShellAmNeedsQuotes();
bool runAdb(const QStringList &args, int timeoutS = 10);
void adbKill(qint64 pid);
QStringList selector() const;
void forceStop();
void logcatReadStandardError();
void logcatReadStandardOutput();
void logcatProcess(const QByteArray &text, QByteArray &buffer, bool onlyError);
void setAndroidRunnable(const AndroidRunnable &runnable);
virtual void asyncStart();
virtual void asyncStop();
virtual void handleRemoteDebuggerRunning();
virtual void handleJdbWaiting();
virtual void handleJdbSettled();
signals:
void remoteProcessStarted(Utils::Port gdbServerPort, const QUrl &qmlServer, int pid);
void remoteProcessFinished(const QString &errString = QString());
void remoteOutput(const QString &output);
void remoteErrorOutput(const QString &output);
protected:
enum class JDBState {
Idle,
Waiting,
Settled
};
virtual void onProcessIdChanged(qint64 pid);
// Create the processes and timer in the worker thread, for correct thread affinity
AndroidRunnable m_androidRunnable;
QString m_adb;
qint64 m_processPID = -1;
std::unique_ptr<QProcess, decltype(&deleter)> m_adbLogcatProcess;
std::unique_ptr<QProcess, decltype(&deleter)> m_psIsAlive;
QByteArray m_stdoutBuffer;
QByteArray m_stderrBuffer;
QRegExp m_logCatRegExp;
QFuture<qint64> m_pidFinder;
bool m_useCppDebugger = false;
QmlDebug::QmlDebugServicesPreset m_qmlDebugServices;
Utils::Port m_localGdbServerPort; // Local end of forwarded debug socket.
QUrl m_qmlServer;
QByteArray m_lastRunAdbRawOutput;
QString m_lastRunAdbError;
JDBState m_jdbState = JDBState::Idle;
Utils::Port m_localJdbServerPort;
std::unique_ptr<QProcess, decltype(&deleter)> m_gdbServerProcess;
std::unique_ptr<QProcess, decltype(&deleter)> m_jdbProcess;
};
class AndroidRunnerWorker : public AndroidRunnerWorkerBase
{
Q_OBJECT
public:
AndroidRunnerWorker(ProjectExplorer::RunControl *runControl, const AndroidRunnable &runnable);
void asyncStart() override;
};
class AndroidRunnerWorkerPreNougat : public AndroidRunnerWorkerBase
{
Q_OBJECT
public:
AndroidRunnerWorkerPreNougat(ProjectExplorer::RunControl *runControl, const AndroidRunnable &runnable);
void asyncStart() override;
};
} // namespace Internal
} // namespace Android

View File

@@ -48,15 +48,19 @@ GTestOutputReader::GTestOutputReader(const QFutureInterface<TestResultPtr> &futu
, m_executable(testApplication ? testApplication->program() : QString()) , m_executable(testApplication ? testApplication->program() : QString())
, m_projectFile(projectFile) , m_projectFile(projectFile)
{ {
// on Windows abort() will result in normal termination, but exit code will be set to 3
if (Utils::HostOsInfo::isWindowsHost()) {
connect(m_testApplication, connect(m_testApplication,
static_cast<void (QProcess::*)(int, QProcess::ExitStatus)>(&QProcess::finished), static_cast<void (QProcess::*)(int, QProcess::ExitStatus)>(&QProcess::finished),
this, [this] (int exitCode, QProcess::ExitStatus /*exitStatus*/) { this, [this] (int exitCode, QProcess::ExitStatus /*exitStatus*/) {
if (exitCode == 3) if (exitCode == 1 && !m_description.isEmpty()) {
// TODO tr()
const QString message{"Running test(s) failed\n" + m_description
+ "\nExecutable: " + m_executable};
createAndReportResult(message, Result::MessageFatal);
}
// on Windows abort() will result in normal termination, but exit code will be set to 3
if (Utils::HostOsInfo::isWindowsHost() && exitCode == 3)
reportCrash(); reportCrash();
}); });
}
} }
void GTestOutputReader::processOutput(const QByteArray &outputLine) void GTestOutputReader::processOutput(const QByteArray &outputLine)

View File

@@ -74,6 +74,14 @@ void TestOutputReader::reportCrash()
m_futureInterface.reportResult(result); m_futureInterface.reportResult(result);
} }
void TestOutputReader::createAndReportResult(const QString &message, Result::Type type)
{
TestResultPtr result = createDefaultResult();
result->setDescription(message);
result->setResult(type);
reportResult(result);
}
void TestOutputReader::reportResult(const TestResultPtr &result) void TestOutputReader::reportResult(const TestResultPtr &result)
{ {
m_futureInterface.reportResult(result); m_futureInterface.reportResult(result);

View File

@@ -45,6 +45,7 @@ public:
virtual void processOutput(const QByteArray &outputLine) = 0; virtual void processOutput(const QByteArray &outputLine) = 0;
virtual void processStdError(const QByteArray &output); virtual void processStdError(const QByteArray &output);
void reportCrash(); void reportCrash();
void createAndReportResult(const QString &message, Result::Type type);
bool hadValidOutput() const { return m_hadValidOutput; } bool hadValidOutput() const { return m_hadValidOutput; }
signals: signals:

View File

@@ -294,7 +294,9 @@
<tabstop>removeButton</tabstop> <tabstop>removeButton</tabstop>
<tabstop>revertButton</tabstop> <tabstop>revertButton</tabstop>
<tabstop>description</tabstop> <tabstop>description</tabstop>
<tabstop>executable</tabstop>
<tabstop>arguments</tabstop> <tabstop>arguments</tabstop>
<tabstop>workingDirectory</tabstop>
<tabstop>outputBehavior</tabstop> <tabstop>outputBehavior</tabstop>
<tabstop>errorOutputBehavior</tabstop> <tabstop>errorOutputBehavior</tabstop>
<tabstop>environmentButton</tabstop> <tabstop>environmentButton</tabstop>

View File

@@ -477,16 +477,16 @@ void DebuggerRunTool::setCoreFileName(const QString &coreFile, bool isSnapshot)
void DebuggerRunTool::appendInferiorCommandLineArgument(const QString &arg) void DebuggerRunTool::appendInferiorCommandLineArgument(const QString &arg)
{ {
if (!m_runParameters.inferior.commandLineArguments.isEmpty()) QtcProcess::addArg(&m_runParameters.inferior.commandLineArguments, arg,
m_runParameters.inferior.commandLineArguments.append(' '); device() ? device()->osType() : HostOsInfo::hostOs());
m_runParameters.inferior.commandLineArguments.append(arg);
} }
void DebuggerRunTool::prependInferiorCommandLineArgument(const QString &arg) void DebuggerRunTool::prependInferiorCommandLineArgument(const QString &arg)
{ {
if (!m_runParameters.inferior.commandLineArguments.isEmpty()) if (!m_runParameters.inferior.commandLineArguments.isEmpty())
m_runParameters.inferior.commandLineArguments.prepend(' '); m_runParameters.inferior.commandLineArguments.prepend(' ');
m_runParameters.inferior.commandLineArguments.prepend(arg); m_runParameters.inferior.commandLineArguments.prepend(
QtcProcess::quoteArg(arg, device() ? device()->osType() : HostOsInfo::hostOs()));
} }
void DebuggerRunTool::addQmlServerInferiorCommandLineArgumentIfNeeded() void DebuggerRunTool::addQmlServerInferiorCommandLineArgumentIfNeeded()

View File

@@ -82,9 +82,11 @@ void QmakeAndroidRunConfiguration::updateDisplayName()
const QmakeProjectManager::QmakeProFileNode *root = project->rootProjectNode(); const QmakeProjectManager::QmakeProFileNode *root = project->rootProjectNode();
if (root) { if (root) {
const QmakeProjectManager::QmakeProFileNode *node = root->findProFileFor(proFilePath()); const QmakeProjectManager::QmakeProFileNode *node = root->findProFileFor(proFilePath());
if (node) // should always be found if (node) { // should always be found
setDisplayName(node->displayName());
setDefaultDisplayName(node->displayName()); setDefaultDisplayName(node->displayName());
} }
}
} }
QString QmakeAndroidRunConfiguration::disabledReason() const QString QmakeAndroidRunConfiguration::disabledReason() const

View File

@@ -421,7 +421,6 @@ void QmakeProject::scheduleAsyncUpdate(QmakeProFile *file, QmakeProFile::AsyncUp
return; return;
} }
emitParsingStarted();
file->setParseInProgressRecursive(true); file->setParseInProgressRecursive(true);
setAllBuildConfigurationsEnabled(false); setAllBuildConfigurationsEnabled(false);
@@ -478,9 +477,6 @@ void QmakeProject::scheduleAsyncUpdate(QmakeProFile::AsyncUpdateDelay delay)
return; return;
} }
if (m_asyncUpdateState != Base)
emitParsingStarted();
rootProFile()->setParseInProgressRecursive(true); rootProFile()->setParseInProgressRecursive(true);
setAllBuildConfigurationsEnabled(false); setAllBuildConfigurationsEnabled(false);
@@ -503,12 +499,15 @@ void QmakeProject::startAsyncTimer(QmakeProFile::AsyncUpdateDelay delay)
m_asyncUpdateTimer.stop(); m_asyncUpdateTimer.stop();
m_asyncUpdateTimer.setInterval(qMin(m_asyncUpdateTimer.interval(), m_asyncUpdateTimer.setInterval(qMin(m_asyncUpdateTimer.interval(),
delay == QmakeProFile::ParseLater ? UPDATE_INTERVAL : 0)); delay == QmakeProFile::ParseLater ? UPDATE_INTERVAL : 0));
if (!isParsing())
emitParsingStarted();
m_asyncUpdateTimer.start(); m_asyncUpdateTimer.start();
} }
void QmakeProject::incrementPendingEvaluateFutures() void QmakeProject::incrementPendingEvaluateFutures()
{ {
++m_pendingEvaluateFuturesCount; ++m_pendingEvaluateFuturesCount;
QTC_ASSERT(isParsing(), emitParsingStarted());
m_asyncUpdateFutureInterface->setProgressRange(m_asyncUpdateFutureInterface->progressMinimum(), m_asyncUpdateFutureInterface->setProgressRange(m_asyncUpdateFutureInterface->progressMinimum(),
m_asyncUpdateFutureInterface->progressMaximum() + 1); m_asyncUpdateFutureInterface->progressMaximum() + 1);
} }

View File

@@ -45,6 +45,7 @@
#include <qmldebug/qmldebugcommandlinearguments.h> #include <qmldebug/qmldebugcommandlinearguments.h>
#include <utils/qtcassert.h> #include <utils/qtcassert.h>
#include <utils/qtcprocess.h>
#include <utils/url.h> #include <utils/url.h>
#include <QMessageBox> #include <QMessageBox>
@@ -253,8 +254,8 @@ LocalQmlProfilerSupport::LocalQmlProfilerSupport(QmlProfilerTool *profilerTool,
else else
QTC_CHECK(false); QTC_CHECK(false);
QString arguments = QmlDebug::qmlDebugCommandLineArguments(QmlDebug::QmlProfilerServices, QString arguments = Utils::QtcProcess::quoteArg(
code, true); QmlDebug::qmlDebugCommandLineArguments(QmlDebug::QmlProfilerServices, code, true));
if (!debuggee.commandLineArguments.isEmpty()) if (!debuggee.commandLineArguments.isEmpty())
arguments += ' ' + debuggee.commandLineArguments; arguments += ' ' + debuggee.commandLineArguments;

View File

@@ -31,6 +31,7 @@
#include <qmlprofiler/qmlprofilertool.h> #include <qmlprofiler/qmlprofilertool.h>
#include <utils/url.h> #include <utils/url.h>
#include <utils/temporaryfile.h>
#include <QtTest> #include <QtTest>
#include <QTcpServer> #include <QTcpServer>
@@ -148,6 +149,31 @@ void LocalQmlProfilerRunnerTest::testRunner()
runControl->initiateFinish(); runControl->initiateFinish();
QTRY_VERIFY(runControl.isNull()); QTRY_VERIFY(runControl.isNull());
QVERIFY(profiler.isNull()); QVERIFY(profiler.isNull());
debuggee.commandLineArguments = QString("-test QmlProfiler,");
serverUrl.setScheme(Utils::urlSocketScheme());
{
Utils::TemporaryFile file("file with spaces");
if (file.open())
serverUrl.setPath(file.fileName());
}
runControl = new ProjectExplorer::RunControl(nullptr,
ProjectExplorer::Constants::QML_PROFILER_RUN_MODE);
runControl->setRunnable(debuggee);
profiler = new LocalQmlProfilerSupport(&tool, runControl, serverUrl);
connectRunner();
runControl->initiateStart();
QTRY_VERIFY_WITH_TIMEOUT(running, 30000);
QTRY_VERIFY_WITH_TIMEOUT(!running, 30000);
QCOMPARE(startCount, 4);
QCOMPARE(stopCount, 4);
QCOMPARE(runCount, 3);
runControl->initiateFinish();
QTRY_VERIFY(runControl.isNull());
QVERIFY(profiler.isNull());
} }
void LocalQmlProfilerRunnerTest::testFindFreePort() void LocalQmlProfilerRunnerTest::testFindFreePort()

View File

@@ -75,11 +75,10 @@ void QnxQmlProfilerSupport::start()
serverUrl.setScheme("tcp"); serverUrl.setScheme("tcp");
m_profiler->recordData("QmlServerUrl", serverUrl); m_profiler->recordData("QmlServerUrl", serverUrl);
QString args = QmlDebug::qmlDebugTcpArguments(QmlDebug::QmlProfilerServices, qmlPort);
auto r = runnable().as<StandardRunnable>(); auto r = runnable().as<StandardRunnable>();
if (!r.commandLineArguments.isEmpty()) QtcProcess::addArg(&r.commandLineArguments,
r.commandLineArguments.append(' '); QmlDebug::qmlDebugTcpArguments(QmlDebug::QmlProfilerServices, qmlPort),
r.commandLineArguments += args; device()->osType());
setRunnable(r); setRunnable(r);

View File

@@ -28,6 +28,7 @@
#include <projectexplorer/runnables.h> #include <projectexplorer/runnables.h>
#include <ssh/sshconnection.h> #include <ssh/sshconnection.h>
#include <utils/qtcprocess.h>
#include <utils/url.h> #include <utils/url.h>
using namespace ProjectExplorer; using namespace ProjectExplorer;
@@ -66,11 +67,9 @@ void RemoteLinuxQmlToolingSupport::start()
serverUrl.setPort(qmlPort.number()); serverUrl.setPort(qmlPort.number());
m_runworker->recordData("QmlServerUrl", serverUrl); m_runworker->recordData("QmlServerUrl", serverUrl);
QString args = QmlDebug::qmlDebugTcpArguments(m_services, qmlPort);
auto r = runnable().as<StandardRunnable>(); auto r = runnable().as<StandardRunnable>();
if (!r.commandLineArguments.isEmpty()) QtcProcess::addArg(&r.commandLineArguments, QmlDebug::qmlDebugTcpArguments(m_services, qmlPort),
r.commandLineArguments.append(' '); device()->osType());
r.commandLineArguments += args;
setRunnable(r); setRunnable(r);

View File

@@ -25,30 +25,25 @@ Second - some of the test suites/test cases expect a build of Qt 4.8.7 to be ava
* Other: * Other:
make -j<number of available cores> make -j<number of available cores>
Third - some of the test suites/test cases expect Qt 5.3.1 (default toolchain), Qt 5.4.1 (gcc, Linux and Windows only) and Qt 5.6.1-1 (default toolchain) Third - some of the test suites/test cases expect Qt versions to be installed in their default
installed in their default locations. On Linux/Mac this is ~/Qt5.x.1 and on Windows this is C:\Qt\Qt5.x.1. The default toolchains are gcc on Linux, locations. On Linux/macOS this is ~/Qt5.x.1 and on Windows this is C:\Qt\Qt5.x.1. It's easiest to
clang on Mac and MSVC2010 (Qt <= 5.5) or MSVC2013 (Qt > 5.5) on Windows. It's easiest to use default installations of the official opensource Qt packages. use installations of the official opensource Qt packages. Just install the Qt version for the
respective toolchain and if possible the additional module Qt Script. Do not install Qt WebEngine.
The exact versions and toolchains are:
On macOS it might be necessary to tweak some files of the Qt installation - depending on the installed Xcode and its installed SDKs. Linux:
If Xcode 8+ is installed you will need to update the file Qt 5.4.1 (gcc)
~/Qt5.3.1/5.3/clang_64/mkspecs/features/mac/default_pre.prf Qt 5.6.1-1 (gcc)
Change the line Qt 5.10.1 (gcc)
isEmpty($$list($$system("/usr/bin/xcrun -find xcrun 2>/dev/null"))) macOS:
Qt 5.6.1-1 (clang)
Qt 5.10.1 (clang)
to Windows:
Qt 5.4.1 (gcc)
isEmpty($$list($$system("/usr/bin/xcrun -find xcodebuild 2>/dev/null"))) Qt 5.6.1-1 (MSVC2013, 32 bit)
Qt 5.10.1 (MSVC2015, 32 bit)
Furthermore - depending on the installed SDK it might be necessary to update the file
~/Qt5.3.1/5.3/clang_64/mkspecs/qdevice.pri
Search for the following line
!host_build:QMAKE_MAC_SDK = macosx10.8
Newer Xcode might miss the 10.8 SDK. Check
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs
which SDKs are installed and update the version number accordingly.
Fourth - you'll have to provide some additional repositories (and for the hooking into subprocesses even some more Squish bundles, see below). Fourth - you'll have to provide some additional repositories (and for the hooking into subprocesses even some more Squish bundles, see below).
These additional repositories are located inside ~/squish-data or C:\Users\<user>\squish-data (depending on the OS you're on). These additional repositories are located inside ~/squish-data or C:\Users\<user>\squish-data (depending on the OS you're on).

View File

@@ -192,6 +192,7 @@
:Select a Git Commit.detailsText_QPlainTextEdit {name='detailsText' type='QPlainTextEdit' visible='1' window=':Select a Git Commit_Git::Internal::ChangeSelectionDialog'} :Select a Git Commit.detailsText_QPlainTextEdit {name='detailsText' type='QPlainTextEdit' visible='1' window=':Select a Git Commit_Git::Internal::ChangeSelectionDialog'}
:Select a Git Commit.workingDirectoryEdit_QLineEdit {type='Utils::FancyLineEdit' unnamed='1' visible='1' window=':Select a Git Commit_Git::Internal::ChangeSelectionDialog'} :Select a Git Commit.workingDirectoryEdit_QLineEdit {type='Utils::FancyLineEdit' unnamed='1' visible='1' window=':Select a Git Commit_Git::Internal::ChangeSelectionDialog'}
:Select a Git Commit_Git::Internal::ChangeSelectionDialog {name='Git__Internal__ChangeSelectionDialog' type='Git::Internal::ChangeSelectionDialog' visible='1' windowTitle='Select a Git Commit'} :Select a Git Commit_Git::Internal::ChangeSelectionDialog {name='Git__Internal__ChangeSelectionDialog' type='Git::Internal::ChangeSelectionDialog' visible='1' windowTitle='Select a Git Commit'}
:Select signal.signalList_QTreeView {container=':Go to slot.Select signal_QGroupBox' name='signalList' type='QTreeView' visible='1'}
:Select signal.signalList_QTreeWidget {container=':Go to slot.Select signal_QGroupBox' name='signalList' type='QTreeWidget' visible='1'} :Select signal.signalList_QTreeWidget {container=':Go to slot.Select signal_QGroupBox' name='signalList' type='QTreeWidget' visible='1'}
:Send to Codepaster.Cancel_QPushButton {text='Cancel' type='QPushButton' unnamed='1' visible='1' window=':Send to Codepaster_CodePaster::PasteView'} :Send to Codepaster.Cancel_QPushButton {text='Cancel' type='QPushButton' unnamed='1' visible='1' window=':Send to Codepaster_CodePaster::PasteView'}
:Send to Codepaster.Description:_QLabel {name='descriptionLabel' text='Description:' type='QLabel' visible='1' window=':Send to Codepaster_CodePaster::PasteView'} :Send to Codepaster.Description:_QLabel {name='descriptionLabel' text='Description:' type='QLabel' visible='1' window=':Send to Codepaster_CodePaster::PasteView'}

View File

@@ -101,7 +101,7 @@
<value type="QString" key="PE.Profile.Icon">:///DESKTOP///</value> <value type="QString" key="PE.Profile.Icon">:///DESKTOP///</value>
<value type="QString" key="PE.Profile.Id">{a1e860d1-c241-4abf-80fe-cf0c9f0a43b3}</value> <value type="QString" key="PE.Profile.Id">{a1e860d1-c241-4abf-80fe-cf0c9f0a43b3}</value>
<valuelist type="QVariantList" key="PE.Profile.MutableInfo"/> <valuelist type="QVariantList" key="PE.Profile.MutableInfo"/>
<value type="QString" key="PE.Profile.Name">Desktop 5.3.1 default</value> <value type="QString" key="PE.Profile.Name">Desktop 5.10.1 default</value>
<value type="bool" key="PE.Profile.SDK">false</value> <value type="bool" key="PE.Profile.SDK">false</value>
<valuelist type="QVariantList" key="PE.Profile.StickyInfo"/> <valuelist type="QVariantList" key="PE.Profile.StickyInfo"/>
</valuemap> </valuemap>

View File

@@ -16,7 +16,7 @@
<variable>QtVersion.1</variable> <variable>QtVersion.1</variable>
<valuemap type="QVariantMap"> <valuemap type="QVariantMap">
<value type="int" key="Id">9</value> <value type="int" key="Id">9</value>
<value type="QString" key="Name">Desktop Qt 5.6.1 (SQUISH_DEFAULT_COMPILER)</value> <value type="QString" key="Name">Qt %{Qt:Version} (SQUISH_DEFAULT_COMPILER)</value>
<value type="QString" key="QMakePath">~/Qt5.6.1/5.6/SQUISH_DEFAULT_COMPILER/bin/qmake</value> <value type="QString" key="QMakePath">~/Qt5.6.1/5.6/SQUISH_DEFAULT_COMPILER/bin/qmake</value>
<value type="QString" key="QtVersion.Type">Qt4ProjectManager.QtVersion.Desktop</value> <value type="QString" key="QtVersion.Type">Qt4ProjectManager.QtVersion.Desktop</value>
<value type="bool" key="isAutodetected">false</value> <value type="bool" key="isAutodetected">false</value>
@@ -26,8 +26,8 @@
<variable>QtVersion.2</variable> <variable>QtVersion.2</variable>
<valuemap type="QVariantMap"> <valuemap type="QVariantMap">
<value type="int" key="Id">11</value> <value type="int" key="Id">11</value>
<value type="QString" key="Name">Desktop Qt 5.3.1 (SQUISH_DEFAULT_COMPILER)</value> <value type="QString" key="Name">Qt %{Qt:Version} (SQUISH_DEFAULT_COMPILER)</value>
<value type="QString" key="QMakePath">~/Qt5.3.1/5.3/SQUISH_DEFAULT_COMPILER/bin/qmake</value> <value type="QString" key="QMakePath">~/Qt5.10.1/5.10.1/SQUISH_DEFAULT_COMPILER/bin/qmake</value>
<value type="QString" key="QtVersion.Type">Qt4ProjectManager.QtVersion.Desktop</value> <value type="QString" key="QtVersion.Type">Qt4ProjectManager.QtVersion.Desktop</value>
<value type="bool" key="isAutodetected">false</value> <value type="bool" key="isAutodetected">false</value>
</valuemap> </valuemap>

View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE QtCreatorProfiles> <!DOCTYPE QtCreatorProfiles>
<!-- Written by QtCreator 4.0.83, 2016-07-21T11:54:33. --> <!-- Written by QtCreator 4.5.1, 2018-01-10T17:26:12. -->
<qtcreator> <qtcreator>
<data> <data>
<variable>Profile.0</variable> <variable>Profile.0</variable>
@@ -50,29 +50,6 @@
</data> </data>
<data> <data>
<variable>Profile.2</variable> <variable>Profile.2</variable>
<valuemap type="QVariantMap">
<value type="bool" key="PE.Profile.AutoDetected">false</value>
<value type="QString" key="PE.Profile.AutoDetectionSource"></value>
<valuemap type="QVariantMap" key="PE.Profile.Data">
<value type="QString" key="Android.GdbServer.Information"></value>
<value type="QString" key="Debugger.Information">{70e26273-2c0b-4534-bbc0-eb6ca670821a}</value>
<value type="QString" key="PE.Profile.Device">Desktop Device</value>
<value type="QByteArray" key="PE.Profile.DeviceType">Desktop</value>
<value type="QString" key="PE.Profile.SysRoot"></value>
<value type="QString" key="PE.Profile.ToolChain">ProjectExplorer.ToolChain.Gcc:{c3f59b87-6997-4bd8-8067-ee04dc536371}</value>
<value type="QString" key="QtPM4.mkSpecInformation"></value>
<value type="int" key="QtSupport.QtInformation">11</value>
</valuemap>
<value type="QString" key="PE.Profile.Icon">:///DESKTOP///</value>
<value type="QString" key="PE.Profile.Id">{e91398ba-6443-4b02-b416-782a70d9df90}</value>
<valuelist type="QVariantList" key="PE.Profile.MutableInfo"/>
<value type="QString" key="PE.Profile.Name">Desktop 5.3.1 default</value>
<value type="bool" key="PE.Profile.SDK">false</value>
<valuelist type="QVariantList" key="PE.Profile.StickyInfo"/>
</valuemap>
</data>
<data>
<variable>Profile.3</variable>
<valuemap type="QVariantMap"> <valuemap type="QVariantMap">
<value type="bool" key="PE.Profile.AutoDetected">false</value> <value type="bool" key="PE.Profile.AutoDetected">false</value>
<value type="QString" key="PE.Profile.AutoDetectionSource"></value> <value type="QString" key="PE.Profile.AutoDetectionSource"></value>
@@ -96,7 +73,7 @@
</valuemap> </valuemap>
</data> </data>
<data> <data>
<variable>Profile.4</variable> <variable>Profile.3</variable>
<valuemap type="QVariantMap"> <valuemap type="QVariantMap">
<value type="bool" key="PE.Profile.AutoDetected">false</value> <value type="bool" key="PE.Profile.AutoDetected">false</value>
<value type="QString" key="PE.Profile.AutoDetectionSource"></value> <value type="QString" key="PE.Profile.AutoDetectionSource"></value>
@@ -119,13 +96,41 @@
<valuelist type="QVariantList" key="PE.Profile.StickyInfo"/> <valuelist type="QVariantList" key="PE.Profile.StickyInfo"/>
</valuemap> </valuemap>
</data> </data>
<data>
<variable>Profile.4</variable>
<valuemap type="QVariantMap">
<value type="bool" key="PE.Profile.AutoDetected">false</value>
<value type="QString" key="PE.Profile.AutoDetectionSource"></value>
<valuemap type="QVariantMap" key="PE.Profile.Data">
<value type="QString"></value>
<value type="QString" key="Android.GdbServer.Information"></value>
<value type="QString" key="Debugger.Information">{70e26273-2c0b-4534-bbc0-eb6ca670821a}</value>
<value type="QString" key="PE.Profile.Device">Desktop Device</value>
<value type="QByteArray" key="PE.Profile.DeviceType">Desktop</value>
<valuelist type="QVariantList" key="PE.Profile.Environment"/>
<value type="QString" key="PE.Profile.SysRoot"></value>
<valuemap type="QVariantMap" key="PE.Profile.ToolChainsV3">
<value type="QByteArray" key="C">{7bfd4fd4-e64a-417f-b10f-20602e1719d1}</value>
<value type="QByteArray" key="Cxx">{c3f59b87-6997-4bd8-8067-ee04dc536371}</value>
</valuemap>
<value type="QString" key="QtPM4.mkSpecInformation"></value>
<value type="int" key="QtSupport.QtInformation">17</value>
</valuemap>
<value type="QString" key="PE.Profile.Icon"></value>
<value type="QString" key="PE.Profile.Id">{0d32ea2d-f954-4011-8f7c-80da4977c94c}</value>
<valuelist type="QVariantList" key="PE.Profile.MutableInfo"/>
<value type="QString" key="PE.Profile.Name">Desktop 5.10.1 default</value>
<value type="bool" key="PE.Profile.SDK">false</value>
<valuelist type="QVariantList" key="PE.Profile.StickyInfo"/>
</valuemap>
</data>
<data> <data>
<variable>Profile.Count</variable> <variable>Profile.Count</variable>
<value type="int">5</value> <value type="int">5</value>
</data> </data>
<data> <data>
<variable>Profile.Default</variable> <variable>Profile.Default</variable>
<value type="QString">{e91398ba-6443-4b02-b416-782a70d9df90}</value> <value type="QString">{542217c7-ce0f-48f7-843b-d4fad339688d}</value>
</data> </data>
<data> <data>
<variable>Version</variable> <variable>Version</variable>

View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE QtCreatorQtVersions> <!DOCTYPE QtCreatorQtVersions>
<!-- Written by QtCreator 4.0.83, 2016-07-21T11:54:33. --> <!-- Written by QtCreator 4.5.1, 2018-01-10T17:13:44. -->
<qtcreator> <qtcreator>
<data> <data>
<variable>QtVersion.0</variable> <variable>QtVersion.0</variable>
@@ -14,16 +14,6 @@
</data> </data>
<data> <data>
<variable>QtVersion.1</variable> <variable>QtVersion.1</variable>
<valuemap type="QVariantMap">
<value type="int" key="Id">11</value>
<value type="QString" key="Name">Qt 5.3.1 (SQUISH_DEFAULT_COMPILER)</value>
<value type="QString" key="QMakePath">~/Qt5.3.1/5.3/SQUISH_DEFAULT_COMPILER/bin/qmake</value>
<value type="QString" key="QtVersion.Type">Qt4ProjectManager.QtVersion.Desktop</value>
<value type="bool" key="isAutodetected">false</value>
</valuemap>
</data>
<data>
<variable>QtVersion.2</variable>
<valuemap type="QVariantMap"> <valuemap type="QVariantMap">
<value type="int" key="Id">13</value> <value type="int" key="Id">13</value>
<value type="QString" key="Name">Qt %{Qt:Version} (SQUISH_DEFAULT_COMPILER)</value> <value type="QString" key="Name">Qt %{Qt:Version} (SQUISH_DEFAULT_COMPILER)</value>
@@ -33,7 +23,7 @@
</valuemap> </valuemap>
</data> </data>
<data> <data>
<variable>QtVersion.3</variable> <variable>QtVersion.2</variable>
<valuemap type="QVariantMap"> <valuemap type="QVariantMap">
<value type="int" key="Id">15</value> <value type="int" key="Id">15</value>
<value type="QString" key="Name">Qt %{Qt:Version} (SQUISH_DEFAULT_COMPILER)</value> <value type="QString" key="Name">Qt %{Qt:Version} (SQUISH_DEFAULT_COMPILER)</value>
@@ -42,6 +32,16 @@
<value type="bool" key="isAutodetected">false</value> <value type="bool" key="isAutodetected">false</value>
</valuemap> </valuemap>
</data> </data>
<data>
<variable>QtVersion.3</variable>
<valuemap type="QVariantMap">
<value type="int" key="Id">17</value>
<value type="QString" key="Name">Qt %{Qt:Version} (SQUISH_DEFAULT_COMPILER)</value>
<value type="QString" key="QMakePath">~/Qt5.10.1/5.10.1/SQUISH_DEFAULT_COMPILER/bin/qmake</value>
<value type="QString" key="QtVersion.Type">Qt4ProjectManager.QtVersion.Desktop</value>
<value type="bool" key="isAutodetected">false</value>
</valuemap>
</data>
<data> <data>
<variable>Version</variable> <variable>Version</variable>
<value type="int">1</value> <value type="int">1</value>

View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE QtCreatorProfiles> <!DOCTYPE QtCreatorProfiles>
<!-- Written by QtCreator 4.2.2, 2017-02-10T17:44:37. --> <!-- Written by QtCreator 4.5.1, 2018-01-10T14:28:58. -->
<qtcreator> <qtcreator>
<data> <data>
<variable>Profile.0</variable> <variable>Profile.0</variable>
@@ -32,34 +32,6 @@
</data> </data>
<data> <data>
<variable>Profile.1</variable> <variable>Profile.1</variable>
<valuemap type="QVariantMap">
<value type="bool" key="PE.Profile.AutoDetected">false</value>
<value type="QString" key="PE.Profile.AutoDetectionSource"></value>
<valuemap type="QVariantMap" key="PE.Profile.Data">
<value type="QString" key="Android.GdbServer.Information"></value>
<value type="QString" key="Debugger.Information">{1b25f20a-d584-4fb7-85b3-74dd15b82f6f}</value>
<value type="QString" key="PE.Profile.Device">Desktop Device</value>
<value type="QByteArray" key="PE.Profile.DeviceType">Desktop</value>
<valuelist type="QVariantList" key="PE.Profile.Environment"/>
<value type="QString" key="PE.Profile.SysRoot"></value>
<value type="QString" key="PE.Profile.ToolChain">ProjectExplorer.ToolChain.Msvc:{1186dad9-c485-4f69-b7e1-aff54c89ecb2}</value>
<valuemap type="QVariantMap" key="PE.Profile.ToolChains">
<value type="QByteArray" key="C">{93e707bd-236f-4d8d-917d-814aa358024b}</value>
<value type="QString" key="Cxx">ProjectExplorer.ToolChain.Msvc:{1186dad9-c485-4f69-b7e1-aff54c89ecb2}</value>
</valuemap>
<value type="QString" key="QtPM4.mkSpecInformation"></value>
<value type="int" key="QtSupport.QtInformation">20</value>
</valuemap>
<value type="QString" key="PE.Profile.Icon">:///DESKTOP///</value>
<value type="QString" key="PE.Profile.Id">{6a95566e-8372-4372-8286-ef73af7de191}</value>
<valuelist type="QVariantList" key="PE.Profile.MutableInfo"/>
<value type="QString" key="PE.Profile.Name">Desktop 5.3.1 default</value>
<value type="bool" key="PE.Profile.SDK">false</value>
<valuelist type="QVariantList" key="PE.Profile.StickyInfo"/>
</valuemap>
</data>
<data>
<variable>Profile.2</variable>
<valuemap type="QVariantMap"> <valuemap type="QVariantMap">
<value type="bool" key="PE.Profile.AutoDetected">false</value> <value type="bool" key="PE.Profile.AutoDetected">false</value>
<value type="QString" key="PE.Profile.AutoDetectionSource"></value> <value type="QString" key="PE.Profile.AutoDetectionSource"></value>
@@ -87,7 +59,7 @@
</valuemap> </valuemap>
</data> </data>
<data> <data>
<variable>Profile.3</variable> <variable>Profile.2</variable>
<valuemap type="QVariantMap"> <valuemap type="QVariantMap">
<value type="bool" key="PE.Profile.AutoDetected">false</value> <value type="bool" key="PE.Profile.AutoDetected">false</value>
<value type="QString" key="PE.Profile.AutoDetectionSource"></value> <value type="QString" key="PE.Profile.AutoDetectionSource"></value>
@@ -114,13 +86,41 @@
<valuelist type="QVariantList" key="PE.Profile.StickyInfo"/> <valuelist type="QVariantList" key="PE.Profile.StickyInfo"/>
</valuemap> </valuemap>
</data> </data>
<data>
<variable>Profile.3</variable>
<valuemap type="QVariantMap">
<value type="bool" key="PE.Profile.AutoDetected">false</value>
<value type="QString" key="PE.Profile.AutoDetectionSource"></value>
<valuemap type="QVariantMap" key="PE.Profile.Data">
<value type="QString"></value>
<value type="QString" key="Android.GdbServer.Information"></value>
<value type="QString" key="Debugger.Information">{1b25f20a-d584-4fb7-85b3-74dd15b82f6f}</value>
<value type="QString" key="PE.Profile.Device">Desktop Device</value>
<value type="QByteArray" key="PE.Profile.DeviceType">Desktop</value>
<valuelist type="QVariantList" key="PE.Profile.Environment"/>
<value type="QString" key="PE.Profile.SysRoot"></value>
<valuemap type="QVariantMap" key="PE.Profile.ToolChainsV3">
<value type="QByteArray" key="C">{c96cfaf3-fb8a-472b-b3c7-e94e8c490f17}</value>
<value type="QByteArray" key="Cxx">{ed856706-2a9d-4745-9d85-4e322b6f91d4}</value>
</valuemap>
<value type="QString" key="QtPM4.mkSpecInformation"></value>
<value type="int" key="QtSupport.QtInformation">26</value>
</valuemap>
<value type="QString" key="PE.Profile.Icon"></value>
<value type="QString" key="PE.Profile.Id">{37fad24d-07f3-442e-8c65-d9ded3633f7e}</value>
<valuelist type="QVariantList" key="PE.Profile.MutableInfo"/>
<value type="QString" key="PE.Profile.Name">Desktop 5.10.1 default</value>
<value type="bool" key="PE.Profile.SDK">false</value>
<valuelist type="QVariantList" key="PE.Profile.StickyInfo"/>
</valuemap>
</data>
<data> <data>
<variable>Profile.Count</variable> <variable>Profile.Count</variable>
<value type="int">4</value> <value type="int">4</value>
</data> </data>
<data> <data>
<variable>Profile.Default</variable> <variable>Profile.Default</variable>
<value type="QString">{6a95566e-8372-4372-8286-ef73af7de191}</value> <value type="QString">{f9c7858c-d167-4b78-847a-91943bd0af07}</value>
</data> </data>
<data> <data>
<variable>Version</variable> <variable>Version</variable>

View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE QtCreatorQtVersions> <!DOCTYPE QtCreatorQtVersions>
<!-- Written by QtCreator 4.0.83, 2016-07-20T17:07:18. --> <!-- Written by QtCreator 4.5.1, 2018-01-10T14:24:21. -->
<qtcreator> <qtcreator>
<data> <data>
<variable>QtVersion.0</variable> <variable>QtVersion.0</variable>
@@ -14,16 +14,6 @@
</data> </data>
<data> <data>
<variable>QtVersion.1</variable> <variable>QtVersion.1</variable>
<valuemap type="QVariantMap">
<value type="int" key="Id">20</value>
<value type="QString" key="Name">Qt 5.3.1 (msvc2010_opengl)</value>
<value type="QString" key="QMakePath">C:/Qt/Qt5.3.1/5.3/msvc2010_opengl/bin/qmake.exe</value>
<value type="QString" key="QtVersion.Type">Qt4ProjectManager.QtVersion.Desktop</value>
<value type="bool" key="isAutodetected">false</value>
</valuemap>
</data>
<data>
<variable>QtVersion.2</variable>
<valuemap type="QVariantMap"> <valuemap type="QVariantMap">
<value type="int" key="Id">22</value> <value type="int" key="Id">22</value>
<value type="QString" key="Name">Qt %{Qt:Version} (mingw491_32)</value> <value type="QString" key="Name">Qt %{Qt:Version} (mingw491_32)</value>
@@ -33,7 +23,7 @@
</valuemap> </valuemap>
</data> </data>
<data> <data>
<variable>QtVersion.3</variable> <variable>QtVersion.2</variable>
<valuemap type="QVariantMap"> <valuemap type="QVariantMap">
<value type="int" key="Id">24</value> <value type="int" key="Id">24</value>
<value type="QString" key="Name">Qt %{Qt:Version} (msvc2013)</value> <value type="QString" key="Name">Qt %{Qt:Version} (msvc2013)</value>
@@ -42,6 +32,16 @@
<value type="bool" key="isAutodetected">false</value> <value type="bool" key="isAutodetected">false</value>
</valuemap> </valuemap>
</data> </data>
<data>
<variable>QtVersion.3</variable>
<valuemap type="QVariantMap">
<value type="int" key="Id">26</value>
<value type="QString" key="Name">Qt %{Qt:Version} (msvc2015)</value>
<value type="QString" key="QMakePath">C:/Qt/Qt5.10.1/5.10.1/msvc2015/bin/qmake.exe</value>
<value type="QString" key="QtVersion.Type">Qt4ProjectManager.QtVersion.Desktop</value>
<value type="bool" key="isAutodetected">false</value>
</valuemap>
</data>
<data> <data>
<variable>Version</variable> <variable>Version</variable>
<value type="int">1</value> <value type="int">1</value>

View File

@@ -4,17 +4,6 @@
<qtcreator> <qtcreator>
<data> <data>
<variable>ToolChain.0</variable> <variable>ToolChain.0</variable>
<valuemap type="QVariantMap">
<value type="QString" key="ProjectExplorer.MsvcToolChain.SupportedAbi">x86-windows-msvc2010-pe-32bit</value>
<value type="QString" key="ProjectExplorer.MsvcToolChain.VarsBat">c:/Program Files (x86)/Microsoft Visual Studio 10.0/VC/vcvarsall.bat</value>
<value type="QString" key="ProjectExplorer.MsvcToolChain.VarsBatArg">x86</value>
<value type="bool" key="ProjectExplorer.ToolChain.Autodetect">true</value>
<value type="QString" key="ProjectExplorer.ToolChain.DisplayName">Microsoft Visual C++ Compiler 10.0 (x86)</value>
<value type="QString" key="ProjectExplorer.ToolChain.Id">ProjectExplorer.ToolChain.Msvc:{1186dad9-c485-4f69-b7e1-aff54c89ecb2}</value>
</valuemap>
</data>
<data>
<variable>ToolChain.1</variable>
<valuemap type="QVariantMap"> <valuemap type="QVariantMap">
<value type="QString" key="ProjectExplorer.GccToolChain.Path">C:/Qt/Qt5.4.1/Tools/mingw491_32/bin/g++.exe</value> <value type="QString" key="ProjectExplorer.GccToolChain.Path">C:/Qt/Qt5.4.1/Tools/mingw491_32/bin/g++.exe</value>
<valuelist type="QVariantList" key="ProjectExplorer.GccToolChain.PlatformCodeGenFlags"/> <valuelist type="QVariantList" key="ProjectExplorer.GccToolChain.PlatformCodeGenFlags"/>
@@ -29,19 +18,7 @@
</valuemap> </valuemap>
</data> </data>
<data> <data>
<variable>ToolChain.2</variable> <variable>ToolChain.1</variable>
<valuemap type="QVariantMap">
<value type="QString" key="ProjectExplorer.MsvcToolChain.SupportedAbi">x86-windows-msvc2010-pe-32bit</value>
<value type="QString" key="ProjectExplorer.MsvcToolChain.VarsBat">C:/Program Files (x86)/Microsoft Visual Studio 10.0/VC/vcvarsall.bat</value>
<value type="QString" key="ProjectExplorer.MsvcToolChain.VarsBatArg">x86</value>
<value type="bool" key="ProjectExplorer.ToolChain.Autodetect">true</value>
<value type="QString" key="ProjectExplorer.ToolChain.DisplayName">Microsoft Visual C++ Compiler 10.0 (x86)</value>
<value type="QString" key="ProjectExplorer.ToolChain.Id">ProjectExplorer.ToolChain.Msvc:{93e707bd-236f-4d8d-917d-814aa358024b}</value>
<value type="int" key="ProjectExplorer.ToolChain.Language">1</value>
</valuemap>
</data>
<data>
<variable>ToolChain.3</variable>
<valuemap type="QVariantMap"> <valuemap type="QVariantMap">
<value type="QString" key="ProjectExplorer.MsvcToolChain.SupportedAbi">x86-windows-msvc2013-pe-32bit</value> <value type="QString" key="ProjectExplorer.MsvcToolChain.SupportedAbi">x86-windows-msvc2013-pe-32bit</value>
<value type="QString" key="ProjectExplorer.MsvcToolChain.VarsBat">C:/Program Files (x86)/Microsoft Visual Studio 12.0/VC/vcvarsall.bat</value> <value type="QString" key="ProjectExplorer.MsvcToolChain.VarsBat">C:/Program Files (x86)/Microsoft Visual Studio 12.0/VC/vcvarsall.bat</value>
@@ -53,7 +30,7 @@
</valuemap> </valuemap>
</data> </data>
<data> <data>
<variable>ToolChain.4</variable> <variable>ToolChain.2</variable>
<valuemap type="QVariantMap"> <valuemap type="QVariantMap">
<value type="QString" key="ProjectExplorer.GccToolChain.OriginalTargetTriple">i686-w64-mingw32</value> <value type="QString" key="ProjectExplorer.GccToolChain.OriginalTargetTriple">i686-w64-mingw32</value>
<value type="QString" key="ProjectExplorer.GccToolChain.Path">C:/Qt/Qt5.4.1/Tools/mingw491_32/bin/gcc.exe</value> <value type="QString" key="ProjectExplorer.GccToolChain.Path">C:/Qt/Qt5.4.1/Tools/mingw491_32/bin/gcc.exe</value>
@@ -69,6 +46,32 @@
<value type="int" key="ProjectExplorer.ToolChain.Language">1</value> <value type="int" key="ProjectExplorer.ToolChain.Language">1</value>
</valuemap> </valuemap>
</data> </data>
<data>
<variable>ToolChain.3</variable>
<valuemap type="QVariantMap">
<value type="QString" key="ProjectExplorer.MsvcToolChain.SupportedAbi">x86-windows-msvc2015-pe-32bit</value>
<value type="QString" key="ProjectExplorer.MsvcToolChain.VarsBat">C:/Program Files (x86)/Microsoft Visual Studio 14.0/VC/vcvarsall.bat</value>
<value type="QString" key="ProjectExplorer.MsvcToolChain.VarsBatArg">x86</value>
<value type="bool" key="ProjectExplorer.ToolChain.Autodetect">true</value>
<value type="QString" key="ProjectExplorer.ToolChain.DisplayName">Microsoft Visual C++ Compiler 14.0 (x86)</value>
<value type="QString" key="ProjectExplorer.ToolChain.Id">ProjectExplorer.ToolChain.Msvc:{c96cfaf3-fb8a-472b-b3c7-e94e8c490f17}</value>
<value type="int" key="ProjectExplorer.ToolChain.Language">1</value>
<value type="QString" key="ProjectExplorer.ToolChain.LanguageV2">C</value>
</valuemap>
</data>
<data>
<variable>ToolChain.4</variable>
<valuemap type="QVariantMap">
<value type="QString" key="ProjectExplorer.MsvcToolChain.SupportedAbi">x86-windows-msvc2015-pe-32bit</value>
<value type="QString" key="ProjectExplorer.MsvcToolChain.VarsBat">C:/Program Files (x86)/Microsoft Visual Studio 14.0/VC/vcvarsall.bat</value>
<value type="QString" key="ProjectExplorer.MsvcToolChain.VarsBatArg">x86</value>
<value type="bool" key="ProjectExplorer.ToolChain.Autodetect">true</value>
<value type="QString" key="ProjectExplorer.ToolChain.DisplayName">Microsoft Visual C++ Compiler 14.0 (x86)</value>
<value type="QString" key="ProjectExplorer.ToolChain.Id">ProjectExplorer.ToolChain.Msvc:{ed856706-2a9d-4745-9d85-4e322b6f91d4}</value>
<value type="int" key="ProjectExplorer.ToolChain.Language">2</value>
<value type="QString" key="ProjectExplorer.ToolChain.LanguageV2">Cxx</value>
</valuemap>
</data>
<data> <data>
<variable>ToolChain.5</variable> <variable>ToolChain.5</variable>
<valuemap type="QVariantMap"> <valuemap type="QVariantMap">

View File

@@ -32,9 +32,9 @@ class Targets:
(DESKTOP_4_8_7_DEFAULT, (DESKTOP_4_8_7_DEFAULT,
EMBEDDED_LINUX, EMBEDDED_LINUX,
DESKTOP_5_3_1_DEFAULT,
DESKTOP_5_4_1_GCC, DESKTOP_5_4_1_GCC,
DESKTOP_5_6_1_DEFAULT) = ALL_TARGETS DESKTOP_5_6_1_DEFAULT,
DESKTOP_5_10_1_DEFAULT) = ALL_TARGETS
@staticmethod @staticmethod
def availableTargetClasses(): def availableTargetClasses():
@@ -62,12 +62,12 @@ class Targets:
return "Desktop 4.8.7 default" return "Desktop 4.8.7 default"
elif target == Targets.EMBEDDED_LINUX: elif target == Targets.EMBEDDED_LINUX:
return "Embedded Linux" return "Embedded Linux"
elif target == Targets.DESKTOP_5_3_1_DEFAULT:
return "Desktop 5.3.1 default"
elif target == Targets.DESKTOP_5_4_1_GCC: elif target == Targets.DESKTOP_5_4_1_GCC:
return "Desktop 5.4.1 GCC" return "Desktop 5.4.1 GCC"
elif target == Targets.DESKTOP_5_6_1_DEFAULT: elif target == Targets.DESKTOP_5_6_1_DEFAULT:
return "Desktop 5.6.1 default" return "Desktop 5.6.1 default"
elif target == Targets.DESKTOP_5_10_1_DEFAULT:
return "Desktop 5.10.1 default"
else: else:
return None return None
@@ -83,7 +83,7 @@ class Targets:
@staticmethod @staticmethod
def getDefaultKit(): def getDefaultKit():
return Targets.DESKTOP_5_3_1_DEFAULT return Targets.DESKTOP_5_6_1_DEFAULT
# this class holds some constants for easier usage inside the Projects view # this class holds some constants for easier usage inside the Projects view
class ProjectSettings: class ProjectSettings:
@@ -169,7 +169,7 @@ class Qt5Path:
@staticmethod @staticmethod
def getPaths(pathSpec): def getPaths(pathSpec):
qt5targets = [Targets.DESKTOP_5_3_1_DEFAULT, Targets.DESKTOP_5_6_1_DEFAULT] qt5targets = [Targets.DESKTOP_5_6_1_DEFAULT, Targets.DESKTOP_5_10_1_DEFAULT]
if platform.system() != 'Darwin': if platform.system() != 'Darwin':
qt5targets.append(Targets.DESKTOP_5_4_1_GCC) qt5targets.append(Targets.DESKTOP_5_4_1_GCC)
if pathSpec == Qt5Path.DOCS: if pathSpec == Qt5Path.DOCS:
@@ -223,20 +223,20 @@ class Qt5Path:
@staticmethod @staticmethod
def examplesPath(target): def examplesPath(target):
qtMinorVersion, qtPatchVersion = Qt5Path.getQtMinorAndPatchVersion(target) qtMinorVersion, qtPatchVersion = Qt5Path.getQtMinorAndPatchVersion(target)
if qtMinorVersion == 2: if qtMinorVersion < 10:
path = "examples"
else:
path = "Examples/Qt-5.%d" % qtMinorVersion path = "Examples/Qt-5.%d" % qtMinorVersion
else:
path = "Examples/Qt-5.%d.%d" % (qtMinorVersion, qtPatchVersion)
return os.path.join(Qt5Path.__createPlatformQtPath__(qtMinorVersion), path) return os.path.join(Qt5Path.__createPlatformQtPath__(qtMinorVersion), path)
@staticmethod @staticmethod
def docsPath(target): def docsPath(target):
qtMinorVersion, qtPatchVersion = Qt5Path.getQtMinorAndPatchVersion(target) qtMinorVersion, qtPatchVersion = Qt5Path.getQtMinorAndPatchVersion(target)
if qtMinorVersion == 2: if qtMinorVersion < 10:
path = "doc"
else:
path = "Docs/Qt-5.%d" % qtMinorVersion path = "Docs/Qt-5.%d" % qtMinorVersion
else:
path = "Docs/Qt-5.%d.%d" % (qtMinorVersion, qtPatchVersion)
return os.path.join(Qt5Path.__createPlatformQtPath__(qtMinorVersion), path) return os.path.join(Qt5Path.__createPlatformQtPath__(qtMinorVersion), path)

View File

@@ -315,7 +315,7 @@ def createNewQtQuickUI(workingDir, qtVersion = "5.6"):
return projectName return projectName
def createNewQmlExtension(workingDir, targets=[Targets.DESKTOP_5_3_1_DEFAULT]): def createNewQmlExtension(workingDir, targets=[Targets.DESKTOP_5_6_1_DEFAULT]):
available = __createProjectOrFileSelectType__(" Library", "Qt Quick 2 Extension Plugin") available = __createProjectOrFileSelectType__(" Library", "Qt Quick 2 Extension Plugin")
if workingDir == None: if workingDir == None:
workingDir = tempDir() workingDir = tempDir()
@@ -639,10 +639,11 @@ def __getSupportedPlatforms__(text, templateName, getAsStrings=False):
version = res.group("version") version = res.group("version")
else: else:
version = None version = None
if 'only available with Qt 5.6' in text: if templateName.startswith("Qt Quick Application - "):
result = [Targets.DESKTOP_5_6_1_DEFAULT] if templateName == "Qt Quick Application - Empty":
elif 'available with Qt 5.7 and later' in text: result = [Targets.DESKTOP_5_6_1_DEFAULT, Targets.DESKTOP_5_10_1_DEFAULT]
result = [] # FIXME we have currently no Qt5.7+ available in predefined settings else:
result = [Targets.DESKTOP_5_10_1_DEFAULT]
elif 'Supported Platforms' in text: elif 'Supported Platforms' in text:
supports = text[text.find('Supported Platforms'):].split(":")[1].strip().split(" ") supports = text[text.find('Supported Platforms'):].split(":")[1].strip().split(" ")
result = [] result = []
@@ -651,7 +652,7 @@ def __getSupportedPlatforms__(text, templateName, getAsStrings=False):
result.append(Targets.DESKTOP_4_8_7_DEFAULT) result.append(Targets.DESKTOP_4_8_7_DEFAULT)
if platform.system() in ("Linux", "Darwin"): if platform.system() in ("Linux", "Darwin"):
result.append(Targets.EMBEDDED_LINUX) result.append(Targets.EMBEDDED_LINUX)
result.extend([Targets.DESKTOP_5_3_1_DEFAULT, Targets.DESKTOP_5_6_1_DEFAULT]) result.extend([Targets.DESKTOP_5_6_1_DEFAULT, Targets.DESKTOP_5_10_1_DEFAULT])
if platform.system() != 'Darwin': if platform.system() != 'Darwin':
result.append(Targets.DESKTOP_5_4_1_GCC) result.append(Targets.DESKTOP_5_4_1_GCC)
elif 'Platform independent' in text: elif 'Platform independent' in text:

View File

@@ -165,7 +165,7 @@ def main():
with TestSection(getCodeModelString(useClang)): with TestSection(getCodeModelString(useClang)):
if not startCreator(useClang): if not startCreator(useClang):
continue continue
openQmakeProject(examplePath, [Targets.DESKTOP_5_3_1_DEFAULT]) openQmakeProject(examplePath, [Targets.DESKTOP_5_6_1_DEFAULT])
checkCodeModelSettings(useClang) checkCodeModelSettings(useClang)
if not openDocument("cplusplus-tools.Sources.main\\.cpp"): if not openDocument("cplusplus-tools.Sources.main\\.cpp"):
earlyExit("Failed to open main.cpp.") earlyExit("Failed to open main.cpp.")

View File

@@ -80,7 +80,7 @@ def main():
if not startedWithoutPluginError(): if not startedWithoutPluginError():
return return
# open example project # open example project
openQmakeProject(examplePath, [Targets.DESKTOP_5_3_1_DEFAULT]) openQmakeProject(examplePath, [Targets.DESKTOP_5_6_1_DEFAULT])
# open qml file # open qml file
openDocument("animation.Resources.animation\\.qrc./animation.basics.color-animation\\.qml") openDocument("animation.Resources.animation\\.qrc./animation.basics.color-animation\\.qml")
# get editor # get editor

View File

@@ -123,7 +123,7 @@ def main():
for p in proFiles: for p in proFiles:
removePackagingDirectory(os.path.dirname(p)) removePackagingDirectory(os.path.dirname(p))
examplesLineEdit = waitForObject(search %(expect[1][0], expect[1][1])) examplesLineEdit = waitForObject(search %(expect[1][0], expect[1][1]))
example = openExample(examplesLineEdit, "address book", "Address Book.*", example = openExample(examplesLineEdit, "address book", "(0000 )?Address Book.*",
"Address Book Example") "Address Book Example")
if example is not None: if example is not None:
# close second example application # close second example application

View File

@@ -108,7 +108,7 @@ def performTest(workingDir, projectName, targetCount, availableConfigs):
colMean, colMedian, colLongest, colShortest) = range(2, 11) colMean, colMedian, colLongest, colShortest) = range(2, 11)
model = waitForObject(":Events.QmlProfilerEventsTable_QmlProfiler::" model = waitForObject(":Events.QmlProfilerEventsTable_QmlProfiler::"
"Internal::QmlProfilerStatisticsMainView").model() "Internal::QmlProfilerStatisticsMainView").model()
compareEventsTab(model, "events_qt5.tsv") compareEventsTab(model, "events_qt%s.tsv" % qtVersion)
test.compare(dumpItems(model, column=colPercent)[0], '100.00 %') test.compare(dumpItems(model, column=colPercent)[0], '100.00 %')
# cannot run following test on colShortest (unstable) # cannot run following test on colShortest (unstable)
for i in [colTotal, colMean, colMedian, colLongest]: for i in [colTotal, colMean, colMedian, colLongest]:

View File

@@ -0,0 +1,10 @@
"0" "1" "6" "11"
"<program>" "" "1" "Main Program"
"main.qml:15" "Handling Signal" "2" "onTriggered: { runCount += 1; var i; for (i = 1; i < 2500; ++i) { var j = i * i; console.log(j); } }"
"main.qml:15" "JavaScript" "2" "onTriggered"
"main.qml:4" "Creating" "2" "QtQuick.Window/Window"
"main.qml:0" "Compiling" "1" "main.qml"
"main.qml:10" "Creating" "2" "QtQuick/Timer"
"main.qml:14" "Binding" "3" "running: runCount < 2"
"main.qml:14" "JavaScript" "3" "expression for running"
"<bytecode>" "Binding" "1" "Source code not available"
1 0 1 6 11
2 <program> 1 Main Program
3 main.qml:15 Handling Signal 2 onTriggered: { runCount += 1; var i; for (i = 1; i < 2500; ++i) { var j = i * i; console.log(j); } }
4 main.qml:15 JavaScript 2 onTriggered
5 main.qml:4 Creating 2 QtQuick.Window/Window
6 main.qml:0 Compiling 1 main.qml
7 main.qml:10 Creating 2 QtQuick/Timer
8 main.qml:14 Binding 3 running: runCount < 2
9 main.qml:14 JavaScript 3 expression for running
10 <bytecode> Binding 1 Source code not available

View File

@@ -27,7 +27,6 @@ source("../../shared/qtcreator.py")
def main(): def main():
global tmpSettingsDir, availableBuildSystems global tmpSettingsDir, availableBuildSystems
qtVersionsForQuick = ["5.6"]
availableBuildSystems = ["qmake", "Qbs"] availableBuildSystems = ["qmake", "Qbs"]
if which("cmake"): if which("cmake"):
availableBuildSystems.append("CMake") availableBuildSystems.append("CMake")
@@ -72,6 +71,7 @@ def main():
template = current.values()[0] template = current.values()[0]
displayedPlatforms = __createProject__(category, template) displayedPlatforms = __createProject__(category, template)
if template.startswith("Qt Quick Application - "): if template.startswith("Qt Quick Application - "):
qtVersionsForQuick = ["5.6", "5.10"] if template == "Qt Quick Application - Empty" else ["5.10"]
for counter, qtVersion in enumerate(qtVersionsForQuick): for counter, qtVersion in enumerate(qtVersionsForQuick):
def additionalFunc(displayedPlatforms, qtVersion): def additionalFunc(displayedPlatforms, qtVersion):
requiredQtVersion = __createProjectHandleQtQuickSelection__(qtVersion) requiredQtVersion = __createProjectHandleQtQuickSelection__(qtVersion)
@@ -128,9 +128,7 @@ def handleBuildSystemVerifyKits(category, template, kits, displayedPlatforms,
test.log("Using build system '%s'" % buildSystem) test.log("Using build system '%s'" % buildSystem)
selectFromCombo(combo, buildSystem) selectFromCombo(combo, buildSystem)
clickButton(waitForObject(":Next_QPushButton")) clickButton(waitForObject(":Next_QPushButton"))
if (template.startswith("Qt Quick Application - ") if template == "Qt Quick Application - Scroll":
and template != "Qt Quick Application - Empty"):
test.warning("No suitable Qt version available for '%s'" % template)
clickButton(waitForObject(":Next_QPushButton")) clickButton(waitForObject(":Next_QPushButton"))
elif specialHandlingFunc: elif specialHandlingFunc:
specialHandlingFunc(displayedPlatforms, *args) specialHandlingFunc(displayedPlatforms, *args)

View File

@@ -188,7 +188,8 @@ def __getExpectedCompilers__():
compilers.extend(findAllFilesInPATH("*g++*")) compilers.extend(findAllFilesInPATH("*g++*"))
compilers.extend(findAllFilesInPATH("*gcc*")) compilers.extend(findAllFilesInPATH("*gcc*"))
if platform.system() == 'Darwin': if platform.system() == 'Darwin':
xcodeClang = getOutputFromCmdline(["xcrun", "--find", "clang++"]).strip("\n") for compilerExe in ('clang++', 'clang'):
xcodeClang = getOutputFromCmdline(["xcrun", "--find", compilerExe]).strip("\n")
if xcodeClang and os.path.exists(xcodeClang) and xcodeClang not in expected: if xcodeClang and os.path.exists(xcodeClang) and xcodeClang not in expected:
expected.append(xcodeClang) expected.append(xcodeClang)
for compiler in compilers: for compiler in compilers:

View File

@@ -64,7 +64,7 @@ def main():
openGeneralMessages() openGeneralMessages()
# Verify messages appear once, from using default kit before configuring # Verify messages appear once, from using default kit before configuring
generalMessages = str(waitForObject(":Qt Creator_Core::OutputWindow").plainText) generalMessages = str(waitForObject(":Qt Creator_Core::OutputWindow").plainText)
test.compare(generalMessages.count("Project MESSAGE: Cannot build Qt Creator with Qt version 5.3.1."), 1, test.compare(generalMessages.count("Project MESSAGE: Cannot build Qt Creator with Qt version 5.6.1."), 2,
"Warning about outdated Qt shown?") "Warning about outdated Qt shown?")
test.compare(generalMessages.count("Project ERROR: Use at least Qt 5.6.2."), 2, test.compare(generalMessages.count("Project ERROR: Use at least Qt 5.6.2."), 2,
"Minimum Qt version shown (once when parsing with default kit, once with selected)?") "Minimum Qt version shown (once when parsing with default kit, once with selected)?")

View File

@@ -53,6 +53,8 @@ def main():
["Resources", "adding.qrc"], ["Resources", "adding.qrc"],
["QML", "example.qml"]]: ["QML", "example.qml"]]:
filenames = ["ABCD" + filename.upper(), "abcd" + filename.lower(), "test", "TEST", filename] filenames = ["ABCD" + filename.upper(), "abcd" + filename.lower(), "test", "TEST", filename]
if (filename.endswith(".qrc") and JIRA.isBugStillOpen(20101)):
filenames.remove("ABCD" + filename.upper())
previous = filenames[-1] previous = filenames[-1]
for filename in filenames: for filename in filenames:
tempFiletype = filetype tempFiletype = filetype

View File

@@ -39,7 +39,7 @@ def main():
"Verifying window title contains created session name.") "Verifying window title contains created session name.")
checkWelcomePage(sessionName, True) checkWelcomePage(sessionName, True)
for project in projects: for project in projects:
openQmakeProject(project, [Targets.DESKTOP_5_3_1_DEFAULT]) openQmakeProject(project, [Targets.DESKTOP_5_6_1_DEFAULT])
progressBarWait(20000) progressBarWait(20000)
checkNavigator(52, "Verifying whether all projects have been opened.") checkNavigator(52, "Verifying whether all projects have been opened.")
openDocument("animation.Resources.animation\\.qrc./animation.basics.animators\\.qml") openDocument("animation.Resources.animation\\.qrc./animation.basics.animators\\.qml")

View File

@@ -39,7 +39,7 @@ def main():
startApplication("qtcreator" + SettingsPath) startApplication("qtcreator" + SettingsPath)
if not startedWithoutPluginError(): if not startedWithoutPluginError():
return return
openQmakeProject(os.path.join(templateDir, proFile), [Targets.DESKTOP_5_3_1_DEFAULT]) openQmakeProject(os.path.join(templateDir, proFile), [Targets.DESKTOP_5_6_1_DEFAULT])
qmlFiles = [treebase + "focus\\.qml", treebase + "Core.ListMenu\\.qml"] qmlFiles = [treebase + "focus\\.qml", treebase + "Core.ListMenu\\.qml"]
checkOutlineFor(qmlFiles) checkOutlineFor(qmlFiles)
testModify() testModify()

View File

@@ -35,14 +35,8 @@ def main():
# using a temporary directory won't mess up a potentially existing # using a temporary directory won't mess up a potentially existing
workingDir = tempDir() workingDir = tempDir()
projectName = createNewQtQuickUI(workingDir, qtVersion) projectName = createNewQtQuickUI(workingDir, qtVersion)
kit = Targets.getStringForTarget(Targets.DESKTOP_5_6_1_DEFAULT)
if addAndActivateKit(Targets.DESKTOP_5_6_1_DEFAULT):
quick = "2.6" quick = "2.6"
else: qmlViewer = modifyRunSettingsForHookIntoQtQuickUI(1, 0, workingDir, projectName, 11223, quick)
test.fatal("Failed to activate kit %s" % kit)
continue
test.log("Running project Qt Quick UI Prototype (%s)" % kit)
qmlViewer = modifyRunSettingsForHookIntoQtQuickUI(2, 1, workingDir, projectName, 11223, quick)
if qmlViewer!=None: if qmlViewer!=None:
qmlViewerPath = os.path.dirname(qmlViewer) qmlViewerPath = os.path.dirname(qmlViewer)
qmlViewer = os.path.basename(qmlViewer) qmlViewer = os.path.basename(qmlViewer)

View File

@@ -29,7 +29,7 @@ def main():
startApplication("qtcreator" + SettingsPath) startApplication("qtcreator" + SettingsPath)
if not startedWithoutPluginError(): if not startedWithoutPluginError():
return return
for target in [Targets.DESKTOP_5_6_1_DEFAULT, Targets.DESKTOP_5_3_1_DEFAULT]: for target in [Targets.DESKTOP_5_6_1_DEFAULT, Targets.DESKTOP_5_10_1_DEFAULT]:
# using a temporary directory won't mess up a potentially existing # using a temporary directory won't mess up a potentially existing
createNewQmlExtension(tempDir(), [target]) createNewQmlExtension(tempDir(), [target])
# wait for parsing to complete # wait for parsing to complete

View File

@@ -39,7 +39,8 @@ def main():
":FormEditorStack_qdesigner_internal::FormWindow", 20, widgets[current], Qt.CopyAction) ":FormEditorStack_qdesigner_internal::FormWindow", 20, widgets[current], Qt.CopyAction)
connections = [] connections = []
for record in testData.dataset("connections.tsv"): for record in testData.dataset("connections.tsv"):
connections.append([testData.field(record, col) for col in ["widget", "signal", "slot"]]) connections.append([testData.field(record, col) for col in ["widget", "baseclass",
"signal", "slot"]])
for con in connections: for con in connections:
selectFromLocator("mainwindow.ui") selectFromLocator("mainwindow.ui")
openContextMenu(waitForObject(con[0]), 5, 5, 0) openContextMenu(waitForObject(con[0]), 5, 5, 0)
@@ -49,13 +50,21 @@ def main():
waitFor("macHackActivateContextMenuItem('Go to slot...', con[0])", 6000) waitFor("macHackActivateContextMenuItem('Go to slot...', con[0])", 6000)
else: else:
activateItem(waitForObjectItem("{type='QMenu' unnamed='1' visible='1'}", "Go to slot...")) activateItem(waitForObjectItem("{type='QMenu' unnamed='1' visible='1'}", "Go to slot..."))
waitForObjectItem(":Select signal.signalList_QTreeWidget", con[1]) try:
clickItem(":Select signal.signalList_QTreeWidget", con[1], 5, 5, 0, Qt.LeftButton) # Creator built with Qt <= 5.9
signalWidgetObject = waitForObject(":Select signal.signalList_QTreeWidget", 5000)
signalName = con[2]
except:
# Creator built with Qt >= 5.10
signalWidgetObject = waitForObject(":Select signal.signalList_QTreeView")
signalName = con[1] + "." + con[2]
waitForObjectItem(signalWidgetObject, signalName)
clickItem(signalWidgetObject, signalName, 5, 5, 0, Qt.LeftButton)
clickButton(waitForObject(":Go to slot.OK_QPushButton")) clickButton(waitForObject(":Go to slot.OK_QPushButton"))
editor = waitForObject(":Qt Creator_CppEditor::Internal::CPPEditorWidget") editor = waitForObject(":Qt Creator_CppEditor::Internal::CPPEditorWidget")
type(editor, "<Up>") type(editor, "<Up>")
type(editor, "<Up>") type(editor, "<Up>")
test.verify(waitFor('str(lineUnderCursor(editor)).strip() == con[2]', 1000), test.verify(waitFor('str(lineUnderCursor(editor)).strip() == con[3]', 1000),
'Comparing line "%s" to expected "%s"' % (lineUnderCursor(editor), con[2])) 'Comparing line "%s" to expected "%s"' % (lineUnderCursor(editor), con[3]))
invokeMenuItem("File", "Save All") invokeMenuItem("File", "Save All")
invokeMenuItem("File", "Exit") invokeMenuItem("File", "Exit")

View File

@@ -1,4 +1,4 @@
"widget" "signal" "slot" "widget" "baseclass" "signal" "slot"
":FormEditorStack.PushButton_QPushButton" "clicked()" "void MainWindow::on_pushButton_clicked()" ":FormEditorStack.PushButton_QPushButton" "QAbstractButton" "clicked()" "void MainWindow::on_pushButton_clicked()"
":FormEditorStack.CheckBox_QCheckBox" "toggled(bool)" "void MainWindow::on_checkBox_toggled(bool checked)" ":FormEditorStack.CheckBox_QCheckBox" "QAbstractButton" "toggled(bool)" "void MainWindow::on_checkBox_toggled(bool checked)"
":FormEditorStack.centralWidget_QDesignerWidget" "destroyed()" "void MainWindow::on_MainWindow_destroyed()" ":FormEditorStack.centralWidget_QDesignerWidget" "QObject" "destroyed()" "void MainWindow::on_MainWindow_destroyed()"
1 widget baseclass signal slot
2 :FormEditorStack.PushButton_QPushButton QAbstractButton clicked() void MainWindow::on_pushButton_clicked()
3 :FormEditorStack.CheckBox_QCheckBox QAbstractButton toggled(bool) void MainWindow::on_checkBox_toggled(bool checked)
4 :FormEditorStack.centralWidget_QDesignerWidget QObject destroyed() void MainWindow::on_MainWindow_destroyed()