Android: parse image file names from manifest

Also scales splash images without stretching and reflects them
to other orientations.

Task-number: QTCREATORBUG-24149
Task-number: QTCREATORBUG-24150
Change-Id: Ie23a8ba5f75132971673d3232807e941dfd50f97
Reviewed-by: Alessandro Portale <alessandro.portale@qt.io>
This commit is contained in:
Ville Voutilainen
2020-06-09 16:25:13 +03:00
parent 03f6517a6a
commit 64896a9436
7 changed files with 411 additions and 111 deletions

View File

@@ -35,9 +35,10 @@ 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 QString highDpiIconPath = QLatin1String("/res/drawable-hdpi/");
const QString mediumDpiIconPath = QLatin1String("/res/drawable-mdpi/");
const QString lowDpiIconPath = QLatin1String("/res/drawable-ldpi/");
const QString imageSuffix = QLatin1String(".png");
const QSize lowDpiIconSize{32, 32};
const QSize mediumDpiIconSize{48, 48};
const QSize highDpiIconSize{72, 72};
@@ -63,11 +64,15 @@ AndroidManifestEditorIconContainerWidget::AndroidManifestEditorIconContainerWidg
iconLayout->addWidget(line);
iconLayout->addStretch(1);
QString iconFileName = m_iconFileName + imageSuffix;
auto lIconButton = new AndroidManifestEditorIconWidget(this,
lowDpiIconSize,
lowDpiIconSize,
tr("Low DPI icon"), tr("Select low DPI icon"),
textEditorWidget, lowDpiIconPath);
textEditorWidget,
lowDpiIconPath,
iconFileName);
iconLayout->addWidget(lIconButton);
m_iconButtons.push_back(lIconButton);
iconLayout->addStretch(1);
@@ -76,7 +81,9 @@ AndroidManifestEditorIconContainerWidget::AndroidManifestEditorIconContainerWidg
mediumDpiIconSize,
mediumDpiIconSize,
tr("Medium DPI icon"), tr("Select medium DPI icon"),
textEditorWidget, mediumDpiIconPath);
textEditorWidget,
mediumDpiIconPath,
iconFileName);
iconLayout->addWidget(mIconButton);
m_iconButtons.push_back(mIconButton);
iconLayout->addStretch(1);
@@ -85,7 +92,9 @@ AndroidManifestEditorIconContainerWidget::AndroidManifestEditorIconContainerWidg
highDpiIconSize,
highDpiIconSize,
tr("High DPI icon"), tr("Select high DPI icon"),
textEditorWidget, highDpiIconPath);
textEditorWidget,
highDpiIconPath,
iconFileName);
iconLayout->addWidget(hIconButton);
m_iconButtons.push_back(hIconButton);
iconLayout->addStretch(6);
@@ -96,13 +105,25 @@ AndroidManifestEditorIconContainerWidget::AndroidManifestEditorIconContainerWidg
}
}
void AndroidManifestEditorIconContainerWidget::loadIcons()
void AndroidManifestEditorIconContainerWidget::setIconFileName(const QString &name)
{
for (auto &&iconButton : m_iconButtons)
iconButton->loadIcon();
m_iconFileName = name;
}
bool AndroidManifestEditorIconContainerWidget::hasIcons()
QString AndroidManifestEditorIconContainerWidget::iconFileName() const
{
return m_iconFileName;
}
void AndroidManifestEditorIconContainerWidget::loadIcons()
{
for (auto &&iconButton : m_iconButtons) {
iconButton->setTargetIconFileName(m_iconFileName + imageSuffix);
iconButton->loadIcon();
}
}
bool AndroidManifestEditorIconContainerWidget::hasIcons() const
{
for (auto &&iconButton : m_iconButtons) {
if (iconButton->hasIcon())

View File

@@ -25,6 +25,7 @@
#pragma once
#include <QString>
#include <QVector>
#include <QWidget>
@@ -42,10 +43,13 @@ class AndroidManifestEditorIconContainerWidget : public QWidget
public:
explicit AndroidManifestEditorIconContainerWidget(QWidget *parent,
TextEditor::TextEditorWidget *textEditorWidget);
void setIconFileName(const QString &name);
QString iconFileName() const;
void loadIcons();
bool hasIcons();
bool hasIcons() const;
private:
QVector<AndroidManifestEditorIconWidget *> m_iconButtons;
QString m_iconFileName = QLatin1String("icon");
};
} // namespace Internal

View File

@@ -34,6 +34,7 @@
#include <QGridLayout>
#include <QLabel>
#include <QLoggingCategory>
#include <QPainter>
#include <QToolButton>
#include <QVBoxLayout>
@@ -59,9 +60,11 @@ AndroidManifestEditorIconWidget::AndroidManifestEditorIconWidget(
QWidget *parent, const QSize &iconSize, const QSize &buttonSize, const QString &title,
const QString &tooltip,
TextEditor::TextEditorWidget *textEditorWidget,
const QString &targetIconPath)
const QString &targetIconPath,
const QString &targetIconFileName)
: QWidget(parent), m_iconSize(iconSize), m_buttonSize(buttonSize),
m_textEditorWidget(textEditorWidget), m_targetIconPath(targetIconPath)
m_textEditorWidget(textEditorWidget),
m_targetIconPath(targetIconPath), m_targetIconFileName(targetIconFileName)
{
auto iconLayout = new QVBoxLayout(this);
auto iconTitle = new QLabel(title, this);
@@ -108,12 +111,9 @@ AndroidManifestEditorIconWidget::AndroidManifestEditorIconWidget(
this->setLayout(iconLayout);
connect(m_button, &QAbstractButton::clicked,
this, &AndroidManifestEditorIconWidget::selectIcon);
if (clearButton) {
if (clearButton)
connect(clearButton, &QAbstractButton::clicked,
this, &AndroidManifestEditorIconWidget::removeIcon);
connect(clearButton, &QAbstractButton::clicked,
this, &AndroidManifestEditorIconWidget::iconRemoved);
}
this, &AndroidManifestEditorIconWidget::clearIcon);
m_iconSelectionText = tooltip;
}
@@ -122,24 +122,27 @@ void AndroidManifestEditorIconWidget::setIcon(const QIcon &icon)
m_button->setIcon(icon);
}
void AndroidManifestEditorIconWidget::clearIcon()
{
removeIcon();
iconRemoved();
}
void AndroidManifestEditorIconWidget::loadIcon()
{
QString baseDir = manifestDir(m_textEditorWidget);
QString iconFile = baseDir + m_targetIconPath;
QString iconFile = baseDir + m_targetIconPath + m_targetIconFileName;
setIconFromPath(iconFile);
}
void AndroidManifestEditorIconWidget::setIconFromPath(const QString &iconPath)
{
iconSelected(iconPath);
if (!m_textEditorWidget)
return;
m_iconPath = iconPath;
QString baseDir = manifestDir(m_textEditorWidget);
copyIcon();
QString iconFile = baseDir + m_targetIconPath;
if (!m_scaled) {
QImage original(iconFile);
QImage original(iconPath);
if (!original.isNull() && m_scaledToOriginalAspectRatio) {
if ((original.width() > original.height() && m_buttonSize.height() > m_buttonSize.width())
|| (original.height() > original.width() && m_buttonSize.width() > m_buttonSize.height())) {
auto width = m_buttonSize.height();
@@ -148,9 +151,13 @@ void AndroidManifestEditorIconWidget::setIconFromPath(const QString &iconPath)
m_button->setMinimumSize(m_buttonSize);
m_button->setMaximumSize(m_buttonSize);
m_button->setIconSize(m_buttonSize);
auto targetWidth = m_iconSize.height();
auto targetHeight = m_iconSize.width();
m_iconSize = QSize(targetWidth, targetHeight);
}
}
copyIcon();
QString iconFile = baseDir + m_targetIconPath + m_targetIconFileName;
m_button->setIcon(QIcon(iconFile));
}
@@ -161,12 +168,13 @@ void AndroidManifestEditorIconWidget::selectIcon()
if (file.isEmpty())
return;
setIconFromPath(file);
iconSelected(file, this);
}
void AndroidManifestEditorIconWidget::removeIcon()
{
QString baseDir = manifestDir(m_textEditorWidget);
const QString targetPath = baseDir + m_targetIconPath;
const QString targetPath = baseDir + m_targetIconPath + m_targetIconFileName;
if (targetPath.isEmpty()) {
qCDebug(androidManifestEditorLog) << "Icon target path empty, cannot remove icon.";
return;
@@ -178,14 +186,39 @@ void AndroidManifestEditorIconWidget::removeIcon()
m_button->setIcon(QIcon());
}
bool AndroidManifestEditorIconWidget::hasIcon()
bool AndroidManifestEditorIconWidget::hasIcon() const
{
return !m_iconPath.isEmpty();
}
void AndroidManifestEditorIconWidget::setScaled(bool scaled)
void AndroidManifestEditorIconWidget::setScaledToOriginalAspectRatio(bool scaled)
{
m_scaled = scaled;
m_scaledToOriginalAspectRatio = scaled;
}
void AndroidManifestEditorIconWidget::setScaledWithoutStretching(bool scaled)
{
m_scaledWithoutStretching = scaled;
}
void AndroidManifestEditorIconWidget::setTargetIconFileName(const QString &targetIconFileName)
{
m_targetIconFileName = targetIconFileName;
}
void AndroidManifestEditorIconWidget::setTargetIconPath(const QString &targetIconPath)
{
m_targetIconPath = targetIconPath;
}
QString AndroidManifestEditorIconWidget::targetIconFileName() const
{
return m_targetIconFileName;
}
QString AndroidManifestEditorIconWidget::targetIconPath() const
{
return m_targetIconPath;
}
void AndroidManifestEditorIconWidget::setScaleWarningLabelVisible(bool visible)
@@ -194,17 +227,42 @@ void AndroidManifestEditorIconWidget::setScaleWarningLabelVisible(bool visible)
m_scaleWarningLabel->setVisible(visible);
}
static QImage scaleWithoutStretching(const QImage& original, const QSize& targetSize)
{
QImage ret(targetSize, QImage::Format_ARGB32);
ret.fill(Qt::white);
if (targetSize.height() > targetSize.width()) {
// portrait target, scale to width and paint in the vertical middle
QImage scaled = original.scaledToWidth(targetSize.width());
int heightDiffHalf = (targetSize.height() - scaled.height()) / 2;
QPainter painter(&ret);
QRect targetRect(0, heightDiffHalf, targetSize.width(), scaled.height());
QRect sourceRect(0, 0, scaled.width(), scaled.height());
painter.drawImage(targetRect, scaled, sourceRect);
} else if (targetSize.width() > targetSize.height()) {
// landscape target, scale to height and paint in the horizontal middle
QImage scaled = original.scaledToHeight(targetSize.height());
int widthDiffHalf = (targetSize.width() - scaled.width()) / 2;
QPainter painter(&ret);
QRect targetRect(widthDiffHalf, 0, scaled.width(), targetSize.height());
QRect sourceRect(0, 0, scaled.width(), scaled.height());
painter.drawImage(targetRect, scaled, sourceRect);
} else
ret = original.scaled(targetSize.width(), targetSize.height(),
Qt::KeepAspectRatio, Qt::SmoothTransformation);
return ret;
}
void AndroidManifestEditorIconWidget::copyIcon()
{
if (m_targetIconPath.isEmpty())
return;
QString baseDir = manifestDir(m_textEditorWidget);
const QString targetPath = baseDir + m_targetIconPath;
const QString targetPath = baseDir + m_targetIconPath + m_targetIconFileName;
if (targetPath.isEmpty()) {
qCDebug(androidManifestEditorLog) << "Icon target path empty, cannot copy icon.";
return;
}
QFileInfo targetFile(targetPath);
QImage original(m_iconPath);
if (m_iconPath != targetPath)
removeIcon();
@@ -221,15 +279,15 @@ void AndroidManifestEditorIconWidget::copyIcon()
m_iconPath.clear();
return;
}
QSize targetSize = m_iconSize;
if (m_scaled) {
QImage scaled = original.scaled(targetSize.width(), targetSize.height(),
Qt::KeepAspectRatio, Qt::SmoothTransformation);
setScaleWarningLabelVisible(scaled.width() > original.width() || scaled.height() > original.height());
scaled.save(targetPath);
} else
original.save(targetPath);
m_iconPath = m_targetIconPath;
QImage scaled;
if (!m_scaledWithoutStretching)
scaled = original.scaled(m_iconSize.width(), m_iconSize.height(),
Qt::KeepAspectRatio, Qt::SmoothTransformation);
else
scaled = scaleWithoutStretching(original, m_iconSize);
setScaleWarningLabelVisible(scaled.width() > original.width() || scaled.height() > original.height());
scaled.save(targetPath);
m_iconPath = targetPath;
} else {
m_iconPath.clear();
}

View File

@@ -50,14 +50,21 @@ public:
const QString &title,
const QString &tooltip,
TextEditor::TextEditorWidget *textEditorWidget = nullptr,
const QString &targetIconPath = {});
const QString &targetIconPath = {},
const QString &targetIconFileName = {});
void setIcon(const QIcon &icon);
void clearIcon();
void loadIcon();
void setIconFromPath(const QString &iconPath);
bool hasIcon();
void setScaled(bool scaled);
bool hasIcon() const;
void setScaledToOriginalAspectRatio(bool scaled);
void setScaledWithoutStretching(bool scaled);
void setTargetIconFileName(const QString &targetIconFileName);
void setTargetIconPath(const QString &targetIconPath);
QString targetIconFileName() const;
QString targetIconPath() const;
signals:
void iconSelected(const QString &path);
void iconSelected(const QString &path, AndroidManifestEditorIconWidget* iconWidget);
void iconRemoved();
private:
@@ -73,8 +80,10 @@ private:
TextEditor::TextEditorWidget *m_textEditorWidget = nullptr;
QString m_iconPath;
QString m_targetIconPath;
QString m_targetIconFileName;
QString m_iconSelectionText;
bool m_scaled = true;
bool m_scaledToOriginalAspectRatio = false;
bool m_scaledWithoutStretching = false;
};
} // namespace Internal

View File

@@ -806,9 +806,20 @@ void AndroidManifestEditorWidget::syncToWidgets(const QDomDocument &doc)
QDomElement activityElem = applicationElement.firstChildElement(QLatin1String("activity"));
m_activityNameLineEdit->setText(activityElem.attribute(QLatin1String("android:label")));
QString appIconValue = applicationElement.attribute(QLatin1String("android:icon"));
if (!appIconValue.isEmpty()) {
QLatin1String drawable = QLatin1String("@drawable/");
if (appIconValue.startsWith(drawable)) {
QString appIconName = appIconValue.mid(drawable.size());
m_iconButtons->setIconFileName(appIconName);
}
}
QDomElement metadataElem = activityElem.firstChildElement(QLatin1String("meta-data"));
enum ActivityParseGuard {none = 0, libName = 1, styleExtract = 2, stickySplash = 4, done = 8};
enum ActivityParseGuard {none = 0, libName = 1, styleExtract = 2, stickySplash = 4, splashImages = 8, done = 16};
int activityParseGuard = ActivityParseGuard::none;
enum SplashImageParseGuard {splashNone = 0, splash = 1, portraitSplash = 2, landscapeSplash = 4, splashDone = 8};
int splashParseGuard = SplashImageParseGuard::splashNone;
while (!metadataElem.isNull()) {
if (metadataElem.attribute(QLatin1String("android:name")) == QLatin1String("android.app.lib_name")
&& !(activityParseGuard & ActivityParseGuard::libName)) {
@@ -826,6 +837,29 @@ void AndroidManifestEditorWidget::syncToWidgets(const QDomDocument &doc)
QString sticky = metadataElem.attribute(QLatin1String("android:value"));
m_splashButtons->setSticky(sticky == QLatin1String("true"));
activityParseGuard |= ActivityParseGuard::stickySplash;
} else if (metadataElem.attribute(QLatin1String("android:name"))
.startsWith(QLatin1String("android.app.splash_screen_drawable"))
&& !(activityParseGuard & ActivityParseGuard::splashImages)
&& !(splashParseGuard & SplashImageParseGuard::splashDone)) {
QString attrName = metadataElem.attribute(QLatin1String("android:name"));
QLatin1String drawable = QLatin1String("@drawable/");
QString splashImageValue = metadataElem.attribute(QLatin1String("android:resource"));
QString splashImageName;
if (splashImageValue.startsWith(drawable)) {
splashImageName = splashImageValue.mid(drawable.size());
}
if (attrName == QLatin1String("android.app.splash_screen_drawable")) {
m_splashButtons->setImageFileName(splashImageName);
splashParseGuard |= SplashImageParseGuard::splash;
} else if (attrName == QLatin1String("android.app.splash_screen_drawable_portrait")) {
m_splashButtons->setPortraitImageFileName(splashImageName);
splashParseGuard |= SplashImageParseGuard::portraitSplash;
} else if (attrName == QLatin1String("android.app.splash_screen_drawable_landscape")) {
m_splashButtons->setLandscapeImageFileName(splashImageName);
splashParseGuard |= SplashImageParseGuard::landscapeSplash;
}
if (splashParseGuard & SplashImageParseGuard::splashDone)
activityParseGuard |= ActivityParseGuard::splashImages;
}
if (activityParseGuard == ActivityParseGuard::done)
break;
@@ -1066,7 +1100,7 @@ void AndroidManifestEditorWidget::parseApplication(QXmlStreamReader &reader, QXm
bool ensureIconAttribute = m_iconButtons->hasIcons();
if (ensureIconAttribute) {
keys << QLatin1String("android:icon");
values << QLatin1String("@drawable/icon");
values << (QLatin1String("@drawable/") + m_iconButtons->iconFileName());
} else
remove << QLatin1String("android:icon");
@@ -1114,15 +1148,15 @@ void AndroidManifestEditorWidget::parseSplashScreen(QXmlStreamWriter &writer)
{
if (m_splashButtons->hasImages())
writeMetadataElement("android.app.splash_screen_drawable",
"android:resource", "@drawable/logo",
"android:resource", QLatin1String("@drawable/") + m_splashButtons->imageFileName(),
writer);
if (m_splashButtons->hasPortraitImages())
writeMetadataElement("android.app.splash_screen_drawable_portrait",
"android:resource", "@drawable/logo_portrait",
"android:resource", QLatin1String("@drawable/") + m_splashButtons->portraitImageFileName(),
writer);
if (m_splashButtons->hasLandscapeImages())
writeMetadataElement("android.app.splash_screen_drawable_landscape",
"android:resource", "@drawable/logo_landscape",
"android:resource", QLatin1String("@drawable/") + m_splashButtons->landscapeImageFileName(),
writer);
if (m_splashButtons->isSticky())
writeMetadataElement("android.app.splash_screen_sticky",

View File

@@ -26,25 +26,30 @@
#include "splashiconcontainerwidget.h"
#include "androidmanifesteditoriconwidget.h"
#include <texteditor/textdocument.h>
#include <texteditor/texteditor.h>
#include <utils/utilsicons.h>
#include <QCheckBox>
#include <QFileInfo>
#include <QTabWidget>
#include <QToolButton>
#include <QVBoxLayout>
namespace Android {
namespace Internal {
namespace {
const QString highDpiImagePath = "/res/drawable-hdpi/logo.png";
const QString mediumDpiImagePath = "/res/drawable-mdpi/logo.png";
const QString lowDpiImagePath = "/res/drawable-ldpi/logo.png";
const QString highDpiLandscapeImagePath = "/res/drawable-hdpi/logo_landscape.png";
const QString mediumDpiLandscapeImagePath = "/res/drawable-mdpi/logo_landscape.png";
const QString lowDpiLandscapeImagePath = "/res/drawable-ldpi/logo_landscape.png";
const QString highDpiPortraitImagePath = "/res/drawable-hdpi/logo_portrait.png";
const QString mediumDpiPortraitImagePath = "/res/drawable-mdpi/logo_portrait.png";
const QString lowDpiPortraitImagePath = "/res/drawable-ldpi/logo_portrait.png";
const QString highDpiImagePath = QLatin1String("/res/drawable-hdpi/");
const QString mediumDpiImagePath = QLatin1String("/res/drawable-mdpi/");
const QString lowDpiImagePath = QLatin1String("/res/drawable-ldpi/");
const QString highDpiPortraitImagePath = QLatin1String("/res/drawable-port-hdpi/");
const QString mediumDpiPortraitImagePath = QLatin1String("/res/drawable-port-mdpi/");
const QString lowDpiPortraitImagePath = QLatin1String("/res/drawable-port-ldpi/");
const QString highDpiLandscapeImagePath = QLatin1String("/res/drawable-land-hdpi/");
const QString mediumDpiLandscapeImagePath = QLatin1String("/res/drawable-land-mdpi/");
const QString lowDpiLandscapeImagePath = QLatin1String("/res/drawable-land-ldpi/");
const QString imageSuffix = QLatin1String(".png");
const QSize lowDpiImageSize{200, 320};
const QSize mediumDpiImageSize{320, 480};
const QSize highDpiImageSize{480, 720};
@@ -53,6 +58,36 @@ const QSize mediumDpiLandscapeImageSize{480, 320};
const QSize highDpiLandscapeImageSize{720, 480};
const QSize displaySize{48, 72};
const QSize landscapeDisplaySize{72, 48};
QString manifestDir(TextEditor::TextEditorWidget *textEditorWidget)
{
// Get the manifest file's directory from its filepath.
return textEditorWidget->textDocument()->filePath().toFileInfo().absolutePath();
}
}
static AndroidManifestEditorIconWidget * addButtonToPage(QWidget *page,
const QSize &splashSize, const QSize &splashDisplaySize,
const QString &title, const QString &tooltip,
TextEditor::TextEditorWidget *textEditorWidget,
const QString &splashPath,
const QString &splashFileName,
QHBoxLayout *iconLayout,
QVector<AndroidManifestEditorIconWidget *> &buttonContainer,
bool scaledToOriginal,
bool scaledWithoutStretching)
{
auto splashButton = new AndroidManifestEditorIconWidget(page,
splashSize,
splashDisplaySize,
title,
tooltip,
textEditorWidget,
splashPath, splashFileName);
splashButton->setScaledToOriginalAspectRatio(scaledToOriginal);
splashButton->setScaledWithoutStretching(scaledWithoutStretching);
iconLayout->addWidget(splashButton);
buttonContainer.push_back(splashButton);
return splashButton;
}
static QWidget *createPage(TextEditor::TextEditorWidget *textEditorWidget,
@@ -62,45 +97,58 @@ static QWidget *createPage(TextEditor::TextEditorWidget *textEditorWidget,
const QSize &splashSize,
const QSize &portraitSplashSize,
const QSize &landscapeSplashSize,
const QString &splashSizeTooltip,
const QString &portraitSplashSizeTooltip,
const QString &landscapeSplashSizeTooltip,
const QString &splashPath,
const QString &splashFileName,
const QString &portraitSplashPath,
const QString &landscapeSplashPath)
const QString &portraitSplashFileName,
const QString &landscapeSplashPath,
const QString &landscapeSplashFileName)
{
QWidget *page = new QWidget();
auto iconLayout = new QHBoxLayout(page);
auto splashButton = new AndroidManifestEditorIconWidget(page,
splashSize,
landscapeDisplaySize,
SplashIconContainerWidget::tr("Splash screen"),
SplashIconContainerWidget::tr("Select splash screen image"),
textEditorWidget, splashPath);
splashButton->setScaled(false);
iconLayout->addWidget(splashButton);
buttonContainer.push_back(splashButton);
iconLayout->addStretch(1);
auto splashButton= addButtonToPage(page, splashSize, landscapeDisplaySize,
SplashIconContainerWidget::tr("Splash screen"),
SplashIconContainerWidget::tr("Select splash screen image")
+ splashSizeTooltip,
textEditorWidget,
splashPath, splashFileName + imageSuffix,
iconLayout,
buttonContainer,
true, false);
auto portraitButton = new AndroidManifestEditorIconWidget(page,
portraitSplashSize,
displaySize,
SplashIconContainerWidget::tr("Portrait splash screen"),
SplashIconContainerWidget::tr("Select portrait splash screen image"),
textEditorWidget, portraitSplashPath);
iconLayout->addWidget(portraitButton);
portraitButtonContainer.push_back(portraitButton);
iconLayout->addStretch(1);
auto portraitButton = addButtonToPage(page, portraitSplashSize, displaySize,
SplashIconContainerWidget::tr("Portrait splash screen"),
SplashIconContainerWidget::tr("Select portrait splash screen image")
+ portraitSplashSizeTooltip,
textEditorWidget,
portraitSplashPath, portraitSplashFileName + imageSuffix,
iconLayout,
portraitButtonContainer,
false, true);
auto landscapeButton = new AndroidManifestEditorIconWidget(page,
landscapeSplashSize,
landscapeDisplaySize,
SplashIconContainerWidget::tr("Landscape splash screen"),
SplashIconContainerWidget::tr("Select landscape splash screen image"),
textEditorWidget, landscapeSplashPath);
iconLayout->addWidget(landscapeButton);
landscapeButtonContainer.push_back(landscapeButton);
iconLayout->addStretch(1);
iconLayout->addStretch(6);
auto landscapeButton = addButtonToPage(page, landscapeSplashSize, landscapeDisplaySize,
SplashIconContainerWidget::tr("Landscape splash screen"),
SplashIconContainerWidget::tr("Select landscape splash screen image")
+ landscapeSplashSizeTooltip,
textEditorWidget,
landscapeSplashPath, landscapeSplashFileName + imageSuffix,
iconLayout,
landscapeButtonContainer,
false, true);
auto clearButton = new QToolButton(page);
clearButton->setText(SplashIconContainerWidget::tr("Clear all"));
iconLayout->addWidget(clearButton);
iconLayout->setAlignment(clearButton, Qt::AlignVCenter);
SplashIconContainerWidget::connect(clearButton, &QAbstractButton::clicked,
splashButton, &AndroidManifestEditorIconWidget::clearIcon);
SplashIconContainerWidget::connect(clearButton, &QAbstractButton::clicked,
portraitButton, &AndroidManifestEditorIconWidget::clearIcon);
SplashIconContainerWidget::connect(clearButton, &QAbstractButton::clicked,
landscapeButton, &AndroidManifestEditorIconWidget::clearIcon);
return page;
}
@@ -108,7 +156,7 @@ static QWidget *createPage(TextEditor::TextEditorWidget *textEditorWidget,
SplashIconContainerWidget::SplashIconContainerWidget(
QWidget *parent,
TextEditor::TextEditorWidget *textEditorWidget)
: QWidget(parent)
: QWidget(parent), m_textEditorWidget(textEditorWidget)
{
auto layout = new QVBoxLayout(this);
m_stickyCheck = new QCheckBox(tr("Sticky splash screen"), this);
@@ -121,39 +169,55 @@ SplashIconContainerWidget::SplashIconContainerWidget(
highDpiImageSize,
highDpiImageSize,
highDpiLandscapeImageSize,
highDpiImagePath, highDpiPortraitImagePath, highDpiLandscapeImagePath);
tr(" (480x720)"), tr(" (480x720)"), tr(" (720x480)"),
highDpiImagePath, m_imageFileName,
highDpiImagePath, m_portraitImageFileName,
highDpiImagePath, m_landscapeImageFileName);
tab->addTab(hdpiPage, tr("High DPI splash screen"));
auto mdpiPage = createPage(textEditorWidget,
m_imageButtons, m_portraitImageButtons, m_landscapeImageButtons,
mediumDpiImageSize,
mediumDpiImageSize,
mediumDpiLandscapeImageSize,
mediumDpiImagePath, mediumDpiPortraitImagePath, mediumDpiLandscapeImagePath);
tr(" (320x480)"), tr(" (320x480)"), tr(" (320x480)"),
mediumDpiImagePath, m_imageFileName,
mediumDpiImagePath, m_portraitImageFileName,
mediumDpiImagePath, m_landscapeImageFileName);
tab->addTab(mdpiPage, tr("Medium DPI splash screen"));
auto ldpiPage = createPage(textEditorWidget,
m_imageButtons, m_portraitImageButtons, m_landscapeImageButtons,
lowDpiImageSize,
lowDpiImageSize,
lowDpiLandscapeImageSize,
lowDpiImagePath, lowDpiPortraitImagePath, lowDpiLandscapeImagePath);
tr(" (200x320)"), tr(" (200x320)"), tr(" (320x200)"),
lowDpiImagePath, m_imageFileName,
lowDpiImagePath, m_portraitImageFileName,
lowDpiImagePath, m_landscapeImageFileName);
tab->addTab(ldpiPage, tr("Low DPI splash screen"));
layout->addWidget(m_stickyCheck);
layout->setAlignment(m_stickyCheck, Qt::AlignLeft);
layout->addWidget(tab);
for (auto &&imageButton : m_imageButtons)
for (auto &&imageButton : m_imageButtons) {
connect(imageButton, &AndroidManifestEditorIconWidget::iconSelected,
this, &SplashIconContainerWidget::splashScreensModified);
connect(imageButton, &AndroidManifestEditorIconWidget::iconSelected,
this, &SplashIconContainerWidget::imageSelected);
}
for (auto &&imageButton : m_portraitImageButtons) {
connect(imageButton, &AndroidManifestEditorIconWidget::iconSelected,
this, &SplashIconContainerWidget::splashScreensModified);
connect(imageButton, &AndroidManifestEditorIconWidget::iconRemoved,
this, &SplashIconContainerWidget::splashScreensModified);
connect(imageButton, &AndroidManifestEditorIconWidget::iconSelected,
this, &SplashIconContainerWidget::imageSelected);
}
for (auto &&imageButton : m_landscapeImageButtons) {
connect(imageButton, &AndroidManifestEditorIconWidget::iconSelected,
this, &SplashIconContainerWidget::splashScreensModified);
connect(imageButton, &AndroidManifestEditorIconWidget::iconRemoved,
this, &SplashIconContainerWidget::splashScreensModified);
connect(imageButton, &AndroidManifestEditorIconWidget::iconSelected,
this, &SplashIconContainerWidget::imageSelected);
}
connect(m_stickyCheck, &QCheckBox::stateChanged, [this](int state) {
bool old = m_splashScreenSticky;
@@ -163,17 +227,48 @@ SplashIconContainerWidget::SplashIconContainerWidget(
});
}
void SplashIconContainerWidget::loadImages()
static void maybeChangeImagePath(AndroidManifestEditorIconWidget *widget,
TextEditor::TextEditorWidget *m_textEditorWidget,
const QString &highDpiAlternativePath,
const QString &mediumDpiAlternativePath,
const QString &lowDpiAlternativePath)
{
for (auto &&imageButton : m_imageButtons)
imageButton->loadIcon();
for (auto &&imageButton : m_portraitImageButtons)
imageButton->loadIcon();
for (auto &&imageButton : m_landscapeImageButtons)
imageButton->loadIcon();
QString currentPath = widget->targetIconPath();
QString alternativePath = currentPath;
if (currentPath == highDpiImagePath)
alternativePath = highDpiAlternativePath;
else if (currentPath == mediumDpiImagePath)
alternativePath = mediumDpiAlternativePath;
else if (currentPath == lowDpiImagePath)
alternativePath = lowDpiAlternativePath;
QString baseDir = manifestDir(m_textEditorWidget);
const QString targetPath = baseDir + alternativePath + widget->targetIconFileName();
QFileInfo image(targetPath);
if (image.exists())
widget->setTargetIconPath(alternativePath);
}
bool SplashIconContainerWidget::hasImages()
void SplashIconContainerWidget::loadImages()
{
for (auto &&imageButton : m_imageButtons) {
imageButton->setTargetIconFileName(m_imageFileName + imageSuffix);
imageButton->loadIcon();
}
for (auto &&imageButton : m_portraitImageButtons) {
imageButton->setTargetIconFileName(m_portraitImageFileName + imageSuffix);
maybeChangeImagePath(imageButton, m_textEditorWidget,
highDpiPortraitImagePath, mediumDpiPortraitImagePath, lowDpiPortraitImagePath);
imageButton->loadIcon();
}
for (auto &&imageButton : m_landscapeImageButtons) {
imageButton->setTargetIconFileName(m_landscapeImageFileName + imageSuffix);
maybeChangeImagePath(imageButton, m_textEditorWidget,
highDpiLandscapeImagePath, mediumDpiLandscapeImagePath, lowDpiLandscapeImagePath);
imageButton->loadIcon();
}
}
bool SplashIconContainerWidget::hasImages() const
{
for (auto &&iconButton : m_imageButtons) {
if (iconButton->hasIcon())
@@ -182,7 +277,7 @@ bool SplashIconContainerWidget::hasImages()
return false;
}
bool SplashIconContainerWidget::hasPortraitImages()
bool SplashIconContainerWidget::hasPortraitImages() const
{
for (auto &&iconButton : m_portraitImageButtons) {
if (iconButton->hasIcon())
@@ -191,7 +286,7 @@ bool SplashIconContainerWidget::hasPortraitImages()
return false;
}
bool SplashIconContainerWidget::hasLandscapeImages()
bool SplashIconContainerWidget::hasLandscapeImages() const
{
for (auto &&iconButton : m_landscapeImageButtons) {
if (iconButton->hasIcon())
@@ -200,7 +295,7 @@ bool SplashIconContainerWidget::hasLandscapeImages()
return false;
}
bool SplashIconContainerWidget::isSticky()
bool SplashIconContainerWidget::isSticky() const
{
return m_splashScreenSticky;
}
@@ -211,5 +306,72 @@ void SplashIconContainerWidget::setSticky(bool sticky)
m_stickyCheck->setCheckState(m_splashScreenSticky ? Qt::Checked : Qt::Unchecked);
}
QString SplashIconContainerWidget::imageFileName() const
{
return m_imageFileName;
}
QString SplashIconContainerWidget::landscapeImageFileName() const
{
return m_landscapeImageFileName;
}
QString SplashIconContainerWidget::portraitImageFileName() const
{
return m_portraitImageFileName;
}
void SplashIconContainerWidget::setImageFileName(const QString &name)
{
m_imageFileName = name;
}
void SplashIconContainerWidget::setLandscapeImageFileName(const QString &name)
{
m_landscapeImageFileName = name;
}
void SplashIconContainerWidget::setPortraitImageFileName(const QString &name)
{
m_portraitImageFileName = name;
}
static void reflectImage(const QString &path,
AndroidManifestEditorIconWidget *iconWidget,
const QVector<AndroidManifestEditorIconWidget *> &source,
QVector<AndroidManifestEditorIconWidget *> *firstTarget,
QVector<AndroidManifestEditorIconWidget *> *secondTarget = nullptr,
Qt::Orientation *imageOrientation = nullptr)
{
for (int i = 0; i < source.size(); ++i)
if (source[i] == iconWidget) {
if (firstTarget && !(*firstTarget)[i]->hasIcon()
&& (!imageOrientation || *imageOrientation == Qt::Horizontal))
(*firstTarget)[i]->setIconFromPath(path);
if (secondTarget && !(*secondTarget)[i]->hasIcon()
&& (!imageOrientation || *imageOrientation == Qt::Vertical))
(*secondTarget)[i]->setIconFromPath(path);
break;
}
}
void SplashIconContainerWidget::imageSelected(const QString &path, AndroidManifestEditorIconWidget *iconWidget)
{
QImage original(path);
Qt::Orientation orientation = Qt::Horizontal;
if (!original.isNull()) {
if (original.width() > original.height()) {
orientation = Qt::Horizontal;
} else {
orientation = Qt::Vertical;
}
}
reflectImage(path, iconWidget,
m_imageButtons, &m_portraitImageButtons, &m_landscapeImageButtons, &orientation);
reflectImage(path, iconWidget, m_portraitImageButtons, &m_landscapeImageButtons);
reflectImage(path, iconWidget, m_landscapeImageButtons, &m_portraitImageButtons);
}
} // namespace Internal
} // namespace Android

View File

@@ -46,21 +46,33 @@ class SplashIconContainerWidget : public QWidget
Q_OBJECT
public:
explicit SplashIconContainerWidget(QWidget *parent,
TextEditor::TextEditorWidget *textEditorWidget);
TextEditor::TextEditorWidget *textEditorWidget);
void loadImages();
bool hasImages();
bool hasPortraitImages();
bool hasLandscapeImages();
bool isSticky();
bool hasImages() const;
bool hasPortraitImages() const;
bool hasLandscapeImages() const;
bool isSticky() const;
void setSticky(bool sticky);
QString imageFileName() const;
QString landscapeImageFileName() const;
QString portraitImageFileName() const;
void setImageFileName(const QString &name);
void setLandscapeImageFileName(const QString &name);
void setPortraitImageFileName(const QString &name);
signals:
void splashScreensModified();
private:
void imageSelected(const QString &path, AndroidManifestEditorIconWidget *iconWidget);
private:
TextEditor::TextEditorWidget *m_textEditorWidget = nullptr;
QVector<AndroidManifestEditorIconWidget *> m_imageButtons;
QVector<AndroidManifestEditorIconWidget *> m_portraitImageButtons;
QVector<AndroidManifestEditorIconWidget *> m_landscapeImageButtons;
bool m_splashScreenSticky = false;
QCheckBox *m_stickyCheck = nullptr;
QString m_imageFileName = QLatin1String("logo");
QString m_landscapeImageFileName = QLatin1String("logo_landscape");
QString m_portraitImageFileName = QLatin1String("logo_portrait");
};
} // namespace Internal