2020-03-02 13:59:52 +02:00
|
|
|
/****************************************************************************
|
|
|
|
|
**
|
|
|
|
|
** 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>
|
2020-06-09 16:25:13 +03:00
|
|
|
#include <QPainter>
|
2020-03-02 13:59:52 +02:00
|
|
|
#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(
|
2020-06-02 09:33:21 +03:00
|
|
|
QWidget *parent, const QSize &iconSize, const QSize &buttonSize, const QString &title,
|
2020-03-02 13:59:52 +02:00
|
|
|
const QString &tooltip,
|
|
|
|
|
TextEditor::TextEditorWidget *textEditorWidget,
|
2020-06-09 16:25:13 +03:00
|
|
|
const QString &targetIconPath,
|
|
|
|
|
const QString &targetIconFileName)
|
2020-06-02 09:33:21 +03:00
|
|
|
: QWidget(parent), m_iconSize(iconSize), m_buttonSize(buttonSize),
|
2020-06-09 16:25:13 +03:00
|
|
|
m_textEditorWidget(textEditorWidget),
|
|
|
|
|
m_targetIconPath(targetIconPath), m_targetIconFileName(targetIconFileName)
|
2020-03-02 13:59:52 +02:00
|
|
|
{
|
|
|
|
|
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);
|
2020-06-09 16:25:13 +03:00
|
|
|
if (clearButton)
|
2020-03-02 13:59:52 +02:00
|
|
|
connect(clearButton, &QAbstractButton::clicked,
|
2020-06-09 16:25:13 +03:00
|
|
|
this, &AndroidManifestEditorIconWidget::clearIcon);
|
2020-03-02 13:59:52 +02:00
|
|
|
m_iconSelectionText = tooltip;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void AndroidManifestEditorIconWidget::setIcon(const QIcon &icon)
|
|
|
|
|
{
|
|
|
|
|
m_button->setIcon(icon);
|
|
|
|
|
}
|
|
|
|
|
|
2020-06-09 16:25:13 +03:00
|
|
|
void AndroidManifestEditorIconWidget::clearIcon()
|
|
|
|
|
{
|
|
|
|
|
removeIcon();
|
|
|
|
|
iconRemoved();
|
|
|
|
|
}
|
|
|
|
|
|
2020-03-02 13:59:52 +02:00
|
|
|
void AndroidManifestEditorIconWidget::loadIcon()
|
|
|
|
|
{
|
|
|
|
|
QString baseDir = manifestDir(m_textEditorWidget);
|
2020-06-09 16:25:13 +03:00
|
|
|
QString iconFile = baseDir + m_targetIconPath + m_targetIconFileName;
|
2020-03-02 13:59:52 +02:00
|
|
|
setIconFromPath(iconFile);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void AndroidManifestEditorIconWidget::setIconFromPath(const QString &iconPath)
|
|
|
|
|
{
|
2020-06-02 09:33:21 +03:00
|
|
|
if (!m_textEditorWidget)
|
2020-03-02 13:59:52 +02:00
|
|
|
return;
|
|
|
|
|
m_iconPath = iconPath;
|
|
|
|
|
QString baseDir = manifestDir(m_textEditorWidget);
|
2020-06-09 16:25:13 +03:00
|
|
|
QImage original(iconPath);
|
|
|
|
|
if (!original.isNull() && m_scaledToOriginalAspectRatio) {
|
2020-06-02 09:33:21 +03:00
|
|
|
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();
|
|
|
|
|
auto height = m_buttonSize.width();
|
|
|
|
|
m_buttonSize = QSize(width, height);
|
|
|
|
|
m_button->setMinimumSize(m_buttonSize);
|
|
|
|
|
m_button->setMaximumSize(m_buttonSize);
|
|
|
|
|
m_button->setIconSize(m_buttonSize);
|
2020-06-09 16:25:13 +03:00
|
|
|
auto targetWidth = m_iconSize.height();
|
|
|
|
|
auto targetHeight = m_iconSize.width();
|
|
|
|
|
m_iconSize = QSize(targetWidth, targetHeight);
|
2020-06-02 09:33:21 +03:00
|
|
|
}
|
|
|
|
|
}
|
2020-06-09 16:25:13 +03:00
|
|
|
copyIcon();
|
|
|
|
|
QString iconFile = baseDir + m_targetIconPath + m_targetIconFileName;
|
2020-03-02 13:59:52 +02:00
|
|
|
m_button->setIcon(QIcon(iconFile));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void AndroidManifestEditorIconWidget::selectIcon()
|
|
|
|
|
{
|
|
|
|
|
QString file = QFileDialog::getOpenFileName(this, m_iconSelectionText,
|
|
|
|
|
QDir::homePath(), fileDialogIconFiles);
|
|
|
|
|
if (file.isEmpty())
|
|
|
|
|
return;
|
|
|
|
|
setIconFromPath(file);
|
2020-06-09 16:25:13 +03:00
|
|
|
iconSelected(file, this);
|
2020-03-02 13:59:52 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void AndroidManifestEditorIconWidget::removeIcon()
|
|
|
|
|
{
|
|
|
|
|
QString baseDir = manifestDir(m_textEditorWidget);
|
2020-06-09 16:25:13 +03:00
|
|
|
const QString targetPath = baseDir + m_targetIconPath + m_targetIconFileName;
|
2020-03-02 13:59:52 +02:00
|
|
|
if (targetPath.isEmpty()) {
|
|
|
|
|
qCDebug(androidManifestEditorLog) << "Icon target path empty, cannot remove icon.";
|
|
|
|
|
return;
|
|
|
|
|
}
|
2020-06-02 09:33:21 +03:00
|
|
|
QFile targetFile(targetPath);
|
|
|
|
|
targetFile.remove();
|
|
|
|
|
m_iconPath.clear();
|
2020-03-02 13:59:52 +02:00
|
|
|
setScaleWarningLabelVisible(false);
|
|
|
|
|
m_button->setIcon(QIcon());
|
|
|
|
|
}
|
|
|
|
|
|
2020-06-09 16:25:13 +03:00
|
|
|
bool AndroidManifestEditorIconWidget::hasIcon() const
|
2020-03-02 13:59:52 +02:00
|
|
|
{
|
2020-03-12 13:34:26 +02:00
|
|
|
return !m_iconPath.isEmpty();
|
2020-03-02 13:59:52 +02:00
|
|
|
}
|
|
|
|
|
|
2020-06-09 16:25:13 +03:00
|
|
|
void AndroidManifestEditorIconWidget::setScaledToOriginalAspectRatio(bool 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
|
2020-06-02 09:33:21 +03:00
|
|
|
{
|
2020-06-09 16:25:13 +03:00
|
|
|
return m_targetIconFileName;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QString AndroidManifestEditorIconWidget::targetIconPath() const
|
|
|
|
|
{
|
|
|
|
|
return m_targetIconPath;
|
2020-06-02 09:33:21 +03:00
|
|
|
}
|
|
|
|
|
|
2020-03-02 13:59:52 +02:00
|
|
|
void AndroidManifestEditorIconWidget::setScaleWarningLabelVisible(bool visible)
|
|
|
|
|
{
|
|
|
|
|
if (m_scaleWarningLabel)
|
|
|
|
|
m_scaleWarningLabel->setVisible(visible);
|
|
|
|
|
}
|
|
|
|
|
|
2020-06-09 16:25:13 +03:00
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
2020-03-02 13:59:52 +02:00
|
|
|
void AndroidManifestEditorIconWidget::copyIcon()
|
|
|
|
|
{
|
|
|
|
|
if (m_targetIconPath.isEmpty())
|
|
|
|
|
return;
|
|
|
|
|
QString baseDir = manifestDir(m_textEditorWidget);
|
2020-06-09 16:25:13 +03:00
|
|
|
const QString targetPath = baseDir + m_targetIconPath + m_targetIconFileName;
|
2020-03-02 13:59:52 +02:00
|
|
|
if (targetPath.isEmpty()) {
|
|
|
|
|
qCDebug(androidManifestEditorLog) << "Icon target path empty, cannot copy icon.";
|
|
|
|
|
return;
|
|
|
|
|
}
|
2020-06-02 09:33:21 +03:00
|
|
|
QImage original(m_iconPath);
|
|
|
|
|
if (m_iconPath != targetPath)
|
|
|
|
|
removeIcon();
|
|
|
|
|
if (original.isNull()) {
|
|
|
|
|
m_iconPath.clear();
|
|
|
|
|
return;
|
|
|
|
|
}
|
2020-03-02 13:59:52 +02:00
|
|
|
if (m_iconPath == targetPath)
|
|
|
|
|
return;
|
|
|
|
|
if (!targetPath.isEmpty() && !original.isNull()) {
|
|
|
|
|
QDir dir;
|
|
|
|
|
if (!dir.mkpath(QFileInfo(targetPath).absolutePath())) {
|
|
|
|
|
qCDebug(androidManifestEditorLog) << "Cannot create icon target path.";
|
|
|
|
|
m_iconPath.clear();
|
|
|
|
|
return;
|
|
|
|
|
}
|
2020-06-09 16:25:13 +03:00
|
|
|
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;
|
2020-03-02 13:59:52 +02:00
|
|
|
} else {
|
|
|
|
|
m_iconPath.clear();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} // namespace Internal
|
|
|
|
|
} // namespace Android
|