diff --git a/kcms/icons/CMakeLists.txt b/kcms/icons/CMakeLists.txt --- a/kcms/icons/CMakeLists.txt +++ b/kcms/icons/CMakeLists.txt @@ -1,11 +1,8 @@ -# KI18N Translation Domain for this library -add_definitions(-DTRANSLATION_DOMAIN=\"kcm5_icons\") - -add_subdirectory(tests) +add_definitions(-DTRANSLATION_DOMAIN=\"kcm_icons\") ########### next target ############### -set(kcm_icons_PART_SRCS iconthemes.cpp icons.cpp main.cpp ) +set(kcm_icons_PART_SRCS main.cpp) add_library(kcm_icons MODULE ${kcm_icons_PART_SRCS}) @@ -18,24 +15,21 @@ KF5::Archive KF5::NewStuff KF5::KIOWidgets - KF5::KDELibs4Support - ${X11_LIBRARIES} + KF5::QuickAddons ) -if(X11_FOUND) - target_link_libraries(kcm_icons Qt5::X11Extras) -endif() - file(GENERATE OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/config.h CONTENT "#define CMAKE_INSTALL_FULL_LIBEXECDIR \"${CMAKE_INSTALL_FULL_LIBEXECDIR}\"") add_executable(plasma-changeicons changeicons.cpp) target_link_libraries(plasma-changeicons PRIVATE Qt5::Core KF5::KIOWidgets KF5::IconThemes) -install(TARGETS kcm_icons DESTINATION ${KDE_INSTALL_PLUGINDIR} ) - -install( FILES icons.desktop DESTINATION ${KDE_INSTALL_KSERVICES5DIR} ) +kcoreaddons_desktop_to_json(kcm_icons "kcm_icons.desktop") +install(FILES kcm_icons.desktop DESTINATION ${KDE_INSTALL_KSERVICES5DIR}) +install(TARGETS kcm_icons DESTINATION ${KDE_INSTALL_PLUGINDIR}/kcms) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/icons.knsrc ${CMAKE_BINARY_DIR}/icons.knsrc) install( FILES ${CMAKE_BINARY_DIR}/icons.knsrc DESTINATION ${KDE_INSTALL_CONFDIR} ) install(TARGETS plasma-changeicons DESTINATION ${KDE_INSTALL_LIBEXECDIR} ) + +kpackage_install_package(package kcm_icons kcms) diff --git a/kcms/icons/Messages.sh b/kcms/icons/Messages.sh --- a/kcms/icons/Messages.sh +++ b/kcms/icons/Messages.sh @@ -1,2 +1,2 @@ #! /usr/bin/env bash -$XGETTEXT *.cpp -o $podir/kcm5_icons.pot +$XGETTEXT `find . -name "*.cpp" -o -name "*.qml"` -o $podir/kcm_icons.pot diff --git a/kcms/icons/icons.h b/kcms/icons/icons.h deleted file mode 100644 --- a/kcms/icons/icons.h +++ /dev/null @@ -1,147 +0,0 @@ -/* vi: ts=8 sts=4 sw=4 - * - * This file is part of the KDE project, module kcmdisplay. - * Copyright (C) 2000 Geert Jansen - * with minor additions and based on ideas from - * Torsten Rahn - * KDE Frameworks 5 port Copyright (C) 2013 Jonathan Riddell - * - * You can Freely distribute this program under the GNU General Public - * License. See the file "COPYING" for the exact licensing terms. - */ - -#ifndef __icons_h__ -#define __icons_h__ - -#include -#include -#include - -#include -#include - -class QCheckBox; -class QColor; -class QComboBox; -class QGridLayout; -class QGroupBox; -class QLabel; -class QListWidget; -class QPushButton; -class QSlider; -class QTabWidget; -class QWidget; - -class KColorButton; -class KIconEffect; -class KIconLoader; - -struct Effect -{ - int type; - float value; - QColor color; - QColor color2; - bool transparent; -}; - - -/** - * The General Icons tab in kcontrol. - */ -class KIconConfig: public KCModule -{ - Q_OBJECT - -public: - KIconConfig(QWidget *parent); - ~KIconConfig(); - - void load() override; - void save() override; - void defaults() override; - void preview(); - -private Q_SLOTS: - void slotEffectSetup0() { EffectSetup(0); } - void slotEffectSetup1() { EffectSetup(1); } - void slotEffectSetup2() { EffectSetup(2); } - - void slotUsage(int index); - void slotSize(int index); - void slotAnimatedCheck(bool check); - -private: - void preview(int i); - void EffectSetup(int state); - QPushButton *addPreviewIcon(int i, const QString &str, QWidget *parent, QGridLayout *lay); - void init(); - void initDefaults(); - void read(); - void apply(); - - void exportToKDE4(); - - - bool mbChanged[6], mbAnimated[6]; - int mSizes[6]; - QList mAvSizes[6]; - - Effect mEffects[6][3]; - Effect mDefaultEffect[3]; - - int mUsage; - QString mTheme, mExample; - QStringList mGroups, mStates; - - KIconEffect *mpEffect; - KIconLoader *mpLoader; - KSharedConfigPtr mpConfig; - - QLabel *mpPreview[3]; - - QListWidget *mpUsageList; - QComboBox *mpSizeBox; - QCheckBox *wordWrapCB, *underlineCB, *mpAnimatedCheck; - QTabWidget *m_pTabWidget; - QWidget *m_pTab1; -}; - -class KIconEffectSetupDialog: public QDialog -{ - Q_OBJECT - -public: - KIconEffectSetupDialog(const Effect &, const Effect &, - const QString &, const QImage &, - QWidget *parent=0L, char *name=0L); - ~KIconEffectSetupDialog(); - Effect effect() { return mEffect; } - -protected: - void preview(); - void init(); - -protected Q_SLOTS: - void slotEffectValue(int value); - void slotEffectColor(const QColor &col); - void slotEffectColor2(const QColor &col); - void slotEffectType(int type); - void slotSTCheck(bool b); - void slotDefault(); - -private: - KIconEffect *mpEffect; - QListWidget *mpEffectBox; - QCheckBox *mpSTCheck; - QSlider *mpEffectSlider; - KColorButton *mpEColButton; - KColorButton *mpECol2Button; - Effect mEffect; - Effect mDefaultEffect; - QImage mExample; - QGroupBox *mpEffectGroup; - QLabel *mpPreview, *mpEffectLabel, *mpEffectColor, *mpEffectColor2; -}; - -#endif diff --git a/kcms/icons/icons.cpp b/kcms/icons/icons.cpp deleted file mode 100644 --- a/kcms/icons/icons.cpp +++ /dev/null @@ -1,716 +0,0 @@ -/* vi: ts=8 sts=4 sw=4 - * - * This file is part of the KDE project, module kcmdisplay. - * Copyright (C) 2000 Geert Jansen - * with minor additions and based on ideas from - * Torsten Rahn * - * KDE Frameworks 5 port Copyright (C) 2013 Jonathan Riddell - * - * You can Freely distribute this program under the GNU General Public - * License version 2 or later. See the file "COPYING" for the exact licensing terms. - */ - -#include "icons.h" - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -Q_DECLARE_LOGGING_CATEGORY(KCM_ICONS) - - -KIconConfig::KIconConfig(QWidget *parent) - : KCModule(parent) -{ - - QGridLayout *top = new QGridLayout(this ); - top->setColumnStretch(0, 1); - top->setColumnStretch(1, 1); - - // Use of Icon at (0,0) - (1, 0) - QGroupBox *gbox = new QGroupBox(i18n("Use of Icon"), this); - top->addWidget(gbox, 0, 0, 2, 1); - QBoxLayout *g_vlay = new QVBoxLayout(gbox); - mpUsageList = new QListWidget(gbox); - connect(mpUsageList, &QListWidget::currentRowChanged, this, &KIconConfig::slotUsage); - g_vlay->addWidget(mpUsageList); - - KSeparator *sep = new KSeparator( Qt::Horizontal, this ); - top->addWidget(sep, 1, 1); - // Preview at (2,0) - (2, 1) - QGridLayout *g_lay = new QGridLayout(); - g_lay->setSpacing( 0); - top->addLayout(g_lay, 2, 0, 1, 2 ); - g_lay->addItem(new QSpacerItem(0, fontMetrics().lineSpacing()), 0, 0); - - QPushButton *push; - - push = addPreviewIcon(0, i18nc("@label The icon rendered by default", "Default"), this, g_lay); - connect(push, &QPushButton::clicked, this, &KIconConfig::slotEffectSetup0); - push = addPreviewIcon(1, i18nc("@label The icon rendered as active", "Active"), this, g_lay); - connect(push, &QPushButton::clicked, this, &KIconConfig::slotEffectSetup1); - push = addPreviewIcon(2, i18nc("@label The icon rendered as disabled", "Disabled"), this, g_lay); - connect(push, &QPushButton::clicked, this, &KIconConfig::slotEffectSetup2); - - m_pTab1 = new QWidget(this); - m_pTab1->setObjectName( QStringLiteral("General Tab" )); - top->addWidget(m_pTab1, 0, 1); - - QGridLayout *grid = new QGridLayout(m_pTab1); - grid->setColumnStretch(1, 1); - grid->setColumnStretch(2, 1); - - - // Size - QLabel *lbl = new QLabel(i18n("Size:"), m_pTab1); - lbl->setFixedSize(lbl->sizeHint()); - grid->addWidget(lbl, 0, 0, Qt::AlignLeft); - mpSizeBox = new QComboBox(m_pTab1); - connect(mpSizeBox, static_cast(&QComboBox::activated), this, &KIconConfig::slotSize); - lbl->setBuddy(mpSizeBox); - grid->addWidget(mpSizeBox, 0, 1, Qt::AlignLeft); - - mpAnimatedCheck = new QCheckBox(i18n("Enable icon animations"), m_pTab1); - connect(mpAnimatedCheck, &QCheckBox::toggled, this, &KIconConfig::slotAnimatedCheck); - grid->addWidget(mpAnimatedCheck, 2, 0, 1, 2, Qt::AlignLeft); - grid->setRowStretch(3, 10); - - top->activate(); - - init(); - read(); - apply(); - preview(); -} - -KIconConfig::~KIconConfig() -{ - delete mpEffect; -} - -QPushButton *KIconConfig::addPreviewIcon(int i, const QString &str, QWidget *parent, QGridLayout *lay) -{ - QLabel *lab = new QLabel(str, parent); - lay->addWidget(lab, 1, i, Qt::AlignCenter); - mpPreview[i] = new QLabel(parent); - mpPreview[i]->setAlignment(Qt::AlignCenter); - mpPreview[i]->setMinimumSize(105, 105); - lay->addWidget(mpPreview[i], 2, i); - QPushButton *push = new QPushButton(i18n("Set Effect..."), parent); - lay->addWidget(push, 3, i, Qt::AlignCenter); - return push; -} - -void KIconConfig::init() -{ - mpLoader = KIconLoader::global(); - mpConfig = KSharedConfig::openConfig(); - mpEffect = new KIconEffect; - mUsage = 0; - for (int i=0; iaddItem(i18n("Desktop")); - mpUsageList->addItem(i18n("Toolbar")); - mpUsageList->addItem(i18n("Main Toolbar")); - mpUsageList->addItem(i18n("Small Icons")); - mpUsageList->addItem(i18n("Panel")); - mpUsageList->addItem(i18n("Dialogs")); - mpUsageList->addItem(i18n("All Icons")); - - // For reading the configuration - mGroups += QStringLiteral("Desktop"); - mGroups += QStringLiteral("Toolbar"); - mGroups += QStringLiteral("MainToolbar"); - mGroups += QStringLiteral("Small"); - mGroups += QStringLiteral("Panel"); - mGroups += QStringLiteral("Dialog"); - - mStates += QStringLiteral("Default"); - mStates += QStringLiteral("Active"); - mStates += QStringLiteral("Disabled"); -} - -void KIconConfig::initDefaults() -{ - mDefaultEffect[0].type = KIconEffect::NoEffect; - mDefaultEffect[1].type = KIconEffect::NoEffect; - mDefaultEffect[2].type = KIconEffect::ToGray; - mDefaultEffect[0].transparent = false; - mDefaultEffect[1].transparent = false; - mDefaultEffect[2].transparent = true; - mDefaultEffect[0].value = 1.0; - mDefaultEffect[1].value = 1.0; - mDefaultEffect[2].value = 1.0; - mDefaultEffect[0].color = QColor(144,128,248); - mDefaultEffect[1].color = QColor(169,156,255); - mDefaultEffect[2].color = QColor(34,202,0); - mDefaultEffect[0].color2 = QColor(0,0,0); - mDefaultEffect[1].color2 = QColor(0,0,0); - mDefaultEffect[2].color2 = QColor(0,0,0); - - const int defDefSizes[] = { 32, 22, 22, 16, 48, 32 }; - - KIconLoader::Group i; - QStringList::ConstIterator it; - for(it=mGroups.constBegin(), i=KIconLoader::FirstGroup; it!=mGroups.constEnd(); ++it, i++) - { - mbChanged[i] = true; - mbAnimated[i] = false; - if (mpLoader->theme()) - mSizes[i] = mpLoader->theme()->defaultSize(i); - else - mSizes[i] = defDefSizes[i]; - - mEffects[i][0] = mDefaultEffect[0]; - mEffects[i][1] = mDefaultEffect[1]; - mEffects[i][2] = mDefaultEffect[2]; - } - // Animate desktop icons by default - int group = mGroups.indexOf( QStringLiteral("Desktop") ); - if ( group != -1 ) - mbAnimated[group] = true; - - // This is the new default in KDE 2.2, in sync with the kiconeffect of kdelibs Nolden 2001/06/11 - int activeState = mStates.indexOf( QStringLiteral("Active") ); - if ( activeState != -1 ) - { - int group = mGroups.indexOf( QStringLiteral("Desktop") ); - if ( group != -1 ) - { - mEffects[ group ][ activeState ].type = KIconEffect::ToGamma; - mEffects[ group ][ activeState ].value = 0.7f; - } - - group = mGroups.indexOf( QStringLiteral("Panel") ); - if ( group != -1 ) - { - mEffects[ group ][ activeState ].type = KIconEffect::ToGamma; - mEffects[ group ][ activeState ].value = 0.7f; - } - } -} - -void KIconConfig::read() -{ - if (mpLoader->theme()) - { - for (KIconLoader::Group i=KIconLoader::FirstGroup; itheme()->querySizes(i); - - // ### Themes need to be fixed to include available sizes for Dialog icons - if (i == KIconLoader::Dialog && mAvSizes[i].isEmpty()) - { - mAvSizes[i] = mAvSizes[KIconLoader::Desktop]; - } - } - - mTheme = mpLoader->theme()->current(); - mExample = mpLoader->theme()->example(); - } - else - { - for (KIconLoader::Group i=KIconLoader::FirstGroup; i(); - - mTheme.clear(); - mExample.clear(); - } - - initDefaults(); - - int i, j, effect; - QStringList::ConstIterator it, it2; - for (it=mGroups.constBegin(), i=0; it!=mGroups.constEnd(); ++it, i++) - { - mbChanged[i] = false; - - KConfigGroup iconGroup(mpConfig, *it + "Icons"); - mSizes[i] = iconGroup.readEntry("Size", mSizes[i]); - mbAnimated[i] = iconGroup.readEntry("Animated", mbAnimated[i]); - - for (it2=mStates.constBegin(), j=0; it2!=mStates.constEnd(); ++it2, j++) - { - QString tmp = iconGroup.readEntry(*it2 + "Effect", QString()); - if (tmp == QLatin1String("togray")) - effect = KIconEffect::ToGray; - else if (tmp == QLatin1String("colorize")) - effect = KIconEffect::Colorize; - else if (tmp == QLatin1String("togamma")) - effect = KIconEffect::ToGamma; - else if (tmp == QLatin1String("desaturate")) - effect = KIconEffect::DeSaturate; - else if (tmp == QLatin1String("tomonochrome")) - effect = KIconEffect::ToMonochrome; - else if (tmp == QLatin1String("none")) - effect = KIconEffect::NoEffect; - else continue; - mEffects[i][j].type = effect; - mEffects[i][j].value = iconGroup.readEntry(*it2 + "Value", 0.0); - mEffects[i][j].color = iconGroup.readEntry(*it2 + "Color",QColor()); - mEffects[i][j].color2 = iconGroup.readEntry(*it2 + "Color2", QColor()); - mEffects[i][j].transparent = iconGroup.readEntry(*it2 + "SemiTransparent", false); - } - } -} - -void KIconConfig::apply() -{ - mpUsageList->setCurrentRow(mUsage); - - int delta = 1000, dw, index = -1, size = 0, i; - QList::Iterator it; - mpSizeBox->clear(); - if (mUsage < KIconLoader::LastGroup) { - for (it=mAvSizes[mUsage].begin(), i=0; it!=mAvSizes[mUsage].end(); ++it, i++) - { - mpSizeBox->addItem(QString().setNum(*it)); - dw = abs(mSizes[mUsage] - *it); - if (dw < delta) - { - delta = dw; - index = i; - size = *it; - } - - } - if (index != -1) - { - mpSizeBox->setCurrentIndex(index); - mSizes[mUsage] = size; // best or exact match - } - mpAnimatedCheck->setChecked(mbAnimated[mUsage]); - } -} - -void KIconConfig::preview(int i) -{ - // Apply effects ourselves because we don't want to sync - // the configuration every preview. - - int viewedGroup = (mUsage == KIconLoader::LastGroup) ? KIconLoader::FirstGroup : mUsage; - - QPixmap pm = mpLoader->loadIcon(mExample, KIconLoader::NoGroup, mSizes[viewedGroup]); - QImage img = pm.toImage(); - - Effect &effect = mEffects[viewedGroup][i]; - - img = mpEffect->apply(img, effect.type, - effect.value, effect.color, effect.color2, effect.transparent); - pm = QPixmap::fromImage(img); - mpPreview[i]->setPixmap(pm); -} - -void KIconConfig::preview() -{ - preview(0); - preview(1); - preview(2); -} - -void KIconConfig::exportToKDE4() -{ - //TODO: killing the kde4 icon cache: possible? (kde4migration doesn't let access the cache folder) - Kdelibs4Migration migration; - QString configFilePath = migration.saveLocation("config") + "kdeglobals"; - - if (configFilePath.isEmpty()) { - return; - } - - KSharedConfigPtr kglobalcfg = KSharedConfig::openConfig( QStringLiteral("kdeglobals") ); - KConfig kde4config(configFilePath, KConfig::SimpleConfig); - - KConfigGroup iconsGroup(kglobalcfg, "Icons"); - KConfigGroup kde4IconGroup(&kde4config, "Icons"); - QString iconTheme = iconsGroup.readEntry("Theme", QString()); - if (!iconTheme.isEmpty()) { - kde4IconGroup.writeEntry("Theme", iconTheme); - } - kde4IconGroup.sync(); - - //Synchronize icon effects - QStringList iconGroups; - iconGroups << QStringLiteral("DesktopIcons") << QStringLiteral("DialogIcons") << QStringLiteral("MainToolbarIcons") << QStringLiteral("PanelIcons") << QStringLiteral("SmallIcons") << QStringLiteral("ToolbarIcons"); - - for (QString grp : iconGroups) { - KConfigGroup cg(kglobalcfg, grp); - KConfigGroup cg2(&kde4config, grp); - cg.copyTo(&cg2); - } - - QProcess cachePathProcess; - cachePathProcess.start(QStringLiteral("kde4-config --path cache")); - cachePathProcess.waitForFinished(); - QString path = cachePathProcess.readAllStandardOutput(); - QFile cacheFile(path.remove(path.length()-1, 1)+"/icon-cache.kcache"); - cacheFile.remove(); - - //message kde4 apps that icon theme is changed - for (int i = 0; i < KIconLoader::LastGroup; i++) { - KIconLoader::emitChange(KIconLoader::Group(i)); - - QDBusMessage message = QDBusMessage::createSignal(QStringLiteral("/KGlobalSettings"), QStringLiteral("org.kde.KGlobalSettings"), QStringLiteral("notifyChange") ); - QList args; - args.append(static_cast(KGlobalSettings::IconChanged)); - args.append(KIconLoader::Group(i)); - message.setArguments(args); - QDBusConnection::sessionBus().send(message); - } -} - -void KIconConfig::load() -{ - read(); - apply(); - emit changed(false); - for (int i=0; isync(); - - exportToKDE4(); - - emit changed(false); - - // Emit KIPC change message. - for (int i=0; isetEnabled(false); - mpAnimatedCheck->setEnabled(false); - } - else - { - mpSizeBox->setEnabled(true); - mpAnimatedCheck->setEnabled( mUsage == KIconLoader::Desktop ); - } - - apply(); - preview(); -} - -void KIconConfig::EffectSetup(int state) -{ - int viewedGroup = (mUsage == KIconLoader::LastGroup) ? KIconLoader::FirstGroup : mUsage; - - QPixmap pm = mpLoader->loadIcon(mExample, KIconLoader::NoGroup, mSizes[viewedGroup]); - QImage img = pm.toImage(); - - QString caption; - switch (state) - { - case 0 : caption = i18n("Setup Default Icon Effect"); break; - case 1 : caption = i18n("Setup Active Icon Effect"); break; - case 2 : caption = i18n("Setup Disabled Icon Effect"); break; - } - - KIconEffectSetupDialog dlg(mEffects[viewedGroup][state], mDefaultEffect[state], caption, img, this); - - if (dlg.exec() == QDialog::Accepted) - { - if (mUsage == KIconLoader::LastGroup) { - for (int i=0; isetLayout(topLayout); - - QGridLayout *top = new QGridLayout(page); - top->setMargin(0); - top->setColumnStretch(0,1); - top->setColumnStretch(1,2); - top->setRowStretch(1,1); - topLayout->addItem(top); - - lbl = new QLabel(i18n("&Effect:"), page); - top->addWidget(lbl, 0, 0, Qt::AlignLeft); - mpEffectBox = new QListWidget(page); - mpEffectBox->addItem(i18n("No Effect")); - mpEffectBox->addItem(i18n("To Gray")); - mpEffectBox->addItem(i18n("Colorize")); - mpEffectBox->addItem(i18n("Gamma")); - mpEffectBox->addItem(i18n("Desaturate")); - mpEffectBox->addItem(i18n("To Monochrome")); - - connect(mpEffectBox, &QListWidget::currentRowChanged, this, &KIconEffectSetupDialog::slotEffectType); - top->addWidget(mpEffectBox, 1, 0, 2, 1, Qt::AlignLeft); - lbl->setBuddy(mpEffectBox); - - mpSTCheck = new QCheckBox(i18n("&Semi-transparent"), page); - connect(mpSTCheck, &QCheckBox::toggled, this, &KIconEffectSetupDialog::slotSTCheck); - top->addWidget(mpSTCheck, 3, 0, Qt::AlignLeft); - - frame = new QGroupBox(i18n("Preview"), page); - top->addWidget(frame, 0, 1, 2, 1); - grid = new QGridLayout(frame); - grid->addItem(new QSpacerItem(0, fontMetrics().lineSpacing()), 0, 0); - grid->setRowStretch(1, 1); - - mpPreview = new QLabel(frame); - mpPreview->setAlignment(Qt::AlignCenter); - mpPreview->setMinimumSize(105, 105); - grid->addWidget(mpPreview, 1, 0); - - mpEffectGroup = new QGroupBox(i18n("Effect Parameters"), page); - top->addWidget(mpEffectGroup, 2, 1, 2, 1); - QFormLayout *form = new QFormLayout(mpEffectGroup); - form->setVerticalSpacing(1); //workaround for crash QTBUG-34731 - - mpEffectSlider = new QSlider(Qt::Horizontal, mpEffectGroup); - mpEffectSlider->setMinimum(0); - mpEffectSlider->setMaximum(100); - mpEffectSlider->setPageStep(5); - connect(mpEffectSlider, &QSlider::valueChanged, this, &KIconEffectSetupDialog::slotEffectValue); - form->addRow(i18n("&Amount:"), mpEffectSlider); - mpEffectLabel = static_cast(form->labelForField(mpEffectSlider)); - - mpEColButton = new KColorButton(mpEffectGroup); - connect(mpEColButton, &KColorButton::changed, this, &KIconEffectSetupDialog::slotEffectColor); - form->addRow(i18n("Co&lor:"), mpEColButton); - mpEffectColor = static_cast(form->labelForField(mpEColButton)); - - mpECol2Button = new KColorButton(mpEffectGroup); - connect(mpECol2Button, &KColorButton::changed, this, &KIconEffectSetupDialog::slotEffectColor2); - form->addRow(i18n("&Second color:"), mpECol2Button); - mpEffectColor2 = static_cast(form->labelForField(mpECol2Button)); - - QDialogButtonBox* buttonBox = new QDialogButtonBox(this); - buttonBox->setStandardButtons(QDialogButtonBox::Ok | QDialogButtonBox::RestoreDefaults | QDialogButtonBox::Cancel); - connect(buttonBox, &QDialogButtonBox::accepted, this, &KIconEffectSetupDialog::accept); - connect(buttonBox, &QDialogButtonBox::rejected, this, &KIconEffectSetupDialog::reject); - connect(buttonBox->button(QDialogButtonBox::RestoreDefaults), &QPushButton::clicked, this, &KIconEffectSetupDialog::slotDefault); - topLayout->addWidget(buttonBox); - - init(); - preview(); -} - -KIconEffectSetupDialog::~KIconEffectSetupDialog() -{ - delete mpEffect; -} - -void KIconEffectSetupDialog::init() -{ - mpEffectBox->setCurrentRow(mEffect.type); - mpEffectSlider->setEnabled(mEffect.type != KIconEffect::NoEffect); - mpEColButton->setEnabled(mEffect.type == KIconEffect::Colorize || mEffect.type == KIconEffect::ToMonochrome); - mpECol2Button->setEnabled(mEffect.type == KIconEffect::ToMonochrome); - mpEffectSlider->setValue((int) (100.0 * mEffect.value + 0.5)); - mpEColButton->setColor(mEffect.color); - mpECol2Button->setColor(mEffect.color2); - mpSTCheck->setChecked(mEffect.transparent); -} - -void KIconEffectSetupDialog::slotEffectValue(int value) -{ - mEffect.value = 0.01 * value; - preview(); -} - -void KIconEffectSetupDialog::slotEffectColor(const QColor &col) -{ - mEffect.color = col; - preview(); -} - -void KIconEffectSetupDialog::slotEffectColor2(const QColor &col) -{ - mEffect.color2 = col; - preview(); -} - -void KIconEffectSetupDialog::slotEffectType(int type) -{ - if (type == -1) - return; - mEffect.type = type; - mpEffectGroup->setEnabled(mEffect.type != KIconEffect::NoEffect); - mpEffectSlider->setEnabled(mEffect.type != KIconEffect::NoEffect); - mpEffectColor->setEnabled(mEffect.type == KIconEffect::Colorize || mEffect.type == KIconEffect::ToMonochrome); - mpEColButton->setEnabled(mEffect.type == KIconEffect::Colorize || mEffect.type == KIconEffect::ToMonochrome); - mpEffectColor2->setEnabled(mEffect.type == KIconEffect::ToMonochrome); - mpECol2Button->setEnabled(mEffect.type == KIconEffect::ToMonochrome); - preview(); -} - -void KIconEffectSetupDialog::slotSTCheck(bool b) -{ - mEffect.transparent = b; - preview(); -} - -void KIconEffectSetupDialog::slotDefault() -{ - mEffect = mDefaultEffect; - init(); - preview(); -} - -void KIconEffectSetupDialog::preview() -{ - QPixmap pm; - QImage img = mExample.copy(); - img = mpEffect->apply(img, mEffect.type, - mEffect.value, mEffect.color, mEffect.color2, mEffect.transparent); - pm = QPixmap::fromImage(img); - mpPreview->setPixmap(pm); -} - diff --git a/kcms/icons/icons.desktop b/kcms/icons/icons.desktop deleted file mode 100644 --- a/kcms/icons/icons.desktop +++ /dev/null @@ -1,214 +0,0 @@ -[Desktop Entry] -Exec=kcmshell5 icons -Icon=preferences-desktop-icons -Type=Service -X-KDE-ServiceTypes=KCModule -X-DocPath=kcontrol/icons/index.html - -X-KDE-Library=kcm_icons -X-KDE-ParentApp=kcontrol - -X-KDE-System-Settings-Parent-Category=icons -X-KDE-Weight=40 - -Name=Icons -Name[af]=Ikone -Name[ar]=الأيقونات -Name[as]=আইকন -Name[be]=Значкі -Name[be@latin]=Ikony -Name[bg]=Икони -Name[bn]=আইকন -Name[bn_IN]=আইকন -Name[br]=Arlunioù -Name[bs]=Ikone -Name[ca]=Icones -Name[ca@valencia]=Icones -Name[cs]=Ikony -Name[csb]=Ikònë -Name[cy]=Eicon -Name[da]=Ikoner -Name[de]=Symbole -Name[el]=Εικονίδια -Name[en_GB]=Icons -Name[eo]=Piktogramoj -Name[es]=Iconos -Name[et]=Ikoonid -Name[eu]=Ikonoak -Name[fa]=شمایلها -Name[fi]=Kuvakkeet -Name[fr]=Icônes -Name[fy]=Byldkaikes -Name[ga]=Deilbhíní -Name[gl]=Iconas -Name[gu]=ચિહ્નો -Name[he]=סמלים -Name[hi]=प्रतीक -Name[hne]=चिनहा -Name[hr]=Ikone -Name[hsb]=Piktogramy -Name[hu]=Ikonok -Name[ia]=Icones -Name[id]=Ikon -Name[is]=Táknmyndir -Name[it]=Icone -Name[ja]=アイコン -Name[ka]=ხატულები -Name[kk]=Таңбашалар -Name[km]=រូប​តំណាង -Name[kn]=ಚಿಹ್ನೆಗಳು -Name[ko]=아이콘 -Name[ku]=Îkon -Name[lt]=Ženkliukai -Name[lv]=Ikonas -Name[mai]=प्रतीक -Name[mk]=Икони -Name[ml]=ചിഹ്നങ്ങള്‍ -Name[mr]=चिन्ह -Name[ms]=Ikon -Name[nb]=Ikoner -Name[nds]=Lüttbiller -Name[ne]=प्रतिमा -Name[nl]=Pictogrammen -Name[nn]=Ikon -Name[oc]=Icònas -Name[or]=ଚିତ୍ର ସଂକେତଗୁଡ଼ିକ -Name[pa]=ਆਈਕਾਨ -Name[pl]=Ikony -Name[pt]=Ícones -Name[pt_BR]=Ícones -Name[ro]=Pictograme -Name[ru]=Значки -Name[si]=අයිකන -Name[sk]=Ikony -Name[sl]=Ikone -Name[sr]=Иконице -Name[sr@ijekavian]=Иконице -Name[sr@ijekavianlatin]=Ikonice -Name[sr@latin]=Ikonice -Name[sv]=Ikoner -Name[ta]=சின்னங்கள் -Name[te]=ప్రతిమలు -Name[tg]=Нишонаҳо -Name[th]=ไอคอน -Name[tr]=Simgeler -Name[ug]=سىنبەلگىلەر -Name[uk]=Піктограми -Name[uz]=Nishonchalar -Name[uz@cyrillic]=Нишончалар -Name[vi]=Biểu tượng -Name[wa]=Imådjetes -Name[xh]=Imphawu zemmifanekiso -Name[x-test]=xxIconsxx -Name[zh_CN]=图标 -Name[zh_TW]=圖示 - -Comment=Icon Theme -Comment[ar]=سمة الأيقونات -Comment[bs]=Tema ikone -Comment[ca]=Tema d'icones -Comment[ca@valencia]=Tema d'icones -Comment[cs]=Motiv ikon -Comment[da]=Ikontema -Comment[de]=Symbol-Design -Comment[el]=Θέμα εικονιδίων -Comment[en_GB]=Icon Theme -Comment[es]=Tema de iconos -Comment[et]=Ikooniteema -Comment[eu]=Ikono gaia -Comment[fi]=Kuvaketeema -Comment[fr]=Thème d'icônes -Comment[gl]=Tema de iconas -Comment[he]=ערכת־נושא לסמלים -Comment[hu]=Ikontéma -Comment[id]=Tema Ikon -Comment[is]=Táknmyndaþema -Comment[it]=Tema delle icone -Comment[ja]=アイコンテーマ -Comment[ko]=아이콘 테마 -Comment[lt]=Ženkliukų apipavidalinimas -Comment[mr]=चिन्ह शैली -Comment[nb]=Ikontema -Comment[nds]=Lüttbildmuster -Comment[nl]=Pictogramthema -Comment[nn]=Ikontema -Comment[pa]=ਆਈਕਾਨ ਥੀਮ -Comment[pl]=Zestaw ikon -Comment[pt]=Tema de Ícones -Comment[pt_BR]=Tema de ícones -Comment[ru]=Набор значков -Comment[sk]=Téma ikon -Comment[sl]=Tema ikon -Comment[sr]=Тема иконица -Comment[sr@ijekavian]=Тема иконица -Comment[sr@ijekavianlatin]=Tema ikonica -Comment[sr@latin]=Tema ikonica -Comment[sv]=Ikontema -Comment[tr]=Simge Teması -Comment[uk]=Тема піктограм -Comment[x-test]=xxIcon Themexx -Comment[zh_CN]=图标主题 -Comment[zh_TW]=圖示主題 - -X-KDE-Keywords=icons,effects,size,hicolor,locolor -X-KDE-Keywords[ar]=أيقونات,تأثيرات,حجم,لون عالي,لون سفلي -X-KDE-Keywords[bg]=icons,effects,size,hicolor,locolor,икони,ефекти,размер -X-KDE-Keywords[bn]=icons,effects,size,hicolor,locolor -X-KDE-Keywords[bs]=icons,effects,size,hicolor,locolor,ikone,efekti,veličina,boje -X-KDE-Keywords[ca]=icones,efectes,mida,color alt,color baix -X-KDE-Keywords[ca@valencia]=icones,efectes,mida,color alt,color baix -X-KDE-Keywords[cs]=ikony,efekty,velikost,hicolor,locolor -X-KDE-Keywords[da]=ikoner,effekter,størrelse,hicolor,locolor -X-KDE-Keywords[de]=Symbole,Icons,Effekte,Größe,16-Bit-Farben,8-Bit-Farben -X-KDE-Keywords[el]=εικονίδια,εφέ,μέγεθος,hicolor,locolor -X-KDE-Keywords[en_GB]=icons,effects,size,hicolor,locolor -X-KDE-Keywords[eo]=piktogramoj,efektoj,grando,hicolor,locolor -X-KDE-Keywords[es]=iconos,efectos,tamaño,hicolor,locolor -X-KDE-Keywords[et]=ikoonid,efektid,suurus,hicolor,locolor -X-KDE-Keywords[eu]=ikonoak,efektuak,tamaina,hicolor,locolor -X-KDE-Keywords[fa]=icons,effects,size,hicolor,locolor -X-KDE-Keywords[fi]=kuvakkeet,tehosteet,koko,hicolor,locolor -X-KDE-Keywords[fr]=icônes, effets, taille, hicolor, locolor -X-KDE-Keywords[ga]=deilbhíní,maisíochtaí,méid,ard-dath,ísealdath -X-KDE-Keywords[gl]=iconas, efectos, tamaño, hicolor, locolor -X-KDE-Keywords[gu]=ચિહ્નો,અસરો,માપ,ઉચ્ચરંગ,નીચરંગ -X-KDE-Keywords[he]=סמלים,אפקטים,icons,effects,size,hicolor,locolor -X-KDE-Keywords[hi]=प्रतीक, प्रभाव, आकार, hicolor, locolor -X-KDE-Keywords[hu]=ikonok,effektusok,méret,hicolor,locolor -X-KDE-Keywords[ia]=icones,effectos,grandor,alte color,basse color -X-KDE-Keywords[id]=ikon,efek,ukuran,warna tinggi,warna rendah -X-KDE-Keywords[is]=táknmynd,sjónhverfingar,brellur,stærð,hicolor,locolor -X-KDE-Keywords[it]=icone,effetti,dimensione,molti colori,pochi colori -X-KDE-Keywords[kk]=icons,effects,size,hicolor,locolor -X-KDE-Keywords[km]=រូបតំណាង បែបផែន ទំហំ ពណ៌​ខ្ពស់ ពណ៌​ទាប -X-KDE-Keywords[ko]=icons,effects,size,hicolor,locolor,아이콘,효과,크기,색상 -X-KDE-Keywords[lv]=ikonas,efekti,izmērs,krāsa -X-KDE-Keywords[mr]=चिन्ह, परिणाम, आकार, हाय कलर, लो कलर -X-KDE-Keywords[nb]=ikoner,effekter,størrelse,fargesterk,fargesvak -X-KDE-Keywords[nds]=Lüttbiller,Effekten,Grött,HiColor,LoColor,Klören,Klöör -X-KDE-Keywords[nl]=pictoogrammen,effecten,grootte,hi-kleur,lo-kleur -X-KDE-Keywords[nn]=ikon,effektar,storleik,hicolor,locolor -X-KDE-Keywords[pa]=ਆਈਕਾਨ,ਪ੍ਰਭਾਵ,ਪਰਭਾਵ,ਆਕਾਰ,ਵੱਧ-ਰੰਗ,ਘੱਟਰੰਗ -X-KDE-Keywords[pl]=ikony,efekty,rozmiar,hicolor,locolor -X-KDE-Keywords[pt]=ícones,efeitos,tamanho,muitas cores,poucas cores -X-KDE-Keywords[pt_BR]=ícones,efeitos,tamanho,muitas cores,poucas cores -X-KDE-Keywords[ro]=pictograme,efecte,mărime,hicolor,locolor -X-KDE-Keywords[ru]=icons,effects,size,hicolor,locolor,значки,иконки,эффекты,размер,цвет -X-KDE-Keywords[sk]=ikony,efekty,veľkosť,hicolor,locolor -X-KDE-Keywords[sl]=ikone,učinki,velikost,barve,barva -X-KDE-Keywords[sr]=icons,effects,size,hicolor,locolor,иконице,ефекти,величина,боја -X-KDE-Keywords[sr@ijekavian]=icons,effects,size,hicolor,locolor,иконице,ефекти,величина,боја -X-KDE-Keywords[sr@ijekavianlatin]=icons,effects,size,hicolor,locolor,ikonice,efekti,veličina,boja -X-KDE-Keywords[sr@latin]=icons,effects,size,hicolor,locolor,ikonice,efekti,veličina,boja -X-KDE-Keywords[sv]=ikoner,effekter,storlek,hicolor,locolor -X-KDE-Keywords[tg]=нишонаҳо,таъсирҳо,андоза,ранги баланд,ранги паст -X-KDE-Keywords[tr]=simgeler,efektler,boyut,yüksekrenk,düşükrenk -X-KDE-Keywords[ug]=سىنبەلگىلەر، ئۈنۈملەر، چوڭلۇق، hicolor، locolor -X-KDE-Keywords[uk]=icons,effects,size,hicolor,locolor,піктограми,значки,іконки,ефект,ефекти,розмір,колір -X-KDE-Keywords[vi]=biểu tượng,hiệu ứng,cỡ,nhiều màu, ít màu, icons,effects,size,hicolor,locolor -X-KDE-Keywords[wa]=imådjetes,efets,grandeu,grandeur,coleur -X-KDE-Keywords[x-test]=xxiconsxx,xxeffectsxx,xxsizexx,xxhicolorxx,xxlocolorxx -X-KDE-Keywords[zh_CN]=icons,effects,size,hicolor,locolor,图标,效果,特效,大小,颜色 -X-KDE-Keywords[zh_TW]=icons,effects,size,hicolor,locolor - -Categories=Qt;KDE;X-KDE-settings-looknfeel; diff --git a/kcms/icons/iconthemes.h b/kcms/icons/iconthemes.h deleted file mode 100644 --- a/kcms/icons/iconthemes.h +++ /dev/null @@ -1,74 +0,0 @@ -/** - * Copyright (c) 2000 Antonio Larrosa - * KDE Frameworks 5 port Copyright (C) 2013 Jonathan Riddell - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -#ifndef ICONTHEMES_H -#define ICONTHEMES_H - -#include -#include -#include - -class QStringList; -class QPushButton; -class QTreeWidget; -class QTreeWidgetItem; - -Q_DECLARE_LOGGING_CATEGORY(KCM_ICONS) - -class IconThemesConfig : public KCModule -{ - Q_OBJECT - -public: - IconThemesConfig(QWidget *parent); - ~IconThemesConfig() override; - - void loadThemes(); - bool installThemes(const QStringList &themes, const QString &archiveName); - QStringList findThemeDirs(const QString &archiveName); - - void updateRemoveButton(); - - void load() override; - void save() override; - void defaults() override; - - int buttons(); - -protected Q_SLOTS: - void themeSelected(QTreeWidgetItem *item); - void installNewTheme(); - void getNewTheme(); - void removeSelectedTheme(); - -private: - QTreeWidgetItem *iconThemeItem(const QString &name); - - QTreeWidget *m_iconThemes; - QPushButton *m_removeButton; - - QLabel *m_previewExec; - QLabel *m_previewFolder; - QLabel *m_previewDocument; - QTreeWidgetItem *m_defaultTheme; - bool m_bChanged; -}; - -#endif // ICONTHEMES_H - diff --git a/kcms/icons/iconthemes.cpp b/kcms/icons/iconthemes.cpp deleted file mode 100644 --- a/kcms/icons/iconthemes.cpp +++ /dev/null @@ -1,491 +0,0 @@ -/** - * Copyright (c) 2000 Antonio Larrosa - * KDE Frameworks 5 port Copyright (C) 2013 Jonathan Riddell - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -#include "iconthemes.h" - -#include -#include "config.h" - -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -static const int ThemeNameRole = Qt::UserRole + 1; - -Q_LOGGING_CATEGORY(KCM_ICONS, "kcm_icons") - -IconThemesConfig::IconThemesConfig(QWidget *parent) - : KCModule(parent) -{ - QLoggingCategory::setFilterRules(QStringLiteral("kcm_icons.debug = true")); - QVBoxLayout *topLayout = new QVBoxLayout(this); - - QFrame *m_preview=new QFrame(this); - m_preview->setMinimumHeight(80); - - QHBoxLayout *lh2=new QHBoxLayout( m_preview ); - lh2->setSpacing(0); - m_previewExec=new QLabel(m_preview); - m_previewExec->setPixmap(DesktopIcon(QStringLiteral("system-run"))); - m_previewFolder=new QLabel(m_preview); - m_previewFolder->setPixmap(DesktopIcon(QStringLiteral("folder"))); - m_previewDocument=new QLabel(m_preview); - m_previewDocument->setPixmap(DesktopIcon(QStringLiteral("document"))); - - lh2->addStretch(10); - lh2->addWidget(m_previewExec); - lh2->addStretch(1); - lh2->addWidget(m_previewFolder); - lh2->addStretch(1); - lh2->addWidget(m_previewDocument); - lh2->addStretch(10); - - - m_iconThemes=new QTreeWidget(this/*"IconThemeList"*/); - QStringList columns; - columns.append(i18n("Name")); - columns.append(i18n("Description")); - m_iconThemes->setHeaderLabels(columns); - m_iconThemes->setAllColumnsShowFocus( true ); - m_iconThemes->setRootIsDecorated(false); - m_iconThemes->setSortingEnabled(true); - m_iconThemes->sortByColumn(0, Qt::AscendingOrder); - connect(m_iconThemes, &QTreeWidget::currentItemChanged, this, &IconThemesConfig::themeSelected); - - QPushButton *installButton=new QPushButton( QIcon::fromTheme(QStringLiteral("document-import")), i18n("Install from File"), this); - installButton->setObjectName( QStringLiteral("InstallNewTheme" )); - installButton->setToolTip(i18n("Install a theme archive file you already have locally")); - installButton->setWhatsThis(i18n("If you already have a theme archive locally, this button will unpack it and make it available for KDE applications")); - connect(installButton, &QPushButton::clicked, this, &IconThemesConfig::installNewTheme); - - QPushButton *newButton=new QPushButton( QIcon::fromTheme(QStringLiteral("get-hot-new-stuff")), i18n("Get New Themes..."), this); - newButton->setObjectName( QStringLiteral("GetNewTheme" )); - newButton->setToolTip(i18n("Get new themes from the Internet")); - newButton->setWhatsThis(i18n("You need to be connected to the Internet to use this action. A dialog will display a list of themes from the http://www.kde.org website. Clicking the Install button associated with a theme will install this theme locally.")); - connect(newButton, &QPushButton::clicked, this, &IconThemesConfig::getNewTheme); - - m_removeButton=new QPushButton( QIcon::fromTheme(QStringLiteral("edit-delete")), i18n("Remove Theme"), this); - m_removeButton->setObjectName( QStringLiteral("RemoveTheme" )); - m_removeButton->setToolTip(i18n("Remove the selected theme from your disk")); - m_removeButton->setWhatsThis(i18n("This will remove the selected theme from your disk.")); - connect(m_removeButton, &QPushButton::clicked, this, &IconThemesConfig::removeSelectedTheme); - - topLayout->addWidget(m_preview); - topLayout->addWidget(m_iconThemes); - QHBoxLayout *lg = new QHBoxLayout(); - lg->addWidget(newButton); - lg->addWidget(installButton); - lg->addStretch(0); - lg->addWidget(m_removeButton); - topLayout->addLayout(lg); - - loadThemes(); - - m_defaultTheme=iconThemeItem(KIconTheme::current()); - if (m_defaultTheme) - m_iconThemes->setCurrentItem(m_defaultTheme); - updateRemoveButton(); - - m_iconThemes->setFocus(); -} - -IconThemesConfig::~IconThemesConfig() -{ -} - -QTreeWidgetItem *IconThemesConfig::iconThemeItem(const QString &name) -{ - for (int i = 0; i < m_iconThemes->topLevelItemCount(); ++i) - if (m_iconThemes->topLevelItem(i)->data(0, ThemeNameRole).toString()==name) - return m_iconThemes->topLevelItem(i); - - return 0L; -} - -void IconThemesConfig::loadThemes() -{ - m_iconThemes->clear(); - const QStringList themelist(KIconTheme::list()); - QString name; - QString tname; - QStringList::const_iterator it; - QMap themeNames; - qCDebug(KCM_ICONS) << "Theme list:" << themelist << "<<"; // this is empty when I run it - jr - for (it=themelist.constBegin(); it != themelist.constEnd(); ++it) - { - KIconTheme icontheme(*it); - if (!icontheme.isValid()) qCDebug(KCM_ICONS) << "not a valid theme" << *it; - if (icontheme.isHidden()) continue; - - name=icontheme.name(); - tname=name; - - // Just in case we have duplicated icon theme names on separate directories - for (int i = 2; themeNames.find(tname) != themeNames.end(); ++i) - tname=QStringLiteral("%1-%2").arg(name).arg(i); - - QTreeWidgetItem *newitem = new QTreeWidgetItem(); - newitem->setText(0, name); - newitem->setText(1, icontheme.description()); - newitem->setData(0, ThemeNameRole, *it); - m_iconThemes->addTopLevelItem(newitem); - - themeNames.insert(name, *it); - } - m_iconThemes->resizeColumnToContents(0); -} - -void IconThemesConfig::installNewTheme() -{ - QUrl themeURL = KUrlRequesterDialog::getUrl(QUrl(), this, i18n("Drag or Type Theme URL")); - if (themeURL.url().isEmpty()) return; - - qCDebug(KCM_ICONS) << themeURL; - QTemporaryFile file; - // themeTmpFile contains the name of the downloaded file - - KJob* job = KIO::storedGet(themeURL); - KJobWidgets::setWindow(job, this); - if (!file.open()) { - KMessageBox::sorry(this, i18n("Unable to create a temporary file.")); - return; - } else if (!job->exec()) { - QString sorryText; - if (themeURL.isLocalFile()) - sorryText = i18n("Unable to find the icon theme archive %1.", - themeURL.toString()); - else - sorryText = i18n("Unable to download the icon theme archive;\n" - "please check that address %1 is correct.", - themeURL.toString()); - KMessageBox::sorry(this, sorryText); - return; - } - - QStringList themesNames = findThemeDirs(file.fileName()); - if (themesNames.isEmpty()) { - QString invalidArch(i18n("The file is not a valid icon theme archive.")); - KMessageBox::error(this, invalidArch); - return; - } - - if (!installThemes(themesNames, file.fileName())) { - //FIXME: make me able to know what is wrong.... - // QStringList instead of bool? - QString somethingWrong = - i18n("A problem occurred during the installation process; " - "however, most of the themes in the archive have been installed"); - KMessageBox::error(this, somethingWrong); - } - - KIconLoader::global()->newIconLoader(); - loadThemes(); - - QTreeWidgetItem *item=iconThemeItem(KIconTheme::current()); - if (item) - m_iconThemes->setCurrentItem(item); - updateRemoveButton(); -} - -bool IconThemesConfig::installThemes(const QStringList &themes, const QString &archiveName) -{ - bool everythingOk = true; - QString localThemesDir(QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + QStringLiteral("/icons/") + "./"); - - QProgressDialog progressDiag(this); - progressDiag.setLabelText(i18n("Installing icon themes...")); - progressDiag.setModal(true); - progressDiag.setAutoClose(true); - progressDiag.setRange(0, themes.count()); - progressDiag.show(); - - KTar archive(archiveName); - archive.open(QIODevice::ReadOnly); - qApp->processEvents(); - - const KArchiveDirectory* rootDir = archive.directory(); - - KArchiveDirectory* currentTheme; - for (QStringList::ConstIterator it = themes.begin(); - it != themes.end(); - ++it) { - progressDiag.setLabelText( - i18n("Installing %1 theme", - *it)); - qApp->processEvents(); - - if (progressDiag.wasCanceled()) - break; - - currentTheme = dynamic_cast( - const_cast( - rootDir->entry(*it))); - if (currentTheme == NULL) { - // we tell back that something went wrong, but try to install as much - // as possible - everythingOk = false; - continue; - } - - currentTheme->copyTo(localThemesDir + *it); - progressDiag.setValue(progressDiag.value()+1); - } - - archive.close(); - return everythingOk; -} - -QStringList IconThemesConfig::findThemeDirs(const QString &archiveName) -{ - QStringList foundThemes; - - KTar archive(archiveName); - archive.open(QIODevice::ReadOnly); - const KArchiveDirectory* themeDir = archive.directory(); - - KArchiveEntry* possibleDir = 0L; - KArchiveDirectory* subDir = 0L; - - // iterate all the dirs looking for an index.theme or index.desktop file - QStringList entries = themeDir->entries(); - for (QStringList::const_iterator it = entries.constBegin(); - it != entries.constEnd(); - ++it) { - possibleDir = const_cast(themeDir->entry(*it)); - if (possibleDir->isDirectory()) { - subDir = dynamic_cast( possibleDir ); - if (subDir && (subDir->entry(QStringLiteral("index.theme")) != NULL || - subDir->entry(QStringLiteral("index.desktop")) != NULL)) - foundThemes.append(subDir->name()); - } - } - - archive.close(); - return foundThemes; -} - -void IconThemesConfig::getNewTheme() -{ - KNS3::DownloadDialog dialog(QStringLiteral("icons.knsrc"), this); - dialog.exec(); - if (!dialog.changedEntries().isEmpty()) { - // reload the display icontheme items - KIconLoader::global()->newIconLoader(); - loadThemes(); - QTreeWidgetItem *item=iconThemeItem(KIconTheme::current()); - if (item) - m_iconThemes->setCurrentItem(item); - updateRemoveButton(); - load(); - } -} - -void IconThemesConfig::removeSelectedTheme() -{ - QTreeWidgetItem *selected = m_iconThemes->currentItem(); - if (!selected) - return; - - QString question=i18n("Are you sure you want to remove the " - "%1 icon theme?
" - "
" - "This will delete the files installed by this theme.
", - selected->text(0)); - - bool deletingCurrentTheme=(selected==iconThemeItem(KIconTheme::current())); - - int r=KMessageBox::warningContinueCancel(this,question,i18n("Confirmation"),KStandardGuiItem::del()); - if (r!=KMessageBox::Continue) return; - - KIconTheme icontheme(selected->data(0, ThemeNameRole).toString()); - - // delete the index file before the async KIO::del so loadThemes() will - // ignore that dir. - unlink(QFile::encodeName(icontheme.dir()+"/index.theme").data()); - unlink(QFile::encodeName(icontheme.dir()+"/index.desktop").data()); - KIO::del(QUrl::fromLocalFile( icontheme.dir() )); - - KIconLoader::global()->newIconLoader(); - - loadThemes(); - - QTreeWidgetItem *item=0L; - //Fallback to the default if we've deleted the current theme - if (!deletingCurrentTheme) - item=iconThemeItem(KIconTheme::current()); - if (!item) - item=iconThemeItem(KIconTheme::defaultThemeName()); - - if (item) - m_iconThemes->setCurrentItem(item); - updateRemoveButton(); - - if (deletingCurrentTheme) // Change the configuration - save(); -} - -void IconThemesConfig::updateRemoveButton() -{ - QTreeWidgetItem *selected = m_iconThemes->currentItem(); - bool enabled = false; - if (selected) - { - QString selectedtheme = selected->data(0, ThemeNameRole).toString(); - KIconTheme icontheme(selectedtheme); - QFileInfo fi(icontheme.dir()); - enabled = fi.isWritable(); - // Don't let users remove the current theme. - if (selectedtheme == KIconTheme::current() || - selectedtheme == KIconTheme::defaultThemeName()) - enabled = false; - } - m_removeButton->setEnabled(enabled); -} - -void loadPreview(QLabel *label, KIconTheme& icontheme, const QStringList& iconnames) -{ - const qreal dpr = label->devicePixelRatioF(); - - //Given the icontheme loads a preview of an icon (several names are allowed for old theme standards) into the pixmap of the given label - const int size = qMin(48, icontheme.defaultSize(KIconLoader::Desktop)) * dpr; - QSvgRenderer renderer; - foreach(const QString &iconthemename, QStringList() << icontheme.internalName() << icontheme.inherits()) { - foreach(const QString &name, iconnames) { - //load the icon image - QString path = KIconTheme(iconthemename).iconPath(QStringLiteral("%1.png").arg(name), size, KIconLoader::MatchBest); - if (path != QString()) { - QPixmap pixmap(path); - pixmap.setDevicePixelRatio(dpr); - label->setPixmap(pixmap.scaled(size, size)); - return; - } - //could not find the .png, try loading the .svg or .svgz - path = KIconTheme(iconthemename).iconPath(QStringLiteral("%1.svg").arg(name), size, KIconLoader::MatchBest); - if( path == QString() ) { - path = KIconTheme(iconthemename).iconPath(QStringLiteral("%1.svgz").arg(name), size, KIconLoader::MatchBest); - if( path == QString() ) { - continue; - } - } - if (renderer.load(path)) { - QPixmap pix(size * dpr, size * dpr); - pix.setDevicePixelRatio(dpr); - pix.fill(QColor(Qt::transparent)); - QPainter p(&pix); - p.setViewport(0, 0, size, size); - renderer.render(&p); - label->setPixmap(pix.scaled(size, size)); - return; - } - } - } - label->setPixmap(QPixmap()); -} - -void IconThemesConfig::themeSelected(QTreeWidgetItem *item) -{ - if (!item) return; - - QString dirName(item->data(0, ThemeNameRole).toString()); - KIconTheme icontheme(dirName); - if (!icontheme.isValid()) qCDebug(KCM_ICONS) << "notvalid\n"; - - updateRemoveButton(); - - loadPreview(m_previewExec, icontheme, QStringList() << QStringLiteral("system-run") << QStringLiteral("exec")); - loadPreview(m_previewFolder, icontheme, QStringList() << QStringLiteral("folder")); - loadPreview(m_previewDocument, icontheme, QStringList() << QStringLiteral("document") << QStringLiteral("text-x-generic")); - - emit changed(true); - m_bChanged = true; -} - -void IconThemesConfig::load() -{ - m_defaultTheme=iconThemeItem(KIconTheme::current()); - if (m_defaultTheme) - m_iconThemes->setCurrentItem(m_defaultTheme); - emit changed(false); - m_bChanged = false; -} - -void IconThemesConfig::save() -{ - if (!m_bChanged) - return; - QTreeWidgetItem *selected = m_iconThemes->currentItem(); - if (!selected) - return; - - QProcess::startDetached(CMAKE_INSTALL_FULL_LIBEXECDIR "/plasma-changeicons", {selected->data(0, ThemeNameRole).toString()}); - - emit changed(false); - - m_bChanged = false; - m_removeButton->setEnabled(false); -} - -void IconThemesConfig::defaults() -{ - if (m_iconThemes->currentItem()==m_defaultTheme) return; - - if (m_defaultTheme) - m_iconThemes->setCurrentItem(m_defaultTheme); - updateRemoveButton(); - - emit changed(true); - m_bChanged = true; -} - diff --git a/kcms/icons/kcm_icons.desktop b/kcms/icons/kcm_icons.desktop new file mode 100644 --- /dev/null +++ b/kcms/icons/kcm_icons.desktop @@ -0,0 +1,214 @@ +[Desktop Entry] +Exec=kcmshell5 icons +Icon=preferences-desktop-icons +Type=Service +X-KDE-ServiceTypes=KCModule +X-DocPath=kcontrol/icons/index.html + +X-KDE-Library=kcm_icons +X-KDE-ParentApp=kcontrol + +X-KDE-System-Settings-Parent-Category=icons +X-KDE-Weight=40 + +Name=Icons +Name[af]=Ikone +Name[ar]=الأيقونات +Name[as]=আইকন +Name[be]=Значкі +Name[be@latin]=Ikony +Name[bg]=Икони +Name[bn]=আইকন +Name[bn_IN]=আইকন +Name[br]=Arlunioù +Name[bs]=Ikone +Name[ca]=Icones +Name[ca@valencia]=Icones +Name[cs]=Ikony +Name[csb]=Ikònë +Name[cy]=Eicon +Name[da]=Ikoner +Name[de]=Symbole +Name[el]=Εικονίδια +Name[en_GB]=Icons +Name[eo]=Piktogramoj +Name[es]=Iconos +Name[et]=Ikoonid +Name[eu]=Ikonoak +Name[fa]=شمایلها +Name[fi]=Kuvakkeet +Name[fr]=Icônes +Name[fy]=Byldkaikes +Name[ga]=Deilbhíní +Name[gl]=Iconas +Name[gu]=ચિહ્નો +Name[he]=סמלים +Name[hi]=प्रतीक +Name[hne]=चिनहा +Name[hr]=Ikone +Name[hsb]=Piktogramy +Name[hu]=Ikonok +Name[ia]=Icones +Name[id]=Ikon +Name[is]=Táknmyndir +Name[it]=Icone +Name[ja]=アイコン +Name[ka]=ხატულები +Name[kk]=Таңбашалар +Name[km]=រូប​តំណាង +Name[kn]=ಚಿಹ್ನೆಗಳು +Name[ko]=아이콘 +Name[ku]=Îkon +Name[lt]=Ženkliukai +Name[lv]=Ikonas +Name[mai]=प्रतीक +Name[mk]=Икони +Name[ml]=ചിഹ്നങ്ങള്‍ +Name[mr]=चिन्ह +Name[ms]=Ikon +Name[nb]=Ikoner +Name[nds]=Lüttbiller +Name[ne]=प्रतिमा +Name[nl]=Pictogrammen +Name[nn]=Ikon +Name[oc]=Icònas +Name[or]=ଚିତ୍ର ସଂକେତଗୁଡ଼ିକ +Name[pa]=ਆਈਕਾਨ +Name[pl]=Ikony +Name[pt]=Ícones +Name[pt_BR]=Ícones +Name[ro]=Pictograme +Name[ru]=Значки +Name[si]=අයිකන +Name[sk]=Ikony +Name[sl]=Ikone +Name[sr]=Иконице +Name[sr@ijekavian]=Иконице +Name[sr@ijekavianlatin]=Ikonice +Name[sr@latin]=Ikonice +Name[sv]=Ikoner +Name[ta]=சின்னங்கள் +Name[te]=ప్రతిమలు +Name[tg]=Нишонаҳо +Name[th]=ไอคอน +Name[tr]=Simgeler +Name[ug]=سىنبەلگىلەر +Name[uk]=Піктограми +Name[uz]=Nishonchalar +Name[uz@cyrillic]=Нишончалар +Name[vi]=Biểu tượng +Name[wa]=Imådjetes +Name[xh]=Imphawu zemmifanekiso +Name[x-test]=xxIconsxx +Name[zh_CN]=图标 +Name[zh_TW]=圖示 + +Comment=Icon Theme +Comment[ar]=سمة الأيقونات +Comment[bs]=Tema ikone +Comment[ca]=Tema d'icones +Comment[ca@valencia]=Tema d'icones +Comment[cs]=Motiv ikon +Comment[da]=Ikontema +Comment[de]=Symbol-Design +Comment[el]=Θέμα εικονιδίων +Comment[en_GB]=Icon Theme +Comment[es]=Tema de iconos +Comment[et]=Ikooniteema +Comment[eu]=Ikono gaia +Comment[fi]=Kuvaketeema +Comment[fr]=Thème d'icônes +Comment[gl]=Tema de iconas +Comment[he]=ערכת־נושא לסמלים +Comment[hu]=Ikontéma +Comment[id]=Tema Ikon +Comment[is]=Táknmyndaþema +Comment[it]=Tema delle icone +Comment[ja]=アイコンテーマ +Comment[ko]=아이콘 테마 +Comment[lt]=Ženkliukų apipavidalinimas +Comment[mr]=चिन्ह शैली +Comment[nb]=Ikontema +Comment[nds]=Lüttbildmuster +Comment[nl]=Pictogramthema +Comment[nn]=Ikontema +Comment[pa]=ਆਈਕਾਨ ਥੀਮ +Comment[pl]=Zestaw ikon +Comment[pt]=Tema de Ícones +Comment[pt_BR]=Tema de ícones +Comment[ru]=Набор значков +Comment[sk]=Téma ikon +Comment[sl]=Tema ikon +Comment[sr]=Тема иконица +Comment[sr@ijekavian]=Тема иконица +Comment[sr@ijekavianlatin]=Tema ikonica +Comment[sr@latin]=Tema ikonica +Comment[sv]=Ikontema +Comment[tr]=Simge Teması +Comment[uk]=Тема піктограм +Comment[x-test]=xxIcon Themexx +Comment[zh_CN]=图标主题 +Comment[zh_TW]=圖示主題 + +X-KDE-Keywords=icons,effects,size,hicolor,locolor +X-KDE-Keywords[ar]=أيقونات,تأثيرات,حجم,لون عالي,لون سفلي +X-KDE-Keywords[bg]=icons,effects,size,hicolor,locolor,икони,ефекти,размер +X-KDE-Keywords[bn]=icons,effects,size,hicolor,locolor +X-KDE-Keywords[bs]=icons,effects,size,hicolor,locolor,ikone,efekti,veličina,boje +X-KDE-Keywords[ca]=icones,efectes,mida,color alt,color baix +X-KDE-Keywords[ca@valencia]=icones,efectes,mida,color alt,color baix +X-KDE-Keywords[cs]=ikony,efekty,velikost,hicolor,locolor +X-KDE-Keywords[da]=ikoner,effekter,størrelse,hicolor,locolor +X-KDE-Keywords[de]=Symbole,Icons,Effekte,Größe,16-Bit-Farben,8-Bit-Farben +X-KDE-Keywords[el]=εικονίδια,εφέ,μέγεθος,hicolor,locolor +X-KDE-Keywords[en_GB]=icons,effects,size,hicolor,locolor +X-KDE-Keywords[eo]=piktogramoj,efektoj,grando,hicolor,locolor +X-KDE-Keywords[es]=iconos,efectos,tamaño,hicolor,locolor +X-KDE-Keywords[et]=ikoonid,efektid,suurus,hicolor,locolor +X-KDE-Keywords[eu]=ikonoak,efektuak,tamaina,hicolor,locolor +X-KDE-Keywords[fa]=icons,effects,size,hicolor,locolor +X-KDE-Keywords[fi]=kuvakkeet,tehosteet,koko,hicolor,locolor +X-KDE-Keywords[fr]=icônes, effets, taille, hicolor, locolor +X-KDE-Keywords[ga]=deilbhíní,maisíochtaí,méid,ard-dath,ísealdath +X-KDE-Keywords[gl]=iconas, efectos, tamaño, hicolor, locolor +X-KDE-Keywords[gu]=ચિહ્નો,અસરો,માપ,ઉચ્ચરંગ,નીચરંગ +X-KDE-Keywords[he]=סמלים,אפקטים,icons,effects,size,hicolor,locolor +X-KDE-Keywords[hi]=प्रतीक, प्रभाव, आकार, hicolor, locolor +X-KDE-Keywords[hu]=ikonok,effektusok,méret,hicolor,locolor +X-KDE-Keywords[ia]=icones,effectos,grandor,alte color,basse color +X-KDE-Keywords[id]=ikon,efek,ukuran,warna tinggi,warna rendah +X-KDE-Keywords[is]=táknmynd,sjónhverfingar,brellur,stærð,hicolor,locolor +X-KDE-Keywords[it]=icone,effetti,dimensione,molti colori,pochi colori +X-KDE-Keywords[kk]=icons,effects,size,hicolor,locolor +X-KDE-Keywords[km]=រូបតំណាង បែបផែន ទំហំ ពណ៌​ខ្ពស់ ពណ៌​ទាប +X-KDE-Keywords[ko]=icons,effects,size,hicolor,locolor,아이콘,효과,크기,색상 +X-KDE-Keywords[lv]=ikonas,efekti,izmērs,krāsa +X-KDE-Keywords[mr]=चिन्ह, परिणाम, आकार, हाय कलर, लो कलर +X-KDE-Keywords[nb]=ikoner,effekter,størrelse,fargesterk,fargesvak +X-KDE-Keywords[nds]=Lüttbiller,Effekten,Grött,HiColor,LoColor,Klören,Klöör +X-KDE-Keywords[nl]=pictoogrammen,effecten,grootte,hi-kleur,lo-kleur +X-KDE-Keywords[nn]=ikon,effektar,storleik,hicolor,locolor +X-KDE-Keywords[pa]=ਆਈਕਾਨ,ਪ੍ਰਭਾਵ,ਪਰਭਾਵ,ਆਕਾਰ,ਵੱਧ-ਰੰਗ,ਘੱਟਰੰਗ +X-KDE-Keywords[pl]=ikony,efekty,rozmiar,hicolor,locolor +X-KDE-Keywords[pt]=ícones,efeitos,tamanho,muitas cores,poucas cores +X-KDE-Keywords[pt_BR]=ícones,efeitos,tamanho,muitas cores,poucas cores +X-KDE-Keywords[ro]=pictograme,efecte,mărime,hicolor,locolor +X-KDE-Keywords[ru]=icons,effects,size,hicolor,locolor,значки,иконки,эффекты,размер,цвет +X-KDE-Keywords[sk]=ikony,efekty,veľkosť,hicolor,locolor +X-KDE-Keywords[sl]=ikone,učinki,velikost,barve,barva +X-KDE-Keywords[sr]=icons,effects,size,hicolor,locolor,иконице,ефекти,величина,боја +X-KDE-Keywords[sr@ijekavian]=icons,effects,size,hicolor,locolor,иконице,ефекти,величина,боја +X-KDE-Keywords[sr@ijekavianlatin]=icons,effects,size,hicolor,locolor,ikonice,efekti,veličina,boja +X-KDE-Keywords[sr@latin]=icons,effects,size,hicolor,locolor,ikonice,efekti,veličina,boja +X-KDE-Keywords[sv]=ikoner,effekter,storlek,hicolor,locolor +X-KDE-Keywords[tg]=нишонаҳо,таъсирҳо,андоза,ранги баланд,ранги паст +X-KDE-Keywords[tr]=simgeler,efektler,boyut,yüksekrenk,düşükrenk +X-KDE-Keywords[ug]=سىنبەلگىلەر، ئۈنۈملەر، چوڭلۇق، hicolor، locolor +X-KDE-Keywords[uk]=icons,effects,size,hicolor,locolor,піктограми,значки,іконки,ефект,ефекти,розмір,колір +X-KDE-Keywords[vi]=biểu tượng,hiệu ứng,cỡ,nhiều màu, ít màu, icons,effects,size,hicolor,locolor +X-KDE-Keywords[wa]=imådjetes,efets,grandeu,grandeur,coleur +X-KDE-Keywords[x-test]=xxiconsxx,xxeffectsxx,xxsizexx,xxhicolorxx,xxlocolorxx +X-KDE-Keywords[zh_CN]=icons,effects,size,hicolor,locolor,图标,效果,特效,大小,颜色 +X-KDE-Keywords[zh_TW]=icons,effects,size,hicolor,locolor + +Categories=Qt;KDE;X-KDE-settings-looknfeel; diff --git a/kcms/icons/main.h b/kcms/icons/main.h --- a/kcms/icons/main.h +++ b/kcms/icons/main.h @@ -3,6 +3,7 @@ * * Copyright (c) 1999 Matthias Hoelzer-Kluepfel * KDE Frameworks 5 port Copyright (C) 2013 Jonathan Riddell + * Copyright (c) 2018 Kai Uwe Broulik * * Requires the Qt widget libraries, available at no cost at * http://www.troll.no/ @@ -22,35 +23,104 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ +#pragma once -#ifndef __MAIN_H__ -#define __MAIN_H__ +#include +#include -#include -#include +#include -class IconModule : public KCModule +class KIconTheme; + +class QStandardItemModel; +class QQuickItem; +class QTemporaryFile; + +class IconModule : public KQuickAddons::ConfigModule { - Q_OBJECT + Q_OBJECT + + Q_PROPERTY(QStandardItemModel *iconsModel READ iconsModel CONSTANT) + + Q_PROPERTY(QString selectedTheme READ selectedTheme WRITE setSelectedTheme NOTIFY selectedThemeChanged) + Q_PROPERTY(int selectedThemeIndex READ selectedThemeIndex NOTIFY selectedThemeIndexChanged) + + Q_PROPERTY(QStringList iconGroups READ iconGroups CONSTANT) public: - IconModule(QWidget *parent, const QVariantList &); + IconModule(QObject *parent, const QVariantList &args); + ~IconModule() override; + + enum Roles { + ThemeNameRole = Qt::UserRole + 1, + DescriptionRole, + RemovableRole, + PendingDeletionRole + }; + + QStandardItemModel *iconsModel() const; + + QString selectedTheme() const; + void setSelectedTheme(const QString &theme); + + int selectedThemeIndex() const; + + QStringList iconGroups() const; + + void load() override; + void save() override; + void defaults() override; + + Q_INVOKABLE void getNewStuff(QQuickItem *ctx); + Q_INVOKABLE void installThemeFromFile(const QUrl &url); + + Q_INVOKABLE void setPendingDeletion(int index, bool pending); - void load() override; - void save() override; - void defaults() override; - QString quickHelp() const override; + Q_INVOKABLE int iconSize(int group) const; + Q_INVOKABLE void setIconSize(int group, int size); + Q_INVOKABLE QList availableIconSizes(int group) const; -protected Q_SLOTS: - void moduleChanged(bool state); + Q_INVOKABLE QVariantList/*QList*/ previewIcons(const QString &themeName, int size, qreal dpr) const; + +signals: + void selectedThemeChanged(); + void selectedThemeIndexChanged(); + void iconSizesChanged(); + + void showSuccessMessage(const QString &message); + void showErrorMessage(const QString &message); + + void showProgress(const QString &message); + void hideProgress(); private: - QTabWidget *tab; + void loadModel(); + void loadIconSizes(); - KCModule *tab1; - KCModule *tab2; -}; + void processPendingDeletions(); + + static QStringList findThemeDirs(const QString &archiveName); + bool installThemes(const QStringList &themes, const QString &archiveName); + void installThemeFile(const QString &path); + + void exportToKDE4(); + QStandardItemModel *m_model; + QString m_selectedTheme; + // so we avoid launching changeicon process when theme didn't change (but only e.g. pending deletions) + bool m_selectedThemeDirty = false; + bool m_iconSizesDirty = false; -#endif + // set when user hits "Defaults" button at which point we'll remove all custom icon effects on Apply + bool m_revertIconEffects = false; + + QVector m_iconSizes; + + QStringList m_iconGroups; + + QScopedPointer m_tempInstallFile; + + QPointer m_newStuffDialog; + +}; diff --git a/kcms/icons/main.cpp b/kcms/icons/main.cpp --- a/kcms/icons/main.cpp +++ b/kcms/icons/main.cpp @@ -2,7 +2,10 @@ * main.cpp * * Copyright (c) 1999 Matthias Hoelzer-Kluepfel + * Copyright (c) 2000 Antonio Larrosa + * Copyright (C) 2000 Geert Jansen * KDE Frameworks 5 port Copyright (C) 2013 Jonathan Riddell + * Copyright (C) 2018 Kai Uwe Broulik * * Requires the Qt widget libraries, available at no cost at * http://www.troll.no/ @@ -24,86 +27,598 @@ #include "main.h" -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include -#include -#include +#include +#include +#include +#include +#include #include +#include +#include +#include + +#include +#include + +#include +#include // for unlink + +#include "config.h" // for CMAKE_INSTALL_FULL_LIBEXECDIR -#include "icons.h" -#include "iconthemes.h" +static const QVector s_defaultIconSizes = { 32, 22, 22, 16, 48, 32 }; +// we try to use KIconTheme::defaultThemeName() but that could be "hicolor" which isn't a "real" theme +static const QString s_defaultThemeName = QStringLiteral("breeze"); -K_PLUGIN_FACTORY(IconsFactory, registerPlugin();) +K_PLUGIN_FACTORY_WITH_JSON(IconsFactory, "kcm_icons.json", registerPlugin();) -IconModule::IconModule(QWidget *parent, const QVariantList &) - : KCModule(parent) +IconModule::IconModule(QObject *parent, const QVariantList &args) + : KQuickAddons::ConfigModule(parent, args) + , m_iconGroups{ + QStringLiteral("Desktop"), + QStringLiteral("Toolbar"), + QStringLiteral("MainToolbar"), + QStringLiteral("Small"), + QStringLiteral("Panel"), + QStringLiteral("Dialog") + } { - QVBoxLayout *layout = new QVBoxLayout(this); - layout->setMargin(0); + qmlRegisterType(); - tab = new QTabWidget(this); - layout->addWidget(tab); + // to be able to access its enums + qmlRegisterUncreatableType("org.kde.private.kcms.icons", 1, 0, "KIconLoader", QString()); - tab1 = new IconThemesConfig(this); - tab1->setObjectName( QStringLiteral( "themes" ) ); - tab->addTab(tab1, i18n("&Theme")); - connect(tab1, SIGNAL(changed(bool)), this, SLOT(moduleChanged(bool))); + KAboutData* about = new KAboutData(QStringLiteral("kcm_icons"), i18n("Icons"), QStringLiteral("1.0"), + i18n("Icons Control Panel Module"), KAboutLicense::GPL, + i18n("(c) 2000-2003 Geert Jansen")); + about->addAuthor(i18n("Geert Jansen"), QString(), QStringLiteral("jansen@kde.org")); + about->addAuthor(i18n("Antonio Larrosa Jimenez"), QString(), QStringLiteral("larrosa@kde.org")); + about->addCredit(i18n("Torsten Rahn"), QString(), QStringLiteral("torsten@kde.org")); + about->addAuthor(i18n("Jonathan Riddell"), QString(), QStringLiteral("jr@jriddell.org")); + about->addAuthor(i18n("Kai Uwe Broulik"), QString(), QStringLiteral("kde@privat.broulik.de>")); + setAboutData(about); - tab2 = new KIconConfig(this); - tab2->setObjectName( QStringLiteral( "effects" ) ); - tab->addTab(tab2, i18n("Ad&vanced")); - connect(tab2, SIGNAL(changed(bool)), this, SLOT(moduleChanged(bool))); + setButtons(Apply | Default); - KAboutData* about = new KAboutData(QStringLiteral("kcmicons"), i18n("Icons"), QStringLiteral("1.0"), - i18n("Icons Control Panel Module"), KAboutLicense::GPL, - i18n("(c) 2000-2003 Geert Jansen")); - about->addAuthor(i18n("Geert Jansen"), QString(), QStringLiteral("jansen@kde.org")); - about->addAuthor(i18n("Antonio Larrosa Jimenez"), QString(), QStringLiteral("larrosa@kde.org")); - about->addCredit(i18n("Torsten Rahn"), QString(), QStringLiteral("torsten@kde.org")); - about->addAuthor(i18n("Jonathan Riddell"), QString(), QStringLiteral("jr@jriddell.org")); - setAboutData( about ); + m_model = new QStandardItemModel(this); + m_model->setItemRoleNames({ + {Qt::DisplayRole, QByteArrayLiteral("display")}, + {DescriptionRole, QByteArrayLiteral("description")}, + {ThemeNameRole, QByteArrayLiteral("themeName")}, + {RemovableRole, QByteArrayLiteral("removable")}, + {PendingDeletionRole, QByteArrayLiteral("pendingDeletion")} + }); } +IconModule::~IconModule() +{ -void IconModule::load() +} + +QStandardItemModel *IconModule::iconsModel() const { - tab1->load(); - tab2->load(); + return m_model; } +QString IconModule::selectedTheme() const +{ + return m_selectedTheme; +} -void IconModule::save() +void IconModule::setSelectedTheme(const QString &theme) +{ + if (m_selectedTheme == theme) { + return; + } + + const bool firstTime = m_selectedTheme.isNull(); + m_selectedTheme = theme; + emit selectedThemeChanged(); + emit selectedThemeIndexChanged(); + + if (!firstTime) { + setNeedsSave(true); + m_selectedThemeDirty = true; + } +} + +int IconModule::selectedThemeIndex() const +{ + const auto results = m_model->match(m_model->index(0, 0), ThemeNameRole, m_selectedTheme); + if (results.count() == 1) { + return results.first().row(); + } + + return -1; +} + +QStringList IconModule::iconGroups() const +{ + return m_iconGroups; +} + +void IconModule::setPendingDeletion(int index, bool pending) +{ + QModelIndex idx = m_model->index(index, 0); + + m_model->setData(idx, pending, PendingDeletionRole); + + if (pending && selectedThemeIndex() == index) { + // move to the next non-pending theme + const auto nonPending = m_model->match(idx, PendingDeletionRole, false); + setSelectedTheme(nonPending.first().data(ThemeNameRole).toString()); + } + + setNeedsSave(true); +} + +int IconModule::iconSize(int group) const +{ + return m_iconSizes[group]; +} + +void IconModule::setIconSize(int group, int size) +{ + if (iconSize(group) == size) { + return; + } + + m_iconSizes[group] = size; + setNeedsSave(true); + m_iconSizesDirty = true; + emit iconSizesChanged(); +} + +QList IconModule::availableIconSizes(int group) const { - tab1->save(); - tab2->save(); + return KIconLoader::global()->theme()->querySizes(static_cast(group)); } +void IconModule::load() +{ + loadModel(); + loadIconSizes(); + setSelectedTheme(KIconTheme::current()); + setNeedsSave(false); + m_selectedThemeDirty = false; + m_iconSizesDirty = false; +} + +void IconModule::save() +{ + if (m_selectedThemeDirty) { + QProcess::startDetached(CMAKE_INSTALL_FULL_LIBEXECDIR "/plasma-changeicons", {m_selectedTheme}); + } + + if (m_iconSizesDirty || m_revertIconEffects) { + auto cfg = KSharedConfig::openConfig(); + for (int i = 0; i < m_iconGroups.count(); ++i) { + const QString &group = m_iconGroups.at(i); + KConfigGroup cg(cfg, group + QLatin1String("Icons")); + cg.writeEntry("Size", m_iconSizes.at(i), KConfig::Normal | KConfig::Global); + + if (m_revertIconEffects) { + cg.revertToDefault("Animated"); + + const QStringList states = { + QStringLiteral("Default"), + QStringLiteral("Active"), + QStringLiteral("Disabled") + }; + + const QStringList keys = { + QStringLiteral("Effect"), + QStringLiteral("Value"), + QStringLiteral("Color"), + QStringLiteral("Color2"), + QStringLiteral("SemiTransparent") + }; + + for (const QString &state : states) { + for (const QString &key : keys) { + cg.revertToDefault(state + key); + } + } + } + } + cfg->sync(); + } + + if (m_selectedThemeDirty || m_iconSizesDirty) { + exportToKDE4(); + } + + const auto pendingDeletions = m_model->match(m_model->index(0, 0), PendingDeletionRole, true, -1 /*all*/); + QVector persistentPendingDeletions; + // turn into persistent model index so we can delete as we go + std::transform(pendingDeletions.begin(), pendingDeletions.end(), + std::back_inserter(persistentPendingDeletions), [](const QModelIndex &idx) { + return QPersistentModelIndex(idx); + }); + + for (const QPersistentModelIndex &idx : persistentPendingDeletions) { + const QString themeName = idx.data(ThemeNameRole).toString(); + + Q_ASSERT(themeName != m_selectedTheme); + + KIconTheme theme(themeName); + auto *job = KIO::del(QUrl::fromLocalFile(theme.dir()), KIO::HideProgressInfo); + // needs to block for it to work on "OK" where the dialog (kcmshell) closes + job->exec(); + } + + KIconLoader::global()->newIconLoader(); + + // remove them in a separate loop after all the delete jobs for a smoother animation + for (const QPersistentModelIndex &idx : persistentPendingDeletions) { + m_model->removeRow(idx.row()); + } + + setNeedsSave(false); + m_selectedThemeDirty = false; + m_iconSizesDirty = false; + m_revertIconEffects = false; +} void IconModule::defaults() { - tab1->defaults(); - tab2->defaults(); + if (m_iconSizes != s_defaultIconSizes) { + m_iconSizes = s_defaultIconSizes; + emit iconSizesChanged(); + } + + auto setThemeIfAvailable = [this](const QString &themeName) { + const auto results = m_model->match(m_model->index(0, 0), ThemeNameRole, themeName); + if (results.isEmpty()) { + return false; + } + + setSelectedTheme(themeName); + return true; + }; + + if (!setThemeIfAvailable(KIconTheme::defaultThemeName())) { + setThemeIfAvailable(QStringLiteral("breeze")); + } + + m_revertIconEffects = true; +} + +void IconModule::loadModel() +{ + m_model->clear(); + + const QStringList themes = KIconTheme::list(); + + for (const QString &themeName : themes) { + KIconTheme theme(themeName); + if (!theme.isValid()) { + //qCWarning(KCM_ICONS) << "Not a valid theme" << themeName; + } + if (theme.isHidden()) { + continue; + } + + QStandardItem *item = new QStandardItem(theme.name()); + item->setData(themeName, ThemeNameRole); + item->setData(theme.description(), DescriptionRole); + item->setData(themeName != KIconTheme::defaultThemeName() + && QFileInfo(theme.dir()).isWritable(), RemovableRole); + item->setData(false, PendingDeletionRole); + + m_model->appendRow(item); + } +} + +void IconModule::loadIconSizes() +{ + auto cfg = KSharedConfig::openConfig(); + + QVector iconSizes(6, 0); // why doesn't KIconLoader::LastGroup - 1 work here?! + + int i = KIconLoader::FirstGroup; + for (const QString &group : qAsConst(m_iconGroups)) { + int size = KIconLoader::global()->theme()->defaultSize(static_cast(i)); + + KConfigGroup iconGroup(cfg, group + QLatin1String("Icons")); + size = iconGroup.readEntry("Size", size); + + iconSizes[i] = size; + + ++i; + } + + if (m_iconSizes != iconSizes) { + m_iconSizes = iconSizes; + emit iconSizesChanged(); + } } +void IconModule::getNewStuff(QQuickItem *ctx) +{ + if (!m_newStuffDialog) { + m_newStuffDialog = new KNS3::DownloadDialog(QStringLiteral("icons.knsrc")); + m_newStuffDialog->setWindowTitle(i18n("Download New Icon Themes")); + m_newStuffDialog->setWindowModality(Qt::WindowModal); + m_newStuffDialog->winId(); // so it creates the windowHandle(); + // TODO would be lovely to scroll to and select the newly installed scheme, if any + connect(m_newStuffDialog.data(), &KNS3::DownloadDialog::accepted, this, [this] { + if (m_newStuffDialog->changedEntries().isEmpty()) { + return; + } + + // reload the display icontheme items + KIconLoader::global()->newIconLoader(); + loadModel(); -void IconModule::moduleChanged(bool state) + emit selectedThemeIndexChanged(); + }); + } + + if (ctx && ctx->window()) { + m_newStuffDialog->windowHandle()->setTransientParent(ctx->window()); + } + + m_newStuffDialog->show(); +} + +void IconModule::installThemeFromFile(const QUrl &url) { - emit changed(state); + if (url.isLocalFile()) { + installThemeFile(url.toLocalFile()); + return; + } + + m_tempInstallFile.reset(new QTemporaryFile()); + if (!m_tempInstallFile->open()) { + emit showErrorMessage(i18n("Unable to create a temporary file.")); + m_tempInstallFile.reset(); + return; + } + + KIO::FileCopyJob *job = KIO::file_copy(url,QUrl::fromLocalFile(m_tempInstallFile->fileName()), + -1, KIO::Overwrite); + job->uiDelegate()->setAutoErrorHandlingEnabled(true); + + connect(job, &KIO::FileCopyJob::result, this, [this, url](KJob *job) { + if (job->error() != KJob::NoError) { + emit showErrorMessage(i18n("Unable to download the icon theme archive: %1", job->errorText())); + return; + } + + installThemeFile(m_tempInstallFile->fileName()); + m_tempInstallFile.reset(); + }); } -QString IconModule::quickHelp() const +void IconModule::installThemeFile(const QString &path) { - return i18n("

Icons

" - "This module allows you to choose the icons for your desktop.

" - "To choose an icon theme, click on its name and apply your choice by pressing the \"Apply\" button below. If you do not want to apply your choice you can press the \"Reset\" button to discard your changes.

" - "

By pressing the \"Install Theme File...\" button you can install your new icon theme by writing its location in the box or browsing to the location." - " Press the \"OK\" button to finish the installation.

" - "

The \"Remove Theme\" button will only be activated if you select a theme that you installed using this module." - " You are not able to remove globally installed themes here.

" - "

You can also specify effects that should be applied to the icons.

"); + const QStringList themesNames = findThemeDirs(path); + if (themesNames.isEmpty()) { + emit showErrorMessage(i18n("The file is not a valid icon theme archive.")); + return; + } + + if (!installThemes(themesNames, path)) { + emit showErrorMessage(i18n("A problem occurred during the installation process; however, most of the themes in the archive have been installed")); + return; + } + + emit showSuccessMessage(i18n("Theme installed successfully.")); + + KIconLoader::global()->newIconLoader(); + loadModel(); } -#include "main.moc" -#include "moc_main.cpp" +void IconModule::exportToKDE4() +{ + //TODO: killing the kde4 icon cache: possible? (kde4migration doesn't let access the cache folder) + Kdelibs4Migration migration; + QString configFilePath = migration.saveLocation("config"); + if (configFilePath.isEmpty()) { + return; + } + + configFilePath += QLatin1String("kdeglobals"); + + KSharedConfigPtr kglobalcfg = KSharedConfig::openConfig(QStringLiteral("kdeglobals")); + KConfig kde4config(configFilePath, KConfig::SimpleConfig); + + KConfigGroup kde4IconGroup(&kde4config, "Icons"); + kde4IconGroup.writeEntry("Theme", m_selectedTheme); + + //Synchronize icon effects + for (const QString &group : qAsConst(m_iconGroups)) { + const QString groupName = group + QLatin1String("Icons"); + KConfigGroup cg(kglobalcfg, groupName); + KConfigGroup cg2(&kde4config, groupName); + cg.copyTo(&cg2); + } + + kde4config.sync(); + + QProcess *cachePathProcess = new QProcess(this); + connect(cachePathProcess, QOverload::of(&QProcess::finished), this, + [cachePathProcess](int exitCode, QProcess::ExitStatus status) { + + if (status == QProcess::NormalExit && exitCode == 0) { + QString path = cachePathProcess->readAllStandardOutput().trimmed(); + path.append(QLatin1String("icon-cache.kcache")); + QFile::remove(path); + } + + //message kde4 apps that icon theme is changed + for (int i = 0; i < KIconLoader::LastGroup; i++) { + KIconLoader::emitChange(KIconLoader::Group(i)); + + QDBusMessage message = QDBusMessage::createSignal(QStringLiteral("/KGlobalSettings"), + QStringLiteral("org.kde.KGlobalSettings"), + QStringLiteral("notifyChange")); + message.setArguments({ + 4, // KGlobalSettings::IconChanged + KIconLoader::Group(i) + }); + QDBusConnection::sessionBus().send(message); + } + + cachePathProcess->deleteLater(); + }); + cachePathProcess->start(QStringLiteral("kde4-config --path cache")); +} + +QStringList IconModule::findThemeDirs(const QString &archiveName) +{ + QStringList foundThemes; + KTar archive(archiveName); + archive.open(QIODevice::ReadOnly); + const KArchiveDirectory *themeDir = archive.directory(); + + KArchiveEntry *possibleDir = nullptr; + KArchiveDirectory *subDir = nullptr; + + // iterate all the dirs looking for an index.theme or index.desktop file + const QStringList entries = themeDir->entries(); + for (const QString &entry : entries) { + possibleDir = const_cast(themeDir->entry(entry)); + if (!possibleDir->isDirectory()) { + continue; + } + + subDir = dynamic_cast(possibleDir); + if (!subDir) { + continue; + } + + if (subDir->entry(QStringLiteral("index.theme")) + || subDir->entry(QStringLiteral("index.desktop"))) { + foundThemes.append(subDir->name()); + } + } + + archive.close(); + return foundThemes; +} + +bool IconModule::installThemes(const QStringList &themes, const QString &archiveName) +{ + bool everythingOk = true; + const QString localThemesDir(QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + QLatin1String("/icons/./")); + + emit showProgress(i18n("Installing icon themes...")); + + KTar archive(archiveName); + archive.open(QIODevice::ReadOnly); + qApp->processEvents(QEventLoop::ExcludeUserInputEvents); + + const KArchiveDirectory *rootDir = archive.directory(); + + KArchiveDirectory *currentTheme = nullptr; + for (const QString &theme : themes) { + emit showProgress(i18n("Installing %1 theme...", theme)); + + qApp->processEvents(QEventLoop::ExcludeUserInputEvents); + + currentTheme = dynamic_cast(const_cast(rootDir->entry(theme))); + if (!currentTheme) { + // we tell back that something went wrong, but try to install as much + // as possible + everythingOk = false; + continue; + } + + currentTheme->copyTo(localThemesDir + theme); + } + + archive.close(); + + emit hideProgress(); + return everythingOk; +} + +QVariantList IconModule::previewIcons(const QString &themeName, int size, qreal dpr) const +{ + KIconTheme theme(themeName); + QSvgRenderer renderer; + + auto getBestIcon = [&](const QStringList &iconNames) { + const int iconSize = size * dpr; + + // not using initializer list as we want to unwrap inherits() + const QStringList themes = QStringList() << theme.internalName() << theme.inherits(); + for (const QString &themeName : themes) { + KIconTheme theme(themeName); + + for (const QString &iconName : iconNames) { + QString path = theme.iconPath(QStringLiteral("%1.png").arg(iconName), iconSize, KIconLoader::MatchBest); + if (!path.isEmpty()) { + QPixmap pixmap(path); + pixmap.setDevicePixelRatio(dpr); + return pixmap; + } + + //could not find the .png, try loading the .svg or .svgz + path = theme.iconPath(QStringLiteral("%1.svg").arg(iconName), iconSize, KIconLoader::MatchBest); + if (path.isEmpty()) { + path = theme.iconPath(QStringLiteral("%1.svgz").arg(iconName), iconSize, KIconLoader::MatchBest); + } + + if (path.isEmpty()) { + continue; + } + + if (!renderer.load(path)) { + continue; + } + + QPixmap pixmap(iconSize, iconSize); + pixmap.setDevicePixelRatio(dpr); + pixmap.fill(QColor(Qt::transparent)); + QPainter p(&pixmap); + p.setViewport(0, 0, size, size); + renderer.render(&p); + return pixmap; + } + } + + return QPixmap(); + }; + + const QVariantList pixmaps{ + getBestIcon({QStringLiteral("system-run"), QStringLiteral("exec")}), + getBestIcon({QStringLiteral("folder")}), + getBestIcon({QStringLiteral("document"), QStringLiteral("text-x-generic")}), + getBestIcon({QStringLiteral("user-trash"), QStringLiteral("user-trash-empty")}), + getBestIcon({QStringLiteral("system-help"), QStringLiteral("help-about"), QStringLiteral("help-contents")}), + getBestIcon({QStringLiteral("preferences-system"), QStringLiteral("systemsettings"), QStringLiteral("configure")}), + + getBestIcon({QStringLiteral("text-html")}), + getBestIcon({QStringLiteral("image-x-generic"), QStringLiteral("image-png"), QStringLiteral("image-jpeg")}), + getBestIcon({QStringLiteral("video-x-generic"), QStringLiteral("video-x-theora+ogg"), QStringLiteral("video-mp4")}), + getBestIcon({QStringLiteral("x-office-document")}), + getBestIcon({QStringLiteral("x-office-spreadsheet")}), + getBestIcon({QStringLiteral("x-office-presentation"), QStringLiteral("application-presentation")}), + + getBestIcon({QStringLiteral("user-home")}), + getBestIcon({QStringLiteral("user-desktop"), QStringLiteral("desktop")}), + getBestIcon({QStringLiteral("folder-image"), QStringLiteral("folder-images"), QStringLiteral("folder-pictures"), QStringLiteral("folder-picture")}), + getBestIcon({QStringLiteral("folder-documents")}), + getBestIcon({QStringLiteral("folder-download"), QStringLiteral("folder-downloads")}), + getBestIcon({QStringLiteral("folder-video"), QStringLiteral("folder-videos")}) + }; + + return pixmaps; +} + +#include "main.moc" diff --git a/kcms/icons/package/contents/ui/IconSizePopup.qml b/kcms/icons/package/contents/ui/IconSizePopup.qml new file mode 100644 --- /dev/null +++ b/kcms/icons/package/contents/ui/IconSizePopup.qml @@ -0,0 +1,169 @@ +/* + * Copyright 2018 Kai Uwe Broulik + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 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 14 of version 3 of the license. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +import QtQuick 2.7 +import QtQuick.Layouts 1.1 +import QtQuick.Controls 2.3 as QtControls +import org.kde.kirigami 2.4 as Kirigami + +QtControls.Popup { + id: iconSizePopup + + width: 400 + modal: true + + onOpened: { + // can we do this automatically with "focus: true" somewhere? + iconTypeList.forceActiveFocus(); + } + + onVisibleChanged: { + if (visible) { + iconSizeSlider.updateSizes(); + } + } + + Connections { + target: kcm + onIconSizesChanged: iconSizeSlider.updateSizes() + } + + RowLayout { + anchors.fill: parent + + ColumnLayout { + id: iconSizeColumn + Layout.fillWidth: true + + QtControls.ItemDelegate { // purely for metrics... + id: measureDelegate + visible: false + } + + QtControls.ScrollView { + id: iconTypeScroll + Layout.fillWidth: true + Layout.fillHeight: true + Layout.preferredHeight: iconTypeList.count * measureDelegate.height + 4 + activeFocusOnTab: false + + Component.onCompleted: iconTypeScroll.background.visible = true; + + ListView { + id: iconTypeList + activeFocusOnTab: true + keyNavigationEnabled: true + keyNavigationWraps: true + highlightMoveDuration: 0 + + model: kcm.iconGroups + + Keys.onLeftPressed: { + LayoutMirroring.enabled ? iconSizeSlider.increase() : iconSizeSlider.decrease() + iconSizeSlider.moved(); + } + Keys.onRightPressed: { + LayoutMirroring.enabled ? iconSizeSlider.decrease() : iconSizeSlider.increase() + iconSizeSlider.moved(); + } + + delegate: QtControls.ItemDelegate { + width: ListView.view.width + highlighted: ListView.isCurrentItem + text: [ + i18n("Desktop"), + i18n("Toolbar"), + i18n("Main Toolbar"), + i18n("Small Icons"), + i18n("Panel"), + i18n("Dialogs") + ][index] + + onClicked: { + ListView.view.currentIndex = index; + ListView.view.forceActiveFocus(); + } + } + } + } + + QtControls.Slider { + id: iconSizeSlider + readonly property var sizes: kcm.availableIconSizes(iconTypeList.currentIndex) + readonly property int currentSize: iconSizeSlider.sizes[iconSizeSlider.value] || 0 + + Layout.fillWidth: true + from: 0 + to: sizes.length - 1 + stepSize: 1.0 + snapMode: QtControls.Slider.SnapAlways + enabled: sizes.length > 0 + + onMoved: kcm.setIconSize(iconTypeList.currentIndex, currentSize) + + function updateSizes() { + // since the icon sizes are queried using invokables, always force an update when opening + // in case the user clicked Default or something + value = Qt.binding(function() { + var iconSize = kcm.iconSize(iconTypeList.currentIndex) + + // I have no idea what this code does but it works and is just copied from the old KCM + var index = -1; + var delta = 1000; + for (var i = 0, length = sizes.length; i < length; ++i) { + var dw = Math.abs(iconSize - sizes[i]); + if (dw < delta) { + delta = dw; + index = i; + } + } + + return index; + }); + } + } + } + + ColumnLayout { + Layout.fillHeight: true + Layout.maximumWidth: Math.round(parent.width / 2) + + Item { + Layout.fillWidth: true + Layout.fillHeight: true + clip: true + + Kirigami.Icon { + anchors.centerIn: parent + width: iconSizeSlider.currentSize + height: width + source: "folder" + } + } + + QtControls.Label { + id: iconSizeLabel + Layout.fillWidth: true + horizontalAlignment: Text.AlignHCenter + text: iconSizeSlider.currentSize + } + } + } +} diff --git a/kcms/icons/package/contents/ui/main.qml b/kcms/icons/package/contents/ui/main.qml new file mode 100644 --- /dev/null +++ b/kcms/icons/package/contents/ui/main.qml @@ -0,0 +1,278 @@ +/* + * Copyright 2018 Kai Uwe Broulik + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 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 14 of version 3 of the license. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +import QtQuick 2.7 +import QtQuick.Layouts 1.1 +import QtQuick.Window 2.2 +import QtQuick.Dialogs 1.0 as QtDialogs +import QtQuick.Controls 2.3 as QtControls +import org.kde.kirigami 2.4 as Kirigami +import org.kde.kcm 1.1 as KCM + +import org.kde.private.kcms.icons 1.0 as Private + +KCM.GridViewKCM { + KCM.ConfigModule.quickHelp: i18n("This module allows you to choose the icons for your desktop.") + + view.model: kcm.iconsModel + view.currentIndex: kcm.selectedThemeIndex + + DropArea { + anchors.fill: parent + onEntered: { + if (!drag.hasUrls) { + drag.accepted = false; + } + } + onDropped: kcm.installThemeFromFile(drop.urls[0]) + } + + view.remove: Transition { + ParallelAnimation { + NumberAnimation { property: "scale"; to: 0.5; duration: Kirigami.Units.longDuration } + NumberAnimation { property: "opacity"; to: 0.0; duration: Kirigami.Units.longDuration } + } + } + + view.removeDisplaced: Transition { + SequentialAnimation { + // wait for the "remove" animation to finish + PauseAnimation { duration: Kirigami.Units.longDuration } + NumberAnimation { properties: "x,y"; duration: Kirigami.Units.longDuration } + } + } + + view.delegate: KCM.GridDelegate { + id: delegate + + text: model.display + toolTip: model.description + + thumbnailAvailable: true + thumbnail: MouseArea { + id: thumbArea + + anchors.fill: parent + acceptedButtons: Qt.NoButton + hoverEnabled: true + + opacity: model.pendingDeletion ? 0.3 : 1 + Behavior on opacity { + NumberAnimation { duration: Kirigami.Units.longDuration } + } + + + Timer { + id: thumbTimer + interval: 1000 + repeat: true + running: thumbArea.containsMouse + onRunningChanged: { + if (!running) { + thumbFlow.currentPage = 0; + } + } + onTriggered: { + ++thumbFlow.currentPage; + if (thumbFlow.currentPage >= thumbFlow.pageCount) { + stop(); + } + } + } + + Flow { + id: thumbFlow + + property var previews: [] + + property int currentPage + readonly property int pageCount: Math.ceil(thumbRepeater.count / (thumbFlow.columns * thumbFlow.rows)) + + readonly property int iconWidth: Math.round(thumbArea.width / thumbFlow.columns) + readonly property int iconHeight: Math.round(thumbArea.height / thumbFlow.rows) + + readonly property int columns: 3 + readonly property int rows: 2 + + width: parent.width + y: -currentPage * iconHeight * rows + + Behavior on y { + NumberAnimation { duration: Kirigami.Units.longDuration } + } + + Component.onCompleted: { + // avoid reloading it when icon sizes or dpr changes on startup + Qt.callLater(function() { + previews = kcm.previewIcons(model.themeName, + Math.min(thumbArea.width / columns, thumbArea.height / rows), + Screen.devicePixelRatio) + }); + } + + Repeater { + id: thumbRepeater + model: thumbFlow.previews + + Kirigami.Icon { + width: thumbFlow.iconWidth + height: thumbFlow.iconHeight + // load on demand and avoid leaking a tiny corner of the icon + source: thumbFlow.y < 0 || index < (thumbFlow.columns * thumbFlow.rows) ? modelData : "" + } + } + } + } + + actions: [ + Kirigami.Action { + iconName: "edit-delete" + tooltip: i18n("Remove Icon Theme") + enabled: model.removable + visible: !model.pendingDeletion + onTriggered: kcm.setPendingDeletion(model.index, true); + }, + Kirigami.Action { + iconName: "edit-undo" + tooltip: i18n("Restore Icon Theme") + visible: model.pendingDeletion + onTriggered: kcm.setPendingDeletion(model.index, false); + } + ] + onClicked: { + if (!model.pendingDeletion) { + kcm.selectedTheme = model.themeName; + } + view.forceActiveFocus(); + } + } + + footer: ColumnLayout { + Kirigami.InlineMessage { + id: infoLabel + Layout.fillWidth: true + + showCloseButton: true + + Connections { + target: kcm + onShowSuccessMessage: { + infoLabel.type = Kirigami.MessageType.Positive; + infoLabel.text = message; + infoLabel.visible = true; + } + onShowErrorMessage: { + infoLabel.type = Kirigami.MessageType.Error; + infoLabel.text = message; + infoLabel.visible = true; + } + } + } + + RowLayout { + id: progressRow + visible: false + + QtControls.BusyIndicator { + id: progressBusy + } + + QtControls.Label { + id: progressLabel + Layout.fillWidth: true + textFormat: Text.PlainText + wrapMode: Text.WordWrap + } + + Connections { + target: kcm + onShowProgress: { + progressLabel.text = message; + progressBusy.running = true; + progressRow.visible = true; + } + onHideProgress: { + progressBusy.running = false; + progressRow.visible = false; + } + } + } + + RowLayout { + Layout.fillWidth: true + + QtControls.Button { + id: iconSizesButton + text: i18n("Configure Icon Sizes") + icon.name: "transform-scale" // proper icon? + checkable: true + checked: iconSizePopupLoader.item && iconSizePopupLoader.item.opened + onClicked: { + iconSizePopupLoader.active = true; + iconSizePopupLoader.item.open(); + } + } + + Item { + Layout.fillWidth: true + } + + QtControls.Button { + id: installFromFileButton + text: i18n("Install from File...") + icon.name: "document-import" + onClicked: fileDialogLoader.active = true + } + + QtControls.Button { + text: i18n("Get New Themes...") + icon.name: "get-hot-new-stuff" + onClicked: kcm.getNewStuff(this) + } + } + } + + Loader { + id: iconSizePopupLoader + active: false + sourceComponent: IconSizePopup { + parent: iconSizesButton + y: -height + } + } + + Loader { + id: fileDialogLoader + active: false + sourceComponent: QtDialogs.FileDialog { + visible: true + title: i18n("Open Theme") + folder: shortcuts.home + nameFilters: [ i18n("Theme Files (*.zip *.tar.gz *.tar.bz2)") ] + onAccepted: { + kcm.installThemeFromFile(fileUrls[0]) + fileDialogLoader.active = false + } + onRejected: { + fileDialogLoader.active = false + } + } + } +} diff --git a/kcms/icons/package/metadata.desktop b/kcms/icons/package/metadata.desktop new file mode 100644 --- /dev/null +++ b/kcms/icons/package/metadata.desktop @@ -0,0 +1,16 @@ +[Desktop Entry] +Name=Icons +Comment=Icon Theme + +Icon=preferences-desktop-icons +Type=Service +X-KDE-PluginInfo-Author=Kai Uwe Broulik +X-KDE-PluginInfo-Email=kde@privat.broulik.de +X-KDE-PluginInfo-License=GPL +X-KDE-PluginInfo-Name=kcm_icons +X-KDE-PluginInfo-Version= +X-KDE-PluginInfo-Website= +X-KDE-ServiceTypes=Plasma/Generic +X-Plasma-API=declarativeappletscript + +X-Plasma-MainScript=ui/main.qml diff --git a/kcms/icons/tests/CMakeLists.txt b/kcms/icons/tests/CMakeLists.txt deleted file mode 100644 --- a/kcms/icons/tests/CMakeLists.txt +++ /dev/null @@ -1,16 +0,0 @@ -set( EXECUTABLE_OUTPUT_PATH ${CMAKE_CURRENT_BINARY_DIR} ) - -include_directories( ${CMAKE_CURRENT_SOURCE_DIR}/.. ) - -set(testicons_SRCS testicons.cpp ${CMAKE_CURRENT_SOURCE_DIR}/../icons.cpp ) - -add_executable(testicons ${testicons_SRCS}) -ecm_mark_as_test(testicons) - -target_link_libraries(testicons - Qt5::Widgets - KF5::KCMUtils - KF5::I18n - KF5::KDELibs4Support - ${X11_LIBRARIES} -) diff --git a/kcms/icons/tests/testicons.cpp b/kcms/icons/tests/testicons.cpp deleted file mode 100644 --- a/kcms/icons/tests/testicons.cpp +++ /dev/null @@ -1,16 +0,0 @@ -/* Test program for icons setup module. */ - -#include -#include -#include "icons.h" - -int main(int argc, char **argv) -{ - QApplication app(argc, argv); - //KComponentData componentData(); - //KIconConfig *w = new KIconConfig(componentData); - QWidget *widget = new QWidget(); - KIconConfig *w = new KIconConfig(widget); - widget->show(); - return app.exec(); -}