forked from qt-creator/qt-creator
Merge remote-tracking branch 'origin/4.5'
Change-Id: Iebd340258966aff910fb9ab0e45b5149e8f242f0
This commit is contained in:
@@ -50,7 +50,10 @@ HEADERS += \
|
||||
androidsdkmanager.h \
|
||||
androidavdmanager.h \
|
||||
androidrunconfigurationwidget.h \
|
||||
adbcommandswidget.h
|
||||
adbcommandswidget.h \
|
||||
androidsdkpackage.h \
|
||||
androidsdkmodel.h \
|
||||
androidsdkmanagerwidget.h
|
||||
|
||||
SOURCES += \
|
||||
androidconfigurations.cpp \
|
||||
@@ -94,7 +97,10 @@ SOURCES += \
|
||||
androidsdkmanager.cpp \
|
||||
androidavdmanager.cpp \
|
||||
androidrunconfigurationwidget.cpp \
|
||||
adbcommandswidget.cpp
|
||||
adbcommandswidget.cpp \
|
||||
androidsdkpackage.cpp \
|
||||
androidsdkmodel.cpp \
|
||||
androidsdkmanagerwidget.cpp
|
||||
|
||||
FORMS += \
|
||||
androidsettingswidget.ui \
|
||||
@@ -104,7 +110,8 @@ FORMS += \
|
||||
androiddeployqtwidget.ui \
|
||||
androidbuildapkwidget.ui \
|
||||
androidrunconfigurationwidget.ui \
|
||||
adbcommandswidget.ui
|
||||
adbcommandswidget.ui \
|
||||
androidsdkmanagerwidget.ui
|
||||
|
||||
RESOURCES = android.qrc
|
||||
|
||||
|
||||
@@ -54,8 +54,6 @@ const char avdInfoAbiKey[] = "abi.type";
|
||||
const char avdInfoTargetKey[] = "target";
|
||||
const char avdInfoErrorKey[] = "Error:";
|
||||
|
||||
const QVersionNumber avdManagerIntroVersion(25, 3 ,0);
|
||||
|
||||
const int avdCreateTimeoutMs = 30000;
|
||||
|
||||
/*!
|
||||
@@ -101,37 +99,37 @@ static bool checkForTimeout(const chrono::steady_clock::time_point &start,
|
||||
return timedOut;
|
||||
}
|
||||
|
||||
static AndroidConfig::CreateAvdInfo createAvdCommand(const AndroidConfig config,
|
||||
const AndroidConfig::CreateAvdInfo &info)
|
||||
static CreateAvdInfo createAvdCommand(const AndroidConfig config, const CreateAvdInfo &info)
|
||||
{
|
||||
AndroidConfig::CreateAvdInfo result = info;
|
||||
CreateAvdInfo result = info;
|
||||
|
||||
if (!result.isValid()) {
|
||||
qCDebug(avdManagerLog) << "AVD Create failed. Invalid CreateAvdInfo" << result.name
|
||||
<< result.target.name << result.target.apiLevel;
|
||||
<< result.sdkPlatform->displayText() << result.sdkPlatform->apiLevel();
|
||||
result.error = QApplication::translate("AndroidAvdManager",
|
||||
"Cannot create AVD. Invalid input.");
|
||||
return result;
|
||||
}
|
||||
|
||||
QStringList arguments({"create", "avd", "-k", result.target.package, "-n", result.name});
|
||||
QStringList arguments({"create", "avd", "-k", result.sdkPlatform->sdkStylePath(), "-n", result.name});
|
||||
|
||||
if (!result.abi.isEmpty()) {
|
||||
SystemImage image = Utils::findOrDefault(result.target.systemImages,
|
||||
SystemImage *image = Utils::findOrDefault(result.sdkPlatform->systemImages(),
|
||||
Utils::equal(&SystemImage::abiName, result.abi));
|
||||
if (image.isValid()) {
|
||||
arguments << "-k" << image.package;
|
||||
if (image && image->isValid()) {
|
||||
arguments << "-k" << image->sdkStylePath();
|
||||
} else {
|
||||
QString name = result.sdkPlatform->displayText();
|
||||
qCDebug(avdManagerLog) << "AVD Create failed. Cannot find system image for the platform"
|
||||
<< result.abi << result.target.name;
|
||||
<< result.abi << name;
|
||||
result.error = QApplication::translate("AndroidAvdManager",
|
||||
"Cannot create AVD. Cannot find system image for "
|
||||
"the ABI %1(%2).").arg(result.abi).arg(result.target.name);
|
||||
"the ABI %1(%2).").arg(result.abi).arg(name);
|
||||
return result;
|
||||
}
|
||||
|
||||
} else {
|
||||
arguments << "-k" << result.target.package;
|
||||
arguments << "-k" << result.sdkPlatform->sdkStylePath();
|
||||
}
|
||||
|
||||
if (result.sdcardSize > 0)
|
||||
@@ -219,14 +217,9 @@ AndroidAvdManager::~AndroidAvdManager()
|
||||
|
||||
}
|
||||
|
||||
bool AndroidAvdManager::avdManagerUiToolAvailable() const
|
||||
{
|
||||
return m_config.sdkToolsVersion() < avdManagerIntroVersion;
|
||||
}
|
||||
|
||||
void AndroidAvdManager::launchAvdManagerUiTool() const
|
||||
{
|
||||
if (avdManagerUiToolAvailable()) {
|
||||
if (m_config.useNativeUiTools()) {
|
||||
m_androidTool->launchAvdManager();
|
||||
} else {
|
||||
qCDebug(avdManagerLog) << "AVD Ui tool launch failed. UI tool not available"
|
||||
@@ -234,10 +227,9 @@ void AndroidAvdManager::launchAvdManagerUiTool() const
|
||||
}
|
||||
}
|
||||
|
||||
QFuture<AndroidConfig::CreateAvdInfo>
|
||||
AndroidAvdManager::createAvd(AndroidConfig::CreateAvdInfo info) const
|
||||
QFuture<CreateAvdInfo> AndroidAvdManager::createAvd(CreateAvdInfo info) const
|
||||
{
|
||||
if (m_config.sdkToolsVersion() < avdManagerIntroVersion)
|
||||
if (m_config.useNativeUiTools())
|
||||
return m_androidTool->createAvd(info);
|
||||
|
||||
return Utils::runAsync(&createAvdCommand, m_config, info);
|
||||
@@ -245,7 +237,7 @@ AndroidAvdManager::createAvd(AndroidConfig::CreateAvdInfo info) const
|
||||
|
||||
bool AndroidAvdManager::removeAvd(const QString &name) const
|
||||
{
|
||||
if (m_config.sdkToolsVersion() < avdManagerIntroVersion)
|
||||
if (m_config.useNativeUiTools())
|
||||
return m_androidTool->removeAvd(name);
|
||||
|
||||
Utils::SynchronousProcess proc;
|
||||
@@ -258,7 +250,7 @@ bool AndroidAvdManager::removeAvd(const QString &name) const
|
||||
|
||||
QFuture<AndroidDeviceInfoList> AndroidAvdManager::avdList() const
|
||||
{
|
||||
if (m_config.sdkToolsVersion() < avdManagerIntroVersion)
|
||||
if (m_config.useNativeUiTools())
|
||||
return m_androidTool->androidVirtualDevicesFuture();
|
||||
|
||||
return Utils::runAsync(&AvdManagerOutputParser::listVirtualDevices, m_parser.get(), m_config);
|
||||
|
||||
@@ -40,9 +40,8 @@ public:
|
||||
AndroidAvdManager(const AndroidConfig& config = AndroidConfigurations::currentConfig());
|
||||
~AndroidAvdManager();
|
||||
|
||||
bool avdManagerUiToolAvailable() const;
|
||||
void launchAvdManagerUiTool() const;
|
||||
QFuture<AndroidConfig::CreateAvdInfo> createAvd(AndroidConfig::CreateAvdInfo info) const;
|
||||
QFuture<CreateAvdInfo> createAvd(CreateAvdInfo info) const;
|
||||
bool removeAvd(const QString &name) const;
|
||||
QFuture<AndroidDeviceInfoList> avdList() const;
|
||||
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
#include "androidconfigurations.h"
|
||||
#include "androidconstants.h"
|
||||
#include "androidmanager.h"
|
||||
#include "androidsdkmanager.h"
|
||||
#include "androidqtsupport.h"
|
||||
#include "certificatesmodel.h"
|
||||
|
||||
@@ -92,7 +93,8 @@ private:
|
||||
|
||||
AndroidBuildApkStep::AndroidBuildApkStep(ProjectExplorer::BuildStepList *parent, const Core::Id id)
|
||||
: ProjectExplorer::AbstractProcessStep(parent, id),
|
||||
m_buildTargetSdk(AndroidConfig::apiLevelNameFor(AndroidConfigurations::currentConfig().highestAndroidSdk()))
|
||||
m_buildTargetSdk(AndroidConfig::apiLevelNameFor(AndroidConfigurations::
|
||||
sdkManager()->latestAndroidSdkPlatform()))
|
||||
{
|
||||
//: AndroidBuildApkStep default display name
|
||||
setDefaultDisplayName(tr("Build Android APK"));
|
||||
@@ -233,8 +235,10 @@ bool AndroidBuildApkStep::fromMap(const QVariantMap &map)
|
||||
m_keystorePath = Utils::FileName::fromString(map.value(KeystoreLocationKey).toString());
|
||||
m_signPackage = false; // don't restore this
|
||||
m_buildTargetSdk = map.value(BuildTargetSdkKey).toString();
|
||||
if (m_buildTargetSdk.isEmpty())
|
||||
m_buildTargetSdk = AndroidConfig::apiLevelNameFor(AndroidConfigurations::currentConfig().highestAndroidSdk());
|
||||
if (m_buildTargetSdk.isEmpty()) {
|
||||
m_buildTargetSdk = AndroidConfig::apiLevelNameFor(AndroidConfigurations::
|
||||
sdkManager()->latestAndroidSdkPlatform());
|
||||
}
|
||||
m_verbose = map.value(VerboseOutputKey).toBool();
|
||||
m_useMinistro = map.value(UseMinistroKey).toBool();
|
||||
return ProjectExplorer::BuildStep::fromMap(map);
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
#include "androidconfigurations.h"
|
||||
#include "androidcreatekeystorecertificate.h"
|
||||
#include "androidmanager.h"
|
||||
#include "androidsdkmanager.h"
|
||||
#include "ui_androidbuildapkwidget.h"
|
||||
|
||||
#include <projectexplorer/buildconfiguration.h>
|
||||
@@ -47,6 +48,8 @@
|
||||
using namespace Android;
|
||||
using namespace Internal;
|
||||
|
||||
const int minApiSupported = 9;
|
||||
|
||||
AndroidBuildApkWidget::AndroidBuildApkWidget(AndroidBuildApkStep *step)
|
||||
: ProjectExplorer::BuildStepConfigWidget(),
|
||||
m_ui(new Ui::AndroidBuildApkWidget),
|
||||
@@ -55,9 +58,8 @@ AndroidBuildApkWidget::AndroidBuildApkWidget(AndroidBuildApkStep *step)
|
||||
m_ui->setupUi(this);
|
||||
|
||||
// Target sdk combobox
|
||||
int minApiLevel = 9;
|
||||
const AndroidConfig &config = AndroidConfigurations::currentConfig();
|
||||
QStringList targets = AndroidConfig::apiLevelNamesFor(config.sdkTargets(minApiLevel));
|
||||
QStringList targets = AndroidConfig::apiLevelNamesFor(AndroidConfigurations::sdkManager()->
|
||||
filteredSdkPlatforms(minApiSupported));
|
||||
targets.removeDuplicates();
|
||||
m_ui->targetSDKComboBox->addItems(targets);
|
||||
m_ui->targetSDKComboBox->setCurrentIndex(targets.indexOf(AndroidManager::buildTargetSDK(step->target())));
|
||||
|
||||
@@ -87,6 +87,7 @@ namespace {
|
||||
|
||||
const QLatin1String SettingsGroup("AndroidConfigurations");
|
||||
const QLatin1String SDKLocationKey("SDKLocation");
|
||||
const QLatin1String SDKManagerToolArgsKey("SDKManagerToolArgs");
|
||||
const QLatin1String NDKLocationKey("NDKLocation");
|
||||
const QLatin1String OpenJDKLocationKey("OpenJDKLocation");
|
||||
const QLatin1String KeystoreLocationKey("KeystoreLocation");
|
||||
@@ -246,6 +247,7 @@ void AndroidConfig::load(const QSettings &settings)
|
||||
// user settings
|
||||
m_partitionSize = settings.value(PartitionSizeKey, 1024).toInt();
|
||||
m_sdkLocation = FileName::fromString(settings.value(SDKLocationKey).toString());
|
||||
m_sdkManagerToolArgs = settings.value(SDKManagerToolArgsKey).toStringList();
|
||||
m_ndkLocation = FileName::fromString(settings.value(NDKLocationKey).toString());
|
||||
m_openJDKLocation = FileName::fromString(settings.value(OpenJDKLocationKey).toString());
|
||||
m_keystoreLocation = FileName::fromString(settings.value(KeystoreLocationKey).toString());
|
||||
@@ -261,6 +263,7 @@ void AndroidConfig::load(const QSettings &settings)
|
||||
&& settings.value(changeTimeStamp).toInt() != QFileInfo(sdkSettingsFileName()).lastModified().toMSecsSinceEpoch() / 1000) {
|
||||
// persisten settings
|
||||
m_sdkLocation = FileName::fromString(reader.restoreValue(SDKLocationKey, m_sdkLocation.toString()).toString());
|
||||
m_sdkManagerToolArgs = reader.restoreValue(SDKManagerToolArgsKey, m_sdkManagerToolArgs).toStringList();
|
||||
m_ndkLocation = FileName::fromString(reader.restoreValue(NDKLocationKey, m_ndkLocation.toString()).toString());
|
||||
m_openJDKLocation = FileName::fromString(reader.restoreValue(OpenJDKLocationKey, m_openJDKLocation.toString()).toString());
|
||||
m_keystoreLocation = FileName::fromString(reader.restoreValue(KeystoreLocationKey, m_keystoreLocation.toString()).toString());
|
||||
@@ -272,7 +275,6 @@ void AndroidConfig::load(const QSettings &settings)
|
||||
m_makeExtraSearchDirectories << extraDirectory;
|
||||
// persistent settings
|
||||
}
|
||||
m_availableSdkPlatformsUpToDate = false;
|
||||
m_NdkInformationUpToDate = false;
|
||||
}
|
||||
|
||||
@@ -284,6 +286,7 @@ void AndroidConfig::save(QSettings &settings) const
|
||||
|
||||
// user settings
|
||||
settings.setValue(SDKLocationKey, m_sdkLocation.toString());
|
||||
settings.setValue(SDKManagerToolArgsKey, m_sdkManagerToolArgs);
|
||||
settings.setValue(NDKLocationKey, m_ndkLocation.toString());
|
||||
settings.setValue(OpenJDKLocationKey, m_openJDKLocation.toString());
|
||||
settings.setValue(KeystoreLocationKey, m_keystoreLocation.toString());
|
||||
@@ -333,40 +336,15 @@ void AndroidConfig::updateNdkInformation() const
|
||||
m_NdkInformationUpToDate = true;
|
||||
}
|
||||
|
||||
void AndroidConfig::updateAvailableSdkPlatforms() const
|
||||
{
|
||||
if (m_availableSdkPlatformsUpToDate)
|
||||
return;
|
||||
|
||||
m_availableSdkPlatforms.clear();
|
||||
AndroidSdkManager sdkManager(*this);
|
||||
bool success = false;
|
||||
m_availableSdkPlatforms = sdkManager.availableSdkPlatforms(&success);
|
||||
if (success)
|
||||
m_availableSdkPlatformsUpToDate = true;
|
||||
}
|
||||
|
||||
QStringList AndroidConfig::apiLevelNamesFor(const QList<SdkPlatform> &platforms)
|
||||
QStringList AndroidConfig::apiLevelNamesFor(const SdkPlatformList &platforms)
|
||||
{
|
||||
return Utils::transform(platforms, AndroidConfig::apiLevelNameFor);
|
||||
}
|
||||
|
||||
QString AndroidConfig::apiLevelNameFor(const SdkPlatform &platform)
|
||||
QString AndroidConfig::apiLevelNameFor(const SdkPlatform *platform)
|
||||
{
|
||||
return platform.apiLevel > 0 ? QString("android-%1").arg(platform.apiLevel) : "";
|
||||
}
|
||||
|
||||
QList<SdkPlatform> AndroidConfig::sdkTargets(int minApiLevel) const
|
||||
{
|
||||
updateAvailableSdkPlatforms();
|
||||
QList<SdkPlatform> result;
|
||||
for (int i = 0; i < m_availableSdkPlatforms.size(); ++i) {
|
||||
if (m_availableSdkPlatforms.at(i).apiLevel >= minApiLevel)
|
||||
result << m_availableSdkPlatforms.at(i);
|
||||
else
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
return platform && platform->apiLevel() > 0 ?
|
||||
QString("android-%1").arg(platform->apiLevel()) : "";
|
||||
}
|
||||
|
||||
FileName AndroidConfig::adbToolPath() const
|
||||
@@ -523,20 +501,6 @@ QVector<AndroidDeviceInfo> AndroidConfig::connectedDevices(const QString &adbToo
|
||||
return devices;
|
||||
}
|
||||
|
||||
AndroidConfig::CreateAvdInfo AndroidConfig::gatherCreateAVDInfo(QWidget *parent, int minApiLevel, QString targetArch) const
|
||||
{
|
||||
CreateAvdInfo result;
|
||||
AvdDialog d(minApiLevel, targetArch, this, parent);
|
||||
if (d.exec() != QDialog::Accepted || !d.isValid())
|
||||
return result;
|
||||
|
||||
result.target = d.target();
|
||||
result.name = d.name();
|
||||
result.abi = d.abi();
|
||||
result.sdcardSize = d.sdcardSize();
|
||||
return result;
|
||||
}
|
||||
|
||||
bool AndroidConfig::isConnected(const QString &serialNumber) const
|
||||
{
|
||||
QVector<AndroidDeviceInfo> devices = connectedDevices();
|
||||
@@ -716,12 +680,10 @@ QStringList AndroidConfig::getAbis(const QString &adbToolPath, const QString &de
|
||||
return result;
|
||||
}
|
||||
|
||||
SdkPlatform AndroidConfig::highestAndroidSdk() const
|
||||
bool AndroidConfig::useNativeUiTools() const
|
||||
{
|
||||
updateAvailableSdkPlatforms();
|
||||
if (m_availableSdkPlatforms.isEmpty())
|
||||
return SdkPlatform();
|
||||
return m_availableSdkPlatforms.first();
|
||||
const QVersionNumber version = sdkToolsVersion();
|
||||
return !version.isNull() && version <= QVersionNumber(25, 3 ,0);
|
||||
}
|
||||
|
||||
QString AndroidConfig::bestNdkPlatformMatch(int target) const
|
||||
@@ -743,7 +705,6 @@ FileName AndroidConfig::sdkLocation() const
|
||||
void AndroidConfig::setSdkLocation(const FileName &sdkLocation)
|
||||
{
|
||||
m_sdkLocation = sdkLocation;
|
||||
m_availableSdkPlatformsUpToDate = false;
|
||||
}
|
||||
|
||||
QVersionNumber AndroidConfig::sdkToolsVersion() const
|
||||
@@ -770,6 +731,17 @@ QVersionNumber AndroidConfig::buildToolsVersion() const
|
||||
return maxVersion;
|
||||
}
|
||||
|
||||
|
||||
QStringList AndroidConfig::sdkManagerToolArgs() const
|
||||
{
|
||||
return m_sdkManagerToolArgs;
|
||||
}
|
||||
|
||||
void AndroidConfig::setSdkManagerToolArgs(const QStringList &args)
|
||||
{
|
||||
m_sdkManagerToolArgs = args;
|
||||
}
|
||||
|
||||
FileName AndroidConfig::ndkLocation() const
|
||||
{
|
||||
return m_ndkLocation;
|
||||
@@ -836,7 +808,6 @@ FileName AndroidConfig::openJDKLocation() const
|
||||
void AndroidConfig::setOpenJDKLocation(const FileName &openJDKLocation)
|
||||
{
|
||||
m_openJDKLocation = openJDKLocation;
|
||||
m_availableSdkPlatformsUpToDate = false;
|
||||
}
|
||||
|
||||
FileName AndroidConfig::keystoreLocation() const
|
||||
@@ -1129,6 +1100,11 @@ const AndroidConfig &AndroidConfigurations::currentConfig()
|
||||
return m_instance->m_config; // ensure that m_instance is initialized
|
||||
}
|
||||
|
||||
AndroidSdkManager *AndroidConfigurations::sdkManager()
|
||||
{
|
||||
return m_instance->m_sdkManager.get();
|
||||
}
|
||||
|
||||
AndroidConfigurations *AndroidConfigurations::instance()
|
||||
{
|
||||
return m_instance;
|
||||
@@ -1143,7 +1119,8 @@ void AndroidConfigurations::save()
|
||||
}
|
||||
|
||||
AndroidConfigurations::AndroidConfigurations(QObject *parent)
|
||||
: QObject(parent)
|
||||
: QObject(parent),
|
||||
m_sdkManager(new AndroidSdkManager(m_config))
|
||||
{
|
||||
load();
|
||||
|
||||
@@ -1155,6 +1132,11 @@ AndroidConfigurations::AndroidConfigurations(QObject *parent)
|
||||
m_instance = this;
|
||||
}
|
||||
|
||||
AndroidConfigurations::~AndroidConfigurations()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
static FileName javaHomeForJavac(const FileName &location)
|
||||
{
|
||||
QFileInfo fileInfo = location.toFileInfo();
|
||||
@@ -1265,13 +1247,4 @@ void AndroidConfigurations::updateAndroidDevice()
|
||||
|
||||
AndroidConfigurations *AndroidConfigurations::m_instance = 0;
|
||||
|
||||
bool SdkPlatform::operator <(const SdkPlatform &other) const
|
||||
{
|
||||
if (apiLevel != other.apiLevel)
|
||||
return apiLevel > other.apiLevel;
|
||||
if (name != other.name)
|
||||
return name < other.name;
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace Android
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "android_global.h"
|
||||
|
||||
#include "androidsdkpackage.h"
|
||||
#include <projectexplorer/toolchain.h>
|
||||
|
||||
#include <QObject>
|
||||
@@ -52,7 +52,9 @@ class Project;
|
||||
namespace Utils { class Environment; }
|
||||
|
||||
namespace Android {
|
||||
|
||||
class AndroidPlugin;
|
||||
namespace Internal { class AndroidSdkManager; }
|
||||
|
||||
class AndroidDeviceInfo
|
||||
{
|
||||
@@ -74,31 +76,16 @@ public:
|
||||
};
|
||||
using AndroidDeviceInfoList = QList<AndroidDeviceInfo>;
|
||||
|
||||
//! Defines an Android system image.
|
||||
class SystemImage
|
||||
class CreateAvdInfo
|
||||
{
|
||||
public:
|
||||
bool isValid() const { return (apiLevel != -1) && !abiName.isEmpty(); }
|
||||
int apiLevel = -1;
|
||||
QString abiName;
|
||||
QString package;
|
||||
Utils::FileName installedLocation;
|
||||
};
|
||||
using SystemImageList = QList<SystemImage>;
|
||||
|
||||
|
||||
class SdkPlatform
|
||||
{
|
||||
public:
|
||||
bool isValid() const { return !name.isEmpty() && apiLevel != -1; }
|
||||
bool operator <(const SdkPlatform &other) const;
|
||||
int apiLevel = -1;
|
||||
bool isValid() const { return sdkPlatform && sdkPlatform->isValid() && !name.isEmpty(); }
|
||||
const SdkPlatform *sdkPlatform = nullptr;
|
||||
QString name;
|
||||
QString package;
|
||||
Utils::FileName installedLocation;
|
||||
SystemImageList systemImages;
|
||||
QString abi;
|
||||
int sdcardSize = 0;
|
||||
QString error; // only used in the return value of createAVD
|
||||
};
|
||||
using SdkPlatformList = QList<SdkPlatform>;
|
||||
|
||||
class ANDROID_EXPORT AndroidConfig
|
||||
{
|
||||
@@ -106,14 +93,15 @@ public:
|
||||
void load(const QSettings &settings);
|
||||
void save(QSettings &settings) const;
|
||||
|
||||
static QStringList apiLevelNamesFor(const QList<SdkPlatform> &platforms);
|
||||
static QString apiLevelNameFor(const SdkPlatform &platform);
|
||||
QList<SdkPlatform> sdkTargets(int minApiLevel = 0) const;
|
||||
static QStringList apiLevelNamesFor(const SdkPlatformList &platforms);
|
||||
static QString apiLevelNameFor(const SdkPlatform *platform);
|
||||
|
||||
Utils::FileName sdkLocation() const;
|
||||
void setSdkLocation(const Utils::FileName &sdkLocation);
|
||||
QVersionNumber sdkToolsVersion() const;
|
||||
QVersionNumber buildToolsVersion() const;
|
||||
QStringList sdkManagerToolArgs() const;
|
||||
void setSdkManagerToolArgs(const QStringList &args);
|
||||
|
||||
Utils::FileName ndkLocation() const;
|
||||
QVersionNumber ndkVersion() const;
|
||||
@@ -147,19 +135,6 @@ public:
|
||||
|
||||
Utils::FileName keytoolPath() const;
|
||||
|
||||
class CreateAvdInfo
|
||||
{
|
||||
public:
|
||||
bool isValid() const { return target.isValid() && !name.isEmpty(); }
|
||||
SdkPlatform target;
|
||||
QString name;
|
||||
QString abi;
|
||||
int sdcardSize = 0;
|
||||
QString error; // only used in the return value of createAVD
|
||||
};
|
||||
|
||||
CreateAvdInfo gatherCreateAVDInfo(QWidget *parent, int minApiLevel = 0, QString targetArch = QString()) const;
|
||||
|
||||
QVector<AndroidDeviceInfo> connectedDevices(QString *error = 0) const;
|
||||
static QVector<AndroidDeviceInfo> connectedDevices(const QString &adbToolPath, QString *error = 0);
|
||||
|
||||
@@ -175,7 +150,8 @@ public:
|
||||
OpenGl getOpenGLEnabled(const QString &emulator) const;
|
||||
bool isConnected(const QString &serialNumber) const;
|
||||
|
||||
SdkPlatform highestAndroidSdk() const;
|
||||
bool useNativeUiTools() const;
|
||||
|
||||
private:
|
||||
static QString getDeviceProperty(const QString &adbToolPath, const QString &device, const QString &property);
|
||||
|
||||
@@ -189,10 +165,10 @@ private:
|
||||
bool isBootToQt(const QString &device) const;
|
||||
static QString getAvdName(const QString &serialnumber);
|
||||
|
||||
void updateAvailableSdkPlatforms() const;
|
||||
void updateNdkInformation() const;
|
||||
|
||||
Utils::FileName m_sdkLocation;
|
||||
QStringList m_sdkManagerToolArgs;
|
||||
Utils::FileName m_ndkLocation;
|
||||
Utils::FileName m_openJDKLocation;
|
||||
Utils::FileName m_keystoreLocation;
|
||||
@@ -201,9 +177,6 @@ private:
|
||||
bool m_automaticKitCreation = true;
|
||||
|
||||
//caches
|
||||
mutable bool m_availableSdkPlatformsUpToDate = false;
|
||||
mutable SdkPlatformList m_availableSdkPlatforms;
|
||||
|
||||
mutable bool m_NdkInformationUpToDate = false;
|
||||
mutable QString m_toolchainHost;
|
||||
mutable QVector<int> m_availableNdkPlatforms;
|
||||
@@ -218,6 +191,7 @@ class ANDROID_EXPORT AndroidConfigurations : public QObject
|
||||
|
||||
public:
|
||||
static const AndroidConfig ¤tConfig();
|
||||
static Internal::AndroidSdkManager *sdkManager();
|
||||
static void setConfig(const AndroidConfig &config);
|
||||
static AndroidConfigurations *instance();
|
||||
|
||||
@@ -236,16 +210,17 @@ signals:
|
||||
|
||||
private:
|
||||
AndroidConfigurations(QObject *parent);
|
||||
~AndroidConfigurations();
|
||||
void load();
|
||||
void save();
|
||||
|
||||
static AndroidConfigurations *m_instance;
|
||||
AndroidConfig m_config;
|
||||
std::unique_ptr<Internal::AndroidSdkManager> m_sdkManager;
|
||||
|
||||
QMap<ProjectExplorer::Project *, QMap<QString, QString> > m_defaultDeviceForAbi;
|
||||
bool m_force32bit;
|
||||
};
|
||||
|
||||
} // namespace Android
|
||||
Q_DECLARE_METATYPE(Android::SdkPlatform)
|
||||
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
#include "androiddevicedialog.h"
|
||||
#include "androidmanager.h"
|
||||
#include "androidavdmanager.h"
|
||||
#include "avddialog.h"
|
||||
#include "ui_androiddevicedialog.h"
|
||||
|
||||
#include <utils/environment.h>
|
||||
@@ -580,9 +581,10 @@ void AndroidDeviceDialog::devicesRefreshed()
|
||||
void AndroidDeviceDialog::createAvd()
|
||||
{
|
||||
m_ui->createAVDButton->setEnabled(false);
|
||||
AndroidConfig::CreateAvdInfo info = AndroidConfigurations::currentConfig().gatherCreateAVDInfo(this, m_apiLevel, m_abi);
|
||||
CreateAvdInfo info = AvdDialog::gatherCreateAVDInfo(this, AndroidConfigurations::sdkManager(),
|
||||
m_apiLevel, m_abi);
|
||||
|
||||
if (!info.target.isValid()) {
|
||||
if (!info.isValid()) {
|
||||
m_ui->createAVDButton->setEnabled(true);
|
||||
return;
|
||||
}
|
||||
@@ -593,7 +595,7 @@ void AndroidDeviceDialog::createAvd()
|
||||
void AndroidDeviceDialog::avdAdded()
|
||||
{
|
||||
m_ui->createAVDButton->setEnabled(true);
|
||||
AndroidConfig::CreateAvdInfo info = m_futureWatcherAddDevice.result();
|
||||
CreateAvdInfo info = m_futureWatcherAddDevice.result();
|
||||
if (!info.error.isEmpty()) {
|
||||
QMessageBox::critical(this, QApplication::translate("AndroidConfig", "Error Creating AVD"), info.error);
|
||||
return;
|
||||
|
||||
@@ -79,7 +79,7 @@ private:
|
||||
QString m_defaultDevice;
|
||||
std::unique_ptr<AndroidAvdManager> m_avdManager;
|
||||
QVector<AndroidDeviceInfo> m_connectedDevices;
|
||||
QFutureWatcher<AndroidConfig::CreateAvdInfo> m_futureWatcherAddDevice;
|
||||
QFutureWatcher<CreateAvdInfo> m_futureWatcherAddDevice;
|
||||
QFutureWatcher<AndroidDeviceInfoList> m_futureWatcherRefreshDevices;
|
||||
};
|
||||
|
||||
|
||||
@@ -35,6 +35,7 @@
|
||||
#include "androidqtversion.h"
|
||||
#include "androidbuildapkstep.h"
|
||||
#include "androidavdmanager.h"
|
||||
#include "androidsdkmanager.h"
|
||||
|
||||
#include <coreplugin/documentmanager.h>
|
||||
#include <coreplugin/messagemanager.h>
|
||||
@@ -174,7 +175,8 @@ QString AndroidManager::buildTargetSDK(ProjectExplorer::Target *target)
|
||||
if (androidBuildApkStep)
|
||||
return androidBuildApkStep->buildTargetSdk();
|
||||
|
||||
QString fallback = AndroidConfig::apiLevelNameFor(AndroidConfigurations::currentConfig().highestAndroidSdk());
|
||||
QString fallback = AndroidConfig::apiLevelNameFor(
|
||||
AndroidConfigurations::sdkManager()->latestAndroidSdkPlatform());
|
||||
return fallback;
|
||||
}
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -25,26 +25,75 @@
|
||||
#pragma once
|
||||
|
||||
#include "utils/fileutils.h"
|
||||
#include "androidconfigurations.h"
|
||||
#include "androidsdkpackage.h"
|
||||
|
||||
#include <QObject>
|
||||
#include <QFuture>
|
||||
|
||||
#include <memory>
|
||||
|
||||
namespace Android {
|
||||
|
||||
class AndroidConfig;
|
||||
|
||||
namespace Internal {
|
||||
|
||||
class SdkManagerOutputParser;
|
||||
class AndroidSdkManagerPrivate;
|
||||
|
||||
class AndroidSdkManager
|
||||
class AndroidSdkManager : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
AndroidSdkManager(const AndroidConfig &config);
|
||||
enum CommandType
|
||||
{
|
||||
None,
|
||||
UpdateAll,
|
||||
UpdatePackage,
|
||||
LicenseCheck,
|
||||
LicenseWorkflow
|
||||
};
|
||||
|
||||
struct OperationOutput
|
||||
{
|
||||
bool success = false;
|
||||
CommandType type = None;
|
||||
QString stdOutput;
|
||||
QString stdError;
|
||||
};
|
||||
|
||||
AndroidSdkManager(const AndroidConfig &config, QObject *parent = nullptr);
|
||||
~AndroidSdkManager();
|
||||
|
||||
SdkPlatformList availableSdkPlatforms(bool *ok = nullptr);
|
||||
SdkPlatformList installedSdkPlatforms();
|
||||
const AndroidSdkPackageList &allSdkPackages();
|
||||
AndroidSdkPackageList availableSdkPackages();
|
||||
AndroidSdkPackageList installedSdkPackages();
|
||||
|
||||
SdkPlatform *latestAndroidSdkPlatform(AndroidSdkPackage::PackageState state
|
||||
= AndroidSdkPackage::Installed);
|
||||
SdkPlatformList filteredSdkPlatforms(int minApiLevel,
|
||||
AndroidSdkPackage::PackageState state
|
||||
= AndroidSdkPackage::Installed);
|
||||
void reloadPackages(bool forceReload = false);
|
||||
bool isBusy() const;
|
||||
|
||||
QFuture<QString> availableArguments() const;
|
||||
QFuture<OperationOutput> updateAll();
|
||||
QFuture<OperationOutput> update(const QStringList &install, const QStringList &uninstall);
|
||||
QFuture<OperationOutput> checkPendingLicenses();
|
||||
QFuture<OperationOutput> runLicenseCommand();
|
||||
|
||||
void cancelOperatons();
|
||||
void acceptSdkLicense(bool accept);
|
||||
|
||||
signals:
|
||||
void packageReloadBegin();
|
||||
void packageReloadFinished();
|
||||
void cancelActiveOperations();
|
||||
|
||||
private:
|
||||
const AndroidConfig &m_config;
|
||||
std::unique_ptr<SdkManagerOutputParser> m_parser;
|
||||
std::unique_ptr<AndroidSdkManagerPrivate> m_d;
|
||||
friend class AndroidSdkManagerPrivate;
|
||||
};
|
||||
|
||||
} // namespace Internal
|
||||
|
||||
579
src/plugins/android/androidsdkmanagerwidget.cpp
Normal file
579
src/plugins/android/androidsdkmanagerwidget.cpp
Normal file
@@ -0,0 +1,579 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2017 The Qt Company Ltd.
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of Qt Creator.
|
||||
**
|
||||
** Commercial License Usage
|
||||
** Licensees holding valid commercial Qt licenses may use this file in
|
||||
** accordance with the commercial license agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and The Qt Company. For licensing terms
|
||||
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||
** information use the contact form at https://www.qt.io/contact-us.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 3 as published by the Free Software
|
||||
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
||||
** included in the packaging of this file. Please review the following
|
||||
** information to ensure the GNU General Public License requirements will
|
||||
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
||||
**
|
||||
****************************************************************************/
|
||||
#include "androidsdkmanagerwidget.h"
|
||||
|
||||
#include "ui_androidsdkmanagerwidget.h"
|
||||
#include "androidconfigurations.h"
|
||||
#include "androidsdkmanager.h"
|
||||
#include "androidsdkmodel.h"
|
||||
|
||||
#include "utils/runextensions.h"
|
||||
#include "utils/outputformatter.h"
|
||||
#include "utils/runextensions.h"
|
||||
#include "utils/qtcassert.h"
|
||||
#include "utils/utilsicons.h"
|
||||
|
||||
#include <QDialogButtonBox>
|
||||
#include <QLabel>
|
||||
#include <QLineEdit>
|
||||
#include <QLoggingCategory>
|
||||
#include <QMessageBox>
|
||||
#include <QProcess>
|
||||
#include <QSortFilterProxyModel>
|
||||
|
||||
namespace {
|
||||
Q_LOGGING_CATEGORY(androidSdkMgrUiLog, "qtc.android.sdkManagerUi")
|
||||
}
|
||||
|
||||
namespace Android {
|
||||
namespace Internal {
|
||||
|
||||
using namespace std::placeholders;
|
||||
|
||||
class OptionsDialog : public QDialog
|
||||
{
|
||||
public:
|
||||
OptionsDialog(AndroidSdkManager *sdkManager, const QStringList &args,
|
||||
QWidget *parent = nullptr);
|
||||
~OptionsDialog();
|
||||
|
||||
QStringList sdkManagerArguments() const;
|
||||
|
||||
private:
|
||||
QPlainTextEdit *argumentDetailsEdit;
|
||||
QLineEdit *argumentsEdit;
|
||||
QFuture<QString> m_optionsFuture;
|
||||
};
|
||||
|
||||
class PackageFilterModel : public QSortFilterProxyModel
|
||||
{
|
||||
public:
|
||||
PackageFilterModel(AndroidSdkModel* sdkModel);
|
||||
|
||||
void setAcceptedPackageState(AndroidSdkPackage::PackageState state);
|
||||
bool filterAcceptsRow(int source_row, const QModelIndex &sourceParent) const override;
|
||||
|
||||
private:
|
||||
AndroidSdkPackage::PackageState m_packageState = AndroidSdkPackage::AnyValidState;
|
||||
};
|
||||
|
||||
AndroidSdkManagerWidget::AndroidSdkManagerWidget(AndroidConfig &config,
|
||||
AndroidSdkManager *sdkManager, QWidget *parent) :
|
||||
QWidget(parent),
|
||||
m_androidConfig(config),
|
||||
m_sdkManager(sdkManager),
|
||||
m_sdkModel(new AndroidSdkModel(m_androidConfig, m_sdkManager, this)),
|
||||
m_ui(new Ui::AndroidSdkManagerWidget)
|
||||
{
|
||||
QTC_CHECK(sdkManager);
|
||||
m_ui->setupUi(this);
|
||||
m_ui->sdkLicensebuttonBox->hide();
|
||||
m_ui->sdkLicenseLabel->hide();
|
||||
m_ui->warningLabel->setElideMode(Qt::ElideRight);
|
||||
m_ui->warningIconLabel->setPixmap(Utils::Icons::WARNING.pixmap());
|
||||
m_ui->viewStack->setCurrentWidget(m_ui->packagesStack);
|
||||
|
||||
m_formatter = new Utils::OutputFormatter;
|
||||
m_formatter->setPlainTextEdit(m_ui->outputEdit);
|
||||
|
||||
connect(m_sdkModel, &AndroidSdkModel::dataChanged, [this]() {
|
||||
if (m_ui->viewStack->currentWidget() == m_ui->packagesStack)
|
||||
m_ui->applySelectionButton->setEnabled(!m_sdkModel->userSelection().isEmpty());
|
||||
});
|
||||
|
||||
connect(m_sdkModel, &AndroidSdkModel::modelAboutToBeReset, [this]() {
|
||||
m_ui->applySelectionButton->setEnabled(false);
|
||||
m_ui->expandCheck->setChecked(false);
|
||||
cancelPendingOperations();
|
||||
switchView(PackageListing);
|
||||
});
|
||||
|
||||
auto proxyModel = new PackageFilterModel(m_sdkModel);
|
||||
m_ui->packagesView->setModel(proxyModel);
|
||||
m_ui->packagesView->header()->setSectionResizeMode(AndroidSdkModel::packageNameColumn,
|
||||
QHeaderView::ResizeToContents);
|
||||
m_ui->packagesView->header()->setSectionResizeMode(AndroidSdkModel::apiLevelColumn,
|
||||
QHeaderView::ResizeToContents);
|
||||
m_ui->packagesView->header()->setSectionResizeMode(AndroidSdkModel::packageRevisionColumn,
|
||||
QHeaderView::ResizeToContents);
|
||||
connect(m_ui->expandCheck, &QCheckBox::stateChanged, [this](int state) {
|
||||
if (state == Qt::Checked)
|
||||
m_ui->packagesView->expandAll();
|
||||
else
|
||||
m_ui->packagesView->collapseAll();
|
||||
});
|
||||
connect(m_ui->updateInstalledButton, &QPushButton::clicked,
|
||||
this, &AndroidSdkManagerWidget::onUpdatePackages);
|
||||
connect(m_ui->showAllRadio, &QRadioButton::toggled, [this, proxyModel](bool checked) {
|
||||
if (checked) {
|
||||
proxyModel->setAcceptedPackageState(AndroidSdkPackage::AnyValidState);
|
||||
m_sdkModel->resetSelection();
|
||||
}
|
||||
});
|
||||
connect(m_ui->showInstalledRadio, &QRadioButton::toggled, [this, proxyModel](bool checked) {
|
||||
if (checked) {
|
||||
proxyModel->setAcceptedPackageState(AndroidSdkPackage::Installed);
|
||||
m_sdkModel->resetSelection();
|
||||
}
|
||||
});
|
||||
connect(m_ui->showAvailableRadio, &QRadioButton::toggled, [this, proxyModel](bool checked) {
|
||||
if (checked) {
|
||||
proxyModel->setAcceptedPackageState(AndroidSdkPackage::Available);
|
||||
m_sdkModel->resetSelection();
|
||||
}
|
||||
});
|
||||
|
||||
connect(m_ui->applySelectionButton, &QPushButton::clicked,
|
||||
this, &AndroidSdkManagerWidget::onApplyButton);
|
||||
connect(m_ui->cancelButton, &QPushButton::clicked, this,
|
||||
&AndroidSdkManagerWidget::onCancel);
|
||||
connect(m_ui->nativeSdkManagerButton, &QPushButton::clicked,
|
||||
this, &AndroidSdkManagerWidget::onNativeSdkManager);
|
||||
connect(m_ui->optionsButton, &QPushButton::clicked,
|
||||
this, &AndroidSdkManagerWidget::onSdkManagerOptions);
|
||||
connect(m_ui->sdkLicensebuttonBox, &QDialogButtonBox::accepted, [this]() {
|
||||
m_sdkManager->acceptSdkLicense(true);
|
||||
m_ui->sdkLicensebuttonBox->setEnabled(false); // Wait for next license to enable controls
|
||||
});
|
||||
connect(m_ui->sdkLicensebuttonBox, &QDialogButtonBox::rejected, [this]() {
|
||||
m_sdkManager->acceptSdkLicense(false);
|
||||
m_ui->sdkLicensebuttonBox->setEnabled(false); // Wait for next license to enable controls
|
||||
});
|
||||
}
|
||||
|
||||
AndroidSdkManagerWidget::~AndroidSdkManagerWidget()
|
||||
{
|
||||
if (m_currentOperation)
|
||||
delete m_currentOperation;
|
||||
cancelPendingOperations();
|
||||
delete m_formatter;
|
||||
delete m_ui;
|
||||
}
|
||||
|
||||
void AndroidSdkManagerWidget::setSdkManagerControlsEnabled(bool enable)
|
||||
{
|
||||
m_ui->packagesTypeGroup->setEnabled(enable);
|
||||
m_ui->expandCheck->setVisible(enable);
|
||||
m_ui->warningIconLabel->setVisible(!enable);
|
||||
m_ui->warningLabel->setVisible(!enable);
|
||||
m_ui->packagesView->setEnabled(enable);
|
||||
m_ui->updateInstalledButton->setEnabled(enable);
|
||||
m_ui->optionsButton->setEnabled(enable);
|
||||
}
|
||||
|
||||
void AndroidSdkManagerWidget::installEssentials()
|
||||
{
|
||||
m_sdkModel->selectMissingEssentials();
|
||||
m_ui->applySelectionButton->click();
|
||||
}
|
||||
|
||||
void AndroidSdkManagerWidget::beginLicenseCheck()
|
||||
{
|
||||
m_formatter->appendMessage(tr("Checking pending licenses...\n"), Utils::NormalMessageFormat);
|
||||
addPackageFuture(m_sdkManager->checkPendingLicenses());
|
||||
}
|
||||
|
||||
void AndroidSdkManagerWidget::onApplyButton()
|
||||
{
|
||||
QTC_ASSERT(m_currentView == PackageListing, return);
|
||||
|
||||
if (m_sdkManager->isBusy()) {
|
||||
m_formatter->appendMessage(tr("\nSDK Manager is busy."), Utils::StdErrFormat);
|
||||
return;
|
||||
}
|
||||
|
||||
const QList<const AndroidSdkPackage *> packagesToUpdate = m_sdkModel->userSelection();
|
||||
if (packagesToUpdate.isEmpty())
|
||||
return;
|
||||
|
||||
QStringList installPackages, uninstallPackages;
|
||||
for (auto package : packagesToUpdate) {
|
||||
QString str = QString(" %1").arg(package->descriptionText());
|
||||
if (package->state() == AndroidSdkPackage::Installed)
|
||||
uninstallPackages << str;
|
||||
else
|
||||
installPackages << str;
|
||||
}
|
||||
|
||||
QMessageBox messageDlg(QMessageBox::Information, tr("Android SDK Changes"),
|
||||
tr("%n Android SDK packages shall be updated.",
|
||||
"", packagesToUpdate.count()),
|
||||
QMessageBox::Ok | QMessageBox::Cancel, this);
|
||||
|
||||
QString details;
|
||||
if (!uninstallPackages.isEmpty())
|
||||
details = tr("[Packages to be uninstalled:]\n").append(uninstallPackages.join("\n"));
|
||||
|
||||
if (!installPackages.isEmpty()) {
|
||||
if (!uninstallPackages.isEmpty())
|
||||
details.append("\n\n");
|
||||
details.append("[Packages to be installed:]\n").append(installPackages.join("\n"));
|
||||
}
|
||||
messageDlg.setDetailedText(details);
|
||||
if (messageDlg.exec() == QMessageBox::Cancel)
|
||||
return;
|
||||
|
||||
switchView(Operations);
|
||||
m_pendingCommand = AndroidSdkManager::UpdatePackage;
|
||||
// User agreed with the selection. Check for licenses.
|
||||
if (!installPackages.isEmpty()) {
|
||||
// Pending license affects installtion only.
|
||||
beginLicenseCheck();
|
||||
} else {
|
||||
// Uninstall only. Go Ahead.
|
||||
beginExecution();
|
||||
}
|
||||
}
|
||||
|
||||
void AndroidSdkManagerWidget::onUpdatePackages()
|
||||
{
|
||||
if (m_sdkManager->isBusy()) {
|
||||
m_formatter->appendMessage(tr("\nSDK Manager is busy."), Utils::StdErrFormat);
|
||||
return;
|
||||
}
|
||||
switchView(Operations);
|
||||
m_pendingCommand = AndroidSdkManager::UpdateAll;
|
||||
beginLicenseCheck();
|
||||
}
|
||||
|
||||
void AndroidSdkManagerWidget::onCancel()
|
||||
{
|
||||
cancelPendingOperations();
|
||||
}
|
||||
|
||||
void AndroidSdkManagerWidget::onNativeSdkManager()
|
||||
{
|
||||
if (m_androidConfig.useNativeUiTools()) {
|
||||
QProcess::startDetached(m_androidConfig.androidToolPath().toString());
|
||||
} else {
|
||||
QMessageBox::warning(this, tr("Native SDK Manager Not Available"),
|
||||
tr("SDK manager UI tool is not available in the installed SDK tools"
|
||||
"(version %1). Use the command line tool \"sdkmanager\" for "
|
||||
"advanced SDK management.")
|
||||
.arg(m_androidConfig.sdkToolsVersion().toString()));
|
||||
}
|
||||
}
|
||||
|
||||
void AndroidSdkManagerWidget::onOperationResult(int index)
|
||||
{
|
||||
QTC_ASSERT(m_currentOperation, return);
|
||||
AndroidSdkManager::OperationOutput result = m_currentOperation->resultAt(index);
|
||||
if (result.type == AndroidSdkManager::LicenseWorkflow) {
|
||||
// Show license controls and enable to user input.
|
||||
m_ui->sdkLicenseLabel->setVisible(true);
|
||||
m_ui->sdkLicensebuttonBox->setVisible(true);
|
||||
m_ui->sdkLicensebuttonBox->setEnabled(true);
|
||||
m_ui->sdkLicensebuttonBox->button(QDialogButtonBox::No)->setDefault(true);
|
||||
}
|
||||
auto breakLine = [](const QString &line) { return line.endsWith("\n") ? line : line + "\n";};
|
||||
if (!result.stdError.isEmpty() && result.type != AndroidSdkManager::LicenseCheck)
|
||||
m_formatter->appendMessage(breakLine(result.stdError), Utils::StdErrFormat);
|
||||
if (!result.stdOutput.isEmpty() && result.type != AndroidSdkManager::LicenseCheck)
|
||||
m_formatter->appendMessage(breakLine(result.stdOutput), Utils::StdOutFormat);
|
||||
m_ui->outputEdit->ensureCursorVisible();
|
||||
}
|
||||
|
||||
void AndroidSdkManagerWidget::onLicenseCheckResult(const AndroidSdkManager::OperationOutput& output)
|
||||
{
|
||||
if (output.success) {
|
||||
// No assertion was found. Looks like all license are accepted. Go Ahead.
|
||||
runPendingCommand();
|
||||
} else {
|
||||
// Assertion was found. Provide user workflow to accept licenses.
|
||||
QString warningMessage = tr("\nPlease note that the installation and use of Android SDK "
|
||||
"packages may fail if respective licenses are not accepted.");
|
||||
int userSelection = QMessageBox::question(this, tr("Android SDK Licenses"),
|
||||
output.stdOutput + warningMessage,
|
||||
QMessageBox::Yes | QMessageBox::No);
|
||||
if (userSelection == QMessageBox::Yes) {
|
||||
// Run license workflow.
|
||||
beginLicenseWorkflow();
|
||||
} else {
|
||||
// User decided to go ahead anyways.
|
||||
runPendingCommand();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AndroidSdkManagerWidget::addPackageFuture(const QFuture<AndroidSdkManager::OperationOutput>
|
||||
&future)
|
||||
{
|
||||
QTC_ASSERT(!m_currentOperation, return);
|
||||
if (!future.isFinished() || !future.isCanceled()) {
|
||||
m_currentOperation = new QFutureWatcher<AndroidSdkManager::OperationOutput>;
|
||||
m_currentOperation->setFuture(future);
|
||||
connect(m_currentOperation,
|
||||
&QFutureWatcher<AndroidSdkManager::OperationOutput>::resultReadyAt,
|
||||
this, &AndroidSdkManagerWidget::onOperationResult);
|
||||
connect(m_currentOperation, &QFutureWatcher<AndroidSdkManager::OperationOutput>::finished,
|
||||
this, &AndroidSdkManagerWidget::packageFutureFinished);
|
||||
connect(m_currentOperation,
|
||||
&QFutureWatcher<AndroidSdkManager::OperationOutput>::progressValueChanged,
|
||||
[this](int value) {
|
||||
m_ui->operationProgress->setValue(value);
|
||||
});
|
||||
} else {
|
||||
qCDebug(androidSdkMgrUiLog) << "Operation canceled/finished before adding to the queue";
|
||||
if (m_sdkManager->isBusy()) {
|
||||
m_formatter->appendMessage(tr("SDK Manager is busy. Operation cancelled."),
|
||||
Utils::StdErrFormat);
|
||||
}
|
||||
notifyOperationFinished();
|
||||
switchView(PackageListing);
|
||||
}
|
||||
}
|
||||
|
||||
void AndroidSdkManagerWidget::beginExecution()
|
||||
{
|
||||
const QList<const AndroidSdkPackage *> packagesToUpdate = m_sdkModel->userSelection();
|
||||
if (packagesToUpdate.isEmpty()) {
|
||||
switchView(PackageListing);
|
||||
return;
|
||||
}
|
||||
|
||||
QStringList installSdkPaths, uninstallSdkPaths;
|
||||
for (auto package : packagesToUpdate) {
|
||||
if (package->state() == AndroidSdkPackage::Installed)
|
||||
uninstallSdkPaths << package->sdkStylePath();
|
||||
else
|
||||
installSdkPaths << package->sdkStylePath();
|
||||
}
|
||||
m_formatter->appendMessage(tr("Installing/Uninstalling selected packages...\n"),
|
||||
Utils::NormalMessageFormat);
|
||||
m_formatter->appendMessage(tr("Closing the %1 dialog will cancel the running and scheduled SDK "
|
||||
"operations.\n").arg(Utils::HostOsInfo::isMacHost() ?
|
||||
tr("preferences") : tr("options")),
|
||||
Utils::LogMessageFormat);
|
||||
|
||||
addPackageFuture(m_sdkManager->update(installSdkPaths, uninstallSdkPaths));
|
||||
}
|
||||
|
||||
void AndroidSdkManagerWidget::beginUpdate()
|
||||
{
|
||||
m_formatter->appendMessage(tr("Updating installed packages...\n"), Utils::NormalMessageFormat);
|
||||
m_formatter->appendMessage(tr("Closing the %1 dialog will cancel the running and scheduled SDK "
|
||||
"operations.\n").arg(Utils::HostOsInfo::isMacHost() ?
|
||||
tr("preferences") : tr("options")),
|
||||
Utils::LogMessageFormat);
|
||||
addPackageFuture(m_sdkManager->updateAll());
|
||||
}
|
||||
|
||||
void AndroidSdkManagerWidget::beginLicenseWorkflow()
|
||||
{
|
||||
switchView(LicenseWorkflow);
|
||||
addPackageFuture(m_sdkManager->runLicenseCommand());
|
||||
}
|
||||
|
||||
void AndroidSdkManagerWidget::notifyOperationFinished()
|
||||
{
|
||||
if (!m_currentOperation || m_currentOperation->isFinished()) {
|
||||
QMessageBox::information(this, tr("Android SDK Changes"),
|
||||
tr("Android SDK operations finished."), QMessageBox::Ok);
|
||||
m_ui->operationProgress->setValue(0);
|
||||
}
|
||||
}
|
||||
|
||||
void AndroidSdkManagerWidget::packageFutureFinished()
|
||||
{
|
||||
QTC_ASSERT (m_currentOperation, return);
|
||||
|
||||
bool continueWorkflow = true;
|
||||
if (m_currentOperation->isCanceled()) {
|
||||
m_formatter->appendMessage(tr("Operation cancelled.\n"), Utils::StdErrFormat);
|
||||
continueWorkflow = false;
|
||||
}
|
||||
m_ui->operationProgress->setValue(100);
|
||||
int resultCount = m_currentOperation->future().resultCount();
|
||||
if (continueWorkflow && resultCount > 0) {
|
||||
AndroidSdkManager::OperationOutput output = m_currentOperation->resultAt(resultCount -1);
|
||||
AndroidSdkManager::CommandType type = output.type;
|
||||
m_currentOperation->deleteLater();
|
||||
m_currentOperation = nullptr;
|
||||
switch (type) {
|
||||
case AndroidSdkManager::LicenseCheck:
|
||||
onLicenseCheckResult(output);
|
||||
break;
|
||||
case AndroidSdkManager::LicenseWorkflow:
|
||||
m_ui->sdkLicensebuttonBox->hide();
|
||||
m_ui->sdkLicenseLabel->hide();
|
||||
runPendingCommand();
|
||||
break;
|
||||
case AndroidSdkManager::UpdateAll:
|
||||
case AndroidSdkManager::UpdatePackage:
|
||||
notifyOperationFinished();
|
||||
switchView(PackageListing);
|
||||
m_sdkManager->reloadPackages(true);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
m_currentOperation->deleteLater();
|
||||
m_currentOperation = nullptr;
|
||||
switchView(PackageListing);
|
||||
m_sdkManager->reloadPackages(true);
|
||||
}
|
||||
}
|
||||
|
||||
void AndroidSdkManagerWidget::cancelPendingOperations()
|
||||
{
|
||||
if (!m_sdkManager->isBusy()) {
|
||||
m_formatter->appendMessage(tr("\nNo pending operations to cancel...\n"),
|
||||
Utils::NormalMessageFormat);
|
||||
switchView(PackageListing);
|
||||
return;
|
||||
}
|
||||
m_formatter->appendMessage(tr("\nCancelling pending operations...\n"),
|
||||
Utils::NormalMessageFormat);
|
||||
m_sdkManager->cancelOperatons();
|
||||
}
|
||||
|
||||
void AndroidSdkManagerWidget::switchView(AndroidSdkManagerWidget::View view)
|
||||
{
|
||||
if (m_currentView == PackageListing) {
|
||||
m_formatter->clear();
|
||||
m_ui->outputEdit->clear();
|
||||
}
|
||||
m_currentView = view;
|
||||
if (m_currentView == PackageListing)
|
||||
emit updatingSdkFinished();
|
||||
else
|
||||
emit updatingSdk();
|
||||
|
||||
m_ui->operationProgress->setValue(0);
|
||||
m_ui->viewStack->setCurrentWidget(m_currentView == PackageListing ?
|
||||
m_ui->packagesStack : m_ui->outputStack);
|
||||
}
|
||||
|
||||
void AndroidSdkManagerWidget::runPendingCommand()
|
||||
{
|
||||
if (m_pendingCommand == AndroidSdkManager::UpdatePackage)
|
||||
beginExecution(); // License workflow can only start when updating packages.
|
||||
else if (m_pendingCommand == AndroidSdkManager::UpdateAll)
|
||||
beginUpdate();
|
||||
else
|
||||
QTC_ASSERT(false, qCDebug(androidSdkMgrUiLog) << "Unexpected state: No pending command.");
|
||||
}
|
||||
|
||||
void AndroidSdkManagerWidget::onSdkManagerOptions()
|
||||
{
|
||||
OptionsDialog dlg(m_sdkManager, m_androidConfig.sdkManagerToolArgs(), this);
|
||||
if (dlg.exec() == QDialog::Accepted) {
|
||||
QStringList arguments = dlg.sdkManagerArguments();
|
||||
if (arguments != m_androidConfig.sdkManagerToolArgs()) {
|
||||
m_androidConfig.setSdkManagerToolArgs(arguments);
|
||||
m_sdkManager->reloadPackages(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PackageFilterModel::PackageFilterModel(AndroidSdkModel *sdkModel) :
|
||||
QSortFilterProxyModel(sdkModel)
|
||||
{
|
||||
setSourceModel(sdkModel);
|
||||
}
|
||||
|
||||
void PackageFilterModel::setAcceptedPackageState(AndroidSdkPackage::PackageState state)
|
||||
{
|
||||
m_packageState = state;
|
||||
invalidateFilter();
|
||||
}
|
||||
|
||||
bool PackageFilterModel::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const
|
||||
{
|
||||
QModelIndex srcIndex = sourceModel()->index(sourceRow, 0, sourceParent);
|
||||
if (!srcIndex.isValid())
|
||||
return false;
|
||||
|
||||
auto packageState = [](const QModelIndex& i) {
|
||||
return (AndroidSdkPackage::PackageState)i.data(AndroidSdkModel::PackageStateRole).toInt();
|
||||
};
|
||||
|
||||
bool showTopLevel = false;
|
||||
if (!sourceParent.isValid()) {
|
||||
// Top Level items
|
||||
for (int row = 0; row < sourceModel()->rowCount(srcIndex); ++row) {
|
||||
QModelIndex childIndex = sourceModel()->index(row, 0, srcIndex);
|
||||
if (m_packageState & packageState(childIndex)) {
|
||||
showTopLevel = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return showTopLevel || (packageState(srcIndex) & m_packageState);
|
||||
}
|
||||
|
||||
OptionsDialog::OptionsDialog(AndroidSdkManager *sdkManager, const QStringList &args,
|
||||
QWidget *parent) : QDialog(parent)
|
||||
{
|
||||
QTC_CHECK(sdkManager);
|
||||
resize(800, 480);
|
||||
setWindowTitle(tr("SDK Manager Arguments"));
|
||||
|
||||
argumentDetailsEdit = new QPlainTextEdit(this);
|
||||
argumentDetailsEdit->setReadOnly(true);
|
||||
|
||||
auto populateOptions = [this](const QString& options) {
|
||||
if (options.isEmpty()) {
|
||||
argumentDetailsEdit->setPlainText(tr("Cannot load available arguments for "
|
||||
"\"sdkmanager\" command."));
|
||||
} else {
|
||||
argumentDetailsEdit->setPlainText(options);
|
||||
}
|
||||
};
|
||||
m_optionsFuture = sdkManager->availableArguments();
|
||||
Utils::onResultReady(m_optionsFuture, populateOptions);
|
||||
|
||||
auto dialogButtons = new QDialogButtonBox(this);
|
||||
dialogButtons->setStandardButtons(QDialogButtonBox::Cancel|QDialogButtonBox::Ok);
|
||||
connect(dialogButtons, &QDialogButtonBox::accepted, this, &OptionsDialog::accept);
|
||||
connect(dialogButtons, &QDialogButtonBox::rejected, this, &OptionsDialog::reject);
|
||||
|
||||
argumentsEdit = new QLineEdit(this);
|
||||
argumentsEdit->setText(args.join(" "));
|
||||
|
||||
auto gridLayout = new QGridLayout(this);
|
||||
gridLayout->addWidget(new QLabel(tr("SDK manager arguments:"), this), 0, 0, 1, 1);
|
||||
gridLayout->addWidget(argumentsEdit, 0, 1, 1, 1);
|
||||
gridLayout->addWidget(new QLabel(tr("Available arguments:"), this), 1, 0, 1, 2);
|
||||
gridLayout->addWidget(argumentDetailsEdit, 2, 0, 1, 2);
|
||||
gridLayout->addWidget(dialogButtons, 3, 0, 1, 2);
|
||||
}
|
||||
|
||||
OptionsDialog::~OptionsDialog()
|
||||
{
|
||||
m_optionsFuture.cancel();
|
||||
m_optionsFuture.waitForFinished();
|
||||
}
|
||||
|
||||
QStringList OptionsDialog::sdkManagerArguments() const
|
||||
{
|
||||
QString userInput = argumentsEdit->text().simplified();
|
||||
return userInput.isEmpty() ? QStringList() : userInput.split(' ');
|
||||
}
|
||||
|
||||
} // namespace Internal
|
||||
} // namespace Android
|
||||
97
src/plugins/android/androidsdkmanagerwidget.h
Normal file
97
src/plugins/android/androidsdkmanagerwidget.h
Normal file
@@ -0,0 +1,97 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2017 The Qt Company Ltd.
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of Qt Creator.
|
||||
**
|
||||
** Commercial License Usage
|
||||
** Licensees holding valid commercial Qt licenses may use this file in
|
||||
** accordance with the commercial license agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and The Qt Company. For licensing terms
|
||||
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||
** information use the contact form at https://www.qt.io/contact-us.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 3 as published by the Free Software
|
||||
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
||||
** included in the packaging of this file. Please review the following
|
||||
** information to ensure the GNU General Public License requirements will
|
||||
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
||||
**
|
||||
****************************************************************************/
|
||||
#pragma once
|
||||
|
||||
#include "androidconfigurations.h"
|
||||
#include "androidsdkmanager.h"
|
||||
|
||||
#include <QWidget>
|
||||
#include <QFutureWatcher>
|
||||
|
||||
namespace Utils { class OutputFormatter; }
|
||||
|
||||
namespace Android {
|
||||
namespace Internal {
|
||||
|
||||
class AndroidSdkManager;
|
||||
namespace Ui {
|
||||
class AndroidSdkManagerWidget;
|
||||
}
|
||||
|
||||
class AndroidSdkModel;
|
||||
|
||||
class AndroidSdkManagerWidget : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
enum View {
|
||||
PackageListing,
|
||||
Operations,
|
||||
LicenseWorkflow
|
||||
};
|
||||
|
||||
public:
|
||||
AndroidSdkManagerWidget(AndroidConfig &config, AndroidSdkManager *sdkManager,
|
||||
QWidget *parent = nullptr);
|
||||
~AndroidSdkManagerWidget();
|
||||
|
||||
void setSdkManagerControlsEnabled(bool enable);
|
||||
void installEssentials();
|
||||
|
||||
signals:
|
||||
void updatingSdk();
|
||||
void updatingSdkFinished();
|
||||
|
||||
private:
|
||||
void onApplyButton();
|
||||
void onUpdatePackages();
|
||||
void onCancel();
|
||||
void onNativeSdkManager();
|
||||
void onOperationResult(int index);
|
||||
void onLicenseCheckResult(const AndroidSdkManager::OperationOutput &output);
|
||||
void onSdkManagerOptions();
|
||||
void addPackageFuture(const QFuture<AndroidSdkManager::OperationOutput> &future);
|
||||
void beginLicenseCheck();
|
||||
void beginExecution();
|
||||
void beginUpdate();
|
||||
void beginLicenseWorkflow();
|
||||
void notifyOperationFinished();
|
||||
void packageFutureFinished();
|
||||
void cancelPendingOperations();
|
||||
void switchView(View view);
|
||||
void runPendingCommand();
|
||||
|
||||
AndroidConfig &m_androidConfig;
|
||||
AndroidSdkManager::CommandType m_pendingCommand = AndroidSdkManager::None;
|
||||
View m_currentView = PackageListing;
|
||||
AndroidSdkManager *m_sdkManager = nullptr;
|
||||
AndroidSdkModel *m_sdkModel = nullptr;
|
||||
Ui::AndroidSdkManagerWidget *m_ui = nullptr;
|
||||
Utils::OutputFormatter *m_formatter = nullptr;
|
||||
QFutureWatcher<AndroidSdkManager::OperationOutput> *m_currentOperation = nullptr;
|
||||
};
|
||||
|
||||
} // namespace Internal
|
||||
} // namespace Android
|
||||
311
src/plugins/android/androidsdkmanagerwidget.ui
Normal file
311
src/plugins/android/androidsdkmanagerwidget.ui
Normal file
@@ -0,0 +1,311 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>Android::Internal::AndroidSdkManagerWidget</class>
|
||||
<widget class="QWidget" name="Android::Internal::AndroidSdkManagerWidget">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>664</width>
|
||||
<height>396</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Android SDK Manager</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_3">
|
||||
<property name="spacing">
|
||||
<number>-1</number>
|
||||
</property>
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QStackedWidget" name="viewStack">
|
||||
<property name="currentIndex">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<widget class="QWidget" name="packagesStack">
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="spacing">
|
||||
<number>4</number>
|
||||
</property>
|
||||
<item row="0" column="0" colspan="2">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QCheckBox" name="expandCheck">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Expand All</string>
|
||||
</property>
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="warningIconLabel">
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="Utils::ElidingLabel" name="warningLabel">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>SDK manger is not available with the current version of SDK tools. Use native SDK manager.</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QTreeView" name="packagesView">
|
||||
<property name="indentation">
|
||||
<number>20</number>
|
||||
</property>
|
||||
<attribute name="headerCascadingSectionResizes">
|
||||
<bool>false</bool>
|
||||
</attribute>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<item>
|
||||
<widget class="QPushButton" name="updateInstalledButton">
|
||||
<property name="text">
|
||||
<string>Update Installed</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="applySelectionButton">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Apply</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="packagesTypeGroup">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="title">
|
||||
<string>Show Packages</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<property name="spacing">
|
||||
<number>12</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QRadioButton" name="showAvailableRadio">
|
||||
<property name="text">
|
||||
<string>Available</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QRadioButton" name="showInstalledRadio">
|
||||
<property name="text">
|
||||
<string>Installed</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QRadioButton" name="showAllRadio">
|
||||
<property name="text">
|
||||
<string>All</string>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="optionsButton">
|
||||
<property name="text">
|
||||
<string>Advanced Options...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::Fixed</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>5</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="nativeSdkManagerButton">
|
||||
<property name="text">
|
||||
<string>Native SDK Manager...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="outputStack">
|
||||
<layout class="QGridLayout" name="gridLayout_2">
|
||||
<item row="3" column="2">
|
||||
<widget class="QPushButton" name="cancelButton">
|
||||
<property name="text">
|
||||
<string>Cancel</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0" colspan="3">
|
||||
<widget class="QProgressBar" name="operationProgress">
|
||||
<property name="maximum">
|
||||
<number>100</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="textVisible">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="invertedAppearance">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="0" column="0" colspan="3">
|
||||
<widget class="QPlainTextEdit" name="outputEdit">
|
||||
<property name="readOnly">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="sdkLicenseLabel">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Do you want to accept the Android SDK license?</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1" colspan="2">
|
||||
<widget class="QDialogButtonBox" name="sdkLicensebuttonBox">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="standardButtons">
|
||||
<set>QDialogButtonBox::No|QDialogButtonBox::Yes</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>Utils::ElidingLabel</class>
|
||||
<extends>QLabel</extends>
|
||||
<header>utils/elidinglabel.h</header>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<tabstops>
|
||||
<tabstop>packagesView</tabstop>
|
||||
<tabstop>showAllRadio</tabstop>
|
||||
<tabstop>showInstalledRadio</tabstop>
|
||||
<tabstop>showAvailableRadio</tabstop>
|
||||
<tabstop>outputEdit</tabstop>
|
||||
</tabstops>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
352
src/plugins/android/androidsdkmodel.cpp
Normal file
352
src/plugins/android/androidsdkmodel.cpp
Normal file
@@ -0,0 +1,352 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2017 The Qt Company Ltd.
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of Qt Creator.
|
||||
**
|
||||
** Commercial License Usage
|
||||
** Licensees holding valid commercial Qt licenses may use this file in
|
||||
** accordance with the commercial license agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and The Qt Company. For licensing terms
|
||||
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||
** information use the contact form at https://www.qt.io/contact-us.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 3 as published by the Free Software
|
||||
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
||||
** included in the packaging of this file. Please review the following
|
||||
** information to ensure the GNU General Public License requirements will
|
||||
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
||||
**
|
||||
****************************************************************************/
|
||||
#include "androidsdkmodel.h"
|
||||
#include "androidmanager.h"
|
||||
#include "androidsdkmanager.h"
|
||||
|
||||
#include "utils/algorithm.h"
|
||||
#include "utils/qtcassert.h"
|
||||
#include "utils/utilsicons.h"
|
||||
|
||||
#include <QIcon>
|
||||
|
||||
namespace Android {
|
||||
namespace Internal {
|
||||
|
||||
const int packageColCount = 4;
|
||||
|
||||
AndroidSdkModel::AndroidSdkModel(const AndroidConfig &config, AndroidSdkManager *sdkManager,
|
||||
QObject *parent)
|
||||
: QAbstractItemModel(parent),
|
||||
m_config(config),
|
||||
m_sdkManager(sdkManager)
|
||||
{
|
||||
QTC_CHECK(m_sdkManager);
|
||||
connect(m_sdkManager, &AndroidSdkManager::packageReloadBegin, [this]() {
|
||||
clearContainers();
|
||||
beginResetModel();
|
||||
});
|
||||
connect(m_sdkManager, &AndroidSdkManager::packageReloadFinished, [this]() {
|
||||
refreshData();
|
||||
endResetModel();
|
||||
});
|
||||
}
|
||||
|
||||
QVariant AndroidSdkModel::headerData(int section, Qt::Orientation orientation, int role) const
|
||||
{
|
||||
Q_UNUSED(orientation)
|
||||
QVariant data;
|
||||
if (role == Qt::DisplayRole) {
|
||||
switch (section) {
|
||||
case packageNameColumn:
|
||||
data = tr("Package");
|
||||
break;
|
||||
case packageRevisionColumn:
|
||||
data = tr("Revision");
|
||||
break;
|
||||
case apiLevelColumn:
|
||||
data = tr("API");
|
||||
break;
|
||||
case operationColumn:
|
||||
data = tr("Operation");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
QModelIndex AndroidSdkModel::index(int row, int column, const QModelIndex &parent) const
|
||||
{
|
||||
if (parent.isValid()) {
|
||||
// Packages under top items.
|
||||
if (parent.row() == 0) {
|
||||
// Tools packages
|
||||
if (row < m_tools.count())
|
||||
return createIndex(row, column, const_cast<AndroidSdkPackage *>(m_tools.at(row)));
|
||||
} else if (parent.row() < m_sdkPlatforms.count() + 1) {
|
||||
// Platform packages
|
||||
const SdkPlatform *sdkPlatform = m_sdkPlatforms.at(parent.row() - 1);
|
||||
SystemImageList images = sdkPlatform->systemImages(AndroidSdkPackage::AnyValidState);
|
||||
if (row < images.count() + 1) {
|
||||
if (row == 0)
|
||||
return createIndex(row, column, const_cast<SdkPlatform *>(sdkPlatform));
|
||||
else
|
||||
return createIndex(row, column, images.at(row - 1));
|
||||
}
|
||||
}
|
||||
} else if (row < m_sdkPlatforms.count() + 1) {
|
||||
return createIndex(row, column); // Top level items (Tools & platform)
|
||||
}
|
||||
|
||||
return QModelIndex();
|
||||
}
|
||||
|
||||
QModelIndex AndroidSdkModel::parent(const QModelIndex &index) const
|
||||
{
|
||||
void *ip = index.internalPointer();
|
||||
if (!ip)
|
||||
return QModelIndex();
|
||||
|
||||
auto package = static_cast<const AndroidSdkPackage *>(ip);
|
||||
if (package->type() == AndroidSdkPackage::SystemImagePackage) {
|
||||
auto image = static_cast<const SystemImage *>(package);
|
||||
int row = m_sdkPlatforms.indexOf(const_cast<SdkPlatform *>(image->platform()));
|
||||
if (row > -1)
|
||||
return createIndex(row + 1, 0);
|
||||
} else if (package->type() == AndroidSdkPackage::SdkPlatformPackage) {
|
||||
int row = m_sdkPlatforms.indexOf(static_cast<const SdkPlatform *>(package));
|
||||
if (row > -1)
|
||||
return createIndex(row + 1, 0);
|
||||
} else {
|
||||
return createIndex(0, 0); // Tools
|
||||
}
|
||||
|
||||
return QModelIndex();
|
||||
}
|
||||
|
||||
int AndroidSdkModel::rowCount(const QModelIndex &parent) const
|
||||
{
|
||||
if (!parent.isValid())
|
||||
return m_sdkPlatforms.count() + 1;
|
||||
|
||||
if (!parent.internalPointer()) {
|
||||
if (parent.row() == 0) // Tools
|
||||
return m_tools.count();
|
||||
|
||||
if (parent.row() <= m_sdkPlatforms.count()) {
|
||||
const SdkPlatform * platform = m_sdkPlatforms.at(parent.row() - 1);
|
||||
return platform->systemImages(AndroidSdkPackage::AnyValidState).count() + 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int AndroidSdkModel::columnCount(const QModelIndex &parent) const
|
||||
{
|
||||
Q_UNUSED(parent)
|
||||
return packageColCount;
|
||||
}
|
||||
|
||||
QVariant AndroidSdkModel::data(const QModelIndex &index, int role) const
|
||||
{
|
||||
if (!index.isValid())
|
||||
return QVariant();
|
||||
|
||||
|
||||
if (!index.parent().isValid()) {
|
||||
// Top level tools
|
||||
if (index.row() == 0) {
|
||||
return role == Qt::DisplayRole && index.column() == packageNameColumn ?
|
||||
QVariant(tr("Tools")) : QVariant();
|
||||
}
|
||||
// Top level platforms
|
||||
const SdkPlatform *platform = m_sdkPlatforms.at(index.row() - 1);
|
||||
if (role == Qt::DisplayRole) {
|
||||
if (index.column() == packageNameColumn) {
|
||||
QString androidName = AndroidManager::androidNameForApiLevel(platform->apiLevel());
|
||||
if (androidName.startsWith("Android"))
|
||||
return androidName;
|
||||
else
|
||||
return platform->displayText();
|
||||
} else if (index.column() == apiLevelColumn) {
|
||||
return platform->apiLevel();
|
||||
}
|
||||
}
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
auto p = static_cast<const AndroidSdkPackage *>(index.internalPointer());
|
||||
QString apiLevelStr;
|
||||
if (p->type() == AndroidSdkPackage::SdkPlatformPackage)
|
||||
apiLevelStr = QString::number(static_cast<const SdkPlatform *>(p)->apiLevel());
|
||||
|
||||
if (p->type() == AndroidSdkPackage::SystemImagePackage)
|
||||
apiLevelStr = QString::number(static_cast<const SystemImage *>(p)->platform()->apiLevel());
|
||||
|
||||
if (role == Qt::DisplayRole) {
|
||||
switch (index.column()) {
|
||||
case packageNameColumn:
|
||||
return p->type() == AndroidSdkPackage::SdkPlatformPackage ?
|
||||
tr("SDK Platform") : p->displayText();
|
||||
case packageRevisionColumn:
|
||||
return p->revision().toString();
|
||||
case apiLevelColumn:
|
||||
return apiLevelStr;
|
||||
case operationColumn:
|
||||
if (p->type() == AndroidSdkPackage::SdkToolsPackage &&
|
||||
p->state() == AndroidSdkPackage::Installed) {
|
||||
return tr("Update Only");
|
||||
} else {
|
||||
return p->state() == AndroidSdkPackage::Installed ? tr("Uninstall") : tr("Install");
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (role == Qt::DecorationRole && index.column() == packageNameColumn) {
|
||||
return p->state() == AndroidSdkPackage::Installed ? Utils::Icons::OK.icon() :
|
||||
Utils::Icons::EMPTY16.icon();
|
||||
}
|
||||
|
||||
if (role == Qt::CheckStateRole && index.column() == operationColumn )
|
||||
return m_changeState.contains(p) ? Qt::Checked : Qt::Unchecked;
|
||||
|
||||
if (role == Qt::ToolTipRole)
|
||||
return QString("%1 - (%2)").arg(p->descriptionText()).arg(p->sdkStylePath());
|
||||
|
||||
if (role == PackageTypeRole)
|
||||
return p->type();
|
||||
|
||||
if (role == PackageStateRole)
|
||||
return p->state();
|
||||
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
QHash<int, QByteArray> AndroidSdkModel::roleNames() const
|
||||
{
|
||||
QHash <int, QByteArray> roles;
|
||||
roles[PackageTypeRole] = "PackageRole";
|
||||
roles[PackageStateRole] = "PackageState";
|
||||
return roles;
|
||||
}
|
||||
|
||||
Qt::ItemFlags AndroidSdkModel::flags(const QModelIndex &index) const
|
||||
{
|
||||
Qt::ItemFlags f = QAbstractItemModel::flags(index);
|
||||
if (index.column() == operationColumn)
|
||||
f |= Qt::ItemIsUserCheckable;
|
||||
|
||||
void *ip = index.internalPointer();
|
||||
if (ip && index.column() == operationColumn) {
|
||||
auto package = static_cast<const AndroidSdkPackage *>(ip);
|
||||
if (package->state() == AndroidSdkPackage::Installed &&
|
||||
package->type() == AndroidSdkPackage::SdkToolsPackage) {
|
||||
f &= ~Qt::ItemIsEnabled;
|
||||
}
|
||||
}
|
||||
return f;
|
||||
}
|
||||
|
||||
bool AndroidSdkModel::setData(const QModelIndex &index, const QVariant &value, int role)
|
||||
{
|
||||
void *ip = index.internalPointer();
|
||||
if (ip && role == Qt::CheckStateRole) {
|
||||
auto package = static_cast<const AndroidSdkPackage *>(ip);
|
||||
if (value.toInt() == Qt::Checked) {
|
||||
m_changeState << package;
|
||||
emit dataChanged(index, index, {Qt::CheckStateRole});
|
||||
} else if (m_changeState.remove(package)) {
|
||||
emit dataChanged(index, index, {Qt::CheckStateRole});
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void AndroidSdkModel::selectMissingEssentials()
|
||||
{
|
||||
resetSelection();
|
||||
bool selectPlatformTool = !m_config.adbToolPath().exists();
|
||||
bool selectBuildTools = m_config.buildToolsVersion().isNull();
|
||||
auto addTool = [this](QList<const AndroidSdkPackage *>::const_iterator itr) {
|
||||
m_changeState << *itr;
|
||||
auto i = index(std::distance(m_tools.cbegin(), itr), 0, index(0, 0));
|
||||
emit dataChanged(i, i, {Qt::CheckStateRole});
|
||||
};
|
||||
for (auto tool = m_tools.cbegin(); tool != m_tools.cend(); ++tool) {
|
||||
if (selectPlatformTool && (*tool)->type() == AndroidSdkPackage::PlatformToolsPackage) {
|
||||
// Select Platform tools
|
||||
addTool(tool);
|
||||
selectPlatformTool = false;
|
||||
}
|
||||
if (selectBuildTools && (*tool)->type() == AndroidSdkPackage::BuildToolsPackage) {
|
||||
// Select build tools
|
||||
addTool(tool);
|
||||
selectBuildTools = false;
|
||||
}
|
||||
if (!selectPlatformTool && !selectBuildTools)
|
||||
break;
|
||||
}
|
||||
|
||||
// Select SDK platform
|
||||
if (m_sdkManager->installedSdkPlatforms().isEmpty() && !m_sdkPlatforms.isEmpty()) {
|
||||
auto i = index(0, 0, index(1,0));
|
||||
m_changeState << m_sdkPlatforms.at(0);
|
||||
emit dataChanged(i , i, {Qt::CheckStateRole});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
QList<const AndroidSdkPackage *> AndroidSdkModel::userSelection() const
|
||||
{
|
||||
return m_changeState.toList();
|
||||
}
|
||||
|
||||
void AndroidSdkModel::resetSelection()
|
||||
{
|
||||
beginResetModel();
|
||||
m_changeState.clear();
|
||||
endResetModel();
|
||||
}
|
||||
|
||||
void AndroidSdkModel::clearContainers()
|
||||
{
|
||||
m_sdkPlatforms.clear();
|
||||
m_tools.clear();
|
||||
m_changeState.clear();
|
||||
}
|
||||
|
||||
void AndroidSdkModel::refreshData()
|
||||
{
|
||||
clearContainers();
|
||||
for (AndroidSdkPackage *p : m_sdkManager->allSdkPackages()) {
|
||||
if (p->type() == AndroidSdkPackage::SdkPlatformPackage)
|
||||
m_sdkPlatforms << static_cast<SdkPlatform *>(p);
|
||||
else
|
||||
m_tools << p;
|
||||
}
|
||||
Utils::sort(m_sdkPlatforms, [](const SdkPlatform *p1, const SdkPlatform *p2) {
|
||||
return p1->apiLevel() > p2->apiLevel();
|
||||
});
|
||||
|
||||
Utils::sort(m_tools, [](const AndroidSdkPackage *p1, const AndroidSdkPackage *p2) {
|
||||
if (p1->state() == p2->state()) {
|
||||
if (p1->type() == p2->type())
|
||||
return p1->revision() > p2->revision();
|
||||
else
|
||||
return p1->type() > p2->type();
|
||||
} else {
|
||||
return p1->state() < p2->state();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
} // namespace Internal
|
||||
} // namespace Android
|
||||
86
src/plugins/android/androidsdkmodel.h
Normal file
86
src/plugins/android/androidsdkmodel.h
Normal file
@@ -0,0 +1,86 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2017 The Qt Company Ltd.
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of Qt Creator.
|
||||
**
|
||||
** Commercial License Usage
|
||||
** Licensees holding valid commercial Qt licenses may use this file in
|
||||
** accordance with the commercial license agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and The Qt Company. For licensing terms
|
||||
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||
** information use the contact form at https://www.qt.io/contact-us.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 3 as published by the Free Software
|
||||
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
||||
** included in the packaging of this file. Please review the following
|
||||
** information to ensure the GNU General Public License requirements will
|
||||
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
||||
**
|
||||
****************************************************************************/
|
||||
#pragma once
|
||||
|
||||
#include "androidconfigurations.h"
|
||||
|
||||
#include <QAbstractItemModel>
|
||||
|
||||
#include <memory>
|
||||
|
||||
namespace Android {
|
||||
namespace Internal {
|
||||
|
||||
class AndroidSdkManager;
|
||||
|
||||
class AndroidSdkModel : public QAbstractItemModel
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
enum PackageColumn {
|
||||
packageNameColumn = 0,
|
||||
apiLevelColumn,
|
||||
packageRevisionColumn,
|
||||
operationColumn
|
||||
};
|
||||
|
||||
enum ExtraRoles {
|
||||
PackageTypeRole = Qt::UserRole + 1,
|
||||
PackageStateRole
|
||||
};
|
||||
|
||||
explicit AndroidSdkModel(const AndroidConfig &config, AndroidSdkManager *sdkManager,
|
||||
QObject *parent = 0);
|
||||
|
||||
// QAbstractItemModel overrides.
|
||||
QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override;
|
||||
QModelIndex index(int row, int column,
|
||||
const QModelIndex &parent = QModelIndex()) const override;
|
||||
QModelIndex parent(const QModelIndex &index) const override;
|
||||
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
|
||||
int columnCount(const QModelIndex &parent = QModelIndex()) const override;
|
||||
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
|
||||
QHash<int, QByteArray> roleNames() const override;
|
||||
Qt::ItemFlags flags(const QModelIndex &index) const override;
|
||||
bool setData(const QModelIndex &index, const QVariant &value, int role) override;
|
||||
|
||||
void selectMissingEssentials();
|
||||
QList<const AndroidSdkPackage *> userSelection() const;
|
||||
void resetSelection();
|
||||
|
||||
private:
|
||||
void clearContainers();
|
||||
void refreshData();
|
||||
|
||||
private:
|
||||
const AndroidConfig &m_config;
|
||||
AndroidSdkManager *m_sdkManager;
|
||||
QList<const SdkPlatform *> m_sdkPlatforms;
|
||||
QList<const AndroidSdkPackage *> m_tools;
|
||||
QSet<const AndroidSdkPackage *> m_changeState;
|
||||
};
|
||||
|
||||
} // namespace Internal
|
||||
} // namespace Android
|
||||
256
src/plugins/android/androidsdkpackage.cpp
Normal file
256
src/plugins/android/androidsdkpackage.cpp
Normal file
@@ -0,0 +1,256 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2017 The Qt Company Ltd.
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of Qt Creator.
|
||||
**
|
||||
** Commercial License Usage
|
||||
** Licensees holding valid commercial Qt licenses may use this file in
|
||||
** accordance with the commercial license agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and The Qt Company. For licensing terms
|
||||
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||
** information use the contact form at https://www.qt.io/contact-us.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 3 as published by the Free Software
|
||||
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
||||
** included in the packaging of this file. Please review the following
|
||||
** information to ensure the GNU General Public License requirements will
|
||||
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
||||
**
|
||||
****************************************************************************/
|
||||
#include "androidsdkpackage.h"
|
||||
|
||||
#include "utils/algorithm.h"
|
||||
|
||||
namespace Android {
|
||||
|
||||
AndroidSdkPackage::AndroidSdkPackage(QVersionNumber version, QString sdkStylePathStr,
|
||||
QObject *parent) :
|
||||
QObject(parent),
|
||||
m_revision(version),
|
||||
m_sdkStylePath(sdkStylePathStr)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
bool AndroidSdkPackage::operator <(const AndroidSdkPackage &other) const
|
||||
{
|
||||
if (typeid(*this) != typeid(other))
|
||||
return type() < other.type();
|
||||
return displayText() < other.displayText();
|
||||
}
|
||||
|
||||
QString AndroidSdkPackage::displayText() const
|
||||
{
|
||||
return m_displayText;
|
||||
}
|
||||
|
||||
QString AndroidSdkPackage::descriptionText() const
|
||||
{
|
||||
return m_descriptionText;
|
||||
}
|
||||
|
||||
const QVersionNumber &AndroidSdkPackage::revision() const
|
||||
{
|
||||
return m_revision;
|
||||
}
|
||||
|
||||
AndroidSdkPackage::PackageState AndroidSdkPackage::state() const
|
||||
{
|
||||
return m_state;
|
||||
}
|
||||
|
||||
const QString &AndroidSdkPackage::sdkStylePath() const
|
||||
{
|
||||
return m_sdkStylePath;
|
||||
}
|
||||
|
||||
const Utils::FileName &AndroidSdkPackage::installedLocation() const
|
||||
{
|
||||
return m_installedLocation;
|
||||
}
|
||||
|
||||
void AndroidSdkPackage::setDisplayText(const QString &str)
|
||||
{
|
||||
m_displayText = str;
|
||||
}
|
||||
|
||||
void AndroidSdkPackage::setDescriptionText(const QString &str)
|
||||
{
|
||||
m_descriptionText = str;
|
||||
}
|
||||
|
||||
void AndroidSdkPackage::setState(AndroidSdkPackage::PackageState state)
|
||||
{
|
||||
m_state = state;
|
||||
}
|
||||
|
||||
void AndroidSdkPackage::setInstalledLocation(const Utils::FileName &path)
|
||||
{
|
||||
m_installedLocation = path;
|
||||
if (m_installedLocation.exists())
|
||||
updatePackageDetails();
|
||||
}
|
||||
|
||||
void AndroidSdkPackage::updatePackageDetails()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
SystemImage::SystemImage(QVersionNumber version, QString sdkStylePathStr, QString abi,
|
||||
SdkPlatform *platform):
|
||||
AndroidSdkPackage(version, sdkStylePathStr, platform),
|
||||
m_platform(platform),
|
||||
m_abiName(abi)
|
||||
{
|
||||
}
|
||||
|
||||
bool SystemImage::isValid() const
|
||||
{
|
||||
return m_platform && m_platform->isValid();
|
||||
}
|
||||
|
||||
AndroidSdkPackage::PackageType SystemImage::type() const
|
||||
{
|
||||
return SystemImagePackage;
|
||||
}
|
||||
|
||||
const QString &SystemImage::abiName() const
|
||||
{
|
||||
return m_abiName;
|
||||
}
|
||||
|
||||
const SdkPlatform *SystemImage::platform() const
|
||||
{
|
||||
return m_platform.data();
|
||||
}
|
||||
|
||||
void SystemImage::setPlatform(SdkPlatform *platform)
|
||||
{
|
||||
m_platform = platform;
|
||||
}
|
||||
|
||||
SdkPlatform::SdkPlatform(QVersionNumber version, QString sdkStylePathStr, int api, QObject *parent) :
|
||||
AndroidSdkPackage(version, sdkStylePathStr, parent),
|
||||
m_apiLevel(api)
|
||||
{
|
||||
setDisplayText(QString("android-%1")
|
||||
.arg(m_apiLevel != -1 ? QString::number(m_apiLevel) : "Unknown"));
|
||||
}
|
||||
|
||||
SdkPlatform::~SdkPlatform()
|
||||
{
|
||||
for (SystemImage *image : m_systemImages)
|
||||
delete image;
|
||||
m_systemImages.clear();
|
||||
}
|
||||
|
||||
bool SdkPlatform::isValid() const
|
||||
{
|
||||
return m_apiLevel != -1;
|
||||
}
|
||||
|
||||
AndroidSdkPackage::PackageType SdkPlatform::type() const
|
||||
{
|
||||
return SdkPlatformPackage;
|
||||
}
|
||||
|
||||
bool SdkPlatform::operator <(const AndroidSdkPackage &other) const
|
||||
{
|
||||
if (typeid(*this) != typeid(other))
|
||||
return AndroidSdkPackage::operator <(other);
|
||||
|
||||
const SdkPlatform &platform = static_cast<const SdkPlatform &>(other);
|
||||
if (platform.m_apiLevel == m_apiLevel)
|
||||
return AndroidSdkPackage::operator <(other);
|
||||
|
||||
return platform.m_apiLevel < m_apiLevel;
|
||||
}
|
||||
|
||||
int SdkPlatform::apiLevel() const
|
||||
{
|
||||
return m_apiLevel;
|
||||
}
|
||||
|
||||
QVersionNumber SdkPlatform::version() const
|
||||
{
|
||||
return m_version;
|
||||
}
|
||||
|
||||
void SdkPlatform::addSystemImage(SystemImage *image)
|
||||
{
|
||||
// Ordered insert. Installed images on top with lexical comparison of the display name.
|
||||
auto itr = m_systemImages.begin();
|
||||
while (itr != m_systemImages.end()) {
|
||||
SystemImage *currentImage = *itr;
|
||||
if (currentImage->state() == image->state()) {
|
||||
if (currentImage->displayText() > image->displayText())
|
||||
break;
|
||||
} else if (currentImage->state() > image->state()) {
|
||||
break;
|
||||
}
|
||||
++itr;
|
||||
}
|
||||
m_systemImages.insert(itr, image);
|
||||
image->setPlatform(this);
|
||||
}
|
||||
|
||||
SystemImageList SdkPlatform::systemImages(PackageState state) const
|
||||
{
|
||||
return Utils::filtered(m_systemImages, [state](const SystemImage *image) {
|
||||
return image->state() & state;
|
||||
});
|
||||
}
|
||||
|
||||
BuildTools::BuildTools(QVersionNumber revision, QString sdkStylePathStr, QObject *parent):
|
||||
AndroidSdkPackage(revision, sdkStylePathStr, parent)
|
||||
{
|
||||
}
|
||||
|
||||
bool BuildTools::isValid() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
AndroidSdkPackage::PackageType BuildTools::type() const
|
||||
{
|
||||
return AndroidSdkPackage::BuildToolsPackage;
|
||||
}
|
||||
|
||||
SdkTools::SdkTools(QVersionNumber revision, QString sdkStylePathStr, QObject *parent):
|
||||
AndroidSdkPackage(revision, sdkStylePathStr, parent)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
bool SdkTools::isValid() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
AndroidSdkPackage::PackageType SdkTools::type() const
|
||||
{
|
||||
return AndroidSdkPackage::SdkToolsPackage;
|
||||
}
|
||||
|
||||
PlatformTools::PlatformTools(QVersionNumber revision, QString sdkStylePathStr, QObject *parent):
|
||||
AndroidSdkPackage(revision, sdkStylePathStr, parent)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
bool PlatformTools::isValid() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
AndroidSdkPackage::PackageType PlatformTools::type() const
|
||||
{
|
||||
return AndroidSdkPackage::PlatformToolsPackage;
|
||||
}
|
||||
|
||||
} // namespace Android
|
||||
184
src/plugins/android/androidsdkpackage.h
Normal file
184
src/plugins/android/androidsdkpackage.h
Normal file
@@ -0,0 +1,184 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2017 The Qt Company Ltd.
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of Qt Creator.
|
||||
**
|
||||
** Commercial License Usage
|
||||
** Licensees holding valid commercial Qt licenses may use this file in
|
||||
** accordance with the commercial license agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and The Qt Company. For licensing terms
|
||||
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||
** information use the contact form at https://www.qt.io/contact-us.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 3 as published by the Free Software
|
||||
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
||||
** included in the packaging of this file. Please review the following
|
||||
** information to ensure the GNU General Public License requirements will
|
||||
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
||||
**
|
||||
****************************************************************************/
|
||||
#include "utils/fileutils.h"
|
||||
|
||||
#include <QList>
|
||||
#include <QObject>
|
||||
#include <QPointer>
|
||||
#include <QVersionNumber>
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace Android {
|
||||
|
||||
namespace Internal {
|
||||
class SdkManagerOutputParser;
|
||||
class AndroidToolOutputParser;
|
||||
}
|
||||
class SdkPlatform;
|
||||
class SystemImage;
|
||||
|
||||
class AndroidSdkPackage : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
enum PackageType {
|
||||
UnknownPackage = 1 << 0,
|
||||
SdkToolsPackage = 1 << 1,
|
||||
BuildToolsPackage = 1 << 2,
|
||||
PlatformToolsPackage = 1 << 3,
|
||||
SdkPlatformPackage = 1 << 4,
|
||||
SystemImagePackage = 1 << 5,
|
||||
AnyValidType = SdkToolsPackage | BuildToolsPackage | PlatformToolsPackage |
|
||||
SdkPlatformPackage | SystemImagePackage
|
||||
};
|
||||
|
||||
enum PackageState {
|
||||
Unknown = 1 << 0,
|
||||
Installed = 1 << 1,
|
||||
Available = 1 << 2,
|
||||
AnyValidState = Installed | Available
|
||||
};
|
||||
|
||||
AndroidSdkPackage(QVersionNumber revision, QString sdkStylePathStr, QObject *parent = nullptr);
|
||||
virtual ~AndroidSdkPackage() { }
|
||||
|
||||
virtual bool isValid() const = 0;
|
||||
virtual PackageType type() const = 0;
|
||||
virtual bool operator <(const AndroidSdkPackage &other) const;
|
||||
|
||||
QString displayText() const;
|
||||
QString descriptionText() const;
|
||||
const QVersionNumber &revision() const;
|
||||
PackageState state() const;
|
||||
const QString &sdkStylePath() const;
|
||||
const Utils::FileName &installedLocation() const;
|
||||
|
||||
protected:
|
||||
void setDisplayText(const QString &str);
|
||||
void setDescriptionText(const QString &str);
|
||||
void setState(PackageState state);
|
||||
void setInstalledLocation(const Utils::FileName &path);
|
||||
|
||||
virtual void updatePackageDetails();
|
||||
|
||||
private:
|
||||
QString m_displayText;
|
||||
QString m_descriptionText;
|
||||
QVersionNumber m_revision;
|
||||
PackageState m_state = PackageState::Unknown;
|
||||
QString m_sdkStylePath;
|
||||
Utils::FileName m_installedLocation;
|
||||
|
||||
friend class Internal::SdkManagerOutputParser;
|
||||
friend class Internal::AndroidToolOutputParser;
|
||||
};
|
||||
using AndroidSdkPackageList = QList<AndroidSdkPackage*>;
|
||||
|
||||
class SystemImage : public AndroidSdkPackage
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
SystemImage(QVersionNumber revision, QString sdkStylePathStr, QString abi,
|
||||
SdkPlatform *platform = nullptr);
|
||||
|
||||
// AndroidSdkPackage Overrides
|
||||
bool isValid() const override;
|
||||
PackageType type() const override;
|
||||
|
||||
const QString &abiName() const;
|
||||
const SdkPlatform *platform() const;
|
||||
void setPlatform(SdkPlatform *platform);
|
||||
|
||||
private:
|
||||
QPointer<SdkPlatform> m_platform;
|
||||
QString m_abiName;
|
||||
};
|
||||
using SystemImageList = QList<SystemImage*>;
|
||||
|
||||
|
||||
class SdkPlatform : public AndroidSdkPackage
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
SdkPlatform(QVersionNumber revision, QString sdkStylePathStr, int api,
|
||||
QObject *parent = nullptr);
|
||||
|
||||
~SdkPlatform();
|
||||
|
||||
// AndroidSdkPackage Overrides
|
||||
bool isValid() const override;
|
||||
PackageType type() const override;
|
||||
bool operator <(const AndroidSdkPackage &other) const override;
|
||||
|
||||
int apiLevel() const;
|
||||
QVersionNumber version() const;
|
||||
void addSystemImage(SystemImage *image);
|
||||
SystemImageList systemImages(AndroidSdkPackage::PackageState state
|
||||
= AndroidSdkPackage::Installed) const;
|
||||
|
||||
private:
|
||||
SystemImageList m_systemImages;
|
||||
int m_apiLevel = -1;
|
||||
QVersionNumber m_version;
|
||||
};
|
||||
using SdkPlatformList = QList<SdkPlatform*>;
|
||||
|
||||
class BuildTools : public AndroidSdkPackage
|
||||
{
|
||||
public:
|
||||
BuildTools(QVersionNumber revision, QString sdkStylePathStr, QObject *parent = nullptr);
|
||||
|
||||
// AndroidSdkPackage Overrides
|
||||
public:
|
||||
bool isValid() const override;
|
||||
PackageType type() const override;
|
||||
};
|
||||
|
||||
class PlatformTools : public AndroidSdkPackage
|
||||
{
|
||||
public:
|
||||
PlatformTools(QVersionNumber revision, QString sdkStylePathStr, QObject *parent = nullptr);
|
||||
|
||||
// AndroidSdkPackage Overrides
|
||||
public:
|
||||
bool isValid() const override;
|
||||
PackageType type() const override;
|
||||
};
|
||||
|
||||
class SdkTools : public AndroidSdkPackage
|
||||
{
|
||||
public:
|
||||
SdkTools(QVersionNumber revision, QString sdkStylePathStr, QObject *parent = nullptr);
|
||||
|
||||
// AndroidSdkPackage Overrides
|
||||
public:
|
||||
bool isValid() const override;
|
||||
PackageType type() const override;
|
||||
};
|
||||
} // namespace Android
|
||||
|
||||
|
||||
@@ -31,8 +31,13 @@
|
||||
#include "androidconstants.h"
|
||||
#include "androidtoolchain.h"
|
||||
#include "androidavdmanager.h"
|
||||
#include "androidsdkmanager.h"
|
||||
#include "avddialog.h"
|
||||
#include "androidsdkmanagerwidget.h"
|
||||
|
||||
#include <utils/qtcassert.h>
|
||||
#include <utils/environment.h>
|
||||
#include <utils/elidinglabel.h>
|
||||
#include <utils/hostosinfo.h>
|
||||
#include <utils/pathchooser.h>
|
||||
#include <utils/runextensions.h>
|
||||
@@ -59,6 +64,100 @@
|
||||
namespace Android {
|
||||
namespace Internal {
|
||||
|
||||
namespace {
|
||||
enum JavaValidation {
|
||||
JavaPathExistsRow,
|
||||
JavaJdkValidRow
|
||||
};
|
||||
|
||||
enum AndroidValidation {
|
||||
SdkPathExistsRow,
|
||||
SdkToolsInstalledRow,
|
||||
PlatformToolsInstalledRow,
|
||||
BuildToolsInstalledRow,
|
||||
PlatformSdkInstalledRow,
|
||||
NdkPathExistsRow,
|
||||
NdkDirStructureRow,
|
||||
NdkinstallDirOkRow
|
||||
};
|
||||
}
|
||||
|
||||
class SummaryWidget : public QWidget
|
||||
{
|
||||
class RowData {
|
||||
public:
|
||||
QLabel *m_iconLabel = nullptr;
|
||||
Utils::ElidingLabel *m_textLabel = nullptr;
|
||||
bool m_valid = false;
|
||||
};
|
||||
|
||||
public:
|
||||
SummaryWidget(const QMap<int, QString> &validationPoints, const QString &validText,
|
||||
const QString &invalidText, Utils::DetailsWidget *detailsWidget) :
|
||||
QWidget(detailsWidget),
|
||||
m_validText(validText),
|
||||
m_invalidText(invalidText),
|
||||
m_detailsWidget(detailsWidget)
|
||||
{
|
||||
QTC_CHECK(m_detailsWidget);
|
||||
auto layout = new QGridLayout(this);
|
||||
layout->setMargin(12);
|
||||
int row = 0;
|
||||
for (auto itr = validationPoints.cbegin(); itr != validationPoints.cend(); ++itr) {
|
||||
RowData data;
|
||||
data.m_iconLabel = new QLabel(this);
|
||||
layout->addWidget(data.m_iconLabel, row, 0, 1, 1);
|
||||
data.m_textLabel = new Utils::ElidingLabel(itr.value(), this);
|
||||
data.m_textLabel->setElideMode(Qt::ElideRight);
|
||||
data.m_textLabel->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
|
||||
layout->addWidget(data.m_textLabel, row, 1, 1, 1);
|
||||
m_validationData[itr.key()] = data;
|
||||
setPointValid(itr.key(), true);
|
||||
++row;
|
||||
}
|
||||
}
|
||||
|
||||
void setPointValid(int key, bool valid)
|
||||
{
|
||||
if (!m_validationData.contains(key))
|
||||
return;
|
||||
RowData& data = m_validationData[key];
|
||||
data.m_valid = valid;
|
||||
data.m_iconLabel->setPixmap(data.m_valid ? Utils::Icons::OK.pixmap() :
|
||||
Utils::Icons::BROKEN.pixmap());
|
||||
updateUi();
|
||||
}
|
||||
|
||||
bool rowsOk(QList<int> keys) const
|
||||
{
|
||||
for (auto key : keys) {
|
||||
if (!m_validationData[key].m_valid)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool allRowsOk() const { return rowsOk(m_validationData.keys()); }
|
||||
void setInfoText(const QString &text) {
|
||||
m_infoText = text;
|
||||
updateUi();
|
||||
}
|
||||
|
||||
private:
|
||||
void updateUi() {
|
||||
bool ok = allRowsOk();
|
||||
m_detailsWidget->setIcon(ok ? Utils::Icons::OK.icon() :
|
||||
Utils::Icons::CRITICAL.icon());
|
||||
m_detailsWidget->setSummaryText(ok ? QString("%1 %2").arg(m_validText).arg(m_infoText)
|
||||
: m_invalidText);
|
||||
}
|
||||
QString m_validText;
|
||||
QString m_invalidText;
|
||||
QString m_infoText;
|
||||
Utils::DetailsWidget *m_detailsWidget = nullptr;
|
||||
QMap<int, RowData> m_validationData;
|
||||
};
|
||||
|
||||
void AvdModel::setAvdList(const AndroidDeviceInfoList &list)
|
||||
{
|
||||
beginResetModel();
|
||||
@@ -125,14 +224,54 @@ int AvdModel::columnCount(const QModelIndex &/*parent*/) const
|
||||
|
||||
AndroidSettingsWidget::AndroidSettingsWidget(QWidget *parent)
|
||||
: QWidget(parent),
|
||||
m_sdkState(NotSet),
|
||||
m_ndkState(NotSet),
|
||||
m_javaState(NotSet),
|
||||
m_ui(new Ui_AndroidSettingsWidget),
|
||||
m_androidConfig(AndroidConfigurations::currentConfig()),
|
||||
m_avdManager(new AndroidAvdManager(m_androidConfig))
|
||||
m_avdManager(new AndroidAvdManager(m_androidConfig)),
|
||||
m_sdkManager(new AndroidSdkManager(m_androidConfig))
|
||||
{
|
||||
m_ui->setupUi(this);
|
||||
m_sdkManagerWidget = new AndroidSdkManagerWidget(m_androidConfig, m_sdkManager.get(),
|
||||
m_ui->sdkManagerTab);
|
||||
auto sdkMangerLayout = new QVBoxLayout(m_ui->sdkManagerTab);
|
||||
sdkMangerLayout->setMargin(0);
|
||||
sdkMangerLayout->addWidget(m_sdkManagerWidget);
|
||||
connect(m_sdkManagerWidget, &AndroidSdkManagerWidget::updatingSdk, [this]() {
|
||||
m_ui->SDKLocationPathChooser->setEnabled(false);
|
||||
// Disable the tab bar to restrict the user moving away from sdk manager tab untill
|
||||
// operations finish.
|
||||
m_ui->managerTabWidget->tabBar()->setEnabled(false);
|
||||
});
|
||||
connect(m_sdkManagerWidget, &AndroidSdkManagerWidget::updatingSdkFinished, [this]() {
|
||||
m_ui->SDKLocationPathChooser->setEnabled(true);
|
||||
m_ui->managerTabWidget->tabBar()->setEnabled(true);
|
||||
});
|
||||
|
||||
QMap<int, QString> javaValidationPoints;
|
||||
javaValidationPoints[JavaPathExistsRow] = tr("JDK path exists.");
|
||||
javaValidationPoints[JavaJdkValidRow] = tr("JDK path is a valid JDK root folder.");
|
||||
auto javaSummary = new SummaryWidget(javaValidationPoints, tr("Java Settings are OK."),
|
||||
tr("Java settings have errors."), m_ui->javaDetailsWidget);
|
||||
m_ui->javaDetailsWidget->setWidget(javaSummary);
|
||||
|
||||
QMap<int, QString> androidValidationPoints;
|
||||
androidValidationPoints[SdkPathExistsRow] = tr("Android SDK path exists.");
|
||||
androidValidationPoints[SdkToolsInstalledRow] = tr("SDK tools installed.");
|
||||
androidValidationPoints[PlatformToolsInstalledRow] = tr("Platform tools installed.");
|
||||
androidValidationPoints[BuildToolsInstalledRow] = tr("Build tools installed.");
|
||||
androidValidationPoints[PlatformSdkInstalledRow] = tr("Platform SDK installed.");
|
||||
androidValidationPoints[NdkPathExistsRow] = tr("Android NDK path exists.");
|
||||
androidValidationPoints[NdkDirStructureRow] = tr("Android NDK directory structure is correct.");
|
||||
androidValidationPoints[NdkinstallDirOkRow] = tr("Android NDK installed into a path without "
|
||||
"spaces.");
|
||||
auto androidSummary = new SummaryWidget(androidValidationPoints, tr("Android settings are OK."),
|
||||
tr("Android settings have errors."),
|
||||
m_ui->androidDetailsWidget);
|
||||
m_ui->androidDetailsWidget->setWidget(androidSummary);
|
||||
|
||||
auto kitsDetailsLabel = new QLabel(m_ui->kitWarningDetails);
|
||||
kitsDetailsLabel->setWordWrap(true);
|
||||
m_ui->kitWarningDetails->setWidget(kitsDetailsLabel);
|
||||
m_ui->kitWarningDetails->setIcon(Utils::Icons::WARNING.icon());
|
||||
|
||||
m_ui->SDKLocationPathChooser->setFileName(m_androidConfig.sdkLocation());
|
||||
m_ui->SDKLocationPathChooser->setPromptDialogTitle(tr("Select Android SDK folder"));
|
||||
@@ -149,29 +288,16 @@ AndroidSettingsWidget::AndroidSettingsWidget(QWidget *parent)
|
||||
|
||||
m_ui->downloadOpenJDKToolButton->setVisible(!Utils::HostOsInfo::isLinuxHost());
|
||||
|
||||
const QPixmap warningPixmap = Utils::Icons::WARNING.pixmap();
|
||||
m_ui->jdkWarningIconLabel->setPixmap(warningPixmap);
|
||||
m_ui->kitWarningIconLabel->setPixmap(warningPixmap);
|
||||
|
||||
const QPixmap errorPixmap = Utils::Icons::CRITICAL.pixmap();
|
||||
m_ui->sdkWarningIconLabel->setPixmap(errorPixmap);
|
||||
m_ui->ndkWarningIconLabel->setPixmap(errorPixmap);
|
||||
|
||||
connect(&m_virtualDevicesWatcher, &QFutureWatcherBase::finished,
|
||||
this, &AndroidSettingsWidget::updateAvds);
|
||||
|
||||
check(All);
|
||||
applyToUi(All);
|
||||
|
||||
connect(&m_futureWatcher, &QFutureWatcherBase::finished,
|
||||
this, &AndroidSettingsWidget::avdAdded);
|
||||
|
||||
connect(m_ui->NDKLocationPathChooser, &Utils::PathChooser::rawPathChanged,
|
||||
this, &AndroidSettingsWidget::ndkLocationEditingFinished);
|
||||
this, &AndroidSettingsWidget::validateNdk);
|
||||
connect(m_ui->SDKLocationPathChooser, &Utils::PathChooser::rawPathChanged,
|
||||
this, &AndroidSettingsWidget::sdkLocationEditingFinished);
|
||||
this, &AndroidSettingsWidget::onSdkPathChanged);
|
||||
connect(m_ui->OpenJDKLocationPathChooser, &Utils::PathChooser::rawPathChanged,
|
||||
this, &AndroidSettingsWidget::openJDKLocationEditingFinished);
|
||||
this, &AndroidSettingsWidget::validateJdk);
|
||||
connect(m_ui->AVDAddPushButton, &QAbstractButton::clicked,
|
||||
this, &AndroidSettingsWidget::addAVD);
|
||||
connect(m_ui->AVDRemovePushButton, &QAbstractButton::clicked,
|
||||
@@ -184,7 +310,7 @@ AndroidSettingsWidget::AndroidSettingsWidget(QWidget *parent)
|
||||
this, &AndroidSettingsWidget::avdActivated);
|
||||
connect(m_ui->DataPartitionSizeSpinBox, &QAbstractSpinBox::editingFinished,
|
||||
this, &AndroidSettingsWidget::dataPartitionSizeEditingFinished);
|
||||
connect(m_ui->manageAVDPushButton, &QAbstractButton::clicked,
|
||||
connect(m_ui->nativeAvdManagerButton, &QAbstractButton::clicked,
|
||||
this, &AndroidSettingsWidget::manageAVD);
|
||||
connect(m_ui->CreateKitCheckBox, &QAbstractButton::toggled,
|
||||
this, &AndroidSettingsWidget::createKitToggled);
|
||||
@@ -194,152 +320,24 @@ AndroidSettingsWidget::AndroidSettingsWidget(QWidget *parent)
|
||||
this, &AndroidSettingsWidget::openNDKDownloadUrl);
|
||||
connect(m_ui->downloadOpenJDKToolButton, &QAbstractButton::clicked,
|
||||
this, &AndroidSettingsWidget::openOpenJDKDownloadUrl);
|
||||
// Validate SDK again after any change in SDK packages.
|
||||
connect(m_sdkManager.get(), &AndroidSdkManager::packageReloadFinished,
|
||||
this, &AndroidSettingsWidget::validateSdk);
|
||||
validateJdk();
|
||||
validateNdk();
|
||||
// Reloading SDK packages is still synchronous. Use zero timer to let settings dialog open
|
||||
// first.
|
||||
QTimer::singleShot(0, std::bind(&AndroidSdkManager::reloadPackages, m_sdkManager.get(), false));
|
||||
}
|
||||
|
||||
AndroidSettingsWidget::~AndroidSettingsWidget()
|
||||
{
|
||||
// Deleting m_sdkManagerWidget will cancel all ongoing and pending sdkmanager operations.
|
||||
delete m_sdkManagerWidget;
|
||||
delete m_ui;
|
||||
m_futureWatcher.waitForFinished();
|
||||
}
|
||||
|
||||
void AndroidSettingsWidget::check(AndroidSettingsWidget::Mode mode)
|
||||
{
|
||||
if (mode & Sdk) {
|
||||
m_sdkState = verifySdkInstallation(&m_sdkInstallationError) ? Okay : Error;
|
||||
}
|
||||
|
||||
if (mode & Ndk) {
|
||||
m_ndkState = Okay;
|
||||
Utils::FileName platformPath = m_androidConfig.ndkLocation();
|
||||
Utils::FileName toolChainPath = m_androidConfig.ndkLocation();
|
||||
Utils::FileName sourcesPath = m_androidConfig.ndkLocation();
|
||||
if (m_androidConfig.ndkLocation().isEmpty()) {
|
||||
m_ndkState = NotSet;
|
||||
} else if (!platformPath.appendPath(QLatin1String("platforms")).exists()
|
||||
|| !toolChainPath.appendPath(QLatin1String("toolchains")).exists()
|
||||
|| !sourcesPath.appendPath(QLatin1String("sources/cxx-stl")).exists()) {
|
||||
m_ndkState = Error;
|
||||
m_ndkErrorMessage = tr("\"%1\" does not seem to be an Android NDK top folder.")
|
||||
.arg(m_androidConfig.ndkLocation().toUserOutput());
|
||||
} else if (platformPath.toString().contains(QLatin1Char(' '))) {
|
||||
m_ndkState = Error;
|
||||
m_ndkErrorMessage = tr("The Android NDK cannot be installed into a path with spaces.");
|
||||
} else {
|
||||
QList<AndroidToolChainFactory::AndroidToolChainInformation> compilerPaths
|
||||
= AndroidToolChainFactory::toolchainPathsForNdk(m_androidConfig.ndkLocation());
|
||||
m_ndkCompilerCount = compilerPaths.count();
|
||||
|
||||
// See if we have qt versions for those toolchains
|
||||
QSet<ProjectExplorer::Abi> toolchainsForAbi;
|
||||
foreach (const AndroidToolChainFactory::AndroidToolChainInformation &ati, compilerPaths) {
|
||||
if (ati.language == Core::Id(ProjectExplorer::Constants::CXX_LANGUAGE_ID))
|
||||
toolchainsForAbi.insert(ati.abi);
|
||||
}
|
||||
|
||||
const QList<QtSupport::BaseQtVersion *> androidQts
|
||||
= QtSupport::QtVersionManager::versions([](const QtSupport::BaseQtVersion *v) {
|
||||
return v->type() == QLatin1String(Constants::ANDROIDQT) && !v->qtAbis().isEmpty();
|
||||
});
|
||||
QSet<ProjectExplorer::Abi> qtVersionsForAbi;
|
||||
foreach (QtSupport::BaseQtVersion *qtVersion, androidQts)
|
||||
qtVersionsForAbi.insert(qtVersion->qtAbis().first());
|
||||
|
||||
QSet<ProjectExplorer::Abi> missingQtArchs = toolchainsForAbi.subtract(qtVersionsForAbi);
|
||||
if (missingQtArchs.isEmpty()) {
|
||||
m_ndkMissingQtArchs.clear();
|
||||
} else {
|
||||
if (missingQtArchs.count() == 1) {
|
||||
m_ndkMissingQtArchs = tr("Qt version for architecture %1 is missing.\n"
|
||||
"To add the Qt version, select Options > Build & Run > Qt Versions.")
|
||||
.arg((*missingQtArchs.constBegin()).toString());
|
||||
} else {
|
||||
m_ndkMissingQtArchs = tr("Qt versions for %n architectures are missing.\n"
|
||||
"To add the Qt versions, select Options > Build & Run > Qt Versions.",
|
||||
nullptr, missingQtArchs.size());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (mode & Java) {
|
||||
m_javaState = Okay;
|
||||
if (m_androidConfig.openJDKLocation().isEmpty()) {
|
||||
m_javaState = NotSet;
|
||||
} else {
|
||||
Utils::FileName bin = m_androidConfig.openJDKLocation();
|
||||
bin.appendPath(QLatin1String("bin/javac" QTC_HOST_EXE_SUFFIX));
|
||||
if (!m_androidConfig.openJDKLocation().exists() || !bin.exists())
|
||||
m_javaState = Error;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AndroidSettingsWidget::applyToUi(AndroidSettingsWidget::Mode mode)
|
||||
{
|
||||
if (mode & Sdk) {
|
||||
if (m_sdkState == Error) {
|
||||
m_ui->sdkWarningIconLabel->setVisible(true);
|
||||
m_ui->sdkWarningLabel->setVisible(true);
|
||||
m_ui->sdkWarningLabel->setText(m_sdkInstallationError);
|
||||
} else {
|
||||
m_ui->sdkWarningIconLabel->setVisible(false);
|
||||
m_ui->sdkWarningLabel->setVisible(false);
|
||||
}
|
||||
}
|
||||
|
||||
if (mode & Ndk) {
|
||||
if (m_ndkState == NotSet) {
|
||||
m_ui->ndkWarningIconLabel->setVisible(false);
|
||||
m_ui->toolchainFoundLabel->setVisible(false);
|
||||
m_ui->kitWarningIconLabel->setVisible(false);
|
||||
m_ui->kitWarningLabel->setVisible(false);
|
||||
} else if (m_ndkState == Error) {
|
||||
m_ui->toolchainFoundLabel->setText(m_ndkErrorMessage);
|
||||
m_ui->toolchainFoundLabel->setVisible(true);
|
||||
m_ui->ndkWarningIconLabel->setVisible(true);
|
||||
m_ui->kitWarningIconLabel->setVisible(false);
|
||||
m_ui->kitWarningLabel->setVisible(false);
|
||||
} else {
|
||||
if (m_ndkCompilerCount > 0) {
|
||||
m_ui->ndkWarningIconLabel->setVisible(false);
|
||||
m_ui->toolchainFoundLabel->setText(tr("Found %n toolchains for this NDK.", 0, m_ndkCompilerCount));
|
||||
m_ui->toolchainFoundLabel->setVisible(true);
|
||||
} else {
|
||||
m_ui->ndkWarningIconLabel->setVisible(false);
|
||||
m_ui->toolchainFoundLabel->setVisible(false);
|
||||
}
|
||||
|
||||
if (m_ndkMissingQtArchs.isEmpty()) {
|
||||
m_ui->kitWarningIconLabel->setVisible(false);
|
||||
m_ui->kitWarningLabel->setVisible(false);
|
||||
} else {
|
||||
m_ui->kitWarningIconLabel->setVisible(true);
|
||||
m_ui->kitWarningLabel->setVisible(true);
|
||||
m_ui->kitWarningLabel->setText(m_ndkMissingQtArchs);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (mode & Java) {
|
||||
Utils::FileName location = m_androidConfig.openJDKLocation();
|
||||
bool error = m_javaState == Error;
|
||||
m_ui->jdkWarningIconLabel->setVisible(error);
|
||||
m_ui->jdkWarningLabel->setVisible(error);
|
||||
if (error)
|
||||
m_ui->jdkWarningLabel->setText(tr("\"%1\" does not seem to be a JDK folder.").arg(location.toUserOutput()));
|
||||
}
|
||||
|
||||
if (mode & Sdk || mode & Java) {
|
||||
if (m_sdkState == Okay && m_javaState == Okay) {
|
||||
m_ui->AVDManagerFrame->setEnabled(true);
|
||||
} else {
|
||||
m_ui->AVDManagerFrame->setEnabled(false);
|
||||
}
|
||||
|
||||
startUpdateAvd();
|
||||
}
|
||||
}
|
||||
|
||||
void AndroidSettingsWidget::disableAvdControls()
|
||||
{
|
||||
m_ui->AVDAddPushButton->setEnabled(false);
|
||||
@@ -371,75 +369,89 @@ void AndroidSettingsWidget::updateAvds()
|
||||
enableAvdControls();
|
||||
}
|
||||
|
||||
bool AndroidSettingsWidget::verifySdkInstallation(QString *errorDetails) const
|
||||
{
|
||||
if (m_androidConfig.sdkLocation().isEmpty()) {
|
||||
if (errorDetails)
|
||||
*errorDetails = tr("Android SDK path not set.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!m_androidConfig.sdkLocation().exists()) {
|
||||
if (errorDetails)
|
||||
*errorDetails = tr("Android SDK path does not exist.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (m_androidConfig.sdkToolsVersion().isNull()) {
|
||||
if (errorDetails)
|
||||
*errorDetails = tr("The SDK path does not seem to be a valid Android SDK top folder.");
|
||||
return false;
|
||||
}
|
||||
|
||||
QStringList missingComponents;
|
||||
if (!m_androidConfig.adbToolPath().exists())
|
||||
missingComponents << "Platform Tools";
|
||||
|
||||
if (m_androidConfig.buildToolsVersion().isNull())
|
||||
missingComponents << "Build Tools";
|
||||
|
||||
if (m_androidConfig.sdkTargets().isEmpty())
|
||||
missingComponents << "Platform SDK";
|
||||
|
||||
if (!missingComponents.isEmpty() && errorDetails) {
|
||||
*errorDetails = tr("Android SDK components missing (%1).\nUse Android SDK Manager to "
|
||||
"manage SDK components.").arg(missingComponents.join(", "));
|
||||
}
|
||||
|
||||
return missingComponents.isEmpty();
|
||||
}
|
||||
|
||||
void AndroidSettingsWidget::saveSettings()
|
||||
{
|
||||
sdkLocationEditingFinished();
|
||||
ndkLocationEditingFinished();
|
||||
openJDKLocationEditingFinished();
|
||||
dataPartitionSizeEditingFinished();
|
||||
AndroidConfigurations::setConfig(m_androidConfig);
|
||||
}
|
||||
|
||||
void AndroidSettingsWidget::sdkLocationEditingFinished()
|
||||
void AndroidSettingsWidget::validateJdk()
|
||||
{
|
||||
m_androidConfig.setSdkLocation(Utils::FileName::fromUserInput(m_ui->SDKLocationPathChooser->rawPath()));
|
||||
auto javaPath = Utils::FileName::fromUserInput(m_ui->OpenJDKLocationPathChooser->rawPath());
|
||||
m_androidConfig.setOpenJDKLocation(javaPath);
|
||||
bool jdkPathExists = m_androidConfig.openJDKLocation().exists();
|
||||
auto summaryWidget = static_cast<SummaryWidget *>(m_ui->javaDetailsWidget->widget());
|
||||
summaryWidget->setPointValid(JavaPathExistsRow, jdkPathExists);
|
||||
|
||||
check(Sdk);
|
||||
applyToUi(Sdk);
|
||||
Utils::FileName bin = m_androidConfig.openJDKLocation();
|
||||
bin.appendPath(QLatin1String("bin/javac" QTC_HOST_EXE_SUFFIX));
|
||||
summaryWidget->setPointValid(JavaJdkValidRow, jdkPathExists && bin.exists());
|
||||
updateUI();
|
||||
}
|
||||
|
||||
void AndroidSettingsWidget::ndkLocationEditingFinished()
|
||||
void AndroidSettingsWidget::validateNdk()
|
||||
{
|
||||
m_androidConfig.setNdkLocation(Utils::FileName::fromUserInput(m_ui->NDKLocationPathChooser->rawPath()));
|
||||
auto ndkPath = Utils::FileName::fromUserInput(m_ui->NDKLocationPathChooser->rawPath());
|
||||
m_androidConfig.setNdkLocation(ndkPath);
|
||||
|
||||
check(Ndk);
|
||||
applyToUi(Ndk);
|
||||
auto summaryWidget = static_cast<SummaryWidget *>(m_ui->androidDetailsWidget->widget());
|
||||
summaryWidget->setPointValid(NdkPathExistsRow, m_androidConfig.ndkLocation().exists());
|
||||
|
||||
Utils::FileName ndkPlatformsDir(ndkPath);
|
||||
ndkPlatformsDir.appendPath("platforms");
|
||||
Utils::FileName ndkToolChainsDir(ndkPath);
|
||||
ndkToolChainsDir.appendPath("toolchains");
|
||||
Utils::FileName ndkSourcesDir(ndkPath);
|
||||
ndkSourcesDir.appendPath("sources/cxx-stl");
|
||||
summaryWidget->setPointValid(NdkDirStructureRow,
|
||||
ndkPlatformsDir.exists()
|
||||
&& ndkToolChainsDir.exists()
|
||||
&& ndkSourcesDir.exists());
|
||||
summaryWidget->setPointValid(NdkinstallDirOkRow,
|
||||
ndkPlatformsDir.exists() &&
|
||||
!ndkPlatformsDir.toString().contains(' '));
|
||||
updateUI();
|
||||
}
|
||||
|
||||
void AndroidSettingsWidget::openJDKLocationEditingFinished()
|
||||
void AndroidSettingsWidget::onSdkPathChanged()
|
||||
{
|
||||
m_androidConfig.setOpenJDKLocation(Utils::FileName::fromUserInput(m_ui->OpenJDKLocationPathChooser->rawPath()));
|
||||
auto sdkPath = Utils::FileName::fromUserInput(m_ui->SDKLocationPathChooser->rawPath());
|
||||
m_androidConfig.setSdkLocation(sdkPath);
|
||||
// Package reload will trigger validateSdk.
|
||||
m_sdkManager->reloadPackages();
|
||||
}
|
||||
|
||||
check(Java);
|
||||
applyToUi(Java);
|
||||
void AndroidSettingsWidget::validateSdk()
|
||||
{
|
||||
auto summaryWidget = static_cast<SummaryWidget *>(m_ui->androidDetailsWidget->widget());
|
||||
summaryWidget->setPointValid(SdkPathExistsRow, m_androidConfig.sdkLocation().exists());
|
||||
summaryWidget->setPointValid(SdkToolsInstalledRow,
|
||||
!m_androidConfig.sdkToolsVersion().isNull());
|
||||
summaryWidget->setPointValid(PlatformToolsInstalledRow,
|
||||
m_androidConfig.adbToolPath().exists());
|
||||
summaryWidget->setPointValid(BuildToolsInstalledRow,
|
||||
!m_androidConfig.buildToolsVersion().isNull());
|
||||
|
||||
// installedSdkPlatforms should not trigger a package reload as validate SDK is only called
|
||||
// after AndroidSdkManager::packageReloadFinished.
|
||||
summaryWidget->setPointValid(PlatformSdkInstalledRow,
|
||||
!m_sdkManager->installedSdkPlatforms().isEmpty());
|
||||
updateUI();
|
||||
bool sdkToolsOk = summaryWidget->rowsOk({SdkPathExistsRow, SdkToolsInstalledRow});
|
||||
bool componentsOk = summaryWidget->rowsOk({PlatformToolsInstalledRow,
|
||||
BuildToolsInstalledRow,
|
||||
PlatformSdkInstalledRow});
|
||||
|
||||
if (sdkToolsOk && !componentsOk && !m_androidConfig.useNativeUiTools()) {
|
||||
// Ask user to install essential SDK components. Works only for sdk tools version >= 26.0.0
|
||||
QString message = tr("Android SDK installation is missing necessary packages. Do you "
|
||||
"want to install the missing packages?");
|
||||
auto userInput = QMessageBox::information(this, tr("Missing Android SDK packages"),
|
||||
message, QMessageBox::Yes | QMessageBox::No);
|
||||
if (userInput == QMessageBox::Yes) {
|
||||
m_ui->managerTabWidget->setCurrentWidget(m_ui->sdkManagerTab);
|
||||
m_sdkManagerWidget->installEssentials();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AndroidSettingsWidget::openSDKDownloadUrl()
|
||||
@@ -460,9 +472,9 @@ void AndroidSettingsWidget::openOpenJDKDownloadUrl()
|
||||
void AndroidSettingsWidget::addAVD()
|
||||
{
|
||||
disableAvdControls();
|
||||
AndroidConfig::CreateAvdInfo info = m_androidConfig.gatherCreateAVDInfo(this);
|
||||
CreateAvdInfo info = AvdDialog::gatherCreateAVDInfo(this, m_sdkManager.get());
|
||||
|
||||
if (!info.target.isValid()) {
|
||||
if (!info.isValid()) {
|
||||
enableAvdControls();
|
||||
return;
|
||||
}
|
||||
@@ -472,7 +484,7 @@ void AndroidSettingsWidget::addAVD()
|
||||
|
||||
void AndroidSettingsWidget::avdAdded()
|
||||
{
|
||||
AndroidConfig::CreateAvdInfo info = m_futureWatcher.result();
|
||||
CreateAvdInfo info = m_futureWatcher.result();
|
||||
if (!info.error.isEmpty()) {
|
||||
enableAvdControls();
|
||||
QMessageBox::critical(this, QApplication::translate("AndroidConfig", "Error Creating AVD"), info.error);
|
||||
@@ -520,9 +532,76 @@ void AndroidSettingsWidget::createKitToggled()
|
||||
m_androidConfig.setAutomaticKitCreation(m_ui->CreateKitCheckBox->isChecked());
|
||||
}
|
||||
|
||||
void AndroidSettingsWidget::checkMissingQtVersion()
|
||||
{
|
||||
auto summaryWidget = static_cast<SummaryWidget *>(m_ui->androidDetailsWidget->widget());
|
||||
if (!summaryWidget->allRowsOk()) {
|
||||
m_ui->kitWarningDetails->setVisible(false);
|
||||
m_ui->kitWarningDetails->setState(Utils::DetailsWidget::Collapsed);
|
||||
return;
|
||||
}
|
||||
|
||||
QList<AndroidToolChainFactory::AndroidToolChainInformation> compilerPaths
|
||||
= AndroidToolChainFactory::toolchainPathsForNdk(m_androidConfig.ndkLocation());
|
||||
|
||||
// See if we have qt versions for those toolchains
|
||||
QSet<ProjectExplorer::Abi> toolchainsForAbi;
|
||||
foreach (const AndroidToolChainFactory::AndroidToolChainInformation &ati, compilerPaths) {
|
||||
if (ati.language == Core::Id(ProjectExplorer::Constants::CXX_LANGUAGE_ID))
|
||||
toolchainsForAbi.insert(ati.abi);
|
||||
}
|
||||
|
||||
const QList<QtSupport::BaseQtVersion *> androidQts
|
||||
= QtSupport::QtVersionManager::versions([](const QtSupport::BaseQtVersion *v) {
|
||||
return v->type() == QLatin1String(Constants::ANDROIDQT) && !v->qtAbis().isEmpty();
|
||||
});
|
||||
QSet<ProjectExplorer::Abi> qtVersionsForAbi;
|
||||
foreach (QtSupport::BaseQtVersion *qtVersion, androidQts)
|
||||
qtVersionsForAbi.insert(qtVersion->qtAbis().first());
|
||||
|
||||
QSet<ProjectExplorer::Abi> missingQtArchs = toolchainsForAbi.subtract(qtVersionsForAbi);
|
||||
bool isArchMissing = !missingQtArchs.isEmpty();
|
||||
m_ui->kitWarningDetails->setVisible(isArchMissing);
|
||||
if (isArchMissing) {
|
||||
m_ui->kitWarningDetails->setSummaryText(tr("Cannot create kits for all architectures."));
|
||||
QLabel *detailsLabel = static_cast<QLabel *>(m_ui->kitWarningDetails->widget());
|
||||
QStringList archNames;
|
||||
for (auto abi : missingQtArchs)
|
||||
archNames << abi.toString();
|
||||
detailsLabel->setText(tr("Qt versions are missing for the following architectures:\n%1"
|
||||
"\n\nTo add the Qt version, select Options > Build & Run > Qt"
|
||||
" Versions.").arg(archNames.join(", ")));
|
||||
}
|
||||
}
|
||||
|
||||
void AndroidSettingsWidget::updateUI()
|
||||
{
|
||||
auto javaSummaryWidget = static_cast<SummaryWidget *>(m_ui->javaDetailsWidget->widget());
|
||||
auto androidSummaryWidget = static_cast<SummaryWidget *>(m_ui->androidDetailsWidget->widget());
|
||||
bool javaSetupOk = javaSummaryWidget->allRowsOk();
|
||||
bool sdkToolsOk = androidSummaryWidget->rowsOk({SdkPathExistsRow, SdkToolsInstalledRow});
|
||||
bool androidSetupOk = androidSummaryWidget->allRowsOk();
|
||||
|
||||
m_ui->avdManagerTab->setEnabled(javaSetupOk && androidSetupOk);
|
||||
m_ui->sdkManagerTab->setEnabled(sdkToolsOk);
|
||||
m_sdkManagerWidget->setSdkManagerControlsEnabled(!m_androidConfig.useNativeUiTools());
|
||||
|
||||
auto infoText = tr("(SDK Version: %1, NDK Version: %2)")
|
||||
.arg(m_androidConfig.sdkToolsVersion().toString())
|
||||
.arg(m_androidConfig.ndkVersion().toString());
|
||||
androidSummaryWidget->setInfoText(androidSetupOk ? infoText : "");
|
||||
|
||||
m_ui->javaDetailsWidget->setState(javaSetupOk ? Utils::DetailsWidget::Collapsed :
|
||||
Utils::DetailsWidget::Expanded);
|
||||
m_ui->androidDetailsWidget->setState(androidSetupOk ? Utils::DetailsWidget::Collapsed :
|
||||
Utils::DetailsWidget::Expanded);
|
||||
startUpdateAvd();
|
||||
checkMissingQtVersion();
|
||||
}
|
||||
|
||||
void AndroidSettingsWidget::manageAVD()
|
||||
{
|
||||
if (m_avdManager->avdManagerUiToolAvailable()) {
|
||||
if (m_androidConfig.useNativeUiTools()) {
|
||||
m_avdManager->launchAvdManagerUiTool();
|
||||
} else {
|
||||
QMessageBox::warning(this, tr("AVD Manager Not Available"),
|
||||
|
||||
@@ -42,6 +42,8 @@ QT_END_NAMESPACE
|
||||
namespace Android {
|
||||
namespace Internal {
|
||||
|
||||
class AndroidSdkManagerWidget;
|
||||
|
||||
class AndroidAvdManager;
|
||||
|
||||
class AvdModel: public QAbstractTableModel
|
||||
@@ -73,9 +75,10 @@ public:
|
||||
void saveSettings();
|
||||
|
||||
private:
|
||||
void sdkLocationEditingFinished();
|
||||
void ndkLocationEditingFinished();
|
||||
void openJDKLocationEditingFinished();
|
||||
void validateJdk();
|
||||
void validateNdk();
|
||||
void onSdkPathChanged();
|
||||
void validateSdk();
|
||||
void openSDKDownloadUrl();
|
||||
void openNDKDownloadUrl();
|
||||
void openOpenJDKDownloadUrl();
|
||||
@@ -88,34 +91,25 @@ private:
|
||||
void manageAVD();
|
||||
void createKitToggled();
|
||||
|
||||
void checkMissingQtVersion();
|
||||
void updateUI();
|
||||
void updateAvds();
|
||||
|
||||
private:
|
||||
enum Mode { Sdk = 1, Ndk = 2, Java = 4, All = Sdk | Ndk | Java };
|
||||
enum State { NotSet = 0, Okay = 1, Error = 2 };
|
||||
bool verifySdkInstallation(QString *errorDetails = nullptr) const;
|
||||
void check(Mode mode);
|
||||
void applyToUi(Mode mode);
|
||||
void startUpdateAvd();
|
||||
void enableAvdControls();
|
||||
void disableAvdControls();
|
||||
|
||||
State m_sdkState;
|
||||
QString m_sdkInstallationError;
|
||||
State m_ndkState;
|
||||
QString m_ndkErrorMessage;
|
||||
int m_ndkCompilerCount;
|
||||
QString m_ndkMissingQtArchs;
|
||||
State m_javaState;
|
||||
|
||||
Ui_AndroidSettingsWidget *m_ui;
|
||||
AndroidSdkManagerWidget *m_sdkManagerWidget = nullptr;
|
||||
AndroidConfig m_androidConfig;
|
||||
AvdModel m_AVDModel;
|
||||
QFutureWatcher<AndroidConfig::CreateAvdInfo> m_futureWatcher;
|
||||
QFutureWatcher<CreateAvdInfo> m_futureWatcher;
|
||||
|
||||
QFutureWatcher<AndroidDeviceInfoList> m_virtualDevicesWatcher;
|
||||
QString m_lastAddedAvd;
|
||||
std::unique_ptr<AndroidAvdManager> m_avdManager;
|
||||
std::unique_ptr<AndroidSdkManager> m_sdkManager;
|
||||
};
|
||||
|
||||
} // namespace Internal
|
||||
|
||||
@@ -6,382 +6,348 @@
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>843</width>
|
||||
<height>625</height>
|
||||
<width>1131</width>
|
||||
<height>826</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Android Configuration</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="9" column="0" colspan="2">
|
||||
<widget class="QFrame" name="AVDManagerFrame">
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::StyledPanel</enum>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<property name="leftMargin">
|
||||
<number>4</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>4</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>4</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>4</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="javaSettingsGroup">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Raised</enum>
|
||||
<property name="title">
|
||||
<string>Java Settings</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_2">
|
||||
<item row="3" column="1">
|
||||
<widget class="QPushButton" name="AVDStartPushButton">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="0" column="1">
|
||||
<widget class="Utils::PathChooser" name="OpenJDKLocationPathChooser" native="true">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="2">
|
||||
<widget class="QToolButton" name="downloadOpenJDKToolButton">
|
||||
<property name="toolTip">
|
||||
<string>Download JDK</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="android.qrc">
|
||||
<normaloff>:/android/images/download.png</normaloff>:/android/images/download.png</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="OpenJDKLocationLabel">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Start...</string>
|
||||
<string>JDK location:</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0" colspan="2">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="AVDManagerLabel">
|
||||
<property name="text">
|
||||
<string>AVD Manager</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="DataPartitionSizeLable">
|
||||
<property name="text">
|
||||
<string>System/data partition size:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QSpinBox" name="DataPartitionSizeSpinBox">
|
||||
<property name="suffix">
|
||||
<string> Mb</string>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>99999</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>1024</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="manageAVDPushButton">
|
||||
<property name="text">
|
||||
<string>Start AVD Manager...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QPushButton" name="AVDRemovePushButton">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Remove</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QPushButton" name="AVDAddPushButton">
|
||||
<property name="text">
|
||||
<string>Add...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0" rowspan="4">
|
||||
<widget class="QTableView" name="AVDTableView">
|
||||
<property name="selectionMode">
|
||||
<enum>QAbstractItemView::SingleSelection</enum>
|
||||
</property>
|
||||
<property name="selectionBehavior">
|
||||
<enum>QAbstractItemView::SelectRows</enum>
|
||||
</property>
|
||||
<property name="textElideMode">
|
||||
<enum>Qt::ElideMiddle</enum>
|
||||
</property>
|
||||
<attribute name="verticalHeaderVisible">
|
||||
<bool>false</bool>
|
||||
</attribute>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="1">
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<item row="1" column="0" colspan="3">
|
||||
<widget class="Utils::DetailsWidget" name="javaDetailsWidget" native="true">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>129</height>
|
||||
<width>0</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="Utils::PathChooser" name="OpenJDKLocationPathChooser" native="true"/>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="Utils::PathChooser" name="SDKLocationPathChooser" native="true"/>
|
||||
</item>
|
||||
<item row="4" column="1">
|
||||
<widget class="Utils::PathChooser" name="NDKLocationPathChooser" native="true"/>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_5">
|
||||
<item>
|
||||
<widget class="QLabel" name="jdkWarningIconLabel">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="jdkWarningLabel">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="4" column="2">
|
||||
<widget class="QToolButton" name="downloadNDKToolButton">
|
||||
<property name="toolTip">
|
||||
<string>Download Android NDK</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="android.qrc">
|
||||
<normaloff>:/android/images/download.png</normaloff>:/android/images/download.png</iconset>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox">
|
||||
<property name="title">
|
||||
<string>Android Settings</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_3">
|
||||
<item row="1" column="1">
|
||||
<widget class="Utils::PathChooser" name="NDKLocationPathChooser" native="true"/>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="Utils::PathChooser" name="SDKLocationPathChooser" native="true">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="2">
|
||||
<widget class="QToolButton" name="downloadNDKToolButton">
|
||||
<property name="toolTip">
|
||||
<string>Download Android NDK</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="android.qrc">
|
||||
<normaloff>:/android/images/download.png</normaloff>:/android/images/download.png</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="NDKLocationLabel">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Android NDK location:</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="SDKLocationLabel">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Android SDK location:</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="2">
|
||||
<widget class="QToolButton" name="downloadSDKToolButton">
|
||||
<property name="toolTip">
|
||||
<string>Download Android SDK</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="android.qrc">
|
||||
<normaloff>:/android/images/download.png</normaloff>:/android/images/download.png</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0" colspan="3">
|
||||
<widget class="Utils::DetailsWidget" name="androidDetailsWidget" native="true"/>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="SDKLocationLabel">
|
||||
<item>
|
||||
<widget class="QCheckBox" name="CreateKitCheckBox">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Android SDK location:</string>
|
||||
<string>Automatically create kits for Android tool chains</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
<property name="checked">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="2">
|
||||
<widget class="QToolButton" name="downloadOpenJDKToolButton">
|
||||
<property name="toolTip">
|
||||
<string>Download JDK</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="android.qrc">
|
||||
<normaloff>:/android/images/download.png</normaloff>:/android/images/download.png</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
<item>
|
||||
<widget class="Utils::DetailsWidget" name="kitWarningDetails" native="true"/>
|
||||
</item>
|
||||
<item row="2" column="2">
|
||||
<widget class="QToolButton" name="downloadSDKToolButton">
|
||||
<property name="toolTip">
|
||||
<string>Download Android SDK</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="android.qrc">
|
||||
<normaloff>:/android/images/download.png</normaloff>:/android/images/download.png</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="8" column="1">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<property name="spacing">
|
||||
<number>2</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QLabel" name="kitWarningIconLabel">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="kitWarningLabel">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="7" column="1">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_8">
|
||||
<property name="spacing">
|
||||
<number>2</number>
|
||||
</property>
|
||||
<property name="leftMargin">
|
||||
<item>
|
||||
<widget class="QTabWidget" name="managerTabWidget">
|
||||
<property name="currentIndex">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="CreateKitCheckBox">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
<widget class="QWidget" name="avdManagerTab">
|
||||
<attribute name="title">
|
||||
<string>AVD Manager</string>
|
||||
</attribute>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Automatically create kits for Android tool chains</string>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>true</bool>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="4" column="0">
|
||||
<widget class="QLabel" name="NDKLocationLabel">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Android NDK location:</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="1">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_3">
|
||||
<property name="spacing">
|
||||
<number>2</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QLabel" name="ndkWarningIconLabel">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="toolchainFoundLabel">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_4">
|
||||
<item>
|
||||
<widget class="QLabel" name="sdkWarningIconLabel">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="sdkWarningLabel">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="OpenJDKLocationLabel">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>JDK location:</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QTableView" name="AVDTableView">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="selectionMode">
|
||||
<enum>QAbstractItemView::SingleSelection</enum>
|
||||
</property>
|
||||
<property name="selectionBehavior">
|
||||
<enum>QAbstractItemView::SelectRows</enum>
|
||||
</property>
|
||||
<property name="textElideMode">
|
||||
<enum>Qt::ElideMiddle</enum>
|
||||
</property>
|
||||
<attribute name="verticalHeaderVisible">
|
||||
<bool>false</bool>
|
||||
</attribute>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<item>
|
||||
<widget class="QLabel" name="DataPartitionSizeLable">
|
||||
<property name="text">
|
||||
<string>System/data partition size:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QSpinBox" name="DataPartitionSizeSpinBox">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="suffix">
|
||||
<string> Mb</string>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>99999</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>1024</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="AVDAddPushButton">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Add...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::Fixed</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>8</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="AVDRemovePushButton">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Remove</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="AVDStartPushButton">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Start...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="nativeAvdManagerButton">
|
||||
<property name="text">
|
||||
<string>Native AVD Manager...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="sdkManagerTab">
|
||||
<attribute name="title">
|
||||
<string>SDK Manager</string>
|
||||
</attribute>
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
@@ -393,6 +359,12 @@
|
||||
<header location="global">utils/pathchooser.h</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>Utils::DetailsWidget</class>
|
||||
<extends>QWidget</extends>
|
||||
<header location="global">utils/detailswidget.h</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources>
|
||||
<include location="android.qrc"/>
|
||||
|
||||
@@ -47,7 +47,7 @@ class AndroidToolOutputParser
|
||||
{
|
||||
public:
|
||||
void parseTargetListing(const QString &output, const FileName &sdkLocation,
|
||||
SdkPlatformList *platformList);
|
||||
SdkPlatformList &platformList);
|
||||
|
||||
QList<SdkPlatform> m_installedPlatforms;
|
||||
};
|
||||
@@ -104,7 +104,7 @@ SdkPlatformList AndroidToolManager::availableSdkPlatforms(bool *ok) const
|
||||
QString targetListing;
|
||||
if (androidToolCommand(m_config.androidToolPath(), QStringList({"list", "target"}),
|
||||
androidToolEnvironment(), &targetListing)) {
|
||||
m_parser->parseTargetListing(targetListing, m_config.sdkLocation(), &list);
|
||||
m_parser->parseTargetListing(targetListing, m_config.sdkLocation(), list);
|
||||
success = true;
|
||||
} else {
|
||||
qCDebug(androidToolLog) << "Android tool target listing failed";
|
||||
@@ -121,8 +121,7 @@ void AndroidToolManager::launchAvdManager() const
|
||||
QProcess::startDetached(m_config.androidToolPath().toString(), QStringList("avd"));
|
||||
}
|
||||
|
||||
QFuture<AndroidConfig::CreateAvdInfo>
|
||||
AndroidToolManager::createAvd(AndroidConfig::CreateAvdInfo info) const
|
||||
QFuture<CreateAvdInfo> AndroidToolManager::createAvd(CreateAvdInfo info) const
|
||||
{
|
||||
return Utils::runAsync(&AndroidToolManager::createAvdImpl, info,
|
||||
m_config.androidToolPath(), androidToolEnvironment());
|
||||
@@ -159,15 +158,14 @@ Environment AndroidToolManager::androidToolEnvironment() const
|
||||
return env;
|
||||
}
|
||||
|
||||
AndroidConfig::CreateAvdInfo AndroidToolManager::createAvdImpl(AndroidConfig::CreateAvdInfo info,
|
||||
FileName androidToolPath,
|
||||
Environment env)
|
||||
CreateAvdInfo AndroidToolManager::createAvdImpl(CreateAvdInfo info, FileName androidToolPath,
|
||||
Environment env)
|
||||
{
|
||||
QProcess proc;
|
||||
proc.setProcessEnvironment(env.toProcessEnvironment());
|
||||
QStringList arguments;
|
||||
arguments << QLatin1String("create") << QLatin1String("avd")
|
||||
<< QLatin1String("-t") << AndroidConfig::apiLevelNameFor(info.target)
|
||||
<< QLatin1String("-t") << AndroidConfig::apiLevelNameFor(info.sdkPlatform)
|
||||
<< QLatin1String("-n") << info.name
|
||||
<< QLatin1String("-b") << info.abi;
|
||||
if (info.sdcardSize > 0)
|
||||
@@ -293,24 +291,36 @@ AndroidDeviceInfoList AndroidToolManager::androidVirtualDevices(const Utils::Fil
|
||||
|
||||
void AndroidToolOutputParser::parseTargetListing(const QString &output,
|
||||
const Utils::FileName &sdkLocation,
|
||||
SdkPlatformList *platformList)
|
||||
SdkPlatformList &platformList)
|
||||
{
|
||||
if (!platformList)
|
||||
return;
|
||||
|
||||
auto addSystemImage = [](const QStringList& abiList, SdkPlatform &platform) {
|
||||
auto addSystemImage = [](const QStringList& abiList, SdkPlatform *platform) {
|
||||
QTC_ASSERT(platform, return);
|
||||
foreach (auto imageAbi, abiList) {
|
||||
SystemImage image;
|
||||
image.abiName = imageAbi;
|
||||
image.apiLevel = platform.apiLevel;
|
||||
platform.systemImages.append(image);
|
||||
auto image = new SystemImage(QVersionNumber(), "", imageAbi, platform);
|
||||
platform->addSystemImage(image);
|
||||
}
|
||||
};
|
||||
|
||||
SdkPlatform platform;
|
||||
QStringList abiList;
|
||||
foreach (const QString &l, output.split('\n')) {
|
||||
const QString line = l.trimmed();
|
||||
class {
|
||||
public:
|
||||
QStringList abiList;
|
||||
QVersionNumber revision;
|
||||
int apiLevel = -1;
|
||||
QString description;
|
||||
Utils::FileName installedLocation;
|
||||
|
||||
void clear() {
|
||||
abiList.clear();
|
||||
revision = QVersionNumber();
|
||||
apiLevel = -1;
|
||||
description.clear();
|
||||
installedLocation.clear();
|
||||
}
|
||||
} platformParams;
|
||||
|
||||
QStringList outputLines = output.split('\n');
|
||||
for (int index = 0; index < outputLines.count(); ++index) {
|
||||
const QString line = outputLines.at(index).trimmed();
|
||||
if (line.startsWith(QLatin1String("id:")) && line.contains(QLatin1String("android-"))) {
|
||||
int index = line.indexOf(QLatin1String("\"android-"));
|
||||
if (index == -1)
|
||||
@@ -319,33 +329,33 @@ void AndroidToolOutputParser::parseTargetListing(const QString &output,
|
||||
const QString tmp = androidTarget.mid(androidTarget.lastIndexOf(QLatin1Char('-')) + 1);
|
||||
Utils::FileName platformPath = sdkLocation;
|
||||
platformPath.appendPath(QString("/platforms/android-%1").arg(tmp));
|
||||
platform.installedLocation = platformPath;
|
||||
platform.apiLevel = AndroidManager::findApiLevel(platformPath);
|
||||
platformParams.installedLocation = platformPath;
|
||||
platformParams.apiLevel = AndroidManager::findApiLevel(platformPath);
|
||||
} else if (line.startsWith(QLatin1String("Name:"))) {
|
||||
platform.name = line.mid(6);
|
||||
platformParams.description = line.mid(6);
|
||||
} else if (line.startsWith(QLatin1String("Revision:"))) {
|
||||
platformParams.revision = QVersionNumber::fromString(line.mid(10));
|
||||
} else if (line.startsWith(QLatin1String("Tag/ABIs :"))) {
|
||||
abiList = cleanAndroidABIs(line.mid(10).trimmed().split(QLatin1String(", ")));
|
||||
platformParams.abiList = cleanAndroidABIs(line.mid(10).trimmed().split(QLatin1String(", ")));
|
||||
} else if (line.startsWith(QLatin1String("ABIs"))) {
|
||||
abiList = cleanAndroidABIs(line.mid(6).trimmed().split(QLatin1String(", ")));
|
||||
} else if (line.startsWith(QLatin1String("---")) || line.startsWith(QLatin1String("==="))) {
|
||||
if (platform.apiLevel == -1)
|
||||
platformParams.abiList = cleanAndroidABIs(line.mid(6).trimmed().split(QLatin1String(", ")));
|
||||
} else if (line.startsWith(QLatin1String("---"))
|
||||
|| line.startsWith(QLatin1String("==="))
|
||||
|| index == outputLines.count() - 1) {
|
||||
if (platformParams.apiLevel == -1)
|
||||
continue;
|
||||
|
||||
addSystemImage(abiList, platform);
|
||||
*platformList << platform;
|
||||
|
||||
platform = SdkPlatform();
|
||||
abiList.clear();
|
||||
auto platform = new SdkPlatform(platformParams.revision,
|
||||
QString("platforms;android-%1").arg(platformParams.apiLevel),
|
||||
platformParams.apiLevel);
|
||||
platform->setState(AndroidSdkPackage::Installed);
|
||||
platform->setDescriptionText(platformParams.description);
|
||||
platform->setInstalledLocation(platformParams.installedLocation);
|
||||
addSystemImage(platformParams.abiList, platform);
|
||||
platformList << platform;
|
||||
platformParams.clear();
|
||||
}
|
||||
}
|
||||
|
||||
// The last parsed Platform.
|
||||
if (platform.apiLevel != -1) {
|
||||
addSystemImage(abiList, platform);
|
||||
*platformList << platform;
|
||||
}
|
||||
|
||||
Utils::sort(*platformList);
|
||||
Utils::sort(platformList);
|
||||
}
|
||||
|
||||
} // namespace Internal
|
||||
|
||||
@@ -51,15 +51,15 @@ public:
|
||||
SdkPlatformList availableSdkPlatforms(bool *ok = nullptr) const;
|
||||
void launchAvdManager() const;
|
||||
|
||||
QFuture<AndroidConfig::CreateAvdInfo> createAvd(AndroidConfig::CreateAvdInfo info) const;
|
||||
QFuture<CreateAvdInfo> createAvd(CreateAvdInfo info) const;
|
||||
bool removeAvd(const QString &name) const;
|
||||
QFuture<AndroidDeviceInfoList> androidVirtualDevicesFuture() const;
|
||||
|
||||
// Helper methods
|
||||
private:
|
||||
Utils::Environment androidToolEnvironment() const;
|
||||
static AndroidConfig::CreateAvdInfo createAvdImpl(AndroidConfig::CreateAvdInfo info,
|
||||
Utils::FileName androidToolPath, Utils::Environment env);
|
||||
static CreateAvdInfo createAvdImpl(CreateAvdInfo info, Utils::FileName androidToolPath,
|
||||
Utils::Environment env);
|
||||
static AndroidDeviceInfoList androidVirtualDevices(const Utils::FileName &androidTool,
|
||||
const Utils::FileName &sdkLlocationPath,
|
||||
const Utils::Environment &environment);
|
||||
|
||||
@@ -24,11 +24,12 @@
|
||||
****************************************************************************/
|
||||
|
||||
#include "avddialog.h"
|
||||
#include "androidconfigurations.h"
|
||||
#include "androidsdkmanager.h"
|
||||
|
||||
#include <utils/algorithm.h>
|
||||
#include <utils/tooltip/tooltip.h>
|
||||
#include <utils/utilsicons.h>
|
||||
#include <utils/qtcassert.h>
|
||||
|
||||
#include <QKeyEvent>
|
||||
#include <QMessageBox>
|
||||
@@ -37,10 +38,14 @@
|
||||
using namespace Android;
|
||||
using namespace Android::Internal;
|
||||
|
||||
AvdDialog::AvdDialog(int minApiLevel, const QString &targetArch, const AndroidConfig *config, QWidget *parent) :
|
||||
QDialog(parent), m_config(config), m_minApiLevel(minApiLevel),
|
||||
AvdDialog::AvdDialog(int minApiLevel, AndroidSdkManager *sdkManager, const QString &targetArch,
|
||||
QWidget *parent) :
|
||||
QDialog(parent),
|
||||
m_sdkManager(sdkManager),
|
||||
m_minApiLevel(minApiLevel),
|
||||
m_allowedNameChars(QLatin1String("[a-z|A-Z|0-9|._-]*"))
|
||||
{
|
||||
QTC_CHECK(m_sdkManager);
|
||||
m_avdDialog.setupUi(this);
|
||||
m_hideTipTimer.setInterval(2000);
|
||||
m_hideTipTimer.setSingleShot(true);
|
||||
@@ -70,12 +75,27 @@ AvdDialog::AvdDialog(int minApiLevel, const QString &targetArch, const AndroidCo
|
||||
|
||||
bool AvdDialog::isValid() const
|
||||
{
|
||||
return !name().isEmpty() && target().isValid() && !abi().isEmpty();
|
||||
return !name().isEmpty() && sdkPlatform() && sdkPlatform()->isValid() && !abi().isEmpty();
|
||||
}
|
||||
|
||||
SdkPlatform AvdDialog::target() const
|
||||
CreateAvdInfo AvdDialog::gatherCreateAVDInfo(QWidget *parent, AndroidSdkManager *sdkManager,
|
||||
int minApiLevel, QString targetArch)
|
||||
{
|
||||
return m_avdDialog.targetComboBox->currentData().value<SdkPlatform>();
|
||||
CreateAvdInfo result;
|
||||
AvdDialog d(minApiLevel, sdkManager, targetArch, parent);
|
||||
if (d.exec() != QDialog::Accepted || !d.isValid())
|
||||
return result;
|
||||
|
||||
result.sdkPlatform = d.sdkPlatform();
|
||||
result.name = d.name();
|
||||
result.abi = d.abi();
|
||||
result.sdcardSize = d.sdcardSize();
|
||||
return result;
|
||||
}
|
||||
|
||||
const SdkPlatform* AvdDialog::sdkPlatform() const
|
||||
{
|
||||
return m_avdDialog.targetComboBox->currentData().value<SdkPlatform*>();
|
||||
}
|
||||
|
||||
QString AvdDialog::name() const
|
||||
@@ -96,21 +116,23 @@ int AvdDialog::sdcardSize() const
|
||||
void AvdDialog::updateApiLevelComboBox()
|
||||
{
|
||||
SdkPlatformList filteredList;
|
||||
SdkPlatformList platforms = m_config->sdkTargets(m_minApiLevel);
|
||||
const SdkPlatformList platforms = m_sdkManager->filteredSdkPlatforms(m_minApiLevel);
|
||||
|
||||
QString selectedAbi = abi();
|
||||
auto hasAbi = [selectedAbi](const SystemImage &image) {
|
||||
return image.isValid() && (image.abiName == selectedAbi);
|
||||
auto hasAbi = [selectedAbi](const SystemImage *image) {
|
||||
return image && image->isValid() && (image->abiName() == selectedAbi);
|
||||
};
|
||||
|
||||
filteredList = Utils::filtered(platforms, [hasAbi](const SdkPlatform &platform) {
|
||||
return Utils::anyOf(platform.systemImages,hasAbi);
|
||||
filteredList = Utils::filtered(platforms, [hasAbi](const SdkPlatform *platform) {
|
||||
return platform && Utils::anyOf(platform->systemImages(), hasAbi);
|
||||
});
|
||||
|
||||
m_avdDialog.targetComboBox->clear();
|
||||
foreach (const SdkPlatform &platform, filteredList) {
|
||||
m_avdDialog.targetComboBox->addItem(AndroidConfig::apiLevelNameFor(platform),
|
||||
QVariant::fromValue<SdkPlatform>(platform));
|
||||
for (SdkPlatform *platform: filteredList) {
|
||||
m_avdDialog.targetComboBox->addItem(platform->displayText(),
|
||||
QVariant::fromValue<SdkPlatform *>(platform));
|
||||
m_avdDialog.targetComboBox->setItemData(m_avdDialog.targetComboBox->count() - 1,
|
||||
platform->descriptionText(), Qt::ToolTipRole);
|
||||
}
|
||||
|
||||
if (platforms.isEmpty()) {
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
****************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "androidconfigurations.h"
|
||||
#include "ui_addnewavddialog.h"
|
||||
|
||||
#include <QDialog>
|
||||
@@ -35,26 +35,28 @@ class AndroidConfig;
|
||||
class SdkPlatform;
|
||||
|
||||
namespace Internal {
|
||||
|
||||
class AndroidSdkManager;
|
||||
class AvdDialog : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit AvdDialog(int minApiLevel, const QString &targetArch,
|
||||
const AndroidConfig *config, QWidget *parent = 0);
|
||||
explicit AvdDialog(int minApiLevel, AndroidSdkManager *sdkManager, const QString &targetArch,
|
||||
QWidget *parent = 0);
|
||||
|
||||
Android::SdkPlatform target() const;
|
||||
const SdkPlatform *sdkPlatform() const;
|
||||
QString name() const;
|
||||
QString abi() const;
|
||||
int sdcardSize() const;
|
||||
bool isValid() const;
|
||||
static CreateAvdInfo gatherCreateAVDInfo(QWidget *parent, AndroidSdkManager *sdkManager,
|
||||
int minApiLevel = 0, QString targetArch = QString());
|
||||
|
||||
private:
|
||||
void updateApiLevelComboBox();
|
||||
bool eventFilter(QObject *obj, QEvent *event);
|
||||
|
||||
Ui::AddNewAVDDialog m_avdDialog;
|
||||
const AndroidConfig *m_config;
|
||||
AndroidSdkManager *m_sdkManager;
|
||||
int m_minApiLevel;
|
||||
QTimer m_hideTipTimer;
|
||||
QRegExp m_allowedNameChars;
|
||||
|
||||
Reference in New Issue
Block a user