forked from qt-creator/qt-creator
Android: Android SDK manager user interface
Task-number: QTCREATORBUG-18978 Change-Id: I421ea66fcd4f3cf38e6cfd3be58a35b3f9204c6f Reviewed-by: BogDan Vatra <bogdan@kdab.com> Reviewed-by: Leena Miettinen <riitta-leena.miettinen@qt.io>
This commit is contained in:
@@ -51,7 +51,9 @@ HEADERS += \
|
||||
androidavdmanager.h \
|
||||
androidrunconfigurationwidget.h \
|
||||
adbcommandswidget.h \
|
||||
androidsdkpackage.h
|
||||
androidsdkpackage.h \
|
||||
androidsdkmodel.h \
|
||||
androidsdkmanagerwidget.h
|
||||
|
||||
SOURCES += \
|
||||
androidconfigurations.cpp \
|
||||
@@ -96,7 +98,9 @@ SOURCES += \
|
||||
androidavdmanager.cpp \
|
||||
androidrunconfigurationwidget.cpp \
|
||||
adbcommandswidget.cpp \
|
||||
androidsdkpackage.cpp
|
||||
androidsdkpackage.cpp \
|
||||
androidsdkmodel.cpp \
|
||||
androidsdkmanagerwidget.cpp
|
||||
|
||||
FORMS += \
|
||||
androidsettingswidget.ui \
|
||||
@@ -106,7 +110,8 @@ FORMS += \
|
||||
androiddeployqtwidget.ui \
|
||||
androidbuildapkwidget.ui \
|
||||
androidrunconfigurationwidget.ui \
|
||||
adbcommandswidget.ui
|
||||
adbcommandswidget.ui \
|
||||
androidsdkmanagerwidget.ui
|
||||
|
||||
RESOURCES = android.qrc
|
||||
|
||||
|
||||
364
src/plugins/android/androidsdkmanagerwidget.cpp
Normal file
364
src/plugins/android/androidsdkmanagerwidget.cpp
Normal file
@@ -0,0 +1,364 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** 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 "androidsdkmodel.h"
|
||||
|
||||
#include "utils/outputformatter.h"
|
||||
#include "utils/runextensions.h"
|
||||
#include "utils/qtcassert.h"
|
||||
#include "utils/utilsicons.h"
|
||||
|
||||
#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 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(const AndroidConfig &config,
|
||||
AndroidSdkManager *sdkManager, QWidget *parent) :
|
||||
QWidget(parent),
|
||||
m_androidConfig(config),
|
||||
m_sdkManager(sdkManager),
|
||||
m_sdkModel(new AndroidSdkModel(m_sdkManager, this)),
|
||||
m_ui(new Ui::AndroidSdkManagerWidget)
|
||||
{
|
||||
m_ui->setupUi(this);
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
void AndroidSdkManagerWidget::onApplyButton()
|
||||
{
|
||||
QTC_ASSERT(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, installSdkPaths, uninstallSdkPaths;
|
||||
for (auto package : packagesToUpdate) {
|
||||
QString str = QString(" %1").arg(package->descriptionText());
|
||||
if (package->state() == AndroidSdkPackage::Installed) {
|
||||
uninstallSdkPaths << package->sdkStylePath();
|
||||
uninstallPackages << str;
|
||||
} else {
|
||||
installSdkPaths << package->sdkStylePath();
|
||||
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;
|
||||
|
||||
// User agreed with the selection. Begin packages install/uninstall
|
||||
emit updatingSdk();
|
||||
switchView(Operations);
|
||||
m_formatter->appendMessage(tr("Updating 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::onUpdatePackages()
|
||||
{
|
||||
if (m_sdkManager->isBusy()) {
|
||||
m_formatter->appendMessage(tr("\nSDK Manager is busy."), Utils::StdErrFormat);
|
||||
return;
|
||||
}
|
||||
switchView(Operations);
|
||||
m_formatter->appendMessage(tr("Updating installed packages\n"), Utils::NormalMessageFormat);
|
||||
addPackageFuture(m_sdkManager->updateAll());
|
||||
}
|
||||
|
||||
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);
|
||||
auto breakLine = [](const QString &line) { return line.endsWith("\n") ? line : line + "\n";};
|
||||
AndroidSdkManager::OperationOutput result = m_currentOperation->resultAt(index);
|
||||
if (!result.stdError.isEmpty())
|
||||
m_formatter->appendMessage(breakLine(result.stdError), Utils::StdErrFormat);
|
||||
if (!result.stdOutput.isEmpty())
|
||||
m_formatter->appendMessage(breakLine(result.stdOutput), Utils::StdOutFormat);
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
void AndroidSdkManagerWidget::notifyOperationFinished()
|
||||
{
|
||||
if (!m_currentOperation || m_currentOperation->isFinished()) {
|
||||
QMessageBox::information(this, tr("Android SDK Changes"),
|
||||
tr("Android SDK operations finished."), QMessageBox::Ok);
|
||||
switchView(PackageListing);
|
||||
m_ui->operationProgress->setValue(0);
|
||||
m_sdkManager->reloadPackages(true);
|
||||
emit updatingSdkFinished();
|
||||
}
|
||||
}
|
||||
|
||||
void AndroidSdkManagerWidget::packageFutureFinished()
|
||||
{
|
||||
if (!m_currentOperation) {
|
||||
qCDebug(androidSdkMgrUiLog) << "Invalid State. No active operation.";
|
||||
return;
|
||||
} else if (m_currentOperation->isCanceled()) {
|
||||
m_formatter->appendMessage(tr("Operation cancelled.\n"), Utils::StdErrFormat);
|
||||
}
|
||||
m_ui->operationProgress->setValue(100);
|
||||
m_currentOperation->deleteLater();
|
||||
m_currentOperation = nullptr;
|
||||
notifyOperationFinished();
|
||||
}
|
||||
|
||||
void AndroidSdkManagerWidget::cancelPendingOperations()
|
||||
{
|
||||
if (!m_sdkManager->isBusy()) {
|
||||
m_formatter->appendMessage(tr("\nNo pending operations to cancel...\n"),
|
||||
Utils::NormalMessageFormat);
|
||||
return;
|
||||
}
|
||||
m_formatter->appendMessage(tr("\nCancelling pending operations...\n"),
|
||||
Utils::NormalMessageFormat);
|
||||
m_sdkManager->cancelOperatons();
|
||||
}
|
||||
|
||||
void AndroidSdkManagerWidget::switchView(AndroidSdkManagerWidget::View view)
|
||||
{
|
||||
m_ui->viewStack->setCurrentWidget(view == PackageListing ?
|
||||
m_ui->packagesStack : m_ui->outputStack);
|
||||
m_formatter->clear();
|
||||
m_ui->outputEdit->clear();
|
||||
}
|
||||
|
||||
AndroidSdkManagerWidget::View AndroidSdkManagerWidget::currentView() const
|
||||
{
|
||||
return m_ui->viewStack->currentWidget() == m_ui->packagesStack ? PackageListing : Operations;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
} // namespace Internal
|
||||
} // namespace Android
|
||||
87
src/plugins/android/androidsdkmanagerwidget.h
Normal file
87
src/plugins/android/androidsdkmanagerwidget.h
Normal file
@@ -0,0 +1,87 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** 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
|
||||
};
|
||||
|
||||
public:
|
||||
AndroidSdkManagerWidget(const AndroidConfig &config, AndroidSdkManager *sdkManager,
|
||||
QWidget *parent = nullptr);
|
||||
~AndroidSdkManagerWidget();
|
||||
|
||||
void setSdkManagerControlsEnabled(bool enable);
|
||||
|
||||
signals:
|
||||
void updatingSdk();
|
||||
void updatingSdkFinished();
|
||||
|
||||
private:
|
||||
void onApplyButton();
|
||||
void onUpdatePackages();
|
||||
void onCancel();
|
||||
void onNativeSdkManager();
|
||||
void onOperationResult(int index);
|
||||
void addPackageFuture(const QFuture<AndroidSdkManager::OperationOutput> &future);
|
||||
void notifyOperationFinished();
|
||||
void packageFutureFinished();
|
||||
void cancelPendingOperations();
|
||||
void switchView(View view);
|
||||
View currentView() const;
|
||||
|
||||
const AndroidConfig &m_androidConfig;
|
||||
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
|
||||
272
src/plugins/android/androidsdkmanagerwidget.ui
Normal file
272
src/plugins/android/androidsdkmanagerwidget.ui
Normal file
@@ -0,0 +1,272 @@
|
||||
<?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>
|
||||
<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="2" column="1">
|
||||
<widget class="QPushButton" name="cancelButton">
|
||||
<property name="text">
|
||||
<string>Cancel</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" 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="2">
|
||||
<widget class="QPlainTextEdit" name="outputEdit">
|
||||
<property name="readOnly">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0" colspan="2">
|
||||
<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>
|
||||
</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>
|
||||
316
src/plugins/android/androidsdkmodel.cpp
Normal file
316
src/plugins/android/androidsdkmodel.cpp
Normal file
@@ -0,0 +1,316 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** 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(AndroidSdkManager *sdkManager, QObject *parent)
|
||||
: QAbstractItemModel(parent),
|
||||
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;
|
||||
}
|
||||
|
||||
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
|
||||
83
src/plugins/android/androidsdkmodel.h
Normal file
83
src/plugins/android/androidsdkmodel.h
Normal file
@@ -0,0 +1,83 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** 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(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;
|
||||
|
||||
QList<const AndroidSdkPackage *> userSelection() const;
|
||||
void resetSelection();
|
||||
|
||||
private:
|
||||
void clearContainers();
|
||||
void refreshData();
|
||||
|
||||
private:
|
||||
AndroidSdkManager *m_sdkManager;
|
||||
QList<const SdkPlatform *> m_sdkPlatforms;
|
||||
QList<const AndroidSdkPackage *> m_tools;
|
||||
QSet<const AndroidSdkPackage *> m_changeState;
|
||||
};
|
||||
|
||||
} // namespace Internal
|
||||
} // namespace Android
|
||||
@@ -183,7 +183,19 @@ QVersionNumber SdkPlatform::version() const
|
||||
|
||||
void SdkPlatform::addSystemImage(SystemImage *image)
|
||||
{
|
||||
m_systemImages.append(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);
|
||||
}
|
||||
|
||||
|
||||
@@ -33,6 +33,7 @@
|
||||
#include "androidavdmanager.h"
|
||||
#include "androidsdkmanager.h"
|
||||
#include "avddialog.h"
|
||||
#include "androidsdkmanagerwidget.h"
|
||||
|
||||
#include <utils/qtcassert.h>
|
||||
#include <utils/environment.h>
|
||||
@@ -124,24 +125,35 @@ public:
|
||||
data.m_valid = valid;
|
||||
data.m_iconLabel->setPixmap(data.m_valid ? Utils::Icons::OK.pixmap() :
|
||||
Utils::Icons::BROKEN.pixmap());
|
||||
bool ok = allRowsOk();
|
||||
m_detailsWidget->setIcon(ok ? Utils::Icons::OK.icon() :
|
||||
Utils::Icons::CRITICAL.icon());
|
||||
m_detailsWidget->setSummaryText(ok ? m_validText : m_invalidText);
|
||||
updateUi();
|
||||
}
|
||||
|
||||
bool allRowsOk() const
|
||||
bool rowsOk(QList<int> keys) const
|
||||
{
|
||||
for (auto itr = m_validationData.cbegin(); itr != m_validationData.cend(); ++itr) {
|
||||
if (!itr.value().m_valid)
|
||||
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;
|
||||
};
|
||||
@@ -218,6 +230,21 @@ AndroidSettingsWidget::AndroidSettingsWidget(QWidget *parent)
|
||||
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.");
|
||||
@@ -283,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);
|
||||
@@ -293,14 +320,20 @@ 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();
|
||||
validateSdk();
|
||||
// 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();
|
||||
}
|
||||
@@ -521,14 +554,23 @@ void AndroidSettingsWidget::updateUI()
|
||||
{
|
||||
auto javaSummaryWidget = static_cast<SummaryWidget *>(m_ui->javaDetailsWidget->widget());
|
||||
auto androidSummaryWidget = static_cast<SummaryWidget *>(m_ui->androidDetailsWidget->widget());
|
||||
m_ui->AVDManagerFrame->setEnabled(javaSummaryWidget->allRowsOk()
|
||||
&& androidSummaryWidget->allRowsOk());
|
||||
m_ui->javaDetailsWidget->setState(javaSummaryWidget->allRowsOk() ?
|
||||
Utils::DetailsWidget::Collapsed :
|
||||
Utils::DetailsWidget::Expanded);
|
||||
m_ui->androidDetailsWidget->setState(androidSummaryWidget->allRowsOk() ?
|
||||
Utils::DetailsWidget::Collapsed :
|
||||
Utils::DetailsWidget::Expanded);
|
||||
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();
|
||||
}
|
||||
|
||||
@@ -42,6 +42,8 @@ QT_END_NAMESPACE
|
||||
namespace Android {
|
||||
namespace Internal {
|
||||
|
||||
class AndroidSdkManagerWidget;
|
||||
|
||||
class AndroidAvdManager;
|
||||
|
||||
class AvdModel: public QAbstractTableModel
|
||||
@@ -98,6 +100,7 @@ private:
|
||||
void disableAvdControls();
|
||||
|
||||
Ui_AndroidSettingsWidget *m_ui;
|
||||
AndroidSdkManagerWidget *m_sdkManagerWidget = nullptr;
|
||||
AndroidConfig m_androidConfig;
|
||||
AvdModel m_AVDModel;
|
||||
QFutureWatcher<CreateAvdInfo> m_futureWatcher;
|
||||
|
||||
@@ -6,14 +6,26 @@
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>938</width>
|
||||
<height>728</height>
|
||||
<width>1131</width>
|
||||
<height>826</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Android Configuration</string>
|
||||
</property>
|
||||
<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">
|
||||
@@ -175,122 +187,167 @@
|
||||
<widget class="Utils::DetailsWidget" name="kitWarningDetails" native="true"/>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QFrame" name="AVDManagerFrame">
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::StyledPanel</enum>
|
||||
<widget class="QTabWidget" name="managerTabWidget">
|
||||
<property name="currentIndex">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Raised</enum>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_2">
|
||||
<item row="3" column="1">
|
||||
<widget class="QPushButton" name="AVDStartPushButton">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Start...</string>
|
||||
</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">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>129</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
<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="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</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>
|
||||
@@ -299,7 +356,7 @@
|
||||
<customwidget>
|
||||
<class>Utils::PathChooser</class>
|
||||
<extends>QWidget</extends>
|
||||
<header>utils/pathchooser.h</header>
|
||||
<header location="global">utils/pathchooser.h</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
|
||||
Reference in New Issue
Block a user