557 lines
18 KiB
C++
557 lines
18 KiB
C++
/******************************************************************************
|
|
* Copyright 2016 David Rosca <nowrep@gmail.com> *
|
|
* *
|
|
* This library is free software; you can redistribute it and/or *
|
|
* modify it under the terms of the GNU Library General Public *
|
|
* License as published by the Free Software Foundation; either *
|
|
* version 2 of the License, or (at your option) any later version. *
|
|
* *
|
|
* This library is distributed in the hope that it will be useful, *
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
|
* Library General Public License for more details. *
|
|
* *
|
|
* You should have received a copy of the GNU Library General Public License *
|
|
* along with this library; see the file COPYING.LIB. If not, write to *
|
|
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, *
|
|
* Boston, MA 02110-1301, USA. *
|
|
*******************************************************************************/
|
|
|
|
#include "iconitemtest.h"
|
|
|
|
#include <QIcon>
|
|
#include <QQmlEngine>
|
|
#include <QQmlContext>
|
|
#include <QQmlComponent>
|
|
#include <QQuickItemGrabResult>
|
|
#include <QSignalSpy>
|
|
|
|
#include <KIconLoader>
|
|
#include <KIconEngine>
|
|
#include <KIconTheme>
|
|
|
|
#include "plasma/theme.h"
|
|
#include "plasma/svg.h"
|
|
|
|
static bool imageIsEmpty(const QImage &img)
|
|
{
|
|
for (int i = 0; i < img.width(); ++i) {
|
|
for (int j = 0; j < img.height(); ++j) {
|
|
if (img.pixel(i, j) != 0) {
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
void IconItemTest::initTestCase()
|
|
{
|
|
if (qgetenv("XDG_DATA_DIRS").isEmpty()) {
|
|
QWARN("\n"
|
|
" !!!\n"
|
|
" Switching QStandardPaths into testing mode.\n"
|
|
" Make sure xdg data can be found or set XDG_DATA_DIRS.\n"
|
|
" !!!\n");
|
|
}
|
|
|
|
// make our theme in search path
|
|
qputenv("XDG_DATA_DIRS",
|
|
qgetenv("XDG_DATA_DIRS") + ":" + QFINDTESTDATA("data").toLocal8Bit());
|
|
|
|
// set default icon theme to test-theme
|
|
QStandardPaths::setTestModeEnabled(true);
|
|
|
|
QString configPath = QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation);
|
|
|
|
if(!QDir(configPath).mkpath(QStringLiteral("."))) {
|
|
qFatal("Failed to create test configuration directory.");
|
|
}
|
|
|
|
QFile::remove(configPath);
|
|
|
|
QIcon::setThemeSearchPaths({QFINDTESTDATA("data/icons")});
|
|
QIcon::setThemeName("test-theme");
|
|
|
|
KIconTheme::forceThemeForTests("test-theme");
|
|
KIconTheme::reconfigure();
|
|
KIconLoader::global()->reconfigure(QString());
|
|
|
|
m_view = new QQuickView();
|
|
m_view->setSource(QUrl::fromLocalFile(QFINDTESTDATA("data/view.qml")));
|
|
m_view->show();
|
|
QVERIFY(QTest::qWaitForWindowExposed(m_view));
|
|
|
|
if (!m_view->rootObject() || !m_view->rootObject()->grabToImage()) {
|
|
QSKIP("Cannot grab item to image.");
|
|
}
|
|
}
|
|
|
|
void IconItemTest::cleanupTestCase()
|
|
{
|
|
delete m_view;
|
|
}
|
|
|
|
void IconItemTest::init()
|
|
{
|
|
Plasma::Theme().setThemeName(QStringLiteral("default"));
|
|
}
|
|
|
|
void IconItemTest::cleanup()
|
|
{
|
|
qDeleteAll(m_view->rootObject()->childItems());
|
|
}
|
|
|
|
QQuickItem *IconItemTest::createIconItem()
|
|
{
|
|
QByteArray iconQml =
|
|
"import QtQuick 2.0;"
|
|
"import org.kde.plasma.core 2.0 as PlasmaCore;"
|
|
"PlasmaCore.IconItem {"
|
|
" id: root;"
|
|
"}";
|
|
|
|
QQmlComponent component(m_view->engine());
|
|
|
|
QSignalSpy spy(&component, SIGNAL(statusChanged(QQmlComponent::Status)));
|
|
component.setData(iconQml, QUrl("test://iconTest"));
|
|
if (component.status() != QQmlComponent::Ready) {
|
|
spy.wait();
|
|
}
|
|
|
|
QQuickItem *item = qobject_cast<QQuickItem*>(component.create(m_view->engine()->rootContext()));
|
|
Q_ASSERT(item && qstrcmp(item->metaObject()->className(), "IconItem") == 0);
|
|
item->setParentItem(m_view->rootObject());
|
|
return item;
|
|
}
|
|
|
|
QImage IconItemTest::grabImage(QQuickItem *item)
|
|
{
|
|
QSharedPointer<QQuickItemGrabResult> grab = item->grabToImage();
|
|
QSignalSpy spy(grab.data(), SIGNAL(ready()));
|
|
spy.wait();
|
|
return grab->image();
|
|
}
|
|
|
|
Plasma::Svg *IconItemTest::findPlasmaSvg(QQuickItem *item)
|
|
{
|
|
return item->findChild<Plasma::Svg *>();
|
|
}
|
|
|
|
void IconItemTest::changeTheme(Plasma::Theme *theme, const QString &themeName)
|
|
{
|
|
if (theme->themeName() != themeName) {
|
|
QSignalSpy spy(theme, SIGNAL(themeChanged()));
|
|
theme->setThemeName(themeName);
|
|
spy.wait();
|
|
}
|
|
}
|
|
|
|
// ------ Tests
|
|
|
|
void IconItemTest::loadPixmap()
|
|
{
|
|
QScopedPointer<QQuickItem> item(createIconItem());
|
|
QPixmap sourcePixmap(QFINDTESTDATA("data/test_image.png"));
|
|
|
|
item->setSize(sourcePixmap.size());
|
|
item->setProperty("source", sourcePixmap);
|
|
QVERIFY(item->property("valid").toBool());
|
|
|
|
QImage capture = grabImage(item.data());
|
|
QCOMPARE(capture, sourcePixmap.toImage().convertToFormat(QImage::Format_ARGB32_Premultiplied));
|
|
QCOMPARE(sourcePixmap, item->property("source").value<QPixmap>());
|
|
}
|
|
|
|
//tests setting icon from a QImage
|
|
void IconItemTest::loadImage()
|
|
{
|
|
QScopedPointer<QQuickItem> item(createIconItem());
|
|
QImage sourceImage(QFINDTESTDATA("data/test_image.png"));
|
|
|
|
item->setSize(sourceImage.size());
|
|
item->setProperty("source", sourceImage);
|
|
QVERIFY(item->property("valid").toBool());
|
|
|
|
QImage capture = grabImage(item.data());
|
|
QCOMPARE(capture, sourceImage.convertToFormat(QImage::Format_ARGB32_Premultiplied));
|
|
QCOMPARE(sourceImage, item->property("source").value<QImage>());
|
|
}
|
|
|
|
void IconItemTest::invalidIcon()
|
|
{
|
|
QString name("tst-plasma-framework-invalid-icon-name");
|
|
KIconLoader iconLoader("tst_plasma-framework");
|
|
if (iconLoader.hasIcon(name)) {
|
|
QSKIP("Current icon theme has 'tst-plasma-framework-invalid-icon-name' icon.");
|
|
}
|
|
|
|
QQuickItem *item = createIconItem();
|
|
item->setProperty("source", name);
|
|
QVERIFY(!item->property("valid").toBool());
|
|
QVERIFY(imageIsEmpty(grabImage(item)));
|
|
}
|
|
|
|
void IconItemTest::usesPlasmaTheme()
|
|
{
|
|
// usesPlasmaTheme = true (default)
|
|
QQuickItem *item1 = createIconItem();
|
|
item1->setProperty("source", "konversation");
|
|
QVERIFY(item1->property("valid").toBool());
|
|
QCOMPARE(QStringLiteral("konversation"), item1->property("source").toString());
|
|
|
|
Plasma::Svg svg;
|
|
svg.setContainsMultipleImages(true);
|
|
svg.setImagePath("icons/konversation");
|
|
|
|
QImage img1 = grabImage(item1);
|
|
QImage img2 = svg.image(QSize(item1->width(), item1->height()), "konversation");
|
|
QVERIFY(!imageIsEmpty(img1));
|
|
QVERIFY(!imageIsEmpty(img2));
|
|
QCOMPARE(img1, img2);
|
|
|
|
// usesPlasmaTheme = false
|
|
QQuickItem *item2 = createIconItem();
|
|
item2->setProperty("usesPlasmaTheme", false);
|
|
item2->setProperty("source", "konversation");
|
|
|
|
img1 = grabImage(item2);
|
|
// This depends on konversation icon being different in Plasma Breeze theme
|
|
// and our test icon theme
|
|
QVERIFY(img1 != img2);
|
|
}
|
|
|
|
void IconItemTest::animation()
|
|
{
|
|
// animated = true (default)
|
|
QQuickItem *item1 = createIconItem();
|
|
item1->setProperty("source", "user-away");
|
|
// first icon is not animated
|
|
QImage userAwayImg = grabImage(item1);
|
|
|
|
item1->setProperty("source", "user-busy");
|
|
grabImage(item1);
|
|
item1->setProperty("source", "user-away");
|
|
// animation from user-busy -> user-away
|
|
QVERIFY(userAwayImg != grabImage(item1));
|
|
|
|
// animated = false
|
|
QQuickItem *item2 = createIconItem();
|
|
item2->setProperty("animated", false);
|
|
item2->setProperty("source", "user-busy");
|
|
QImage userBusyImg = grabImage(item2);
|
|
|
|
item2->setProperty("source", "user-away");
|
|
QCOMPARE(userAwayImg, grabImage(item2));
|
|
|
|
item2->setProperty("source", "user-busy");
|
|
QCOMPARE(userBusyImg, grabImage(item2));
|
|
}
|
|
|
|
void IconItemTest::animationAfterHide()
|
|
{
|
|
QQuickItem *item1 = createIconItem();
|
|
QQuickItem *item2 = createIconItem();
|
|
item1->setProperty("source", "user-away");
|
|
item2->setProperty("source", "user-busy");
|
|
// first icon is not animated
|
|
QImage userAwayImg = grabImage(item1);
|
|
QImage userBusyImg = grabImage(item2);
|
|
|
|
item1->setProperty("source", "user-busy");
|
|
grabImage(item1);
|
|
item1->setProperty("visible", "false");
|
|
item1->setProperty("visible", "true");
|
|
item1->setProperty("source", "user-away");
|
|
// icon was hidden, no animation
|
|
QCOMPARE(userAwayImg, grabImage(item1));
|
|
|
|
item1->setProperty("source", "user-busy");
|
|
QVERIFY(userBusyImg != grabImage(item1));
|
|
}
|
|
|
|
void IconItemTest::bug_359388()
|
|
{
|
|
if (!KIconTheme::list().contains("hicolor")) {
|
|
// This test depends on hicolor icon theme to resolve the icon.
|
|
QSKIP("hicolor icon theme not available");
|
|
}
|
|
|
|
QString name("bug359388");
|
|
KIconLoader iconLoader("tst_plasma-framework");
|
|
QIcon customThemeIcon(new KIconEngine(name, &iconLoader));
|
|
if (iconLoader.hasIcon(name)) {
|
|
QSKIP("Current icon theme has 'bug359388' icon.");
|
|
}
|
|
|
|
iconLoader.addAppDir("tst_plasma-framework", QFINDTESTDATA("data/bug359388"));
|
|
|
|
QQuickItem *item1 = createIconItem();
|
|
item1->setProperty("source", customThemeIcon);
|
|
QVERIFY(item1->property("valid").toBool());
|
|
QCOMPARE(customThemeIcon, item1->property("source").value<QIcon>());
|
|
|
|
QQuickItem *item2 = createIconItem();
|
|
item2->setProperty("source", QIcon(QFINDTESTDATA("data/bug359388/hicolor/22x22/apps/" + name + ".svg")));
|
|
QVERIFY(item2->property("valid").toBool());
|
|
|
|
QCOMPARE(grabImage(item1), grabImage(item2));
|
|
}
|
|
|
|
void IconItemTest::loadSvg()
|
|
{
|
|
QString name("tst-plasma-framework-test-icon");
|
|
|
|
QQuickItem *item = createIconItem();
|
|
item->setProperty("animated", false);
|
|
item->setSize(QSize(22, 22));
|
|
item->setProperty("source", name);
|
|
QVERIFY(item->property("valid").toBool());
|
|
|
|
Plasma::Svg *svg;
|
|
svg = findPlasmaSvg(item);
|
|
Q_ASSERT(svg);
|
|
QCOMPARE(svg->imagePath(), QFINDTESTDATA("data/icons/test-theme/apps/22/" + name + ".svg"));
|
|
|
|
// we only have 32x32 and 22x22 version in the theme, thus 32x32 is a better match.
|
|
item->setSize(QSize(64, 64));
|
|
// just to update the icon
|
|
grabImage(item);
|
|
svg = findPlasmaSvg(item);
|
|
Q_ASSERT(svg);
|
|
QCOMPARE(svg->imagePath(), QFINDTESTDATA("data/icons/test-theme/apps/32/" + name + ".svg"));
|
|
}
|
|
|
|
void IconItemTest::themeChange()
|
|
{
|
|
// Icon from Plasma theme
|
|
QQuickItem *item1 = createIconItem();
|
|
item1->setProperty("animated", false);
|
|
item1->setProperty("source", "zoom-fit-height");
|
|
Plasma::Svg *svg1 = item1->findChild<Plasma::Svg*>();
|
|
changeTheme(svg1->theme(), "breeze-light");
|
|
QImage img1 = grabImage(item1);
|
|
changeTheme(svg1->theme(), "breeze-dark");
|
|
QImage img2 = grabImage(item1);
|
|
QVERIFY(img1 != img2);
|
|
|
|
// Icon from icon theme
|
|
QQuickItem *item2 = createIconItem();
|
|
item2->setProperty("animated", false);
|
|
item2->setProperty("width", 22);
|
|
item2->setProperty("height", 22);
|
|
item2->setProperty("source", "tst-plasma-framework-test-icon");
|
|
Plasma::Svg *svg2 = item2->findChild<Plasma::Svg*>();
|
|
changeTheme(svg2->theme(), "breeze-light");
|
|
img1 = grabImage(item2);
|
|
changeTheme(svg2->theme(), "breeze-dark");
|
|
img2 = grabImage(item2);
|
|
QVERIFY(img1 != img2);
|
|
}
|
|
|
|
void IconItemTest::qiconFromTheme()
|
|
{
|
|
// Icon from Plasma theme
|
|
QQuickItem *item1 = createIconItem();
|
|
QIcon icon1 = QIcon::fromTheme("konversation");
|
|
item1->setProperty("source", icon1);
|
|
QVERIFY(item1->findChild<Plasma::Svg*>());
|
|
QVERIFY(!imageIsEmpty(grabImage(item1)));
|
|
QCOMPARE(icon1, item1->property("source").value<QIcon>());
|
|
|
|
// Icon from icon theme
|
|
QQuickItem *item2 = createIconItem();
|
|
QIcon icon2 = QIcon::fromTheme("tst-plasma-framework-test-icon");
|
|
item2->setProperty("source", icon2);
|
|
QVERIFY(item2->findChild<Plasma::Svg*>());
|
|
QVERIFY(!imageIsEmpty(grabImage(item2)));
|
|
QCOMPARE(icon2, item2->property("source").value<QIcon>());
|
|
}
|
|
|
|
void IconItemTest::changeColorGroup()
|
|
{
|
|
// Icon from Plasma theme
|
|
QQuickItem *item = createIconItem();
|
|
item->setProperty("animated", false);
|
|
item->setProperty("source", "zoom-fit-height");
|
|
Plasma::Svg *svg = item->findChild<Plasma::Svg*>();
|
|
// not using "breeze" theme as that one follows system color scheme
|
|
// and that one might not have a complementary group or a broken one
|
|
changeTheme(svg->theme(), "breeze-light");
|
|
QSignalSpy spy(svg, SIGNAL(repaintNeeded()));
|
|
QVERIFY(spy.isValid());
|
|
QImage img1 = grabImage(item);
|
|
item->setProperty("colorGroup", Plasma::Theme::ComplementaryColorGroup);
|
|
QTRY_VERIFY(spy.count() == 1);
|
|
QImage img2 = grabImage(item);
|
|
QVERIFY(img1 != img2);
|
|
}
|
|
|
|
void IconItemTest::animatingActiveChange()
|
|
{
|
|
QQuickItem *item1 = createIconItem();
|
|
item1->setProperty("animated", false);
|
|
item1->setProperty("source", "tst-plasma-framework-test-icon");
|
|
QImage img1 = grabImage(item1);
|
|
|
|
QQuickItem *item2 = createIconItem();
|
|
item2->setProperty("animated", false);
|
|
item2->setProperty("active", true);
|
|
item2->setProperty("source", "tst-plasma-framework-test-icon");
|
|
QImage img2 = grabImage(item2);
|
|
QVERIFY(img1 != img2);
|
|
|
|
item1->setProperty("active", true);
|
|
img1 = grabImage(item1);
|
|
QVERIFY(img1 != img2); // animation is running
|
|
}
|
|
|
|
void IconItemTest::animatingEnabledChange()
|
|
{
|
|
QQuickItem *item1 = createIconItem();
|
|
item1->setProperty("animated", false);
|
|
item1->setProperty("source", "tst-plasma-framework-test-icon");
|
|
QImage img1 = grabImage(item1);
|
|
|
|
QQuickItem *item2 = createIconItem();
|
|
item2->setProperty("animated", false);
|
|
item2->setProperty("enabled", false);
|
|
item2->setProperty("source", "tst-plasma-framework-test-icon");
|
|
QImage img2 = grabImage(item2);
|
|
QVERIFY(img1 != img2);
|
|
|
|
item1->setProperty("enabled", false);
|
|
img1 = grabImage(item1);
|
|
QVERIFY(img1 != img2); // animation is running
|
|
}
|
|
|
|
void IconItemTest::windowChanged()
|
|
{
|
|
QQuickItem *item = createIconItem();
|
|
item->setProperty("animated", false);
|
|
item->setProperty("source", "tst-plasma-framework-test-icon");
|
|
QImage img = grabImage(item);
|
|
|
|
QQuickView newView;
|
|
newView.setSource(QUrl::fromLocalFile(QFINDTESTDATA("data/view.qml")));
|
|
newView.show();
|
|
QVERIFY(QTest::qWaitForWindowExposed(&newView));
|
|
|
|
item->setProperty("visible", false);
|
|
item->setParentItem(newView.rootObject());
|
|
item->setProperty("visible", true);
|
|
QCOMPARE(grabImage(item), img);
|
|
}
|
|
|
|
void IconItemTest::paintedSize()
|
|
{
|
|
QQuickItem *item = createIconItem();
|
|
|
|
QCOMPARE(item->property("paintedWidth").toInt(), item->property("implicitWidth").toInt());
|
|
QCOMPARE(item->property("paintedHeight").toInt(), item->property("implicitHeight").toInt());
|
|
|
|
item->setWidth(40);
|
|
item->setHeight(40);
|
|
|
|
QCOMPARE(item->property("paintedWidth").toInt(), 32);
|
|
QCOMPARE(item->property("paintedHeight").toInt(), 32);
|
|
|
|
QIcon landscapeIcon(QPixmap(40, 35));
|
|
item->setProperty("source", landscapeIcon);
|
|
grabImage(item); // basically just to force loading the pixmap
|
|
|
|
// expanded to fit IconItem size whilst keeping aspect ratio
|
|
// width should be rounded to icon size, ie. 32 is next smallest
|
|
QCOMPARE(item->property("paintedWidth").toInt(), 32);
|
|
// height should still match aspect ratio, so *not* 24!
|
|
QCOMPARE(item->property("paintedHeight").toInt(), 28);
|
|
|
|
QIcon portraitIcon(QPixmap(15, 40));
|
|
item->setProperty("source", portraitIcon);
|
|
grabImage(item);
|
|
|
|
QCOMPARE(item->property("paintedWidth").toInt(), 12);
|
|
QCOMPARE(item->property("paintedHeight").toInt(), 32);
|
|
|
|
item->setWidth(400);
|
|
item->setHeight(400);
|
|
|
|
grabImage(item);
|
|
|
|
QCOMPARE(item->property("paintedWidth").toInt(), 150);
|
|
QCOMPARE(item->property("paintedHeight").toInt(), 400);
|
|
}
|
|
|
|
void IconItemTest::implicitSize()
|
|
{
|
|
KConfigGroup cg(KSharedConfig::openConfig(), "DialogIcons");
|
|
cg.writeEntry("Size", 22);
|
|
cg.sync();
|
|
KIconLoader::global()->reconfigure(QString());
|
|
|
|
QQuickItem *item = createIconItem();
|
|
|
|
// qreal cast needed as QTest::qCompare<double, int> fails to link
|
|
QCOMPARE(item->implicitWidth(), qreal(22));
|
|
QCOMPARE(item->implicitHeight(), qreal(22));
|
|
|
|
QSignalSpy widthSpy(item, &QQuickItem::implicitWidthChanged);
|
|
QVERIFY(widthSpy.isValid());
|
|
QSignalSpy heightSpy(item, &QQuickItem::implicitHeightChanged);
|
|
QVERIFY(heightSpy.isValid());
|
|
|
|
cg.writeEntry("Size", 64);
|
|
cg.sync();
|
|
KIconLoader::global()->reconfigure(QString());
|
|
// merely changing the setting and calling reconfigure won't emit this signal,
|
|
// the KCM uses a method "newIconLoader" method which does that but it's deprecated
|
|
emit KIconLoader::global()->iconLoaderSettingsChanged();
|
|
|
|
QCOMPARE(widthSpy.count(), 1);
|
|
QCOMPARE(heightSpy.count(), 1);
|
|
|
|
QCOMPARE(item->implicitWidth(), qreal(64));
|
|
QCOMPARE(item->implicitHeight(), qreal(64));
|
|
}
|
|
|
|
void IconItemTest::nonSquareImplicitSize()
|
|
{
|
|
QQuickItem *item1 = createIconItem();
|
|
|
|
// Both file:///foo and /foo must behave the same
|
|
item1->setProperty("source", QFINDTESTDATA("data/test_nonsquare.png"));
|
|
|
|
QCOMPARE(item1->implicitWidth(), qreal(150));
|
|
QCOMPARE(item1->implicitHeight(), qreal(50));
|
|
|
|
QQuickItem *item2 = createIconItem();
|
|
|
|
item2->setProperty("source", QUrl::fromLocalFile(QFINDTESTDATA("data/test_nonsquare.png")));
|
|
|
|
QCOMPARE(item2->implicitWidth(), item1->implicitWidth());
|
|
QCOMPARE(item2->implicitHeight(), item1->implicitHeight());
|
|
}
|
|
|
|
void IconItemTest::roundToIconSize()
|
|
{
|
|
QQuickItem *item = createIconItem();
|
|
|
|
item->setWidth(25);
|
|
item->setHeight(25);
|
|
QVERIFY(item->property("paintedWidth").toInt() != 25);
|
|
QVERIFY(item->property("paintedHeight").toInt() != 25);
|
|
|
|
QSignalSpy paintedSizeSpy(item, SIGNAL(paintedSizeChanged()));
|
|
QSignalSpy roundToIconSizeSpy(item, SIGNAL(roundToIconSizeChanged()));
|
|
|
|
item->setProperty("roundToIconSize", false);
|
|
|
|
QTRY_COMPARE(paintedSizeSpy.count(), 1);
|
|
QTRY_COMPARE(roundToIconSizeSpy.count(), 1);
|
|
QVERIFY(item->property("paintedWidth").toInt() == 25);
|
|
QVERIFY(item->property("paintedHeight").toInt() == 25);
|
|
}
|
|
|
|
QTEST_MAIN(IconItemTest)
|
|
|