diff --git a/autotests/kiconloader_unittest.cpp b/autotests/kiconloader_unittest.cpp index ee24533..6724442 100644 --- a/autotests/kiconloader_unittest.cpp +++ b/autotests/kiconloader_unittest.cpp @@ -1,526 +1,526 @@ /* This file is part of the KDE libraries Copyright 2008 David Faure 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 #include #include #include #include #include #include #include #include extern KICONTHEMES_EXPORT void uintToHex(uint32_t colorData, QChar *buffer); class KIconLoader_UnitTest : public QObject { Q_OBJECT public: KIconLoader_UnitTest() : testSizes({ 12, 22, 32, 42, 82, 132, 243 }) {} private: QDir testDataDir; QDir testIconsDir; QString appName; QDir appDataDir; const QVector testSizes; private Q_SLOTS: void initTestCase() { QStandardPaths::setTestModeEnabled(true); const QStringList genericIconsFiles = QStandardPaths::locateAll(QStandardPaths::GenericDataLocation, QStringLiteral("mime/generic-icons")); QVERIFY(!genericIconsFiles.isEmpty()); // KIconLoader relies on fallbacks to generic icons (e.g. x-office-document), which comes from a shared-mime-info file. Make sure it's installed! KConfigGroup cg(KSharedConfig::openConfig(), "Icons"); cg.writeEntry("Theme", "breeze"); cg.sync(); testDataDir = QDir(QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation)); testIconsDir = QDir(testDataDir.absoluteFilePath(QStringLiteral("icons"))); appName = QStringLiteral("kiconloader_unittest"); appDataDir = QDir(testDataDir.absoluteFilePath(appName)); // we will be recursively deleting these, so a sanity check is in order QVERIFY(testIconsDir.absolutePath().contains(QStringLiteral("qttest"))); QVERIFY(appDataDir.absolutePath().contains(QStringLiteral("qttest"))); testIconsDir.removeRecursively(); appDataDir.removeRecursively(); QVERIFY(appDataDir.mkpath(QStringLiteral("pics"))); QVERIFY(QFile::copy(QStringLiteral(":/app-image.png"), appDataDir.filePath(QStringLiteral("pics/image1.png")))); QVERIFY(QFile::copy(QStringLiteral(":/app-image.png"), appDataDir.filePath(QStringLiteral("pics/image2.png")))); // set up a minimal Oxygen icon theme, in case it is not installed QVERIFY(testIconsDir.mkpath(QStringLiteral("oxygen/22x22/actions"))); QVERIFY(testIconsDir.mkpath(QStringLiteral("oxygen/22x22/animations"))); QVERIFY(testIconsDir.mkpath(QStringLiteral("oxygen/22x22/apps"))); QVERIFY(testIconsDir.mkpath(QStringLiteral("oxygen/22x22/mimetypes"))); QVERIFY(testIconsDir.mkpath(QStringLiteral("oxygen/32x32/apps"))); QVERIFY(QFile::copy(QStringLiteral(":/oxygen.theme"), testIconsDir.filePath(QStringLiteral("oxygen/index.theme")))); QVERIFY(QFile::copy(QStringLiteral(":/test-22x22.png"), testIconsDir.filePath(QStringLiteral("oxygen/22x22/apps/kde.png")))); QVERIFY(QFile::copy(QStringLiteral(":/anim-22x22.png"), testIconsDir.filePath(QStringLiteral("oxygen/22x22/animations/process-working.png")))); QVERIFY(QFile::copy(QStringLiteral(":/test-22x22.png"), testIconsDir.filePath(QStringLiteral("oxygen/22x22/mimetypes/text-plain.png")))); QVERIFY(QFile::copy(QStringLiteral(":/test-22x22.png"), testIconsDir.filePath(QStringLiteral("oxygen/22x22/mimetypes/application-octet-stream.png")))); QVERIFY(QFile::copy(QStringLiteral(":/test-22x22.png"), testIconsDir.filePath(QStringLiteral("oxygen/22x22/mimetypes/image-x-generic.png")))); QVERIFY(QFile::copy(QStringLiteral(":/test-22x22.png"), testIconsDir.filePath(QStringLiteral("oxygen/22x22/mimetypes/video-x-generic.png")))); QVERIFY(QFile::copy(QStringLiteral(":/test-22x22.png"), testIconsDir.filePath(QStringLiteral("oxygen/22x22/mimetypes/x-office-document.png")))); QVERIFY(QFile::copy(QStringLiteral(":/test-22x22.png"), testIconsDir.filePath(QStringLiteral("oxygen/22x22/mimetypes/audio-x-generic.png")))); QVERIFY(QFile::copy(QStringLiteral(":/test-22x22.png"), testIconsDir.filePath(QStringLiteral("oxygen/22x22/mimetypes/unknown.png")))); QVERIFY(QFile::copy(QStringLiteral(":/test-32x32.png"), testIconsDir.filePath(QStringLiteral("oxygen/32x32/apps/kde.png")))); // set up a minimal Breeze icon theme, fallback to oxygen QVERIFY(testIconsDir.mkpath(QStringLiteral("breeze/22x22/actions"))); QVERIFY(testIconsDir.mkpath(QStringLiteral("breeze/22x22/animations"))); QVERIFY(testIconsDir.mkpath(QStringLiteral("breeze/22x22/apps"))); QVERIFY(testIconsDir.mkpath(QStringLiteral("breeze/22x22/mimetypes"))); QVERIFY(testIconsDir.mkpath(QStringLiteral("breeze/22x22/appsNoContext"))); QVERIFY(testIconsDir.mkpath(QStringLiteral("breeze/22x22/appsNoType"))); QVERIFY(testIconsDir.mkpath(QStringLiteral("breeze/22x22/appsNoContextOrType"))); const QString breezeThemeFile = testIconsDir.filePath(QStringLiteral("breeze/index.theme")); QVERIFY(QFile::copy(QStringLiteral(":/breeze.theme"), breezeThemeFile)); //kde.png is missing, it should fallback to oxygen //QVERIFY(QFile::copy(QStringLiteral(":/test-22x22.png"), testIconsDir.filePath(QStringLiteral("breeze/22x22/apps/kde.png")))); QVERIFY(QFile::copy(QStringLiteral(":/test-22x22.png"), testIconsDir.filePath(QStringLiteral("breeze/22x22/appsNoContext/iconindirectorywithoutcontext.png")))); QVERIFY(QFile::copy(QStringLiteral(":/test-22x22.png"), testIconsDir.filePath(QStringLiteral("breeze/22x22/appsNoType/iconindirectorywithouttype.png")))); QVERIFY(QFile::copy(QStringLiteral(":/test-22x22.png"), testIconsDir.filePath(QStringLiteral("breeze/22x22/appsNoContextOrType/iconindirectorywithoutcontextortype.png")))); QVERIFY(QFile::copy(QStringLiteral(":/anim-22x22.png"), testIconsDir.filePath(QStringLiteral("breeze/22x22/animations/process-working.png")))); QVERIFY(QFile::copy(QStringLiteral(":/test-22x22.png"), testIconsDir.filePath(QStringLiteral("breeze/22x22/mimetypes/text-plain.png")))); QVERIFY(QFile::copy(QStringLiteral(":/test-22x22.png"), testIconsDir.filePath(QStringLiteral("breeze/22x22/mimetypes/application-octet-stream.png")))); QVERIFY(QFile::copy(QStringLiteral(":/test-22x22.png"), testIconsDir.filePath(QStringLiteral("breeze/22x22/mimetypes/image-x-generic.png")))); QVERIFY(QFile::copy(QStringLiteral(":/test-22x22.png"), testIconsDir.filePath(QStringLiteral("breeze/22x22/mimetypes/video-x-generic.png")))); QVERIFY(QFile::copy(QStringLiteral(":/test-22x22.png"), testIconsDir.filePath(QStringLiteral("breeze/22x22/mimetypes/x-office-document.png")))); QVERIFY(QFile::copy(QStringLiteral(":/test-22x22.png"), testIconsDir.filePath(QStringLiteral("breeze/22x22/mimetypes/audio-x-generic.png")))); QVERIFY(QFile::copy(QStringLiteral(":/test-22x22.png"), testIconsDir.filePath(QStringLiteral("breeze/22x22/mimetypes/unknown.png")))); QVERIFY(QFile::copy(QStringLiteral(":/coloredsvgicon.svg"), testIconsDir.filePath(QStringLiteral("breeze/22x22/apps/coloredsvgicon.svg")))); QVERIFY(QFile::setPermissions(breezeThemeFile, QFileDevice::ReadOwner|QFileDevice::WriteOwner)); KConfig configFile(breezeThemeFile); KConfigGroup iconThemeGroup = configFile.group("Icon Theme"); QVERIFY(iconThemeGroup.isValid()); QStringList dirs = iconThemeGroup.readEntry("Directories", QStringList()); Q_FOREACH(int i, testSizes) { const QString relDir = QStringLiteral("%1x%1/emblems").arg(i); const QString dir = testIconsDir.filePath(QStringLiteral("breeze/") + relDir); QVERIFY(QDir().mkpath(dir)); QPixmap img(i, i); img.fill(Qt::red); QVERIFY(img.save(dir + "/red.png")); dirs += relDir; KConfigGroup dirGroup = configFile.group(relDir); dirGroup.writeEntry("Size", i); dirGroup.writeEntry("Context", "Emblems"); dirGroup.writeEntry("Type", "Fixed"); } iconThemeGroup.writeEntry("Directories", dirs); QVERIFY(configFile.sync()); } void cleanupTestCase() { testIconsDir.removeRecursively(); appDataDir.removeRecursively(); } void init() { // Remove icon cache const QString cacheFile = QStandardPaths::writableLocation(QStandardPaths::GenericCacheLocation) + "/icon-cache.kcache"; QFile::remove(cacheFile); // Clear SHM cache KIconLoader::global()->reconfigure(QString()); } void testUnknownIconNotCached() { // This is a test to ensure that "unknown" icons do not pin themselves // in the icon loader. Or in other words, if an "unknown" icon is // returned, but the appropriate icon is subsequently installed // properly, the next request for that icon should return the new icon // instead of the unknown icon. QString actionIconsSubdir = QStringLiteral("oxygen/22x22/actions"); QVERIFY(testIconsDir.mkpath(actionIconsSubdir)); QString actionIconsDir = testIconsDir.filePath(actionIconsSubdir); QString nonExistingIconName = QStringLiteral("fhqwhgads_homsar"); QString newIconPath = actionIconsDir + QLatin1String("/") + nonExistingIconName + QLatin1String(".png"); QFile::remove(newIconPath); KIconLoader iconLoader; // Find a non-existent icon, allowing unknown icon to be returned QPixmap nonExistingIcon = iconLoader.loadIcon( nonExistingIconName, KIconLoader::Toolbar); QCOMPARE(nonExistingIcon.isNull(), false); // Install the existing icon by copying. QVERIFY(QFile::copy(QStringLiteral(":/test-22x22.png"), newIconPath)); // Verify the icon can now be found. QPixmap nowExistingIcon = iconLoader.loadIcon( nonExistingIconName, KIconLoader::Toolbar); QVERIFY(nowExistingIcon.cacheKey() != nonExistingIcon.cacheKey()); QCOMPARE(iconLoader.iconPath(nonExistingIconName, KIconLoader::Toolbar), newIconPath); } void testLoadIconCanReturnNull() { // This is a test for the "canReturnNull" argument of KIconLoader::loadIcon(). // We try to load an icon that doesn't exist, first with canReturnNull=false (the default) // then with canReturnNull=true. KIconLoader iconLoader; // We expect a warning here... This doesn't work though, due to the extended debug //QTest::ignoreMessage(QtWarningMsg, "KIconLoader::loadIcon: No such icon \"this-icon-does-not-exist\""); QPixmap pix = iconLoader.loadIcon(QStringLiteral("this-icon-does-not-exist"), KIconLoader::Desktop, 16); QVERIFY(!pix.isNull()); QCOMPARE(pix.size(), QSize(16, 16)); // Try it again, to see if the cache interfers pix = iconLoader.loadIcon(QStringLiteral("this-icon-does-not-exist"), KIconLoader::Desktop, 16); QVERIFY(!pix.isNull()); QCOMPARE(pix.size(), QSize(16, 16)); // And now set canReturnNull to true pix = iconLoader.loadIcon(QStringLiteral("this-icon-does-not-exist"), KIconLoader::Desktop, 16, KIconLoader::DefaultState, - QStringList(), 0, true); + QStringList(), nullptr, true); QVERIFY(pix.isNull()); // Try getting the "unknown" icon again, to see if the above call didn't put a null icon into the cache... pix = iconLoader.loadIcon(QStringLiteral("this-icon-does-not-exist"), KIconLoader::Desktop, 16); QVERIFY(!pix.isNull()); QCOMPARE(pix.size(), QSize(16, 16)); // Another one, to clear "last" cache pix = iconLoader.loadIcon(QStringLiteral("this-icon-does-not-exist-either"), KIconLoader::Desktop, 16); QVERIFY(!pix.isNull()); QCOMPARE(pix.size(), QSize(16, 16)); // Now load the initial one again - do we get the warning again? pix = iconLoader.loadIcon(QStringLiteral("this-icon-does-not-exist"), KIconLoader::Desktop, 16); QVERIFY(!pix.isNull()); QCOMPARE(pix.size(), QSize(16, 16)); pix = iconLoader.loadIcon(QStringLiteral("#crazyname"), KIconLoader::NoGroup, 1600); QVERIFY(!pix.isNull()); QCOMPARE(pix.size(), QSize(1600, 1600)); } void testAppPicsDir() { KIconLoader appIconLoader(appName); QString iconPath = appIconLoader.iconPath(QStringLiteral("image1"), KIconLoader::User); QCOMPARE(iconPath, appDataDir.filePath("pics/image1.png")); QVERIFY(QFile::exists(iconPath)); // Load it again, to use the "last loaded" cache QString iconPath2 = appIconLoader.iconPath(QStringLiteral("image1"), KIconLoader::User); QCOMPARE(iconPath, iconPath2); // Load something else, to clear the "last loaded" cache QString iconPathTextEdit = appIconLoader.iconPath(QStringLiteral("image2"), KIconLoader::User); QCOMPARE(iconPathTextEdit, appDataDir.filePath("pics/image2.png")); QVERIFY(QFile::exists(iconPathTextEdit)); // Now load kdialog again, to use the real kiconcache iconPath2 = appIconLoader.iconPath(QStringLiteral("image1"), KIconLoader::User); QCOMPARE(iconPath, iconPath2); } void testAppPicsDir_KDE_icon() { // #### This test is broken; it passes even if appName is set to foobar, because // QIcon::pixmap returns an unknown icon if it can't find the real icon... KIconLoader appIconLoader(appName); // Now using KDE::icon. Separate test so that KIconLoader isn't fully inited. QIcon icon = KDE::icon(QStringLiteral("image1"), &appIconLoader); { QPixmap pix = icon.pixmap(QSize(22, 22)); QVERIFY(!pix.isNull()); } QCOMPARE(icon.actualSize(QSize(96, 22)), QSize(22, 22)); QCOMPARE(icon.actualSize(QSize(22, 96)), QSize(22, 22)); QCOMPARE(icon.actualSize(QSize(22, 16)), QSize(16, 16)); // Can we ask for a really small size? { QPixmap pix8 = icon.pixmap(QSize(8, 8)); QCOMPARE(pix8.size(), QSize(8, 8)); } } void testLoadMimeTypeIcon_data() { QTest::addColumn("iconName"); QTest::addColumn("expectedFileName"); QTest::newRow("existing icon") << "text-plain" << "text-plain.png"; QTest::newRow("octet-stream icon") << "application-octet-stream" << "application-octet-stream.png"; QTest::newRow("non-existing icon") << "foo-bar" << "application-octet-stream.png"; // Test this again, because now we won't go into the "fast path" of loadMimeTypeIcon anymore. QTest::newRow("existing icon again") << "text-plain" << "text-plain.png"; QTest::newRow("generic fallback") << "image-foo-bar" << "image-x-generic.png"; QTest::newRow("video generic fallback") << "video-foo-bar" << "video-x-generic.png"; QTest::newRow("image-x-generic itself") << "image-x-generic" << "image-x-generic.png"; QTest::newRow("x-office-document icon") << "x-office-document" << "x-office-document.png"; QTest::newRow("unavailable generic icon") << "application/x-font-vfont" << "application-octet-stream.png"; QTest::newRow("#184852") << "audio/x-tuxguitar" << "audio-x-generic.png"; QTest::newRow("#178847") << "image/x-compressed-xcf" << "image-x-generic.png"; QTest::newRow("mimetype generic icon") << "application-x-fluid" << "x-office-document.png"; } void testLoadMimeTypeIcon() { QFETCH(QString, iconName); QFETCH(QString, expectedFileName); KIconLoader iconLoader; QString path; QPixmap pix = iconLoader.loadMimeTypeIcon(iconName, KIconLoader::Desktop, 24, KIconLoader::DefaultState, QStringList(), &path); QVERIFY(!pix.isNull()); QCOMPARE(path.section('/', -1), expectedFileName); // do the same test using a global iconloader, so that // we get into the final return statement, which can only happen // if d->extraDesktopIconsLoaded becomes true first.... QString path2; pix = KIconLoader::global()->loadMimeTypeIcon(iconName, KIconLoader::Desktop, 24, KIconLoader::DefaultState, QStringList(), &path2); QVERIFY(!pix.isNull()); QCOMPARE(path2, path); } void testHasIcon() { // Do everything twice to check code paths that might use a cache QVERIFY(KIconLoader::global()->hasIcon("kde")); QVERIFY(KIconLoader::global()->hasIcon("kde")); KIconLoader iconLoader; QVERIFY(iconLoader.hasIcon("kde")); QVERIFY(KIconLoader::global()->hasIcon("process-working")); QVERIFY(KIconLoader::global()->hasIcon("process-working")); QVERIFY(!KIconLoader::global()->hasIcon("no-such-icon-exists")); QVERIFY(!KIconLoader::global()->hasIcon("no-such-icon-exists")); } void testIconPath() { // Test iconPath with non-existing icon const QString path = KIconLoader::global()->iconPath(QStringLiteral("nope-no-such-icon"), KIconLoader::Desktop, true /*canReturnNull*/); QVERIFY2(path.isEmpty(), qPrintable(path)); const QString unknownPath = KIconLoader::global()->iconPath(QStringLiteral("nope-no-such-icon"), KIconLoader::Desktop, false); QVERIFY(!unknownPath.isEmpty()); QVERIFY(QFile::exists(unknownPath)); } void testPathStore() { QString path; QPixmap pix = KIconLoader::global()->loadIcon(QStringLiteral("kde"), KIconLoader::Desktop, 0, KIconLoader::DefaultState, QStringList(), &path); QVERIFY(!path.isEmpty()); QVERIFY(QFile::exists(path)); QVERIFY2(path.contains("32x32"), qPrintable(path)); QCOMPARE(pix.size(), QSize(32, 32)); // Compare with iconPath() QString path2 = KIconLoader::global()->iconPath(QStringLiteral("kde"), KIconLoader::Desktop); QCOMPARE(path2, path); // Now specify a size pix = KIconLoader::global()->loadIcon(QStringLiteral("kde"), KIconLoader::Desktop, 24, KIconLoader::DefaultState, QStringList(), &path); QVERIFY(!path.isEmpty()); QVERIFY(QFile::exists(path)); QVERIFY2(path.contains("22x22"), qPrintable(path)); QCOMPARE(pix.size(), QSize(24, 24)); QVERIFY(KIconLoader::global()->hasIcon("kde")); path = QString(); KIconLoader::global()->loadIcon(QStringLiteral("does_not_exist"), KIconLoader::Desktop, 24, KIconLoader::DefaultState, QStringList(), &path, true /* canReturnNull */); QVERIFY2(path.isEmpty(), qPrintable(path)); path = QStringLiteral("some filler to check loadIcon() clears the variable"); KIconLoader::global()->loadIcon(QStringLiteral("does_not_exist"), KIconLoader::Desktop, 24, KIconLoader::DefaultState, QStringList(), &path, true /* canReturnNull */); QVERIFY2(path.isEmpty(), qPrintable(path)); //Test that addAppDir doesn't break loading of icons from the old known paths KIconLoader loader; //only addAppDir loader.addAppDir(QStringLiteral("kiconloader_unittest")); path = QString(); loader.loadIcon(QStringLiteral("kde"), KIconLoader::Desktop, 24, KIconLoader::DefaultState, QStringList(), &path); QVERIFY(!path.isEmpty()); path = QString(); loader.loadIcon(QStringLiteral("image1"), KIconLoader::Desktop, 24, KIconLoader::DefaultState, QStringList(), &path); QVERIFY(!path.isEmpty()); //only reconfigure KIconLoader loader2; path = QString(); loader2.reconfigure(QStringLiteral("kiconloader_unittest")); loader2.loadIcon(QStringLiteral("kde"), KIconLoader::Desktop, 24, KIconLoader::DefaultState, QStringList(), &path); QVERIFY(!path.isEmpty()); loader2.loadIcon(QStringLiteral("image1"), KIconLoader::Desktop, 24, KIconLoader::DefaultState, QStringList(), &path); QVERIFY(!path.isEmpty()); //both addAppDir and reconfigure KIconLoader loader3; path = QString(); loader3.addAppDir(QStringLiteral("kiconloader_unittest")); loader3.reconfigure(QStringLiteral("kiconloader_unittest")); loader3.loadIcon(QStringLiteral("kde"), KIconLoader::Desktop, 24, KIconLoader::DefaultState, QStringList(), &path); QVERIFY(!path.isEmpty()); path = QString(); loader3.loadIcon(QStringLiteral("image1"), KIconLoader::Desktop, 24, KIconLoader::DefaultState, QStringList(), &path); QVERIFY(!path.isEmpty()); } void testPathsNoContextType() { { QString path; KIconLoader::global()->loadIcon(QStringLiteral("iconindirectorywithoutcontext"), KIconLoader::Desktop, 24, KIconLoader::DefaultState, QStringList(), &path); QVERIFY(path.endsWith("appsNoContext/iconindirectorywithoutcontext.png")); } { QString path; KIconLoader::global()->loadIcon(QStringLiteral("iconindirectorywithouttype"), KIconLoader::Desktop, 24, KIconLoader::DefaultState, QStringList(), &path); QVERIFY(path.endsWith("appsNoType/iconindirectorywithouttype.png")); } { QString path; KIconLoader::global()->loadIcon(QStringLiteral("iconindirectorywithoutcontextortype"), KIconLoader::Desktop, 24, KIconLoader::DefaultState, QStringList(), &path); QVERIFY(path.endsWith("appsNoContextOrType/iconindirectorywithoutcontextortype.png")); } } void testLoadIconNoGroupOrSize() // #246016 { QPixmap pix = KIconLoader::global()->loadIcon(QStringLiteral("connected"), KIconLoader::NoGroup); QVERIFY(!pix.isNull()); } void testLoadPixmapSequence() { KPixmapSequence seq = KIconLoader::global()->loadPixmapSequence(QStringLiteral("process-working"), 22); QVERIFY(seq.isValid()); } void testAppropriateSizes() { const KIconLoader iconLoader; const QRegularExpression rx(QStringLiteral("/(\\d+)x\\d+/")); for(int i=1; i= i) { ts = curr; break; } } QVERIFY(ts == foundSize); } } void testColoredSvgIcon() { QPalette pal = qApp->palette(); pal.setColor(QPalette::WindowText, QColor(255, 0, 0)); qApp->setPalette(pal); QImage img = KIconLoader::global()->loadIcon(QStringLiteral("coloredsvgicon"), KIconLoader::NoGroup).toImage(); QVERIFY(!img.isNull()); //Has the image been recolored to red, //that is the color we wrote in kdeglobals as text color? QCOMPARE(img.pixel(0,0), (uint)4294901760); } void testUintToHex() { // HEX (ARGB format without the #): ff6496c8 QColor testColorNoAlpha(100, 150, 200); // The ARGB string in which the composed hex value is stored. QString argbHex(8, Qt::Uninitialized); // Verify the ARGB hex (ff6496c8) uintToHex(testColorNoAlpha.rgba(), argbHex.data()); QCOMPARE(argbHex, QString("ff6496c8")); // HEX (ARGB format without the #): 7b6496c8 QColor testColorWithAlpha(100, 150, 200, 123); // Test uintToHex to verify its ARGB output. uintToHex(testColorWithAlpha.rgba(), argbHex.data()); QCOMPARE(argbHex, QString("7b6496c8")); } }; QTEST_MAIN(KIconLoader_UnitTest) #include "kiconloader_unittest.moc" diff --git a/src/kiconbutton.cpp b/src/kiconbutton.cpp index 70f7444..a12f839 100644 --- a/src/kiconbutton.cpp +++ b/src/kiconbutton.cpp @@ -1,187 +1,187 @@ /* vi: ts=8 sts=4 sw=4 * * This file is part of the KDE project, module kfile. * Copyright (C) 2000 Geert Jansen * (C) 2000 Kurt Granroth * (C) 1997 Christoph Neerfeld * (C) 2002 Carsten Pfeiffer * * This is free software; it comes under the GNU Library General * Public License, version 2. See the file "COPYING.LIB" for the * exact licensing terms. */ #include "kiconbutton.h" #include #include "kicondialog.h" class KIconButton::KIconButtonPrivate { public: KIconButtonPrivate(KIconButton *qq, KIconLoader *loader); ~KIconButtonPrivate(); // slots void _k_slotChangeIcon(); void _k_newIconName(const QString &); KIconButton *q; int iconSize; int buttonIconSize; bool m_bStrictIconSize; bool mbUser; KIconLoader::Group mGroup; KIconLoader::Context mContext; QString mIcon; KIconDialog *mpDialog; KIconLoader *mpLoader; }; /* * KIconButton: A "choose icon" pushbutton. */ KIconButton::KIconButton(QWidget *parent) : QPushButton(parent), d(new KIconButtonPrivate(this, KIconLoader::global())) { QPushButton::setIconSize(QSize(48, 48)); } KIconButton::KIconButton(KIconLoader *loader, QWidget *parent) : QPushButton(parent), d(new KIconButtonPrivate(this, loader)) { QPushButton::setIconSize(QSize(48, 48)); } KIconButton::KIconButtonPrivate::KIconButtonPrivate(KIconButton *qq, KIconLoader *loader) : q(qq) { m_bStrictIconSize = false; iconSize = 0; // let KIconLoader choose the default buttonIconSize = -1; //When buttonIconSize is -1, iconSize will be used for the button mGroup = KIconLoader::Desktop; mContext = KIconLoader::Application; mbUser = false; mpLoader = loader; - mpDialog = 0L; + mpDialog = nullptr; connect(q, SIGNAL(clicked()), q, SLOT(_k_slotChangeIcon())); } KIconButton::KIconButtonPrivate::~KIconButtonPrivate() { delete mpDialog; } KIconButton::~KIconButton() { delete d; } void KIconButton::setStrictIconSize(bool b) { d->m_bStrictIconSize = b; } bool KIconButton::strictIconSize() const { return d->m_bStrictIconSize; } void KIconButton::setIconSize(int size) { if (d->buttonIconSize == -1) { QPushButton::setIconSize(QSize(size, size)); } d->iconSize = size; } int KIconButton::iconSize() const { return d->iconSize; } void KIconButton::setButtonIconSize(int size) { QPushButton::setIconSize(QSize(size, size)); d->buttonIconSize = size; } int KIconButton::buttonIconSize() const { return QPushButton::iconSize().height(); } void KIconButton::setIconType(KIconLoader::Group group, KIconLoader::Context context, bool user) { d->mGroup = group; d->mContext = context; d->mbUser = user; } void KIconButton::setIcon(const QString &icon) { d->mIcon = icon; setIcon(QIcon::fromTheme(d->mIcon)); if (!d->mpDialog) { d->mpDialog = new KIconDialog(d->mpLoader, this); connect(d->mpDialog, SIGNAL(newIconName(QString)), this, SLOT(_k_newIconName(QString))); } if (d->mbUser) { d->mpDialog->setCustomLocation(QFileInfo(d->mpLoader->iconPath(d->mIcon, d->mGroup, true)).absolutePath()); } } void KIconButton::setIcon(const QIcon &icon) { QPushButton::setIcon(icon); } void KIconButton::resetIcon() { d->mIcon.clear(); setIcon(QIcon()); } const QString &KIconButton::icon() const { return d->mIcon; } void KIconButton::KIconButtonPrivate::_k_slotChangeIcon() { if (!mpDialog) { mpDialog = new KIconDialog(mpLoader, q); connect(mpDialog, SIGNAL(newIconName(QString)), q, SLOT(_k_newIconName(QString))); } mpDialog->setup(mGroup, mContext, m_bStrictIconSize, iconSize, mbUser); mpDialog->showDialog(); } void KIconButton::KIconButtonPrivate::_k_newIconName(const QString &name) { if (name.isEmpty()) { return; } q->setIcon(QIcon::fromTheme(name)); mIcon = name; if (mbUser) { mpDialog->setCustomLocation(QFileInfo(mpLoader->iconPath(mIcon, mGroup, true)).absolutePath()); } emit q->iconChanged(name); } #include "moc_kiconbutton.cpp" diff --git a/src/kiconbutton.h b/src/kiconbutton.h index 8e09a23..cace836 100644 --- a/src/kiconbutton.h +++ b/src/kiconbutton.h @@ -1,134 +1,134 @@ /* vi: ts=8 sts=4 sw=4 * * This file is part of the KDE project, module kfile. * Copyright (C) 2000 Geert Jansen * (C) 2000 Kurt Granroth * (C) 1997 Christoph Neerfeld * (C) 2002 Carsten Pfeiffer * * This is free software; it comes under the GNU Library General * Public License, version 2. See the file "COPYING.LIB" for the * exact licensing terms. */ #ifndef KICONBUTTON_H #define KICONBUTTON_H #include "kiconthemes_export.h" #include #include /** * A pushbutton for choosing an icon. Pressing on the button will open a * KIconDialog for the user to select an icon. The current icon will be * displayed on the button. * * @see KIconDialog * @short A push button that allows selection of an icon. */ class KICONTHEMES_EXPORT KIconButton: public QPushButton { Q_OBJECT Q_PROPERTY(QString icon READ icon WRITE setIcon RESET resetIcon NOTIFY iconChanged USER true) Q_PROPERTY(int iconSize READ iconSize WRITE setIconSize) Q_PROPERTY(bool strictIconSize READ strictIconSize WRITE setStrictIconSize) public: /** * Constructs a KIconButton using the global icon loader. * * @param parent The parent widget. */ - explicit KIconButton(QWidget *parent = 0L); + explicit KIconButton(QWidget *parent = nullptr); /** * Constructs a KIconButton using a specific icon loader. * * @param loader The icon loader to use. * @param parent The parent widget. */ KIconButton(KIconLoader *loader, QWidget *parent); /** * Destructs the button. */ ~KIconButton(); /** * Sets a strict icon size policy for allowed icons. When true, * only icons of the specified group's size in setIconType() are allowed, * and only icons of that size will be shown in the icon dialog. */ void setStrictIconSize(bool b); /** * Returns true if a strict icon size policy is set. */ bool strictIconSize() const; /** * Sets the icon group and context. Use KIconLoader::NoGroup if you want to * allow icons for any group in the given context. */ void setIconType(KIconLoader::Group group, KIconLoader::Context context, bool user = false); /** * Sets the button's initial icon. */ void setIcon(const QString &icon); void setIcon(const QIcon &icon); /** * Resets the icon (reverts to an empty button). */ void resetIcon(); /** * Returns the name of the selected icon. */ const QString &icon() const; /** * Sets the size of the icon to be shown / selected. * @see KIconLoader::StdSizes * @see iconSize */ void setIconSize(int size); /** * Returns the icon size set via setIconSize() or 0, if the default * icon size will be used. */ int iconSize() const; /** * Sets the size of the icon to be shown on the button. * @see KIconLoader::StdSizes * @see buttonIconSize * @since 4.1 */ void setButtonIconSize(int size); /** * Returns the button's icon size. * @since 4.1 */ int buttonIconSize() const; Q_SIGNALS: /** * Emitted when the icon has changed. */ void iconChanged(const QString &icon); private: class KIconButtonPrivate; KIconButtonPrivate *const d; Q_DISABLE_COPY(KIconButton) Q_PRIVATE_SLOT(d, void _k_slotChangeIcon()) Q_PRIVATE_SLOT(d, void _k_newIconName(const QString &)) }; #endif // KICONBUTTON_H diff --git a/src/kicondialog.cpp b/src/kicondialog.cpp index 68650ed..d3cf554 100644 --- a/src/kicondialog.cpp +++ b/src/kicondialog.cpp @@ -1,664 +1,664 @@ /* vi: ts=8 sts=4 sw=4 * * This file is part of the KDE project, module kfile. * Copyright (C) 2000 Geert Jansen * (C) 2000 Kurt Granroth * (C) 1997 Christoph Neerfeld * (C) 2002 Carsten Pfeiffer * * This is free software; it comes under the GNU Library General * Public License, version 2. See the file "COPYING.LIB" for the * exact licensing terms. */ #include "kicondialog.h" #include "kicondialog_p.h" #include #include #ifndef _WIN32_WCE #include #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include /** * Qt allocates very little horizontal space for the icon name, * even if the gridSize width is large. This delegate allocates * the gridSize width (minus some padding) for the icon and icon name. */ class KIconCanvasDelegate : public QAbstractItemDelegate { public: KIconCanvasDelegate(KIconCanvas *parent, QAbstractItemDelegate *defaultDelegate); ~KIconCanvasDelegate() {}; void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const Q_DECL_OVERRIDE; QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const Q_DECL_OVERRIDE; private: KIconCanvas *m_iconCanvas; QAbstractItemDelegate *m_defaultDelegate; static const int HORIZONTAL_EDGE_PAD = 3; }; KIconCanvasDelegate::KIconCanvasDelegate(KIconCanvas *parent, QAbstractItemDelegate *defaultDelegate) : QAbstractItemDelegate(parent) { m_iconCanvas = parent; m_defaultDelegate = defaultDelegate; } void KIconCanvasDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const { const int GRID_WIDTH = m_iconCanvas->gridSize().width(); QStyleOptionViewItem newOption = option; // Manipulate the width available. newOption.rect.setX((option.rect.x() / GRID_WIDTH) * GRID_WIDTH + HORIZONTAL_EDGE_PAD); newOption.rect.setWidth(GRID_WIDTH - 2 * HORIZONTAL_EDGE_PAD); m_defaultDelegate->paint(painter, newOption, index); } QSize KIconCanvasDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const { QSize size = m_defaultDelegate->sizeHint(option, index); const int GRID_WIDTH = m_iconCanvas->gridSize().width(); size.setWidth(GRID_WIDTH - 2 * HORIZONTAL_EDGE_PAD); return size; } /* * KIconCanvas: Iconview for the iconloader dialog. */ KIconCanvas::KIconCanvas(QWidget *parent) : QListWidget(parent), m_loading(false), m_timer(new QTimer(this)), m_delegate(new KIconCanvasDelegate(this, itemDelegate())) { setViewMode(IconMode); setUniformItemSizes(true); setMovement(Static); setIconSize(QSize(60, 60)); connect(m_timer, SIGNAL(timeout()), this, SLOT(loadFiles())); connect(this, &QListWidget::currentItemChanged, this, &KIconCanvas::currentListItemChanged); setGridSize(QSize(100, 80)); setItemDelegate(m_delegate); } KIconCanvas::~KIconCanvas() { delete m_timer; delete m_delegate; } void KIconCanvas::loadFiles(const QStringList &files) { clear(); m_files = files; emit startLoading(m_files.count()); m_timer->setSingleShot(true); m_timer->start(10); m_loading = false; } void KIconCanvas::loadFiles() { setResizeMode(QListWidget::Fixed); QApplication::setOverrideCursor(Qt::WaitCursor); // disable updates to not trigger paint events when adding child items, // but force an initial paint so that we do not get garbage repaint(); setUpdatesEnabled(false); // Cache these as we will call them frequently. const int canvasIconWidth = iconSize().width(); const int canvasIconHeight = iconSize().width(); const bool uniformIconSize = uniformItemSizes(); m_loading = true; int i; QStringList::ConstIterator it; uint emitProgress = 10; // so we will emit it once in the beginning QStringList::ConstIterator end(m_files.constEnd()); for (it = m_files.constBegin(), i = 0; it != end; ++it, ++i) { if (emitProgress >= 10) { emit progress(i); emitProgress = 0; } emitProgress++; if (!m_loading) { // user clicked on a button that will load another set of icons break; } QImage img; // Use the extension as the format. Works for XPM and PNG, but not for SVG QString path = *it; QString ext = path.right(3).toUpper(); if (ext != QLatin1String("SVG") && ext != QLatin1String("VGZ")) { img.load(*it); } else { #ifndef _WIN32_WCE // Special stuff for SVG icons img = QImage(canvasIconWidth, canvasIconHeight, QImage::Format_ARGB32_Premultiplied); img.fill(0); QSvgRenderer renderer(*it); if (renderer.isValid()) { QPainter p(&img); renderer.render(&p); } #endif } if (img.isNull()) { continue; } if (img.width() > canvasIconWidth || img.height() > canvasIconHeight) { if (img.width() / (float)canvasIconWidth > img.height() / (float)canvasIconHeight) { int height = (int)(((float)canvasIconWidth / img.width()) * img.height()); img = img.scaled(canvasIconWidth, height, Qt::IgnoreAspectRatio, Qt::SmoothTransformation); } else { int width = (int)(((float)canvasIconHeight / img.height()) * img.width()); img = img.scaled(width, canvasIconHeight, Qt::IgnoreAspectRatio, Qt::SmoothTransformation); } } if (uniformIconSize && (img.width() != canvasIconWidth || img.height() != canvasIconHeight)) { // Image is smaller than desired. Draw onto a transparent QImage of the required dimensions. // (Unpleasant glitches occur if we break the uniformIconSizes() contract). QImage paddedImage = QImage(canvasIconWidth, canvasIconHeight, QImage::Format_ARGB32_Premultiplied); paddedImage.fill(0); QPainter painter(&paddedImage); painter.drawImage((canvasIconWidth - img.width()) / 2, (canvasIconHeight - img.height()) / 2, img); img = paddedImage; } QPixmap pm = QPixmap::fromImage(img); QFileInfo fi(*it); QListWidgetItem *item = new QListWidgetItem(pm, fi.completeBaseName(), this); item->setData(Qt::UserRole, *it); item->setToolTip(fi.completeBaseName()); } // enable updates since we have to draw the whole view now setUpdatesEnabled(true); QApplication::restoreOverrideCursor(); m_loading = false; emit finished(); setResizeMode(QListWidget::Adjust); } QString KIconCanvas::getCurrent() const { if (!currentItem()) { return QString(); } return currentItem()->data(Qt::UserRole).toString(); } void KIconCanvas::stopLoading() { m_loading = false; } void KIconCanvas::currentListItemChanged(QListWidgetItem *item) { - emit nameChanged((item != 0L) ? item->text() : QString()); + emit nameChanged((item != nullptr) ? item->text() : QString()); } // TODO KF6 remove and override KIconDialog::showEvent() class ShowEventFilter : public QObject { public: explicit ShowEventFilter(QObject *parent) : QObject(parent) {}; virtual ~ShowEventFilter() {}; private: bool eventFilter(QObject *watched, QEvent *event) Q_DECL_OVERRIDE { if (event->type() == QEvent::Show) { KIconDialog *q = static_cast(parent()); q->d->showIcons(); q->d->searchLine->setFocus(); } return QObject::eventFilter(watched, event); } }; /* * KIconDialog: Dialog for selecting icons. Both system and user * specified icons can be chosen. */ KIconDialog::KIconDialog(QWidget *parent) : QDialog(parent), d(new KIconDialogPrivate(this)) { setModal(true); setWindowTitle(i18n("Select Icon")); d->mpLoader = KIconLoader::global(); d->init(); installEventFilter(new ShowEventFilter(this)); } KIconDialog::KIconDialog(KIconLoader *loader, QWidget *parent) : QDialog(parent), d(new KIconDialogPrivate(this)) { setModal(true); setWindowTitle(i18n("Select Icon")); d->mpLoader = loader; d->init(); installEventFilter(new ShowEventFilter(this)); } void KIconDialog::KIconDialogPrivate::init() { mGroupOrSize = KIconLoader::Desktop; mContext = KIconLoader::Any; QVBoxLayout *top = new QVBoxLayout; q->setLayout(top); QGroupBox *bgroup = new QGroupBox(q); bgroup->setTitle(i18n("Icon Source")); QVBoxLayout *vbox = new QVBoxLayout; bgroup->setLayout(vbox); top->addWidget(bgroup); QGridLayout *grid = new QGridLayout(); vbox->addLayout(grid); mpSystemIcons = new QRadioButton(i18n("S&ystem icons:"), bgroup); connect(mpSystemIcons, SIGNAL(clicked()), q, SLOT(_k_slotSystemIconClicked())); grid->addWidget(mpSystemIcons, 1, 0); mpCombo = new QComboBox(bgroup); connect(mpCombo, SIGNAL(activated(int)), q, SLOT(_k_slotContext(int))); grid->addWidget(mpCombo, 1, 1); mpOtherIcons = new QRadioButton(i18n("O&ther icons:"), bgroup); connect(mpOtherIcons, SIGNAL(clicked()), q, SLOT(_k_slotOtherIconClicked())); grid->addWidget(mpOtherIcons, 2, 0); mpBrowseBut = new QPushButton(i18n("&Browse..."), bgroup); connect(mpBrowseBut, SIGNAL(clicked()), q, SLOT(_k_slotBrowse())); grid->addWidget(mpBrowseBut, 2, 1); // // ADD SEARCHLINE // QHBoxLayout *searchLayout = new QHBoxLayout(); searchLayout->setMargin(0); top->addLayout(searchLayout); QLabel *searchLabel = new QLabel(i18n("&Search:"), q); searchLayout->addWidget(searchLabel); searchLine = new KListWidgetSearchLine(q); searchLayout->addWidget(searchLine); searchLabel->setBuddy(searchLine); QString wtstr = i18n("Search interactively for icon names (e.g. folder)."); searchLabel->setWhatsThis(wtstr); searchLine->setWhatsThis(wtstr); mpCanvas = new KIconCanvas(q); connect(mpCanvas, SIGNAL(itemActivated(QListWidgetItem*)), q, SLOT(_k_slotAcceptIcons())); top->addWidget(mpCanvas); searchLine->setListWidget(mpCanvas); // Compute width of canvas with 4 icons displayed in a row QStyleOption opt; opt.initFrom(mpCanvas); int width = 4 * mpCanvas->gridSize().width() + 1; width += mpCanvas->verticalScrollBar()->sizeHint().width(); width += 2 * mpCanvas->frameWidth(); if (mpCanvas->style()->styleHint(QStyle::SH_ScrollView_FrameOnlyAroundContents, &opt, mpCanvas)) { width += mpCanvas->style()->pixelMetric(QStyle::PM_ScrollView_ScrollBarSpacing, &opt, mpCanvas); } mpCanvas->setMinimumSize(width, 125); mpProgress = new QProgressBar(q); top->addWidget(mpProgress); connect(mpCanvas, SIGNAL(startLoading(int)), q, SLOT(_k_slotStartLoading(int))); connect(mpCanvas, SIGNAL(progress(int)), q, SLOT(_k_slotProgress(int))); connect(mpCanvas, SIGNAL(finished()), q, SLOT(_k_slotFinished())); // When pressing Ok or Cancel, stop loading icons connect(q, &QDialog::finished, mpCanvas, &KIconCanvas::stopLoading); static const char *const context_text[] = { I18N_NOOP("Actions"), I18N_NOOP("Applications"), I18N_NOOP("Categories"), I18N_NOOP("Devices"), I18N_NOOP("Emblems"), I18N_NOOP("Emotes"), I18N_NOOP("Mimetypes"), I18N_NOOP("Places"), I18N_NOOP("Status"), I18N_NOOP("All") }; static const KIconLoader::Context context_id[] = { KIconLoader::Action, KIconLoader::Application, KIconLoader::Category, KIconLoader::Device, KIconLoader::Emblem, KIconLoader::Emote, KIconLoader::MimeType, KIconLoader::Place, KIconLoader::StatusIcon, KIconLoader::Any }; mNumContext = 0; int cnt = sizeof(context_text) / sizeof(context_text[ 0 ]); // check all 3 arrays have same sizes Q_ASSERT(cnt == sizeof(context_id) / sizeof(context_id[ 0 ]) && cnt == sizeof(mContextMap) / sizeof(mContextMap[ 0 ])); for (int i = 0; i < cnt; ++i) { if (mpLoader->hasContext(context_id[ i ])) { mpCombo->addItem(i18n(context_text[ i ])); mContextMap[ mNumContext++ ] = context_id[ i ]; } } mpCombo->setMaxVisibleItems(cnt); mpCombo->setFixedSize(mpCombo->sizeHint()); mpBrowseBut->setFixedWidth(mpCombo->width()); QDialogButtonBox *buttonBox = new QDialogButtonBox(q); buttonBox->setStandardButtons(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); connect(buttonBox, &QDialogButtonBox::accepted, q, &KIconDialog::slotOk); connect(buttonBox, &QDialogButtonBox::rejected, q, &QDialog::reject); top->addWidget(buttonBox); // Make the dialog a little taller q->resize(q->sizeHint() + QSize(0, 100)); q->adjustSize(); } KIconDialog::~KIconDialog() { delete d; } void KIconDialog::KIconDialogPrivate::_k_slotAcceptIcons() { custom.clear(); q->slotOk(); } static bool sortByFileName(const QString &path1, const QString &path2) { const QString fileName1 = path1.mid(path1.lastIndexOf('/') + 1); const QString fileName2 = path2.mid(path1.lastIndexOf('/') + 1); return QString::compare(fileName1, fileName2, Qt::CaseInsensitive) < 0; } void KIconDialog::KIconDialogPrivate::showIcons() { mpCanvas->clear(); QStringList filelist; if (mpSystemIcons->isChecked()) { if (m_bStrictIconSize) { filelist = mpLoader->queryIcons(mGroupOrSize, mContext); } else { filelist = mpLoader->queryIconsByContext(mGroupOrSize, mContext); } } else if (!customLocation.isEmpty()) { filelist = mpLoader->queryIconsByDir(customLocation); } else { // List PNG files found directly in the kiconload search paths. Q_FOREACH (const QString &relDir, KIconLoader::global()->searchPaths()) { const QStringList dirs = QStandardPaths::locateAll(QStandardPaths::GenericDataLocation, relDir, QStandardPaths::LocateDirectory); Q_FOREACH (const QString &dir, dirs) { Q_FOREACH (const QString &fileName, QDir(dir).entryList(QStringList() << "*.png")) { filelist << dir + '/' + fileName; } } } } qSort(filelist.begin(), filelist.end(), sortByFileName); // The KIconCanvas has uniformItemSizes set which really expects // all added icons to be the same size, otherwise weirdness ensues :) // Ensure all SVGs are scaled to the desired size and that as few icons // need to be padded as possible by specifying a sensible size. if (mGroupOrSize < -1) { // mGroupOrSize can be -1 if NoGroup is chosen. // Explicit size. mpCanvas->setIconSize(QSize(-mGroupOrSize, -mGroupOrSize)); } else { // Icon group. int groupSize = mpLoader->currentSize((KIconLoader::Group)mGroupOrSize); mpCanvas->setIconSize(QSize(groupSize, groupSize)); } mpCanvas->loadFiles(filelist); } void KIconDialog::setStrictIconSize(bool b) { d->m_bStrictIconSize = b; } bool KIconDialog::strictIconSize() const { return d->m_bStrictIconSize; } void KIconDialog::setIconSize(int size) { // see KIconLoader, if you think this is weird if (size == 0) { d->mGroupOrSize = KIconLoader::Desktop; // default Group } else { d->mGroupOrSize = -size; // yes, KIconLoader::queryIconsByContext is weird } } int KIconDialog::iconSize() const { // 0 or any other value ==> mGroupOrSize is a group, so we return 0 return (d->mGroupOrSize < 0) ? -d->mGroupOrSize : 0; } void KIconDialog::setup(KIconLoader::Group group, KIconLoader::Context context, bool strictIconSize, int iconSize, bool user, bool lockUser, bool lockCustomDir) { d->m_bStrictIconSize = strictIconSize; d->m_bLockUser = lockUser; d->m_bLockCustomDir = lockCustomDir; if (iconSize == 0) { if (group == KIconLoader::NoGroup) { // NoGroup has numeric value -1, which should // not really be used with KIconLoader::queryIcons*(...); // pick a proper group. d->mGroupOrSize = KIconLoader::Small; } else { d->mGroupOrSize = group; } } else { d->mGroupOrSize = -iconSize; } d->mpSystemIcons->setChecked(!user); d->mpSystemIcons->setEnabled(!lockUser || !user); d->mpOtherIcons->setChecked(user); d->mpOtherIcons->setEnabled(!lockUser || user); d->mpCombo->setEnabled(!user); d->mpBrowseBut->setEnabled(user && !lockCustomDir); d->setContext(context); } void KIconDialog::KIconDialogPrivate::setContext(KIconLoader::Context context) { mContext = context; for (int i = 0; i < mNumContext; ++i) { if (mContextMap[ i ] == context) { mpCombo->setCurrentIndex(i); return; } } } void KIconDialog::setCustomLocation(const QString &location) { d->customLocation = location; } QString KIconDialog::openDialog() { if (exec() == Accepted) { if (!d->custom.isEmpty()) { return d->custom; } QString name = d->mpCanvas->getCurrent(); if (name.isEmpty() || d->mpOtherIcons->isChecked()) { return name; } QFileInfo fi(name); return fi.completeBaseName(); } return QString(); } void KIconDialog::showDialog() { setModal(false); show(); } void KIconDialog::slotOk() { QString name; if (!d->custom.isEmpty()) { name = d->custom; } else { name = d->mpCanvas->getCurrent(); if (!name.isEmpty() && d->mpSystemIcons->isChecked()) { const QFileInfo fi(name); name = fi.completeBaseName(); } } emit newIconName(name); QDialog::accept(); } QString KIconDialog::getIcon(KIconLoader::Group group, KIconLoader::Context context, bool strictIconSize, int iconSize, bool user, QWidget *parent, const QString &caption) { KIconDialog dlg(parent); dlg.setup(group, context, strictIconSize, iconSize, user); if (!caption.isEmpty()) { dlg.setWindowTitle(caption); } return dlg.openDialog(); } void KIconDialog::KIconDialogPrivate::_k_slotBrowse() { if (browseDialog) { browseDialog.data()->show(); browseDialog.data()->raise(); return; } // Create a file dialog to select a PNG, XPM or SVG file, // with the image previewer shown. QFileDialog *dlg = new QFileDialog(q, i18n("Select Icon"), QString(), i18n("*.png *.xpm *.svg *.svgz|Icon Files (*.png *.xpm *.svg *.svgz)")); dlg->setModal(false); dlg->setFileMode(QFileDialog::ExistingFile); connect(dlg, SIGNAL(fileSelected(QString)), q, SLOT(_k_customFileSelected(QString))); browseDialog = dlg; dlg->show(); } void KIconDialog::KIconDialogPrivate::_k_customFileSelected(const QString &path) { if (!path.isEmpty()) { custom = path; if (mpSystemIcons->isChecked()) { customLocation = QFileInfo(custom).absolutePath(); } q->slotOk(); } } void KIconDialog::KIconDialogPrivate::_k_slotSystemIconClicked() { mpBrowseBut->setEnabled(false); mpCombo->setEnabled(true); showIcons(); } void KIconDialog::KIconDialogPrivate::_k_slotOtherIconClicked() { mpBrowseBut->setEnabled(!m_bLockCustomDir); mpCombo->setEnabled(false); showIcons(); } void KIconDialog::KIconDialogPrivate::_k_slotContext(int id) { mContext = static_cast(mContextMap[ id ]); showIcons(); } void KIconDialog::KIconDialogPrivate::_k_slotStartLoading(int steps) { if (steps < 10) { mpProgress->hide(); } else { mNumOfSteps = steps; mpProgress->setValue(0); mpProgress->show(); } } void KIconDialog::KIconDialogPrivate::_k_slotProgress(int p) { mpProgress->setValue(static_cast(100.0 * (double)p / (double)mNumOfSteps)); } void KIconDialog::KIconDialogPrivate::_k_slotFinished() { mNumOfSteps = 1; mpProgress->hide(); } #include "moc_kicondialog.cpp" #include "moc_kicondialog_p.cpp" diff --git a/src/kicondialog.h b/src/kicondialog.h index feb72e4..b1809f1 100644 --- a/src/kicondialog.h +++ b/src/kicondialog.h @@ -1,163 +1,163 @@ /* vi: ts=8 sts=4 sw=4 * * This file is part of the KDE project, module kfile. * Copyright (C) 2000 Geert Jansen * (C) 2000 Kurt Granroth * (C) 1997 Christoph Neerfeld * (C) 2002 Carsten Pfeiffer * * This is free software; it comes under the GNU Library General * Public License, version 2. See the file "COPYING.LIB" for the * exact licensing terms. */ #ifndef KICONDIALOG_H #define KICONDIALOG_H #include "kiconthemes_export.h" #include #include #include #include /** * Dialog for interactive selection of icons. Use the function * getIcon() to let the user select an icon. * * @short An icon selection dialog. */ class KICONTHEMES_EXPORT KIconDialog: public QDialog { Q_OBJECT public: /** * Constructs an icon selection dialog using the global icon loader. * * @param parent The parent widget. */ - explicit KIconDialog(QWidget *parent = 0L); + explicit KIconDialog(QWidget *parent = nullptr); /** * Constructs an icon selection dialog using a specific icon loader. * * @param loader The icon loader to use. * @param parent The parent widget. */ - explicit KIconDialog(KIconLoader *loader, QWidget *parent = 0); + explicit KIconDialog(KIconLoader *loader, QWidget *parent = nullptr); /** * Destructs the dialog. */ ~KIconDialog(); /** * Sets a strict icon size policy for allowed icons. * * @param policy When true, only icons of the specified group's * size in getIcon() are shown. * When false, icons not available at the desired group's size will * also be selectable. */ void setStrictIconSize(bool policy); /** * Returns true if a strict icon size policy is set. */ bool strictIconSize() const; /** * Sets the location of the custom icon directory. Only local directory * paths are allowed. */ void setCustomLocation(const QString &location); /** * Sets the size of the icons to be shown / selected. * @see KIconLoader::StdSizes * @see iconSize */ void setIconSize(int size); /** * Returns the icon size set via setIconSize() or 0, if the default * icon size will be used. */ int iconSize() const; /** * Allows you to set the same parameters as in the class method * getIcon(), as well as two additional parameters to lock * the choice between system and user directories and to lock the * custom icon directory itself. */ void setup(KIconLoader::Group group, KIconLoader::Context context = KIconLoader::Application, bool strictIconSize = false, int iconSize = 0, bool user = false, bool lockUser = false, bool lockCustomDir = false); /** * exec()utes this modal dialog and returns the name of the selected icon, * or QString() if the dialog was aborted. * @returns the name of the icon, suitable for loading with KIconLoader. * @see getIcon */ QString openDialog(); /** * show()s this dialog and emits a newIconName(const QString&) signal when * successful. QString() will be emitted if the dialog was aborted. */ void showDialog(); /** * Pops up the dialog an lets the user select an icon. * * @param group The icon group this icon is intended for. Providing the * group shows the icons in the dialog with the same appearance as when * used outside the dialog. * @param context The initial icon context. Initially, the icons having * this context are shown in the dialog. The user can change this. * @param strictIconSize When true, only icons of the specified group's size * are shown, otherwise icon not available in the desired group's size * will also be selectable. * @param iconSize the size of the icons -- the default of the icon group * if set to 0 * @param user Begin with the "user icons" instead of "system icons". * @param parent The parent widget of the dialog. * @param caption The caption to use for the dialog. * @return The name of the icon, suitable for loading with KIconLoader. */ static QString getIcon(KIconLoader::Group group = KIconLoader::Desktop, KIconLoader::Context context = KIconLoader::Application, bool strictIconSize = false, int iconSize = 0, - bool user = false, QWidget *parent = 0, + bool user = false, QWidget *parent = nullptr, const QString &caption = QString()); Q_SIGNALS: void newIconName(const QString &iconName); protected Q_SLOTS: void slotOk(); private: class KIconDialogPrivate; KIconDialogPrivate *const d; friend class ShowEventFilter; Q_DISABLE_COPY(KIconDialog) Q_PRIVATE_SLOT(d, void _k_slotContext(int)) Q_PRIVATE_SLOT(d, void _k_slotStartLoading(int)) Q_PRIVATE_SLOT(d, void _k_slotProgress(int)) Q_PRIVATE_SLOT(d, void _k_slotFinished()) Q_PRIVATE_SLOT(d, void _k_slotAcceptIcons()) Q_PRIVATE_SLOT(d, void _k_slotBrowse()) Q_PRIVATE_SLOT(d, void _k_customFileSelected(const QString &path)) Q_PRIVATE_SLOT(d, void _k_slotOtherIconClicked()) Q_PRIVATE_SLOT(d, void _k_slotSystemIconClicked()) }; #endif // KICONDIALOG_H diff --git a/src/kicondialog_p.h b/src/kicondialog_p.h index f25e3a4..9ab4335 100644 --- a/src/kicondialog_p.h +++ b/src/kicondialog_p.h @@ -1,155 +1,155 @@ /* vi: ts=8 sts=4 sw=4 * * This file is part of the KDE project, module kfile. * Copyright (C) 2000 Geert Jansen * (C) 2000 Kurt Granroth * (C) 1997 Christoph Neerfeld * (C) 2002 Carsten Pfeiffer * * This is free software; it comes under the GNU Library General * Public License, version 2. See the file "COPYING.LIB" for the * exact licensing terms. */ #ifndef KICONDIALOG_P_H #define KICONDIALOG_P_H #include #include #include #include #include class QComboBox; class QProgressBar; class QRadioButton; class KIconCanvasDelegate; class KListWidgetSearchLine; /** * Icon canvas for KIconDialog. */ class KIconCanvas: public QListWidget { Q_OBJECT public: /** * Creates a new icon canvas. * * @param parent The parent widget. */ - explicit KIconCanvas(QWidget *parent = 0L); + explicit KIconCanvas(QWidget *parent = nullptr); /** * Destroys the icon canvas. */ ~KIconCanvas(); /** * Load icons into the canvas. */ void loadFiles(const QStringList &files); /** * Returns the current icon. */ QString getCurrent() const; public Q_SLOTS: /** * Call this slot to stop the loading of the icons. */ void stopLoading(); Q_SIGNALS: /** * Emitted when the current icon has changed. */ void nameChanged(const QString &); /** * This signal is emitted when the loading of the icons * has started. * * @param count The number of icons to be loaded. */ void startLoading(int count); /** * This signal is emitted whenever an icon has been loaded. * * @param number The number of the currently loaded item. */ void progress(int number); /** * This signal is emitted when the loading of the icons * has been finished. */ void finished(); private Q_SLOTS: void loadFiles(); void currentListItemChanged(QListWidgetItem *item); private: bool m_loading; QStringList m_files; QTimer *m_timer; KIconCanvasDelegate *m_delegate; }; class KIconDialog::KIconDialogPrivate { public: KIconDialogPrivate(KIconDialog *qq) { q = qq; m_bStrictIconSize = true; m_bLockUser = false; m_bLockCustomDir = false; - searchLine = 0; + searchLine = nullptr; mNumOfSteps = 1; } ~KIconDialogPrivate() {} void init(); void showIcons(); void setContext(KIconLoader::Context context); // slots void _k_slotContext(int); void _k_slotStartLoading(int); void _k_slotProgress(int); void _k_slotFinished(); void _k_slotAcceptIcons(); void _k_slotBrowse(); void _k_customFileSelected(const QString &path); void _k_slotOtherIconClicked(); void _k_slotSystemIconClicked(); KIconDialog *q; int mGroupOrSize; KIconLoader::Context mContext; QComboBox *mpCombo; QPushButton *mpBrowseBut; QRadioButton *mpSystemIcons, *mpOtherIcons; QProgressBar *mpProgress; int mNumOfSteps; KIconLoader *mpLoader; KIconCanvas *mpCanvas; int mNumContext; KIconLoader::Context mContextMap[ 10 ]; // must match KDE::icon::Context size, code has assert bool m_bStrictIconSize, m_bLockUser, m_bLockCustomDir; QString custom; QString customLocation; KListWidgetSearchLine *searchLine; QPointer browseDialog; }; #endif // KICONDIALOG_P_H diff --git a/src/kiconloader.cpp b/src/kiconloader.cpp index 726b43f..22e7253 100644 --- a/src/kiconloader.cpp +++ b/src/kiconloader.cpp @@ -1,1821 +1,1821 @@ /* vi: ts=8 sts=4 sw=4 * * kiconloader.cpp: An icon loader for KDE with theming functionality. * * This file is part of the KDE project, module kdeui. * Copyright (C) 2000 Geert Jansen * Antonio Larrosa * 2010 Michael Pyne * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License version 2 as published by the Free Software Foundation. * * 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 "kiconloader.h" #include //for readlink #include #include #include #include #include #include #include #include // % operator for QString #include #include #include #include #include #include #include #include // kdecore #include #include #include #include #include #include #include #include #include // kdeui #include "kicontheme.h" #include "kiconeffect.h" #include "debug.h" //kwidgetsaddons #include #include #include namespace { // Used to make cache keys for icons with no group. Result type is QString* QString NULL_EFFECT_FINGERPRINT() { return QStringLiteral("noeffect"); } QString STYLESHEET_TEMPLATE() { return QStringLiteral(".ColorScheme-Text {\ color:%1;\ }\ .ColorScheme-Background{\ color:%2;\ }\ .ColorScheme-Highlight{\ color:%3;\ }\ .ColorScheme-PositiveText{\ color:%4;\ }\ .ColorScheme-NeutralText{\ color:%5;\ }\ .ColorScheme-NegativeText{\ color:%6;\ }"); } } /** * Checks for relative paths quickly on UNIX-alikes, slowly on everything else. */ static bool pathIsRelative(const QString &path) { #ifdef Q_OS_UNIX return (!path.isEmpty() && path[0] != QChar('/')); #else return QDir::isRelativePath(path); #endif } /** * Holds a QPixmap for this process, along with its associated path on disk. */ struct PixmapWithPath { QPixmap pixmap; QString path; }; /** * Function to convert an uint32_t to AARRGGBB hex values. * * W A R N I N G ! * This function is for internal use! */ KICONTHEMES_EXPORT void uintToHex(uint32_t colorData, QChar *buffer) { static const char hexLookup[] = "0123456789abcdef"; buffer += 7; uchar *colorFields = reinterpret_cast(&colorData); for (int i = 0; i < 4; i++) { *buffer-- = hexLookup[*colorFields & 0xf]; *buffer-- = hexLookup[*colorFields >> 4]; colorFields++; } } static QString paletteId(const QPalette &pal) { // 8 per color. We want 3 colors thus 8*3=24. QString buffer(24, Qt::Uninitialized); uintToHex(pal.text().color().rgba(), buffer.data()); uintToHex(pal.highlight().color().rgba(), buffer.data() + 8); uintToHex(pal.highlightedText().color().rgba(), buffer.data() + 16); return buffer; } /*** KIconThemeNode: A node in the icon theme dependancy tree. ***/ class KIconThemeNode { public: KIconThemeNode(KIconTheme *_theme); ~KIconThemeNode(); void queryIcons(QStringList *lst, int size, KIconLoader::Context context) const; void queryIconsByContext(QStringList *lst, int size, KIconLoader::Context context) const; QString findIcon(const QString &name, int size, KIconLoader::MatchType match) const; KIconTheme *theme; }; KIconThemeNode::KIconThemeNode(KIconTheme *_theme) { theme = _theme; } KIconThemeNode::~KIconThemeNode() { delete theme; } void KIconThemeNode::queryIcons(QStringList *result, int size, KIconLoader::Context context) const { // add the icons of this theme to it *result += theme->queryIcons(size, context); } void KIconThemeNode::queryIconsByContext(QStringList *result, int size, KIconLoader::Context context) const { // add the icons of this theme to it *result += theme->queryIconsByContext(size, context); } QString KIconThemeNode::findIcon(const QString &name, int size, KIconLoader::MatchType match) const { return theme->iconPath(name, size, match); } /*** KIconGroup: Icon type description. ***/ struct KIconGroup { int size; }; extern KICONTHEMES_EXPORT int kiconloader_ms_between_checks; KICONTHEMES_EXPORT int kiconloader_ms_between_checks = 5000; /*** d pointer for KIconLoader. ***/ class KIconLoaderPrivate { public: KIconLoaderPrivate(KIconLoader *q) : q(q) - , mpGroups(0) - , mIconCache(0) + , mpGroups(nullptr) + , mIconCache(nullptr) { } ~KIconLoaderPrivate() { clear(); } void clear() { /* antlarr: There's no need to delete d->mpThemeRoot as it's already deleted when the elements of d->links are deleted */ qDeleteAll(links); delete[] mpGroups; delete mIconCache; - mpGroups = 0; - mIconCache = 0; + mpGroups = nullptr; + mIconCache = nullptr; mPixmapCache.clear(); appname.clear(); searchPaths.clear(); links.clear(); mIconThemeInited = false; mThemesInTree.clear(); } /** * @internal */ void init(const QString &_appname, const QStringList &extraSearchPaths = QStringList()); /** * @internal */ bool initIconThemes(); /** * @internal * tries to find an icon with the name. It tries some extension and * match strategies */ QString findMatchingIcon(const QString &name, int size) const; /** * @internal * tries to find an icon with the name. * This is one layer above findMatchingIcon -- it also implements generic fallbacks * such as generic icons for mimetypes. */ QString findMatchingIconWithGenericFallbacks(const QString &name, int size) const; /** * @internal * Adds themes installed in the application's directory. **/ void addAppThemes(const QString &appname, const QString &themeBaseDir = QString()); /** * @internal * Adds all themes that are part of this node and the themes * below (the fallbacks of the theme) into the tree. */ void addBaseThemes(KIconThemeNode *node, const QString &appname); /** * @internal * Recursively adds all themes that are specified in the "Inherits" * property of the given theme into the tree. */ void addInheritedThemes(KIconThemeNode *node, const QString &appname); /** * @internal * Creates a KIconThemeNode out of a theme name, and adds this theme * as well as all its inherited themes into the tree. Themes that already * exist in the tree will be ignored and not added twice. */ void addThemeByName(const QString &themename, const QString &appname); /** * Adds all the default themes from other desktops at the end of * the list of icon themes. */ void addExtraDesktopThemes(); /** * @internal * return the path for the unknown icon in that size */ QString unknownIconPath(int size) const; /** * Checks if name ends in one of the supported icon formats (i.e. .png) * and returns the name without the extension if it does. */ QString removeIconExtension(const QString &name) const; /** * @internal * Used with KIconLoader::loadIcon to convert the given name, size, group, * and icon state information to valid states. All parameters except the * name can be modified as well to be valid. */ void normalizeIconMetadata(KIconLoader::Group &group, int &size, int &state) const; /** * @internal * Used with KIconLoader::loadIcon to get a base key name from the given * icon metadata. Ensure the metadata is normalized first. */ QString makeCacheKey(const QString &name, KIconLoader::Group group, const QStringList &overlays, int size, int state) const; /** * @internal * If the icon is an SVG file, process it generating a stylesheet * following the current color scheme. in this case the icon can use named colors * as text color, background color, highlight color, positive/neutral/negative color * @see KColorScheme */ QByteArray processSvg(const QString &path, KIconLoader::States state) const; /** * @internal * Creates the QImage for @p path, using SVG rendering as appropriate. * @p size is only used for scalable images, but if non-zero non-scalable * images will be resized anyways. */ QImage createIconImage(const QString &path, int size = 0, KIconLoader::States state = KIconLoader::DefaultState); /** * @internal * Adds an QPixmap with its associated path to the shared icon cache. */ void insertCachedPixmapWithPath(const QString &key, const QPixmap &data, const QString &path); /** * @internal * Retrieves the path and pixmap of the given key from the shared * icon cache. */ bool findCachedPixmapWithPath(const QString &key, QPixmap &data, QString &path); /** * Find the given file in the search paths. */ QString locate(const QString &fileName); /** * @internal * React to a global icon theme change */ void _k_refreshIcons(int group); bool shouldCheckForUnknownIcons() { if (mLastUnknownIconCheck.isValid() && mLastUnknownIconCheck.elapsed() < kiconloader_ms_between_checks) { return false; } mLastUnknownIconCheck.start(); return true; } KIconLoader *const q; QStringList mThemesInTree; KIconGroup *mpGroups; KIconThemeNode *mpThemeRoot; QStringList searchPaths; KIconEffect mpEffect; QList links; // This shares the icons across all processes KSharedDataCache *mIconCache; // This caches rendered QPixmaps in just this process. QCache mPixmapCache; bool extraDesktopIconsLoaded : 1; // lazy loading: initIconThemes() is only needed when the "links" list is needed // mIconThemeInited is used inside initIconThemes() to init only once bool mIconThemeInited : 1; QString appname; void drawOverlays(const KIconLoader *loader, KIconLoader::Group group, int state, QPixmap &pix, const QStringList &overlays); QHash mIconAvailability; // icon name -> true (known to be available) or false (known to be unavailable) QElapsedTimer mLastUnknownIconCheck; // recheck for unknown icons after kiconloader_ms_between_checks }; class KIconLoaderGlobalData : public QObject { Q_OBJECT public: KIconLoaderGlobalData() { const QStringList genericIconsFiles = QStandardPaths::locateAll(QStandardPaths::GenericDataLocation, QStringLiteral("mime/generic-icons")); //qCDebug(KICONTHEMES) << genericIconsFiles; Q_FOREACH (const QString &file, genericIconsFiles) { parseGenericIconsFiles(file); } QDBusConnection::sessionBus().connect(QString(), QStringLiteral("/KIconLoader"), QStringLiteral("org.kde.KIconLoader"), QStringLiteral("iconChanged"), this, SIGNAL(iconChanged(int))); } void emitChange(KIconLoader::Group group) { QDBusMessage message = QDBusMessage::createSignal(QStringLiteral("/KIconLoader"), QStringLiteral("org.kde.KIconLoader"), QStringLiteral("iconChanged")); message.setArguments(QList() << int(group)); QDBusConnection::sessionBus().send(message); } QString genericIconFor(const QString &icon) const { return m_genericIcons.value(icon); } Q_SIGNALS: void iconChanged(int group); private: void parseGenericIconsFiles(const QString &fileName); QHash m_genericIcons; }; void KIconLoaderGlobalData::parseGenericIconsFiles(const QString &fileName) { QFile file(fileName); if (file.open(QIODevice::ReadOnly)) { QTextStream stream(&file); stream.setCodec("ISO 8859-1"); while (!stream.atEnd()) { const QString line = stream.readLine(); if (line.isEmpty() || line[0] == '#') { continue; } const int pos = line.indexOf(':'); if (pos == -1) { // syntax error continue; } QString mimeIcon = line.left(pos); const int slashindex = mimeIcon.indexOf(QLatin1Char('/')); if (slashindex != -1) { mimeIcon[slashindex] = QLatin1Char('-'); } const QString genericIcon = line.mid(pos + 1); m_genericIcons.insert(mimeIcon, genericIcon); //qCDebug(KICONTHEMES) << mimeIcon << "->" << genericIcon; } } } Q_GLOBAL_STATIC(KIconLoaderGlobalData, s_globalData) void KIconLoaderPrivate::drawOverlays(const KIconLoader *iconLoader, KIconLoader::Group group, int state, QPixmap &pix, const QStringList &overlays) { if (overlays.isEmpty()) { return; } const int width = pix.size().width(); const int height = pix.size().height(); const int iconSize = qMin(width, height); int overlaySize; if (iconSize < 32) { overlaySize = 8; } else if (iconSize <= 48) { overlaySize = 16; } else if (iconSize <= 96) { overlaySize = 22; } else if (iconSize < 256) { overlaySize = 32; } else { overlaySize = 64; } QPainter painter(&pix); int count = 0; foreach (const QString &overlay, overlays) { // Ensure empty strings fill up a emblem spot // Needed when you have several emblems to ensure they're always painted // at the same place, even if one is not here if (overlay.isEmpty()) { ++count; continue; } //TODO: should we pass in the kstate? it results in a slower // path, and perhaps emblems should remain in the default state // anyways? - const QPixmap pixmap = iconLoader->loadIcon(overlay, group, overlaySize, state, QStringList(), 0, true); + const QPixmap pixmap = iconLoader->loadIcon(overlay, group, overlaySize, state, QStringList(), nullptr, true); if (pixmap.isNull()) { continue; } QPoint startPoint; switch (count) { case 0: // bottom left corner startPoint = QPoint(2, height - overlaySize - 2); break; case 1: // bottom right corner startPoint = QPoint(width - overlaySize - 2, height - overlaySize - 2); break; case 2: // top right corner startPoint = QPoint(width - overlaySize - 2, 2); break; case 3: // top left corner startPoint = QPoint(2, 2); break; } painter.drawPixmap(startPoint, pixmap); ++count; if (count > 3) { break; } } } void KIconLoaderPrivate::_k_refreshIcons(int group) { KSharedConfig::Ptr sharedConfig = KSharedConfig::openConfig(); sharedConfig->reparseConfiguration(); const QString newThemeName = sharedConfig->group("Icons") .readEntry("Theme", QString()); if (!newThemeName.isEmpty()) { // If we're refreshing icons the Qt platform plugin has probably // already cached the old theme, which will accidentally filter back // into KIconTheme unless we reset it QIcon::setThemeName(newThemeName); } q->newIconLoader(); mIconAvailability.clear(); emit q->iconChanged(group); } KIconLoader::KIconLoader(const QString &_appname, const QStringList &extraSearchPaths, QObject *parent) : QObject(parent) { setObjectName(_appname); d = new KIconLoaderPrivate(this); connect(s_globalData, SIGNAL(iconChanged(int)), SLOT(_k_refreshIcons(int))); d->init(_appname, extraSearchPaths); } void KIconLoader::reconfigure(const QString &_appname, const QStringList &extraSearchPaths) { d->mIconCache->clear(); d->clear(); d->init(_appname, extraSearchPaths); } void KIconLoaderPrivate::init(const QString &_appname, const QStringList &extraSearchPaths) { extraDesktopIconsLoaded = false; mIconThemeInited = false; - mpThemeRoot = 0; + mpThemeRoot = nullptr; searchPaths = extraSearchPaths; appname = _appname; if (appname.isEmpty()) { appname = QCoreApplication::applicationName(); } // Initialize icon cache mIconCache = new KSharedDataCache(QStringLiteral("icon-cache"), 10 * 1024 * 1024); // Cost here is number of pixels, not size. So this is actually a bit // smaller. mPixmapCache.setMaxCost(10 * 1024 * 1024); // These have to match the order in kiconloader.h - static const char *const groups[] = { "Desktop", "Toolbar", "MainToolbar", "Small", "Panel", "Dialog", 0L }; + static const char *const groups[] = { "Desktop", "Toolbar", "MainToolbar", "Small", "Panel", "Dialog", nullptr }; KSharedConfig::Ptr config = KSharedConfig::openConfig(); // loading config and default sizes initIconThemes(); - KIconTheme *defaultSizesTheme = links.empty() ? 0 : links.first()->theme; + KIconTheme *defaultSizesTheme = links.empty() ? nullptr : links.first()->theme; mpGroups = new KIconGroup[(int) KIconLoader::LastGroup]; for (KIconLoader::Group i = KIconLoader::FirstGroup; i < KIconLoader::LastGroup; ++i) { - if (groups[i] == 0L) { + if (groups[i] == nullptr) { break; } KConfigGroup cg(config, QLatin1String(groups[i]) + "Icons"); mpGroups[i].size = cg.readEntry("Size", 0); if (!mpGroups[i].size && defaultSizesTheme) { mpGroups[i].size = defaultSizesTheme->defaultSize(i); } } } bool KIconLoaderPrivate::initIconThemes() { if (mIconThemeInited) { // If mpThemeRoot isn't 0 then initing has succeeded - return (mpThemeRoot != 0); + return (mpThemeRoot != nullptr); } //qCDebug(KICONTHEMES); mIconThemeInited = true; // Add the default theme and its base themes to the theme tree KIconTheme *def = new KIconTheme(KIconTheme::current(), appname); if (!def->isValid()) { delete def; // warn, as this is actually a small penalty hit qCDebug(KICONTHEMES) << "Couldn't find current icon theme, falling back to default."; def = new KIconTheme(KIconTheme::defaultThemeName(), appname); if (!def->isValid()) { qWarning() << "Error: standard icon theme" << KIconTheme::defaultThemeName() << "not found!"; delete def; return false; } } mpThemeRoot = new KIconThemeNode(def); mThemesInTree.append(def->internalName()); links.append(mpThemeRoot); addBaseThemes(mpThemeRoot, appname); // Insert application specific themes at the top. searchPaths.append(appname + "/pics"); // Add legacy icon dirs. searchPaths.append(QStringLiteral("icons")); // was xdgdata-icon in KStandardDirs // These are not in the icon spec, but e.g. GNOME puts some icons there anyway. searchPaths.append(QStringLiteral("pixmaps")); // was xdgdata-pixmaps in KStandardDirs return true; } KIconLoader::~KIconLoader() { delete d; } QStringList KIconLoader::searchPaths() const { return d->searchPaths; } void KIconLoader::addAppDir(const QString &appname, const QString &themeBaseDir) { d->initIconThemes(); d->searchPaths.append(appname + "/pics"); d->addAppThemes(appname, themeBaseDir); } void KIconLoaderPrivate::addAppThemes(const QString &appname, const QString &themeBaseDir) { initIconThemes(); KIconTheme *def = new KIconTheme(QStringLiteral("hicolor"), appname, themeBaseDir); if (!def->isValid()) { delete def; def = new KIconTheme(KIconTheme::defaultThemeName(), appname, themeBaseDir); } KIconThemeNode *node = new KIconThemeNode(def); bool addedToLinks = false; if (!mThemesInTree.contains(appname)) { mThemesInTree.append(appname); links.append(node); addedToLinks = true; } addBaseThemes(node, appname); if (!addedToLinks) { // Nodes in links are being deleted later - this one needs manual care. delete node; } } void KIconLoaderPrivate::addBaseThemes(KIconThemeNode *node, const QString &appname) { // Quote from the icon theme specification: // The lookup is done first in the current theme, and then recursively // in each of the current theme's parents, and finally in the // default theme called "hicolor" (implementations may add more // default themes before "hicolor", but "hicolor" must be last). // // So we first make sure that all inherited themes are added, then we // add the KDE default theme as fallback for all icons that might not be // present in an inherited theme, and hicolor goes last. addInheritedThemes(node, appname); addThemeByName(QStringLiteral("hicolor"), appname); } void KIconLoaderPrivate::addInheritedThemes(KIconThemeNode *node, const QString &appname) { const QStringList lst = node->theme->inherits(); for (QStringList::ConstIterator it = lst.begin(); it != lst.end(); ++it) { if ((*it) == QLatin1String("hicolor")) { // The icon theme spec says that "hicolor" must be the very last // of all inherited themes, so don't add it here but at the very end // of addBaseThemes(). continue; } addThemeByName(*it, appname); } } void KIconLoaderPrivate::addThemeByName(const QString &themename, const QString &appname) { if (mThemesInTree.contains(themename + appname)) { return; } KIconTheme *theme = new KIconTheme(themename, appname); if (!theme->isValid()) { delete theme; return; } KIconThemeNode *n = new KIconThemeNode(theme); mThemesInTree.append(themename + appname); links.append(n); addInheritedThemes(n, appname); } void KIconLoaderPrivate::addExtraDesktopThemes() { if (extraDesktopIconsLoaded) { return; } initIconThemes(); QStringList list; const QStringList icnlibs = QStandardPaths::locateAll(QStandardPaths::GenericDataLocation, QStringLiteral("icons"), QStandardPaths::LocateDirectory); QStringList::ConstIterator it; char buf[1000]; for (it = icnlibs.begin(); it != icnlibs.end(); ++it) { QDir dir(*it); if (!dir.exists()) { continue; } const QStringList lst = dir.entryList(QStringList(QStringLiteral("default.*")), QDir::Dirs); QStringList::ConstIterator it2; for (it2 = lst.begin(); it2 != lst.end(); ++it2) { if (!QFileInfo::exists(*it + *it2 + "/index.desktop") && !QFileInfo::exists(*it + *it2 + "/index.theme")) { continue; } //TODO: Is any special handling required for NTFS symlinks? #ifndef Q_OS_WIN const int r = readlink(QFile::encodeName(*it + *it2), buf, sizeof(buf) - 1); if (r > 0) { buf[r] = 0; const QDir dir2(buf); QString themeName = dir2.dirName(); if (!list.contains(themeName)) { list.append(themeName); } } #endif } } for (it = list.constBegin(); it != list.constEnd(); ++it) { // Don't add the KDE defaults once more, we have them anyways. if (*it == QLatin1String("default.kde") || *it == QLatin1String("default.kde4")) { continue; } addThemeByName(*it, QLatin1String("")); } extraDesktopIconsLoaded = true; } void KIconLoader::drawOverlays(const QStringList &overlays, QPixmap &pixmap, KIconLoader::Group group, int state) const { d->drawOverlays(this, group, state, pixmap, overlays); } QString KIconLoaderPrivate::removeIconExtension(const QString &name) const { if (name.endsWith(QLatin1String(".png")) || name.endsWith(QLatin1String(".xpm")) || name.endsWith(QLatin1String(".svg"))) { return name.left(name.length() - 4); } else if (name.endsWith(QLatin1String(".svgz"))) { return name.left(name.length() - 5); } return name; } void KIconLoaderPrivate::normalizeIconMetadata(KIconLoader::Group &group, int &size, int &state) const { if ((state < 0) || (state >= KIconLoader::LastState)) { qWarning() << "Illegal icon state:" << state; state = KIconLoader::DefaultState; } if (size < 0) { size = 0; } // For "User" icons, bail early since the size should be based on the size on disk, // which we've already checked. if (group == KIconLoader::User) { return; } if ((group < -1) || (group >= KIconLoader::LastGroup)) { qWarning() << "Illegal icon group:" << group; group = KIconLoader::Desktop; } // If size == 0, use default size for the specified group. if (size == 0) { if (group < 0) { qWarning() << "Neither size nor group specified!"; group = KIconLoader::Desktop; } size = mpGroups[group].size; } } QString KIconLoaderPrivate::makeCacheKey(const QString &name, KIconLoader::Group group, const QStringList &overlays, int size, int state) const { // The KSharedDataCache is shared so add some namespacing. The following code // uses QStringBuilder (new in Qt 4.6) return (group == KIconLoader::User ? QLatin1Literal("$kicou_") : QLatin1Literal("$kico_")) % name % QLatin1Char('_') % QString::number(size) % QLatin1Char('_') % overlays.join(QStringLiteral("_")) % (group >= 0 ? mpEffect.fingerprint(group, state) : NULL_EFFECT_FINGERPRINT()) % QLatin1Char('_') % paletteId(qApp->palette()) % (q->theme() && q->theme()->followsColorScheme() && state == KIconLoader::SelectedState ? QStringLiteral("_selected") : QString()); } QByteArray KIconLoaderPrivate::processSvg(const QString &path, KIconLoader::States state) const { QScopedPointer device; if (path.endsWith(QLatin1String("svgz"))) { device.reset(new KCompressionDevice(path, KCompressionDevice::GZip)); } else { device.reset(new QFile(path)); } if (!device->open(QIODevice::ReadOnly)) { return QByteArray(); } const QPalette pal = qApp->palette(); KColorScheme scheme(QPalette::Active, KColorScheme::Window); QString styleSheet = STYLESHEET_TEMPLATE().arg( state == KIconLoader::SelectedState ? pal.highlightedText().color().name() : pal.windowText().color().name(), state == KIconLoader::SelectedState ? pal.highlight().color().name() : pal.window().color().name(), state == KIconLoader::SelectedState ? pal.highlightedText().color().name() : pal.highlight().color().name(), scheme.foreground(KColorScheme::PositiveText).color().name(), scheme.foreground(KColorScheme::NeutralText).color().name(), scheme.foreground(KColorScheme::NegativeText).color().name()); QByteArray processedContents; QXmlStreamReader reader(device.data()); QBuffer buffer(&processedContents); buffer.open(QIODevice::WriteOnly); QXmlStreamWriter writer(&buffer); while (!reader.atEnd()) { if (reader.readNext() == QXmlStreamReader::StartElement && reader.qualifiedName() == QLatin1String("style") && reader.attributes().value(QLatin1String("id")) == QLatin1String("current-color-scheme")) { writer.writeStartElement(QLatin1String("style")); writer.writeAttributes(reader.attributes()); writer.writeCharacters(styleSheet); writer.writeEndElement(); while (reader.tokenType() != QXmlStreamReader::EndElement) { reader.readNext(); } } else if (reader.tokenType() != QXmlStreamReader::Invalid) { writer.writeCurrentToken(reader); } } buffer.close(); return processedContents; } QImage KIconLoaderPrivate::createIconImage(const QString &path, int size, KIconLoader::States state) { //TODO: metadata in the theme to make it do this only if explicitly supported? QScopedPointer reader; QBuffer buffer; if (q->theme()->followsColorScheme() && (path.endsWith(QLatin1String("svg")) || path.endsWith(QLatin1String("svgz")))) { buffer.setData(processSvg(path, state)); reader.reset(new QImageReader(&buffer)); } else { reader.reset(new QImageReader(path)); } if (!reader->canRead()) { return QImage(); } if (size != 0) { reader->setScaledSize(QSize(size, size)); } return reader->read(); } void KIconLoaderPrivate::insertCachedPixmapWithPath( const QString &key, const QPixmap &data, const QString &path = QString()) { // Even if the pixmap is null, we add it to the caches so that we record // the fact that whatever icon led to us getting a null pixmap doesn't // exist. QBuffer output; output.open(QIODevice::WriteOnly); QDataStream outputStream(&output); outputStream.setVersion(QDataStream::Qt_4_6); outputStream << path; // Convert the QPixmap to PNG. This is actually done by Qt's own operator. outputStream << data; output.close(); // The byte array contained in the QBuffer is what we want in the cache. mIconCache->insert(key, output.buffer()); // Also insert the object into our process-local cache for even more // speed. PixmapWithPath *pixmapPath = new PixmapWithPath; pixmapPath->pixmap = data; pixmapPath->path = path; mPixmapCache.insert(key, pixmapPath, data.width() * data.height() + 1); } bool KIconLoaderPrivate::findCachedPixmapWithPath(const QString &key, QPixmap &data, QString &path) { // If the pixmap is present in our local process cache, use that since we // don't need to decompress and upload it to the X server/graphics card. const PixmapWithPath *pixmapPath = mPixmapCache.object(key); if (pixmapPath) { path = pixmapPath->path; data = pixmapPath->pixmap; return true; } // Otherwise try to find it in our shared memory cache since that will // be quicker than the disk, especially for SVGs. QByteArray result; if (!mIconCache->find(key, &result) || result.isEmpty()) { return false; } QBuffer buffer; buffer.setBuffer(&result); buffer.open(QIODevice::ReadOnly); QDataStream inputStream(&buffer); inputStream.setVersion(QDataStream::Qt_4_6); QString tempPath; inputStream >> tempPath; if (inputStream.status() == QDataStream::Ok) { QPixmap tempPixmap; inputStream >> tempPixmap; if (inputStream.status() == QDataStream::Ok) { data = tempPixmap; path = tempPath; // Since we're here we didn't have a QPixmap cache entry, add one now. PixmapWithPath *newPixmapWithPath = new PixmapWithPath; newPixmapWithPath->pixmap = data; newPixmapWithPath->path = path; mPixmapCache.insert(key, newPixmapWithPath, data.width() * data.height() + 1); return true; } } return false; } QString KIconLoaderPrivate::findMatchingIconWithGenericFallbacks(const QString &name, int size) const { QString path = findMatchingIcon(name, size); if (!path.isEmpty()) { return path; } const QString genericIcon = s_globalData()->genericIconFor(name); if (!genericIcon.isEmpty()) { path = findMatchingIcon(genericIcon, size); } return path; } QString KIconLoaderPrivate::findMatchingIcon(const QString &name, int size) const { const_cast(this)->initIconThemes(); // Do two passes through themeNodes. // // The first pass looks for an exact match in each themeNode one after the other. // If one is found and it is an app icon then return that icon. // // In the next pass (assuming the first pass failed), it looks for // generic fallbacks in each themeNode one after the other. // In theory we should only do this for mimetype icons, not for app icons, // but that would require different APIs. The long term solution is under // development for Qt >= 5.8, QFileIconProvider calling QPlatformTheme::fileIcon, // using QMimeType::genericIconName() to get the proper -x-generic fallback. // Once everone uses that to look up mimetype icons, we can kill the fallback code // from this method. foreach (KIconThemeNode *themeNode, links) { const QString path = themeNode->theme->iconPathByName(name, size, KIconLoader::MatchBest); if (!path.isEmpty()) { return path; } } if (name.endsWith(QLatin1String("-x-generic"))) { return QString(); // no further fallback } bool genericFallback = false; QString path; foreach (KIconThemeNode *themeNode, links) { QString currentName = name; while (!currentName.isEmpty()) { if (genericFallback) { // we already tested the base name break; } int rindex = currentName.lastIndexOf('-'); if (rindex > 1) { // > 1 so that we don't split x-content or x-epoc currentName.truncate(rindex); if (currentName.endsWith(QLatin1String("-x"))) { currentName.chop(2); } } else { // From update-mime-database.c static const QSet mediaTypes = QSet() << QStringLiteral("text") << QStringLiteral("application") << QStringLiteral("image") << QStringLiteral("audio") << QStringLiteral("inode") << QStringLiteral("video") << QStringLiteral("message") << QStringLiteral("model") << QStringLiteral("multipart") << QStringLiteral("x-content") << QStringLiteral("x-epoc"); // Shared-mime-info spec says: // "If [generic-icon] is not specified then the mimetype is used to generate the // generic icon by using the top-level media type (e.g. "video" in "video/ogg") // and appending "-x-generic" (i.e. "video-x-generic" in the previous example)." if (mediaTypes.contains(currentName)) { currentName += QLatin1String("-x-generic"); genericFallback = true; } else { break; } } if (currentName.isEmpty()) { break; } //qCDebug(KICONTHEMES) << "Looking up" << currentName; path = themeNode->theme->iconPathByName(currentName, size, KIconLoader::MatchBest); if (!path.isEmpty()) { return path; } } } return path; } inline QString KIconLoaderPrivate::unknownIconPath(int size) const { QString path = findMatchingIcon(QStringLiteral("unknown"), size); if (path.isEmpty()) { qCDebug(KICONTHEMES) << "Warning: could not find \"unknown\" icon for size" << size; return QString(); } return path; } QString KIconLoaderPrivate::locate(const QString &fileName) { Q_FOREACH (const QString &dir, searchPaths) { const QString path = dir + '/' + fileName; if (QDir(dir).isAbsolute()) { if (QFileInfo::exists(path)) { return path; } } else { const QString fullPath = QStandardPaths::locate(QStandardPaths::GenericDataLocation, path); if (!fullPath.isEmpty()) { return fullPath; } } } return QString(); } // Finds the absolute path to an icon. QString KIconLoader::iconPath(const QString &_name, int group_or_size, bool canReturnNull) const { if (!d->initIconThemes()) { return QString(); } if (_name.isEmpty() || !pathIsRelative(_name)) { // we have either an absolute path or nothing to work with return _name; } QString name = d->removeIconExtension(_name); QString path; if (group_or_size == KIconLoader::User) { path = d->locate(name + QLatin1String(".png")); if (path.isEmpty()) { path = d->locate(name + QLatin1String(".svgz")); } if (path.isEmpty()) { path = d->locate(name + QLatin1String(".svg")); } if (path.isEmpty()) { path = d->locate(name + QLatin1String(".xpm")); } return path; } if (group_or_size >= KIconLoader::LastGroup) { qCDebug(KICONTHEMES) << "Illegal icon group:" << group_or_size; return path; } int size; if (group_or_size >= 0) { size = d->mpGroups[group_or_size].size; } else { size = -group_or_size; } if (_name.isEmpty()) { if (canReturnNull) { return QString(); } else { return d->unknownIconPath(size); } } path = d->findMatchingIconWithGenericFallbacks(name, size); if (path.isEmpty()) { // Try "User" group too. path = iconPath(name, KIconLoader::User, true); if (!path.isEmpty() || canReturnNull) { return path; } return d->unknownIconPath(size); } return path; } QPixmap KIconLoader::loadMimeTypeIcon(const QString &_iconName, KIconLoader::Group group, int size, int state, const QStringList &overlays, QString *path_store) const { QString iconName = _iconName; const int slashindex = iconName.indexOf(QLatin1Char('/')); if (slashindex != -1) { iconName[slashindex] = QLatin1Char('-'); } if (!d->extraDesktopIconsLoaded) { const QPixmap pixmap = loadIcon(iconName, group, size, state, overlays, path_store, true); if (!pixmap.isNull()) { return pixmap; } d->addExtraDesktopThemes(); } const QPixmap pixmap = loadIcon(iconName, group, size, state, overlays, path_store, true); if (pixmap.isNull()) { // Icon not found, fallback to application/octet-stream return loadIcon(QStringLiteral("application-octet-stream"), group, size, state, overlays, path_store, false); } return pixmap; } QPixmap KIconLoader::loadIcon(const QString &_name, KIconLoader::Group group, int size, int state, const QStringList &overlays, QString *path_store, bool canReturnNull) const { QString name = _name; bool favIconOverlay = false; if (size < 0 || _name.isEmpty()) { return QPixmap(); } /* * This method works in a kind of pipeline, with the following steps: * 1. Sanity checks. * 2. Convert _name, group, size, etc. to a key name. * 3. Check if the key is already cached. * 4. If not, initialize the theme and find/load the icon. * 4a Apply overlays * 4b Re-add to cache. */ // Special case for absolute path icons. if (name.startsWith(QLatin1String("favicons/"))) { favIconOverlay = true; name = QStandardPaths::writableLocation(QStandardPaths::GenericCacheLocation) + '/' + name + ".png"; } bool absolutePath = !pathIsRelative(name); if (!absolutePath) { name = d->removeIconExtension(name); } // Don't bother looking for an icon with no name. if (name.isEmpty()) { return QPixmap(); } // May modify group, size, or state. This function puts them into sane // states. d->normalizeIconMetadata(group, size, state); // See if the image is already cached. QString key = d->makeCacheKey(name, group, overlays, size, state); QPixmap pix; bool iconWasUnknown = false; QString path; if (d->findCachedPixmapWithPath(key, pix, path)) { if (path_store) { *path_store = path; } if (!path.isEmpty()) { return pix; } else { // path is empty for "unknown" icons, which should be searched for // anew regularly if (!d->shouldCheckForUnknownIcons()) { return canReturnNull ? QPixmap() : pix; } } } // Image is not cached... go find it and apply effects. if (!d->initIconThemes()) { return QPixmap(); } favIconOverlay = favIconOverlay && size > 22; // First we look for non-User icons. If we don't find one we'd search in // the User space anyways... if (group != KIconLoader::User) { if (absolutePath && !favIconOverlay) { path = name; } else { path = d->findMatchingIconWithGenericFallbacks(favIconOverlay ? QStringLiteral("text-html") : name, size); } } if (path.isEmpty()) { // We do have a "User" icon, or we couldn't find the non-User one. path = (absolutePath) ? name : iconPath(name, KIconLoader::User, canReturnNull); } // Still can't find it? Use "unknown" if we can't return null. // We keep going in the function so we can ensure this result gets cached. if (path.isEmpty() && !canReturnNull) { path = d->unknownIconPath(size); iconWasUnknown = true; } QImage img; if (!path.isEmpty()) { img = d->createIconImage(path, size, (KIconLoader::States)state); } if (group >= 0) { img = d->mpEffect.apply(img, group, state); } if (favIconOverlay) { QImage favIcon(name, "PNG"); if (!favIcon.isNull()) { // if favIcon not there yet, don't try to blend it QPainter p(&img); // Align the favicon overlay QRect r(favIcon.rect()); r.moveBottomRight(img.rect().bottomRight()); r.adjust(-1, -1, -1, -1); // Move off edge // Blend favIcon over img. p.drawImage(r, favIcon); } } pix = QPixmap::fromImage(img); // TODO: If we make a loadIcon that returns the image we can convert // drawOverlays to use the image instead of pixmaps as well so we don't // have to transfer so much to the graphics card. d->drawOverlays(this, group, state, pix, overlays); // Don't add the path to our unknown icon to the cache, only cache the // actual image. if (iconWasUnknown) { path.clear(); } d->insertCachedPixmapWithPath(key, pix, path); if (path_store) { *path_store = path; } return pix; } KPixmapSequence KIconLoader::loadPixmapSequence(const QString &xdgIconName, int size) const { return KPixmapSequence(iconPath(xdgIconName, -size), size); } QMovie *KIconLoader::loadMovie(const QString &name, KIconLoader::Group group, int size, QObject *parent) const { QString file = moviePath(name, group, size); if (file.isEmpty()) { - return 0; + return nullptr; } int dirLen = file.lastIndexOf('/'); QString icon = iconPath(name, size ? -size : group, true); if (!icon.isEmpty() && file.left(dirLen) != icon.left(dirLen)) { - return 0; + return nullptr; } QMovie *movie = new QMovie(file, QByteArray(), parent); if (!movie->isValid()) { delete movie; - return 0; + return nullptr; } return movie; } QString KIconLoader::moviePath(const QString &name, KIconLoader::Group group, int size) const { if (!d->mpGroups) { return QString(); } d->initIconThemes(); if ((group < -1 || group >= KIconLoader::LastGroup) && group != KIconLoader::User) { qCDebug(KICONTHEMES) << "Illegal icon group:" << group; group = KIconLoader::Desktop; } if (size == 0 && group < 0) { qCDebug(KICONTHEMES) << "Neither size nor group specified!"; group = KIconLoader::Desktop; } QString file = name + ".mng"; if (group == KIconLoader::User) { file = d->locate(file); } else { if (size == 0) { size = d->mpGroups[group].size; } QString path; foreach (KIconThemeNode *themeNode, d->links) { path = themeNode->theme->iconPath(file, size, KIconLoader::MatchExact); if (!path.isEmpty()) { break; } } if (path.isEmpty()) { foreach (KIconThemeNode *themeNode, d->links) { path = themeNode->theme->iconPath(file, size, KIconLoader::MatchBest); if (!path.isEmpty()) { break; } } } file = path; } return file; } QStringList KIconLoader::loadAnimated(const QString &name, KIconLoader::Group group, int size) const { QStringList lst; if (!d->mpGroups) { return lst; } d->initIconThemes(); if ((group < -1) || (group >= KIconLoader::LastGroup)) { qCDebug(KICONTHEMES) << "Illegal icon group: " << group; group = KIconLoader::Desktop; } if ((size == 0) && (group < 0)) { qCDebug(KICONTHEMES) << "Neither size nor group specified!"; group = KIconLoader::Desktop; } QString file = name + "/0001"; if (group == KIconLoader::User) { file = d->locate(file + ".png"); } else { if (size == 0) { size = d->mpGroups[group].size; } file = d->findMatchingIcon(file, size); } if (file.isEmpty()) { return lst; } QString path = file.left(file.length() - 8); QDir dir(QFile::encodeName(path)); if (!dir.exists()) { return lst; } foreach (const QString &entry, dir.entryList()) { if (!(entry.leftRef(4)).toUInt()) { continue; } lst += path + entry; } lst.sort(); return lst; } KIconTheme *KIconLoader::theme() const { d->initIconThemes(); if (d->mpThemeRoot) { return d->mpThemeRoot->theme; } - return 0L; + return nullptr; } int KIconLoader::currentSize(KIconLoader::Group group) const { if (!d->mpGroups) { return -1; } if (group < 0 || group >= KIconLoader::LastGroup) { qCDebug(KICONTHEMES) << "Illegal icon group:" << group; return -1; } return d->mpGroups[group].size; } QStringList KIconLoader::queryIconsByDir(const QString &iconsDir) const { const QDir dir(iconsDir); const QStringList formats = QStringList() << QStringLiteral("*.png") << QStringLiteral("*.xpm") << QStringLiteral("*.svg") << QStringLiteral("*.svgz"); const QStringList lst = dir.entryList(formats, QDir::Files); QStringList result; QStringList::ConstIterator it; for (it = lst.begin(); it != lst.end(); ++it) { result += iconsDir + '/' + *it; } return result; } QStringList KIconLoader::queryIconsByContext(int group_or_size, KIconLoader::Context context) const { d->initIconThemes(); QStringList result; if (group_or_size >= KIconLoader::LastGroup) { qCDebug(KICONTHEMES) << "Illegal icon group:" << group_or_size; return result; } int size; if (group_or_size >= 0) { size = d->mpGroups[group_or_size].size; } else { size = -group_or_size; } foreach (KIconThemeNode *themeNode, d->links) { themeNode->queryIconsByContext(&result, size, context); } // Eliminate duplicate entries (same icon in different directories) QString name; QStringList res2, entries; QStringList::ConstIterator it; for (it = result.constBegin(); it != result.constEnd(); ++it) { int n = (*it).lastIndexOf('/'); if (n == -1) { name = *it; } else { name = (*it).mid(n + 1); } name = d->removeIconExtension(name); if (!entries.contains(name)) { entries += name; res2 += *it; } } return res2; } QStringList KIconLoader::queryIcons(int group_or_size, KIconLoader::Context context) const { d->initIconThemes(); QStringList result; if (group_or_size >= KIconLoader::LastGroup) { qCDebug(KICONTHEMES) << "Illegal icon group:" << group_or_size; return result; } int size; if (group_or_size >= 0) { size = d->mpGroups[group_or_size].size; } else { size = -group_or_size; } foreach (KIconThemeNode *themeNode, d->links) { themeNode->queryIcons(&result, size, context); } // Eliminate duplicate entries (same icon in different directories) QString name; QStringList res2, entries; QStringList::ConstIterator it; for (it = result.constBegin(); it != result.constEnd(); ++it) { int n = (*it).lastIndexOf('/'); if (n == -1) { name = *it; } else { name = (*it).mid(n + 1); } name = d->removeIconExtension(name); if (!entries.contains(name)) { entries += name; res2 += *it; } } return res2; } // used by KIconDialog to find out which contexts to offer in a combobox bool KIconLoader::hasContext(KIconLoader::Context context) const { d->initIconThemes(); foreach (KIconThemeNode *themeNode, d->links) if (themeNode->theme->hasContext(context)) { return true; } return false; } KIconEffect *KIconLoader::iconEffect() const { return &d->mpEffect; } bool KIconLoader::alphaBlending(KIconLoader::Group group) const { if (!d->mpGroups) { return false; } if (group < 0 || group >= KIconLoader::LastGroup) { qCDebug(KICONTHEMES) << "Illegal icon group:" << group; return false; } return true; } // deprecated #ifndef KICONTHEMES_NO_DEPRECATED QIcon KIconLoader::loadIconSet(const QString &name, KIconLoader::Group g, int s, bool canReturnNull) { QIcon iconset; - QPixmap tmp = loadIcon(name, g, s, KIconLoader::ActiveState, QStringList(), NULL, canReturnNull); + QPixmap tmp = loadIcon(name, g, s, KIconLoader::ActiveState, QStringList(), nullptr, canReturnNull); iconset.addPixmap(tmp, QIcon::Active, QIcon::On); // we don't use QIconSet's resizing anyway - tmp = loadIcon(name, g, s, KIconLoader::DisabledState, QStringList(), NULL, canReturnNull); + tmp = loadIcon(name, g, s, KIconLoader::DisabledState, QStringList(), nullptr, canReturnNull); iconset.addPixmap(tmp, QIcon::Disabled, QIcon::On); - tmp = loadIcon(name, g, s, KIconLoader::DefaultState, QStringList(), NULL, canReturnNull); + tmp = loadIcon(name, g, s, KIconLoader::DefaultState, QStringList(), nullptr, canReturnNull); iconset.addPixmap(tmp, QIcon::Normal, QIcon::On); return iconset; } #endif // Easy access functions QPixmap DesktopIcon(const QString &name, int force_size, int state, const QStringList &overlays) { KIconLoader *loader = KIconLoader::global(); return loader->loadIcon(name, KIconLoader::Desktop, force_size, state, overlays); } // deprecated #ifndef KICONTHEMES_NO_DEPRECATED QIcon DesktopIconSet(const QString &name, int force_size) { KIconLoader *loader = KIconLoader::global(); return loader->loadIconSet(name, KIconLoader::Desktop, force_size); } #endif QPixmap BarIcon(const QString &name, int force_size, int state, const QStringList &overlays) { KIconLoader *loader = KIconLoader::global(); return loader->loadIcon(name, KIconLoader::Toolbar, force_size, state, overlays); } // deprecated #ifndef KICONTHEMES_NO_DEPRECATED QIcon BarIconSet(const QString &name, int force_size) { KIconLoader *loader = KIconLoader::global(); return loader->loadIconSet(name, KIconLoader::Toolbar, force_size); } #endif QPixmap SmallIcon(const QString &name, int force_size, int state, const QStringList &overlays) { KIconLoader *loader = KIconLoader::global(); return loader->loadIcon(name, KIconLoader::Small, force_size, state, overlays); } // deprecated #ifndef KICONTHEMES_NO_DEPRECATED QIcon SmallIconSet(const QString &name, int force_size) { KIconLoader *loader = KIconLoader::global(); return loader->loadIconSet(name, KIconLoader::Small, force_size); } #endif QPixmap MainBarIcon(const QString &name, int force_size, int state, const QStringList &overlays) { KIconLoader *loader = KIconLoader::global(); return loader->loadIcon(name, KIconLoader::MainToolbar, force_size, state, overlays); } // deprecated #ifndef KICONTHEMES_NO_DEPRECATED QIcon MainBarIconSet(const QString &name, int force_size) { KIconLoader *loader = KIconLoader::global(); return loader->loadIconSet(name, KIconLoader::MainToolbar, force_size); } #endif QPixmap UserIcon(const QString &name, int state, const QStringList &overlays) { KIconLoader *loader = KIconLoader::global(); return loader->loadIcon(name, KIconLoader::User, 0, state, overlays); } // deprecated #ifndef KICONTHEMES_NO_DEPRECATED QIcon UserIconSet(const QString &name) { KIconLoader *loader = KIconLoader::global(); return loader->loadIconSet(name, KIconLoader::User); } #endif int IconSize(KIconLoader::Group group) { KIconLoader *loader = KIconLoader::global(); return loader->currentSize(group); } QPixmap KIconLoader::unknown() { QPixmap pix; if (QPixmapCache::find(QStringLiteral("unknown"), pix)) { //krazy:exclude=iconnames return pix; } QString path = global()->iconPath(QStringLiteral("unknown"), KIconLoader::Small, true); //krazy:exclude=iconnames if (path.isEmpty()) { qCDebug(KICONTHEMES) << "Warning: Cannot find \"unknown\" icon."; pix = QPixmap(32, 32); } else { pix.load(path); QPixmapCache::insert(QStringLiteral("unknown"), pix); //krazy:exclude=iconnames } return pix; } bool KIconLoader::hasIcon(const QString &name) const { auto it = d->mIconAvailability.constFind(name); const auto end = d->mIconAvailability.constEnd(); if (it != end && !it.value() && !d->shouldCheckForUnknownIcons()) { return false; // known to be unavailable } bool found = it != end && it.value(); if (!found) { if (!iconPath(name, KIconLoader::Desktop, KIconLoader::MatchBest).isEmpty()) { found = true; } d->mIconAvailability.insert(name, found); // remember whether the icon is available or not } return found; } /*** the global icon loader ***/ Q_GLOBAL_STATIC(KIconLoader, globalIconLoader) KIconLoader *KIconLoader::global() { return globalIconLoader(); } #ifndef KICONTHEMES_NO_DEPRECATED void KIconLoader::newIconLoader() { if (global() == this) { KIconTheme::reconfigure(); } reconfigure(objectName()); emit iconLoaderSettingsChanged(); } #endif void KIconLoader::emitChange(KIconLoader::Group g) { s_globalData->emitChange(g); } #include QIcon KDE::icon(const QString &iconName, KIconLoader *iconLoader) { return QIcon(new KIconEngine(iconName, iconLoader ? iconLoader : KIconLoader::global())); } QIcon KDE::icon(const QString &iconName, const QStringList &overlays, KIconLoader *iconLoader) { return QIcon(new KIconEngine(iconName, iconLoader ? iconLoader : KIconLoader::global(), overlays)); } #include "kiconloader.moc" #include "moc_kiconloader.moc" diff --git a/src/kiconloader.h b/src/kiconloader.h index 830f3fa..3e47b8a 100644 --- a/src/kiconloader.h +++ b/src/kiconloader.h @@ -1,619 +1,619 @@ /* vi: ts=8 sts=4 sw=4 * * This file is part of the KDE project, module kdecore. * Copyright (C) 2000 Geert Jansen * Antonio Larrosa * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License version 2 as published by the Free Software Foundation. * * 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. */ #ifndef KICONLOADER_H #define KICONLOADER_H #include #include #include #include class QIcon; class QMovie; class QPixmap; class KIconLoaderPrivate; class KIconEffect; class KIconTheme; class KPixmapSequence; /** * Iconloader for KDE. * * KIconLoader will load the current icon theme and all its base themes. * Icons will be searched in any of these themes. Additionally, it caches * icons and applies effects according to the user's preferences. * * In KDE, it is encouraged to load icons by "Group". An icon group is a * location on the screen where icons are being used. Standard groups are: * Desktop, Toolbar, MainToolbar, Small and Panel. Each group has some * centrally configured properties bound to it, including the icon size * and effects. This makes it possible to offer a consistent icon look in * all KDE applications. * * The standard groups are defined below. * * @li KIconLoader::Desktop: Icons in the iconview of konqueror, kdesktop and similar apps. * @li KIconLoader::Toolbar: Icons in toolbars. * @li KIconLoader::MainToolbar: Icons in the main toolbars. * @li KIconLoader::Small: Various small (typical 16x16) places: titlebars, listviews * and menu entries. * @li KIconLoader::Panel: Icons in kicker's panel * * The icons are stored on disk in an icon theme or in a standalone * directory. The icon theme directories contain multiple sizes and/or * depths for the same icon. The iconloader will load the correct one based * on the icon group and the current theme. Icon themes are stored globally * in share/icons, or, application specific in share/apps/$appdir/icons. * * The standalone directories contain just one version of an icon. The * directories that are searched are: $appdir/pics and $appdir/toolbar. * Icons in these directories can be loaded by using the special group * "User". * */ class KICONTHEMES_EXPORT KIconLoader : public QObject { Q_OBJECT public: /** * Defines the context of the icon. */ enum Context { Any, ///< Some icon with unknown purpose. Action, ///< An action icon (e.g. 'save', 'print'). Application, ///< An icon that represents an application. Device, ///< An icon that represents a device. FileSystem, ///< An icon that represents a file system. @deprecated Use Place instead. MimeType, ///< An icon that represents a mime type (or file type). Animation, ///< An icon that is animated. Category, ///< An icon that represents a category. Emblem, ///< An icon that adds information to an existing icon. Emote, ///< An icon that expresses an emotion. International, ///< An icon that represents a country's flag. Place, ///< An icon that represents a location (e.g. 'home', 'trash'). StatusIcon ///< An icon that represents an event. }; Q_ENUM(Context) /** * The type of the icon. */ enum Type { Fixed, ///< Fixed-size icon. Scalable, ///< Scalable-size icon. Threshold ///< A threshold icon. }; Q_ENUM(Type) /** * The type of a match. */ enum MatchType { MatchExact, ///< Only try to find an exact match. MatchBest ///< Take the best match if there is no exact match. }; Q_ENUM(MatchType) /** * The group of the icon. */ enum Group { /// No group NoGroup = -1, /// Desktop icons Desktop = 0, /// First group FirstGroup = 0, /// Toolbar icons Toolbar, /// Main toolbar icons MainToolbar, /// Small icons, e.g. for buttons Small, /// Panel (Plasma Taskbar) icons Panel, /// Icons for use in dialog titles, page lists, etc Dialog, /// Last group LastGroup, /// User icons User }; Q_ENUM(Group) /** * These are the standard sizes for icons. */ enum StdSizes { /// small icons for menu entries SizeSmall = 16, /// slightly larger small icons for toolbars, panels, etc SizeSmallMedium = 22, /// medium sized icons for the desktop SizeMedium = 32, /// large sized icons for the panel SizeLarge = 48, /// huge sized icons for iconviews SizeHuge = 64, /// enormous sized icons for iconviews SizeEnormous = 128 }; Q_ENUM(StdSizes) /** * Defines the possible states of an icon. */ enum States { DefaultState, ///< The default state. ActiveState, ///< Icon is active. DisabledState, ///< Icon is disabled. SelectedState, ///< Icon is selected. @since 5.22 LastState ///< Last state (last constant) }; Q_ENUM(States) /** * Constructs an iconloader. * @param appname Add the data directories of this application to the * icon search path for the "User" group. The default argument adds the * directories of the current application. * @param extraSearchPaths additional search paths, either absolute or relative to GenericDataLocation * * Usually, you use the default iconloader, which can be accessed via * KIconLoader::global(), so you hardly ever have to create an * iconloader object yourself. That one is the application's iconloader. */ - explicit KIconLoader(const QString &appname = QString(), const QStringList &extraSearchPaths = QStringList(), QObject *parent = 0); + explicit KIconLoader(const QString &appname = QString(), const QStringList &extraSearchPaths = QStringList(), QObject *parent = nullptr); /** * Cleanup */ ~KIconLoader(); /** * Returns the global icon loader initialized with the application name. * @return global icon loader */ static KIconLoader *global(); /** * Adds @p appname to the list of application specific directories with @p themeBaseDir as its base directory. * Assume the icons are in /home/user/app/icons/hicolor/48x48/my_app.png, the base directory would be * /home/user/app/icons; KIconLoader automatically searches @p themeBaseDir + "/hicolor" * This directory must contain a dir structure as defined by the XDG icons specification * @param appname The application name. * @param themeBaseDir The base directory of the application's theme (eg. "/home/user/app/icons") */ void addAppDir(const QString &appname, const QString &themeBaseDir = QString()); /** * Loads an icon. It will try very hard to find an icon which is * suitable. If no exact match is found, a close match is searched. * If neither an exact nor a close match is found, a null pixmap or * the "unknown" pixmap is returned, depending on the value of the * @p canReturnNull parameter. * * @param name The name of the icon, without extension. * @param group The icon group. This will specify the size of and effects to * be applied to the icon. * @param size If nonzero, this overrides the size specified by @p group. * See KIconLoader::StdSizes. * @param state The icon state: @p DefaultState, @p ActiveState or * @p DisabledState. Depending on the user's preferences, the iconloader * may apply a visual effect to hint about its state. * @param overlays a list of emblem icons to overlay, by name * @see drawOverlays * @param path_store If not null, the path of the icon is stored here, * if the icon was found. If the icon was not found @p path_store * is unaltered even if the "unknown" pixmap was returned. * @param canReturnNull Can return a null pixmap? If false, the * "unknown" pixmap is returned when no appropriate icon has been * found. Note: a null pixmap can still be returned in the * event of invalid parameters, such as empty names, negative sizes, * and etc. * @return the QPixmap. Can be null when not found, depending on * @p canReturnNull. */ QPixmap loadIcon(const QString &name, KIconLoader::Group group, int size = 0, int state = KIconLoader::DefaultState, const QStringList &overlays = QStringList(), - QString *path_store = 0L, + QString *path_store = nullptr, bool canReturnNull = false) const; /** * Loads an icon for a mimetype. * This is basically like loadIcon except that extra desktop themes are loaded if necessary. * * @param iconName The name of the icon, without extension, usually from KMimeType. * @param group The icon group. This will specify the size of and effects to * be applied to the icon. * @param size If nonzero, this overrides the size specified by @p group. * See KIconLoader::StdSizes. * @param state The icon state: @p DefaultState, @p ActiveState or * @p DisabledState. Depending on the user's preferences, the iconloader * may apply a visual effect to hint about its state. * @param path_store If not null, the path of the icon is stored here. * @param overlays a list of emblem icons to overlay, by name * @see drawOverlays * @return the QPixmap. Can not be null, the * "unknown" pixmap is returned when no appropriate icon has been found. */ QPixmap loadMimeTypeIcon(const QString &iconName, KIconLoader::Group group, int size = 0, int state = KIconLoader::DefaultState, const QStringList &overlays = QStringList(), - QString *path_store = 0) const; + QString *path_store = nullptr) const; /** * Loads a pixmapSequence given the xdg icon name * * @param name The name of the icon, without extension. * @param size the size/group to be used * @since 5.0 */ KPixmapSequence loadPixmapSequence(const QString &iconName, int size = SizeSmall) const; /** * Creates an icon set, that will do on-demand loading of the icon. * Loading itself is done by calling loadIcon . * * @param name The name of the icon, without extension. * @param group The icon group. This will specify the size of and effects to * be applied to the icon. * @param size If nonzero, this overrides the size specified by @p group. * See KIconLoader::StdSizes. * @param canReturnNull Can return a null iconset? If false, iconset * containing the "unknown" pixmap is returned when no appropriate icon has * been found. * @return the icon set. Can be null when not found, depending on * @p canReturnNull. * * @deprecated use QIcon::fromTheme instead, which uses the iconloader internally */ #ifndef KICONTHEMES_NO_DEPRECATED KICONTHEMES_DEPRECATED QIcon loadIconSet(const QString &name, KIconLoader::Group group, int size = 0, bool canReturnNull = false); #endif /** * Returns the path of an icon. * @param name The name of the icon, without extension. If an absolute * path is supplied for this parameter, iconPath will return it * directly. * @param group_or_size If positive, search icons whose size is * specified by the icon group @p group_or_size. If negative, search * icons whose size is - @p group_or_size. * See KIconLoader::Group and KIconLoader::StdSizes * @param canReturnNull Can return a null string? If not, a path to the * "unknown" icon will be returned. * @return the path of an icon, can be null or the "unknown" icon when * not found, depending on @p canReturnNull. */ QString iconPath(const QString &name, int group_or_size, bool canReturnNull = false) const; /** * Loads an animated icon. * @param name The name of the icon. * @param group The icon group. See loadIcon(). * @param size Override the default size for @p group. * See KIconLoader::StdSizes. * @param parent The parent object of the returned QMovie. * @return A QMovie object. Can be null if not found or not valid. * Ownership is passed to the caller. */ - QMovie *loadMovie(const QString &name, KIconLoader::Group group, int size = 0, QObject *parent = 0) const; + QMovie *loadMovie(const QString &name, KIconLoader::Group group, int size = 0, QObject *parent = nullptr) const; /** * Returns the path to an animated icon. * @param name The name of the icon. * @param group The icon group. See loadIcon(). * @param size Override the default size for @p group. * See KIconLoader::StdSizes. * @return the full path to the movie, ready to be passed to QMovie's constructor. * Empty string if not found. */ QString moviePath(const QString &name, KIconLoader::Group group, int size = 0) const; /** * Loads an animated icon as a series of still frames. If you want to load * a .mng animation as QMovie instead, please use loadMovie() instead. * @param name The name of the icon. * @param group The icon group. See loadIcon(). * @param size Override the default size for @p group. * See KIconLoader::StdSizes. * @return A QStringList containing the absolute path of all the frames * making up the animation. */ QStringList loadAnimated(const QString &name, KIconLoader::Group group, int size = 0) const; /** * Queries all available icons for a specific group, having a specific * context. * @param group_or_size If positive, search icons whose size is * specified by the icon group @p group_or_size. If negative, search * icons whose size is - @p group_or_size. * See KIconLoader::Group and KIconLoader::StdSizes * @param context The icon context. * @return a list of all icons */ QStringList queryIcons(int group_or_size, KIconLoader::Context context = KIconLoader::Any) const; /** * Queries all available icons for a specific context. * @param group_or_size The icon preferred group or size. If available * at this group or size, those icons will be returned, in other case, * icons of undefined size will be returned. Positive numbers are groups, * negative numbers are negated sizes. See KIconLoader::Group and * KIconLoader::StdSizes * @param context The icon context. * @return A QStringList containing the icon names * available for that context */ QStringList queryIconsByContext(int group_or_size, KIconLoader::Context context = KIconLoader::Any) const; /** * @internal */ bool hasContext(KIconLoader::Context context) const; /** * Returns a list of all icons (*.png or *.xpm extension) in the * given directory. * @param iconsDir the directory to search in * @return A QStringList containing the icon paths */ QStringList queryIconsByDir(const QString &iconsDir) const; /** * Returns all the search paths for this icon loader, either absolute or * relative to GenericDataLocation. * Mostly internal (for KIconDialog). * \since 5.0 */ QStringList searchPaths() const; /** * Returns the current size of the icon group. * Using e.g. KIconLoader::SmallIcon will retrieve the icon size * that is currently set from System Settings->Appearance->Icon * sizes. SmallIcon for instance, would typically be 16x16, but * the user could increase it and this setting would change as well. * @param group the group to check. * @return the current size for an icon group. */ int currentSize(KIconLoader::Group group) const; /** * Returns a pointer to the current theme. Can be used to query * available and default sizes for groups. * @note The KIconTheme will change if reconfigure() is called and * therefore it's not recommended to store the pointer anywhere. * @return a pointer to the current theme. 0 if no theme set. */ KIconTheme *theme() const; /** * Returns a pointer to the KIconEffect object used by the icon loader. * @return the KIconEffect. */ KIconEffect *iconEffect() const; /** * Reconfigure the icon loader, for instance to change the associated app name or extra search paths. * This also clears the in-memory pixmap cache (even if the appname didn't change, which is useful for unittests) * @param appname the application name (empty for the global iconloader) * @param extraSearchPaths additional search paths, either absolute or relative to GenericDataLocation */ void reconfigure(const QString &appname, const QStringList &extraSearchPaths = QStringList()); /** * Returns the unknown icon. An icon that is used when no other icon * can be found. * @return the unknown pixmap */ static QPixmap unknown(); /** * Checks whether the user wants to blend the icons with the background * using the alpha channel information for a given group. * @param group the group to check * @return true if alpha blending is desired * @obsolete */ bool alphaBlending(KIconLoader::Group group) const; /** * Draws overlays on the specified pixmap, it takes the width and height * of the pixmap into consideration * @param overlays List of up to 4 overlays to blend over the pixmap. The first overlay * will be in the bottom left corner, followed by bottom right, top right * and top left. An empty QString can be used to leave the specific position * blank. * @param pixmap to draw on * @since 4.7 */ void drawOverlays(const QStringList &overlays, QPixmap &pixmap, KIconLoader::Group group, int state = KIconLoader::DefaultState) const; bool hasIcon(const QString &iconName) const; public Q_SLOTS: /** * Re-initialize the global icon loader * * @deprecated since 5.0, use emitChange(Group) */ #ifndef KICONTHEMES_NO_DEPRECATED KICONTHEMES_DEPRECATED void newIconLoader(); #endif /** * Emits an iconChanged() signal on all the KIconLoader instances in the system * indicating that a system's icon group has changed in some way. It will also trigger * a reload in all of them to update to the new theme. * * @p group indicates the group that has changed * * @since 5.0 */ static void emitChange(Group group); Q_SIGNALS: /** * Emitted by newIconLoader once the new settings have been loaded */ void iconLoaderSettingsChanged(); /** * Emitted when the system icon theme changes * * @since 5.0 */ void iconChanged(int group); private: // @internal the data object KIconLoaderPrivate *d; Q_PRIVATE_SLOT(d, void _k_refreshIcons(int group)) }; /** * \relates KIconLoader * Load a desktop icon. */ KICONTHEMES_EXPORT QPixmap DesktopIcon(const QString &name, int size = 0, int state = KIconLoader::DefaultState, const QStringList &overlays = QStringList()); /** * \relates KIconLoader * Load a desktop icon, and apply the necessary effects to get an IconSet. * @deprecated use QIcon::fromTheme instead */ #ifndef KICONTHEMES_NO_DEPRECATED KICONTHEMES_DEPRECATED_EXPORT QIcon DesktopIconSet(const QString &name, int size = 0); #endif /** * \relates KIconLoader * Load a toolbar icon. */ KICONTHEMES_EXPORT QPixmap BarIcon(const QString &name, int size = 0, int state = KIconLoader::DefaultState, const QStringList &overlays = QStringList()); /** * \relates KIconLoader * Load a toolbar icon, and apply the necessary effects to get an IconSet. * @deprecated use QIcon::fromTheme instead */ #ifndef KICONTHEMES_NO_DEPRECATED KICONTHEMES_DEPRECATED_EXPORT QIcon BarIconSet(const QString &name, int size = 0); #endif /** * \relates KIconLoader * Load a small icon. */ KICONTHEMES_EXPORT QPixmap SmallIcon(const QString &name, int size = 0, int state = KIconLoader::DefaultState, const QStringList &overlays = QStringList()); /** * \relates KIconLoader * Load a small icon, and apply the necessary effects to get an IconSet. * @deprecated use QIcon::fromTheme instead */ #ifndef KICONTHEMES_NO_DEPRECATED KICONTHEMES_DEPRECATED_EXPORT QIcon SmallIconSet(const QString &name, int size = 0); #endif /** * \relates KIconLoader * Load a main toolbar icon. */ KICONTHEMES_EXPORT QPixmap MainBarIcon(const QString &name, int size = 0, int state = KIconLoader::DefaultState, const QStringList &overlays = QStringList()); /** * \relates KIconLoader * Load a main toolbar icon, and apply the effects to get an IconSet. * @deprecated use QIcon::fromTheme instead */ #ifndef KICONTHEMES_NO_DEPRECATED KICONTHEMES_DEPRECATED_EXPORT QIcon MainBarIconSet(const QString &name, int size = 0); #endif /** * \relates KIconLoader * Load a user icon. User icons are searched in $appdir/pics. */ KICONTHEMES_EXPORT QPixmap UserIcon(const QString &name, int state = KIconLoader::DefaultState, const QStringList &overlays = QStringList()); /** * \relates KIconLoader * Load a user icon, and apply the effects to get an IconSet. * @deprecated use QIcon::fromTheme instead */ #ifndef KICONTHEMES_NO_DEPRECATED KICONTHEMES_DEPRECATED_EXPORT QIcon UserIconSet(const QString &name); #endif /** * \relates KIconLoader * Returns the current icon size for a specific group. */ KICONTHEMES_EXPORT int IconSize(KIconLoader::Group group); namespace KDE { /** * \relates KIconLoader * Returns a QIcon with an appropriate * KIconEngine to perform loading and rendering. KIcons thus adhere to * KDE style and effect standards. * @since 5.0 */ -KICONTHEMES_EXPORT QIcon icon(const QString &iconName, KIconLoader *iconLoader = 0); +KICONTHEMES_EXPORT QIcon icon(const QString &iconName, KIconLoader *iconLoader = nullptr); /** * \relates KIconLoader * Returns a QIcon for the given icon, with additional overlays. * @since 5.0 */ -KICONTHEMES_EXPORT QIcon icon(const QString &iconName, const QStringList &overlays, KIconLoader *iconLoader = 0); +KICONTHEMES_EXPORT QIcon icon(const QString &iconName, const QStringList &overlays, KIconLoader *iconLoader = nullptr); } inline KIconLoader::Group &operator++(KIconLoader::Group &group) { group = static_cast(group + 1); return group; } inline KIconLoader::Group operator++(KIconLoader::Group &group, int) { KIconLoader::Group ret = group; ++group; return ret; } #endif // KICONLOADER_H diff --git a/tests/kicondialogtest.cpp b/tests/kicondialogtest.cpp index 208187f..e46330c 100644 --- a/tests/kicondialogtest.cpp +++ b/tests/kicondialogtest.cpp @@ -1,71 +1,71 @@ /* * Copyright 2014 Alex Merry * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) version 3, or any * later version accepted by the membership of KDE e.V. (or its * successor approved by the membership of KDE e.V.), which shall * act as a proxy defined in Section 6 of version 3 of the license. * * 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. If not, see * . */ #include #include #include #include class Listener : public QObject { Q_OBJECT public Q_SLOTS: void dialog1Done() { KIconDialog *dialog = new KIconDialog(); dialog->setup(KIconLoader::Toolbar, KIconLoader::Action); QString icon = dialog->openDialog(); QTextStream(stdout) << "Icon \"" << icon << "\" was chosen (openDialog)\n"; delete dialog; icon = KIconDialog::getIcon(KIconLoader::Desktop, KIconLoader::MimeType, - true, 48, true, 0, QStringLiteral("Test dialog")); + true, 48, true, nullptr, QStringLiteral("Test dialog")); QTextStream(stdout) << "Icon \"" << icon << "\" was chosen (getIcon)\n"; } void iconChosen(const QString &name) { QTextStream(stdout) << "Icon \"" << name << "\" was chosen (showDialog).\n"; } }; int main(int argc, char **argv) { QApplication app(argc, argv); Listener listener; KIconDialog dialog; QObject::connect(&dialog, &KIconDialog::newIconName, &listener, &Listener::iconChosen); QObject::connect(&dialog, &QDialog::finished, &listener, &Listener::dialog1Done); dialog.showDialog(); return app.exec(); } #include "kicondialogtest.moc" diff --git a/tests/kiconeffecttest.h b/tests/kiconeffecttest.h index 34ad2eb..71b8a18 100644 --- a/tests/kiconeffecttest.h +++ b/tests/kiconeffecttest.h @@ -1,29 +1,29 @@ #ifndef KICONEFFECTTEST_H #define KICONEFFECTTEST_H #include #include class QLabel; class KIconEffectTestWidget : public QScrollArea { Q_OBJECT public: - KIconEffectTestWidget(QWidget *parent = 0); + KIconEffectTestWidget(QWidget *parent = nullptr); private Q_SLOTS: void slotGray(int); void slotMonochrome(int); void slotDesaturate(int); void slotGamma(int); void slotColorizeColor(const QColor &); void slotColorizeValue(int); private: QImage img; QLabel *lbl[6]; QColor colorizedColor; float colorizedValue; }; #endif