Android: turn manifest editor application icons into widgets

Change-Id: If192b1b4809cd68ebd214f3fd82e26c7818df32f
Reviewed-by: BogDan Vatra <bogdan@kdab.com>
This commit is contained in:
Ville Voutilainen
2020-03-02 13:59:52 +02:00
parent 8f89c9a846
commit 1fbc8a7f68
9 changed files with 469 additions and 359 deletions

View File

@@ -24,6 +24,8 @@ add_qtc_plugin(Android
androidmanifesteditor.cpp androidmanifesteditor.h androidmanifesteditor.cpp androidmanifesteditor.h
androidmanifesteditorfactory.cpp androidmanifesteditorfactory.h androidmanifesteditorfactory.cpp androidmanifesteditorfactory.h
androidmanifesteditorwidget.cpp androidmanifesteditorwidget.h androidmanifesteditorwidget.cpp androidmanifesteditorwidget.h
androidmanifesteditoriconwidget.cpp androidmanifesteditoriconwidget.h
androidmanifesteditoriconcontainerwidget.cpp androidmanifesteditoriconcontainerwidget.h
androidpackageinstallationstep.cpp androidpackageinstallationstep.h androidpackageinstallationstep.cpp androidpackageinstallationstep.h
androidplugin.cpp androidplugin.h androidplugin.cpp androidplugin.h
androidpotentialkit.cpp androidpotentialkit.h androidpotentialkit.cpp androidpotentialkit.h

View File

@@ -9,6 +9,8 @@ HEADERS += \
androidconstants.h \ androidconstants.h \
androidconfigurations.h \ androidconfigurations.h \
androidmanager.h \ androidmanager.h \
androidmanifesteditoriconcontainerwidget.h \
androidmanifesteditoriconwidget.h \
androidrunconfiguration.h \ androidrunconfiguration.h \
androidruncontrol.h \ androidruncontrol.h \
androidsettingswidget.h \ androidsettingswidget.h \
@@ -54,6 +56,8 @@ HEADERS += \
SOURCES += \ SOURCES += \
androidconfigurations.cpp \ androidconfigurations.cpp \
androidmanager.cpp \ androidmanager.cpp \
androidmanifesteditoriconcontainerwidget.cpp \
androidmanifesteditoriconwidget.cpp \
androidrunconfiguration.cpp \ androidrunconfiguration.cpp \
androidruncontrol.cpp \ androidruncontrol.cpp \
androidsettingswidget.cpp \ androidsettingswidget.cpp \

View File

@@ -56,6 +56,10 @@ Project {
"androidmanifestdocument.h", "androidmanifestdocument.h",
"androidmanifesteditor.cpp", "androidmanifesteditor.cpp",
"androidmanifesteditor.h", "androidmanifesteditor.h",
"androidmanifesteditoriconwidget.cpp",
"androidmanifesteditoriconwidget.h",
"androidmanifesteditoriconcontainerwidget.cpp",
"androidmanifesteditoriconcontainerwidget.h",
"androidmanifesteditorfactory.cpp", "androidmanifesteditorfactory.cpp",
"androidmanifesteditorfactory.h", "androidmanifesteditorfactory.h",
"androidmanifesteditorwidget.cpp", "androidmanifesteditorwidget.cpp",

View File

@@ -0,0 +1,111 @@
/****************************************************************************
**
** Copyright (C) 2020 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 "androidmanifesteditoriconcontainerwidget.h"
#include "androidmanifesteditoriconwidget.h"
#include <utils/utilsicons.h>
#include <QFrame>
#include <QHBoxLayout>
namespace Android {
namespace Internal {
namespace {
const QString highDpiIconPath = "/res/drawable-hdpi/icon.png";
const QString mediumDpiIconPath = "/res/drawable-mdpi/icon.png";
const QString lowDpiIconPath = "/res/drawable-ldpi/icon.png";
const QSize lowDpiIconSize{32, 32};
const QSize mediumDpiIconSize{48, 48};
const QSize highDpiIconSize{72, 72};
}
AndroidManifestEditorIconContainerWidget::AndroidManifestEditorIconContainerWidget(
QWidget *parent,
TextEditor::TextEditorWidget *textEditorWidget)
: QWidget(parent)
{
auto iconLayout = new QHBoxLayout(this);
auto masterIconButton = new AndroidManifestEditorIconWidget(this,
lowDpiIconSize,
tr("Master icon"), tr("Select master icon"));
masterIconButton->setIcon(QIcon::fromTheme(QLatin1String("document-open"), Utils::Icons::OPENFILE.icon()));
iconLayout->addWidget(masterIconButton);
iconLayout->addStretch(1);
QFrame *line = new QFrame(this);
line->setFrameShape(QFrame::VLine);
line->setFrameShadow(QFrame::Sunken);
iconLayout->addWidget(line);
iconLayout->addStretch(1);
auto lIconButton = new AndroidManifestEditorIconWidget(this,
lowDpiIconSize,
tr("Low DPI icon"), tr("Select low DPI icon"),
textEditorWidget, lowDpiIconPath);
iconLayout->addWidget(lIconButton);
m_iconButtons.push_back(lIconButton);
iconLayout->addStretch(1);
auto mIconButton = new AndroidManifestEditorIconWidget(this,
mediumDpiIconSize,
tr("Medium DPI icon"), tr("Select medium DPI icon"),
textEditorWidget, mediumDpiIconPath);
iconLayout->addWidget(mIconButton);
m_iconButtons.push_back(mIconButton);
iconLayout->addStretch(1);
auto hIconButton = new AndroidManifestEditorIconWidget(this,
highDpiIconSize,
tr("High DPI icon"), tr("Select high DPI icon"),
textEditorWidget, highDpiIconPath);
iconLayout->addWidget(hIconButton);
m_iconButtons.push_back(hIconButton);
iconLayout->addStretch(6);
for (auto &&iconButton : m_iconButtons) {
connect(masterIconButton, &AndroidManifestEditorIconWidget::iconSelected,
iconButton, &AndroidManifestEditorIconWidget::setIconFromPath);
}
}
void AndroidManifestEditorIconContainerWidget::loadIcons()
{
for (auto &&iconButton : m_iconButtons)
iconButton->loadIcon();
}
bool AndroidManifestEditorIconContainerWidget::hasIcons()
{
for (auto &&iconButton : m_iconButtons) {
if (iconButton->hasIcon())
return true;
}
return false;
}
} // namespace Internal
} // namespace Android

View File

@@ -0,0 +1,52 @@
/****************************************************************************
**
** Copyright (C) 2020 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 <QVector>
#include <QWidget>
namespace TextEditor {
class TextEditorWidget;
}
namespace Android {
namespace Internal {
class AndroidManifestEditorIconWidget;
class AndroidManifestEditorIconContainerWidget : public QWidget
{
public:
explicit AndroidManifestEditorIconContainerWidget(QWidget *parent,
TextEditor::TextEditorWidget *textEditorWidget);
void loadIcons();
bool hasIcons();
private:
QVector<AndroidManifestEditorIconWidget *> m_iconButtons;
};
} // namespace Internal
} // namespace Android

View File

@@ -0,0 +1,213 @@
/****************************************************************************
**
** Copyright (C) 2020 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 "androidmanifesteditoriconwidget.h"
#include <texteditor/textdocument.h>
#include <texteditor/texteditor.h>
#include <utils/utilsicons.h>
#include <QFileDialog>
#include <QFileInfo>
#include <QGridLayout>
#include <QLabel>
#include <QLoggingCategory>
#include <QToolButton>
#include <QVBoxLayout>
namespace Android {
namespace Internal {
namespace {
static Q_LOGGING_CATEGORY(androidManifestEditorLog, "qtc.android.manifestEditor", QtWarningMsg)
const auto fileDialogIconFiles = QWidget::tr("Images (*.png *.jpg *.webp *.svg)");
QString manifestDir(TextEditor::TextEditorWidget *textEditorWidget)
{
// Get the manifest file's directory from its filepath.
return textEditorWidget->textDocument()->filePath().toFileInfo().absolutePath();
}
}
AndroidManifestEditorIconWidget::AndroidManifestEditorIconWidget(QWidget *parent) : QWidget(parent)
{
}
AndroidManifestEditorIconWidget::AndroidManifestEditorIconWidget(
QWidget *parent, const QSize &buttonSize, const QString &title,
const QString &tooltip,
TextEditor::TextEditorWidget *textEditorWidget,
const QString &targetIconPath)
: QWidget(parent), m_buttonSize(buttonSize),
m_textEditorWidget(textEditorWidget), m_targetIconPath(targetIconPath)
{
auto iconLayout = new QVBoxLayout(this);
auto iconTitle = new QLabel(title, this);
auto iconButtonLayout = new QGridLayout();
m_button = new QToolButton(this);
m_button->setMinimumSize(buttonSize);
m_button->setMaximumSize(buttonSize);
m_button->setToolTip(tooltip);
m_button->setIconSize(buttonSize);
QSize clearAndWarningSize(16, 16);
QToolButton *clearButton = nullptr;
if (textEditorWidget) {
clearButton = new QToolButton(this);
clearButton->setMinimumSize(clearAndWarningSize);
clearButton->setMaximumSize(clearAndWarningSize);
clearButton->setIcon(Utils::Icons::CLOSE_FOREGROUND.icon());
}
if (textEditorWidget) {
m_scaleWarningLabel = new QLabel(this);
m_scaleWarningLabel->setMinimumSize(clearAndWarningSize);
m_scaleWarningLabel->setMaximumSize(clearAndWarningSize);
m_scaleWarningLabel->setPixmap(Utils::Icons::WARNING.icon().pixmap(clearAndWarningSize));
m_scaleWarningLabel->setToolTip(tr("Icon scaled up"));
m_scaleWarningLabel->setVisible(false);
}
auto label = new QLabel(tr("Click to select..."), parent);
iconLayout->addWidget(iconTitle);
iconLayout->setAlignment(iconTitle, Qt::AlignHCenter);
iconButtonLayout->setColumnMinimumWidth(0, 16);
iconButtonLayout->addWidget(m_button, 0, 1, 1, 3);
iconButtonLayout->setAlignment(m_button, Qt::AlignVCenter);
if (textEditorWidget) {
iconButtonLayout->addWidget(clearButton, 0, 4, 1, 1);
iconButtonLayout->setAlignment(clearButton, Qt::AlignTop);
}
if (textEditorWidget) {
iconButtonLayout->addWidget(m_scaleWarningLabel, 0, 0, 1, 1);
iconButtonLayout->setAlignment(m_scaleWarningLabel, Qt::AlignTop);
}
iconLayout->addLayout(iconButtonLayout);
iconLayout->setAlignment(iconButtonLayout, Qt::AlignHCenter);
iconLayout->addWidget(label);
iconLayout->setAlignment(label, Qt::AlignHCenter);
this->setLayout(iconLayout);
connect(m_button, &QAbstractButton::clicked,
this, &AndroidManifestEditorIconWidget::selectIcon);
if (clearButton)
connect(clearButton, &QAbstractButton::clicked,
this, &AndroidManifestEditorIconWidget::removeIcon);
m_iconSelectionText = tooltip;
}
void AndroidManifestEditorIconWidget::setIcon(const QIcon &icon)
{
m_button->setIcon(icon);
}
void AndroidManifestEditorIconWidget::loadIcon()
{
QString baseDir = manifestDir(m_textEditorWidget);
QString iconFile = baseDir + m_targetIconPath;
setIconFromPath(iconFile);
}
void AndroidManifestEditorIconWidget::setIconFromPath(const QString &iconPath)
{
if (!m_textEditorWidget) {
iconSelected(iconPath);
return;
}
m_iconPath = iconPath;
QString baseDir = manifestDir(m_textEditorWidget);
copyIcon();
QString iconFile = baseDir + m_targetIconPath;
m_button->setIcon(QIcon(iconFile));
}
void AndroidManifestEditorIconWidget::selectIcon()
{
QString file = QFileDialog::getOpenFileName(this, m_iconSelectionText,
QDir::homePath(), fileDialogIconFiles);
if (file.isEmpty())
return;
setIconFromPath(file);
}
void AndroidManifestEditorIconWidget::removeIcon()
{
QString baseDir = manifestDir(m_textEditorWidget);
const QString targetPath = baseDir + m_targetIconPath;
if (targetPath.isEmpty()) {
qCDebug(androidManifestEditorLog) << "Icon target path empty, cannot remove icon.";
return;
}
QFileInfo targetFile(targetPath);
if (targetFile.exists()) {
QDir rmRf(targetFile.absoluteDir());
rmRf.removeRecursively();
}
setScaleWarningLabelVisible(false);
m_button->setIcon(QIcon());
}
bool AndroidManifestEditorIconWidget::hasIcon()
{
return m_iconPath.isEmpty();
}
void AndroidManifestEditorIconWidget::setScaleWarningLabelVisible(bool visible)
{
if (m_scaleWarningLabel)
m_scaleWarningLabel->setVisible(visible);
}
void AndroidManifestEditorIconWidget::copyIcon()
{
if (m_targetIconPath.isEmpty())
return;
QString baseDir = manifestDir(m_textEditorWidget);
const QString targetPath = baseDir + m_targetIconPath;
if (targetPath.isEmpty()) {
qCDebug(androidManifestEditorLog) << "Icon target path empty, cannot copy icon.";
return;
}
QFileInfo targetFile(targetPath);
if (m_iconPath == targetPath)
return;
removeIcon();
QImage original(m_iconPath);
if (!targetPath.isEmpty() && !original.isNull()) {
QDir dir;
if (!dir.mkpath(QFileInfo(targetPath).absolutePath())) {
qCDebug(androidManifestEditorLog) << "Cannot create icon target path.";
m_iconPath.clear();
return;
}
QSize targetSize = m_buttonSize;
QImage scaled = original.scaled(targetSize.width(), targetSize.height(),
Qt::KeepAspectRatio, Qt::SmoothTransformation);
setScaleWarningLabelVisible(scaled.width() > original.width() || scaled.height() > original.height());
scaled.save(targetPath);
m_iconPath = m_targetIconPath;
} else {
m_iconPath.clear();
}
}
} // namespace Internal
} // namespace Android

View File

@@ -0,0 +1,75 @@
/****************************************************************************
**
** Copyright (C) 2020 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 <QWidget>
namespace TextEditor {
class TextEditorWidget;
}
class QLabel;
class QToolButton;
namespace Android {
namespace Internal {
class AndroidManifestEditorIconWidget : public QWidget
{
Q_OBJECT
public:
explicit AndroidManifestEditorIconWidget(QWidget *parent);
AndroidManifestEditorIconWidget(QWidget *parent,
const QSize &buttonSize,
const QString &title,
const QString &tooltip,
TextEditor::TextEditorWidget *textEditorWidget = nullptr,
const QString &targetIconPath = {});
void setIcon(const QIcon &icon);
void loadIcon();
void setIconFromPath(const QString &iconPath);
bool hasIcon();
signals:
void iconSelected(const QString &path);
private:
void selectIcon();
void removeIcon();
void copyIcon();
void setScaleWarningLabelVisible(bool visible);
private:
QToolButton *m_button = nullptr;
QSize m_buttonSize;
QLabel *m_scaleWarningLabel = nullptr;
TextEditor::TextEditorWidget *m_textEditorWidget = nullptr;
QString m_iconPath;
QString m_targetIconPath;
QString m_iconSelectionText;
};
} // namespace Internal
} // namespace Android

View File

@@ -24,6 +24,7 @@
****************************************************************************/ ****************************************************************************/
#include "androidmanifesteditorwidget.h" #include "androidmanifesteditorwidget.h"
#include "androidmanifesteditoriconcontainerwidget.h"
#include "androidmanifesteditor.h" #include "androidmanifesteditor.h"
#include "androidconfigurations.h" #include "androidconfigurations.h"
#include "androidconstants.h" #include "androidconstants.h"
@@ -67,7 +68,6 @@
#include <QLabel> #include <QLabel>
#include <QLineEdit> #include <QLineEdit>
#include <QListView> #include <QListView>
#include <QLoggingCategory>
#include <QPushButton> #include <QPushButton>
#include <QScrollArea> #include <QScrollArea>
#include <QSpinBox> #include <QSpinBox>
@@ -77,11 +77,6 @@
#include <algorithm> #include <algorithm>
#include <limits> #include <limits>
namespace {
static Q_LOGGING_CATEGORY(androidManifestEditorLog, "qtc.android.manifestEditor", QtWarningMsg)
}
using namespace ProjectExplorer; using namespace ProjectExplorer;
using namespace Android; using namespace Android;
using namespace Android::Internal; using namespace Android::Internal;
@@ -252,54 +247,11 @@ void AndroidManifestEditorWidget::initializePage()
m_styleExtractMethod->setItemData(i, styleMethodsMap.at(i).at(1), Qt::ToolTipRole); m_styleExtractMethod->setItemData(i, styleMethodsMap.at(i).at(1), Qt::ToolTipRole);
} }
auto iconLayout = new QHBoxLayout(); m_iconButtons = new AndroidManifestEditorIconContainerWidget(applicationGroupBox, m_textEditorWidget);
createDPIButton(iconLayout,
applicationGroupBox,
m_masterIconButton, iconSize(LowDPI),
tr("Master icon"), tr("Select master icon."));
m_masterIconButton->setIcon(QIcon::fromTheme(QLatin1String("document-open"), Utils::Icons::OPENFILE.icon()));
iconLayout->addStretch(1);
QFrame* line = new QFrame();
line->setFrameShape(QFrame::VLine);
line->setFrameShadow(QFrame::Sunken);
iconLayout->addWidget(line);
iconLayout->addStretch(1);
createDPIButton(iconLayout,
applicationGroupBox,
m_lIconButton, iconSize(LowDPI),
tr("Low DPI icon"), tr("Select low DPI icon."),
&m_lIconClearButton,
&m_lIconScaleWarningLabel);
iconLayout->addStretch(1);
createDPIButton(iconLayout,
applicationGroupBox,
m_mIconButton, iconSize(MediumDPI),
tr("Medium DPI icon"), tr("Select medium DPI icon."),
&m_mIconClearButton,
&m_mIconScaleWarningLabel);
iconLayout->addStretch(1);
createDPIButton(iconLayout,
applicationGroupBox,
m_hIconButton, iconSize(HighDPI),
tr("High DPI icon"), tr("Select high DPI icon."),
&m_hIconClearButton,
&m_hIconScaleWarningLabel);
iconLayout->addStretch(6);
formLayout->addRow(tr("Application icon:"), new QLabel()); formLayout->addRow(tr("Application icon:"), new QLabel());
formLayout->addRow(QString(), iconLayout); formLayout->addRow(QString(), m_iconButtons);
applicationGroupBox->setLayout(formLayout); applicationGroupBox->setLayout(formLayout);
@@ -312,21 +264,6 @@ void AndroidManifestEditorWidget::initializePage()
connect(m_styleExtractMethod, connect(m_styleExtractMethod,
QOverload<int>::of(&QComboBox::currentIndexChanged), QOverload<int>::of(&QComboBox::currentIndexChanged),
this, setDirtyFunc); this, setDirtyFunc);
connect(m_masterIconButton, &QAbstractButton::clicked,
this, &AndroidManifestEditorWidget::setMasterIcon);
connect(m_lIconButton, &QAbstractButton::clicked,
this, &AndroidManifestEditorWidget::setLDPIIcon);
connect(m_mIconButton, &QAbstractButton::clicked,
this, &AndroidManifestEditorWidget::setMDPIIcon);
connect(m_hIconButton, &QAbstractButton::clicked,
this, &AndroidManifestEditorWidget::setHDPIIcon);
connect(m_lIconClearButton, &QAbstractButton::clicked,
this, &AndroidManifestEditorWidget::clearLDPIIcon);
connect(m_mIconClearButton, &QAbstractButton::clicked,
this, &AndroidManifestEditorWidget::clearMDPIIcon);
connect(m_hIconClearButton, &QAbstractButton::clicked,
this, &AndroidManifestEditorWidget::clearHDPIIcon);
} }
@@ -634,13 +571,7 @@ void AndroidManifestEditorWidget::preSave()
if (activePage() != Source) if (activePage() != Source)
syncToEditor(); syncToEditor();
QString baseDir = m_textEditorWidget->textDocument()->filePath().toFileInfo().absolutePath();
copyIcon(LowDPI, baseDir, m_lIconPath);
copyIcon(MediumDPI, baseDir, m_mIconPath);
copyIcon(HighDPI, baseDir, m_hIconPath);
// no need to emit changed() since this is called as part of saving // no need to emit changed() since this is called as part of saving
updateInfoBar(); updateInfoBar();
} }
@@ -841,13 +772,6 @@ void AndroidManifestEditorWidget::syncToWidgets(const QDomDocument &doc)
metadataElem = metadataElem.nextSiblingElement(QLatin1String("meta-data")); metadataElem = metadataElem.nextSiblingElement(QLatin1String("meta-data"));
} }
m_lIconButton->setIcon(icon(baseDir, LowDPI));
m_mIconButton->setIcon(icon(baseDir, MediumDPI));
m_hIconButton->setIcon(icon(baseDir, HighDPI));
m_lIconPath = baseDir + iconPath(LowDPI);
m_mIconPath = baseDir + iconPath(MediumDPI);
m_hIconPath = baseDir + iconPath(HighDPI);
disconnect(m_defaultPermissonsCheckBox, &QCheckBox::stateChanged, disconnect(m_defaultPermissonsCheckBox, &QCheckBox::stateChanged,
this, &AndroidManifestEditorWidget::defaultPermissionOrFeatureCheckBoxClicked); this, &AndroidManifestEditorWidget::defaultPermissionOrFeatureCheckBoxClicked);
disconnect(m_defaultFeaturesCheckBox, &QCheckBox::stateChanged, disconnect(m_defaultFeaturesCheckBox, &QCheckBox::stateChanged,
@@ -887,6 +811,8 @@ void AndroidManifestEditorWidget::syncToWidgets(const QDomDocument &doc)
m_permissionsModel->setPermissions(permissions); m_permissionsModel->setPermissions(permissions);
updateAddRemovePermissionButtons(); updateAddRemovePermissionButtons();
m_iconButtons->loadIcons();
m_stayClean = false; m_stayClean = false;
m_dirty = false; m_dirty = false;
} }
@@ -1049,9 +975,7 @@ void AndroidManifestEditorWidget::parseApplication(QXmlStreamReader &reader, QXm
QStringList keys = {QLatin1String("android:label")}; QStringList keys = {QLatin1String("android:label")};
QStringList values = {m_appNameLineEdit->text()}; QStringList values = {m_appNameLineEdit->text()};
QStringList remove; QStringList remove;
bool ensureIconAttribute = !m_lIconPath.isEmpty() bool ensureIconAttribute = m_iconButtons->hasIcons();
|| !m_mIconPath.isEmpty()
|| !m_hIconPath.isEmpty();
if (ensureIconAttribute) { if (ensureIconAttribute) {
keys << QLatin1String("android:icon"); keys << QLatin1String("android:icon");
values << QLatin1String("@drawable/icon"); values << QLatin1String("@drawable/icon");
@@ -1277,246 +1201,6 @@ void AndroidManifestEditorWidget::parseUnknownElement(QXmlStreamReader &reader,
} }
} }
QString AndroidManifestEditorWidget::iconPath(IconDPI dpi)
{
switch (dpi) {
case HighDPI:
return QString("/res/drawable-hdpi/icon.png");
case MediumDPI:
return QString("/res/drawable-mdpi/icon.png");
case LowDPI:
return QString("/res/drawable-ldpi/icon.png");
}
return {};
}
QSize AndroidManifestEditorWidget::iconSize(IconDPI dpi)
{
switch (dpi) {
case HighDPI:
return QSize(72, 72);
case MediumDPI:
return QSize(48, 48);
case LowDPI:
return QSize(32, 32);
}
return QSize(72, 72);
}
void AndroidManifestEditorWidget::updateIconPath(const QString &newPath, IconDPI dpi)
{
switch (dpi) {
case HighDPI:
m_hIconPath = newPath;
break;
case MediumDPI:
m_mIconPath = newPath;
break;
case LowDPI:
m_lIconPath = newPath;
break;
}
}
QIcon AndroidManifestEditorWidget::icon(const QString &baseDir, IconDPI dpi)
{
if (dpi == HighDPI && !m_hIconPath.isEmpty())
return QIcon(m_hIconPath);
if (dpi == MediumDPI && !m_mIconPath.isEmpty())
return QIcon(m_mIconPath);
if (dpi == LowDPI && !m_lIconPath.isEmpty())
return QIcon(m_lIconPath);
QString fileName = baseDir + iconPath(dpi);
if (fileName.isEmpty())
return QIcon();
return QIcon(fileName);
}
void AndroidManifestEditorWidget::copyIcon(IconDPI dpi, const QString &baseDir, const QString &filePath)
{
const QString targetPath = baseDir + iconPath(dpi);
if (targetPath.isEmpty()) {
qCDebug(androidManifestEditorLog) << "Icon target path empty, cannot copy icon.";
return;
}
QFileInfo targetFile(targetPath);
if (filePath == targetPath)
return;
removeIcon(dpi, baseDir);
QImage original(filePath);
if (!targetPath.isEmpty() && !original.isNull()) {
QDir dir;
dir.mkpath(QFileInfo(targetPath).absolutePath());
QSize targetSize = iconSize(dpi);
QImage scaled = original.scaled(targetSize.width(), targetSize.height(),
Qt::KeepAspectRatio, Qt::SmoothTransformation);
toggleIconScaleWarning(dpi, scaled.width() > original.width() || scaled.height() > original.height());
scaled.save(targetPath);
updateIconPath(targetPath, dpi);
}
}
void AndroidManifestEditorWidget::removeIcon(IconDPI dpi, const QString &baseDir)
{
const QString targetPath = baseDir + iconPath(dpi);
if (targetPath.isEmpty()) {
qCDebug(androidManifestEditorLog) << "Icon target path empty, cannot remove icon.";
return;
}
QFileInfo targetFile(targetPath);
if (targetFile.exists()) {
QDir rmRf(targetFile.absoluteDir());
rmRf.removeRecursively();
}
toggleIconScaleWarning(dpi, false);
}
void AndroidManifestEditorWidget::toggleIconScaleWarning(IconDPI dpi, bool visible)
{
switch (dpi) {
case HighDPI:
m_hIconScaleWarningLabel->setVisible(visible);
break;
case MediumDPI:
m_mIconScaleWarningLabel->setVisible(visible);
break;
case LowDPI:
m_lIconScaleWarningLabel->setVisible(visible);
break;
}
}
const auto fileDialogIconFiles = QWidget::tr("Images (*.png *.jpg *.webp *.svg)");
void AndroidManifestEditorWidget::setMasterIcon()
{
QString file = QFileDialog::getOpenFileName(this, tr("Choose Master Icon"), QDir::homePath(), fileDialogIconFiles);
if (file.isEmpty())
return;
QString baseDir = m_textEditorWidget->textDocument()->filePath().toFileInfo().absolutePath();
copyIcon(LowDPI, baseDir, file);
copyIcon(MediumDPI, baseDir, file);
copyIcon(HighDPI, baseDir, file);
m_lIconButton->setIcon(icon(baseDir, LowDPI));
m_mIconButton->setIcon(icon(baseDir, MediumDPI));
m_hIconButton->setIcon(icon(baseDir, HighDPI));
}
void AndroidManifestEditorWidget::setLDPIIcon()
{
QString file = QFileDialog::getOpenFileName(this, tr("Choose Low DPI Icon"), QDir::homePath(), fileDialogIconFiles);
if (file.isEmpty())
return;
m_lIconPath = file;
QString baseDir = m_textEditorWidget->textDocument()->filePath().toFileInfo().absolutePath();
copyIcon(LowDPI, baseDir, m_lIconPath);
m_lIconButton->setIcon(icon(baseDir, LowDPI));
}
void AndroidManifestEditorWidget::setMDPIIcon()
{
QString file = QFileDialog::getOpenFileName(this, tr("Choose Medium DPI Icon"), QDir::homePath(), fileDialogIconFiles);
if (file.isEmpty())
return;
m_mIconPath = file;
QString baseDir = m_textEditorWidget->textDocument()->filePath().toFileInfo().absolutePath();
copyIcon(MediumDPI, baseDir, m_mIconPath);
m_mIconButton->setIcon(icon(baseDir, MediumDPI));
}
void AndroidManifestEditorWidget::setHDPIIcon()
{
QString file = QFileDialog::getOpenFileName(this, tr("Choose High DPI Icon"), QDir::homePath(), fileDialogIconFiles);
if (file.isEmpty())
return;
m_hIconPath = file;
QString baseDir = m_textEditorWidget->textDocument()->filePath().toFileInfo().absolutePath();
copyIcon(HighDPI, baseDir, m_hIconPath);
m_hIconButton->setIcon(icon(baseDir, HighDPI));
}
void AndroidManifestEditorWidget::clearLDPIIcon()
{
m_lIconPath.clear();
m_lIconButton->setIcon(QIcon());
QString baseDir = m_textEditorWidget->textDocument()->filePath().toFileInfo().absolutePath();
removeIcon(LowDPI, baseDir);
}
void AndroidManifestEditorWidget::clearMDPIIcon()
{
m_mIconPath.clear();
m_mIconButton->setIcon(QIcon());
QString baseDir = m_textEditorWidget->textDocument()->filePath().toFileInfo().absolutePath();
removeIcon(MediumDPI, baseDir);
}
void AndroidManifestEditorWidget::clearHDPIIcon()
{
m_hIconPath.clear();
m_hIconButton->setIcon(QIcon());
QString baseDir = m_textEditorWidget->textDocument()->filePath().toFileInfo().absolutePath();
removeIcon(HighDPI, baseDir);
}
void AndroidManifestEditorWidget::createDPIButton(QHBoxLayout *layout,
QWidget *parent,
QToolButton *&button,
const QSize &buttonSize,
const QString &title,
const QString &tooltip,
QToolButton **clearButton,
QLabel **scaleWarningLabel)
{
auto iconLayout = new QVBoxLayout();
auto iconTitle = new QLabel(title, parent);
auto iconButtonLayout = new QGridLayout();
button = new QToolButton(parent);
button->setMinimumSize(buttonSize);
button->setMaximumSize(buttonSize);
button->setToolTip(tooltip);
button->setIconSize(buttonSize);
QSize clearAndWarningSize(16, 16);
if (clearButton) {
*clearButton = new QToolButton(parent);
(*clearButton)->setMinimumSize(clearAndWarningSize);
(*clearButton)->setMaximumSize(clearAndWarningSize);
(*clearButton)->setIcon(Utils::Icons::CLOSE_FOREGROUND.icon());
}
if (scaleWarningLabel) {
*scaleWarningLabel = new QLabel(parent);
(*scaleWarningLabel)->setMinimumSize(clearAndWarningSize);
(*scaleWarningLabel)->setMaximumSize(clearAndWarningSize);
(*scaleWarningLabel)->setPixmap(Utils::Icons::WARNING.icon().pixmap(clearAndWarningSize));
(*scaleWarningLabel)->setToolTip(tr("Icon scaled up"));
(*scaleWarningLabel)->setVisible(false);
}
auto label = new QLabel(tr("Click to select"), parent);
iconLayout->addWidget(iconTitle);
iconLayout->setAlignment(iconTitle, Qt::AlignHCenter);
iconButtonLayout->setColumnMinimumWidth(0, 16);
iconButtonLayout->addWidget(button, 0, 1, 1, 3);
iconButtonLayout->setAlignment(button, Qt::AlignVCenter);
if (clearButton) {
iconButtonLayout->addWidget(*clearButton, 0, 4, 1, 1);
iconButtonLayout->setAlignment(*clearButton, Qt::AlignTop);
}
if (scaleWarningLabel) {
iconButtonLayout->addWidget(*scaleWarningLabel, 0, 0, 1, 1);
iconButtonLayout->setAlignment(*scaleWarningLabel, Qt::AlignTop);
}
iconLayout->addLayout(iconButtonLayout);
iconLayout->setAlignment(iconButtonLayout, Qt::AlignHCenter);
iconLayout->addWidget(label);
iconLayout->setAlignment(label, Qt::AlignHCenter);
layout->addLayout(iconLayout);
}
void AndroidManifestEditorWidget::defaultPermissionOrFeatureCheckBoxClicked() void AndroidManifestEditorWidget::defaultPermissionOrFeatureCheckBoxClicked()
{ {
setDirty(true); setDirty(true);

View File

@@ -52,9 +52,9 @@ namespace Core { class IEditor; }
namespace Android { namespace Android {
namespace Internal { namespace Internal {
class AndroidManifestEditor; class AndroidManifestEditor;
class AndroidManifestEditorIconContainerWidget;
class AndroidManifestEditorWidget; class AndroidManifestEditorWidget;
class PermissionsModel: public QAbstractListModel class PermissionsModel: public QAbstractListModel
{ {
Q_OBJECT Q_OBJECT
@@ -116,21 +116,6 @@ protected:
void focusInEvent(QFocusEvent *event) override; void focusInEvent(QFocusEvent *event) override;
private: private:
void setMasterIcon();
void clearMasterIcon();
void setLDPIIcon();
void setMDPIIcon();
void setHDPIIcon();
void clearLDPIIcon();
void clearMDPIIcon();
void clearHDPIIcon();
void createDPIButton(QHBoxLayout *layout,
QWidget *parent,
QToolButton *&button, const QSize &buttonSize,
const QString &title, const QString &tooltip,
QToolButton **clearButton = nullptr,
QLabel **scaleWarningLabel = nullptr
);
void defaultPermissionOrFeatureCheckBoxClicked(); void defaultPermissionOrFeatureCheckBoxClicked();
void addPermission(); void addPermission();
void removePermission(); void removePermission();
@@ -148,14 +133,6 @@ private:
bool checkDocument(const QDomDocument &doc, QString *errorMessage, bool checkDocument(const QDomDocument &doc, QString *errorMessage,
int *errorLine, int *errorColumn); int *errorLine, int *errorColumn);
enum IconDPI { LowDPI, MediumDPI, HighDPI };
QIcon icon(const QString &baseDir, IconDPI dpi);
QString iconPath(IconDPI dpi);
QSize iconSize(IconDPI dpi);
void updateIconPath(const QString &newPath, IconDPI dpi);
void copyIcon(IconDPI dpi, const QString &baseDir, const QString &filePath);
void removeIcon(IconDPI dpi, const QString &baseDir);
void toggleIconScaleWarning(IconDPI dpi, bool visible);
void updateInfoBar(const QString &errorMessage, int line, int column); void updateInfoBar(const QString &errorMessage, int line, int column);
void hideInfoBar(); void hideInfoBar();
@@ -190,19 +167,7 @@ private:
QLineEdit *m_activityNameLineEdit; QLineEdit *m_activityNameLineEdit;
QComboBox *m_targetLineEdit; QComboBox *m_targetLineEdit;
QComboBox *m_styleExtractMethod; QComboBox *m_styleExtractMethod;
QToolButton *m_masterIconButton; AndroidManifestEditorIconContainerWidget *m_iconButtons;
QToolButton *m_lIconButton;
QToolButton *m_lIconClearButton;
QLabel *m_lIconScaleWarningLabel;
QToolButton *m_mIconButton;
QToolButton *m_mIconClearButton;
QLabel *m_mIconScaleWarningLabel;
QToolButton *m_hIconButton;
QToolButton *m_hIconClearButton;
QLabel *m_hIconScaleWarningLabel;
QString m_lIconPath;
QString m_mIconPath;
QString m_hIconPath;
// Permissions // Permissions
QCheckBox *m_defaultPermissonsCheckBox; QCheckBox *m_defaultPermissonsCheckBox;