Advance Wayland and KDE package bring-up
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
This commit is contained in:
@@ -0,0 +1,97 @@
|
||||
add_library(KF6IconWidgets)
|
||||
add_library(KF6::IconWidgets ALIAS KF6IconWidgets)
|
||||
|
||||
set_target_properties(KF6IconWidgets PROPERTIES
|
||||
VERSION ${KICONTHEMES_VERSION}
|
||||
SOVERSION ${KICONTHEMES_SOVERSION}
|
||||
EXPORT_NAME IconWidgets
|
||||
)
|
||||
|
||||
target_sources(KF6IconWidgets PRIVATE
|
||||
kiconbutton.cpp
|
||||
kiconbutton.h
|
||||
kicondialog.cpp
|
||||
kicondialog.h
|
||||
kicondialogmodel_p.h
|
||||
kicondialog_p.h
|
||||
kpixmapsequenceloader.h
|
||||
kpixmapsequenceloader.cpp
|
||||
)
|
||||
|
||||
ki18n_wrap_ui(KF6IconWidgets kicondialog.ui)
|
||||
|
||||
ecm_generate_export_header(KF6IconWidgets
|
||||
BASE_NAME KIconWidgets
|
||||
GROUP_BASE_NAME KF
|
||||
VERSION ${KF_VERSION}
|
||||
USE_VERSION_HEADER
|
||||
VERSION_BASE_NAME KIconThemes
|
||||
DEPRECATED_BASE_VERSION 0
|
||||
DEPRECATION_VERSIONS
|
||||
EXCLUDE_DEPRECATED_BEFORE_AND_AT ${EXCLUDE_DEPRECATED_BEFORE_AND_AT}
|
||||
)
|
||||
|
||||
target_include_directories(KF6IconWidgets INTERFACE "$<INSTALL_INTERFACE:${KDE_INSTALL_INCLUDEDIR_KF}/KIconWidgets>")
|
||||
|
||||
target_link_libraries(KF6IconWidgets
|
||||
PUBLIC
|
||||
Qt6::Widgets
|
||||
KF6::IconThemes
|
||||
PRIVATE
|
||||
Qt6::GuiPrivate
|
||||
Qt6::Svg
|
||||
KF6::I18n # for i18n in KIconDialog
|
||||
KF6::ConfigGui # for KStandardActions
|
||||
KF6::WidgetsAddons # for KPixmapSequence
|
||||
)
|
||||
|
||||
ecm_generate_headers(KIconWidgets_HEADERS
|
||||
HEADER_NAMES
|
||||
KIconButton
|
||||
KIconDialog
|
||||
KPixmapSequenceLoader
|
||||
|
||||
REQUIRED_HEADERS KIconWidgets_HEADERS
|
||||
)
|
||||
|
||||
install(TARGETS KF6IconWidgets EXPORT KF6IconThemesTargets ${KF_INSTALL_TARGETS_DEFAULT_ARGS})
|
||||
|
||||
install(FILES
|
||||
${CMAKE_CURRENT_BINARY_DIR}/kiconwidgets_export.h
|
||||
${KIconWidgets_HEADERS}
|
||||
DESTINATION ${KDE_INSTALL_INCLUDEDIR_KF}/KIconWidgets COMPONENT Devel
|
||||
)
|
||||
|
||||
if(BUILD_DESIGNERPLUGIN)
|
||||
add_subdirectory(designer)
|
||||
endif()
|
||||
|
||||
if(BUILD_QCH)
|
||||
ecm_add_qch(
|
||||
KF6IconWidgets_QCH
|
||||
NAME KIconWidgets
|
||||
BASE_NAME KF6IconWidgets
|
||||
VERSION ${KF_VERSION}
|
||||
ORG_DOMAIN org.kde
|
||||
SOURCES # using only public headers, to cover only public API
|
||||
${KIconWidgets_HEADERS}
|
||||
MD_MAINPAGE "${CMAKE_SOURCE_DIR}/README.md"
|
||||
IMAGE_DIRS "${CMAKE_SOURCE_DIR}/docs/pics"
|
||||
LINK_QCHS
|
||||
Qt6Widgets_QCH
|
||||
INCLUDE_DIRS
|
||||
${CMAKE_CURRENT_BINARY_DIR}
|
||||
BLANK_MACROS
|
||||
KICONWIDGETS_EXPORT
|
||||
KICONWIDGETS_DEPRECATED
|
||||
KICONWIDGETS_DEPRECATED_EXPORT
|
||||
"KICONWIDGETS_DEPRECATED_VERSION(x, y, t)"
|
||||
"KICONWIDGETS_DEPRECATED_VERSION_BELATED(x, y, xt, yt, t)"
|
||||
"KICONWIDGETS_ENUMERATOR_DEPRECATED_VERSION(x, y, t)"
|
||||
"KICONWIDGETS_ENUMERATOR_DEPRECATED_VERSION_BELATED(x, y, xt, yt, t)"
|
||||
TAGFILE_INSTALL_DESTINATION ${KDE_INSTALL_QTQCHDIR}
|
||||
QCH_INSTALL_DESTINATION ${KDE_INSTALL_QTQCHDIR}
|
||||
COMPONENT Devel
|
||||
)
|
||||
endif()
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
include(ECMAddQtDesignerPlugin)
|
||||
|
||||
ecm_qtdesignerplugin_widget(KIconButton
|
||||
TOOLTIP "Button for selecting an icon (KF6)"
|
||||
GROUP "Buttons (KF6)"
|
||||
)
|
||||
|
||||
ecm_add_qtdesignerplugin(kiconthemeswidgets
|
||||
NAME KIconThemesWidgets
|
||||
OUTPUT_NAME kiconthemes6widgets
|
||||
WIDGETS
|
||||
KIconButton
|
||||
LINK_LIBRARIES
|
||||
KF6::IconWidgets
|
||||
INSTALL_DESTINATION "${KDE_INSTALL_QTPLUGINDIR}/designer"
|
||||
COMPONENT Devel
|
||||
)
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 1.1 KiB |
@@ -0,0 +1,188 @@
|
||||
/*
|
||||
|
||||
This file is part of the KDE project, module kfile.
|
||||
SPDX-FileCopyrightText: 2000 Geert Jansen <jansen@kde.org>
|
||||
SPDX-FileCopyrightText: 2000 Kurt Granroth <granroth@kde.org>
|
||||
SPDX-FileCopyrightText: 1997 Christoph Neerfeld <chris@kde.org>
|
||||
SPDX-FileCopyrightText: 2002 Carsten Pfeiffer <pfeiffer@kde.org>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.0-only
|
||||
*/
|
||||
|
||||
#include "kiconbutton.h"
|
||||
|
||||
#include <QFileInfo>
|
||||
|
||||
#include <KLocalizedString>
|
||||
|
||||
#include "kicondialog.h"
|
||||
|
||||
class KIconButtonPrivate
|
||||
{
|
||||
public:
|
||||
KIconButtonPrivate(KIconButton *qq, KIconLoader *loader);
|
||||
~KIconButtonPrivate();
|
||||
|
||||
KIconDialog *dialog();
|
||||
|
||||
// slots
|
||||
void _k_slotChangeIcon();
|
||||
void _k_newIconName(const QString &);
|
||||
|
||||
KIconButton *q;
|
||||
|
||||
int iconSize;
|
||||
int buttonIconSize;
|
||||
bool m_bStrictIconSize;
|
||||
|
||||
bool mbUser;
|
||||
KIconLoader::Group mGroup;
|
||||
KIconLoader::Context mContext;
|
||||
|
||||
QString mIcon;
|
||||
KIconDialog *mpDialog;
|
||||
KIconLoader *mpLoader;
|
||||
};
|
||||
|
||||
/*
|
||||
* KIconButton: A "choose icon" pushbutton.
|
||||
*/
|
||||
|
||||
KIconButton::KIconButton(QWidget *parent)
|
||||
: QPushButton(parent)
|
||||
, d(new KIconButtonPrivate(this, KIconLoader::global()))
|
||||
{
|
||||
QPushButton::setIconSize(QSize(48, 48));
|
||||
}
|
||||
|
||||
KIconButtonPrivate::KIconButtonPrivate(KIconButton *qq, KIconLoader *loader)
|
||||
: q(qq)
|
||||
{
|
||||
m_bStrictIconSize = false;
|
||||
iconSize = 0; // let KIconLoader choose the default
|
||||
buttonIconSize = -1; // When buttonIconSize is -1, iconSize will be used for the button
|
||||
|
||||
mGroup = KIconLoader::Desktop;
|
||||
mContext = KIconLoader::Application;
|
||||
mbUser = false;
|
||||
|
||||
mpLoader = loader;
|
||||
mpDialog = nullptr;
|
||||
QObject::connect(q, &KIconButton::clicked, q, [this]() {
|
||||
_k_slotChangeIcon();
|
||||
});
|
||||
|
||||
q->setToolTip(i18nc("@info:tooltip", "Select Icon…"));
|
||||
}
|
||||
|
||||
KIconButtonPrivate::~KIconButtonPrivate()
|
||||
{
|
||||
delete mpDialog;
|
||||
}
|
||||
|
||||
KIconDialog *KIconButtonPrivate::dialog()
|
||||
{
|
||||
if (!mpDialog) {
|
||||
mpDialog = new KIconDialog(q);
|
||||
QObject::connect(mpDialog, &KIconDialog::newIconName, q, [this](const QString &iconName) {
|
||||
_k_newIconName(iconName);
|
||||
});
|
||||
}
|
||||
|
||||
return mpDialog;
|
||||
}
|
||||
|
||||
KIconButton::~KIconButton() = default;
|
||||
|
||||
void KIconButton::setStrictIconSize(bool b)
|
||||
{
|
||||
d->m_bStrictIconSize = b;
|
||||
}
|
||||
|
||||
bool KIconButton::strictIconSize() const
|
||||
{
|
||||
return d->m_bStrictIconSize;
|
||||
}
|
||||
|
||||
void KIconButton::setIconSize(int size)
|
||||
{
|
||||
if (d->buttonIconSize == -1) {
|
||||
QPushButton::setIconSize(QSize(size, size));
|
||||
}
|
||||
|
||||
d->iconSize = size;
|
||||
}
|
||||
|
||||
int KIconButton::iconSize() const
|
||||
{
|
||||
return d->iconSize;
|
||||
}
|
||||
|
||||
void KIconButton::setButtonIconSize(int size)
|
||||
{
|
||||
QPushButton::setIconSize(QSize(size, size));
|
||||
d->buttonIconSize = size;
|
||||
}
|
||||
|
||||
int KIconButton::buttonIconSize() const
|
||||
{
|
||||
return QPushButton::iconSize().height();
|
||||
}
|
||||
|
||||
void KIconButton::setIconType(KIconLoader::Group group, KIconLoader::Context context, bool user)
|
||||
{
|
||||
d->mGroup = group;
|
||||
d->mContext = context;
|
||||
d->mbUser = user;
|
||||
}
|
||||
|
||||
void KIconButton::setIcon(const QString &icon)
|
||||
{
|
||||
d->mIcon = icon;
|
||||
setIcon(QIcon::fromTheme(d->mIcon));
|
||||
|
||||
if (d->mbUser) {
|
||||
d->dialog()->setCustomLocation(QFileInfo(d->mpLoader->iconPath(d->mIcon, d->mGroup, true)).absolutePath());
|
||||
}
|
||||
}
|
||||
|
||||
void KIconButton::setIcon(const QIcon &icon)
|
||||
{
|
||||
QPushButton::setIcon(icon);
|
||||
}
|
||||
|
||||
void KIconButton::resetIcon()
|
||||
{
|
||||
d->mIcon.clear();
|
||||
setIcon(QIcon());
|
||||
}
|
||||
|
||||
const QString &KIconButton::icon() const
|
||||
{
|
||||
return d->mIcon;
|
||||
}
|
||||
|
||||
void KIconButtonPrivate::_k_slotChangeIcon()
|
||||
{
|
||||
dialog()->setup(mGroup, mContext, m_bStrictIconSize, iconSize, mbUser);
|
||||
dialog()->setSelectedIcon(mIcon);
|
||||
dialog()->showDialog();
|
||||
}
|
||||
|
||||
void KIconButtonPrivate::_k_newIconName(const QString &name)
|
||||
{
|
||||
if (name.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
q->setIcon(QIcon::fromTheme(name));
|
||||
mIcon = name;
|
||||
|
||||
if (mbUser) {
|
||||
mpDialog->setCustomLocation(QFileInfo(mpLoader->iconPath(mIcon, mGroup, true)).absolutePath());
|
||||
}
|
||||
|
||||
Q_EMIT q->iconChanged(name);
|
||||
}
|
||||
|
||||
#include "moc_kiconbutton.cpp"
|
||||
@@ -0,0 +1,123 @@
|
||||
/*
|
||||
|
||||
This file is part of the KDE project, module kfile.
|
||||
SPDX-FileCopyrightText: 2000 Geert Jansen <jansen@kde.org>
|
||||
SPDX-FileCopyrightText: 2000 Kurt Granroth <granroth@kde.org>
|
||||
SPDX-FileCopyrightText: 1997 Christoph Neerfeld <chris@kde.org>
|
||||
SPDX-FileCopyrightText: 2002 Carsten Pfeiffer <pfeiffer@kde.org>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.0-only
|
||||
*/
|
||||
|
||||
#ifndef KICONBUTTON_H
|
||||
#define KICONBUTTON_H
|
||||
|
||||
#include "kiconwidgets_export.h"
|
||||
|
||||
#include <QPushButton>
|
||||
#include <memory>
|
||||
|
||||
#include <kiconloader.h>
|
||||
|
||||
/**
|
||||
* @class KIconButton kiconbutton.h KIconButton
|
||||
*
|
||||
* A pushbutton for choosing an icon. Pressing on the button will open a
|
||||
* KIconDialog for the user to select an icon. The current icon will be
|
||||
* displayed on the button.
|
||||
*
|
||||
* @see KIconDialog
|
||||
* @short A push button that allows selection of an icon.
|
||||
*/
|
||||
class KICONWIDGETS_EXPORT KIconButton : public QPushButton
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(QString icon READ icon WRITE setIcon RESET resetIcon NOTIFY iconChanged USER true)
|
||||
Q_PROPERTY(int iconSize READ iconSize WRITE setIconSize)
|
||||
Q_PROPERTY(bool strictIconSize READ strictIconSize WRITE setStrictIconSize)
|
||||
|
||||
public:
|
||||
/**
|
||||
* Constructs a KIconButton using the global icon loader.
|
||||
*
|
||||
* @param parent The parent widget.
|
||||
*/
|
||||
explicit KIconButton(QWidget *parent = nullptr);
|
||||
|
||||
/**
|
||||
* Destructs the button.
|
||||
*/
|
||||
~KIconButton() override;
|
||||
|
||||
/**
|
||||
* Sets a strict icon size policy for allowed icons. When true,
|
||||
* only icons of the specified group's size in setIconType() are allowed,
|
||||
* and only icons of that size will be shown in the icon dialog.
|
||||
*/
|
||||
void setStrictIconSize(bool b);
|
||||
/**
|
||||
* Returns true if a strict icon size policy is set.
|
||||
*/
|
||||
bool strictIconSize() const;
|
||||
|
||||
/**
|
||||
* Sets the icon group and context. Use KIconLoader::NoGroup if you want to
|
||||
* allow icons for any group in the given context.
|
||||
*/
|
||||
void setIconType(KIconLoader::Group group, KIconLoader::Context context, bool user = false);
|
||||
|
||||
/**
|
||||
* Sets the button's initial icon.
|
||||
*/
|
||||
void setIcon(const QString &icon);
|
||||
|
||||
void setIcon(const QIcon &icon);
|
||||
|
||||
/**
|
||||
* Resets the icon (reverts to an empty button).
|
||||
*/
|
||||
void resetIcon();
|
||||
|
||||
/**
|
||||
* Returns the name of the selected icon.
|
||||
*/
|
||||
const QString &icon() const;
|
||||
|
||||
/**
|
||||
* Sets the size of the icon to be shown / selected.
|
||||
* @see KIconLoader::StdSizes
|
||||
* @see iconSize
|
||||
*/
|
||||
void setIconSize(int size);
|
||||
/**
|
||||
* Returns the icon size set via setIconSize() or 0, if the default
|
||||
* icon size will be used.
|
||||
*/
|
||||
int iconSize() const;
|
||||
|
||||
/**
|
||||
* Sets the size of the icon to be shown on the button.
|
||||
* @see KIconLoader::StdSizes
|
||||
* @see buttonIconSize
|
||||
* @since 4.1
|
||||
*/
|
||||
void setButtonIconSize(int size);
|
||||
/**
|
||||
* Returns the button's icon size.
|
||||
* @since 4.1
|
||||
*/
|
||||
int buttonIconSize() const;
|
||||
|
||||
Q_SIGNALS:
|
||||
/**
|
||||
* Emitted when the icon has changed.
|
||||
*/
|
||||
void iconChanged(const QString &icon);
|
||||
|
||||
private:
|
||||
std::unique_ptr<class KIconButtonPrivate> const d;
|
||||
|
||||
Q_DISABLE_COPY(KIconButton)
|
||||
};
|
||||
|
||||
#endif // KICONBUTTON_H
|
||||
@@ -0,0 +1,754 @@
|
||||
/*
|
||||
|
||||
This file is part of the KDE project, module kfile.
|
||||
SPDX-FileCopyrightText: 2000 Geert Jansen <jansen@kde.org>
|
||||
SPDX-FileCopyrightText: 2000 Kurt Granroth <granroth@kde.org>
|
||||
SPDX-FileCopyrightText: 1997 Christoph Neerfeld <chris@kde.org>
|
||||
SPDX-FileCopyrightText: 2002 Carsten Pfeiffer <pfeiffer@kde.org>
|
||||
SPDX-FileCopyrightText: 2021 Kai Uwe Broulik <kde@broulik.de>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.0-only
|
||||
*/
|
||||
|
||||
#include "kicondialog.h"
|
||||
#include "kicondialog_p.h"
|
||||
#include "kicondialogmodel_p.h"
|
||||
|
||||
#include <KLazyLocalizedString>
|
||||
#include <KLocalizedString>
|
||||
#include <KStandardActions>
|
||||
|
||||
#include <QAbstractListModel>
|
||||
#include <QActionGroup>
|
||||
#include <QApplication>
|
||||
#include <QComboBox>
|
||||
#include <QDialogButtonBox>
|
||||
#include <QFileInfo>
|
||||
#include <QGraphicsOpacityEffect>
|
||||
#include <QLabel>
|
||||
#include <QList>
|
||||
#include <QMenu>
|
||||
#include <QPainter>
|
||||
#include <QScrollBar>
|
||||
#include <QSortFilterProxyModel>
|
||||
#include <QStandardItemModel> // for manipulatig QComboBox
|
||||
#include <QStandardPaths>
|
||||
#include <QSvgRenderer>
|
||||
|
||||
#include <algorithm>
|
||||
#include <math.h>
|
||||
|
||||
static const int s_edgePad = 3;
|
||||
|
||||
class KIconDialogSortFilterProxyModel : public QSortFilterProxyModel
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit KIconDialogSortFilterProxyModel(QObject *parent);
|
||||
|
||||
enum SymbolicIcons { AllSymbolicIcons, OnlySymbolicIcons, NoSymbolicIcons };
|
||||
|
||||
void setSymbolicIcons(SymbolicIcons symbolicIcons);
|
||||
void setHasSymbolicIcon(bool hasSymbolicIcon);
|
||||
|
||||
protected:
|
||||
bool filterAcceptsRow(int source_row, const QModelIndex &source_parent) const override;
|
||||
|
||||
private:
|
||||
SymbolicIcons m_symbolicIcons = AllSymbolicIcons;
|
||||
bool m_hasSymbolicIcon = false;
|
||||
};
|
||||
|
||||
KIconDialogSortFilterProxyModel::KIconDialogSortFilterProxyModel(QObject *parent)
|
||||
: QSortFilterProxyModel(parent)
|
||||
{
|
||||
}
|
||||
|
||||
void KIconDialogSortFilterProxyModel::setSymbolicIcons(SymbolicIcons symbolicIcons)
|
||||
{
|
||||
if (m_symbolicIcons == symbolicIcons) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_symbolicIcons = symbolicIcons;
|
||||
invalidateFilter();
|
||||
}
|
||||
|
||||
void KIconDialogSortFilterProxyModel::setHasSymbolicIcon(bool hasSymbolicIcon)
|
||||
{
|
||||
if (m_hasSymbolicIcon == hasSymbolicIcon) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_hasSymbolicIcon = hasSymbolicIcon;
|
||||
invalidateFilter();
|
||||
}
|
||||
|
||||
bool KIconDialogSortFilterProxyModel::filterAcceptsRow(int source_row, const QModelIndex &source_parent) const
|
||||
{
|
||||
if (m_hasSymbolicIcon) {
|
||||
if (m_symbolicIcons == OnlySymbolicIcons || m_symbolicIcons == NoSymbolicIcons) {
|
||||
const QString display = sourceModel()->index(source_row, 0, source_parent).data(Qt::DisplayRole).toString();
|
||||
const bool isSymbolic = display.endsWith(KIconDialogModel::symbolicSuffix());
|
||||
if ((m_symbolicIcons == OnlySymbolicIcons && !isSymbolic) || (m_symbolicIcons == NoSymbolicIcons && isSymbolic)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return QSortFilterProxyModel::filterAcceptsRow(source_row, source_parent);
|
||||
}
|
||||
|
||||
KIconDialogModel::KIconDialogModel(KIconLoader *loader, QObject *parent)
|
||||
: QAbstractListModel(parent)
|
||||
, m_loader(loader)
|
||||
{
|
||||
}
|
||||
|
||||
KIconDialogModel::~KIconDialogModel() = default;
|
||||
|
||||
qreal KIconDialogModel::devicePixelRatio() const
|
||||
{
|
||||
return m_dpr;
|
||||
}
|
||||
|
||||
void KIconDialogModel::setDevicePixelRatio(qreal dpr)
|
||||
{
|
||||
m_dpr = dpr;
|
||||
}
|
||||
|
||||
QSize KIconDialogModel::iconSize() const
|
||||
{
|
||||
return m_iconSize;
|
||||
}
|
||||
|
||||
void KIconDialogModel::setIconSize(const QSize &iconSize)
|
||||
{
|
||||
m_iconSize = iconSize;
|
||||
}
|
||||
|
||||
QLatin1String KIconDialogModel::symbolicSuffix()
|
||||
{
|
||||
return QLatin1String("-symbolic");
|
||||
}
|
||||
|
||||
bool KIconDialogModel::hasSymbolicIcon() const
|
||||
{
|
||||
return m_hasSymbolicIcon;
|
||||
}
|
||||
|
||||
void KIconDialogModel::load(const QStringList &paths)
|
||||
{
|
||||
beginResetModel();
|
||||
|
||||
const bool oldSymbolic = m_hasSymbolicIcon;
|
||||
m_hasSymbolicIcon = false;
|
||||
|
||||
m_data.clear();
|
||||
m_data.reserve(paths.count());
|
||||
|
||||
for (const QString &path : paths) {
|
||||
const QFileInfo fi(path);
|
||||
|
||||
KIconDialogModelData item;
|
||||
item.name = fi.completeBaseName();
|
||||
item.path = path;
|
||||
// pixmap is created on demand
|
||||
|
||||
if (!m_hasSymbolicIcon && item.name.endsWith(symbolicSuffix())) {
|
||||
m_hasSymbolicIcon = true;
|
||||
}
|
||||
|
||||
m_data.append(item);
|
||||
}
|
||||
|
||||
endResetModel();
|
||||
|
||||
if (oldSymbolic != m_hasSymbolicIcon) {
|
||||
Q_EMIT hasSymbolicIconChanged(m_hasSymbolicIcon);
|
||||
}
|
||||
}
|
||||
|
||||
int KIconDialogModel::rowCount(const QModelIndex &parent) const
|
||||
{
|
||||
if (parent.isValid()) {
|
||||
return 0;
|
||||
}
|
||||
return m_data.count();
|
||||
}
|
||||
|
||||
QVariant KIconDialogModel::data(const QModelIndex &index, int role) const
|
||||
{
|
||||
if (!checkIndex(index, QAbstractItemModel::CheckIndexOption::IndexIsValid)) {
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
const auto &item = m_data.at(index.row());
|
||||
|
||||
switch (role) {
|
||||
case Qt::DisplayRole:
|
||||
return item.name;
|
||||
case Qt::DecorationRole:
|
||||
if (item.pixmap.isNull()) {
|
||||
const_cast<KIconDialogModel *>(this)->loadPixmap(index);
|
||||
}
|
||||
return item.pixmap;
|
||||
case Qt::ToolTipRole:
|
||||
return item.name;
|
||||
case PathRole:
|
||||
return item.path;
|
||||
}
|
||||
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
void KIconDialogModel::loadPixmap(const QModelIndex &index)
|
||||
{
|
||||
Q_ASSERT(index.isValid());
|
||||
|
||||
auto &item = m_data[index.row()];
|
||||
Q_ASSERT(item.pixmap.isNull());
|
||||
|
||||
const auto dpr = devicePixelRatio();
|
||||
|
||||
item.pixmap = m_loader->loadScaledIcon(item.path, KIconLoader::Desktop, dpr, iconSize(), KIconLoader::DefaultState, {}, nullptr, true);
|
||||
item.pixmap.setDevicePixelRatio(dpr);
|
||||
}
|
||||
|
||||
/**
|
||||
* Qt allocates very little horizontal space for the icon name,
|
||||
* even if the gridSize width is large. This delegate allocates
|
||||
* the gridSize width (minus some padding) for the icon and icon name.
|
||||
*/
|
||||
class KIconCanvasDelegate : public QAbstractItemDelegate
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
KIconCanvasDelegate(QListView *parent, QAbstractItemDelegate *defaultDelegate);
|
||||
~KIconCanvasDelegate() override
|
||||
{
|
||||
}
|
||||
void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override;
|
||||
QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const override;
|
||||
|
||||
private:
|
||||
QAbstractItemDelegate *m_defaultDelegate = nullptr;
|
||||
};
|
||||
|
||||
KIconCanvasDelegate::KIconCanvasDelegate(QListView *parent, QAbstractItemDelegate *defaultDelegate)
|
||||
: QAbstractItemDelegate(parent)
|
||||
{
|
||||
m_defaultDelegate = defaultDelegate;
|
||||
}
|
||||
|
||||
void KIconCanvasDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
|
||||
{
|
||||
auto *canvas = static_cast<QListView *>(parent());
|
||||
const int gridWidth = canvas->gridSize().width();
|
||||
QStyleOptionViewItem newOption = option;
|
||||
newOption.displayAlignment = Qt::AlignHCenter | Qt::AlignTop;
|
||||
newOption.features.setFlag(QStyleOptionViewItem::WrapText);
|
||||
// Manipulate the width available.
|
||||
newOption.rect.setX((option.rect.x() / gridWidth) * gridWidth + s_edgePad);
|
||||
newOption.rect.setY(option.rect.y() + s_edgePad);
|
||||
newOption.rect.setWidth(gridWidth - 2 * s_edgePad);
|
||||
newOption.rect.setHeight(option.rect.height() - 2 * s_edgePad);
|
||||
m_defaultDelegate->paint(painter, newOption, index);
|
||||
}
|
||||
|
||||
QSize KIconCanvasDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const
|
||||
{
|
||||
auto *canvas = static_cast<QListView *>(parent());
|
||||
|
||||
// TODO can we set wrap text and display alignment somewhere globally?
|
||||
QStyleOptionViewItem newOption = option;
|
||||
newOption.displayAlignment = Qt::AlignHCenter | Qt::AlignTop;
|
||||
newOption.features.setFlag(QStyleOptionViewItem::WrapText);
|
||||
|
||||
QSize size = m_defaultDelegate->sizeHint(newOption, index);
|
||||
const int gridWidth = canvas->gridSize().width();
|
||||
const int gridHeight = canvas->gridSize().height();
|
||||
size.setWidth(gridWidth - 2 * s_edgePad);
|
||||
size.setHeight(gridHeight - 2 * s_edgePad);
|
||||
QFontMetrics metrics(option.font);
|
||||
size.setHeight(gridHeight + metrics.height() * 3);
|
||||
return size;
|
||||
}
|
||||
|
||||
KIconDialogPrivate::KIconDialogPrivate(KIconDialog *qq)
|
||||
: q(qq)
|
||||
, mpLoader(KIconLoader::global())
|
||||
, model(new KIconDialogModel(mpLoader, qq))
|
||||
, proxyModel(new KIconDialogSortFilterProxyModel(qq))
|
||||
, filterSymbolicAction(new QAction(qq))
|
||||
, filterSymbolicGroup(new QActionGroup(qq))
|
||||
{
|
||||
proxyModel->setSourceModel(model);
|
||||
proxyModel->setFilterCaseSensitivity(Qt::CaseInsensitive);
|
||||
|
||||
filterSymbolicGroup->setExclusive(true);
|
||||
|
||||
QObject::connect(model, &KIconDialogModel::hasSymbolicIconChanged, filterSymbolicAction, &QAction::setVisible);
|
||||
QObject::connect(model, &KIconDialogModel::hasSymbolicIconChanged, proxyModel, &KIconDialogSortFilterProxyModel::setHasSymbolicIcon);
|
||||
}
|
||||
|
||||
/*
|
||||
* KIconDialog: Dialog for selecting icons. Both system and user
|
||||
* specified icons can be chosen.
|
||||
*/
|
||||
|
||||
KIconDialog::KIconDialog(QWidget *parent)
|
||||
: QDialog(parent)
|
||||
, d(new KIconDialogPrivate(this))
|
||||
{
|
||||
setModal(true);
|
||||
|
||||
d->init();
|
||||
}
|
||||
|
||||
void KIconDialogPrivate::init()
|
||||
{
|
||||
mGroupOrSize = KIconLoader::Desktop;
|
||||
mContext = KIconLoader::Any;
|
||||
|
||||
ui.setupUi(q);
|
||||
|
||||
auto updatePlaceholder = [this] {
|
||||
updatePlaceholderLabel();
|
||||
};
|
||||
QObject::connect(proxyModel, &QSortFilterProxyModel::modelReset, q, updatePlaceholder);
|
||||
QObject::connect(proxyModel, &QSortFilterProxyModel::rowsInserted, q, updatePlaceholder);
|
||||
QObject::connect(proxyModel, &QSortFilterProxyModel::rowsRemoved, q, updatePlaceholder);
|
||||
|
||||
QAction *findAction = KStandardActions::find(ui.searchLine, qOverload<>(&QWidget::setFocus), q);
|
||||
q->addAction(findAction);
|
||||
|
||||
QMenu *filterSymbolicMenu = new QMenu(q);
|
||||
|
||||
QAction *filterSymbolicAll = filterSymbolicMenu->addAction(i18nc("@item:inmenu All icons", "All"));
|
||||
filterSymbolicAll->setData(KIconDialogSortFilterProxyModel::AllSymbolicIcons);
|
||||
filterSymbolicAll->setChecked(true); // Start with "All" icons.
|
||||
filterSymbolicAll->setCheckable(true);
|
||||
|
||||
QAction *filterSymbolicOnly = filterSymbolicMenu->addAction(i18nc("@item:inmenu Show only symbolic icons", "Only Symbolic"));
|
||||
filterSymbolicOnly->setData(KIconDialogSortFilterProxyModel::OnlySymbolicIcons);
|
||||
filterSymbolicOnly->setCheckable(true);
|
||||
|
||||
QAction *filterSymbolicNone = filterSymbolicMenu->addAction(i18nc("@item:inmenu Hide symbolic icons", "No Symbolic"));
|
||||
filterSymbolicNone->setData(KIconDialogSortFilterProxyModel::NoSymbolicIcons);
|
||||
filterSymbolicNone->setCheckable(true);
|
||||
|
||||
filterSymbolicAction->setIcon(QIcon::fromTheme(QStringLiteral("view-filter")));
|
||||
filterSymbolicAction->setCheckable(true);
|
||||
filterSymbolicAction->setChecked(true);
|
||||
filterSymbolicAction->setMenu(filterSymbolicMenu);
|
||||
|
||||
filterSymbolicGroup->addAction(filterSymbolicAll);
|
||||
filterSymbolicGroup->addAction(filterSymbolicOnly);
|
||||
filterSymbolicGroup->addAction(filterSymbolicNone);
|
||||
QObject::connect(filterSymbolicGroup, &QActionGroup::triggered, q, [this](QAction *action) {
|
||||
proxyModel->setSymbolicIcons(static_cast<KIconDialogSortFilterProxyModel::SymbolicIcons>(action->data().toInt()));
|
||||
});
|
||||
|
||||
ui.searchLine->addAction(filterSymbolicAction, QLineEdit::TrailingPosition);
|
||||
|
||||
QObject::connect(ui.searchLine, &QLineEdit::textChanged, proxyModel, &QSortFilterProxyModel::setFilterFixedString);
|
||||
|
||||
static const KLazyLocalizedString context_text[] = {
|
||||
kli18n("All"),
|
||||
kli18n("Actions"),
|
||||
kli18n("Applications"),
|
||||
kli18n("Categories"),
|
||||
kli18n("Devices"),
|
||||
kli18n("Emblems"),
|
||||
kli18n("Emotes"),
|
||||
kli18n("Mimetypes"),
|
||||
kli18n("Places"),
|
||||
kli18n("Status"),
|
||||
};
|
||||
static const KIconLoader::Context context_id[] = {
|
||||
KIconLoader::Any,
|
||||
KIconLoader::Action,
|
||||
KIconLoader::Application,
|
||||
KIconLoader::Category,
|
||||
KIconLoader::Device,
|
||||
KIconLoader::Emblem,
|
||||
KIconLoader::Emote,
|
||||
KIconLoader::MimeType,
|
||||
KIconLoader::Place,
|
||||
KIconLoader::StatusIcon,
|
||||
};
|
||||
const int cnt = sizeof(context_text) / sizeof(context_text[0]);
|
||||
for (int i = 0; i < cnt; ++i) {
|
||||
if (mpLoader->hasContext(context_id[i])) {
|
||||
ui.contextCombo->addItem(context_text[i].toString(), context_id[i]);
|
||||
if (i == 0) {
|
||||
ui.contextCombo->insertSeparator(i + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
ui.contextCombo->insertSeparator(ui.contextCombo->count());
|
||||
ui.contextCombo->addItem(i18nc("Other icons", "Other"));
|
||||
ui.contextCombo->setMaxVisibleItems(ui.contextCombo->count());
|
||||
ui.contextCombo->setFixedSize(ui.contextCombo->sizeHint());
|
||||
|
||||
QObject::connect(ui.contextCombo, qOverload<int>(&QComboBox::activated), q, [this]() {
|
||||
const auto currentData = ui.contextCombo->currentData();
|
||||
if (currentData.isValid()) {
|
||||
mContext = static_cast<KIconLoader::Context>(ui.contextCombo->currentData().toInt());
|
||||
} else {
|
||||
mContext = static_cast<KIconLoader::Context>(-1);
|
||||
}
|
||||
showIcons();
|
||||
});
|
||||
|
||||
auto *delegate = new KIconCanvasDelegate(ui.canvas, ui.canvas->itemDelegate());
|
||||
ui.canvas->setItemDelegate(delegate);
|
||||
|
||||
ui.canvas->setModel(proxyModel);
|
||||
|
||||
QObject::connect(ui.canvas, &QAbstractItemView::activated, q, [this]() {
|
||||
custom.clear();
|
||||
q->slotOk();
|
||||
});
|
||||
|
||||
// You can't just stack widgets on top of each other in Qt Designer
|
||||
auto *placeholderLayout = new QVBoxLayout(ui.canvas);
|
||||
|
||||
placeholderLabel = new QLabel();
|
||||
QFont placeholderLabelFont;
|
||||
// To match the size of a level 2 Heading/KTitleWidget
|
||||
placeholderLabelFont.setPointSize(qRound(placeholderLabelFont.pointSize() * 1.3));
|
||||
placeholderLabel->setFont(placeholderLabelFont);
|
||||
placeholderLabel->setTextInteractionFlags(Qt::NoTextInteraction);
|
||||
placeholderLabel->setWordWrap(true);
|
||||
placeholderLabel->setAlignment(Qt::AlignCenter);
|
||||
|
||||
// Match opacity of QML placeholder label component
|
||||
auto *effect = new QGraphicsOpacityEffect(placeholderLabel);
|
||||
effect->setOpacity(0.5);
|
||||
placeholderLabel->setGraphicsEffect(effect);
|
||||
|
||||
placeholderLayout->addWidget(placeholderLabel);
|
||||
placeholderLayout->setAlignment(placeholderLabel, Qt::AlignCenter);
|
||||
|
||||
updatePlaceholderLabel();
|
||||
|
||||
// TODO I bet there is a KStandardAction for that?
|
||||
browseButton = new QPushButton(QIcon::fromTheme(QStringLiteral("folder-open")), i18n("Browse…"));
|
||||
// TODO does this have implicatons? I just want the "Browse" button on the left side :)
|
||||
ui.buttonBox->addButton(browseButton, QDialogButtonBox::HelpRole);
|
||||
QObject::connect(browseButton, &QPushButton::clicked, q, [this] {
|
||||
browse();
|
||||
});
|
||||
|
||||
QObject::connect(ui.buttonBox, &QDialogButtonBox::accepted, q, &KIconDialog::slotOk);
|
||||
QObject::connect(ui.buttonBox, &QDialogButtonBox::rejected, q, &QDialog::reject);
|
||||
|
||||
q->adjustSize();
|
||||
}
|
||||
|
||||
KIconDialog::~KIconDialog() = default;
|
||||
|
||||
static bool sortByFileName(const QString &path1, const QString &path2)
|
||||
{
|
||||
const QString fileName1 = path1.mid(path1.lastIndexOf(QLatin1Char('/')) + 1);
|
||||
const QString fileName2 = path2.mid(path2.lastIndexOf(QLatin1Char('/')) + 1);
|
||||
return QString::compare(fileName1, fileName2, Qt::CaseInsensitive) < 0;
|
||||
}
|
||||
|
||||
void KIconDialogPrivate::showIcons()
|
||||
{
|
||||
QStringList filelist;
|
||||
if (isSystemIconsContext()) {
|
||||
if (m_bStrictIconSize) {
|
||||
filelist = mpLoader->queryIcons(mGroupOrSize, mContext);
|
||||
} else {
|
||||
filelist = mpLoader->queryIconsByContext(mGroupOrSize, mContext);
|
||||
}
|
||||
} else if (!customLocation.isEmpty()) {
|
||||
filelist = mpLoader->queryIconsByDir(customLocation);
|
||||
} else {
|
||||
// List PNG files found directly in the kiconload search paths.
|
||||
const QStringList pngNameFilter(QStringLiteral("*.png"));
|
||||
for (const QString &relDir : KIconLoader::global()->searchPaths()) {
|
||||
const QStringList dirs = QStandardPaths::locateAll(QStandardPaths::GenericDataLocation, relDir, QStandardPaths::LocateDirectory);
|
||||
for (const QString &dir : dirs) {
|
||||
const auto files = QDir(dir).entryList(pngNameFilter);
|
||||
for (const QString &fileName : files) {
|
||||
filelist << dir + QLatin1Char('/') + fileName;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::sort(filelist.begin(), filelist.end(), sortByFileName);
|
||||
|
||||
// The KIconCanvas has uniformItemSizes set which really expects
|
||||
// all added icons to be the same size, otherwise weirdness ensues :)
|
||||
// Ensure all SVGs are scaled to the desired size and that as few icons
|
||||
// need to be padded as possible by specifying a sensible size.
|
||||
if (mGroupOrSize < -1) {
|
||||
// mGroupOrSize can be -1 if NoGroup is chosen.
|
||||
// Explicit size.
|
||||
ui.canvas->setIconSize(QSize(-mGroupOrSize, -mGroupOrSize));
|
||||
} else {
|
||||
// Icon group.
|
||||
int groupSize = mpLoader->currentSize(static_cast<KIconLoader::Group>(mGroupOrSize));
|
||||
ui.canvas->setIconSize(QSize(groupSize, groupSize));
|
||||
}
|
||||
|
||||
// Try to make room for three lines of text...
|
||||
QFontMetrics metrics(ui.canvas->font());
|
||||
const int frameHMargin = ui.canvas->style()->pixelMetric(QStyle::PM_FocusFrameHMargin, nullptr, ui.canvas) + 1;
|
||||
const int lineCount = 3;
|
||||
ui.canvas->setGridSize(QSize(100, ui.canvas->iconSize().height() + lineCount * metrics.height() + 3 * frameHMargin));
|
||||
|
||||
// Set a minimum size of 6x3 icons
|
||||
const int columnCount = 6;
|
||||
const int rowCount = 3;
|
||||
QStyleOption opt;
|
||||
opt.initFrom(ui.canvas);
|
||||
int width = columnCount * ui.canvas->gridSize().width();
|
||||
width += ui.canvas->verticalScrollBar()->sizeHint().width() + 1;
|
||||
width += 2 * ui.canvas->frameWidth();
|
||||
if (ui.canvas->style()->styleHint(QStyle::SH_ScrollView_FrameOnlyAroundContents, &opt, ui.canvas)) {
|
||||
width += ui.canvas->style()->pixelMetric(QStyle::PM_ScrollView_ScrollBarSpacing, &opt, ui.canvas);
|
||||
}
|
||||
int height = rowCount * ui.canvas->gridSize().height() + 1;
|
||||
height += 2 * ui.canvas->frameWidth();
|
||||
|
||||
ui.canvas->setMinimumSize(QSize(width, height));
|
||||
|
||||
model->setIconSize(ui.canvas->iconSize());
|
||||
model->setDevicePixelRatio(q->devicePixelRatioF());
|
||||
model->load(filelist);
|
||||
|
||||
if (!pendingSelectedIcon.isEmpty()) {
|
||||
selectIcon(pendingSelectedIcon);
|
||||
pendingSelectedIcon.clear();
|
||||
}
|
||||
}
|
||||
|
||||
bool KIconDialogPrivate::selectIcon(const QString &iconName)
|
||||
{
|
||||
for (int i = 0; i < proxyModel->rowCount(); ++i) {
|
||||
const QModelIndex idx = proxyModel->index(i, 0);
|
||||
|
||||
QString name = idx.data(KIconDialogModel::PathRole).toString();
|
||||
if (!name.isEmpty() && isSystemIconsContext()) {
|
||||
const QFileInfo fi(name);
|
||||
name = fi.completeBaseName();
|
||||
}
|
||||
|
||||
if (iconName == name) {
|
||||
ui.canvas->setCurrentIndex(idx);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void KIconDialog::setStrictIconSize(bool b)
|
||||
{
|
||||
d->m_bStrictIconSize = b;
|
||||
}
|
||||
|
||||
bool KIconDialog::strictIconSize() const
|
||||
{
|
||||
return d->m_bStrictIconSize;
|
||||
}
|
||||
|
||||
void KIconDialog::setIconSize(int size)
|
||||
{
|
||||
// see KIconLoader, if you think this is weird
|
||||
if (size == 0) {
|
||||
d->mGroupOrSize = KIconLoader::Desktop; // default Group
|
||||
} else {
|
||||
d->mGroupOrSize = -size; // yes, KIconLoader::queryIconsByContext is weird
|
||||
}
|
||||
}
|
||||
|
||||
int KIconDialog::iconSize() const
|
||||
{
|
||||
// 0 or any other value ==> mGroupOrSize is a group, so we return 0
|
||||
return (d->mGroupOrSize < 0) ? -d->mGroupOrSize : 0;
|
||||
}
|
||||
|
||||
void KIconDialog::setSelectedIcon(const QString &iconName)
|
||||
{
|
||||
// TODO Update live when dialog is already open
|
||||
d->pendingSelectedIcon = iconName;
|
||||
}
|
||||
|
||||
void KIconDialog::setup(KIconLoader::Group group, KIconLoader::Context context, bool strictIconSize, int iconSize, bool user, bool lockUser, bool lockCustomDir)
|
||||
{
|
||||
d->m_bStrictIconSize = strictIconSize;
|
||||
d->m_bLockUser = lockUser;
|
||||
d->m_bLockCustomDir = lockCustomDir;
|
||||
if (iconSize == 0) {
|
||||
if (group == KIconLoader::NoGroup) {
|
||||
// NoGroup has numeric value -1, which should
|
||||
// not really be used with KIconLoader::queryIcons*(...);
|
||||
// pick a proper group.
|
||||
d->mGroupOrSize = KIconLoader::Small;
|
||||
} else {
|
||||
d->mGroupOrSize = group;
|
||||
}
|
||||
} else {
|
||||
d->mGroupOrSize = -iconSize;
|
||||
}
|
||||
|
||||
if (user) {
|
||||
d->ui.contextCombo->setCurrentIndex(d->ui.contextCombo->count() - 1);
|
||||
} else {
|
||||
d->setContext(context);
|
||||
}
|
||||
|
||||
d->ui.contextCombo->setEnabled(!user || !lockUser);
|
||||
|
||||
// Disable "Other" entry when user is locked
|
||||
auto *model = qobject_cast<QStandardItemModel *>(d->ui.contextCombo->model());
|
||||
auto *otherItem = model->item(model->rowCount() - 1);
|
||||
auto flags = otherItem->flags();
|
||||
flags.setFlag(Qt::ItemIsEnabled, !lockUser);
|
||||
otherItem->setFlags(flags);
|
||||
|
||||
// Only allow browsing when explicitly allowed and user icons are allowed
|
||||
// An app may not expect a path when asking only about system icons
|
||||
d->browseButton->setVisible(!lockCustomDir && (!user || !lockUser));
|
||||
}
|
||||
|
||||
void KIconDialogPrivate::setContext(KIconLoader::Context context)
|
||||
{
|
||||
mContext = context;
|
||||
const int index = ui.contextCombo->findData(context);
|
||||
if (index > -1) {
|
||||
ui.contextCombo->setCurrentIndex(index);
|
||||
}
|
||||
}
|
||||
|
||||
void KIconDialogPrivate::updatePlaceholderLabel()
|
||||
{
|
||||
if (proxyModel->rowCount() > 0) {
|
||||
placeholderLabel->hide();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!ui.searchLine->text().isEmpty()) {
|
||||
placeholderLabel->setText(i18n("No icons matching the search"));
|
||||
} else {
|
||||
placeholderLabel->setText(i18n("No icons in this category"));
|
||||
}
|
||||
|
||||
placeholderLabel->show();
|
||||
}
|
||||
|
||||
void KIconDialog::setCustomLocation(const QString &location)
|
||||
{
|
||||
d->customLocation = location;
|
||||
}
|
||||
|
||||
QString KIconDialog::openDialog()
|
||||
{
|
||||
if (exec() == Accepted) {
|
||||
if (!d->custom.isEmpty()) {
|
||||
return d->custom;
|
||||
}
|
||||
|
||||
const QString name = d->ui.canvas->currentIndex().data(KIconDialogModel::PathRole).toString();
|
||||
if (name.isEmpty() || !d->ui.contextCombo->currentData().isValid()) {
|
||||
return name;
|
||||
}
|
||||
|
||||
QFileInfo fi(name);
|
||||
return fi.completeBaseName();
|
||||
}
|
||||
|
||||
return QString();
|
||||
}
|
||||
|
||||
void KIconDialog::showDialog()
|
||||
{
|
||||
setModal(false);
|
||||
show();
|
||||
}
|
||||
|
||||
void KIconDialog::slotOk()
|
||||
{
|
||||
QString name;
|
||||
if (!d->custom.isEmpty()) {
|
||||
name = d->custom;
|
||||
} else {
|
||||
name = d->ui.canvas->currentIndex().data(KIconDialogModel::PathRole).toString();
|
||||
if (!name.isEmpty() && d->isSystemIconsContext()) {
|
||||
const QFileInfo fi(name);
|
||||
name = fi.completeBaseName();
|
||||
}
|
||||
}
|
||||
|
||||
Q_EMIT newIconName(name);
|
||||
QDialog::accept();
|
||||
}
|
||||
|
||||
void KIconDialog::showEvent(QShowEvent *event)
|
||||
{
|
||||
QDialog::showEvent(event);
|
||||
d->showIcons();
|
||||
d->ui.searchLine->setFocus();
|
||||
}
|
||||
|
||||
QString KIconDialog::getIcon(KIconLoader::Group group,
|
||||
KIconLoader::Context context,
|
||||
bool strictIconSize,
|
||||
int iconSize,
|
||||
bool user,
|
||||
QWidget *parent,
|
||||
const QString &title)
|
||||
{
|
||||
KIconDialog dlg(parent);
|
||||
dlg.setup(group, context, strictIconSize, iconSize, user);
|
||||
if (!title.isEmpty()) {
|
||||
dlg.setWindowTitle(title);
|
||||
}
|
||||
|
||||
return dlg.openDialog();
|
||||
}
|
||||
|
||||
void KIconDialogPrivate::browse()
|
||||
{
|
||||
if (browseDialog) {
|
||||
browseDialog.data()->show();
|
||||
browseDialog.data()->raise();
|
||||
return;
|
||||
}
|
||||
|
||||
// Create a file dialog to select an ICO, PNG, XPM or SVG file,
|
||||
// with the image previewer shown.
|
||||
QFileDialog *dlg = new QFileDialog(q, i18n("Select Icon"), QString(), i18n("*.ico *.png *.xpm *.svg *.svgz|Icon Files (*.ico *.png *.xpm *.svg *.svgz)"));
|
||||
// TODO This was deliberately modal before, why? Or just because "window modal" wasn't a thing?
|
||||
dlg->setWindowModality(Qt::WindowModal);
|
||||
dlg->setFileMode(QFileDialog::ExistingFile);
|
||||
QObject::connect(dlg, &QFileDialog::fileSelected, q, [this](const QString &path) {
|
||||
if (!path.isEmpty()) {
|
||||
custom = path;
|
||||
if (isSystemIconsContext()) {
|
||||
customLocation = QFileInfo(custom).absolutePath();
|
||||
}
|
||||
q->slotOk();
|
||||
}
|
||||
});
|
||||
browseDialog = dlg;
|
||||
dlg->show();
|
||||
}
|
||||
|
||||
bool KIconDialogPrivate::isSystemIconsContext() const
|
||||
{
|
||||
return ui.contextCombo->currentData().isValid();
|
||||
}
|
||||
|
||||
#include "kicondialog.moc"
|
||||
#include "moc_kicondialog.cpp"
|
||||
#include "moc_kicondialogmodel_p.cpp"
|
||||
@@ -0,0 +1,163 @@
|
||||
/*
|
||||
|
||||
This file is part of the KDE project, module kfile.
|
||||
SPDX-FileCopyrightText: 2000 Geert Jansen <jansen@kde.org>
|
||||
SPDX-FileCopyrightText: 2000 Kurt Granroth <granroth@kde.org>
|
||||
SPDX-FileCopyrightText: 1997 Christoph Neerfeld <chris@kde.org>
|
||||
SPDX-FileCopyrightText: 2002 Carsten Pfeiffer <pfeiffer@kde.org>
|
||||
SPDX-FileCopyrightText: 2021 Kai Uwe Broulik <kde@broulik.de>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.0-only
|
||||
*/
|
||||
|
||||
#ifndef KICONDIALOG_H
|
||||
#define KICONDIALOG_H
|
||||
|
||||
#include "kiconwidgets_export.h"
|
||||
|
||||
#include <QDialog>
|
||||
#include <QPushButton>
|
||||
#include <memory>
|
||||
|
||||
#include <kiconloader.h>
|
||||
|
||||
/**
|
||||
* @class KIconDialog kicondialog.h KIconDialog
|
||||
*
|
||||
* Dialog for interactive selection of icons. Use the function
|
||||
* getIcon() to let the user select an icon.
|
||||
*
|
||||
* @short An icon selection dialog.
|
||||
*/
|
||||
class KICONWIDGETS_EXPORT KIconDialog : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
/**
|
||||
* Constructs an icon selection dialog using the global icon loader.
|
||||
*
|
||||
* @param parent The parent widget.
|
||||
*/
|
||||
explicit KIconDialog(QWidget *parent = nullptr);
|
||||
|
||||
/**
|
||||
* Destructs the dialog.
|
||||
*/
|
||||
~KIconDialog() override;
|
||||
|
||||
/**
|
||||
* Sets a strict icon size policy for allowed icons.
|
||||
*
|
||||
* @param policy When true, only icons of the specified group's
|
||||
* size in getIcon() are shown.
|
||||
* When false, icons not available at the desired group's size will
|
||||
* also be selectable.
|
||||
*/
|
||||
void setStrictIconSize(bool policy);
|
||||
/**
|
||||
* Returns true if a strict icon size policy is set.
|
||||
*/
|
||||
bool strictIconSize() const;
|
||||
|
||||
/**
|
||||
* Sets the location of the custom icon directory. Only local directory
|
||||
* paths are allowed.
|
||||
*/
|
||||
void setCustomLocation(const QString &location);
|
||||
|
||||
/**
|
||||
* Sets the size of the icons to be shown / selected.
|
||||
* @see KIconLoader::StdSizes
|
||||
* @see iconSize
|
||||
*/
|
||||
void setIconSize(int size);
|
||||
/**
|
||||
* Returns the icon size set via setIconSize() or 0, if the default
|
||||
* icon size will be used.
|
||||
*/
|
||||
int iconSize() const;
|
||||
|
||||
/**
|
||||
* Sets the icon that is initially selected in the dialog.
|
||||
*
|
||||
* @note Changing this after the dialog has been shown has no effect.
|
||||
* @note If the given icon cannot be found in the current context,
|
||||
* no icon will be selected.
|
||||
* @param iconName The name of the icon to select
|
||||
* @since 5.89
|
||||
*/
|
||||
void setSelectedIcon(const QString &iconName);
|
||||
|
||||
/**
|
||||
* Allows you to set the same parameters as in the class method
|
||||
* getIcon(), as well as two additional parameters to lock
|
||||
* the choice between system and user directories and to lock the
|
||||
* custom icon directory itself.
|
||||
*/
|
||||
void setup(KIconLoader::Group group,
|
||||
KIconLoader::Context context = KIconLoader::Application,
|
||||
bool strictIconSize = false,
|
||||
int iconSize = 0,
|
||||
bool user = false,
|
||||
bool lockUser = false,
|
||||
bool lockCustomDir = false);
|
||||
|
||||
/**
|
||||
* exec()utes this modal dialog and returns the name of the selected icon,
|
||||
* or QString() if the dialog was aborted.
|
||||
* @returns the name of the icon, suitable for loading with KIconLoader.
|
||||
* @see getIcon
|
||||
*/
|
||||
QString openDialog();
|
||||
|
||||
/**
|
||||
* show()s this dialog and emits a newIconName(const QString&) signal when
|
||||
* successful. QString() will be emitted if the dialog was aborted.
|
||||
*/
|
||||
void showDialog();
|
||||
|
||||
/**
|
||||
* Pops up the dialog an lets the user select an icon.
|
||||
*
|
||||
* @param group The icon group this icon is intended for. Providing the
|
||||
* group shows the icons in the dialog with the same appearance as when
|
||||
* used outside the dialog.
|
||||
* @param context The initial icon context. Initially, the icons having
|
||||
* this context are shown in the dialog. The user can change this.
|
||||
* @param strictIconSize When true, only icons of the specified group's size
|
||||
* are shown, otherwise icon not available in the desired group's size
|
||||
* will also be selectable.
|
||||
* @param iconSize the size of the icons -- the default of the icon group
|
||||
* if set to 0
|
||||
* @param user Begin with the "user icons" instead of "system icons".
|
||||
* @param parent The parent widget of the dialog.
|
||||
* @param title The title to use for the dialog.
|
||||
* @return The name of the icon, suitable for loading with KIconLoader.
|
||||
*/
|
||||
static QString getIcon(KIconLoader::Group group = KIconLoader::Desktop,
|
||||
KIconLoader::Context context = KIconLoader::Application,
|
||||
bool strictIconSize = false,
|
||||
int iconSize = 0,
|
||||
bool user = false,
|
||||
QWidget *parent = nullptr,
|
||||
const QString &title = QString());
|
||||
|
||||
Q_SIGNALS:
|
||||
void newIconName(const QString &iconName);
|
||||
|
||||
protected:
|
||||
void showEvent(QShowEvent *event) override;
|
||||
|
||||
protected Q_SLOTS:
|
||||
void slotOk();
|
||||
|
||||
private:
|
||||
std::unique_ptr<class KIconDialogPrivate> const d;
|
||||
|
||||
friend class KIconDialogPrivate;
|
||||
|
||||
Q_DISABLE_COPY(KIconDialog)
|
||||
};
|
||||
|
||||
#endif // KICONDIALOG_H
|
||||
@@ -0,0 +1,88 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>IconDialog</class>
|
||||
<widget class="QWidget" name="IconDialog">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>400</width>
|
||||
<height>300</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Select Icon</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QComboBox" name="contextCombo">
|
||||
<property name="accessibleName">
|
||||
<string>Icon category</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLineEdit" name="searchLine">
|
||||
<property name="placeholderText">
|
||||
<string>Search Icons...</string>
|
||||
</property>
|
||||
<property name="clearButtonEnabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QListView" name="canvas">
|
||||
<property name="iconSize">
|
||||
<size>
|
||||
<width>60</width>
|
||||
<height>60</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="movement">
|
||||
<enum>QListView::Static</enum>
|
||||
</property>
|
||||
<property name="resizeMode">
|
||||
<enum>QListView::Adjust</enum>
|
||||
</property>
|
||||
<property name="viewMode">
|
||||
<enum>QListView::IconMode</enum>
|
||||
</property>
|
||||
<property name="uniformItemSizes">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDialogButtonBox" name="buttonBox">
|
||||
<property name="standardButtons">
|
||||
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
|
||||
This file is part of the KDE project, module kfile.
|
||||
SPDX-FileCopyrightText: 2000 Geert Jansen <jansen@kde.org>
|
||||
SPDX-FileCopyrightText: 2000 Kurt Granroth <granroth@kde.org>
|
||||
SPDX-FileCopyrightText: 1997 Christoph Neerfeld <chris@kde.org>
|
||||
SPDX-FileCopyrightText: 2002 Carsten Pfeiffer <pfeiffer@kde.org>
|
||||
SPDX-FileCopyrightText: 2021 Kai Uwe Broulik <kde@broulik.de>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.0-only
|
||||
*/
|
||||
|
||||
#ifndef KICONDIALOG_P_H
|
||||
#define KICONDIALOG_P_H
|
||||
|
||||
#include <QFileDialog>
|
||||
#include <QPointer>
|
||||
#include <QSortFilterProxyModel>
|
||||
|
||||
#include <kiconloader.h>
|
||||
|
||||
#include "kicondialogmodel_p.h"
|
||||
|
||||
#include "ui_kicondialog.h"
|
||||
|
||||
class QLabel;
|
||||
class QPushButton;
|
||||
|
||||
class KIconDialog;
|
||||
class KIconDialogSortFilterProxyModel;
|
||||
|
||||
class KIconDialogPrivate
|
||||
{
|
||||
public:
|
||||
KIconDialogPrivate(KIconDialog *qq);
|
||||
|
||||
void init();
|
||||
void showIcons();
|
||||
bool selectIcon(const QString &iconName);
|
||||
void setContext(KIconLoader::Context context);
|
||||
void updatePlaceholderLabel();
|
||||
|
||||
void browse();
|
||||
|
||||
bool isSystemIconsContext() const;
|
||||
|
||||
KIconDialog *q;
|
||||
|
||||
KIconLoader *mpLoader;
|
||||
|
||||
KIconDialogModel *model;
|
||||
KIconDialogSortFilterProxyModel *proxyModel;
|
||||
|
||||
int mGroupOrSize;
|
||||
KIconLoader::Context mContext;
|
||||
|
||||
QLabel *placeholderLabel;
|
||||
QPushButton *browseButton;
|
||||
|
||||
QAction *filterSymbolicAction;
|
||||
QActionGroup *filterSymbolicGroup;
|
||||
|
||||
bool m_bStrictIconSize = true;
|
||||
bool m_bLockUser = false;
|
||||
bool m_bLockCustomDir = false;
|
||||
QString custom;
|
||||
QString customLocation;
|
||||
QString pendingSelectedIcon;
|
||||
QPointer<QFileDialog> browseDialog;
|
||||
|
||||
Ui::IconDialog ui;
|
||||
};
|
||||
|
||||
#endif // KICONDIALOG_P_H
|
||||
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
SPDX-FileCopyrightText: 2021 Kai Uwe Broulik <kde@broulik.de>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#ifndef KICONDIALOGMODEL_P_H
|
||||
#define KICONDIALOGMODEL_P_H
|
||||
|
||||
#include <QAbstractListModel>
|
||||
#include <QList>
|
||||
#include <QPixmap>
|
||||
#include <QSize>
|
||||
#include <QString>
|
||||
#include <QStringList>
|
||||
|
||||
class KIconLoader;
|
||||
|
||||
struct KIconDialogModelData {
|
||||
QString name;
|
||||
QString path;
|
||||
QPixmap pixmap;
|
||||
};
|
||||
Q_DECLARE_TYPEINFO(KIconDialogModelData, Q_RELOCATABLE_TYPE);
|
||||
|
||||
class KIconDialogModel : public QAbstractListModel
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
KIconDialogModel(KIconLoader *loader, QObject *parent);
|
||||
~KIconDialogModel() override;
|
||||
|
||||
enum Roles { PathRole = Qt::UserRole };
|
||||
|
||||
qreal devicePixelRatio() const;
|
||||
void setDevicePixelRatio(qreal dpr);
|
||||
|
||||
QSize iconSize() const;
|
||||
void setIconSize(const QSize &iconSize);
|
||||
|
||||
static QLatin1String symbolicSuffix();
|
||||
bool hasSymbolicIcon() const;
|
||||
|
||||
void load(const QStringList &paths);
|
||||
|
||||
int rowCount(const QModelIndex &parent) const override;
|
||||
QVariant data(const QModelIndex &index, int role) const override;
|
||||
|
||||
Q_SIGNALS:
|
||||
void hasSymbolicIconChanged(bool hasSymbolicIcon);
|
||||
|
||||
private:
|
||||
void loadPixmap(const QModelIndex &index);
|
||||
|
||||
QList<KIconDialogModelData> m_data;
|
||||
|
||||
KIconLoader *m_loader;
|
||||
qreal m_dpr = 1;
|
||||
QSize m_iconSize;
|
||||
bool m_hasSymbolicIcon = false;
|
||||
};
|
||||
|
||||
#endif // KICONDIALOGMODEL_P_H
|
||||
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
SPDX-FileCopyrightText: 2000 Geert Jansen <jansen@kde.org>
|
||||
SPDX-FileCopyrightText: 2000 Antonio Larrosa <larrosa@kde.org>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.0-only
|
||||
*/
|
||||
|
||||
#include "kpixmapsequenceloader.h"
|
||||
|
||||
#include <KIconLoader>
|
||||
|
||||
namespace KPixmapSequenceLoader
|
||||
{
|
||||
|
||||
KPixmapSequence load(const QString &iconName, int size)
|
||||
{
|
||||
return KPixmapSequence(KIconLoader::global()->iconPath(iconName, -size), size);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
SPDX-FileCopyrightText: 2000 Geert Jansen <jansen@kde.org>
|
||||
SPDX-FileCopyrightText: 2000 Antonio Larrosa <larrosa@kde.org>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.0-only
|
||||
*/
|
||||
|
||||
#ifndef KPIXMAPSEQUENCELOADER_H
|
||||
#define KPIXMAPSEQUENCELOADER_H
|
||||
|
||||
#include <KPixmapSequence>
|
||||
|
||||
#include "kiconwidgets_export.h"
|
||||
|
||||
namespace KPixmapSequenceLoader
|
||||
{
|
||||
|
||||
/**
|
||||
* Loads a pixmapSequence given the xdg icon name
|
||||
*
|
||||
* @param iconName The name of the icon, without extension.
|
||||
* @param size the size to be used
|
||||
* @since 6.0
|
||||
*/
|
||||
KICONWIDGETS_EXPORT KPixmapSequence load(const QString &iconName, int size);
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user