Commit 9496728f authored by Kai Uwe Broulik's avatar Kai Uwe Broulik 🍇
Browse files

[Icon KCM] Port to new design

This completely drops the icon customization with icon effects and only retains the icon size settings.
Should there be any custom icon effects, pressing "Defaults" in the KCM will remove them.
I also couldn't find any trace of that "animations enabled" check box it used to have.
It adds drag and drop support for installing archives as themes. It can also download them from remote location
when dropped from e.g. a browser.

Installing theme files actually never worked in Plasma 5 as it got broken in the port from KIO NetAccess
to storedGet.
An animated preview is also added on hover showing a common selection of icons.

Implements T7262

BUG: 367619
BUG: 334301
CCBUG: 163992
FIXED-IN: 5.13.0

Differential Revision: https://phabricator.kde.org/D12459
parent 9961a720
# 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 iconsmodel.cpp)
add_library(kcm_icons MODULE ${kcm_icons_PART_SRCS})
......@@ -18,24 +15,21 @@ target_link_libraries(kcm_icons
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)
#! /usr/bin/env bash
$XGETTEXT *.cpp -o $podir/kcm5_icons.pot
$XGETTEXT `find . -name "*.cpp" -o -name "*.qml"` -o $podir/kcm_icons.pot
This diff is collapsed.
/* vi: ts=8 sts=4 sw=4
*
* This file is part of the KDE project, module kcmdisplay.
* Copyright (C) 2000 Geert Jansen <jansen@kde.org>
* with minor additions and based on ideas from
* Torsten Rahn <torsten@kde.org>
* KDE Frameworks 5 port Copyright (C) 2013 Jonathan Riddell <jr@jriddell.org>
*
* 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 <QColor>
#include <QImage>
#include <QDialog>
#include <KCModule>
#include <KSharedConfig>
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<int> 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
/*
* Copyright (c) 1999 Matthias Hoelzer-Kluepfel <hoelzer@kde.org>
* Copyright (c) 2000 Antonio Larrosa <larrosa@kde.org>
* Copyright (C) 2000 Geert Jansen <jansen@kde.org>
* KDE Frameworks 5 port Copyright (C) 2013 Jonathan Riddell <jr@jriddell.org>
* Copyright (C) 2018 Kai Uwe Broulik <kde@privat.broulik.de>
*
* Requires the Qt widget libraries, available at no cost at
* http://www.troll.no/
*
* 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 "iconsmodel.h"
#include <QFileIconProvider>
#include <KIconTheme>
IconsModel::IconsModel(QObject *parent) : QAbstractListModel(parent)
{
}
IconsModel::~IconsModel() = default;
int IconsModel::rowCount(const QModelIndex &parent) const
{
if (parent.isValid()) {
return 0;
}
return m_data.count();
}
QVariant IconsModel::data(const QModelIndex &index, int role) const
{
if (!index.isValid() || index.row() >= m_data.count()) {
return QVariant();
}
const auto &item = m_data.at(index.row());
switch (role) {
case Qt::DisplayRole: return item.display;
case ThemeNameRole: return item.themeName;
case DescriptionRole: return item.description;
case RemovableRole: return item.removable;
case PendingDeletionRole: return item.pendingDeletion;
}
return QVariant();
}
bool IconsModel::setData(const QModelIndex &index, const QVariant &value, int role)
{
if (!index.isValid() || index.row() >= m_data.count()) {
return false;
}
if (role == PendingDeletionRole) {
auto &item = m_data[index.row()];
const bool pendingDeletion = value.toBool();
if (item.pendingDeletion != pendingDeletion) {
item.pendingDeletion = pendingDeletion;
emit dataChanged(index, index, {PendingDeletionRole});
// move to the next non-pending theme
const auto nonPending = match(index, PendingDeletionRole, false);
if (!nonPending.isEmpty()) {
setSelectedTheme(nonPending.first().data(ThemeNameRole).toString());
}
emit pendingDeletionsChanged();
return true;
}
}
return false;
}
QHash<int, QByteArray> IconsModel::roleNames() const
{
return {
{Qt::DisplayRole, QByteArrayLiteral("display")},
{DescriptionRole, QByteArrayLiteral("description")},
{ThemeNameRole, QByteArrayLiteral("themeName")},
{RemovableRole, QByteArrayLiteral("removable")},
{PendingDeletionRole, QByteArrayLiteral("pendingDeletion")}
};
}
QString IconsModel::selectedTheme() const
{
return m_selectedTheme;
}
void IconsModel::setSelectedTheme(const QString &theme)
{
if (m_selectedTheme == theme) {
return;
}
const bool firstTime = m_selectedTheme.isNull();
m_selectedTheme = theme;
if (!firstTime) {
emit selectedThemeChanged();
}
emit selectedThemeIndexChanged();
}
int IconsModel::selectedThemeIndex() const
{
auto it = std::find_if(m_data.begin(), m_data.end(), [this](const IconsModelData &item) {
return item.themeName == m_selectedTheme;
});
if (it != m_data.end()) {
return std::distance(m_data.begin(), it);
}
return -1;
}
void IconsModel::load()
{
beginResetModel();
const int oldCount = m_data.count();
m_data.clear();
const QStringList themes = KIconTheme::list();
m_data.reserve(themes.count());
for (const QString &themeName : themes) {
KIconTheme theme(themeName);
if (!theme.isValid()) {
//qCWarning(KCM_ICONS) << "Not a valid theme" << themeName;
}
if (theme.isHidden()) {
continue;
}
IconsModelData item{
theme.name(),
themeName,
theme.description(),
themeName != KIconTheme::defaultThemeName()
&& QFileInfo(theme.dir()).isWritable(),
false // pending deletion
};
m_data.append(item);
}
endResetModel();
// an item might have been added before the currently selected one
if (oldCount != m_data.count()) {
emit selectedThemeIndexChanged();
}
}
QStringList IconsModel::pendingDeletions() const
{
QStringList pendingDeletions;
for (const auto &item : m_data) {
if (item.pendingDeletion) {
pendingDeletions.append(item.themeName);
}
}
return pendingDeletions;
}
void IconsModel::removeItemsPendingDeletion()
{
for (int i = m_data.count() - 1; i >= 0; --i) {
if (m_data.at(i).pendingDeletion) {
beginRemoveRows(QModelIndex(), i, i);
m_data.remove(i);
endRemoveRows();
}
}
}
#include "iconsmodel.moc"
/**
* Copyright (c) 2000 Antonio Larrosa <larrosa@kde.org>
/*
* Copyright (c) 1999 Matthias Hoelzer-Kluepfel <hoelzer@kde.org>
* KDE Frameworks 5 port Copyright (C) 2013 Jonathan Riddell <jr@jriddell.org>
* Copyright (c) 2018 Kai Uwe Broulik <kde@privat.broulik.de>
*
* Requires the Qt widget libraries, available at no cost at
* http://www.troll.no/
*
* 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
......@@ -17,58 +21,64 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef ICONTHEMES_H
#define ICONTHEMES_H
#include <KCModule>
#include <QLabel>
#include <QLoggingCategory>
#pragma once
class QStringList;
class QPushButton;
class QTreeWidget;
class QTreeWidgetItem;
#include <QAbstractListModel>
#include <QString>
#include <QVector>
Q_DECLARE_LOGGING_CATEGORY(KCM_ICONS)
struct IconsModelData
{
QString display;
QString themeName;
QString description;
bool removable;
bool pendingDeletion;
};
Q_DECLARE_TYPEINFO(IconsModelData, Q_MOVABLE_TYPE);
class IconThemesConfig : public KCModule
class IconsModel : public QAbstractListModel
{
Q_OBJECT
Q_OBJECT
Q_PROPERTY(QString selectedTheme READ selectedTheme WRITE setSelectedTheme NOTIFY selectedThemeChanged)
Q_PROPERTY(int selectedThemeIndex READ selectedThemeIndex NOTIFY selectedThemeIndexChanged)
public:
IconThemesConfig(QWidget *parent);
~IconThemesConfig() override;
IconsModel(QObject *parent);
~IconsModel() override;
void loadThemes();
bool installThemes(const QStringList &themes, const QString &archiveName);
QStringList findThemeDirs(const QString &archiveName);
enum Roles {
ThemeNameRole = Qt::UserRole + 1,
DescriptionRole,
RemovableRole,
PendingDeletionRole
};
void updateRemoveButton();
int rowCount(const QModelIndex &parent) const override;
QVariant data(const QModelIndex &index, int role) const;
bool setData(const QModelIndex &index, const QVariant &value, int role) override;
QHash<int, QByteArray> roleNames() const override;
void load() override;
void save() override;
void defaults() override;
QString selectedTheme() const;
void setSelectedTheme(const QString &theme);
int buttons();
int selectedThemeIndex() const;
protected Q_SLOTS:
void themeSelected(QTreeWidgetItem *item);
void installNewTheme();
void getNewTheme();
void removeSelectedTheme();
QStringList pendingDeletions() const;
void removeItemsPendingDeletion();
private:
QTreeWidgetItem *iconThemeItem(const QString &name);
void load();
QTreeWidget *m_iconThemes;
QPushButton *m_removeButton;
signals:
void selectedThemeChanged();
void selectedThemeIndexChanged();
QLabel *m_previewExec;
QLabel *m_previewFolder;
QLabel *m_previewDocument;
QTreeWidgetItem *m_defaultTheme;
bool m_bChanged;
};
void pendingDeletionsChanged();
#endif // ICONTHEMES_H
private:
QString m_selectedTheme;
QVector<IconsModelData> m_data;
};
/**
* Copyright (c) 2000 Antonio Larrosa <larrosa@kde.org>
* KDE Frameworks 5 port Copyright (C) 2013 Jonathan Riddell <jr@jriddell.org>
*
* 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 <config-runtime.h>
#include "config.h"
#include <stdlib.h>
#include <unistd.h>
#include <QFileInfo>
#include <QLabel>
#include <QPixmap>
#include <QVBoxLayout>
#include <QFrame>
#include <QHBoxLayout>
#include <QTreeWidget>
#include <QPainter>
#include <QSvgRenderer>
#include <QLoggingCategory>
#include <QPushButton>
#include <QProgressDialog>
#include <qprogressbar.h>
#include <QStandardPaths>
#include <QUrl>
#include <qtemporaryfile.h>
#include <QApplication>
#include <QProcess>
#include <KBuildSycocaProgressDialog>
#include <KLocalizedString>
#include <KSharedDataCache>
#include <KIconTheme>
#include <KConfig>
#include <KConfigGroup>
#include <KSharedConfig>
#include <KNS3/DownloadDialog>
#include <KTar>
#include <KMessageBox>
#include <KIconLoader>
#include <KIO/Job>
#include <KIO/DeleteJob>
#include <KUrlRequesterDialog>
#include <KJobWidgets>
#include <KTar>
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 );